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
227/// MEMRA_STEP_NVFP4_EP2=1: whole-expert (expert-parallel) NVFP4 banks at 2 ranks — expert e
228/// lives ENTIRE on rank (e & 1) at bank slot (e >> 1), replacing the TP column/row shards
229/// (same total VRAM; both sets cannot coexist). Decode rides owner-guarded full-width
230/// sweeps with per-rank slot-ordered partial sums; the cross-rank join is unchanged.
231/// NUMERIC-CLASS door (the slot chain regroups per rank): run-gen argmax gate + battery +
232/// fresh tape, the DEV_ROUTES acceptance class.
233pub(crate) fn step_nvfp4_ep2_on() -> bool {
234    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
235    *ON.get_or_init(|| std::env::var("MEMRA_STEP_NVFP4_EP2").as_deref() == Ok("1"))
236}
237
238pub(crate) fn sel_down8_on() -> bool {
239    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
240    *ON.get_or_init(|| std::env::var("MEMRA_SEL_DOWN8").as_deref() == Ok("1"))
241}
242
243pub(crate) fn oproj_direct_on() -> bool {
244    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
245    *ON.get_or_init(|| std::env::var("MEMRA_OPROJ_DIRECT").as_deref() == Ok("1"))
246}
247
248pub(crate) fn raw_copy_bytes(
249    dst: u64,
250    src: u64,
251    bytes: usize,
252    engine: &Engine,
253) -> Result<(), Box<dyn std::error::Error>> {
254    use cudarc::driver::sys;
255    let r = unsafe {
256        sys::cuMemcpyAsync(
257            dst as sys::CUdeviceptr,
258            src as sys::CUdeviceptr,
259            bytes,
260            engine.stream().cu_stream() as sys::CUstream,
261        )
262    };
263    if r == sys::CUresult::CUDA_SUCCESS {
264        Ok(())
265    } else {
266        Err(format!("raw_copy_bytes: {r:?}").into())
267    }
268}
269
270pub fn step_expert_activation_host(gate: f32, up: f32, limit: Option<f32>) -> f32 {
271    let silu = gate / (1.0 + (-gate).exp());
272    match limit {
273        Some(limit) => silu.min(limit) * up.clamp(-limit, limit),
274        None => silu * up,
275    }
276}
277
278#[derive(Debug, Clone, PartialEq, Eq)]
279struct ExpertOwnerRoutes {
280    rank: usize,
281    selected: Vec<usize>,
282    token_rows: Vec<usize>,
283    global_pairs: Vec<usize>,
284}
285
286fn partition_expert_owner_routes(
287    expert_count: usize,
288    ranks: usize,
289    tokens: usize,
290    experts_per_token: usize,
291    selected: &[usize],
292) -> Result<Vec<ExpertOwnerRoutes>, String> {
293    if expert_count == 0
294        || ranks == 0
295        || tokens == 0
296        || experts_per_token == 0
297        || expert_count % ranks != 0
298    {
299        return Err(format!(
300            "invalid expert-owner route geometry experts={expert_count} ranks={ranks} \
301             tokens={tokens} experts_per_token={experts_per_token}"
302        ));
303    }
304    let pairs = tokens
305        .checked_mul(experts_per_token)
306        .ok_or("expert-owner route count overflow")?;
307    if selected.len() != pairs {
308        return Err(format!(
309            "expert-owner routes {} != {tokens}x{experts_per_token} ({pairs})",
310            selected.len()
311        ));
312    }
313    let per_rank = expert_count / ranks;
314    let mut owners = (0..ranks)
315        .map(|rank| ExpertOwnerRoutes {
316            rank,
317            selected: Vec::new(),
318            token_rows: Vec::new(),
319            global_pairs: Vec::new(),
320        })
321        .collect::<Vec<_>>();
322    for (pair, &expert) in selected.iter().enumerate() {
323        if expert >= expert_count {
324            return Err(format!(
325                "expert-owner route {pair} selects expert {expert} outside 0..{expert_count}"
326            ));
327        }
328        let rank = expert / per_rank;
329        owners[rank].selected.push(expert - rank * per_rank);
330        owners[rank].token_rows.push(pair / experts_per_token);
331        owners[rank].global_pairs.push(pair);
332    }
333    Ok(owners)
334}
335
336fn validate_step_grouped_owner_routes(
337    expert_count: usize,
338    tokens: usize,
339    selected: &[usize],
340) -> Result<usize, String> {
341    if expert_count != STEP_GROUPED_FP8_EXPERTS || tokens == 0 {
342        return Err(format!(
343            "official Step owner-grouped FP8 requires {} experts and nonzero tokens, got \
344             experts={expert_count} tokens={tokens}",
345            STEP_GROUPED_FP8_EXPERTS
346        ));
347    }
348    let pairs = tokens
349        .checked_mul(STEP_GROUPED_FP8_TOP_K)
350        .ok_or("official Step owner-grouped FP8 route count overflow")?;
351    if selected.len() != pairs {
352        return Err(format!(
353            "official Step owner-grouped FP8 routes {} != {tokens}x{} ({pairs})",
354            selected.len(),
355            STEP_GROUPED_FP8_TOP_K,
356        ));
357    }
358    for (token, routes) in selected.chunks_exact(STEP_GROUPED_FP8_TOP_K).enumerate() {
359        let mut unique = routes.to_vec();
360        unique.sort_unstable();
361        unique.dedup();
362        if unique.len() != STEP_GROUPED_FP8_TOP_K {
363            return Err(format!(
364                "official Step owner-grouped FP8 token {token} routes are not top-8 unique: \
365                 {routes:?}"
366            ));
367        }
368    }
369    Ok(pairs)
370}
371
372#[derive(Debug, Clone, Copy, PartialEq, Eq)]
373struct WeightedRouteCombineShape {
374    pairs: usize,
375    max_pairs: usize,
376}
377
378fn validate_weighted_route_combine(
379    width: usize,
380    experts_per_token: usize,
381    max_tokens: usize,
382    tokens: usize,
383    owner_global_pairs: &[&[usize]],
384    route_weights: &[f32],
385) -> Result<WeightedRouteCombineShape, String> {
386    if width == 0
387        || experts_per_token == 0
388        || max_tokens == 0
389        || tokens == 0
390        || tokens > max_tokens
391        || width > i32::MAX as usize
392        || experts_per_token > i32::MAX as usize
393        || tokens > i32::MAX as usize
394    {
395        return Err(format!(
396            "invalid weighted route combine geometry width={width} experts_per_token=\
397             {experts_per_token} tokens={tokens}/{max_tokens}"
398        ));
399    }
400    let pairs = tokens
401        .checked_mul(experts_per_token)
402        .ok_or("weighted route combine pair count overflow")?;
403    let max_pairs = max_tokens
404        .checked_mul(experts_per_token)
405        .ok_or("weighted route combine capacity overflow")?;
406    if route_weights.len() != pairs || !route_weights.iter().all(|weight| weight.is_finite()) {
407        return Err(format!(
408            "weighted route combine weights {} != pairs {pairs} or contain a non-finite value",
409            route_weights.len()
410        ));
411    }
412    let mut seen = vec![false; pairs];
413    let mut observed = 0usize;
414    for pairs_for_owner in owner_global_pairs {
415        observed = observed
416            .checked_add(pairs_for_owner.len())
417            .ok_or("weighted route combine observed pair count overflow")?;
418        for &pair in *pairs_for_owner {
419            if pair >= pairs || std::mem::replace(&mut seen[pair], true) {
420                return Err(format!(
421                    "weighted route combine pair {pair} is outside 0..{pairs} or duplicated"
422                ));
423            }
424        }
425    }
426    if observed != pairs || seen.iter().any(|present| !present) {
427        return Err(format!(
428            "weighted route combine owner schedules cover {observed} of {pairs} canonical pairs"
429        ));
430    }
431    Ok(WeightedRouteCombineShape { pairs, max_pairs })
432}
433
434fn cache_rank_rows(
435    rows: &[u8],
436    tokens: usize,
437    local_token_bytes: usize,
438    ranks: usize,
439    rank: usize,
440) -> Result<Vec<u8>, String> {
441    if ranks == 0 || rank >= ranks {
442        return Err(format!(
443            "TP cache rank {rank} is outside a {ranks}-rank layout"
444        ));
445    }
446    let global_token_bytes = local_token_bytes
447        .checked_mul(ranks)
448        .ok_or("TP cache global token-byte overflow")?;
449    let expected = tokens
450        .checked_mul(global_token_bytes)
451        .ok_or("TP cache row-byte overflow")?;
452    if rows.len() != expected {
453        return Err(format!(
454            "TP cache rows contain {} bytes, expected {tokens}x{global_token_bytes}={expected}",
455            rows.len()
456        ));
457    }
458    let mut shard = Vec::with_capacity(tokens * local_token_bytes);
459    for token in 0..tokens {
460        let start = token * global_token_bytes + rank * local_token_bytes;
461        shard.extend_from_slice(&rows[start..start + local_token_bytes]);
462    }
463    Ok(shard)
464}
465
466fn parse_step_tp_native_p2p(value: Option<&str>) -> Result<bool, String> {
467    match value {
468        None | Some("") | Some("0") => Ok(false),
469        Some("1") => Ok(true),
470        Some(value) => Err(format!(
471            "MEMRA_STEP_TP_NATIVE_P2P={value:?} is invalid; expected 0 or 1"
472        )),
473    }
474}
475
476pub fn step_tp_native_p2p_enabled() -> Result<bool, String> {
477    parse_step_tp_native_p2p(std::env::var("MEMRA_STEP_TP_NATIVE_P2P").ok().as_deref())
478}
479
480fn parse_step_tp_bulk_p2p(value: Option<&str>) -> Result<bool, String> {
481    match value {
482        None | Some("") | Some("0") => Ok(false),
483        Some("1") => Ok(true),
484        Some(value) => Err(format!(
485            "MEMRA_STEP_TP_BULK_P2P={value:?} is invalid; expected 0 or 1"
486        )),
487    }
488}
489
490pub fn step_tp_bulk_p2p_enabled() -> Result<bool, String> {
491    parse_step_tp_bulk_p2p(std::env::var("MEMRA_STEP_TP_BULK_P2P").ok().as_deref())
492}
493
494fn parse_step_ep_device_arithmetic(value: Option<&str>) -> Result<bool, String> {
495    match value {
496        None | Some("") | Some("0") => Ok(false),
497        Some("1") => Ok(true),
498        Some(value) => Err(format!(
499            "MEMRA_STEP_EP_DEVICE_ARITHMETIC={value:?} is invalid; expected 0 or 1"
500        )),
501    }
502}
503
504fn parse_step_nvfp4_dev_routes(value: Option<&str>) -> Result<bool, String> {
505    match value {
506        None | Some("") | Some("0") => Ok(false),
507        Some("1") => Ok(true),
508        Some(value) => Err(format!(
509            "MEMRA_STEP_NVFP4_DEV_ROUTES={value:?} is invalid; expected 0 or 1"
510        )),
511    }
512}
513
514/// Opt-in door for the device-resident NVFP4 TP routed-expert decode program. Default OFF; the
515/// host-canonical program remains the oracle until the device path carries its own gates.
516pub fn step_nvfp4_dev_routes_enabled() -> Result<bool, String> {
517    parse_step_nvfp4_dev_routes(std::env::var("MEMRA_STEP_NVFP4_DEV_ROUTES").ok().as_deref())
518}
519
520pub fn step_ep_device_arithmetic_enabled() -> Result<bool, String> {
521    parse_step_ep_device_arithmetic(
522        std::env::var("MEMRA_STEP_EP_DEVICE_ARITHMETIC")
523            .ok()
524            .as_deref(),
525    )
526}
527
528fn parse_step_tp_f32_mirror(value: Option<&str>) -> Result<bool, String> {
529    match value {
530        None | Some("") | Some("0") => Ok(false),
531        Some("1") => Ok(true),
532        Some(value) => Err(format!(
533            "MEMRA_STEP_TP_F32_MIRROR={value:?} is invalid; expected 0 or 1"
534        )),
535    }
536}
537
538pub fn step_tp_f32_mirror_enabled() -> Result<bool, String> {
539    parse_step_tp_f32_mirror(std::env::var("MEMRA_STEP_TP_F32_MIRROR").ok().as_deref())
540}
541
542fn parse_step_tp_decode_v2(value: Option<&str>) -> Result<bool, String> {
543    match value {
544        None | Some("") | Some("0") => Ok(false),
545        Some("1") => Ok(true),
546        Some(value) => Err(format!(
547            "MEMRA_STEP_TP_DECODE_V2={value:?} is invalid; expected 0 or 1"
548        )),
549    }
550}
551
552/// The v2 rank-local Step decode-attention driver: persistent workspaces, evented cross-stream
553/// ordering, and a root-device O reduction — same kernels, values, and canonical reduction order
554/// as the v1 driver (it requires the F32 mirror so no per-call weight expansion exists on either
555/// side of the comparison).
556pub fn step_tp_decode_v2_enabled() -> Result<bool, String> {
557    parse_step_tp_decode_v2(std::env::var("MEMRA_STEP_TP_DECODE_V2").ok().as_deref())
558}
559
560fn parse_step_tp_qkv_fused(value: Option<&str>) -> Result<bool, String> {
561    match value {
562        None | Some("") | Some("0") => Ok(false),
563        Some("1") => Ok(true),
564        Some(value) => Err(format!(
565            "MEMRA_STEP_TP_QKV_FUSED={value:?} is invalid; expected 0 or 1"
566        )),
567    }
568}
569
570fn parse_step_tp_dev_router(value: Option<&str>) -> Result<bool, String> {
571    match value {
572        None | Some("") | Some("0") => Ok(false),
573        Some("1") => Ok(true),
574        Some(value) => Err(format!(
575            "MEMRA_STEP_TP_DEV_ROUTER={value:?} is invalid; expected 0 or 1"
576        )),
577    }
578}
579
580/// Device-side sigmoid top-k routing for the TP device-IO expert program: the per-layer host
581/// logits readback (the last per-layer host sync) disappears. Selection tie-breaking may
582/// differ from the host router — NUMERIC-CLASS door, run-gen argmax gate + boot battery.
583pub fn step_tp_dev_router_enabled() -> Result<bool, String> {
584    parse_step_tp_dev_router(std::env::var("MEMRA_STEP_TP_DEV_ROUTER").ok().as_deref())
585}
586
587fn parse_step_tp_graph(value: Option<&str>) -> Result<bool, String> {
588    match value {
589        None | Some("") | Some("0") => Ok(false),
590        Some("1") => Ok(true),
591        Some(value) => Err(format!(
592            "MEMRA_STEP_TP_GRAPH={value:?} is invalid; expected 0 or 1"
593        )),
594    }
595}
596
597fn parse_step_tp_dcw(value: Option<&str>) -> Result<bool, String> {
598    match value {
599        None | Some("") | Some("0") => Ok(false),
600        Some("1") => Ok(true),
601        Some(value) => Err(format!(
602            "MEMRA_STEP_TP_DCW={value:?} is invalid; expected 0 or 1"
603        )),
604    }
605}
606
607/// Device-counter attention path (graph increment A run EAGERLY): append at len_d - base_d,
608/// inc_i32, fa over the counter-derived window — with bucket = the effective t_kv this is
609/// bit-identical to the host-row + kvmod path (the one-partition law), and it is the exact
610/// child content the capture wraps. Rebase tokens and sub-vec-floor contexts fall back.
611pub fn step_tp_dcw_enabled() -> Result<bool, String> {
612    parse_step_tp_dcw(std::env::var("MEMRA_STEP_TP_DCW").ok().as_deref())
613}
614
615/// CUDA-graph door for the shape-stable TP segments (first increment: the device-routed
616/// expert program — per-layer multi-device parents built from per-rank children, launched on
617/// the model engine's stream; zero per-token node updates). Mechanism proven by
618/// tp_graph_probe. VALUE-IDENTICAL: the graphs replay exactly the eager kernel/copy sequence.
619pub fn step_tp_graph_enabled() -> Result<bool, String> {
620    parse_step_tp_graph(std::env::var("MEMRA_STEP_TP_GRAPH").ok().as_deref())
621}
622
623/// Fused single-launch QKV projection inside the v2 decode driver — a NUMERIC-CLASS door
624/// (per-row deterministic tree reduce instead of the chunked cuBLASLt program), default OFF,
625/// gated by the run-gen argmax gate + boot battery like MEMRA_STEP_NVFP4_DEV_ROUTES.
626pub fn step_tp_qkv_fused_enabled() -> Result<bool, String> {
627    parse_step_tp_qkv_fused(std::env::var("MEMRA_STEP_TP_QKV_FUSED").ok().as_deref())
628}
629
630#[derive(Debug, Clone, PartialEq, Eq)]
631pub struct StepEpLayerSpec {
632    pub layer: usize,
633    pub devices: Vec<usize>,
634}
635
636pub type StepTpLayerSpec = StepEpLayerSpec;
637
638fn parse_step_layer_specs(
639    flag: &str,
640    value: Option<&str>,
641    allow_full_model: bool,
642) -> Result<Vec<StepEpLayerSpec>, String> {
643    let Some(value) = value else {
644        return Ok(Vec::new());
645    };
646    if value.is_empty() || value == "0" {
647        return Ok(Vec::new());
648    }
649
650    let mut specs = Vec::new();
651    for item in value.split(';') {
652        let (layers, devices) = item.split_once('@').ok_or_else(|| {
653            let layers = if allow_full_model {
654                "LAYER[-LAYER] or all"
655            } else {
656                "LAYER[-LAYER]"
657            };
658            format!("{flag} must be {layers}@DEVICE,DEVICE[;...]")
659        })?;
660        let (first, last) = if layers == "all" {
661            if !allow_full_model {
662                return Err(format!(
663                    "{flag} does not support the full-model shorthand; assign routed layers \
664                     explicitly"
665                ));
666            }
667            (0, STEP37_TRUNK_LAYERS - 1)
668        } else {
669            match layers.split_once('-') {
670                Some((first, last)) => {
671                    let first = first
672                        .parse::<usize>()
673                        .map_err(|_| format!("{flag} layer {first:?} is not an integer"))?;
674                    let last = last
675                        .parse::<usize>()
676                        .map_err(|_| format!("{flag} layer {last:?} is not an integer"))?;
677                    if first > last {
678                        return Err(format!("{flag} layer range {first}-{last} is reversed"));
679                    }
680                    if last - first + 1 > 128 {
681                        return Err(format!(
682                            "{flag} layer range {first}-{last} exceeds the 128-layer parser cap"
683                        ));
684                    }
685                    (first, last)
686                }
687                None => {
688                    let layer = layers
689                        .parse::<usize>()
690                        .map_err(|_| format!("{flag} layer {layers:?} is not an integer"))?;
691                    (layer, layer)
692                }
693            }
694        };
695        let devices = devices
696            .split(',')
697            .map(|device| {
698                device
699                    .parse::<usize>()
700                    .map_err(|_| format!("{flag} device {device:?} is not an integer"))
701            })
702            .collect::<Result<Vec<_>, _>>()?;
703        if !(2..=8).contains(&devices.len()) {
704            return Err(format!(
705                "{flag} requires 2..=8 devices, got {}",
706                devices.len()
707            ));
708        }
709        let mut unique = devices.clone();
710        unique.sort_unstable();
711        unique.dedup();
712        if unique.len() != devices.len() {
713            return Err(format!("{flag} devices must be distinct, got {devices:?}"));
714        }
715        for layer in first..=last {
716            if specs
717                .iter()
718                .any(|existing: &StepEpLayerSpec| existing.layer == layer)
719            {
720                return Err(format!("{flag} assigns layer {layer} more than once"));
721            }
722            specs.push(StepEpLayerSpec {
723                layer,
724                devices: devices.clone(),
725            });
726        }
727    }
728    Ok(specs)
729}
730
731pub fn parse_step_ep_layer_specs(value: Option<&str>) -> Result<Vec<StepEpLayerSpec>, String> {
732    parse_step_layer_specs("MEMRA_STEP_EP", value, false)
733}
734
735pub fn step_ep_layer_specs() -> Result<Vec<StepEpLayerSpec>, String> {
736    parse_step_ep_layer_specs(std::env::var("MEMRA_STEP_EP").ok().as_deref())
737}
738
739pub fn parse_step_tp_layer_specs(value: Option<&str>) -> Result<Vec<StepTpLayerSpec>, String> {
740    parse_step_layer_specs("MEMRA_STEP_TP", value, true)
741}
742
743pub fn step_tp_layer_specs() -> Result<Vec<StepTpLayerSpec>, String> {
744    parse_step_tp_layer_specs(std::env::var("MEMRA_STEP_TP").ok().as_deref())
745}
746
747#[derive(Clone, Copy)]
748pub struct E4m3BlockMatrix<'a> {
749    pub codes: &'a [u8],
750    pub scales: &'a [f32],
751    pub out_features: usize,
752    pub in_features: usize,
753}
754
755impl E4m3BlockMatrix<'_> {
756    fn validate(&self) -> Result<(), String> {
757        let code_count = self
758            .out_features
759            .checked_mul(self.in_features)
760            .ok_or_else(|| "E4M3 matrix size overflow".to_string())?;
761        if self.codes.len() != code_count {
762            return Err(format!(
763                "E4M3 code count {} != {}x{} ({code_count})",
764                self.codes.len(),
765                self.out_features,
766                self.in_features,
767            ));
768        }
769        let scale_count =
770            self.out_features.div_ceil(FP8_BLOCK) * self.in_features.div_ceil(FP8_BLOCK);
771        if self.scales.len() != scale_count {
772            return Err(format!(
773                "E4M3 scale count {} != {scale_count} for {}x{}",
774                self.scales.len(),
775                self.out_features,
776                self.in_features,
777            ));
778        }
779        if !self
780            .scales
781            .iter()
782            .all(|scale| scale.is_finite() && *scale > 0.0)
783        {
784            return Err("E4M3 scale grid contains a non-finite or non-positive value".to_string());
785        }
786        Ok(())
787    }
788}
789
790#[derive(Clone, Copy)]
791pub struct E4m3ExpertBank<'a> {
792    pub codes: &'a [u8],
793    pub scales: &'a [f32],
794    pub expert_count: usize,
795    pub out_features: usize,
796    pub in_features: usize,
797}
798
799impl E4m3ExpertBank<'_> {
800    fn validate(&self) -> Result<(), String> {
801        if self.expert_count == 0 {
802            return Err("E4M3 expert bank is empty".to_string());
803        }
804        let code_stride = self
805            .out_features
806            .checked_mul(self.in_features)
807            .ok_or_else(|| "E4M3 expert code stride overflow".to_string())?;
808        let code_count = self
809            .expert_count
810            .checked_mul(code_stride)
811            .ok_or_else(|| "E4M3 expert code count overflow".to_string())?;
812        if self.codes.len() != code_count {
813            return Err(format!(
814                "E4M3 expert code count {} != {}x{} ({code_count})",
815                self.codes.len(),
816                self.expert_count,
817                code_stride,
818            ));
819        }
820        let scale_stride =
821            self.out_features.div_ceil(FP8_BLOCK) * self.in_features.div_ceil(FP8_BLOCK);
822        let scale_count = self
823            .expert_count
824            .checked_mul(scale_stride)
825            .ok_or_else(|| "E4M3 expert scale count overflow".to_string())?;
826        if self.scales.len() != scale_count {
827            return Err(format!(
828                "E4M3 expert scale count {} != {}x{} ({scale_count})",
829                self.scales.len(),
830                self.expert_count,
831                scale_stride,
832            ));
833        }
834        if !self
835            .scales
836            .iter()
837            .all(|scale| scale.is_finite() && *scale > 0.0)
838        {
839            return Err(
840                "E4M3 expert scale grid contains a non-finite or non-positive value".to_string(),
841            );
842        }
843        Ok(())
844    }
845
846    pub fn expert(&self, expert: usize) -> Result<E4m3BlockMatrix<'_>, String> {
847        if expert >= self.expert_count {
848            return Err(format!("expert {expert} outside 0..{}", self.expert_count));
849        }
850        let code_stride = self.out_features * self.in_features;
851        let scale_stride =
852            self.out_features.div_ceil(FP8_BLOCK) * self.in_features.div_ceil(FP8_BLOCK);
853        Ok(E4m3BlockMatrix {
854            codes: &self.codes[expert * code_stride..(expert + 1) * code_stride],
855            scales: &self.scales[expert * scale_stride..(expert + 1) * scale_stride],
856            out_features: self.out_features,
857            in_features: self.in_features,
858        })
859    }
860}
861
862pub struct ColumnParallelResult {
863    pub gathered: Vec<f32>,
864    pub rank_outputs: Vec<Vec<f32>>,
865}
866
867pub struct RowParallelResult {
868    pub reduced: Vec<f32>,
869    pub rank_partials: Vec<Vec<f32>>,
870}
871
872#[derive(Clone, Copy)]
873pub struct Bf16Matrix<'a> {
874    pub bytes: &'a [u8],
875    pub out_features: usize,
876    pub in_features: usize,
877}
878
879impl Bf16Matrix<'_> {
880    pub fn validate(&self) -> Result<(), String> {
881        if self.out_features == 0 || self.in_features == 0 {
882            return Err("BF16 matrix dimensions must be nonzero".into());
883        }
884        let expected = self
885            .out_features
886            .checked_mul(self.in_features)
887            .and_then(|values| values.checked_mul(2))
888            .ok_or("BF16 matrix byte count overflow")?;
889        if self.bytes.len() != expected {
890            return Err(format!(
891                "BF16 matrix bytes {} != {}x{}x2 ({expected})",
892                self.bytes.len(),
893                self.out_features,
894                self.in_features,
895            ));
896        }
897        Ok(())
898    }
899}
900
901struct ResidentE4m3Rank {
902    codes: CudaSlice<u8>,
903    scales: CudaSlice<f32>,
904    out_features: usize,
905    in_features: usize,
906}
907
908enum ResidentBf16Weight {
909    Bf16(CudaSlice<u8>),
910    F32(CudaSlice<f32>),
911}
912
913impl ResidentBf16Weight {
914    fn ordinal(&self) -> usize {
915        match self {
916            Self::Bf16(bytes) => bytes.ordinal(),
917            Self::F32(values) => values.ordinal(),
918        }
919    }
920}
921
922struct ResidentBf16Rank {
923    weight: ResidentBf16Weight,
924    out_features: usize,
925    in_features: usize,
926}
927
928pub struct ResidentColumnParallel {
929    ranks: Vec<ResidentE4m3Rank>,
930    out_features: usize,
931    in_features: usize,
932}
933
934pub struct ResidentRowParallel {
935    ranks: Vec<ResidentE4m3Rank>,
936    out_features: usize,
937    in_features: usize,
938}
939
940pub struct ResidentBf16ColumnParallel {
941    ranks: Vec<ResidentBf16Rank>,
942    out_features: usize,
943    in_features: usize,
944    canonical_chunk_rows: Option<usize>,
945}
946
947pub struct ResidentBf16RowParallel {
948    ranks: Vec<ResidentBf16Rank>,
949    out_features: usize,
950    in_features: usize,
951}
952
953pub struct ResidentStepBf16RowParallel {
954    ranks: Vec<Vec<ResidentBf16Rank>>,
955    out_features: usize,
956    in_features: usize,
957    canonical_chunk_cols: usize,
958}
959
960/// Root-owned BF16 sigmoid router with persistent F32 weight, bias, and active mask.
961pub struct ResidentSigmoidTopKRouter {
962    weight: CudaSlice<f32>,
963    correction_bias: CudaSlice<f32>,
964    active: CudaSlice<u8>,
965    root_device: usize,
966    input_width: usize,
967    expert_count: usize,
968    experts_per_token: usize,
969    active_count: usize,
970    scaling_factor: f32,
971    route_norm: bool,
972}
973
974pub struct SigmoidTopKHostOutput {
975    pub logits: Vec<f32>,
976    pub selected: Vec<u32>,
977    pub weights: Vec<f32>,
978}
979
980/// Full BF16 SwiGLU weights replicated independently on every runtime rank.
981pub struct ResidentReplicatedBf16SwiGlu {
982    gate: Vec<ResidentBf16Rank>,
983    up: Vec<ResidentBf16Rank>,
984    down: Vec<ResidentBf16Rank>,
985    input_width: usize,
986    intermediate_width: usize,
987}
988
989/// One token-major F32 batch replicated across a native-P2P rank group.
990///
991/// Every allocation is owned by its matching rank CUDA context. This is the generic handoff
992/// substrate between independently sharded operators; it carries no model or topology claim.
993pub struct ResidentReplicatedDeviceRows {
994    ranks: Vec<CudaSlice<f32>>,
995    tokens: usize,
996    width: usize,
997}
998
999impl ResidentReplicatedDeviceRows {
1000    pub fn tokens(&self) -> usize {
1001        self.tokens
1002    }
1003
1004    pub fn width(&self) -> usize {
1005        self.width
1006    }
1007
1008    pub fn ranks(&self) -> usize {
1009        self.ranks.len()
1010    }
1011}
1012
1013/// Canonical MoE output order: routed plus shared, then add the layer residual.
1014pub fn moe_residual_host(
1015    residual: &[f32],
1016    routed: &[f32],
1017    shared: &[f32],
1018) -> Result<Vec<f32>, String> {
1019    if residual.len() != routed.len() || residual.len() != shared.len() {
1020        return Err(format!(
1021            "MoE residual lengths residual={} routed={} shared={}",
1022            residual.len(),
1023            routed.len(),
1024            shared.len()
1025        ));
1026    }
1027    let ffn = routed
1028        .iter()
1029        .zip(shared)
1030        .map(|(&routed, &shared)| routed + shared)
1031        .collect::<Vec<_>>();
1032    Ok(residual
1033        .iter()
1034        .zip(ffn)
1035        .map(|(&residual, ffn)| residual + ffn)
1036        .collect())
1037}
1038
1039pub use memra_kv::{
1040    KvRingAppend, ResidentTpKvCache, ResidentTpKvCacheRank, TpKvAppendPlan, TpKvTransaction,
1041};
1042
1043/// Persistent TP2/TP4/TP8 routed-expert reference.
1044///
1045/// Rank-local checkpoint shards are uploaded once and remain tied to their owning CUDA context.
1046/// Activations and deterministic host-staged collectives remain per invocation. This is the
1047/// correctness substrate for serving TP/EP, not product-throughput evidence.
1048pub struct ResidentTpExpert {
1049    gate: ResidentColumnParallel,
1050    up: ResidentColumnParallel,
1051    down: ResidentRowParallel,
1052    input_width: usize,
1053    expert_width: usize,
1054}
1055
1056struct ResidentE4m3ExpertBankRank {
1057    codes: CudaSlice<u8>,
1058    scales: CudaSlice<f32>,
1059    expert_range: Range<usize>,
1060    out_features: usize,
1061    in_features: usize,
1062    code_stride: usize,
1063    scale_stride: usize,
1064    /// TP row banks are packed by native 128-wide K block so reduction can replay the
1065    /// checkpoint's global block order exactly. Other banks remain row-major.
1066    k_blocks: Option<usize>,
1067}
1068
1069struct PackedE4m3ExpertBankRank {
1070    codes: Vec<u8>,
1071    scales: Vec<f32>,
1072    expert_range: Range<usize>,
1073    out_features: usize,
1074    in_features: usize,
1075    code_stride: usize,
1076    scale_stride: usize,
1077    k_blocks: Option<usize>,
1078}
1079
1080struct ResidentEpRank {
1081    gate: ResidentE4m3ExpertBankRank,
1082    up: ResidentE4m3ExpertBankRank,
1083    down: ResidentE4m3ExpertBankRank,
1084}
1085
1086/// Persistent expert-parallel reference.
1087///
1088/// Every routed expert has exactly one owner rank. Shared experts are deliberately absent from
1089/// this object because Step replicates them per rank. Routes execute on the owner CUDA context.
1090/// The default oracle stages through host memory; the native path peer-dispatches inputs and
1091/// peer-returns owner outputs while preserving host-canonical activation and accumulation.
1092pub struct ResidentExpertParallel {
1093    ranks: Vec<ResidentEpRank>,
1094    expert_count: usize,
1095    input_width: usize,
1096    expert_width: usize,
1097}
1098
1099/// Projection-level output from the opt-in official Step grouped-FP8 gate.
1100///
1101/// Rows remain pair-major. Routing, weighted combine, and production integration are deliberately
1102/// outside this gate-only adapter.
1103pub struct StepGroupedFp8ProjectionOutput {
1104    pub gate: Vec<f32>,
1105    pub up: Vec<f32>,
1106    pub down: Vec<f32>,
1107}
1108
1109/// Prepared official Step grouped-FP8 projection gate.
1110///
1111/// The complete tensor banks, both CSR schedules, input, activation buffer, and three projection
1112/// workspaces are uploaded or allocated once. Repeated execution performs no device allocation.
1113pub struct PreparedStepGroupedFp8Gate {
1114    device: usize,
1115    gate: ResidentE4m3ExpertBankRank,
1116    up: ResidentE4m3ExpertBankRank,
1117    down: ResidentE4m3ExpertBankRank,
1118    input: CudaSlice<f32>,
1119    route_csr: DeviceExpertCsr,
1120    down_csr: DeviceExpertCsr,
1121    gate_workspace: Fp8GroupedWorkspace,
1122    up_workspace: Fp8GroupedWorkspace,
1123    down_workspace: Fp8GroupedWorkspace,
1124    activation: CudaSlice<f32>,
1125    activation_limit: Option<f32>,
1126    tokens: usize,
1127    pairs: usize,
1128}
1129
1130impl PreparedStepGroupedFp8Gate {
1131    pub fn tokens(&self) -> usize {
1132        self.tokens
1133    }
1134
1135    pub fn pairs(&self) -> usize {
1136        self.pairs
1137    }
1138}
1139
1140struct PreparedStepGroupedExpertOwner {
1141    rank: usize,
1142    global_pairs: Vec<usize>,
1143    route_csr: DeviceExpertCsr,
1144    down_csr: DeviceExpertCsr,
1145    gate_workspace: Fp8GroupedWorkspace,
1146    up_workspace: Fp8GroupedWorkspace,
1147    down_workspace: Fp8GroupedWorkspace,
1148    activation: CudaSlice<f32>,
1149}
1150
1151struct StepGroupedExpertOwnerSchedule {
1152    global_pairs: Vec<usize>,
1153    route_csr: ExpertCsr,
1154    down_csr: ExpertCsr,
1155}
1156
1157/// Prepared official Step expert-owner grouped-FP8 projection gate.
1158///
1159/// Route partitioning, owner-local CSR uploads, input dispatch, activation buffers, and grouped
1160/// workspaces are persistent. Projection rows are scattered back to canonical pair order only
1161/// after every owner has completed its rank-local program.
1162pub struct PreparedStepGroupedExpertParallelGate {
1163    rank_inputs: Vec<CudaSlice<f32>>,
1164    owners: Vec<PreparedStepGroupedExpertOwner>,
1165    activation_limit: Option<f32>,
1166    tokens: usize,
1167    pairs: usize,
1168    max_tokens: usize,
1169    max_pairs: usize,
1170    input_width: usize,
1171    expert_width: usize,
1172    generation: u64,
1173    executed_generation: Option<u64>,
1174    ready: bool,
1175}
1176
1177impl PreparedStepGroupedExpertParallelGate {
1178    pub fn tokens(&self) -> usize {
1179        self.tokens
1180    }
1181
1182    pub fn pairs(&self) -> usize {
1183        self.pairs
1184    }
1185
1186    pub fn max_tokens(&self) -> usize {
1187        self.max_tokens
1188    }
1189
1190    pub fn input_width(&self) -> usize {
1191        self.input_width
1192    }
1193
1194    pub fn expert_width(&self) -> usize {
1195        self.expert_width
1196    }
1197
1198    pub fn set_activation_limit(&mut self, limit: Option<f32>) -> Result<(), String> {
1199        validate_step_expert_activation_limit(limit)?;
1200        self.activation_limit = limit;
1201        self.executed_generation = None;
1202        Ok(())
1203    }
1204
1205    pub fn active_owners(&self) -> usize {
1206        self.owners
1207            .iter()
1208            .filter(|owner| !owner.global_pairs.is_empty())
1209            .count()
1210    }
1211
1212    pub fn owner_pair_counts(&self) -> Vec<usize> {
1213        self.owners
1214            .iter()
1215            .map(|owner| owner.global_pairs.len())
1216            .collect()
1217    }
1218
1219    pub fn generation(&self) -> u64 {
1220        self.generation
1221    }
1222}
1223
1224struct PreparedPeerWeightedRouteOwner {
1225    token_rows: CudaSlice<i32>,
1226    slots: CudaSlice<i32>,
1227    weights: CudaSlice<f32>,
1228    active_pairs: usize,
1229}
1230
1231/// Persistent root-side weighted combine for peer-owned canonical route rows.
1232///
1233/// Owner metadata, one reusable peer staging buffer, the canonical slot bank, weight bank, and
1234/// output are allocated once. Refreshes update metadata prefixes; execution peer-copies active
1235/// rows, scatters them by canonical token/slot, and reduces in the requested numeric order.
1236pub struct PreparedPeerWeightedRouteCombine {
1237    root_device: usize,
1238    owners: Vec<PreparedPeerWeightedRouteOwner>,
1239    peer_staging: CudaSlice<f32>,
1240    slots: CudaSlice<f32>,
1241    weights: CudaSlice<f32>,
1242    output: CudaSlice<f32>,
1243    peer_devices: Vec<usize>,
1244    peer_outputs: Vec<CudaSlice<f32>>,
1245    width: usize,
1246    experts_per_token: usize,
1247    max_tokens: usize,
1248    max_pairs: usize,
1249    tokens: usize,
1250    pairs: usize,
1251    projection_generation: u64,
1252    output_generation: Option<u64>,
1253    broadcast_generation: Option<u64>,
1254    ready: bool,
1255}
1256
1257impl PreparedPeerWeightedRouteCombine {
1258    pub fn tokens(&self) -> usize {
1259        self.tokens
1260    }
1261
1262    pub fn pairs(&self) -> usize {
1263        self.pairs
1264    }
1265
1266    pub fn owner_pair_counts(&self) -> Vec<usize> {
1267        self.owners.iter().map(|owner| owner.active_pairs).collect()
1268    }
1269
1270    pub fn distributed_ranks(&self) -> usize {
1271        1 + self.peer_outputs.len()
1272    }
1273}
1274
1275struct ResidentTpExpertBank {
1276    gate: Vec<ResidentE4m3ExpertBankRank>,
1277    up: Vec<ResidentE4m3ExpertBankRank>,
1278    down: Vec<ResidentE4m3ExpertBankRank>,
1279    expert_count: usize,
1280    input_width: usize,
1281    expert_width: usize,
1282}
1283
1284/// Persistent tensor-parallel expert bank.
1285///
1286/// Every rank owns a checkpoint-aligned output-row shard of every gate/up projection and an
1287/// input-column shard of every down projection. Activations cross deterministic host-staged
1288/// collectives on hosts where native peer copies are unavailable or corrupt.
1289pub struct ResidentTensorParallel {
1290    bank: ResidentTpExpertBank,
1291}
1292
1293/// Multi-context TP correctness runtime. Each rank owns an independent `Engine` and CUDA context.
1294///
1295/// Host bounce is the default oracle. Native P2P is opt-in and preserves the oracle's global
1296/// checkpoint-block reduction order; it remains a correctness path until serving gates and
1297/// repeated performance evidence qualify it.
1298pub struct TpE4m3HostBounce {
1299    devices: Vec<usize>,
1300    ranks: Vec<Engine>,
1301    native_p2p: bool,
1302    ep_device_arithmetic: bool,
1303    bulk_p2p: bool,
1304    /// v2 decode-attention workspace (MEMRA_STEP_TP_DECODE_V2). One per runtime, shared by
1305    /// every TP attention layer — the buffer shapes are geometry-constant across the trunk.
1306    decode_v2: std::sync::Mutex<Vec<StepTpDecodeV2Ws>>,
1307}
1308
1309/// Persistent workspace of the v2 rank-local decode-attention driver.
1310///
1311/// Buffers live in their producing rank's CUDA context, are never freed, and events are
1312/// re-recorded per call — the pp.rs `BoundarySlot` discipline — so the per-token path has no
1313/// cuMemAlloc, no cross-stream free, and no host round-trip. Every buffer is fully overwritten
1314/// before its consumers run in the same call; nothing carries state between tokens.
1315/// Per-rank attn_gate row shards for the fused QKV+gate kernel, in the weight class the
1316/// fused kernels read (F32 mirror or raw checkpoint bf16).
1317pub enum StepTpGateShards<'a> {
1318    F32(&'a [crate::CudaSlice<f32>]),
1319    Bf16(&'a [crate::CudaSlice<u8>]),
1320}
1321
1322pub struct StepTpDecodeV2Ws {
1323    /// T-COLUMN verify slabs (spec MTP): per-rank [t, local_dim] projections computed by
1324    /// the weight-amortized qkvg_tcol kernel; the col-select door copies one column into
1325    /// the single-row buffers and everything downstream runs the unmodified t=1 program.
1326    pub(crate) tcol_q: Vec<CudaSlice<f32>>,
1327    pub(crate) tcol_k: Vec<CudaSlice<f32>>,
1328    pub(crate) tcol_v: Vec<CudaSlice<f32>>,
1329    pub(crate) tcol_g: Vec<CudaSlice<f32>>,
1330    pub(crate) tcol_in: Vec<CudaSlice<f32>>,
1331    pub(crate) tcol_cap: usize,
1332    /// MEMRA_TCOL_OPROJ slabs: per-rank stashed `gated` rows ([8, local_q_dim]), per-rank
1333    /// b4_tcol partials ([8, o_out]), a root-side peer pull of rank1's partial slab, and
1334    /// the root-side joined `mixed` slab. Armed lazily by the first stash.
1335    /// MEMRA_SPEC_FA2 slabs: per-rank stashed post-rope q rows ([2, local_q_dim]), gate
1336    /// rows ([2, heads/ranks]) and the two gated outputs the per-row combine writes
1337    /// ([2, local_q_dim]). Armed lazily by the first stash.
1338    pub(crate) fa2_q: Vec<CudaSlice<f32>>,
1339    pub(crate) fa2_gate: Vec<CudaSlice<f32>>,
1340    pub(crate) fa2_gated: Vec<CudaSlice<f32>>,
1341    pub(crate) fa2_cap: usize,
1342    tcol_gated: Vec<CudaSlice<f32>>,
1343    tcol_opart: Vec<CudaSlice<f32>>,
1344    tcol_opeer: Option<CudaSlice<f32>>,
1345    tcol_omix: Option<CudaSlice<f32>>,
1346    tcol_ocap: usize,
1347    // rank-context buffers, indexed by rank (pub(crate): the v2 driver in hybrid_forward
1348    // feeds them to the KV transaction and attention kernels between the two v2 phases)
1349    pub(crate) q_raw: Vec<CudaSlice<f32>>,
1350    pub(crate) k_raw: Vec<CudaSlice<f32>>,
1351    pub(crate) v_raw: Vec<CudaSlice<f32>>,
1352    pub(crate) q: Vec<CudaSlice<f32>>,
1353    pub(crate) k: Vec<CudaSlice<f32>>,
1354    pub(crate) pos: Vec<CudaSlice<i32>>,
1355    /// FUSION #1 last-block counters (one per rank; atomicInc auto-resets per launch).
1356    pub(crate) fuse_ctr: Vec<CudaSlice<u32>>,
1357    pub(crate) gate: Vec<CudaSlice<f32>>,
1358    pub(crate) attn_out: Vec<CudaSlice<f32>>,
1359    pub(crate) gated: Vec<CudaSlice<f32>>,
1360    /// [rank][block] O partials, each `o_out` wide, in the owning rank's context.
1361    o_partials: Vec<Vec<CudaSlice<f32>>>,
1362    /// Recorded on each rank's stream after its per-call work; root waits before peer reads.
1363    ev_rank: Vec<CudaEvent>,
1364    // root-context buffers
1365    peer_partial: CudaSlice<f32>,
1366    reduce_a: CudaSlice<f32>,
1367    reduce_b: CudaSlice<f32>,
1368    /// Never written; the canonical zero start of the v1 add chain.
1369    zeros: CudaSlice<f32>,
1370    pub(crate) k_shadow: CudaSlice<f32>,
1371    pub(crate) v_shadow: CudaSlice<f32>,
1372    ev_refresh: CudaEvent,
1373    ev_oproj: CudaEvent,
1374    // model-engine (e) context
1375    gate_e: CudaSlice<f32>,
1376    /// Per-token stages (e-ctx, fixed addresses): one eager e-stream copy each per layer; the
1377    /// rank flows raw-copy FROM them, which is exactly the shape graph capture needs.
1378    pub(crate) h_stage: Option<CudaSlice<f32>>,
1379    pub(crate) pos_stage: Option<CudaSlice<i32>>,
1380    /// Workspace-owned per-rank attention input rows (the stage flow copies into THESE, not
1381    /// the per-layer decode_input buffers — the workspace is shared across layers, so every
1382    /// captured/raw address it uses must be layer-invariant).
1383    attn_in: Vec<CudaSlice<f32>>,
1384    /// Cached raw pointers of the stage-flow operands (set when the stages arm).
1385    raw_h_stage: u64,
1386    raw_pos_stage: u64,
1387    raw_attn_in: Vec<u64>,
1388    raw_pos: Vec<u64>,
1389    raw_o_partial1: u64,
1390    raw_peer_partial: u64,
1391    raw_k1: u64,
1392    raw_v1: u64,
1393    raw_k_shadow: u64,
1394    raw_v_shadow: u64,
1395    /// Token-graph e-context mirrors (armed by the orchestrator): the root section
1396    /// raw-copies the reduced attention output and the shadow rows here so the e-glue
1397    /// children read same-context memory (cross-context kernel args are capture-illegal).
1398    raw_mixed_stage_e: u64,
1399    raw_reduce_a: u64,
1400    raw_shadow_stage_e: (u64, u64),
1401    ev_entry: CudaEvent,
1402    e_device: usize,
1403    // geometry pins
1404    local_q_dim: usize,
1405    local_kv_dim: usize,
1406    heads: usize,
1407    pub(crate) o_out: usize,
1408    o_block_cols: usize,
1409    blocks_per_rank: usize,
1410}
1411
1412impl TpE4m3HostBounce {
1413    pub fn new(devices: &[usize]) -> Result<Self, Box<dyn std::error::Error>> {
1414        Self::new_inner(devices, false, false, false, false)
1415    }
1416
1417    pub fn new_native_p2p(devices: &[usize]) -> Result<Self, Box<dyn std::error::Error>> {
1418        Self::new_inner(devices, false, true, false, false)
1419    }
1420
1421    pub fn new_native_p2p_device_arithmetic(
1422        devices: &[usize],
1423    ) -> Result<Self, Box<dyn std::error::Error>> {
1424        Self::new_inner(devices, false, true, true, false)
1425    }
1426
1427    pub(crate) fn new_configured(
1428        devices: &[usize],
1429        native_p2p: bool,
1430        ep_device_arithmetic: bool,
1431        bulk_p2p: bool,
1432    ) -> Result<Self, Box<dyn std::error::Error>> {
1433        Self::new_inner(devices, false, native_p2p, ep_device_arithmetic, bulk_p2p)
1434    }
1435
1436    /// Single-rank execution of the canonical checkpoint-block TP program.
1437    ///
1438    /// This is an oracle for distributed exactness, not a serving topology. It lets gates compare
1439    /// TP=1 and TP>1 with the same packing, kernel launches, and deterministic reduction order.
1440    pub fn new_single_rank_oracle(device: usize) -> Result<Self, Box<dyn std::error::Error>> {
1441        Self::new_inner(&[device], true, false, false, false)
1442    }
1443
1444    fn new_inner(
1445        devices: &[usize],
1446        allow_single_rank: bool,
1447        native_p2p: bool,
1448        ep_device_arithmetic: bool,
1449        bulk_p2p: bool,
1450    ) -> Result<Self, Box<dyn std::error::Error>> {
1451        if ep_device_arithmetic && !native_p2p {
1452            return Err("device-resident EP arithmetic requires native P2P".into());
1453        }
1454        if bulk_p2p && !native_p2p {
1455            return Err("bulk TP transport requires native P2P".into());
1456        }
1457        let minimum = if allow_single_rank { 1 } else { 2 };
1458        if !(minimum..=8).contains(&devices.len()) {
1459            return Err(format!(
1460                "TP reference requires {minimum}..=8 devices, got {}",
1461                devices.len()
1462            )
1463            .into());
1464        }
1465        let mut unique = devices.to_vec();
1466        unique.sort_unstable();
1467        unique.dedup();
1468        if unique.len() != devices.len() {
1469            return Err(format!("TP devices must be distinct, got {devices:?}").into());
1470        }
1471        let ranks = devices
1472            .iter()
1473            .map(|&device| Engine::new(device))
1474            .collect::<Result<Vec<_>, _>>()?;
1475        if native_p2p {
1476            configure_native_p2p(&ranks, devices)?;
1477        }
1478        if allow_single_rank {
1479            eprintln!(
1480                "[tp] canonical oracle transport=local device={} performance_claim=false",
1481                devices[0]
1482            );
1483        } else if native_p2p {
1484            if ep_device_arithmetic {
1485                eprintln!(
1486                    "[tp] correctness transport=native-p2p devices={devices:?} \
1487                     native_p2p=true activation=device-host-exact \
1488                     accumulation=device-host-exact output=root-readback \
1489                     bulk_p2p={bulk_p2p} performance_claim=false"
1490                );
1491            } else {
1492                eprintln!(
1493                    "[tp] correctness transport=native-p2p devices={devices:?} \
1494                     native_p2p=true activation=host-canonical bulk_p2p={bulk_p2p} \
1495                     performance_claim=false"
1496                );
1497            }
1498        } else {
1499            eprintln!(
1500                "[tp] correctness transport=host-bounce devices={devices:?} \
1501                 native_p2p=false performance_claim=false"
1502            );
1503        }
1504        Ok(Self {
1505            devices: devices.to_vec(),
1506            ranks,
1507            native_p2p,
1508            ep_device_arithmetic,
1509            bulk_p2p,
1510            decode_v2: std::sync::Mutex::new(Vec::new()),
1511        })
1512    }
1513
1514    pub fn devices(&self) -> &[usize] {
1515        &self.devices
1516    }
1517
1518    pub fn native_p2p(&self) -> bool {
1519        self.native_p2p
1520    }
1521
1522    pub fn bulk_p2p(&self) -> bool {
1523        self.bulk_p2p
1524    }
1525
1526    pub fn expert_activation_label(&self) -> &'static str {
1527        if self.ep_device_arithmetic {
1528            "device-host-exact"
1529        } else {
1530            "host-canonical"
1531        }
1532    }
1533
1534    pub fn expert_accumulation_label(&self) -> &'static str {
1535        self.expert_activation_label()
1536    }
1537
1538    pub fn expert_output_label(&self) -> &'static str {
1539        if self.ep_device_arithmetic {
1540            "root-readback"
1541        } else {
1542            "host-accumulated"
1543        }
1544    }
1545
1546    pub fn transport_label(&self) -> &'static str {
1547        if self.devices.len() == 1 {
1548            "local"
1549        } else if self.native_p2p {
1550            "native-p2p"
1551        } else {
1552            "host-bounce"
1553        }
1554    }
1555
1556    pub fn device_names(&self) -> Result<Vec<String>, Box<dyn std::error::Error>> {
1557        self.ranks
1558            .iter()
1559            .map(|rank| rank.ctx().name().map_err(Into::into))
1560            .collect()
1561    }
1562
1563    /// Correctness-gate access to the engine that owns one TP rank.
1564    ///
1565    /// Model execution should prefer collective methods on this runtime. This accessor exists so
1566    /// focused gates can prove that the rank-local projection outputs remain device-resident
1567    /// through the next ownership boundary before that boundary is wired into serving.
1568    pub fn rank_engine(&self, rank: usize) -> Option<&Engine> {
1569        self.ranks.get(rank)
1570    }
1571
1572    pub fn allocate_tp_kv_cache(
1573        &self,
1574        kv_dim_k: usize,
1575        kv_dim_v: usize,
1576        capacity: usize,
1577    ) -> Result<ResidentTpKvCache, Box<dyn std::error::Error>> {
1578        self.allocate_tp_kv_cache_inner(kv_dim_k, kv_dim_v, capacity, None)
1579    }
1580
1581    pub fn allocate_tp_swa_kv_cache(
1582        &self,
1583        kv_dim_k: usize,
1584        kv_dim_v: usize,
1585        capacity: usize,
1586        window: usize,
1587    ) -> Result<ResidentTpKvCache, Box<dyn std::error::Error>> {
1588        if window == 0 {
1589            return Err("TP SWA KV window must be nonzero".into());
1590        }
1591        self.allocate_tp_kv_cache_inner(kv_dim_k, kv_dim_v, capacity, Some(window))
1592    }
1593
1594    fn allocate_tp_kv_cache_inner(
1595        &self,
1596        kv_dim_k: usize,
1597        kv_dim_v: usize,
1598        capacity: usize,
1599        window: Option<usize>,
1600    ) -> Result<ResidentTpKvCache, Box<dyn std::error::Error>> {
1601        if capacity == 0 || capacity > i32::MAX as usize {
1602            return Err(
1603                format!("TP KV capacity must be in 1..={}, got {capacity}", i32::MAX).into(),
1604            );
1605        }
1606        let tp = self.ranks.len();
1607        let shape = crate::cache::tp_kv_rank_allocation_shape(kv_dim_k, kv_dim_v, tp)?;
1608        let physical_rows = window
1609            .map(|window| crate::cache::swa_ring_rows(window, capacity))
1610            .unwrap_or(capacity);
1611        let k_plane_bytes = physical_rows
1612            .checked_mul(shape.k_token_bytes)
1613            .and_then(|bytes| bytes.checked_add(8))
1614            .ok_or("TP KV K plane-byte overflow")?;
1615        let v_plane_bytes = physical_rows
1616            .checked_mul(shape.v_token_bytes)
1617            .and_then(|bytes| bytes.checked_add(8))
1618            .ok_or("TP KV V plane-byte overflow")?;
1619        let mut ranks = Vec::with_capacity(tp);
1620        for engine in &self.ranks {
1621            let _main = engine.gpu.enter_main()?;
1622            ranks.push(ResidentTpKvCacheRank::new(
1623                engine.alloc_u8(k_plane_bytes)?,
1624                engine.alloc_u8(v_plane_bytes)?,
1625                engine.htod_i32(&[0])?,
1626            ));
1627        }
1628        Ok(match window {
1629            Some(window) => ResidentTpKvCache::new_swa(
1630                ranks,
1631                shape.kv_dim_k,
1632                shape.kv_dim_v,
1633                shape.k_token_bytes,
1634                shape.v_token_bytes,
1635                capacity,
1636                window,
1637            ),
1638            None => ResidentTpKvCache::new(
1639                ranks,
1640                shape.kv_dim_k,
1641                shape.kv_dim_v,
1642                shape.k_token_bytes,
1643                shape.v_token_bytes,
1644                capacity,
1645            ),
1646        })
1647    }
1648
1649    pub fn grow_tp_kv_cache(
1650        &self,
1651        source: &ResidentTpKvCache,
1652        target_capacity: usize,
1653        rows: usize,
1654    ) -> Result<ResidentTpKvCache, Box<dyn std::error::Error>> {
1655        self.validate_tp_kv_cache(source)?;
1656        let plan = source.prepare_grow(target_capacity, rows)?;
1657        let ranks = self.ranks.len();
1658        let global_k = source
1659            .kv_dim_k()
1660            .checked_mul(ranks)
1661            .ok_or("TP KV grow global K dimension overflow")?;
1662        let global_v = source
1663            .kv_dim_v()
1664            .checked_mul(ranks)
1665            .ok_or("TP KV grow global V dimension overflow")?;
1666        let mut target = match source.ring_window() {
1667            Some(window) => {
1668                self.allocate_tp_swa_kv_cache(global_k, global_v, target_capacity, window)?
1669            }
1670            None => self.allocate_tp_kv_cache(global_k, global_v, target_capacity)?,
1671        };
1672        self.validate_tp_kv_cache(&target)?;
1673
1674        for (rank, engine) in self.ranks.iter().enumerate() {
1675            let _main = engine.gpu.enter_main()?;
1676            let src = source
1677                .rank(rank)
1678                .ok_or_else(|| format!("TP KV grow source has no rank {rank}"))?;
1679            let dst = target
1680                .rank_mut(rank)
1681                .ok_or_else(|| format!("TP KV grow target has no rank {rank}"))?;
1682            if plan.k_bytes() > 0 {
1683                engine.copy_u8_range_into(
1684                    dst.k_mut(),
1685                    0,
1686                    src.k(),
1687                    plan.source_row() * source.k_tok_bytes(),
1688                    plan.k_bytes(),
1689                )?;
1690            }
1691            if plan.v_bytes() > 0 {
1692                engine.copy_u8_range_into(
1693                    dst.v_mut(),
1694                    0,
1695                    src.v(),
1696                    plan.source_row() * source.v_tok_bytes(),
1697                    plan.v_bytes(),
1698                )?;
1699            }
1700        }
1701        self.set_tp_kv_len_mirrors(&mut target, plan.rows())?;
1702
1703        // The caller publishes `target` and immediately drops `source`. Drain every rank's
1704        // stream so an async-pool free cannot recycle a source plane under an in-flight D2D copy.
1705        for engine in &self.ranks {
1706            let _main = engine.gpu.enter_main()?;
1707            engine.stream().synchronize()?;
1708        }
1709        let physical_copy_rows = plan.copy_rows();
1710        target.publish_grow(plan)?;
1711        eprintln!(
1712            "[step-tp-kv-grow] rows={} source_capacity={} target_capacity={} ranks={} \
1713             physical_copy_rows={} ring_window={:?} copy=rank-local-dtod \
1714             rank_streams_synchronized=true generation_preserved=true",
1715            rows,
1716            source.capacity(),
1717            target_capacity,
1718            ranks,
1719            physical_copy_rows,
1720            source.ring_window(),
1721        );
1722        Ok(target)
1723    }
1724
1725    pub fn hydrate_tp_kv_cache(
1726        &self,
1727        cache: &mut ResidentTpKvCache,
1728        rows: usize,
1729        k_rows: &[u8],
1730        v_rows: &[u8],
1731    ) -> Result<(), Box<dyn std::error::Error>> {
1732        self.hydrate_tp_kv_cache_from(cache, rows, 0, k_rows, v_rows)
1733    }
1734
1735    pub fn hydrate_tp_kv_cache_from(
1736        &self,
1737        cache: &mut ResidentTpKvCache,
1738        logical_len: usize,
1739        resident_start: usize,
1740        k_rows: &[u8],
1741        v_rows: &[u8],
1742    ) -> Result<(), Box<dyn std::error::Error>> {
1743        self.validate_tp_kv_cache(cache)?;
1744        if cache.committed_len() != 0 || cache.staged_len() != 0 {
1745            return Err(format!(
1746                "TP KV hydration requires an empty cache, got committed/staged={}/{}",
1747                cache.committed_len(),
1748                cache.staged_len()
1749            )
1750            .into());
1751        }
1752        if resident_start > logical_len || logical_len > cache.capacity() {
1753            return Err(format!(
1754                "TP KV hydration range [{resident_start},{logical_len}) exceeds capacity {}",
1755                cache.capacity(),
1756            )
1757            .into());
1758        }
1759        let rows = logical_len - resident_start;
1760        if rows > cache.physical_capacity() {
1761            return Err(format!(
1762                "TP KV hydration rows {rows} exceed physical capacity {}",
1763                cache.physical_capacity()
1764            )
1765            .into());
1766        }
1767        for rank in 0..self.ranks.len() {
1768            let k_rank =
1769                cache_rank_rows(k_rows, rows, cache.k_tok_bytes(), self.ranks.len(), rank)?;
1770            let v_rank =
1771                cache_rank_rows(v_rows, rows, cache.v_tok_bytes(), self.ranks.len(), rank)?;
1772            let engine = &self.ranks[rank];
1773            let _main = engine.gpu.enter_main()?;
1774            let rank_cache = cache
1775                .rank_mut(rank)
1776                .ok_or_else(|| format!("TP KV cache has no rank {rank}"))?;
1777            engine.htod_u8_into(rank_cache.k_mut(), 0, &k_rank)?;
1778            engine.htod_u8_into(rank_cache.v_mut(), 0, &v_rank)?;
1779        }
1780        cache.publish_hydration(logical_len, resident_start)?;
1781        Ok(())
1782    }
1783
1784    pub fn append_tp_kv_transaction(
1785        &self,
1786        cache: &mut ResidentTpKvCache,
1787        transaction: TpKvTransaction,
1788        k_shards: &[CudaSlice<f32>],
1789        v_shards: &[CudaSlice<f32>],
1790        rows: usize,
1791    ) -> Result<(), Box<dyn std::error::Error>> {
1792        self.append_tp_kv_transaction_inner(cache, transaction, k_shards, v_shards, rows, false)
1793    }
1794
1795    /// `external_rank_appends`: the dcw path already wrote the rank rows (device-counter
1796    /// append) — run everything EXCEPT the per-rank quantize/append loop (plan validation,
1797    /// rebase arm — unreachable when the caller peeked — and the absolute len-mirror sets,
1798    /// which land the same value the in-stream inc produced).
1799    #[allow(clippy::too_many_arguments)]
1800    pub fn append_tp_kv_transaction_inner(
1801        &self,
1802        cache: &mut ResidentTpKvCache,
1803        transaction: TpKvTransaction,
1804        k_shards: &[CudaSlice<f32>],
1805        v_shards: &[CudaSlice<f32>],
1806        rows: usize,
1807        external_rank_appends: bool,
1808    ) -> Result<(), Box<dyn std::error::Error>> {
1809        self.validate_tp_kv_cache(cache)?;
1810        let plan = cache.prepare_append(transaction, rows)?;
1811        let target = plan.target();
1812        let expected_k = rows
1813            .checked_mul(cache.kv_dim_k())
1814            .ok_or("TP KV K append size overflow")?;
1815        let expected_v = rows
1816            .checked_mul(cache.kv_dim_v())
1817            .ok_or("TP KV V append size overflow")?;
1818        // external_rank_appends passes no shards — the graph's dcw appends already wrote
1819        // the rank rows, so this call is bookkeeping-only and the shard slices are unused.
1820        if !external_rank_appends
1821            && (k_shards.len() != self.ranks.len() || v_shards.len() != self.ranks.len())
1822        {
1823            return Err(format!(
1824                "TP KV append shard counts k={} v={} != ranks {}",
1825                k_shards.len(),
1826                v_shards.len(),
1827                self.ranks.len()
1828            )
1829            .into());
1830        }
1831        let kv_dim_k = cache.kv_dim_k();
1832        let kv_dim_v = cache.kv_dim_v();
1833        let k_tok_bytes = cache.k_tok_bytes();
1834        let v_tok_bytes = cache.v_tok_bytes();
1835        if let Some(KvRingAppend::Rebase {
1836            src_row,
1837            keep_rows,
1838            new_base,
1839            ..
1840        }) = plan.ring_append()
1841        {
1842            for rank in 0..self.ranks.len() {
1843                let engine = &self.ranks[rank];
1844                let _main = engine.gpu.enter_main()?;
1845                let rank_cache = cache
1846                    .rank_mut(rank)
1847                    .ok_or_else(|| format!("TP KV cache has no rank {rank}"))?;
1848                if keep_rows > 0 {
1849                    let k_len = keep_rows
1850                        .checked_mul(k_tok_bytes)
1851                        .ok_or("TP KV K rebase-byte overflow")?;
1852                    let v_len = keep_rows
1853                        .checked_mul(v_tok_bytes)
1854                        .ok_or("TP KV V rebase-byte overflow")?;
1855                    let mut k_tmp = engine.alloc_u8_uninit(k_len)?;
1856                    let mut v_tmp = engine.alloc_u8_uninit(v_len)?;
1857                    engine.copy_u8_range_into(
1858                        &mut k_tmp,
1859                        0,
1860                        rank_cache.k(),
1861                        src_row * k_tok_bytes,
1862                        k_len,
1863                    )?;
1864                    engine.copy_u8_range_into(
1865                        &mut v_tmp,
1866                        0,
1867                        rank_cache.v(),
1868                        src_row * v_tok_bytes,
1869                        v_len,
1870                    )?;
1871                    engine.copy_u8_into(rank_cache.k_mut(), 0, &k_tmp, k_len)?;
1872                    engine.copy_u8_into(rank_cache.v_mut(), 0, &v_tmp, v_len)?;
1873                }
1874                // dcw base mirror (graph increment A): physical row 0 now holds logical
1875                // row `new_base`; armed device mirrors track it (rebases are rare host
1876                // events, so a host set here is the whole maintenance cost).
1877                if rank_cache.base_d().is_some() {
1878                    let value = new_base as i32;
1879                    let rank_cache = cache
1880                        .rank_mut(rank)
1881                        .ok_or_else(|| format!("TP KV cache has no rank {rank}"))?;
1882                    if let Some(base_d) = rank_cache.base_d_mut() {
1883                        engine.set_i32_one(base_d, value)?;
1884                    }
1885                }
1886            }
1887        }
1888        cache.publish_append_rebase(plan)?;
1889        let write_row = plan.write_row();
1890        for rank in 0..self.ranks.len() {
1891            if external_rank_appends {
1892                break;
1893            }
1894            let engine = &self.ranks[rank];
1895            let _main = engine.gpu.enter_main()?;
1896            if k_shards[rank].len() != expected_k
1897                || v_shards[rank].len() != expected_v
1898                || k_shards[rank].ordinal() != engine.ctx().ordinal()
1899                || v_shards[rank].ordinal() != engine.ctx().ordinal()
1900            {
1901                return Err(format!(
1902                    "TP KV rank {rank} shard geometry/device k={}/{} v={}/{} \
1903                     != expected {expected_k}/{expected_v} on device {}",
1904                    k_shards[rank].len(),
1905                    k_shards[rank].ordinal(),
1906                    v_shards[rank].len(),
1907                    v_shards[rank].ordinal(),
1908                    engine.ctx().ordinal(),
1909                )
1910                .into());
1911            }
1912            let rank_cache = cache
1913                .rank_mut(rank)
1914                .ok_or_else(|| format!("TP KV cache has no rank {rank}"))?;
1915            let (rank_k, rank_v) = rank_cache.planes_mut();
1916            engine.append_kv_quantized_rows(
1917                &k_shards[rank],
1918                &v_shards[rank],
1919                rank_k,
1920                rank_v,
1921                write_row,
1922                rows,
1923                kv_dim_k,
1924                kv_dim_v,
1925                k_tok_bytes,
1926                v_tok_bytes,
1927                Engine::kv_fp8_on(),
1928            )?;
1929        }
1930        if !external_rank_appends {
1931            // dcw appends advance the device counters with in-stream inc_i32; an absolute set
1932            // here would race the merged per-rank append (it reads len_d for its write row).
1933            self.set_tp_kv_len_mirrors(cache, target)?;
1934        }
1935        cache.publish_append_plan(plan)?;
1936        Ok(())
1937    }
1938
1939    pub fn commit_tp_kv_transaction(
1940        &self,
1941        cache: &mut ResidentTpKvCache,
1942        transaction: TpKvTransaction,
1943        accepted_rows: usize,
1944    ) -> Result<(), Box<dyn std::error::Error>> {
1945        self.validate_tp_kv_cache(cache)?;
1946        let target = cache.commit_target(transaction, accepted_rows)?;
1947        self.set_tp_kv_len_mirrors(cache, target)?;
1948        cache.publish_finalize(transaction, target)?;
1949        Ok(())
1950    }
1951
1952    /// Commit for the external-appends (token graph) path: host bookkeeping only, NO absolute
1953    /// len-mirror sets. The graph's in-stream inc_i32 owns the device counters; a rank-stream
1954    /// set here has no ordering edge against the NEXT token's graph launch (graph children do
1955    /// not wait on the rank streams), so it can land AFTER that graph's inc and drag the
1956    /// counter backward mid-token.
1957    pub fn commit_tp_kv_transaction_external(
1958        &self,
1959        cache: &mut ResidentTpKvCache,
1960        transaction: TpKvTransaction,
1961        accepted_rows: usize,
1962    ) -> Result<(), Box<dyn std::error::Error>> {
1963        self.validate_tp_kv_cache(cache)?;
1964        let target = cache.commit_target(transaction, accepted_rows)?;
1965        cache.publish_finalize(transaction, target)?;
1966        Ok(())
1967    }
1968
1969    pub fn rollback_tp_kv_transaction(
1970        &self,
1971        cache: &mut ResidentTpKvCache,
1972        transaction: TpKvTransaction,
1973    ) -> Result<(), Box<dyn std::error::Error>> {
1974        self.validate_tp_kv_cache(cache)?;
1975        cache.validate_transaction(transaction)?;
1976        let target = transaction.base_len();
1977        self.set_tp_kv_len_mirrors(cache, target)?;
1978        cache.publish_finalize(transaction, target)?;
1979        Ok(())
1980    }
1981
1982    pub fn tp_kv_device_lengths(
1983        &self,
1984        cache: &ResidentTpKvCache,
1985    ) -> Result<Vec<i32>, Box<dyn std::error::Error>> {
1986        self.validate_tp_kv_cache(cache)?;
1987        let mut lengths = Vec::with_capacity(self.ranks.len());
1988        for (engine, rank_cache) in self.ranks.iter().zip(cache.ranks()) {
1989            let _main = engine.gpu.enter_main()?;
1990            lengths.push(engine.dtoh_i32_one(rank_cache.len_d())?);
1991        }
1992        Ok(lengths)
1993    }
1994
1995    fn set_tp_kv_len_mirrors(
1996        &self,
1997        cache: &mut ResidentTpKvCache,
1998        len: usize,
1999    ) -> Result<(), Box<dyn std::error::Error>> {
2000        let len = i32::try_from(len).map_err(|_| "TP KV length exceeds i32 device mirror")?;
2001        for (engine, rank_cache) in self.ranks.iter().zip(cache.ranks_mut()) {
2002            let _main = engine.gpu.enter_main()?;
2003            engine.set_i32_one(rank_cache.len_d_mut(), len)?;
2004        }
2005        Ok(())
2006    }
2007
2008    fn validate_tp_kv_cache(
2009        &self,
2010        cache: &ResidentTpKvCache,
2011    ) -> Result<(), Box<dyn std::error::Error>> {
2012        if cache.ranks_len() != self.ranks.len() {
2013            return Err(format!(
2014                "TP KV cache ranks {} != runtime ranks {}",
2015                cache.ranks_len(),
2016                self.ranks.len()
2017            )
2018            .into());
2019        }
2020        let expected_k = cache
2021            .physical_capacity()
2022            .checked_mul(cache.k_tok_bytes())
2023            .and_then(|bytes| bytes.checked_add(8))
2024            .ok_or("TP KV K plane validation overflow")?;
2025        let expected_v = cache
2026            .physical_capacity()
2027            .checked_mul(cache.v_tok_bytes())
2028            .and_then(|bytes| bytes.checked_add(8))
2029            .ok_or("TP KV V plane validation overflow")?;
2030        for (rank, (engine, rank_cache)) in self.ranks.iter().zip(cache.ranks()).enumerate() {
2031            let device = engine.ctx().ordinal();
2032            if rank_cache.k().len() != expected_k
2033                || rank_cache.v().len() != expected_v
2034                || rank_cache.len_d().len() != 1
2035                || rank_cache.k().ordinal() != device
2036                || rank_cache.v().ordinal() != device
2037                || rank_cache.len_d().ordinal() != device
2038            {
2039                return Err(format!(
2040                    "TP KV rank {rank} residency does not match device {device} or plane geometry"
2041                )
2042                .into());
2043            }
2044        }
2045        Ok(())
2046    }
2047
2048    pub fn full(
2049        &self,
2050        matrix: E4m3BlockMatrix<'_>,
2051        activations: &[f32],
2052        tokens: usize,
2053    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
2054        matrix.validate()?;
2055        validate_activations(activations, tokens, matrix.in_features)?;
2056        run_rank(&self.ranks[0], matrix, activations, tokens)
2057    }
2058
2059    /// Column-parallel projection. Weight output rows and their scale rows are partitioned across
2060    /// ranks. The input is host-broadcast, rank-local projections execute independently, and the
2061    /// output is host-gathered in rank order.
2062    pub fn column_parallel(
2063        &self,
2064        matrix: E4m3BlockMatrix<'_>,
2065        activations: &[f32],
2066        tokens: usize,
2067    ) -> Result<ColumnParallelResult, Box<dyn std::error::Error>> {
2068        matrix.validate()?;
2069        validate_activations(activations, tokens, matrix.in_features)?;
2070        let tp = self.ranks.len();
2071        if matrix.out_features % tp != 0 {
2072            return Err(format!(
2073                "column-parallel out_features {} is not divisible by TP={tp}",
2074                matrix.out_features
2075            )
2076            .into());
2077        }
2078        let local_out = matrix.out_features / tp;
2079        if local_out % FP8_BLOCK != 0 {
2080            return Err(format!(
2081                "column-parallel output shard {local_out} cuts through a {FP8_BLOCK}-row \
2082                 E4M3 scale block"
2083            )
2084            .into());
2085        }
2086
2087        let mut gathered = vec![0.0f32; tokens * matrix.out_features];
2088        let mut rank_outputs = Vec::with_capacity(tp);
2089        for (rank_index, rank) in self.ranks.iter().enumerate() {
2090            let shard = column_shard(matrix, tp, rank_index)?;
2091            let output = run_rank(rank, shard, activations, tokens)?;
2092            let row_start = rank_index * local_out;
2093            for token in 0..tokens {
2094                gathered[token * matrix.out_features + row_start
2095                    ..token * matrix.out_features + row_start + local_out]
2096                    .copy_from_slice(&output[token * local_out..(token + 1) * local_out]);
2097            }
2098            rank_outputs.push(output);
2099        }
2100        Ok(ColumnParallelResult {
2101            gathered,
2102            rank_outputs,
2103        })
2104    }
2105
2106    pub fn upload_column_parallel(
2107        &self,
2108        matrix: E4m3BlockMatrix<'_>,
2109    ) -> Result<ResidentColumnParallel, Box<dyn std::error::Error>> {
2110        matrix.validate()?;
2111        let tp = self.ranks.len();
2112        validate_column_shape(matrix, tp)?;
2113        let mut ranks = Vec::with_capacity(tp);
2114        for (rank_index, engine) in self.ranks.iter().enumerate() {
2115            ranks.push(upload_rank(engine, column_shard(matrix, tp, rank_index)?)?);
2116        }
2117        Ok(ResidentColumnParallel {
2118            ranks,
2119            out_features: matrix.out_features,
2120            in_features: matrix.in_features,
2121        })
2122    }
2123
2124    pub fn column_parallel_resident(
2125        &self,
2126        matrix: &ResidentColumnParallel,
2127        activations: &[f32],
2128        tokens: usize,
2129    ) -> Result<ColumnParallelResult, Box<dyn std::error::Error>> {
2130        validate_resident_ranks(&self.ranks, &matrix.ranks)?;
2131        validate_activations(activations, tokens, matrix.in_features)?;
2132        let local_out = matrix.out_features / self.ranks.len();
2133        let mut gathered = vec![0.0f32; tokens * matrix.out_features];
2134        let mut rank_outputs = Vec::with_capacity(self.ranks.len());
2135        for (rank_index, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
2136            let output = run_resident_rank(engine, shard, activations, tokens)?;
2137            let row_start = rank_index * local_out;
2138            for token in 0..tokens {
2139                gathered[token * matrix.out_features + row_start
2140                    ..token * matrix.out_features + row_start + local_out]
2141                    .copy_from_slice(&output[token * local_out..(token + 1) * local_out]);
2142            }
2143            rank_outputs.push(output);
2144        }
2145        Ok(ColumnParallelResult {
2146            gathered,
2147            rank_outputs,
2148        })
2149    }
2150
2151    /// Row-parallel projection. Weight/input columns and their scale columns are partitioned
2152    /// across ranks. Rank-local partials return through host memory and are reduced in stable
2153    /// rank order.
2154    pub fn row_parallel(
2155        &self,
2156        matrix: E4m3BlockMatrix<'_>,
2157        activations: &[f32],
2158        tokens: usize,
2159    ) -> Result<RowParallelResult, Box<dyn std::error::Error>> {
2160        matrix.validate()?;
2161        validate_activations(activations, tokens, matrix.in_features)?;
2162        let tp = self.ranks.len();
2163        if matrix.in_features % tp != 0 {
2164            return Err(format!(
2165                "row-parallel in_features {} is not divisible by TP={tp}",
2166                matrix.in_features
2167            )
2168            .into());
2169        }
2170        let local_in = matrix.in_features / tp;
2171        if local_in % FP8_BLOCK != 0 {
2172            return Err(format!(
2173                "row-parallel input shard {local_in} cuts through a {FP8_BLOCK}-column \
2174                 E4M3 scale block"
2175            )
2176            .into());
2177        }
2178
2179        let mut reduced = vec![0.0f32; tokens * matrix.out_features];
2180        let mut rank_partials = Vec::with_capacity(tp);
2181        for (rank_index, rank) in self.ranks.iter().enumerate() {
2182            let (codes, scales) = row_shard(matrix, tp, rank_index)?;
2183            let local_activations =
2184                activation_shard(activations, tokens, matrix.in_features, tp, rank_index);
2185            let shard = E4m3BlockMatrix {
2186                codes: &codes,
2187                scales: &scales,
2188                out_features: matrix.out_features,
2189                in_features: local_in,
2190            };
2191            let partial = run_rank(rank, shard, &local_activations, tokens)?;
2192            for (sum, value) in reduced.iter_mut().zip(&partial) {
2193                *sum += *value;
2194            }
2195            rank_partials.push(partial);
2196        }
2197        Ok(RowParallelResult {
2198            reduced,
2199            rank_partials,
2200        })
2201    }
2202
2203    pub fn upload_row_parallel(
2204        &self,
2205        matrix: E4m3BlockMatrix<'_>,
2206    ) -> Result<ResidentRowParallel, Box<dyn std::error::Error>> {
2207        matrix.validate()?;
2208        let tp = self.ranks.len();
2209        validate_row_shape(matrix, tp)?;
2210        let local_in = matrix.in_features / tp;
2211        let mut ranks = Vec::with_capacity(tp);
2212        for (rank_index, engine) in self.ranks.iter().enumerate() {
2213            let (codes, scales) = row_shard(matrix, tp, rank_index)?;
2214            ranks.push(upload_rank(
2215                engine,
2216                E4m3BlockMatrix {
2217                    codes: &codes,
2218                    scales: &scales,
2219                    out_features: matrix.out_features,
2220                    in_features: local_in,
2221                },
2222            )?);
2223        }
2224        Ok(ResidentRowParallel {
2225            ranks,
2226            out_features: matrix.out_features,
2227            in_features: matrix.in_features,
2228        })
2229    }
2230
2231    pub fn row_parallel_resident(
2232        &self,
2233        matrix: &ResidentRowParallel,
2234        activations: &[f32],
2235        tokens: usize,
2236    ) -> Result<RowParallelResult, Box<dyn std::error::Error>> {
2237        validate_resident_ranks(&self.ranks, &matrix.ranks)?;
2238        validate_activations(activations, tokens, matrix.in_features)?;
2239        let tp = self.ranks.len();
2240        let mut reduced = vec![0.0f32; tokens * matrix.out_features];
2241        let mut rank_partials = Vec::with_capacity(tp);
2242        for (rank_index, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
2243            let local_activations =
2244                activation_shard(activations, tokens, matrix.in_features, tp, rank_index);
2245            let partial = run_resident_rank(engine, shard, &local_activations, tokens)?;
2246            for (sum, value) in reduced.iter_mut().zip(&partial) {
2247                *sum += *value;
2248            }
2249            rank_partials.push(partial);
2250        }
2251        Ok(RowParallelResult {
2252            reduced,
2253            rank_partials,
2254        })
2255    }
2256
2257    pub fn upload_bf16_column_parallel(
2258        &self,
2259        matrix: Bf16Matrix<'_>,
2260    ) -> Result<ResidentBf16ColumnParallel, Box<dyn std::error::Error>> {
2261        self.upload_bf16_column_parallel_inner(matrix, None, false)
2262    }
2263
2264    /// Step-3.7 column projection with one numerical program across TP1/TP2/TP4/TP8.
2265    pub fn upload_step_bf16_column_parallel(
2266        &self,
2267        matrix: Bf16Matrix<'_>,
2268    ) -> Result<ResidentBf16ColumnParallel, Box<dyn std::error::Error>> {
2269        self.upload_step_bf16_column_parallel_inner(matrix, false)
2270    }
2271
2272    /// Load-time exact F32 expansion of a Step BF16 shard.
2273    ///
2274    /// The original BF16 allocation is released after the stream-ordered conversion. Decode then
2275    /// reuses the resident F32 values with the same topology-invariant output-row chunks.
2276    pub fn upload_step_bf16_column_parallel_f32_mirror(
2277        &self,
2278        matrix: Bf16Matrix<'_>,
2279    ) -> Result<ResidentBf16ColumnParallel, Box<dyn std::error::Error>> {
2280        self.upload_step_bf16_column_parallel_inner(matrix, true)
2281    }
2282
2283    fn upload_step_bf16_column_parallel_inner(
2284        &self,
2285        matrix: Bf16Matrix<'_>,
2286        f32_mirror: bool,
2287    ) -> Result<ResidentBf16ColumnParallel, Box<dyn std::error::Error>> {
2288        let canonical_chunk_rows =
2289            step_bf16_canonical_chunk_rows(matrix.out_features, self.ranks.len())?;
2290        self.upload_bf16_column_parallel_inner(matrix, Some(canonical_chunk_rows), f32_mirror)
2291    }
2292
2293    fn upload_bf16_column_parallel_inner(
2294        &self,
2295        matrix: Bf16Matrix<'_>,
2296        canonical_chunk_rows: Option<usize>,
2297        f32_mirror: bool,
2298    ) -> Result<ResidentBf16ColumnParallel, Box<dyn std::error::Error>> {
2299        matrix.validate()?;
2300        let tp = self.ranks.len();
2301        if matrix.out_features % tp != 0 {
2302            return Err(format!(
2303                "BF16 column-parallel out_features {} is not divisible by TP={tp}",
2304                matrix.out_features
2305            )
2306            .into());
2307        }
2308        let mut ranks = Vec::with_capacity(tp);
2309        for (rank, engine) in self.ranks.iter().enumerate() {
2310            ranks.push(upload_bf16_rank(
2311                engine,
2312                bf16_column_shard(matrix, tp, rank)?,
2313                f32_mirror,
2314            )?);
2315        }
2316        Ok(ResidentBf16ColumnParallel {
2317            ranks,
2318            out_features: matrix.out_features,
2319            in_features: matrix.in_features,
2320            canonical_chunk_rows,
2321        })
2322    }
2323
2324    pub fn bf16_column_parallel_resident(
2325        &self,
2326        matrix: &ResidentBf16ColumnParallel,
2327        activations: &[f32],
2328        tokens: usize,
2329    ) -> Result<ColumnParallelResult, Box<dyn std::error::Error>> {
2330        validate_resident_bf16_ranks(&self.ranks, &matrix.ranks)?;
2331        validate_activations(activations, tokens, matrix.in_features)?;
2332        let local_out = matrix.out_features / self.ranks.len();
2333        let mut gathered = vec![0.0f32; tokens * matrix.out_features];
2334        let mut rank_outputs = Vec::with_capacity(self.ranks.len());
2335        for (rank, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
2336            let output = run_resident_bf16_rank(
2337                engine,
2338                shard,
2339                activations,
2340                tokens,
2341                matrix.canonical_chunk_rows,
2342            )?;
2343            for token in 0..tokens {
2344                let src = &output[token * local_out..(token + 1) * local_out];
2345                let dst_start = token * matrix.out_features + rank * local_out;
2346                gathered[dst_start..dst_start + local_out].copy_from_slice(src);
2347            }
2348            rank_outputs.push(output);
2349        }
2350        Ok(ColumnParallelResult {
2351            gathered,
2352            rank_outputs,
2353        })
2354    }
2355
2356    /// Native-P2P twin of [`Self::bf16_column_parallel_resident`].
2357    ///
2358    /// The host-canonical activation is uploaded once on rank zero and peer-broadcast to the
2359    /// remaining ranks. Rank-local outputs are peer-gathered in token-major order before one root
2360    /// readback. This removes per-rank host staging but deliberately still returns a host oracle;
2361    /// attention and KV ownership are separate milestones.
2362    pub fn bf16_column_parallel_resident_native(
2363        &self,
2364        matrix: &ResidentBf16ColumnParallel,
2365        activations: &[f32],
2366        tokens: usize,
2367    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
2368        let rank_outputs =
2369            self.bf16_column_parallel_resident_device_shards(matrix, activations, tokens)?;
2370        let local_out = matrix.out_features / self.ranks.len();
2371        self.gather_native_column_shards(&rank_outputs, tokens, local_out)
2372    }
2373
2374    /// Does the serving engine live in the SAME CUDA context as this runtime's root rank?
2375    /// The device-resident input/output seams below hand raw device buffers across the
2376    /// Engine boundary, which is only addressable when both sides share the root device's
2377    /// primary context — the seam `step35_tp_qkv` keys its residency dispatch on.
2378    pub fn root_shares_ctx(&self, e: &Engine) -> bool {
2379        self.ranks
2380            .first()
2381            .is_some_and(|root| root.ctx().cu_ctx() == e.ctx().cu_ctx())
2382    }
2383
2384    /// Device-input twin of [`Self::bf16_column_parallel_resident_native`] (lane/
2385    /// hermes-perf-fixes, 2026-08-23 — the step QKV TP host-bounce finding). The activation
2386    /// arrives as a ROOT-DEVICE buffer (first `tokens * in_features` values) instead of a
2387    /// host slice, and the gathered output stays root-resident: no DtoH of the hidden state,
2388    /// no host q/k/v staging, no re-upload. BYTE-IDENTICAL to the host-canonical native arm
2389    /// by construction — the root input bytes are dtod-copied where the host arm htod'd the
2390    /// same bytes, and every kernel, peer copy, and gather order is shared.
2391    ///
2392    /// FENCES: caller must have synchronized the producer stream that wrote
2393    /// `root_activation` (the serving engine's — a DIFFERENT stream in the same context);
2394    /// this method synchronizes the root stream before returning so the caller's stream can
2395    /// consume the gathered output immediately.
2396    pub fn bf16_column_parallel_resident_native_device(
2397        &self,
2398        matrix: &ResidentBf16ColumnParallel,
2399        root_activation: &CudaSlice<f32>,
2400        tokens: usize,
2401    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
2402        let rank_outputs = self.bf16_column_parallel_resident_device_shards_from_root(
2403            matrix,
2404            root_activation,
2405            tokens,
2406        )?;
2407        let local_out = matrix.out_features / self.ranks.len();
2408        let gathered = self.gather_native_column_shards_device(&rank_outputs, tokens, local_out)?;
2409        let root = &self.ranks[0];
2410        let _main = root.gpu.enter_main()?;
2411        root.stream().synchronize()?;
2412        Ok(gathered)
2413    }
2414
2415    /// Root-device-input twin of [`Self::bf16_column_parallel_resident_device_shards`]:
2416    /// the canonical activation is already resident on the root device (len >=
2417    /// `tokens * in_features`; extra tail values beyond the active prefix are ignored,
2418    /// the reused-prime-slab contract of `active_matrix_values`).
2419    pub fn bf16_column_parallel_resident_device_shards_from_root(
2420        &self,
2421        matrix: &ResidentBf16ColumnParallel,
2422        root_activation: &CudaSlice<f32>,
2423        tokens: usize,
2424    ) -> Result<Vec<CudaSlice<f32>>, Box<dyn std::error::Error>> {
2425        if self.ranks.len() > 1 && !self.native_p2p {
2426            return Err("device-resident BF16 column parallelism requires native P2P ranks".into());
2427        }
2428        validate_resident_bf16_ranks(&self.ranks, &matrix.ranks)?;
2429        let values = tokens
2430            .checked_mul(matrix.in_features)
2431            .ok_or("device BF16 column activation size overflow")?;
2432        let root = &self.ranks[0];
2433        if tokens == 0
2434            || root_activation.len() < values
2435            || root_activation.ordinal() != root.ctx().ordinal()
2436        {
2437            return Err("device BF16 column root activation geometry mismatch".into());
2438        }
2439
2440        let mut rank_inputs = Vec::with_capacity(self.ranks.len());
2441        let root_input = {
2442            let _main = root.gpu.enter_main()?;
2443            let mut root_input = root.uninit(values)?;
2444            root.stream()
2445                .memcpy_dtod(&root_activation.slice(0..values), &mut root_input)?;
2446            root_input
2447        };
2448        // PRODUCER FENCE (same discipline as the host-input twin): the peer broadcast
2449        // below reads this buffer from the OTHER ranks' streams while the root dtod may
2450        // still be in flight.
2451        {
2452            let _main = root.gpu.enter_main()?;
2453            root.stream().synchronize()?;
2454        }
2455        rank_inputs.push(root_input);
2456        for engine in &self.ranks[1..] {
2457            let peer_input = {
2458                let _main = engine.gpu.enter_main()?;
2459                let mut peer_input = engine.uninit(values)?;
2460                engine
2461                    .stream()
2462                    .memcpy_dtod(&rank_inputs[0], &mut peer_input)?;
2463                peer_input
2464            };
2465            rank_inputs.push(peer_input);
2466        }
2467
2468        let mut rank_outputs = Vec::with_capacity(self.ranks.len());
2469        for rank in 0..self.ranks.len() {
2470            rank_outputs.push(run_resident_bf16_rank_device(
2471                &self.ranks[rank],
2472                &matrix.ranks[rank],
2473                &rank_inputs[rank],
2474                tokens,
2475                matrix.canonical_chunk_rows,
2476                self.bulk_p2p,
2477            )?);
2478        }
2479        Ok(rank_outputs)
2480    }
2481
2482    /// Keep Step BF16 column outputs resident on their owning TP ranks.
2483    ///
2484    /// Rank zero receives the host-canonical activation once and peer-broadcasts it when TP>1.
2485    /// Unlike [`Self::bf16_column_parallel_resident_native`], this method performs no output
2486    /// gather or readback. It is the correctness substrate for rank-local norm, RoPE, attention,
2487    /// and cache ownership; callers must not treat its existence as serving qualification.
2488    pub fn bf16_column_parallel_resident_device_shards(
2489        &self,
2490        matrix: &ResidentBf16ColumnParallel,
2491        activations: &[f32],
2492        tokens: usize,
2493    ) -> Result<Vec<CudaSlice<f32>>, Box<dyn std::error::Error>> {
2494        if self.ranks.len() > 1 && !self.native_p2p {
2495            return Err("device-resident BF16 column parallelism requires native P2P ranks".into());
2496        }
2497        validate_resident_bf16_ranks(&self.ranks, &matrix.ranks)?;
2498        validate_activations(activations, tokens, matrix.in_features)?;
2499
2500        let mut rank_inputs = Vec::with_capacity(self.ranks.len());
2501        let root_input = {
2502            let root = &self.ranks[0];
2503            let _main = root.gpu.enter_main()?;
2504            root.htod(activations)?
2505        };
2506        // PRODUCER FENCE (2026-08-20 flake fix): the peer broadcast below reads this buffer from
2507        // the OTHER ranks' streams, and clone_htod is asynchronous on the root stream. Without
2508        // this fence a peer copy can overtake the in-flight H2D and replicate stale bytes — the
2509        // measured ~30%-of-boots prefill/decode argmax flake. Same discipline as
2510        // `upload_replicated_device_rows`.
2511        {
2512            let root = &self.ranks[0];
2513            let _main = root.gpu.enter_main()?;
2514            root.stream().synchronize()?;
2515        }
2516        rank_inputs.push(root_input);
2517        for engine in &self.ranks[1..] {
2518            let peer_input = {
2519                let _main = engine.gpu.enter_main()?;
2520                let mut peer_input = engine.uninit(activations.len())?;
2521                engine
2522                    .stream()
2523                    .memcpy_dtod(&rank_inputs[0], &mut peer_input)?;
2524                peer_input
2525            };
2526            rank_inputs.push(peer_input);
2527        }
2528
2529        let mut rank_outputs = Vec::with_capacity(self.ranks.len());
2530        for rank in 0..self.ranks.len() {
2531            rank_outputs.push(run_resident_bf16_rank_device(
2532                &self.ranks[rank],
2533                &matrix.ranks[rank],
2534                &rank_inputs[rank],
2535                tokens,
2536                matrix.canonical_chunk_rows,
2537                self.bulk_p2p,
2538            )?);
2539        }
2540        Ok(rank_outputs)
2541    }
2542
2543    /// Allocate one fixed-shape replicated batch without initializing its contents.
2544    ///
2545    /// Callers must refresh every rank before passing the batch to an operator.
2546    pub fn allocate_replicated_device_rows(
2547        &self,
2548        tokens: usize,
2549        width: usize,
2550    ) -> Result<ResidentReplicatedDeviceRows, Box<dyn std::error::Error>> {
2551        if self.ranks.len() > 1 && !self.native_p2p {
2552            return Err("replicated device rows require native P2P ranks".into());
2553        }
2554        let values = tokens
2555            .checked_mul(width)
2556            .ok_or("replicated device row size overflow")?;
2557        let rank_lengths = vec![values; self.ranks.len()];
2558        replicated_device_row_values(tokens, width, self.ranks.len(), &rank_lengths)?;
2559        let mut ranks = Vec::with_capacity(self.ranks.len());
2560        for engine in &self.ranks {
2561            let _main = engine.gpu.enter_main()?;
2562            ranks.push(engine.uninit(values)?);
2563        }
2564        Ok(ResidentReplicatedDeviceRows {
2565            ranks,
2566            tokens,
2567            width,
2568        })
2569    }
2570
2571    /// Replace a fixed-shape replicated batch from a root-device source.
2572    pub fn refresh_replicated_device_rows_from_root(
2573        &self,
2574        rows: &mut ResidentReplicatedDeviceRows,
2575        source: &CudaSlice<f32>,
2576    ) -> Result<(), Box<dyn std::error::Error>> {
2577        if self.ranks.len() > 1 && !self.native_p2p {
2578            return Err("replicated device rows require native P2P ranks".into());
2579        }
2580        validate_replicated_device_rows(&self.ranks, rows)?;
2581        let root = self
2582            .ranks
2583            .first()
2584            .ok_or("replicated rows have no root rank")?;
2585        let values = replicated_device_row_source_values(
2586            rows.tokens,
2587            rows.width,
2588            source.len(),
2589            source.ordinal(),
2590            root.ctx().ordinal(),
2591        )?;
2592        let (root_rows, peer_rows) = rows
2593            .ranks
2594            .split_first_mut()
2595            .ok_or("replicated rows have no root allocation")?;
2596        {
2597            let _main = root.gpu.enter_main()?;
2598            let mut destination = root_rows.slice_mut(0..values);
2599            root.stream()
2600                .memcpy_dtod(&source.slice(0..values), &mut destination)?;
2601            root.stream().synchronize()?;
2602        }
2603        for (engine, peer_rows) in self.ranks.iter().skip(1).zip(peer_rows) {
2604            let _main = engine.gpu.enter_main()?;
2605            let mut destination = peer_rows.slice_mut(0..values);
2606            engine
2607                .stream()
2608                .memcpy_dtod(&root_rows.slice(0..values), &mut destination)?;
2609        }
2610        Ok(())
2611    }
2612
2613    /// Upload one canonical batch on rank zero and replicate it over native P2P.
2614    pub fn upload_replicated_device_rows(
2615        &self,
2616        rows: &[f32],
2617        tokens: usize,
2618        width: usize,
2619    ) -> Result<ResidentReplicatedDeviceRows, Box<dyn std::error::Error>> {
2620        if self.ranks.len() > 1 && !self.native_p2p {
2621            return Err("replicated device rows require native P2P ranks".into());
2622        }
2623        validate_activations(rows, tokens, width)?;
2624        let root = self
2625            .ranks
2626            .first()
2627            .ok_or("replicated rows have no root rank")?;
2628        let root_rows = {
2629            let _main = root.gpu.enter_main()?;
2630            root.htod(rows)?
2631        };
2632        {
2633            let _main = root.gpu.enter_main()?;
2634            root.stream().synchronize()?;
2635        }
2636        let mut ranks = Vec::with_capacity(self.ranks.len());
2637        ranks.push(root_rows);
2638        for engine in self.ranks.iter().skip(1) {
2639            let _main = engine.gpu.enter_main()?;
2640            let mut peer_rows = engine.uninit(rows.len())?;
2641            engine.stream().memcpy_dtod(&ranks[0], &mut peer_rows)?;
2642            ranks.push(peer_rows);
2643        }
2644        Ok(ResidentReplicatedDeviceRows {
2645            ranks,
2646            tokens,
2647            width,
2648        })
2649    }
2650
2651    /// Execute a column-parallel BF16 matrix directly from rank-local replicated inputs.
2652    pub fn bf16_column_parallel_resident_replicated_device_shards(
2653        &self,
2654        matrix: &ResidentBf16ColumnParallel,
2655        activations: &ResidentReplicatedDeviceRows,
2656    ) -> Result<Vec<CudaSlice<f32>>, Box<dyn std::error::Error>> {
2657        validate_resident_bf16_ranks(&self.ranks, &matrix.ranks)?;
2658        validate_replicated_device_rows(&self.ranks, activations)?;
2659        if activations.width != matrix.in_features {
2660            return Err(format!(
2661                "replicated BF16 column input width {} != matrix width {}",
2662                activations.width, matrix.in_features
2663            )
2664            .into());
2665        }
2666        let mut outputs = Vec::with_capacity(self.ranks.len());
2667        for rank in 0..self.ranks.len() {
2668            outputs.push(run_resident_bf16_rank_device(
2669                &self.ranks[rank],
2670                &matrix.ranks[rank],
2671                &activations.ranks[rank],
2672                activations.tokens,
2673                matrix.canonical_chunk_rows,
2674                self.bulk_p2p,
2675            )?);
2676        }
2677        Ok(outputs)
2678    }
2679
2680    /// Upload a BF16 router once on rank zero and retain its exact F32 expansion.
2681    #[allow(clippy::too_many_arguments)]
2682    pub fn upload_sigmoid_topk_router(
2683        &self,
2684        weight: Bf16Matrix<'_>,
2685        correction_bias: &[f32],
2686        active: Option<&[bool]>,
2687        experts_per_token: usize,
2688        scaling_factor: f32,
2689        route_norm: bool,
2690    ) -> Result<ResidentSigmoidTopKRouter, Box<dyn std::error::Error>> {
2691        weight.validate()?;
2692        if correction_bias.len() != weight.out_features
2693            || experts_per_token == 0
2694            || experts_per_token > weight.out_features
2695            || !correction_bias.iter().all(|value| value.is_finite())
2696            || !scaling_factor.is_finite()
2697            || scaling_factor <= 0.0
2698        {
2699            return Err(format!(
2700                "sigmoid router geometry weight={}x{} bias={} top_k={} scale={scaling_factor}",
2701                weight.out_features,
2702                weight.in_features,
2703                correction_bias.len(),
2704                experts_per_token,
2705            )
2706            .into());
2707        }
2708        let active_row = active
2709            .map(|mask| {
2710                if mask.len() != weight.out_features {
2711                    return Err(format!(
2712                        "sigmoid router active mask {} != experts {}",
2713                        mask.len(),
2714                        weight.out_features
2715                    ));
2716                }
2717                Ok(mask
2718                    .iter()
2719                    .map(|&enabled| u8::from(enabled))
2720                    .collect::<Vec<_>>())
2721            })
2722            .transpose()?
2723            .unwrap_or_else(|| vec![1; weight.out_features]);
2724        let active_count = active_row.iter().filter(|&&enabled| enabled != 0).count();
2725        crate::sigrouter_contract::validate_active_count(experts_per_token, active_count)?;
2726
2727        let root = self
2728            .ranks
2729            .first()
2730            .ok_or("sigmoid router runtime has no root rank")?;
2731        let _main = root.gpu.enter_main()?;
2732        let bf16 = root.htod_bytes(weight.bytes)?;
2733        let weight_f32 = root.bf16_to_f32(
2734            &bf16.slice(0..bf16.len()),
2735            weight.out_features * weight.in_features,
2736        )?;
2737        Ok(ResidentSigmoidTopKRouter {
2738            weight: weight_f32,
2739            correction_bias: root.htod(correction_bias)?,
2740            active: root.htod_bytes(&active_row)?,
2741            root_device: root.ctx().ordinal(),
2742            input_width: weight.in_features,
2743            expert_count: weight.out_features,
2744            experts_per_token,
2745            active_count,
2746            scaling_factor,
2747            route_norm,
2748        })
2749    }
2750
2751    /// Route rank-zero replicated rows and return the narrow host control result plus logits.
2752    ///
2753    /// The logits readback exists for independent oracle comparison. This method is a correctness
2754    /// surface; a serving scheduler may retain logits and selected routes on device.
2755    pub fn sigmoid_topk_replicated_device_rows_host(
2756        &self,
2757        router: &ResidentSigmoidTopKRouter,
2758        input: &ResidentReplicatedDeviceRows,
2759    ) -> Result<SigmoidTopKHostOutput, Box<dyn std::error::Error>> {
2760        validate_replicated_device_rows(&self.ranks, input)?;
2761        if input.width != router.input_width {
2762            return Err(format!(
2763                "sigmoid router input width {} != resident width {}",
2764                input.width, router.input_width
2765            )
2766            .into());
2767        }
2768        let root = self
2769            .ranks
2770            .first()
2771            .ok_or("sigmoid router runtime has no root rank")?;
2772        let _main = root.gpu.enter_main()?;
2773        if root.ctx().ordinal() != router.root_device
2774            || router.weight.ordinal() != router.root_device
2775            || router.correction_bias.ordinal() != router.root_device
2776            || router.active.ordinal() != router.root_device
2777        {
2778            return Err("sigmoid router root residency changed".into());
2779        }
2780        let logits = root.router_gemv(
2781            &router.weight,
2782            &input.ranks[0],
2783            router.input_width,
2784            router.expert_count,
2785            input.tokens,
2786        )?;
2787        let (selected, weights) = root.moe_router_sigmoid_topk_host(
2788            &logits,
2789            input.tokens,
2790            router.expert_count,
2791            router.experts_per_token,
2792            router.active_count,
2793            &router.correction_bias,
2794            &router.active,
2795            router.scaling_factor,
2796            router.route_norm,
2797        )?;
2798        Ok(SigmoidTopKHostOutput {
2799            logits: root.dtoh(&logits)?,
2800            selected,
2801            weights,
2802        })
2803    }
2804
2805    /// Replicate a full BF16 SwiGLU bank on every rank.
2806    pub fn upload_replicated_bf16_swiglu(
2807        &self,
2808        gate: Bf16Matrix<'_>,
2809        up: Bf16Matrix<'_>,
2810        down: Bf16Matrix<'_>,
2811    ) -> Result<ResidentReplicatedBf16SwiGlu, Box<dyn std::error::Error>> {
2812        gate.validate()?;
2813        up.validate()?;
2814        down.validate()?;
2815        if gate.in_features != up.in_features
2816            || gate.out_features != up.out_features
2817            || down.in_features != gate.out_features
2818            || down.out_features != gate.in_features
2819        {
2820            return Err(format!(
2821                "replicated BF16 SwiGLU geometry gate={}x{} up={}x{} down={}x{}",
2822                gate.out_features,
2823                gate.in_features,
2824                up.out_features,
2825                up.in_features,
2826                down.out_features,
2827                down.in_features,
2828            )
2829            .into());
2830        }
2831        let mut gate_ranks = Vec::with_capacity(self.ranks.len());
2832        let mut up_ranks = Vec::with_capacity(self.ranks.len());
2833        let mut down_ranks = Vec::with_capacity(self.ranks.len());
2834        for engine in &self.ranks {
2835            gate_ranks.push(upload_bf16_rank(engine, gate, false)?);
2836            up_ranks.push(upload_bf16_rank(engine, up, false)?);
2837            down_ranks.push(upload_bf16_rank(engine, down, false)?);
2838        }
2839        Ok(ResidentReplicatedBf16SwiGlu {
2840            gate: gate_ranks,
2841            up: up_ranks,
2842            down: down_ranks,
2843            input_width: gate.in_features,
2844            intermediate_width: gate.out_features,
2845        })
2846    }
2847
2848    /// Execute a fully replicated BF16 SwiGLU directly from replicated device rows.
2849    pub fn replicated_bf16_swiglu_resident_device(
2850        &self,
2851        mlp: &ResidentReplicatedBf16SwiGlu,
2852        input: &ResidentReplicatedDeviceRows,
2853        activation_limit: Option<f32>,
2854    ) -> Result<ResidentReplicatedDeviceRows, Box<dyn std::error::Error>> {
2855        validate_step_expert_activation_limit(activation_limit)?;
2856        validate_replicated_device_rows(&self.ranks, input)?;
2857        validate_resident_bf16_ranks(&self.ranks, &mlp.gate)?;
2858        validate_resident_bf16_ranks(&self.ranks, &mlp.up)?;
2859        validate_resident_bf16_ranks(&self.ranks, &mlp.down)?;
2860        if input.width != mlp.input_width
2861            || mlp.gate.len() != self.ranks.len()
2862            || mlp.up.len() != self.ranks.len()
2863            || mlp.down.len() != self.ranks.len()
2864        {
2865            return Err("replicated BF16 SwiGLU residency or input width changed".into());
2866        }
2867
2868        let mut outputs = Vec::with_capacity(self.ranks.len());
2869        for rank in 0..self.ranks.len() {
2870            let engine = &self.ranks[rank];
2871            let gate = run_resident_bf16_rank_device(
2872                engine,
2873                &mlp.gate[rank],
2874                &input.ranks[rank],
2875                input.tokens,
2876                None,
2877                self.bulk_p2p,
2878            )?;
2879            let up = run_resident_bf16_rank_device(
2880                engine,
2881                &mlp.up[rank],
2882                &input.ranks[rank],
2883                input.tokens,
2884                None,
2885                self.bulk_p2p,
2886            )?;
2887            let _main = engine.gpu.enter_main()?;
2888            let values = input
2889                .tokens
2890                .checked_mul(mlp.intermediate_width)
2891                .ok_or("replicated BF16 SwiGLU activation size overflow")?;
2892            let mut activation = engine.uninit(values)?;
2893            if let Some(limit) = activation_limit {
2894                engine.silu_clamped_mul_host_expf(&gate, &up, limit, &mut activation, values)?;
2895            } else {
2896                engine.silu_mul_host_expf(&gate, &up, &mut activation, values)?;
2897            }
2898            outputs.push(run_resident_bf16_rank_device(
2899                engine,
2900                &mlp.down[rank],
2901                &activation,
2902                input.tokens,
2903                None,
2904                self.bulk_p2p,
2905            )?);
2906        }
2907        Ok(ResidentReplicatedDeviceRows {
2908            ranks: outputs,
2909            tokens: input.tokens,
2910            width: mlp.input_width,
2911        })
2912    }
2913
2914    /// Apply the same RMS-norm row program independently on every replicated rank.
2915    pub fn rms_norm_replicated_device_rows(
2916        &self,
2917        input: &ResidentReplicatedDeviceRows,
2918        weight: &[f32],
2919        eps: f32,
2920    ) -> Result<ResidentReplicatedDeviceRows, Box<dyn std::error::Error>> {
2921        validate_replicated_device_rows(&self.ranks, input)?;
2922        if weight.len() != input.width || !eps.is_finite() || eps <= 0.0 {
2923            return Err(format!(
2924                "replicated RMS norm weight/eps {}/{} != width {}",
2925                weight.len(),
2926                eps,
2927                input.width
2928            )
2929            .into());
2930        }
2931        let mut ranks = Vec::with_capacity(self.ranks.len());
2932        for (rank, engine) in self.ranks.iter().enumerate() {
2933            let _main = engine.gpu.enter_main()?;
2934            let weight = engine.htod(weight)?;
2935            let mut output = engine.uninit(input.tokens * input.width)?;
2936            engine.rms_norm(
2937                &input.ranks[rank],
2938                &weight,
2939                &mut output,
2940                input.width,
2941                input.tokens,
2942                eps,
2943            )?;
2944            ranks.push(output);
2945        }
2946        Ok(ResidentReplicatedDeviceRows {
2947            ranks,
2948            tokens: input.tokens,
2949            width: input.width,
2950        })
2951    }
2952
2953    /// Add two replicated batches and RMS-normalize the exact residual on every rank.
2954    pub fn add_rms_norm_replicated_device_rows(
2955        &self,
2956        input: &ResidentReplicatedDeviceRows,
2957        update: &ResidentReplicatedDeviceRows,
2958        weight: &[f32],
2959        eps: f32,
2960    ) -> Result<
2961        (ResidentReplicatedDeviceRows, ResidentReplicatedDeviceRows),
2962        Box<dyn std::error::Error>,
2963    > {
2964        validate_replicated_device_rows(&self.ranks, input)?;
2965        validate_replicated_device_rows(&self.ranks, update)?;
2966        if input.tokens != update.tokens
2967            || input.width != update.width
2968            || weight.len() != input.width
2969            || !eps.is_finite()
2970            || eps <= 0.0
2971        {
2972            return Err(format!(
2973                "replicated add/RMS geometry input={}x{} update={}x{} weight={} eps={eps}",
2974                input.tokens,
2975                input.width,
2976                update.tokens,
2977                update.width,
2978                weight.len(),
2979            )
2980            .into());
2981        }
2982        let values = input.tokens * input.width;
2983        let mut residual_ranks = Vec::with_capacity(self.ranks.len());
2984        let mut normalized_ranks = Vec::with_capacity(self.ranks.len());
2985        for (rank, engine) in self.ranks.iter().enumerate() {
2986            let _main = engine.gpu.enter_main()?;
2987            let weight = engine.htod(weight)?;
2988            let mut residual = engine.uninit(values)?;
2989            let mut normalized = engine.uninit(values)?;
2990            engine.add_rms_norm(
2991                &input.ranks[rank],
2992                &update.ranks[rank],
2993                &weight,
2994                &mut residual,
2995                &mut normalized,
2996                input.width,
2997                input.tokens,
2998                eps,
2999            )?;
3000            residual_ranks.push(residual);
3001            normalized_ranks.push(normalized);
3002        }
3003        Ok((
3004            ResidentReplicatedDeviceRows {
3005                ranks: residual_ranks,
3006                tokens: input.tokens,
3007                width: input.width,
3008            },
3009            ResidentReplicatedDeviceRows {
3010                ranks: normalized_ranks,
3011                tokens: input.tokens,
3012                width: input.width,
3013            },
3014        ))
3015    }
3016
3017    pub fn collect_replicated_device_rows(
3018        &self,
3019        rows: &ResidentReplicatedDeviceRows,
3020    ) -> Result<Vec<Vec<f32>>, Box<dyn std::error::Error>> {
3021        validate_replicated_device_rows(&self.ranks, rows)?;
3022        let mut outputs = Vec::with_capacity(self.ranks.len());
3023        for (rank, engine) in self.ranks.iter().enumerate() {
3024            let _main = engine.gpu.enter_main()?;
3025            outputs.push(engine.dtoh(&rows.ranks[rank])?);
3026        }
3027        Ok(outputs)
3028    }
3029
3030    pub fn upload_bf16_row_parallel(
3031        &self,
3032        matrix: Bf16Matrix<'_>,
3033    ) -> Result<ResidentBf16RowParallel, Box<dyn std::error::Error>> {
3034        matrix.validate()?;
3035        let tp = self.ranks.len();
3036        if matrix.in_features % tp != 0 {
3037            return Err(format!(
3038                "BF16 row-parallel in_features {} is not divisible by TP={tp}",
3039                matrix.in_features
3040            )
3041            .into());
3042        }
3043        let mut ranks = Vec::with_capacity(tp);
3044        for (rank, engine) in self.ranks.iter().enumerate() {
3045            let shard = bf16_row_shard(matrix, tp, rank)?;
3046            ranks.push(upload_bf16_rank(
3047                engine,
3048                Bf16Matrix {
3049                    bytes: &shard,
3050                    out_features: matrix.out_features,
3051                    in_features: matrix.in_features / tp,
3052                },
3053                false,
3054            )?);
3055        }
3056        Ok(ResidentBf16RowParallel {
3057            ranks,
3058            out_features: matrix.out_features,
3059            in_features: matrix.in_features,
3060        })
3061    }
3062
3063    pub fn bf16_row_parallel_resident(
3064        &self,
3065        matrix: &ResidentBf16RowParallel,
3066        activations: &[f32],
3067        tokens: usize,
3068    ) -> Result<RowParallelResult, Box<dyn std::error::Error>> {
3069        validate_resident_bf16_ranks(&self.ranks, &matrix.ranks)?;
3070        validate_activations(activations, tokens, matrix.in_features)?;
3071        let tp = self.ranks.len();
3072        let mut reduced = vec![0.0f32; tokens * matrix.out_features];
3073        let mut rank_partials = Vec::with_capacity(tp);
3074        for (rank, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
3075            let local_activations =
3076                activation_shard(activations, tokens, matrix.in_features, tp, rank);
3077            let partial = run_resident_bf16_rank(engine, shard, &local_activations, tokens, None)?;
3078            for (sum, value) in reduced.iter_mut().zip(&partial) {
3079                *sum += value;
3080            }
3081            rank_partials.push(partial);
3082        }
3083        Ok(RowParallelResult {
3084            reduced,
3085            rank_partials,
3086        })
3087    }
3088
3089    /// Step-3.7 row projection split into the same eight global K blocks for TP1/TP2/TP4/TP8.
3090    pub fn upload_step_bf16_row_parallel(
3091        &self,
3092        matrix: Bf16Matrix<'_>,
3093    ) -> Result<ResidentStepBf16RowParallel, Box<dyn std::error::Error>> {
3094        self.upload_step_bf16_row_parallel_inner(matrix, false)
3095    }
3096
3097    pub fn upload_step_bf16_row_parallel_f32_mirror(
3098        &self,
3099        matrix: Bf16Matrix<'_>,
3100    ) -> Result<ResidentStepBf16RowParallel, Box<dyn std::error::Error>> {
3101        self.upload_step_bf16_row_parallel_inner(matrix, true)
3102    }
3103
3104    fn upload_step_bf16_row_parallel_inner(
3105        &self,
3106        matrix: Bf16Matrix<'_>,
3107        f32_mirror: bool,
3108    ) -> Result<ResidentStepBf16RowParallel, Box<dyn std::error::Error>> {
3109        matrix.validate()?;
3110        let tp = self.ranks.len();
3111        let canonical_chunk_cols = step_bf16_canonical_chunk_cols(matrix.in_features, tp)?;
3112        let local_in = matrix.in_features / tp;
3113        let blocks_per_rank = local_in / canonical_chunk_cols;
3114        let mut ranks = Vec::with_capacity(tp);
3115        for (rank, engine) in self.ranks.iter().enumerate() {
3116            let mut blocks = Vec::with_capacity(blocks_per_rank);
3117            for block in 0..blocks_per_rank {
3118                let global_block = rank * blocks_per_rank + block;
3119                let col_start = global_block * canonical_chunk_cols;
3120                let bytes = bf16_row_block(matrix, col_start, canonical_chunk_cols)?;
3121                blocks.push(upload_bf16_rank(
3122                    engine,
3123                    Bf16Matrix {
3124                        bytes: &bytes,
3125                        out_features: matrix.out_features,
3126                        in_features: canonical_chunk_cols,
3127                    },
3128                    f32_mirror,
3129                )?);
3130            }
3131            ranks.push(blocks);
3132        }
3133        Ok(ResidentStepBf16RowParallel {
3134            ranks,
3135            out_features: matrix.out_features,
3136            in_features: matrix.in_features,
3137            canonical_chunk_cols,
3138        })
3139    }
3140
3141    /// Host-staged exactness twin of [`Self::step_bf16_row_parallel_resident_native`].
3142    ///
3143    /// Block inputs and partials cross host memory, but every partial is added on the root device
3144    /// in global checkpoint-column order. Native transport must reproduce this result bitwise.
3145    pub fn step_bf16_row_parallel_resident(
3146        &self,
3147        matrix: &ResidentStepBf16RowParallel,
3148        activations: &[f32],
3149        tokens: usize,
3150    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
3151        validate_step_bf16_row_residency(&self.ranks, matrix)?;
3152        validate_activations(activations, tokens, matrix.in_features)?;
3153        let root = &self.ranks[0];
3154        let output_len = tokens
3155            .checked_mul(matrix.out_features)
3156            .ok_or("Step BF16 row output size overflow")?;
3157        let mut reduced = {
3158            let _main = root.gpu.enter_main()?;
3159            root.htod(&vec![0.0f32; output_len])?
3160        };
3161        let blocks_per_rank = PRODUCT_MAX_CARDS / self.ranks.len();
3162        for (rank, blocks) in matrix.ranks.iter().enumerate() {
3163            for (block, resident) in blocks.iter().enumerate() {
3164                let global_block = rank * blocks_per_rank + block;
3165                let input = activation_shard(
3166                    activations,
3167                    tokens,
3168                    matrix.in_features,
3169                    PRODUCT_MAX_CARDS,
3170                    global_block,
3171                );
3172                let partial =
3173                    run_resident_bf16_rank(&self.ranks[rank], resident, &input, tokens, None)?;
3174                let next = {
3175                    let _main = root.gpu.enter_main()?;
3176                    let partial = root.htod(&partial)?;
3177                    let mut next = root.uninit(output_len)?;
3178                    root.add(&reduced, &partial, &mut next, output_len)?;
3179                    next
3180                };
3181                reduced = next;
3182            }
3183        }
3184        let _main = root.gpu.enter_main()?;
3185        root.dtoh(&reduced)
3186    }
3187
3188    /// Native-P2P Step row projection with canonical global K-block reduction.
3189    ///
3190    /// The full activation is uploaded once on the root. Each TP8-sized block is peer-scattered
3191    /// to its owning rank, its BF16 partial is peer-returned to the root, and root-device adds
3192    /// replay the same eight-block order as TP1 and the host-staged oracle.
3193    pub fn step_bf16_row_parallel_resident_native(
3194        &self,
3195        matrix: &ResidentStepBf16RowParallel,
3196        activations: &[f32],
3197        tokens: usize,
3198    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
3199        if self.ranks.len() > 1 && !self.native_p2p {
3200            return Err("native Step BF16 row parallelism requires P2P ranks".into());
3201        }
3202        validate_step_bf16_row_residency(&self.ranks, matrix)?;
3203        validate_activations(activations, tokens, matrix.in_features)?;
3204        let root = &self.ranks[0];
3205        let root_input = {
3206            let _main = root.gpu.enter_main()?;
3207            root.htod(activations)?
3208        };
3209        // PRODUCER FENCE (2026-08-20 flake fix): the non-bulk arm below peer-reads root_input
3210        // from the other ranks' streams while root's clone_htod may still be in flight.
3211        {
3212            let _main = root.gpu.enter_main()?;
3213            root.stream().synchronize()?;
3214        }
3215        let reduced = self.step_bf16_row_native_reduce_from_root(matrix, &root_input, tokens)?;
3216        let _main = root.gpu.enter_main()?;
3217        root.dtoh(&reduced)
3218    }
3219
3220    /// Device-input twin of [`Self::step_bf16_row_parallel_resident_native`] (lane/
3221    /// hermes-perf-fixes, 2026-08-23): the full activation arrives as a ROOT-DEVICE buffer
3222    /// and the reduced output stays root-resident — no DtoH of the attention output, no
3223    /// host O staging, no re-upload. Byte-identical to the host-canonical arm by
3224    /// construction (same block scatter, kernels, and global TP8 reduction order; the root
3225    /// bytes are dtod-copied where the host arm htod'd the same bytes). Caller must have
3226    /// synchronized the producer stream; the root stream is synchronized before returning.
3227    pub fn step_bf16_row_parallel_resident_native_device(
3228        &self,
3229        matrix: &ResidentStepBf16RowParallel,
3230        root_activation: &CudaSlice<f32>,
3231        tokens: usize,
3232    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
3233        if self.ranks.len() > 1 && !self.native_p2p {
3234            return Err("native Step BF16 row parallelism requires P2P ranks".into());
3235        }
3236        validate_step_bf16_row_residency(&self.ranks, matrix)?;
3237        let values = tokens
3238            .checked_mul(matrix.in_features)
3239            .ok_or("device Step BF16 row activation size overflow")?;
3240        let root = &self.ranks[0];
3241        if tokens == 0
3242            || root_activation.len() < values
3243            || root_activation.ordinal() != root.ctx().ordinal()
3244        {
3245            return Err("device Step BF16 row root activation geometry mismatch".into());
3246        }
3247        let root_input = {
3248            let _main = root.gpu.enter_main()?;
3249            let mut root_input = root.uninit(values)?;
3250            root.stream()
3251                .memcpy_dtod(&root_activation.slice(0..values), &mut root_input)?;
3252            root.stream().synchronize()?; // producer fence, as the host-input twin
3253            root_input
3254        };
3255        let reduced = self.step_bf16_row_native_reduce_from_root(matrix, &root_input, tokens)?;
3256        let _main = root.gpu.enter_main()?;
3257        root.stream().synchronize()?;
3258        Ok(reduced)
3259    }
3260
3261    /// Shared core of the two native Step row arms above: block scatter + rank GEMMs +
3262    /// canonical global TP8-order root reduction, from a root-resident input, returning the
3263    /// root-resident reduced output. Extracted verbatim so the host and device twins cannot
3264    /// drift numerically.
3265    fn step_bf16_row_native_reduce_from_root(
3266        &self,
3267        matrix: &ResidentStepBf16RowParallel,
3268        root_input: &CudaSlice<f32>,
3269        tokens: usize,
3270    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
3271        let root = &self.ranks[0];
3272        let output_len = tokens
3273            .checked_mul(matrix.out_features)
3274            .ok_or("native Step BF16 row output size overflow")?;
3275        let mut reduced = {
3276            let _main = root.gpu.enter_main()?;
3277            root.htod(&vec![0.0f32; output_len])?
3278        };
3279        let blocks_per_rank = PRODUCT_MAX_CARDS / self.ranks.len();
3280        let mut block_input_keepalive = Vec::with_capacity(PRODUCT_MAX_CARDS);
3281        let mut root_packed_keepalive = Vec::with_capacity(PRODUCT_MAX_CARDS);
3282        let mut remote_partial_keepalive = Vec::new();
3283        for (rank, blocks) in matrix.ranks.iter().enumerate() {
3284            for (block, resident) in blocks.iter().enumerate() {
3285                let global_block = rank * blocks_per_rank + block;
3286                let col_start = global_block * matrix.canonical_chunk_cols;
3287                let block_len = tokens
3288                    .checked_mul(matrix.canonical_chunk_cols)
3289                    .ok_or("native Step BF16 row block size overflow")?;
3290                let block_input = if self.bulk_p2p {
3291                    let root_packed = {
3292                        let _main = root.gpu.enter_main()?;
3293                        let mut root_packed = root.uninit(block_len)?;
3294                        root.copy_rows_strided(
3295                            &root_input,
3296                            &mut root_packed,
3297                            matrix.canonical_chunk_cols,
3298                            tokens,
3299                            matrix.in_features,
3300                            col_start,
3301                        )?;
3302                        root_packed
3303                    };
3304                    if rank == 0 {
3305                        root_packed
3306                    } else {
3307                        // PRODUCER FENCE (2026-08-20 flake fix): the pack kernel runs on the
3308                        // root stream; this rank's peer read must not overtake it.
3309                        {
3310                            let _main = root.gpu.enter_main()?;
3311                            root.stream().synchronize()?;
3312                        }
3313                        let engine = &self.ranks[rank];
3314                        let _main = engine.gpu.enter_main()?;
3315                        let mut block_input = engine.uninit(block_len)?;
3316                        engine
3317                            .stream()
3318                            .memcpy_dtod(&root_packed, &mut block_input)?;
3319                        root_packed_keepalive.push(root_packed);
3320                        block_input
3321                    }
3322                } else {
3323                    let engine = &self.ranks[rank];
3324                    let _main = engine.gpu.enter_main()?;
3325                    let mut block_input = engine.uninit(block_len)?;
3326                    for token in 0..tokens {
3327                        let source_start = token * matrix.in_features + col_start;
3328                        let source = root_input
3329                            .slice(source_start..source_start + matrix.canonical_chunk_cols);
3330                        let destination_start = token * matrix.canonical_chunk_cols;
3331                        let mut destination = block_input.slice_mut(
3332                            destination_start..destination_start + matrix.canonical_chunk_cols,
3333                        );
3334                        engine.stream().memcpy_dtod(&source, &mut destination)?;
3335                    }
3336                    block_input
3337                };
3338                let partial = run_resident_bf16_rank_device(
3339                    &self.ranks[rank],
3340                    resident,
3341                    &block_input,
3342                    tokens,
3343                    None,
3344                    self.bulk_p2p,
3345                )?;
3346                block_input_keepalive.push(block_input);
3347                let root_partial = if rank == 0 {
3348                    partial
3349                } else {
3350                    // PRODUCER FENCE (2026-08-20 flake fix): the partial was produced by this
3351                    // rank's kernel on its own stream; root's peer read must not overtake it.
3352                    {
3353                        let engine = &self.ranks[rank];
3354                        let _main = engine.gpu.enter_main()?;
3355                        engine.stream().synchronize()?;
3356                    }
3357                    let _main = root.gpu.enter_main()?;
3358                    let mut peer_partial = root.uninit(output_len)?;
3359                    root.stream().memcpy_dtod(&partial, &mut peer_partial)?;
3360                    remote_partial_keepalive.push(partial);
3361                    peer_partial
3362                };
3363                let next = {
3364                    let _main = root.gpu.enter_main()?;
3365                    let mut next = root.uninit(output_len)?;
3366                    root.add(&reduced, &root_partial, &mut next, output_len)?;
3367                    next
3368                };
3369                reduced = next;
3370            }
3371        }
3372        {
3373            let _main = root.gpu.enter_main()?;
3374            root.stream().synchronize()?;
3375        }
3376        drop(remote_partial_keepalive);
3377        drop(root_packed_keepalive);
3378        drop(block_input_keepalive);
3379        Ok(reduced)
3380    }
3381
3382    /// Reduce rank-local Step attention shards in canonical TP8 K-block order and keep the result
3383    /// on the root device.
3384    pub fn step_bf16_row_parallel_resident_root_device(
3385        &self,
3386        matrix: &ResidentStepBf16RowParallel,
3387        rank_activations: &[CudaSlice<f32>],
3388        tokens: usize,
3389    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
3390        if self.ranks.len() > 1 && !self.native_p2p {
3391            return Err(
3392                "device-resident Step BF16 row parallelism requires native P2P ranks".into(),
3393            );
3394        }
3395        validate_step_bf16_row_residency(&self.ranks, matrix)?;
3396        let local_width = matrix.in_features / self.ranks.len();
3397        let shard_len = tokens
3398            .checked_mul(local_width)
3399            .ok_or("device Step BF16 row shard size overflow")?;
3400        if tokens == 0
3401            || rank_activations.len() != self.ranks.len()
3402            || rank_activations
3403                .iter()
3404                .zip(&self.ranks)
3405                .any(|(rows, engine)| {
3406                    rows.len() != shard_len || rows.ordinal() != engine.ctx().ordinal()
3407                })
3408        {
3409            return Err("device Step BF16 row activation shard geometry changed".into());
3410        }
3411
3412        let blocks_per_rank = PRODUCT_MAX_CARDS / self.ranks.len();
3413        let mut block_inputs = Vec::with_capacity(self.ranks.len());
3414        let mut partials = Vec::with_capacity(self.ranks.len());
3415        for (rank, blocks) in matrix.ranks.iter().enumerate() {
3416            if blocks.len() != blocks_per_rank {
3417                return Err(format!(
3418                    "device Step BF16 row rank {rank} blocks {} != {blocks_per_rank}",
3419                    blocks.len()
3420                )
3421                .into());
3422            }
3423            let engine = &self.ranks[rank];
3424            let _main = engine.gpu.enter_main()?;
3425            let mut rank_inputs = Vec::with_capacity(blocks_per_rank);
3426            let mut rank_partials = Vec::with_capacity(blocks_per_rank);
3427            for (block, resident) in blocks.iter().enumerate() {
3428                let block_len = tokens
3429                    .checked_mul(matrix.canonical_chunk_cols)
3430                    .ok_or("device Step BF16 row block size overflow")?;
3431                let mut block_input = engine.uninit(block_len)?;
3432                let local_col_start = block * matrix.canonical_chunk_cols;
3433                if self.bulk_p2p {
3434                    engine.copy_rows_strided(
3435                        &rank_activations[rank],
3436                        &mut block_input,
3437                        matrix.canonical_chunk_cols,
3438                        tokens,
3439                        local_width,
3440                        local_col_start,
3441                    )?;
3442                } else {
3443                    for token in 0..tokens {
3444                        let source_start = token * local_width + local_col_start;
3445                        let source = rank_activations[rank]
3446                            .slice(source_start..source_start + matrix.canonical_chunk_cols);
3447                        let destination_start = token * matrix.canonical_chunk_cols;
3448                        let mut destination = block_input.slice_mut(
3449                            destination_start..destination_start + matrix.canonical_chunk_cols,
3450                        );
3451                        engine.stream().memcpy_dtod(&source, &mut destination)?;
3452                    }
3453                }
3454                let partial = run_resident_bf16_rank_device(
3455                    engine,
3456                    resident,
3457                    &block_input,
3458                    tokens,
3459                    None,
3460                    self.bulk_p2p,
3461                )?;
3462                rank_inputs.push(block_input);
3463                rank_partials.push(partial);
3464            }
3465            block_inputs.push(rank_inputs);
3466            partials.push(rank_partials);
3467        }
3468        for engine in self.ranks.iter().skip(1) {
3469            let _main = engine.gpu.enter_main()?;
3470            engine.stream().synchronize()?;
3471        }
3472
3473        let output_len = tokens
3474            .checked_mul(matrix.out_features)
3475            .ok_or("device Step BF16 row output size overflow")?;
3476        let root = &self.ranks[0];
3477        let _main = root.gpu.enter_main()?;
3478        let mut reduced = root.htod(&vec![0.0f32; output_len])?;
3479        let mut remote_partials = Vec::new();
3480        for (rank, rank_partials) in partials.into_iter().enumerate() {
3481            for partial in rank_partials {
3482                let root_partial = if rank == 0 {
3483                    partial
3484                } else {
3485                    let mut peer_partial = root.uninit(output_len)?;
3486                    root.stream().memcpy_dtod(&partial, &mut peer_partial)?;
3487                    remote_partials.push(partial);
3488                    peer_partial
3489                };
3490                let mut next = root.uninit(output_len)?;
3491                root.add(&reduced, &root_partial, &mut next, output_len)?;
3492                reduced = next;
3493            }
3494        }
3495        root.stream().synchronize()?;
3496        drop(remote_partials);
3497        drop(block_inputs);
3498        Ok(reduced)
3499    }
3500
3501    /// Reduce rank-local Step attention shards, then replicate the canonical root result.
3502    pub fn step_bf16_row_parallel_resident_replicated_device(
3503        &self,
3504        matrix: &ResidentStepBf16RowParallel,
3505        rank_activations: &[CudaSlice<f32>],
3506        tokens: usize,
3507    ) -> Result<ResidentReplicatedDeviceRows, Box<dyn std::error::Error>> {
3508        let reduced =
3509            self.step_bf16_row_parallel_resident_root_device(matrix, rank_activations, tokens)?;
3510        let output_len = tokens
3511            .checked_mul(matrix.out_features)
3512            .ok_or("device Step BF16 row output size overflow")?;
3513        let mut ranks = Vec::with_capacity(self.ranks.len());
3514        ranks.push(reduced);
3515        for engine in self.ranks.iter().skip(1) {
3516            let _main = engine.gpu.enter_main()?;
3517            let mut peer_output = engine.uninit(output_len)?;
3518            engine.stream().memcpy_dtod(&ranks[0], &mut peer_output)?;
3519            ranks.push(peer_output);
3520        }
3521        Ok(ResidentReplicatedDeviceRows {
3522            ranks,
3523            tokens,
3524            width: matrix.out_features,
3525        })
3526    }
3527
3528    pub fn upload_expert(
3529        &self,
3530        gate: E4m3BlockMatrix<'_>,
3531        up: E4m3BlockMatrix<'_>,
3532        down: E4m3BlockMatrix<'_>,
3533    ) -> Result<ResidentTpExpert, Box<dyn std::error::Error>> {
3534        if gate.in_features != up.in_features || gate.out_features != up.out_features {
3535            return Err("TP expert gate/up dimensions differ".into());
3536        }
3537        if down.in_features != gate.out_features || down.out_features != gate.in_features {
3538            return Err(format!(
3539                "TP expert down {}x{} does not invert gate/up {}x{}",
3540                down.out_features, down.in_features, gate.out_features, gate.in_features
3541            )
3542            .into());
3543        }
3544        Ok(ResidentTpExpert {
3545            gate: self.upload_column_parallel(gate)?,
3546            up: self.upload_column_parallel(up)?,
3547            down: self.upload_row_parallel(down)?,
3548            input_width: gate.in_features,
3549            expert_width: gate.out_features,
3550        })
3551    }
3552
3553    pub fn run_expert(
3554        &self,
3555        expert: &ResidentTpExpert,
3556        input: &[f32],
3557        tokens: usize,
3558    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
3559        validate_activations(input, tokens, expert.input_width)?;
3560        let gate = self.column_parallel_resident(&expert.gate, input, tokens)?;
3561        let up = self.column_parallel_resident(&expert.up, input, tokens)?;
3562        let activated: Vec<f32> = gate
3563            .gathered
3564            .iter()
3565            .zip(&up.gathered)
3566            .map(|(&gate, &up)| gate / (1.0 + (-gate).exp()) * up)
3567            .collect();
3568        debug_assert_eq!(activated.len(), tokens * expert.expert_width);
3569        Ok(self
3570            .row_parallel_resident(&expert.down, &activated, tokens)?
3571            .reduced)
3572    }
3573
3574    pub fn upload_expert_parallel(
3575        &self,
3576        gate: E4m3ExpertBank<'_>,
3577        up: E4m3ExpertBank<'_>,
3578        down: E4m3ExpertBank<'_>,
3579    ) -> Result<ResidentExpertParallel, Box<dyn std::error::Error>> {
3580        gate.validate()?;
3581        up.validate()?;
3582        down.validate()?;
3583        if gate.expert_count != up.expert_count || gate.expert_count != down.expert_count {
3584            return Err("EP gate/up/down expert counts differ".into());
3585        }
3586        if gate.in_features != up.in_features || gate.out_features != up.out_features {
3587            return Err("EP gate/up dimensions differ".into());
3588        }
3589        if down.in_features != gate.out_features || down.out_features != gate.in_features {
3590            return Err(format!(
3591                "EP down {}x{} does not invert gate/up {}x{}",
3592                down.out_features, down.in_features, gate.out_features, gate.in_features
3593            )
3594            .into());
3595        }
3596        if gate.expert_count % self.ranks.len() != 0 {
3597            return Err(format!(
3598                "EP expert count {} is not divisible by {} ranks",
3599                gate.expert_count,
3600                self.ranks.len()
3601            )
3602            .into());
3603        }
3604
3605        let per_rank = gate.expert_count / self.ranks.len();
3606        let mut ranks = Vec::with_capacity(self.ranks.len());
3607        for (rank, engine) in self.ranks.iter().enumerate() {
3608            let expert_range = rank * per_rank..(rank + 1) * per_rank;
3609            ranks.push(ResidentEpRank {
3610                gate: upload_expert_bank_rank(engine, gate, expert_range.clone())?,
3611                up: upload_expert_bank_rank(engine, up, expert_range.clone())?,
3612                down: upload_expert_bank_rank(engine, down, expert_range)?,
3613            });
3614        }
3615        Ok(ResidentExpertParallel {
3616            ranks,
3617            expert_count: gate.expert_count,
3618            input_width: gate.in_features,
3619            expert_width: gate.out_features,
3620        })
3621    }
3622
3623    /// Prepare the official Step gate-only grouped-FP8 projection oracle on rank zero.
3624    ///
3625    /// This intentionally does not alter the resident EP path. It owns a full rank-local tensor
3626    /// bank solely so the grouped projection can be compared with the existing per-route oracle
3627    /// without routing, transport, or combine changing underneath it.
3628    #[allow(clippy::too_many_arguments)]
3629    pub fn prepare_step_grouped_fp8_gate(
3630        &self,
3631        gate: E4m3ExpertBank<'_>,
3632        up: E4m3ExpertBank<'_>,
3633        down: E4m3ExpertBank<'_>,
3634        input: &[f32],
3635        tokens: usize,
3636        selected: &[usize],
3637        activation_limit: Option<f32>,
3638    ) -> Result<PreparedStepGroupedFp8Gate, Box<dyn std::error::Error>> {
3639        gate.validate()?;
3640        up.validate()?;
3641        down.validate()?;
3642        validate_step_expert_activation_limit(activation_limit)?;
3643        if gate.expert_count != STEP_GROUPED_FP8_EXPERTS
3644            || up.expert_count != STEP_GROUPED_FP8_EXPERTS
3645            || down.expert_count != STEP_GROUPED_FP8_EXPERTS
3646        {
3647            return Err(format!(
3648                "official Step grouped FP8 gate requires {STEP_GROUPED_FP8_EXPERTS} experts, \
3649                 got gate/up/down={}/{}/{}",
3650                gate.expert_count, up.expert_count, down.expert_count,
3651            )
3652            .into());
3653        }
3654        if gate.in_features != up.in_features
3655            || gate.out_features != STEP_GROUPED_FP8_WIDTH
3656            || up.out_features != STEP_GROUPED_FP8_WIDTH
3657            || down.in_features != STEP_GROUPED_FP8_WIDTH
3658            || down.out_features != gate.in_features
3659        {
3660            return Err(format!(
3661                "official Step grouped FP8 geometry gate={}x{} up={}x{} down={}x{}",
3662                gate.out_features,
3663                gate.in_features,
3664                up.out_features,
3665                up.in_features,
3666                down.out_features,
3667                down.in_features,
3668            )
3669            .into());
3670        }
3671        validate_activations(input, tokens, gate.in_features)?;
3672        let pairs = tokens
3673            .checked_mul(STEP_GROUPED_FP8_TOP_K)
3674            .ok_or("official Step grouped FP8 route count overflow")?;
3675        if selected.len() != pairs {
3676            return Err(format!(
3677                "official Step grouped FP8 routes {} != {tokens}x{STEP_GROUPED_FP8_TOP_K} \
3678                 ({pairs})",
3679                selected.len()
3680            )
3681            .into());
3682        }
3683        for (token, routes) in selected.chunks_exact(STEP_GROUPED_FP8_TOP_K).enumerate() {
3684            let mut unique = routes.to_vec();
3685            unique.sort_unstable();
3686            unique.dedup();
3687            if unique.len() != STEP_GROUPED_FP8_TOP_K {
3688                return Err(format!(
3689                    "official Step grouped FP8 token {token} routes are not top-8 unique: \
3690                     {routes:?}"
3691                )
3692                .into());
3693            }
3694        }
3695
3696        let engine = self
3697            .ranks
3698            .first()
3699            .ok_or("official Step grouped FP8 gate has no rank-zero engine")?;
3700        let _main = engine.gpu.enter_main()?;
3701        let expert_range = 0..STEP_GROUPED_FP8_EXPERTS;
3702        let gate = upload_expert_bank_rank(engine, gate, expert_range.clone())?;
3703        let up = upload_expert_bank_rank(engine, up, expert_range.clone())?;
3704        let down = upload_expert_bank_rank(engine, down, expert_range)?;
3705        let input = engine.htod(input)?;
3706        let route_csr = ExpertCsr::from_token_routes(
3707            STEP_GROUPED_FP8_EXPERTS,
3708            tokens,
3709            STEP_GROUPED_FP8_TOP_K,
3710            selected,
3711        )?
3712        .upload(engine)?;
3713        let pair_rows = (0..pairs).collect::<Vec<_>>();
3714        let down_csr =
3715            ExpertCsr::from_pair_rows(STEP_GROUPED_FP8_EXPERTS, pairs, selected, &pair_rows)?
3716                .upload(engine)?;
3717        let gate_workspace =
3718            Fp8GroupedWorkspace::new(engine, gate.in_features, gate.out_features, tokens, pairs)?;
3719        let up_workspace =
3720            Fp8GroupedWorkspace::new(engine, up.in_features, up.out_features, tokens, pairs)?;
3721        let down_workspace =
3722            Fp8GroupedWorkspace::new(engine, down.in_features, down.out_features, pairs, pairs)?;
3723        let activation = engine.uninit(pairs * STEP_GROUPED_FP8_WIDTH)?;
3724        Ok(PreparedStepGroupedFp8Gate {
3725            device: engine.ctx().ordinal(),
3726            gate,
3727            up,
3728            down,
3729            input,
3730            route_csr,
3731            down_csr,
3732            gate_workspace,
3733            up_workspace,
3734            down_workspace,
3735            activation,
3736            activation_limit,
3737            tokens,
3738            pairs,
3739        })
3740    }
3741
3742    /// Execute one prepared gate/up/activation/down projection sequence on rank zero.
3743    pub fn run_step_grouped_fp8_gate(
3744        &self,
3745        plan: &mut PreparedStepGroupedFp8Gate,
3746    ) -> Result<StepGroupedFp8ProjectionOutput, Box<dyn std::error::Error>> {
3747        let engine = self
3748            .ranks
3749            .first()
3750            .ok_or("official Step grouped FP8 gate has no rank-zero engine")?;
3751        if engine.ctx().ordinal() != plan.device {
3752            return Err(format!(
3753                "official Step grouped FP8 plan device {} != rank-zero device {}",
3754                plan.device,
3755                engine.ctx().ordinal()
3756            )
3757            .into());
3758        }
3759        let _main = engine.gpu.enter_main()?;
3760
3761        plan.gate_workspace.quantize(engine, &plan.input)?;
3762        plan.gate_workspace.project(
3763            engine,
3764            &plan.gate.codes,
3765            &plan.gate.scales,
3766            &plan.route_csr,
3767            plan.gate.code_stride,
3768            plan.gate.scale_stride,
3769            1.0,
3770        )?;
3771        plan.up_workspace.quantize(engine, &plan.input)?;
3772        plan.up_workspace.project(
3773            engine,
3774            &plan.up.codes,
3775            &plan.up.scales,
3776            &plan.route_csr,
3777            plan.up.code_stride,
3778            plan.up.scale_stride,
3779            1.0,
3780        )?;
3781        if let Some(limit) = plan.activation_limit {
3782            engine.silu_clamped_mul_host_expf(
3783                plan.gate_workspace.output(),
3784                plan.up_workspace.output(),
3785                limit,
3786                &mut plan.activation,
3787                plan.pairs * STEP_GROUPED_FP8_WIDTH,
3788            )?;
3789        } else {
3790            engine.silu_mul_host_expf(
3791                plan.gate_workspace.output(),
3792                plan.up_workspace.output(),
3793                &mut plan.activation,
3794                plan.pairs * STEP_GROUPED_FP8_WIDTH,
3795            )?;
3796        }
3797        plan.down_workspace.quantize(engine, &plan.activation)?;
3798        plan.down_workspace.project(
3799            engine,
3800            &plan.down.codes,
3801            &plan.down.scales,
3802            &plan.down_csr,
3803            plan.down.code_stride,
3804            plan.down.scale_stride,
3805            1.0,
3806        )?;
3807
3808        Ok(StepGroupedFp8ProjectionOutput {
3809            gate: engine.dtoh(plan.gate_workspace.output())?,
3810            up: engine.dtoh(plan.up_workspace.output())?,
3811            down: engine.dtoh(plan.down_workspace.output())?,
3812        })
3813    }
3814
3815    pub fn prepare_step_grouped_expert_parallel_gate(
3816        &self,
3817        experts: &ResidentExpertParallel,
3818        input: &[f32],
3819        tokens: usize,
3820        selected: &[usize],
3821        activation_limit: Option<f32>,
3822    ) -> Result<PreparedStepGroupedExpertParallelGate, Box<dyn std::error::Error>> {
3823        self.prepare_step_grouped_expert_parallel_gate_with_capacity(
3824            experts,
3825            input,
3826            tokens,
3827            selected,
3828            activation_limit,
3829            tokens,
3830        )
3831    }
3832
3833    #[allow(clippy::too_many_arguments)]
3834    pub fn prepare_step_grouped_expert_parallel_gate_with_capacity(
3835        &self,
3836        experts: &ResidentExpertParallel,
3837        input: &[f32],
3838        tokens: usize,
3839        selected: &[usize],
3840        activation_limit: Option<f32>,
3841        max_tokens: usize,
3842    ) -> Result<PreparedStepGroupedExpertParallelGate, Box<dyn std::error::Error>> {
3843        if !self.native_p2p || !self.ep_device_arithmetic {
3844            return Err(
3845                "Step owner-grouped FP8 requires native P2P and device-resident arithmetic".into(),
3846            );
3847        }
3848        validate_step_expert_activation_limit(activation_limit)?;
3849        validate_ep_residency(&self.ranks, experts)?;
3850        validate_activations(input, tokens, experts.input_width)?;
3851        if max_tokens < tokens || max_tokens > i32::MAX as usize {
3852            return Err(format!(
3853                "official Step owner-grouped FP8 tokens {tokens} exceed capacity {max_tokens}"
3854            )
3855            .into());
3856        }
3857        if experts.expert_count != STEP_GROUPED_FP8_EXPERTS
3858            || experts.expert_width != STEP_GROUPED_FP8_WIDTH
3859        {
3860            return Err(format!(
3861                "official Step owner-grouped FP8 requires {} experts at width {}, got {} at {}",
3862                STEP_GROUPED_FP8_EXPERTS,
3863                STEP_GROUPED_FP8_WIDTH,
3864                experts.expert_count,
3865                experts.expert_width,
3866            )
3867            .into());
3868        }
3869        validate_step_grouped_owner_routes(experts.expert_count, tokens, selected)?;
3870        let max_pairs = max_tokens
3871            .checked_mul(STEP_GROUPED_FP8_TOP_K)
3872            .ok_or("official Step owner-grouped FP8 capacity route count overflow")?;
3873        let input_capacity = max_tokens
3874            .checked_mul(experts.input_width)
3875            .ok_or("official Step owner-grouped FP8 input capacity overflow")?;
3876
3877        let mut rank_inputs = Vec::with_capacity(self.ranks.len());
3878        for engine in &self.ranks {
3879            let _main = engine.gpu.enter_main()?;
3880            rank_inputs.push(engine.uninit(input_capacity)?);
3881        }
3882
3883        let mut owners = Vec::with_capacity(self.ranks.len());
3884        for (owner_rank, rank) in experts.ranks.iter().enumerate() {
3885            if rank.gate.expert_range != rank.up.expert_range
3886                || rank.gate.expert_range != rank.down.expert_range
3887            {
3888                return Err(format!(
3889                    "owner-grouped FP8 rank {} gate/up/down expert ranges differ",
3890                    owner_rank
3891                )
3892                .into());
3893            }
3894            let local_experts = rank.gate.expert_range.len();
3895            let engine = &self.ranks[owner_rank];
3896            let _main = engine.gpu.enter_main()?;
3897            let route_csr =
3898                DeviceExpertCsr::with_capacity(engine, local_experts, max_tokens, max_pairs)?;
3899            let down_csr =
3900                DeviceExpertCsr::with_capacity(engine, local_experts, max_pairs, max_pairs)?;
3901            let gate_workspace = Fp8GroupedWorkspace::new(
3902                engine,
3903                experts.input_width,
3904                experts.expert_width,
3905                max_tokens,
3906                max_pairs,
3907            )?;
3908            let up_workspace = Fp8GroupedWorkspace::new(
3909                engine,
3910                experts.input_width,
3911                experts.expert_width,
3912                max_tokens,
3913                max_pairs,
3914            )?;
3915            let down_workspace = Fp8GroupedWorkspace::new(
3916                engine,
3917                experts.expert_width,
3918                experts.input_width,
3919                max_pairs,
3920                max_pairs,
3921            )?;
3922            let activation = engine.uninit(
3923                max_pairs
3924                    .checked_mul(experts.expert_width)
3925                    .ok_or("official Step owner-grouped FP8 activation capacity overflow")?,
3926            )?;
3927            owners.push(PreparedStepGroupedExpertOwner {
3928                rank: owner_rank,
3929                global_pairs: Vec::new(),
3930                route_csr,
3931                down_csr,
3932                gate_workspace,
3933                up_workspace,
3934                down_workspace,
3935                activation,
3936            });
3937        }
3938
3939        let mut plan = PreparedStepGroupedExpertParallelGate {
3940            rank_inputs,
3941            owners,
3942            activation_limit,
3943            tokens: 0,
3944            pairs: 0,
3945            max_tokens,
3946            max_pairs,
3947            input_width: experts.input_width,
3948            expert_width: experts.expert_width,
3949            generation: 0,
3950            executed_generation: None,
3951            ready: false,
3952        };
3953        self.refresh_step_grouped_expert_parallel_gate(
3954            experts, &mut plan, input, tokens, selected,
3955        )?;
3956        Ok(plan)
3957    }
3958
3959    fn prepare_step_grouped_expert_parallel_refresh(
3960        &self,
3961        experts: &ResidentExpertParallel,
3962        plan: &PreparedStepGroupedExpertParallelGate,
3963        tokens: usize,
3964        selected: &[usize],
3965    ) -> Result<(usize, u64, Vec<Option<StepGroupedExpertOwnerSchedule>>), Box<dyn std::error::Error>>
3966    {
3967        validate_ep_residency(&self.ranks, experts)?;
3968        if plan.rank_inputs.len() != self.ranks.len()
3969            || plan.owners.len() != self.ranks.len()
3970            || plan.input_width != experts.input_width
3971            || plan.expert_width != experts.expert_width
3972            || tokens > plan.max_tokens
3973        {
3974            return Err(format!(
3975                "Step owner-grouped FP8 refresh geometry changed ranks={}/{} owners={}/{} \
3976                 input={}/{} expert={}/{} tokens={}/{}",
3977                plan.rank_inputs.len(),
3978                self.ranks.len(),
3979                plan.owners.len(),
3980                self.ranks.len(),
3981                plan.input_width,
3982                experts.input_width,
3983                plan.expert_width,
3984                experts.expert_width,
3985                tokens,
3986                plan.max_tokens,
3987            )
3988            .into());
3989        }
3990        let pairs = validate_step_grouped_owner_routes(experts.expert_count, tokens, selected)?;
3991        if pairs > plan.max_pairs {
3992            return Err(format!(
3993                "Step owner-grouped FP8 route count {pairs} exceeds capacity {}",
3994                plan.max_pairs
3995            )
3996            .into());
3997        }
3998        let next_generation = plan
3999            .generation
4000            .checked_add(1)
4001            .ok_or("Step owner-grouped FP8 plan generation overflow")?;
4002        let owner_routes = partition_expert_owner_routes(
4003            experts.expert_count,
4004            self.ranks.len(),
4005            tokens,
4006            STEP_GROUPED_FP8_TOP_K,
4007            selected,
4008        )?;
4009        let mut schedules = Vec::with_capacity(self.ranks.len());
4010        for routes in owner_routes {
4011            if routes.selected.is_empty() {
4012                schedules.push(None);
4013                continue;
4014            }
4015            let local_experts = experts.ranks[routes.rank].gate.expert_range.len();
4016            let local_pairs = routes.selected.len();
4017            let route_csr = ExpertCsr::from_pair_rows(
4018                local_experts,
4019                tokens,
4020                &routes.selected,
4021                &routes.token_rows,
4022            )?;
4023            let down_rows = (0..local_pairs).collect::<Vec<_>>();
4024            let down_csr = ExpertCsr::from_pair_rows(
4025                local_experts,
4026                local_pairs,
4027                &routes.selected,
4028                &down_rows,
4029            )?;
4030            schedules.push(Some(StepGroupedExpertOwnerSchedule {
4031                global_pairs: routes.global_pairs,
4032                route_csr,
4033                down_csr,
4034            }));
4035        }
4036        Ok((pairs, next_generation, schedules))
4037    }
4038
4039    fn commit_step_grouped_expert_parallel_refresh(
4040        &self,
4041        plan: &mut PreparedStepGroupedExpertParallelGate,
4042        tokens: usize,
4043        pairs: usize,
4044        next_generation: u64,
4045        schedules: Vec<Option<StepGroupedExpertOwnerSchedule>>,
4046    ) -> Result<(), Box<dyn std::error::Error>> {
4047        for (owner, schedule) in plan.owners.iter_mut().zip(schedules) {
4048            let engine = &self.ranks[owner.rank];
4049            let _main = engine.gpu.enter_main()?;
4050            if let Some(schedule) = schedule {
4051                owner.route_csr.refresh(engine, &schedule.route_csr)?;
4052                owner.down_csr.refresh(engine, &schedule.down_csr)?;
4053                owner.global_pairs = schedule.global_pairs;
4054            } else {
4055                owner.route_csr.clear();
4056                owner.down_csr.clear();
4057                owner.global_pairs.clear();
4058            }
4059        }
4060        plan.tokens = tokens;
4061        plan.pairs = pairs;
4062        plan.generation = next_generation;
4063        plan.ready = true;
4064        Ok(())
4065    }
4066
4067    pub fn refresh_step_grouped_expert_parallel_gate(
4068        &self,
4069        experts: &ResidentExpertParallel,
4070        plan: &mut PreparedStepGroupedExpertParallelGate,
4071        input: &[f32],
4072        tokens: usize,
4073        selected: &[usize],
4074    ) -> Result<(), Box<dyn std::error::Error>> {
4075        validate_activations(input, tokens, experts.input_width)?;
4076        let (pairs, next_generation, schedules) =
4077            self.prepare_step_grouped_expert_parallel_refresh(experts, plan, tokens, selected)?;
4078
4079        plan.ready = false;
4080        plan.executed_generation = None;
4081        {
4082            let root = &self.ranks[0];
4083            let _main = root.gpu.enter_main()?;
4084            let mut destination = plan.rank_inputs[0].slice_mut(0..input.len());
4085            root.stream().memcpy_htod(input, &mut destination)?;
4086            root.stream().synchronize()?;
4087        }
4088        let (root_inputs, peer_inputs) = plan.rank_inputs.split_at_mut(1);
4089        let root_input = &root_inputs[0];
4090        for (rank, peer_input) in peer_inputs.iter_mut().enumerate() {
4091            let engine = &self.ranks[rank + 1];
4092            let _main = engine.gpu.enter_main()?;
4093            let mut destination = peer_input.slice_mut(0..input.len());
4094            engine
4095                .stream()
4096                .memcpy_dtod(&root_input.slice(0..input.len()), &mut destination)?;
4097        }
4098        self.commit_step_grouped_expert_parallel_refresh(
4099            plan,
4100            tokens,
4101            pairs,
4102            next_generation,
4103            schedules,
4104        )
4105    }
4106
4107    /// Refresh routes and inputs from an already-resident rank-zero activation.
4108    ///
4109    /// The caller must order the source producer before this call. The root copy is completed
4110    /// before peer dispatch, while CSR and workspace allocations retain their stable addresses.
4111    pub fn refresh_step_grouped_expert_parallel_gate_from_root_device(
4112        &self,
4113        experts: &ResidentExpertParallel,
4114        plan: &mut PreparedStepGroupedExpertParallelGate,
4115        input: &CudaSlice<f32>,
4116        tokens: usize,
4117        selected: &[usize],
4118    ) -> Result<(), Box<dyn std::error::Error>> {
4119        let input_values = tokens
4120            .checked_mul(experts.input_width)
4121            .ok_or("Step owner-grouped FP8 input size overflow")?;
4122        let root = self
4123            .ranks
4124            .first()
4125            .ok_or("Step owner-grouped FP8 runtime has no root rank")?;
4126        if input.len() < input_values || input.ordinal() != root.ctx().ordinal() {
4127            return Err(format!(
4128                "Step owner-grouped FP8 root input len/device {}/{} does not cover {} values on \
4129                 device {}",
4130                input.len(),
4131                input.ordinal(),
4132                input_values,
4133                root.ctx().ordinal(),
4134            )
4135            .into());
4136        }
4137        let (pairs, next_generation, schedules) =
4138            self.prepare_step_grouped_expert_parallel_refresh(experts, plan, tokens, selected)?;
4139
4140        plan.ready = false;
4141        plan.executed_generation = None;
4142        {
4143            let _main = root.gpu.enter_main()?;
4144            let mut destination = plan.rank_inputs[0].slice_mut(0..input_values);
4145            root.stream()
4146                .memcpy_dtod(&input.slice(0..input_values), &mut destination)?;
4147            root.stream().synchronize()?;
4148        }
4149        let (root_inputs, peer_inputs) = plan.rank_inputs.split_at_mut(1);
4150        let root_input = &root_inputs[0];
4151        for (rank, peer_input) in peer_inputs.iter_mut().enumerate() {
4152            let engine = &self.ranks[rank + 1];
4153            let _main = engine.gpu.enter_main()?;
4154            let mut destination = peer_input.slice_mut(0..input_values);
4155            engine
4156                .stream()
4157                .memcpy_dtod(&root_input.slice(0..input_values), &mut destination)?;
4158        }
4159        self.commit_step_grouped_expert_parallel_refresh(
4160            plan,
4161            tokens,
4162            pairs,
4163            next_generation,
4164            schedules,
4165        )
4166    }
4167
4168    /// Replace a fixed route plan's rank inputs from an already replicated device batch.
4169    ///
4170    /// Route CSR remains unchanged. Advancing the generation invalidates every prior projection
4171    /// and combine result, so callers must refresh combine metadata before executing again.
4172    pub fn refresh_step_grouped_expert_parallel_inputs_from_replicated(
4173        &self,
4174        experts: &ResidentExpertParallel,
4175        plan: &mut PreparedStepGroupedExpertParallelGate,
4176        input: &ResidentReplicatedDeviceRows,
4177    ) -> Result<(), Box<dyn std::error::Error>> {
4178        validate_ep_residency(&self.ranks, experts)?;
4179        validate_replicated_device_rows(&self.ranks, input)?;
4180        if !plan.ready
4181            || input.tokens != plan.tokens
4182            || input.width != plan.input_width
4183            || input.tokens > plan.max_tokens
4184            || plan.rank_inputs.len() != self.ranks.len()
4185            || plan.owners.len() != self.ranks.len()
4186            || plan.input_width != experts.input_width
4187            || plan.expert_width != experts.expert_width
4188        {
4189            return Err("Step owner-grouped replicated input geometry changed".into());
4190        }
4191        let values = input
4192            .tokens
4193            .checked_mul(input.width)
4194            .ok_or("Step owner-grouped replicated input size overflow")?;
4195        let next_generation = plan
4196            .generation
4197            .checked_add(1)
4198            .ok_or("Step owner-grouped FP8 plan generation overflow")?;
4199        plan.ready = false;
4200        plan.executed_generation = None;
4201        for (rank, engine) in self.ranks.iter().enumerate() {
4202            let _main = engine.gpu.enter_main()?;
4203            let mut destination = plan.rank_inputs[rank].slice_mut(0..values);
4204            engine
4205                .stream()
4206                .memcpy_dtod(&input.ranks[rank], &mut destination)?;
4207        }
4208        plan.generation = next_generation;
4209        plan.ready = true;
4210        Ok(())
4211    }
4212
4213    pub fn execute_step_grouped_expert_parallel_gate(
4214        &self,
4215        experts: &ResidentExpertParallel,
4216        plan: &mut PreparedStepGroupedExpertParallelGate,
4217    ) -> Result<(), Box<dyn std::error::Error>> {
4218        validate_ep_residency(&self.ranks, experts)?;
4219        if !plan.ready
4220            || plan.rank_inputs.len() != self.ranks.len()
4221            || plan.owners.len() != self.ranks.len()
4222            || plan.input_width != experts.input_width
4223            || plan.expert_width != experts.expert_width
4224        {
4225            return Err("Step owner-grouped FP8 plan is not ready or its geometry changed".into());
4226        }
4227        plan.executed_generation = None;
4228
4229        for owner in &mut plan.owners {
4230            if owner.global_pairs.is_empty() {
4231                continue;
4232            }
4233            let engine = &self.ranks[owner.rank];
4234            let bank = &experts.ranks[owner.rank];
4235            let _main = engine.gpu.enter_main()?;
4236            let local_pairs = owner.global_pairs.len();
4237            owner.gate_workspace.quantize_for_shape(
4238                engine,
4239                &plan.rank_inputs[owner.rank],
4240                plan.tokens,
4241                local_pairs,
4242            )?;
4243            owner.gate_workspace.project(
4244                engine,
4245                &bank.gate.codes,
4246                &bank.gate.scales,
4247                &owner.route_csr,
4248                bank.gate.code_stride,
4249                bank.gate.scale_stride,
4250                1.0,
4251            )?;
4252            owner.up_workspace.quantize_for_shape(
4253                engine,
4254                &plan.rank_inputs[owner.rank],
4255                plan.tokens,
4256                local_pairs,
4257            )?;
4258            owner.up_workspace.project(
4259                engine,
4260                &bank.up.codes,
4261                &bank.up.scales,
4262                &owner.route_csr,
4263                bank.up.code_stride,
4264                bank.up.scale_stride,
4265                1.0,
4266            )?;
4267        }
4268        for owner in &mut plan.owners {
4269            if owner.global_pairs.is_empty() {
4270                continue;
4271            }
4272            let engine = &self.ranks[owner.rank];
4273            let _main = engine.gpu.enter_main()?;
4274            let values = owner.global_pairs.len() * plan.expert_width;
4275            if let Some(limit) = plan.activation_limit {
4276                engine.silu_clamped_mul_host_expf(
4277                    owner.gate_workspace.output(),
4278                    owner.up_workspace.output(),
4279                    limit,
4280                    &mut owner.activation,
4281                    values,
4282                )?;
4283            } else {
4284                engine.silu_mul_host_expf(
4285                    owner.gate_workspace.output(),
4286                    owner.up_workspace.output(),
4287                    &mut owner.activation,
4288                    values,
4289                )?;
4290            }
4291        }
4292        for owner in &mut plan.owners {
4293            if owner.global_pairs.is_empty() {
4294                continue;
4295            }
4296            let engine = &self.ranks[owner.rank];
4297            let bank = &experts.ranks[owner.rank];
4298            let _main = engine.gpu.enter_main()?;
4299            let local_pairs = owner.global_pairs.len();
4300            owner.down_workspace.quantize_for_shape(
4301                engine,
4302                &owner.activation,
4303                local_pairs,
4304                local_pairs,
4305            )?;
4306            owner.down_workspace.project(
4307                engine,
4308                &bank.down.codes,
4309                &bank.down.scales,
4310                &owner.down_csr,
4311                bank.down.code_stride,
4312                bank.down.scale_stride,
4313                1.0,
4314            )?;
4315        }
4316        plan.executed_generation = Some(plan.generation);
4317        Ok(())
4318    }
4319
4320    pub fn collect_step_grouped_expert_parallel_gate(
4321        &self,
4322        plan: &PreparedStepGroupedExpertParallelGate,
4323    ) -> Result<StepGroupedFp8ProjectionOutput, Box<dyn std::error::Error>> {
4324        if !plan.ready || plan.executed_generation != Some(plan.generation) {
4325            return Err("Step owner-grouped FP8 projection is stale or has not executed".into());
4326        }
4327        let mut gate = vec![0.0f32; plan.pairs * plan.expert_width];
4328        let mut up = vec![0.0f32; plan.pairs * plan.expert_width];
4329        let mut down = vec![0.0f32; plan.pairs * plan.input_width];
4330        for owner in &plan.owners {
4331            if owner.global_pairs.is_empty() {
4332                continue;
4333            }
4334            let engine = &self.ranks[owner.rank];
4335            let _main = engine.gpu.enter_main()?;
4336            let owner_gate = engine.dtoh_view(
4337                &owner
4338                    .gate_workspace
4339                    .output()
4340                    .slice(0..owner.gate_workspace.output_len()),
4341            )?;
4342            let owner_up = engine.dtoh_view(
4343                &owner
4344                    .up_workspace
4345                    .output()
4346                    .slice(0..owner.up_workspace.output_len()),
4347            )?;
4348            let owner_down = engine.dtoh_view(
4349                &owner
4350                    .down_workspace
4351                    .output()
4352                    .slice(0..owner.down_workspace.output_len()),
4353            )?;
4354            for (local_pair, &global_pair) in owner.global_pairs.iter().enumerate() {
4355                let local_expert = local_pair * plan.expert_width;
4356                let global_expert = global_pair * plan.expert_width;
4357                gate[global_expert..global_expert + plan.expert_width]
4358                    .copy_from_slice(&owner_gate[local_expert..local_expert + plan.expert_width]);
4359                up[global_expert..global_expert + plan.expert_width]
4360                    .copy_from_slice(&owner_up[local_expert..local_expert + plan.expert_width]);
4361
4362                let local_hidden = local_pair * plan.input_width;
4363                let global_hidden = global_pair * plan.input_width;
4364                down[global_hidden..global_hidden + plan.input_width]
4365                    .copy_from_slice(&owner_down[local_hidden..local_hidden + plan.input_width]);
4366            }
4367        }
4368        Ok(StepGroupedFp8ProjectionOutput { gate, up, down })
4369    }
4370
4371    pub fn run_step_grouped_expert_parallel_gate(
4372        &self,
4373        experts: &ResidentExpertParallel,
4374        plan: &mut PreparedStepGroupedExpertParallelGate,
4375    ) -> Result<StepGroupedFp8ProjectionOutput, Box<dyn std::error::Error>> {
4376        self.execute_step_grouped_expert_parallel_gate(experts, plan)?;
4377        self.collect_step_grouped_expert_parallel_gate(plan)
4378    }
4379
4380    pub fn prepare_step_grouped_expert_parallel_combine(
4381        &self,
4382        plan: &PreparedStepGroupedExpertParallelGate,
4383        route_weights: &[f32],
4384    ) -> Result<PreparedPeerWeightedRouteCombine, Box<dyn std::error::Error>> {
4385        if !self.native_p2p || !self.ep_device_arithmetic || !plan.ready {
4386            return Err(
4387                "Step owner-grouped combine requires a ready native-P2P device plan".into(),
4388            );
4389        }
4390        let owner_pairs = plan
4391            .owners
4392            .iter()
4393            .map(|owner| owner.global_pairs.as_slice())
4394            .collect::<Vec<_>>();
4395        let shape = validate_weighted_route_combine(
4396            plan.input_width,
4397            STEP_GROUPED_FP8_TOP_K,
4398            plan.max_tokens,
4399            plan.tokens,
4400            &owner_pairs,
4401            route_weights,
4402        )?;
4403        if shape.max_pairs != plan.max_pairs {
4404            return Err(format!(
4405                "Step owner-grouped combine capacity {} != projection capacity {}",
4406                shape.max_pairs, plan.max_pairs
4407            )
4408            .into());
4409        }
4410        let root = self
4411            .ranks
4412            .first()
4413            .ok_or("Step owner-grouped combine has no root rank")?;
4414        let slot_values = shape
4415            .max_pairs
4416            .checked_mul(plan.input_width)
4417            .ok_or("Step owner-grouped combine slot capacity overflow")?;
4418        let output_values = plan
4419            .max_tokens
4420            .checked_mul(plan.input_width)
4421            .ok_or("Step owner-grouped combine output capacity overflow")?;
4422        let (root_device, owners, peer_staging, slots, weights, output) = {
4423            let _main = root.gpu.enter_main()?;
4424            let mut owners = Vec::with_capacity(plan.owners.len());
4425            for _ in &plan.owners {
4426                owners.push(PreparedPeerWeightedRouteOwner {
4427                    token_rows: root.htod_i32(&vec![0; shape.max_pairs])?,
4428                    slots: root.htod_i32(&vec![0; shape.max_pairs])?,
4429                    weights: root.htod(&vec![0.0; shape.max_pairs])?,
4430                    active_pairs: 0,
4431                });
4432            }
4433            (
4434                root.ctx().ordinal(),
4435                owners,
4436                root.uninit(slot_values)?,
4437                root.uninit(slot_values)?,
4438                root.uninit(shape.max_pairs)?,
4439                root.uninit(output_values)?,
4440            )
4441        };
4442        let mut peer_devices = Vec::with_capacity(self.ranks.len().saturating_sub(1));
4443        let mut peer_outputs = Vec::with_capacity(self.ranks.len().saturating_sub(1));
4444        for engine in self.ranks.iter().skip(1) {
4445            let _main = engine.gpu.enter_main()?;
4446            peer_devices.push(engine.ctx().ordinal());
4447            peer_outputs.push(engine.uninit(output_values)?);
4448        }
4449        let mut combine = PreparedPeerWeightedRouteCombine {
4450            root_device,
4451            owners,
4452            peer_staging,
4453            slots,
4454            weights,
4455            output,
4456            peer_devices,
4457            peer_outputs,
4458            width: plan.input_width,
4459            experts_per_token: STEP_GROUPED_FP8_TOP_K,
4460            max_tokens: plan.max_tokens,
4461            max_pairs: shape.max_pairs,
4462            tokens: 0,
4463            pairs: 0,
4464            projection_generation: 0,
4465            output_generation: None,
4466            broadcast_generation: None,
4467            ready: false,
4468        };
4469        self.refresh_step_grouped_expert_parallel_combine(plan, &mut combine, route_weights)?;
4470        Ok(combine)
4471    }
4472
4473    pub fn refresh_step_grouped_expert_parallel_combine(
4474        &self,
4475        plan: &PreparedStepGroupedExpertParallelGate,
4476        combine: &mut PreparedPeerWeightedRouteCombine,
4477        route_weights: &[f32],
4478    ) -> Result<(), Box<dyn std::error::Error>> {
4479        let output_capacity = combine
4480            .max_tokens
4481            .checked_mul(combine.width)
4482            .ok_or("Step owner-grouped combine output capacity overflow")?;
4483        if !plan.ready
4484            || combine.owners.len() != plan.owners.len()
4485            || combine.peer_devices.len() + 1 != self.ranks.len()
4486            || combine.peer_outputs.len() + 1 != self.ranks.len()
4487            || combine.width != plan.input_width
4488            || combine.experts_per_token != STEP_GROUPED_FP8_TOP_K
4489            || combine.max_tokens != plan.max_tokens
4490            || combine.max_pairs != plan.max_pairs
4491            || combine.output.len() < output_capacity
4492            || combine
4493                .peer_outputs
4494                .iter()
4495                .any(|output| output.len() < output_capacity)
4496        {
4497            return Err("Step owner-grouped combine/projection geometry changed".into());
4498        }
4499        if self
4500            .ranks
4501            .iter()
4502            .skip(1)
4503            .zip(&combine.peer_devices)
4504            .any(|(engine, &device)| engine.ctx().ordinal() != device)
4505        {
4506            return Err("Step owner-grouped combine peer devices changed".into());
4507        }
4508        let owner_pairs = plan
4509            .owners
4510            .iter()
4511            .map(|owner| owner.global_pairs.as_slice())
4512            .collect::<Vec<_>>();
4513        let shape = validate_weighted_route_combine(
4514            combine.width,
4515            combine.experts_per_token,
4516            combine.max_tokens,
4517            plan.tokens,
4518            &owner_pairs,
4519            route_weights,
4520        )?;
4521        if shape.max_pairs != combine.max_pairs {
4522            return Err("Step owner-grouped combine capacity changed during refresh".into());
4523        }
4524        let metadata = owner_pairs
4525            .iter()
4526            .map(|pairs| {
4527                let token_rows = pairs
4528                    .iter()
4529                    .map(|&pair| (pair / combine.experts_per_token) as i32)
4530                    .collect::<Vec<_>>();
4531                let slots = pairs
4532                    .iter()
4533                    .map(|&pair| (pair % combine.experts_per_token) as i32)
4534                    .collect::<Vec<_>>();
4535                let weights = pairs
4536                    .iter()
4537                    .map(|&pair| route_weights[pair])
4538                    .collect::<Vec<_>>();
4539                (token_rows, slots, weights)
4540            })
4541            .collect::<Vec<_>>();
4542
4543        combine.ready = false;
4544        combine.output_generation = None;
4545        combine.broadcast_generation = None;
4546        let root = self
4547            .ranks
4548            .first()
4549            .ok_or("Step owner-grouped combine has no root rank")?;
4550        let _main = root.gpu.enter_main()?;
4551        if root.ctx().ordinal() != combine.root_device {
4552            return Err(format!(
4553                "Step owner-grouped combine root device changed {} != {}",
4554                root.ctx().ordinal(),
4555                combine.root_device
4556            )
4557            .into());
4558        }
4559        for (owner, (token_rows, slots, weights)) in combine.owners.iter_mut().zip(metadata) {
4560            if token_rows.is_empty() {
4561                owner.active_pairs = 0;
4562                continue;
4563            }
4564            root.htod_i32_into(&mut owner.token_rows, &token_rows)?;
4565            root.htod_i32_into(&mut owner.slots, &slots)?;
4566            let mut weight_prefix = owner.weights.slice_mut(0..weights.len());
4567            root.stream().memcpy_htod(&weights, &mut weight_prefix)?;
4568            owner.active_pairs = token_rows.len();
4569        }
4570        combine.tokens = plan.tokens;
4571        combine.pairs = shape.pairs;
4572        combine.projection_generation = plan.generation;
4573        combine.ready = true;
4574        Ok(())
4575    }
4576
4577    pub fn execute_step_grouped_expert_parallel_combine(
4578        &self,
4579        plan: &PreparedStepGroupedExpertParallelGate,
4580        combine: &mut PreparedPeerWeightedRouteCombine,
4581    ) -> Result<(), Box<dyn std::error::Error>> {
4582        if !plan.ready
4583            || plan.executed_generation != Some(plan.generation)
4584            || !combine.ready
4585            || combine.tokens != plan.tokens
4586            || combine.pairs != plan.pairs
4587            || combine.width != plan.input_width
4588            || combine.owners.len() != plan.owners.len()
4589            || combine.projection_generation != plan.generation
4590        {
4591            return Err("Step owner-grouped combine is stale or its geometry changed".into());
4592        }
4593        combine.output_generation = None;
4594        combine.broadcast_generation = None;
4595        for owner in &plan.owners {
4596            if owner.rank == 0 || owner.global_pairs.is_empty() {
4597                continue;
4598            }
4599            let engine = &self.ranks[owner.rank];
4600            let _main = engine.gpu.enter_main()?;
4601            engine.stream().synchronize()?;
4602        }
4603        let root = self
4604            .ranks
4605            .first()
4606            .ok_or("Step owner-grouped combine has no root rank")?;
4607        let _main = root.gpu.enter_main()?;
4608        if root.ctx().ordinal() != combine.root_device {
4609            return Err("Step owner-grouped combine is not resident on the root device".into());
4610        }
4611        for (index, owner) in plan.owners.iter().enumerate() {
4612            let metadata = &combine.owners[index];
4613            if owner.global_pairs.len() != metadata.active_pairs {
4614                return Err(format!(
4615                    "Step owner-grouped combine owner {index} rows {} != metadata {}",
4616                    owner.global_pairs.len(),
4617                    metadata.active_pairs
4618                )
4619                .into());
4620            }
4621            if metadata.active_pairs == 0 {
4622                continue;
4623            }
4624            let values = metadata
4625                .active_pairs
4626                .checked_mul(combine.width)
4627                .ok_or("Step owner-grouped combine peer value count overflow")?;
4628            if owner.rank == 0 {
4629                root.scatter_slot(
4630                    owner.down_workspace.output(),
4631                    &metadata.token_rows,
4632                    &metadata.slots,
4633                    &metadata.weights,
4634                    &mut combine.slots,
4635                    &mut combine.weights,
4636                    combine.width,
4637                    combine.experts_per_token,
4638                    metadata.active_pairs,
4639                )?;
4640            } else {
4641                let source = owner.down_workspace.output().slice(0..values);
4642                let mut destination = combine.peer_staging.slice_mut(0..values);
4643                root.stream().memcpy_dtod(&source, &mut destination)?;
4644                root.scatter_slot(
4645                    &combine.peer_staging,
4646                    &metadata.token_rows,
4647                    &metadata.slots,
4648                    &metadata.weights,
4649                    &mut combine.slots,
4650                    &mut combine.weights,
4651                    combine.width,
4652                    combine.experts_per_token,
4653                    metadata.active_pairs,
4654                )?;
4655            }
4656        }
4657        root.reduce_slots_host(
4658            &combine.slots,
4659            &combine.weights,
4660            &mut combine.output,
4661            combine.width,
4662            combine.experts_per_token,
4663            combine.tokens,
4664        )?;
4665        combine.output_generation = Some(plan.generation);
4666        Ok(())
4667    }
4668
4669    pub fn collect_step_grouped_expert_parallel_combine(
4670        &self,
4671        plan: &PreparedStepGroupedExpertParallelGate,
4672        combine: &PreparedPeerWeightedRouteCombine,
4673    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
4674        if !plan.ready
4675            || combine.output_generation != Some(plan.generation)
4676            || combine.projection_generation != plan.generation
4677        {
4678            return Err("Step owner-grouped combine output is stale or has not executed".into());
4679        }
4680        let root = self
4681            .ranks
4682            .first()
4683            .ok_or("Step owner-grouped combine has no root rank")?;
4684        let _main = root.gpu.enter_main()?;
4685        if root.ctx().ordinal() != combine.root_device {
4686            return Err("Step owner-grouped combine is not resident on the root device".into());
4687        }
4688        root.dtoh_view(&combine.output.slice(0..combine.tokens * combine.width))
4689    }
4690
4691    /// Copy the active root combine result into a caller-owned engine on the same CUDA device.
4692    ///
4693    /// The persistent combine buffer remains reusable by the next route generation; the returned
4694    /// allocation follows the serving runtime's ordinary transient-output ownership.
4695    pub fn copy_step_grouped_expert_parallel_combine_root(
4696        &self,
4697        plan: &PreparedStepGroupedExpertParallelGate,
4698        combine: &PreparedPeerWeightedRouteCombine,
4699        destination: &Engine,
4700    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
4701        if !plan.ready
4702            || combine.output_generation != Some(plan.generation)
4703            || combine.projection_generation != plan.generation
4704        {
4705            return Err("Step owner-grouped combine output is stale or has not executed".into());
4706        }
4707        let root = self
4708            .ranks
4709            .first()
4710            .ok_or("Step owner-grouped combine has no root rank")?;
4711        if root.ctx().ordinal() != combine.root_device
4712            || destination.ctx().ordinal() != combine.root_device
4713        {
4714            return Err(format!(
4715                "Step owner-grouped combine root/destination devices {}/{} != {}",
4716                root.ctx().ordinal(),
4717                destination.ctx().ordinal(),
4718                combine.root_device,
4719            )
4720            .into());
4721        }
4722        let values = combine
4723            .tokens
4724            .checked_mul(combine.width)
4725            .ok_or("Step owner-grouped combine copy size overflow")?;
4726        {
4727            let _main = root.gpu.enter_main()?;
4728            root.stream().synchronize()?;
4729        }
4730        let _main = destination.gpu.enter_main()?;
4731        let mut output = destination.uninit(values)?;
4732        destination
4733            .stream()
4734            .memcpy_dtod(&combine.output.slice(0..values), &mut output)?;
4735        Ok(output)
4736    }
4737
4738    pub fn broadcast_step_grouped_expert_parallel_combine(
4739        &self,
4740        plan: &PreparedStepGroupedExpertParallelGate,
4741        combine: &mut PreparedPeerWeightedRouteCombine,
4742    ) -> Result<(), Box<dyn std::error::Error>> {
4743        if !plan.ready
4744            || combine.output_generation != Some(plan.generation)
4745            || combine.projection_generation != plan.generation
4746            || combine.peer_devices.len() + 1 != self.ranks.len()
4747            || combine.peer_outputs.len() + 1 != self.ranks.len()
4748        {
4749            return Err("Step owner-grouped combine output cannot be broadcast".into());
4750        }
4751        combine.broadcast_generation = None;
4752        let values = combine
4753            .tokens
4754            .checked_mul(combine.width)
4755            .ok_or("Step owner-grouped combine broadcast size overflow")?;
4756        {
4757            let root = self
4758                .ranks
4759                .first()
4760                .ok_or("Step owner-grouped combine has no root rank")?;
4761            let _main = root.gpu.enter_main()?;
4762            if root.ctx().ordinal() != combine.root_device {
4763                return Err("Step owner-grouped combine root device changed".into());
4764            }
4765            root.stream().synchronize()?;
4766        }
4767        let source = &combine.output;
4768        for (index, destination_buffer) in combine.peer_outputs.iter_mut().enumerate() {
4769            let engine = &self.ranks[index + 1];
4770            let _main = engine.gpu.enter_main()?;
4771            if engine.ctx().ordinal() != combine.peer_devices[index] {
4772                return Err(format!(
4773                    "Step owner-grouped combine peer {} device changed",
4774                    index + 1
4775                )
4776                .into());
4777            }
4778            let mut destination = destination_buffer.slice_mut(0..values);
4779            engine
4780                .stream()
4781                .memcpy_dtod(&source.slice(0..values), &mut destination)?;
4782        }
4783        combine.broadcast_generation = Some(plan.generation);
4784        Ok(())
4785    }
4786
4787    pub fn collect_step_grouped_expert_parallel_broadcast(
4788        &self,
4789        plan: &PreparedStepGroupedExpertParallelGate,
4790        combine: &PreparedPeerWeightedRouteCombine,
4791    ) -> Result<Vec<Vec<f32>>, Box<dyn std::error::Error>> {
4792        if !plan.ready
4793            || combine.output_generation != Some(plan.generation)
4794            || combine.broadcast_generation != Some(plan.generation)
4795            || combine.peer_outputs.len() + 1 != self.ranks.len()
4796        {
4797            return Err("Step owner-grouped combine broadcast is stale or incomplete".into());
4798        }
4799        let values = combine
4800            .tokens
4801            .checked_mul(combine.width)
4802            .ok_or("Step owner-grouped combine collection size overflow")?;
4803        let mut outputs = Vec::with_capacity(self.ranks.len());
4804        {
4805            let root = &self.ranks[0];
4806            let _main = root.gpu.enter_main()?;
4807            outputs.push(root.dtoh_view(&combine.output.slice(0..values))?);
4808        }
4809        for (index, output) in combine.peer_outputs.iter().enumerate() {
4810            let engine = &self.ranks[index + 1];
4811            let _main = engine.gpu.enter_main()?;
4812            outputs.push(engine.dtoh_view(&output.slice(0..values))?);
4813        }
4814        Ok(outputs)
4815    }
4816
4817    /// Add routed and replicated shared-expert outputs, then add the attention residual.
4818    pub fn finish_step_grouped_expert_parallel_layer(
4819        &self,
4820        plan: &PreparedStepGroupedExpertParallelGate,
4821        combine: &PreparedPeerWeightedRouteCombine,
4822        shared: &ResidentReplicatedDeviceRows,
4823        residual: &ResidentReplicatedDeviceRows,
4824    ) -> Result<ResidentReplicatedDeviceRows, Box<dyn std::error::Error>> {
4825        validate_replicated_device_rows(&self.ranks, shared)?;
4826        validate_replicated_device_rows(&self.ranks, residual)?;
4827        if !plan.ready
4828            || plan.executed_generation != Some(plan.generation)
4829            || combine.output_generation != Some(plan.generation)
4830            || combine.broadcast_generation != Some(plan.generation)
4831            || combine.projection_generation != plan.generation
4832            || combine.peer_outputs.len() + 1 != self.ranks.len()
4833            || shared.tokens != combine.tokens
4834            || residual.tokens != combine.tokens
4835            || shared.width != combine.width
4836            || residual.width != combine.width
4837        {
4838            return Err("Step full-layer finish inputs are stale or their geometry changed".into());
4839        }
4840        let values = combine
4841            .tokens
4842            .checked_mul(combine.width)
4843            .ok_or("Step full-layer output size overflow")?;
4844        let mut ranks = Vec::with_capacity(self.ranks.len());
4845        for rank in 0..self.ranks.len() {
4846            let engine = &self.ranks[rank];
4847            let _main = engine.gpu.enter_main()?;
4848            let routed = if rank == 0 {
4849                &combine.output
4850            } else {
4851                &combine.peer_outputs[rank - 1]
4852            };
4853            let mut ffn = engine.uninit(values)?;
4854            engine.add(routed, &shared.ranks[rank], &mut ffn, values)?;
4855            let mut output = engine.uninit(values)?;
4856            engine.add(&residual.ranks[rank], &ffn, &mut output, values)?;
4857            ranks.push(output);
4858        }
4859        Ok(ResidentReplicatedDeviceRows {
4860            ranks,
4861            tokens: combine.tokens,
4862            width: combine.width,
4863        })
4864    }
4865
4866    pub fn run_step_grouped_expert_parallel_combine(
4867        &self,
4868        plan: &PreparedStepGroupedExpertParallelGate,
4869        combine: &mut PreparedPeerWeightedRouteCombine,
4870    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
4871        self.execute_step_grouped_expert_parallel_combine(plan, combine)?;
4872        self.collect_step_grouped_expert_parallel_combine(plan, combine)
4873    }
4874
4875    pub fn upload_tensor_parallel(
4876        &self,
4877        gate: E4m3ExpertBank<'_>,
4878        up: E4m3ExpertBank<'_>,
4879        down: E4m3ExpertBank<'_>,
4880    ) -> Result<ResidentTensorParallel, Box<dyn std::error::Error>> {
4881        gate.validate()?;
4882        up.validate()?;
4883        down.validate()?;
4884        if gate.expert_count != up.expert_count || gate.expert_count != down.expert_count {
4885            return Err("TP gate/up/down expert counts differ".into());
4886        }
4887        if gate.in_features != up.in_features || gate.out_features != up.out_features {
4888            return Err("TP gate/up dimensions differ".into());
4889        }
4890        if down.in_features != gate.out_features || down.out_features != gate.in_features {
4891            return Err(format!(
4892                "TP down {}x{} does not invert gate/up {}x{}",
4893                down.out_features, down.in_features, gate.out_features, gate.in_features
4894            )
4895            .into());
4896        }
4897        let tp = self.ranks.len();
4898        validate_column_bank_shape(gate, tp)?;
4899        validate_column_bank_shape(up, tp)?;
4900        validate_row_bank_shape(down, tp)?;
4901
4902        let mut gate_ranks = Vec::with_capacity(tp);
4903        let mut up_ranks = Vec::with_capacity(tp);
4904        let mut down_ranks = Vec::with_capacity(tp);
4905        for (rank, engine) in self.ranks.iter().enumerate() {
4906            gate_ranks.push(upload_column_bank_rank(engine, gate, tp, rank)?);
4907            up_ranks.push(upload_column_bank_rank(engine, up, tp, rank)?);
4908            down_ranks.push(upload_row_bank_rank(engine, down, tp, rank)?);
4909        }
4910        Ok(ResidentTensorParallel {
4911            bank: ResidentTpExpertBank {
4912                gate: gate_ranks,
4913                up: up_ranks,
4914                down: down_ranks,
4915                expert_count: gate.expert_count,
4916                input_width: gate.in_features,
4917                expert_width: gate.out_features,
4918            },
4919        })
4920    }
4921
4922    pub fn run_tensor_parallel_routes(
4923        &self,
4924        experts: &ResidentTensorParallel,
4925        input: &[f32],
4926        tokens: usize,
4927        selected: &[usize],
4928        route_weights: &[f32],
4929        experts_per_token: usize,
4930    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
4931        validate_tp_bank_residency(&self.ranks, &experts.bank)?;
4932        validate_activations(input, tokens, experts.bank.input_width)?;
4933        let pairs = tokens
4934            .checked_mul(experts_per_token)
4935            .ok_or("TP route count overflow")?;
4936        if selected.len() != pairs || route_weights.len() != pairs {
4937            return Err(format!(
4938                "TP routes selected={} weights={} != tokens {tokens} x experts/token \
4939                 {experts_per_token} ({pairs})",
4940                selected.len(),
4941                route_weights.len(),
4942            )
4943            .into());
4944        }
4945        if !route_weights.iter().all(|weight| weight.is_finite()) {
4946            return Err("TP route weights contain a non-finite value".into());
4947        }
4948
4949        let mut output = vec![0.0f32; tokens * experts.bank.input_width];
4950        for token in 0..tokens {
4951            let input_row =
4952                &input[token * experts.bank.input_width..(token + 1) * experts.bank.input_width];
4953            for slot in 0..experts_per_token {
4954                let pair = token * experts_per_token + slot;
4955                let expert = selected[pair];
4956                if expert >= experts.bank.expert_count {
4957                    return Err(format!(
4958                        "TP selected expert {expert} outside 0..{}",
4959                        experts.bank.expert_count
4960                    )
4961                    .into());
4962                }
4963                let down = if self.native_p2p {
4964                    self.run_tensor_parallel_expert_native(&experts.bank, expert, input_row)?
4965                } else {
4966                    let gate =
4967                        self.run_column_bank_expert(&experts.bank.gate, expert, input_row)?;
4968                    let up = self.run_column_bank_expert(&experts.bank.up, expert, input_row)?;
4969                    let activated: Vec<f32> = gate
4970                        .iter()
4971                        .zip(&up)
4972                        .map(|(&gate, &up)| gate / (1.0 + (-gate).exp()) * up)
4973                        .collect();
4974                    debug_assert_eq!(activated.len(), experts.bank.expert_width);
4975                    self.run_row_bank_expert(&experts.bank.down, expert, &activated)?
4976                };
4977                let weight = route_weights[pair];
4978                for (sum, value) in output
4979                    [token * experts.bank.input_width..(token + 1) * experts.bank.input_width]
4980                    .iter_mut()
4981                    .zip(down)
4982                {
4983                    *sum += weight * value;
4984                }
4985            }
4986        }
4987        Ok(output)
4988    }
4989
4990    fn run_column_bank_expert(
4991        &self,
4992        ranks: &[ResidentE4m3ExpertBankRank],
4993        expert: usize,
4994        input: &[f32],
4995    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
4996        let local_out = ranks
4997            .first()
4998            .ok_or("TP column bank has no ranks")?
4999            .out_features;
5000        let mut gathered = vec![0.0f32; local_out * ranks.len()];
5001        for (rank, (engine, bank)) in self.ranks.iter().zip(ranks).enumerate() {
5002            let shard = run_resident_bank_expert(engine, bank, expert, input, 1)?;
5003            gathered[rank * local_out..(rank + 1) * local_out].copy_from_slice(&shard);
5004        }
5005        Ok(gathered)
5006    }
5007
5008    fn run_row_bank_expert(
5009        &self,
5010        ranks: &[ResidentE4m3ExpertBankRank],
5011        expert: usize,
5012        input: &[f32],
5013    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
5014        let local_in = ranks.first().ok_or("TP row bank has no ranks")?.in_features;
5015        if input.len() != local_in * ranks.len() {
5016            return Err(format!(
5017                "TP row input {} != {} ranks x {local_in}",
5018                input.len(),
5019                ranks.len()
5020            )
5021            .into());
5022        }
5023        let out_features = ranks[0].out_features;
5024        let mut reduced = vec![0.0f32; out_features];
5025        for (rank, (engine, bank)) in self.ranks.iter().zip(ranks).enumerate() {
5026            let blocks = bank
5027                .k_blocks
5028                .ok_or("TP row bank is not packed in native K-block order")?;
5029            if blocks * FP8_BLOCK != local_in {
5030                return Err(format!(
5031                    "TP row bank has {blocks} blocks but local input width is {local_in}"
5032                )
5033                .into());
5034            }
5035            for block in 0..blocks {
5036                let global_start = rank * local_in + block * FP8_BLOCK;
5037                let partial = run_resident_bank_expert_block(
5038                    engine,
5039                    bank,
5040                    expert,
5041                    block,
5042                    &input[global_start..global_start + FP8_BLOCK],
5043                )?;
5044                for (sum, value) in reduced.iter_mut().zip(partial) {
5045                    *sum += value;
5046                }
5047            }
5048        }
5049        Ok(reduced)
5050    }
5051
5052    fn run_tensor_parallel_expert_native(
5053        &self,
5054        bank: &ResidentTpExpertBank,
5055        expert: usize,
5056        input: &[f32],
5057    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
5058        if !self.native_p2p || self.ranks.len() < 2 {
5059            return Err("native TP expert execution requires at least two P2P ranks".into());
5060        }
5061        let local_out = bank
5062            .gate
5063            .first()
5064            .ok_or("native TP gate bank has no ranks")?
5065            .out_features;
5066        if local_out * self.ranks.len() != bank.expert_width {
5067            return Err(format!(
5068                "native TP gate shards {}x{local_out} != expert width {}",
5069                self.ranks.len(),
5070                bank.expert_width
5071            )
5072            .into());
5073        }
5074
5075        // The caller's routed input is already host-canonical. Upload once on rank zero, then
5076        // broadcast over peer copies so no other rank receives a host-staged duplicate.
5077        let mut rank_inputs = Vec::with_capacity(self.ranks.len());
5078        let root_input = {
5079            let root = &self.ranks[0];
5080            let _main = root.gpu.enter_main()?;
5081            root.htod(input)?
5082        };
5083        rank_inputs.push(root_input);
5084        for engine in &self.ranks[1..] {
5085            let peer_input = {
5086                let _main = engine.gpu.enter_main()?;
5087                let mut peer_input = engine.uninit(input.len())?;
5088                engine
5089                    .stream()
5090                    .memcpy_dtod(&rank_inputs[0], &mut peer_input)?;
5091                peer_input
5092            };
5093            rank_inputs.push(peer_input);
5094        }
5095
5096        let mut gate_shards = Vec::with_capacity(self.ranks.len());
5097        let mut up_shards = Vec::with_capacity(self.ranks.len());
5098        for rank in 0..self.ranks.len() {
5099            gate_shards.push(run_resident_bank_expert_device(
5100                &self.ranks[rank],
5101                &bank.gate[rank],
5102                expert,
5103                &rank_inputs[rank],
5104                1,
5105            )?);
5106            up_shards.push(run_resident_bank_expert_device(
5107                &self.ranks[rank],
5108                &bank.up[rank],
5109                expert,
5110                &rank_inputs[rank],
5111                1,
5112            )?);
5113        }
5114
5115        // Preserve the established canonical activation program for the first native transport
5116        // milestone. The shards move to rank zero over P2P; only the scalar activation expression
5117        // executes on host. A later device-activation increment must earn its own exactness gate.
5118        let gate = self.gather_native_column_shards(&gate_shards, 1, local_out)?;
5119        let up = self.gather_native_column_shards(&up_shards, 1, local_out)?;
5120        let activated = gate
5121            .iter()
5122            .zip(&up)
5123            .map(|(&gate, &up)| gate / (1.0 + (-gate).exp()) * up)
5124            .collect::<Vec<_>>();
5125        debug_assert_eq!(activated.len(), bank.expert_width);
5126
5127        let root_activated = {
5128            let root = &self.ranks[0];
5129            let _main = root.gpu.enter_main()?;
5130            root.htod(&activated)?
5131        };
5132        let mut rank_activated = Vec::with_capacity(self.ranks.len());
5133        for (rank, engine) in self.ranks.iter().enumerate() {
5134            let start = rank * local_out;
5135            let source = root_activated.slice(start..start + local_out);
5136            let local = {
5137                let _main = engine.gpu.enter_main()?;
5138                let mut local = engine.uninit(local_out)?;
5139                engine.stream().memcpy_dtod(&source, &mut local)?;
5140                local
5141            };
5142            rank_activated.push(local);
5143        }
5144
5145        let out_features = bank
5146            .down
5147            .first()
5148            .ok_or("native TP down bank has no ranks")?
5149            .out_features;
5150        let mut reduced = {
5151            let root = &self.ranks[0];
5152            let _main = root.gpu.enter_main()?;
5153            root.htod(&vec![0.0f32; out_features])?
5154        };
5155        let mut remote_partial_keepalive = Vec::new();
5156        for rank in 0..self.ranks.len() {
5157            let down = &bank.down[rank];
5158            let blocks = down
5159                .k_blocks
5160                .ok_or("native TP row bank is not packed in checkpoint-block order")?;
5161            if blocks * FP8_BLOCK != local_out {
5162                return Err(format!(
5163                    "native TP rank {rank} has {blocks} blocks but local activation width is \
5164                     {local_out}"
5165                )
5166                .into());
5167            }
5168            for block in 0..blocks {
5169                let start = block * FP8_BLOCK;
5170                let input_block = rank_activated[rank].slice(start..start + FP8_BLOCK);
5171                let partial = run_resident_bank_expert_block_device(
5172                    &self.ranks[rank],
5173                    down,
5174                    expert,
5175                    block,
5176                    &input_block,
5177                )?;
5178                let root_partial = if rank == 0 {
5179                    partial
5180                } else {
5181                    let root = &self.ranks[0];
5182                    let _main = root.gpu.enter_main()?;
5183                    let mut peer_partial = root.uninit(out_features)?;
5184                    root.stream().memcpy_dtod(&partial, &mut peer_partial)?;
5185                    remote_partial_keepalive.push(partial);
5186                    peer_partial
5187                };
5188                let next = {
5189                    let root = &self.ranks[0];
5190                    let _main = root.gpu.enter_main()?;
5191                    let mut next = root.uninit(out_features)?;
5192                    root.add(&reduced, &root_partial, &mut next, out_features)?;
5193                    next
5194                };
5195                reduced = next;
5196            }
5197        }
5198        let output = {
5199            let root = &self.ranks[0];
5200            let _main = root.gpu.enter_main()?;
5201            root.dtoh(&reduced)?
5202        };
5203        drop(remote_partial_keepalive);
5204        Ok(output)
5205    }
5206
5207    /// Gather token-major rank-local columns into one canonical root-device matrix.
5208    pub fn gather_native_column_shards_device(
5209        &self,
5210        shards: &[CudaSlice<f32>],
5211        tokens: usize,
5212        local_out: usize,
5213    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
5214        let shard_len = tokens
5215            .checked_mul(local_out)
5216            .ok_or("native TP gather shard size overflow")?;
5217        if shards.len() != self.ranks.len() || shards.iter().any(|shard| shard.len() != shard_len) {
5218            return Err("native TP gather shard geometry mismatch".into());
5219        }
5220        // PRODUCER FENCE (2026-08-20 flake fix): the root stream peer-reads shards produced on
5221        // the other ranks' streams; without fencing those producers the copy can read a partial
5222        // kernel output.
5223        for engine in &self.ranks[1..] {
5224            let _main = engine.gpu.enter_main()?;
5225            engine.stream().synchronize()?;
5226        }
5227        let root = &self.ranks[0];
5228        let _main = root.gpu.enter_main()?;
5229        let global_out = shards
5230            .len()
5231            .checked_mul(local_out)
5232            .ok_or("native TP gather output width overflow")?;
5233        let gathered_len = tokens
5234            .checked_mul(global_out)
5235            .ok_or("native TP gather output size overflow")?;
5236        let mut gathered = root.uninit(gathered_len)?;
5237        if self.bulk_p2p {
5238            root.place_rows_strided(&shards[0], &mut gathered, local_out, tokens, global_out, 0)?;
5239            if shards.len() > 1 {
5240                let mut staging = root.uninit(shard_len)?;
5241                for (rank, shard) in shards.iter().enumerate().skip(1) {
5242                    root.stream().memcpy_dtod(shard, &mut staging)?;
5243                    root.place_rows_strided(
5244                        &staging,
5245                        &mut gathered,
5246                        local_out,
5247                        tokens,
5248                        global_out,
5249                        rank * local_out,
5250                    )?;
5251                }
5252            }
5253        } else {
5254            for token in 0..tokens {
5255                for (rank, shard) in shards.iter().enumerate() {
5256                    let source = shard.slice(token * local_out..(token + 1) * local_out);
5257                    let start = token * global_out + rank * local_out;
5258                    let mut destination = gathered.slice_mut(start..start + local_out);
5259                    root.stream().memcpy_dtod(&source, &mut destination)?;
5260                }
5261            }
5262        }
5263        Ok(gathered)
5264    }
5265
5266    pub fn gather_native_column_shards(
5267        &self,
5268        shards: &[CudaSlice<f32>],
5269        tokens: usize,
5270        local_out: usize,
5271    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
5272        let gathered = self.gather_native_column_shards_device(shards, tokens, local_out)?;
5273        let root = &self.ranks[0];
5274        let _main = root.gpu.enter_main()?;
5275        root.dtoh(&gathered)
5276    }
5277
5278    pub(crate) fn decode_v2_workspace(&self) -> &std::sync::Mutex<Vec<StepTpDecodeV2Ws>> {
5279        &self.decode_v2
5280    }
5281
5282    /// Build the v2 decode-attention workspace for this layer's geometry on first use, or
5283    /// return the index of the matching one. Attention geometry varies across the trunk
5284    /// (per-layer query-head counts), so workspaces are keyed by their geometry pins — a
5285    /// handful exist per model, never one per layer.
5286    ///
5287    /// Refuses non-F32-resident projections: the v2 driver's bit-exactness claim against v1
5288    /// holds per residency class, and only the mirror class has no per-call weight expansion
5289    /// to hide allocation churn behind.
5290    pub(crate) fn decode_v2_ensure(
5291        &self,
5292        e: &Engine,
5293        q_m: &ResidentBf16ColumnParallel,
5294        k_m: &ResidentBf16ColumnParallel,
5295        v_m: &ResidentBf16ColumnParallel,
5296        o_m: &ResidentStepBf16RowParallel,
5297        heads: usize,
5298    ) -> Result<usize, Box<dyn std::error::Error>> {
5299        if self.ranks.len() > 1 && !self.native_p2p {
5300            return Err("step TP decode v2 requires native P2P ranks".into());
5301        }
5302        let ranks = self.ranks.len();
5303        // Residency contract: the canonical-chunk (non-fused) program needs the F32 mirror;
5304        // the fused-kernel door also reads raw checkpoint bf16 directly (halving the weight
5305        // traffic), so bf16 residency is accepted when that door is on.
5306        let fused_door = step_tp_qkv_fused_enabled()?;
5307        let arm_ok = |weight: &ResidentBf16Weight| match weight {
5308            ResidentBf16Weight::F32(_) => true,
5309            ResidentBf16Weight::Bf16(_) => fused_door,
5310        };
5311        for matrix in [q_m, k_m, v_m] {
5312            validate_resident_bf16_ranks(&self.ranks, &matrix.ranks)?;
5313            if matrix.out_features % ranks != 0 || matrix.in_features != q_m.in_features {
5314                return Err("step TP decode v2 QKV geometry mismatch".into());
5315            }
5316            for rank in &matrix.ranks {
5317                if !arm_ok(&rank.weight) {
5318                    return Err("step TP decode v2 requires MEMRA_STEP_TP_F32_MIRROR=1 or \
5319                                MEMRA_STEP_TP_QKV_FUSED=1 (bf16-resident fused kernels)"
5320                        .into());
5321                }
5322            }
5323        }
5324        validate_step_bf16_row_residency(&self.ranks, o_m)?;
5325        for blocks in &o_m.ranks {
5326            for block in blocks {
5327                if !arm_ok(&block.weight) {
5328                    return Err("step TP decode v2 requires MEMRA_STEP_TP_F32_MIRROR=1 or \
5329                                MEMRA_STEP_TP_QKV_FUSED=1 (bf16-resident fused kernels)"
5330                        .into());
5331                }
5332            }
5333        }
5334        if v_m.out_features != k_m.out_features
5335            || o_m.in_features != q_m.out_features
5336            || heads == 0
5337            || heads % ranks != 0
5338        {
5339            return Err("step TP decode v2 K/V/O geometry mismatch".into());
5340        }
5341        let local_q_dim = q_m.out_features / ranks;
5342        let local_kv_dim = k_m.out_features / ranks;
5343        let o_out = o_m.out_features;
5344        let o_block_cols = o_m.canonical_chunk_cols;
5345        let blocks_per_rank = o_m.ranks.first().map(Vec::len).unwrap_or(0);
5346        if blocks_per_rank == 0
5347            || o_m
5348                .ranks
5349                .iter()
5350                .any(|blocks| blocks.len() != blocks_per_rank)
5351            || blocks_per_rank * o_block_cols * ranks != o_m.in_features
5352        {
5353            return Err("step TP decode v2 O canonical block grid mismatch".into());
5354        }
5355
5356        let mut guard = self
5357            .decode_v2
5358            .lock()
5359            .map_err(|_| "step TP decode v2 workspace lock is poisoned")?;
5360        if let Some(index) = guard.iter().position(|ws| {
5361            ws.local_q_dim == local_q_dim
5362                && ws.local_kv_dim == local_kv_dim
5363                && ws.heads == heads
5364                && ws.o_out == o_out
5365                && ws.o_block_cols == o_block_cols
5366                && ws.blocks_per_rank == blocks_per_rank
5367                && ws.e_device == e.ctx().ordinal()
5368                && ws.q.len() == ranks
5369        }) {
5370            return Ok(index);
5371        }
5372
5373        let mut q_raw = Vec::with_capacity(ranks);
5374        let mut k_raw = Vec::with_capacity(ranks);
5375        let mut v_raw = Vec::with_capacity(ranks);
5376        let mut q = Vec::with_capacity(ranks);
5377        let mut k = Vec::with_capacity(ranks);
5378        let mut pos = Vec::with_capacity(ranks);
5379        let mut gate = Vec::with_capacity(ranks);
5380        let mut attn_out = Vec::with_capacity(ranks);
5381        let mut gated = Vec::with_capacity(ranks);
5382        let mut fuse_ctr = Vec::with_capacity(ranks);
5383        let mut o_partials = Vec::with_capacity(ranks);
5384        let mut ev_rank = Vec::with_capacity(ranks);
5385        let direct_join = oproj_direct_on();
5386        for (rank, engine) in self.ranks.iter().enumerate() {
5387            let _main = engine.gpu.enter_main()?;
5388            q_raw.push(engine.uninit(local_q_dim)?);
5389            k_raw.push(engine.uninit(local_kv_dim)?);
5390            v_raw.push(engine.uninit(local_kv_dim)?);
5391            q.push(engine.uninit(local_q_dim)?);
5392            k.push(engine.uninit(local_kv_dim)?);
5393            pos.push(engine.htod_i32(&[0])?);
5394            fuse_ctr.push(engine.stream().clone_htod(&[0u32])?);
5395            gate.push(engine.uninit(heads / ranks)?);
5396            attn_out.push(engine.uninit(local_q_dim)?);
5397            gated.push(engine.uninit(local_q_dim)?);
5398            let mut rank_partials = Vec::with_capacity(blocks_per_rank);
5399            for _ in 0..blocks_per_rank {
5400                // Direct join: peer ranks' partials live on ROOT so the b4 kernel's
5401                // stores land there over P2P (UVA) and no pull copy is needed.
5402                if direct_join && rank != 0 {
5403                    let root = &self.ranks[0];
5404                    let _root_main = root.gpu.enter_main()?;
5405                    rank_partials.push(root.uninit(o_out)?);
5406                } else {
5407                    rank_partials.push(engine.uninit(o_out)?);
5408                }
5409            }
5410            o_partials.push(rank_partials);
5411            ev_rank.push(engine.ctx().new_event(None)?);
5412        }
5413        let root = &self.ranks[0];
5414        let (peer_partial, reduce_a, reduce_b, zeros, k_shadow, v_shadow, ev_refresh, ev_oproj) = {
5415            let _main = root.gpu.enter_main()?;
5416            (
5417                root.uninit(o_out)?,
5418                root.uninit(o_out)?,
5419                root.uninit(o_out)?,
5420                root.htod(&vec![0.0f32; o_out])?,
5421                root.uninit(ranks * local_kv_dim)?,
5422                root.uninit(ranks * local_kv_dim)?,
5423                root.ctx().new_event(None)?,
5424                root.ctx().new_event(None)?,
5425            )
5426        };
5427        let (gate_e, ev_entry) = {
5428            let _main = e.gpu.enter_main()?;
5429            (e.uninit(heads)?, e.ctx().new_event(None)?)
5430        };
5431        let raw_attn_in = Vec::new();
5432        let raw_pos = Vec::new();
5433        guard.push(StepTpDecodeV2Ws {
5434            tcol_q: Vec::new(),
5435            tcol_k: Vec::new(),
5436            tcol_v: Vec::new(),
5437            tcol_g: Vec::new(),
5438            tcol_in: Vec::new(),
5439            tcol_cap: 0,
5440            fa2_q: Vec::new(),
5441            fa2_gate: Vec::new(),
5442            fa2_gated: Vec::new(),
5443            fa2_cap: 0,
5444            tcol_gated: Vec::new(),
5445            tcol_opart: Vec::new(),
5446            tcol_opeer: None,
5447            tcol_omix: None,
5448            tcol_ocap: 0,
5449            q_raw,
5450            k_raw,
5451            v_raw,
5452            q,
5453            k,
5454            pos,
5455            fuse_ctr,
5456            gate,
5457            attn_out,
5458            gated,
5459            o_partials,
5460            ev_rank,
5461            peer_partial,
5462            reduce_a,
5463            reduce_b,
5464            zeros,
5465            k_shadow,
5466            v_shadow,
5467            ev_refresh,
5468            ev_oproj,
5469            gate_e,
5470            attn_in: Vec::new(),
5471            h_stage: None,
5472            pos_stage: None,
5473            raw_h_stage: 0,
5474            raw_pos_stage: 0,
5475            raw_attn_in,
5476            raw_pos,
5477            raw_o_partial1: 0,
5478            raw_peer_partial: 0,
5479            raw_k1: 0,
5480            raw_v1: 0,
5481            raw_k_shadow: 0,
5482            raw_v_shadow: 0,
5483            raw_mixed_stage_e: 0,
5484            raw_reduce_a: 0,
5485            raw_shadow_stage_e: (0, 0),
5486            ev_entry,
5487            e_device: e.ctx().ordinal(),
5488            local_q_dim,
5489            local_kv_dim,
5490            heads,
5491            o_out,
5492            o_block_cols,
5493            blocks_per_rank,
5494        });
5495        eprintln!(
5496            "[step-tp-decode-v2] workspace ranks={ranks} local_q={local_q_dim} \
5497             local_kv={local_kv_dim} heads={heads} o_blocks={blocks_per_rank}x{o_block_cols} \
5498             residency=persistent ordering=evented performance_claim=false"
5499        );
5500        Ok(guard.len() - 1)
5501    }
5502
5503    /// v2 phase 1: replicate the layer input, project QKV, norm, rope, and stage the gate —
5504    /// all into the persistent workspace, ordered by events instead of host syncs.
5505    ///
5506    /// The caller must have queued every producer of `h`, `pos_d`, and `gate_raw` on `e`'s
5507    /// stream BEFORE this call: `ev_entry` is recorded once here and every rank stream waits
5508    /// on it (the entry fence also guards workspace reuse across layers — any consumer of the
5509    /// previous layer's outputs was queued on `e`'s stream before this record).
5510    #[allow(clippy::too_many_arguments)]
5511    /// T-COLUMN verify precompute (spec MTP): stage T input rows to every rank and run the
5512    /// weight-amortized qkvg_tcol per rank into the ws slabs. Rope/norm/append stay per
5513    /// column in the unmodified t=1 program (defer_norm_rope contract). Bit-exact per
5514    /// column vs the t=1 kernel by construction.
5515    #[allow(clippy::too_many_arguments)]
5516    pub fn decode_v2_input_qkv_tcol(
5517        &self,
5518        ws_index: usize,
5519        e: &Engine,
5520        h_t: &CudaSlice<f32>,
5521        t: usize,
5522        q_m: &ResidentBf16ColumnParallel,
5523        k_m: &ResidentBf16ColumnParallel,
5524        v_m: &ResidentBf16ColumnParallel,
5525        gate_shards: Option<StepTpGateShards<'_>>,
5526    ) -> Result<(), Box<dyn std::error::Error>> {
5527        let ranks = self.ranks.len();
5528        let mut guard = self
5529            .decode_v2
5530            .lock()
5531            .map_err(|_| "step TP decode v2 workspace lock is poisoned")?;
5532        let ws = guard
5533            .get_mut(ws_index)
5534            .ok_or("step TP decode v2 workspace index out of range")?;
5535        let in_f = q_m.in_features;
5536        if h_t.len() < t * in_f || t == 0 || t > 8 {
5537            return Err("decode_v2_input_qkv_tcol geometry".into());
5538        }
5539        // Lazily arm the slabs to capacity.
5540        if ws.tcol_cap < t || ws.tcol_q.len() != ranks {
5541            ws.tcol_q.clear();
5542            ws.tcol_k.clear();
5543            ws.tcol_v.clear();
5544            ws.tcol_g.clear();
5545            ws.tcol_in.clear();
5546            for engine in &self.ranks {
5547                let _m = engine.gpu.enter_main()?;
5548                ws.tcol_q.push(engine.uninit(8 * ws.local_q_dim)?);
5549                ws.tcol_k.push(engine.uninit(8 * ws.local_kv_dim)?);
5550                ws.tcol_v.push(engine.uninit(8 * ws.local_kv_dim)?);
5551                ws.tcol_g
5552                    .push(engine.uninit(8 * (ws.heads / ranks).max(1))?);
5553                ws.tcol_in.push(engine.uninit(8 * in_f)?);
5554            }
5555            ws.tcol_cap = 8;
5556        }
5557        // Stage the T input rows on e, fence, per-rank pull + tcol launch.
5558        use cudarc::driver::DevicePtr;
5559        let raw_src = {
5560            let _main = e.gpu.enter_main()?;
5561            let stream = e.stream();
5562            let (p, _g) = h_t.device_ptr(&stream);
5563            ws.ev_entry.record(&stream)?;
5564            p as u64
5565        };
5566        for rank in 0..ranks {
5567            let engine = &self.ranks[rank];
5568            let _main = engine.gpu.enter_main()?;
5569            engine.stream().wait(&ws.ev_entry)?;
5570            let raw_dst = {
5571                let stream = engine.stream();
5572                let (p, _g) = ws.tcol_in[rank].device_ptr(&stream);
5573                p as u64
5574            };
5575            raw_copy_bytes(raw_dst, raw_src, t * in_f * 4, engine)?;
5576            let out_g = match &gate_shards {
5577                Some(_) => ws.heads / ranks,
5578                None => 0,
5579            };
5580            match (
5581                &q_m.ranks[rank].weight,
5582                &k_m.ranks[rank].weight,
5583                &v_m.ranks[rank].weight,
5584            ) {
5585                (
5586                    ResidentBf16Weight::Bf16(wq),
5587                    ResidentBf16Weight::Bf16(wk),
5588                    ResidentBf16Weight::Bf16(wv),
5589                ) => {
5590                    let wg = match &gate_shards {
5591                        Some(StepTpGateShards::Bf16(shards)) => &shards[rank],
5592                        Some(StepTpGateShards::F32(_)) => {
5593                            return Err(
5594                                "tcol verify: gate shard class does not match bf16 QKV".into()
5595                            );
5596                        }
5597                        None => wq,
5598                    };
5599                    let StepTpDecodeV2Ws {
5600                        tcol_q,
5601                        tcol_k,
5602                        tcol_v,
5603                        tcol_g,
5604                        tcol_in,
5605                        local_q_dim,
5606                        local_kv_dim,
5607                        ..
5608                    } = &mut *ws;
5609                    // MEMRA_TCOL_REFKERN=1 (bisect): fill the slabs via the t=1 kernel per
5610                    // column — separates driver bugs from tcol-kernel bugs.
5611                    static REFK: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
5612                    let refk = *REFK
5613                        .get_or_init(|| std::env::var("MEMRA_TCOL_REFKERN").as_deref() == Ok("1"));
5614                    if refk {
5615                        let lq = *local_q_dim;
5616                        let lkv = *local_kv_dim;
5617                        let mut hrow = engine.uninit(in_f)?;
5618                        let mut qr = engine.uninit(lq)?;
5619                        let mut kr = engine.uninit(lkv)?;
5620                        let mut vr = engine.uninit(lkv)?;
5621                        let mut gr = engine.uninit(out_g.max(1))?;
5622                        for c in 0..t {
5623                            {
5624                                let mut dst = hrow.slice_mut(0..in_f);
5625                                engine.stream().memcpy_dtod(
5626                                    &tcol_in[rank].slice(c * in_f..(c + 1) * in_f),
5627                                    &mut dst,
5628                                )?;
5629                            }
5630                            engine.matvec_bf16_qkvg_into(
5631                                wq, wk, wv, wg, &hrow, &mut qr, &mut kr, &mut vr, &mut gr, in_f,
5632                                lq, lkv, out_g,
5633                            )?;
5634                            let stream = engine.stream();
5635                            {
5636                                let mut dst = tcol_q[rank].slice_mut(c * lq..(c + 1) * lq);
5637                                stream.memcpy_dtod(&qr.slice(0..lq), &mut dst)?;
5638                            }
5639                            {
5640                                let mut dst = tcol_k[rank].slice_mut(c * lkv..(c + 1) * lkv);
5641                                stream.memcpy_dtod(&kr.slice(0..lkv), &mut dst)?;
5642                            }
5643                            {
5644                                let mut dst = tcol_v[rank].slice_mut(c * lkv..(c + 1) * lkv);
5645                                stream.memcpy_dtod(&vr.slice(0..lkv), &mut dst)?;
5646                            }
5647                            if out_g > 0 {
5648                                let mut dst = tcol_g[rank].slice_mut(c * out_g..(c + 1) * out_g);
5649                                stream.memcpy_dtod(&gr.slice(0..out_g), &mut dst)?;
5650                            }
5651                        }
5652                    } else {
5653                        engine.matvec_bf16_qkvg_tcol_into(
5654                            wq,
5655                            wk,
5656                            wv,
5657                            wg,
5658                            &tcol_in[rank],
5659                            &mut tcol_q[rank],
5660                            &mut tcol_k[rank],
5661                            &mut tcol_v[rank],
5662                            &mut tcol_g[rank],
5663                            in_f,
5664                            *local_q_dim,
5665                            *local_kv_dim,
5666                            out_g,
5667                            t,
5668                        )?;
5669                    }
5670                }
5671                _ => return Err("tcol verify requires bf16-resident fused QKV".into()),
5672            }
5673        }
5674        Ok(())
5675    }
5676
5677    /// MEMRA_TCOL_OPROJ eligibility: the defer replaces exactly the o_fused direct-join
5678    /// finish (bf16 b4 kernel, 2 ranks, 4 canonical blocks) with the shadow gathers
5679    /// skipped — so it requires the same doors that arm dictate that finish shape.
5680    pub(crate) fn decode_v2_oproj_tcol_eligible(
5681        &self,
5682        ws: &StepTpDecodeV2Ws,
5683        o_m: &ResidentStepBf16RowParallel,
5684    ) -> bool {
5685        self.ranks.len() == 2
5686            && ws.blocks_per_rank == 4
5687            && step_tp_qkv_fused_enabled().unwrap_or(false)
5688            && no_local_shadow_on()
5689            && std::env::var("MEMRA_B4_X2").as_deref() != Ok("1")
5690            && o_m
5691                .ranks
5692                .iter()
5693                .flatten()
5694                .all(|block| matches!(block.weight, ResidentBf16Weight::Bf16(_)))
5695    }
5696
5697    /// MEMRA_SPEC_FA2 stash: copy this column's per-rank post-rope q and gate rows into
5698    /// the fa2 slabs (rank-stream ordered behind the rope/append that produced them), and
5699    /// give `e` the same anti-dependency wait the skipped finish provided (next column's
5700    /// h/pos re-staging must not overtake this column's rank pulls).
5701    pub(crate) fn decode_v2_stash_fa2(
5702        &self,
5703        ws: &mut StepTpDecodeV2Ws,
5704        e: &Engine,
5705        col: usize,
5706    ) -> Result<(), Box<dyn std::error::Error>> {
5707        let ranks = self.ranks.len();
5708        if col >= 2 {
5709            return Err("decode_v2_stash_fa2 column out of range".into());
5710        }
5711        let lq = ws.local_q_dim;
5712        let lg = (ws.heads / ranks).max(1);
5713        if ws.fa2_cap == 0 || ws.fa2_q.len() != ranks {
5714            ws.fa2_q.clear();
5715            ws.fa2_gate.clear();
5716            ws.fa2_gated.clear();
5717            for engine in &self.ranks {
5718                let _m = engine.gpu.enter_main()?;
5719                ws.fa2_q.push(engine.uninit(2 * lq)?);
5720                ws.fa2_gate.push(engine.uninit(2 * lg)?);
5721                ws.fa2_gated.push(engine.uninit(2 * lq)?);
5722            }
5723            ws.fa2_cap = 2;
5724        }
5725        for rank in 0..ranks {
5726            let engine = &self.ranks[rank];
5727            let _main = engine.gpu.enter_main()?;
5728            {
5729                let mut dst = ws.fa2_q[rank].slice_mut(col * lq..(col + 1) * lq);
5730                engine
5731                    .stream()
5732                    .memcpy_dtod(&ws.q[rank].slice(0..lq), &mut dst)?;
5733            }
5734            {
5735                let mut dst = ws.fa2_gate[rank].slice_mut(col * lg..(col + 1) * lg);
5736                engine
5737                    .stream()
5738                    .memcpy_dtod(&ws.gate[rank].slice(0..lg), &mut dst)?;
5739            }
5740            ws.ev_rank[rank].record(&engine.stream())?;
5741        }
5742        {
5743            let _main = e.gpu.enter_main()?;
5744            for ev in ws.ev_rank.iter() {
5745                e.stream().wait(ev)?;
5746            }
5747        }
5748        Ok(())
5749    }
5750
5751    /// MEMRA_SPEC_FA2 join: after BOTH verify columns stashed (their appends landed in
5752    /// rank-stream order), run ONE fa_decode_dcw2 per rank over the shared KV stream —
5753    /// two query rows, per-row causal bounds, per-row combine+gate — then land the two
5754    /// gated rows in the o-tcol slabs and reuse the weight-amortized o_proj join.
5755    /// Returns the [2, o_out] `mixed` slab on `e`. The caller's precheck enforced the
5756    /// equal-partition guard (boundary rounds never arm the defer).
5757    #[allow(clippy::too_many_arguments)]
5758    pub(crate) fn decode_v2_spec_fa2_join(
5759        &self,
5760        ws_index: usize,
5761        e: &Engine,
5762        o_m: &ResidentStepBf16RowParallel,
5763        kv: &ResidentTpKvCache,
5764        head_dim: usize,
5765        window: usize,
5766        bucket_max: usize,
5767        scale: f32,
5768    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
5769        let ranks = self.ranks.len();
5770        // Engagement receipt: a vacuous gate (precheck never passing) must be visible.
5771        static ONCE: std::sync::Once = std::sync::Once::new();
5772        ONCE.call_once(|| eprintln!("[spec-fa2] joined T=2 attention ENGAGED"));
5773        {
5774            let mut guard = self
5775                .decode_v2
5776                .lock()
5777                .map_err(|_| "step TP decode v2 workspace lock is poisoned")?;
5778            let ws = guard
5779                .get_mut(ws_index)
5780                .ok_or("step TP decode v2 workspace index out of range")?;
5781            if ws.fa2_cap < 2 || ws.fa2_q.len() != ranks {
5782                return Err("spec fa2 join without stashed columns".into());
5783            }
5784            let lq = ws.local_q_dim;
5785            let local_heads = (ws.heads / ranks).max(1);
5786            let local_kv_heads = (ws.local_kv_dim / head_dim).max(1);
5787            let capacity = kv.physical_capacity();
5788            let (k_tok_bytes, v_tok_bytes) = (kv.k_tok_bytes(), kv.v_tok_bytes());
5789            // Arm the o-tcol slabs if the oproj door never ran this boot (same shapes).
5790            if ws.tcol_ocap < 2 || ws.tcol_gated.len() != ranks {
5791                ws.tcol_gated.clear();
5792                ws.tcol_opart.clear();
5793                for engine in &self.ranks {
5794                    let _m = engine.gpu.enter_main()?;
5795                    ws.tcol_gated.push(engine.uninit(8 * lq)?);
5796                    ws.tcol_opart.push(engine.uninit(8 * ws.o_out)?);
5797                }
5798                let root = &self.ranks[0];
5799                let _m = root.gpu.enter_main()?;
5800                ws.tcol_opeer = Some(root.uninit(8 * ws.o_out)?);
5801                ws.tcol_omix = Some(root.uninit(8 * ws.o_out)?);
5802                ws.tcol_ocap = 8;
5803            }
5804            for rank in 0..ranks {
5805                let engine = &self.ranks[rank];
5806                let _main = engine.gpu.enter_main()?;
5807                let rank_cache = kv
5808                    .rank(rank)
5809                    .ok_or("spec fa2 join lost its KV cache rank")?;
5810                let k_ring = engine.view_u8_range(rank_cache.k(), 0, capacity * k_tok_bytes);
5811                let v_ring = engine.view_u8_range(rank_cache.v(), 0, capacity * v_tok_bytes);
5812                {
5813                    let StepTpDecodeV2Ws {
5814                        fa2_q,
5815                        fa2_gate,
5816                        fa2_gated,
5817                        ..
5818                    } = &mut *ws;
5819                    engine.fa_decode_dcw2(
5820                        &fa2_q[rank],
5821                        &k_ring,
5822                        &v_ring,
5823                        &mut fa2_gated[rank],
5824                        head_dim,
5825                        local_heads,
5826                        local_kv_heads,
5827                        rank_cache.len_d(),
5828                        rank_cache.base_d(),
5829                        window,
5830                        bucket_max,
5831                        scale,
5832                        k_tok_bytes,
5833                        v_tok_bytes,
5834                        &fa2_gate[rank],
5835                    )?;
5836                }
5837                // Both gated rows are contiguous [2, lq] — exactly columns 0..2 of the
5838                // o-tcol slab layout. One dtod, in rank-stream order behind the fa.
5839                let StepTpDecodeV2Ws {
5840                    fa2_gated,
5841                    tcol_gated,
5842                    ..
5843                } = &mut *ws;
5844                let mut dst = tcol_gated[rank].slice_mut(0..2 * lq);
5845                engine
5846                    .stream()
5847                    .memcpy_dtod(&fa2_gated[rank].slice(0..2 * lq), &mut dst)?;
5848            }
5849        }
5850        self.decode_v2_oproj_tcol(ws_index, e, o_m, 2)
5851    }
5852
5853    /// MEMRA_TCOL_OPROJ stash: copy this column's per-rank `gated` rows into the o-tcol
5854    /// slabs (rank-stream ordered behind the attention kernels that produced them). The
5855    /// per-column finish choreography is skipped entirely; `decode_v2_oproj_tcol` joins
5856    /// every column afterwards.
5857    pub(crate) fn decode_v2_stash_gated(
5858        &self,
5859        ws: &mut StepTpDecodeV2Ws,
5860        e: &Engine,
5861        col: usize,
5862    ) -> Result<(), Box<dyn std::error::Error>> {
5863        let ranks = self.ranks.len();
5864        if col >= 8 {
5865            return Err("decode_v2_stash_gated column out of range".into());
5866        }
5867        let lq = ws.local_q_dim;
5868        if ws.tcol_ocap == 0 || ws.tcol_gated.len() != ranks {
5869            ws.tcol_gated.clear();
5870            ws.tcol_opart.clear();
5871            for engine in &self.ranks {
5872                let _m = engine.gpu.enter_main()?;
5873                ws.tcol_gated.push(engine.uninit(8 * lq)?);
5874                ws.tcol_opart.push(engine.uninit(8 * ws.o_out)?);
5875            }
5876            let root = &self.ranks[0];
5877            let _m = root.gpu.enter_main()?;
5878            ws.tcol_opeer = Some(root.uninit(8 * ws.o_out)?);
5879            ws.tcol_omix = Some(root.uninit(8 * ws.o_out)?);
5880            ws.tcol_ocap = 8;
5881        }
5882        for rank in 0..ranks {
5883            let engine = &self.ranks[rank];
5884            let _main = engine.gpu.enter_main()?;
5885            let mut dst = ws.tcol_gated[rank].slice_mut(col * lq..(col + 1) * lq);
5886            engine
5887                .stream()
5888                .memcpy_dtod(&ws.gated[rank].slice(0..lq), &mut dst)?;
5889            // The skipped finish's e-wait was ALSO the anti-dependency guard: it ordered
5890            // e's NEXT column's h/pos re-staging behind this column's rank-side raw pulls.
5891            // Record each rank here and make e wait — same protection, no o_proj work.
5892            ws.ev_rank[rank].record(&engine.stream())?;
5893        }
5894        {
5895            let _main = e.gpu.enter_main()?;
5896            for ev in ws.ev_rank.iter() {
5897                e.stream().wait(ev)?;
5898            }
5899        }
5900        Ok(())
5901    }
5902
5903    /// MEMRA_TCOL_OPROJ join: one weight-amortized b4_tcol per rank over the stashed
5904    /// `gated` slabs (per-column FP order == the t=1 b4 kernel), one peer pull of rank1's
5905    /// partial slab, one elementwise slab add on the root (independent elements — each
5906    /// column's add is the exact direct-join `add(p0, p1)`), then the joined `mixed` slab
5907    /// lands on `e`. Returns [t, o_out] on the model engine.
5908    pub(crate) fn decode_v2_oproj_tcol(
5909        &self,
5910        ws_index: usize,
5911        e: &Engine,
5912        o_m: &ResidentStepBf16RowParallel,
5913        t: usize,
5914    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
5915        let ranks = self.ranks.len();
5916        let mut guard = self
5917            .decode_v2
5918            .lock()
5919            .map_err(|_| "step TP decode v2 workspace lock is poisoned")?;
5920        let ws = guard
5921            .get_mut(ws_index)
5922            .ok_or("step TP decode v2 workspace index out of range")?;
5923        if ranks != 2 || ws.blocks_per_rank != 4 || t == 0 || t > 8 || ws.tcol_ocap < t {
5924            return Err("decode_v2_oproj_tcol geometry".into());
5925        }
5926        for rank in 0..ranks {
5927            let engine = &self.ranks[rank];
5928            let _main = engine.gpu.enter_main()?;
5929            let mut weights = Vec::with_capacity(4);
5930            for block in 0..4 {
5931                let ResidentBf16Weight::Bf16(weight) = &o_m.ranks[rank][block].weight else {
5932                    return Err("tcol o_proj requires bf16-resident O blocks".into());
5933                };
5934                weights.push(weight);
5935            }
5936            {
5937                let StepTpDecodeV2Ws {
5938                    tcol_gated,
5939                    tcol_opart,
5940                    local_q_dim,
5941                    o_block_cols,
5942                    o_out,
5943                    ..
5944                } = &mut *ws;
5945                // MEMRA_TCOL_OPROJ_REF=1 (bisect): fill the partial slab via the t=1 b4
5946                // kernel per column — separates choreography bugs from tcol-kernel bugs.
5947                static REFK: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
5948                let refk = *REFK
5949                    .get_or_init(|| std::env::var("MEMRA_TCOL_OPROJ_REF").as_deref() == Ok("1"));
5950                if refk {
5951                    let lq = *local_q_dim;
5952                    let mut xr = engine.uninit(lq)?;
5953                    let mut yr = engine.uninit(*o_out)?;
5954                    for c in 0..t {
5955                        {
5956                            let mut dst = xr.slice_mut(0..lq);
5957                            engine.stream().memcpy_dtod(
5958                                &tcol_gated[rank].slice(c * lq..(c + 1) * lq),
5959                                &mut dst,
5960                            )?;
5961                        }
5962                        engine.matvec_bf16_b4_into(
5963                            [weights[0], weights[1], weights[2], weights[3]],
5964                            &xr,
5965                            &mut yr,
5966                            *o_block_cols,
5967                            *o_out,
5968                        )?;
5969                        let mut dst = tcol_opart[rank].slice_mut(c * *o_out..(c + 1) * *o_out);
5970                        engine
5971                            .stream()
5972                            .memcpy_dtod(&yr.slice(0..*o_out), &mut dst)?;
5973                    }
5974                } else {
5975                    engine.matvec_bf16_b4_tcol_into(
5976                        [weights[0], weights[1], weights[2], weights[3]],
5977                        &tcol_gated[rank],
5978                        &mut tcol_opart[rank],
5979                        *o_block_cols,
5980                        *o_out,
5981                        t,
5982                    )?;
5983                }
5984            }
5985            if rank != 0 {
5986                ws.ev_rank[rank].record(&engine.stream())?;
5987            }
5988        }
5989        let root = &self.ranks[0];
5990        {
5991            let _main = root.gpu.enter_main()?;
5992            for ev in ws.ev_rank.iter().skip(1) {
5993                root.stream().wait(ev)?;
5994            }
5995            {
5996                let StepTpDecodeV2Ws {
5997                    tcol_opart,
5998                    tcol_opeer,
5999                    tcol_omix,
6000                    o_out,
6001                    ..
6002                } = &mut *ws;
6003                let opeer = tcol_opeer.as_mut().ok_or("tcol o_proj slabs not armed")?;
6004                let omix = tcol_omix.as_mut().ok_or("tcol o_proj slabs not armed")?;
6005                {
6006                    let mut dst = opeer.slice_mut(0..t * *o_out);
6007                    root.stream()
6008                        .memcpy_dtod(&tcol_opart[1].slice(0..t * *o_out), &mut dst)?;
6009                }
6010                // Elementwise over the whole slab: per element identical to the per-column
6011                // direct-join add (independent lanes, same operand values).
6012                root.add(&tcol_opart[0], opeer, omix, t * *o_out)?;
6013            }
6014            ws.ev_oproj.record(&root.stream())?;
6015        }
6016        let _main = e.gpu.enter_main()?;
6017        e.stream().wait(&ws.ev_oproj)?;
6018        let mut out = e.uninit(t * ws.o_out)?;
6019        let omix = ws.tcol_omix.as_ref().ok_or("tcol o_proj slabs not armed")?;
6020        e.stream().memcpy_dtod(
6021            &omix.slice(0..t * ws.o_out),
6022            &mut out.slice_mut(0..t * ws.o_out),
6023        )?;
6024        Ok(out)
6025    }
6026
6027    pub(crate) fn decode_v2_input_qkv(
6028        &self,
6029        ws: &mut StepTpDecodeV2Ws,
6030        e: &Engine,
6031        h: &CudaSlice<f32>,
6032        pos_d: &CudaSlice<i32>,
6033        gate_raw: Option<&CudaSlice<f32>>,
6034        gate_shards: Option<StepTpGateShards<'_>>,
6035        decode_input: &mut ResidentReplicatedDeviceRows,
6036        q_m: &ResidentBf16ColumnParallel,
6037        k_m: &ResidentBf16ColumnParallel,
6038        v_m: &ResidentBf16ColumnParallel,
6039        q_norm: &[CudaSlice<f32>],
6040        k_norm: &[CudaSlice<f32>],
6041        head_dim: usize,
6042        n_rot: usize,
6043        rope_base: f32,
6044        rope_freqs: &[Option<&CudaSlice<f32>>],
6045        rms_eps: f32,
6046        defer_norm_rope: bool,
6047        tcol_col: Option<usize>,
6048    ) -> Result<(), Box<dyn std::error::Error>> {
6049        let ranks = self.ranks.len();
6050        validate_replicated_device_rows(&self.ranks, decode_input)?;
6051        if decode_input.tokens != 1
6052            || decode_input.width != q_m.in_features
6053            || pos_d.len() != 1
6054            || gate_raw.is_some_and(|gate| gate.len() != ws.heads)
6055            || gate_raw.is_none() != gate_shards.is_some()
6056            || gate_shards.as_ref().is_some_and(|shards| match shards {
6057                StepTpGateShards::F32(shards) => shards.len() != ranks,
6058                StepTpGateShards::Bf16(shards) => shards.len() != ranks,
6059            })
6060            || q_norm.len() != ranks
6061            || k_norm.len() != ranks
6062            || rope_freqs.len() != ranks
6063            || e.ctx().ordinal() != ws.e_device
6064        {
6065            return Err("step TP decode v2 input geometry mismatch".into());
6066        }
6067
6068        let qkv_fused = step_tp_qkv_fused_enabled()?;
6069        if gate_shards.is_some() && !qkv_fused {
6070            return Err("step TP decode v2 gate shards require MEMRA_STEP_TP_QKV_FUSED=1".into());
6071        }
6072        let values = decode_input.width;
6073        if h.len() != values {
6074            return Err(format!(
6075                "step TP decode v2 hidden width {} != replicated width {values}",
6076                h.len()
6077            )
6078            .into());
6079        }
6080
6081        if qkv_fused {
6082            // STAGE-BASED flow (graph increment A): h and pos land in fixed e-context stages
6083            // (one e-stream copy each), the entry event covers them, and every rank raw-copies
6084            // from the stages on its own stream — exactly the shape graph capture wraps.
6085            if ws.h_stage.is_none() {
6086                use cudarc::driver::DevicePtr;
6087                let _main = e.gpu.enter_main()?;
6088                let h_stage = e.uninit(values)?;
6089                let pos_stage = e.htod_i32(&[0])?;
6090                {
6091                    let stream = e.stream();
6092                    let (hp, _g0) = h_stage.device_ptr(&stream);
6093                    let (pp, _g1) = pos_stage.device_ptr(&stream);
6094                    ws.raw_h_stage = hp as u64;
6095                    ws.raw_pos_stage = pp as u64;
6096                }
6097                ws.h_stage = Some(h_stage);
6098                ws.pos_stage = Some(pos_stage);
6099                for rank in 0..ranks {
6100                    use cudarc::driver::DevicePtr;
6101                    let engine = &self.ranks[rank];
6102                    let _rmain = engine.gpu.enter_main()?;
6103                    let attn_in = engine.uninit(values)?;
6104                    let (dp, pp) = {
6105                        let stream = engine.stream();
6106                        let (dp, _g2) = attn_in.device_ptr(&stream);
6107                        let (pp, _g3) = ws.pos[rank].device_ptr(&stream);
6108                        (dp as u64, pp as u64)
6109                    };
6110                    ws.raw_attn_in.push(dp);
6111                    ws.raw_pos.push(pp);
6112                    ws.attn_in.push(attn_in);
6113                }
6114                {
6115                    use cudarc::driver::DevicePtr;
6116                    let root = &self.ranks[0];
6117                    let _rmain = root.gpu.enter_main()?;
6118                    let stream = root.stream();
6119                    let (a, _g) = ws.peer_partial.device_ptr(&stream);
6120                    let (b, _g) = ws.k_shadow.device_ptr(&stream);
6121                    let (c, _g) = ws.v_shadow.device_ptr(&stream);
6122                    ws.raw_peer_partial = a as u64;
6123                    ws.raw_k_shadow = b as u64;
6124                    ws.raw_v_shadow = c as u64;
6125                }
6126                {
6127                    use cudarc::driver::DevicePtr;
6128                    let rank1 = &self.ranks[1];
6129                    let _rmain = rank1.gpu.enter_main()?;
6130                    let stream = rank1.stream();
6131                    let (a, _g) = ws.o_partials[1][0].device_ptr(&stream);
6132                    let (b, _g) = ws.k[1].device_ptr(&stream);
6133                    let (c, _g) = ws.v_raw[1].device_ptr(&stream);
6134                    ws.raw_o_partial1 = a as u64;
6135                    ws.raw_k1 = b as u64;
6136                    ws.raw_v1 = c as u64;
6137                }
6138            }
6139            {
6140                let _main = e.gpu.enter_main()?;
6141                {
6142                    // (Always staged: a tcol column below the dcw floor falls back to the
6143                    // normal fused arm, which reads h through this stage.)
6144                    let h_stage = ws.h_stage.as_mut().expect("stage armed above");
6145                    let mut dst = h_stage.slice_mut(0..values);
6146                    e.stream().memcpy_dtod(&h.slice(0..values), &mut dst)?;
6147                }
6148                {
6149                    let pos_stage = ws.pos_stage.as_mut().expect("stage armed above");
6150                    let mut dst = pos_stage.slice_mut(0..1);
6151                    e.stream().memcpy_dtod(&pos_d.slice(0..1), &mut dst)?;
6152                }
6153                ws.ev_entry.record(&e.stream())?;
6154            }
6155            for rank in 0..ranks {
6156                let engine = &self.ranks[rank];
6157                let _main = engine.gpu.enter_main()?;
6158                engine.stream().wait(&ws.ev_entry)?;
6159            }
6160        } else {
6161            // Evented replicate flow (the pre-stage shape, kept for the non-fused class).
6162            {
6163                let _main = e.gpu.enter_main()?;
6164                if let Some(gate_raw) = gate_raw {
6165                    let mut gate_dst = ws.gate_e.slice_mut(0..ws.heads);
6166                    e.stream()
6167                        .memcpy_dtod(&gate_raw.slice(0..ws.heads), &mut gate_dst)?;
6168                }
6169                ws.ev_entry.record(&e.stream())?;
6170            }
6171            {
6172                let root = &self.ranks[0];
6173                let _main = root.gpu.enter_main()?;
6174                root.stream().wait(&ws.ev_entry)?;
6175                let mut destination = decode_input.ranks[0].slice_mut(0..values);
6176                root.stream()
6177                    .memcpy_dtod(&h.slice(0..values), &mut destination)?;
6178                ws.ev_refresh.record(&root.stream())?;
6179            }
6180            for rank in 1..ranks {
6181                let engine = &self.ranks[rank];
6182                let _main = engine.gpu.enter_main()?;
6183                engine.stream().wait(&ws.ev_refresh)?;
6184                let (root_rows, peer_rows) = decode_input.ranks.split_at_mut(rank);
6185                let mut destination = peer_rows[0].slice_mut(0..values);
6186                engine
6187                    .stream()
6188                    .memcpy_dtod(&root_rows[0].slice(0..values), &mut destination)?;
6189            }
6190        }
6191        for rank in 0..ranks {
6192            self.decode_v2_input_qkv_rank(
6193                ws,
6194                pos_d,
6195                decode_input,
6196                q_m,
6197                k_m,
6198                v_m,
6199                q_norm,
6200                k_norm,
6201                head_dim,
6202                n_rot,
6203                rope_base,
6204                rope_freqs,
6205                rms_eps,
6206                gate_shards.as_ref(),
6207                qkv_fused,
6208                defer_norm_rope,
6209                rank,
6210                tcol_col,
6211            )?;
6212        }
6213        Ok(())
6214    }
6215
6216    /// One rank's slice of `decode_v2_input_qkv` (projection, norm+rope, gate staging) — the
6217    /// per-device issue unit the whole-token graph captures on that rank's stream.
6218    #[allow(clippy::too_many_arguments)]
6219    pub(crate) fn decode_v2_input_qkv_rank(
6220        &self,
6221        ws: &mut StepTpDecodeV2Ws,
6222        pos_d: &CudaSlice<i32>,
6223        decode_input: &mut ResidentReplicatedDeviceRows,
6224        q_m: &ResidentBf16ColumnParallel,
6225        k_m: &ResidentBf16ColumnParallel,
6226        v_m: &ResidentBf16ColumnParallel,
6227        q_norm: &[CudaSlice<f32>],
6228        k_norm: &[CudaSlice<f32>],
6229        head_dim: usize,
6230        n_rot: usize,
6231        rope_base: f32,
6232        rope_freqs: &[Option<&CudaSlice<f32>>],
6233        rms_eps: f32,
6234        gate_shards: Option<&StepTpGateShards<'_>>,
6235        qkv_fused: bool,
6236        defer_norm_rope: bool,
6237        rank: usize,
6238        tcol_col: Option<usize>,
6239    ) -> Result<(), Box<dyn std::error::Error>> {
6240        let ranks = self.ranks.len();
6241        let local_heads = ws.local_q_dim / head_dim;
6242        let local_kv_heads = ws.local_kv_dim / head_dim;
6243        let engine = &self.ranks[rank];
6244        let _main = engine.gpu.enter_main()?;
6245        let ws_e_device = ws.e_device;
6246        // T-COLUMN SELECT (spec verify): the projections for this column were precomputed
6247        // by the weight-amortized tcol kernel — copy the column into the single-row buffers
6248        // (pure f32 moves, bit-exact) and skip the per-column matvec. Rope/norm/append run
6249        // below exactly as in the t=1 program.
6250        if qkv_fused && tcol_col.is_some() {
6251            let c = tcol_col.expect("checked");
6252            if ws.tcol_cap == 0 || ws.tcol_q.len() != ranks {
6253                return Err("tcol select without precompute".into());
6254            }
6255            // The select skips the matvec but NOT the position: rope/append below still
6256            // read this rank's pos buffer, which only the (skipped) stage path fills for
6257            // peer-device ranks. Stage it here or rank1 ropes at the previous position.
6258            if engine.ctx().ordinal() != ws_e_device {
6259                raw_copy_bytes(ws.raw_pos[rank], ws.raw_pos_stage, 4, engine)?;
6260            }
6261            let StepTpDecodeV2Ws {
6262                tcol_q,
6263                tcol_k,
6264                tcol_v,
6265                tcol_g,
6266                q_raw,
6267                k_raw,
6268                v_raw,
6269                gate,
6270                local_q_dim,
6271                local_kv_dim,
6272                heads,
6273                ..
6274            } = &mut *ws;
6275            let lg = *heads / ranks;
6276            let stream = engine.stream();
6277            {
6278                let mut dst = q_raw[rank].slice_mut(0..*local_q_dim);
6279                stream.memcpy_dtod(
6280                    &tcol_q[rank].slice(c * *local_q_dim..(c + 1) * *local_q_dim),
6281                    &mut dst,
6282                )?;
6283            }
6284            {
6285                let mut dst = k_raw[rank].slice_mut(0..*local_kv_dim);
6286                stream.memcpy_dtod(
6287                    &tcol_k[rank].slice(c * *local_kv_dim..(c + 1) * *local_kv_dim),
6288                    &mut dst,
6289                )?;
6290            }
6291            {
6292                let mut dst = v_raw[rank].slice_mut(0..*local_kv_dim);
6293                stream.memcpy_dtod(
6294                    &tcol_v[rank].slice(c * *local_kv_dim..(c + 1) * *local_kv_dim),
6295                    &mut dst,
6296                )?;
6297            }
6298            if lg > 0 {
6299                let mut dst = gate[rank].slice_mut(0..lg);
6300                stream.memcpy_dtod(&tcol_g[rank].slice(c * lg..(c + 1) * lg), &mut dst)?;
6301            }
6302            if !defer_norm_rope {
6303                // Below the dcw floor (or a non-defer shape) the col-select cannot apply:
6304                // fall through and recompute this column's QKV from the REAL h row — the
6305                // caller always passes it. The slab copies above are dead stores.
6306            } else {
6307                return Ok(());
6308            }
6309        }
6310        if qkv_fused {
6311            // Stage-based input: raw copies from the fixed e-context stages (capture-safe;
6312            // eager ordering comes from the caller's ev_entry wait on this stream). The rank
6313            // SHARING e's device reads the stages directly — same context (probed), ordering
6314            // identical (ev_entry / graph edge), bytes identical: the copies are pure waste.
6315            let same_dev = engine.ctx().ordinal() == ws.e_device;
6316            if !same_dev {
6317                raw_copy_bytes(
6318                    ws.raw_attn_in[rank],
6319                    ws.raw_h_stage,
6320                    q_m.in_features * 4,
6321                    engine,
6322                )?;
6323                raw_copy_bytes(ws.raw_pos[rank], ws.raw_pos_stage, 4, engine)?;
6324            }
6325            let StepTpDecodeV2Ws {
6326                q_raw,
6327                k_raw,
6328                v_raw,
6329                gate,
6330                gate_e,
6331                attn_in,
6332                h_stage,
6333                heads,
6334                local_q_dim,
6335                local_kv_dim,
6336                ..
6337            } = &mut *ws;
6338            let input_ref: &CudaSlice<f32> = if same_dev {
6339                h_stage
6340                    .as_ref()
6341                    .ok_or("step TP decode v2 stage not armed")?
6342            } else {
6343                &attn_in[rank]
6344            };
6345            match (
6346                &q_m.ranks[rank].weight,
6347                &k_m.ranks[rank].weight,
6348                &v_m.ranks[rank].weight,
6349            ) {
6350                (
6351                    ResidentBf16Weight::F32(wq),
6352                    ResidentBf16Weight::F32(wk),
6353                    ResidentBf16Weight::F32(wv),
6354                ) => {
6355                    let (wg, out_g) = match &gate_shards {
6356                        Some(StepTpGateShards::F32(shards)) => (&shards[rank], *heads / ranks),
6357                        Some(StepTpGateShards::Bf16(_)) => {
6358                            return Err("step TP decode v2 gate shard class does not \
6359                                            match the F32 projections"
6360                                .into());
6361                        }
6362                        // out_g = 0: the kernel never reads wg; any resident buffer works.
6363                        None => (&*gate_e, 0),
6364                    };
6365                    engine.matvec_f32_qkv_into(
6366                        wq,
6367                        wk,
6368                        wv,
6369                        wg,
6370                        input_ref,
6371                        &mut q_raw[rank],
6372                        &mut k_raw[rank],
6373                        &mut v_raw[rank],
6374                        &mut gate[rank],
6375                        q_m.in_features,
6376                        *local_q_dim,
6377                        *local_kv_dim,
6378                        out_g,
6379                    )?;
6380                }
6381                (
6382                    ResidentBf16Weight::Bf16(wq),
6383                    ResidentBf16Weight::Bf16(wk),
6384                    ResidentBf16Weight::Bf16(wv),
6385                ) => {
6386                    let (wg, out_g) = match &gate_shards {
6387                        Some(StepTpGateShards::Bf16(shards)) => (&shards[rank], *heads / ranks),
6388                        Some(StepTpGateShards::F32(_)) => {
6389                            return Err("step TP decode v2 gate shard class does not \
6390                                            match the bf16 projections"
6391                                .into());
6392                        }
6393                        None => (wq, 0),
6394                    };
6395                    engine.matvec_bf16_qkvg_into(
6396                        wq,
6397                        wk,
6398                        wv,
6399                        wg,
6400                        input_ref,
6401                        &mut q_raw[rank],
6402                        &mut k_raw[rank],
6403                        &mut v_raw[rank],
6404                        &mut gate[rank],
6405                        q_m.in_features,
6406                        *local_q_dim,
6407                        *local_kv_dim,
6408                        out_g,
6409                    )?;
6410                }
6411                _ => {
6412                    return Err("step TP decode v2 QKV projections mix residency classes".into());
6413                }
6414            }
6415        } else {
6416            for (matrix, local_out, raw) in [
6417                (q_m, ws.local_q_dim, &mut ws.q_raw),
6418                (k_m, ws.local_kv_dim, &mut ws.k_raw),
6419                (v_m, ws.local_kv_dim, &mut ws.v_raw),
6420            ] {
6421                let ResidentBf16Weight::F32(values_w) = &matrix.ranks[rank].weight else {
6422                    return Err("step TP decode v2 lost its F32 projection residency".into());
6423                };
6424                let chunk_rows = matrix.canonical_chunk_rows.unwrap_or(local_out);
6425                engine.linear_f32_resident_canonical_rows_t1_into(
6426                    &decode_input.ranks[rank],
6427                    values_w,
6428                    &mut raw[rank],
6429                    matrix.in_features,
6430                    local_out,
6431                    chunk_rows,
6432                )?;
6433            }
6434        }
6435        if qkv_fused && defer_norm_rope {
6436            // FUSION #1 defers norm+rope to the caller's fused rope+append+inc launch.
6437        } else if qkv_fused {
6438            // Fused norm+rope: one launch; the position comes from the rank-local staged
6439            // copy (raw-copied above from the fixed e-context pos stage — capture-safe).
6440            let StepTpDecodeV2Ws {
6441                q_raw,
6442                k_raw,
6443                q,
6444                k,
6445                pos,
6446                pos_stage,
6447                ..
6448            } = &mut *ws;
6449            let same_dev = engine.ctx().ordinal() == ws_e_device;
6450            let pos_ref: &CudaSlice<i32> = if same_dev {
6451                pos_stage
6452                    .as_ref()
6453                    .ok_or("step TP decode v2 pos stage not armed")?
6454            } else {
6455                &pos[rank]
6456            };
6457            engine.qk_norm_rope_into(
6458                &q_raw[rank],
6459                &k_raw[rank],
6460                &q_norm[rank],
6461                &k_norm[rank],
6462                &mut q[rank],
6463                &mut k[rank],
6464                pos_ref,
6465                head_dim,
6466                n_rot,
6467                local_heads,
6468                local_kv_heads,
6469                rms_eps,
6470                rope_base,
6471                1.0,
6472                rope_freqs[rank],
6473            )?;
6474        } else {
6475            engine.rms_norm(
6476                &ws.q_raw[rank],
6477                &q_norm[rank],
6478                &mut ws.q[rank],
6479                head_dim,
6480                local_heads,
6481                rms_eps,
6482            )?;
6483            engine.rms_norm(
6484                &ws.k_raw[rank],
6485                &k_norm[rank],
6486                &mut ws.k[rank],
6487                head_dim,
6488                local_kv_heads,
6489                rms_eps,
6490            )?;
6491            {
6492                let mut pos_dst = ws.pos[rank].slice_mut(0..1);
6493                engine
6494                    .stream()
6495                    .memcpy_dtod(&pos_d.slice(0..1), &mut pos_dst)?;
6496            }
6497            engine.rope_neox2(
6498                &mut ws.q[rank],
6499                &mut ws.k[rank],
6500                &ws.pos[rank],
6501                head_dim,
6502                n_rot,
6503                local_heads,
6504                local_kv_heads,
6505                1,
6506                rope_base,
6507                1.0,
6508                rope_freqs[rank],
6509            )?;
6510        }
6511        if gate_shards.is_none() {
6512            let gate_start = rank * (ws.heads / ranks);
6513            let mut gate_dst = ws.gate[rank].slice_mut(0..ws.heads / ranks);
6514            engine.stream().memcpy_dtod(
6515                &ws.gate_e.slice(gate_start..gate_start + ws.heads / ranks),
6516                &mut gate_dst,
6517            )?;
6518        }
6519        Ok(())
6520    }
6521
6522    /// One rank's O-partial slice of `decode_v2_finish` — the per-device issue unit the
6523    /// whole-token graph captures on that rank's stream (the rank-done event stays with the
6524    /// eager caller; graphs order via parent edges instead).
6525    pub(crate) fn decode_v2_finish_rank_partial(
6526        &self,
6527        ws: &mut StepTpDecodeV2Ws,
6528        o_m: &ResidentStepBf16RowParallel,
6529        o_fused: bool,
6530        rank: usize,
6531    ) -> Result<(), Box<dyn std::error::Error>> {
6532        let engine = &self.ranks[rank];
6533        let _main = engine.gpu.enter_main()?;
6534        if o_fused {
6535            let StepTpDecodeV2Ws {
6536                gated,
6537                o_partials,
6538                o_block_cols,
6539                o_out,
6540                ..
6541            } = &mut *ws;
6542            let all_f32 = o_m.ranks[rank]
6543                .iter()
6544                .all(|block| matches!(block.weight, ResidentBf16Weight::F32(_)));
6545            if all_f32 {
6546                let mut weights = Vec::with_capacity(4);
6547                for block in 0..4 {
6548                    let ResidentBf16Weight::F32(weight) = &o_m.ranks[rank][block].weight else {
6549                        unreachable!("all_f32 checked above");
6550                    };
6551                    weights.push(weight);
6552                }
6553                engine.matvec_f32_b4_into(
6554                    [weights[0], weights[1], weights[2], weights[3]],
6555                    &gated[rank],
6556                    &mut o_partials[rank][0],
6557                    *o_block_cols,
6558                    *o_out,
6559                )?;
6560            } else {
6561                let mut weights = Vec::with_capacity(4);
6562                for block in 0..4 {
6563                    let ResidentBf16Weight::Bf16(weight) = &o_m.ranks[rank][block].weight else {
6564                        return Err("step TP decode v2 O projections mix residency classes".into());
6565                    };
6566                    weights.push(weight);
6567                }
6568                engine.matvec_bf16_b4_into(
6569                    [weights[0], weights[1], weights[2], weights[3]],
6570                    &gated[rank],
6571                    &mut o_partials[rank][0],
6572                    *o_block_cols,
6573                    *o_out,
6574                )?;
6575            }
6576        } else {
6577            for block in 0..ws.blocks_per_rank {
6578                let ResidentBf16Weight::F32(weight) = &o_m.ranks[rank][block].weight else {
6579                    return Err("step TP decode v2 lost its F32 O residency".into());
6580                };
6581                let x =
6582                    ws.gated[rank].slice(block * ws.o_block_cols..(block + 1) * ws.o_block_cols);
6583                let w = weight.slice(0..weight.len());
6584                let mut y = ws.o_partials[rank][block].slice_mut(0..ws.o_out);
6585                engine.linear_t1_into(&x, &w, &mut y, ws.o_block_cols, ws.o_out)?;
6586            }
6587        }
6588        Ok(())
6589    }
6590
6591    /// v2 phase 2: canonical-block O reduction on the root device plus the K/V shadow gathers,
6592    /// returning a fresh model-engine output ordered behind `ev_oproj` on `e`'s stream.
6593    ///
6594    /// The caller must have queued every rank's attention work (reading `ws.gated`, `ws.k`,
6595    /// `ws.v_raw`) on the rank streams before this call. Reduction order is identical to
6596    /// `step_bf16_row_parallel_resident_native`: zeros, then rank 0's blocks, then each peer
6597    /// rank's blocks, one `add` per block.
6598    pub(crate) fn decode_v2_finish(
6599        &self,
6600        ws: &mut StepTpDecodeV2Ws,
6601        e: &Engine,
6602        o_m: &ResidentStepBf16RowParallel,
6603    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
6604        let ranks = self.ranks.len();
6605        if e.ctx().ordinal() != ws.e_device {
6606            return Err("step TP decode v2 finish engine changed".into());
6607        }
6608        // MEMRA_STEP_TP_QKV_FUSED extends to the O path: one matvec_f32_b4 launch per rank
6609        // (in-order canonical block accumulation per element) and a single peer-copy + add on
6610        // the root, replacing 4 cuBLASLt launches per rank + the 4-copy/8-add chain. Same
6611        // numeric-class door and gate as the fused QKV projection.
6612        let o_fused = step_tp_qkv_fused_enabled()? && ws.blocks_per_rank == 4 && ranks == 2;
6613
6614        // Per-rank O block partials on the owning rank's stream (serial after the attention
6615        // kernels the driver queued there), then the rank-done event for root's peer reads.
6616        for rank in 0..ranks {
6617            self.decode_v2_finish_rank_partial(ws, o_m, o_fused, rank)?;
6618            if rank == 0 {
6619                // root == rank0: its own stream order covers the partial; only peers need
6620                // the record/wait pair (host-op diet, matches the routes-arm skip).
6621                continue;
6622            }
6623            let engine = &self.ranks[rank];
6624            let _main = engine.gpu.enter_main()?;
6625            ws.ev_rank[rank].record(&engine.stream())?;
6626        }
6627
6628        // Root reduce in canonical order + shadow gathers, all on the root stream.
6629        let root = &self.ranks[0];
6630        #[allow(unused_assignments)]
6631        let mut final_in_a = false;
6632        {
6633            let _main = root.gpu.enter_main()?;
6634            for ev in ws.ev_rank.iter().skip(1) {
6635                root.stream().wait(ev)?;
6636            }
6637            if o_fused && oproj_direct_on() && ranks == 2 && no_local_shadow_on() {
6638                // DIRECT JOIN: rank1's partial already sits in root memory (P2P kernel
6639                // stores; visibility guaranteed by the ev_rank[1] wait above), rank0's
6640                // partial is root-stream-ordered — record ONE event and let the model
6641                // engine do the single add itself, straight into its own output row.
6642                // Same operands, same add order as finish_root_fused: BIT-IDENTICAL.
6643                ws.ev_oproj.record(&root.stream())?;
6644                let _main = e.gpu.enter_main()?;
6645                e.stream().wait(&ws.ev_oproj)?;
6646                let mut output = e.uninit(ws.o_out)?;
6647                if oproj_tail_on() && oproj_tail_eligible() {
6648                    // M2: defer the add into the residual+norm consumer (waits stay HERE;
6649                    // only the arithmetic moves). `output` is returned unwritten.
6650                    use cudarc::driver::DevicePtr;
6651                    let stream = e.stream();
6652                    let (p0, _g0) = ws.o_partials[0][0].device_ptr(&stream);
6653                    let (p1, _g1) = ws.o_partials[1][0].device_ptr(&stream);
6654                    set_oproj_tail((p0 as u64, p1 as u64));
6655                    return Ok(output);
6656                }
6657                e.add(
6658                    &ws.o_partials[0][0],
6659                    &ws.o_partials[1][0],
6660                    &mut output,
6661                    ws.o_out,
6662                )?;
6663                return Ok(output);
6664            }
6665            if o_fused {
6666                self.decode_v2_finish_root_fused(ws)?;
6667                ws.ev_oproj.record(&root.stream())?;
6668                let _main = e.gpu.enter_main()?;
6669                e.stream().wait(&ws.ev_oproj)?;
6670                let mut output = e.uninit(ws.o_out)?;
6671                e.stream().memcpy_dtod(
6672                    &ws.reduce_a.slice(0..ws.o_out),
6673                    &mut output.slice_mut(0..ws.o_out),
6674                )?;
6675                return Ok(output);
6676            }
6677            let mut first = true;
6678            let mut current_is_a = false;
6679            for rank in 0..ranks {
6680                for block in 0..ws.blocks_per_rank {
6681                    let use_peer = rank != 0;
6682                    if use_peer {
6683                        root.stream()
6684                            .memcpy_dtod(&ws.o_partials[rank][block], &mut ws.peer_partial)?;
6685                    }
6686                    // add(prev, partial) -> the other reduce buffer, exactly one add per block
6687                    match (first, current_is_a, use_peer) {
6688                        (true, _, true) => {
6689                            root.add(&ws.zeros, &ws.peer_partial, &mut ws.reduce_a, ws.o_out)?
6690                        }
6691                        (true, _, false) => root.add(
6692                            &ws.zeros,
6693                            &ws.o_partials[0][block],
6694                            &mut ws.reduce_a,
6695                            ws.o_out,
6696                        )?,
6697                        (false, true, true) => {
6698                            root.add(&ws.reduce_a, &ws.peer_partial, &mut ws.reduce_b, ws.o_out)?
6699                        }
6700                        (false, true, false) => root.add(
6701                            &ws.reduce_a,
6702                            &ws.o_partials[0][block],
6703                            &mut ws.reduce_b,
6704                            ws.o_out,
6705                        )?,
6706                        (false, false, true) => {
6707                            root.add(&ws.reduce_b, &ws.peer_partial, &mut ws.reduce_a, ws.o_out)?
6708                        }
6709                        (false, false, false) => root.add(
6710                            &ws.reduce_b,
6711                            &ws.o_partials[0][block],
6712                            &mut ws.reduce_a,
6713                            ws.o_out,
6714                        )?,
6715                    }
6716                    current_is_a = first || !current_is_a;
6717                    first = false;
6718                }
6719            }
6720            final_in_a = current_is_a;
6721
6722            for rank in 0..ranks {
6723                let start = rank * ws.local_kv_dim;
6724                let mut k_dst = ws.k_shadow.slice_mut(start..start + ws.local_kv_dim);
6725                root.stream().memcpy_dtod(&ws.k[rank], &mut k_dst)?;
6726                let mut v_dst = ws.v_shadow.slice_mut(start..start + ws.local_kv_dim);
6727                root.stream().memcpy_dtod(&ws.v_raw[rank], &mut v_dst)?;
6728            }
6729            ws.ev_oproj.record(&root.stream())?;
6730        }
6731
6732        // Model-engine output: e waits the root event, then copies the reduced row into a
6733        // fresh e-context buffer (same ownership contract as v1's `e.htod`). The same wait
6734        // orders the driver's shadow append (it reads ws.k_shadow/ws.v_shadow on e's stream).
6735        let _main = e.gpu.enter_main()?;
6736        e.stream().wait(&ws.ev_oproj)?;
6737        let mut output = e.uninit(ws.o_out)?;
6738        let source = if final_in_a {
6739            &ws.reduce_a
6740        } else {
6741            &ws.reduce_b
6742        };
6743        e.stream().memcpy_dtod(
6744            &source.slice(0..ws.o_out),
6745            &mut output.slice_mut(0..ws.o_out),
6746        )?;
6747        Ok(output)
6748    }
6749
6750    pub fn run_routed_experts(
6751        &self,
6752        experts: &ResidentExpertParallel,
6753        input: &[f32],
6754        tokens: usize,
6755        selected: &[usize],
6756        route_weights: &[f32],
6757        experts_per_token: usize,
6758        activation_limit: Option<f32>,
6759    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
6760        validate_step_expert_activation_limit(activation_limit)?;
6761        validate_ep_residency(&self.ranks, experts)?;
6762        validate_activations(input, tokens, experts.input_width)?;
6763        let pairs = tokens
6764            .checked_mul(experts_per_token)
6765            .ok_or("EP route count overflow")?;
6766        if selected.len() != pairs || route_weights.len() != pairs {
6767            return Err(format!(
6768                "EP routes selected={} weights={} != tokens {tokens} x experts/token \
6769                 {experts_per_token} ({pairs})",
6770                selected.len(),
6771                route_weights.len(),
6772            )
6773            .into());
6774        }
6775        if !route_weights.iter().all(|weight| weight.is_finite()) {
6776            return Err("EP route weights contain a non-finite value".into());
6777        }
6778        if self.native_p2p {
6779            return self.run_routed_experts_native(
6780                experts,
6781                input,
6782                tokens,
6783                selected,
6784                route_weights,
6785                experts_per_token,
6786                activation_limit,
6787            );
6788        }
6789
6790        let mut output = vec![0.0f32; tokens * experts.input_width];
6791        let per_rank = experts.expert_count / experts.ranks.len();
6792        for token in 0..tokens {
6793            let input_row = &input[token * experts.input_width..(token + 1) * experts.input_width];
6794            for slot in 0..experts_per_token {
6795                let pair = token * experts_per_token + slot;
6796                let expert = selected[pair];
6797                if expert >= experts.expert_count {
6798                    return Err(format!(
6799                        "EP selected expert {expert} outside 0..{}",
6800                        experts.expert_count
6801                    )
6802                    .into());
6803                }
6804                let owner = expert / per_rank;
6805                let local_expert = expert - experts.ranks[owner].gate.expert_range.start;
6806                let rank = &experts.ranks[owner];
6807                let engine = &self.ranks[owner];
6808                let gate =
6809                    run_resident_bank_expert(engine, &rank.gate, local_expert, input_row, 1)?;
6810                let up = run_resident_bank_expert(engine, &rank.up, local_expert, input_row, 1)?;
6811                let activated: Vec<f32> = gate
6812                    .iter()
6813                    .zip(&up)
6814                    .map(|(&gate, &up)| step_expert_activation_host(gate, up, activation_limit))
6815                    .collect();
6816                debug_assert_eq!(activated.len(), experts.expert_width);
6817                let down =
6818                    run_resident_bank_expert(engine, &rank.down, local_expert, &activated, 1)?;
6819                let weight = route_weights[pair];
6820                for (sum, value) in output
6821                    [token * experts.input_width..(token + 1) * experts.input_width]
6822                    .iter_mut()
6823                    .zip(down)
6824                {
6825                    *sum += weight * value;
6826                }
6827            }
6828        }
6829        Ok(output)
6830    }
6831
6832    fn run_routed_experts_native(
6833        &self,
6834        experts: &ResidentExpertParallel,
6835        input: &[f32],
6836        tokens: usize,
6837        selected: &[usize],
6838        route_weights: &[f32],
6839        experts_per_token: usize,
6840        activation_limit: Option<f32>,
6841    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
6842        if !self.native_p2p || self.ranks.len() < 2 {
6843            return Err("native EP execution requires at least two P2P ranks".into());
6844        }
6845        if self.ep_device_arithmetic {
6846            return self.run_routed_experts_native_device(
6847                experts,
6848                input,
6849                tokens,
6850                selected,
6851                route_weights,
6852                experts_per_token,
6853                activation_limit,
6854            );
6855        }
6856        let mut output = vec![0.0f32; tokens * experts.input_width];
6857        let per_rank = experts.expert_count / experts.ranks.len();
6858        for token in 0..tokens {
6859            let input_row = &input[token * experts.input_width..(token + 1) * experts.input_width];
6860            let mut rank_inputs = (0..self.ranks.len())
6861                .map(|_| None)
6862                .collect::<Vec<Option<CudaSlice<f32>>>>();
6863            rank_inputs[0] = Some({
6864                let root = &self.ranks[0];
6865                let _main = root.gpu.enter_main()?;
6866                root.htod(input_row)?
6867            });
6868
6869            for slot in 0..experts_per_token {
6870                let pair = token * experts_per_token + slot;
6871                let expert = selected[pair];
6872                if expert >= experts.expert_count {
6873                    return Err(format!(
6874                        "EP selected expert {expert} outside 0..{}",
6875                        experts.expert_count
6876                    )
6877                    .into());
6878                }
6879                let owner = expert / per_rank;
6880                let local_expert = expert - experts.ranks[owner].gate.expert_range.start;
6881                if rank_inputs[owner].is_none() {
6882                    let peer_input = {
6883                        let root_input = rank_inputs[0]
6884                            .as_ref()
6885                            .ok_or("native EP lost its root input")?;
6886                        let engine = &self.ranks[owner];
6887                        let _main = engine.gpu.enter_main()?;
6888                        let mut peer_input = engine.uninit(experts.input_width)?;
6889                        engine.stream().memcpy_dtod(root_input, &mut peer_input)?;
6890                        peer_input
6891                    };
6892                    rank_inputs[owner] = Some(peer_input);
6893                }
6894
6895                let rank = &experts.ranks[owner];
6896                let engine = &self.ranks[owner];
6897                let owner_input = rank_inputs[owner]
6898                    .as_ref()
6899                    .ok_or("native EP owner input is absent after dispatch")?;
6900                let gate = run_resident_bank_expert_device(
6901                    engine,
6902                    &rank.gate,
6903                    local_expert,
6904                    owner_input,
6905                    1,
6906                )?;
6907                let up = run_resident_bank_expert_device(
6908                    engine,
6909                    &rank.up,
6910                    local_expert,
6911                    owner_input,
6912                    1,
6913                )?;
6914                let (gate, up) = {
6915                    let _main = engine.gpu.enter_main()?;
6916                    (engine.dtoh(&gate)?, engine.dtoh(&up)?)
6917                };
6918                let activated = gate
6919                    .iter()
6920                    .zip(&up)
6921                    .map(|(&gate, &up)| step_expert_activation_host(gate, up, activation_limit))
6922                    .collect::<Vec<_>>();
6923                debug_assert_eq!(activated.len(), experts.expert_width);
6924                let activated = {
6925                    let _main = engine.gpu.enter_main()?;
6926                    engine.htod(&activated)?
6927                };
6928                let down = run_resident_bank_expert_device(
6929                    engine,
6930                    &rank.down,
6931                    local_expert,
6932                    &activated,
6933                    1,
6934                )?;
6935                let down = if owner == 0 {
6936                    let _main = engine.gpu.enter_main()?;
6937                    engine.dtoh(&down)?
6938                } else {
6939                    let root = &self.ranks[0];
6940                    let _main = root.gpu.enter_main()?;
6941                    let mut root_down = root.uninit(experts.input_width)?;
6942                    root.stream().memcpy_dtod(&down, &mut root_down)?;
6943                    root.dtoh(&root_down)?
6944                };
6945                let weight = route_weights[pair];
6946                for (sum, value) in output
6947                    [token * experts.input_width..(token + 1) * experts.input_width]
6948                    .iter_mut()
6949                    .zip(down)
6950                {
6951                    *sum += weight * value;
6952                }
6953            }
6954        }
6955        Ok(output)
6956    }
6957
6958    fn run_routed_experts_native_device(
6959        &self,
6960        experts: &ResidentExpertParallel,
6961        input: &[f32],
6962        tokens: usize,
6963        selected: &[usize],
6964        route_weights: &[f32],
6965        experts_per_token: usize,
6966        activation_limit: Option<f32>,
6967    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
6968        if !self.native_p2p || !self.ep_device_arithmetic || self.ranks.len() < 2 {
6969            return Err(
6970                "device-resident EP arithmetic requires at least two native P2P ranks".into(),
6971            );
6972        }
6973        let mut output = Vec::with_capacity(tokens * experts.input_width);
6974        let per_rank = experts.expert_count / experts.ranks.len();
6975        let root = &self.ranks[0];
6976        for token in 0..tokens {
6977            let input_row = &input[token * experts.input_width..(token + 1) * experts.input_width];
6978            let mut rank_inputs = (0..self.ranks.len())
6979                .map(|_| None)
6980                .collect::<Vec<Option<CudaSlice<f32>>>>();
6981            rank_inputs[0] = Some({
6982                let _main = root.gpu.enter_main()?;
6983                root.htod(input_row)?
6984            });
6985            let mut root_output = {
6986                let _main = root.gpu.enter_main()?;
6987                root.zeros(experts.input_width)?
6988            };
6989            let mut remote_down_keepalive = Vec::new();
6990
6991            for slot in 0..experts_per_token {
6992                let pair = token * experts_per_token + slot;
6993                let expert = selected[pair];
6994                if expert >= experts.expert_count {
6995                    return Err(format!(
6996                        "EP selected expert {expert} outside 0..{}",
6997                        experts.expert_count
6998                    )
6999                    .into());
7000                }
7001                let owner = expert / per_rank;
7002                let local_expert = expert - experts.ranks[owner].gate.expert_range.start;
7003                if rank_inputs[owner].is_none() {
7004                    let peer_input = {
7005                        let root_input = rank_inputs[0]
7006                            .as_ref()
7007                            .ok_or("native EP lost its root input")?;
7008                        let engine = &self.ranks[owner];
7009                        let _main = engine.gpu.enter_main()?;
7010                        let mut peer_input = engine.uninit(experts.input_width)?;
7011                        engine.stream().memcpy_dtod(root_input, &mut peer_input)?;
7012                        peer_input
7013                    };
7014                    rank_inputs[owner] = Some(peer_input);
7015                }
7016
7017                let rank = &experts.ranks[owner];
7018                let engine = &self.ranks[owner];
7019                let owner_input = rank_inputs[owner]
7020                    .as_ref()
7021                    .ok_or("native EP owner input is absent after dispatch")?;
7022                let gate = run_resident_bank_expert_device(
7023                    engine,
7024                    &rank.gate,
7025                    local_expert,
7026                    owner_input,
7027                    1,
7028                )?;
7029                let up = run_resident_bank_expert_device(
7030                    engine,
7031                    &rank.up,
7032                    local_expert,
7033                    owner_input,
7034                    1,
7035                )?;
7036                let activated = {
7037                    let _main = engine.gpu.enter_main()?;
7038                    let mut activated = engine.uninit(experts.expert_width)?;
7039                    if let Some(limit) = activation_limit {
7040                        engine.silu_clamped_mul_host_expf(
7041                            &gate,
7042                            &up,
7043                            limit,
7044                            &mut activated,
7045                            experts.expert_width,
7046                        )?;
7047                    } else {
7048                        engine.silu_mul_host_expf(
7049                            &gate,
7050                            &up,
7051                            &mut activated,
7052                            experts.expert_width,
7053                        )?;
7054                    }
7055                    activated
7056                };
7057                let down = run_resident_bank_expert_device(
7058                    engine,
7059                    &rank.down,
7060                    local_expert,
7061                    &activated,
7062                    1,
7063                )?;
7064                let root_down = if owner == 0 {
7065                    down
7066                } else {
7067                    let _main = root.gpu.enter_main()?;
7068                    let mut root_down = root.uninit(experts.input_width)?;
7069                    root.stream().memcpy_dtod(&down, &mut root_down)?;
7070                    // The peer copy runs on the root stream. Keep its remote source alive until
7071                    // the final root readback synchronizes that stream; otherwise async free can
7072                    // recycle the owner's allocation while cuMemcpyPeerAsync is still reading it.
7073                    remote_down_keepalive.push(down);
7074                    root_down
7075                };
7076                let _main = root.gpu.enter_main()?;
7077                let mut destination = root_output.slice_mut(0..experts.input_width);
7078                root.axpy_host_into(
7079                    &root_down.slice(0..root_down.len()),
7080                    route_weights[pair],
7081                    &mut destination,
7082                    experts.input_width,
7083                )?;
7084            }
7085
7086            let _main = root.gpu.enter_main()?;
7087            let root_output = root.dtoh(&root_output)?;
7088            drop(remote_down_keepalive);
7089            output.extend(root_output);
7090        }
7091        Ok(output)
7092    }
7093}
7094
7095fn validate_column_shape(matrix: E4m3BlockMatrix<'_>, tp: usize) -> Result<(), String> {
7096    if matrix.out_features % tp != 0 {
7097        return Err(format!(
7098            "column-parallel out_features {} is not divisible by TP={tp}",
7099            matrix.out_features
7100        ));
7101    }
7102    let local_out = matrix.out_features / tp;
7103    if local_out % FP8_BLOCK != 0 {
7104        return Err(format!(
7105            "column-parallel output shard {local_out} cuts through a {FP8_BLOCK}-row \
7106             E4M3 scale block"
7107        ));
7108    }
7109    Ok(())
7110}
7111
7112fn step_bf16_canonical_chunk_rows(out_features: usize, tp: usize) -> Result<usize, String> {
7113    if !matches!(tp, 1 | 2 | 4 | 8) {
7114        return Err(format!(
7115            "Step BF16 canonical projection requires TP1/TP2/TP4/TP8, got TP={tp}"
7116        ));
7117    }
7118    if out_features == 0 || out_features % PRODUCT_MAX_CARDS != 0 {
7119        return Err(format!(
7120            "Step BF16 output width {out_features} is not divisible by the TP8 product envelope"
7121        ));
7122    }
7123    let canonical_rows = out_features / PRODUCT_MAX_CARDS;
7124    let local_out = out_features / tp;
7125    if local_out % canonical_rows != 0 {
7126        return Err(format!(
7127            "Step BF16 TP={tp} output shard {local_out} is not divisible by canonical \
7128             {canonical_rows}-row chunks"
7129        ));
7130    }
7131    Ok(canonical_rows)
7132}
7133
7134fn step_bf16_canonical_chunk_cols(in_features: usize, tp: usize) -> Result<usize, String> {
7135    if !matches!(tp, 1 | 2 | 4 | 8) {
7136        return Err(format!(
7137            "Step BF16 canonical row projection requires TP1/TP2/TP4/TP8, got TP={tp}"
7138        ));
7139    }
7140    if in_features == 0 || in_features % PRODUCT_MAX_CARDS != 0 {
7141        return Err(format!(
7142            "Step BF16 input width {in_features} is not divisible by the TP8 product envelope"
7143        ));
7144    }
7145    let canonical_cols = in_features / PRODUCT_MAX_CARDS;
7146    let local_in = in_features / tp;
7147    if local_in % canonical_cols != 0 {
7148        return Err(format!(
7149            "Step BF16 TP={tp} input shard {local_in} is not divisible by canonical \
7150             {canonical_cols}-column chunks"
7151        ));
7152    }
7153    Ok(canonical_cols)
7154}
7155
7156fn validate_row_shape(matrix: E4m3BlockMatrix<'_>, tp: usize) -> Result<(), String> {
7157    if matrix.in_features % tp != 0 {
7158        return Err(format!(
7159            "row-parallel in_features {} is not divisible by TP={tp}",
7160            matrix.in_features
7161        ));
7162    }
7163    let local_in = matrix.in_features / tp;
7164    if local_in % FP8_BLOCK != 0 {
7165        return Err(format!(
7166            "row-parallel input shard {local_in} cuts through a {FP8_BLOCK}-column \
7167             E4M3 scale block"
7168        ));
7169    }
7170    Ok(())
7171}
7172
7173fn upload_rank(
7174    engine: &Engine,
7175    matrix: E4m3BlockMatrix<'_>,
7176) -> Result<ResidentE4m3Rank, Box<dyn std::error::Error>> {
7177    let _main = engine.gpu.enter_main()?;
7178    matrix.validate()?;
7179    Ok(ResidentE4m3Rank {
7180        codes: engine.htod_bytes(matrix.codes)?,
7181        scales: engine.htod(matrix.scales)?,
7182        out_features: matrix.out_features,
7183        in_features: matrix.in_features,
7184    })
7185}
7186
7187fn upload_bf16_rank(
7188    engine: &Engine,
7189    matrix: Bf16Matrix<'_>,
7190    f32_mirror: bool,
7191) -> Result<ResidentBf16Rank, Box<dyn std::error::Error>> {
7192    let _main = engine.gpu.enter_main()?;
7193    matrix.validate()?;
7194    let bytes = engine.htod_bytes(matrix.bytes)?;
7195    let weight = if f32_mirror {
7196        let values = matrix
7197            .out_features
7198            .checked_mul(matrix.in_features)
7199            .ok_or("resident BF16 mirror element count overflow")?;
7200        ResidentBf16Weight::F32(engine.bf16_to_f32(&bytes.slice(0..bytes.len()), values)?)
7201    } else {
7202        ResidentBf16Weight::Bf16(bytes)
7203    };
7204    Ok(ResidentBf16Rank {
7205        weight,
7206        out_features: matrix.out_features,
7207        in_features: matrix.in_features,
7208    })
7209}
7210
7211fn upload_expert_bank_rank(
7212    engine: &Engine,
7213    bank: E4m3ExpertBank<'_>,
7214    expert_range: Range<usize>,
7215) -> Result<ResidentE4m3ExpertBankRank, Box<dyn std::error::Error>> {
7216    let _main = engine.gpu.enter_main()?;
7217    bank.validate()?;
7218    if expert_range.start >= expert_range.end || expert_range.end > bank.expert_count {
7219        return Err(format!(
7220            "invalid EP expert range {expert_range:?} for {} experts",
7221            bank.expert_count
7222        )
7223        .into());
7224    }
7225    let code_stride = bank.out_features * bank.in_features;
7226    let scale_stride = bank.out_features.div_ceil(FP8_BLOCK) * bank.in_features.div_ceil(FP8_BLOCK);
7227    Ok(ResidentE4m3ExpertBankRank {
7228        codes: engine.htod_bytes(
7229            &bank.codes[expert_range.start * code_stride..expert_range.end * code_stride],
7230        )?,
7231        scales: engine.htod(
7232            &bank.scales[expert_range.start * scale_stride..expert_range.end * scale_stride],
7233        )?,
7234        expert_range,
7235        out_features: bank.out_features,
7236        in_features: bank.in_features,
7237        code_stride,
7238        scale_stride,
7239        k_blocks: None,
7240    })
7241}
7242
7243fn validate_column_bank_shape(bank: E4m3ExpertBank<'_>, tp: usize) -> Result<(), String> {
7244    if bank.out_features % tp != 0 {
7245        return Err(format!(
7246            "TP expert output width {} is not divisible by TP={tp}",
7247            bank.out_features
7248        ));
7249    }
7250    let local_out = bank.out_features / tp;
7251    if local_out % FP8_BLOCK != 0 {
7252        return Err(format!(
7253            "TP expert output shard {local_out} cuts through a {FP8_BLOCK}-row E4M3 scale block"
7254        ));
7255    }
7256    Ok(())
7257}
7258
7259fn validate_row_bank_shape(bank: E4m3ExpertBank<'_>, tp: usize) -> Result<(), String> {
7260    if bank.in_features % tp != 0 {
7261        return Err(format!(
7262            "TP expert input width {} is not divisible by TP={tp}",
7263            bank.in_features
7264        ));
7265    }
7266    let local_in = bank.in_features / tp;
7267    if local_in % FP8_BLOCK != 0 {
7268        return Err(format!(
7269            "TP expert input shard {local_in} cuts through a {FP8_BLOCK}-column E4M3 scale block"
7270        ));
7271    }
7272    Ok(())
7273}
7274
7275fn upload_column_bank_rank(
7276    engine: &Engine,
7277    bank: E4m3ExpertBank<'_>,
7278    tp: usize,
7279    rank: usize,
7280) -> Result<ResidentE4m3ExpertBankRank, Box<dyn std::error::Error>> {
7281    let _main = engine.gpu.enter_main()?;
7282    let packed = pack_column_bank_rank(bank, tp, rank)?;
7283    Ok(ResidentE4m3ExpertBankRank {
7284        codes: engine.htod_bytes(&packed.codes)?,
7285        scales: engine.htod(&packed.scales)?,
7286        expert_range: packed.expert_range,
7287        out_features: packed.out_features,
7288        in_features: packed.in_features,
7289        code_stride: packed.code_stride,
7290        scale_stride: packed.scale_stride,
7291        k_blocks: packed.k_blocks,
7292    })
7293}
7294
7295fn pack_column_bank_rank(
7296    bank: E4m3ExpertBank<'_>,
7297    tp: usize,
7298    rank: usize,
7299) -> Result<PackedE4m3ExpertBankRank, String> {
7300    bank.validate()?;
7301    validate_column_bank_shape(bank, tp)?;
7302    if rank >= tp {
7303        return Err(format!("TP rank {rank} outside 0..{tp}"));
7304    }
7305    let local_out = bank.out_features / tp;
7306    let full_code_stride = bank.out_features * bank.in_features;
7307    let local_code_stride = local_out * bank.in_features;
7308    let scale_cols = bank.in_features.div_ceil(FP8_BLOCK);
7309    let full_scale_stride = bank.out_features.div_ceil(FP8_BLOCK) * scale_cols;
7310    let local_scale_rows = local_out / FP8_BLOCK;
7311    let local_scale_stride = local_scale_rows * scale_cols;
7312    let mut codes = Vec::with_capacity(bank.expert_count * local_code_stride);
7313    let mut scales = Vec::with_capacity(bank.expert_count * local_scale_stride);
7314    let row_start = rank * local_out;
7315    let scale_row_start = rank * local_scale_rows;
7316    for expert in 0..bank.expert_count {
7317        let code_start = expert * full_code_stride + row_start * bank.in_features;
7318        codes.extend_from_slice(&bank.codes[code_start..code_start + local_code_stride]);
7319        let scale_start = expert * full_scale_stride + scale_row_start * scale_cols;
7320        scales.extend_from_slice(&bank.scales[scale_start..scale_start + local_scale_stride]);
7321    }
7322    Ok(PackedE4m3ExpertBankRank {
7323        codes,
7324        scales,
7325        expert_range: 0..bank.expert_count,
7326        out_features: local_out,
7327        in_features: bank.in_features,
7328        code_stride: local_code_stride,
7329        scale_stride: local_scale_stride,
7330        k_blocks: None,
7331    })
7332}
7333
7334fn upload_row_bank_rank(
7335    engine: &Engine,
7336    bank: E4m3ExpertBank<'_>,
7337    tp: usize,
7338    rank: usize,
7339) -> Result<ResidentE4m3ExpertBankRank, Box<dyn std::error::Error>> {
7340    let _main = engine.gpu.enter_main()?;
7341    let packed = pack_row_bank_rank(bank, tp, rank)?;
7342    Ok(ResidentE4m3ExpertBankRank {
7343        codes: engine.htod_bytes(&packed.codes)?,
7344        scales: engine.htod(&packed.scales)?,
7345        expert_range: packed.expert_range,
7346        out_features: packed.out_features,
7347        in_features: packed.in_features,
7348        code_stride: packed.code_stride,
7349        scale_stride: packed.scale_stride,
7350        k_blocks: packed.k_blocks,
7351    })
7352}
7353
7354fn pack_row_bank_rank(
7355    bank: E4m3ExpertBank<'_>,
7356    tp: usize,
7357    rank: usize,
7358) -> Result<PackedE4m3ExpertBankRank, String> {
7359    bank.validate()?;
7360    validate_row_bank_shape(bank, tp)?;
7361    if rank >= tp {
7362        return Err(format!("TP rank {rank} outside 0..{tp}"));
7363    }
7364    let local_in = bank.in_features / tp;
7365    let full_code_stride = bank.out_features * bank.in_features;
7366    let local_code_stride = bank.out_features * local_in;
7367    let full_scale_cols = bank.in_features.div_ceil(FP8_BLOCK);
7368    let local_scale_cols = local_in / FP8_BLOCK;
7369    let scale_rows = bank.out_features.div_ceil(FP8_BLOCK);
7370    let full_scale_stride = scale_rows * full_scale_cols;
7371    let local_scale_stride = scale_rows * local_scale_cols;
7372    let global_block_start = rank * local_scale_cols;
7373    let mut codes = Vec::with_capacity(bank.expert_count * local_code_stride);
7374    let mut scales = Vec::with_capacity(bank.expert_count * local_scale_stride);
7375    for expert in 0..bank.expert_count {
7376        let expert_code_start = expert * full_code_stride;
7377        let expert_scale_start = expert * full_scale_stride;
7378        for local_block in 0..local_scale_cols {
7379            let global_block = global_block_start + local_block;
7380            let column_start = global_block * FP8_BLOCK;
7381            for row in 0..bank.out_features {
7382                let start = expert_code_start + row * bank.in_features + column_start;
7383                codes.extend_from_slice(&bank.codes[start..start + FP8_BLOCK]);
7384            }
7385            for row in 0..scale_rows {
7386                scales.push(bank.scales[expert_scale_start + row * full_scale_cols + global_block]);
7387            }
7388        }
7389    }
7390    Ok(PackedE4m3ExpertBankRank {
7391        codes,
7392        scales,
7393        expert_range: 0..bank.expert_count,
7394        out_features: bank.out_features,
7395        in_features: local_in,
7396        code_stride: local_code_stride,
7397        scale_stride: local_scale_stride,
7398        k_blocks: Some(local_scale_cols),
7399    })
7400}
7401
7402fn validate_resident_ranks(engines: &[Engine], ranks: &[ResidentE4m3Rank]) -> Result<(), String> {
7403    if engines.len() != ranks.len() {
7404        return Err(format!(
7405            "resident TP rank count {} != runtime rank count {}",
7406            ranks.len(),
7407            engines.len()
7408        ));
7409    }
7410    for (rank, (engine, matrix)) in engines.iter().zip(ranks).enumerate() {
7411        let device = engine.ctx().ordinal();
7412        if matrix.codes.ordinal() != device || matrix.scales.ordinal() != device {
7413            return Err(format!(
7414                "resident TP rank {rank} is not owned by runtime device {device}"
7415            ));
7416        }
7417    }
7418    Ok(())
7419}
7420
7421fn validate_tp_bank_residency(
7422    engines: &[Engine],
7423    experts: &ResidentTpExpertBank,
7424) -> Result<(), String> {
7425    if engines.len() != experts.gate.len()
7426        || engines.len() != experts.up.len()
7427        || engines.len() != experts.down.len()
7428    {
7429        return Err(format!(
7430            "resident TP expert-bank rank counts gate={} up={} down={} != runtime {}",
7431            experts.gate.len(),
7432            experts.up.len(),
7433            experts.down.len(),
7434            engines.len()
7435        ));
7436    }
7437    for (rank, engine) in engines.iter().enumerate() {
7438        let device = engine.ctx().ordinal();
7439        for (projection, bank) in [
7440            ("gate", &experts.gate[rank]),
7441            ("up", &experts.up[rank]),
7442            ("down", &experts.down[rank]),
7443        ] {
7444            if bank.codes.ordinal() != device || bank.scales.ordinal() != device {
7445                return Err(format!(
7446                    "resident TP rank {rank} {projection} bank is not owned by runtime device \
7447                     {device}"
7448                ));
7449            }
7450        }
7451    }
7452    Ok(())
7453}
7454
7455fn validate_ep_residency(
7456    engines: &[Engine],
7457    experts: &ResidentExpertParallel,
7458) -> Result<(), String> {
7459    if engines.len() != experts.ranks.len() {
7460        return Err(format!(
7461            "resident EP rank count {} != runtime rank count {}",
7462            experts.ranks.len(),
7463            engines.len()
7464        ));
7465    }
7466    for (rank, (engine, resident)) in engines.iter().zip(&experts.ranks).enumerate() {
7467        let device = engine.ctx().ordinal();
7468        for (projection, bank) in [
7469            ("gate", &resident.gate),
7470            ("up", &resident.up),
7471            ("down", &resident.down),
7472        ] {
7473            if bank.codes.ordinal() != device || bank.scales.ordinal() != device {
7474                return Err(format!(
7475                    "resident EP rank {rank} {projection} bank is not owned by runtime device \
7476                     {device}"
7477                ));
7478            }
7479        }
7480    }
7481    Ok(())
7482}
7483
7484fn run_rank(
7485    engine: &Engine,
7486    matrix: E4m3BlockMatrix<'_>,
7487    activations: &[f32],
7488    tokens: usize,
7489) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
7490    let _main = engine.gpu.enter_main()?;
7491    let codes = engine.htod_bytes(matrix.codes)?;
7492    let scales = engine.htod(matrix.scales)?;
7493    let activations = engine.htod(activations)?;
7494    let output = engine.qmatvec_mmq_fp8_blk(
7495        &codes,
7496        &scales,
7497        &activations,
7498        tokens,
7499        matrix.in_features,
7500        matrix.out_features,
7501    )?;
7502    engine.dtoh(&output)
7503}
7504
7505fn run_resident_rank(
7506    engine: &Engine,
7507    matrix: &ResidentE4m3Rank,
7508    activations: &[f32],
7509    tokens: usize,
7510) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
7511    let _main = engine.gpu.enter_main()?;
7512    let activations = engine.htod(activations)?;
7513    let output = engine.qmatvec_mmq_fp8_blk(
7514        &matrix.codes,
7515        &matrix.scales,
7516        &activations,
7517        tokens,
7518        matrix.in_features,
7519        matrix.out_features,
7520    )?;
7521    engine.dtoh(&output)
7522}
7523
7524fn run_resident_bf16_rank(
7525    engine: &Engine,
7526    matrix: &ResidentBf16Rank,
7527    activations: &[f32],
7528    tokens: usize,
7529    canonical_chunk_rows: Option<usize>,
7530) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
7531    let _main = engine.gpu.enter_main()?;
7532    let activations = engine.htod(activations)?;
7533    let output = run_resident_bf16_rank_device(
7534        engine,
7535        matrix,
7536        &activations,
7537        tokens,
7538        canonical_chunk_rows,
7539        false,
7540    )?;
7541    engine.dtoh(&output)
7542}
7543
7544fn run_resident_bf16_rank_device(
7545    engine: &Engine,
7546    matrix: &ResidentBf16Rank,
7547    activations: &CudaSlice<f32>,
7548    tokens: usize,
7549    canonical_chunk_rows: Option<usize>,
7550    strided_chunk_output: bool,
7551) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
7552    let _main = engine.gpu.enter_main()?;
7553    if activations.ordinal() != engine.ctx().ordinal() {
7554        return Err(format!(
7555            "resident BF16 activation device {} != rank device {}",
7556            activations.ordinal(),
7557            engine.ctx().ordinal()
7558        )
7559        .into());
7560    }
7561    if activations.len() != tokens * matrix.in_features {
7562        return Err(format!(
7563            "resident BF16 activation count {} != {tokens}x{}",
7564            activations.len(),
7565            matrix.in_features
7566        )
7567        .into());
7568    }
7569    match (&matrix.weight, canonical_chunk_rows) {
7570        (ResidentBf16Weight::Bf16(bytes), Some(rows)) => engine
7571            .linear_bf16_resident_canonical_rows(
7572                activations,
7573                bytes,
7574                tokens,
7575                matrix.in_features,
7576                matrix.out_features,
7577                rows,
7578            ),
7579        (ResidentBf16Weight::Bf16(bytes), None) => engine.linear_bf16_resident(
7580            activations,
7581            bytes,
7582            tokens,
7583            matrix.in_features,
7584            matrix.out_features,
7585        ),
7586        (ResidentBf16Weight::F32(values), Some(rows)) if strided_chunk_output => engine
7587            .linear_f32_resident_canonical_rows_strided(
7588                activations,
7589                values,
7590                tokens,
7591                matrix.in_features,
7592                matrix.out_features,
7593                rows,
7594            ),
7595        (ResidentBf16Weight::F32(values), Some(rows)) => engine.linear_f32_resident_canonical_rows(
7596            activations,
7597            values,
7598            tokens,
7599            matrix.in_features,
7600            matrix.out_features,
7601            rows,
7602        ),
7603        (ResidentBf16Weight::F32(values), None) => engine.linear(
7604            activations,
7605            values,
7606            tokens,
7607            matrix.in_features,
7608            matrix.out_features,
7609        ),
7610    }
7611}
7612
7613fn validate_resident_bf16_ranks(
7614    engines: &[Engine],
7615    ranks: &[ResidentBf16Rank],
7616) -> Result<(), String> {
7617    if engines.len() != ranks.len() {
7618        return Err(format!(
7619            "resident BF16 TP rank count {} != runtime rank count {}",
7620            ranks.len(),
7621            engines.len(),
7622        ));
7623    }
7624    for (rank, (engine, matrix)) in engines.iter().zip(ranks).enumerate() {
7625        let device = engine.ctx().ordinal();
7626        if matrix.weight.ordinal() != device {
7627            return Err(format!(
7628                "resident BF16 TP rank {rank} is not owned by runtime device {device}"
7629            ));
7630        }
7631    }
7632    Ok(())
7633}
7634
7635fn validate_step_bf16_row_residency(
7636    engines: &[Engine],
7637    matrix: &ResidentStepBf16RowParallel,
7638) -> Result<(), String> {
7639    if engines.len() != matrix.ranks.len() {
7640        return Err(format!(
7641            "resident Step BF16 row rank count {} != runtime rank count {}",
7642            matrix.ranks.len(),
7643            engines.len(),
7644        ));
7645    }
7646    let canonical_cols = step_bf16_canonical_chunk_cols(matrix.in_features, engines.len())?;
7647    if matrix.canonical_chunk_cols != canonical_cols {
7648        return Err(format!(
7649            "resident Step BF16 row canonical columns {} != registered {canonical_cols}",
7650            matrix.canonical_chunk_cols
7651        ));
7652    }
7653    let blocks_per_rank = PRODUCT_MAX_CARDS / engines.len();
7654    for (rank, (engine, blocks)) in engines.iter().zip(&matrix.ranks).enumerate() {
7655        if blocks.len() != blocks_per_rank {
7656            return Err(format!(
7657                "resident Step BF16 row rank {rank} has {} blocks, expected {blocks_per_rank}",
7658                blocks.len()
7659            ));
7660        }
7661        let device = engine.ctx().ordinal();
7662        for (block, resident) in blocks.iter().enumerate() {
7663            if resident.weight.ordinal() != device
7664                || resident.in_features != canonical_cols
7665                || resident.out_features != matrix.out_features
7666            {
7667                return Err(format!(
7668                    "resident Step BF16 row rank {rank} block {block} has inconsistent \
7669                     device or geometry"
7670                ));
7671            }
7672        }
7673    }
7674    Ok(())
7675}
7676
7677fn validate_replicated_device_rows(
7678    engines: &[Engine],
7679    rows: &ResidentReplicatedDeviceRows,
7680) -> Result<(), String> {
7681    let rank_lengths = rows
7682        .ranks
7683        .iter()
7684        .map(|rank_rows| rank_rows.len())
7685        .collect::<Vec<_>>();
7686    replicated_device_row_values(rows.tokens, rows.width, engines.len(), &rank_lengths)?;
7687    if rows
7688        .ranks
7689        .iter()
7690        .zip(engines)
7691        .any(|(rank_rows, engine)| rank_rows.ordinal() != engine.ctx().ordinal())
7692    {
7693        return Err("replicated device rows are owned by the wrong CUDA contexts".into());
7694    }
7695    Ok(())
7696}
7697
7698fn replicated_device_row_values(
7699    tokens: usize,
7700    width: usize,
7701    expected_ranks: usize,
7702    rank_lengths: &[usize],
7703) -> Result<usize, String> {
7704    let values = tokens
7705        .checked_mul(width)
7706        .ok_or("replicated device row size overflow")?;
7707    if tokens == 0
7708        || width == 0
7709        || expected_ranks == 0
7710        || rank_lengths.len() != expected_ranks
7711        || rank_lengths.iter().any(|&rank_len| rank_len != values)
7712    {
7713        return Err(format!(
7714            "replicated device rows have inconsistent geometry tokens={} width={} ranks={}/{}",
7715            tokens,
7716            width,
7717            rank_lengths.len(),
7718            expected_ranks
7719        ));
7720    }
7721    Ok(values)
7722}
7723
7724fn replicated_device_row_source_values(
7725    tokens: usize,
7726    width: usize,
7727    source_len: usize,
7728    source_device: usize,
7729    root_device: usize,
7730) -> Result<usize, String> {
7731    let values = tokens
7732        .checked_mul(width)
7733        .ok_or("replicated device row size overflow")?;
7734    if tokens == 0 || width == 0 || source_len != values || source_device != root_device {
7735        return Err(format!(
7736            "replicated device row source has inconsistent geometry/device \
7737             tokens={tokens} width={width} source={source_len}@{source_device} root={root_device}"
7738        ));
7739    }
7740    Ok(values)
7741}
7742
7743fn bf16_column_shard(
7744    matrix: Bf16Matrix<'_>,
7745    tp: usize,
7746    rank: usize,
7747) -> Result<Bf16Matrix<'_>, String> {
7748    matrix.validate()?;
7749    if tp == 0 || rank >= tp || matrix.out_features % tp != 0 {
7750        return Err(format!(
7751            "invalid BF16 column shard out={} TP={tp} rank={rank}",
7752            matrix.out_features
7753        ));
7754    }
7755    let local_out = matrix.out_features / tp;
7756    let row_bytes = matrix.in_features * 2;
7757    let start = rank * local_out * row_bytes;
7758    Ok(Bf16Matrix {
7759        bytes: &matrix.bytes[start..start + local_out * row_bytes],
7760        out_features: local_out,
7761        in_features: matrix.in_features,
7762    })
7763}
7764
7765fn bf16_row_shard(matrix: Bf16Matrix<'_>, tp: usize, rank: usize) -> Result<Vec<u8>, String> {
7766    matrix.validate()?;
7767    if tp == 0 || rank >= tp || matrix.in_features % tp != 0 {
7768        return Err(format!(
7769            "invalid BF16 row shard in={} TP={tp} rank={rank}",
7770            matrix.in_features
7771        ));
7772    }
7773    let local_in = matrix.in_features / tp;
7774    let mut bytes = Vec::with_capacity(matrix.out_features * local_in * 2);
7775    for row in 0..matrix.out_features {
7776        let start = (row * matrix.in_features + rank * local_in) * 2;
7777        bytes.extend_from_slice(&matrix.bytes[start..start + local_in * 2]);
7778    }
7779    Ok(bytes)
7780}
7781
7782fn bf16_row_block(
7783    matrix: Bf16Matrix<'_>,
7784    col_start: usize,
7785    block_cols: usize,
7786) -> Result<Vec<u8>, String> {
7787    matrix.validate()?;
7788    let col_end = col_start
7789        .checked_add(block_cols)
7790        .ok_or("BF16 row block column overflow")?;
7791    if block_cols == 0 || col_end > matrix.in_features {
7792        return Err(format!(
7793            "invalid BF16 row block columns {col_start}..{col_end} for input width {}",
7794            matrix.in_features
7795        ));
7796    }
7797    let mut bytes = Vec::with_capacity(matrix.out_features * block_cols * 2);
7798    for row in 0..matrix.out_features {
7799        let start = (row * matrix.in_features + col_start) * 2;
7800        bytes.extend_from_slice(&matrix.bytes[start..start + block_cols * 2]);
7801    }
7802    Ok(bytes)
7803}
7804
7805fn run_resident_bank_expert(
7806    engine: &Engine,
7807    bank: &ResidentE4m3ExpertBankRank,
7808    local_expert: usize,
7809    activations: &[f32],
7810    tokens: usize,
7811) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
7812    let _main = engine.gpu.enter_main()?;
7813    if bank.k_blocks.is_some() {
7814        return Err("block-major TP row bank requires canonical block execution".into());
7815    }
7816    let local_count = bank.expert_range.end - bank.expert_range.start;
7817    if local_expert >= local_count {
7818        return Err(format!(
7819            "local EP expert {local_expert} outside 0..{local_count} for range {:?}",
7820            bank.expert_range
7821        )
7822        .into());
7823    }
7824    validate_activations(activations, tokens, bank.in_features)?;
7825    let activations = engine.htod(activations)?;
7826    let weight = bank
7827        .codes
7828        .slice(local_expert * bank.code_stride..(local_expert + 1) * bank.code_stride);
7829    let scales = bank
7830        .scales
7831        .slice(local_expert * bank.scale_stride..(local_expert + 1) * bank.scale_stride);
7832    let input = activations.slice(0..activations.len());
7833    let output = engine.qmatvec_mmq_fp8_blk_view(
7834        &weight,
7835        &scales,
7836        &input,
7837        tokens,
7838        bank.in_features,
7839        bank.out_features,
7840    )?;
7841    engine.dtoh(&output)
7842}
7843
7844fn run_resident_bank_expert_block(
7845    engine: &Engine,
7846    bank: &ResidentE4m3ExpertBankRank,
7847    local_expert: usize,
7848    block: usize,
7849    activations: &[f32],
7850) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
7851    let _main = engine.gpu.enter_main()?;
7852    let local_count = bank.expert_range.end - bank.expert_range.start;
7853    if local_expert >= local_count {
7854        return Err(format!(
7855            "local TP expert {local_expert} outside 0..{local_count} for range {:?}",
7856            bank.expert_range
7857        )
7858        .into());
7859    }
7860    let blocks = bank
7861        .k_blocks
7862        .ok_or("TP row bank is not packed in native K-block order")?;
7863    if block >= blocks {
7864        return Err(format!("TP row block {block} outside 0..{blocks}").into());
7865    }
7866    validate_activations(activations, 1, FP8_BLOCK)?;
7867    let block_code_stride = bank.out_features * FP8_BLOCK;
7868    let block_scale_stride = bank.out_features.div_ceil(FP8_BLOCK);
7869    if bank.in_features != blocks * FP8_BLOCK
7870        || bank.code_stride != blocks * block_code_stride
7871        || bank.scale_stride != blocks * block_scale_stride
7872    {
7873        return Err("TP row bank block-major geometry is inconsistent".into());
7874    }
7875
7876    let expert_code_start = local_expert * bank.code_stride;
7877    let expert_scale_start = local_expert * bank.scale_stride;
7878    let weight = bank.codes.slice(
7879        expert_code_start + block * block_code_stride
7880            ..expert_code_start + (block + 1) * block_code_stride,
7881    );
7882    let scales = bank.scales.slice(
7883        expert_scale_start + block * block_scale_stride
7884            ..expert_scale_start + (block + 1) * block_scale_stride,
7885    );
7886    let activations = engine.htod(activations)?;
7887    let input = activations.slice(0..activations.len());
7888    let output = engine.qmatvec_mmq_fp8_blk_view(
7889        &weight,
7890        &scales,
7891        &input,
7892        1,
7893        FP8_BLOCK,
7894        bank.out_features,
7895    )?;
7896    engine.dtoh(&output)
7897}
7898
7899fn run_resident_bank_expert_device(
7900    engine: &Engine,
7901    bank: &ResidentE4m3ExpertBankRank,
7902    local_expert: usize,
7903    activations: &CudaSlice<f32>,
7904    tokens: usize,
7905) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
7906    let _main = engine.gpu.enter_main()?;
7907    if bank.k_blocks.is_some() {
7908        return Err("block-major TP row bank requires canonical block execution".into());
7909    }
7910    let local_count = bank.expert_range.end - bank.expert_range.start;
7911    if local_expert >= local_count {
7912        return Err(format!(
7913            "local TP expert {local_expert} outside 0..{local_count} for range {:?}",
7914            bank.expert_range
7915        )
7916        .into());
7917    }
7918    let expected = tokens
7919        .checked_mul(bank.in_features)
7920        .ok_or("native TP activation size overflow")?;
7921    if activations.len() != expected || activations.ordinal() != engine.ctx().ordinal() {
7922        return Err(format!(
7923            "native TP activation len/device {}/{} != expected {expected}/{}",
7924            activations.len(),
7925            activations.ordinal(),
7926            engine.ctx().ordinal()
7927        )
7928        .into());
7929    }
7930    let weight = bank
7931        .codes
7932        .slice(local_expert * bank.code_stride..(local_expert + 1) * bank.code_stride);
7933    let scales = bank
7934        .scales
7935        .slice(local_expert * bank.scale_stride..(local_expert + 1) * bank.scale_stride);
7936    let input = activations.slice(0..activations.len());
7937    engine.qmatvec_mmq_fp8_blk_view(
7938        &weight,
7939        &scales,
7940        &input,
7941        tokens,
7942        bank.in_features,
7943        bank.out_features,
7944    )
7945}
7946
7947fn run_resident_bank_expert_block_device(
7948    engine: &Engine,
7949    bank: &ResidentE4m3ExpertBankRank,
7950    local_expert: usize,
7951    block: usize,
7952    activations: &cudarc::driver::CudaView<'_, f32>,
7953) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
7954    let _main = engine.gpu.enter_main()?;
7955    let local_count = bank.expert_range.end - bank.expert_range.start;
7956    if local_expert >= local_count {
7957        return Err(format!(
7958            "local TP expert {local_expert} outside 0..{local_count} for range {:?}",
7959            bank.expert_range
7960        )
7961        .into());
7962    }
7963    let blocks = bank
7964        .k_blocks
7965        .ok_or("native TP row bank is not packed in checkpoint-block order")?;
7966    if block >= blocks {
7967        return Err(format!("native TP row block {block} outside 0..{blocks}").into());
7968    }
7969    let activation_device = activations.stream().context().ordinal();
7970    if activations.len() != FP8_BLOCK || activation_device != engine.ctx().ordinal() {
7971        return Err(format!(
7972            "native TP block activation len/device {}/{} != expected {FP8_BLOCK}/{}",
7973            activations.len(),
7974            activation_device,
7975            engine.ctx().ordinal()
7976        )
7977        .into());
7978    }
7979    let block_code_stride = bank.out_features * FP8_BLOCK;
7980    let block_scale_stride = bank.out_features.div_ceil(FP8_BLOCK);
7981    if bank.in_features != blocks * FP8_BLOCK
7982        || bank.code_stride != blocks * block_code_stride
7983        || bank.scale_stride != blocks * block_scale_stride
7984    {
7985        return Err("native TP row bank block-major geometry is inconsistent".into());
7986    }
7987    let expert_code_start = local_expert * bank.code_stride;
7988    let expert_scale_start = local_expert * bank.scale_stride;
7989    let weight = bank.codes.slice(
7990        expert_code_start + block * block_code_stride
7991            ..expert_code_start + (block + 1) * block_code_stride,
7992    );
7993    let scales = bank.scales.slice(
7994        expert_scale_start + block * block_scale_stride
7995            ..expert_scale_start + (block + 1) * block_scale_stride,
7996    );
7997    engine.qmatvec_mmq_fp8_blk_view(
7998        &weight,
7999        &scales,
8000        activations,
8001        1,
8002        FP8_BLOCK,
8003        bank.out_features,
8004    )
8005}
8006
8007fn configure_native_p2p(
8008    ranks: &[Engine],
8009    devices: &[usize],
8010) -> Result<(), Box<dyn std::error::Error>> {
8011    if ranks.len() != devices.len() || ranks.len() < 2 {
8012        return Err("native TP P2P setup requires matching multi-rank devices".into());
8013    }
8014    for (rank, (&device, engine)) in devices.iter().zip(ranks).enumerate() {
8015        if engine.ctx().ordinal() != device {
8016            return Err(format!(
8017                "native TP rank {rank} context device {} != requested device {device}",
8018                engine.ctx().ordinal()
8019            )
8020            .into());
8021        }
8022    }
8023
8024    for src in 0..ranks.len() {
8025        for dst in 0..ranks.len() {
8026            if src == dst {
8027                continue;
8028            }
8029            let mut can_access = 0;
8030            unsafe {
8031                cudarc::driver::sys::cuDeviceCanAccessPeer(
8032                    &mut can_access,
8033                    ranks[src].ctx().cu_device(),
8034                    ranks[dst].ctx().cu_device(),
8035                )
8036                .result()?;
8037            }
8038            if can_access == 0 {
8039                return Err(format!(
8040                    "native TP requires P2P, but dev{} cannot access dev{}",
8041                    devices[src], devices[dst]
8042                )
8043                .into());
8044            }
8045            ranks[src].ctx().bind_to_thread()?;
8046            let rc =
8047                unsafe { cudarc::driver::sys::cuCtxEnablePeerAccess(ranks[dst].ctx().cu_ctx(), 0) };
8048            use cudarc::driver::sys::cudaError_enum as E;
8049            if rc != E::CUDA_SUCCESS && rc != E::CUDA_ERROR_PEER_ACCESS_ALREADY_ENABLED {
8050                return Err(format!(
8051                    "native TP cuCtxEnablePeerAccess(dev{} -> dev{}) failed: {rc:?}",
8052                    devices[src], devices[dst]
8053                )
8054                .into());
8055            }
8056        }
8057    }
8058
8059    for &owner in devices {
8060        for &accessor in devices {
8061            if owner == accessor {
8062                continue;
8063            }
8064            let device = cudarc::driver::result::device::get(owner as i32)?;
8065            let mut pool: cudarc::driver::sys::CUmemoryPool = std::ptr::null_mut();
8066            unsafe {
8067                cudarc::driver::sys::cuDeviceGetDefaultMemPool(&mut pool, device).result()?;
8068            }
8069            let desc = cudarc::driver::sys::CUmemAccessDesc {
8070                location: cudarc::driver::sys::CUmemLocation {
8071                    type_: cudarc::driver::sys::CUmemLocationType::CU_MEM_LOCATION_TYPE_DEVICE,
8072                    id: accessor as i32,
8073                },
8074                flags: cudarc::driver::sys::CUmemAccess_flags::CU_MEM_ACCESS_FLAGS_PROT_READWRITE,
8075            };
8076            let rc = unsafe { cudarc::driver::sys::cuMemPoolSetAccess(pool, &desc, 1) };
8077            if rc != cudarc::driver::sys::cudaError_enum::CUDA_SUCCESS {
8078                return Err(format!(
8079                    "native TP cuMemPoolSetAccess(dev{owner} pool -> dev{accessor}) failed: \
8080                     {rc:?}"
8081                )
8082                .into());
8083            }
8084        }
8085    }
8086
8087    for src in 0..ranks.len() {
8088        for dst in 0..ranks.len() {
8089            if src == dst {
8090                continue;
8091            }
8092            let expected = (0..NATIVE_P2P_PROBE_WORDS)
8093                .map(|index| {
8094                    (index as u32)
8095                        .wrapping_mul(0x9e37_79b9)
8096                        .wrapping_add(((src as u32) << 16) | dst as u32)
8097                })
8098                .collect::<Vec<_>>();
8099            let poison = expected.iter().map(|value| !value).collect::<Vec<_>>();
8100            let source = ranks[src].htod_u32_v(&expected)?;
8101            let mut destination = ranks[dst].htod_u32_v(&poison)?;
8102            ranks[dst].stream().memcpy_dtod(&source, &mut destination)?;
8103            let actual = ranks[dst].dtoh_u32(&destination)?;
8104            if actual != expected {
8105                let mismatches = actual
8106                    .iter()
8107                    .zip(&expected)
8108                    .filter(|(actual, expected)| actual != expected)
8109                    .count();
8110                return Err(format!(
8111                    "native TP peer probe dev{}->dev{} failed: {mismatches}/{} words differ",
8112                    devices[src],
8113                    devices[dst],
8114                    expected.len()
8115                )
8116                .into());
8117            }
8118        }
8119    }
8120    ranks[0].ctx().bind_to_thread()?;
8121    eprintln!(
8122        "[tp] native peer byte-integrity probe PASS: devices={devices:?} \
8123         directions={} bytes={} mismatches=0",
8124        ranks.len() * (ranks.len() - 1),
8125        NATIVE_P2P_PROBE_WORDS * std::mem::size_of::<u32>(),
8126    );
8127    Ok(())
8128}
8129
8130fn validate_activations(
8131    activations: &[f32],
8132    tokens: usize,
8133    in_features: usize,
8134) -> Result<(), String> {
8135    let expected = tokens
8136        .checked_mul(in_features)
8137        .ok_or_else(|| "activation size overflow".to_string())?;
8138    if activations.len() != expected {
8139        return Err(format!(
8140            "activation count {} != {tokens}x{in_features} ({expected})",
8141            activations.len()
8142        ));
8143    }
8144    if !activations.iter().all(|value| value.is_finite()) {
8145        return Err("activations contain a non-finite value".to_string());
8146    }
8147    Ok(())
8148}
8149
8150fn column_shard(
8151    matrix: E4m3BlockMatrix<'_>,
8152    tp: usize,
8153    rank: usize,
8154) -> Result<E4m3BlockMatrix<'_>, String> {
8155    let local_out = matrix.out_features / tp;
8156    let row_start = rank * local_out;
8157    let code_start = row_start * matrix.in_features;
8158    let code_end = code_start + local_out * matrix.in_features;
8159    let scale_cols = matrix.in_features.div_ceil(FP8_BLOCK);
8160    let local_scale_rows = local_out / FP8_BLOCK;
8161    let scale_start = rank * local_scale_rows * scale_cols;
8162    let scale_end = scale_start + local_scale_rows * scale_cols;
8163    Ok(E4m3BlockMatrix {
8164        codes: &matrix.codes[code_start..code_end],
8165        scales: &matrix.scales[scale_start..scale_end],
8166        out_features: local_out,
8167        in_features: matrix.in_features,
8168    })
8169}
8170
8171fn row_shard(
8172    matrix: E4m3BlockMatrix<'_>,
8173    tp: usize,
8174    rank: usize,
8175) -> Result<(Vec<u8>, Vec<f32>), String> {
8176    let local_in = matrix.in_features / tp;
8177    let col_start = rank * local_in;
8178    let mut codes = Vec::with_capacity(matrix.out_features * local_in);
8179    for row in 0..matrix.out_features {
8180        let start = row * matrix.in_features + col_start;
8181        codes.extend_from_slice(&matrix.codes[start..start + local_in]);
8182    }
8183
8184    let scale_rows = matrix.out_features.div_ceil(FP8_BLOCK);
8185    let scale_cols = matrix.in_features.div_ceil(FP8_BLOCK);
8186    let local_scale_cols = local_in / FP8_BLOCK;
8187    let scale_col_start = rank * local_scale_cols;
8188    let mut scales = Vec::with_capacity(scale_rows * local_scale_cols);
8189    for row in 0..scale_rows {
8190        let start = row * scale_cols + scale_col_start;
8191        scales.extend_from_slice(&matrix.scales[start..start + local_scale_cols]);
8192    }
8193    Ok((codes, scales))
8194}
8195
8196fn activation_shard(
8197    activations: &[f32],
8198    tokens: usize,
8199    in_features: usize,
8200    tp: usize,
8201    rank: usize,
8202) -> Vec<f32> {
8203    let local_in = in_features / tp;
8204    let col_start = rank * local_in;
8205    let mut shard = Vec::with_capacity(tokens * local_in);
8206    for token in 0..tokens {
8207        let start = token * in_features + col_start;
8208        shard.extend_from_slice(&activations[start..start + local_in]);
8209    }
8210    shard
8211}
8212
8213// ─── Step NVFP4 expert TP program (official Step-3.7-Flash-NVFP4 checkpoint class) ─────────────
8214//
8215// The routed experts of the NVFP4 checkpoint are modelopt-packed: e2m1 codes (2/byte), per-16
8216// UE4M3 sub-scales, and a per-EXPERT `weight_scale_2` f32 macro (~1e-5..1e-4, LOAD-BEARING).
8217// Rank compute repacks each shard host-side into memra block_nvfp4 rows (nibble reorder only —
8218// value-exact, see nvfp4_repack.rs) and runs the proven `qmatvec_nvfp4_fast` dp4a kernel; the
8219// activation q8_1 quantization uses per-32 blocks, and every shard cut here is 64-aligned, so a
8220// rank-local partial is bit-identical to the corresponding slice of the unsharded kernel.
8221//
8222// MACRO CANONICAL ORDER: the macro multiplies each assembled f32 output exactly ONCE — after the
8223// column gather (gate/up) and after the FULL row-parallel reduce (down), never per-partial.
8224// `(a + b) * m` and `a * m + b * m` differ in f32, so applying it per-rank would break the
8225// TP1-vs-TP2 bit gate. Every entry point below follows this order.
8226//
8227// TP2 shard legality is NVFP4-native: column parallelism splits whole output rows (scale rows
8228// ride along, nothing cuts), row parallelism splits input columns at 64-element superblock
8229// boundaries (16-element scale groups nest inside). The 128-block E4M3 constraint does not apply.
8230
8231/// One expert's modelopt NVFP4 projection: packed codes + per-16 UE4M3 scale bytes + macro.
8232#[derive(Clone, Copy)]
8233pub struct Nvfp4BlockMatrix<'a> {
8234    pub codes: &'a [u8],  // [out_features, in_features/2] packed e2m1, row-major
8235    pub scales: &'a [u8], // [out_features, in_features/16] UE4M3 bytes, row-major
8236    pub macro_scale: f32, // per-expert weight_scale_2 dequant multiplier
8237    pub out_features: usize,
8238    pub in_features: usize,
8239}
8240
8241impl Nvfp4BlockMatrix<'_> {
8242    pub fn validate(&self) -> Result<(), String> {
8243        if self.in_features == 0 || self.out_features == 0 {
8244            return Err("NVFP4 matrix has a zero dimension".to_string());
8245        }
8246        if self.in_features % 64 != 0 {
8247            return Err(format!(
8248                "NVFP4 in_features {} is not 64-aligned (memra block_nvfp4 superblock)",
8249                self.in_features
8250            ));
8251        }
8252        if self.codes.len() != self.out_features * self.in_features / 2 {
8253            return Err(format!(
8254                "NVFP4 code bytes {} != {}x{}/2",
8255                self.codes.len(),
8256                self.out_features,
8257                self.in_features
8258            ));
8259        }
8260        if self.scales.len() != self.out_features * self.in_features / 16 {
8261            return Err(format!(
8262                "NVFP4 scale bytes {} != {}x{}/16",
8263                self.scales.len(),
8264                self.out_features,
8265                self.in_features
8266            ));
8267        }
8268        if !self.macro_scale.is_finite() || self.macro_scale <= 0.0 {
8269            return Err(format!(
8270                "NVFP4 macro scale {} is not finite-positive",
8271                self.macro_scale
8272            ));
8273        }
8274        Ok(())
8275    }
8276}
8277
8278/// Stacked modelopt NVFP4 expert bank (host view over the checkpoint bytes).
8279#[derive(Clone, Copy)]
8280pub struct Nvfp4ExpertBank<'a> {
8281    pub codes: &'a [u8],   // [expert_count, out_features, in_features/2]
8282    pub scales: &'a [u8],  // [expert_count, out_features, in_features/16]
8283    pub macros: &'a [f32], // [expert_count] weight_scale_2
8284    pub expert_count: usize,
8285    pub out_features: usize,
8286    pub in_features: usize,
8287}
8288
8289impl Nvfp4ExpertBank<'_> {
8290    pub fn validate(&self) -> Result<(), String> {
8291        if self.expert_count == 0 {
8292            return Err("NVFP4 expert bank is empty".to_string());
8293        }
8294        if self.macros.len() != self.expert_count {
8295            return Err(format!(
8296                "NVFP4 bank macros {} != expert count {}",
8297                self.macros.len(),
8298                self.expert_count
8299            ));
8300        }
8301        self.expert(0).map(|_| ())
8302    }
8303
8304    pub fn expert(&self, expert: usize) -> Result<Nvfp4BlockMatrix<'_>, String> {
8305        if expert >= self.expert_count {
8306            return Err(format!("expert {expert} outside 0..{}", self.expert_count));
8307        }
8308        let code_stride = self.out_features * self.in_features / 2;
8309        let scale_stride = self.out_features * self.in_features / 16;
8310        if self.codes.len() != self.expert_count * code_stride
8311            || self.scales.len() != self.expert_count * scale_stride
8312        {
8313            return Err("NVFP4 bank byte extents do not match the declared geometry".to_string());
8314        }
8315        let matrix = Nvfp4BlockMatrix {
8316            codes: &self.codes[expert * code_stride..(expert + 1) * code_stride],
8317            scales: &self.scales[expert * scale_stride..(expert + 1) * scale_stride],
8318            macro_scale: self.macros[expert],
8319            out_features: self.out_features,
8320            in_features: self.in_features,
8321        };
8322        matrix.validate()?;
8323        Ok(matrix)
8324    }
8325}
8326
8327/// One rank's resident repacked NVFP4 shard: memra block_nvfp4 rows on device.
8328pub struct ResidentNvfp4Rank {
8329    blocks: crate::CudaSlice<u8>,
8330    macro_scale: f32,
8331    out_features: usize,
8332    in_features: usize,
8333    row_bytes: usize,
8334}
8335
8336pub struct ResidentNvfp4ColumnParallel {
8337    ranks: Vec<ResidentNvfp4Rank>,
8338    pub out_features: usize,
8339    pub in_features: usize,
8340}
8341
8342pub struct ResidentNvfp4RowParallel {
8343    ranks: Vec<ResidentNvfp4Rank>,
8344    pub out_features: usize,
8345    pub in_features: usize,
8346}
8347
8348pub struct ResidentTpNvfp4Expert {
8349    gate: ResidentNvfp4ColumnParallel,
8350    up: ResidentNvfp4ColumnParallel,
8351    down: ResidentNvfp4RowParallel,
8352    pub input_width: usize,
8353    pub expert_width: usize,
8354}
8355
8356/// One rank's resident NVFP4 expert bank shard: one repacked block buffer PER expert (per-expert
8357/// device allocations keep this increment off any new strided-kernel API; the strided twin is a
8358/// later perf rung, mirroring the FP8 bank's history).
8359pub struct ResidentNvfp4ColumnBankRank {
8360    /// Contiguous per-rank expert bank: `expert_count` repacked shards of `expert_bytes` each.
8361    /// Contiguity is what lets the device-routes program cover every selected expert with ONE
8362    /// launch (`qmatvec_nvfp4_dp4a_sel` indexes `sel[t] * expert_bytes`).
8363    bank: crate::CudaSlice<u8>,
8364    expert_bytes: usize,
8365    local_out: usize,
8366    in_features: usize,
8367    row_bytes: usize,
8368}
8369
8370impl ResidentNvfp4ColumnBankRank {
8371    fn expert(&self, index: usize) -> cudarc::driver::CudaView<'_, u8> {
8372        self.bank
8373            .slice(index * self.expert_bytes..(index + 1) * self.expert_bytes)
8374    }
8375}
8376
8377/// Canonical row-shard count for the NVFP4 down projection. The down reduction ALWAYS executes
8378/// as exactly this many input-column windows summed in shard order, at every world size: a
8379/// single full-width dot and a two-half-dots-plus-add differ in f32 parenthesization, so pinning
8380/// the shard grid (not the world size) is what makes the TP1-oracle-vs-TP2 bit gate meaningful.
8381/// This is the NVFP4 twin of the FP8 bank's canonical checkpoint-block reduction.
8382pub const NVFP4_CANONICAL_ROW_SHARDS: usize = 2;
8383
8384pub struct ResidentNvfp4RowBankRank {
8385    /// Contiguous per-shard expert bank (see `ResidentNvfp4ColumnBankRank::bank`).
8386    bank: crate::CudaSlice<u8>,
8387    expert_bytes: usize,
8388    device_rank: usize, // index into the runtime's rank engines this canonical shard lives on
8389    out_features: usize,
8390    local_in: usize,
8391    row_bytes: usize,
8392}
8393
8394impl ResidentNvfp4RowBankRank {
8395    fn expert(&self, index: usize) -> cudarc::driver::CudaView<'_, u8> {
8396        self.bank
8397            .slice(index * self.expert_bytes..(index + 1) * self.expert_bytes)
8398    }
8399}
8400
8401impl ResidentNvfp4TensorParallel {
8402    pub(crate) fn device_workspace_handle(
8403        &self,
8404    ) -> &std::sync::Mutex<Option<Nvfp4DeviceRoutesWorkspace>> {
8405        &self.device_workspace
8406    }
8407}
8408
8409pub struct ResidentNvfp4TensorParallel {
8410    gate: Vec<ResidentNvfp4ColumnBankRank>,
8411    up: Vec<ResidentNvfp4ColumnBankRank>,
8412    down: Vec<ResidentNvfp4RowBankRank>,
8413    macros_gate: Vec<f32>,
8414    macros_up: Vec<f32>,
8415    macros_down: Vec<f32>,
8416    /// Per-rank device copies of the gate/up macro-scales (E f32 each), indexed by the
8417    /// batched SwiGLU kernel via the selection array. Down macros stay host-side — they fold
8418    /// into the route-weight axpy scalar.
8419    macros_gate_dev: Vec<crate::CudaSlice<f32>>,
8420    macros_up_dev: Vec<crate::CudaSlice<f32>>,
8421    macros_down_dev: Vec<crate::CudaSlice<f32>>,
8422    pub expert_count: usize,
8423    pub input_width: usize,
8424    pub expert_width: usize,
8425    /// Lazily-built persistent decode workspace (device routes program). Interior mutability
8426    /// mirrors StepEpGroupedDecode: the forward holds the bank behind a shared reference.
8427    device_workspace: std::sync::Mutex<Option<Nvfp4DeviceRoutesWorkspace>>,
8428    /// Lazily-built spec-verify t=2 workspace (MEMRA_TCOL_FFN): the two-column routed
8429    /// sweep's slabs and events, kept apart from the serving workspace so the verify walk
8430    /// never perturbs serving state.
8431    t2_workspace: std::sync::Mutex<Option<Nvfp4T2Workspace>>,
8432    /// MEMRA_STEP_NVFP4_EP2: the rank banks above hold WHOLE experts (owner = id & 1,
8433    /// slot = id >> 1) at full width instead of TP shards. Consumers must branch on this;
8434    /// shard-semantics paths refuse loudly.
8435    pub(crate) ep2: bool,
8436}
8437
8438/// Persistent buffers for the two-column (spec verify) NVFP4 device-routed program: every
8439/// slab is the t=1 workspace shape doubled along the pair axis, plus per-column
8440/// accumulators. One per expert bank, reused every (round, layer) call.
8441pub struct Nvfp4T2Workspace {
8442    input2: Vec<crate::CudaSlice<f32>>,
8443    in_q2: Vec<crate::CudaSlice<i8>>,
8444    in_d2: Vec<crate::CudaSlice<f32>>,
8445    sel2: Vec<crate::CudaSlice<i32>>,
8446    route_w2: Vec<crate::CudaSlice<f32>>,
8447    gate_out2: Vec<crate::CudaSlice<f32>>,
8448    up_out2: Vec<crate::CudaSlice<f32>>,
8449    act_q2: Vec<crate::CudaSlice<i8>>,
8450    act_d2: Vec<crate::CudaSlice<f32>>,
8451    partial2: Vec<crate::CudaSlice<f32>>,
8452    /// Per-rank per-column combine accumulators ([width] each).
8453    acc_a: Vec<crate::CudaSlice<f32>>,
8454    acc_b: Vec<crate::CudaSlice<f32>>,
8455    /// down8_t2 arm: per-rank [2, width] combined slab, root peer pull and joined slab —
8456    /// the fused kernel writes both columns, so the join is ONE pull + ONE add.
8457    acc2: Vec<crate::CudaSlice<f32>>,
8458    peer2: crate::CudaSlice<f32>,
8459    omix2: crate::CudaSlice<f32>,
8460    /// Root-side pulls of rank1's accumulators and the joined columns.
8461    peer_a: crate::CudaSlice<f32>,
8462    peer_b: crate::CudaSlice<f32>,
8463    omix_a: crate::CudaSlice<f32>,
8464    omix_b: crate::CudaSlice<f32>,
8465    ev_entry: CudaEvent,
8466    ev_rank: Vec<CudaEvent>,
8467    ev_root: CudaEvent,
8468    n_sel: usize,
8469    e_device: usize,
8470}
8471
8472/// Persistent per-call device buffers for the NVFP4 device routes program: one gate/up output,
8473/// one down partial, and one shard accumulator per rank, plus root combine staging. Reused every
8474/// (token, layer) call so the decode loop performs zero output allocations.
8475/// A stitched multi-device parent graph for one layer's device-routed expert program, plus
8476/// the children it was built from (retained: AddChildGraphNode clones, but the probe retains
8477/// conservatively) and the persistent e-context input staging its copies read.
8478struct RoutesGraph {
8479    exec: cudarc::driver::sys::CUgraphExec,
8480    parent: cudarc::driver::sys::CUgraph,
8481    _children: Vec<cudarc::driver::CudaGraph>,
8482}
8483// SAFETY: the raw handles are only used from the single decode thread; CUDA graph handles are
8484// context-agnostic process handles.
8485unsafe impl Send for RoutesGraph {}
8486
8487impl Drop for RoutesGraph {
8488    fn drop(&mut self) {
8489        unsafe {
8490            let _ = cudarc::driver::sys::cuGraphExecDestroy(self.exec);
8491            let _ = cudarc::driver::sys::cuGraphDestroy(self.parent);
8492        }
8493    }
8494}
8495
8496impl Nvfp4DeviceRoutesWorkspace {
8497    pub(crate) fn in_stage_handle(&self) -> Option<&crate::CudaSlice<f32>> {
8498        self.in_stage_e.as_ref()
8499    }
8500    pub(crate) fn in_stage_mut(&mut self) -> Option<&mut crate::CudaSlice<f32>> {
8501        self.in_stage_e.as_mut()
8502    }
8503    pub(crate) fn out_stage_mut(&mut self) -> Option<&mut crate::CudaSlice<f32>> {
8504        self.out_stage_e.as_mut()
8505    }
8506    /// Arm the e-context stages + router staging pair when absent (token-graph entry).
8507    pub(crate) fn arm_stages(
8508        &mut self,
8509        e: &Engine,
8510        width: usize,
8511        n_sel: usize,
8512    ) -> Result<(), Box<dyn std::error::Error>> {
8513        let _main = e.gpu.enter_main()?;
8514        if self.in_stage_e.is_none() {
8515            self.in_stage_e = Some(e.htod(&vec![0.0f32; width])?);
8516            self.out_stage_e = Some(e.htod(&vec![0.0f32; width])?);
8517        }
8518        if self.dev_route_e.is_none() {
8519            self.dev_route_e = Some((
8520                e.htod_i32(&vec![0i32; n_sel])?,
8521                e.htod(&vec![0.0f32; n_sel])?,
8522            ));
8523        }
8524        Ok(())
8525    }
8526
8527    /// Split-borrow: the routes input (shared) + output (mut) stages together.
8528    pub(crate) fn in_and_out_stages_mut(
8529        &mut self,
8530    ) -> Option<(&crate::CudaSlice<f32>, &mut crate::CudaSlice<f32>)> {
8531        match (self.in_stage_e.as_ref(), self.out_stage_e.as_mut()) {
8532            (Some(input), Some(output)) => Some((input, output)),
8533            _ => None,
8534        }
8535    }
8536    pub(crate) fn dev_route_e_mut(
8537        &mut self,
8538    ) -> Option<(&mut crate::CudaSlice<i32>, &mut crate::CudaSlice<f32>)> {
8539        self.dev_route_e.as_mut().map(|(a, b)| (a, b))
8540    }
8541}
8542
8543pub struct Nvfp4DeviceRoutesWorkspace {
8544    /// [n_sel, local_out] batched gate/up outputs and the SwiGLU q8_1 pair; [n_sel, width]
8545    /// down partials. Sized for `n_sel` selected experts per token (pinned at first call).
8546    gate_out: Vec<crate::CudaSlice<f32>>,
8547    up_out: Vec<crate::CudaSlice<f32>>,
8548    act_q: Vec<crate::CudaSlice<i8>>,
8549    act_d: Vec<crate::CudaSlice<f32>>,
8550    sel: Vec<crate::CudaSlice<i32>>,
8551    partial: Vec<crate::CudaSlice<f32>>,
8552    accumulator: Vec<crate::CudaSlice<f32>>,
8553    /// Per-rank folded combine weights (route_weight x down macro), one htod per call.
8554    combine_w: Vec<crate::CudaSlice<f32>>,
8555    /// Device-routed extension: per-rank raw route weights (the down-macro fold happens
8556    /// in-kernel via sel + macros_down_dev).
8557    route_w: Vec<crate::CudaSlice<f32>>,
8558    /// Persistent q8_1 pair of the shared layer input (one quantize per rank per call, no
8559    /// per-call allocation).
8560    in_q: Vec<crate::CudaSlice<i8>>,
8561    in_d: Vec<crate::CudaSlice<f32>>,
8562    /// e-context staging for the device router outputs (persistent — rank streams peer-read
8563    /// them, so the router's fresh outputs are copied here on e's stream first; the pp.rs
8564    /// never-free discipline).
8565    dev_route_e: Option<(crate::CudaSlice<i32>, crate::CudaSlice<f32>)>,
8566    /// Prestage door state: input pull + quantize already issued for this layer's call
8567    /// (nvfp4_routes_prestage), so the routed run skips them. Reset per call.
8568    prestaged: bool,
8569    /// Peer-router door state: rank1's sel/route_w were computed locally in prestage;
8570    /// the routed run skips rank1's sel pull. Reset per call.
8571    rank1_routed: bool,
8572    /// Doorbell fences (MEMRA_FENCE_MEMOPS): raw cuMemAlloc'd [rank1_flag, root_flag]
8573    /// u32 pair in ROOT memory (async-pool memory is memop-INELIGIBLE — receipted
8574    /// CUDA_ERROR_INVALID_VALUE) + the host-side monotonic ticket. 0 = unarmed.
8575    fence_flags_raw: u64,
8576    fence_ticket: u32,
8577    /// Prestage input fence, recorded on e after the input's producer.
8578    ev_input: Option<(CudaEvent, usize)>,
8579    /// Graph-door staging: persistent e-context input row + output row (fixed addresses the
8580    /// captured copies read/write), and the per-layer stitched parent.
8581    in_stage_e: Option<crate::CudaSlice<f32>>,
8582    out_stage_e: Option<crate::CudaSlice<f32>>,
8583    routes_graph: Option<RoutesGraph>,
8584    /// Token-graph raw pointer sets (armed once by routes_arm_raw).
8585    raw_dev_route_e: Option<(u64, u64)>,
8586    raw_combine: Option<(u64, u64, u64, u64)>,
8587    raw_input: Vec<u64>,
8588    raw_sel: Vec<u64>,
8589    raw_route_w: Vec<u64>,
8590    remote: crate::CudaSlice<f32>,
8591    combined: crate::CudaSlice<f32>,
8592    n_sel: usize,
8593    /// Device-IO extension (lazily built by `run_tensor_parallel_routes_nvfp4_device_io`):
8594    /// persistent per-rank input rows plus the evented ordering pair — the pp.rs
8595    /// BoundarySlot discipline, same as the v2 attention workspace.
8596    input: Vec<crate::CudaSlice<f32>>,
8597    ev_rank: Vec<CudaEvent>,
8598    ev_done: Option<CudaEvent>,
8599    ev_entry: Option<(CudaEvent, usize)>,
8600}
8601
8602/// One rank's whole-expert NVFP4 residency (expert-parallel ownership).
8603struct ResidentNvfp4EpRank {
8604    gate: Vec<crate::CudaSlice<u8>>,
8605    up: Vec<crate::CudaSlice<u8>>,
8606    down: Vec<crate::CudaSlice<u8>>,
8607    #[allow(dead_code)]
8608    expert_range: Range<usize>,
8609}
8610
8611pub struct ResidentNvfp4ExpertParallel {
8612    ranks: Vec<ResidentNvfp4EpRank>,
8613    macros_gate: Vec<f32>,
8614    macros_up: Vec<f32>,
8615    macros_down: Vec<f32>,
8616    pub expert_count: usize,
8617    pub input_width: usize,
8618    pub expert_width: usize,
8619    gate_row_bytes: usize,
8620    down_row_bytes: usize,
8621}
8622
8623fn nvfp4_repack_matrix(matrix: Nvfp4BlockMatrix<'_>) -> Vec<u8> {
8624    memra_gguf::nvfp4_repack::repack_modelopt_to_gguf(
8625        matrix.codes,
8626        matrix.scales,
8627        matrix.out_features,
8628        matrix.in_features,
8629    )
8630}
8631
8632fn nvfp4_row_bytes(in_features: usize) -> usize {
8633    in_features / 64 * 36 // memra block_nvfp4: 64 elems -> 36 bytes (4 UE4M3 + 32 packed e2m1)
8634}
8635
8636/// MEMRA_NVFP4_BANK_V2=1: store the contiguous expert banks in the slot-major layout the
8637/// coalesced `*_v2` kernels read (see qmatvec.cu). Pure byte permutation — value-exact.
8638/// MEMRA_NO_LOCAL_SHADOW=1: skip the per-layer local-KV shadow gathers and appends in the
8639/// eager v2 decode (lengths still advance) — the graph door proved contents-stale local KV
8640/// is decode-identical (12/12). The local contents feed spec/MTP scratch only.
8641/// MEMRA_FUSE_ROPE_APPEND=1: fuse qk norms + rope + dcw KV append + len inc into one
8642/// launch per rank per layer (bit-identical; identity-gated). dcw path only.
8643pub(crate) fn fuse_rope_append_on() -> bool {
8644    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
8645    *ON.get_or_init(|| std::env::var("MEMRA_FUSE_ROPE_APPEND").as_deref() == Ok("1"))
8646}
8647
8648pub(crate) fn no_local_shadow_on() -> bool {
8649    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
8650    *ON.get_or_init(|| std::env::var("MEMRA_NO_LOCAL_SHADOW").as_deref() == Ok("1"))
8651}
8652
8653pub(crate) fn nvfp4_bank_v2_on() -> bool {
8654    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
8655    *ON.get_or_init(|| std::env::var("MEMRA_NVFP4_BANK_V2").as_deref() == Ok("1"))
8656}
8657
8658/// Permute one repacked block_nvfp4 matrix (out_features rows of `nvfp4_row_bytes(in_f)`)
8659/// into the slot-major v2 row layout: per row, slot g's 16 qs bytes at g*16, then the two
8660/// UE4M3 scale bytes per slot at nslots*16 + g*2. Row byte count unchanged.
8661fn nvfp4_matrix_v2_permute(v1: &[u8], out_features: usize, in_features: usize) -> Vec<u8> {
8662    let row_bytes = nvfp4_row_bytes(in_features);
8663    assert_eq!(v1.len(), out_features * row_bytes, "v2 permute geometry");
8664    let n_slots = in_features / 32;
8665    let mut out = Vec::with_capacity(v1.len());
8666    for row in 0..out_features {
8667        let r = &v1[row * row_bytes..(row + 1) * row_bytes];
8668        for g in 0..n_slots {
8669            let (sblk, h) = (g / 2, g % 2);
8670            let b = &r[sblk * 36..sblk * 36 + 36];
8671            out.extend_from_slice(&b[4 + 16 * h..4 + 16 * h + 16]);
8672        }
8673        for g in 0..n_slots {
8674            let (sblk, h) = (g / 2, g % 2);
8675            let b = &r[sblk * 36..sblk * 36 + 36];
8676            out.push(b[2 * h]);
8677            out.push(b[2 * h + 1]);
8678        }
8679    }
8680    out
8681}
8682
8683/// Repack + (optionally) v2-permute one expert shard for the contiguous banks.
8684fn nvfp4_repack_bank_matrix(matrix: Nvfp4BlockMatrix<'_>) -> Vec<u8> {
8685    let (out_features, in_features) = (matrix.out_features, matrix.in_features);
8686    let v1 = nvfp4_repack_matrix(matrix);
8687    if nvfp4_bank_v2_on() {
8688        nvfp4_matrix_v2_permute(&v1, out_features, in_features)
8689    } else {
8690        v1
8691    }
8692}
8693
8694/// Column shard: whole output rows per rank (codes and scales are row-major, so both slices are
8695/// contiguous borrows). The macro rides unchanged — it is applied post-gather by the caller.
8696fn nvfp4_column_shard<'a>(
8697    matrix: Nvfp4BlockMatrix<'a>,
8698    tp: usize,
8699    rank: usize,
8700) -> Result<Nvfp4BlockMatrix<'a>, String> {
8701    if matrix.out_features % tp != 0 {
8702        return Err(format!(
8703            "NVFP4 column-parallel out_features {} is not divisible by TP={tp}",
8704            matrix.out_features
8705        ));
8706    }
8707    let local_out = matrix.out_features / tp;
8708    let code_row = matrix.in_features / 2;
8709    let scale_row = matrix.in_features / 16;
8710    Ok(Nvfp4BlockMatrix {
8711        codes: &matrix.codes[rank * local_out * code_row..(rank + 1) * local_out * code_row],
8712        scales: &matrix.scales[rank * local_out * scale_row..(rank + 1) * local_out * scale_row],
8713        macro_scale: matrix.macro_scale,
8714        out_features: local_out,
8715        in_features: matrix.in_features,
8716    })
8717}
8718
8719/// Row shard: input-column windows per rank, 64-superblock aligned. Owned buffers: each output
8720/// row contributes one contiguous byte window, gathered across rows.
8721fn nvfp4_row_shard(
8722    matrix: Nvfp4BlockMatrix<'_>,
8723    tp: usize,
8724    rank: usize,
8725) -> Result<(Vec<u8>, Vec<u8>, usize), String> {
8726    if matrix.in_features % tp != 0 {
8727        return Err(format!(
8728            "NVFP4 row-parallel in_features {} is not divisible by TP={tp}",
8729            matrix.in_features
8730        ));
8731    }
8732    let local_in = matrix.in_features / tp;
8733    if local_in % 64 != 0 {
8734        return Err(format!(
8735            "NVFP4 row-parallel input shard {local_in} cuts through a 64-element superblock"
8736        ));
8737    }
8738    let code_row = matrix.in_features / 2;
8739    let scale_row = matrix.in_features / 16;
8740    let local_code = local_in / 2;
8741    let local_scale = local_in / 16;
8742    let mut codes = Vec::with_capacity(matrix.out_features * local_code);
8743    let mut scales = Vec::with_capacity(matrix.out_features * local_scale);
8744    for row in 0..matrix.out_features {
8745        let code_start = row * code_row + rank * local_code;
8746        codes.extend_from_slice(&matrix.codes[code_start..code_start + local_code]);
8747        let scale_start = row * scale_row + rank * local_scale;
8748        scales.extend_from_slice(&matrix.scales[scale_start..scale_start + local_scale]);
8749    }
8750    Ok((codes, scales, local_in))
8751}
8752
8753/// Rank compute leaf: repack modelopt -> block_nvfp4, upload, run the proven dp4a kernel. The
8754/// macro is NOT applied here — callers apply it once at the canonical post-gather/post-reduce
8755/// point (see the section header).
8756fn run_rank_nvfp4(
8757    engine: &Engine,
8758    matrix: Nvfp4BlockMatrix<'_>,
8759    activations: &[f32],
8760    tokens: usize,
8761) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
8762    matrix.validate()?;
8763    validate_activations(activations, tokens, matrix.in_features)?;
8764    let _main = engine.gpu.enter_main()?;
8765    let blocks = engine.htod_bytes(&nvfp4_repack_matrix(matrix))?;
8766    let activations = engine.htod(activations)?;
8767    let output = engine.qmatvec_nvfp4_fast(
8768        &blocks.slice(0..blocks.len()),
8769        &activations,
8770        tokens,
8771        matrix.in_features,
8772        matrix.out_features,
8773        nvfp4_row_bytes(matrix.in_features),
8774    )?;
8775    engine.dtoh(&output)
8776}
8777
8778fn upload_rank_nvfp4(
8779    engine: &Engine,
8780    matrix: Nvfp4BlockMatrix<'_>,
8781) -> Result<ResidentNvfp4Rank, Box<dyn std::error::Error>> {
8782    matrix.validate()?;
8783    let _main = engine.gpu.enter_main()?;
8784    Ok(ResidentNvfp4Rank {
8785        blocks: engine.htod_bytes(&nvfp4_repack_matrix(matrix))?,
8786        macro_scale: matrix.macro_scale,
8787        out_features: matrix.out_features,
8788        in_features: matrix.in_features,
8789        row_bytes: nvfp4_row_bytes(matrix.in_features),
8790    })
8791}
8792
8793fn run_resident_rank_nvfp4(
8794    engine: &Engine,
8795    rank: &ResidentNvfp4Rank,
8796    activations: &[f32],
8797    tokens: usize,
8798) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
8799    validate_activations(activations, tokens, rank.in_features)?;
8800    let _main = engine.gpu.enter_main()?;
8801    let activations = engine.htod(activations)?;
8802    let output = engine.qmatvec_nvfp4_fast(
8803        &rank.blocks.slice(0..rank.blocks.len()),
8804        &activations,
8805        tokens,
8806        rank.in_features,
8807        rank.out_features,
8808        rank.row_bytes,
8809    )?;
8810    engine.dtoh(&output)
8811}
8812
8813fn apply_macro(values: &mut [f32], macro_scale: f32) {
8814    for value in values.iter_mut() {
8815        *value *= macro_scale;
8816    }
8817}
8818
8819impl TpE4m3HostBounce {
8820    /// Unsharded NVFP4 projection on rank 0 (compatibility oracle). Macro applied post-kernel.
8821    pub fn full_nvfp4(
8822        &self,
8823        matrix: Nvfp4BlockMatrix<'_>,
8824        activations: &[f32],
8825        tokens: usize,
8826    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
8827        let mut output = run_rank_nvfp4(&self.ranks[0], matrix, activations, tokens)?;
8828        apply_macro(&mut output, matrix.macro_scale);
8829        Ok(output)
8830    }
8831
8832    /// Column-parallel NVFP4 projection: output rows partition across ranks, host gather in rank
8833    /// order, macro applied ONCE post-gather.
8834    pub fn column_parallel_nvfp4(
8835        &self,
8836        matrix: Nvfp4BlockMatrix<'_>,
8837        activations: &[f32],
8838        tokens: usize,
8839    ) -> Result<ColumnParallelResult, Box<dyn std::error::Error>> {
8840        matrix.validate()?;
8841        validate_activations(activations, tokens, matrix.in_features)?;
8842        let tp = self.ranks.len();
8843        let local_out = matrix.out_features / tp;
8844        let mut gathered = vec![0.0f32; tokens * matrix.out_features];
8845        let mut rank_outputs = Vec::with_capacity(tp);
8846        for (rank_index, rank) in self.ranks.iter().enumerate() {
8847            let shard = nvfp4_column_shard(matrix, tp, rank_index)?;
8848            let output = run_rank_nvfp4(rank, shard, activations, tokens)?;
8849            let row_start = rank_index * local_out;
8850            for token in 0..tokens {
8851                gathered[token * matrix.out_features + row_start
8852                    ..token * matrix.out_features + row_start + local_out]
8853                    .copy_from_slice(&output[token * local_out..(token + 1) * local_out]);
8854            }
8855            rank_outputs.push(output);
8856        }
8857        apply_macro(&mut gathered, matrix.macro_scale);
8858        Ok(ColumnParallelResult {
8859            gathered,
8860            rank_outputs,
8861        })
8862    }
8863
8864    /// Row-parallel NVFP4 projection: input columns partition at 64-superblock boundaries,
8865    /// rank-local partials reduce in stable rank order, macro applied ONCE post-reduce.
8866    pub fn row_parallel_nvfp4(
8867        &self,
8868        matrix: Nvfp4BlockMatrix<'_>,
8869        activations: &[f32],
8870        tokens: usize,
8871    ) -> Result<RowParallelResult, Box<dyn std::error::Error>> {
8872        matrix.validate()?;
8873        validate_activations(activations, tokens, matrix.in_features)?;
8874        let tp = self.ranks.len();
8875        let mut reduced = vec![0.0f32; tokens * matrix.out_features];
8876        let mut rank_partials = Vec::with_capacity(tp);
8877        for (rank_index, rank) in self.ranks.iter().enumerate() {
8878            let (codes, scales, local_in) = nvfp4_row_shard(matrix, tp, rank_index)?;
8879            let local_activations =
8880                activation_shard(activations, tokens, matrix.in_features, tp, rank_index);
8881            let shard = Nvfp4BlockMatrix {
8882                codes: &codes,
8883                scales: &scales,
8884                macro_scale: matrix.macro_scale,
8885                out_features: matrix.out_features,
8886                in_features: local_in,
8887            };
8888            let partial = run_rank_nvfp4(rank, shard, &local_activations, tokens)?;
8889            for (sum, value) in reduced.iter_mut().zip(&partial) {
8890                *sum += *value;
8891            }
8892            rank_partials.push(partial);
8893        }
8894        apply_macro(&mut reduced, matrix.macro_scale);
8895        Ok(RowParallelResult {
8896            reduced,
8897            rank_partials,
8898        })
8899    }
8900
8901    pub fn upload_expert_nvfp4(
8902        &self,
8903        gate: Nvfp4BlockMatrix<'_>,
8904        up: Nvfp4BlockMatrix<'_>,
8905        down: Nvfp4BlockMatrix<'_>,
8906    ) -> Result<ResidentTpNvfp4Expert, Box<dyn std::error::Error>> {
8907        if gate.in_features != up.in_features || gate.out_features != up.out_features {
8908            return Err("NVFP4 TP expert gate/up dimensions differ".into());
8909        }
8910        if down.in_features != gate.out_features || down.out_features != gate.in_features {
8911            return Err(format!(
8912                "NVFP4 TP expert down {}x{} does not invert gate/up {}x{}",
8913                down.out_features, down.in_features, gate.out_features, gate.in_features
8914            )
8915            .into());
8916        }
8917        let tp = self.ranks.len();
8918        let mut gate_ranks = Vec::with_capacity(tp);
8919        let mut up_ranks = Vec::with_capacity(tp);
8920        let mut down_ranks = Vec::with_capacity(tp);
8921        for (rank_index, engine) in self.ranks.iter().enumerate() {
8922            gate_ranks.push(upload_rank_nvfp4(
8923                engine,
8924                nvfp4_column_shard(gate, tp, rank_index)?,
8925            )?);
8926            up_ranks.push(upload_rank_nvfp4(
8927                engine,
8928                nvfp4_column_shard(up, tp, rank_index)?,
8929            )?);
8930            let (codes, scales, local_in) = nvfp4_row_shard(down, tp, rank_index)?;
8931            down_ranks.push(upload_rank_nvfp4(
8932                engine,
8933                Nvfp4BlockMatrix {
8934                    codes: &codes,
8935                    scales: &scales,
8936                    macro_scale: down.macro_scale,
8937                    out_features: down.out_features,
8938                    in_features: local_in,
8939                },
8940            )?);
8941        }
8942        Ok(ResidentTpNvfp4Expert {
8943            gate: ResidentNvfp4ColumnParallel {
8944                ranks: gate_ranks,
8945                out_features: gate.out_features,
8946                in_features: gate.in_features,
8947            },
8948            up: ResidentNvfp4ColumnParallel {
8949                ranks: up_ranks,
8950                out_features: up.out_features,
8951                in_features: up.in_features,
8952            },
8953            down: ResidentNvfp4RowParallel {
8954                ranks: down_ranks,
8955                out_features: down.out_features,
8956                in_features: down.in_features,
8957            },
8958            input_width: gate.in_features,
8959            expert_width: gate.out_features,
8960        })
8961    }
8962
8963    fn column_parallel_resident_nvfp4(
8964        &self,
8965        matrix: &ResidentNvfp4ColumnParallel,
8966        activations: &[f32],
8967        tokens: usize,
8968    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
8969        validate_activations(activations, tokens, matrix.in_features)?;
8970        let local_out = matrix.out_features / self.ranks.len();
8971        let mut gathered = vec![0.0f32; tokens * matrix.out_features];
8972        let mut macro_scale = None;
8973        for (rank_index, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
8974            let output = run_resident_rank_nvfp4(engine, shard, activations, tokens)?;
8975            let row_start = rank_index * local_out;
8976            for token in 0..tokens {
8977                gathered[token * matrix.out_features + row_start
8978                    ..token * matrix.out_features + row_start + local_out]
8979                    .copy_from_slice(&output[token * local_out..(token + 1) * local_out]);
8980            }
8981            macro_scale = Some(shard.macro_scale);
8982        }
8983        apply_macro(
8984            &mut gathered,
8985            macro_scale.ok_or("NVFP4 column-parallel matrix has no ranks")?,
8986        );
8987        Ok(gathered)
8988    }
8989
8990    fn row_parallel_resident_nvfp4(
8991        &self,
8992        matrix: &ResidentNvfp4RowParallel,
8993        activations: &[f32],
8994        tokens: usize,
8995    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
8996        validate_activations(activations, tokens, matrix.in_features)?;
8997        let tp = self.ranks.len();
8998        let local_in = matrix.in_features / tp;
8999        let mut reduced = vec![0.0f32; tokens * matrix.out_features];
9000        let mut macro_scale = None;
9001        for (rank_index, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
9002            if shard.in_features != local_in {
9003                return Err(format!(
9004                    "NVFP4 resident row shard in_features {} != expected {local_in}",
9005                    shard.in_features
9006                )
9007                .into());
9008            }
9009            let local_activations =
9010                activation_shard(activations, tokens, matrix.in_features, tp, rank_index);
9011            let partial = run_resident_rank_nvfp4(engine, shard, &local_activations, tokens)?;
9012            for (sum, value) in reduced.iter_mut().zip(&partial) {
9013                *sum += *value;
9014            }
9015            macro_scale = Some(shard.macro_scale);
9016        }
9017        apply_macro(
9018            &mut reduced,
9019            macro_scale.ok_or("NVFP4 row-parallel matrix has no ranks")?,
9020        );
9021        Ok(reduced)
9022    }
9023
9024    pub fn run_expert_nvfp4(
9025        &self,
9026        expert: &ResidentTpNvfp4Expert,
9027        input: &[f32],
9028        tokens: usize,
9029    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
9030        validate_activations(input, tokens, expert.input_width)?;
9031        let gate = self.column_parallel_resident_nvfp4(&expert.gate, input, tokens)?;
9032        let up = self.column_parallel_resident_nvfp4(&expert.up, input, tokens)?;
9033        let activated: Vec<f32> = gate
9034            .iter()
9035            .zip(&up)
9036            .map(|(&gate, &up)| gate / (1.0 + (-gate).exp()) * up)
9037            .collect();
9038        debug_assert_eq!(activated.len(), tokens * expert.expert_width);
9039        self.row_parallel_resident_nvfp4(&expert.down, &activated, tokens)
9040    }
9041
9042    /// Upload every expert's TP shards resident (one repacked block buffer per expert per rank).
9043    pub fn upload_tensor_parallel_nvfp4(
9044        &self,
9045        gate: Nvfp4ExpertBank<'_>,
9046        up: Nvfp4ExpertBank<'_>,
9047        down: Nvfp4ExpertBank<'_>,
9048    ) -> Result<ResidentNvfp4TensorParallel, Box<dyn std::error::Error>> {
9049        gate.validate()?;
9050        up.validate()?;
9051        down.validate()?;
9052        if gate.expert_count != up.expert_count || gate.expert_count != down.expert_count {
9053            return Err("NVFP4 TP gate/up/down expert counts differ".into());
9054        }
9055        if gate.in_features != up.in_features || gate.out_features != up.out_features {
9056            return Err("NVFP4 TP gate/up dimensions differ".into());
9057        }
9058        if down.in_features != gate.out_features || down.out_features != gate.in_features {
9059            return Err(format!(
9060                "NVFP4 TP down {}x{} does not invert gate/up {}x{}",
9061                down.out_features, down.in_features, gate.out_features, gate.in_features
9062            )
9063            .into());
9064        }
9065        let tp = self.ranks.len();
9066        if gate.out_features % tp != 0 {
9067            return Err(format!(
9068                "NVFP4 TP expert output width {} is not divisible by TP={tp}",
9069                gate.out_features
9070            )
9071            .into());
9072        }
9073        if down.in_features % NVFP4_CANONICAL_ROW_SHARDS != 0
9074            || (down.in_features / NVFP4_CANONICAL_ROW_SHARDS) % 64 != 0
9075        {
9076            return Err(format!(
9077                "NVFP4 TP expert input width {} does not split into 64-aligned canonical \
9078                 shards ({NVFP4_CANONICAL_ROW_SHARDS})",
9079                down.in_features
9080            )
9081            .into());
9082        }
9083        if tp > NVFP4_CANONICAL_ROW_SHARDS {
9084            return Err(format!(
9085                "NVFP4 TP world {tp} exceeds the canonical row-shard grid \
9086                 ({NVFP4_CANONICAL_ROW_SHARDS})"
9087            )
9088            .into());
9089        }
9090
9091        let ep2 = step_nvfp4_ep2_on() && tp == 2;
9092        let mut gate_ranks = Vec::with_capacity(tp);
9093        let mut up_ranks = Vec::with_capacity(tp);
9094        let mut macros_gate_dev = Vec::with_capacity(tp);
9095        let mut macros_up_dev = Vec::with_capacity(tp);
9096        let mut macros_down_dev = Vec::with_capacity(tp);
9097        for (rank_index, engine) in self.ranks.iter().enumerate() {
9098            let _main = engine.gpu.enter_main()?;
9099            // Contiguous per-rank banks: repack every expert shard into one host buffer, one
9100            // upload. Contiguity feeds the batched selected-experts launch; per-expert bytes
9101            // are unchanged (same repack).
9102            // EP2: this rank holds the FULL matrices of the experts it owns (id & 1 ==
9103            // rank_index), stacked at slot id >> 1 — same total bytes as the shard bank.
9104            let mut gate_host: Vec<u8> = Vec::new();
9105            let mut up_host: Vec<u8> = Vec::new();
9106            let mut owned = 0usize;
9107            for expert in 0..gate.expert_count {
9108                if ep2 {
9109                    if expert % 2 != rank_index {
9110                        continue;
9111                    }
9112                    owned += 1;
9113                    gate_host.extend_from_slice(&nvfp4_repack_bank_matrix(gate.expert(expert)?));
9114                    up_host.extend_from_slice(&nvfp4_repack_bank_matrix(up.expert(expert)?));
9115                } else {
9116                    let gate_shard = nvfp4_column_shard(gate.expert(expert)?, tp, rank_index)?;
9117                    gate_host.extend_from_slice(&nvfp4_repack_bank_matrix(gate_shard));
9118                    let up_shard = nvfp4_column_shard(up.expert(expert)?, tp, rank_index)?;
9119                    up_host.extend_from_slice(&nvfp4_repack_bank_matrix(up_shard));
9120                }
9121            }
9122            let bank_experts = if ep2 { owned } else { gate.expert_count };
9123            let gate_expert_bytes = gate_host.len() / bank_experts.max(1);
9124            let up_expert_bytes = up_host.len() / bank_experts.max(1);
9125            let local_out = if ep2 {
9126                gate.out_features
9127            } else {
9128                gate.out_features / tp
9129            };
9130            gate_ranks.push(ResidentNvfp4ColumnBankRank {
9131                bank: engine.htod_bytes(&gate_host)?,
9132                expert_bytes: gate_expert_bytes,
9133                local_out,
9134                in_features: gate.in_features,
9135                row_bytes: nvfp4_row_bytes(gate.in_features),
9136            });
9137            up_ranks.push(ResidentNvfp4ColumnBankRank {
9138                bank: engine.htod_bytes(&up_host)?,
9139                expert_bytes: up_expert_bytes,
9140                local_out,
9141                in_features: up.in_features,
9142                row_bytes: nvfp4_row_bytes(up.in_features),
9143            });
9144            macros_gate_dev.push(engine.htod(gate.macros)?);
9145            macros_up_dev.push(engine.htod(up.macros)?);
9146            macros_down_dev.push(engine.htod(down.macros)?);
9147        }
9148        // Down: canonical shard grid, NOT the world size (see NVFP4_CANONICAL_ROW_SHARDS).
9149        // Shard s lives on rank s % world, so TP1 holds both shards and TP2 one each, while the
9150        // execution and reduction order stay identical.
9151        let mut down_ranks = Vec::with_capacity(NVFP4_CANONICAL_ROW_SHARDS);
9152        for shard_index in 0..NVFP4_CANONICAL_ROW_SHARDS {
9153            let device_rank = shard_index % tp;
9154            let engine = &self.ranks[device_rank];
9155            let _main = engine.gpu.enter_main()?;
9156            let mut down_host: Vec<u8> = Vec::new();
9157            let mut owned = 0usize;
9158            for expert in 0..down.expert_count {
9159                let down_matrix = down.expert(expert)?;
9160                if ep2 {
9161                    // EP2: shard_index doubles as the owner rank; full-width down matrices
9162                    // of the owned experts, stacked at slot id >> 1.
9163                    if expert % 2 != device_rank {
9164                        continue;
9165                    }
9166                    owned += 1;
9167                    down_host.extend_from_slice(&nvfp4_repack_bank_matrix(down_matrix));
9168                } else {
9169                    let (codes, scales, local_in) =
9170                        nvfp4_row_shard(down_matrix, NVFP4_CANONICAL_ROW_SHARDS, shard_index)?;
9171                    down_host.extend_from_slice(&nvfp4_repack_bank_matrix(Nvfp4BlockMatrix {
9172                        codes: &codes,
9173                        scales: &scales,
9174                        macro_scale: down_matrix.macro_scale,
9175                        out_features: down_matrix.out_features,
9176                        in_features: local_in,
9177                    }));
9178                }
9179            }
9180            let bank_experts = if ep2 { owned } else { down.expert_count };
9181            let down_expert_bytes = down_host.len() / bank_experts.max(1);
9182            let local_in = if ep2 {
9183                down.in_features
9184            } else {
9185                down.in_features / NVFP4_CANONICAL_ROW_SHARDS
9186            };
9187            down_ranks.push(ResidentNvfp4RowBankRank {
9188                bank: engine.htod_bytes(&down_host)?,
9189                expert_bytes: down_expert_bytes,
9190                device_rank,
9191                out_features: down.out_features,
9192                local_in,
9193                row_bytes: nvfp4_row_bytes(local_in),
9194            });
9195        }
9196        Ok(ResidentNvfp4TensorParallel {
9197            gate: gate_ranks,
9198            up: up_ranks,
9199            down: down_ranks,
9200            macros_gate: gate.macros.to_vec(),
9201            macros_up: up.macros.to_vec(),
9202            macros_down: down.macros.to_vec(),
9203            macros_gate_dev,
9204            macros_up_dev,
9205            macros_down_dev,
9206            expert_count: gate.expert_count,
9207            input_width: gate.in_features,
9208            expert_width: gate.out_features,
9209            device_workspace: std::sync::Mutex::new(None),
9210            t2_workspace: std::sync::Mutex::new(None),
9211            ep2,
9212        })
9213    }
9214
9215    /// EP2 host-canonical: the whole expert executes on its owning rank at full width
9216    /// (owner = expert & 1, bank slot = expert >> 1). Per-row program == the column-bank
9217    /// path's kernel, so gate/up are bit-equal to the TP layout.
9218    fn run_full_bank_expert_nvfp4(
9219        &self,
9220        ranks: &[ResidentNvfp4ColumnBankRank],
9221        macros: &[f32],
9222        expert: usize,
9223        input: &[f32],
9224    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
9225        let owner = expert & 1;
9226        let slot = expert >> 1;
9227        let bank = ranks
9228            .get(owner)
9229            .ok_or("NVFP4 EP2 column bank missing owner rank")?;
9230        let engine = &self.ranks[owner];
9231        let _main = engine.gpu.enter_main()?;
9232        let activations = engine.htod(input)?;
9233        let output = if nvfp4_bank_v2_on() {
9234            engine.qmatvec_nvfp4_fast_v2(
9235                &bank.expert(slot),
9236                &activations,
9237                1,
9238                bank.in_features,
9239                bank.local_out,
9240                bank.row_bytes,
9241            )?
9242        } else {
9243            engine.qmatvec_nvfp4_fast(
9244                &bank.expert(slot),
9245                &activations,
9246                1,
9247                bank.in_features,
9248                bank.local_out,
9249                bank.row_bytes,
9250            )?
9251        };
9252        let mut out = engine.dtoh(&output)?;
9253        apply_macro(&mut out, macros[expert]);
9254        Ok(out)
9255    }
9256
9257    /// EP2 host-canonical down: one full-width dot on the owner (NUMERIC-CLASS vs the
9258    /// canonical 2-shard sum — the parenthesization this door declares).
9259    fn run_full_down_expert_nvfp4(
9260        &self,
9261        shards: &[ResidentNvfp4RowBankRank],
9262        macros: &[f32],
9263        expert: usize,
9264        input: &[f32],
9265    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
9266        let owner = expert & 1;
9267        let slot = expert >> 1;
9268        let shard = shards
9269            .get(owner)
9270            .ok_or("NVFP4 EP2 down bank missing owner rank")?;
9271        let engine = &self.ranks[owner];
9272        let _main = engine.gpu.enter_main()?;
9273        let activations = engine.htod(input)?;
9274        let output = if nvfp4_bank_v2_on() {
9275            engine.qmatvec_nvfp4_fast_v2(
9276                &shard.expert(slot),
9277                &activations,
9278                1,
9279                shard.local_in,
9280                shard.out_features,
9281                shard.row_bytes,
9282            )?
9283        } else {
9284            engine.qmatvec_nvfp4_fast(
9285                &shard.expert(slot),
9286                &activations,
9287                1,
9288                shard.local_in,
9289                shard.out_features,
9290                shard.row_bytes,
9291            )?
9292        };
9293        let mut out = engine.dtoh(&output)?;
9294        apply_macro(&mut out, macros[expert]);
9295        Ok(out)
9296    }
9297
9298    fn run_column_bank_expert_nvfp4(
9299        &self,
9300        ranks: &[ResidentNvfp4ColumnBankRank],
9301        macros: &[f32],
9302        expert: usize,
9303        input: &[f32],
9304    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
9305        let local_out = ranks
9306            .first()
9307            .ok_or("NVFP4 TP column bank has no ranks")?
9308            .local_out;
9309        let mut gathered = vec![0.0f32; local_out * ranks.len()];
9310        for (rank_index, (engine, bank)) in self.ranks.iter().zip(ranks).enumerate() {
9311            let _main = engine.gpu.enter_main()?;
9312            let activations = engine.htod(input)?;
9313            let output = if nvfp4_bank_v2_on() {
9314                engine.qmatvec_nvfp4_fast_v2(
9315                    &bank.expert(expert),
9316                    &activations,
9317                    1,
9318                    bank.in_features,
9319                    bank.local_out,
9320                    bank.row_bytes,
9321                )?
9322            } else {
9323                engine.qmatvec_nvfp4_fast(
9324                    &bank.expert(expert),
9325                    &activations,
9326                    1,
9327                    bank.in_features,
9328                    bank.local_out,
9329                    bank.row_bytes,
9330                )?
9331            };
9332            let output = engine.dtoh(&output)?;
9333            gathered[rank_index * local_out..(rank_index + 1) * local_out].copy_from_slice(&output);
9334        }
9335        apply_macro(&mut gathered, macros[expert]);
9336        Ok(gathered)
9337    }
9338
9339    /// Canonical-shard row reduction: iterate the FIXED shard grid in shard order (each shard
9340    /// executes on its owning rank engine), so the reduction parenthesization is identical at
9341    /// every world size — that identity is what the TP1-oracle-vs-TP2 bit gate proves.
9342    fn run_row_bank_expert_nvfp4(
9343        &self,
9344        shards: &[ResidentNvfp4RowBankRank],
9345        macros: &[f32],
9346        expert: usize,
9347        input: &[f32],
9348    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
9349        let out_features = shards
9350            .first()
9351            .ok_or("NVFP4 TP row bank has no canonical shards")?
9352            .out_features;
9353        let in_features = shards.iter().map(|shard| shard.local_in).sum::<usize>();
9354        let mut reduced = vec![0.0f32; out_features];
9355        for (shard_index, shard) in shards.iter().enumerate() {
9356            let engine = self
9357                .ranks
9358                .get(shard.device_rank)
9359                .ok_or("NVFP4 canonical shard names a rank outside this runtime")?;
9360            let _main = engine.gpu.enter_main()?;
9361            let local_activations =
9362                activation_shard(input, 1, in_features, shards.len(), shard_index);
9363            let activations = engine.htod(&local_activations)?;
9364            let output = if nvfp4_bank_v2_on() {
9365                engine.qmatvec_nvfp4_fast_v2(
9366                    &shard.expert(expert),
9367                    &activations,
9368                    1,
9369                    shard.local_in,
9370                    shard.out_features,
9371                    shard.row_bytes,
9372                )?
9373            } else {
9374                engine.qmatvec_nvfp4_fast(
9375                    &shard.expert(expert),
9376                    &activations,
9377                    1,
9378                    shard.local_in,
9379                    shard.out_features,
9380                    shard.row_bytes,
9381                )?
9382            };
9383            let partial = engine.dtoh(&output)?;
9384            for (sum, value) in reduced.iter_mut().zip(&partial) {
9385                *sum += *value;
9386            }
9387        }
9388        apply_macro(&mut reduced, macros[expert]);
9389        Ok(reduced)
9390    }
9391
9392    /// Upload whole experts per owning rank (NVFP4 expert-parallel: the layout the clamped tail
9393    /// layers require — clamp semantics do not distribute across a tensor shard). Each owned
9394    /// expert keeps its full gate/up/down as one repacked block buffer on its owner.
9395    pub fn upload_expert_parallel_nvfp4(
9396        &self,
9397        gate: Nvfp4ExpertBank<'_>,
9398        up: Nvfp4ExpertBank<'_>,
9399        down: Nvfp4ExpertBank<'_>,
9400    ) -> Result<ResidentNvfp4ExpertParallel, Box<dyn std::error::Error>> {
9401        gate.validate()?;
9402        up.validate()?;
9403        down.validate()?;
9404        if gate.expert_count != up.expert_count || gate.expert_count != down.expert_count {
9405            return Err("NVFP4 EP gate/up/down expert counts differ".into());
9406        }
9407        if gate.in_features != up.in_features || gate.out_features != up.out_features {
9408            return Err("NVFP4 EP gate/up dimensions differ".into());
9409        }
9410        if down.in_features != gate.out_features || down.out_features != gate.in_features {
9411            return Err(format!(
9412                "NVFP4 EP down {}x{} does not invert gate/up {}x{}",
9413                down.out_features, down.in_features, gate.out_features, gate.in_features
9414            )
9415            .into());
9416        }
9417        let world = self.ranks.len();
9418        if gate.expert_count % world != 0 {
9419            return Err(format!(
9420                "NVFP4 EP expert count {} is not divisible by {world} ranks",
9421                gate.expert_count
9422            )
9423            .into());
9424        }
9425        let experts_per_rank = gate.expert_count / world;
9426        let mut ranks = Vec::with_capacity(world);
9427        for (rank_index, engine) in self.ranks.iter().enumerate() {
9428            let _main = engine.gpu.enter_main()?;
9429            let expert_range = rank_index * experts_per_rank..(rank_index + 1) * experts_per_rank;
9430            let mut gate_experts = Vec::with_capacity(experts_per_rank);
9431            let mut up_experts = Vec::with_capacity(experts_per_rank);
9432            let mut down_experts = Vec::with_capacity(experts_per_rank);
9433            for expert in expert_range.clone() {
9434                gate_experts.push(engine.htod_bytes(&nvfp4_repack_matrix(gate.expert(expert)?))?);
9435                up_experts.push(engine.htod_bytes(&nvfp4_repack_matrix(up.expert(expert)?))?);
9436                down_experts.push(engine.htod_bytes(&nvfp4_repack_matrix(down.expert(expert)?))?);
9437            }
9438            ranks.push(ResidentNvfp4EpRank {
9439                gate: gate_experts,
9440                up: up_experts,
9441                down: down_experts,
9442                expert_range,
9443            });
9444        }
9445        Ok(ResidentNvfp4ExpertParallel {
9446            ranks,
9447            macros_gate: gate.macros.to_vec(),
9448            macros_up: up.macros.to_vec(),
9449            macros_down: down.macros.to_vec(),
9450            expert_count: gate.expert_count,
9451            input_width: gate.in_features,
9452            expert_width: gate.out_features,
9453            gate_row_bytes: nvfp4_row_bytes(gate.in_features),
9454            down_row_bytes: nvfp4_row_bytes(down.in_features),
9455        })
9456    }
9457
9458    /// Routed NVFP4 expert-parallel program, host-canonical: every selected expert executes WHOLE
9459    /// on its owning rank (gate -> up -> clamped-or-plain SwiGLU on host -> down), each projection
9460    /// macro applied once post-kernel, route-weighted accumulate on the host in slot order. The
9461    /// activation uses `step_expert_activation_host`, so the clamped tail layers keep the official
9462    /// contract. Exactness-first; no throughput claim.
9463    #[allow(clippy::too_many_arguments)]
9464    pub fn run_routed_experts_nvfp4(
9465        &self,
9466        experts: &ResidentNvfp4ExpertParallel,
9467        input: &[f32],
9468        tokens: usize,
9469        selected: &[usize],
9470        route_weights: &[f32],
9471        experts_per_token: usize,
9472        activation_limit: Option<f32>,
9473    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
9474        validate_activations(input, tokens, experts.input_width)?;
9475        let pairs = tokens
9476            .checked_mul(experts_per_token)
9477            .ok_or("NVFP4 EP route count overflow")?;
9478        if selected.len() != pairs || route_weights.len() != pairs {
9479            return Err(format!(
9480                "NVFP4 EP routes selected={} weights={} != tokens {tokens} x experts/token \
9481                 {experts_per_token} ({pairs})",
9482                selected.len(),
9483                route_weights.len(),
9484            )
9485            .into());
9486        }
9487        if !route_weights.iter().all(|weight| weight.is_finite()) {
9488            return Err("NVFP4 EP route weights contain a non-finite value".into());
9489        }
9490        let experts_per_rank = experts.expert_count / experts.ranks.len();
9491        let mut output = vec![0.0f32; tokens * experts.input_width];
9492        for token in 0..tokens {
9493            let input_row = &input[token * experts.input_width..(token + 1) * experts.input_width];
9494            for slot in 0..experts_per_token {
9495                let pair = token * experts_per_token + slot;
9496                let expert = selected[pair];
9497                if expert >= experts.expert_count {
9498                    return Err(format!(
9499                        "NVFP4 EP selected expert {expert} outside 0..{}",
9500                        experts.expert_count
9501                    )
9502                    .into());
9503                }
9504                let owner = expert / experts_per_rank;
9505                let local = expert - owner * experts_per_rank;
9506                let rank = &experts.ranks[owner];
9507                let engine = &self.ranks[owner];
9508                let _main = engine.gpu.enter_main()?;
9509                let device_input = engine.htod(input_row)?;
9510                let gate_out = engine.qmatvec_nvfp4_fast(
9511                    &rank.gate[local].slice(0..rank.gate[local].len()),
9512                    &device_input,
9513                    1,
9514                    experts.input_width,
9515                    experts.expert_width,
9516                    experts.gate_row_bytes,
9517                )?;
9518                let up_out = engine.qmatvec_nvfp4_fast(
9519                    &rank.up[local].slice(0..rank.up[local].len()),
9520                    &device_input,
9521                    1,
9522                    experts.input_width,
9523                    experts.expert_width,
9524                    experts.gate_row_bytes,
9525                )?;
9526                let mut gate_host = engine.dtoh(&gate_out)?;
9527                let mut up_host = engine.dtoh(&up_out)?;
9528                apply_macro(&mut gate_host, experts.macros_gate[expert]);
9529                apply_macro(&mut up_host, experts.macros_up[expert]);
9530                let activated: Vec<f32> = gate_host
9531                    .iter()
9532                    .zip(&up_host)
9533                    .map(|(&gate, &up)| step_expert_activation_host(gate, up, activation_limit))
9534                    .collect();
9535                let device_activated = engine.htod(&activated)?;
9536                let down_out = engine.qmatvec_nvfp4_fast(
9537                    &rank.down[local].slice(0..rank.down[local].len()),
9538                    &device_activated,
9539                    1,
9540                    experts.expert_width,
9541                    experts.input_width,
9542                    experts.down_row_bytes,
9543                )?;
9544                let mut down_host = engine.dtoh(&down_out)?;
9545                apply_macro(&mut down_host, experts.macros_down[expert]);
9546                let weight = route_weights[pair];
9547                for (sum, value) in output
9548                    [token * experts.input_width..(token + 1) * experts.input_width]
9549                    .iter_mut()
9550                    .zip(down_host)
9551                {
9552                    *sum += weight * value;
9553                }
9554            }
9555        }
9556        Ok(output)
9557    }
9558
9559    /// Device-resident routed NVFP4 expert program (decode shape, t=1 rows). The geometry gift
9560    /// this exploits: gate/up column halves land on the SAME rank that owns the matching down
9561    /// canonical shard (act[rank r] is exactly down-shard r's input-column window), so the whole
9562    /// expert interior — gate, up, macro-scaled SwiGLU, down partial, route-weighted accumulate —
9563    /// runs rank-local with ZERO cross-rank transfer. Per (token, layer): one input upload per
9564    /// rank, one fenced peer copy of the remote accumulator, one root add, one readback.
9565    ///
9566    /// Numeric class: device silu (silu_mul_scaled) with gate/up macros folded as gs/us and the
9567    /// down macro folded into the accumulate scalar (weight * macro_down — exact, both are
9568    /// per-expert constants). This matches the owning-stage MoE dev-path semantics, NOT the
9569    /// host-canonical program bit-for-bit; gate it with argmax + relative bounds against the
9570    /// host-canonical oracle, and with repeat determinism against itself.
9571    /// Clamped layers refuse (they stay on the EP program).
9572    pub fn run_tensor_parallel_routes_nvfp4_device(
9573        &self,
9574        experts: &ResidentNvfp4TensorParallel,
9575        input: &[f32],
9576        selected: &[usize],
9577        route_weights: &[f32],
9578        experts_per_token: usize,
9579        activation_limit: Option<f32>,
9580    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
9581        validate_activations(input, 1, experts.input_width)?;
9582        if selected.len() != experts_per_token || route_weights.len() != experts_per_token {
9583            return Err(format!(
9584                "NVFP4 device routes selected={} weights={} != experts/token {experts_per_token}",
9585                selected.len(),
9586                route_weights.len(),
9587            )
9588            .into());
9589        }
9590        if !route_weights.iter().all(|weight| weight.is_finite()) {
9591            return Err("NVFP4 device route weights contain a non-finite value".into());
9592        }
9593        let world = self.ranks.len();
9594        if world != NVFP4_CANONICAL_ROW_SHARDS {
9595            return Err(format!(
9596                "NVFP4 device routes require world == canonical shard grid \
9597                 ({NVFP4_CANONICAL_ROW_SHARDS}), got {world}"
9598            )
9599            .into());
9600        }
9601        let local_out = if experts.ep2 {
9602            experts.expert_width
9603        } else {
9604            experts.expert_width / world
9605        };
9606
9607        // MEMRA_STEP_TP_TIMING=1: cumulative wall-clock of this program, printed every 430 calls
9608        // (~one 43-layer decode step's worth) so a bench run decomposes expert-program time vs
9609        // everything else without Nsight.
9610        static TIMING_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
9611        static TIMING_CALLS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
9612        let timing = std::env::var("MEMRA_STEP_TP_TIMING").as_deref() == Ok("1");
9613        let started = timing.then(std::time::Instant::now);
9614
9615        let n_sel = experts_per_token;
9616        let mut workspace_guard = experts
9617            .device_workspace
9618            .lock()
9619            .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
9620        if workspace_guard.is_none() {
9621            let mut gate_out = Vec::with_capacity(world);
9622            let mut up_out = Vec::with_capacity(world);
9623            let mut act_q = Vec::with_capacity(world);
9624            let mut act_d = Vec::with_capacity(world);
9625            let mut sel = Vec::with_capacity(world);
9626            let mut partial = Vec::with_capacity(world);
9627            let mut accumulator = Vec::with_capacity(world);
9628            let mut combine_w = Vec::with_capacity(world);
9629            let mut route_w = Vec::with_capacity(world);
9630            let mut in_q = Vec::with_capacity(world);
9631            let mut in_d = Vec::with_capacity(world);
9632            let mut input = Vec::with_capacity(world);
9633            let mut ev_rank = Vec::with_capacity(world);
9634            let moe_direct = moe_direct_on();
9635            for (rank, engine) in self.ranks.iter().enumerate() {
9636                let _main = engine.gpu.enter_main()?;
9637                gate_out.push(engine.uninit(n_sel * local_out)?);
9638                up_out.push(engine.uninit(n_sel * local_out)?);
9639                act_q.push(engine.uninit_i8(n_sel * local_out)?);
9640                act_d.push(engine.uninit(n_sel * local_out / 32)?);
9641                sel.push(engine.htod_i32(&vec![0i32; n_sel])?);
9642                partial.push(engine.uninit(n_sel * experts.input_width)?);
9643                // Direct join: peer accumulators live on ROOT (single P2P store pass).
9644                if moe_direct && rank != 0 {
9645                    let root = &self.ranks[0];
9646                    let _root_main = root.gpu.enter_main()?;
9647                    accumulator.push(root.zeros(experts.input_width)?);
9648                } else {
9649                    accumulator.push(engine.zeros(experts.input_width)?);
9650                }
9651                combine_w.push(engine.htod(&vec![0.0f32; n_sel])?);
9652                route_w.push(engine.htod(&vec![0.0f32; n_sel])?);
9653                in_q.push(engine.uninit_i8(experts.input_width)?);
9654                in_d.push(engine.uninit(experts.input_width / 32)?);
9655                input.push(engine.uninit(experts.input_width)?);
9656                ev_rank.push(engine.ctx().new_event(None)?);
9657            }
9658            let root = &self.ranks[0];
9659            let _main = root.gpu.enter_main()?;
9660            *workspace_guard = Some(Nvfp4DeviceRoutesWorkspace {
9661                prestaged: false,
9662                rank1_routed: false,
9663                ev_input: None,
9664                fence_flags_raw: 0,
9665                fence_ticket: 0,
9666                gate_out,
9667                up_out,
9668                act_q,
9669                act_d,
9670                sel,
9671                partial,
9672                accumulator,
9673                combine_w,
9674                route_w,
9675                in_q,
9676                in_d,
9677                dev_route_e: None,
9678                in_stage_e: None,
9679                out_stage_e: None,
9680                routes_graph: None,
9681                raw_dev_route_e: None,
9682                raw_combine: None,
9683                raw_input: Vec::new(),
9684                raw_sel: Vec::new(),
9685                raw_route_w: Vec::new(),
9686                remote: root.uninit(experts.input_width)?,
9687                combined: root.uninit(experts.input_width)?,
9688                n_sel,
9689                input,
9690                ev_rank,
9691                ev_done: Some(root.ctx().new_event(None)?),
9692                ev_entry: None,
9693            });
9694        }
9695        let workspace = workspace_guard
9696            .as_mut()
9697            .expect("NVFP4 device routes workspace initialized above");
9698        // EP2 uses this call only as the workspace-arming warmup (the prejoin path drives
9699        // decode); its host-routed sweep semantics do not apply to whole-expert banks.
9700        if experts.ep2 {
9701            return Ok(vec![0.0f32; experts.input_width]);
9702        }
9703        if workspace.n_sel != n_sel {
9704            return Err(format!(
9705                "NVFP4 device routes experts/token changed: workspace {} != call {n_sel}",
9706                workspace.n_sel
9707            )
9708            .into());
9709        }
9710        for &expert in selected {
9711            if expert >= experts.expert_count {
9712                return Err(format!(
9713                    "NVFP4 device selected expert {expert} outside 0..{}",
9714                    experts.expert_count
9715                )
9716                .into());
9717            }
9718        }
9719        let sel_i32 = selected
9720            .iter()
9721            .map(|&expert| expert as i32)
9722            .collect::<Vec<_>>();
9723
9724        // BATCHED program (2026-08-20): per rank, ONE launch per sweep (gate, up, SwiGLU,
9725        // down) covers every selected expert via the selection array and the contiguous bank —
9726        // the per-expert launch loop was pure host latency (~100 sequential launches/layer,
9727        // 291us wall for ~35us of arithmetic). Per (expert, row) the kernels are bit-identical
9728        // to the per-expert forms, and the route-weight axpy chain keeps its exact sequential
9729        // accumulation order — the program's values are unchanged.
9730        for (rank_index, engine) in self.ranks.iter().enumerate() {
9731            let _main = engine.gpu.enter_main()?;
9732            let device_input = engine.htod(input)?;
9733            let Nvfp4DeviceRoutesWorkspace { in_q, in_d, .. } = &mut *workspace;
9734            engine.quantize_q8_1_into(
9735                &device_input,
9736                1,
9737                experts.input_width,
9738                &mut in_q[rank_index],
9739                &mut in_d[rank_index],
9740            )?;
9741            // device_input frees on this rank's stream after the quantize — same-stream order.
9742        }
9743        self.nvfp4_routes_batched_sweeps(
9744            experts,
9745            workspace,
9746            selected,
9747            route_weights,
9748            &sel_i32,
9749            local_out,
9750            n_sel,
9751            activation_limit,
9752            false,
9753        )?;
9754
9755        // Combine: fence the remote shard's producer stream, peer-copy its accumulator to root,
9756        // reduce in canonical shard order, read back once.
9757        let root = &self.ranks[0];
9758        for engine in &self.ranks[1..] {
9759            let _main = engine.gpu.enter_main()?;
9760            engine.stream().synchronize()?;
9761        }
9762        let _main = root.gpu.enter_main()?;
9763        root.stream()
9764            .memcpy_dtod(&workspace.accumulator[1], &mut workspace.remote)?;
9765        root.add(
9766            &workspace.accumulator[0],
9767            &workspace.remote,
9768            &mut workspace.combined,
9769            experts.input_width,
9770        )?;
9771        let output = root.dtoh(&workspace.combined)?;
9772        if let Some(started) = started {
9773            use std::sync::atomic::Ordering;
9774            let ns = TIMING_NS.fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
9775                + started.elapsed().as_nanos() as u64;
9776            let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
9777            if calls % 430 == 0 {
9778                eprintln!(
9779                    "[nvfp4-dev-routes-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
9780                    ns as f64 / 1.0e6,
9781                    ns as f64 / calls as f64 / 1.0e3,
9782                );
9783            }
9784        }
9785        Ok(output)
9786    }
9787
9788    /// The shared batched sweeps of the device routes program: per rank, upload the selection,
9789    /// reset the accumulator, run the gate/up/SwiGLU/down batched launches, then the
9790    /// route-weight axpy chain in exact sequential per-pair order. Every op queues on the
9791    /// owning rank's stream; callers own input acquisition and the combine.
9792    #[allow(clippy::too_many_arguments)]
9793    fn nvfp4_routes_batched_sweeps(
9794        &self,
9795        experts: &ResidentNvfp4TensorParallel,
9796        workspace: &mut Nvfp4DeviceRoutesWorkspace,
9797        selected: &[usize],
9798        route_weights: &[f32],
9799        sel_i32: &[i32],
9800        local_out: usize,
9801        n_sel: usize,
9802        activation_limit: Option<f32>,
9803        device_routed: bool,
9804    ) -> Result<(), Box<dyn std::error::Error>> {
9805        for rank_index in 0..self.ranks.len() {
9806            self.nvfp4_routes_batched_sweeps_rank(
9807                experts,
9808                workspace,
9809                selected,
9810                route_weights,
9811                sel_i32,
9812                local_out,
9813                n_sel,
9814                activation_limit,
9815                device_routed,
9816                rank_index,
9817            )?;
9818        }
9819        Ok(())
9820    }
9821
9822    /// One rank's sweeps (the per-rank body of `nvfp4_routes_batched_sweeps`) — separated so
9823    /// the graph door can capture each rank's segment on its own stream.
9824    #[allow(clippy::too_many_arguments)]
9825    fn nvfp4_routes_batched_sweeps_rank(
9826        &self,
9827        experts: &ResidentNvfp4TensorParallel,
9828        workspace: &mut Nvfp4DeviceRoutesWorkspace,
9829        selected: &[usize],
9830        route_weights: &[f32],
9831        sel_i32: &[i32],
9832        local_out: usize,
9833        n_sel: usize,
9834        activation_limit: Option<f32>,
9835        device_routed: bool,
9836        rank_index: usize,
9837    ) -> Result<(), Box<dyn std::error::Error>> {
9838        {
9839            let engine = &self.ranks[rank_index];
9840            let _main = engine.gpu.enter_main()?;
9841            // EP2: whole-expert full-width sweep, owner-guarded; down+combine fused writes
9842            // this rank's slot-ordered partial straight into its accumulator (the join is
9843            // unchanged). Device-routed only — the host-routed arm and the graph door refuse
9844            // at the caller.
9845            if experts.ep2 {
9846                if !device_routed {
9847                    return Err("NVFP4 EP2 banks support the device-routed decode arm only".into());
9848                }
9849                let gate_bank = &experts.gate[rank_index];
9850                let up_bank = &experts.up[rank_index];
9851                if gate_bank.local_out != experts.expert_width
9852                    || gate_bank.expert_bytes != up_bank.expert_bytes
9853                {
9854                    return Err("NVFP4 EP2 bank geometry drifted".into());
9855                }
9856                {
9857                    let Nvfp4DeviceRoutesWorkspace {
9858                        sel,
9859                        gate_out,
9860                        up_out,
9861                        in_q,
9862                        in_d,
9863                        ..
9864                    } = &mut *workspace;
9865                    engine.qmatvec_nvfp4_sel_gu_ep_into(
9866                        &gate_bank.bank,
9867                        &up_bank.bank,
9868                        &sel[rank_index],
9869                        &in_q[rank_index],
9870                        &in_d[rank_index],
9871                        &mut gate_out[rank_index],
9872                        &mut up_out[rank_index],
9873                        n_sel,
9874                        gate_bank.in_features,
9875                        gate_bank.local_out,
9876                        gate_bank.row_bytes,
9877                        gate_bank.expert_bytes,
9878                        rank_index,
9879                    )?;
9880                }
9881                {
9882                    let Nvfp4DeviceRoutesWorkspace {
9883                        gate_out,
9884                        up_out,
9885                        sel,
9886                        act_q,
9887                        act_d,
9888                        ..
9889                    } = &mut *workspace;
9890                    engine.silu_mul_scaled_q8_1_sel_ep_into(
9891                        &gate_out[rank_index],
9892                        &up_out[rank_index],
9893                        &experts.macros_gate_dev[rank_index],
9894                        &experts.macros_up_dev[rank_index],
9895                        &sel[rank_index],
9896                        activation_limit,
9897                        &mut act_q[rank_index],
9898                        &mut act_d[rank_index],
9899                        local_out,
9900                        n_sel,
9901                        rank_index,
9902                    )?;
9903                }
9904                let shard = &experts.down[rank_index];
9905                if shard.device_rank != rank_index || shard.local_in != local_out {
9906                    return Err("NVFP4 EP2 down bank placement drifted".into());
9907                }
9908                {
9909                    let Nvfp4DeviceRoutesWorkspace {
9910                        sel,
9911                        act_q,
9912                        act_d,
9913                        route_w,
9914                        accumulator,
9915                        ..
9916                    } = &mut *workspace;
9917                    engine.qmatvec_nvfp4_sel_down8_ep_into(
9918                        &shard.bank,
9919                        &sel[rank_index],
9920                        &act_q[rank_index],
9921                        &act_d[rank_index],
9922                        &route_w[rank_index],
9923                        &experts.macros_down_dev[rank_index],
9924                        &mut accumulator[rank_index],
9925                        n_sel,
9926                        shard.local_in,
9927                        shard.out_features,
9928                        shard.row_bytes,
9929                        shard.expert_bytes,
9930                        local_out,
9931                        local_out / 32,
9932                        rank_index,
9933                    )?;
9934                }
9935                return Ok(());
9936            }
9937            if !device_routed {
9938                engine.htod_i32_into(&mut workspace.sel[rank_index], sel_i32)?;
9939                // Folded combine weights (route_weight x down macro) — one 40-byte upload
9940                // replaces the accumulator reset + n_sel sequential axpy launches below.
9941                let folded = (0..n_sel)
9942                    .map(|pair| route_weights[pair] * experts.macros_down[selected[pair]])
9943                    .collect::<Vec<_>>();
9944                let mut view = workspace.combine_w[rank_index].slice_mut(0..n_sel);
9945                engine.stream().memcpy_htod(&folded, &mut view)?;
9946            }
9947            let gate_bank = &experts.gate[rank_index];
9948            let up_bank = &experts.up[rank_index];
9949            let (aq, ad) = (&workspace.in_q[rank_index], &workspace.in_d[rank_index]);
9950            // FUSION #2a (v2 banks): the two sweeps share sel/aq/ad and identical geometry
9951            // — one launch, per-row bit-identical, double the grid fill.
9952            let gu_fused = nvfp4_bank_v2_on()
9953                && gate_bank.in_features == up_bank.in_features
9954                && gate_bank.local_out == up_bank.local_out
9955                && gate_bank.row_bytes == up_bank.row_bytes
9956                && gate_bank.expert_bytes == up_bank.expert_bytes;
9957            if gu_fused {
9958                let Nvfp4DeviceRoutesWorkspace {
9959                    sel,
9960                    gate_out,
9961                    up_out,
9962                    in_q,
9963                    in_d,
9964                    ..
9965                } = &mut *workspace;
9966                engine.qmatvec_nvfp4_sel_gu_into(
9967                    &gate_bank.bank,
9968                    &up_bank.bank,
9969                    &sel[rank_index],
9970                    &in_q[rank_index],
9971                    &in_d[rank_index],
9972                    &mut gate_out[rank_index],
9973                    &mut up_out[rank_index],
9974                    n_sel,
9975                    gate_bank.in_features,
9976                    gate_bank.local_out,
9977                    gate_bank.row_bytes,
9978                    gate_bank.expert_bytes,
9979                )?;
9980            } else {
9981                engine.qmatvec_nvfp4_sel_into(
9982                    &gate_bank.bank,
9983                    &workspace.sel[rank_index],
9984                    aq,
9985                    ad,
9986                    &mut workspace.gate_out[rank_index],
9987                    n_sel,
9988                    gate_bank.in_features,
9989                    gate_bank.local_out,
9990                    gate_bank.row_bytes,
9991                    gate_bank.expert_bytes,
9992                    0,
9993                    0,
9994                )?;
9995                engine.qmatvec_nvfp4_sel_into(
9996                    &up_bank.bank,
9997                    &workspace.sel[rank_index],
9998                    aq,
9999                    ad,
10000                    &mut workspace.up_out[rank_index],
10001                    n_sel,
10002                    up_bank.in_features,
10003                    up_bank.local_out,
10004                    up_bank.row_bytes,
10005                    up_bank.expert_bytes,
10006                    0,
10007                    0,
10008                )?;
10009            }
10010            // Fused macro-scaled SwiGLU that EMITS q8_1 directly — down consumes it with no
10011            // separate quantize launch. act[rank] IS down canonical shard `rank_index`'s
10012            // input-column window (the geometry gift; see the method doc).
10013            {
10014                let Nvfp4DeviceRoutesWorkspace {
10015                    gate_out,
10016                    up_out,
10017                    sel,
10018                    act_q,
10019                    act_d,
10020                    ..
10021                } = &mut *workspace;
10022                engine.silu_mul_scaled_q8_1_sel_into(
10023                    &gate_out[rank_index],
10024                    &up_out[rank_index],
10025                    &experts.macros_gate_dev[rank_index],
10026                    &experts.macros_up_dev[rank_index],
10027                    &sel[rank_index],
10028                    activation_limit,
10029                    &mut act_q[rank_index],
10030                    &mut act_d[rank_index],
10031                    local_out,
10032                    n_sel,
10033                )?;
10034            }
10035            let shard = &experts.down[rank_index];
10036            if shard.device_rank != rank_index || shard.local_in != local_out {
10037                return Err(
10038                    "NVFP4 device routes: down canonical shard placement drifted from \
10039                     the gate/up column split"
10040                        .into(),
10041                );
10042            }
10043            // MEMRA_SEL_DOWN8=1: down sweep + route-weight combine in ONE launch, one warp
10044            // per SLOT instead of one warp per (row, slot) — the q8 `down8 w8` occupancy arm
10045            // (cx-downkernel: waves/SM 0.91 -> 4.36) ported to the NVFP4 banks. Bit-identical
10046            // (same dot program, same reduce tree, same slot-ordered chain), and the
10047            // n_sel x out_f partial buffer round trip disappears. Device-routed only: the
10048            // host-routed arm folds the macro into combine_w instead of reading md on device.
10049            let down8 = device_routed && sel_down8_on() && (shard.local_in >> 5) <= 32;
10050            if down8 {
10051                let Nvfp4DeviceRoutesWorkspace {
10052                    sel,
10053                    act_q,
10054                    act_d,
10055                    route_w,
10056                    accumulator,
10057                    ..
10058                } = &mut *workspace;
10059                engine.qmatvec_nvfp4_sel_down8_into(
10060                    &shard.bank,
10061                    &sel[rank_index],
10062                    &act_q[rank_index],
10063                    &act_d[rank_index],
10064                    &route_w[rank_index],
10065                    &experts.macros_down_dev[rank_index],
10066                    &mut accumulator[rank_index],
10067                    n_sel,
10068                    shard.local_in,
10069                    shard.out_features,
10070                    shard.row_bytes,
10071                    shard.expert_bytes,
10072                    local_out,
10073                    local_out / 32,
10074                )?;
10075            } else {
10076                let Nvfp4DeviceRoutesWorkspace {
10077                    sel,
10078                    act_q,
10079                    act_d,
10080                    partial,
10081                    ..
10082                } = &mut *workspace;
10083                engine.qmatvec_nvfp4_sel_into(
10084                    &shard.bank,
10085                    &sel[rank_index],
10086                    &act_q[rank_index],
10087                    &act_d[rank_index],
10088                    &mut partial[rank_index],
10089                    n_sel,
10090                    shard.local_in,
10091                    shard.out_features,
10092                    shard.row_bytes,
10093                    shard.expert_bytes,
10094                    local_out,
10095                    local_out / 32,
10096                )?;
10097            }
10098            // Route-weight accumulation: axpy_rows_seq keeps the exact sequential per-pair
10099            // FP chain of the reset + n_sel axpy launches in ONE launch. Device-routed calls
10100            // fold the down macro in-kernel from the device selection. (down8 already
10101            // produced the accumulator inside the sweep.)
10102            if !down8 {
10103                let Nvfp4DeviceRoutesWorkspace {
10104                    partial,
10105                    combine_w,
10106                    route_w,
10107                    sel,
10108                    accumulator,
10109                    ..
10110                } = &mut *workspace;
10111                if device_routed {
10112                    engine.axpy_rows_seq_md_into(
10113                        &partial[rank_index],
10114                        &route_w[rank_index],
10115                        &experts.macros_down_dev[rank_index],
10116                        &sel[rank_index],
10117                        &mut accumulator[rank_index],
10118                        experts.input_width,
10119                        n_sel,
10120                    )?;
10121                } else {
10122                    engine.axpy_rows_seq_into(
10123                        &partial[rank_index],
10124                        &combine_w[rank_index],
10125                        &mut accumulator[rank_index],
10126                        experts.input_width,
10127                        n_sel,
10128                    )?;
10129                }
10130            }
10131        }
10132        Ok(())
10133    }
10134
10135    /// Device-IO twin of `run_tensor_parallel_routes_nvfp4_device`: the layer input arrives as
10136    /// a device row on the model engine `e` and the combined output returns as a fresh
10137    /// `e`-context row — no host round-trip, no host stream sync. Ordering is evented (the v2
10138    /// attention discipline): `ev_entry` is recorded on `e`'s stream AFTER the caller queued
10139    /// the input's producer; each rank waits it before its peer read; the root reduce waits
10140    /// every rank's done event; `e` waits the root's done event before copying out. The
10141    /// program bytes are identical to the host-IO twin — dtoh/htod and dtod preserve f32 bits.
10142    pub fn run_tensor_parallel_routes_nvfp4_device_io(
10143        &self,
10144        experts: &ResidentNvfp4TensorParallel,
10145        e: &Engine,
10146        input_dev: &crate::CudaSlice<f32>,
10147        selected: &[usize],
10148        route_weights: &[f32],
10149        experts_per_token: usize,
10150        activation_limit: Option<f32>,
10151    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
10152        if input_dev.len() != experts.input_width {
10153            return Err(format!(
10154                "NVFP4 device-io routes input {} != width {}",
10155                input_dev.len(),
10156                experts.input_width
10157            )
10158            .into());
10159        }
10160        if selected.len() != experts_per_token || route_weights.len() != experts_per_token {
10161            return Err(format!(
10162                "NVFP4 device-io routes selected={} weights={} != experts/token {experts_per_token}",
10163                selected.len(),
10164                route_weights.len(),
10165            )
10166            .into());
10167        }
10168        if !route_weights.iter().all(|weight| weight.is_finite()) {
10169            return Err("NVFP4 device route weights contain a non-finite value".into());
10170        }
10171        let world = self.ranks.len();
10172        if world != NVFP4_CANONICAL_ROW_SHARDS {
10173            return Err(format!(
10174                "NVFP4 device routes require world == canonical shard grid \
10175                 ({NVFP4_CANONICAL_ROW_SHARDS}), got {world}"
10176            )
10177            .into());
10178        }
10179        let local_out = experts.expert_width / world;
10180        let n_sel = experts_per_token;
10181
10182        static TIMING_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
10183        static TIMING_CALLS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
10184        let timing = std::env::var("MEMRA_STEP_TP_TIMING").as_deref() == Ok("1");
10185        let started = timing.then(std::time::Instant::now);
10186
10187        let mut workspace_guard = experts
10188            .device_workspace
10189            .lock()
10190            .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
10191        if workspace_guard.is_none() {
10192            drop(workspace_guard);
10193            // Build through the host-IO ensure path exactly once: run it with a zero input.
10194            // Cheaper than duplicating the init; the first real call overwrites everything.
10195            let zero = vec![0.0f32; experts.input_width];
10196            let zero_sel = vec![0usize; n_sel];
10197            let zero_w = vec![0.0f32; n_sel];
10198            let _ = self.run_tensor_parallel_routes_nvfp4_device(
10199                experts,
10200                &zero,
10201                &zero_sel,
10202                &zero_w,
10203                n_sel,
10204                activation_limit,
10205            )?;
10206            workspace_guard = experts
10207                .device_workspace
10208                .lock()
10209                .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
10210        }
10211        let workspace = workspace_guard
10212            .as_mut()
10213            .expect("NVFP4 device routes workspace initialized above");
10214        if workspace.n_sel != n_sel {
10215            return Err(format!(
10216                "NVFP4 device routes experts/token changed: workspace {} != call {n_sel}",
10217                workspace.n_sel
10218            )
10219            .into());
10220        }
10221        for &expert in selected {
10222            if expert >= experts.expert_count {
10223                return Err(format!(
10224                    "NVFP4 device selected expert {expert} outside 0..{}",
10225                    experts.expert_count
10226                )
10227                .into());
10228            }
10229        }
10230        let sel_i32 = selected
10231            .iter()
10232            .map(|&expert| expert as i32)
10233            .collect::<Vec<_>>();
10234
10235        // Entry fence: e's stream position covers the input's producer AND every consumer of
10236        // the previous layer's output (queued on e's stream before this call), guarding the
10237        // workspace reuse exactly like the v2 attention driver.
10238        if let Some((_, device)) = workspace.ev_entry.as_ref() {
10239            if *device != e.ctx().ordinal() {
10240                return Err("NVFP4 device-io routes engine changed".into());
10241            }
10242        } else {
10243            let _main = e.gpu.enter_main()?;
10244            workspace.ev_entry = Some((e.ctx().new_event(None)?, e.ctx().ordinal()));
10245        }
10246        {
10247            let _main = e.gpu.enter_main()?;
10248            let (ev_entry, _) = workspace.ev_entry.as_ref().expect("entry event set above");
10249            ev_entry.record(&e.stream())?;
10250        }
10251        for (rank_index, engine) in self.ranks.iter().enumerate() {
10252            let _main = engine.gpu.enter_main()?;
10253            let (ev_entry, _) = workspace.ev_entry.as_ref().expect("entry event set above");
10254            engine.stream().wait(ev_entry)?;
10255            {
10256                let mut destination = workspace.input[rank_index].slice_mut(0..experts.input_width);
10257                engine
10258                    .stream()
10259                    .memcpy_dtod(&input_dev.slice(0..experts.input_width), &mut destination)?;
10260            }
10261            {
10262                let Nvfp4DeviceRoutesWorkspace {
10263                    input, in_q, in_d, ..
10264                } = &mut *workspace;
10265                engine.quantize_q8_1_into(
10266                    &input[rank_index],
10267                    1,
10268                    experts.input_width,
10269                    &mut in_q[rank_index],
10270                    &mut in_d[rank_index],
10271                )?;
10272            }
10273        }
10274        self.nvfp4_routes_batched_sweeps(
10275            experts,
10276            workspace,
10277            selected,
10278            route_weights,
10279            &sel_i32,
10280            local_out,
10281            n_sel,
10282            activation_limit,
10283            false,
10284        )?;
10285
10286        // Evented combine: rank done events replace the host stream syncs, the reduce runs on
10287        // the root stream in canonical shard order, and e copies the combined row out behind
10288        // the root's done event.
10289        // rank0 == root: its own stream order already covers its sweep; only the PEER
10290        // ranks need the record/wait pair (host-op diet at the #1 eager seam, 2026-08-21).
10291        for (rank_index, engine) in self.ranks.iter().enumerate().skip(1) {
10292            let _main = engine.gpu.enter_main()?;
10293            workspace.ev_rank[rank_index].record(&engine.stream())?;
10294        }
10295        if moe_direct_on() && self.ranks.len() == 2 {
10296            // DIRECT JOIN: rank1's accumulator is root-resident (P2P single-store pass);
10297            // rank0's is root-stream-ordered. One root event + rank1's own event order
10298            // the model engine's single add — same operand order as root's add
10299            // (accumulator[0] + accumulator[1]): BIT-IDENTICAL. Output is a FRESH
10300            // e-context row (NOT an alias of ws state — the reverted zero-copy handoff's
10301            // hazard class does not apply).
10302            {
10303                let root = &self.ranks[0];
10304                let _main = root.gpu.enter_main()?;
10305                workspace
10306                    .ev_done
10307                    .as_ref()
10308                    .expect("device routes done event")
10309                    .record(&root.stream())?;
10310            }
10311            let _main = e.gpu.enter_main()?;
10312            e.stream().wait(
10313                workspace
10314                    .ev_done
10315                    .as_ref()
10316                    .expect("device routes done event"),
10317            )?;
10318            for ev in workspace.ev_rank.iter().skip(1) {
10319                e.stream().wait(ev)?;
10320            }
10321            let mut output = e.uninit(experts.input_width)?;
10322            e.add(
10323                &workspace.accumulator[0],
10324                &workspace.accumulator[1],
10325                &mut output,
10326                experts.input_width,
10327            )?;
10328            let output = output;
10329            if let Some(started) = started {
10330                use std::sync::atomic::Ordering;
10331                let ns = TIMING_NS
10332                    .fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
10333                    + started.elapsed().as_nanos() as u64;
10334                let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
10335                if calls % 430 == 0 {
10336                    eprintln!(
10337                        "[nvfp4-dev-routes-direct-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
10338                        ns as f64 / 1.0e6,
10339                        ns as f64 / calls as f64 / 1.0e3,
10340                    );
10341                }
10342            }
10343            return Ok(output);
10344        }
10345        {
10346            let root = &self.ranks[0];
10347            let _main = root.gpu.enter_main()?;
10348            for ev in workspace.ev_rank.iter().skip(1) {
10349                root.stream().wait(ev)?;
10350            }
10351            root.stream()
10352                .memcpy_dtod(&workspace.accumulator[1], &mut workspace.remote)?;
10353            {
10354                let Nvfp4DeviceRoutesWorkspace {
10355                    accumulator,
10356                    remote,
10357                    combined,
10358                    ..
10359                } = &mut *workspace;
10360                root.add(&accumulator[0], remote, combined, experts.input_width)?;
10361            }
10362            workspace
10363                .ev_done
10364                .as_ref()
10365                .expect("device routes done event")
10366                .record(&root.stream())?;
10367        }
10368        let output = {
10369            let _main = e.gpu.enter_main()?;
10370            e.stream().wait(
10371                workspace
10372                    .ev_done
10373                    .as_ref()
10374                    .expect("device routes done event"),
10375            )?;
10376            // (Zero-copy clone handoff REVERTED 2026-08-21: identity mismatch in the
10377            // routes-diet bisect. The alloc+copy stays until the hazard is understood.)
10378            let mut output = e.uninit(experts.input_width)?;
10379            e.stream().memcpy_dtod(
10380                &workspace.combined.slice(0..experts.input_width),
10381                &mut output.slice_mut(0..experts.input_width),
10382            )?;
10383            output
10384        };
10385        if let Some(started) = started {
10386            use std::sync::atomic::Ordering;
10387            let ns = TIMING_NS.fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
10388                + started.elapsed().as_nanos() as u64;
10389            let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
10390            if calls % 430 == 0 {
10391                eprintln!(
10392                    "[nvfp4-dev-routes-io-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
10393                    ns as f64 / 1.0e6,
10394                    ns as f64 / calls as f64 / 1.0e3,
10395                );
10396            }
10397        }
10398        Ok(output)
10399    }
10400
10401    /// Device-routed twin of `run_tensor_parallel_routes_nvfp4_device_io`: the selection and
10402    /// route weights arrive as the device router's e-context outputs — the per-layer host
10403    /// logits readback disappears. The fresh router outputs are staged into persistent
10404    /// e-context buffers on e's stream (never-free discipline) before the entry event; each
10405    /// rank peer-reads them behind it. The down-macro fold happens in-kernel.
10406    #[allow(clippy::too_many_arguments)]
10407    /// Prestage the routed-expert input: pull the shared row to every rank and quantize it
10408    /// there, WITHOUT the selection — callable before the router so the rank chains overlap
10409    /// it. No-op (returns false) when the workspace is not built yet or the door is off;
10410    /// the routed run then does its own staging as before.
10411    pub fn nvfp4_routes_prestage(
10412        &self,
10413        experts: &ResidentNvfp4TensorParallel,
10414        e: &Engine,
10415        input_dev: &crate::CudaSlice<f32>,
10416    ) -> Result<bool, Box<dyn std::error::Error>> {
10417        self.nvfp4_routes_prestage_with(experts, e, input_dev, |_, _, _, _| Ok(false))
10418    }
10419
10420    /// `nvfp4_routes_prestage` with a PEER-ROUTER hook: after rank1's input pull +
10421    /// quantize, the hook may compute rank1's route selection LOCALLY (replicated router —
10422    /// deterministic kernels on identical input bits produce identical sel/w, so the
10423    /// selection is bit-equal to the root's). Returns true when it wrote sel/route_w; the
10424    /// routed run then skips rank1's sel pull.
10425    pub fn nvfp4_routes_prestage_with(
10426        &self,
10427        experts: &ResidentNvfp4TensorParallel,
10428        e: &Engine,
10429        input_dev: &crate::CudaSlice<f32>,
10430        rank1_router: impl FnOnce(
10431            &Engine,
10432            &crate::CudaSlice<f32>,
10433            &mut crate::CudaSlice<i32>,
10434            &mut crate::CudaSlice<f32>,
10435        ) -> Result<bool, Box<dyn std::error::Error>>,
10436    ) -> Result<bool, Box<dyn std::error::Error>> {
10437        if !routes_prestage_on() || step_tp_graph_enabled()? {
10438            return Ok(false);
10439        }
10440        if input_dev.len() != experts.input_width {
10441            return Err("NVFP4 prestage input width mismatch".into());
10442        }
10443        let mut workspace_guard = experts
10444            .device_workspace
10445            .lock()
10446            .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
10447        let Some(workspace) = workspace_guard.as_mut() else {
10448            return Ok(false);
10449        };
10450        if workspace.ev_input.is_none() {
10451            let _main = e.gpu.enter_main()?;
10452            workspace.ev_input = Some((e.ctx().new_event(None)?, e.ctx().ordinal()));
10453        } else if workspace.ev_input.as_ref().map(|(_, d)| *d) != Some(e.ctx().ordinal()) {
10454            return Err("NVFP4 prestage engine changed".into());
10455        }
10456        {
10457            let _main = e.gpu.enter_main()?;
10458            let (ev, _) = workspace.ev_input.as_ref().expect("armed above");
10459            ev.record(&e.stream())?;
10460        }
10461        for (rank_index, engine) in self.ranks.iter().enumerate() {
10462            let _main = engine.gpu.enter_main()?;
10463            let (ev, _) = workspace.ev_input.as_ref().expect("armed above");
10464            engine.stream().wait(ev)?;
10465            {
10466                let mut destination = workspace.input[rank_index].slice_mut(0..experts.input_width);
10467                engine
10468                    .stream()
10469                    .memcpy_dtod(&input_dev.slice(0..experts.input_width), &mut destination)?;
10470            }
10471            {
10472                let Nvfp4DeviceRoutesWorkspace {
10473                    input, in_q, in_d, ..
10474                } = &mut *workspace;
10475                engine.quantize_q8_1_into(
10476                    &input[rank_index],
10477                    1,
10478                    experts.input_width,
10479                    &mut in_q[rank_index],
10480                    &mut in_d[rank_index],
10481                )?;
10482            }
10483        }
10484        if self.ranks.len() == 2 {
10485            let rank1 = &self.ranks[1];
10486            let _r1 = rank1.gpu.enter_main()?;
10487            let Nvfp4DeviceRoutesWorkspace {
10488                input,
10489                sel,
10490                route_w,
10491                ..
10492            } = &mut *workspace;
10493            let (in1, rest_sel) = (&input[1], &mut sel[1]);
10494            if rank1_router(rank1, in1, rest_sel, &mut route_w[1])? {
10495                workspace.rank1_routed = true;
10496            }
10497        }
10498        workspace.prestaged = true;
10499        Ok(true)
10500    }
10501
10502    /// TWO-COLUMN device-routed expert program (spec verify, MEMRA_TCOL_FFN): one gu_tcol
10503    /// sweep over 2*n_sel_col pairs (pair t reads activation row t/n_sel_col — weights the
10504    /// two columns share dedup through L2), the UNCHANGED silu/down kernels at n_sel=16
10505    /// (both already index per pair), and one offset-axpy combine per column (the exact
10506    /// t=1 sequential chain over that column's 8 pairs). No serving doors: no graph, no
10507    /// prestage, no shexp folding — plain evented ordering. Returns [2, input_width] on e.
10508    ///
10509    /// EXACTNESS: every kernel body is the t=1 program per (pair,row) or per element; the
10510    /// per-column combine order equals the t=1 combine; the cross-rank join adds the same
10511    /// operand values elementwise. Gated by the greedy tape like every verify arm.
10512    #[allow(clippy::too_many_arguments)]
10513    pub fn run_tensor_parallel_routes_nvfp4_device_routed_tn(
10514        &self,
10515        experts: &ResidentNvfp4TensorParallel,
10516        e: &Engine,
10517        z_t: &crate::CudaSlice<f32>,
10518        sel_d: &crate::CudaSlice<i32>,
10519        w_d: &crate::CudaSlice<f32>,
10520        t: usize,
10521        n_sel_col: usize,
10522        activation_limit: Option<f32>,
10523    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
10524        let world = self.ranks.len();
10525        if world != NVFP4_CANONICAL_ROW_SHARDS {
10526            return Err("NVFP4 t-row routes require the canonical 2-shard grid".into());
10527        }
10528        let width = experts.input_width;
10529        let n_sel = t * n_sel_col;
10530        if t == 0 || t > 8 || z_t.len() < t * width || sel_d.len() < n_sel || w_d.len() < n_sel {
10531            return Err("NVFP4 t-row routes geometry".into());
10532        }
10533        if !nvfp4_bank_v2_on() {
10534            return Err("NVFP4 t-row routes require the v2 banks (MEMRA_NVFP4_BANK_V2=1)".into());
10535        }
10536        let local_out = experts.expert_width / world;
10537        let mut guard = experts
10538            .t2_workspace
10539            .lock()
10540            .map_err(|_| "NVFP4 t2 workspace lock is poisoned")?;
10541        if guard.as_ref().is_none_or(|ws| ws.n_sel != n_sel) {
10542            let mut input2 = Vec::new();
10543            let mut in_q2 = Vec::new();
10544            let mut in_d2 = Vec::new();
10545            let mut sel2 = Vec::new();
10546            let mut route_w2 = Vec::new();
10547            let mut gate_out2 = Vec::new();
10548            let mut up_out2 = Vec::new();
10549            let mut act_q2 = Vec::new();
10550            let mut act_d2 = Vec::new();
10551            let mut partial2 = Vec::new();
10552            let mut acc_a = Vec::new();
10553            let mut acc_b = Vec::new();
10554            let mut acc2 = Vec::new();
10555            let mut ev_rank = Vec::new();
10556            for engine in &self.ranks {
10557                let _m = engine.gpu.enter_main()?;
10558                input2.push(engine.uninit(t * width)?);
10559                in_q2.push(engine.alloc_i8_uninit(t * width)?);
10560                in_d2.push(engine.uninit(t * (width / 32))?);
10561                sel2.push(engine.htod_i32(&vec![0i32; n_sel])?);
10562                route_w2.push(engine.uninit(n_sel)?);
10563                gate_out2.push(engine.uninit(n_sel * local_out)?);
10564                up_out2.push(engine.uninit(n_sel * local_out)?);
10565                act_q2.push(engine.alloc_i8_uninit(n_sel * local_out)?);
10566                act_d2.push(engine.uninit(n_sel * (local_out / 32))?);
10567                partial2.push(engine.uninit(n_sel * width)?);
10568                acc_a.push(engine.uninit(width)?);
10569                acc_b.push(engine.uninit(width)?);
10570                acc2.push(engine.uninit(t * width)?);
10571                ev_rank.push(engine.ctx().new_event(None)?);
10572            }
10573            let root = &self.ranks[0];
10574            let (peer_a, peer_b, omix_a, omix_b, peer2, omix2, ev_root) = {
10575                let _m = root.gpu.enter_main()?;
10576                (
10577                    root.uninit(width)?,
10578                    root.uninit(width)?,
10579                    root.uninit(width)?,
10580                    root.uninit(width)?,
10581                    root.uninit(t * width)?,
10582                    root.uninit(t * width)?,
10583                    root.ctx().new_event(None)?,
10584                )
10585            };
10586            let ev_entry = {
10587                let _m = e.gpu.enter_main()?;
10588                e.ctx().new_event(None)?
10589            };
10590            *guard = Some(Nvfp4T2Workspace {
10591                input2,
10592                in_q2,
10593                in_d2,
10594                sel2,
10595                route_w2,
10596                gate_out2,
10597                up_out2,
10598                act_q2,
10599                act_d2,
10600                partial2,
10601                acc_a,
10602                acc_b,
10603                acc2,
10604                peer2,
10605                omix2,
10606                peer_a,
10607                peer_b,
10608                omix_a,
10609                omix_b,
10610                ev_entry,
10611                ev_rank,
10612                ev_root,
10613                n_sel,
10614                e_device: e.ctx().ordinal(),
10615            });
10616        }
10617        let ws = guard.as_mut().expect("armed above");
10618        if ws.e_device != e.ctx().ordinal() {
10619            return Err("NVFP4 t2 routes engine changed".into());
10620        }
10621        {
10622            let _main = e.gpu.enter_main()?;
10623            ws.ev_entry.record(&e.stream())?;
10624        }
10625        // One decision for the sweep AND the join (an acc2 the sweep never wrote must
10626        // never be joined). t > 2 has no split-accumulator fallback: it requires the
10627        // fused rows kernel.
10628        let down8 = sel_down8_on() && (local_out >> 5) <= 32 && n_sel_col <= 8;
10629        if !down8 && t != 2 {
10630            return Err(
10631                "NVFP4 t-row routes at t != 2 require MEMRA_SEL_DOWN8=1 (fused rows kernel)".into(),
10632            );
10633        }
10634        for rank in 0..world {
10635            let engine = &self.ranks[rank];
10636            let _main = engine.gpu.enter_main()?;
10637            engine.stream().wait(&ws.ev_entry)?;
10638            {
10639                let mut dst = ws.input2[rank].slice_mut(0..t * width);
10640                engine
10641                    .stream()
10642                    .memcpy_dtod(&z_t.slice(0..t * width), &mut dst)?;
10643            }
10644            {
10645                let mut dst = ws.sel2[rank].slice_mut(0..n_sel);
10646                engine
10647                    .stream()
10648                    .memcpy_dtod(&sel_d.slice(0..n_sel), &mut dst)?;
10649            }
10650            {
10651                let mut dst = ws.route_w2[rank].slice_mut(0..n_sel);
10652                engine
10653                    .stream()
10654                    .memcpy_dtod(&w_d.slice(0..n_sel), &mut dst)?;
10655            }
10656            {
10657                let Nvfp4T2Workspace {
10658                    input2,
10659                    in_q2,
10660                    in_d2,
10661                    ..
10662                } = &mut *ws;
10663                engine.quantize_q8_1_into(
10664                    &input2[rank],
10665                    t,
10666                    width,
10667                    &mut in_q2[rank],
10668                    &mut in_d2[rank],
10669                )?;
10670            }
10671            let gate_bank = &experts.gate[rank];
10672            let up_bank = &experts.up[rank];
10673            if gate_bank.in_features != up_bank.in_features
10674                || gate_bank.local_out != up_bank.local_out
10675                || gate_bank.row_bytes != up_bank.row_bytes
10676                || gate_bank.expert_bytes != up_bank.expert_bytes
10677            {
10678                return Err("NVFP4 t-row routes need matched gate/up bank geometry".into());
10679            }
10680            {
10681                let Nvfp4T2Workspace {
10682                    sel2,
10683                    in_q2,
10684                    in_d2,
10685                    gate_out2,
10686                    up_out2,
10687                    ..
10688                } = &mut *ws;
10689                engine.qmatvec_nvfp4_sel_gu_tcol_into(
10690                    &gate_bank.bank,
10691                    &up_bank.bank,
10692                    &sel2[rank],
10693                    &in_q2[rank],
10694                    &in_d2[rank],
10695                    &mut gate_out2[rank],
10696                    &mut up_out2[rank],
10697                    n_sel,
10698                    n_sel_col,
10699                    gate_bank.in_features,
10700                    gate_bank.local_out,
10701                    gate_bank.row_bytes,
10702                    gate_bank.expert_bytes,
10703                    width,
10704                    width / 32,
10705                )?;
10706            }
10707            {
10708                let Nvfp4T2Workspace {
10709                    gate_out2,
10710                    up_out2,
10711                    sel2,
10712                    act_q2,
10713                    act_d2,
10714                    ..
10715                } = &mut *ws;
10716                engine.silu_mul_scaled_q8_1_sel_into(
10717                    &gate_out2[rank],
10718                    &up_out2[rank],
10719                    &experts.macros_gate_dev[rank],
10720                    &experts.macros_up_dev[rank],
10721                    &sel2[rank],
10722                    activation_limit,
10723                    &mut act_q2[rank],
10724                    &mut act_d2[rank],
10725                    local_out,
10726                    n_sel,
10727                )?;
10728            }
10729            let shard = &experts.down[rank];
10730            if shard.device_rank != rank || shard.local_in != local_out {
10731                return Err("NVFP4 t-row routes: down shard placement drifted".into());
10732            }
10733            // MEMRA_SEL_DOWN8=1: down sweep + per-row combine in ONE launch (t2 twin of
10734            // the t=1 fusion) — kills the n_sel x width partial round-trip and both axpy
10735            // passes. Each row's FP chain == its own down8/axpy pair (bit-identical).
10736            if down8 {
10737                let Nvfp4T2Workspace {
10738                    sel2,
10739                    act_q2,
10740                    act_d2,
10741                    route_w2,
10742                    acc2,
10743                    ..
10744                } = &mut *ws;
10745                engine.qmatvec_nvfp4_sel_down8_rows_into(
10746                    &shard.bank,
10747                    &sel2[rank],
10748                    &act_q2[rank],
10749                    &act_d2[rank],
10750                    &route_w2[rank],
10751                    &experts.macros_down_dev[rank],
10752                    &mut acc2[rank],
10753                    t,
10754                    n_sel_col,
10755                    shard.local_in,
10756                    shard.out_features,
10757                    shard.row_bytes,
10758                    shard.expert_bytes,
10759                    local_out,
10760                    local_out / 32,
10761                )?;
10762            } else {
10763                {
10764                    let Nvfp4T2Workspace {
10765                        sel2,
10766                        act_q2,
10767                        act_d2,
10768                        partial2,
10769                        ..
10770                    } = &mut *ws;
10771                    engine.qmatvec_nvfp4_sel_into(
10772                        &shard.bank,
10773                        &sel2[rank],
10774                        &act_q2[rank],
10775                        &act_d2[rank],
10776                        &mut partial2[rank],
10777                        n_sel,
10778                        shard.local_in,
10779                        shard.out_features,
10780                        shard.row_bytes,
10781                        shard.expert_bytes,
10782                        local_out,
10783                        local_out / 32,
10784                    )?;
10785                }
10786                let Nvfp4T2Workspace {
10787                    partial2,
10788                    route_w2,
10789                    sel2,
10790                    acc_a,
10791                    acc_b,
10792                    ..
10793                } = &mut *ws;
10794                engine.axpy_rows_seq_md_off_into(
10795                    &partial2[rank],
10796                    &route_w2[rank],
10797                    &experts.macros_down_dev[rank],
10798                    &sel2[rank],
10799                    &mut acc_a[rank],
10800                    width,
10801                    n_sel_col,
10802                    0,
10803                )?;
10804                engine.axpy_rows_seq_md_off_into(
10805                    &partial2[rank],
10806                    &route_w2[rank],
10807                    &experts.macros_down_dev[rank],
10808                    &sel2[rank],
10809                    &mut acc_b[rank],
10810                    width,
10811                    n_sel_col,
10812                    n_sel_col,
10813                )?;
10814            }
10815            if rank != 0 {
10816                ws.ev_rank[rank].record(&engine.stream())?;
10817            }
10818        }
10819        let root = &self.ranks[0];
10820        {
10821            let _main = root.gpu.enter_main()?;
10822            for ev in ws.ev_rank.iter().skip(1) {
10823                root.stream().wait(ev)?;
10824            }
10825            if down8 {
10826                // Fused-slab join: ONE peer pull + ONE elementwise add cover every
10827                // row (independent elements; per-element op == the split join).
10828                let Nvfp4T2Workspace {
10829                    acc2, peer2, omix2, ..
10830                } = &mut *ws;
10831                {
10832                    let mut dst = peer2.slice_mut(0..t * width);
10833                    root.stream()
10834                        .memcpy_dtod(&acc2[1].slice(0..t * width), &mut dst)?;
10835                }
10836                root.add(&acc2[0], peer2, omix2, t * width)?;
10837            } else {
10838                let Nvfp4T2Workspace {
10839                    acc_a,
10840                    acc_b,
10841                    peer_a,
10842                    peer_b,
10843                    omix_a,
10844                    omix_b,
10845                    ..
10846                } = &mut *ws;
10847                {
10848                    let mut dst = peer_a.slice_mut(0..width);
10849                    root.stream()
10850                        .memcpy_dtod(&acc_a[1].slice(0..width), &mut dst)?;
10851                }
10852                {
10853                    let mut dst = peer_b.slice_mut(0..width);
10854                    root.stream()
10855                        .memcpy_dtod(&acc_b[1].slice(0..width), &mut dst)?;
10856                }
10857                root.add(&acc_a[0], peer_a, omix_a, width)?;
10858                root.add(&acc_b[0], peer_b, omix_b, width)?;
10859            }
10860            ws.ev_root.record(&root.stream())?;
10861        }
10862        let _main = e.gpu.enter_main()?;
10863        e.stream().wait(&ws.ev_root)?;
10864        let mut out = e.uninit(t * width)?;
10865        if down8 {
10866            e.stream().memcpy_dtod(
10867                &ws.omix2.slice(0..t * width),
10868                &mut out.slice_mut(0..t * width),
10869            )?;
10870        } else {
10871            e.stream()
10872                .memcpy_dtod(&ws.omix_a.slice(0..width), &mut out.slice_mut(0..width))?;
10873            e.stream().memcpy_dtod(
10874                &ws.omix_b.slice(0..width),
10875                &mut out.slice_mut(width..2 * width),
10876            )?;
10877        }
10878        Ok(out)
10879    }
10880
10881    pub fn run_tensor_parallel_routes_nvfp4_device_routed(
10882        &self,
10883        experts: &ResidentNvfp4TensorParallel,
10884        e: &Engine,
10885        input_dev: &crate::CudaSlice<f32>,
10886        sel_d: &crate::CudaSlice<i32>,
10887        w_d: &crate::CudaSlice<f32>,
10888        experts_per_token: usize,
10889        activation_limit: Option<f32>,
10890    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
10891        self.run_tensor_parallel_routes_nvfp4_device_routed_prejoin(
10892            experts,
10893            e,
10894            input_dev,
10895            sel_d,
10896            w_d,
10897            experts_per_token,
10898            activation_limit,
10899            || Ok(()),
10900        )
10901    }
10902
10903    /// `run_tensor_parallel_routes_nvfp4_device_routed` with a PREJOIN hook: `pre_join`
10904    /// runs on the host right before the join wait is enqueued on e's stream — work it
10905    /// issues there (e.g. the shexp overlap) executes WHILE the peer rank finishes its
10906    /// sweep, instead of after the join. Value-neutral by construction (the hook only
10907    /// reorders independent host issue).
10908    #[allow(clippy::too_many_arguments)]
10909    pub fn run_tensor_parallel_routes_nvfp4_device_routed_prejoin(
10910        &self,
10911        experts: &ResidentNvfp4TensorParallel,
10912        e: &Engine,
10913        input_dev: &crate::CudaSlice<f32>,
10914        sel_d: &crate::CudaSlice<i32>,
10915        w_d: &crate::CudaSlice<f32>,
10916        experts_per_token: usize,
10917        activation_limit: Option<f32>,
10918        pre_join: impl FnOnce() -> Result<(), Box<dyn std::error::Error>>,
10919    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
10920        self.run_tensor_parallel_routes_nvfp4_device_routed_prejoin_add3(
10921            experts,
10922            e,
10923            input_dev,
10924            sel_d,
10925            w_d,
10926            experts_per_token,
10927            activation_limit,
10928            pre_join,
10929            None,
10930        )
10931    }
10932
10933    /// The prejoin variant with MOE TAIL FUSION M1: when `post_add = Some((sh_raw,
10934    /// scale_raw))`, the direct-join arm folds the shexp apply into the join add
10935    /// (`dst = (acc0+acc1) + sh*scale[0]`, exact split-pair sequence) — the caller skips
10936    /// its apply launch. Raw UVA pointers so no lock is held across the call.
10937    #[allow(clippy::too_many_arguments)]
10938    pub fn run_tensor_parallel_routes_nvfp4_device_routed_prejoin_add3(
10939        &self,
10940        experts: &ResidentNvfp4TensorParallel,
10941        e: &Engine,
10942        input_dev: &crate::CudaSlice<f32>,
10943        sel_d: &crate::CudaSlice<i32>,
10944        w_d: &crate::CudaSlice<f32>,
10945        experts_per_token: usize,
10946        activation_limit: Option<f32>,
10947        pre_join: impl FnOnce() -> Result<(), Box<dyn std::error::Error>>,
10948        post_add: Option<(u64, u64)>,
10949    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
10950        if input_dev.len() != experts.input_width {
10951            return Err(format!(
10952                "NVFP4 device-routed input {} != width {}",
10953                input_dev.len(),
10954                experts.input_width
10955            )
10956            .into());
10957        }
10958        let n_sel = experts_per_token;
10959        if sel_d.len() < n_sel || w_d.len() < n_sel {
10960            return Err(format!(
10961                "NVFP4 device-routed routes sel={} w={} < experts/token {n_sel}",
10962                sel_d.len(),
10963                w_d.len()
10964            )
10965            .into());
10966        }
10967        let world = self.ranks.len();
10968        if world != NVFP4_CANONICAL_ROW_SHARDS {
10969            return Err(format!(
10970                "NVFP4 device routes require world == canonical shard grid \
10971                 ({NVFP4_CANONICAL_ROW_SHARDS}), got {world}"
10972            )
10973            .into());
10974        }
10975        let local_out = if experts.ep2 {
10976            experts.expert_width
10977        } else {
10978            experts.expert_width / world
10979        };
10980
10981        static TIMING_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
10982        static TIMING_CALLS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
10983        let timing = std::env::var("MEMRA_STEP_TP_TIMING").as_deref() == Ok("1");
10984        let started = timing.then(std::time::Instant::now);
10985
10986        let mut workspace_guard = experts
10987            .device_workspace
10988            .lock()
10989            .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
10990        if workspace_guard.is_none() {
10991            drop(workspace_guard);
10992            let zero = vec![0.0f32; experts.input_width];
10993            let zero_sel = vec![0usize; n_sel];
10994            let zero_w = vec![0.0f32; n_sel];
10995            let _ = self.run_tensor_parallel_routes_nvfp4_device(
10996                experts,
10997                &zero,
10998                &zero_sel,
10999                &zero_w,
11000                n_sel,
11001                activation_limit,
11002            )?;
11003            workspace_guard = experts
11004                .device_workspace
11005                .lock()
11006                .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
11007        }
11008        let workspace = workspace_guard
11009            .as_mut()
11010            .expect("NVFP4 device routes workspace initialized above");
11011        if workspace.n_sel != n_sel {
11012            return Err(format!(
11013                "NVFP4 device routes experts/token changed: workspace {} != call {n_sel}",
11014                workspace.n_sel
11015            )
11016            .into());
11017        }
11018
11019        // GRAPH DOOR (MEMRA_STEP_TP_GRAPH=1): the whole rank+root segment replays as one
11020        // stitched multi-device parent launched on e's stream — no events, no per-token node
11021        // updates (every address is persistent staging). VALUE-IDENTICAL to the eager path:
11022        // the children replay exactly the same kernel/copy sequence.
11023        if step_tp_graph_enabled()? {
11024            if experts.ep2 {
11025                return Err(
11026                    "MEMRA_STEP_TP_GRAPH=1 with MEMRA_STEP_NVFP4_EP2=1 has never been \
11027                     co-gated; unset one"
11028                        .into(),
11029                );
11030            }
11031            if workspace.dev_route_e.is_none() {
11032                let _main = e.gpu.enter_main()?;
11033                workspace.dev_route_e = Some((
11034                    e.htod_i32(&vec![0i32; n_sel])?,
11035                    e.htod(&vec![0.0f32; n_sel])?,
11036                ));
11037            }
11038            if workspace.in_stage_e.is_none() {
11039                let _main = e.gpu.enter_main()?;
11040                workspace.in_stage_e = Some(e.htod(&vec![0.0f32; experts.input_width])?);
11041                workspace.out_stage_e = Some(e.htod(&vec![0.0f32; experts.input_width])?);
11042            }
11043            if workspace.routes_graph.is_none() {
11044                let graph = self.nvfp4_routes_build_graph(
11045                    experts,
11046                    workspace,
11047                    local_out,
11048                    n_sel,
11049                    activation_limit,
11050                )?;
11051                workspace.routes_graph = Some(graph);
11052                eprintln!(
11053                    "[step-tp-graph] routes segment captured: ranks={world} n_sel={n_sel} \
11054                     children=3 updates=none performance_claim=false"
11055                );
11056            }
11057            let output = {
11058                let _main = e.gpu.enter_main()?;
11059                {
11060                    let (sel_e, w_e) = workspace
11061                        .dev_route_e
11062                        .as_mut()
11063                        .expect("device route staging set above");
11064                    {
11065                        let mut dst = sel_e.slice_mut(0..n_sel);
11066                        e.stream().memcpy_dtod(&sel_d.slice(0..n_sel), &mut dst)?;
11067                    }
11068                    {
11069                        let mut dst = w_e.slice_mut(0..n_sel);
11070                        e.stream().memcpy_dtod(&w_d.slice(0..n_sel), &mut dst)?;
11071                    }
11072                }
11073                {
11074                    let in_stage = workspace
11075                        .in_stage_e
11076                        .as_mut()
11077                        .expect("graph staging set above");
11078                    let mut dst = in_stage.slice_mut(0..experts.input_width);
11079                    e.stream()
11080                        .memcpy_dtod(&input_dev.slice(0..experts.input_width), &mut dst)?;
11081                }
11082                unsafe {
11083                    let r = cudarc::driver::sys::cuGraphLaunch(
11084                        workspace
11085                            .routes_graph
11086                            .as_ref()
11087                            .expect("routes graph built above")
11088                            .exec,
11089                        e.stream().cu_stream() as cudarc::driver::sys::CUstream,
11090                    );
11091                    if r != cudarc::driver::sys::CUresult::CUDA_SUCCESS {
11092                        return Err(format!("routes graph launch: {r:?}").into());
11093                    }
11094                }
11095                let mut output = e.uninit(experts.input_width)?;
11096                {
11097                    let out_stage = workspace
11098                        .out_stage_e
11099                        .as_ref()
11100                        .expect("graph staging set above");
11101                    e.stream().memcpy_dtod(
11102                        &out_stage.slice(0..experts.input_width),
11103                        &mut output.slice_mut(0..experts.input_width),
11104                    )?;
11105                }
11106                output
11107            };
11108            if let Some(started) = started {
11109                use std::sync::atomic::Ordering;
11110                let ns = TIMING_NS
11111                    .fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
11112                    + started.elapsed().as_nanos() as u64;
11113                let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
11114                if calls % 430 == 0 {
11115                    eprintln!(
11116                        "[nvfp4-dev-routed-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
11117                        ns as f64 / 1.0e6,
11118                        ns as f64 / calls as f64 / 1.0e3,
11119                    );
11120                }
11121            }
11122            return Ok(output);
11123        }
11124
11125        // Entry fence + router-output staging, all on e's stream: the fresh sel/w slices are
11126        // copied into the persistent e-context pair, then the event is recorded — the caller's
11127        // sel_d/w_d can free on e's stream with no cross-stream reader.
11128        if let Some((_, device)) = workspace.ev_entry.as_ref() {
11129            if *device != e.ctx().ordinal() {
11130                return Err("NVFP4 device-routed routes engine changed".into());
11131            }
11132        } else {
11133            let _main = e.gpu.enter_main()?;
11134            workspace.ev_entry = Some((e.ctx().new_event(None)?, e.ctx().ordinal()));
11135        }
11136        if workspace.dev_route_e.is_none() {
11137            let _main = e.gpu.enter_main()?;
11138            workspace.dev_route_e = Some((
11139                e.htod_i32(&vec![0i32; n_sel])?,
11140                e.htod(&vec![0.0f32; n_sel])?,
11141            ));
11142        }
11143        // MEMRA_SEL_MIRROR: the staging pair exists so the rank streams read a persistent
11144        // e-context address. The caller's sel_d/w_d ARE persistent (the process-static
11145        // selection rows), so when every consuming rank shares e's device the ranks can read
11146        // them directly and this hop disappears. The graph door keeps the staging (its
11147        // captured copies read the fixed addresses).
11148        let mirror = sel_mirror_on() && !step_tp_graph_enabled()?;
11149        let e_device = e.ctx().ordinal();
11150        // rank1_routed is consumed (taken) below; peek it here for the staging decision.
11151        let rank1_routed_peek = workspace.rank1_routed;
11152        let stage_needed = !mirror
11153            || self.ranks.iter().enumerate().any(|(rank_index, engine)| {
11154                !(rank1_routed_peek && rank_index == 1) && engine.ctx().ordinal() != e_device
11155            });
11156        {
11157            let _main = e.gpu.enter_main()?;
11158            if stage_needed {
11159                let (sel_e, w_e) = workspace
11160                    .dev_route_e
11161                    .as_mut()
11162                    .expect("device route staging set above");
11163                {
11164                    let mut dst = sel_e.slice_mut(0..n_sel);
11165                    e.stream().memcpy_dtod(&sel_d.slice(0..n_sel), &mut dst)?;
11166                }
11167                {
11168                    let mut dst = w_e.slice_mut(0..n_sel);
11169                    e.stream().memcpy_dtod(&w_d.slice(0..n_sel), &mut dst)?;
11170                }
11171            }
11172            let (ev_entry, _) = workspace.ev_entry.as_ref().expect("entry event set above");
11173            ev_entry.record(&e.stream())?;
11174        }
11175        // Prestage door: input pull + quantize were already issued on the rank streams
11176        // (before the router) — the rank stream order suffices, skip them here.
11177        let prestaged = std::mem::take(&mut workspace.prestaged);
11178        let rank1_routed = std::mem::take(&mut workspace.rank1_routed);
11179        for (rank_index, engine) in self.ranks.iter().enumerate() {
11180            let _main = engine.gpu.enter_main()?;
11181            let (ev_entry, _) = workspace.ev_entry.as_ref().expect("entry event set above");
11182            engine.stream().wait(ev_entry)?;
11183            if !prestaged {
11184                let mut destination = workspace.input[rank_index].slice_mut(0..experts.input_width);
11185                engine
11186                    .stream()
11187                    .memcpy_dtod(&input_dev.slice(0..experts.input_width), &mut destination)?;
11188            }
11189            if !(rank1_routed && rank_index == 1) {
11190                // ONE mirror launch instead of two 32-byte copy-engine dispatches; source is
11191                // the caller's persistent rows when this rank shares e's device (UVA, ordered
11192                // by ev_entry), else the staged e-context pair.
11193                let same_dev = engine.ctx().ordinal() == e_device;
11194                if mirror {
11195                    // Split the workspace borrow so the source (the staged pair, when this
11196                    // rank is off-device) and the destination rows coexist.
11197                    let Nvfp4DeviceRoutesWorkspace {
11198                        sel,
11199                        route_w,
11200                        dev_route_e,
11201                        ..
11202                    } = &mut *workspace;
11203                    let (src_sel, src_w): (&crate::CudaSlice<i32>, &crate::CudaSlice<f32>) =
11204                        if same_dev {
11205                            (sel_d, w_d)
11206                        } else {
11207                            let (sel_e, w_e) = dev_route_e
11208                                .as_ref()
11209                                .expect("device route staging set above");
11210                            (sel_e, w_e)
11211                        };
11212                    engine.moe_sel_w_mirror(
11213                        src_sel,
11214                        src_w,
11215                        &mut sel[rank_index],
11216                        &mut route_w[rank_index],
11217                        n_sel,
11218                    )?;
11219                } else {
11220                    let (sel_e, w_e) = workspace
11221                        .dev_route_e
11222                        .as_ref()
11223                        .expect("device route staging set above");
11224                    {
11225                        let mut dst = workspace.sel[rank_index].slice_mut(0..n_sel);
11226                        engine
11227                            .stream()
11228                            .memcpy_dtod(&sel_e.slice(0..n_sel), &mut dst)?;
11229                    }
11230                    {
11231                        let mut dst = workspace.route_w[rank_index].slice_mut(0..n_sel);
11232                        engine
11233                            .stream()
11234                            .memcpy_dtod(&w_e.slice(0..n_sel), &mut dst)?;
11235                    }
11236                }
11237            }
11238            if !prestaged {
11239                let Nvfp4DeviceRoutesWorkspace {
11240                    input, in_q, in_d, ..
11241                } = &mut *workspace;
11242                engine.quantize_q8_1_into(
11243                    &input[rank_index],
11244                    1,
11245                    experts.input_width,
11246                    &mut in_q[rank_index],
11247                    &mut in_d[rank_index],
11248                )?;
11249            }
11250        }
11251        self.nvfp4_routes_batched_sweeps(
11252            experts,
11253            workspace,
11254            &[],
11255            &[],
11256            &[],
11257            local_out,
11258            n_sel,
11259            activation_limit,
11260            true,
11261        )?;
11262
11263        // rank0 == root: its own stream order already covers its sweep; only the PEER
11264        // ranks need the record/wait pair (host-op diet at the #1 eager seam, 2026-08-21).
11265        for (rank_index, engine) in self.ranks.iter().enumerate().skip(1) {
11266            let _main = engine.gpu.enter_main()?;
11267            workspace.ev_rank[rank_index].record(&engine.stream())?;
11268        }
11269        // Doorbell fences (MEMRA_FENCE_MEMOPS=1): rank1 + root ring their flags; e waits
11270        // the tickets instead of the two events. Arm lazily; 0-len = unsupported.
11271        let memops = fence_memops_on() && moe_direct_on() && self.ranks.len() == 2;
11272        let mut ticket = 0u32;
11273        if memops {
11274            use cudarc::driver::sys;
11275            if workspace.fence_flags_raw == 0 {
11276                let root = &self.ranks[0];
11277                let _main = root.gpu.enter_main()?;
11278                let mut ptr: sys::CUdeviceptr = 0;
11279                let r = unsafe { sys::cuMemAlloc_v2(&mut ptr, 8) };
11280                if r != sys::CUresult::CUDA_SUCCESS {
11281                    return Err(format!("fence flag alloc: {r:?}").into());
11282                }
11283                let r = unsafe { sys::cuMemsetD8_v2(ptr, 0, 8) };
11284                if r != sys::CUresult::CUDA_SUCCESS {
11285                    return Err(format!("fence flag memset: {r:?}").into());
11286                }
11287                workspace.fence_flags_raw = ptr as u64;
11288            }
11289            workspace.fence_ticket = workspace.fence_ticket.wrapping_add(1).max(1);
11290            ticket = workspace.fence_ticket;
11291            let base = workspace.fence_flags_raw;
11292            // rank1's fence: a peer stream MEMOP is rejected over PCIe P2P
11293            // (CUDA_ERROR_INVALID_VALUE, receipted 2026-08-23), but a peer KERNEL STORE into
11294            // root memory is legal — the direct join already relies on it. Under
11295            // MEMRA_FENCE_RANK1 rank1 rings flag[0] that way and e waits it same-device,
11296            // replacing the cross-device event wait below.
11297            if fence_rank1_on() {
11298                let peer = &self.ranks[1];
11299                let _pmain = peer.gpu.enter_main()?;
11300                peer.ring_flag_raw(base, ticket)?;
11301            }
11302            {
11303                let root = &self.ranks[0];
11304                let _main = root.gpu.enter_main()?;
11305                let r = unsafe {
11306                    sys::cuStreamWriteValue32_v2(
11307                        root.stream().cu_stream() as sys::CUstream,
11308                        (base + 4) as sys::CUdeviceptr,
11309                        ticket,
11310                        0,
11311                    )
11312                };
11313                if r != sys::CUresult::CUDA_SUCCESS {
11314                    return Err(format!("fence write root: {r:?}").into());
11315                }
11316            }
11317        }
11318        // PREJOIN hook: rank work is fully issued (dev1 running); independent e-stream
11319        // kernels queued here execute while the peer rank drains its sweep.
11320        pre_join()?;
11321
11322        if moe_direct_on() && self.ranks.len() == 2 {
11323            // DIRECT JOIN: rank1's accumulator is root-resident (P2P single-store pass);
11324            // rank0's is root-stream-ordered. One root event + rank1's own event order
11325            // the model engine's single add — same operand order as root's add
11326            // (accumulator[0] + accumulator[1]): BIT-IDENTICAL. Output is a FRESH
11327            // e-context row (NOT an alias of ws state — the reverted zero-copy handoff's
11328            // hazard class does not apply).
11329            let _main = e.gpu.enter_main()?;
11330            if memops {
11331                use cudarc::driver::sys;
11332                let base = workspace.fence_flags_raw;
11333                let r = unsafe {
11334                    sys::cuStreamWaitValue32_v2(
11335                        e.stream().cu_stream() as sys::CUstream,
11336                        (base + 4) as sys::CUdeviceptr,
11337                        ticket,
11338                        sys::CUstreamWaitValue_flags::CU_STREAM_WAIT_VALUE_GEQ as u32,
11339                    )
11340                };
11341                if r != sys::CUresult::CUDA_SUCCESS {
11342                    return Err(format!("fence wait: {r:?}").into());
11343                }
11344                if fence_rank1_on() {
11345                    // Same-device wait on the flag rank1 rang over P2P.
11346                    let r = unsafe {
11347                        sys::cuStreamWaitValue32_v2(
11348                            e.stream().cu_stream() as sys::CUstream,
11349                            base as sys::CUdeviceptr,
11350                            ticket,
11351                            sys::CUstreamWaitValue_flags::CU_STREAM_WAIT_VALUE_GEQ as u32,
11352                        )
11353                    };
11354                    if r != sys::CUresult::CUDA_SUCCESS {
11355                        return Err(format!("fence wait rank1: {r:?}").into());
11356                    }
11357                } else {
11358                    for ev in workspace.ev_rank.iter().skip(1) {
11359                        e.stream().wait(ev)?;
11360                    }
11361                }
11362            } else {
11363                {
11364                    let root = &self.ranks[0];
11365                    let _rmain = root.gpu.enter_main()?;
11366                    workspace
11367                        .ev_done
11368                        .as_ref()
11369                        .expect("device routes done event")
11370                        .record(&root.stream())?;
11371                }
11372                e.stream().wait(
11373                    workspace
11374                        .ev_done
11375                        .as_ref()
11376                        .expect("device routes done event"),
11377                )?;
11378                for ev in workspace.ev_rank.iter().skip(1) {
11379                    e.stream().wait(ev)?;
11380                }
11381            }
11382            let mut output = e.uninit(experts.input_width)?;
11383            if let Some((sh_raw, scale_raw)) = post_add {
11384                // MOE TAIL FUSION M1: fold the shexp apply into the join add —
11385                // dst = (acc0 + acc1) + sh*scale[0], the exact split-pair sequence.
11386                e.add3_raw(
11387                    &workspace.accumulator[0],
11388                    &workspace.accumulator[1],
11389                    sh_raw,
11390                    scale_raw,
11391                    &mut output,
11392                    experts.input_width,
11393                )?;
11394            } else {
11395                e.add(
11396                    &workspace.accumulator[0],
11397                    &workspace.accumulator[1],
11398                    &mut output,
11399                    experts.input_width,
11400                )?;
11401            }
11402            let output = output;
11403            if let Some(started) = started {
11404                use std::sync::atomic::Ordering;
11405                let ns = TIMING_NS
11406                    .fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
11407                    + started.elapsed().as_nanos() as u64;
11408                let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
11409                if calls % 430 == 0 {
11410                    eprintln!(
11411                        "[nvfp4-dev-routes-direct-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
11412                        ns as f64 / 1.0e6,
11413                        ns as f64 / calls as f64 / 1.0e3,
11414                    );
11415                }
11416            }
11417            return Ok(output);
11418        }
11419        {
11420            let root = &self.ranks[0];
11421            let _main = root.gpu.enter_main()?;
11422            for ev in workspace.ev_rank.iter().skip(1) {
11423                root.stream().wait(ev)?;
11424            }
11425            root.stream()
11426                .memcpy_dtod(&workspace.accumulator[1], &mut workspace.remote)?;
11427            {
11428                let Nvfp4DeviceRoutesWorkspace {
11429                    accumulator,
11430                    remote,
11431                    combined,
11432                    ..
11433                } = &mut *workspace;
11434                root.add(&accumulator[0], remote, combined, experts.input_width)?;
11435            }
11436            workspace
11437                .ev_done
11438                .as_ref()
11439                .expect("device routes done event")
11440                .record(&root.stream())?;
11441        }
11442        let output = {
11443            let _main = e.gpu.enter_main()?;
11444            e.stream().wait(
11445                workspace
11446                    .ev_done
11447                    .as_ref()
11448                    .expect("device routes done event"),
11449            )?;
11450            // (Zero-copy clone handoff REVERTED 2026-08-21: identity mismatch in the
11451            // routes-diet bisect. The alloc+copy stays until the hazard is understood.)
11452            let mut output = e.uninit(experts.input_width)?;
11453            e.stream().memcpy_dtod(
11454                &workspace.combined.slice(0..experts.input_width),
11455                &mut output.slice_mut(0..experts.input_width),
11456            )?;
11457            output
11458        };
11459        if let Some(started) = started {
11460            use std::sync::atomic::Ordering;
11461            let ns = TIMING_NS.fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
11462                + started.elapsed().as_nanos() as u64;
11463            let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
11464            if calls % 430 == 0 {
11465                eprintln!(
11466                    "[nvfp4-dev-routed-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
11467                    ns as f64 / 1.0e6,
11468                    ns as f64 / calls as f64 / 1.0e3,
11469                );
11470            }
11471        }
11472        Ok(output)
11473    }
11474
11475    /// The fused finish's ROOT section (combine + shadow gathers), event-free: the eager
11476    /// caller wraps it with rank-event waits + the done record; the token graph captures it
11477    /// verbatim (parent edges provide the ordering).
11478    pub(crate) fn decode_v2_finish_root_fused(
11479        &self,
11480        ws: &mut StepTpDecodeV2Ws,
11481    ) -> Result<(), Box<dyn std::error::Error>> {
11482        let root = &self.ranks[0];
11483        let _main = root.gpu.enter_main()?;
11484        if ws.raw_peer_partial != 0 {
11485            // Capture-safe raw seams (arming happened in the stage flow).
11486            raw_copy_bytes(ws.raw_peer_partial, ws.raw_o_partial1, ws.o_out * 4, root)?;
11487        } else {
11488            root.stream()
11489                .memcpy_dtod(&ws.o_partials[1][0], &mut ws.peer_partial)?;
11490        }
11491        {
11492            let StepTpDecodeV2Ws {
11493                o_partials,
11494                peer_partial,
11495                reduce_a,
11496                o_out,
11497                ..
11498            } = &mut *ws;
11499            root.add(&o_partials[0][0], peer_partial, reduce_a, *o_out)?;
11500        }
11501        let shadows = !no_local_shadow_on() || ws.raw_mixed_stage_e != 0;
11502        if shadows {
11503            // rank0's shadows are same-context (root) copies; rank1's cross-context reads go
11504            // raw when armed.
11505            let mut k_dst = ws.k_shadow.slice_mut(0..ws.local_kv_dim);
11506            root.stream().memcpy_dtod(&ws.k[0], &mut k_dst)?;
11507            let mut v_dst = ws.v_shadow.slice_mut(0..ws.local_kv_dim);
11508            root.stream().memcpy_dtod(&ws.v_raw[0], &mut v_dst)?;
11509        }
11510        if shadows && ws.raw_peer_partial != 0 {
11511            raw_copy_bytes(
11512                ws.raw_k_shadow + (ws.local_kv_dim * 4) as u64,
11513                ws.raw_k1,
11514                ws.local_kv_dim * 4,
11515                root,
11516            )?;
11517            raw_copy_bytes(
11518                ws.raw_v_shadow + (ws.local_kv_dim * 4) as u64,
11519                ws.raw_v1,
11520                ws.local_kv_dim * 4,
11521                root,
11522            )?;
11523        } else if shadows {
11524            let start = ws.local_kv_dim;
11525            let mut k_dst = ws.k_shadow.slice_mut(start..start + ws.local_kv_dim);
11526            root.stream().memcpy_dtod(&ws.k[1], &mut k_dst)?;
11527            let mut v_dst = ws.v_shadow.slice_mut(start..start + ws.local_kv_dim);
11528            root.stream().memcpy_dtod(&ws.v_raw[1], &mut v_dst)?;
11529        }
11530        if ws.raw_mixed_stage_e != 0 {
11531            // Token-graph mirrors: the e-glue children read same-context copies of the
11532            // root-produced rows.
11533            raw_copy_bytes(ws.raw_mixed_stage_e, ws.raw_reduce_a, ws.o_out * 4, root)?;
11534            let (k_stage, v_stage) = ws.raw_shadow_stage_e;
11535            raw_copy_bytes(k_stage, ws.raw_k_shadow, 2 * ws.local_kv_dim * 4, root)?;
11536            raw_copy_bytes(v_stage, ws.raw_v_shadow, 2 * ws.local_kv_dim * 4, root)?;
11537        }
11538        Ok(())
11539    }
11540
11541    /// Arm the token-graph e-context mirrors (orchestrator-supplied fixed addresses) plus
11542    /// reduce_a's own pointer.
11543    pub(crate) fn decode_v2_arm_token_mirrors(
11544        &self,
11545        ws: &mut StepTpDecodeV2Ws,
11546        mixed_stage_e: u64,
11547        shadow_stage_e: (u64, u64),
11548    ) -> Result<(), Box<dyn std::error::Error>> {
11549        use cudarc::driver::DevicePtr;
11550        let root = &self.ranks[0];
11551        let _main = root.gpu.enter_main()?;
11552        let stream = root.stream();
11553        let (a, _g) = ws.reduce_a.device_ptr(&stream);
11554        ws.raw_reduce_a = a as u64;
11555        ws.raw_mixed_stage_e = mixed_stage_e;
11556        ws.raw_shadow_stage_e = shadow_stage_e;
11557        Ok(())
11558    }
11559
11560    /// Build one layer's stitched routes graph: per-rank children captured on their own
11561    /// streams (raw cuMemcpyAsync at every cross-context seam — cudarc's slice tracking is
11562    /// capture-illegal there), a root combine child, and a multi-device parent with
11563    /// {rank0, rank1} -> root dependency edges. Zero per-token updates: every address the
11564    /// nodes touch is persistent workspace/staging.
11565    fn nvfp4_routes_build_graph(
11566        &self,
11567        experts: &ResidentNvfp4TensorParallel,
11568        workspace: &mut Nvfp4DeviceRoutesWorkspace,
11569        local_out: usize,
11570        n_sel: usize,
11571        activation_limit: Option<f32>,
11572    ) -> Result<RoutesGraph, Box<dyn std::error::Error>> {
11573        use cudarc::driver::DevicePtr;
11574        use cudarc::driver::sys;
11575        fn cu_try(r: sys::CUresult, what: &str) -> Result<(), Box<dyn std::error::Error>> {
11576            if r == sys::CUresult::CUDA_SUCCESS {
11577                Ok(())
11578            } else {
11579                Err(format!("{what}: {r:?}").into())
11580            }
11581        }
11582        let world = self.ranks.len();
11583        if world != 2 {
11584            return Err("routes graph door is built for the TP2 pair".into());
11585        }
11586        let width = experts.input_width;
11587
11588        // Raw pointers cached before capture (each read with its owner's stream).
11589        let ptr_f32 = |buf: &crate::CudaSlice<f32>, engine: &Engine| -> u64 {
11590            let stream = engine.stream();
11591            let (ptr, _g) = buf.device_ptr(&stream);
11592            ptr as u64
11593        };
11594        let ptr_i32 = |buf: &crate::CudaSlice<i32>, engine: &Engine| -> u64 {
11595            let stream = engine.stream();
11596            let (ptr, _g) = buf.device_ptr(&stream);
11597            ptr as u64
11598        };
11599        let (sel_e, w_e) = workspace
11600            .dev_route_e
11601            .as_ref()
11602            .expect("device route staging set before graph build");
11603        let root_engine = &self.ranks[0];
11604        let p_in_stage = ptr_f32(
11605            workspace.in_stage_e.as_ref().expect("graph staging"),
11606            root_engine,
11607        );
11608        let p_out_stage = ptr_f32(
11609            workspace.out_stage_e.as_ref().expect("graph staging"),
11610            root_engine,
11611        );
11612        let p_sel_e = ptr_i32(sel_e, root_engine);
11613        let p_w_e = ptr_f32(w_e, root_engine);
11614        let p_input: Vec<u64> = (0..world)
11615            .map(|r| ptr_f32(&workspace.input[r], &self.ranks[r]))
11616            .collect();
11617        let p_sel: Vec<u64> = (0..world)
11618            .map(|r| ptr_i32(&workspace.sel[r], &self.ranks[r]))
11619            .collect();
11620        let p_route_w: Vec<u64> = (0..world)
11621            .map(|r| ptr_f32(&workspace.route_w[r], &self.ranks[r]))
11622            .collect();
11623        let p_acc1 = ptr_f32(&workspace.accumulator[1], &self.ranks[1]);
11624        let p_remote = ptr_f32(&workspace.remote, root_engine);
11625        let p_combined = ptr_f32(&workspace.combined, root_engine);
11626
11627        let raw_copy = |dst: u64,
11628                        src: u64,
11629                        bytes: usize,
11630                        engine: &Engine|
11631         -> Result<(), Box<dyn std::error::Error>> {
11632            unsafe {
11633                cu_try(
11634                    sys::cuMemcpyAsync(
11635                        dst as sys::CUdeviceptr,
11636                        src as sys::CUdeviceptr,
11637                        bytes,
11638                        engine.stream().cu_stream() as sys::CUstream,
11639                    ),
11640                    "routes graph cuMemcpyAsync",
11641                )
11642            }
11643        };
11644
11645        let mut children = Vec::with_capacity(3);
11646        for rank in 0..world {
11647            let engine = &self.ranks[rank];
11648            let _main = engine.gpu.enter_main()?;
11649            let (child, _retained) = engine.capture_graph_retained(|_| {
11650                raw_copy(p_input[rank], p_in_stage, width * 4, engine)?;
11651                raw_copy(p_sel[rank], p_sel_e, n_sel * 4, engine)?;
11652                raw_copy(p_route_w[rank], p_w_e, n_sel * 4, engine)?;
11653                {
11654                    let Nvfp4DeviceRoutesWorkspace {
11655                        input, in_q, in_d, ..
11656                    } = &mut *workspace;
11657                    engine.quantize_q8_1_into(
11658                        &input[rank],
11659                        1,
11660                        width,
11661                        &mut in_q[rank],
11662                        &mut in_d[rank],
11663                    )?;
11664                }
11665                self.nvfp4_routes_batched_sweeps_rank(
11666                    experts,
11667                    workspace,
11668                    &[],
11669                    &[],
11670                    &[],
11671                    local_out,
11672                    n_sel,
11673                    activation_limit,
11674                    true,
11675                    rank,
11676                )?;
11677                Ok(())
11678            })?;
11679            children.push(child);
11680        }
11681        {
11682            let root = &self.ranks[0];
11683            let _main = root.gpu.enter_main()?;
11684            let (child, _retained) = root.capture_graph_retained(|_| {
11685                raw_copy(p_remote, p_acc1, width * 4, root)?;
11686                {
11687                    let Nvfp4DeviceRoutesWorkspace {
11688                        accumulator,
11689                        remote,
11690                        combined,
11691                        ..
11692                    } = &mut *workspace;
11693                    root.add(&accumulator[0], remote, combined, width)?;
11694                }
11695                raw_copy(p_out_stage, p_combined, width * 4, root)?;
11696                Ok(())
11697            })?;
11698            children.push(child);
11699        }
11700
11701        let mut parent: sys::CUgraph = std::ptr::null_mut();
11702        unsafe {
11703            cu_try(sys::cuGraphCreate(&mut parent, 0), "routes cuGraphCreate")?;
11704        }
11705        let mut n0: sys::CUgraphNode = std::ptr::null_mut();
11706        let mut n1: sys::CUgraphNode = std::ptr::null_mut();
11707        let mut n2: sys::CUgraphNode = std::ptr::null_mut();
11708        unsafe {
11709            cu_try(
11710                sys::cuGraphAddChildGraphNode(
11711                    &mut n0,
11712                    parent,
11713                    std::ptr::null(),
11714                    0,
11715                    children[0].cu_graph(),
11716                ),
11717                "routes child r0",
11718            )?;
11719            cu_try(
11720                sys::cuGraphAddChildGraphNode(
11721                    &mut n1,
11722                    parent,
11723                    std::ptr::null(),
11724                    0,
11725                    children[1].cu_graph(),
11726                ),
11727                "routes child r1",
11728            )?;
11729            let deps = [n0, n1];
11730            cu_try(
11731                sys::cuGraphAddChildGraphNode(
11732                    &mut n2,
11733                    parent,
11734                    deps.as_ptr(),
11735                    2,
11736                    children[2].cu_graph(),
11737                ),
11738                "routes child root",
11739            )?;
11740        }
11741        let mut exec: sys::CUgraphExec = std::ptr::null_mut();
11742        unsafe {
11743            cu_try(
11744                sys::cuGraphInstantiateWithFlags(&mut exec, parent, 0),
11745                "routes instantiate",
11746            )?;
11747        }
11748        Ok(RoutesGraph {
11749            exec,
11750            parent,
11751            _children: children,
11752        })
11753    }
11754
11755    /// One rank's routes section for the token graph (event-free): staged input copy (raw
11756    /// when the caller supplies the source pointer), quantize, and the batched sweeps.
11757    /// Eager device_routed wraps it with the entry-event wait.
11758    #[allow(clippy::too_many_arguments)]
11759    pub(crate) fn routes_rank_section(
11760        &self,
11761        experts: &ResidentNvfp4TensorParallel,
11762        workspace: &mut Nvfp4DeviceRoutesWorkspace,
11763        raw_input_src: u64,
11764        local_out: usize,
11765        n_sel: usize,
11766        activation_limit: Option<f32>,
11767        rank_index: usize,
11768    ) -> Result<(), Box<dyn std::error::Error>> {
11769        let engine = &self.ranks[rank_index];
11770        {
11771            let _main = engine.gpu.enter_main()?;
11772            // sel/route_w land via raw copies from the e staging (fixed addresses).
11773            let (sel_e_ptr, w_e_ptr) = workspace
11774                .raw_dev_route_e
11775                .ok_or("routes rank section requires armed staging pointers")?;
11776            raw_copy_bytes(
11777                workspace.raw_input[rank_index],
11778                raw_input_src,
11779                experts.input_width * 4,
11780                engine,
11781            )?;
11782            raw_copy_bytes(workspace.raw_sel[rank_index], sel_e_ptr, n_sel * 4, engine)?;
11783            raw_copy_bytes(
11784                workspace.raw_route_w[rank_index],
11785                w_e_ptr,
11786                n_sel * 4,
11787                engine,
11788            )?;
11789            {
11790                let Nvfp4DeviceRoutesWorkspace {
11791                    input, in_q, in_d, ..
11792                } = &mut *workspace;
11793                engine.quantize_q8_1_into(
11794                    &input[rank_index],
11795                    1,
11796                    experts.input_width,
11797                    &mut in_q[rank_index],
11798                    &mut in_d[rank_index],
11799                )?;
11800            }
11801        }
11802        self.nvfp4_routes_batched_sweeps_rank(
11803            experts,
11804            workspace,
11805            &[],
11806            &[],
11807            &[],
11808            local_out,
11809            n_sel,
11810            activation_limit,
11811            true,
11812            rank_index,
11813        )
11814    }
11815
11816    /// The routes ROOT combine section (event-free): peer accumulator read (raw), canonical
11817    /// add, combined row raw-copied into the fixed e-context out stage.
11818    pub(crate) fn routes_root_section(
11819        &self,
11820        experts: &ResidentNvfp4TensorParallel,
11821        workspace: &mut Nvfp4DeviceRoutesWorkspace,
11822    ) -> Result<(), Box<dyn std::error::Error>> {
11823        let root = &self.ranks[0];
11824        let _main = root.gpu.enter_main()?;
11825        let (acc1_ptr, remote_ptr, combined_ptr, out_stage_ptr) = workspace
11826            .raw_combine
11827            .ok_or("routes root section requires armed combine pointers")?;
11828        raw_copy_bytes(remote_ptr, acc1_ptr, experts.input_width * 4, root)?;
11829        {
11830            let Nvfp4DeviceRoutesWorkspace {
11831                accumulator,
11832                remote,
11833                combined,
11834                ..
11835            } = &mut *workspace;
11836            root.add(&accumulator[0], remote, combined, experts.input_width)?;
11837        }
11838        raw_copy_bytes(out_stage_ptr, combined_ptr, experts.input_width * 4, root)?;
11839        Ok(())
11840    }
11841
11842    /// Arm the routes raw pointers (once): staging pair, per-rank input/sel/route_w, and the
11843    /// combine set. Requires dev_route_e + in/out stages already allocated.
11844    pub(crate) fn routes_arm_raw(
11845        &self,
11846        experts: &ResidentNvfp4TensorParallel,
11847        workspace: &mut Nvfp4DeviceRoutesWorkspace,
11848    ) -> Result<(), Box<dyn std::error::Error>> {
11849        use cudarc::driver::DevicePtr;
11850        if workspace.raw_dev_route_e.is_some() {
11851            return Ok(());
11852        }
11853        let _ = experts;
11854        let (sel_e, w_e) = workspace
11855            .dev_route_e
11856            .as_ref()
11857            .ok_or("routes staging not armed")?;
11858        let root = &self.ranks[0];
11859        {
11860            let _main = root.gpu.enter_main()?;
11861            let stream = root.stream();
11862            let (a, _g) = sel_e.device_ptr(&stream);
11863            let (b, _g) = w_e.device_ptr(&stream);
11864            workspace.raw_dev_route_e = Some((a as u64, b as u64));
11865            let (c, _g) = workspace.accumulator[1].device_ptr(&stream);
11866            let (d, _g) = workspace.remote.device_ptr(&stream);
11867            let (f, _g) = workspace.combined.device_ptr(&stream);
11868            let out_stage = workspace
11869                .out_stage_e
11870                .as_ref()
11871                .ok_or("routes out stage not armed")?;
11872            let (g_, _g) = out_stage.device_ptr(&stream);
11873            workspace.raw_combine = Some((c as u64, d as u64, f as u64, g_ as u64));
11874        }
11875        for rank in 0..self.ranks.len() {
11876            let engine = &self.ranks[rank];
11877            let _main = engine.gpu.enter_main()?;
11878            let stream = engine.stream();
11879            let (a, _g) = workspace.input[rank].device_ptr(&stream);
11880            let (b, _g) = workspace.sel[rank].device_ptr(&stream);
11881            let (c, _g) = workspace.route_w[rank].device_ptr(&stream);
11882            workspace.raw_input.push(a as u64);
11883            workspace.raw_sel.push(b as u64);
11884            workspace.raw_route_w.push(c as u64);
11885        }
11886        Ok(())
11887    }
11888
11889    /// Routed NVFP4 expert program, host-canonical transport. Native/bulk P2P transport for the
11890    /// NVFP4 bank is a separate increment; this entry point is exactness-first and reports no
11891    /// throughput claim.
11892    pub fn run_tensor_parallel_routes_nvfp4(
11893        &self,
11894        experts: &ResidentNvfp4TensorParallel,
11895        input: &[f32],
11896        tokens: usize,
11897        selected: &[usize],
11898        route_weights: &[f32],
11899        experts_per_token: usize,
11900        activation_limit: Option<f32>,
11901    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
11902        validate_activations(input, tokens, experts.input_width)?;
11903        let pairs = tokens
11904            .checked_mul(experts_per_token)
11905            .ok_or("NVFP4 TP route count overflow")?;
11906        if selected.len() != pairs || route_weights.len() != pairs {
11907            return Err(format!(
11908                "NVFP4 TP routes selected={} weights={} != tokens {tokens} x experts/token \
11909                 {experts_per_token} ({pairs})",
11910                selected.len(),
11911                route_weights.len(),
11912            )
11913            .into());
11914        }
11915        if !route_weights.iter().all(|weight| weight.is_finite()) {
11916            return Err("NVFP4 TP route weights contain a non-finite value".into());
11917        }
11918
11919        let mut output = vec![0.0f32; tokens * experts.input_width];
11920        for token in 0..tokens {
11921            let input_row = &input[token * experts.input_width..(token + 1) * experts.input_width];
11922            for slot in 0..experts_per_token {
11923                let pair = token * experts_per_token + slot;
11924                let expert = selected[pair];
11925                if expert >= experts.expert_count {
11926                    return Err(format!(
11927                        "NVFP4 TP selected expert {expert} outside 0..{}",
11928                        experts.expert_count
11929                    )
11930                    .into());
11931                }
11932                // EP2 banks hold the WHOLE expert on rank (expert & 1) at slot (expert >> 1);
11933                // per-row dots are the same full-width program either way (a column shard
11934                // splits ROWS, not the dot), so gate/up are bit-equal across layouts. Only
11935                // down's parenthesization moves (full-width dot vs canonical 2-shard sum) —
11936                // the numeric-class this door declares.
11937                let gate = if experts.ep2 {
11938                    self.run_full_bank_expert_nvfp4(
11939                        &experts.gate,
11940                        &experts.macros_gate,
11941                        expert,
11942                        input_row,
11943                    )?
11944                } else {
11945                    self.run_column_bank_expert_nvfp4(
11946                        &experts.gate,
11947                        &experts.macros_gate,
11948                        expert,
11949                        input_row,
11950                    )?
11951                };
11952                let up = if experts.ep2 {
11953                    self.run_full_bank_expert_nvfp4(
11954                        &experts.up,
11955                        &experts.macros_up,
11956                        expert,
11957                        input_row,
11958                    )?
11959                } else {
11960                    self.run_column_bank_expert_nvfp4(
11961                        &experts.up,
11962                        &experts.macros_up,
11963                        expert,
11964                        input_row,
11965                    )?
11966                };
11967                let activated: Vec<f32> = gate
11968                    .iter()
11969                    .zip(&up)
11970                    .map(|(&gate, &up)| step_expert_activation_host(gate, up, activation_limit))
11971                    .collect();
11972                debug_assert_eq!(activated.len(), experts.expert_width);
11973                let down = if experts.ep2 {
11974                    self.run_full_down_expert_nvfp4(
11975                        &experts.down,
11976                        &experts.macros_down,
11977                        expert,
11978                        &activated,
11979                    )?
11980                } else {
11981                    self.run_row_bank_expert_nvfp4(
11982                        &experts.down,
11983                        &experts.macros_down,
11984                        expert,
11985                        &activated,
11986                    )?
11987                };
11988                let weight = route_weights[pair];
11989                for (sum, value) in output
11990                    [token * experts.input_width..(token + 1) * experts.input_width]
11991                    .iter_mut()
11992                    .zip(down)
11993                {
11994                    *sum += weight * value;
11995                }
11996            }
11997        }
11998        Ok(output)
11999    }
12000}
12001
12002#[cfg(test)]
12003mod tests {
12004    use super::*;
12005
12006    #[test]
12007    fn step_expert_activation_clamps_each_arm_by_the_official_contract() {
12008        let limit = Some(7.0);
12009        assert_eq!(step_expert_activation_host(20.0, 9.0, limit), 49.0);
12010        assert_eq!(step_expert_activation_host(20.0, -9.0, limit), -49.0);
12011        assert!(
12012            step_expert_activation_host(-20.0, 9.0, limit).abs()
12013                < step_expert_activation_host(-20.0, 9.0, None).abs()
12014        );
12015        assert!(validate_step_expert_activation_limit(Some(f32::NAN)).is_err());
12016        assert!(validate_step_expert_activation_limit(Some(0.0)).is_err());
12017        assert!(validate_step_expert_activation_limit(limit).is_ok());
12018    }
12019
12020    #[test]
12021    fn moe_residual_host_preserves_official_add_order() {
12022        let output = moe_residual_host(&[1.0e20], &[-1.0e20], &[1.0]).unwrap();
12023        assert_eq!(output, [0.0]);
12024        assert_eq!(
12025            moe_residual_host(&[0.0], &[0.0, 1.0], &[0.0]).unwrap_err(),
12026            "MoE residual lengths residual=1 routed=2 shared=1"
12027        );
12028    }
12029
12030    #[test]
12031    fn expert_owner_routes_preserve_global_pair_order_with_local_expert_ids() {
12032        let selected = [0, 36, 72, 108, 144, 180, 216, 252];
12033        let owners = partition_expert_owner_routes(288, 4, 1, 8, &selected).unwrap();
12034        assert_eq!(owners.len(), 4);
12035        for (rank, owner) in owners.iter().enumerate() {
12036            assert_eq!(owner.rank, rank);
12037            assert_eq!(owner.selected, vec![0, 36]);
12038            assert_eq!(owner.token_rows, vec![0, 0]);
12039            assert_eq!(owner.global_pairs, vec![rank * 2, rank * 2 + 1]);
12040        }
12041    }
12042
12043    #[test]
12044    fn expert_owner_routes_validate_geometry_and_selected_experts() {
12045        assert!(partition_expert_owner_routes(288, 5, 1, 8, &[0; 8]).is_err());
12046        assert!(partition_expert_owner_routes(288, 4, 2, 8, &[0; 8]).is_err());
12047        let error = partition_expert_owner_routes(288, 4, 1, 8, &[288; 8]).unwrap_err();
12048        assert!(error.contains("outside 0..288"));
12049    }
12050
12051    #[test]
12052    fn step_grouped_owner_routes_validate_dynamic_top8_shapes() {
12053        let selected = [
12054            1, 73, 80, 145, 152, 159, 217, 224, 12, 84, 91, 156, 163, 170, 228, 235,
12055        ];
12056        assert_eq!(
12057            validate_step_grouped_owner_routes(288, 2, &selected).unwrap(),
12058            16
12059        );
12060        let owners = partition_expert_owner_routes(288, 4, 2, 8, &selected).unwrap();
12061        assert_eq!(
12062            owners
12063                .iter()
12064                .map(|owner| owner.selected.len())
12065                .collect::<Vec<_>>(),
12066            vec![2, 4, 6, 4]
12067        );
12068        assert!(validate_step_grouped_owner_routes(288, 2, &selected[..8]).is_err());
12069        assert!(validate_step_grouped_owner_routes(288, 1, &[0; 8]).is_err());
12070        assert!(validate_step_grouped_owner_routes(287, 2, &selected).is_err());
12071    }
12072
12073    #[test]
12074    fn weighted_route_combine_requires_a_canonical_pair_permutation() {
12075        let owner0 = [0usize, 3];
12076        let owner1 = [1usize, 2];
12077        let owners = [owner0.as_slice(), owner1.as_slice()];
12078        assert_eq!(
12079            validate_weighted_route_combine(4096, 4, 3, 1, &owners, &[0.1, 0.2, 0.3, 0.4],)
12080                .unwrap(),
12081            WeightedRouteCombineShape {
12082                pairs: 4,
12083                max_pairs: 12,
12084            }
12085        );
12086        let duplicate = [owner0.as_slice(), &[1usize, 1][..]];
12087        assert!(
12088            validate_weighted_route_combine(4096, 4, 3, 1, &duplicate, &[0.1, 0.2, 0.3, 0.4],)
12089                .is_err()
12090        );
12091        assert!(
12092            validate_weighted_route_combine(4096, 4, 3, 1, &owners, &[0.1, f32::NAN, 0.3, 0.4],)
12093                .is_err()
12094        );
12095        assert!(
12096            validate_weighted_route_combine(4096, 4, 1, 2, &owners, &[0.1, 0.2, 0.3, 0.4],)
12097                .is_err()
12098        );
12099    }
12100
12101    #[test]
12102    fn native_p2p_door_is_strict_and_default_off() {
12103        assert!(!parse_step_tp_native_p2p(None).unwrap());
12104        assert!(!parse_step_tp_native_p2p(Some("")).unwrap());
12105        assert!(!parse_step_tp_native_p2p(Some("0")).unwrap());
12106        assert!(parse_step_tp_native_p2p(Some("1")).unwrap());
12107        assert!(parse_step_tp_native_p2p(Some("true")).is_err());
12108        assert!(parse_step_tp_native_p2p(Some("2")).is_err());
12109    }
12110
12111    #[test]
12112    fn bulk_p2p_door_is_strict_and_default_off() {
12113        assert!(!parse_step_tp_bulk_p2p(None).unwrap());
12114        assert!(!parse_step_tp_bulk_p2p(Some("")).unwrap());
12115        assert!(!parse_step_tp_bulk_p2p(Some("0")).unwrap());
12116        assert!(parse_step_tp_bulk_p2p(Some("1")).unwrap());
12117        assert!(parse_step_tp_bulk_p2p(Some("true")).is_err());
12118        assert!(parse_step_tp_bulk_p2p(Some("2")).is_err());
12119    }
12120
12121    #[test]
12122    fn ep_device_arithmetic_door_is_strict_and_default_off() {
12123        assert!(!parse_step_ep_device_arithmetic(None).unwrap());
12124        assert!(!parse_step_ep_device_arithmetic(Some("")).unwrap());
12125        assert!(!parse_step_ep_device_arithmetic(Some("0")).unwrap());
12126        assert!(parse_step_ep_device_arithmetic(Some("1")).unwrap());
12127        assert!(parse_step_ep_device_arithmetic(Some("true")).is_err());
12128        assert!(parse_step_ep_device_arithmetic(Some("2")).is_err());
12129    }
12130
12131    #[test]
12132    fn f32_mirror_door_is_strict_and_default_off() {
12133        assert!(!parse_step_tp_f32_mirror(None).unwrap());
12134        assert!(!parse_step_tp_f32_mirror(Some("")).unwrap());
12135        assert!(!parse_step_tp_f32_mirror(Some("0")).unwrap());
12136        assert!(parse_step_tp_f32_mirror(Some("1")).unwrap());
12137        assert!(parse_step_tp_f32_mirror(Some("true")).is_err());
12138        assert!(parse_step_tp_f32_mirror(Some("2")).is_err());
12139    }
12140
12141    fn matrix(out_features: usize, in_features: usize) -> (Vec<u8>, Vec<f32>) {
12142        let codes = (0..out_features * in_features)
12143            .map(|index| (index % 251) as u8)
12144            .collect();
12145        let scales = (0..out_features.div_ceil(FP8_BLOCK) * in_features.div_ceil(FP8_BLOCK))
12146            .map(|index| index as f32 + 1.0)
12147            .collect();
12148        (codes, scales)
12149    }
12150
12151    fn bf16_matrix_bytes(out_features: usize, in_features: usize) -> Vec<u8> {
12152        (0..out_features * in_features)
12153            .flat_map(|value| (value as u16).to_le_bytes())
12154            .collect()
12155    }
12156
12157    fn decode_u16(bytes: &[u8]) -> Vec<u16> {
12158        bytes
12159            .chunks_exact(2)
12160            .map(|bytes| u16::from_le_bytes([bytes[0], bytes[1]]))
12161            .collect()
12162    }
12163
12164    #[test]
12165    fn bf16_matrix_rejects_wrong_byte_count() {
12166        let bytes = vec![0u8; 4 * 4 * 2 - 1];
12167        let matrix = Bf16Matrix {
12168            bytes: &bytes,
12169            out_features: 4,
12170            in_features: 4,
12171        };
12172        assert!(matrix.validate().unwrap_err().contains("4x4x2"));
12173    }
12174
12175    #[test]
12176    fn replicated_device_rows_require_exact_rank_local_shapes() {
12177        assert_eq!(
12178            replicated_device_row_values(3, 4096, 4, &[12_288; 4]).unwrap(),
12179            12_288
12180        );
12181        assert!(replicated_device_row_values(0, 4096, 4, &[0; 4]).is_err());
12182        assert!(replicated_device_row_values(3, 0, 4, &[0; 4]).is_err());
12183        assert!(replicated_device_row_values(3, 4096, 4, &[12_288; 3]).is_err());
12184        assert!(
12185            replicated_device_row_values(3, 4096, 4, &[12_288, 12_288, 12_287, 12_288]).is_err()
12186        );
12187        assert!(replicated_device_row_values(usize::MAX, 2, 1, &[0]).is_err());
12188    }
12189
12190    #[test]
12191    fn replicated_device_row_refresh_requires_exact_root_source() {
12192        assert_eq!(
12193            replicated_device_row_source_values(1, 12_288, 12_288, 3, 3).unwrap(),
12194            12_288
12195        );
12196        assert!(replicated_device_row_source_values(0, 12_288, 0, 3, 3).is_err());
12197        assert!(replicated_device_row_source_values(1, 0, 0, 3, 3).is_err());
12198        assert!(replicated_device_row_source_values(1, 12_288, 12_287, 3, 3).is_err());
12199        assert!(replicated_device_row_source_values(1, 12_288, 12_288, 2, 3).is_err());
12200        assert!(replicated_device_row_source_values(usize::MAX, 2, 0, 3, 3).is_err());
12201    }
12202
12203    #[test]
12204    fn step_bf16_canonical_rows_are_topology_invariant_through_tp8() {
12205        for tp in [1, 2, 4, 8] {
12206            assert_eq!(step_bf16_canonical_chunk_rows(8_192, tp).unwrap(), 1_024);
12207            assert_eq!(step_bf16_canonical_chunk_rows(12_288, tp).unwrap(), 1_536);
12208            assert_eq!(step_bf16_canonical_chunk_rows(1_024, tp).unwrap(), 128);
12209            assert_eq!(step_bf16_canonical_chunk_cols(8_192, tp).unwrap(), 1_024);
12210            assert_eq!(step_bf16_canonical_chunk_cols(12_288, tp).unwrap(), 1_536);
12211        }
12212        assert!(step_bf16_canonical_chunk_rows(12_288, 3).is_err());
12213        assert!(step_bf16_canonical_chunk_rows(1_001, 2).is_err());
12214        assert!(step_bf16_canonical_chunk_cols(12_288, 3).is_err());
12215        assert!(step_bf16_canonical_chunk_cols(1_001, 2).is_err());
12216    }
12217
12218    #[test]
12219    fn cache_rows_split_by_token_then_rank() {
12220        let rows = (0u8..24).collect::<Vec<_>>();
12221        assert_eq!(
12222            cache_rank_rows(&rows, 3, 4, 2, 0).unwrap(),
12223            vec![0, 1, 2, 3, 8, 9, 10, 11, 16, 17, 18, 19]
12224        );
12225        assert_eq!(
12226            cache_rank_rows(&rows, 3, 4, 2, 1).unwrap(),
12227            vec![4, 5, 6, 7, 12, 13, 14, 15, 20, 21, 22, 23]
12228        );
12229        assert!(cache_rank_rows(&rows[..23], 3, 4, 2, 0).is_err());
12230        assert!(cache_rank_rows(&rows, 3, 4, 2, 2).is_err());
12231    }
12232
12233    #[test]
12234    fn bf16_column_shard_preserves_contiguous_output_rows() {
12235        let bytes = bf16_matrix_bytes(4, 4);
12236        let matrix = Bf16Matrix {
12237            bytes: &bytes,
12238            out_features: 4,
12239            in_features: 4,
12240        };
12241        let shard = bf16_column_shard(matrix, 2, 1).unwrap();
12242        assert_eq!(shard.out_features, 2);
12243        assert_eq!(shard.in_features, 4);
12244        assert_eq!(decode_u16(shard.bytes), (8..16).collect::<Vec<_>>());
12245    }
12246
12247    #[test]
12248    fn bf16_row_shard_preserves_each_input_column_window() {
12249        let bytes = bf16_matrix_bytes(3, 4);
12250        let matrix = Bf16Matrix {
12251            bytes: &bytes,
12252            out_features: 3,
12253            in_features: 4,
12254        };
12255        let shard = bf16_row_shard(matrix, 2, 1).unwrap();
12256        assert_eq!(decode_u16(&shard), vec![2, 3, 6, 7, 10, 11]);
12257    }
12258
12259    #[test]
12260    fn bf16_row_block_preserves_global_column_order() {
12261        let bytes = bf16_matrix_bytes(3, 8);
12262        let matrix = Bf16Matrix {
12263            bytes: &bytes,
12264            out_features: 3,
12265            in_features: 8,
12266        };
12267        let block = bf16_row_block(matrix, 2, 3).unwrap();
12268        assert_eq!(decode_u16(&block), vec![2, 3, 4, 10, 11, 12, 18, 19, 20]);
12269    }
12270
12271    #[test]
12272    fn column_shard_preserves_contiguous_weight_and_scale_rows() {
12273        let (codes, scales) = matrix(1280, 4096);
12274        let matrix = E4m3BlockMatrix {
12275            codes: &codes,
12276            scales: &scales,
12277            out_features: 1280,
12278            in_features: 4096,
12279        };
12280        let shard = column_shard(matrix, 2, 1).unwrap();
12281        assert_eq!(shard.out_features, 640);
12282        assert_eq!(shard.codes, &codes[640 * 4096..]);
12283        assert_eq!(shard.scales, &scales[5 * 32..]);
12284    }
12285
12286    #[test]
12287    fn row_shard_preserves_each_weight_and_scale_column_window() {
12288        let (codes, scales) = matrix(4096, 1280);
12289        let matrix = E4m3BlockMatrix {
12290            codes: &codes,
12291            scales: &scales,
12292            out_features: 4096,
12293            in_features: 1280,
12294        };
12295        let (shard_codes, shard_scales) = row_shard(matrix, 2, 1).unwrap();
12296        assert_eq!(shard_codes.len(), 4096 * 640);
12297        assert_eq!(&shard_codes[..640], &codes[640..1280]);
12298        assert_eq!(&shard_codes[640..1280], &codes[1280 + 640..2560]);
12299        assert_eq!(shard_scales.len(), 32 * 5);
12300        assert_eq!(&shard_scales[..5], &scales[5..10]);
12301        assert_eq!(&shard_scales[5..10], &scales[15..20]);
12302    }
12303
12304    #[test]
12305    fn activation_shards_keep_token_rows_separate() {
12306        let activations: Vec<f32> = (0..2 * 8).map(|value| value as f32).collect();
12307        assert_eq!(
12308            activation_shard(&activations, 2, 8, 2, 1),
12309            vec![4.0, 5.0, 6.0, 7.0, 12.0, 13.0, 14.0, 15.0],
12310        );
12311    }
12312
12313    #[test]
12314    fn expert_bank_selects_expert_major_code_and_scale_planes() {
12315        let expert_count = 2;
12316        let out_features = 128;
12317        let in_features = 128;
12318        let code_stride = out_features * in_features;
12319        let codes: Vec<u8> = (0..expert_count * code_stride)
12320            .map(|index| (index % 251) as u8)
12321            .collect();
12322        let scales = vec![1.0f32, 2.0];
12323        let bank = E4m3ExpertBank {
12324            codes: &codes,
12325            scales: &scales,
12326            expert_count,
12327            out_features,
12328            in_features,
12329        };
12330        bank.validate().unwrap();
12331        let expert = bank.expert(1).unwrap();
12332        assert_eq!(expert.codes, &codes[code_stride..]);
12333        assert_eq!(expert.scales, &[2.0]);
12334    }
12335
12336    #[test]
12337    fn expert_bank_rejects_non_positive_scale() {
12338        let codes = vec![0u8; 128 * 128];
12339        let scales = vec![0.0f32];
12340        let bank = E4m3ExpertBank {
12341            codes: &codes,
12342            scales: &scales,
12343            expert_count: 1,
12344            out_features: 128,
12345            in_features: 128,
12346        };
12347        assert!(bank.validate().unwrap_err().contains("non-positive"));
12348    }
12349
12350    #[test]
12351    fn tensor_parallel_column_bank_keeps_each_expert_scale_plane_separate() {
12352        let expert_count = 2;
12353        let out_features = 256;
12354        let in_features = 128;
12355        let code_stride = out_features * in_features;
12356        let scale_stride = 2;
12357        let codes = (0..expert_count * code_stride)
12358            .map(|index| (index % 251) as u8)
12359            .collect::<Vec<_>>();
12360        let scales = vec![10.0f32, 11.0, 20.0, 21.0];
12361        let bank = E4m3ExpertBank {
12362            codes: &codes,
12363            scales: &scales,
12364            expert_count,
12365            out_features,
12366            in_features,
12367        };
12368
12369        let rank = pack_column_bank_rank(bank, 2, 1).unwrap();
12370        assert_eq!(rank.out_features, 128);
12371        assert_eq!(rank.in_features, 128);
12372        assert_eq!(rank.codes.len(), expert_count * 128 * 128);
12373        assert_eq!(rank.scales, vec![11.0, 21.0]);
12374        assert_eq!(&rank.codes[..128 * 128], &codes[128 * 128..256 * 128]);
12375        assert_eq!(
12376            &rank.codes[128 * 128..],
12377            &codes[code_stride + 128 * 128..2 * code_stride]
12378        );
12379        assert_eq!(scale_stride, scales.len() / expert_count);
12380    }
12381
12382    #[test]
12383    fn tensor_parallel_row_bank_keeps_each_expert_scale_plane_separate() {
12384        let expert_count = 2;
12385        let out_features = 128;
12386        let in_features = 256;
12387        let code_stride = out_features * in_features;
12388        let codes = (0..expert_count * code_stride)
12389            .map(|index| (index % 251) as u8)
12390            .collect::<Vec<_>>();
12391        let scales = vec![10.0f32, 11.0, 20.0, 21.0];
12392        let bank = E4m3ExpertBank {
12393            codes: &codes,
12394            scales: &scales,
12395            expert_count,
12396            out_features,
12397            in_features,
12398        };
12399
12400        let rank = pack_row_bank_rank(bank, 2, 1).unwrap();
12401        assert_eq!(rank.out_features, 128);
12402        assert_eq!(rank.in_features, 128);
12403        assert_eq!(rank.k_blocks, Some(1));
12404        assert_eq!(rank.codes.len(), expert_count * 128 * 128);
12405        assert_eq!(rank.scales, vec![11.0, 21.0]);
12406        assert_eq!(&rank.codes[..128], &codes[128..256]);
12407        assert_eq!(
12408            &rank.codes[128 * 128..128 * 128 + 128],
12409            &codes[code_stride + 128..code_stride + 256]
12410        );
12411    }
12412
12413    #[test]
12414    fn tensor_parallel_row_bank_preserves_global_k_block_order() {
12415        let expert_count = 2;
12416        let out_features = 256;
12417        let in_features = 512;
12418        let code_stride = out_features * in_features;
12419        let mut codes = vec![0u8; expert_count * code_stride];
12420        for expert in 0..expert_count {
12421            for row in 0..out_features {
12422                for block in 0..4 {
12423                    let value = (expert * 80 + block * 16 + row % 16) as u8;
12424                    let start = expert * code_stride + row * in_features + block * FP8_BLOCK;
12425                    codes[start..start + FP8_BLOCK].fill(value);
12426                }
12427            }
12428        }
12429        let scales = vec![
12430            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,
12431            112.0, 113.0, 114.0,
12432        ];
12433        let bank = E4m3ExpertBank {
12434            codes: &codes,
12435            scales: &scales,
12436            expert_count,
12437            out_features,
12438            in_features,
12439        };
12440
12441        let rank = pack_row_bank_rank(bank, 2, 1).unwrap();
12442        assert_eq!(rank.out_features, out_features);
12443        assert_eq!(rank.in_features, 256);
12444        assert_eq!(rank.k_blocks, Some(2));
12445        assert_eq!(rank.code_stride, out_features * 256);
12446        assert_eq!(rank.scale_stride, 4);
12447        assert_eq!(&rank.scales[..4], &[3.0, 13.0, 4.0, 14.0]);
12448        assert_eq!(&rank.scales[4..], &[103.0, 113.0, 104.0, 114.0]);
12449
12450        let block_stride = out_features * FP8_BLOCK;
12451        assert!(rank.codes[..FP8_BLOCK].iter().all(|&code| code == 32));
12452        assert!(
12453            rank.codes[block_stride..block_stride + FP8_BLOCK]
12454                .iter()
12455                .all(|&code| code == 48)
12456        );
12457        assert!(
12458            rank.codes[rank.code_stride..rank.code_stride + FP8_BLOCK]
12459                .iter()
12460                .all(|&code| code == 112)
12461        );
12462        assert!(
12463            rank.codes
12464                [rank.code_stride + block_stride..rank.code_stride + block_stride + FP8_BLOCK]
12465                .iter()
12466                .all(|&code| code == 128)
12467        );
12468    }
12469
12470    #[test]
12471    fn step_ep_layer_specs_are_literal_and_fail_closed() {
12472        assert!(parse_step_ep_layer_specs(None).unwrap().is_empty());
12473        assert!(parse_step_ep_layer_specs(Some("0")).unwrap().is_empty());
12474        assert_eq!(
12475            parse_step_ep_layer_specs(Some("24@1,2")).unwrap(),
12476            vec![StepEpLayerSpec {
12477                layer: 24,
12478                devices: vec![1, 2],
12479            }]
12480        );
12481        assert_eq!(
12482            parse_step_ep_layer_specs(Some("24-25@1,2;31@0,2")).unwrap(),
12483            vec![
12484                StepEpLayerSpec {
12485                    layer: 24,
12486                    devices: vec![1, 2],
12487                },
12488                StepEpLayerSpec {
12489                    layer: 25,
12490                    devices: vec![1, 2],
12491                },
12492                StepEpLayerSpec {
12493                    layer: 31,
12494                    devices: vec![0, 2],
12495                },
12496            ]
12497        );
12498        assert!(parse_step_ep_layer_specs(Some("24@1")).is_err());
12499        assert!(parse_step_ep_layer_specs(Some("24@1,1")).is_err());
12500        assert!(parse_step_ep_layer_specs(Some("layer@1,2")).is_err());
12501        assert!(parse_step_ep_layer_specs(Some("25-24@1,2")).is_err());
12502        assert!(parse_step_ep_layer_specs(Some("0-128@1,2")).is_err());
12503        assert!(parse_step_ep_layer_specs(Some("24-25@1,2;25@0,2")).is_err());
12504        assert!(parse_step_ep_layer_specs(Some("all@0,1")).is_err());
12505    }
12506
12507    #[test]
12508    fn step_tp_layer_specs_share_the_fail_closed_layer_contract() {
12509        assert!(parse_step_tp_layer_specs(None).unwrap().is_empty());
12510        assert!(parse_step_tp_layer_specs(Some("0")).unwrap().is_empty());
12511        assert_eq!(
12512            parse_step_tp_layer_specs(Some("24-25@1,2")).unwrap(),
12513            vec![
12514                StepTpLayerSpec {
12515                    layer: 24,
12516                    devices: vec![1, 2],
12517                },
12518                StepTpLayerSpec {
12519                    layer: 25,
12520                    devices: vec![1, 2],
12521                },
12522            ]
12523        );
12524        let error = parse_step_tp_layer_specs(Some("24@1")).unwrap_err();
12525        assert!(error.contains("MEMRA_STEP_TP"));
12526        assert!(parse_step_tp_layer_specs(Some("24@1,1")).is_err());
12527        assert!(parse_step_tp_layer_specs(Some("24-25@1,2;25@0,2")).is_err());
12528
12529        let all = parse_step_tp_layer_specs(Some("all@0,1,2,3,4,5,6,7")).unwrap();
12530        assert_eq!(all.len(), STEP37_TRUNK_LAYERS);
12531        assert_eq!(all.first().unwrap().layer, 0);
12532        assert_eq!(all.last().unwrap().layer, STEP37_TRUNK_LAYERS - 1);
12533        let devices = (0..8).collect::<Vec<_>>();
12534        assert!(all.iter().all(|spec| spec.devices == devices));
12535        assert!(parse_step_tp_layer_specs(Some("all@0,1;44@0,1")).is_err());
12536    }
12537}
12538
12539// ===== Whole-token graph builder (increment B) ==================================================
12540//
12541// The decode fns are already sectioned at every e/rank/root seam (the stage flow, sweeps_rank,
12542// finish splits, the dcw arm). `graph_section` is the one annotation those seams call: eager
12543// mode runs the closure verbatim; build mode wraps it in a stream capture on the section's
12544// device and records a child + its dependency edges. A token then assembles as ONE multi-device
12545// parent (children per section per layer), launched once per token — the launch-collapse the
12546// per-layer minis could not reach (routes-mini negative, 2026-08-21).
12547
12548/// One captured section: the child graph plus which parent node it became, and the CUDA
12549/// context it was captured under (exec memset updates need it).
12550struct TokenGraphChild {
12551    graph: cudarc::driver::CudaGraph,
12552    node: cudarc::driver::sys::CUgraphNode,
12553    ctx: cudarc::driver::sys::CUcontext,
12554}
12555
12556/// Exec-updatable fa geometry discovered in one attention rank child: the three partial-pool
12557/// memsets, the dcw fa kernel, and its combine — everything a bucket change touches. Node
12558/// handles address the parent's CLONED child graphs (the M1-probed update path).
12559struct TokenGraphFaSite {
12560    ctx: cudarc::driver::sys::CUcontext,
12561    memset_o: cudarc::driver::sys::CUgraphNode,
12562    memset_m: [cudarc::driver::sys::CUgraphNode; 2],
12563    fa: cudarc::driver::sys::CUgraphNode,
12564    combine: cudarc::driver::sys::CUgraphNode,
12565    window: usize,
12566    n_head: usize,
12567    n_head_kv: usize,
12568    head_dim: usize,
12569}
12570
12571pub struct TokenGraphBuilder {
12572    parent: cudarc::driver::sys::CUgraph,
12573    children: Vec<TokenGraphChild>,
12574    /// Nodes every NEXT section must depend on (the frontier): one node for serial flow,
12575    /// several while a parallel group is open.
12576    frontier: Vec<cudarc::driver::sys::CUgraphNode>,
12577    /// Detached sections: forked from the frontier at issue time, joined ONLY by the next
12578    /// non-group section (they never gate a parallel group merge — the SH1 shape).
12579    pending_detached: Vec<cudarc::driver::sys::CUgraphNode>,
12580    /// Open parallel group: sections issued under the same group id fork from the SAME
12581    /// predecessor set and merge into the frontier together when the group closes.
12582    group: Option<(
12583        u32,
12584        Vec<cudarc::driver::sys::CUgraphNode>,
12585        Vec<cudarc::driver::sys::CUgraphNode>,
12586    )>,
12587}
12588
12589// SAFETY: single decode thread; graph handles are process handles.
12590unsafe impl Send for TokenGraphBuilder {}
12591
12592impl TokenGraphBuilder {
12593    pub fn new() -> Result<Self, Box<dyn std::error::Error>> {
12594        use cudarc::driver::sys;
12595        let mut parent: sys::CUgraph = std::ptr::null_mut();
12596        let r = unsafe { sys::cuGraphCreate(&mut parent, 0) };
12597        if r != sys::CUresult::CUDA_SUCCESS {
12598            return Err(format!("token graph create: {r:?}").into());
12599        }
12600        Ok(Self {
12601            parent,
12602            children: Vec::new(),
12603            frontier: Vec::new(),
12604            pending_detached: Vec::new(),
12605            group: None,
12606        })
12607    }
12608
12609    fn push_child(
12610        &mut self,
12611        graph: cudarc::driver::CudaGraph,
12612        parallel_group: Option<u32>,
12613        detached: bool,
12614        absorb: bool,
12615        ctx: cudarc::driver::sys::CUcontext,
12616    ) -> Result<(), Box<dyn std::error::Error>> {
12617        use cudarc::driver::sys;
12618        // Resolve the dependency set: serial sections depend on the current frontier; a
12619        // parallel-group section depends on the frontier AS OF the group opening; a
12620        // DETACHED section forks like a group member but joins only the next serial section.
12621        let deps: Vec<sys::CUgraphNode> = match (&mut self.group, parallel_group) {
12622            (Some((open, base, _)), Some(group)) if *open == group => base.clone(),
12623            (state, Some(group)) => {
12624                // opening a new group (closing any previous one first)
12625                if let Some((_, _, members)) = state.take() {
12626                    self.frontier = members;
12627                }
12628                let base = self.frontier.clone();
12629                *state = Some((group, base.clone(), Vec::new()));
12630                base
12631            }
12632            (state, None) if detached => match state.as_ref() {
12633                Some((_, base, _)) => base.clone(),
12634                None => self.frontier.clone(),
12635            },
12636            (state, None) => {
12637                if let Some((_, _, members)) = state.take() {
12638                    self.frontier = members;
12639                }
12640                let mut deps = self.frontier.clone();
12641                if absorb {
12642                    deps.append(&mut self.pending_detached);
12643                }
12644                deps
12645            }
12646        };
12647        let mut node: sys::CUgraphNode = std::ptr::null_mut();
12648        let r = unsafe {
12649            sys::cuGraphAddChildGraphNode(
12650                &mut node,
12651                self.parent,
12652                if deps.is_empty() {
12653                    std::ptr::null()
12654                } else {
12655                    deps.as_ptr()
12656                },
12657                deps.len(),
12658                graph.cu_graph(),
12659            )
12660        };
12661        if r != sys::CUresult::CUDA_SUCCESS {
12662            return Err(format!("token graph child: {r:?}").into());
12663        }
12664        match (&mut self.group, parallel_group, detached) {
12665            (_, None, true) => self.pending_detached.push(node),
12666            (Some((_, _, members)), Some(_), _) => members.push(node),
12667            _ => self.frontier = vec![node],
12668        }
12669        self.children.push(TokenGraphChild { graph, node, ctx });
12670        Ok(())
12671    }
12672
12673    pub fn finish(mut self) -> Result<TokenGraph, Box<dyn std::error::Error>> {
12674        use cudarc::driver::sys;
12675        if let Some((_, _, members)) = self.group.take() {
12676            self.frontier = members;
12677        }
12678        // Discover the fa sites BEFORE instantiate: the parent's cloned child graphs hold
12679        // the node handles the exec update path (M1) addresses.
12680        let mut fa_sites = Vec::new();
12681        for child in &self.children {
12682            if let Some(site) = discover_fa_site(child.node, child.ctx)? {
12683                fa_sites.push(site);
12684            }
12685        }
12686        let mut exec: sys::CUgraphExec = std::ptr::null_mut();
12687        let r = unsafe { sys::cuGraphInstantiateWithFlags(&mut exec, self.parent, 0) };
12688        if r != sys::CUresult::CUDA_SUCCESS {
12689            return Err(format!("token graph instantiate: {r:?}").into());
12690        }
12691        Ok(TokenGraph {
12692            exec,
12693            parent: self.parent,
12694            _children: self.children,
12695            fa_sites,
12696        })
12697    }
12698}
12699
12700/// Walk one child graph; if it carries the attention-section signature (exactly three MEMSET
12701/// nodes chained memset->memset->memset->fa_kernel->combine_kernel), return its update site.
12702fn discover_fa_site(
12703    child_node: cudarc::driver::sys::CUgraphNode,
12704    ctx: cudarc::driver::sys::CUcontext,
12705) -> Result<Option<TokenGraphFaSite>, Box<dyn std::error::Error>> {
12706    use cudarc::driver::sys;
12707    fn cu_try(r: sys::CUresult, what: &str) -> Result<(), Box<dyn std::error::Error>> {
12708        if r == sys::CUresult::CUDA_SUCCESS {
12709            Ok(())
12710        } else {
12711            Err(format!("{what}: {r:?}").into())
12712        }
12713    }
12714    let mut graph: sys::CUgraph = std::ptr::null_mut();
12715    unsafe {
12716        cu_try(
12717            sys::cuGraphChildGraphNodeGetGraph(child_node, &mut graph),
12718            "fa-site child GetGraph",
12719        )?;
12720    }
12721    let mut count: usize = 0;
12722    unsafe {
12723        cu_try(
12724            sys::cuGraphGetNodes(graph, std::ptr::null_mut(), &mut count),
12725            "fa-site GetNodes(count)",
12726        )?;
12727    }
12728    let mut nodes: Vec<sys::CUgraphNode> = vec![std::ptr::null_mut(); count];
12729    unsafe {
12730        cu_try(
12731            sys::cuGraphGetNodes(graph, nodes.as_mut_ptr(), &mut count),
12732            "fa-site GetNodes",
12733        )?;
12734    }
12735    nodes.truncate(count);
12736    let node_type =
12737        |node: sys::CUgraphNode| -> Result<sys::CUgraphNodeType, Box<dyn std::error::Error>> {
12738            let mut ty = sys::CUgraphNodeType::CU_GRAPH_NODE_TYPE_EMPTY;
12739            unsafe {
12740                cu_try(
12741                    sys::cuGraphNodeGetType(node, &mut ty),
12742                    "fa-site NodeGetType",
12743                )?;
12744            }
12745            Ok(ty)
12746        };
12747    let memsets: Vec<sys::CUgraphNode> = {
12748        let mut v = Vec::new();
12749        for &node in &nodes {
12750            if node_type(node)? == sys::CUgraphNodeType::CU_GRAPH_NODE_TYPE_MEMSET {
12751                v.push(node);
12752            }
12753        }
12754        v
12755    };
12756    if memsets.len() != 3 {
12757        return Ok(None);
12758    }
12759    // Single-stream capture makes the chain linear: follow dependent edges from each memset.
12760    let dependents =
12761        |node: sys::CUgraphNode| -> Result<Vec<sys::CUgraphNode>, Box<dyn std::error::Error>> {
12762            let mut n: usize = 0;
12763            unsafe {
12764                cu_try(
12765                    sys::cuGraphNodeGetDependentNodes_v2(
12766                        node,
12767                        std::ptr::null_mut(),
12768                        std::ptr::null_mut(),
12769                        &mut n,
12770                    ),
12771                    "fa-site GetDependentNodes(count)",
12772                )?;
12773            }
12774            let mut v: Vec<sys::CUgraphNode> = vec![std::ptr::null_mut(); n];
12775            unsafe {
12776                cu_try(
12777                    sys::cuGraphNodeGetDependentNodes_v2(
12778                        node,
12779                        v.as_mut_ptr(),
12780                        std::ptr::null_mut(),
12781                        &mut n,
12782                    ),
12783                    "fa-site GetDependentNodes",
12784                )?;
12785            }
12786            v.truncate(n);
12787            Ok(v)
12788        };
12789    // The LAST memset is the one whose direct dependent is a kernel (fa); the other two are
12790    // ordered among themselves but interchangeable for width updates.
12791    let mut fa: Option<sys::CUgraphNode> = None;
12792    let mut last_memset: Option<sys::CUgraphNode> = None;
12793    for &ms in &memsets {
12794        for dep in dependents(ms)? {
12795            if node_type(dep)? == sys::CUgraphNodeType::CU_GRAPH_NODE_TYPE_KERNEL {
12796                fa = Some(dep);
12797                last_memset = Some(ms);
12798            }
12799        }
12800    }
12801    let (Some(fa), Some(_last)) = (fa, last_memset) else {
12802        return Ok(None);
12803    };
12804    let mut combine: Option<sys::CUgraphNode> = None;
12805    for dep in dependents(fa)? {
12806        if node_type(dep)? == sys::CUgraphNodeType::CU_GRAPH_NODE_TYPE_KERNEL {
12807            combine = Some(dep);
12808        }
12809    }
12810    let Some(combine) = combine else {
12811        return Ok(None);
12812    };
12813    // Read the fa launch geometry from its baked args (arg order pinned by fa_decode_dcw):
12814    // 6=hd 7=nh 8=nhkv 11=win 13=nsp 14=ski.
12815    let mut params: sys::CUDA_KERNEL_NODE_PARAMS = unsafe { std::mem::zeroed() };
12816    unsafe {
12817        cu_try(
12818            sys::cuGraphKernelNodeGetParams_v2(fa, &mut params),
12819            "fa-site KernelNodeGetParams",
12820        )?;
12821    }
12822    let arg_i32 =
12823        |slot: usize| -> i32 { unsafe { *(*params.kernelParams.add(slot) as *const i32) } };
12824    let (hd, nh, nhkv, win) = (arg_i32(6), arg_i32(7), arg_i32(8), arg_i32(11));
12825    // Identify the o-partial memset (hd x wider than the m/l pair).
12826    let width_of = |node: sys::CUgraphNode| -> Result<usize, Box<dyn std::error::Error>> {
12827        let mut mp: sys::CUDA_MEMSET_NODE_PARAMS = unsafe { std::mem::zeroed() };
12828        unsafe {
12829            cu_try(
12830                sys::cuGraphMemsetNodeGetParams(node, &mut mp),
12831                "fa-site MemsetNodeGetParams",
12832            )?;
12833        }
12834        Ok(mp.width)
12835    };
12836    let mut widest = memsets[0];
12837    for &ms in &memsets[1..] {
12838        if width_of(ms)? > width_of(widest)? {
12839            widest = ms;
12840        }
12841    }
12842    let memset_m: Vec<sys::CUgraphNode> =
12843        memsets.iter().copied().filter(|&m| m != widest).collect();
12844    Ok(Some(TokenGraphFaSite {
12845        ctx,
12846        memset_o: widest,
12847        memset_m: [memset_m[0], memset_m[1]],
12848        fa,
12849        combine,
12850        window: win as usize,
12851        n_head: nh as usize,
12852        n_head_kv: nhkv as usize,
12853        head_dim: hd as usize,
12854    }))
12855}
12856
12857pub struct TokenGraph {
12858    exec: cudarc::driver::sys::CUgraphExec,
12859    parent: cudarc::driver::sys::CUgraph,
12860    _children: Vec<TokenGraphChild>,
12861    fa_sites: Vec<TokenGraphFaSite>,
12862}
12863
12864unsafe impl Send for TokenGraph {}
12865
12866impl TokenGraph {
12867    /// Retarget every fa site to a new bucket via exec param updates (M1 path) — replaces the
12868    /// per-bucket whole-graph rebuild (~55ms) with ~450 node updates (~1ms). Per site the
12869    /// bucket caps at the layer window; nsp/ski/gridDimY and the partial-pool memset widths
12870    /// move together so the exec always matches what a fresh build at `bucket` would bake.
12871    pub fn retarget_bucket(&mut self, bucket: usize) -> Result<(), Box<dyn std::error::Error>> {
12872        use cudarc::driver::sys;
12873        fn cu_try(r: sys::CUresult, what: &str) -> Result<(), Box<dyn std::error::Error>> {
12874            if r == sys::CUresult::CUDA_SUCCESS {
12875                Ok(())
12876            } else {
12877                Err(format!("{what}: {r:?}").into())
12878            }
12879        }
12880        for site in &self.fa_sites {
12881            let layer_bucket = if site.window > 0 {
12882                bucket.min(site.window)
12883            } else {
12884                bucket
12885            };
12886            let sp = crate::fa_split_keys(layer_bucket, site.n_head_kv);
12887            let nsp = layer_bucket.div_ceil(sp).max(1);
12888            // fa kernel: nsp (slot 13), ski (slot 14), gridDimY = nsp.
12889            let mut params: sys::CUDA_KERNEL_NODE_PARAMS = unsafe { std::mem::zeroed() };
12890            unsafe {
12891                cu_try(
12892                    sys::cuGraphKernelNodeGetParams_v2(site.fa, &mut params),
12893                    "retarget fa GetParams",
12894                )?;
12895                *(*params.kernelParams.add(13) as *mut i32) = nsp as i32;
12896                *(*params.kernelParams.add(14) as *mut i32) = sp as i32;
12897                params.gridDimY = nsp as u32;
12898                cu_try(
12899                    sys::cuGraphExecKernelNodeSetParams_v2(self.exec, site.fa, &params),
12900                    "retarget fa SetParams",
12901                )?;
12902            }
12903            // combine: nsp (slot 6).
12904            let mut cparams: sys::CUDA_KERNEL_NODE_PARAMS = unsafe { std::mem::zeroed() };
12905            unsafe {
12906                cu_try(
12907                    sys::cuGraphKernelNodeGetParams_v2(site.combine, &mut cparams),
12908                    "retarget combine GetParams",
12909                )?;
12910                *(*cparams.kernelParams.add(6) as *mut i32) = nsp as i32;
12911                cu_try(
12912                    sys::cuGraphExecKernelNodeSetParams_v2(self.exec, site.combine, &cparams),
12913                    "retarget combine SetParams",
12914                )?;
12915            }
12916            // partial-pool memsets: o = nh*nsp*hd elements, m/l = nh*nsp.
12917            let set_width =
12918                |node: sys::CUgraphNode, width: usize| -> Result<(), Box<dyn std::error::Error>> {
12919                    let mut mp: sys::CUDA_MEMSET_NODE_PARAMS = unsafe { std::mem::zeroed() };
12920                    unsafe {
12921                        cu_try(
12922                            sys::cuGraphMemsetNodeGetParams(node, &mut mp),
12923                            "retarget memset GetParams",
12924                        )?;
12925                    }
12926                    mp.width = width;
12927                    unsafe {
12928                        cu_try(
12929                            sys::cuGraphExecMemsetNodeSetParams(self.exec, node, &mp, site.ctx),
12930                            "retarget memset SetParams",
12931                        )?;
12932                    }
12933                    Ok(())
12934                };
12935            set_width(site.memset_o, site.n_head * nsp * site.head_dim)?;
12936            set_width(site.memset_m[0], site.n_head * nsp)?;
12937            set_width(site.memset_m[1], site.n_head * nsp)?;
12938        }
12939        Ok(())
12940    }
12941
12942    pub fn launch(&self, e: &Engine) -> Result<(), Box<dyn std::error::Error>> {
12943        use cudarc::driver::sys;
12944        let _main = e.gpu.enter_main()?;
12945        let r = unsafe { sys::cuGraphLaunch(self.exec, e.stream().cu_stream() as sys::CUstream) };
12946        if r != sys::CUresult::CUDA_SUCCESS {
12947            return Err(format!("token graph launch: {r:?}").into());
12948        }
12949        Ok(())
12950    }
12951}
12952
12953impl Drop for TokenGraph {
12954    fn drop(&mut self) {
12955        unsafe {
12956            let _ = cudarc::driver::sys::cuGraphExecDestroy(self.exec);
12957            let _ = cudarc::driver::sys::cuGraphDestroy(self.parent);
12958        }
12959    }
12960}
12961
12962std::thread_local! {
12963    static TOKEN_GRAPH_BUILDER: std::cell::RefCell<Option<TokenGraphBuilder>> =
12964        const { std::cell::RefCell::new(None) };
12965}
12966
12967/// Arm the thread-local builder (build mode) — the next `graph_section` calls capture.
12968pub fn token_graph_build_begin() -> Result<(), Box<dyn std::error::Error>> {
12969    let builder = TokenGraphBuilder::new()?;
12970    TOKEN_GRAPH_BUILDER.with(|cell| *cell.borrow_mut() = Some(builder));
12971    Ok(())
12972}
12973
12974/// Take the finished parent (ends build mode).
12975pub fn token_graph_build_finish() -> Result<TokenGraph, Box<dyn std::error::Error>> {
12976    let builder = TOKEN_GRAPH_BUILDER
12977        .with(|cell| cell.borrow_mut().take())
12978        .ok_or("token graph build was not begun")?;
12979    builder.finish()
12980}
12981
12982/// True while the thread-local builder is armed.
12983pub fn token_graph_building() -> bool {
12984    TOKEN_GRAPH_BUILDER.with(|cell| cell.borrow().is_some())
12985}
12986
12987/// The section annotation: eager mode runs the closure verbatim; build mode wraps it in a
12988/// stream capture on `engine`'s stream and records the child. Sections sharing a
12989/// `parallel_group` id fork from the same predecessor set and merge together. The closure
12990/// must be capture-safe (raw copies at cross-context seams, no host syncs, no events).
12991pub fn graph_section<F>(
12992    engine: &Engine,
12993    parallel_group: Option<u32>,
12994    f: F,
12995) -> Result<(), Box<dyn std::error::Error>>
12996where
12997    F: FnMut() -> Result<(), Box<dyn std::error::Error>>,
12998{
12999    graph_section_opts(engine, parallel_group, false, false, f)
13000}
13001
13002/// Serial section that ALSO joins every pending detached section (the SH1 consumer shape).
13003pub fn graph_section_absorbing<F>(engine: &Engine, f: F) -> Result<(), Box<dyn std::error::Error>>
13004where
13005    F: FnMut() -> Result<(), Box<dyn std::error::Error>>,
13006{
13007    graph_section_opts(engine, None, false, true, f)
13008}
13009
13010/// `graph_section` with the DETACHED shape: forks from the current frontier (or the open
13011/// group base) and is joined only by the next serial section — never gates a group merge.
13012pub fn graph_section_detached<F>(engine: &Engine, f: F) -> Result<(), Box<dyn std::error::Error>>
13013where
13014    F: FnMut() -> Result<(), Box<dyn std::error::Error>>,
13015{
13016    graph_section_opts(engine, None, true, false, f)
13017}
13018
13019pub fn graph_section_opts<F>(
13020    engine: &Engine,
13021    parallel_group: Option<u32>,
13022    detached: bool,
13023    absorb: bool,
13024    f: F,
13025) -> Result<(), Box<dyn std::error::Error>>
13026where
13027    F: FnMut() -> Result<(), Box<dyn std::error::Error>>,
13028{
13029    let building = token_graph_building();
13030    if !building {
13031        let mut f = f;
13032        return f();
13033    }
13034    let (child, ctx) = {
13035        let _main = engine.gpu.enter_main()?;
13036        let mut ctx: cudarc::driver::sys::CUcontext = std::ptr::null_mut();
13037        let r = unsafe { cudarc::driver::sys::cuCtxGetCurrent(&mut ctx) };
13038        if r != cudarc::driver::sys::CUresult::CUDA_SUCCESS {
13039            return Err(format!("graph section ctx query: {r:?}").into());
13040        }
13041        let mut f = f;
13042        // NO WARMUP RUNS: section bodies carry device side effects (dcw appends, counter
13043        // incs) that a warmup would really execute — the len_d-drift crash of 2026-08-21.
13044        let (child, _retained) = engine.capture_graph_retained_nowarm(|_| f())?;
13045        (child, ctx)
13046    };
13047    TOKEN_GRAPH_BUILDER.with(|cell| {
13048        cell.borrow_mut()
13049            .as_mut()
13050            .expect("builder checked above")
13051            .push_child(child, parallel_group, detached, absorb, ctx)
13052    })
13053}