Skip to main content

memra_engine/
tp.rs

1//! Tensor-parallel correctness runtime.
2//!
3//! This module is deliberately narrower than the serving runtime. It executes real rank-local
4//! E4M3 projections on distinct CUDA devices. Deterministic host-staged collectives remain the
5//! default exactness reference; an opt-in native-P2P path must reproduce the same canonical
6//! checkpoint-block program before it can advance. Neither path is product-throughput evidence.
7
8use crate::Engine;
9use crate::mmq_ffi::{DeviceExpertCsr, ExpertCsr, Fp8GroupedWorkspace};
10use crate::parallel::{PRODUCT_MAX_CARDS, STEP37_TRUNK_LAYERS};
11use cudarc::driver::{CudaEvent, CudaSlice, DeviceSlice};
12use std::ops::Range;
13
14/// Previous gate output per (rank, t), so the determ probe can report the SHAPE of a divergence
15/// (dense-ULP vs sparse-huge) and not merely that a checksum moved. Probe-only state.
16#[allow(clippy::type_complexity)] // allow: one-shot composite type; naming it would hide the shape that matters at the call site
17static DETERM_PREV: std::sync::OnceLock<
18    std::sync::Mutex<std::collections::HashMap<(usize, usize), Vec<f32>>>,
19> = std::sync::OnceLock::new();
20
21const FP8_BLOCK: usize = 128;
22const NATIVE_P2P_PROBE_WORDS: &[usize] = &[4096, 16_384, 262_144, 16_777_216];
23const STEP_GROUPED_FP8_EXPERTS: usize = 288;
24const STEP_GROUPED_FP8_TOP_K: usize = 8;
25const STEP_GROUPED_FP8_WIDTH: usize = 1280;
26
27fn validate_step_expert_activation_limit(limit: Option<f32>) -> Result<(), String> {
28    if let Some(limit) = limit
29        && (!limit.is_finite() || limit <= 0.0)
30    {
31        return Err(format!(
32            "Step routed-expert activation limit must be positive and finite, got {limit}"
33        ));
34    }
35    Ok(())
36}
37
38/// Host-canonical Step routed-expert SwiGLU operation.
39///
40/// Step's final routed layers clamp the linear arm symmetrically and the SiLU arm only above.
41/// Keeping this scalar order explicit also defines the device-host-exact CUDA gate.
42/// Raw stream-ordered device copy for capture-safe cross-context seams (cudarc's slice-use
43/// tracking creates capture-illegal dependencies there). Pointers must be pre-cached with
44/// their owners' streams; bytes flow identically to the tracked copy.
45/// MEMRA_OPROJ_DIRECT=1 (o-proj direct join, default OFF until gated): peer ranks write
46/// their fused O partial OVER P2P into a root-resident buffer (UVA kernel stores), and the
47/// model engine adds the two partials itself — the root stream leaves the join entirely
48/// (no peer pull copy, no root add, no second event hop, no final 16KB ownership copy).
49/// Reduction order and kernel programs are unchanged, so the row is BIT-IDENTICAL.
50/// MEMRA_MOE_DIRECT=1 (moe direct join, default OFF until gated): the o-proj direct-join
51/// recipe on the expert combine — peer ranks' accumulators live root-side (the axpy twin
52/// register-accumulates and stores ONCE, so the P2P cost is a single 16KB store pass), and
53/// the model engine adds the two shard rows itself. Operand order matches root's add:
54/// BIT-IDENTICAL.
55/// MEMRA_ROUTES_PRESTAGE=1 (default OFF until gated): stage the shared layer input to
56/// every rank and quantize it BEFORE the router runs — neither depends on the selection,
57/// so the rank streams' pull+quantize overlaps dev0's router gemv+topk instead of chaining
58/// behind it (the router->quantize and axpy->add gap edges). Same copies, same quantize
59/// kernel, same operands: BIT-IDENTICAL.
60pub(crate) fn routes_prestage_on() -> bool {
61    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
62    *ON.get_or_init(|| std::env::var("MEMRA_ROUTES_PRESTAGE").as_deref() == Ok("1"))
63}
64
65/// MEMRA_FENCE_MEMOPS=1 (default OFF until gated): the moe direct join's two event
66/// fences become cuStreamWriteValue32/cuStreamWaitValue32 doorbells — hardware stream
67/// memops with lower signal->wake latency than cross-device cuStreamWaitEvent. Ordering:
68/// PCIe posted writes from one device arrive in order, so rank1's accumulator stores are
69/// visible before its flag write lands; e's GEQ wait then covers them. Falls back to
70/// events when the device rejects stream memops. Scheduling-only: BIT-IDENTICAL values.
71/// MEMRA_LEN_MIRROR_LAZY=1 (default OFF until gated): skip redundant per-layer 4B len
72/// htods — the local device mirror is unread in TP decode, and under FUSE_ROPE_APPEND the
73/// fused append's atomicInc owns the rank counters. Every one of those tiny copies is a
74/// compute->copy engine turnaround in the middle of the layer stream.
75/// MEMRA_RANK0_MERGE=1 (default OFF until gated): same-device rank0 rides e's stream via
76/// the runtime redirect — see decode_step_h.
77/// MEMRA_OPROJ_TAIL=1 (default OFF until gated): the o-proj direct-join add is DEFERRED —
78/// the finish arm keeps its waits, stores the two partial pointers here, and the residual
79/// add_rms_norm consumer composes mixed = a0+a1 in-register (join_add_rms_norm, verbatim
80/// program: BIT-IDENTICAL). The returned `mixed` buffer is UNWRITTEN in this mode; its
81/// only live consumer is the residual_norm_ffn seam, which takes the handoff.
82pub(crate) fn oproj_tail_on() -> bool {
83    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
84    *ON.get_or_init(|| std::env::var("MEMRA_OPROJ_TAIL").as_deref() == Ok("1"))
85}
86thread_local! {
87    static OPROJ_TAIL_PENDING: std::cell::Cell<Option<(u64, u64)>> =
88        const { std::cell::Cell::new(None) };
89}
90thread_local! {
91    /// The deferral is legal ONLY under callers whose walk flows into
92    /// residual_norm_ffn (decode_step_h / decode_step_chain arm this) — the verify
93    /// prefill reaches the same finish and would consume unwritten `mixed` otherwise
94    /// (M2-MISMATCH receipt: prefill argmax corrupted while decode stayed exact).
95    static OPROJ_TAIL_ELIGIBLE: std::cell::Cell<bool> = const { std::cell::Cell::new(false) };
96}
97/// RAII eligibility scope for the o-proj tail deferral.
98pub(crate) struct OprojTailScope(());
99pub(crate) fn oproj_tail_scope() -> OprojTailScope {
100    OPROJ_TAIL_ELIGIBLE.with(|c| c.set(true));
101    OprojTailScope(())
102}
103impl Drop for OprojTailScope {
104    fn drop(&mut self) {
105        OPROJ_TAIL_ELIGIBLE.with(|c| c.set(false));
106        // A leftover un-consumed handoff must never leak across calls.
107        OPROJ_TAIL_PENDING.with(|c| c.set(None));
108    }
109}
110thread_local! {
111    /// T-COLUMN verify select: the verify driver sets the column before each per-column
112    /// attention call; decode_v2_input_qkv takes it (once) and selects from the slabs.
113    static VERIFY_TCOL: std::cell::Cell<Option<usize>> = const { std::cell::Cell::new(None) };
114}
115pub(crate) fn set_verify_tcol(c: Option<usize>) {
116    VERIFY_TCOL.with(|x| x.set(c));
117}
118pub(crate) fn take_verify_tcol() -> Option<usize> {
119    VERIFY_TCOL.with(|x| x.take())
120}
121
122/// MEMRA_TCOL_OPROJ=1 (spec verify): defer each column's o_proj out of the per-column
123/// walk — the finish seam stashes the column's `gated` rows instead of running the
124/// per-column finish choreography (rank events, P2P join, engine handoff), and one
125/// weight-amortized b4_tcol per rank + one elementwise join produce every column's
126/// `mixed` afterwards. Bit-exact per column: the tcol kernel is the t=1 b4 program per
127/// column, and the slab join adds the same operand values elementwise.
128pub(crate) fn tcol_oproj_on() -> bool {
129    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
130    *ON.get_or_init(|| std::env::var("MEMRA_TCOL_OPROJ").as_deref() == Ok("1"))
131}
132thread_local! {
133    /// The verify driver arms the column before each per-column attention call; the
134    /// finish seam takes it (once). Stashed=true reports the defer actually happened
135    /// (the seam falls back to the normal finish when the config is ineligible).
136    static TCOL_OPROJ_DEFER: std::cell::Cell<Option<usize>> = const { std::cell::Cell::new(None) };
137    static TCOL_OPROJ_STASHED: std::cell::Cell<bool> = const { std::cell::Cell::new(false) };
138}
139pub(crate) fn set_tcol_oproj_defer(c: Option<usize>) {
140    TCOL_OPROJ_DEFER.with(|x| x.set(c));
141}
142pub(crate) fn take_tcol_oproj_defer() -> Option<usize> {
143    TCOL_OPROJ_DEFER.with(|x| x.take())
144}
145pub(crate) fn set_tcol_oproj_stashed() {
146    TCOL_OPROJ_STASHED.with(|x| x.set(true));
147}
148pub(crate) fn take_tcol_oproj_stashed() -> bool {
149    TCOL_OPROJ_STASHED.with(|x| x.replace(false))
150}
151
152pub(crate) fn oproj_tail_eligible() -> bool {
153    OPROJ_TAIL_ELIGIBLE.with(|c| c.get())
154}
155pub(crate) fn take_oproj_tail() -> Option<(u64, u64)> {
156    OPROJ_TAIL_PENDING.with(|c| c.take())
157}
158pub(crate) fn set_oproj_tail(v: (u64, u64)) {
159    OPROJ_TAIL_PENDING.with(|c| c.set(Some(v)));
160}
161
162pub(crate) fn rank0_merge_on() -> bool {
163    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
164    *ON.get_or_init(|| std::env::var("MEMRA_RANK0_MERGE").as_deref() == Ok("1"))
165}
166
167pub(crate) fn len_mirror_lazy_on() -> bool {
168    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
169    *ON.get_or_init(|| std::env::var("MEMRA_LEN_MIRROR_LAZY").as_deref() == Ok("1"))
170}
171
172pub(crate) fn fence_memops_on() -> bool {
173    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
174    *ON.get_or_init(|| std::env::var("MEMRA_FENCE_MEMOPS").as_deref() == Ok("1"))
175}
176
177pub(crate) fn moe_direct_on() -> bool {
178    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
179    *ON.get_or_init(|| std::env::var("MEMRA_MOE_DIRECT").as_deref() == Ok("1"))
180}
181
182/// MEMRA_SEL_MIRROR=1: the per-rank routed-selection pull runs as ONE `moe_sel_w_mirror`
183/// launch instead of two 32-byte D2D copies, and when every consuming rank shares e's device
184/// the intermediate e-context staging pair is skipped entirely (the caller's sel/route_w rows
185/// are process-persistent, so the ranks read them directly). Bit-identical: same bytes, one
186/// fewer hop. Refused under the graph door, whose captured copies need the fixed staging
187/// addresses. Default OFF until receipted.
188/// MEMRA_FENCE_RANK1=1: the peer rank rings a doorbell in ROOT memory with a kernel store
189/// (`memra_ring_flag`) and the model engine waits it with a SAME-DEVICE stream memop, instead
190/// of waiting a cross-device event. Completes the half the memops receipt left open (peer
191/// memops are rejected; peer kernel stores are the direct-join mechanism). Ordering only —
192/// values are untouched. Requires MEMRA_FENCE_MEMOPS=1 (it owns the flag allocation).
193pub(crate) fn fence_rank1_on() -> bool {
194    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
195    *ON.get_or_init(|| std::env::var("MEMRA_FENCE_RANK1").as_deref() == Ok("1"))
196}
197
198/// MEMRA_SPEC_FA2=1 (the DSpark verify lesson): the T=2 verify walk defers each column's
199/// ATTENTION CORE — the dcw arm appends the column's K/V and stashes its post-rope q and
200/// gate rows, then ONE fa_decode_dcw2 per rank walks the KV stream once for both columns
201/// (per-row causal bounds; bit-identical per row under the equal-partition guard), the
202/// per-row combine writes both gated rows, and the o_proj join runs on the TCOL slabs.
203/// ROW-TABLE RESTAGE (`MEMRA_ROWS_TAB_RESTAGE`, DEFAULT ON since this lane).
204///
205/// ON: `decode_v2_rope_fa_rows` builds the 6-word-per-row pointer table from the caller's
206/// freshly-read live cache pointers and stages it into a persistent per-rank slab before
207/// every launch. OFF (`=0`): the retired process-lifetime `rows_tabs` memo, keyed by a hash
208/// of (k pointer, base pointer, layer, t) that could not see the V or LEN pointers the
209/// entry also carried, and that nothing invalidated when a session's KV cache was dropped.
210///
211/// Default ON because the OFF arm is a proven use-after-free, not a slower correct path:
212/// on step37-flash with MEMRA_FUSE_ROPE_APPEND=1 it made speculative decoding unservable
213/// (whole non-finite verify rows, then CUDA_ERROR_ILLEGAL_ADDRESS). ON is value-neutral on
214/// every fresh lookup by construction: identical bytes reach the same kernels. Rollback
215/// seam: `MEMRA_ROWS_TAB_RESTAGE=0`.
216/// The 6-word-per-row launch table `{k, v, len, base, ctr, back}` the fused rope/append/fa
217/// kernels dereference. Pure so it can be tested: the words come from the caller's live
218/// per-row `[k, v, len, base]` pointers, `ctr` is this rank's counter slab (one shared cell
219/// for same-session rows, one cell per row otherwise) and `back` is the same-session causal
220/// step-back `t-1-r` (0 across sessions, where each row owns its own len).
221pub(crate) fn rows_tab_host(
222    parts_rank: &[[u64; 4]],
223    ctr_base: u64,
224    same_session: bool,
225    t: usize,
226) -> Vec<u64> {
227    let mut host = Vec::with_capacity(t * 6);
228    for (r, parts) in parts_rank.iter().enumerate().take(t) {
229        host.extend_from_slice(&[
230            parts[0],
231            parts[1],
232            parts[2],
233            parts[3],
234            if same_session {
235                ctr_base
236            } else {
237                ctr_base + (r as u64) * 4
238            },
239            if same_session {
240                (t - 1 - r) as u64
241            } else {
242                0u64
243            },
244        ]);
245    }
246    host
247}
248
249/// The RETIRED memo key, kept ONLY so a test can assert what it cannot see. Both historical
250/// call sites hashed a SUBSET of the pointers the table carries; this reproduces the verify
251/// site's formula verbatim.
252#[cfg(test)]
253pub(crate) fn retired_rows_tab_key(kp: u64, bp: u64, il: usize, t: usize) -> u64 {
254    kp.rotate_left(17)
255        .wrapping_add(bp)
256        .wrapping_add((il as u64) << 32)
257        .wrapping_add(t as u64)
258        .wrapping_add(1 << 63)
259}
260
261pub(crate) fn rows_tab_restage_on() -> bool {
262    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
263    *ON.get_or_init(|| std::env::var("MEMRA_ROWS_TAB_RESTAGE").as_deref() != Ok("0"))
264}
265
266/// STALE-HIT RECEIPT (`MEMRA_ROWS_TAB_STALE_SCAN`, DEFAULT OFF, diagnostic only).
267///
268/// Keeps a HOST shadow of the last table staged under each retired memo key and prints one
269/// line whenever the key repeats with different contents, naming the words that moved. It
270/// costs a host hash lookup and a small clone per rank per layer per verify round, so it is
271/// off in serving. `[rows-tab] engaged=` on the counter proves the path executes at all,
272/// which is what separates "the memo was innocent" from "the memo never ran".
273/// Rollback seam: unset it (or `=0`).
274pub(crate) fn rows_tab_stale_scan() -> bool {
275    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
276    *ON.get_or_init(|| std::env::var("MEMRA_ROWS_TAB_STALE_SCAN").as_deref() == Ok("1"))
277}
278
279pub(crate) static ROWS_TAB_ENGAGED: std::sync::atomic::AtomicU64 =
280    std::sync::atomic::AtomicU64::new(0);
281pub(crate) static ROWS_TAB_STALE: std::sync::atomic::AtomicU64 =
282    std::sync::atomic::AtomicU64::new(0);
283
284pub(crate) fn spec_fa2_on() -> bool {
285    static ENV: std::sync::OnceLock<Option<bool>> = std::sync::OnceLock::new();
286    crate::step37_door(&ENV, "MEMRA_SPEC_FA2")
287}
288thread_local! {
289    /// The verify driver arms the column before each per-column attention call; the dcw
290    /// arm takes it (once) and stashes q/gate instead of running fa+finish.
291    static SPEC_FA2_DEFER: std::cell::Cell<Option<usize>> = const { std::cell::Cell::new(None) };
292    static SPEC_FA2_STASHED: std::cell::Cell<bool> = const { std::cell::Cell::new(false) };
293}
294pub(crate) fn set_spec_fa2_defer(c: Option<usize>) {
295    SPEC_FA2_DEFER.with(|x| x.set(c));
296}
297pub(crate) fn take_spec_fa2_defer() -> Option<usize> {
298    SPEC_FA2_DEFER.with(|x| x.take())
299}
300pub(crate) fn set_spec_fa2_stashed() {
301    SPEC_FA2_STASHED.with(|x| x.set(true));
302}
303pub(crate) fn take_spec_fa2_stashed() -> bool {
304    SPEC_FA2_STASHED.with(|x| x.replace(false))
305}
306
307pub(crate) fn sel_mirror_on() -> bool {
308    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
309    *ON.get_or_init(|| std::env::var("MEMRA_SEL_MIRROR").as_deref() == Ok("1"))
310}
311
312/// MEMRA_STEP_NVFP4_EP2=1: whole-expert (expert-parallel) NVFP4 banks at 2 ranks — expert e
313/// lives ENTIRE on rank (e & 1) at bank slot (e >> 1), replacing the TP column/row shards
314/// (same total VRAM; both sets cannot coexist). Decode rides owner-guarded full-width
315/// sweeps with per-rank slot-ordered partial sums; the cross-rank join is unchanged.
316/// NUMERIC-CLASS door (the slot chain regroups per rank): run-gen argmax gate + battery +
317/// fresh tape, the DEV_ROUTES acceptance class.
318pub(crate) fn step_nvfp4_ep2_on() -> bool {
319    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
320    *ON.get_or_init(|| std::env::var("MEMRA_STEP_NVFP4_EP2").as_deref() == Ok("1"))
321}
322
323pub(crate) fn oproj_direct_on() -> bool {
324    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
325    *ON.get_or_init(|| std::env::var("MEMRA_OPROJ_DIRECT").as_deref() == Ok("1"))
326}
327
328// ─── Slot-major NVFP4 expert-bank programs: THREE independent doors ───────────────────────────
329//
330// These restore, under separate flags, the three programs that the 2026-08-29 removal
331// (`fd0a175ab`) deleted behind ONE env var (`MEMRA_NVFP4_BANK_V2`). That coupling is why the
332// incident's bisect could not name a mechanism: toggling one var moved the bank layout, the
333// gate+up fusion (which auto-armed on the same predicate with no door of its own) and the fused
334// down+combine (which hard-refused without the layout) all at once, so the priced -21.5% wall /
335// -23.7% decode (research/perf-chain-20260831 cell 1) was an unattributable bundle.
336//
337// The corruption they were removed for was NOT any of them: it was a defaulted `in_f = 0`
338// argument at two `kq_fetch` call sites in the PREFILL grouped-GEMM tail
339// (research/step37-bankv3-20260901/DIAGNOSIS.md), fixed compiler-enforced at `1b18a61e8` and
340// gated device-side by the `nvfp4-bank-oracle` bin. Each door below is strict `0`/`1` and
341// admitted separately so its contribution is a number; BANK_SM and SEL_DOWN8 default ON since
342// 2026-09-01 (one coupled decision, PR #76 battery), SEL_GU and the sub-doors default OFF.
343//
344// LAYOUT IS A PROPERTY OF THE BANK. `bank_slot_major_on()` is read ONCE, at bank BUILD, and
345// recorded on the resident bank (`ResidentNvfp4{Column,Row}BankRank::slot_major`). Every reader
346// branches on that stored field, never on the env door. The removed implementation read
347// `nvfp4_bank_v2_on()` at each reader site instead, which is the same class of hole as the
348// defaulted `in_f`: a piece of layout geometry that a caller can fail to supply or can supply
349// inconsistently with the bytes actually resident.
350
351/// Read a DEFAULT-ON door strictly, and report the SOURCE of the answer rather than only the
352/// answer. `0` disables (the rollback seam), `1` re-states the default, unset takes the default.
353///
354/// Two properties this buys, both learned the hard way in this lane's own archaeology:
355///
356/// * **A typo cannot silently disarm a rollback seam.** The default-OFF doors here parse as
357///   `== Ok("1")`, which is safe when the default is OFF (a typo reads as the default) and
358///   DANGEROUS when the default is ON: `MEMRA_NVFP4_BANK_SM=false` under a `!= Ok("0")` rule
359///   would keep the program armed while the operator believed it was rolled back. So an
360///   unrecognized value is reported as such and the default is kept, loudly.
361/// * **The engagement receipt can name the source.** `default-on` and `MEMRA_..=1` are
362///   different facts about the same boot: one says the flip is doing the work, the other says
363///   a recipe is. A pricing or post-deploy receipt that cannot tell them apart cannot prove a
364///   DEFAULT was measured (TRAP:corrupt-arm-inflates-its-own-perf-price's sibling: an arm that
365///   cannot name what armed it is not an arm).
366fn door_default_on(name: &'static str) -> (bool, &'static str) {
367    let raw = std::env::var(name).ok();
368    door_default_on_value(name, raw.as_deref())
369}
370
371/// The parse, separated from the environment so it can be TESTED. `std::env` is process-global
372/// state and these doors are `OnceLock`-cached, so an env-var test would be both racy under
373/// `cargo test`'s thread pool and unrepeatable within one process — i.e. exactly the kind of
374/// gate that passes because it never really ran.
375fn door_default_on_value(name: &str, value: Option<&str>) -> (bool, &'static str) {
376    match value {
377        Some("0") => (false, "env=0 (rollback seam)"),
378        Some("1") => (true, "env=1"),
379        None => (true, "default-on"),
380        Some(_) => {
381            eprintln!(
382                "[nvfp4-door] WARN {name} has an unrecognized value; only `0` and `1` are \
383                 accepted and the DEFAULT-ON answer is kept. To roll back, set {name}=0."
384            );
385            (true, "default-on (unrecognized value ignored)")
386        }
387    }
388}
389
390/// MEMRA_NVFP4_BANK_SM (PROGRAM 1, **default ON since 2026-09-01**): build the step TP
391/// contiguous NVFP4 expert banks (gate/up/down) in the SLOT-MAJOR row layout — slot g's 16 qs
392/// bytes contiguous at `g*16` (one coalesced 512B warp wave) and the two UE4M3 scale bytes at
393/// `nslots*16 + g*2` — and dispatch the `_sel_v2` decode readers over them. Pure byte
394/// permutation, so BIT-IDENTICAL per row; the claim is gated by `nvfp4-bank-oracle`
395/// (device-side, prefill GEMM included) and by end-to-end greedy byte identity, never by a
396/// comment.
397///
398/// **WHY A BIT-IDENTICAL, MEASURABLY-FREE PROGRAM DEFAULTS ON.** On its own this layout earns
399/// nothing: x5 interleaved, 105.35 vs 106.78 decode tok/s, per-boot range `[104.66, 107.95]`
400/// overlapping the OFF arm's `[105.11, 107.09]`. It defaults ON for exactly one reason —
401/// `MEMRA_NVFP4_SEL_DOWN8` (PROGRAM 3), the one program that DOES separate (+5.48% decode), is
402/// gated at its call site on `shard.slot_major`, so with this door off PROGRAM 3's default-ON
403/// is a SILENT NO-OP: `down8=false door=true`, no refusal, no warning, and the win simply does
404/// not happen. The deployable unit is the two together, which makes this one coupled default
405/// decision and not two independent ones. Receipts:
406/// `research/step37-bankv3-20260901/RESULTS.md` (the down8 default-ON qualification battery).
407///
408/// ROLLBACK SEAM: `MEMRA_NVFP4_BANK_SM=0`, which also disarms PROGRAM 3 by construction.
409pub(crate) fn bank_slot_major_on() -> bool {
410    bank_slot_major_source().0
411}
412
413/// `bank_slot_major_on()` plus the SOURCE of the answer, for the engagement receipt.
414pub(crate) fn bank_slot_major_source() -> (bool, &'static str) {
415    static ON: std::sync::OnceLock<(bool, &'static str)> = std::sync::OnceLock::new();
416    *ON.get_or_init(|| door_default_on("MEMRA_NVFP4_BANK_SM"))
417}
418
419/// MEMRA_NVFP4_SEL_GU=1 (PROGRAM 2, default OFF): run the routed gate and up sweeps as ONE
420/// launch (`qmatvec_nvfp4_dp4a_sel_v2_gu`) instead of two — the two sweeps share sel/aq/ad and
421/// have identical geometry, so blocks `[0,out_f)` take the gate bank and `[out_f,2*out_f)` the
422/// up bank. Per-row bit-identical; halves the sweep launch count and doubles grid fill.
423/// Subordinate to PROGRAM 1 by construction: it reads slot-major rows, so the caller arms it
424/// only when both banks report `slot_major`. In the removed implementation this fusion had NO
425/// door of its own and auto-armed on the bank predicate, which is one third of why the bundle
426/// was unattributable.
427pub(crate) fn sel_gu_fused_on() -> bool {
428    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
429    *ON.get_or_init(|| std::env::var("MEMRA_NVFP4_SEL_GU").as_deref() == Ok("1"))
430}
431
432/// MEMRA_NVFP4_SEL_DOWN8 (PROGRAM 3, default ON since 2026-09-01; `=0` is the rollback seam): fuse the routed DOWN sweep with the
433/// route-weight combine into one launch (`qmatvec_nvfp4_dp4a_sel_v2_down8`, the q8 `down8 w8`
434/// occupancy arm ported to the NVFP4 banks) — one warp per routed slot instead of one warp per
435/// (row, slot), and the `n_sel x out_f` partial-buffer round trip disappears. Bit-identical
436/// (same dot program, same reduce tree, same slot-ordered combine chain). Also subordinate to
437/// PROGRAM 1: the caller arms it only when the down shard reports `slot_major`, and only on the
438/// device-routed arm at `nsb <= 32` (the fit-block class the reduce identity is argued at).
439/// Rides LAST per the lane mandate: it is priced only on green gates for the layers beneath it.
440///
441/// **DEFAULT ON since 2026-09-01**, and it is the reason PROGRAM 1 defaults ON too. This is the
442/// only one of the three restored programs that separates from noise: +5.48% decode / +5.09%
443/// wall, x5 interleaved vendor-default sampled, per-boot range `[112.59, 114.82]` with NO
444/// overlap against either the OFF arm or the arm directly beneath it, re-qualified at deploy
445/// grade in `research/step37-bankv3-20260901/RESULTS.md`.
446///
447/// ELIGIBILITY IS NARROWER THAN THE DEFAULT, and the engagement receipt below prints every
448/// condition: the arm needs `device_routed`, `shard.slot_major` (i.e. PROGRAM 1) and
449/// `nsb <= 32`. On any other geometry or route the default is INERT, which is correct-by-
450/// refusal and NOT a regression — but it does mean "default ON" and "engaged" are two facts,
451/// and only the `[nvfp4-sweep]` line settles the second.
452///
453/// ROLLBACK SEAM: `MEMRA_NVFP4_SEL_DOWN8=0` (or `MEMRA_NVFP4_BANK_SM=0`, which disarms it by
454/// construction).
455pub(crate) fn sel_down8_on() -> bool {
456    sel_down8_source().0
457}
458
459/// `sel_down8_on()` plus the SOURCE of the answer, for the engagement receipt.
460pub(crate) fn sel_down8_source() -> (bool, &'static str) {
461    static ON: std::sync::OnceLock<(bool, &'static str)> = std::sync::OnceLock::new();
462    *ON.get_or_init(|| door_default_on("MEMRA_NVFP4_SEL_DOWN8"))
463}
464
465pub(crate) fn raw_copy_bytes(
466    dst: u64,
467    src: u64,
468    bytes: usize,
469    engine: &Engine,
470) -> Result<(), Box<dyn std::error::Error>> {
471    use cudarc::driver::sys;
472    let r = unsafe {
473        sys::cuMemcpyAsync(
474            dst as sys::CUdeviceptr,
475            src as sys::CUdeviceptr,
476            bytes,
477            engine.stream().cu_stream() as sys::CUstream,
478        )
479    };
480    if r == sys::CUresult::CUDA_SUCCESS {
481        Ok(())
482    } else {
483        // MEMRA_RAW_COPY_TRACE=1: a raw D2D failure carries no call site by itself, and
484        // every slab-width bug in the t-row family surfaces here. Operands + backtrace.
485        if std::env::var("MEMRA_RAW_COPY_TRACE").as_deref() == Ok("1") {
486            eprintln!(
487                "[raw-copy-fail] dst={dst:#x} src={src:#x} bytes={bytes} {r:?}\n{}",
488                std::backtrace::Backtrace::force_capture()
489            );
490        }
491        Err(format!("raw_copy_bytes: {r:?} bytes={bytes} dst={dst:#x} src={src:#x}").into())
492    }
493}
494
495pub fn step_expert_activation_host(gate: f32, up: f32, limit: Option<f32>) -> f32 {
496    let silu = gate / (1.0 + (-gate).exp());
497    match limit {
498        Some(limit) => silu.min(limit) * up.clamp(-limit, limit),
499        None => silu * up,
500    }
501}
502
503#[derive(Debug, Clone, PartialEq, Eq)]
504struct ExpertOwnerRoutes {
505    rank: usize,
506    selected: Vec<usize>,
507    token_rows: Vec<usize>,
508    global_pairs: Vec<usize>,
509}
510
511#[allow(clippy::manual_is_multiple_of)] // allow: divisor is runtime-derived; the modulo form keeps a zero divisor loud (a panic), where is_multiple_of would return false silently
512fn partition_expert_owner_routes(
513    expert_count: usize,
514    ranks: usize,
515    tokens: usize,
516    experts_per_token: usize,
517    selected: &[usize],
518) -> Result<Vec<ExpertOwnerRoutes>, String> {
519    if expert_count == 0
520        || ranks == 0
521        || tokens == 0
522        || experts_per_token == 0
523        || expert_count % ranks != 0
524    {
525        return Err(format!(
526            "invalid expert-owner route geometry experts={expert_count} ranks={ranks} \
527             tokens={tokens} experts_per_token={experts_per_token}"
528        ));
529    }
530    let pairs = tokens
531        .checked_mul(experts_per_token)
532        .ok_or("expert-owner route count overflow")?;
533    if selected.len() != pairs {
534        return Err(format!(
535            "expert-owner routes {} != {tokens}x{experts_per_token} ({pairs})",
536            selected.len()
537        ));
538    }
539    let per_rank = expert_count / ranks;
540    let mut owners = (0..ranks)
541        .map(|rank| ExpertOwnerRoutes {
542            rank,
543            selected: Vec::new(),
544            token_rows: Vec::new(),
545            global_pairs: Vec::new(),
546        })
547        .collect::<Vec<_>>();
548    for (pair, &expert) in selected.iter().enumerate() {
549        if expert >= expert_count {
550            return Err(format!(
551                "expert-owner route {pair} selects expert {expert} outside 0..{expert_count}"
552            ));
553        }
554        let rank = expert / per_rank;
555        owners[rank].selected.push(expert - rank * per_rank);
556        owners[rank].token_rows.push(pair / experts_per_token);
557        owners[rank].global_pairs.push(pair);
558    }
559    Ok(owners)
560}
561
562fn validate_step_grouped_owner_routes(
563    expert_count: usize,
564    tokens: usize,
565    selected: &[usize],
566) -> Result<usize, String> {
567    if expert_count != STEP_GROUPED_FP8_EXPERTS || tokens == 0 {
568        return Err(format!(
569            "official Step owner-grouped FP8 requires {} experts and nonzero tokens, got \
570             experts={expert_count} tokens={tokens}",
571            STEP_GROUPED_FP8_EXPERTS
572        ));
573    }
574    let pairs = tokens
575        .checked_mul(STEP_GROUPED_FP8_TOP_K)
576        .ok_or("official Step owner-grouped FP8 route count overflow")?;
577    if selected.len() != pairs {
578        return Err(format!(
579            "official Step owner-grouped FP8 routes {} != {tokens}x{} ({pairs})",
580            selected.len(),
581            STEP_GROUPED_FP8_TOP_K,
582        ));
583    }
584    for (token, routes) in selected.chunks_exact(STEP_GROUPED_FP8_TOP_K).enumerate() {
585        let mut unique = routes.to_vec();
586        unique.sort_unstable();
587        unique.dedup();
588        if unique.len() != STEP_GROUPED_FP8_TOP_K {
589            return Err(format!(
590                "official Step owner-grouped FP8 token {token} routes are not top-8 unique: \
591                 {routes:?}"
592            ));
593        }
594    }
595    Ok(pairs)
596}
597
598#[derive(Debug, Clone, Copy, PartialEq, Eq)]
599struct WeightedRouteCombineShape {
600    pairs: usize,
601    max_pairs: usize,
602}
603
604fn validate_weighted_route_combine(
605    width: usize,
606    experts_per_token: usize,
607    max_tokens: usize,
608    tokens: usize,
609    owner_global_pairs: &[&[usize]],
610    route_weights: &[f32],
611) -> Result<WeightedRouteCombineShape, String> {
612    if width == 0
613        || experts_per_token == 0
614        || max_tokens == 0
615        || tokens == 0
616        || tokens > max_tokens
617        || width > i32::MAX as usize
618        || experts_per_token > i32::MAX as usize
619        || tokens > i32::MAX as usize
620    {
621        return Err(format!(
622            "invalid weighted route combine geometry width={width} experts_per_token=\
623             {experts_per_token} tokens={tokens}/{max_tokens}"
624        ));
625    }
626    let pairs = tokens
627        .checked_mul(experts_per_token)
628        .ok_or("weighted route combine pair count overflow")?;
629    let max_pairs = max_tokens
630        .checked_mul(experts_per_token)
631        .ok_or("weighted route combine capacity overflow")?;
632    if route_weights.len() != pairs || !route_weights.iter().all(|weight| weight.is_finite()) {
633        return Err(format!(
634            "weighted route combine weights {} != pairs {pairs} or contain a non-finite value",
635            route_weights.len()
636        ));
637    }
638    let mut seen = vec![false; pairs];
639    let mut observed = 0usize;
640    for pairs_for_owner in owner_global_pairs {
641        observed = observed
642            .checked_add(pairs_for_owner.len())
643            .ok_or("weighted route combine observed pair count overflow")?;
644        for &pair in *pairs_for_owner {
645            if pair >= pairs || std::mem::replace(&mut seen[pair], true) {
646                return Err(format!(
647                    "weighted route combine pair {pair} is outside 0..{pairs} or duplicated"
648                ));
649            }
650        }
651    }
652    if observed != pairs || seen.iter().any(|present| !present) {
653        return Err(format!(
654            "weighted route combine owner schedules cover {observed} of {pairs} canonical pairs"
655        ));
656    }
657    Ok(WeightedRouteCombineShape { pairs, max_pairs })
658}
659
660fn cache_rank_rows(
661    rows: &[u8],
662    tokens: usize,
663    local_token_bytes: usize,
664    ranks: usize,
665    rank: usize,
666) -> Result<Vec<u8>, String> {
667    if ranks == 0 || rank >= ranks {
668        return Err(format!(
669            "TP cache rank {rank} is outside a {ranks}-rank layout"
670        ));
671    }
672    let global_token_bytes = local_token_bytes
673        .checked_mul(ranks)
674        .ok_or("TP cache global token-byte overflow")?;
675    let expected = tokens
676        .checked_mul(global_token_bytes)
677        .ok_or("TP cache row-byte overflow")?;
678    if rows.len() != expected {
679        return Err(format!(
680            "TP cache rows contain {} bytes, expected {tokens}x{global_token_bytes}={expected}",
681            rows.len()
682        ));
683    }
684    let mut shard = Vec::with_capacity(tokens * local_token_bytes);
685    for token in 0..tokens {
686        let start = token * global_token_bytes + rank * local_token_bytes;
687        shard.extend_from_slice(&rows[start..start + local_token_bytes]);
688    }
689    Ok(shard)
690}
691
692fn parse_step_tp_native_p2p(value: Option<&str>) -> Result<bool, String> {
693    match value {
694        None | Some("") | Some("0") => Ok(false),
695        Some("1") => Ok(true),
696        Some(value) => Err(format!(
697            "MEMRA_STEP_TP_NATIVE_P2P={value:?} is invalid; expected 0 or 1"
698        )),
699    }
700}
701
702pub fn step_tp_native_p2p_enabled() -> Result<bool, String> {
703    parse_step_tp_native_p2p(std::env::var("MEMRA_STEP_TP_NATIVE_P2P").ok().as_deref())
704}
705
706fn parse_step_tp_bulk_p2p(value: Option<&str>) -> Result<bool, String> {
707    match value {
708        None | Some("") | Some("0") => Ok(false),
709        Some("1") => Ok(true),
710        Some(value) => Err(format!(
711            "MEMRA_STEP_TP_BULK_P2P={value:?} is invalid; expected 0 or 1"
712        )),
713    }
714}
715
716pub fn step_tp_bulk_p2p_enabled() -> Result<bool, String> {
717    parse_step_tp_bulk_p2p(std::env::var("MEMRA_STEP_TP_BULK_P2P").ok().as_deref())
718}
719
720fn parse_step_ep_device_arithmetic(value: Option<&str>) -> Result<bool, String> {
721    match value {
722        None | Some("") | Some("0") => Ok(false),
723        Some("1") => Ok(true),
724        Some(value) => Err(format!(
725            "MEMRA_STEP_EP_DEVICE_ARITHMETIC={value:?} is invalid; expected 0 or 1"
726        )),
727    }
728}
729
730fn parse_step_nvfp4_dev_routes(value: Option<&str>) -> Result<bool, String> {
731    match value {
732        None | Some("") | Some("0") => Ok(false),
733        Some("1") => Ok(true),
734        Some(value) => Err(format!(
735            "MEMRA_STEP_NVFP4_DEV_ROUTES={value:?} is invalid; expected 0 or 1"
736        )),
737    }
738}
739
740/// Opt-in door for the device-resident NVFP4 TP routed-expert decode program. Default OFF; the
741/// host-canonical program remains the oracle until the device path carries its own gates.
742pub fn step_nvfp4_dev_routes_enabled() -> Result<bool, String> {
743    parse_step_nvfp4_dev_routes(std::env::var("MEMRA_STEP_NVFP4_DEV_ROUTES").ok().as_deref())
744}
745
746pub fn step_ep_device_arithmetic_enabled() -> Result<bool, String> {
747    parse_step_ep_device_arithmetic(
748        std::env::var("MEMRA_STEP_EP_DEVICE_ARITHMETIC")
749            .ok()
750            .as_deref(),
751    )
752}
753
754fn parse_step_tp_f32_mirror(value: Option<&str>) -> Result<bool, String> {
755    match value {
756        None | Some("") | Some("0") => Ok(false),
757        Some("1") => Ok(true),
758        Some(value) => Err(format!(
759            "MEMRA_STEP_TP_F32_MIRROR={value:?} is invalid; expected 0 or 1"
760        )),
761    }
762}
763
764pub fn step_tp_f32_mirror_enabled() -> Result<bool, String> {
765    parse_step_tp_f32_mirror(std::env::var("MEMRA_STEP_TP_F32_MIRROR").ok().as_deref())
766}
767
768fn parse_step_tp_decode_v2(value: Option<&str>) -> Result<bool, String> {
769    match value {
770        None | Some("") | Some("0") => Ok(false),
771        Some("1") => Ok(true),
772        Some(value) => Err(format!(
773            "MEMRA_STEP_TP_DECODE_V2={value:?} is invalid; expected 0 or 1"
774        )),
775    }
776}
777
778/// The v2 rank-local Step decode-attention driver: persistent workspaces, evented cross-stream
779/// ordering, and a root-device O reduction — same kernels, values, and canonical reduction order
780/// as the v1 driver (it requires the F32 mirror so no per-call weight expansion exists on either
781/// side of the comparison).
782pub fn step_tp_decode_v2_enabled() -> Result<bool, String> {
783    parse_step_tp_decode_v2(std::env::var("MEMRA_STEP_TP_DECODE_V2").ok().as_deref())
784}
785
786fn parse_step_tp_qkv_fused(value: Option<&str>) -> Result<bool, String> {
787    match value {
788        None | Some("") | Some("0") => Ok(false),
789        Some("1") => Ok(true),
790        Some(value) => Err(format!(
791            "MEMRA_STEP_TP_QKV_FUSED={value:?} is invalid; expected 0 or 1"
792        )),
793    }
794}
795
796fn parse_step_tp_dev_router(value: Option<&str>) -> Result<bool, String> {
797    match value {
798        None | Some("") | Some("0") => Ok(false),
799        Some("1") => Ok(true),
800        Some(value) => Err(format!(
801            "MEMRA_STEP_TP_DEV_ROUTER={value:?} is invalid; expected 0 or 1"
802        )),
803    }
804}
805
806/// Device-side sigmoid top-k routing for the TP device-IO expert program: the per-layer host
807/// logits readback (the last per-layer host sync) disappears. Selection tie-breaking may
808/// differ from the host router — NUMERIC-CLASS door, run-gen argmax gate + boot battery.
809pub fn step_tp_dev_router_enabled() -> Result<bool, String> {
810    parse_step_tp_dev_router(std::env::var("MEMRA_STEP_TP_DEV_ROUTER").ok().as_deref())
811}
812
813fn parse_step_tp_graph(value: Option<&str>) -> Result<bool, String> {
814    match value {
815        None | Some("") | Some("0") => Ok(false),
816        Some("1") => Ok(true),
817        Some(value) => Err(format!(
818            "MEMRA_STEP_TP_GRAPH={value:?} is invalid; expected 0 or 1"
819        )),
820    }
821}
822
823fn parse_step_tp_dcw(value: Option<&str>) -> Result<bool, String> {
824    match value {
825        None | Some("") | Some("0") => Ok(false),
826        Some("1") => Ok(true),
827        Some(value) => Err(format!(
828            "MEMRA_STEP_TP_DCW={value:?} is invalid; expected 0 or 1"
829        )),
830    }
831}
832
833/// Device-counter attention path (graph increment A run EAGERLY): append at len_d - base_d,
834/// inc_i32, fa over the counter-derived window — with bucket = the effective t_kv this is
835/// bit-identical to the host-row + kvmod path (the one-partition law), and it is the exact
836/// child content the capture wraps. Rebase tokens and sub-vec-floor contexts fall back.
837pub fn step_tp_dcw_enabled() -> Result<bool, String> {
838    parse_step_tp_dcw(std::env::var("MEMRA_STEP_TP_DCW").ok().as_deref())
839}
840
841/// CUDA-graph door for the shape-stable TP segments (first increment: the device-routed
842/// expert program — per-layer multi-device parents built from per-rank children, launched on
843/// the model engine's stream; zero per-token node updates). Mechanism proven by
844/// tp_graph_probe. VALUE-IDENTICAL: the graphs replay exactly the eager kernel/copy sequence.
845pub fn step_tp_graph_enabled() -> Result<bool, String> {
846    parse_step_tp_graph(std::env::var("MEMRA_STEP_TP_GRAPH").ok().as_deref())
847}
848
849/// GRAPH-LAUNCH HEADROOM GUARD for the routed-prejoin graph door (see
850/// `spec::GRAPH_LAUNCH_MIN_FREE`): checked on the launching engine only when the door
851/// is armed (short-circuit after `step_tp_graph_enabled`), noting once per process with
852/// the sweep's grep-stable `graph replay suspended:` key.
853fn step_tp_graph_headroom_ok(e: &Engine) -> bool {
854    let ok = crate::spec::graph_launch_headroom_ok(e);
855    if !ok {
856        static NOTED: std::sync::Once = std::sync::Once::new();
857        NOTED.call_once(|| crate::spec::graph_replay_suspended_note("step-tp-routes"));
858    }
859    ok
860}
861
862/// Fused single-launch QKV projection inside the v2 decode driver — a NUMERIC-CLASS door
863/// (per-row deterministic tree reduce instead of the chunked cuBLASLt program), default OFF,
864/// gated by the run-gen argmax gate + boot battery like MEMRA_STEP_NVFP4_DEV_ROUTES.
865pub fn step_tp_qkv_fused_enabled() -> Result<bool, String> {
866    parse_step_tp_qkv_fused(std::env::var("MEMRA_STEP_TP_QKV_FUSED").ok().as_deref())
867}
868
869#[derive(Debug, Clone, PartialEq, Eq)]
870pub struct StepEpLayerSpec {
871    pub layer: usize,
872    pub devices: Vec<usize>,
873}
874
875pub type StepTpLayerSpec = StepEpLayerSpec;
876
877/// ModelPlan-driven whole-model parallel policy. `auto` removes per-layer family recipes; the
878/// loader derives its scope from dense/MoE operations and selects a registered numeric backend
879/// from the artifact tensor/activation contract.
880fn parse_auto_parallel_devices(
881    mode: Option<&str>,
882    raw_devices: Option<&str>,
883) -> Result<Option<Vec<usize>>, String> {
884    let mode = match mode {
885        None | Some("") | Some("0") | Some("off") => return Ok(None),
886        Some("auto") => "auto",
887        Some(value) => {
888            return Err(format!(
889                "MEMRA_PARALLEL={value:?} is invalid; expected off or auto"
890            ));
891        }
892    };
893    let raw = raw_devices.ok_or_else(|| {
894        format!("{mode} parallel placement requires MEMRA_PARALLEL_DEVICES=DEVICE,DEVICE[...]")
895    })?;
896    let devices =
897        raw.split(',')
898            .map(|device| {
899                device.trim().parse::<usize>().map_err(|_| {
900                    format!("MEMRA_PARALLEL_DEVICES entry {device:?} is not an integer")
901                })
902            })
903            .collect::<Result<Vec<_>, _>>()?;
904    if !(2..=crate::parallel::AUTO_PARALLEL_MAX_CARDS).contains(&devices.len()) {
905        return Err(format!(
906            "MEMRA_PARALLEL=auto requires 2..={} devices, got {}",
907            crate::parallel::AUTO_PARALLEL_MAX_CARDS,
908            devices.len()
909        ));
910    }
911    let mut unique = devices.clone();
912    unique.sort_unstable();
913    unique.dedup();
914    if unique.len() != devices.len() {
915        return Err(format!(
916            "MEMRA_PARALLEL_DEVICES must be distinct, got {devices:?}"
917        ));
918    }
919    Ok(Some(devices))
920}
921
922pub fn auto_parallel_devices() -> Result<Option<Vec<usize>>, String> {
923    parse_auto_parallel_devices(
924        std::env::var("MEMRA_PARALLEL").ok().as_deref(),
925        std::env::var("MEMRA_PARALLEL_DEVICES").ok().as_deref(),
926    )
927}
928
929fn parse_parallel_ep_device_router(value: Option<&str>) -> Result<bool, String> {
930    match value {
931        None | Some("") | Some("0") => Ok(false),
932        Some("1") => Ok(true),
933        Some(value) => Err(format!(
934            "MEMRA_PARALLEL_EP_DEVICE_ROUTER={value:?} is invalid; expected 0 or 1"
935        )),
936    }
937}
938
939pub fn parallel_ep_device_router_enabled() -> Result<bool, String> {
940    parse_parallel_ep_device_router(
941        std::env::var("MEMRA_PARALLEL_EP_DEVICE_ROUTER")
942            .ok()
943            .as_deref(),
944    )
945}
946
947fn parse_parallel_ep_graph(value: Option<&str>) -> Result<bool, String> {
948    match value {
949        None | Some("") | Some("0") => Ok(false),
950        Some("1") => Ok(true),
951        Some(value) => Err(format!(
952            "MEMRA_PARALLEL_EP_GRAPH={value:?} is invalid; expected 0 or 1"
953        )),
954    }
955}
956
957pub fn parallel_ep_graph_enabled() -> Result<bool, String> {
958    parse_parallel_ep_graph(std::env::var("MEMRA_PARALLEL_EP_GRAPH").ok().as_deref())
959}
960
961fn parse_parallel_ep_pair_down(value: Option<&str>) -> Result<bool, String> {
962    match value {
963        None | Some("") | Some("0") => Ok(false),
964        Some("1") => Ok(true),
965        Some(value) => Err(format!(
966            "MEMRA_PARALLEL_EP_PAIR_DOWN={value:?} is invalid; expected 0 or 1"
967        )),
968    }
969}
970
971pub fn parallel_ep_pair_down_enabled() -> Result<bool, String> {
972    parse_parallel_ep_pair_down(std::env::var("MEMRA_PARALLEL_EP_PAIR_DOWN").ok().as_deref())
973}
974
975fn parse_parallel_ep_q8_act(value: Option<&str>) -> Result<bool, String> {
976    match value {
977        None | Some("") | Some("0") => Ok(false),
978        Some("1") => Ok(true),
979        Some(value) => Err(format!(
980            "MEMRA_PARALLEL_EP_Q8_ACT={value:?} is invalid; expected 0 or 1"
981        )),
982    }
983}
984
985pub fn parallel_ep_q8_act_enabled() -> Result<bool, String> {
986    parse_parallel_ep_q8_act(std::env::var("MEMRA_PARALLEL_EP_Q8_ACT").ok().as_deref())
987}
988
989#[derive(Clone, Copy, Debug, PartialEq, Eq)]
990pub(crate) enum ParallelEpQ8Scope {
991    All,
992    GateUp,
993    Down,
994}
995
996impl ParallelEpQ8Scope {
997    fn label(self) -> &'static str {
998        match self {
999            Self::All => "all",
1000            Self::GateUp => "gate-up",
1001            Self::Down => "down",
1002        }
1003    }
1004}
1005
1006fn parse_parallel_ep_q8_scope(value: Option<&str>) -> Result<Option<ParallelEpQ8Scope>, String> {
1007    match value {
1008        None | Some("") => Ok(None),
1009        Some("all") => Ok(Some(ParallelEpQ8Scope::All)),
1010        Some("gate-up") => Ok(Some(ParallelEpQ8Scope::GateUp)),
1011        Some("down") => Ok(Some(ParallelEpQ8Scope::Down)),
1012        Some(value) => Err(format!(
1013            "MEMRA_PARALLEL_EP_Q8_SCOPE={value:?} is invalid; expected all, gate-up, or down"
1014        )),
1015    }
1016}
1017
1018pub(crate) fn parallel_ep_q8_scope() -> Result<Option<ParallelEpQ8Scope>, String> {
1019    parse_parallel_ep_q8_scope(std::env::var("MEMRA_PARALLEL_EP_Q8_SCOPE").ok().as_deref())
1020}
1021
1022fn parse_parallel_ep_q8_gu_paired(value: Option<&str>) -> Result<Option<bool>, String> {
1023    match value {
1024        None | Some("") => Ok(None),
1025        Some("0") => Ok(Some(false)),
1026        Some("1") => Ok(Some(true)),
1027        Some(value) => Err(format!(
1028            "MEMRA_PARALLEL_EP_Q8_GU_PAIRED={value:?} is invalid; expected 0 or 1"
1029        )),
1030    }
1031}
1032
1033fn resolve_parallel_ep_q8_gu_paired(
1034    value: Option<&str>,
1035    q8_active: bool,
1036    scope: Option<ParallelEpQ8Scope>,
1037) -> Result<bool, String> {
1038    let configured = parse_parallel_ep_q8_gu_paired(value)?;
1039    if configured == Some(true) && !q8_active {
1040        return Err("MEMRA_PARALLEL_EP_Q8_GU_PAIRED=1 requires MEMRA_PARALLEL_EP_Q8_ACT=1".into());
1041    }
1042    if configured == Some(true) && scope == Some(ParallelEpQ8Scope::Down) {
1043        return Err(
1044            "MEMRA_PARALLEL_EP_Q8_GU_PAIRED=1 requires Q8 gate/up arithmetic; \
1045             MEMRA_PARALLEL_EP_Q8_SCOPE=down keeps gate/up BF16"
1046                .into(),
1047        );
1048    }
1049    Ok(q8_active && scope != Some(ParallelEpQ8Scope::Down) && configured.unwrap_or(true))
1050}
1051
1052pub(crate) fn parallel_ep_q8_gu_paired_enabled(
1053    q8_active: bool,
1054    scope: Option<ParallelEpQ8Scope>,
1055) -> Result<bool, String> {
1056    resolve_parallel_ep_q8_gu_paired(
1057        std::env::var("MEMRA_PARALLEL_EP_Q8_GU_PAIRED")
1058            .ok()
1059            .as_deref(),
1060        q8_active,
1061        scope,
1062    )
1063}
1064
1065fn parse_step_layer_specs(
1066    flag: &str,
1067    value: Option<&str>,
1068    allow_full_model: bool,
1069) -> Result<Vec<StepEpLayerSpec>, String> {
1070    let trunk = allow_full_model.then_some(STEP37_TRUNK_LAYERS);
1071    parse_layer_specs_for_trunk(flag, value, trunk)
1072}
1073
1074/// The pure composition-refusal law behind every parallel door's UNPROVEN-pair matrix
1075/// (hoisted from the glm5 TP door, lane/glm5-extract-general): the first armed flag in
1076/// `table` refuses by name, BEFORE any parallel CUDA state exists. Each family owns its
1077/// own TABLE of `(flag, why)` rows — the reasons are gate receipts, part of the law; a
1078/// pair unlocks only with its own composition gate (the primary flag's FLAGS.md row
1079/// carries the matrix). `armed` reports whether a flag is set to `"1"` (env in
1080/// production; a plain set in unit tests — the pattern keeps tests env-mutation-free).
1081pub(crate) fn refuse_door_composition(
1082    primary: &str,
1083    table: &[(&str, &str)],
1084    armed: impl Fn(&str) -> bool,
1085) -> Result<(), String> {
1086    for (flag, why) in table {
1087        if armed(flag) {
1088            return Err(format!(
1089                "{primary} + {flag}: unproven composition, refused ({why})"
1090            ));
1091        }
1092    }
1093    Ok(())
1094}
1095
1096/// The shared `LAYER[-LAYER]@DEVICE,DEVICE[;...]` grammar behind every per-layer parallel
1097/// door. `full_model_trunk` enables the `all` shorthand and names the trunk it expands to —
1098/// the caller's model contract owns that constant, never this parser (the step door passes
1099/// `STEP37_TRUNK_LAYERS`; the glm5 door passes its own trunk length at load time).
1100pub(crate) fn parse_layer_specs_for_trunk(
1101    flag: &str,
1102    value: Option<&str>,
1103    full_model_trunk: Option<usize>,
1104) -> Result<Vec<StepEpLayerSpec>, String> {
1105    let Some(value) = value else {
1106        return Ok(Vec::new());
1107    };
1108    if value.is_empty() || value == "0" {
1109        return Ok(Vec::new());
1110    }
1111
1112    let mut specs = Vec::new();
1113    for item in value.split(';') {
1114        let (layers, devices) = item.split_once('@').ok_or_else(|| {
1115            let layers = if full_model_trunk.is_some() {
1116                "LAYER[-LAYER] or all"
1117            } else {
1118                "LAYER[-LAYER]"
1119            };
1120            format!("{flag} must be {layers}@DEVICE,DEVICE[;...]")
1121        })?;
1122        let (first, last) = if layers == "all" {
1123            let Some(trunk) = full_model_trunk else {
1124                return Err(format!(
1125                    "{flag} does not support the full-model shorthand; assign routed layers \
1126                     explicitly"
1127                ));
1128            };
1129            (0, trunk - 1)
1130        } else {
1131            match layers.split_once('-') {
1132                Some((first, last)) => {
1133                    let first = first
1134                        .parse::<usize>()
1135                        .map_err(|_| format!("{flag} layer {first:?} is not an integer"))?;
1136                    let last = last
1137                        .parse::<usize>()
1138                        .map_err(|_| format!("{flag} layer {last:?} is not an integer"))?;
1139                    if first > last {
1140                        return Err(format!("{flag} layer range {first}-{last} is reversed"));
1141                    }
1142                    if last - first + 1 > 128 {
1143                        return Err(format!(
1144                            "{flag} layer range {first}-{last} exceeds the 128-layer parser cap"
1145                        ));
1146                    }
1147                    (first, last)
1148                }
1149                None => {
1150                    let layer = layers
1151                        .parse::<usize>()
1152                        .map_err(|_| format!("{flag} layer {layers:?} is not an integer"))?;
1153                    (layer, layer)
1154                }
1155            }
1156        };
1157        let devices = devices
1158            .split(',')
1159            .map(|device| {
1160                device
1161                    .parse::<usize>()
1162                    .map_err(|_| format!("{flag} device {device:?} is not an integer"))
1163            })
1164            .collect::<Result<Vec<_>, _>>()?;
1165        if !(2..=8).contains(&devices.len()) {
1166            return Err(format!(
1167                "{flag} requires 2..=8 devices, got {}",
1168                devices.len()
1169            ));
1170        }
1171        let mut unique = devices.clone();
1172        unique.sort_unstable();
1173        unique.dedup();
1174        if unique.len() != devices.len() {
1175            return Err(format!("{flag} devices must be distinct, got {devices:?}"));
1176        }
1177        for layer in first..=last {
1178            if specs
1179                .iter()
1180                .any(|existing: &StepEpLayerSpec| existing.layer == layer)
1181            {
1182                return Err(format!("{flag} assigns layer {layer} more than once"));
1183            }
1184            specs.push(StepEpLayerSpec {
1185                layer,
1186                devices: devices.clone(),
1187            });
1188        }
1189    }
1190    Ok(specs)
1191}
1192
1193pub fn parse_step_ep_layer_specs(value: Option<&str>) -> Result<Vec<StepEpLayerSpec>, String> {
1194    parse_step_layer_specs("MEMRA_STEP_EP", value, false)
1195}
1196
1197pub fn step_ep_layer_specs() -> Result<Vec<StepEpLayerSpec>, String> {
1198    parse_step_ep_layer_specs(std::env::var("MEMRA_STEP_EP").ok().as_deref())
1199}
1200
1201pub fn parse_step_tp_layer_specs(value: Option<&str>) -> Result<Vec<StepTpLayerSpec>, String> {
1202    parse_step_layer_specs("MEMRA_STEP_TP", value, true)
1203}
1204
1205pub fn step_tp_layer_specs() -> Result<Vec<StepTpLayerSpec>, String> {
1206    parse_step_tp_layer_specs(std::env::var("MEMRA_STEP_TP").ok().as_deref())
1207}
1208
1209#[derive(Clone, Copy)]
1210pub struct E4m3BlockMatrix<'a> {
1211    pub codes: &'a [u8],
1212    pub scales: &'a [f32],
1213    pub out_features: usize,
1214    pub in_features: usize,
1215}
1216
1217impl E4m3BlockMatrix<'_> {
1218    fn validate(&self) -> Result<(), String> {
1219        let code_count = self
1220            .out_features
1221            .checked_mul(self.in_features)
1222            .ok_or_else(|| "E4M3 matrix size overflow".to_string())?;
1223        if self.codes.len() != code_count {
1224            return Err(format!(
1225                "E4M3 code count {} != {}x{} ({code_count})",
1226                self.codes.len(),
1227                self.out_features,
1228                self.in_features,
1229            ));
1230        }
1231        let scale_count =
1232            self.out_features.div_ceil(FP8_BLOCK) * self.in_features.div_ceil(FP8_BLOCK);
1233        if self.scales.len() != scale_count {
1234            return Err(format!(
1235                "E4M3 scale count {} != {scale_count} for {}x{}",
1236                self.scales.len(),
1237                self.out_features,
1238                self.in_features,
1239            ));
1240        }
1241        if !self
1242            .scales
1243            .iter()
1244            .all(|scale| scale.is_finite() && *scale > 0.0)
1245        {
1246            return Err("E4M3 scale grid contains a non-finite or non-positive value".to_string());
1247        }
1248        Ok(())
1249    }
1250}
1251
1252#[derive(Clone, Copy)]
1253pub struct E4m3ExpertBank<'a> {
1254    pub codes: &'a [u8],
1255    pub scales: &'a [f32],
1256    pub expert_count: usize,
1257    pub out_features: usize,
1258    pub in_features: usize,
1259}
1260
1261impl E4m3ExpertBank<'_> {
1262    fn validate(&self) -> Result<(), String> {
1263        if self.expert_count == 0 {
1264            return Err("E4M3 expert bank is empty".to_string());
1265        }
1266        let code_stride = self
1267            .out_features
1268            .checked_mul(self.in_features)
1269            .ok_or_else(|| "E4M3 expert code stride overflow".to_string())?;
1270        let code_count = self
1271            .expert_count
1272            .checked_mul(code_stride)
1273            .ok_or_else(|| "E4M3 expert code count overflow".to_string())?;
1274        if self.codes.len() != code_count {
1275            return Err(format!(
1276                "E4M3 expert code count {} != {}x{} ({code_count})",
1277                self.codes.len(),
1278                self.expert_count,
1279                code_stride,
1280            ));
1281        }
1282        let scale_stride =
1283            self.out_features.div_ceil(FP8_BLOCK) * self.in_features.div_ceil(FP8_BLOCK);
1284        let scale_count = self
1285            .expert_count
1286            .checked_mul(scale_stride)
1287            .ok_or_else(|| "E4M3 expert scale count overflow".to_string())?;
1288        if self.scales.len() != scale_count {
1289            return Err(format!(
1290                "E4M3 expert scale count {} != {}x{} ({scale_count})",
1291                self.scales.len(),
1292                self.expert_count,
1293                scale_stride,
1294            ));
1295        }
1296        if !self
1297            .scales
1298            .iter()
1299            .all(|scale| scale.is_finite() && *scale > 0.0)
1300        {
1301            return Err(
1302                "E4M3 expert scale grid contains a non-finite or non-positive value".to_string(),
1303            );
1304        }
1305        Ok(())
1306    }
1307
1308    pub fn expert(&self, expert: usize) -> Result<E4m3BlockMatrix<'_>, String> {
1309        if expert >= self.expert_count {
1310            return Err(format!("expert {expert} outside 0..{}", self.expert_count));
1311        }
1312        let code_stride = self.out_features * self.in_features;
1313        let scale_stride =
1314            self.out_features.div_ceil(FP8_BLOCK) * self.in_features.div_ceil(FP8_BLOCK);
1315        Ok(E4m3BlockMatrix {
1316            codes: &self.codes[expert * code_stride..(expert + 1) * code_stride],
1317            scales: &self.scales[expert * scale_stride..(expert + 1) * scale_stride],
1318            out_features: self.out_features,
1319            in_features: self.in_features,
1320        })
1321    }
1322}
1323
1324pub struct ColumnParallelResult {
1325    pub gathered: Vec<f32>,
1326    pub rank_outputs: Vec<Vec<f32>>,
1327}
1328
1329pub struct RowParallelResult {
1330    pub reduced: Vec<f32>,
1331    pub rank_partials: Vec<Vec<f32>>,
1332}
1333
1334#[derive(Clone, Copy)]
1335pub struct Bf16Matrix<'a> {
1336    pub bytes: &'a [u8],
1337    pub out_features: usize,
1338    pub in_features: usize,
1339}
1340
1341impl Bf16Matrix<'_> {
1342    pub fn validate(&self) -> Result<(), String> {
1343        if self.out_features == 0 || self.in_features == 0 {
1344            return Err("BF16 matrix dimensions must be nonzero".into());
1345        }
1346        let expected = self
1347            .out_features
1348            .checked_mul(self.in_features)
1349            .and_then(|values| values.checked_mul(2))
1350            .ok_or("BF16 matrix byte count overflow")?;
1351        if self.bytes.len() != expected {
1352            return Err(format!(
1353                "BF16 matrix bytes {} != {}x{}x2 ({expected})",
1354                self.bytes.len(),
1355                self.out_features,
1356                self.in_features,
1357            ));
1358        }
1359        Ok(())
1360    }
1361}
1362
1363struct ResidentE4m3Rank {
1364    codes: CudaSlice<u8>,
1365    scales: CudaSlice<f32>,
1366    out_features: usize,
1367    in_features: usize,
1368}
1369
1370enum ResidentBf16Weight {
1371    Bf16(CudaSlice<u8>),
1372    F32(CudaSlice<f32>),
1373}
1374
1375impl ResidentBf16Weight {
1376    fn ordinal(&self) -> usize {
1377        match self {
1378            Self::Bf16(bytes) => bytes.ordinal(),
1379            Self::F32(values) => values.ordinal(),
1380        }
1381    }
1382}
1383
1384struct ResidentBf16Rank {
1385    weight: ResidentBf16Weight,
1386    out_features: usize,
1387    in_features: usize,
1388    /// q8_0 mirror built at load under MEMRA_STEP_TP_W8 (numeric-class door; the bf16 slab
1389    /// stays resident because every prefill/verify path is qualified against it).
1390    q8: Option<CudaSlice<u8>>,
1391}
1392
1393pub struct ResidentColumnParallel {
1394    ranks: Vec<ResidentE4m3Rank>,
1395    out_features: usize,
1396    in_features: usize,
1397}
1398
1399pub struct ResidentRowParallel {
1400    ranks: Vec<ResidentE4m3Rank>,
1401    out_features: usize,
1402    in_features: usize,
1403}
1404
1405pub struct ResidentBf16ColumnParallel {
1406    ranks: Vec<ResidentBf16Rank>,
1407    out_features: usize,
1408    in_features: usize,
1409    canonical_chunk_rows: Option<usize>,
1410}
1411
1412pub struct ResidentBf16RowParallel {
1413    ranks: Vec<ResidentBf16Rank>,
1414    out_features: usize,
1415    in_features: usize,
1416}
1417
1418pub struct ResidentStepBf16RowParallel {
1419    ranks: Vec<Vec<ResidentBf16Rank>>,
1420    out_features: usize,
1421    in_features: usize,
1422    canonical_chunk_cols: usize,
1423}
1424
1425/// Root-owned BF16 sigmoid router with persistent F32 weight, bias, and active mask.
1426pub struct ResidentSigmoidTopKRouter {
1427    weight: CudaSlice<f32>,
1428    correction_bias: CudaSlice<f32>,
1429    active: CudaSlice<u8>,
1430    root_device: usize,
1431    input_width: usize,
1432    expert_count: usize,
1433    experts_per_token: usize,
1434    active_count: usize,
1435    scaling_factor: f32,
1436    route_norm: bool,
1437}
1438
1439pub struct SigmoidTopKHostOutput {
1440    pub logits: Vec<f32>,
1441    pub selected: Vec<u32>,
1442    pub weights: Vec<f32>,
1443}
1444
1445/// Full BF16 SwiGLU weights replicated independently on every runtime rank.
1446pub struct ResidentReplicatedBf16SwiGlu {
1447    gate: Vec<ResidentBf16Rank>,
1448    up: Vec<ResidentBf16Rank>,
1449    down: Vec<ResidentBf16Rank>,
1450    input_width: usize,
1451    intermediate_width: usize,
1452}
1453
1454/// One token-major F32 batch replicated across a native-P2P rank group.
1455///
1456/// Every allocation is owned by its matching rank CUDA context. This is the generic handoff
1457/// substrate between independently sharded operators; it carries no model or topology claim.
1458pub struct ResidentReplicatedDeviceRows {
1459    ranks: Vec<CudaSlice<f32>>,
1460    tokens: usize,
1461    width: usize,
1462}
1463
1464impl ResidentReplicatedDeviceRows {
1465    pub fn tokens(&self) -> usize {
1466        self.tokens
1467    }
1468
1469    pub fn width(&self) -> usize {
1470        self.width
1471    }
1472
1473    pub fn ranks(&self) -> usize {
1474        self.ranks.len()
1475    }
1476}
1477
1478/// Canonical MoE output order: routed plus shared, then add the layer residual.
1479pub fn moe_residual_host(
1480    residual: &[f32],
1481    routed: &[f32],
1482    shared: &[f32],
1483) -> Result<Vec<f32>, String> {
1484    if residual.len() != routed.len() || residual.len() != shared.len() {
1485        return Err(format!(
1486            "MoE residual lengths residual={} routed={} shared={}",
1487            residual.len(),
1488            routed.len(),
1489            shared.len()
1490        ));
1491    }
1492    let ffn = routed
1493        .iter()
1494        .zip(shared)
1495        .map(|(&routed, &shared)| routed + shared)
1496        .collect::<Vec<_>>();
1497    Ok(residual
1498        .iter()
1499        .zip(ffn)
1500        .map(|(&residual, ffn)| residual + ffn)
1501        .collect())
1502}
1503
1504pub use memra_kv::{
1505    KvRingAppend, ResidentTpKvCache, ResidentTpKvCacheRank, TpKvAppendPlan, TpKvTransaction,
1506};
1507
1508/// Persistent TP2/TP4/TP8 routed-expert reference.
1509///
1510/// Rank-local checkpoint shards are uploaded once and remain tied to their owning CUDA context.
1511/// Activations and deterministic host-staged collectives remain per invocation. This is the
1512/// correctness substrate for serving TP/EP, not product-throughput evidence.
1513pub struct ResidentTpExpert {
1514    gate: ResidentColumnParallel,
1515    up: ResidentColumnParallel,
1516    down: ResidentRowParallel,
1517    input_width: usize,
1518    expert_width: usize,
1519}
1520
1521struct ResidentE4m3ExpertBankRank {
1522    codes: CudaSlice<u8>,
1523    scales: CudaSlice<f32>,
1524    expert_range: Range<usize>,
1525    out_features: usize,
1526    in_features: usize,
1527    code_stride: usize,
1528    scale_stride: usize,
1529    /// TP row banks are packed by native 128-wide K block so reduction can replay the
1530    /// checkpoint's global block order exactly. Other banks remain row-major.
1531    k_blocks: Option<usize>,
1532}
1533
1534struct PackedE4m3ExpertBankRank {
1535    codes: Vec<u8>,
1536    scales: Vec<f32>,
1537    expert_range: Range<usize>,
1538    out_features: usize,
1539    in_features: usize,
1540    code_stride: usize,
1541    scale_stride: usize,
1542    k_blocks: Option<usize>,
1543}
1544
1545struct ResidentEpRank {
1546    gate: ResidentE4m3ExpertBankRank,
1547    up: ResidentE4m3ExpertBankRank,
1548    down: ResidentE4m3ExpertBankRank,
1549}
1550
1551/// Persistent expert-parallel reference.
1552///
1553/// Every routed expert has exactly one owner rank. Shared experts are deliberately absent from
1554/// this object because Step replicates them per rank. Routes execute on the owner CUDA context.
1555/// The default oracle stages through host memory; the native path peer-dispatches inputs and
1556/// peer-returns owner outputs while preserving host-canonical activation and accumulation.
1557pub struct ResidentExpertParallel {
1558    ranks: Vec<ResidentEpRank>,
1559    expert_count: usize,
1560    input_width: usize,
1561    expert_width: usize,
1562}
1563
1564/// Projection-level output from the opt-in official Step grouped-FP8 gate.
1565///
1566/// Rows remain pair-major. Routing, weighted combine, and production integration are deliberately
1567/// outside this gate-only adapter.
1568pub struct StepGroupedFp8ProjectionOutput {
1569    pub gate: Vec<f32>,
1570    pub up: Vec<f32>,
1571    pub down: Vec<f32>,
1572}
1573
1574/// Prepared official Step grouped-FP8 projection gate.
1575///
1576/// The complete tensor banks, both CSR schedules, input, activation buffer, and three projection
1577/// workspaces are uploaded or allocated once. Repeated execution performs no device allocation.
1578pub struct PreparedStepGroupedFp8Gate {
1579    device: usize,
1580    gate: ResidentE4m3ExpertBankRank,
1581    up: ResidentE4m3ExpertBankRank,
1582    down: ResidentE4m3ExpertBankRank,
1583    input: CudaSlice<f32>,
1584    route_csr: DeviceExpertCsr,
1585    down_csr: DeviceExpertCsr,
1586    gate_workspace: Fp8GroupedWorkspace,
1587    up_workspace: Fp8GroupedWorkspace,
1588    down_workspace: Fp8GroupedWorkspace,
1589    activation: CudaSlice<f32>,
1590    activation_limit: Option<f32>,
1591    tokens: usize,
1592    pairs: usize,
1593}
1594
1595impl PreparedStepGroupedFp8Gate {
1596    pub fn tokens(&self) -> usize {
1597        self.tokens
1598    }
1599
1600    pub fn pairs(&self) -> usize {
1601        self.pairs
1602    }
1603}
1604
1605struct PreparedStepGroupedExpertOwner {
1606    rank: usize,
1607    global_pairs: Vec<usize>,
1608    route_csr: DeviceExpertCsr,
1609    down_csr: DeviceExpertCsr,
1610    gate_workspace: Fp8GroupedWorkspace,
1611    up_workspace: Fp8GroupedWorkspace,
1612    down_workspace: Fp8GroupedWorkspace,
1613    activation: CudaSlice<f32>,
1614}
1615
1616struct StepGroupedExpertOwnerSchedule {
1617    global_pairs: Vec<usize>,
1618    route_csr: ExpertCsr,
1619    down_csr: ExpertCsr,
1620}
1621
1622/// Prepared official Step expert-owner grouped-FP8 projection gate.
1623///
1624/// Route partitioning, owner-local CSR uploads, input dispatch, activation buffers, and grouped
1625/// workspaces are persistent. Projection rows are scattered back to canonical pair order only
1626/// after every owner has completed its rank-local program.
1627pub struct PreparedStepGroupedExpertParallelGate {
1628    rank_inputs: Vec<CudaSlice<f32>>,
1629    owners: Vec<PreparedStepGroupedExpertOwner>,
1630    activation_limit: Option<f32>,
1631    tokens: usize,
1632    pairs: usize,
1633    max_tokens: usize,
1634    max_pairs: usize,
1635    input_width: usize,
1636    expert_width: usize,
1637    generation: u64,
1638    executed_generation: Option<u64>,
1639    ready: bool,
1640}
1641
1642impl PreparedStepGroupedExpertParallelGate {
1643    pub fn tokens(&self) -> usize {
1644        self.tokens
1645    }
1646
1647    pub fn pairs(&self) -> usize {
1648        self.pairs
1649    }
1650
1651    pub fn max_tokens(&self) -> usize {
1652        self.max_tokens
1653    }
1654
1655    pub fn input_width(&self) -> usize {
1656        self.input_width
1657    }
1658
1659    pub fn expert_width(&self) -> usize {
1660        self.expert_width
1661    }
1662
1663    pub fn set_activation_limit(&mut self, limit: Option<f32>) -> Result<(), String> {
1664        validate_step_expert_activation_limit(limit)?;
1665        self.activation_limit = limit;
1666        self.executed_generation = None;
1667        Ok(())
1668    }
1669
1670    pub fn active_owners(&self) -> usize {
1671        self.owners
1672            .iter()
1673            .filter(|owner| !owner.global_pairs.is_empty())
1674            .count()
1675    }
1676
1677    pub fn owner_pair_counts(&self) -> Vec<usize> {
1678        self.owners
1679            .iter()
1680            .map(|owner| owner.global_pairs.len())
1681            .collect()
1682    }
1683
1684    pub fn generation(&self) -> u64 {
1685        self.generation
1686    }
1687}
1688
1689struct PreparedPeerWeightedRouteOwner {
1690    token_rows: CudaSlice<i32>,
1691    slots: CudaSlice<i32>,
1692    weights: CudaSlice<f32>,
1693    active_pairs: usize,
1694}
1695
1696/// Persistent root-side weighted combine for peer-owned canonical route rows.
1697///
1698/// Owner metadata, one reusable peer staging buffer, the canonical slot bank, weight bank, and
1699/// output are allocated once. Refreshes update metadata prefixes; execution peer-copies active
1700/// rows, scatters them by canonical token/slot, and reduces in the requested numeric order.
1701pub struct PreparedPeerWeightedRouteCombine {
1702    root_device: usize,
1703    owners: Vec<PreparedPeerWeightedRouteOwner>,
1704    peer_staging: CudaSlice<f32>,
1705    slots: CudaSlice<f32>,
1706    weights: CudaSlice<f32>,
1707    output: CudaSlice<f32>,
1708    peer_devices: Vec<usize>,
1709    peer_outputs: Vec<CudaSlice<f32>>,
1710    width: usize,
1711    experts_per_token: usize,
1712    max_tokens: usize,
1713    max_pairs: usize,
1714    tokens: usize,
1715    pairs: usize,
1716    projection_generation: u64,
1717    output_generation: Option<u64>,
1718    broadcast_generation: Option<u64>,
1719    ready: bool,
1720}
1721
1722impl PreparedPeerWeightedRouteCombine {
1723    pub fn tokens(&self) -> usize {
1724        self.tokens
1725    }
1726
1727    pub fn pairs(&self) -> usize {
1728        self.pairs
1729    }
1730
1731    pub fn owner_pair_counts(&self) -> Vec<usize> {
1732        self.owners.iter().map(|owner| owner.active_pairs).collect()
1733    }
1734
1735    pub fn distributed_ranks(&self) -> usize {
1736        1 + self.peer_outputs.len()
1737    }
1738}
1739
1740struct ResidentTpExpertBank {
1741    gate: Vec<ResidentE4m3ExpertBankRank>,
1742    up: Vec<ResidentE4m3ExpertBankRank>,
1743    down: Vec<ResidentE4m3ExpertBankRank>,
1744    expert_count: usize,
1745    input_width: usize,
1746    expert_width: usize,
1747}
1748
1749/// Persistent tensor-parallel expert bank.
1750///
1751/// Every rank owns a checkpoint-aligned output-row shard of every gate/up projection and an
1752/// input-column shard of every down projection. Activations cross deterministic host-staged
1753/// collectives on hosts where native peer copies are unavailable or corrupt.
1754pub struct ResidentTensorParallel {
1755    bank: ResidentTpExpertBank,
1756}
1757
1758/// Multi-context TP correctness runtime. Each rank owns an independent `Engine` and CUDA context.
1759///
1760/// Host bounce is the default oracle. Native P2P is opt-in and preserves the oracle's global
1761/// checkpoint-block reduction order; it remains a correctness path until serving gates and
1762/// repeated performance evidence qualify it.
1763pub struct TpE4m3HostBounce {
1764    devices: Vec<usize>,
1765    ranks: Vec<Engine>,
1766    native_p2p: bool,
1767    ep_device_arithmetic: bool,
1768    bulk_p2p: bool,
1769    /// v2 decode-attention workspace (MEMRA_STEP_TP_DECODE_V2). One per runtime, shared by
1770    /// every TP attention layer — the buffer shapes are geometry-constant across the trunk.
1771    decode_v2: std::sync::Mutex<Vec<StepTpDecodeV2Ws>>,
1772}
1773
1774/// Persistent workspace of the v2 rank-local decode-attention driver.
1775///
1776/// Buffers live in their producing rank's CUDA context, are never freed, and events are
1777/// re-recorded per call — the pp.rs `BoundarySlot` discipline — so the per-token path has no
1778/// cuMemAlloc, no cross-stream free, and no host round-trip. Every buffer is fully overwritten
1779/// before its consumers run in the same call; nothing carries state between tokens.
1780/// Per-rank attn_gate row shards for the fused QKV+gate kernel, in the weight class the
1781/// fused kernels read (F32 mirror or raw checkpoint bf16).
1782pub enum StepTpGateShards<'a> {
1783    F32(&'a [crate::CudaSlice<f32>]),
1784    Bf16(&'a [crate::CudaSlice<u8>]),
1785}
1786
1787pub struct StepTpDecodeV2Ws {
1788    /// T-COLUMN verify slabs (spec MTP): per-rank [t, local_dim] projections computed by
1789    /// the weight-amortized qkvg_tcol kernel; the col-select door copies one column into
1790    /// the single-row buffers and everything downstream runs the unmodified t=1 program.
1791    pub(crate) tcol_q: Vec<CudaSlice<f32>>,
1792    pub(crate) tcol_k: Vec<CudaSlice<f32>>,
1793    pub(crate) tcol_v: Vec<CudaSlice<f32>>,
1794    pub(crate) tcol_g: Vec<CudaSlice<f32>>,
1795    pub(crate) tcol_in: Vec<CudaSlice<f32>>,
1796    pub(crate) tcol_cap: usize,
1797    /// MEMRA_STEP_TP_W8 activation scratch: per-rank q8_1 quantized attention input
1798    /// ([in_f] i8 + one f32 scale pair per 32). Persistent because the alternative is an
1799    /// allocation per rank per layer per token.
1800    w8_aq: Vec<CudaSlice<i8>>,
1801    w8_ad: Vec<CudaSlice<f32>>,
1802    w8_in: usize,
1803    /// o_proj-side twin of the same scratch (its activation is the gated attention output,
1804    /// a different vector from the QKV input, so it needs its own buffers).
1805    w8o_aq: Vec<CudaSlice<i8>>,
1806    w8o_ad: Vec<CudaSlice<f32>>,
1807    w8o_in: usize,
1808    /// VERIFY-WALK q8_1 activation scratch, t columns wide (the decode scratch above is one
1809    /// row). Two sets because the QKV input and the gated attention output are different
1810    /// vectors of different widths.
1811    w8t_aq: Vec<CudaSlice<i8>>,
1812    w8t_ad: Vec<CudaSlice<f32>>,
1813    w8t_in: usize,
1814    w8t_oaq: Vec<CudaSlice<i8>>,
1815    w8t_oad: Vec<CudaSlice<f32>>,
1816    w8t_oin: usize,
1817    w8t_cap: usize,
1818    /// MEMRA_TCOL_OPROJ slabs: per-rank stashed `gated` rows ([8, local_q_dim]), per-rank
1819    /// b4_tcol partials ([8, o_out]), a root-side peer pull of rank1's partial slab, and
1820    /// the root-side joined `mixed` slab. Armed lazily by the first stash.
1821    /// MEMRA_SPEC_FA2 slabs: per-rank stashed post-rope q rows ([2, local_q_dim]), gate
1822    /// rows ([2, heads/ranks]) and the two gated outputs the per-row combine writes
1823    /// ([2, local_q_dim]). Armed lazily by the first stash.
1824    pub(crate) fa2_q: Vec<CudaSlice<f32>>,
1825    pub(crate) fa2_gate: Vec<CudaSlice<f32>>,
1826    pub(crate) fa2_gated: Vec<CudaSlice<f32>>,
1827    pub(crate) fa2_cap: usize,
1828    /// T-ROW rope/append twin scratch: per-rank roped-k rows ([8, local_kv]), per-row
1829    /// last-block counters ([8]) and the per-tick position slab ([8]). Armed with the
1830    /// fa2 slabs.
1831    rope_k_t: Vec<CudaSlice<f32>>,
1832    rope_ctr_t: Vec<CudaSlice<u32>>,
1833    rope_pos_t: Vec<CudaSlice<i32>>,
1834    /// Per-rank combined 6-word row tables, keyed by the caller's (layer, session-set,
1835    /// base-arming) signature. LEGACY: only the `MEMRA_ROWS_TAB_RESTAGE=0` rollback arm
1836    /// reads this. See `rows_tab_t` for why the key cannot be made safe.
1837    rows_tabs: Vec<std::collections::HashMap<u64, CudaSlice<u64>>>,
1838    /// Per-rank PERSISTENT 6-word row-table slab ([32, 6] u64), RESTAGED from the live
1839    /// distributed cache before every launch. Replaces the `rows_tabs` memo, whose key was
1840    /// a hash of (k pointer, base pointer, layer, t) while the table it returned also
1841    /// carried the V and LEN pointers: a session whose K buffer address was recycled hit
1842    /// another session's table and the append kernel wrote its K/V through the FREED
1843    /// pointers the entry still held. Same defect and same cure as the row-table twin in
1844    /// `step35_verify_fa_rows_join` (8c8397e0b2, Hermes `11339f5cd3c132a3`), which this
1845    /// path was left out of. One 32-word htod per rank per layer replaces the map lookup;
1846    /// no allocation, and the staging is stream-ordered exactly like `rope_pos_t`.
1847    rows_tab_t: Vec<CudaSlice<u64>>,
1848    /// HOST shadow of the last table staged under each retired memo key, used ONLY by
1849    /// `MEMRA_ROWS_TAB_STALE_SCAN=1` to prove that the retired key would have handed a live
1850    /// launch another allocation's pointers. Never read by a kernel.
1851    rows_tab_shadow: Vec<std::collections::HashMap<u64, Vec<u64>>>,
1852    tcol_gated: Vec<CudaSlice<f32>>,
1853    tcol_opart: Vec<CudaSlice<f32>>,
1854    tcol_opeer: Option<CudaSlice<f32>>,
1855    tcol_omix: Option<CudaSlice<f32>>,
1856    tcol_ocap: usize,
1857    // rank-context buffers, indexed by rank (pub(crate): the v2 driver in hybrid_forward
1858    // feeds them to the KV transaction and attention kernels between the two v2 phases)
1859    pub(crate) q_raw: Vec<CudaSlice<f32>>,
1860    pub(crate) k_raw: Vec<CudaSlice<f32>>,
1861    pub(crate) v_raw: Vec<CudaSlice<f32>>,
1862    pub(crate) q: Vec<CudaSlice<f32>>,
1863    pub(crate) k: Vec<CudaSlice<f32>>,
1864    pub(crate) pos: Vec<CudaSlice<i32>>,
1865    /// FUSION #1 last-block counters (one per rank; atomicInc auto-resets per launch).
1866    pub(crate) fuse_ctr: Vec<CudaSlice<u32>>,
1867    pub(crate) gate: Vec<CudaSlice<f32>>,
1868    pub(crate) attn_out: Vec<CudaSlice<f32>>,
1869    pub(crate) gated: Vec<CudaSlice<f32>>,
1870    /// [rank][block] O partials, each `o_out` wide, in the owning rank's context.
1871    o_partials: Vec<Vec<CudaSlice<f32>>>,
1872    /// Stable workspace pointers for the rank-done-fenced raw P2P gather. Safe
1873    /// `memcpy_dtod` creates a fresh source event for every cross-context copy; the v2
1874    /// driver already records one persistent `ev_rank` after all three source families.
1875    raw_o_partials: Vec<Vec<u64>>,
1876    raw_k: Vec<u64>,
1877    raw_v_raw: Vec<u64>,
1878    /// Recorded on each rank's stream after its per-call work; root waits before peer reads.
1879    ev_rank: Vec<CudaEvent>,
1880    // root-context buffers
1881    peer_partial: CudaSlice<f32>,
1882    reduce_a: CudaSlice<f32>,
1883    reduce_b: CudaSlice<f32>,
1884    /// Never written; the canonical zero start of the v1 add chain.
1885    zeros: CudaSlice<f32>,
1886    pub(crate) k_shadow: CudaSlice<f32>,
1887    pub(crate) v_shadow: CudaSlice<f32>,
1888    ev_refresh: CudaEvent,
1889    ev_oproj: CudaEvent,
1890    // model-engine (e) context
1891    gate_e: CudaSlice<f32>,
1892    /// Per-token stages (e-ctx, fixed addresses): one eager e-stream copy each per layer; the
1893    /// rank flows raw-copy FROM them, which is exactly the shape graph capture needs.
1894    pub(crate) h_stage: Option<CudaSlice<f32>>,
1895    pub(crate) pos_stage: Option<CudaSlice<i32>>,
1896    /// Workspace-owned per-rank attention input rows (the stage flow copies into THESE, not
1897    /// the per-layer decode_input buffers — the workspace is shared across layers, so every
1898    /// captured/raw address it uses must be layer-invariant).
1899    attn_in: Vec<CudaSlice<f32>>,
1900    /// Cached raw pointers of the stage-flow operands (set when the stages arm).
1901    raw_h_stage: u64,
1902    raw_pos_stage: u64,
1903    raw_attn_in: Vec<u64>,
1904    raw_pos: Vec<u64>,
1905    raw_o_partial1: u64,
1906    raw_peer_partial: u64,
1907    raw_k1: u64,
1908    raw_v1: u64,
1909    raw_k_shadow: u64,
1910    raw_v_shadow: u64,
1911    /// Token-graph e-context mirrors (armed by the orchestrator): the root section
1912    /// raw-copies the reduced attention output and the shadow rows here so the e-glue
1913    /// children read same-context memory (cross-context kernel args are capture-illegal).
1914    raw_mixed_stage_e: u64,
1915    raw_reduce_a: u64,
1916    raw_shadow_stage_e: (u64, u64),
1917    ev_entry: CudaEvent,
1918    e_device: usize,
1919    // geometry pins
1920    local_q_dim: usize,
1921    local_kv_dim: usize,
1922    heads: usize,
1923    pub(crate) o_out: usize,
1924    o_block_cols: usize,
1925    blocks_per_rank: usize,
1926}
1927
1928impl TpE4m3HostBounce {
1929    pub fn new(devices: &[usize]) -> Result<Self, Box<dyn std::error::Error>> {
1930        Self::new_inner(devices, false, false, false, false)
1931    }
1932
1933    pub fn new_native_p2p(devices: &[usize]) -> Result<Self, Box<dyn std::error::Error>> {
1934        Self::new_inner(devices, false, true, false, false)
1935    }
1936
1937    pub fn new_native_p2p_device_arithmetic(
1938        devices: &[usize],
1939    ) -> Result<Self, Box<dyn std::error::Error>> {
1940        Self::new_inner(devices, false, true, true, false)
1941    }
1942
1943    pub(crate) fn new_configured(
1944        devices: &[usize],
1945        native_p2p: bool,
1946        ep_device_arithmetic: bool,
1947        bulk_p2p: bool,
1948    ) -> Result<Self, Box<dyn std::error::Error>> {
1949        Self::new_inner(devices, false, native_p2p, ep_device_arithmetic, bulk_p2p)
1950    }
1951
1952    /// Single-rank execution of the canonical checkpoint-block TP program.
1953    ///
1954    /// This is an oracle for distributed exactness, not a serving topology. It lets gates compare
1955    /// TP=1 and TP>1 with the same packing, kernel launches, and deterministic reduction order.
1956    pub fn new_single_rank_oracle(device: usize) -> Result<Self, Box<dyn std::error::Error>> {
1957        Self::new_inner(&[device], true, false, false, false)
1958    }
1959
1960    fn new_inner(
1961        devices: &[usize],
1962        allow_single_rank: bool,
1963        native_p2p: bool,
1964        ep_device_arithmetic: bool,
1965        bulk_p2p: bool,
1966    ) -> Result<Self, Box<dyn std::error::Error>> {
1967        if ep_device_arithmetic && !native_p2p {
1968            return Err("device-resident EP arithmetic requires native P2P".into());
1969        }
1970        if bulk_p2p && !native_p2p {
1971            return Err("bulk TP transport requires native P2P".into());
1972        }
1973        let minimum = if allow_single_rank { 1 } else { 2 };
1974        if !(minimum..=8).contains(&devices.len()) {
1975            return Err(format!(
1976                "TP reference requires {minimum}..=8 devices, got {}",
1977                devices.len()
1978            )
1979            .into());
1980        }
1981        let mut unique = devices.to_vec();
1982        unique.sort_unstable();
1983        unique.dedup();
1984        if unique.len() != devices.len() {
1985            return Err(format!("TP devices must be distinct, got {devices:?}").into());
1986        }
1987        let ranks = devices
1988            .iter()
1989            .map(|&device| Engine::new(device))
1990            .collect::<Result<Vec<_>, _>>()?;
1991        if native_p2p {
1992            configure_native_p2p(&ranks, devices)?;
1993        }
1994        if allow_single_rank {
1995            eprintln!(
1996                "[tp] canonical oracle transport=local device={} performance_claim=false",
1997                devices[0]
1998            );
1999        } else if native_p2p {
2000            if ep_device_arithmetic {
2001                eprintln!(
2002                    "[tp] correctness transport=native-p2p devices={devices:?} \
2003                     native_p2p=true activation=device-host-exact \
2004                     accumulation=device-host-exact output=root-readback \
2005                     bulk_p2p={bulk_p2p} performance_claim=false"
2006                );
2007            } else {
2008                eprintln!(
2009                    "[tp] correctness transport=native-p2p devices={devices:?} \
2010                     native_p2p=true activation=host-canonical bulk_p2p={bulk_p2p} \
2011                     performance_claim=false"
2012                );
2013            }
2014        } else {
2015            eprintln!(
2016                "[tp] correctness transport=host-bounce devices={devices:?} \
2017                 native_p2p=false performance_claim=false"
2018            );
2019        }
2020        Ok(Self {
2021            devices: devices.to_vec(),
2022            ranks,
2023            native_p2p,
2024            ep_device_arithmetic,
2025            bulk_p2p,
2026            decode_v2: std::sync::Mutex::new(Vec::new()),
2027        })
2028    }
2029
2030    pub fn devices(&self) -> &[usize] {
2031        &self.devices
2032    }
2033
2034    pub fn native_p2p(&self) -> bool {
2035        self.native_p2p
2036    }
2037
2038    pub fn bulk_p2p(&self) -> bool {
2039        self.bulk_p2p
2040    }
2041
2042    pub fn expert_activation_label(&self) -> &'static str {
2043        if self.ep_device_arithmetic {
2044            "device-host-exact"
2045        } else {
2046            "host-canonical"
2047        }
2048    }
2049
2050    pub fn expert_accumulation_label(&self) -> &'static str {
2051        self.expert_activation_label()
2052    }
2053
2054    pub fn expert_output_label(&self) -> &'static str {
2055        if self.ep_device_arithmetic {
2056            "root-readback"
2057        } else {
2058            "host-accumulated"
2059        }
2060    }
2061
2062    pub fn transport_label(&self) -> &'static str {
2063        if self.devices.len() == 1 {
2064            "local"
2065        } else if self.native_p2p {
2066            "native-p2p"
2067        } else {
2068            "host-bounce"
2069        }
2070    }
2071
2072    pub fn device_names(&self) -> Result<Vec<String>, Box<dyn std::error::Error>> {
2073        self.ranks
2074            .iter()
2075            .map(|rank| rank.ctx().name().map_err(Into::into))
2076            .collect()
2077    }
2078
2079    /// Correctness-gate access to the engine that owns one TP rank.
2080    ///
2081    /// Model execution should prefer collective methods on this runtime. This accessor exists so
2082    /// focused gates can prove that the rank-local projection outputs remain device-resident
2083    /// through the next ownership boundary before that boundary is wired into serving.
2084    pub fn rank_engine(&self, rank: usize) -> Option<&Engine> {
2085        self.ranks.get(rank)
2086    }
2087
2088    pub fn allocate_tp_kv_cache(
2089        &self,
2090        kv_dim_k: usize,
2091        kv_dim_v: usize,
2092        capacity: usize,
2093    ) -> Result<ResidentTpKvCache, Box<dyn std::error::Error>> {
2094        self.allocate_tp_kv_cache_inner(kv_dim_k, kv_dim_v, capacity, None)
2095    }
2096
2097    pub fn allocate_tp_swa_kv_cache(
2098        &self,
2099        kv_dim_k: usize,
2100        kv_dim_v: usize,
2101        capacity: usize,
2102        window: usize,
2103    ) -> Result<ResidentTpKvCache, Box<dyn std::error::Error>> {
2104        if window == 0 {
2105            return Err("TP SWA KV window must be nonzero".into());
2106        }
2107        self.allocate_tp_kv_cache_inner(kv_dim_k, kv_dim_v, capacity, Some(window))
2108    }
2109
2110    fn allocate_tp_kv_cache_inner(
2111        &self,
2112        kv_dim_k: usize,
2113        kv_dim_v: usize,
2114        capacity: usize,
2115        window: Option<usize>,
2116    ) -> Result<ResidentTpKvCache, Box<dyn std::error::Error>> {
2117        if capacity == 0 || capacity > i32::MAX as usize {
2118            return Err(
2119                format!("TP KV capacity must be in 1..={}, got {capacity}", i32::MAX).into(),
2120            );
2121        }
2122        let tp = self.ranks.len();
2123        let shape = crate::cache::tp_kv_rank_allocation_shape(kv_dim_k, kv_dim_v, tp)?;
2124        let physical_rows = window
2125            .map(|window| crate::cache::swa_ring_rows(window, capacity))
2126            .unwrap_or(capacity);
2127        let k_plane_bytes = physical_rows
2128            .checked_mul(shape.k_token_bytes)
2129            .and_then(|bytes| bytes.checked_add(8))
2130            .ok_or("TP KV K plane-byte overflow")?;
2131        let v_plane_bytes = physical_rows
2132            .checked_mul(shape.v_token_bytes)
2133            .and_then(|bytes| bytes.checked_add(8))
2134            .ok_or("TP KV V plane-byte overflow")?;
2135        let mut ranks = Vec::with_capacity(tp);
2136        for engine in &self.ranks {
2137            let _main = engine.gpu.enter_main()?;
2138            ranks.push(ResidentTpKvCacheRank::new(
2139                engine.alloc_u8(k_plane_bytes)?,
2140                engine.alloc_u8(v_plane_bytes)?,
2141                engine.htod_i32(&[0])?,
2142            ));
2143        }
2144        Ok(match window {
2145            Some(window) => ResidentTpKvCache::new_swa(
2146                ranks,
2147                shape.kv_dim_k,
2148                shape.kv_dim_v,
2149                shape.k_token_bytes,
2150                shape.v_token_bytes,
2151                capacity,
2152                window,
2153            ),
2154            None => ResidentTpKvCache::new(
2155                ranks,
2156                shape.kv_dim_k,
2157                shape.kv_dim_v,
2158                shape.k_token_bytes,
2159                shape.v_token_bytes,
2160                capacity,
2161            ),
2162        })
2163    }
2164
2165    pub fn grow_tp_kv_cache(
2166        &self,
2167        source: &ResidentTpKvCache,
2168        target_capacity: usize,
2169        rows: usize,
2170    ) -> Result<ResidentTpKvCache, Box<dyn std::error::Error>> {
2171        self.validate_tp_kv_cache(source)?;
2172        let plan = source.prepare_grow(target_capacity, rows)?;
2173        let ranks = self.ranks.len();
2174        let global_k = source
2175            .kv_dim_k()
2176            .checked_mul(ranks)
2177            .ok_or("TP KV grow global K dimension overflow")?;
2178        let global_v = source
2179            .kv_dim_v()
2180            .checked_mul(ranks)
2181            .ok_or("TP KV grow global V dimension overflow")?;
2182        let mut target = match source.ring_window() {
2183            Some(window) => {
2184                self.allocate_tp_swa_kv_cache(global_k, global_v, target_capacity, window)?
2185            }
2186            None => self.allocate_tp_kv_cache(global_k, global_v, target_capacity)?,
2187        };
2188        self.validate_tp_kv_cache(&target)?;
2189
2190        for (rank, engine) in self.ranks.iter().enumerate() {
2191            let _main = engine.gpu.enter_main()?;
2192            let src = source
2193                .rank(rank)
2194                .ok_or_else(|| format!("TP KV grow source has no rank {rank}"))?;
2195            let dst = target
2196                .rank_mut(rank)
2197                .ok_or_else(|| format!("TP KV grow target has no rank {rank}"))?;
2198            if plan.k_bytes() > 0 {
2199                engine.copy_u8_range_into(
2200                    dst.k_mut(),
2201                    0,
2202                    src.k(),
2203                    plan.source_row() * source.k_tok_bytes(),
2204                    plan.k_bytes(),
2205                )?;
2206            }
2207            if plan.v_bytes() > 0 {
2208                engine.copy_u8_range_into(
2209                    dst.v_mut(),
2210                    0,
2211                    src.v(),
2212                    plan.source_row() * source.v_tok_bytes(),
2213                    plan.v_bytes(),
2214                )?;
2215            }
2216        }
2217        self.set_tp_kv_len_mirrors(&mut target, plan.rows())?;
2218
2219        // The caller publishes `target` and immediately drops `source`. Drain every rank's
2220        // stream so an async-pool free cannot recycle a source plane under an in-flight D2D copy.
2221        for engine in &self.ranks {
2222            let _main = engine.gpu.enter_main()?;
2223            engine.stream().synchronize()?;
2224        }
2225        let physical_copy_rows = plan.copy_rows();
2226        target.publish_grow(plan)?;
2227        eprintln!(
2228            "[step-tp-kv-grow] rows={} source_capacity={} target_capacity={} ranks={} \
2229             physical_copy_rows={} ring_window={:?} copy=rank-local-dtod \
2230             rank_streams_synchronized=true generation_preserved=true",
2231            rows,
2232            source.capacity(),
2233            target_capacity,
2234            ranks,
2235            physical_copy_rows,
2236            source.ring_window(),
2237        );
2238        Ok(target)
2239    }
2240
2241    pub fn hydrate_tp_kv_cache(
2242        &self,
2243        cache: &mut ResidentTpKvCache,
2244        rows: usize,
2245        k_rows: &[u8],
2246        v_rows: &[u8],
2247    ) -> Result<(), Box<dyn std::error::Error>> {
2248        self.hydrate_tp_kv_cache_from(cache, rows, 0, k_rows, v_rows)
2249    }
2250
2251    pub fn hydrate_tp_kv_cache_from(
2252        &self,
2253        cache: &mut ResidentTpKvCache,
2254        logical_len: usize,
2255        resident_start: usize,
2256        k_rows: &[u8],
2257        v_rows: &[u8],
2258    ) -> Result<(), Box<dyn std::error::Error>> {
2259        self.validate_tp_kv_cache(cache)?;
2260        if cache.committed_len() != 0 || cache.staged_len() != 0 {
2261            return Err(format!(
2262                "TP KV hydration requires an empty cache, got committed/staged={}/{}",
2263                cache.committed_len(),
2264                cache.staged_len()
2265            )
2266            .into());
2267        }
2268        if resident_start > logical_len || logical_len > cache.capacity() {
2269            return Err(format!(
2270                "TP KV hydration range [{resident_start},{logical_len}) exceeds capacity {}",
2271                cache.capacity(),
2272            )
2273            .into());
2274        }
2275        let rows = logical_len - resident_start;
2276        if rows > cache.physical_capacity() {
2277            return Err(format!(
2278                "TP KV hydration rows {rows} exceed physical capacity {}",
2279                cache.physical_capacity()
2280            )
2281            .into());
2282        }
2283        for rank in 0..self.ranks.len() {
2284            let k_rank =
2285                cache_rank_rows(k_rows, rows, cache.k_tok_bytes(), self.ranks.len(), rank)?;
2286            let v_rank =
2287                cache_rank_rows(v_rows, rows, cache.v_tok_bytes(), self.ranks.len(), rank)?;
2288            let engine = &self.ranks[rank];
2289            let _main = engine.gpu.enter_main()?;
2290            let rank_cache = cache
2291                .rank_mut(rank)
2292                .ok_or_else(|| format!("TP KV cache has no rank {rank}"))?;
2293            engine.htod_u8_into(rank_cache.k_mut(), 0, &k_rank)?;
2294            engine.htod_u8_into(rank_cache.v_mut(), 0, &v_rank)?;
2295        }
2296        cache.publish_hydration(logical_len, resident_start)?;
2297        Ok(())
2298    }
2299
2300    pub fn append_tp_kv_transaction(
2301        &self,
2302        cache: &mut ResidentTpKvCache,
2303        transaction: TpKvTransaction,
2304        k_shards: &[CudaSlice<f32>],
2305        v_shards: &[CudaSlice<f32>],
2306        rows: usize,
2307    ) -> Result<(), Box<dyn std::error::Error>> {
2308        self.append_tp_kv_transaction_inner(cache, transaction, k_shards, v_shards, rows, false)
2309    }
2310
2311    /// `external_rank_appends`: the dcw path already wrote the rank rows (device-counter
2312    /// append) — run everything EXCEPT the per-rank quantize/append loop (plan validation,
2313    /// rebase arm — unreachable when the caller peeked — and the absolute len-mirror sets,
2314    /// which land the same value the in-stream inc produced).
2315    #[allow(clippy::too_many_arguments)]
2316    pub fn append_tp_kv_transaction_inner(
2317        &self,
2318        cache: &mut ResidentTpKvCache,
2319        transaction: TpKvTransaction,
2320        k_shards: &[CudaSlice<f32>],
2321        v_shards: &[CudaSlice<f32>],
2322        rows: usize,
2323        external_rank_appends: bool,
2324    ) -> Result<(), Box<dyn std::error::Error>> {
2325        self.validate_tp_kv_cache(cache)?;
2326        let plan = cache.prepare_append(transaction, rows)?;
2327        let target = plan.target();
2328        let expected_k = rows
2329            .checked_mul(cache.kv_dim_k())
2330            .ok_or("TP KV K append size overflow")?;
2331        let expected_v = rows
2332            .checked_mul(cache.kv_dim_v())
2333            .ok_or("TP KV V append size overflow")?;
2334        // external_rank_appends passes no shards — the graph's dcw appends already wrote
2335        // the rank rows, so this call is bookkeeping-only and the shard slices are unused.
2336        if !external_rank_appends
2337            && (k_shards.len() != self.ranks.len() || v_shards.len() != self.ranks.len())
2338        {
2339            return Err(format!(
2340                "TP KV append shard counts k={} v={} != ranks {}",
2341                k_shards.len(),
2342                v_shards.len(),
2343                self.ranks.len()
2344            )
2345            .into());
2346        }
2347        let kv_dim_k = cache.kv_dim_k();
2348        let kv_dim_v = cache.kv_dim_v();
2349        let k_tok_bytes = cache.k_tok_bytes();
2350        let v_tok_bytes = cache.v_tok_bytes();
2351        if let Some(KvRingAppend::Rebase {
2352            src_row,
2353            keep_rows,
2354            new_base,
2355            ..
2356        }) = plan.ring_append()
2357        {
2358            for rank in 0..self.ranks.len() {
2359                let engine = &self.ranks[rank];
2360                let _main = engine.gpu.enter_main()?;
2361                let rank_cache = cache
2362                    .rank_mut(rank)
2363                    .ok_or_else(|| format!("TP KV cache has no rank {rank}"))?;
2364                if keep_rows > 0 {
2365                    let k_len = keep_rows
2366                        .checked_mul(k_tok_bytes)
2367                        .ok_or("TP KV K rebase-byte overflow")?;
2368                    let v_len = keep_rows
2369                        .checked_mul(v_tok_bytes)
2370                        .ok_or("TP KV V rebase-byte overflow")?;
2371                    let mut k_tmp = engine.alloc_u8_uninit(k_len)?;
2372                    let mut v_tmp = engine.alloc_u8_uninit(v_len)?;
2373                    engine.copy_u8_range_into(
2374                        &mut k_tmp,
2375                        0,
2376                        rank_cache.k(),
2377                        src_row * k_tok_bytes,
2378                        k_len,
2379                    )?;
2380                    engine.copy_u8_range_into(
2381                        &mut v_tmp,
2382                        0,
2383                        rank_cache.v(),
2384                        src_row * v_tok_bytes,
2385                        v_len,
2386                    )?;
2387                    engine.copy_u8_into(rank_cache.k_mut(), 0, &k_tmp, k_len)?;
2388                    engine.copy_u8_into(rank_cache.v_mut(), 0, &v_tmp, v_len)?;
2389                }
2390                // dcw base mirror (graph increment A): physical row 0 now holds logical
2391                // row `new_base`; armed device mirrors track it (rebases are rare host
2392                // events, so a host set here is the whole maintenance cost).
2393                if rank_cache.base_d().is_some() {
2394                    let value = new_base as i32;
2395                    let rank_cache = cache
2396                        .rank_mut(rank)
2397                        .ok_or_else(|| format!("TP KV cache has no rank {rank}"))?;
2398                    if let Some(base_d) = rank_cache.base_d_mut() {
2399                        engine.set_i32_one(base_d, value)?;
2400                    }
2401                }
2402            }
2403        }
2404        cache.publish_append_rebase(plan)?;
2405        let write_row = plan.write_row();
2406        for rank in 0..self.ranks.len() {
2407            if external_rank_appends {
2408                break;
2409            }
2410            let engine = &self.ranks[rank];
2411            let _main = engine.gpu.enter_main()?;
2412            if k_shards[rank].len() != expected_k
2413                || v_shards[rank].len() != expected_v
2414                || k_shards[rank].ordinal() != engine.ctx().ordinal()
2415                || v_shards[rank].ordinal() != engine.ctx().ordinal()
2416            {
2417                return Err(format!(
2418                    "TP KV rank {rank} shard geometry/device k={}/{} v={}/{} \
2419                     != expected {expected_k}/{expected_v} on device {}",
2420                    k_shards[rank].len(),
2421                    k_shards[rank].ordinal(),
2422                    v_shards[rank].len(),
2423                    v_shards[rank].ordinal(),
2424                    engine.ctx().ordinal(),
2425                )
2426                .into());
2427            }
2428            let rank_cache = cache
2429                .rank_mut(rank)
2430                .ok_or_else(|| format!("TP KV cache has no rank {rank}"))?;
2431            let (rank_k, rank_v) = rank_cache.planes_mut();
2432            engine.append_kv_quantized_rows(
2433                &k_shards[rank],
2434                &v_shards[rank],
2435                rank_k,
2436                rank_v,
2437                write_row,
2438                rows,
2439                kv_dim_k,
2440                kv_dim_v,
2441                k_tok_bytes,
2442                v_tok_bytes,
2443                Engine::kv_fp8_on(),
2444            )?;
2445        }
2446        if !external_rank_appends {
2447            // dcw appends advance the device counters with in-stream inc_i32; an absolute set
2448            // here would race the merged per-rank append (it reads len_d for its write row).
2449            self.set_tp_kv_len_mirrors(cache, target)?;
2450        }
2451        cache.publish_append_plan(plan)?;
2452        Ok(())
2453    }
2454
2455    pub fn commit_tp_kv_transaction(
2456        &self,
2457        cache: &mut ResidentTpKvCache,
2458        transaction: TpKvTransaction,
2459        accepted_rows: usize,
2460    ) -> Result<(), Box<dyn std::error::Error>> {
2461        self.validate_tp_kv_cache(cache)?;
2462        let target = cache.commit_target(transaction, accepted_rows)?;
2463        self.set_tp_kv_len_mirrors(cache, target)?;
2464        cache.publish_finalize(transaction, target)?;
2465        Ok(())
2466    }
2467
2468    /// Commit for the external-appends (token graph) path: host bookkeeping only, NO absolute
2469    /// len-mirror sets. The graph's in-stream inc_i32 owns the device counters; a rank-stream
2470    /// set here has no ordering edge against the NEXT token's graph launch (graph children do
2471    /// not wait on the rank streams), so it can land AFTER that graph's inc and drag the
2472    /// counter backward mid-token.
2473    pub fn commit_tp_kv_transaction_external(
2474        &self,
2475        cache: &mut ResidentTpKvCache,
2476        transaction: TpKvTransaction,
2477        accepted_rows: usize,
2478    ) -> Result<(), Box<dyn std::error::Error>> {
2479        self.validate_tp_kv_cache(cache)?;
2480        let target = cache.commit_target(transaction, accepted_rows)?;
2481        cache.publish_finalize(transaction, target)?;
2482        Ok(())
2483    }
2484
2485    pub fn rollback_tp_kv_transaction(
2486        &self,
2487        cache: &mut ResidentTpKvCache,
2488        transaction: TpKvTransaction,
2489    ) -> Result<(), Box<dyn std::error::Error>> {
2490        self.validate_tp_kv_cache(cache)?;
2491        cache.validate_transaction(transaction)?;
2492        let target = transaction.base_len();
2493        self.set_tp_kv_len_mirrors(cache, target)?;
2494        cache.publish_finalize(transaction, target)?;
2495        Ok(())
2496    }
2497
2498    pub fn tp_kv_device_lengths(
2499        &self,
2500        cache: &ResidentTpKvCache,
2501    ) -> Result<Vec<i32>, Box<dyn std::error::Error>> {
2502        self.validate_tp_kv_cache(cache)?;
2503        let mut lengths = Vec::with_capacity(self.ranks.len());
2504        for (engine, rank_cache) in self.ranks.iter().zip(cache.ranks()) {
2505            let _main = engine.gpu.enter_main()?;
2506            lengths.push(engine.dtoh_i32_one(rank_cache.len_d())?);
2507        }
2508        Ok(lengths)
2509    }
2510
2511    fn set_tp_kv_len_mirrors(
2512        &self,
2513        cache: &mut ResidentTpKvCache,
2514        len: usize,
2515    ) -> Result<(), Box<dyn std::error::Error>> {
2516        let len = i32::try_from(len).map_err(|_| "TP KV length exceeds i32 device mirror")?;
2517        for (engine, rank_cache) in self.ranks.iter().zip(cache.ranks_mut()) {
2518            let _main = engine.gpu.enter_main()?;
2519            engine.set_i32_one(rank_cache.len_d_mut(), len)?;
2520        }
2521        Ok(())
2522    }
2523
2524    fn validate_tp_kv_cache(
2525        &self,
2526        cache: &ResidentTpKvCache,
2527    ) -> Result<(), Box<dyn std::error::Error>> {
2528        if cache.ranks_len() != self.ranks.len() {
2529            return Err(format!(
2530                "TP KV cache ranks {} != runtime ranks {}",
2531                cache.ranks_len(),
2532                self.ranks.len()
2533            )
2534            .into());
2535        }
2536        let expected_k = cache
2537            .physical_capacity()
2538            .checked_mul(cache.k_tok_bytes())
2539            .and_then(|bytes| bytes.checked_add(8))
2540            .ok_or("TP KV K plane validation overflow")?;
2541        let expected_v = cache
2542            .physical_capacity()
2543            .checked_mul(cache.v_tok_bytes())
2544            .and_then(|bytes| bytes.checked_add(8))
2545            .ok_or("TP KV V plane validation overflow")?;
2546        for (rank, (engine, rank_cache)) in self.ranks.iter().zip(cache.ranks()).enumerate() {
2547            let device = engine.ctx().ordinal();
2548            if rank_cache.k().len() != expected_k
2549                || rank_cache.v().len() != expected_v
2550                || rank_cache.len_d().len() != 1
2551                || rank_cache.k().ordinal() != device
2552                || rank_cache.v().ordinal() != device
2553                || rank_cache.len_d().ordinal() != device
2554            {
2555                return Err(format!(
2556                    "TP KV rank {rank} residency does not match device {device} or plane geometry"
2557                )
2558                .into());
2559            }
2560        }
2561        Ok(())
2562    }
2563
2564    pub fn full(
2565        &self,
2566        matrix: E4m3BlockMatrix<'_>,
2567        activations: &[f32],
2568        tokens: usize,
2569    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
2570        matrix.validate()?;
2571        validate_activations(activations, tokens, matrix.in_features)?;
2572        run_rank(&self.ranks[0], matrix, activations, tokens)
2573    }
2574
2575    /// Column-parallel projection. Weight output rows and their scale rows are partitioned across
2576    /// ranks. The input is host-broadcast, rank-local projections execute independently, and the
2577    /// output is host-gathered in rank order.
2578    #[allow(clippy::manual_is_multiple_of)] // allow: divisor is runtime-derived; the modulo form keeps a zero divisor loud (a panic), where is_multiple_of would return false silently
2579    pub fn column_parallel(
2580        &self,
2581        matrix: E4m3BlockMatrix<'_>,
2582        activations: &[f32],
2583        tokens: usize,
2584    ) -> Result<ColumnParallelResult, Box<dyn std::error::Error>> {
2585        matrix.validate()?;
2586        validate_activations(activations, tokens, matrix.in_features)?;
2587        let tp = self.ranks.len();
2588        if matrix.out_features % tp != 0 {
2589            return Err(format!(
2590                "column-parallel out_features {} is not divisible by TP={tp}",
2591                matrix.out_features
2592            )
2593            .into());
2594        }
2595        let local_out = matrix.out_features / tp;
2596        if !local_out.is_multiple_of(FP8_BLOCK) {
2597            return Err(format!(
2598                "column-parallel output shard {local_out} cuts through a {FP8_BLOCK}-row \
2599                 E4M3 scale block"
2600            )
2601            .into());
2602        }
2603
2604        let mut gathered = vec![0.0f32; tokens * matrix.out_features];
2605        let mut rank_outputs = Vec::with_capacity(tp);
2606        for (rank_index, rank) in self.ranks.iter().enumerate() {
2607            let shard = column_shard(matrix, tp, rank_index)?;
2608            let output = run_rank(rank, shard, activations, tokens)?;
2609            let row_start = rank_index * local_out;
2610            for token in 0..tokens {
2611                gathered[token * matrix.out_features + row_start
2612                    ..token * matrix.out_features + row_start + local_out]
2613                    .copy_from_slice(&output[token * local_out..(token + 1) * local_out]);
2614            }
2615            rank_outputs.push(output);
2616        }
2617        Ok(ColumnParallelResult {
2618            gathered,
2619            rank_outputs,
2620        })
2621    }
2622
2623    pub fn upload_column_parallel(
2624        &self,
2625        matrix: E4m3BlockMatrix<'_>,
2626    ) -> Result<ResidentColumnParallel, Box<dyn std::error::Error>> {
2627        matrix.validate()?;
2628        let tp = self.ranks.len();
2629        validate_column_shape(matrix, tp)?;
2630        let mut ranks = Vec::with_capacity(tp);
2631        for (rank_index, engine) in self.ranks.iter().enumerate() {
2632            ranks.push(upload_rank(engine, column_shard(matrix, tp, rank_index)?)?);
2633        }
2634        Ok(ResidentColumnParallel {
2635            ranks,
2636            out_features: matrix.out_features,
2637            in_features: matrix.in_features,
2638        })
2639    }
2640
2641    pub fn column_parallel_resident(
2642        &self,
2643        matrix: &ResidentColumnParallel,
2644        activations: &[f32],
2645        tokens: usize,
2646    ) -> Result<ColumnParallelResult, Box<dyn std::error::Error>> {
2647        validate_resident_ranks(&self.ranks, &matrix.ranks)?;
2648        validate_activations(activations, tokens, matrix.in_features)?;
2649        let local_out = matrix.out_features / self.ranks.len();
2650        let mut gathered = vec![0.0f32; tokens * matrix.out_features];
2651        let mut rank_outputs = Vec::with_capacity(self.ranks.len());
2652        for (rank_index, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
2653            let output = run_resident_rank(engine, shard, activations, tokens)?;
2654            let row_start = rank_index * local_out;
2655            for token in 0..tokens {
2656                gathered[token * matrix.out_features + row_start
2657                    ..token * matrix.out_features + row_start + local_out]
2658                    .copy_from_slice(&output[token * local_out..(token + 1) * local_out]);
2659            }
2660            rank_outputs.push(output);
2661        }
2662        Ok(ColumnParallelResult {
2663            gathered,
2664            rank_outputs,
2665        })
2666    }
2667
2668    /// Row-parallel projection. Weight/input columns and their scale columns are partitioned
2669    /// across ranks. Rank-local partials return through host memory and are reduced in stable
2670    /// rank order.
2671    #[allow(clippy::manual_is_multiple_of)] // allow: divisor is runtime-derived; the modulo form keeps a zero divisor loud (a panic), where is_multiple_of would return false silently
2672    pub fn row_parallel(
2673        &self,
2674        matrix: E4m3BlockMatrix<'_>,
2675        activations: &[f32],
2676        tokens: usize,
2677    ) -> Result<RowParallelResult, Box<dyn std::error::Error>> {
2678        matrix.validate()?;
2679        validate_activations(activations, tokens, matrix.in_features)?;
2680        let tp = self.ranks.len();
2681        if matrix.in_features % tp != 0 {
2682            return Err(format!(
2683                "row-parallel in_features {} is not divisible by TP={tp}",
2684                matrix.in_features
2685            )
2686            .into());
2687        }
2688        let local_in = matrix.in_features / tp;
2689        if !local_in.is_multiple_of(FP8_BLOCK) {
2690            return Err(format!(
2691                "row-parallel input shard {local_in} cuts through a {FP8_BLOCK}-column \
2692                 E4M3 scale block"
2693            )
2694            .into());
2695        }
2696
2697        let mut reduced = vec![0.0f32; tokens * matrix.out_features];
2698        let mut rank_partials = Vec::with_capacity(tp);
2699        for (rank_index, rank) in self.ranks.iter().enumerate() {
2700            let (codes, scales) = row_shard(matrix, tp, rank_index)?;
2701            let local_activations =
2702                activation_shard(activations, tokens, matrix.in_features, tp, rank_index);
2703            let shard = E4m3BlockMatrix {
2704                codes: &codes,
2705                scales: &scales,
2706                out_features: matrix.out_features,
2707                in_features: local_in,
2708            };
2709            let partial = run_rank(rank, shard, &local_activations, tokens)?;
2710            for (sum, value) in reduced.iter_mut().zip(&partial) {
2711                *sum += *value;
2712            }
2713            rank_partials.push(partial);
2714        }
2715        Ok(RowParallelResult {
2716            reduced,
2717            rank_partials,
2718        })
2719    }
2720
2721    pub fn upload_row_parallel(
2722        &self,
2723        matrix: E4m3BlockMatrix<'_>,
2724    ) -> Result<ResidentRowParallel, Box<dyn std::error::Error>> {
2725        matrix.validate()?;
2726        let tp = self.ranks.len();
2727        validate_row_shape(matrix, tp)?;
2728        let local_in = matrix.in_features / tp;
2729        let mut ranks = Vec::with_capacity(tp);
2730        for (rank_index, engine) in self.ranks.iter().enumerate() {
2731            let (codes, scales) = row_shard(matrix, tp, rank_index)?;
2732            ranks.push(upload_rank(
2733                engine,
2734                E4m3BlockMatrix {
2735                    codes: &codes,
2736                    scales: &scales,
2737                    out_features: matrix.out_features,
2738                    in_features: local_in,
2739                },
2740            )?);
2741        }
2742        Ok(ResidentRowParallel {
2743            ranks,
2744            out_features: matrix.out_features,
2745            in_features: matrix.in_features,
2746        })
2747    }
2748
2749    pub fn row_parallel_resident(
2750        &self,
2751        matrix: &ResidentRowParallel,
2752        activations: &[f32],
2753        tokens: usize,
2754    ) -> Result<RowParallelResult, Box<dyn std::error::Error>> {
2755        validate_resident_ranks(&self.ranks, &matrix.ranks)?;
2756        validate_activations(activations, tokens, matrix.in_features)?;
2757        let tp = self.ranks.len();
2758        let mut reduced = vec![0.0f32; tokens * matrix.out_features];
2759        let mut rank_partials = Vec::with_capacity(tp);
2760        for (rank_index, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
2761            let local_activations =
2762                activation_shard(activations, tokens, matrix.in_features, tp, rank_index);
2763            let partial = run_resident_rank(engine, shard, &local_activations, tokens)?;
2764            for (sum, value) in reduced.iter_mut().zip(&partial) {
2765                *sum += *value;
2766            }
2767            rank_partials.push(partial);
2768        }
2769        Ok(RowParallelResult {
2770            reduced,
2771            rank_partials,
2772        })
2773    }
2774
2775    pub fn upload_bf16_column_parallel(
2776        &self,
2777        matrix: Bf16Matrix<'_>,
2778    ) -> Result<ResidentBf16ColumnParallel, Box<dyn std::error::Error>> {
2779        self.upload_bf16_column_parallel_inner(matrix, None, false)
2780    }
2781
2782    /// Step-3.7 column projection with one numerical program across TP1/TP2/TP4/TP8.
2783    pub fn upload_step_bf16_column_parallel(
2784        &self,
2785        matrix: Bf16Matrix<'_>,
2786    ) -> Result<ResidentBf16ColumnParallel, Box<dyn std::error::Error>> {
2787        self.upload_step_bf16_column_parallel_inner(matrix, false)
2788    }
2789
2790    /// Load-time exact F32 expansion of a Step BF16 shard.
2791    ///
2792    /// The original BF16 allocation is released after the stream-ordered conversion. Decode then
2793    /// reuses the resident F32 values with the same topology-invariant output-row chunks.
2794    pub fn upload_step_bf16_column_parallel_f32_mirror(
2795        &self,
2796        matrix: Bf16Matrix<'_>,
2797    ) -> Result<ResidentBf16ColumnParallel, Box<dyn std::error::Error>> {
2798        self.upload_step_bf16_column_parallel_inner(matrix, true)
2799    }
2800
2801    fn upload_step_bf16_column_parallel_inner(
2802        &self,
2803        matrix: Bf16Matrix<'_>,
2804        f32_mirror: bool,
2805    ) -> Result<ResidentBf16ColumnParallel, Box<dyn std::error::Error>> {
2806        let canonical_chunk_rows =
2807            step_bf16_canonical_chunk_rows(matrix.out_features, self.ranks.len())?;
2808        self.upload_bf16_column_parallel_inner(matrix, Some(canonical_chunk_rows), f32_mirror)
2809    }
2810
2811    #[allow(clippy::manual_is_multiple_of)] // allow: divisor is runtime-derived; the modulo form keeps a zero divisor loud (a panic), where is_multiple_of would return false silently
2812    fn upload_bf16_column_parallel_inner(
2813        &self,
2814        matrix: Bf16Matrix<'_>,
2815        canonical_chunk_rows: Option<usize>,
2816        f32_mirror: bool,
2817    ) -> Result<ResidentBf16ColumnParallel, Box<dyn std::error::Error>> {
2818        matrix.validate()?;
2819        let tp = self.ranks.len();
2820        if matrix.out_features % tp != 0 {
2821            return Err(format!(
2822                "BF16 column-parallel out_features {} is not divisible by TP={tp}",
2823                matrix.out_features
2824            )
2825            .into());
2826        }
2827        let mut ranks = Vec::with_capacity(tp);
2828        for (rank, engine) in self.ranks.iter().enumerate() {
2829            ranks.push(upload_bf16_rank(
2830                engine,
2831                bf16_column_shard(matrix, tp, rank)?,
2832                f32_mirror,
2833            )?);
2834        }
2835        Ok(ResidentBf16ColumnParallel {
2836            ranks,
2837            out_features: matrix.out_features,
2838            in_features: matrix.in_features,
2839            canonical_chunk_rows,
2840        })
2841    }
2842
2843    pub fn bf16_column_parallel_resident(
2844        &self,
2845        matrix: &ResidentBf16ColumnParallel,
2846        activations: &[f32],
2847        tokens: usize,
2848    ) -> Result<ColumnParallelResult, Box<dyn std::error::Error>> {
2849        validate_resident_bf16_ranks(&self.ranks, &matrix.ranks)?;
2850        validate_activations(activations, tokens, matrix.in_features)?;
2851        let local_out = matrix.out_features / self.ranks.len();
2852        let mut gathered = vec![0.0f32; tokens * matrix.out_features];
2853        let mut rank_outputs = Vec::with_capacity(self.ranks.len());
2854        for (rank, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
2855            let output = run_resident_bf16_rank(
2856                engine,
2857                shard,
2858                activations,
2859                tokens,
2860                matrix.canonical_chunk_rows,
2861            )?;
2862            for token in 0..tokens {
2863                let src = &output[token * local_out..(token + 1) * local_out];
2864                let dst_start = token * matrix.out_features + rank * local_out;
2865                gathered[dst_start..dst_start + local_out].copy_from_slice(src);
2866            }
2867            rank_outputs.push(output);
2868        }
2869        Ok(ColumnParallelResult {
2870            gathered,
2871            rank_outputs,
2872        })
2873    }
2874
2875    /// Native-P2P twin of [`Self::bf16_column_parallel_resident`].
2876    ///
2877    /// The host-canonical activation is uploaded once on rank zero and peer-broadcast to the
2878    /// remaining ranks. Rank-local outputs are peer-gathered in token-major order before one root
2879    /// readback. This removes per-rank host staging but deliberately still returns a host oracle;
2880    /// attention and KV ownership are separate milestones.
2881    pub fn bf16_column_parallel_resident_native(
2882        &self,
2883        matrix: &ResidentBf16ColumnParallel,
2884        activations: &[f32],
2885        tokens: usize,
2886    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
2887        let rank_outputs =
2888            self.bf16_column_parallel_resident_device_shards(matrix, activations, tokens)?;
2889        let local_out = matrix.out_features / self.ranks.len();
2890        self.gather_native_column_shards(&rank_outputs, tokens, local_out)
2891    }
2892
2893    /// Does the serving engine live in the SAME CUDA context as this runtime's root rank?
2894    /// The device-resident input/output seams below hand raw device buffers across the
2895    /// Engine boundary, which is only addressable when both sides share the root device's
2896    /// primary context — the generic full-attention TP seam keys its residency dispatch on.
2897    pub fn root_shares_ctx(&self, e: &Engine) -> bool {
2898        self.ranks
2899            .first()
2900            .is_some_and(|root| root.ctx().cu_ctx() == e.ctx().cu_ctx())
2901    }
2902
2903    /// Device-input twin of [`Self::bf16_column_parallel_resident_native`] (lane/
2904    /// hermes-perf-fixes, 2026-08-23 — the step QKV TP host-bounce finding). The activation
2905    /// arrives as a ROOT-DEVICE buffer (first `tokens * in_features` values) instead of a
2906    /// host slice, and the gathered output stays root-resident: no DtoH of the hidden state,
2907    /// no host q/k/v staging, no re-upload. BYTE-IDENTICAL to the host-canonical native arm
2908    /// by construction — the root input bytes are dtod-copied where the host arm htod'd the
2909    /// same bytes, and every kernel, peer copy, and gather order is shared.
2910    ///
2911    /// FENCES: caller must have synchronized the producer stream that wrote
2912    /// `root_activation` (the serving engine's — a DIFFERENT stream in the same context);
2913    /// this method synchronizes the root stream before returning so the caller's stream can
2914    /// consume the gathered output immediately.
2915    pub fn bf16_column_parallel_resident_native_device(
2916        &self,
2917        matrix: &ResidentBf16ColumnParallel,
2918        root_activation: &CudaSlice<f32>,
2919        tokens: usize,
2920    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
2921        let rank_outputs = self.bf16_column_parallel_resident_device_shards_from_root(
2922            matrix,
2923            root_activation,
2924            tokens,
2925        )?;
2926        let local_out = matrix.out_features / self.ranks.len();
2927        let gathered = self.gather_native_column_shards_device(&rank_outputs, tokens, local_out)?;
2928        let root = &self.ranks[0];
2929        let _main = root.gpu.enter_main()?;
2930        root.stream().synchronize()?;
2931        Ok(gathered)
2932    }
2933
2934    /// Root-device-input twin of [`Self::bf16_column_parallel_resident_device_shards`]:
2935    /// the canonical activation is already resident on the root device (len >=
2936    /// `tokens * in_features`; extra tail values beyond the active prefix are ignored,
2937    /// the reused-prime-slab contract of `active_matrix_values`).
2938    pub fn bf16_column_parallel_resident_device_shards_from_root(
2939        &self,
2940        matrix: &ResidentBf16ColumnParallel,
2941        root_activation: &CudaSlice<f32>,
2942        tokens: usize,
2943    ) -> Result<Vec<CudaSlice<f32>>, Box<dyn std::error::Error>> {
2944        if self.ranks.len() > 1 && !self.native_p2p {
2945            return Err("device-resident BF16 column parallelism requires native P2P ranks".into());
2946        }
2947        validate_resident_bf16_ranks(&self.ranks, &matrix.ranks)?;
2948        let values = tokens
2949            .checked_mul(matrix.in_features)
2950            .ok_or("device BF16 column activation size overflow")?;
2951        let root = &self.ranks[0];
2952        if tokens == 0
2953            || root_activation.len() < values
2954            || root_activation.ordinal() != root.ctx().ordinal()
2955        {
2956            return Err("device BF16 column root activation geometry mismatch".into());
2957        }
2958
2959        let mut rank_inputs = Vec::with_capacity(self.ranks.len());
2960        let root_input = {
2961            let _main = root.gpu.enter_main()?;
2962            let mut root_input = root.uninit(values)?;
2963            root.stream()
2964                .memcpy_dtod(&root_activation.slice(0..values), &mut root_input)?;
2965            root_input
2966        };
2967        // PRODUCER FENCE (same discipline as the host-input twin): the peer broadcast
2968        // below reads this buffer from the OTHER ranks' streams while the root dtod may
2969        // still be in flight.
2970        {
2971            let _main = root.gpu.enter_main()?;
2972            root.stream().synchronize()?;
2973        }
2974        rank_inputs.push(root_input);
2975        for engine in &self.ranks[1..] {
2976            let peer_input = {
2977                let _main = engine.gpu.enter_main()?;
2978                let mut peer_input = engine.uninit(values)?;
2979                engine
2980                    .stream()
2981                    .memcpy_dtod(&rank_inputs[0], &mut peer_input)?;
2982                peer_input
2983            };
2984            rank_inputs.push(peer_input);
2985        }
2986
2987        let mut rank_outputs = Vec::with_capacity(self.ranks.len());
2988        #[allow(clippy::needless_range_loop)]
2989        // allow: the explicit index loop keeps the offset arithmetic visible and aligned with the device-side indexing
2990        for rank in 0..self.ranks.len() {
2991            rank_outputs.push(run_resident_bf16_rank_device(
2992                &self.ranks[rank],
2993                &matrix.ranks[rank],
2994                &rank_inputs[rank],
2995                tokens,
2996                matrix.canonical_chunk_rows,
2997                self.bulk_p2p,
2998            )?);
2999        }
3000        Ok(rank_outputs)
3001    }
3002
3003    /// Keep Step BF16 column outputs resident on their owning TP ranks.
3004    ///
3005    /// Rank zero receives the host-canonical activation once and peer-broadcasts it when TP>1.
3006    /// Unlike [`Self::bf16_column_parallel_resident_native`], this method performs no output
3007    /// gather or readback. It is the correctness substrate for rank-local norm, RoPE, attention,
3008    /// and cache ownership; callers must not treat its existence as serving qualification.
3009    pub fn bf16_column_parallel_resident_device_shards(
3010        &self,
3011        matrix: &ResidentBf16ColumnParallel,
3012        activations: &[f32],
3013        tokens: usize,
3014    ) -> Result<Vec<CudaSlice<f32>>, Box<dyn std::error::Error>> {
3015        if self.ranks.len() > 1 && !self.native_p2p {
3016            return Err("device-resident BF16 column parallelism requires native P2P ranks".into());
3017        }
3018        validate_resident_bf16_ranks(&self.ranks, &matrix.ranks)?;
3019        validate_activations(activations, tokens, matrix.in_features)?;
3020
3021        let mut rank_inputs = Vec::with_capacity(self.ranks.len());
3022        let root_input = {
3023            let root = &self.ranks[0];
3024            let _main = root.gpu.enter_main()?;
3025            root.htod(activations)?
3026        };
3027        // PRODUCER FENCE (2026-08-20 flake fix): the peer broadcast below reads this buffer from
3028        // the OTHER ranks' streams, and clone_htod is asynchronous on the root stream. Without
3029        // this fence a peer copy can overtake the in-flight H2D and replicate stale bytes — the
3030        // measured ~30%-of-boots prefill/decode argmax flake. Same discipline as
3031        // `upload_replicated_device_rows`.
3032        {
3033            let root = &self.ranks[0];
3034            let _main = root.gpu.enter_main()?;
3035            root.stream().synchronize()?;
3036        }
3037        rank_inputs.push(root_input);
3038        for engine in &self.ranks[1..] {
3039            let peer_input = {
3040                let _main = engine.gpu.enter_main()?;
3041                let mut peer_input = engine.uninit(activations.len())?;
3042                engine
3043                    .stream()
3044                    .memcpy_dtod(&rank_inputs[0], &mut peer_input)?;
3045                peer_input
3046            };
3047            rank_inputs.push(peer_input);
3048        }
3049
3050        let mut rank_outputs = Vec::with_capacity(self.ranks.len());
3051        #[allow(clippy::needless_range_loop)]
3052        // allow: the explicit index loop keeps the offset arithmetic visible and aligned with the device-side indexing
3053        for rank in 0..self.ranks.len() {
3054            rank_outputs.push(run_resident_bf16_rank_device(
3055                &self.ranks[rank],
3056                &matrix.ranks[rank],
3057                &rank_inputs[rank],
3058                tokens,
3059                matrix.canonical_chunk_rows,
3060                self.bulk_p2p,
3061            )?);
3062        }
3063        Ok(rank_outputs)
3064    }
3065
3066    /// Allocate one fixed-shape replicated batch without initializing its contents.
3067    ///
3068    /// Callers must refresh every rank before passing the batch to an operator.
3069    pub fn allocate_replicated_device_rows(
3070        &self,
3071        tokens: usize,
3072        width: usize,
3073    ) -> Result<ResidentReplicatedDeviceRows, Box<dyn std::error::Error>> {
3074        if self.ranks.len() > 1 && !self.native_p2p {
3075            return Err("replicated device rows require native P2P ranks".into());
3076        }
3077        let values = tokens
3078            .checked_mul(width)
3079            .ok_or("replicated device row size overflow")?;
3080        let rank_lengths = vec![values; self.ranks.len()];
3081        replicated_device_row_values(tokens, width, self.ranks.len(), &rank_lengths)?;
3082        let mut ranks = Vec::with_capacity(self.ranks.len());
3083        for engine in &self.ranks {
3084            let _main = engine.gpu.enter_main()?;
3085            ranks.push(engine.uninit(values)?);
3086        }
3087        Ok(ResidentReplicatedDeviceRows {
3088            ranks,
3089            tokens,
3090            width,
3091        })
3092    }
3093
3094    /// Replace a fixed-shape replicated batch from a root-device source.
3095    pub fn refresh_replicated_device_rows_from_root(
3096        &self,
3097        rows: &mut ResidentReplicatedDeviceRows,
3098        source: &CudaSlice<f32>,
3099    ) -> Result<(), Box<dyn std::error::Error>> {
3100        if self.ranks.len() > 1 && !self.native_p2p {
3101            return Err("replicated device rows require native P2P ranks".into());
3102        }
3103        validate_replicated_device_rows(&self.ranks, rows)?;
3104        let root = self
3105            .ranks
3106            .first()
3107            .ok_or("replicated rows have no root rank")?;
3108        let values = replicated_device_row_source_values(
3109            rows.tokens,
3110            rows.width,
3111            source.len(),
3112            source.ordinal(),
3113            root.ctx().ordinal(),
3114        )?;
3115        let (root_rows, peer_rows) = rows
3116            .ranks
3117            .split_first_mut()
3118            .ok_or("replicated rows have no root allocation")?;
3119        {
3120            let _main = root.gpu.enter_main()?;
3121            let mut destination = root_rows.slice_mut(0..values);
3122            root.stream()
3123                .memcpy_dtod(&source.slice(0..values), &mut destination)?;
3124            root.stream().synchronize()?;
3125        }
3126        for (engine, peer_rows) in self.ranks.iter().skip(1).zip(peer_rows) {
3127            let _main = engine.gpu.enter_main()?;
3128            let mut destination = peer_rows.slice_mut(0..values);
3129            engine
3130                .stream()
3131                .memcpy_dtod(&root_rows.slice(0..values), &mut destination)?;
3132        }
3133        Ok(())
3134    }
3135
3136    /// Upload one canonical batch on rank zero and replicate it over native P2P.
3137    pub fn upload_replicated_device_rows(
3138        &self,
3139        rows: &[f32],
3140        tokens: usize,
3141        width: usize,
3142    ) -> Result<ResidentReplicatedDeviceRows, Box<dyn std::error::Error>> {
3143        if self.ranks.len() > 1 && !self.native_p2p {
3144            return Err("replicated device rows require native P2P ranks".into());
3145        }
3146        validate_activations(rows, tokens, width)?;
3147        let root = self
3148            .ranks
3149            .first()
3150            .ok_or("replicated rows have no root rank")?;
3151        let root_rows = {
3152            let _main = root.gpu.enter_main()?;
3153            root.htod(rows)?
3154        };
3155        {
3156            let _main = root.gpu.enter_main()?;
3157            root.stream().synchronize()?;
3158        }
3159        let mut ranks = Vec::with_capacity(self.ranks.len());
3160        ranks.push(root_rows);
3161        for engine in self.ranks.iter().skip(1) {
3162            let _main = engine.gpu.enter_main()?;
3163            let mut peer_rows = engine.uninit(rows.len())?;
3164            engine.stream().memcpy_dtod(&ranks[0], &mut peer_rows)?;
3165            ranks.push(peer_rows);
3166        }
3167        Ok(ResidentReplicatedDeviceRows {
3168            ranks,
3169            tokens,
3170            width,
3171        })
3172    }
3173
3174    /// Execute a column-parallel BF16 matrix directly from rank-local replicated inputs.
3175    pub fn bf16_column_parallel_resident_replicated_device_shards(
3176        &self,
3177        matrix: &ResidentBf16ColumnParallel,
3178        activations: &ResidentReplicatedDeviceRows,
3179    ) -> Result<Vec<CudaSlice<f32>>, Box<dyn std::error::Error>> {
3180        validate_resident_bf16_ranks(&self.ranks, &matrix.ranks)?;
3181        validate_replicated_device_rows(&self.ranks, activations)?;
3182        if activations.width != matrix.in_features {
3183            return Err(format!(
3184                "replicated BF16 column input width {} != matrix width {}",
3185                activations.width, matrix.in_features
3186            )
3187            .into());
3188        }
3189        let mut outputs = Vec::with_capacity(self.ranks.len());
3190        for rank in 0..self.ranks.len() {
3191            outputs.push(run_resident_bf16_rank_device(
3192                &self.ranks[rank],
3193                &matrix.ranks[rank],
3194                &activations.ranks[rank],
3195                activations.tokens,
3196                matrix.canonical_chunk_rows,
3197                self.bulk_p2p,
3198            )?);
3199        }
3200        Ok(outputs)
3201    }
3202
3203    /// Upload a BF16 router once on rank zero and retain its exact F32 expansion.
3204    #[allow(clippy::too_many_arguments)]
3205    pub fn upload_sigmoid_topk_router(
3206        &self,
3207        weight: Bf16Matrix<'_>,
3208        correction_bias: &[f32],
3209        active: Option<&[bool]>,
3210        experts_per_token: usize,
3211        scaling_factor: f32,
3212        route_norm: bool,
3213    ) -> Result<ResidentSigmoidTopKRouter, Box<dyn std::error::Error>> {
3214        weight.validate()?;
3215        if correction_bias.len() != weight.out_features
3216            || experts_per_token == 0
3217            || experts_per_token > weight.out_features
3218            || !correction_bias.iter().all(|value| value.is_finite())
3219            || !scaling_factor.is_finite()
3220            || scaling_factor <= 0.0
3221        {
3222            return Err(format!(
3223                "sigmoid router geometry weight={}x{} bias={} top_k={} scale={scaling_factor}",
3224                weight.out_features,
3225                weight.in_features,
3226                correction_bias.len(),
3227                experts_per_token,
3228            )
3229            .into());
3230        }
3231        let active_row = active
3232            .map(|mask| {
3233                if mask.len() != weight.out_features {
3234                    return Err(format!(
3235                        "sigmoid router active mask {} != experts {}",
3236                        mask.len(),
3237                        weight.out_features
3238                    ));
3239                }
3240                Ok(mask
3241                    .iter()
3242                    .map(|&enabled| u8::from(enabled))
3243                    .collect::<Vec<_>>())
3244            })
3245            .transpose()?
3246            .unwrap_or_else(|| vec![1; weight.out_features]);
3247        let active_count = active_row.iter().filter(|&&enabled| enabled != 0).count();
3248        crate::sigrouter_contract::validate_active_count(experts_per_token, active_count)?;
3249
3250        let root = self
3251            .ranks
3252            .first()
3253            .ok_or("sigmoid router runtime has no root rank")?;
3254        let _main = root.gpu.enter_main()?;
3255        let bf16 = root.htod_bytes(weight.bytes)?;
3256        let weight_f32 = root.bf16_to_f32(
3257            &bf16.slice(0..bf16.len()),
3258            weight.out_features * weight.in_features,
3259        )?;
3260        Ok(ResidentSigmoidTopKRouter {
3261            weight: weight_f32,
3262            correction_bias: root.htod(correction_bias)?,
3263            active: root.htod_bytes(&active_row)?,
3264            root_device: root.ctx().ordinal(),
3265            input_width: weight.in_features,
3266            expert_count: weight.out_features,
3267            experts_per_token,
3268            active_count,
3269            scaling_factor,
3270            route_norm,
3271        })
3272    }
3273
3274    /// Route rank-zero replicated rows and return the narrow host control result plus logits.
3275    ///
3276    /// The logits readback exists for independent oracle comparison. This method is a correctness
3277    /// surface; a serving scheduler may retain logits and selected routes on device.
3278    pub fn sigmoid_topk_replicated_device_rows_host(
3279        &self,
3280        router: &ResidentSigmoidTopKRouter,
3281        input: &ResidentReplicatedDeviceRows,
3282    ) -> Result<SigmoidTopKHostOutput, Box<dyn std::error::Error>> {
3283        validate_replicated_device_rows(&self.ranks, input)?;
3284        if input.width != router.input_width {
3285            return Err(format!(
3286                "sigmoid router input width {} != resident width {}",
3287                input.width, router.input_width
3288            )
3289            .into());
3290        }
3291        let root = self
3292            .ranks
3293            .first()
3294            .ok_or("sigmoid router runtime has no root rank")?;
3295        let _main = root.gpu.enter_main()?;
3296        if root.ctx().ordinal() != router.root_device
3297            || router.weight.ordinal() != router.root_device
3298            || router.correction_bias.ordinal() != router.root_device
3299            || router.active.ordinal() != router.root_device
3300        {
3301            return Err("sigmoid router root residency changed".into());
3302        }
3303        let logits = root.router_gemv(
3304            &router.weight,
3305            &input.ranks[0],
3306            router.input_width,
3307            router.expert_count,
3308            input.tokens,
3309        )?;
3310        let (selected, weights) = root.moe_router_sigmoid_topk_host(
3311            &logits,
3312            input.tokens,
3313            router.expert_count,
3314            router.experts_per_token,
3315            router.active_count,
3316            &router.correction_bias,
3317            &router.active,
3318            router.scaling_factor,
3319            router.route_norm,
3320        )?;
3321        Ok(SigmoidTopKHostOutput {
3322            logits: root.dtoh(&logits)?,
3323            selected,
3324            weights,
3325        })
3326    }
3327
3328    /// Replicate a full BF16 SwiGLU bank on every rank.
3329    pub fn upload_replicated_bf16_swiglu(
3330        &self,
3331        gate: Bf16Matrix<'_>,
3332        up: Bf16Matrix<'_>,
3333        down: Bf16Matrix<'_>,
3334    ) -> Result<ResidentReplicatedBf16SwiGlu, Box<dyn std::error::Error>> {
3335        gate.validate()?;
3336        up.validate()?;
3337        down.validate()?;
3338        if gate.in_features != up.in_features
3339            || gate.out_features != up.out_features
3340            || down.in_features != gate.out_features
3341            || down.out_features != gate.in_features
3342        {
3343            return Err(format!(
3344                "replicated BF16 SwiGLU geometry gate={}x{} up={}x{} down={}x{}",
3345                gate.out_features,
3346                gate.in_features,
3347                up.out_features,
3348                up.in_features,
3349                down.out_features,
3350                down.in_features,
3351            )
3352            .into());
3353        }
3354        let mut gate_ranks = Vec::with_capacity(self.ranks.len());
3355        let mut up_ranks = Vec::with_capacity(self.ranks.len());
3356        let mut down_ranks = Vec::with_capacity(self.ranks.len());
3357        for engine in &self.ranks {
3358            gate_ranks.push(upload_bf16_rank(engine, gate, false)?);
3359            up_ranks.push(upload_bf16_rank(engine, up, false)?);
3360            down_ranks.push(upload_bf16_rank(engine, down, false)?);
3361        }
3362        Ok(ResidentReplicatedBf16SwiGlu {
3363            gate: gate_ranks,
3364            up: up_ranks,
3365            down: down_ranks,
3366            input_width: gate.in_features,
3367            intermediate_width: gate.out_features,
3368        })
3369    }
3370
3371    /// Execute a fully replicated BF16 SwiGLU directly from replicated device rows.
3372    pub fn replicated_bf16_swiglu_resident_device(
3373        &self,
3374        mlp: &ResidentReplicatedBf16SwiGlu,
3375        input: &ResidentReplicatedDeviceRows,
3376        activation_limit: Option<f32>,
3377    ) -> Result<ResidentReplicatedDeviceRows, Box<dyn std::error::Error>> {
3378        validate_step_expert_activation_limit(activation_limit)?;
3379        validate_replicated_device_rows(&self.ranks, input)?;
3380        validate_resident_bf16_ranks(&self.ranks, &mlp.gate)?;
3381        validate_resident_bf16_ranks(&self.ranks, &mlp.up)?;
3382        validate_resident_bf16_ranks(&self.ranks, &mlp.down)?;
3383        if input.width != mlp.input_width
3384            || mlp.gate.len() != self.ranks.len()
3385            || mlp.up.len() != self.ranks.len()
3386            || mlp.down.len() != self.ranks.len()
3387        {
3388            return Err("replicated BF16 SwiGLU residency or input width changed".into());
3389        }
3390
3391        let mut outputs = Vec::with_capacity(self.ranks.len());
3392        for rank in 0..self.ranks.len() {
3393            let engine = &self.ranks[rank];
3394            let gate = run_resident_bf16_rank_device(
3395                engine,
3396                &mlp.gate[rank],
3397                &input.ranks[rank],
3398                input.tokens,
3399                None,
3400                self.bulk_p2p,
3401            )?;
3402            let up = run_resident_bf16_rank_device(
3403                engine,
3404                &mlp.up[rank],
3405                &input.ranks[rank],
3406                input.tokens,
3407                None,
3408                self.bulk_p2p,
3409            )?;
3410            let _main = engine.gpu.enter_main()?;
3411            let values = input
3412                .tokens
3413                .checked_mul(mlp.intermediate_width)
3414                .ok_or("replicated BF16 SwiGLU activation size overflow")?;
3415            let mut activation = engine.uninit(values)?;
3416            if let Some(limit) = activation_limit {
3417                engine.silu_clamped_mul_host_expf(&gate, &up, limit, &mut activation, values)?;
3418            } else {
3419                engine.silu_mul_host_expf(&gate, &up, &mut activation, values)?;
3420            }
3421            outputs.push(run_resident_bf16_rank_device(
3422                engine,
3423                &mlp.down[rank],
3424                &activation,
3425                input.tokens,
3426                None,
3427                self.bulk_p2p,
3428            )?);
3429        }
3430        Ok(ResidentReplicatedDeviceRows {
3431            ranks: outputs,
3432            tokens: input.tokens,
3433            width: mlp.input_width,
3434        })
3435    }
3436
3437    /// Apply the same RMS-norm row program independently on every replicated rank.
3438    pub fn rms_norm_replicated_device_rows(
3439        &self,
3440        input: &ResidentReplicatedDeviceRows,
3441        weight: &[f32],
3442        eps: f32,
3443    ) -> Result<ResidentReplicatedDeviceRows, Box<dyn std::error::Error>> {
3444        validate_replicated_device_rows(&self.ranks, input)?;
3445        if weight.len() != input.width || !eps.is_finite() || eps <= 0.0 {
3446            return Err(format!(
3447                "replicated RMS norm weight/eps {}/{} != width {}",
3448                weight.len(),
3449                eps,
3450                input.width
3451            )
3452            .into());
3453        }
3454        let mut ranks = Vec::with_capacity(self.ranks.len());
3455        for (rank, engine) in self.ranks.iter().enumerate() {
3456            let _main = engine.gpu.enter_main()?;
3457            let weight = engine.htod(weight)?;
3458            let mut output = engine.uninit(input.tokens * input.width)?;
3459            engine.rms_norm(
3460                &input.ranks[rank],
3461                &weight,
3462                &mut output,
3463                input.width,
3464                input.tokens,
3465                eps,
3466            )?;
3467            ranks.push(output);
3468        }
3469        Ok(ResidentReplicatedDeviceRows {
3470            ranks,
3471            tokens: input.tokens,
3472            width: input.width,
3473        })
3474    }
3475
3476    /// Add two replicated batches and RMS-normalize the exact residual on every rank.
3477    pub fn add_rms_norm_replicated_device_rows(
3478        &self,
3479        input: &ResidentReplicatedDeviceRows,
3480        update: &ResidentReplicatedDeviceRows,
3481        weight: &[f32],
3482        eps: f32,
3483    ) -> Result<
3484        (ResidentReplicatedDeviceRows, ResidentReplicatedDeviceRows),
3485        Box<dyn std::error::Error>,
3486    > {
3487        validate_replicated_device_rows(&self.ranks, input)?;
3488        validate_replicated_device_rows(&self.ranks, update)?;
3489        if input.tokens != update.tokens
3490            || input.width != update.width
3491            || weight.len() != input.width
3492            || !eps.is_finite()
3493            || eps <= 0.0
3494        {
3495            return Err(format!(
3496                "replicated add/RMS geometry input={}x{} update={}x{} weight={} eps={eps}",
3497                input.tokens,
3498                input.width,
3499                update.tokens,
3500                update.width,
3501                weight.len(),
3502            )
3503            .into());
3504        }
3505        let values = input.tokens * input.width;
3506        let mut residual_ranks = Vec::with_capacity(self.ranks.len());
3507        let mut normalized_ranks = Vec::with_capacity(self.ranks.len());
3508        for (rank, engine) in self.ranks.iter().enumerate() {
3509            let _main = engine.gpu.enter_main()?;
3510            let weight = engine.htod(weight)?;
3511            let mut residual = engine.uninit(values)?;
3512            let mut normalized = engine.uninit(values)?;
3513            engine.add_rms_norm(
3514                &input.ranks[rank],
3515                &update.ranks[rank],
3516                &weight,
3517                &mut residual,
3518                &mut normalized,
3519                input.width,
3520                input.tokens,
3521                eps,
3522            )?;
3523            residual_ranks.push(residual);
3524            normalized_ranks.push(normalized);
3525        }
3526        Ok((
3527            ResidentReplicatedDeviceRows {
3528                ranks: residual_ranks,
3529                tokens: input.tokens,
3530                width: input.width,
3531            },
3532            ResidentReplicatedDeviceRows {
3533                ranks: normalized_ranks,
3534                tokens: input.tokens,
3535                width: input.width,
3536            },
3537        ))
3538    }
3539
3540    pub fn collect_replicated_device_rows(
3541        &self,
3542        rows: &ResidentReplicatedDeviceRows,
3543    ) -> Result<Vec<Vec<f32>>, Box<dyn std::error::Error>> {
3544        validate_replicated_device_rows(&self.ranks, rows)?;
3545        let mut outputs = Vec::with_capacity(self.ranks.len());
3546        for (rank, engine) in self.ranks.iter().enumerate() {
3547            let _main = engine.gpu.enter_main()?;
3548            outputs.push(engine.dtoh(&rows.ranks[rank])?);
3549        }
3550        Ok(outputs)
3551    }
3552
3553    #[allow(clippy::manual_is_multiple_of)] // allow: divisor is runtime-derived; the modulo form keeps a zero divisor loud (a panic), where is_multiple_of would return false silently
3554    pub fn upload_bf16_row_parallel(
3555        &self,
3556        matrix: Bf16Matrix<'_>,
3557    ) -> Result<ResidentBf16RowParallel, Box<dyn std::error::Error>> {
3558        matrix.validate()?;
3559        let tp = self.ranks.len();
3560        if matrix.in_features % tp != 0 {
3561            return Err(format!(
3562                "BF16 row-parallel in_features {} is not divisible by TP={tp}",
3563                matrix.in_features
3564            )
3565            .into());
3566        }
3567        let mut ranks = Vec::with_capacity(tp);
3568        for (rank, engine) in self.ranks.iter().enumerate() {
3569            let shard = bf16_row_shard(matrix, tp, rank)?;
3570            ranks.push(upload_bf16_rank(
3571                engine,
3572                Bf16Matrix {
3573                    bytes: &shard,
3574                    out_features: matrix.out_features,
3575                    in_features: matrix.in_features / tp,
3576                },
3577                false,
3578            )?);
3579        }
3580        Ok(ResidentBf16RowParallel {
3581            ranks,
3582            out_features: matrix.out_features,
3583            in_features: matrix.in_features,
3584        })
3585    }
3586
3587    pub fn bf16_row_parallel_resident(
3588        &self,
3589        matrix: &ResidentBf16RowParallel,
3590        activations: &[f32],
3591        tokens: usize,
3592    ) -> Result<RowParallelResult, Box<dyn std::error::Error>> {
3593        validate_resident_bf16_ranks(&self.ranks, &matrix.ranks)?;
3594        validate_activations(activations, tokens, matrix.in_features)?;
3595        let tp = self.ranks.len();
3596        let mut reduced = vec![0.0f32; tokens * matrix.out_features];
3597        let mut rank_partials = Vec::with_capacity(tp);
3598        for (rank, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
3599            let local_activations =
3600                activation_shard(activations, tokens, matrix.in_features, tp, rank);
3601            let partial = run_resident_bf16_rank(engine, shard, &local_activations, tokens, None)?;
3602            for (sum, value) in reduced.iter_mut().zip(&partial) {
3603                *sum += value;
3604            }
3605            rank_partials.push(partial);
3606        }
3607        Ok(RowParallelResult {
3608            reduced,
3609            rank_partials,
3610        })
3611    }
3612
3613    /// Step-3.7 row projection split into the same eight global K blocks for TP1/TP2/TP4/TP8.
3614    pub fn upload_step_bf16_row_parallel(
3615        &self,
3616        matrix: Bf16Matrix<'_>,
3617    ) -> Result<ResidentStepBf16RowParallel, Box<dyn std::error::Error>> {
3618        self.upload_step_bf16_row_parallel_inner(matrix, false)
3619    }
3620
3621    pub fn upload_step_bf16_row_parallel_f32_mirror(
3622        &self,
3623        matrix: Bf16Matrix<'_>,
3624    ) -> Result<ResidentStepBf16RowParallel, Box<dyn std::error::Error>> {
3625        self.upload_step_bf16_row_parallel_inner(matrix, true)
3626    }
3627
3628    fn upload_step_bf16_row_parallel_inner(
3629        &self,
3630        matrix: Bf16Matrix<'_>,
3631        f32_mirror: bool,
3632    ) -> Result<ResidentStepBf16RowParallel, Box<dyn std::error::Error>> {
3633        matrix.validate()?;
3634        let tp = self.ranks.len();
3635        let canonical_chunk_cols = step_bf16_canonical_chunk_cols(matrix.in_features, tp)?;
3636        let local_in = matrix.in_features / tp;
3637        let blocks_per_rank = local_in / canonical_chunk_cols;
3638        let mut ranks = Vec::with_capacity(tp);
3639        for (rank, engine) in self.ranks.iter().enumerate() {
3640            let mut blocks = Vec::with_capacity(blocks_per_rank);
3641            for block in 0..blocks_per_rank {
3642                let global_block = rank * blocks_per_rank + block;
3643                let col_start = global_block * canonical_chunk_cols;
3644                let bytes = bf16_row_block(matrix, col_start, canonical_chunk_cols)?;
3645                blocks.push(upload_bf16_rank(
3646                    engine,
3647                    Bf16Matrix {
3648                        bytes: &bytes,
3649                        out_features: matrix.out_features,
3650                        in_features: canonical_chunk_cols,
3651                    },
3652                    f32_mirror,
3653                )?);
3654            }
3655            ranks.push(blocks);
3656        }
3657        Ok(ResidentStepBf16RowParallel {
3658            ranks,
3659            out_features: matrix.out_features,
3660            in_features: matrix.in_features,
3661            canonical_chunk_cols,
3662        })
3663    }
3664
3665    /// Host-staged exactness twin of [`Self::step_bf16_row_parallel_resident_native`].
3666    ///
3667    /// Block inputs and partials cross host memory, but every partial is added on the root device
3668    /// in global checkpoint-column order. Native transport must reproduce this result bitwise.
3669    pub fn step_bf16_row_parallel_resident(
3670        &self,
3671        matrix: &ResidentStepBf16RowParallel,
3672        activations: &[f32],
3673        tokens: usize,
3674    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
3675        validate_step_bf16_row_residency(&self.ranks, matrix)?;
3676        validate_activations(activations, tokens, matrix.in_features)?;
3677        let root = &self.ranks[0];
3678        let output_len = tokens
3679            .checked_mul(matrix.out_features)
3680            .ok_or("Step BF16 row output size overflow")?;
3681        let mut reduced = {
3682            let _main = root.gpu.enter_main()?;
3683            root.htod(&vec![0.0f32; output_len])?
3684        };
3685        let blocks_per_rank = PRODUCT_MAX_CARDS / self.ranks.len();
3686        for (rank, blocks) in matrix.ranks.iter().enumerate() {
3687            for (block, resident) in blocks.iter().enumerate() {
3688                let global_block = rank * blocks_per_rank + block;
3689                let input = activation_shard(
3690                    activations,
3691                    tokens,
3692                    matrix.in_features,
3693                    PRODUCT_MAX_CARDS,
3694                    global_block,
3695                );
3696                let partial =
3697                    run_resident_bf16_rank(&self.ranks[rank], resident, &input, tokens, None)?;
3698                let next = {
3699                    let _main = root.gpu.enter_main()?;
3700                    let partial = root.htod(&partial)?;
3701                    let mut next = root.uninit(output_len)?;
3702                    root.add(&reduced, &partial, &mut next, output_len)?;
3703                    next
3704                };
3705                reduced = next;
3706            }
3707        }
3708        let _main = root.gpu.enter_main()?;
3709        root.dtoh(&reduced)
3710    }
3711
3712    /// Native-P2P Step row projection with canonical global K-block reduction.
3713    ///
3714    /// The full activation is uploaded once on the root. Each TP8-sized block is peer-scattered
3715    /// to its owning rank, its BF16 partial is peer-returned to the root, and root-device adds
3716    /// replay the same eight-block order as TP1 and the host-staged oracle.
3717    pub fn step_bf16_row_parallel_resident_native(
3718        &self,
3719        matrix: &ResidentStepBf16RowParallel,
3720        activations: &[f32],
3721        tokens: usize,
3722    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
3723        if self.ranks.len() > 1 && !self.native_p2p {
3724            return Err("native Step BF16 row parallelism requires P2P ranks".into());
3725        }
3726        validate_step_bf16_row_residency(&self.ranks, matrix)?;
3727        validate_activations(activations, tokens, matrix.in_features)?;
3728        let root = &self.ranks[0];
3729        let root_input = {
3730            let _main = root.gpu.enter_main()?;
3731            root.htod(activations)?
3732        };
3733        // PRODUCER FENCE (2026-08-20 flake fix): the non-bulk arm below peer-reads root_input
3734        // from the other ranks' streams while root's clone_htod may still be in flight.
3735        {
3736            let _main = root.gpu.enter_main()?;
3737            root.stream().synchronize()?;
3738        }
3739        let reduced = self.step_bf16_row_native_reduce_from_root(matrix, &root_input, tokens)?;
3740        let _main = root.gpu.enter_main()?;
3741        root.dtoh(&reduced)
3742    }
3743
3744    /// Device-input twin of [`Self::step_bf16_row_parallel_resident_native`] (lane/
3745    /// hermes-perf-fixes, 2026-08-23): the full activation arrives as a ROOT-DEVICE buffer
3746    /// and the reduced output stays root-resident — no DtoH of the attention output, no
3747    /// host O staging, no re-upload. Byte-identical to the host-canonical arm by
3748    /// construction (same block scatter, kernels, and global TP8 reduction order; the root
3749    /// bytes are dtod-copied where the host arm htod'd the same bytes). Caller must have
3750    /// synchronized the producer stream; the root stream is synchronized before returning.
3751    pub fn step_bf16_row_parallel_resident_native_device(
3752        &self,
3753        matrix: &ResidentStepBf16RowParallel,
3754        root_activation: &CudaSlice<f32>,
3755        tokens: usize,
3756    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
3757        if self.ranks.len() > 1 && !self.native_p2p {
3758            return Err("native Step BF16 row parallelism requires P2P ranks".into());
3759        }
3760        validate_step_bf16_row_residency(&self.ranks, matrix)?;
3761        let values = tokens
3762            .checked_mul(matrix.in_features)
3763            .ok_or("device Step BF16 row activation size overflow")?;
3764        let root = &self.ranks[0];
3765        if tokens == 0
3766            || root_activation.len() < values
3767            || root_activation.ordinal() != root.ctx().ordinal()
3768        {
3769            return Err("device Step BF16 row root activation geometry mismatch".into());
3770        }
3771        let root_input = {
3772            let _main = root.gpu.enter_main()?;
3773            let mut root_input = root.uninit(values)?;
3774            root.stream()
3775                .memcpy_dtod(&root_activation.slice(0..values), &mut root_input)?;
3776            root.stream().synchronize()?; // producer fence, as the host-input twin
3777            root_input
3778        };
3779        let reduced = self.step_bf16_row_native_reduce_from_root(matrix, &root_input, tokens)?;
3780        let _main = root.gpu.enter_main()?;
3781        root.stream().synchronize()?;
3782        Ok(reduced)
3783    }
3784
3785    /// Shared core of the two native Step row arms above: block scatter + rank GEMMs +
3786    /// canonical global TP8-order root reduction, from a root-resident input, returning the
3787    /// root-resident reduced output. Extracted verbatim so the host and device twins cannot
3788    /// drift numerically.
3789    fn step_bf16_row_native_reduce_from_root(
3790        &self,
3791        matrix: &ResidentStepBf16RowParallel,
3792        root_input: &CudaSlice<f32>,
3793        tokens: usize,
3794    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
3795        let root = &self.ranks[0];
3796        let output_len = tokens
3797            .checked_mul(matrix.out_features)
3798            .ok_or("native Step BF16 row output size overflow")?;
3799        let mut reduced = {
3800            let _main = root.gpu.enter_main()?;
3801            root.htod(&vec![0.0f32; output_len])?
3802        };
3803        let blocks_per_rank = PRODUCT_MAX_CARDS / self.ranks.len();
3804        let mut block_input_keepalive = Vec::with_capacity(PRODUCT_MAX_CARDS);
3805        let mut root_packed_keepalive = Vec::with_capacity(PRODUCT_MAX_CARDS);
3806        let mut remote_partial_keepalive = Vec::new();
3807        for (rank, blocks) in matrix.ranks.iter().enumerate() {
3808            for (block, resident) in blocks.iter().enumerate() {
3809                let global_block = rank * blocks_per_rank + block;
3810                let col_start = global_block * matrix.canonical_chunk_cols;
3811                let block_len = tokens
3812                    .checked_mul(matrix.canonical_chunk_cols)
3813                    .ok_or("native Step BF16 row block size overflow")?;
3814                let block_input = if self.bulk_p2p {
3815                    let root_packed = {
3816                        let _main = root.gpu.enter_main()?;
3817                        let mut root_packed = root.uninit(block_len)?;
3818                        root.copy_rows_strided(
3819                            root_input,
3820                            &mut root_packed,
3821                            matrix.canonical_chunk_cols,
3822                            tokens,
3823                            matrix.in_features,
3824                            col_start,
3825                        )?;
3826                        root_packed
3827                    };
3828                    if rank == 0 {
3829                        root_packed
3830                    } else {
3831                        // PRODUCER FENCE (2026-08-20 flake fix): the pack kernel runs on the
3832                        // root stream; this rank's peer read must not overtake it.
3833                        {
3834                            let _main = root.gpu.enter_main()?;
3835                            root.stream().synchronize()?;
3836                        }
3837                        let engine = &self.ranks[rank];
3838                        let _main = engine.gpu.enter_main()?;
3839                        let mut block_input = engine.uninit(block_len)?;
3840                        engine
3841                            .stream()
3842                            .memcpy_dtod(&root_packed, &mut block_input)?;
3843                        root_packed_keepalive.push(root_packed);
3844                        block_input
3845                    }
3846                } else {
3847                    let engine = &self.ranks[rank];
3848                    let _main = engine.gpu.enter_main()?;
3849                    let mut block_input = engine.uninit(block_len)?;
3850                    for token in 0..tokens {
3851                        let source_start = token * matrix.in_features + col_start;
3852                        let source = root_input
3853                            .slice(source_start..source_start + matrix.canonical_chunk_cols);
3854                        let destination_start = token * matrix.canonical_chunk_cols;
3855                        let mut destination = block_input.slice_mut(
3856                            destination_start..destination_start + matrix.canonical_chunk_cols,
3857                        );
3858                        engine.stream().memcpy_dtod(&source, &mut destination)?;
3859                    }
3860                    block_input
3861                };
3862                let partial = run_resident_bf16_rank_device(
3863                    &self.ranks[rank],
3864                    resident,
3865                    &block_input,
3866                    tokens,
3867                    None,
3868                    self.bulk_p2p,
3869                )?;
3870                block_input_keepalive.push(block_input);
3871                let root_partial = if rank == 0 {
3872                    partial
3873                } else {
3874                    // PRODUCER FENCE (2026-08-20 flake fix): the partial was produced by this
3875                    // rank's kernel on its own stream; root's peer read must not overtake it.
3876                    {
3877                        let engine = &self.ranks[rank];
3878                        let _main = engine.gpu.enter_main()?;
3879                        engine.stream().synchronize()?;
3880                    }
3881                    let _main = root.gpu.enter_main()?;
3882                    let mut peer_partial = root.uninit(output_len)?;
3883                    root.stream().memcpy_dtod(&partial, &mut peer_partial)?;
3884                    remote_partial_keepalive.push(partial);
3885                    peer_partial
3886                };
3887                let next = {
3888                    let _main = root.gpu.enter_main()?;
3889                    let mut next = root.uninit(output_len)?;
3890                    root.add(&reduced, &root_partial, &mut next, output_len)?;
3891                    next
3892                };
3893                reduced = next;
3894            }
3895        }
3896        {
3897            let _main = root.gpu.enter_main()?;
3898            root.stream().synchronize()?;
3899        }
3900        drop(remote_partial_keepalive);
3901        drop(root_packed_keepalive);
3902        drop(block_input_keepalive);
3903        Ok(reduced)
3904    }
3905
3906    /// Reduce rank-local Step attention shards in canonical TP8 K-block order and keep the result
3907    /// on the root device.
3908    pub fn step_bf16_row_parallel_resident_root_device(
3909        &self,
3910        matrix: &ResidentStepBf16RowParallel,
3911        rank_activations: &[CudaSlice<f32>],
3912        tokens: usize,
3913    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
3914        if self.ranks.len() > 1 && !self.native_p2p {
3915            return Err(
3916                "device-resident Step BF16 row parallelism requires native P2P ranks".into(),
3917            );
3918        }
3919        validate_step_bf16_row_residency(&self.ranks, matrix)?;
3920        let local_width = matrix.in_features / self.ranks.len();
3921        let shard_len = tokens
3922            .checked_mul(local_width)
3923            .ok_or("device Step BF16 row shard size overflow")?;
3924        if tokens == 0
3925            || rank_activations.len() != self.ranks.len()
3926            || rank_activations
3927                .iter()
3928                .zip(&self.ranks)
3929                .any(|(rows, engine)| {
3930                    rows.len() != shard_len || rows.ordinal() != engine.ctx().ordinal()
3931                })
3932        {
3933            return Err("device Step BF16 row activation shard geometry changed".into());
3934        }
3935
3936        let blocks_per_rank = PRODUCT_MAX_CARDS / self.ranks.len();
3937        let mut block_inputs = Vec::with_capacity(self.ranks.len());
3938        let mut partials = Vec::with_capacity(self.ranks.len());
3939        for (rank, blocks) in matrix.ranks.iter().enumerate() {
3940            if blocks.len() != blocks_per_rank {
3941                return Err(format!(
3942                    "device Step BF16 row rank {rank} blocks {} != {blocks_per_rank}",
3943                    blocks.len()
3944                )
3945                .into());
3946            }
3947            let engine = &self.ranks[rank];
3948            let _main = engine.gpu.enter_main()?;
3949            let mut rank_inputs = Vec::with_capacity(blocks_per_rank);
3950            let mut rank_partials = Vec::with_capacity(blocks_per_rank);
3951            for (block, resident) in blocks.iter().enumerate() {
3952                let block_len = tokens
3953                    .checked_mul(matrix.canonical_chunk_cols)
3954                    .ok_or("device Step BF16 row block size overflow")?;
3955                let mut block_input = engine.uninit(block_len)?;
3956                let local_col_start = block * matrix.canonical_chunk_cols;
3957                if self.bulk_p2p {
3958                    engine.copy_rows_strided(
3959                        &rank_activations[rank],
3960                        &mut block_input,
3961                        matrix.canonical_chunk_cols,
3962                        tokens,
3963                        local_width,
3964                        local_col_start,
3965                    )?;
3966                } else {
3967                    for token in 0..tokens {
3968                        let source_start = token * local_width + local_col_start;
3969                        let source = rank_activations[rank]
3970                            .slice(source_start..source_start + matrix.canonical_chunk_cols);
3971                        let destination_start = token * matrix.canonical_chunk_cols;
3972                        let mut destination = block_input.slice_mut(
3973                            destination_start..destination_start + matrix.canonical_chunk_cols,
3974                        );
3975                        engine.stream().memcpy_dtod(&source, &mut destination)?;
3976                    }
3977                }
3978                let partial = run_resident_bf16_rank_device(
3979                    engine,
3980                    resident,
3981                    &block_input,
3982                    tokens,
3983                    None,
3984                    self.bulk_p2p,
3985                )?;
3986                rank_inputs.push(block_input);
3987                rank_partials.push(partial);
3988            }
3989            block_inputs.push(rank_inputs);
3990            partials.push(rank_partials);
3991        }
3992        for engine in self.ranks.iter().skip(1) {
3993            let _main = engine.gpu.enter_main()?;
3994            engine.stream().synchronize()?;
3995        }
3996
3997        let output_len = tokens
3998            .checked_mul(matrix.out_features)
3999            .ok_or("device Step BF16 row output size overflow")?;
4000        let root = &self.ranks[0];
4001        let _main = root.gpu.enter_main()?;
4002        let mut reduced = root.htod(&vec![0.0f32; output_len])?;
4003        let mut remote_partials = Vec::new();
4004        for (rank, rank_partials) in partials.into_iter().enumerate() {
4005            for partial in rank_partials {
4006                let root_partial = if rank == 0 {
4007                    partial
4008                } else {
4009                    let mut peer_partial = root.uninit(output_len)?;
4010                    root.stream().memcpy_dtod(&partial, &mut peer_partial)?;
4011                    remote_partials.push(partial);
4012                    peer_partial
4013                };
4014                let mut next = root.uninit(output_len)?;
4015                root.add(&reduced, &root_partial, &mut next, output_len)?;
4016                reduced = next;
4017            }
4018        }
4019        root.stream().synchronize()?;
4020        drop(remote_partials);
4021        drop(block_inputs);
4022        Ok(reduced)
4023    }
4024
4025    /// Reduce rank-local Step attention shards, then replicate the canonical root result.
4026    pub fn step_bf16_row_parallel_resident_replicated_device(
4027        &self,
4028        matrix: &ResidentStepBf16RowParallel,
4029        rank_activations: &[CudaSlice<f32>],
4030        tokens: usize,
4031    ) -> Result<ResidentReplicatedDeviceRows, Box<dyn std::error::Error>> {
4032        let reduced =
4033            self.step_bf16_row_parallel_resident_root_device(matrix, rank_activations, tokens)?;
4034        let output_len = tokens
4035            .checked_mul(matrix.out_features)
4036            .ok_or("device Step BF16 row output size overflow")?;
4037        let mut ranks = Vec::with_capacity(self.ranks.len());
4038        ranks.push(reduced);
4039        for engine in self.ranks.iter().skip(1) {
4040            let _main = engine.gpu.enter_main()?;
4041            let mut peer_output = engine.uninit(output_len)?;
4042            engine.stream().memcpy_dtod(&ranks[0], &mut peer_output)?;
4043            ranks.push(peer_output);
4044        }
4045        Ok(ResidentReplicatedDeviceRows {
4046            ranks,
4047            tokens,
4048            width: matrix.out_features,
4049        })
4050    }
4051
4052    pub fn upload_expert(
4053        &self,
4054        gate: E4m3BlockMatrix<'_>,
4055        up: E4m3BlockMatrix<'_>,
4056        down: E4m3BlockMatrix<'_>,
4057    ) -> Result<ResidentTpExpert, Box<dyn std::error::Error>> {
4058        if gate.in_features != up.in_features || gate.out_features != up.out_features {
4059            return Err("TP expert gate/up dimensions differ".into());
4060        }
4061        if down.in_features != gate.out_features || down.out_features != gate.in_features {
4062            return Err(format!(
4063                "TP expert down {}x{} does not invert gate/up {}x{}",
4064                down.out_features, down.in_features, gate.out_features, gate.in_features
4065            )
4066            .into());
4067        }
4068        Ok(ResidentTpExpert {
4069            gate: self.upload_column_parallel(gate)?,
4070            up: self.upload_column_parallel(up)?,
4071            down: self.upload_row_parallel(down)?,
4072            input_width: gate.in_features,
4073            expert_width: gate.out_features,
4074        })
4075    }
4076
4077    pub fn run_expert(
4078        &self,
4079        expert: &ResidentTpExpert,
4080        input: &[f32],
4081        tokens: usize,
4082    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
4083        validate_activations(input, tokens, expert.input_width)?;
4084        let gate = self.column_parallel_resident(&expert.gate, input, tokens)?;
4085        let up = self.column_parallel_resident(&expert.up, input, tokens)?;
4086        let activated: Vec<f32> = gate
4087            .gathered
4088            .iter()
4089            .zip(&up.gathered)
4090            .map(|(&gate, &up)| gate / (1.0 + (-gate).exp()) * up)
4091            .collect();
4092        debug_assert_eq!(activated.len(), tokens * expert.expert_width);
4093        Ok(self
4094            .row_parallel_resident(&expert.down, &activated, tokens)?
4095            .reduced)
4096    }
4097
4098    #[allow(clippy::manual_is_multiple_of)] // allow: divisor is runtime-derived; the modulo form keeps a zero divisor loud (a panic), where is_multiple_of would return false silently
4099    pub fn upload_expert_parallel(
4100        &self,
4101        gate: E4m3ExpertBank<'_>,
4102        up: E4m3ExpertBank<'_>,
4103        down: E4m3ExpertBank<'_>,
4104    ) -> Result<ResidentExpertParallel, Box<dyn std::error::Error>> {
4105        gate.validate()?;
4106        up.validate()?;
4107        down.validate()?;
4108        if gate.expert_count != up.expert_count || gate.expert_count != down.expert_count {
4109            return Err("EP gate/up/down expert counts differ".into());
4110        }
4111        if gate.in_features != up.in_features || gate.out_features != up.out_features {
4112            return Err("EP gate/up dimensions differ".into());
4113        }
4114        if down.in_features != gate.out_features || down.out_features != gate.in_features {
4115            return Err(format!(
4116                "EP down {}x{} does not invert gate/up {}x{}",
4117                down.out_features, down.in_features, gate.out_features, gate.in_features
4118            )
4119            .into());
4120        }
4121        if gate.expert_count % self.ranks.len() != 0 {
4122            return Err(format!(
4123                "EP expert count {} is not divisible by {} ranks",
4124                gate.expert_count,
4125                self.ranks.len()
4126            )
4127            .into());
4128        }
4129
4130        let per_rank = gate.expert_count / self.ranks.len();
4131        let mut ranks = Vec::with_capacity(self.ranks.len());
4132        for (rank, engine) in self.ranks.iter().enumerate() {
4133            let expert_range = rank * per_rank..(rank + 1) * per_rank;
4134            ranks.push(ResidentEpRank {
4135                gate: upload_expert_bank_rank(engine, gate, expert_range.clone())?,
4136                up: upload_expert_bank_rank(engine, up, expert_range.clone())?,
4137                down: upload_expert_bank_rank(engine, down, expert_range)?,
4138            });
4139        }
4140        Ok(ResidentExpertParallel {
4141            ranks,
4142            expert_count: gate.expert_count,
4143            input_width: gate.in_features,
4144            expert_width: gate.out_features,
4145        })
4146    }
4147
4148    /// Prepare the official Step gate-only grouped-FP8 projection oracle on rank zero.
4149    ///
4150    /// This intentionally does not alter the resident EP path. It owns a full rank-local tensor
4151    /// bank solely so the grouped projection can be compared with the existing per-route oracle
4152    /// without routing, transport, or combine changing underneath it.
4153    #[allow(clippy::too_many_arguments)]
4154    pub fn prepare_step_grouped_fp8_gate(
4155        &self,
4156        gate: E4m3ExpertBank<'_>,
4157        up: E4m3ExpertBank<'_>,
4158        down: E4m3ExpertBank<'_>,
4159        input: &[f32],
4160        tokens: usize,
4161        selected: &[usize],
4162        activation_limit: Option<f32>,
4163    ) -> Result<PreparedStepGroupedFp8Gate, Box<dyn std::error::Error>> {
4164        gate.validate()?;
4165        up.validate()?;
4166        down.validate()?;
4167        validate_step_expert_activation_limit(activation_limit)?;
4168        if gate.expert_count != STEP_GROUPED_FP8_EXPERTS
4169            || up.expert_count != STEP_GROUPED_FP8_EXPERTS
4170            || down.expert_count != STEP_GROUPED_FP8_EXPERTS
4171        {
4172            return Err(format!(
4173                "official Step grouped FP8 gate requires {STEP_GROUPED_FP8_EXPERTS} experts, \
4174                 got gate/up/down={}/{}/{}",
4175                gate.expert_count, up.expert_count, down.expert_count,
4176            )
4177            .into());
4178        }
4179        if gate.in_features != up.in_features
4180            || gate.out_features != STEP_GROUPED_FP8_WIDTH
4181            || up.out_features != STEP_GROUPED_FP8_WIDTH
4182            || down.in_features != STEP_GROUPED_FP8_WIDTH
4183            || down.out_features != gate.in_features
4184        {
4185            return Err(format!(
4186                "official Step grouped FP8 geometry gate={}x{} up={}x{} down={}x{}",
4187                gate.out_features,
4188                gate.in_features,
4189                up.out_features,
4190                up.in_features,
4191                down.out_features,
4192                down.in_features,
4193            )
4194            .into());
4195        }
4196        validate_activations(input, tokens, gate.in_features)?;
4197        let pairs = tokens
4198            .checked_mul(STEP_GROUPED_FP8_TOP_K)
4199            .ok_or("official Step grouped FP8 route count overflow")?;
4200        if selected.len() != pairs {
4201            return Err(format!(
4202                "official Step grouped FP8 routes {} != {tokens}x{STEP_GROUPED_FP8_TOP_K} \
4203                 ({pairs})",
4204                selected.len()
4205            )
4206            .into());
4207        }
4208        for (token, routes) in selected.chunks_exact(STEP_GROUPED_FP8_TOP_K).enumerate() {
4209            let mut unique = routes.to_vec();
4210            unique.sort_unstable();
4211            unique.dedup();
4212            if unique.len() != STEP_GROUPED_FP8_TOP_K {
4213                return Err(format!(
4214                    "official Step grouped FP8 token {token} routes are not top-8 unique: \
4215                     {routes:?}"
4216                )
4217                .into());
4218            }
4219        }
4220
4221        let engine = self
4222            .ranks
4223            .first()
4224            .ok_or("official Step grouped FP8 gate has no rank-zero engine")?;
4225        let _main = engine.gpu.enter_main()?;
4226        let expert_range = 0..STEP_GROUPED_FP8_EXPERTS;
4227        let gate = upload_expert_bank_rank(engine, gate, expert_range.clone())?;
4228        let up = upload_expert_bank_rank(engine, up, expert_range.clone())?;
4229        let down = upload_expert_bank_rank(engine, down, expert_range)?;
4230        let input = engine.htod(input)?;
4231        let route_csr = ExpertCsr::from_token_routes(
4232            STEP_GROUPED_FP8_EXPERTS,
4233            tokens,
4234            STEP_GROUPED_FP8_TOP_K,
4235            selected,
4236        )?
4237        .upload(engine)?;
4238        let pair_rows = (0..pairs).collect::<Vec<_>>();
4239        let down_csr =
4240            ExpertCsr::from_pair_rows(STEP_GROUPED_FP8_EXPERTS, pairs, selected, &pair_rows)?
4241                .upload(engine)?;
4242        let gate_workspace =
4243            Fp8GroupedWorkspace::new(engine, gate.in_features, gate.out_features, tokens, pairs)?;
4244        let up_workspace =
4245            Fp8GroupedWorkspace::new(engine, up.in_features, up.out_features, tokens, pairs)?;
4246        let down_workspace =
4247            Fp8GroupedWorkspace::new(engine, down.in_features, down.out_features, pairs, pairs)?;
4248        let activation = engine.uninit(pairs * STEP_GROUPED_FP8_WIDTH)?;
4249        Ok(PreparedStepGroupedFp8Gate {
4250            device: engine.ctx().ordinal(),
4251            gate,
4252            up,
4253            down,
4254            input,
4255            route_csr,
4256            down_csr,
4257            gate_workspace,
4258            up_workspace,
4259            down_workspace,
4260            activation,
4261            activation_limit,
4262            tokens,
4263            pairs,
4264        })
4265    }
4266
4267    /// Execute one prepared gate/up/activation/down projection sequence on rank zero.
4268    pub fn run_step_grouped_fp8_gate(
4269        &self,
4270        plan: &mut PreparedStepGroupedFp8Gate,
4271    ) -> Result<StepGroupedFp8ProjectionOutput, Box<dyn std::error::Error>> {
4272        let engine = self
4273            .ranks
4274            .first()
4275            .ok_or("official Step grouped FP8 gate has no rank-zero engine")?;
4276        if engine.ctx().ordinal() != plan.device {
4277            return Err(format!(
4278                "official Step grouped FP8 plan device {} != rank-zero device {}",
4279                plan.device,
4280                engine.ctx().ordinal()
4281            )
4282            .into());
4283        }
4284        let _main = engine.gpu.enter_main()?;
4285
4286        plan.gate_workspace.quantize(engine, &plan.input)?;
4287        plan.gate_workspace.project(
4288            engine,
4289            &plan.gate.codes,
4290            &plan.gate.scales,
4291            &plan.route_csr,
4292            plan.gate.code_stride,
4293            plan.gate.scale_stride,
4294            1.0,
4295        )?;
4296        plan.up_workspace.quantize(engine, &plan.input)?;
4297        plan.up_workspace.project(
4298            engine,
4299            &plan.up.codes,
4300            &plan.up.scales,
4301            &plan.route_csr,
4302            plan.up.code_stride,
4303            plan.up.scale_stride,
4304            1.0,
4305        )?;
4306        if let Some(limit) = plan.activation_limit {
4307            engine.silu_clamped_mul_host_expf(
4308                plan.gate_workspace.output(),
4309                plan.up_workspace.output(),
4310                limit,
4311                &mut plan.activation,
4312                plan.pairs * STEP_GROUPED_FP8_WIDTH,
4313            )?;
4314        } else {
4315            engine.silu_mul_host_expf(
4316                plan.gate_workspace.output(),
4317                plan.up_workspace.output(),
4318                &mut plan.activation,
4319                plan.pairs * STEP_GROUPED_FP8_WIDTH,
4320            )?;
4321        }
4322        plan.down_workspace.quantize(engine, &plan.activation)?;
4323        plan.down_workspace.project(
4324            engine,
4325            &plan.down.codes,
4326            &plan.down.scales,
4327            &plan.down_csr,
4328            plan.down.code_stride,
4329            plan.down.scale_stride,
4330            1.0,
4331        )?;
4332
4333        Ok(StepGroupedFp8ProjectionOutput {
4334            gate: engine.dtoh(plan.gate_workspace.output())?,
4335            up: engine.dtoh(plan.up_workspace.output())?,
4336            down: engine.dtoh(plan.down_workspace.output())?,
4337        })
4338    }
4339
4340    pub fn prepare_step_grouped_expert_parallel_gate(
4341        &self,
4342        experts: &ResidentExpertParallel,
4343        input: &[f32],
4344        tokens: usize,
4345        selected: &[usize],
4346        activation_limit: Option<f32>,
4347    ) -> Result<PreparedStepGroupedExpertParallelGate, Box<dyn std::error::Error>> {
4348        self.prepare_step_grouped_expert_parallel_gate_with_capacity(
4349            experts,
4350            input,
4351            tokens,
4352            selected,
4353            activation_limit,
4354            tokens,
4355        )
4356    }
4357
4358    #[allow(clippy::too_many_arguments)]
4359    pub fn prepare_step_grouped_expert_parallel_gate_with_capacity(
4360        &self,
4361        experts: &ResidentExpertParallel,
4362        input: &[f32],
4363        tokens: usize,
4364        selected: &[usize],
4365        activation_limit: Option<f32>,
4366        max_tokens: usize,
4367    ) -> Result<PreparedStepGroupedExpertParallelGate, Box<dyn std::error::Error>> {
4368        if !self.native_p2p || !self.ep_device_arithmetic {
4369            return Err(
4370                "Step owner-grouped FP8 requires native P2P and device-resident arithmetic".into(),
4371            );
4372        }
4373        validate_step_expert_activation_limit(activation_limit)?;
4374        validate_ep_residency(&self.ranks, experts)?;
4375        validate_activations(input, tokens, experts.input_width)?;
4376        if max_tokens < tokens || max_tokens > i32::MAX as usize {
4377            return Err(format!(
4378                "official Step owner-grouped FP8 tokens {tokens} exceed capacity {max_tokens}"
4379            )
4380            .into());
4381        }
4382        if experts.expert_count != STEP_GROUPED_FP8_EXPERTS
4383            || experts.expert_width != STEP_GROUPED_FP8_WIDTH
4384        {
4385            return Err(format!(
4386                "official Step owner-grouped FP8 requires {} experts at width {}, got {} at {}",
4387                STEP_GROUPED_FP8_EXPERTS,
4388                STEP_GROUPED_FP8_WIDTH,
4389                experts.expert_count,
4390                experts.expert_width,
4391            )
4392            .into());
4393        }
4394        validate_step_grouped_owner_routes(experts.expert_count, tokens, selected)?;
4395        let max_pairs = max_tokens
4396            .checked_mul(STEP_GROUPED_FP8_TOP_K)
4397            .ok_or("official Step owner-grouped FP8 capacity route count overflow")?;
4398        let input_capacity = max_tokens
4399            .checked_mul(experts.input_width)
4400            .ok_or("official Step owner-grouped FP8 input capacity overflow")?;
4401
4402        let mut rank_inputs = Vec::with_capacity(self.ranks.len());
4403        for engine in &self.ranks {
4404            let _main = engine.gpu.enter_main()?;
4405            rank_inputs.push(engine.uninit(input_capacity)?);
4406        }
4407
4408        let mut owners = Vec::with_capacity(self.ranks.len());
4409        for (owner_rank, rank) in experts.ranks.iter().enumerate() {
4410            if rank.gate.expert_range != rank.up.expert_range
4411                || rank.gate.expert_range != rank.down.expert_range
4412            {
4413                return Err(format!(
4414                    "owner-grouped FP8 rank {} gate/up/down expert ranges differ",
4415                    owner_rank
4416                )
4417                .into());
4418            }
4419            let local_experts = rank.gate.expert_range.len();
4420            let engine = &self.ranks[owner_rank];
4421            let _main = engine.gpu.enter_main()?;
4422            let route_csr =
4423                DeviceExpertCsr::with_capacity(engine, local_experts, max_tokens, max_pairs)?;
4424            let down_csr =
4425                DeviceExpertCsr::with_capacity(engine, local_experts, max_pairs, max_pairs)?;
4426            let gate_workspace = Fp8GroupedWorkspace::new(
4427                engine,
4428                experts.input_width,
4429                experts.expert_width,
4430                max_tokens,
4431                max_pairs,
4432            )?;
4433            let up_workspace = Fp8GroupedWorkspace::new(
4434                engine,
4435                experts.input_width,
4436                experts.expert_width,
4437                max_tokens,
4438                max_pairs,
4439            )?;
4440            let down_workspace = Fp8GroupedWorkspace::new(
4441                engine,
4442                experts.expert_width,
4443                experts.input_width,
4444                max_pairs,
4445                max_pairs,
4446            )?;
4447            let activation = engine.uninit(
4448                max_pairs
4449                    .checked_mul(experts.expert_width)
4450                    .ok_or("official Step owner-grouped FP8 activation capacity overflow")?,
4451            )?;
4452            owners.push(PreparedStepGroupedExpertOwner {
4453                rank: owner_rank,
4454                global_pairs: Vec::new(),
4455                route_csr,
4456                down_csr,
4457                gate_workspace,
4458                up_workspace,
4459                down_workspace,
4460                activation,
4461            });
4462        }
4463
4464        let mut plan = PreparedStepGroupedExpertParallelGate {
4465            rank_inputs,
4466            owners,
4467            activation_limit,
4468            tokens: 0,
4469            pairs: 0,
4470            max_tokens,
4471            max_pairs,
4472            input_width: experts.input_width,
4473            expert_width: experts.expert_width,
4474            generation: 0,
4475            executed_generation: None,
4476            ready: false,
4477        };
4478        self.refresh_step_grouped_expert_parallel_gate(
4479            experts, &mut plan, input, tokens, selected,
4480        )?;
4481        Ok(plan)
4482    }
4483
4484    #[allow(clippy::type_complexity)] // allow: one-shot composite type; naming it would hide the shape that matters at the call site
4485    fn prepare_step_grouped_expert_parallel_refresh(
4486        &self,
4487        experts: &ResidentExpertParallel,
4488        plan: &PreparedStepGroupedExpertParallelGate,
4489        tokens: usize,
4490        selected: &[usize],
4491    ) -> Result<(usize, u64, Vec<Option<StepGroupedExpertOwnerSchedule>>), Box<dyn std::error::Error>>
4492    {
4493        validate_ep_residency(&self.ranks, experts)?;
4494        if plan.rank_inputs.len() != self.ranks.len()
4495            || plan.owners.len() != self.ranks.len()
4496            || plan.input_width != experts.input_width
4497            || plan.expert_width != experts.expert_width
4498            || tokens > plan.max_tokens
4499        {
4500            return Err(format!(
4501                "Step owner-grouped FP8 refresh geometry changed ranks={}/{} owners={}/{} \
4502                 input={}/{} expert={}/{} tokens={}/{}",
4503                plan.rank_inputs.len(),
4504                self.ranks.len(),
4505                plan.owners.len(),
4506                self.ranks.len(),
4507                plan.input_width,
4508                experts.input_width,
4509                plan.expert_width,
4510                experts.expert_width,
4511                tokens,
4512                plan.max_tokens,
4513            )
4514            .into());
4515        }
4516        let pairs = validate_step_grouped_owner_routes(experts.expert_count, tokens, selected)?;
4517        if pairs > plan.max_pairs {
4518            return Err(format!(
4519                "Step owner-grouped FP8 route count {pairs} exceeds capacity {}",
4520                plan.max_pairs
4521            )
4522            .into());
4523        }
4524        let next_generation = plan
4525            .generation
4526            .checked_add(1)
4527            .ok_or("Step owner-grouped FP8 plan generation overflow")?;
4528        let owner_routes = partition_expert_owner_routes(
4529            experts.expert_count,
4530            self.ranks.len(),
4531            tokens,
4532            STEP_GROUPED_FP8_TOP_K,
4533            selected,
4534        )?;
4535        let mut schedules = Vec::with_capacity(self.ranks.len());
4536        for routes in owner_routes {
4537            if routes.selected.is_empty() {
4538                schedules.push(None);
4539                continue;
4540            }
4541            let local_experts = experts.ranks[routes.rank].gate.expert_range.len();
4542            let local_pairs = routes.selected.len();
4543            let route_csr = ExpertCsr::from_pair_rows(
4544                local_experts,
4545                tokens,
4546                &routes.selected,
4547                &routes.token_rows,
4548            )?;
4549            let down_rows = (0..local_pairs).collect::<Vec<_>>();
4550            let down_csr = ExpertCsr::from_pair_rows(
4551                local_experts,
4552                local_pairs,
4553                &routes.selected,
4554                &down_rows,
4555            )?;
4556            schedules.push(Some(StepGroupedExpertOwnerSchedule {
4557                global_pairs: routes.global_pairs,
4558                route_csr,
4559                down_csr,
4560            }));
4561        }
4562        Ok((pairs, next_generation, schedules))
4563    }
4564
4565    fn commit_step_grouped_expert_parallel_refresh(
4566        &self,
4567        plan: &mut PreparedStepGroupedExpertParallelGate,
4568        tokens: usize,
4569        pairs: usize,
4570        next_generation: u64,
4571        schedules: Vec<Option<StepGroupedExpertOwnerSchedule>>,
4572    ) -> Result<(), Box<dyn std::error::Error>> {
4573        for (owner, schedule) in plan.owners.iter_mut().zip(schedules) {
4574            let engine = &self.ranks[owner.rank];
4575            let _main = engine.gpu.enter_main()?;
4576            if let Some(schedule) = schedule {
4577                owner.route_csr.refresh(engine, &schedule.route_csr)?;
4578                owner.down_csr.refresh(engine, &schedule.down_csr)?;
4579                owner.global_pairs = schedule.global_pairs;
4580            } else {
4581                owner.route_csr.clear();
4582                owner.down_csr.clear();
4583                owner.global_pairs.clear();
4584            }
4585        }
4586        plan.tokens = tokens;
4587        plan.pairs = pairs;
4588        plan.generation = next_generation;
4589        plan.ready = true;
4590        Ok(())
4591    }
4592
4593    pub fn refresh_step_grouped_expert_parallel_gate(
4594        &self,
4595        experts: &ResidentExpertParallel,
4596        plan: &mut PreparedStepGroupedExpertParallelGate,
4597        input: &[f32],
4598        tokens: usize,
4599        selected: &[usize],
4600    ) -> Result<(), Box<dyn std::error::Error>> {
4601        validate_activations(input, tokens, experts.input_width)?;
4602        let (pairs, next_generation, schedules) =
4603            self.prepare_step_grouped_expert_parallel_refresh(experts, plan, tokens, selected)?;
4604
4605        plan.ready = false;
4606        plan.executed_generation = None;
4607        {
4608            let root = &self.ranks[0];
4609            let _main = root.gpu.enter_main()?;
4610            let mut destination = plan.rank_inputs[0].slice_mut(0..input.len());
4611            root.stream().memcpy_htod(input, &mut destination)?;
4612            root.stream().synchronize()?;
4613        }
4614        let (root_inputs, peer_inputs) = plan.rank_inputs.split_at_mut(1);
4615        let root_input = &root_inputs[0];
4616        for (rank, peer_input) in peer_inputs.iter_mut().enumerate() {
4617            let engine = &self.ranks[rank + 1];
4618            let _main = engine.gpu.enter_main()?;
4619            let mut destination = peer_input.slice_mut(0..input.len());
4620            engine
4621                .stream()
4622                .memcpy_dtod(&root_input.slice(0..input.len()), &mut destination)?;
4623        }
4624        self.commit_step_grouped_expert_parallel_refresh(
4625            plan,
4626            tokens,
4627            pairs,
4628            next_generation,
4629            schedules,
4630        )
4631    }
4632
4633    /// Refresh routes and inputs from an already-resident rank-zero activation.
4634    ///
4635    /// The caller must order the source producer before this call. The root copy is completed
4636    /// before peer dispatch, while CSR and workspace allocations retain their stable addresses.
4637    pub fn refresh_step_grouped_expert_parallel_gate_from_root_device(
4638        &self,
4639        experts: &ResidentExpertParallel,
4640        plan: &mut PreparedStepGroupedExpertParallelGate,
4641        input: &CudaSlice<f32>,
4642        tokens: usize,
4643        selected: &[usize],
4644    ) -> Result<(), Box<dyn std::error::Error>> {
4645        let input_values = tokens
4646            .checked_mul(experts.input_width)
4647            .ok_or("Step owner-grouped FP8 input size overflow")?;
4648        let root = self
4649            .ranks
4650            .first()
4651            .ok_or("Step owner-grouped FP8 runtime has no root rank")?;
4652        if input.len() < input_values || input.ordinal() != root.ctx().ordinal() {
4653            return Err(format!(
4654                "Step owner-grouped FP8 root input len/device {}/{} does not cover {} values on \
4655                 device {}",
4656                input.len(),
4657                input.ordinal(),
4658                input_values,
4659                root.ctx().ordinal(),
4660            )
4661            .into());
4662        }
4663        let (pairs, next_generation, schedules) =
4664            self.prepare_step_grouped_expert_parallel_refresh(experts, plan, tokens, selected)?;
4665
4666        plan.ready = false;
4667        plan.executed_generation = None;
4668        {
4669            let _main = root.gpu.enter_main()?;
4670            let mut destination = plan.rank_inputs[0].slice_mut(0..input_values);
4671            root.stream()
4672                .memcpy_dtod(&input.slice(0..input_values), &mut destination)?;
4673            root.stream().synchronize()?;
4674        }
4675        let (root_inputs, peer_inputs) = plan.rank_inputs.split_at_mut(1);
4676        let root_input = &root_inputs[0];
4677        for (rank, peer_input) in peer_inputs.iter_mut().enumerate() {
4678            let engine = &self.ranks[rank + 1];
4679            let _main = engine.gpu.enter_main()?;
4680            let mut destination = peer_input.slice_mut(0..input_values);
4681            engine
4682                .stream()
4683                .memcpy_dtod(&root_input.slice(0..input_values), &mut destination)?;
4684        }
4685        self.commit_step_grouped_expert_parallel_refresh(
4686            plan,
4687            tokens,
4688            pairs,
4689            next_generation,
4690            schedules,
4691        )
4692    }
4693
4694    /// Replace a fixed route plan's rank inputs from an already replicated device batch.
4695    ///
4696    /// Route CSR remains unchanged. Advancing the generation invalidates every prior projection
4697    /// and combine result, so callers must refresh combine metadata before executing again.
4698    pub fn refresh_step_grouped_expert_parallel_inputs_from_replicated(
4699        &self,
4700        experts: &ResidentExpertParallel,
4701        plan: &mut PreparedStepGroupedExpertParallelGate,
4702        input: &ResidentReplicatedDeviceRows,
4703    ) -> Result<(), Box<dyn std::error::Error>> {
4704        validate_ep_residency(&self.ranks, experts)?;
4705        validate_replicated_device_rows(&self.ranks, input)?;
4706        if !plan.ready
4707            || input.tokens != plan.tokens
4708            || input.width != plan.input_width
4709            || input.tokens > plan.max_tokens
4710            || plan.rank_inputs.len() != self.ranks.len()
4711            || plan.owners.len() != self.ranks.len()
4712            || plan.input_width != experts.input_width
4713            || plan.expert_width != experts.expert_width
4714        {
4715            return Err("Step owner-grouped replicated input geometry changed".into());
4716        }
4717        let values = input
4718            .tokens
4719            .checked_mul(input.width)
4720            .ok_or("Step owner-grouped replicated input size overflow")?;
4721        let next_generation = plan
4722            .generation
4723            .checked_add(1)
4724            .ok_or("Step owner-grouped FP8 plan generation overflow")?;
4725        plan.ready = false;
4726        plan.executed_generation = None;
4727        for (rank, engine) in self.ranks.iter().enumerate() {
4728            let _main = engine.gpu.enter_main()?;
4729            let mut destination = plan.rank_inputs[rank].slice_mut(0..values);
4730            engine
4731                .stream()
4732                .memcpy_dtod(&input.ranks[rank], &mut destination)?;
4733        }
4734        plan.generation = next_generation;
4735        plan.ready = true;
4736        Ok(())
4737    }
4738
4739    pub fn execute_step_grouped_expert_parallel_gate(
4740        &self,
4741        experts: &ResidentExpertParallel,
4742        plan: &mut PreparedStepGroupedExpertParallelGate,
4743    ) -> Result<(), Box<dyn std::error::Error>> {
4744        validate_ep_residency(&self.ranks, experts)?;
4745        if !plan.ready
4746            || plan.rank_inputs.len() != self.ranks.len()
4747            || plan.owners.len() != self.ranks.len()
4748            || plan.input_width != experts.input_width
4749            || plan.expert_width != experts.expert_width
4750        {
4751            return Err("Step owner-grouped FP8 plan is not ready or its geometry changed".into());
4752        }
4753        plan.executed_generation = None;
4754
4755        for owner in &mut plan.owners {
4756            if owner.global_pairs.is_empty() {
4757                continue;
4758            }
4759            let engine = &self.ranks[owner.rank];
4760            let bank = &experts.ranks[owner.rank];
4761            let _main = engine.gpu.enter_main()?;
4762            let local_pairs = owner.global_pairs.len();
4763            owner.gate_workspace.quantize_for_shape(
4764                engine,
4765                &plan.rank_inputs[owner.rank],
4766                plan.tokens,
4767                local_pairs,
4768            )?;
4769            owner.gate_workspace.project(
4770                engine,
4771                &bank.gate.codes,
4772                &bank.gate.scales,
4773                &owner.route_csr,
4774                bank.gate.code_stride,
4775                bank.gate.scale_stride,
4776                1.0,
4777            )?;
4778            owner.up_workspace.quantize_for_shape(
4779                engine,
4780                &plan.rank_inputs[owner.rank],
4781                plan.tokens,
4782                local_pairs,
4783            )?;
4784            owner.up_workspace.project(
4785                engine,
4786                &bank.up.codes,
4787                &bank.up.scales,
4788                &owner.route_csr,
4789                bank.up.code_stride,
4790                bank.up.scale_stride,
4791                1.0,
4792            )?;
4793        }
4794        for owner in &mut plan.owners {
4795            if owner.global_pairs.is_empty() {
4796                continue;
4797            }
4798            let engine = &self.ranks[owner.rank];
4799            let _main = engine.gpu.enter_main()?;
4800            let values = owner.global_pairs.len() * plan.expert_width;
4801            if let Some(limit) = plan.activation_limit {
4802                engine.silu_clamped_mul_host_expf(
4803                    owner.gate_workspace.output(),
4804                    owner.up_workspace.output(),
4805                    limit,
4806                    &mut owner.activation,
4807                    values,
4808                )?;
4809            } else {
4810                engine.silu_mul_host_expf(
4811                    owner.gate_workspace.output(),
4812                    owner.up_workspace.output(),
4813                    &mut owner.activation,
4814                    values,
4815                )?;
4816            }
4817        }
4818        for owner in &mut plan.owners {
4819            if owner.global_pairs.is_empty() {
4820                continue;
4821            }
4822            let engine = &self.ranks[owner.rank];
4823            let bank = &experts.ranks[owner.rank];
4824            let _main = engine.gpu.enter_main()?;
4825            let local_pairs = owner.global_pairs.len();
4826            owner.down_workspace.quantize_for_shape(
4827                engine,
4828                &owner.activation,
4829                local_pairs,
4830                local_pairs,
4831            )?;
4832            owner.down_workspace.project(
4833                engine,
4834                &bank.down.codes,
4835                &bank.down.scales,
4836                &owner.down_csr,
4837                bank.down.code_stride,
4838                bank.down.scale_stride,
4839                1.0,
4840            )?;
4841        }
4842        plan.executed_generation = Some(plan.generation);
4843        Ok(())
4844    }
4845
4846    pub fn collect_step_grouped_expert_parallel_gate(
4847        &self,
4848        plan: &PreparedStepGroupedExpertParallelGate,
4849    ) -> Result<StepGroupedFp8ProjectionOutput, Box<dyn std::error::Error>> {
4850        if !plan.ready || plan.executed_generation != Some(plan.generation) {
4851            return Err("Step owner-grouped FP8 projection is stale or has not executed".into());
4852        }
4853        let mut gate = vec![0.0f32; plan.pairs * plan.expert_width];
4854        let mut up = vec![0.0f32; plan.pairs * plan.expert_width];
4855        let mut down = vec![0.0f32; plan.pairs * plan.input_width];
4856        for owner in &plan.owners {
4857            if owner.global_pairs.is_empty() {
4858                continue;
4859            }
4860            let engine = &self.ranks[owner.rank];
4861            let _main = engine.gpu.enter_main()?;
4862            let owner_gate = engine.dtoh_view(
4863                &owner
4864                    .gate_workspace
4865                    .output()
4866                    .slice(0..owner.gate_workspace.output_len()),
4867            )?;
4868            let owner_up = engine.dtoh_view(
4869                &owner
4870                    .up_workspace
4871                    .output()
4872                    .slice(0..owner.up_workspace.output_len()),
4873            )?;
4874            let owner_down = engine.dtoh_view(
4875                &owner
4876                    .down_workspace
4877                    .output()
4878                    .slice(0..owner.down_workspace.output_len()),
4879            )?;
4880            for (local_pair, &global_pair) in owner.global_pairs.iter().enumerate() {
4881                let local_expert = local_pair * plan.expert_width;
4882                let global_expert = global_pair * plan.expert_width;
4883                gate[global_expert..global_expert + plan.expert_width]
4884                    .copy_from_slice(&owner_gate[local_expert..local_expert + plan.expert_width]);
4885                up[global_expert..global_expert + plan.expert_width]
4886                    .copy_from_slice(&owner_up[local_expert..local_expert + plan.expert_width]);
4887
4888                let local_hidden = local_pair * plan.input_width;
4889                let global_hidden = global_pair * plan.input_width;
4890                down[global_hidden..global_hidden + plan.input_width]
4891                    .copy_from_slice(&owner_down[local_hidden..local_hidden + plan.input_width]);
4892            }
4893        }
4894        Ok(StepGroupedFp8ProjectionOutput { gate, up, down })
4895    }
4896
4897    pub fn run_step_grouped_expert_parallel_gate(
4898        &self,
4899        experts: &ResidentExpertParallel,
4900        plan: &mut PreparedStepGroupedExpertParallelGate,
4901    ) -> Result<StepGroupedFp8ProjectionOutput, Box<dyn std::error::Error>> {
4902        self.execute_step_grouped_expert_parallel_gate(experts, plan)?;
4903        self.collect_step_grouped_expert_parallel_gate(plan)
4904    }
4905
4906    pub fn prepare_step_grouped_expert_parallel_combine(
4907        &self,
4908        plan: &PreparedStepGroupedExpertParallelGate,
4909        route_weights: &[f32],
4910    ) -> Result<PreparedPeerWeightedRouteCombine, Box<dyn std::error::Error>> {
4911        if !self.native_p2p || !self.ep_device_arithmetic || !plan.ready {
4912            return Err(
4913                "Step owner-grouped combine requires a ready native-P2P device plan".into(),
4914            );
4915        }
4916        let owner_pairs = plan
4917            .owners
4918            .iter()
4919            .map(|owner| owner.global_pairs.as_slice())
4920            .collect::<Vec<_>>();
4921        let shape = validate_weighted_route_combine(
4922            plan.input_width,
4923            STEP_GROUPED_FP8_TOP_K,
4924            plan.max_tokens,
4925            plan.tokens,
4926            &owner_pairs,
4927            route_weights,
4928        )?;
4929        if shape.max_pairs != plan.max_pairs {
4930            return Err(format!(
4931                "Step owner-grouped combine capacity {} != projection capacity {}",
4932                shape.max_pairs, plan.max_pairs
4933            )
4934            .into());
4935        }
4936        let root = self
4937            .ranks
4938            .first()
4939            .ok_or("Step owner-grouped combine has no root rank")?;
4940        let slot_values = shape
4941            .max_pairs
4942            .checked_mul(plan.input_width)
4943            .ok_or("Step owner-grouped combine slot capacity overflow")?;
4944        let output_values = plan
4945            .max_tokens
4946            .checked_mul(plan.input_width)
4947            .ok_or("Step owner-grouped combine output capacity overflow")?;
4948        let (root_device, owners, peer_staging, slots, weights, output) = {
4949            let _main = root.gpu.enter_main()?;
4950            let mut owners = Vec::with_capacity(plan.owners.len());
4951            for _ in &plan.owners {
4952                owners.push(PreparedPeerWeightedRouteOwner {
4953                    token_rows: root.htod_i32(&vec![0; shape.max_pairs])?,
4954                    slots: root.htod_i32(&vec![0; shape.max_pairs])?,
4955                    weights: root.htod(&vec![0.0; shape.max_pairs])?,
4956                    active_pairs: 0,
4957                });
4958            }
4959            (
4960                root.ctx().ordinal(),
4961                owners,
4962                root.uninit(slot_values)?,
4963                root.uninit(slot_values)?,
4964                root.uninit(shape.max_pairs)?,
4965                root.uninit(output_values)?,
4966            )
4967        };
4968        let mut peer_devices = Vec::with_capacity(self.ranks.len().saturating_sub(1));
4969        let mut peer_outputs = Vec::with_capacity(self.ranks.len().saturating_sub(1));
4970        for engine in self.ranks.iter().skip(1) {
4971            let _main = engine.gpu.enter_main()?;
4972            peer_devices.push(engine.ctx().ordinal());
4973            peer_outputs.push(engine.uninit(output_values)?);
4974        }
4975        let mut combine = PreparedPeerWeightedRouteCombine {
4976            root_device,
4977            owners,
4978            peer_staging,
4979            slots,
4980            weights,
4981            output,
4982            peer_devices,
4983            peer_outputs,
4984            width: plan.input_width,
4985            experts_per_token: STEP_GROUPED_FP8_TOP_K,
4986            max_tokens: plan.max_tokens,
4987            max_pairs: shape.max_pairs,
4988            tokens: 0,
4989            pairs: 0,
4990            projection_generation: 0,
4991            output_generation: None,
4992            broadcast_generation: None,
4993            ready: false,
4994        };
4995        self.refresh_step_grouped_expert_parallel_combine(plan, &mut combine, route_weights)?;
4996        Ok(combine)
4997    }
4998
4999    pub fn refresh_step_grouped_expert_parallel_combine(
5000        &self,
5001        plan: &PreparedStepGroupedExpertParallelGate,
5002        combine: &mut PreparedPeerWeightedRouteCombine,
5003        route_weights: &[f32],
5004    ) -> Result<(), Box<dyn std::error::Error>> {
5005        let output_capacity = combine
5006            .max_tokens
5007            .checked_mul(combine.width)
5008            .ok_or("Step owner-grouped combine output capacity overflow")?;
5009        if !plan.ready
5010            || combine.owners.len() != plan.owners.len()
5011            || combine.peer_devices.len() + 1 != self.ranks.len()
5012            || combine.peer_outputs.len() + 1 != self.ranks.len()
5013            || combine.width != plan.input_width
5014            || combine.experts_per_token != STEP_GROUPED_FP8_TOP_K
5015            || combine.max_tokens != plan.max_tokens
5016            || combine.max_pairs != plan.max_pairs
5017            || combine.output.len() < output_capacity
5018            || combine
5019                .peer_outputs
5020                .iter()
5021                .any(|output| output.len() < output_capacity)
5022        {
5023            return Err("Step owner-grouped combine/projection geometry changed".into());
5024        }
5025        if self
5026            .ranks
5027            .iter()
5028            .skip(1)
5029            .zip(&combine.peer_devices)
5030            .any(|(engine, &device)| engine.ctx().ordinal() != device)
5031        {
5032            return Err("Step owner-grouped combine peer devices changed".into());
5033        }
5034        let owner_pairs = plan
5035            .owners
5036            .iter()
5037            .map(|owner| owner.global_pairs.as_slice())
5038            .collect::<Vec<_>>();
5039        let shape = validate_weighted_route_combine(
5040            combine.width,
5041            combine.experts_per_token,
5042            combine.max_tokens,
5043            plan.tokens,
5044            &owner_pairs,
5045            route_weights,
5046        )?;
5047        if shape.max_pairs != combine.max_pairs {
5048            return Err("Step owner-grouped combine capacity changed during refresh".into());
5049        }
5050        let metadata = owner_pairs
5051            .iter()
5052            .map(|pairs| {
5053                let token_rows = pairs
5054                    .iter()
5055                    .map(|&pair| (pair / combine.experts_per_token) as i32)
5056                    .collect::<Vec<_>>();
5057                let slots = pairs
5058                    .iter()
5059                    .map(|&pair| (pair % combine.experts_per_token) as i32)
5060                    .collect::<Vec<_>>();
5061                let weights = pairs
5062                    .iter()
5063                    .map(|&pair| route_weights[pair])
5064                    .collect::<Vec<_>>();
5065                (token_rows, slots, weights)
5066            })
5067            .collect::<Vec<_>>();
5068
5069        combine.ready = false;
5070        combine.output_generation = None;
5071        combine.broadcast_generation = None;
5072        let root = self
5073            .ranks
5074            .first()
5075            .ok_or("Step owner-grouped combine has no root rank")?;
5076        let _main = root.gpu.enter_main()?;
5077        if root.ctx().ordinal() != combine.root_device {
5078            return Err(format!(
5079                "Step owner-grouped combine root device changed {} != {}",
5080                root.ctx().ordinal(),
5081                combine.root_device
5082            )
5083            .into());
5084        }
5085        for (owner, (token_rows, slots, weights)) in combine.owners.iter_mut().zip(metadata) {
5086            if token_rows.is_empty() {
5087                owner.active_pairs = 0;
5088                continue;
5089            }
5090            root.htod_i32_into(&mut owner.token_rows, &token_rows)?;
5091            root.htod_i32_into(&mut owner.slots, &slots)?;
5092            let mut weight_prefix = owner.weights.slice_mut(0..weights.len());
5093            root.stream().memcpy_htod(&weights, &mut weight_prefix)?;
5094            owner.active_pairs = token_rows.len();
5095        }
5096        combine.tokens = plan.tokens;
5097        combine.pairs = shape.pairs;
5098        combine.projection_generation = plan.generation;
5099        combine.ready = true;
5100        Ok(())
5101    }
5102
5103    pub fn execute_step_grouped_expert_parallel_combine(
5104        &self,
5105        plan: &PreparedStepGroupedExpertParallelGate,
5106        combine: &mut PreparedPeerWeightedRouteCombine,
5107    ) -> Result<(), Box<dyn std::error::Error>> {
5108        if !plan.ready
5109            || plan.executed_generation != Some(plan.generation)
5110            || !combine.ready
5111            || combine.tokens != plan.tokens
5112            || combine.pairs != plan.pairs
5113            || combine.width != plan.input_width
5114            || combine.owners.len() != plan.owners.len()
5115            || combine.projection_generation != plan.generation
5116        {
5117            return Err("Step owner-grouped combine is stale or its geometry changed".into());
5118        }
5119        combine.output_generation = None;
5120        combine.broadcast_generation = None;
5121        for owner in &plan.owners {
5122            if owner.rank == 0 || owner.global_pairs.is_empty() {
5123                continue;
5124            }
5125            let engine = &self.ranks[owner.rank];
5126            let _main = engine.gpu.enter_main()?;
5127            engine.stream().synchronize()?;
5128        }
5129        let root = self
5130            .ranks
5131            .first()
5132            .ok_or("Step owner-grouped combine has no root rank")?;
5133        let _main = root.gpu.enter_main()?;
5134        if root.ctx().ordinal() != combine.root_device {
5135            return Err("Step owner-grouped combine is not resident on the root device".into());
5136        }
5137        for (index, owner) in plan.owners.iter().enumerate() {
5138            let metadata = &combine.owners[index];
5139            if owner.global_pairs.len() != metadata.active_pairs {
5140                return Err(format!(
5141                    "Step owner-grouped combine owner {index} rows {} != metadata {}",
5142                    owner.global_pairs.len(),
5143                    metadata.active_pairs
5144                )
5145                .into());
5146            }
5147            if metadata.active_pairs == 0 {
5148                continue;
5149            }
5150            let values = metadata
5151                .active_pairs
5152                .checked_mul(combine.width)
5153                .ok_or("Step owner-grouped combine peer value count overflow")?;
5154            if owner.rank == 0 {
5155                root.scatter_slot(
5156                    owner.down_workspace.output(),
5157                    &metadata.token_rows,
5158                    &metadata.slots,
5159                    &metadata.weights,
5160                    &mut combine.slots,
5161                    &mut combine.weights,
5162                    combine.width,
5163                    combine.experts_per_token,
5164                    metadata.active_pairs,
5165                )?;
5166            } else {
5167                let source = owner.down_workspace.output().slice(0..values);
5168                let mut destination = combine.peer_staging.slice_mut(0..values);
5169                root.stream().memcpy_dtod(&source, &mut destination)?;
5170                root.scatter_slot(
5171                    &combine.peer_staging,
5172                    &metadata.token_rows,
5173                    &metadata.slots,
5174                    &metadata.weights,
5175                    &mut combine.slots,
5176                    &mut combine.weights,
5177                    combine.width,
5178                    combine.experts_per_token,
5179                    metadata.active_pairs,
5180                )?;
5181            }
5182        }
5183        root.reduce_slots_host(
5184            &combine.slots,
5185            &combine.weights,
5186            &mut combine.output,
5187            combine.width,
5188            combine.experts_per_token,
5189            combine.tokens,
5190        )?;
5191        combine.output_generation = Some(plan.generation);
5192        Ok(())
5193    }
5194
5195    pub fn collect_step_grouped_expert_parallel_combine(
5196        &self,
5197        plan: &PreparedStepGroupedExpertParallelGate,
5198        combine: &PreparedPeerWeightedRouteCombine,
5199    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
5200        if !plan.ready
5201            || combine.output_generation != Some(plan.generation)
5202            || combine.projection_generation != plan.generation
5203        {
5204            return Err("Step owner-grouped combine output is stale or has not executed".into());
5205        }
5206        let root = self
5207            .ranks
5208            .first()
5209            .ok_or("Step owner-grouped combine has no root rank")?;
5210        let _main = root.gpu.enter_main()?;
5211        if root.ctx().ordinal() != combine.root_device {
5212            return Err("Step owner-grouped combine is not resident on the root device".into());
5213        }
5214        root.dtoh_view(&combine.output.slice(0..combine.tokens * combine.width))
5215    }
5216
5217    /// Copy the active root combine result into a caller-owned engine on the same CUDA device.
5218    ///
5219    /// The persistent combine buffer remains reusable by the next route generation; the returned
5220    /// allocation follows the serving runtime's ordinary transient-output ownership.
5221    pub fn copy_step_grouped_expert_parallel_combine_root(
5222        &self,
5223        plan: &PreparedStepGroupedExpertParallelGate,
5224        combine: &PreparedPeerWeightedRouteCombine,
5225        destination: &Engine,
5226    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
5227        if !plan.ready
5228            || combine.output_generation != Some(plan.generation)
5229            || combine.projection_generation != plan.generation
5230        {
5231            return Err("Step owner-grouped combine output is stale or has not executed".into());
5232        }
5233        let root = self
5234            .ranks
5235            .first()
5236            .ok_or("Step owner-grouped combine has no root rank")?;
5237        if root.ctx().ordinal() != combine.root_device
5238            || destination.ctx().ordinal() != combine.root_device
5239        {
5240            return Err(format!(
5241                "Step owner-grouped combine root/destination devices {}/{} != {}",
5242                root.ctx().ordinal(),
5243                destination.ctx().ordinal(),
5244                combine.root_device,
5245            )
5246            .into());
5247        }
5248        let values = combine
5249            .tokens
5250            .checked_mul(combine.width)
5251            .ok_or("Step owner-grouped combine copy size overflow")?;
5252        {
5253            let _main = root.gpu.enter_main()?;
5254            root.stream().synchronize()?;
5255        }
5256        let _main = destination.gpu.enter_main()?;
5257        let mut output = destination.uninit(values)?;
5258        destination
5259            .stream()
5260            .memcpy_dtod(&combine.output.slice(0..values), &mut output)?;
5261        Ok(output)
5262    }
5263
5264    pub fn broadcast_step_grouped_expert_parallel_combine(
5265        &self,
5266        plan: &PreparedStepGroupedExpertParallelGate,
5267        combine: &mut PreparedPeerWeightedRouteCombine,
5268    ) -> Result<(), Box<dyn std::error::Error>> {
5269        if !plan.ready
5270            || combine.output_generation != Some(plan.generation)
5271            || combine.projection_generation != plan.generation
5272            || combine.peer_devices.len() + 1 != self.ranks.len()
5273            || combine.peer_outputs.len() + 1 != self.ranks.len()
5274        {
5275            return Err("Step owner-grouped combine output cannot be broadcast".into());
5276        }
5277        combine.broadcast_generation = None;
5278        let values = combine
5279            .tokens
5280            .checked_mul(combine.width)
5281            .ok_or("Step owner-grouped combine broadcast size overflow")?;
5282        {
5283            let root = self
5284                .ranks
5285                .first()
5286                .ok_or("Step owner-grouped combine has no root rank")?;
5287            let _main = root.gpu.enter_main()?;
5288            if root.ctx().ordinal() != combine.root_device {
5289                return Err("Step owner-grouped combine root device changed".into());
5290            }
5291            root.stream().synchronize()?;
5292        }
5293        let source = &combine.output;
5294        for (index, destination_buffer) in combine.peer_outputs.iter_mut().enumerate() {
5295            let engine = &self.ranks[index + 1];
5296            let _main = engine.gpu.enter_main()?;
5297            if engine.ctx().ordinal() != combine.peer_devices[index] {
5298                return Err(format!(
5299                    "Step owner-grouped combine peer {} device changed",
5300                    index + 1
5301                )
5302                .into());
5303            }
5304            let mut destination = destination_buffer.slice_mut(0..values);
5305            engine
5306                .stream()
5307                .memcpy_dtod(&source.slice(0..values), &mut destination)?;
5308        }
5309        combine.broadcast_generation = Some(plan.generation);
5310        Ok(())
5311    }
5312
5313    pub fn collect_step_grouped_expert_parallel_broadcast(
5314        &self,
5315        plan: &PreparedStepGroupedExpertParallelGate,
5316        combine: &PreparedPeerWeightedRouteCombine,
5317    ) -> Result<Vec<Vec<f32>>, Box<dyn std::error::Error>> {
5318        if !plan.ready
5319            || combine.output_generation != Some(plan.generation)
5320            || combine.broadcast_generation != Some(plan.generation)
5321            || combine.peer_outputs.len() + 1 != self.ranks.len()
5322        {
5323            return Err("Step owner-grouped combine broadcast is stale or incomplete".into());
5324        }
5325        let values = combine
5326            .tokens
5327            .checked_mul(combine.width)
5328            .ok_or("Step owner-grouped combine collection size overflow")?;
5329        let mut outputs = Vec::with_capacity(self.ranks.len());
5330        {
5331            let root = &self.ranks[0];
5332            let _main = root.gpu.enter_main()?;
5333            outputs.push(root.dtoh_view(&combine.output.slice(0..values))?);
5334        }
5335        for (index, output) in combine.peer_outputs.iter().enumerate() {
5336            let engine = &self.ranks[index + 1];
5337            let _main = engine.gpu.enter_main()?;
5338            outputs.push(engine.dtoh_view(&output.slice(0..values))?);
5339        }
5340        Ok(outputs)
5341    }
5342
5343    /// Add routed and replicated shared-expert outputs, then add the attention residual.
5344    pub fn finish_step_grouped_expert_parallel_layer(
5345        &self,
5346        plan: &PreparedStepGroupedExpertParallelGate,
5347        combine: &PreparedPeerWeightedRouteCombine,
5348        shared: &ResidentReplicatedDeviceRows,
5349        residual: &ResidentReplicatedDeviceRows,
5350    ) -> Result<ResidentReplicatedDeviceRows, Box<dyn std::error::Error>> {
5351        validate_replicated_device_rows(&self.ranks, shared)?;
5352        validate_replicated_device_rows(&self.ranks, residual)?;
5353        if !plan.ready
5354            || plan.executed_generation != Some(plan.generation)
5355            || combine.output_generation != Some(plan.generation)
5356            || combine.broadcast_generation != Some(plan.generation)
5357            || combine.projection_generation != plan.generation
5358            || combine.peer_outputs.len() + 1 != self.ranks.len()
5359            || shared.tokens != combine.tokens
5360            || residual.tokens != combine.tokens
5361            || shared.width != combine.width
5362            || residual.width != combine.width
5363        {
5364            return Err("Step full-layer finish inputs are stale or their geometry changed".into());
5365        }
5366        let values = combine
5367            .tokens
5368            .checked_mul(combine.width)
5369            .ok_or("Step full-layer output size overflow")?;
5370        let mut ranks = Vec::with_capacity(self.ranks.len());
5371        for rank in 0..self.ranks.len() {
5372            let engine = &self.ranks[rank];
5373            let _main = engine.gpu.enter_main()?;
5374            let routed = if rank == 0 {
5375                &combine.output
5376            } else {
5377                &combine.peer_outputs[rank - 1]
5378            };
5379            let mut ffn = engine.uninit(values)?;
5380            engine.add(routed, &shared.ranks[rank], &mut ffn, values)?;
5381            let mut output = engine.uninit(values)?;
5382            engine.add(&residual.ranks[rank], &ffn, &mut output, values)?;
5383            ranks.push(output);
5384        }
5385        Ok(ResidentReplicatedDeviceRows {
5386            ranks,
5387            tokens: combine.tokens,
5388            width: combine.width,
5389        })
5390    }
5391
5392    pub fn run_step_grouped_expert_parallel_combine(
5393        &self,
5394        plan: &PreparedStepGroupedExpertParallelGate,
5395        combine: &mut PreparedPeerWeightedRouteCombine,
5396    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
5397        self.execute_step_grouped_expert_parallel_combine(plan, combine)?;
5398        self.collect_step_grouped_expert_parallel_combine(plan, combine)
5399    }
5400
5401    pub fn upload_tensor_parallel(
5402        &self,
5403        gate: E4m3ExpertBank<'_>,
5404        up: E4m3ExpertBank<'_>,
5405        down: E4m3ExpertBank<'_>,
5406    ) -> Result<ResidentTensorParallel, Box<dyn std::error::Error>> {
5407        gate.validate()?;
5408        up.validate()?;
5409        down.validate()?;
5410        if gate.expert_count != up.expert_count || gate.expert_count != down.expert_count {
5411            return Err("TP gate/up/down expert counts differ".into());
5412        }
5413        if gate.in_features != up.in_features || gate.out_features != up.out_features {
5414            return Err("TP gate/up dimensions differ".into());
5415        }
5416        if down.in_features != gate.out_features || down.out_features != gate.in_features {
5417            return Err(format!(
5418                "TP down {}x{} does not invert gate/up {}x{}",
5419                down.out_features, down.in_features, gate.out_features, gate.in_features
5420            )
5421            .into());
5422        }
5423        let tp = self.ranks.len();
5424        validate_column_bank_shape(gate, tp)?;
5425        validate_column_bank_shape(up, tp)?;
5426        validate_row_bank_shape(down, tp)?;
5427
5428        let mut gate_ranks = Vec::with_capacity(tp);
5429        let mut up_ranks = Vec::with_capacity(tp);
5430        let mut down_ranks = Vec::with_capacity(tp);
5431        for (rank, engine) in self.ranks.iter().enumerate() {
5432            gate_ranks.push(upload_column_bank_rank(engine, gate, tp, rank)?);
5433            up_ranks.push(upload_column_bank_rank(engine, up, tp, rank)?);
5434            down_ranks.push(upload_row_bank_rank(engine, down, tp, rank)?);
5435        }
5436        Ok(ResidentTensorParallel {
5437            bank: ResidentTpExpertBank {
5438                gate: gate_ranks,
5439                up: up_ranks,
5440                down: down_ranks,
5441                expert_count: gate.expert_count,
5442                input_width: gate.in_features,
5443                expert_width: gate.out_features,
5444            },
5445        })
5446    }
5447
5448    pub fn run_tensor_parallel_routes(
5449        &self,
5450        experts: &ResidentTensorParallel,
5451        input: &[f32],
5452        tokens: usize,
5453        selected: &[usize],
5454        route_weights: &[f32],
5455        experts_per_token: usize,
5456    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
5457        validate_tp_bank_residency(&self.ranks, &experts.bank)?;
5458        validate_activations(input, tokens, experts.bank.input_width)?;
5459        let pairs = tokens
5460            .checked_mul(experts_per_token)
5461            .ok_or("TP route count overflow")?;
5462        if selected.len() != pairs || route_weights.len() != pairs {
5463            return Err(format!(
5464                "TP routes selected={} weights={} != tokens {tokens} x experts/token \
5465                 {experts_per_token} ({pairs})",
5466                selected.len(),
5467                route_weights.len(),
5468            )
5469            .into());
5470        }
5471        if !route_weights.iter().all(|weight| weight.is_finite()) {
5472            return Err("TP route weights contain a non-finite value".into());
5473        }
5474
5475        let mut output = vec![0.0f32; tokens * experts.bank.input_width];
5476        for token in 0..tokens {
5477            let input_row =
5478                &input[token * experts.bank.input_width..(token + 1) * experts.bank.input_width];
5479            for slot in 0..experts_per_token {
5480                let pair = token * experts_per_token + slot;
5481                let expert = selected[pair];
5482                if expert >= experts.bank.expert_count {
5483                    return Err(format!(
5484                        "TP selected expert {expert} outside 0..{}",
5485                        experts.bank.expert_count
5486                    )
5487                    .into());
5488                }
5489                let down = if self.native_p2p {
5490                    self.run_tensor_parallel_expert_native(&experts.bank, expert, input_row)?
5491                } else {
5492                    let gate =
5493                        self.run_column_bank_expert(&experts.bank.gate, expert, input_row)?;
5494                    let up = self.run_column_bank_expert(&experts.bank.up, expert, input_row)?;
5495                    let activated: Vec<f32> = gate
5496                        .iter()
5497                        .zip(&up)
5498                        .map(|(&gate, &up)| gate / (1.0 + (-gate).exp()) * up)
5499                        .collect();
5500                    debug_assert_eq!(activated.len(), experts.bank.expert_width);
5501                    self.run_row_bank_expert(&experts.bank.down, expert, &activated)?
5502                };
5503                let weight = route_weights[pair];
5504                for (sum, value) in output
5505                    [token * experts.bank.input_width..(token + 1) * experts.bank.input_width]
5506                    .iter_mut()
5507                    .zip(down)
5508                {
5509                    *sum += weight * value;
5510                }
5511            }
5512        }
5513        Ok(output)
5514    }
5515
5516    fn run_column_bank_expert(
5517        &self,
5518        ranks: &[ResidentE4m3ExpertBankRank],
5519        expert: usize,
5520        input: &[f32],
5521    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
5522        let local_out = ranks
5523            .first()
5524            .ok_or("TP column bank has no ranks")?
5525            .out_features;
5526        let mut gathered = vec![0.0f32; local_out * ranks.len()];
5527        for (rank, (engine, bank)) in self.ranks.iter().zip(ranks).enumerate() {
5528            let shard = run_resident_bank_expert(engine, bank, expert, input, 1)?;
5529            gathered[rank * local_out..(rank + 1) * local_out].copy_from_slice(&shard);
5530        }
5531        Ok(gathered)
5532    }
5533
5534    fn run_row_bank_expert(
5535        &self,
5536        ranks: &[ResidentE4m3ExpertBankRank],
5537        expert: usize,
5538        input: &[f32],
5539    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
5540        let local_in = ranks.first().ok_or("TP row bank has no ranks")?.in_features;
5541        if input.len() != local_in * ranks.len() {
5542            return Err(format!(
5543                "TP row input {} != {} ranks x {local_in}",
5544                input.len(),
5545                ranks.len()
5546            )
5547            .into());
5548        }
5549        let out_features = ranks[0].out_features;
5550        let mut reduced = vec![0.0f32; out_features];
5551        for (rank, (engine, bank)) in self.ranks.iter().zip(ranks).enumerate() {
5552            let blocks = bank
5553                .k_blocks
5554                .ok_or("TP row bank is not packed in native K-block order")?;
5555            if blocks * FP8_BLOCK != local_in {
5556                return Err(format!(
5557                    "TP row bank has {blocks} blocks but local input width is {local_in}"
5558                )
5559                .into());
5560            }
5561            for block in 0..blocks {
5562                let global_start = rank * local_in + block * FP8_BLOCK;
5563                let partial = run_resident_bank_expert_block(
5564                    engine,
5565                    bank,
5566                    expert,
5567                    block,
5568                    &input[global_start..global_start + FP8_BLOCK],
5569                )?;
5570                for (sum, value) in reduced.iter_mut().zip(partial) {
5571                    *sum += value;
5572                }
5573            }
5574        }
5575        Ok(reduced)
5576    }
5577
5578    fn run_tensor_parallel_expert_native(
5579        &self,
5580        bank: &ResidentTpExpertBank,
5581        expert: usize,
5582        input: &[f32],
5583    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
5584        if !self.native_p2p || self.ranks.len() < 2 {
5585            return Err("native TP expert execution requires at least two P2P ranks".into());
5586        }
5587        let local_out = bank
5588            .gate
5589            .first()
5590            .ok_or("native TP gate bank has no ranks")?
5591            .out_features;
5592        if local_out * self.ranks.len() != bank.expert_width {
5593            return Err(format!(
5594                "native TP gate shards {}x{local_out} != expert width {}",
5595                self.ranks.len(),
5596                bank.expert_width
5597            )
5598            .into());
5599        }
5600
5601        // The caller's routed input is already host-canonical. Upload once on rank zero, then
5602        // broadcast over peer copies so no other rank receives a host-staged duplicate.
5603        let mut rank_inputs = Vec::with_capacity(self.ranks.len());
5604        let root_input = {
5605            let root = &self.ranks[0];
5606            let _main = root.gpu.enter_main()?;
5607            root.htod(input)?
5608        };
5609        rank_inputs.push(root_input);
5610        for engine in &self.ranks[1..] {
5611            let peer_input = {
5612                let _main = engine.gpu.enter_main()?;
5613                let mut peer_input = engine.uninit(input.len())?;
5614                engine
5615                    .stream()
5616                    .memcpy_dtod(&rank_inputs[0], &mut peer_input)?;
5617                peer_input
5618            };
5619            rank_inputs.push(peer_input);
5620        }
5621
5622        let mut gate_shards = Vec::with_capacity(self.ranks.len());
5623        let mut up_shards = Vec::with_capacity(self.ranks.len());
5624        #[allow(clippy::needless_range_loop)]
5625        // allow: the explicit index loop keeps the offset arithmetic visible and aligned with the device-side indexing
5626        for rank in 0..self.ranks.len() {
5627            gate_shards.push(run_resident_bank_expert_device(
5628                &self.ranks[rank],
5629                &bank.gate[rank],
5630                expert,
5631                &rank_inputs[rank],
5632                1,
5633            )?);
5634            up_shards.push(run_resident_bank_expert_device(
5635                &self.ranks[rank],
5636                &bank.up[rank],
5637                expert,
5638                &rank_inputs[rank],
5639                1,
5640            )?);
5641        }
5642
5643        // Preserve the established canonical activation program for the first native transport
5644        // milestone. The shards move to rank zero over P2P; only the scalar activation expression
5645        // executes on host. A later device-activation increment must earn its own exactness gate.
5646        let gate = self.gather_native_column_shards(&gate_shards, 1, local_out)?;
5647        let up = self.gather_native_column_shards(&up_shards, 1, local_out)?;
5648        let activated = gate
5649            .iter()
5650            .zip(&up)
5651            .map(|(&gate, &up)| gate / (1.0 + (-gate).exp()) * up)
5652            .collect::<Vec<_>>();
5653        debug_assert_eq!(activated.len(), bank.expert_width);
5654
5655        let root_activated = {
5656            let root = &self.ranks[0];
5657            let _main = root.gpu.enter_main()?;
5658            root.htod(&activated)?
5659        };
5660        let mut rank_activated = Vec::with_capacity(self.ranks.len());
5661        for (rank, engine) in self.ranks.iter().enumerate() {
5662            let start = rank * local_out;
5663            let source = root_activated.slice(start..start + local_out);
5664            let local = {
5665                let _main = engine.gpu.enter_main()?;
5666                let mut local = engine.uninit(local_out)?;
5667                engine.stream().memcpy_dtod(&source, &mut local)?;
5668                local
5669            };
5670            rank_activated.push(local);
5671        }
5672
5673        let out_features = bank
5674            .down
5675            .first()
5676            .ok_or("native TP down bank has no ranks")?
5677            .out_features;
5678        let mut reduced = {
5679            let root = &self.ranks[0];
5680            let _main = root.gpu.enter_main()?;
5681            root.htod(&vec![0.0f32; out_features])?
5682        };
5683        let mut remote_partial_keepalive = Vec::new();
5684        #[allow(clippy::needless_range_loop)]
5685        // allow: the explicit index loop keeps the offset arithmetic visible and aligned with the device-side indexing
5686        for rank in 0..self.ranks.len() {
5687            let down = &bank.down[rank];
5688            let blocks = down
5689                .k_blocks
5690                .ok_or("native TP row bank is not packed in checkpoint-block order")?;
5691            if blocks * FP8_BLOCK != local_out {
5692                return Err(format!(
5693                    "native TP rank {rank} has {blocks} blocks but local activation width is \
5694                     {local_out}"
5695                )
5696                .into());
5697            }
5698            for block in 0..blocks {
5699                let start = block * FP8_BLOCK;
5700                let input_block = rank_activated[rank].slice(start..start + FP8_BLOCK);
5701                let partial = run_resident_bank_expert_block_device(
5702                    &self.ranks[rank],
5703                    down,
5704                    expert,
5705                    block,
5706                    &input_block,
5707                )?;
5708                let root_partial = if rank == 0 {
5709                    partial
5710                } else {
5711                    let root = &self.ranks[0];
5712                    let _main = root.gpu.enter_main()?;
5713                    let mut peer_partial = root.uninit(out_features)?;
5714                    root.stream().memcpy_dtod(&partial, &mut peer_partial)?;
5715                    remote_partial_keepalive.push(partial);
5716                    peer_partial
5717                };
5718                let next = {
5719                    let root = &self.ranks[0];
5720                    let _main = root.gpu.enter_main()?;
5721                    let mut next = root.uninit(out_features)?;
5722                    root.add(&reduced, &root_partial, &mut next, out_features)?;
5723                    next
5724                };
5725                reduced = next;
5726            }
5727        }
5728        let output = {
5729            let root = &self.ranks[0];
5730            let _main = root.gpu.enter_main()?;
5731            root.dtoh(&reduced)?
5732        };
5733        drop(remote_partial_keepalive);
5734        Ok(output)
5735    }
5736
5737    /// Gather token-major rank-local columns into one canonical root-device matrix.
5738    pub fn gather_native_column_shards_device(
5739        &self,
5740        shards: &[CudaSlice<f32>],
5741        tokens: usize,
5742        local_out: usize,
5743    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
5744        let shard_len = tokens
5745            .checked_mul(local_out)
5746            .ok_or("native TP gather shard size overflow")?;
5747        if shards.len() != self.ranks.len() || shards.iter().any(|shard| shard.len() != shard_len) {
5748            return Err("native TP gather shard geometry mismatch".into());
5749        }
5750        // PRODUCER FENCE (2026-08-20 flake fix): the root stream peer-reads shards produced on
5751        // the other ranks' streams; without fencing those producers the copy can read a partial
5752        // kernel output.
5753        for engine in &self.ranks[1..] {
5754            let _main = engine.gpu.enter_main()?;
5755            engine.stream().synchronize()?;
5756        }
5757        let root = &self.ranks[0];
5758        let _main = root.gpu.enter_main()?;
5759        let global_out = shards
5760            .len()
5761            .checked_mul(local_out)
5762            .ok_or("native TP gather output width overflow")?;
5763        let gathered_len = tokens
5764            .checked_mul(global_out)
5765            .ok_or("native TP gather output size overflow")?;
5766        let mut gathered = root.uninit(gathered_len)?;
5767        if self.bulk_p2p {
5768            root.place_rows_strided(&shards[0], &mut gathered, local_out, tokens, global_out, 0)?;
5769            if shards.len() > 1 {
5770                let mut staging = root.uninit(shard_len)?;
5771                for (rank, shard) in shards.iter().enumerate().skip(1) {
5772                    root.stream().memcpy_dtod(shard, &mut staging)?;
5773                    root.place_rows_strided(
5774                        &staging,
5775                        &mut gathered,
5776                        local_out,
5777                        tokens,
5778                        global_out,
5779                        rank * local_out,
5780                    )?;
5781                }
5782            }
5783        } else {
5784            for token in 0..tokens {
5785                for (rank, shard) in shards.iter().enumerate() {
5786                    let source = shard.slice(token * local_out..(token + 1) * local_out);
5787                    let start = token * global_out + rank * local_out;
5788                    let mut destination = gathered.slice_mut(start..start + local_out);
5789                    root.stream().memcpy_dtod(&source, &mut destination)?;
5790                }
5791            }
5792        }
5793        Ok(gathered)
5794    }
5795
5796    pub fn gather_native_column_shards(
5797        &self,
5798        shards: &[CudaSlice<f32>],
5799        tokens: usize,
5800        local_out: usize,
5801    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
5802        let gathered = self.gather_native_column_shards_device(shards, tokens, local_out)?;
5803        let root = &self.ranks[0];
5804        let _main = root.gpu.enter_main()?;
5805        root.dtoh(&gathered)
5806    }
5807
5808    pub(crate) fn decode_v2_workspace(&self) -> &std::sync::Mutex<Vec<StepTpDecodeV2Ws>> {
5809        &self.decode_v2
5810    }
5811
5812    /// Build the v2 decode-attention workspace for this layer's geometry on first use, or
5813    /// return the index of the matching one. Attention geometry varies across the trunk
5814    /// (per-layer query-head counts), so workspaces are keyed by their geometry pins — a
5815    /// handful exist per model, never one per layer.
5816    ///
5817    /// Refuses non-F32-resident projections: the v2 driver's bit-exactness claim against v1
5818    /// holds per residency class, and only the mirror class has no per-call weight expansion
5819    /// to hide allocation churn behind.
5820    #[allow(clippy::manual_is_multiple_of)] // allow: divisor is runtime-derived; the modulo form keeps a zero divisor loud (a panic), where is_multiple_of would return false silently
5821    pub(crate) fn decode_v2_ensure(
5822        &self,
5823        e: &Engine,
5824        q_m: &ResidentBf16ColumnParallel,
5825        k_m: &ResidentBf16ColumnParallel,
5826        v_m: &ResidentBf16ColumnParallel,
5827        o_m: &ResidentStepBf16RowParallel,
5828        heads: usize,
5829    ) -> Result<usize, Box<dyn std::error::Error>> {
5830        if self.ranks.len() > 1 && !self.native_p2p {
5831            return Err("step TP decode v2 requires native P2P ranks".into());
5832        }
5833        let ranks = self.ranks.len();
5834        // Residency contract: the canonical-chunk (non-fused) program needs the F32 mirror;
5835        // the fused-kernel door also reads raw checkpoint bf16 directly (halving the weight
5836        // traffic), so bf16 residency is accepted when that door is on.
5837        let fused_door = step_tp_qkv_fused_enabled()?;
5838        let arm_ok = |weight: &ResidentBf16Weight| match weight {
5839            ResidentBf16Weight::F32(_) => true,
5840            ResidentBf16Weight::Bf16(_) => fused_door,
5841        };
5842        for matrix in [q_m, k_m, v_m] {
5843            validate_resident_bf16_ranks(&self.ranks, &matrix.ranks)?;
5844            if matrix.out_features % ranks != 0 || matrix.in_features != q_m.in_features {
5845                return Err("step TP decode v2 QKV geometry mismatch".into());
5846            }
5847            for rank in &matrix.ranks {
5848                if !arm_ok(&rank.weight) {
5849                    return Err("step TP decode v2 requires MEMRA_STEP_TP_F32_MIRROR=1 or \
5850                                MEMRA_STEP_TP_QKV_FUSED=1 (bf16-resident fused kernels)"
5851                        .into());
5852                }
5853            }
5854        }
5855        validate_step_bf16_row_residency(&self.ranks, o_m)?;
5856        for blocks in &o_m.ranks {
5857            for block in blocks {
5858                if !arm_ok(&block.weight) {
5859                    return Err("step TP decode v2 requires MEMRA_STEP_TP_F32_MIRROR=1 or \
5860                                MEMRA_STEP_TP_QKV_FUSED=1 (bf16-resident fused kernels)"
5861                        .into());
5862                }
5863            }
5864        }
5865        if v_m.out_features != k_m.out_features
5866            || o_m.in_features != q_m.out_features
5867            || heads == 0
5868            || heads % ranks != 0
5869        {
5870            return Err("step TP decode v2 K/V/O geometry mismatch".into());
5871        }
5872        let local_q_dim = q_m.out_features / ranks;
5873        let local_kv_dim = k_m.out_features / ranks;
5874        let o_out = o_m.out_features;
5875        let o_block_cols = o_m.canonical_chunk_cols;
5876        let blocks_per_rank = o_m.ranks.first().map(Vec::len).unwrap_or(0);
5877        if blocks_per_rank == 0
5878            || o_m
5879                .ranks
5880                .iter()
5881                .any(|blocks| blocks.len() != blocks_per_rank)
5882            || blocks_per_rank * o_block_cols * ranks != o_m.in_features
5883        {
5884            return Err("step TP decode v2 O canonical block grid mismatch".into());
5885        }
5886
5887        let mut guard = self
5888            .decode_v2
5889            .lock()
5890            .map_err(|_| "step TP decode v2 workspace lock is poisoned")?;
5891        if let Some(index) = guard.iter().position(|ws| {
5892            ws.local_q_dim == local_q_dim
5893                && ws.local_kv_dim == local_kv_dim
5894                && ws.heads == heads
5895                && ws.o_out == o_out
5896                && ws.o_block_cols == o_block_cols
5897                && ws.blocks_per_rank == blocks_per_rank
5898                && ws.e_device == e.ctx().ordinal()
5899                && ws.q.len() == ranks
5900        }) {
5901            return Ok(index);
5902        }
5903
5904        let mut q_raw = Vec::with_capacity(ranks);
5905        let mut k_raw = Vec::with_capacity(ranks);
5906        let mut v_raw = Vec::with_capacity(ranks);
5907        let mut q = Vec::with_capacity(ranks);
5908        let mut k = Vec::with_capacity(ranks);
5909        let mut pos = Vec::with_capacity(ranks);
5910        let mut gate = Vec::with_capacity(ranks);
5911        let mut attn_out = Vec::with_capacity(ranks);
5912        let mut gated = Vec::with_capacity(ranks);
5913        let mut fuse_ctr = Vec::with_capacity(ranks);
5914        let mut o_partials = Vec::with_capacity(ranks);
5915        let mut ev_rank = Vec::with_capacity(ranks);
5916        let direct_join = oproj_direct_on();
5917        for (rank, engine) in self.ranks.iter().enumerate() {
5918            let _main = engine.gpu.enter_main()?;
5919            q_raw.push(engine.uninit(local_q_dim)?);
5920            k_raw.push(engine.uninit(local_kv_dim)?);
5921            v_raw.push(engine.uninit(local_kv_dim)?);
5922            q.push(engine.uninit(local_q_dim)?);
5923            k.push(engine.uninit(local_kv_dim)?);
5924            pos.push(engine.htod_i32(&[0])?);
5925            fuse_ctr.push(engine.stream().clone_htod(&[0u32])?);
5926            gate.push(engine.uninit(heads / ranks)?);
5927            attn_out.push(engine.uninit(local_q_dim)?);
5928            gated.push(engine.uninit(local_q_dim)?);
5929            let mut rank_partials = Vec::with_capacity(blocks_per_rank);
5930            for _ in 0..blocks_per_rank {
5931                // Direct join: peer ranks' partials live on ROOT so the b4 kernel's
5932                // stores land there over P2P (UVA) and no pull copy is needed.
5933                if direct_join && rank != 0 {
5934                    let root = &self.ranks[0];
5935                    let _root_main = root.gpu.enter_main()?;
5936                    rank_partials.push(root.uninit(o_out)?);
5937                } else {
5938                    rank_partials.push(engine.uninit(o_out)?);
5939                }
5940            }
5941            o_partials.push(rank_partials);
5942            ev_rank.push(engine.ctx().new_event(None)?);
5943        }
5944        use cudarc::driver::DevicePtr;
5945        let mut raw_o_partials = Vec::with_capacity(ranks);
5946        let mut raw_k = Vec::with_capacity(ranks);
5947        let mut raw_v_raw = Vec::with_capacity(ranks);
5948        for rank in 0..ranks {
5949            let engine = &self.ranks[rank];
5950            {
5951                let _main = engine.gpu.enter_main()?;
5952                let stream = engine.stream();
5953                let (k_ptr, _k_guard) = k[rank].device_ptr(&stream);
5954                let (v_ptr, _v_guard) = v_raw[rank].device_ptr(&stream);
5955                raw_k.push(k_ptr);
5956                raw_v_raw.push(v_ptr);
5957            }
5958            let partial_engine = if direct_join && rank != 0 {
5959                &self.ranks[0]
5960            } else {
5961                engine
5962            };
5963            let _main = partial_engine.gpu.enter_main()?;
5964            let stream = partial_engine.stream();
5965            let mut rank_raw = Vec::with_capacity(blocks_per_rank);
5966            for partial in &o_partials[rank] {
5967                let (ptr, _guard) = partial.device_ptr(&stream);
5968                rank_raw.push(ptr);
5969            }
5970            raw_o_partials.push(rank_raw);
5971        }
5972        let root = &self.ranks[0];
5973        let (peer_partial, reduce_a, reduce_b, zeros, k_shadow, v_shadow, ev_refresh, ev_oproj) = {
5974            let _main = root.gpu.enter_main()?;
5975            (
5976                root.uninit(o_out)?,
5977                root.uninit(o_out)?,
5978                root.uninit(o_out)?,
5979                root.htod(&vec![0.0f32; o_out])?,
5980                root.uninit(ranks * local_kv_dim)?,
5981                root.uninit(ranks * local_kv_dim)?,
5982                root.ctx().new_event(None)?,
5983                root.ctx().new_event(None)?,
5984            )
5985        };
5986        let (raw_peer_partial, raw_k_shadow, raw_v_shadow) = {
5987            let _main = root.gpu.enter_main()?;
5988            let stream = root.stream();
5989            let (peer, _peer_guard) = peer_partial.device_ptr(&stream);
5990            let (k, _k_guard) = k_shadow.device_ptr(&stream);
5991            let (v, _v_guard) = v_shadow.device_ptr(&stream);
5992            (peer, k, v)
5993        };
5994        let (gate_e, ev_entry) = {
5995            let _main = e.gpu.enter_main()?;
5996            (e.uninit(heads)?, e.ctx().new_event(None)?)
5997        };
5998        let raw_attn_in = Vec::new();
5999        let raw_pos = Vec::new();
6000        guard.push(StepTpDecodeV2Ws {
6001            tcol_q: Vec::new(),
6002            tcol_k: Vec::new(),
6003            tcol_v: Vec::new(),
6004            tcol_g: Vec::new(),
6005            tcol_in: Vec::new(),
6006            tcol_cap: 0,
6007            w8_aq: Vec::new(),
6008            w8_ad: Vec::new(),
6009            w8_in: 0,
6010            w8o_aq: Vec::new(),
6011            w8o_ad: Vec::new(),
6012            w8o_in: 0,
6013            w8t_aq: Vec::new(),
6014            w8t_ad: Vec::new(),
6015            w8t_in: 0,
6016            w8t_oaq: Vec::new(),
6017            w8t_oad: Vec::new(),
6018            w8t_oin: 0,
6019            w8t_cap: 0,
6020            fa2_q: Vec::new(),
6021            fa2_gate: Vec::new(),
6022            fa2_gated: Vec::new(),
6023            fa2_cap: 0,
6024            rope_k_t: Vec::new(),
6025            rope_ctr_t: Vec::new(),
6026            rope_pos_t: Vec::new(),
6027            rows_tabs: Vec::new(),
6028            rows_tab_t: Vec::new(),
6029            rows_tab_shadow: Vec::new(),
6030            tcol_gated: Vec::new(),
6031            tcol_opart: Vec::new(),
6032            tcol_opeer: None,
6033            tcol_omix: None,
6034            tcol_ocap: 0,
6035            q_raw,
6036            k_raw,
6037            v_raw,
6038            q,
6039            k,
6040            pos,
6041            fuse_ctr,
6042            gate,
6043            attn_out,
6044            gated,
6045            o_partials,
6046            raw_o_partials,
6047            raw_k,
6048            raw_v_raw,
6049            ev_rank,
6050            peer_partial,
6051            reduce_a,
6052            reduce_b,
6053            zeros,
6054            k_shadow,
6055            v_shadow,
6056            ev_refresh,
6057            ev_oproj,
6058            gate_e,
6059            attn_in: Vec::new(),
6060            h_stage: None,
6061            pos_stage: None,
6062            raw_h_stage: 0,
6063            raw_pos_stage: 0,
6064            raw_attn_in,
6065            raw_pos,
6066            raw_o_partial1: 0,
6067            raw_peer_partial,
6068            raw_k1: 0,
6069            raw_v1: 0,
6070            raw_k_shadow,
6071            raw_v_shadow,
6072            raw_mixed_stage_e: 0,
6073            raw_reduce_a: 0,
6074            raw_shadow_stage_e: (0, 0),
6075            ev_entry,
6076            e_device: e.ctx().ordinal(),
6077            local_q_dim,
6078            local_kv_dim,
6079            heads,
6080            o_out,
6081            o_block_cols,
6082            blocks_per_rank,
6083        });
6084        eprintln!(
6085            "[step-tp-decode-v2] workspace ranks={ranks} local_q={local_q_dim} \
6086             local_kv={local_kv_dim} heads={heads} o_blocks={blocks_per_rank}x{o_block_cols} \
6087             residency=persistent ordering=evented performance_claim=false"
6088        );
6089        Ok(guard.len() - 1)
6090    }
6091
6092    /// v2 phase 1: replicate the layer input, project QKV, norm, rope, and stage the gate —
6093    /// all into the persistent workspace, ordered by events instead of host syncs.
6094    ///
6095    /// The caller must have queued every producer of `h`, `pos_d`, and `gate_raw` on `e`'s
6096    /// stream BEFORE this call: `ev_entry` is recorded once here and every rank stream waits
6097    /// on it (the entry fence also guards workspace reuse across layers — any consumer of the
6098    /// previous layer's outputs was queued on `e`'s stream before this record).
6099    #[allow(clippy::too_many_arguments)]
6100    /// T-COLUMN verify precompute (spec MTP): stage T input rows to every rank and run the
6101    /// weight-amortized qkvg_tcol per rank into the ws slabs. Rope/norm/append stay per
6102    /// column in the unmodified t=1 program (defer_norm_rope contract). Bit-exact per
6103    /// column vs the t=1 kernel by construction.
6104    #[allow(clippy::too_many_arguments)]
6105    pub fn decode_v2_input_qkv_tcol(
6106        &self,
6107        ws_index: usize,
6108        e: &Engine,
6109        h_t: &CudaSlice<f32>,
6110        t: usize,
6111        q_m: &ResidentBf16ColumnParallel,
6112        k_m: &ResidentBf16ColumnParallel,
6113        v_m: &ResidentBf16ColumnParallel,
6114        gate_shards: Option<StepTpGateShards<'_>>,
6115    ) -> Result<(), Box<dyn std::error::Error>> {
6116        let ranks = self.ranks.len();
6117        let mut guard = self
6118            .decode_v2
6119            .lock()
6120            .map_err(|_| "step TP decode v2 workspace lock is poisoned")?;
6121        let ws = guard
6122            .get_mut(ws_index)
6123            .ok_or("step TP decode v2 workspace index out of range")?;
6124        let in_f = q_m.in_features;
6125        if h_t.len() < t * in_f || t == 0 || t > 32 {
6126            return Err("decode_v2_input_qkv_tcol geometry".into());
6127        }
6128        // Lazily arm the slabs to capacity.
6129        if ws.tcol_cap < t || ws.tcol_q.len() != ranks {
6130            ws.tcol_q.clear();
6131            ws.tcol_k.clear();
6132            ws.tcol_v.clear();
6133            ws.tcol_g.clear();
6134            ws.tcol_in.clear();
6135            for engine in &self.ranks {
6136                let _m = engine.gpu.enter_main()?;
6137                ws.tcol_q.push(engine.uninit(32 * ws.local_q_dim)?);
6138                ws.tcol_k.push(engine.uninit(32 * ws.local_kv_dim)?);
6139                ws.tcol_v.push(engine.uninit(32 * ws.local_kv_dim)?);
6140                ws.tcol_g
6141                    .push(engine.uninit(32 * (ws.heads / ranks).max(1))?);
6142                ws.tcol_in.push(engine.uninit(32 * in_f)?);
6143            }
6144            ws.tcol_cap = 32;
6145        }
6146        // Stage the T input rows on e, fence, per-rank pull + tcol launch.
6147        use cudarc::driver::DevicePtr;
6148        let raw_src = {
6149            let _main = e.gpu.enter_main()?;
6150            let stream = e.stream();
6151            let (p, _g) = h_t.device_ptr(&stream);
6152            ws.ev_entry.record(&stream)?;
6153            p
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            let raw_dst = {
6160                let stream = engine.stream();
6161                let (p, _g) = ws.tcol_in[rank].device_ptr(&stream);
6162                p
6163            };
6164            raw_copy_bytes(raw_dst, raw_src, t * in_f * 4, engine)?;
6165            let out_g = match &gate_shards {
6166                Some(_) => ws.heads / ranks,
6167                None => 0,
6168            };
6169            match (
6170                &q_m.ranks[rank].weight,
6171                &k_m.ranks[rank].weight,
6172                &v_m.ranks[rank].weight,
6173            ) {
6174                (
6175                    ResidentBf16Weight::Bf16(wq),
6176                    ResidentBf16Weight::Bf16(wk),
6177                    ResidentBf16Weight::Bf16(wv),
6178                ) => {
6179                    let wg = match &gate_shards {
6180                        Some(StepTpGateShards::Bf16(shards)) => &shards[rank],
6181                        Some(StepTpGateShards::F32(_)) => {
6182                            return Err(
6183                                "tcol verify: gate shard class does not match bf16 QKV".into()
6184                            );
6185                        }
6186                        None => wq,
6187                    };
6188                    let StepTpDecodeV2Ws {
6189                        tcol_q,
6190                        tcol_k,
6191                        tcol_v,
6192                        tcol_g,
6193                        tcol_in,
6194                        local_q_dim,
6195                        local_kv_dim,
6196                        w8t_aq,
6197                        w8t_ad,
6198                        w8t_in,
6199                        w8t_cap,
6200                        ..
6201                    } = &mut *ws;
6202                    // MEMRA_TCOL_REFKERN=1 (bisect): fill the slabs via the t=1 kernel per
6203                    // column — separates driver bugs from tcol-kernel bugs.
6204                    static REFK: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
6205                    let refk = *REFK
6206                        .get_or_init(|| std::env::var("MEMRA_TCOL_REFKERN").as_deref() == Ok("1"));
6207                    if refk {
6208                        let lq = *local_q_dim;
6209                        let lkv = *local_kv_dim;
6210                        let mut hrow = engine.uninit(in_f)?;
6211                        let mut qr = engine.uninit(lq)?;
6212                        let mut kr = engine.uninit(lkv)?;
6213                        let mut vr = engine.uninit(lkv)?;
6214                        let mut gr = engine.uninit(out_g.max(1))?;
6215                        for c in 0..t {
6216                            {
6217                                let mut dst = hrow.slice_mut(0..in_f);
6218                                engine.stream().memcpy_dtod(
6219                                    &tcol_in[rank].slice(c * in_f..(c + 1) * in_f),
6220                                    &mut dst,
6221                                )?;
6222                            }
6223                            engine.matvec_bf16_qkvg_into(
6224                                wq, wk, wv, wg, &hrow, &mut qr, &mut kr, &mut vr, &mut gr, in_f,
6225                                lq, lkv, out_g,
6226                            )?;
6227                            let stream = engine.stream();
6228                            {
6229                                let mut dst = tcol_q[rank].slice_mut(c * lq..(c + 1) * lq);
6230                                stream.memcpy_dtod(&qr.slice(0..lq), &mut dst)?;
6231                            }
6232                            {
6233                                let mut dst = tcol_k[rank].slice_mut(c * lkv..(c + 1) * lkv);
6234                                stream.memcpy_dtod(&kr.slice(0..lkv), &mut dst)?;
6235                            }
6236                            {
6237                                let mut dst = tcol_v[rank].slice_mut(c * lkv..(c + 1) * lkv);
6238                                stream.memcpy_dtod(&vr.slice(0..lkv), &mut dst)?;
6239                            }
6240                            if out_g > 0 {
6241                                let mut dst = tcol_g[rank].slice_mut(c * out_g..(c + 1) * out_g);
6242                                stream.memcpy_dtod(&gr.slice(0..out_g), &mut dst)?;
6243                            }
6244                        }
6245                    } else if crate::step_tp_w8_on()
6246                        && q_m.ranks[rank].q8.is_some()
6247                        && k_m.ranks[rank].q8.is_some()
6248                        && v_m.ranks[rank].q8.is_some()
6249                        && in_f.is_multiple_of(32)
6250                    {
6251                        // MEMRA_STEP_TP_W8 on the VERIFY walk. nsys put the bf16 tcol QKV at
6252                        // 12.3% of spec GPU time and the bf16 tcol o_proj at 24.8% — the door
6253                        // had only ever replaced the DECODE kernels, so 37% of the verify still
6254                        // streamed bf16 weights. One q8 launch over all t columns; the gate rows
6255                        // stay bf16 as on the decode side.
6256                        if *w8t_in != in_f || *w8t_cap < t || w8t_aq.len() != ranks {
6257                            w8t_aq.clear();
6258                            w8t_ad.clear();
6259                            for e_rank in &self.ranks {
6260                                let _m = e_rank.gpu.enter_main()?;
6261                                w8t_aq.push(e_rank.alloc_i8_uninit(32 * in_f)?);
6262                                w8t_ad.push(e_rank.alloc_uninit::<f32>(32 * (in_f / 32))?);
6263                            }
6264                            *w8t_in = in_f;
6265                            *w8t_cap = 32;
6266                        }
6267                        engine.quantize_q8_1_into(
6268                            &tcol_in[rank],
6269                            t,
6270                            in_f,
6271                            &mut w8t_aq[rank],
6272                            &mut w8t_ad[rank],
6273                        )?;
6274                        engine.qmatvec_q8_0_qkv_rp_t_into(
6275                            q_m.ranks[rank].q8.as_ref().unwrap(),
6276                            k_m.ranks[rank].q8.as_ref().unwrap(),
6277                            v_m.ranks[rank].q8.as_ref().unwrap(),
6278                            &w8t_aq[rank],
6279                            &w8t_ad[rank],
6280                            &mut tcol_q[rank],
6281                            &mut tcol_k[rank],
6282                            &mut tcol_v[rank],
6283                            in_f,
6284                            *local_q_dim,
6285                            *local_kv_dim,
6286                            t,
6287                        )?;
6288                        if out_g > 0 {
6289                            engine.matvec_bf16_rows_into(
6290                                wg,
6291                                &tcol_in[rank],
6292                                &mut tcol_g[rank],
6293                                in_f,
6294                                out_g,
6295                                t,
6296                            )?;
6297                        }
6298                    } else {
6299                        engine.matvec_bf16_qkvg_tcol_into(
6300                            wq,
6301                            wk,
6302                            wv,
6303                            wg,
6304                            &tcol_in[rank],
6305                            &mut tcol_q[rank],
6306                            &mut tcol_k[rank],
6307                            &mut tcol_v[rank],
6308                            &mut tcol_g[rank],
6309                            in_f,
6310                            *local_q_dim,
6311                            *local_kv_dim,
6312                            out_g,
6313                            t,
6314                        )?;
6315                    }
6316                }
6317                _ => return Err("tcol verify requires bf16-resident fused QKV".into()),
6318            }
6319        }
6320        Ok(())
6321    }
6322
6323    /// MEMRA_TCOL_OPROJ eligibility: the defer replaces exactly the o_fused direct-join
6324    /// finish (bf16 b4 kernel, 2 ranks, 4 canonical blocks) with the shadow gathers
6325    /// skipped — so it requires the same doors that arm dictate that finish shape.
6326    pub(crate) fn decode_v2_oproj_tcol_eligible(
6327        &self,
6328        ws: &StepTpDecodeV2Ws,
6329        o_m: &ResidentStepBf16RowParallel,
6330    ) -> bool {
6331        self.ranks.len() == 2
6332            && ws.blocks_per_rank == 4
6333            && step_tp_qkv_fused_enabled().unwrap_or(false)
6334            && no_local_shadow_on()
6335            && std::env::var("MEMRA_B4_X2").as_deref() != Ok("1")
6336            && o_m
6337                .ranks
6338                .iter()
6339                .flatten()
6340                .all(|block| matches!(block.weight, ResidentBf16Weight::Bf16(_)))
6341    }
6342
6343    /// MEMRA_SPEC_FA2 stash: copy this column's per-rank post-rope q and gate rows into
6344    /// the fa2 slabs (rank-stream ordered behind the rope/append that produced them), and
6345    /// give `e` the same anti-dependency wait the skipped finish provided (next column's
6346    /// h/pos re-staging must not overtake this column's rank pulls).
6347    pub(crate) fn decode_v2_stash_fa2(
6348        &self,
6349        ws: &mut StepTpDecodeV2Ws,
6350        e: &Engine,
6351        col: usize,
6352    ) -> Result<(), Box<dyn std::error::Error>> {
6353        let ranks = self.ranks.len();
6354        if col >= 32 {
6355            return Err("decode_v2_stash_fa2 column out of range".into());
6356        }
6357        let lq = ws.local_q_dim;
6358        let lg = (ws.heads / ranks).max(1);
6359        if ws.fa2_cap < 32 || ws.fa2_q.len() != ranks || ws.rows_tab_t.len() != ranks {
6360            ws.fa2_q.clear();
6361            ws.fa2_gate.clear();
6362            ws.fa2_gated.clear();
6363            ws.rope_k_t.clear();
6364            ws.rope_ctr_t.clear();
6365            ws.rope_pos_t.clear();
6366            ws.rows_tab_t.clear();
6367            for engine in &self.ranks {
6368                let _m = engine.gpu.enter_main()?;
6369                ws.fa2_q.push(engine.uninit(32 * lq)?);
6370                ws.fa2_gate.push(engine.uninit(32 * lg)?);
6371                ws.fa2_gated.push(engine.uninit(32 * lq)?);
6372                ws.rope_k_t.push(engine.uninit(32 * ws.local_kv_dim)?);
6373                ws.rope_ctr_t.push(engine.stream().clone_htod(&[0u32; 32])?);
6374                ws.rope_pos_t.push(engine.htod_i32(&[0i32; 32])?);
6375                ws.rows_tab_t
6376                    .push(engine.stream().clone_htod(&[0u64; 32 * 6])?);
6377            }
6378            ws.rows_tabs = (0..ranks).map(|_| Default::default()).collect();
6379            ws.fa2_cap = 32;
6380        }
6381        for rank in 0..ranks {
6382            let engine = &self.ranks[rank];
6383            let _main = engine.gpu.enter_main()?;
6384            {
6385                let mut dst = ws.fa2_q[rank].slice_mut(col * lq..(col + 1) * lq);
6386                engine
6387                    .stream()
6388                    .memcpy_dtod(&ws.q[rank].slice(0..lq), &mut dst)?;
6389            }
6390            {
6391                let mut dst = ws.fa2_gate[rank].slice_mut(col * lg..(col + 1) * lg);
6392                engine
6393                    .stream()
6394                    .memcpy_dtod(&ws.gate[rank].slice(0..lg), &mut dst)?;
6395            }
6396            ws.ev_rank[rank].record(&engine.stream())?;
6397        }
6398        {
6399            let _main = e.gpu.enter_main()?;
6400            for ev in ws.ev_rank.iter() {
6401                e.stream().wait(ev)?;
6402            }
6403        }
6404        Ok(())
6405    }
6406
6407    /// MEMRA_SPEC_FA2 join: after BOTH verify columns stashed (their appends landed in
6408    /// rank-stream order), run ONE fa_decode_dcw2 per rank over the shared KV stream —
6409    /// two query rows, per-row causal bounds, per-row combine+gate — then land the two
6410    /// gated rows in the o-tcol slabs and reuse the weight-amortized o_proj join.
6411    /// Returns the [2, o_out] `mixed` slab on `e`. The caller's precheck enforced the
6412    /// equal-partition guard (boundary rounds never arm the defer).
6413    #[allow(clippy::too_many_arguments)]
6414    #[allow(dead_code)] // allow: banked MEMRA_SPEC_FA2 arm; kept as the named seam its precheck twin documents
6415    pub(crate) fn decode_v2_spec_fa2_join(
6416        &self,
6417        ws_index: usize,
6418        e: &Engine,
6419        o_m: &ResidentStepBf16RowParallel,
6420        kv: &ResidentTpKvCache,
6421        head_dim: usize,
6422        window: usize,
6423        bucket_max: usize,
6424        scale: f32,
6425    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
6426        let ranks = self.ranks.len();
6427        // Engagement receipt: a vacuous gate (precheck never passing) must be visible.
6428        static ONCE: std::sync::Once = std::sync::Once::new();
6429        ONCE.call_once(|| eprintln!("[spec-fa2] joined T=2 attention ENGAGED"));
6430        {
6431            let mut guard = self
6432                .decode_v2
6433                .lock()
6434                .map_err(|_| "step TP decode v2 workspace lock is poisoned")?;
6435            let ws = guard
6436                .get_mut(ws_index)
6437                .ok_or("step TP decode v2 workspace index out of range")?;
6438            if ws.fa2_cap < 2 || ws.fa2_q.len() != ranks {
6439                return Err("spec fa2 join without stashed columns".into());
6440            }
6441            let lq = ws.local_q_dim;
6442            let local_heads = (ws.heads / ranks).max(1);
6443            let local_kv_heads = (ws.local_kv_dim / head_dim).max(1);
6444            let capacity = kv.physical_capacity();
6445            let (k_tok_bytes, v_tok_bytes) = (kv.k_tok_bytes(), kv.v_tok_bytes());
6446            // Arm the o-tcol slabs if the oproj door never ran this boot (same shapes).
6447            if ws.tcol_ocap < 2 || ws.tcol_gated.len() != ranks {
6448                ws.tcol_gated.clear();
6449                ws.tcol_opart.clear();
6450                for engine in &self.ranks {
6451                    let _m = engine.gpu.enter_main()?;
6452                    ws.tcol_gated.push(engine.uninit(32 * lq)?);
6453                    ws.tcol_opart.push(engine.uninit(32 * ws.o_out)?);
6454                }
6455                let root = &self.ranks[0];
6456                let _m = root.gpu.enter_main()?;
6457                ws.tcol_opeer = Some(root.uninit(32 * ws.o_out)?);
6458                ws.tcol_omix = Some(root.uninit(32 * ws.o_out)?);
6459                ws.tcol_ocap = 32;
6460            }
6461            for rank in 0..ranks {
6462                let engine = &self.ranks[rank];
6463                let _main = engine.gpu.enter_main()?;
6464                let rank_cache = kv
6465                    .rank(rank)
6466                    .ok_or("spec fa2 join lost its KV cache rank")?;
6467                let k_ring = engine.view_u8_range(rank_cache.k(), 0, capacity * k_tok_bytes);
6468                let v_ring = engine.view_u8_range(rank_cache.v(), 0, capacity * v_tok_bytes);
6469                {
6470                    let StepTpDecodeV2Ws {
6471                        fa2_q,
6472                        fa2_gate,
6473                        fa2_gated,
6474                        ..
6475                    } = &mut *ws;
6476                    engine.fa_decode_dcw2(
6477                        &fa2_q[rank],
6478                        &k_ring,
6479                        &v_ring,
6480                        &mut fa2_gated[rank],
6481                        head_dim,
6482                        local_heads,
6483                        local_kv_heads,
6484                        rank_cache.len_d(),
6485                        rank_cache.base_d(),
6486                        window,
6487                        bucket_max,
6488                        scale,
6489                        k_tok_bytes,
6490                        v_tok_bytes,
6491                        &fa2_gate[rank],
6492                    )?;
6493                }
6494                // Both gated rows are contiguous [2, lq] — exactly columns 0..2 of the
6495                // o-tcol slab layout. One dtod, in rank-stream order behind the fa.
6496                let StepTpDecodeV2Ws {
6497                    fa2_gated,
6498                    tcol_gated,
6499                    ..
6500                } = &mut *ws;
6501                let mut dst = tcol_gated[rank].slice_mut(0..2 * lq);
6502                engine
6503                    .stream()
6504                    .memcpy_dtod(&fa2_gated[rank].slice(0..2 * lq), &mut dst)?;
6505            }
6506        }
6507        self.decode_v2_oproj_tcol(ws_index, e, o_m, 2)
6508    }
6509
6510    /// FULL T-ROW ATTENTION PASS over per-row session tables (batched serving): reads
6511    /// the tcol raw-projection slabs, runs ONE rope/append rows launch + ONE fa rows
6512    /// launch + ONE combine per rank (gate straight from the tcol gate slab), then the
6513    /// o_proj tcol join — the whole per-row attention loop in 3 launches/rank/layer.
6514    /// Per-(row, head) programs are the t=1 kernels verbatim; each row appends to and
6515    /// attends its OWN session. `session_parts[rank][row]` = {k_plane, v_plane, len_ptr,
6516    /// base_ptr}; `tab_keys[rank]` keys the per-rank combined-table cache (caller folds
6517    /// layer + session-set + base-arming into it); `stage_pos` stages the position slab
6518    /// (positions are constant across layers within a tick — stage on the first layer).
6519    #[allow(clippy::too_many_arguments)]
6520    pub(crate) fn decode_v2_rope_fa_rows(
6521        &self,
6522        ws_index: usize,
6523        e: &Engine,
6524        o_m: &ResidentStepBf16RowParallel,
6525        session_parts: &[Vec<[u64; 4]>],
6526        tab_keys: &[u64],
6527        positions: &[i32],
6528        stage_pos: bool,
6529        same_session: bool,
6530        q_norms: &[CudaSlice<f32>],
6531        k_norms: &[CudaSlice<f32>],
6532        rope_freqs: &[Option<&crate::CudaSlice<f32>>],
6533        t: usize,
6534        head_dim: usize,
6535        n_rot: usize,
6536        window: usize,
6537        max_ns: usize,
6538        scale: f32,
6539        k_tok_bytes: usize,
6540        v_tok_bytes: usize,
6541        eps: f32,
6542        rope_base: f32,
6543    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
6544        use cudarc::driver::DevicePtr;
6545        let ranks = self.ranks.len();
6546        if session_parts.len() != ranks || tab_keys.len() != ranks || positions.len() < t {
6547            return Err("rope fa rows geometry".into());
6548        }
6549        {
6550            let mut guard = self
6551                .decode_v2
6552                .lock()
6553                .map_err(|_| "step TP decode v2 workspace lock is poisoned")?;
6554            let ws = guard
6555                .get_mut(ws_index)
6556                .ok_or("step TP decode v2 workspace index out of range")?;
6557            if ws.tcol_cap < t || ws.tcol_q.len() != ranks {
6558                return Err("rope fa rows without tcol slabs".into());
6559            }
6560            let lq = ws.local_q_dim;
6561            let lkv = ws.local_kv_dim;
6562            let lg = (ws.heads / ranks).max(1);
6563            let local_heads = (ws.heads / ranks).max(1);
6564            let local_kv_heads = (lkv / head_dim).max(1);
6565            // Arm the fa2/rope slabs (shared with the stash path).
6566            if ws.fa2_cap < 32 || ws.fa2_q.len() != ranks || ws.rows_tab_t.len() != ranks {
6567                ws.fa2_q.clear();
6568                ws.fa2_gate.clear();
6569                ws.fa2_gated.clear();
6570                ws.rope_k_t.clear();
6571                ws.rope_ctr_t.clear();
6572                ws.rope_pos_t.clear();
6573                ws.rows_tab_t.clear();
6574                for engine in &self.ranks {
6575                    let _m = engine.gpu.enter_main()?;
6576                    ws.fa2_q.push(engine.uninit(32 * lq)?);
6577                    ws.fa2_gate.push(engine.uninit(32 * lg)?);
6578                    ws.fa2_gated.push(engine.uninit(32 * lq)?);
6579                    ws.rope_k_t.push(engine.uninit(32 * lkv)?);
6580                    ws.rope_ctr_t.push(engine.stream().clone_htod(&[0u32; 32])?);
6581                    ws.rope_pos_t.push(engine.htod_i32(&[0i32; 32])?);
6582                    ws.rows_tab_t
6583                        .push(engine.stream().clone_htod(&[0u64; 32 * 6])?);
6584                }
6585                ws.rows_tabs = (0..ranks).map(|_| Default::default()).collect();
6586                ws.fa2_cap = 32;
6587            }
6588            if ws.tcol_ocap < t || ws.tcol_gated.len() != ranks {
6589                ws.tcol_gated.clear();
6590                ws.tcol_opart.clear();
6591                for engine in &self.ranks {
6592                    let _m = engine.gpu.enter_main()?;
6593                    ws.tcol_gated.push(engine.uninit(32 * lq)?);
6594                    ws.tcol_opart.push(engine.uninit(32 * ws.o_out)?);
6595                }
6596                let root = &self.ranks[0];
6597                let _m = root.gpu.enter_main()?;
6598                ws.tcol_opeer = Some(root.uninit(32 * ws.o_out)?);
6599                ws.tcol_omix = Some(root.uninit(32 * ws.o_out)?);
6600                ws.tcol_ocap = 32;
6601            }
6602            for rank in 0..ranks {
6603                let engine = &self.ranks[rank];
6604                let _main = engine.gpu.enter_main()?;
6605                if stage_pos {
6606                    let host: Vec<i32> = positions[..t].to_vec();
6607                    let mut view = ws.rope_pos_t[rank].slice_mut(0..t);
6608                    engine.stream().memcpy_htod(&host, &mut view)?;
6609                }
6610                // Combined 6-word table {k, v, len, base, ctr, back}; ctr = this rank's
6611                // per-row counter slab. Built from the pointers the CALLER just read off
6612                // the live distributed cache, and RESTAGED into a persistent slab before
6613                // every launch (MEMRA_ROWS_TAB_RESTAGE, default ON).
6614                //
6615                // The `rows_tabs` memo this replaces was keyed by a hash of
6616                // (k pointer, base pointer, layer, t) but the table it handed back ALSO
6617                // carried the V and LEN pointers, and nothing invalidated it when a
6618                // session's KV cache was dropped. A later session whose K buffer landed on
6619                // a recycled address therefore hit a dead entry, and
6620                // `qk_norm_rope_append_inc_dcw_rows` WROTE this session's K/V rows through
6621                // the freed V/len pointers it still held while `fa_decode_dcw_rows` read
6622                // them back: a whole non-finite row when the freed pages were re-mapped,
6623                // CUDA_ERROR_ILLEGAL_ADDRESS when they were not. The row-table twin in
6624                // `step35_verify_fa_rows_join` was cured of exactly this in 8c8397e0b2
6625                // ("a process-lifetime map cannot prove allocation generation", Hermes
6626                // `11339f5cd3c132a3`); this fused rope+append+fa path was left out of it,
6627                // and MEMRA_FUSE_ROPE_APPEND=1 makes it the arm that actually runs.
6628                let ctr_base = {
6629                    let s = engine.stream();
6630                    let (p, _g) = ws.rope_ctr_t[rank].device_ptr(&s);
6631                    p
6632                };
6633                let host = rows_tab_host(&session_parts[rank], ctr_base, same_session, t);
6634                // STALE-HIT RECEIPT (MEMRA_ROWS_TAB_STALE_SCAN=1, default OFF): replay the
6635                // retired key against the contents we are about to stage. `engaged` proves
6636                // this path executes at all; `STALE` proves the retired memo would have
6637                // handed a live launch another allocation's pointers, and names which word
6638                // moved. Diagnostic only: it never feeds a kernel.
6639                if rows_tab_stale_scan() {
6640                    if ws.rows_tab_shadow.len() != ranks {
6641                        ws.rows_tab_shadow = (0..ranks).map(|_| Default::default()).collect();
6642                    }
6643                    let n = ROWS_TAB_ENGAGED.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
6644                    if let Some(prev) = ws.rows_tab_shadow[rank].get(&tab_keys[rank])
6645                        && prev != &host
6646                    {
6647                        let words = ["k", "v", "len", "base", "ctr", "back"];
6648                        let moved: Vec<String> = (0..host.len())
6649                            .filter(|&i| prev.get(i) != Some(&host[i]))
6650                            .map(|i| format!("{}[row{}]", words[i % 6], i / 6))
6651                            .collect();
6652                        let stale =
6653                            ROWS_TAB_STALE.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
6654                        eprintln!(
6655                            "[rows-tab] STALE #{stale} lookup #{n} rank={rank} t={t} key={:#018x} moved={}: the retired memo would have launched this row on another allocation's pointers",
6656                            tab_keys[rank],
6657                            moved.join(",")
6658                        );
6659                    }
6660                    ws.rows_tab_shadow[rank].insert(tab_keys[rank], host.clone());
6661                }
6662                let legacy_memo = !rows_tab_restage_on();
6663                if legacy_memo && !ws.rows_tabs[rank].contains_key(&tab_keys[rank]) {
6664                    let tab = engine.stream().clone_htod(&host)?;
6665                    ws.rows_tabs[rank].insert(tab_keys[rank], tab);
6666                }
6667                if !legacy_memo {
6668                    let mut view = ws.rows_tab_t[rank].slice_mut(0..t * 6);
6669                    engine.stream().memcpy_htod(&host, &mut view)?;
6670                }
6671                let StepTpDecodeV2Ws {
6672                    tcol_q,
6673                    tcol_k,
6674                    tcol_v,
6675                    tcol_g,
6676                    fa2_q,
6677                    fa2_gated,
6678                    rope_k_t,
6679                    rope_pos_t,
6680                    rows_tabs,
6681                    rows_tab_t,
6682                    ..
6683                } = &mut *ws;
6684                let tab = if legacy_memo {
6685                    rows_tabs[rank]
6686                        .get(&tab_keys[rank])
6687                        .ok_or("rows tab memo lost its entry")?
6688                } else {
6689                    &rows_tab_t[rank]
6690                };
6691                engine.qk_norm_rope_append_inc_dcw_rows(
6692                    &tcol_q[rank],
6693                    &tcol_k[rank],
6694                    &tcol_v[rank],
6695                    &q_norms[rank],
6696                    &k_norms[rank],
6697                    &mut fa2_q[rank],
6698                    &mut rope_k_t[rank],
6699                    tab,
6700                    &rope_pos_t[rank],
6701                    same_session,
6702                    t,
6703                    lkv,
6704                    lkv,
6705                    k_tok_bytes,
6706                    v_tok_bytes,
6707                    head_dim,
6708                    n_rot,
6709                    local_heads,
6710                    local_kv_heads,
6711                    eps,
6712                    rope_base,
6713                    1.0,
6714                    rope_freqs[rank],
6715                )?;
6716                engine.fa_decode_dcw_rows(
6717                    &fa2_q[rank],
6718                    tab,
6719                    &mut fa2_gated[rank],
6720                    t,
6721                    head_dim,
6722                    local_heads,
6723                    local_kv_heads,
6724                    window,
6725                    max_ns,
6726                    scale,
6727                    k_tok_bytes,
6728                    v_tok_bytes,
6729                    &tcol_g[rank],
6730                )?;
6731                let StepTpDecodeV2Ws {
6732                    fa2_gated,
6733                    tcol_gated,
6734                    ..
6735                } = &mut *ws;
6736                let mut dst = tcol_gated[rank].slice_mut(0..t * lq);
6737                engine
6738                    .stream()
6739                    .memcpy_dtod(&fa2_gated[rank].slice(0..t * lq), &mut dst)?;
6740            }
6741        }
6742        self.decode_v2_oproj_tcol(ws_index, e, o_m, t)
6743    }
6744
6745    /// T-ROW fa join over per-row session tables (the per-session distributed-KV
6746    /// primitive): after all t rows stashed q+gate (their appends landed in rank-stream
6747    /// order), ONE fa_decode_dcw_rows per rank walks every row's own ring with its own
6748    /// geometry — bit-identical per row to its per-row launch — then the o_proj tcol
6749    /// join lands the [t, o_out] `mixed` slab on `e`. `tabs[rank]` is the pre-staged
6750    /// device table on that rank.
6751    #[allow(clippy::too_many_arguments)]
6752    pub(crate) fn decode_v2_fa_rows_join(
6753        &self,
6754        ws_index: usize,
6755        e: &Engine,
6756        o_m: &ResidentStepBf16RowParallel,
6757        tabs: &[&crate::CudaSlice<u64>],
6758        t: usize,
6759        head_dim: usize,
6760        window: usize,
6761        max_ns: usize,
6762        scale: f32,
6763        k_tok_bytes: usize,
6764        v_tok_bytes: usize,
6765    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
6766        let ranks = self.ranks.len();
6767        if tabs.len() != ranks {
6768            return Err("fa rows join needs one table per rank".into());
6769        }
6770        {
6771            let mut guard = self
6772                .decode_v2
6773                .lock()
6774                .map_err(|_| "step TP decode v2 workspace lock is poisoned")?;
6775            let ws = guard
6776                .get_mut(ws_index)
6777                .ok_or("step TP decode v2 workspace index out of range")?;
6778            if ws.fa2_cap < t || ws.fa2_q.len() != ranks {
6779                return Err("fa rows join without stashed rows".into());
6780            }
6781            let lq = ws.local_q_dim;
6782            let local_heads = (ws.heads / ranks).max(1);
6783            let local_kv_heads = (ws.local_kv_dim / head_dim).max(1);
6784            if ws.tcol_ocap < t || ws.tcol_gated.len() != ranks {
6785                ws.tcol_gated.clear();
6786                ws.tcol_opart.clear();
6787                for engine in &self.ranks {
6788                    let _m = engine.gpu.enter_main()?;
6789                    ws.tcol_gated.push(engine.uninit(32 * lq)?);
6790                    ws.tcol_opart.push(engine.uninit(32 * ws.o_out)?);
6791                }
6792                let root = &self.ranks[0];
6793                let _m = root.gpu.enter_main()?;
6794                ws.tcol_opeer = Some(root.uninit(32 * ws.o_out)?);
6795                ws.tcol_omix = Some(root.uninit(32 * ws.o_out)?);
6796                ws.tcol_ocap = 32;
6797            }
6798            for rank in 0..ranks {
6799                let engine = &self.ranks[rank];
6800                let _main = engine.gpu.enter_main()?;
6801                {
6802                    let StepTpDecodeV2Ws {
6803                        fa2_q,
6804                        fa2_gate,
6805                        fa2_gated,
6806                        ..
6807                    } = &mut *ws;
6808                    engine.fa_decode_dcw_rows(
6809                        &fa2_q[rank],
6810                        tabs[rank],
6811                        &mut fa2_gated[rank],
6812                        t,
6813                        head_dim,
6814                        local_heads,
6815                        local_kv_heads,
6816                        window,
6817                        max_ns,
6818                        scale,
6819                        k_tok_bytes,
6820                        v_tok_bytes,
6821                        &fa2_gate[rank],
6822                    )?;
6823                }
6824                let StepTpDecodeV2Ws {
6825                    fa2_gated,
6826                    tcol_gated,
6827                    ..
6828                } = &mut *ws;
6829                let mut dst = tcol_gated[rank].slice_mut(0..t * lq);
6830                engine
6831                    .stream()
6832                    .memcpy_dtod(&fa2_gated[rank].slice(0..t * lq), &mut dst)?;
6833            }
6834        }
6835        self.decode_v2_oproj_tcol(ws_index, e, o_m, t)
6836    }
6837
6838    /// MEMRA_TCOL_OPROJ stash: copy this column's per-rank `gated` rows into the o-tcol
6839    /// slabs (rank-stream ordered behind the attention kernels that produced them). The
6840    /// per-column finish choreography is skipped entirely; `decode_v2_oproj_tcol` joins
6841    /// every column afterwards.
6842    pub(crate) fn decode_v2_stash_gated(
6843        &self,
6844        ws: &mut StepTpDecodeV2Ws,
6845        e: &Engine,
6846        col: usize,
6847    ) -> Result<(), Box<dyn std::error::Error>> {
6848        let ranks = self.ranks.len();
6849        // 32, not 8: the slabs below have been 32 rows since the slab-width fix, and the walk now
6850        // runs chunks up to t=32 (the w=16 arm died here on a guard three widths staler than its
6851        // own allocation, 2026-08-27).
6852        if col >= 32 {
6853            return Err("decode_v2_stash_gated column out of range".into());
6854        }
6855        let lq = ws.local_q_dim;
6856        if ws.tcol_ocap == 0 || ws.tcol_gated.len() != ranks {
6857            ws.tcol_gated.clear();
6858            ws.tcol_opart.clear();
6859            for engine in &self.ranks {
6860                let _m = engine.gpu.enter_main()?;
6861                ws.tcol_gated.push(engine.uninit(32 * lq)?);
6862                ws.tcol_opart.push(engine.uninit(32 * ws.o_out)?);
6863            }
6864            let root = &self.ranks[0];
6865            let _m = root.gpu.enter_main()?;
6866            ws.tcol_opeer = Some(root.uninit(32 * ws.o_out)?);
6867            ws.tcol_omix = Some(root.uninit(32 * ws.o_out)?);
6868            ws.tcol_ocap = 32;
6869        }
6870        for rank in 0..ranks {
6871            let engine = &self.ranks[rank];
6872            let _main = engine.gpu.enter_main()?;
6873            let mut dst = ws.tcol_gated[rank].slice_mut(col * lq..(col + 1) * lq);
6874            engine
6875                .stream()
6876                .memcpy_dtod(&ws.gated[rank].slice(0..lq), &mut dst)?;
6877            // The skipped finish's e-wait was ALSO the anti-dependency guard: it ordered
6878            // e's NEXT column's h/pos re-staging behind this column's rank-side raw pulls.
6879            // Record each rank here and make e wait — same protection, no o_proj work.
6880            ws.ev_rank[rank].record(&engine.stream())?;
6881        }
6882        {
6883            let _main = e.gpu.enter_main()?;
6884            for ev in ws.ev_rank.iter() {
6885                e.stream().wait(ev)?;
6886            }
6887        }
6888        Ok(())
6889    }
6890
6891    /// MEMRA_TCOL_OPROJ join: one weight-amortized b4_tcol per rank over the stashed
6892    /// `gated` slabs (per-column FP order == the t=1 b4 kernel), one peer pull of rank1's
6893    /// partial slab, one elementwise slab add on the root (independent elements — each
6894    /// column's add is the exact direct-join `add(p0, p1)`), then the joined `mixed` slab
6895    /// lands on `e`. Returns [t, o_out] on the model engine.
6896    pub(crate) fn decode_v2_oproj_tcol(
6897        &self,
6898        ws_index: usize,
6899        e: &Engine,
6900        o_m: &ResidentStepBf16RowParallel,
6901        t: usize,
6902    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
6903        let ranks = self.ranks.len();
6904        let mut guard = self
6905            .decode_v2
6906            .lock()
6907            .map_err(|_| "step TP decode v2 workspace lock is poisoned")?;
6908        let ws = guard
6909            .get_mut(ws_index)
6910            .ok_or("step TP decode v2 workspace index out of range")?;
6911        if ranks != 2 || ws.blocks_per_rank != 4 || t == 0 || t > 32 || ws.tcol_ocap < t {
6912            return Err("decode_v2_oproj_tcol geometry".into());
6913        }
6914        for rank in 0..ranks {
6915            let engine = &self.ranks[rank];
6916            let _main = engine.gpu.enter_main()?;
6917            let mut weights = Vec::with_capacity(4);
6918            for block in 0..4 {
6919                let ResidentBf16Weight::Bf16(weight) = &o_m.ranks[rank][block].weight else {
6920                    return Err("tcol o_proj requires bf16-resident O blocks".into());
6921                };
6922                weights.push(weight);
6923            }
6924            {
6925                let StepTpDecodeV2Ws {
6926                    tcol_gated,
6927                    tcol_opart,
6928                    local_q_dim,
6929                    o_block_cols,
6930                    o_out,
6931                    w8t_oaq,
6932                    w8t_oad,
6933                    w8t_oin,
6934                    w8t_cap,
6935                    ..
6936                } = &mut *ws;
6937                // MEMRA_TCOL_OPROJ_REF=1 (bisect): fill the partial slab via the t=1 b4
6938                // kernel per column — separates choreography bugs from tcol-kernel bugs.
6939                static REFK: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
6940                let refk = *REFK
6941                    .get_or_init(|| std::env::var("MEMRA_TCOL_OPROJ_REF").as_deref() == Ok("1"));
6942                if refk {
6943                    let lq = *local_q_dim;
6944                    let mut xr = engine.uninit(lq)?;
6945                    let mut yr = engine.uninit(*o_out)?;
6946                    for c in 0..t {
6947                        {
6948                            let mut dst = xr.slice_mut(0..lq);
6949                            engine.stream().memcpy_dtod(
6950                                &tcol_gated[rank].slice(c * lq..(c + 1) * lq),
6951                                &mut dst,
6952                            )?;
6953                        }
6954                        engine.matvec_bf16_b4_into(
6955                            [weights[0], weights[1], weights[2], weights[3]],
6956                            &xr,
6957                            &mut yr,
6958                            *o_block_cols,
6959                            *o_out,
6960                        )?;
6961                        let mut dst = tcol_opart[rank].slice_mut(c * *o_out..(c + 1) * *o_out);
6962                        engine
6963                            .stream()
6964                            .memcpy_dtod(&yr.slice(0..*o_out), &mut dst)?;
6965                    }
6966                } else if crate::step_tp_w8_on()
6967                    && (0..4).all(|b| o_m.ranks[rank][b].q8.is_some())
6968                    && (4 * *o_block_cols) % 32 == 0
6969                {
6970                    // The verify walk's biggest single kernel: bf16 tcol o_proj was 24.8% of
6971                    // spec GPU time. Same planar q8_0 mirrors the decode arm uses, one launch
6972                    // over all t columns.
6973                    let in_f = 4 * *o_block_cols;
6974                    if *w8t_oin != in_f || *w8t_cap < t || w8t_oaq.len() != ranks {
6975                        w8t_oaq.clear();
6976                        w8t_oad.clear();
6977                        for e_rank in &self.ranks {
6978                            let _m = e_rank.gpu.enter_main()?;
6979                            w8t_oaq.push(e_rank.alloc_i8_uninit(32 * in_f)?);
6980                            w8t_oad.push(e_rank.alloc_uninit::<f32>(32 * (in_f / 32))?);
6981                        }
6982                        *w8t_oin = in_f;
6983                        *w8t_cap = (*w8t_cap).max(32);
6984                    }
6985                    engine.quantize_q8_1_into(
6986                        &tcol_gated[rank],
6987                        t,
6988                        in_f,
6989                        &mut w8t_oaq[rank],
6990                        &mut w8t_oad[rank],
6991                    )?;
6992                    engine.qmatvec_q8_0_b4_rp_t_into(
6993                        [
6994                            o_m.ranks[rank][0].q8.as_ref().unwrap(),
6995                            o_m.ranks[rank][1].q8.as_ref().unwrap(),
6996                            o_m.ranks[rank][2].q8.as_ref().unwrap(),
6997                            o_m.ranks[rank][3].q8.as_ref().unwrap(),
6998                        ],
6999                        &w8t_oaq[rank],
7000                        &w8t_oad[rank],
7001                        &mut tcol_opart[rank],
7002                        *o_block_cols,
7003                        *o_out,
7004                        t,
7005                    )?;
7006                } else {
7007                    engine.matvec_bf16_b4_tcol_into(
7008                        [weights[0], weights[1], weights[2], weights[3]],
7009                        &tcol_gated[rank],
7010                        &mut tcol_opart[rank],
7011                        *o_block_cols,
7012                        *o_out,
7013                        t,
7014                    )?;
7015                }
7016            }
7017            if rank != 0 {
7018                ws.ev_rank[rank].record(&engine.stream())?;
7019            }
7020        }
7021        let root = &self.ranks[0];
7022        {
7023            let _main = root.gpu.enter_main()?;
7024            for ev in ws.ev_rank.iter().skip(1) {
7025                root.stream().wait(ev)?;
7026            }
7027            {
7028                let StepTpDecodeV2Ws {
7029                    tcol_opart,
7030                    tcol_opeer,
7031                    tcol_omix,
7032                    o_out,
7033                    ..
7034                } = &mut *ws;
7035                let opeer = tcol_opeer.as_mut().ok_or("tcol o_proj slabs not armed")?;
7036                let omix = tcol_omix.as_mut().ok_or("tcol o_proj slabs not armed")?;
7037                {
7038                    let mut dst = opeer.slice_mut(0..t * *o_out);
7039                    root.stream()
7040                        .memcpy_dtod(&tcol_opart[1].slice(0..t * *o_out), &mut dst)?;
7041                }
7042                // Elementwise over the whole slab: per element identical to the per-column
7043                // direct-join add (independent lanes, same operand values).
7044                root.add(&tcol_opart[0], opeer, omix, t * *o_out)?;
7045            }
7046            ws.ev_oproj.record(&root.stream())?;
7047        }
7048        let _main = e.gpu.enter_main()?;
7049        e.stream().wait(&ws.ev_oproj)?;
7050        let mut out = e.uninit(t * ws.o_out)?;
7051        let omix = ws.tcol_omix.as_ref().ok_or("tcol o_proj slabs not armed")?;
7052        e.stream().memcpy_dtod(
7053            &omix.slice(0..t * ws.o_out),
7054            &mut out.slice_mut(0..t * ws.o_out),
7055        )?;
7056        Ok(out)
7057    }
7058
7059    #[allow(clippy::too_many_arguments)] // allow: the parameter list mirrors the kernel/FFI/call contract; bundling into a struct is a refactor, not a lint fix
7060    pub(crate) fn decode_v2_input_qkv(
7061        &self,
7062        ws: &mut StepTpDecodeV2Ws,
7063        e: &Engine,
7064        h: &CudaSlice<f32>,
7065        pos_d: &CudaSlice<i32>,
7066        gate_raw: Option<&CudaSlice<f32>>,
7067        gate_shards: Option<StepTpGateShards<'_>>,
7068        decode_input: &mut ResidentReplicatedDeviceRows,
7069        q_m: &ResidentBf16ColumnParallel,
7070        k_m: &ResidentBf16ColumnParallel,
7071        v_m: &ResidentBf16ColumnParallel,
7072        q_norm: &[CudaSlice<f32>],
7073        k_norm: &[CudaSlice<f32>],
7074        head_dim: usize,
7075        n_rot: usize,
7076        rope_base: f32,
7077        rope_freqs: &[Option<&CudaSlice<f32>>],
7078        rms_eps: f32,
7079        has_gate: bool,
7080        defer_norm_rope: bool,
7081        tcol_col: Option<usize>,
7082    ) -> Result<(), Box<dyn std::error::Error>> {
7083        let ranks = self.ranks.len();
7084        validate_replicated_device_rows(&self.ranks, decode_input)?;
7085        let gate_sources = usize::from(gate_raw.is_some()) + usize::from(gate_shards.is_some());
7086        if decode_input.tokens != 1
7087            || decode_input.width != q_m.in_features
7088            || pos_d.len() != 1
7089            || gate_raw.is_some_and(|gate| gate.len() != ws.heads)
7090            || (has_gate && gate_sources != 1)
7091            || (!has_gate && gate_sources != 0)
7092            || gate_shards.as_ref().is_some_and(|shards| match shards {
7093                StepTpGateShards::F32(shards) => shards.len() != ranks,
7094                StepTpGateShards::Bf16(shards) => shards.len() != ranks,
7095            })
7096            || q_norm.len() != ranks
7097            || k_norm.len() != ranks
7098            || rope_freqs.len() != ranks
7099            || e.ctx().ordinal() != ws.e_device
7100        {
7101            return Err("step TP decode v2 input geometry mismatch".into());
7102        }
7103
7104        let qkv_fused = step_tp_qkv_fused_enabled()?;
7105        if gate_shards.is_some() && !qkv_fused {
7106            return Err("step TP decode v2 gate shards require MEMRA_STEP_TP_QKV_FUSED=1".into());
7107        }
7108        let values = decode_input.width;
7109        if h.len() != values {
7110            return Err(format!(
7111                "step TP decode v2 hidden width {} != replicated width {values}",
7112                h.len()
7113            )
7114            .into());
7115        }
7116
7117        if qkv_fused {
7118            // STAGE-BASED flow (graph increment A): h and pos land in fixed e-context stages
7119            // (one e-stream copy each), the entry event covers them, and every rank raw-copies
7120            // from the stages on its own stream — exactly the shape graph capture wraps.
7121            if ws.h_stage.is_none() {
7122                use cudarc::driver::DevicePtr;
7123                let _main = e.gpu.enter_main()?;
7124                let h_stage = e.uninit(values)?;
7125                let pos_stage = e.htod_i32(&[0])?;
7126                {
7127                    let stream = e.stream();
7128                    let (hp, _g0) = h_stage.device_ptr(&stream);
7129                    let (pp, _g1) = pos_stage.device_ptr(&stream);
7130                    ws.raw_h_stage = hp;
7131                    ws.raw_pos_stage = pp;
7132                }
7133                ws.h_stage = Some(h_stage);
7134                ws.pos_stage = Some(pos_stage);
7135                for rank in 0..ranks {
7136                    use cudarc::driver::DevicePtr;
7137                    let engine = &self.ranks[rank];
7138                    let _rmain = engine.gpu.enter_main()?;
7139                    let attn_in = engine.uninit(values)?;
7140                    let (dp, pp) = {
7141                        let stream = engine.stream();
7142                        let (dp, _g2) = attn_in.device_ptr(&stream);
7143                        let (pp, _g3) = ws.pos[rank].device_ptr(&stream);
7144                        (dp, pp)
7145                    };
7146                    ws.raw_attn_in.push(dp);
7147                    ws.raw_pos.push(pp);
7148                    ws.attn_in.push(attn_in);
7149                }
7150                {
7151                    use cudarc::driver::DevicePtr;
7152                    let root = &self.ranks[0];
7153                    let _rmain = root.gpu.enter_main()?;
7154                    let stream = root.stream();
7155                    let (a, _g) = ws.peer_partial.device_ptr(&stream);
7156                    let (b, _g) = ws.k_shadow.device_ptr(&stream);
7157                    let (c, _g) = ws.v_shadow.device_ptr(&stream);
7158                    ws.raw_peer_partial = a;
7159                    ws.raw_k_shadow = b;
7160                    ws.raw_v_shadow = c;
7161                }
7162                {
7163                    use cudarc::driver::DevicePtr;
7164                    let rank1 = &self.ranks[1];
7165                    let _rmain = rank1.gpu.enter_main()?;
7166                    let stream = rank1.stream();
7167                    let (a, _g) = ws.o_partials[1][0].device_ptr(&stream);
7168                    let (b, _g) = ws.k[1].device_ptr(&stream);
7169                    let (c, _g) = ws.v_raw[1].device_ptr(&stream);
7170                    ws.raw_o_partial1 = a;
7171                    ws.raw_k1 = b;
7172                    ws.raw_v1 = c;
7173                }
7174            }
7175            {
7176                let _main = e.gpu.enter_main()?;
7177                {
7178                    // (Always staged: a tcol column below the dcw floor falls back to the
7179                    // normal fused arm, which reads h through this stage.)
7180                    let h_stage = ws.h_stage.as_mut().expect("stage armed above");
7181                    let mut dst = h_stage.slice_mut(0..values);
7182                    e.stream().memcpy_dtod(&h.slice(0..values), &mut dst)?;
7183                }
7184                {
7185                    let pos_stage = ws.pos_stage.as_mut().expect("stage armed above");
7186                    let mut dst = pos_stage.slice_mut(0..1);
7187                    e.stream().memcpy_dtod(&pos_d.slice(0..1), &mut dst)?;
7188                }
7189                ws.ev_entry.record(&e.stream())?;
7190            }
7191            for rank in 0..ranks {
7192                let engine = &self.ranks[rank];
7193                let _main = engine.gpu.enter_main()?;
7194                engine.stream().wait(&ws.ev_entry)?;
7195            }
7196        } else {
7197            // Evented replicate flow (the pre-stage shape, kept for the non-fused class).
7198            {
7199                let _main = e.gpu.enter_main()?;
7200                if let Some(gate_raw) = gate_raw {
7201                    let mut gate_dst = ws.gate_e.slice_mut(0..ws.heads);
7202                    e.stream()
7203                        .memcpy_dtod(&gate_raw.slice(0..ws.heads), &mut gate_dst)?;
7204                }
7205                ws.ev_entry.record(&e.stream())?;
7206            }
7207            {
7208                let root = &self.ranks[0];
7209                let _main = root.gpu.enter_main()?;
7210                root.stream().wait(&ws.ev_entry)?;
7211                let mut destination = decode_input.ranks[0].slice_mut(0..values);
7212                root.stream()
7213                    .memcpy_dtod(&h.slice(0..values), &mut destination)?;
7214                ws.ev_refresh.record(&root.stream())?;
7215            }
7216            for rank in 1..ranks {
7217                let engine = &self.ranks[rank];
7218                let _main = engine.gpu.enter_main()?;
7219                engine.stream().wait(&ws.ev_refresh)?;
7220                let (root_rows, peer_rows) = decode_input.ranks.split_at_mut(rank);
7221                let mut destination = peer_rows[0].slice_mut(0..values);
7222                engine
7223                    .stream()
7224                    .memcpy_dtod(&root_rows[0].slice(0..values), &mut destination)?;
7225            }
7226        }
7227        for rank in 0..ranks {
7228            self.decode_v2_input_qkv_rank(
7229                ws,
7230                pos_d,
7231                decode_input,
7232                q_m,
7233                k_m,
7234                v_m,
7235                q_norm,
7236                k_norm,
7237                head_dim,
7238                n_rot,
7239                rope_base,
7240                rope_freqs,
7241                rms_eps,
7242                gate_shards.as_ref(),
7243                has_gate,
7244                qkv_fused,
7245                defer_norm_rope,
7246                rank,
7247                tcol_col,
7248            )?;
7249        }
7250        Ok(())
7251    }
7252
7253    /// One rank's slice of `decode_v2_input_qkv` (projection, norm+rope, gate staging) — the
7254    /// per-device issue unit the whole-token graph captures on that rank's stream.
7255    #[allow(clippy::too_many_arguments)]
7256    pub(crate) fn decode_v2_input_qkv_rank(
7257        &self,
7258        ws: &mut StepTpDecodeV2Ws,
7259        pos_d: &CudaSlice<i32>,
7260        decode_input: &mut ResidentReplicatedDeviceRows,
7261        q_m: &ResidentBf16ColumnParallel,
7262        k_m: &ResidentBf16ColumnParallel,
7263        v_m: &ResidentBf16ColumnParallel,
7264        q_norm: &[CudaSlice<f32>],
7265        k_norm: &[CudaSlice<f32>],
7266        head_dim: usize,
7267        n_rot: usize,
7268        rope_base: f32,
7269        rope_freqs: &[Option<&CudaSlice<f32>>],
7270        rms_eps: f32,
7271        gate_shards: Option<&StepTpGateShards<'_>>,
7272        has_gate: bool,
7273        qkv_fused: bool,
7274        defer_norm_rope: bool,
7275        rank: usize,
7276        tcol_col: Option<usize>,
7277    ) -> Result<(), Box<dyn std::error::Error>> {
7278        let ranks = self.ranks.len();
7279        let local_heads = ws.local_q_dim / head_dim;
7280        let local_kv_heads = ws.local_kv_dim / head_dim;
7281        let engine = &self.ranks[rank];
7282        let _main = engine.gpu.enter_main()?;
7283        let ws_e_device = ws.e_device;
7284        // T-COLUMN SELECT (spec verify): the projections for this column were precomputed
7285        // by the weight-amortized tcol kernel — copy the column into the single-row buffers
7286        // (pure f32 moves, bit-exact) and skip the per-column matvec. Rope/norm/append run
7287        // below exactly as in the t=1 program.
7288        if qkv_fused && tcol_col.is_some() {
7289            #[allow(clippy::unnecessary_unwrap)]
7290            // allow: the Some-guard sits in a multi-clause regime gate; if-let would reshape the arm structure
7291            let c = tcol_col.expect("checked");
7292            if ws.tcol_cap == 0 || ws.tcol_q.len() != ranks {
7293                return Err("tcol select without precompute".into());
7294            }
7295            // The select skips the matvec but NOT the position: rope/append below still
7296            // read this rank's pos buffer, which only the (skipped) stage path fills for
7297            // peer-device ranks. Stage it here or rank1 ropes at the previous position.
7298            if engine.ctx().ordinal() != ws_e_device {
7299                raw_copy_bytes(ws.raw_pos[rank], ws.raw_pos_stage, 4, engine)?;
7300            }
7301            let StepTpDecodeV2Ws {
7302                tcol_q,
7303                tcol_k,
7304                tcol_v,
7305                tcol_g,
7306                q_raw,
7307                k_raw,
7308                v_raw,
7309                gate,
7310                local_q_dim,
7311                local_kv_dim,
7312                heads,
7313                ..
7314            } = &mut *ws;
7315            let lg = *heads / ranks;
7316            let stream = engine.stream();
7317            {
7318                let mut dst = q_raw[rank].slice_mut(0..*local_q_dim);
7319                stream.memcpy_dtod(
7320                    &tcol_q[rank].slice(c * *local_q_dim..(c + 1) * *local_q_dim),
7321                    &mut dst,
7322                )?;
7323            }
7324            {
7325                let mut dst = k_raw[rank].slice_mut(0..*local_kv_dim);
7326                stream.memcpy_dtod(
7327                    &tcol_k[rank].slice(c * *local_kv_dim..(c + 1) * *local_kv_dim),
7328                    &mut dst,
7329                )?;
7330            }
7331            {
7332                let mut dst = v_raw[rank].slice_mut(0..*local_kv_dim);
7333                stream.memcpy_dtod(
7334                    &tcol_v[rank].slice(c * *local_kv_dim..(c + 1) * *local_kv_dim),
7335                    &mut dst,
7336                )?;
7337            }
7338            if has_gate && lg > 0 {
7339                let mut dst = gate[rank].slice_mut(0..lg);
7340                stream.memcpy_dtod(&tcol_g[rank].slice(c * lg..(c + 1) * lg), &mut dst)?;
7341            }
7342            if !defer_norm_rope {
7343                // Below the dcw floor (or a non-defer shape) the col-select cannot apply:
7344                // fall through and recompute this column's QKV from the REAL h row — the
7345                // caller always passes it. The slab copies above are dead stores.
7346            } else {
7347                return Ok(());
7348            }
7349        }
7350        if qkv_fused {
7351            // Stage-based input: raw copies from the fixed e-context stages (capture-safe;
7352            // eager ordering comes from the caller's ev_entry wait on this stream). The rank
7353            // SHARING e's device reads the stages directly — same context (probed), ordering
7354            // identical (ev_entry / graph edge), bytes identical: the copies are pure waste.
7355            let same_dev = engine.ctx().ordinal() == ws.e_device;
7356            if !same_dev {
7357                raw_copy_bytes(
7358                    ws.raw_attn_in[rank],
7359                    ws.raw_h_stage,
7360                    q_m.in_features * 4,
7361                    engine,
7362                )?;
7363                raw_copy_bytes(ws.raw_pos[rank], ws.raw_pos_stage, 4, engine)?;
7364            }
7365            let StepTpDecodeV2Ws {
7366                q_raw,
7367                k_raw,
7368                v_raw,
7369                gate,
7370                gate_e,
7371                attn_in,
7372                h_stage,
7373                heads,
7374                local_q_dim,
7375                local_kv_dim,
7376                w8_aq,
7377                w8_ad,
7378                w8_in,
7379                ..
7380            } = &mut *ws;
7381            let input_ref: &CudaSlice<f32> = if same_dev {
7382                h_stage
7383                    .as_ref()
7384                    .ok_or("step TP decode v2 stage not armed")?
7385            } else {
7386                &attn_in[rank]
7387            };
7388            match (
7389                &q_m.ranks[rank].weight,
7390                &k_m.ranks[rank].weight,
7391                &v_m.ranks[rank].weight,
7392            ) {
7393                (
7394                    ResidentBf16Weight::F32(wq),
7395                    ResidentBf16Weight::F32(wk),
7396                    ResidentBf16Weight::F32(wv),
7397                ) => {
7398                    let (wg, out_g) = match &gate_shards {
7399                        Some(StepTpGateShards::F32(shards)) => (&shards[rank], *heads / ranks),
7400                        Some(StepTpGateShards::Bf16(_)) => {
7401                            return Err("step TP decode v2 gate shard class does not \
7402                                            match the F32 projections"
7403                                .into());
7404                        }
7405                        // out_g = 0: the kernel never reads wg; any resident buffer works.
7406                        None => (&*gate_e, 0),
7407                    };
7408                    engine.matvec_f32_qkv_into(
7409                        wq,
7410                        wk,
7411                        wv,
7412                        wg,
7413                        input_ref,
7414                        &mut q_raw[rank],
7415                        &mut k_raw[rank],
7416                        &mut v_raw[rank],
7417                        &mut gate[rank],
7418                        q_m.in_features,
7419                        *local_q_dim,
7420                        *local_kv_dim,
7421                        out_g,
7422                    )?;
7423                }
7424                (
7425                    ResidentBf16Weight::Bf16(wq),
7426                    ResidentBf16Weight::Bf16(wk),
7427                    ResidentBf16Weight::Bf16(wv),
7428                ) => {
7429                    let (wg, out_g) = match &gate_shards {
7430                        Some(StepTpGateShards::Bf16(shards)) => (&shards[rank], *heads / ranks),
7431                        Some(StepTpGateShards::F32(_)) => {
7432                            return Err("step TP decode v2 gate shard class does not \
7433                                            match the bf16 projections"
7434                                .into());
7435                        }
7436                        None => (wq, 0),
7437                    };
7438                    // MEMRA_STEP_TP_W8: q8_0 weights + q8_1 activation through mmvq instead of
7439                    // the fused bf16 qkvg. NUMERIC CLASS (int8 dp4a with per-32 scales, not a
7440                    // bf16 fma chain) — argmax-gated, never a bit-tape flip. Q, K and V each
7441                    // get their own launch because the fused kernel has no q8 twin; the gate
7442                    // rows stay bf16 (32 rows, ~0.3 MB, nothing to win and one less class to
7443                    // qualify). Measured motive: 23.0 us bf16 -> 14.0 us q8 at this shape.
7444                    let in_f = q_m.in_features;
7445                    let q8_ready = crate::step_tp_w8_on()
7446                        && q_m.ranks[rank].q8.is_some()
7447                        && k_m.ranks[rank].q8.is_some()
7448                        && v_m.ranks[rank].q8.is_some();
7449                    if q8_ready {
7450                        if *w8_in != in_f || w8_aq.len() != ranks {
7451                            w8_aq.clear();
7452                            w8_ad.clear();
7453                            for e_rank in &self.ranks {
7454                                let _m = e_rank.gpu.enter_main()?;
7455                                w8_aq.push(e_rank.alloc_uninit::<i8>(in_f)?);
7456                                w8_ad.push(e_rank.alloc_uninit::<f32>(in_f / 32)?);
7457                            }
7458                            *w8_in = in_f;
7459                        }
7460                        engine.quantize_q8_1_into(
7461                            input_ref,
7462                            1,
7463                            in_f,
7464                            &mut w8_aq[rank],
7465                            &mut w8_ad[rank],
7466                        )?;
7467                        // ONE launch over the stacked q/k/v rows. The three-call version
7468                        // measured 79.52 vs 80.72 tok/s — SLOWER than the bf16 fused kernel —
7469                        // because three launches plus the activation quantize cost more than
7470                        // the halved weight bytes save. Bit-identical to those three calls.
7471                        engine.qmatvec_q8_0_qkv_rp_into(
7472                            q_m.ranks[rank].q8.as_ref().unwrap(),
7473                            k_m.ranks[rank].q8.as_ref().unwrap(),
7474                            v_m.ranks[rank].q8.as_ref().unwrap(),
7475                            &w8_aq[rank],
7476                            &w8_ad[rank],
7477                            &mut q_raw[rank],
7478                            &mut k_raw[rank],
7479                            &mut v_raw[rank],
7480                            in_f,
7481                            *local_q_dim,
7482                            *local_kv_dim,
7483                        )?;
7484                        if out_g > 0 {
7485                            engine.matvec_bf16_into(wg, input_ref, &mut gate[rank], in_f, out_g)?;
7486                        }
7487                    } else {
7488                        engine.matvec_bf16_qkvg_into(
7489                            wq,
7490                            wk,
7491                            wv,
7492                            wg,
7493                            input_ref,
7494                            &mut q_raw[rank],
7495                            &mut k_raw[rank],
7496                            &mut v_raw[rank],
7497                            &mut gate[rank],
7498                            q_m.in_features,
7499                            *local_q_dim,
7500                            *local_kv_dim,
7501                            out_g,
7502                        )?;
7503                    }
7504                }
7505                _ => {
7506                    return Err("step TP decode v2 QKV projections mix residency classes".into());
7507                }
7508            }
7509        } else {
7510            for (matrix, local_out, raw) in [
7511                (q_m, ws.local_q_dim, &mut ws.q_raw),
7512                (k_m, ws.local_kv_dim, &mut ws.k_raw),
7513                (v_m, ws.local_kv_dim, &mut ws.v_raw),
7514            ] {
7515                let ResidentBf16Weight::F32(values_w) = &matrix.ranks[rank].weight else {
7516                    return Err("step TP decode v2 lost its F32 projection residency".into());
7517                };
7518                let chunk_rows = matrix.canonical_chunk_rows.unwrap_or(local_out);
7519                engine.linear_f32_resident_canonical_rows_t1_into(
7520                    &decode_input.ranks[rank],
7521                    values_w,
7522                    &mut raw[rank],
7523                    matrix.in_features,
7524                    local_out,
7525                    chunk_rows,
7526                )?;
7527            }
7528        }
7529        if qkv_fused && defer_norm_rope {
7530            // FUSION #1 defers norm+rope to the caller's fused rope+append+inc launch.
7531        } else if qkv_fused {
7532            // Fused norm+rope: one launch; the position comes from the rank-local staged
7533            // copy (raw-copied above from the fixed e-context pos stage — capture-safe).
7534            let StepTpDecodeV2Ws {
7535                q_raw,
7536                k_raw,
7537                q,
7538                k,
7539                pos,
7540                pos_stage,
7541                ..
7542            } = &mut *ws;
7543            let same_dev = engine.ctx().ordinal() == ws_e_device;
7544            let pos_ref: &CudaSlice<i32> = if same_dev {
7545                pos_stage
7546                    .as_ref()
7547                    .ok_or("step TP decode v2 pos stage not armed")?
7548            } else {
7549                &pos[rank]
7550            };
7551            engine.qk_norm_rope_into(
7552                &q_raw[rank],
7553                &k_raw[rank],
7554                &q_norm[rank],
7555                &k_norm[rank],
7556                &mut q[rank],
7557                &mut k[rank],
7558                pos_ref,
7559                head_dim,
7560                n_rot,
7561                local_heads,
7562                local_kv_heads,
7563                rms_eps,
7564                rope_base,
7565                1.0,
7566                rope_freqs[rank],
7567            )?;
7568        } else {
7569            engine.rms_norm(
7570                &ws.q_raw[rank],
7571                &q_norm[rank],
7572                &mut ws.q[rank],
7573                head_dim,
7574                local_heads,
7575                rms_eps,
7576            )?;
7577            engine.rms_norm(
7578                &ws.k_raw[rank],
7579                &k_norm[rank],
7580                &mut ws.k[rank],
7581                head_dim,
7582                local_kv_heads,
7583                rms_eps,
7584            )?;
7585            {
7586                let mut pos_dst = ws.pos[rank].slice_mut(0..1);
7587                engine
7588                    .stream()
7589                    .memcpy_dtod(&pos_d.slice(0..1), &mut pos_dst)?;
7590            }
7591            engine.rope_neox2(
7592                &mut ws.q[rank],
7593                &mut ws.k[rank],
7594                &ws.pos[rank],
7595                head_dim,
7596                n_rot,
7597                local_heads,
7598                local_kv_heads,
7599                1,
7600                rope_base,
7601                1.0,
7602                rope_freqs[rank],
7603            )?;
7604        }
7605        if has_gate && gate_shards.is_none() {
7606            let gate_start = rank * (ws.heads / ranks);
7607            let mut gate_dst = ws.gate[rank].slice_mut(0..ws.heads / ranks);
7608            engine.stream().memcpy_dtod(
7609                &ws.gate_e.slice(gate_start..gate_start + ws.heads / ranks),
7610                &mut gate_dst,
7611            )?;
7612        }
7613        Ok(())
7614    }
7615
7616    /// One rank's O-partial slice of `decode_v2_finish` — the per-device issue unit the
7617    /// whole-token graph captures on that rank's stream (the rank-done event stays with the
7618    /// eager caller; graphs order via parent edges instead).
7619    pub(crate) fn decode_v2_finish_rank_partial(
7620        &self,
7621        ws: &mut StepTpDecodeV2Ws,
7622        o_m: &ResidentStepBf16RowParallel,
7623        o_fused: bool,
7624        rank: usize,
7625    ) -> Result<(), Box<dyn std::error::Error>> {
7626        let engine = &self.ranks[rank];
7627        let _main = engine.gpu.enter_main()?;
7628        if o_fused {
7629            let StepTpDecodeV2Ws {
7630                gated,
7631                o_partials,
7632                o_block_cols,
7633                o_out,
7634                w8o_aq,
7635                w8o_ad,
7636                w8o_in,
7637                ..
7638            } = &mut *ws;
7639            let all_f32 = o_m.ranks[rank]
7640                .iter()
7641                .all(|block| matches!(block.weight, ResidentBf16Weight::F32(_)));
7642            if all_f32 {
7643                let mut weights = Vec::with_capacity(4);
7644                for block in 0..4 {
7645                    let ResidentBf16Weight::F32(weight) = &o_m.ranks[rank][block].weight else {
7646                        unreachable!("all_f32 checked above");
7647                    };
7648                    weights.push(weight);
7649                }
7650                engine.matvec_f32_b4_into(
7651                    [weights[0], weights[1], weights[2], weights[3]],
7652                    &gated[rank],
7653                    &mut o_partials[rank][0],
7654                    *o_block_cols,
7655                    *o_out,
7656                )?;
7657            } else if crate::step_tp_w8_on() && (0..4).all(|b| o_m.ranks[rank][b].q8.is_some()) {
7658                // MEMRA_STEP_TP_W8, o_proj half: quantize the gated attention output once and
7659                // run all four HEAD_SPLIT blocks in one q8 launch. Measured motive: bf16 b4 is
7660                // 24.2 us/layer against 11.7 for the q8 shape — the largest decode line left
7661                // after the QKV arm banked +2.9%.
7662                let in_f = 4 * *o_block_cols;
7663                if *w8o_in != in_f || w8o_aq.len() != self.ranks.len() {
7664                    w8o_aq.clear();
7665                    w8o_ad.clear();
7666                    for e_rank in &self.ranks {
7667                        let _m = e_rank.gpu.enter_main()?;
7668                        w8o_aq.push(e_rank.alloc_uninit::<i8>(in_f)?);
7669                        w8o_ad.push(e_rank.alloc_uninit::<f32>(in_f / 32)?);
7670                    }
7671                    *w8o_in = in_f;
7672                }
7673                engine.quantize_q8_1_into(
7674                    &gated[rank],
7675                    1,
7676                    in_f,
7677                    &mut w8o_aq[rank],
7678                    &mut w8o_ad[rank],
7679                )?;
7680                engine.qmatvec_q8_0_b4_rp_into(
7681                    [
7682                        o_m.ranks[rank][0].q8.as_ref().unwrap(),
7683                        o_m.ranks[rank][1].q8.as_ref().unwrap(),
7684                        o_m.ranks[rank][2].q8.as_ref().unwrap(),
7685                        o_m.ranks[rank][3].q8.as_ref().unwrap(),
7686                    ],
7687                    &w8o_aq[rank],
7688                    &w8o_ad[rank],
7689                    &mut o_partials[rank][0],
7690                    *o_block_cols,
7691                    *o_out,
7692                )?;
7693            } else {
7694                let mut weights = Vec::with_capacity(4);
7695                for block in 0..4 {
7696                    let ResidentBf16Weight::Bf16(weight) = &o_m.ranks[rank][block].weight else {
7697                        return Err("step TP decode v2 O projections mix residency classes".into());
7698                    };
7699                    weights.push(weight);
7700                }
7701                engine.matvec_bf16_b4_into(
7702                    [weights[0], weights[1], weights[2], weights[3]],
7703                    &gated[rank],
7704                    &mut o_partials[rank][0],
7705                    *o_block_cols,
7706                    *o_out,
7707                )?;
7708            }
7709        } else {
7710            for block in 0..ws.blocks_per_rank {
7711                let x =
7712                    ws.gated[rank].slice(block * ws.o_block_cols..(block + 1) * ws.o_block_cols);
7713                let mut y = ws.o_partials[rank][block].slice_mut(0..ws.o_out);
7714                match &o_m.ranks[rank][block].weight {
7715                    ResidentBf16Weight::F32(weight) => {
7716                        let w = weight.slice(0..weight.len());
7717                        engine.linear_t1_into(&x, &w, &mut y, ws.o_block_cols, ws.o_out)?;
7718                    }
7719                    ResidentBf16Weight::Bf16(weight) => {
7720                        engine.matvec_bf16_views_into(
7721                            weight,
7722                            &x,
7723                            &mut y,
7724                            ws.o_block_cols,
7725                            ws.o_out,
7726                        )?;
7727                    }
7728                }
7729            }
7730        }
7731        Ok(())
7732    }
7733
7734    /// v2 phase 2: canonical-block O reduction on the root device plus the K/V shadow gathers,
7735    /// returning a fresh model-engine output ordered behind `ev_oproj` on `e`'s stream.
7736    ///
7737    /// The caller must have queued every rank's attention work (reading `ws.gated`, `ws.k`,
7738    /// `ws.v_raw`) on the rank streams before this call. Reduction order is identical to
7739    /// `step_bf16_row_parallel_resident_native`: zeros, then rank 0's blocks, then each peer
7740    /// rank's blocks, one `add` per block.
7741    pub(crate) fn decode_v2_finish(
7742        &self,
7743        ws: &mut StepTpDecodeV2Ws,
7744        e: &Engine,
7745        o_m: &ResidentStepBf16RowParallel,
7746    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
7747        let ranks = self.ranks.len();
7748        if e.ctx().ordinal() != ws.e_device {
7749            return Err("step TP decode v2 finish engine changed".into());
7750        }
7751        // MEMRA_STEP_TP_QKV_FUSED extends to the O path: one matvec_f32_b4 launch per rank
7752        // (in-order canonical block accumulation per element) and a single peer-copy + add on
7753        // the root, replacing 4 cuBLASLt launches per rank + the 4-copy/8-add chain. Same
7754        // numeric-class door and gate as the fused QKV projection.
7755        let o_fused = step_tp_qkv_fused_enabled()? && ws.blocks_per_rank == 4 && ranks == 2;
7756
7757        // Per-rank O block partials on the owning rank's stream (serial after the attention
7758        // kernels the driver queued there), then the rank-done event for root's peer reads.
7759        for rank in 0..ranks {
7760            self.decode_v2_finish_rank_partial(ws, o_m, o_fused, rank)?;
7761            if rank == 0 {
7762                // root == rank0: its own stream order covers the partial; only peers need
7763                // the record/wait pair (host-op diet, matches the routes-arm skip).
7764                continue;
7765            }
7766            let engine = &self.ranks[rank];
7767            let _main = engine.gpu.enter_main()?;
7768            ws.ev_rank[rank].record(&engine.stream())?;
7769        }
7770
7771        // Root reduce in canonical order + shadow gathers, all on the root stream.
7772        let root = &self.ranks[0];
7773        #[allow(unused_assignments)]
7774        let mut final_in_a = false;
7775        {
7776            let _main = root.gpu.enter_main()?;
7777            for ev in ws.ev_rank.iter().skip(1) {
7778                root.stream().wait(ev)?;
7779            }
7780            if o_fused && oproj_direct_on() && ranks == 2 && no_local_shadow_on() {
7781                // DIRECT JOIN: rank1's partial already sits in root memory (P2P kernel
7782                // stores; visibility guaranteed by the ev_rank[1] wait above), rank0's
7783                // partial is root-stream-ordered — record ONE event and let the model
7784                // engine do the single add itself, straight into its own output row.
7785                // Same operands, same add order as finish_root_fused: BIT-IDENTICAL.
7786                ws.ev_oproj.record(&root.stream())?;
7787                let _main = e.gpu.enter_main()?;
7788                e.stream().wait(&ws.ev_oproj)?;
7789                let mut output = e.uninit(ws.o_out)?;
7790                if oproj_tail_on() && oproj_tail_eligible() {
7791                    // M2: defer the add into the residual+norm consumer (waits stay HERE;
7792                    // only the arithmetic moves). `output` is returned unwritten.
7793                    use cudarc::driver::DevicePtr;
7794                    let stream = e.stream();
7795                    let (p0, _g0) = ws.o_partials[0][0].device_ptr(&stream);
7796                    let (p1, _g1) = ws.o_partials[1][0].device_ptr(&stream);
7797                    set_oproj_tail((p0, p1));
7798                    return Ok(output);
7799                }
7800                e.add(
7801                    &ws.o_partials[0][0],
7802                    &ws.o_partials[1][0],
7803                    &mut output,
7804                    ws.o_out,
7805                )?;
7806                return Ok(output);
7807            }
7808            if o_fused {
7809                self.decode_v2_finish_root_fused(ws)?;
7810                ws.ev_oproj.record(&root.stream())?;
7811                let _main = e.gpu.enter_main()?;
7812                e.stream().wait(&ws.ev_oproj)?;
7813                let mut output = e.uninit(ws.o_out)?;
7814                e.stream().memcpy_dtod(
7815                    &ws.reduce_a.slice(0..ws.o_out),
7816                    &mut output.slice_mut(0..ws.o_out),
7817                )?;
7818                return Ok(output);
7819            }
7820            let mut first = true;
7821            let mut current_is_a = false;
7822            for rank in 0..ranks {
7823                for block in 0..ws.blocks_per_rank {
7824                    let use_peer = rank != 0;
7825                    if use_peer {
7826                        raw_copy_bytes(
7827                            ws.raw_peer_partial,
7828                            ws.raw_o_partials[rank][block],
7829                            ws.o_out * std::mem::size_of::<f32>(),
7830                            root,
7831                        )?;
7832                    }
7833                    // add(prev, partial) -> the other reduce buffer, exactly one add per block
7834                    match (first, current_is_a, use_peer) {
7835                        (true, _, true) => {
7836                            root.add(&ws.zeros, &ws.peer_partial, &mut ws.reduce_a, ws.o_out)?
7837                        }
7838                        (true, _, false) => root.add(
7839                            &ws.zeros,
7840                            &ws.o_partials[0][block],
7841                            &mut ws.reduce_a,
7842                            ws.o_out,
7843                        )?,
7844                        (false, true, true) => {
7845                            root.add(&ws.reduce_a, &ws.peer_partial, &mut ws.reduce_b, ws.o_out)?
7846                        }
7847                        (false, true, false) => root.add(
7848                            &ws.reduce_a,
7849                            &ws.o_partials[0][block],
7850                            &mut ws.reduce_b,
7851                            ws.o_out,
7852                        )?,
7853                        (false, false, true) => {
7854                            root.add(&ws.reduce_b, &ws.peer_partial, &mut ws.reduce_a, ws.o_out)?
7855                        }
7856                        (false, false, false) => root.add(
7857                            &ws.reduce_b,
7858                            &ws.o_partials[0][block],
7859                            &mut ws.reduce_a,
7860                            ws.o_out,
7861                        )?,
7862                    }
7863                    current_is_a = first || !current_is_a;
7864                    first = false;
7865                }
7866            }
7867            final_in_a = current_is_a;
7868
7869            if !no_local_shadow_on() {
7870                let bytes = ws.local_kv_dim * std::mem::size_of::<f32>();
7871                for rank in 0..ranks {
7872                    let offset = rank * bytes;
7873                    raw_copy_bytes(ws.raw_k_shadow + offset as u64, ws.raw_k[rank], bytes, root)?;
7874                    raw_copy_bytes(
7875                        ws.raw_v_shadow + offset as u64,
7876                        ws.raw_v_raw[rank],
7877                        bytes,
7878                        root,
7879                    )?;
7880                }
7881            }
7882            ws.ev_oproj.record(&root.stream())?;
7883        }
7884
7885        // Model-engine output: e waits the root event, then copies the reduced row into a
7886        // fresh e-context buffer (same ownership contract as v1's `e.htod`). The same wait
7887        // orders the driver's shadow append (it reads ws.k_shadow/ws.v_shadow on e's stream).
7888        let _main = e.gpu.enter_main()?;
7889        e.stream().wait(&ws.ev_oproj)?;
7890        let mut output = e.uninit(ws.o_out)?;
7891        let source = if final_in_a {
7892            &ws.reduce_a
7893        } else {
7894            &ws.reduce_b
7895        };
7896        e.stream().memcpy_dtod(
7897            &source.slice(0..ws.o_out),
7898            &mut output.slice_mut(0..ws.o_out),
7899        )?;
7900        Ok(output)
7901    }
7902
7903    #[allow(clippy::too_many_arguments)] // allow: the parameter list mirrors the kernel/FFI/call contract; bundling into a struct is a refactor, not a lint fix
7904    pub fn run_routed_experts(
7905        &self,
7906        experts: &ResidentExpertParallel,
7907        input: &[f32],
7908        tokens: usize,
7909        selected: &[usize],
7910        route_weights: &[f32],
7911        experts_per_token: usize,
7912        activation_limit: Option<f32>,
7913    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
7914        validate_step_expert_activation_limit(activation_limit)?;
7915        validate_ep_residency(&self.ranks, experts)?;
7916        validate_activations(input, tokens, experts.input_width)?;
7917        let pairs = tokens
7918            .checked_mul(experts_per_token)
7919            .ok_or("EP route count overflow")?;
7920        if selected.len() != pairs || route_weights.len() != pairs {
7921            return Err(format!(
7922                "EP routes selected={} weights={} != tokens {tokens} x experts/token \
7923                 {experts_per_token} ({pairs})",
7924                selected.len(),
7925                route_weights.len(),
7926            )
7927            .into());
7928        }
7929        if !route_weights.iter().all(|weight| weight.is_finite()) {
7930            return Err("EP route weights contain a non-finite value".into());
7931        }
7932        if self.native_p2p {
7933            return self.run_routed_experts_native(
7934                experts,
7935                input,
7936                tokens,
7937                selected,
7938                route_weights,
7939                experts_per_token,
7940                activation_limit,
7941            );
7942        }
7943
7944        let mut output = vec![0.0f32; tokens * experts.input_width];
7945        let per_rank = experts.expert_count / experts.ranks.len();
7946        for token in 0..tokens {
7947            let input_row = &input[token * experts.input_width..(token + 1) * experts.input_width];
7948            for slot in 0..experts_per_token {
7949                let pair = token * experts_per_token + slot;
7950                let expert = selected[pair];
7951                if expert >= experts.expert_count {
7952                    return Err(format!(
7953                        "EP selected expert {expert} outside 0..{}",
7954                        experts.expert_count
7955                    )
7956                    .into());
7957                }
7958                let owner = expert / per_rank;
7959                let local_expert = expert - experts.ranks[owner].gate.expert_range.start;
7960                let rank = &experts.ranks[owner];
7961                let engine = &self.ranks[owner];
7962                let gate =
7963                    run_resident_bank_expert(engine, &rank.gate, local_expert, input_row, 1)?;
7964                let up = run_resident_bank_expert(engine, &rank.up, local_expert, input_row, 1)?;
7965                let activated: Vec<f32> = gate
7966                    .iter()
7967                    .zip(&up)
7968                    .map(|(&gate, &up)| step_expert_activation_host(gate, up, activation_limit))
7969                    .collect();
7970                debug_assert_eq!(activated.len(), experts.expert_width);
7971                let down =
7972                    run_resident_bank_expert(engine, &rank.down, local_expert, &activated, 1)?;
7973                let weight = route_weights[pair];
7974                for (sum, value) in output
7975                    [token * experts.input_width..(token + 1) * experts.input_width]
7976                    .iter_mut()
7977                    .zip(down)
7978                {
7979                    *sum += weight * value;
7980                }
7981            }
7982        }
7983        Ok(output)
7984    }
7985
7986    #[allow(clippy::too_many_arguments)] // allow: the parameter list mirrors the kernel/FFI/call contract; bundling into a struct is a refactor, not a lint fix
7987    fn run_routed_experts_native(
7988        &self,
7989        experts: &ResidentExpertParallel,
7990        input: &[f32],
7991        tokens: usize,
7992        selected: &[usize],
7993        route_weights: &[f32],
7994        experts_per_token: usize,
7995        activation_limit: Option<f32>,
7996    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
7997        if !self.native_p2p || self.ranks.len() < 2 {
7998            return Err("native EP execution requires at least two P2P ranks".into());
7999        }
8000        if self.ep_device_arithmetic {
8001            return self.run_routed_experts_native_device(
8002                experts,
8003                input,
8004                tokens,
8005                selected,
8006                route_weights,
8007                experts_per_token,
8008                activation_limit,
8009            );
8010        }
8011        let mut output = vec![0.0f32; tokens * experts.input_width];
8012        let per_rank = experts.expert_count / experts.ranks.len();
8013        for token in 0..tokens {
8014            let input_row = &input[token * experts.input_width..(token + 1) * experts.input_width];
8015            let mut rank_inputs = (0..self.ranks.len())
8016                .map(|_| None)
8017                .collect::<Vec<Option<CudaSlice<f32>>>>();
8018            rank_inputs[0] = Some({
8019                let root = &self.ranks[0];
8020                let _main = root.gpu.enter_main()?;
8021                root.htod(input_row)?
8022            });
8023
8024            for slot in 0..experts_per_token {
8025                let pair = token * experts_per_token + slot;
8026                let expert = selected[pair];
8027                if expert >= experts.expert_count {
8028                    return Err(format!(
8029                        "EP selected expert {expert} outside 0..{}",
8030                        experts.expert_count
8031                    )
8032                    .into());
8033                }
8034                let owner = expert / per_rank;
8035                let local_expert = expert - experts.ranks[owner].gate.expert_range.start;
8036                if rank_inputs[owner].is_none() {
8037                    let peer_input = {
8038                        let root_input = rank_inputs[0]
8039                            .as_ref()
8040                            .ok_or("native EP lost its root input")?;
8041                        let engine = &self.ranks[owner];
8042                        let _main = engine.gpu.enter_main()?;
8043                        let mut peer_input = engine.uninit(experts.input_width)?;
8044                        engine.stream().memcpy_dtod(root_input, &mut peer_input)?;
8045                        peer_input
8046                    };
8047                    rank_inputs[owner] = Some(peer_input);
8048                }
8049
8050                let rank = &experts.ranks[owner];
8051                let engine = &self.ranks[owner];
8052                let owner_input = rank_inputs[owner]
8053                    .as_ref()
8054                    .ok_or("native EP owner input is absent after dispatch")?;
8055                let gate = run_resident_bank_expert_device(
8056                    engine,
8057                    &rank.gate,
8058                    local_expert,
8059                    owner_input,
8060                    1,
8061                )?;
8062                let up = run_resident_bank_expert_device(
8063                    engine,
8064                    &rank.up,
8065                    local_expert,
8066                    owner_input,
8067                    1,
8068                )?;
8069                let (gate, up) = {
8070                    let _main = engine.gpu.enter_main()?;
8071                    (engine.dtoh(&gate)?, engine.dtoh(&up)?)
8072                };
8073                let activated = gate
8074                    .iter()
8075                    .zip(&up)
8076                    .map(|(&gate, &up)| step_expert_activation_host(gate, up, activation_limit))
8077                    .collect::<Vec<_>>();
8078                debug_assert_eq!(activated.len(), experts.expert_width);
8079                let activated = {
8080                    let _main = engine.gpu.enter_main()?;
8081                    engine.htod(&activated)?
8082                };
8083                let down = run_resident_bank_expert_device(
8084                    engine,
8085                    &rank.down,
8086                    local_expert,
8087                    &activated,
8088                    1,
8089                )?;
8090                let down = if owner == 0 {
8091                    let _main = engine.gpu.enter_main()?;
8092                    engine.dtoh(&down)?
8093                } else {
8094                    let root = &self.ranks[0];
8095                    let _main = root.gpu.enter_main()?;
8096                    let mut root_down = root.uninit(experts.input_width)?;
8097                    root.stream().memcpy_dtod(&down, &mut root_down)?;
8098                    root.dtoh(&root_down)?
8099                };
8100                let weight = route_weights[pair];
8101                for (sum, value) in output
8102                    [token * experts.input_width..(token + 1) * experts.input_width]
8103                    .iter_mut()
8104                    .zip(down)
8105                {
8106                    *sum += weight * value;
8107                }
8108            }
8109        }
8110        Ok(output)
8111    }
8112
8113    #[allow(clippy::too_many_arguments)] // allow: the parameter list mirrors the kernel/FFI/call contract; bundling into a struct is a refactor, not a lint fix
8114    fn run_routed_experts_native_device(
8115        &self,
8116        experts: &ResidentExpertParallel,
8117        input: &[f32],
8118        tokens: usize,
8119        selected: &[usize],
8120        route_weights: &[f32],
8121        experts_per_token: usize,
8122        activation_limit: Option<f32>,
8123    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
8124        if !self.native_p2p || !self.ep_device_arithmetic || self.ranks.len() < 2 {
8125            return Err(
8126                "device-resident EP arithmetic requires at least two native P2P ranks".into(),
8127            );
8128        }
8129        let mut output = Vec::with_capacity(tokens * experts.input_width);
8130        let per_rank = experts.expert_count / experts.ranks.len();
8131        let root = &self.ranks[0];
8132        for token in 0..tokens {
8133            let input_row = &input[token * experts.input_width..(token + 1) * experts.input_width];
8134            let mut rank_inputs = (0..self.ranks.len())
8135                .map(|_| None)
8136                .collect::<Vec<Option<CudaSlice<f32>>>>();
8137            rank_inputs[0] = Some({
8138                let _main = root.gpu.enter_main()?;
8139                root.htod(input_row)?
8140            });
8141            let mut root_output = {
8142                let _main = root.gpu.enter_main()?;
8143                root.zeros(experts.input_width)?
8144            };
8145            let mut remote_down_keepalive = Vec::new();
8146
8147            for slot in 0..experts_per_token {
8148                let pair = token * experts_per_token + slot;
8149                let expert = selected[pair];
8150                if expert >= experts.expert_count {
8151                    return Err(format!(
8152                        "EP selected expert {expert} outside 0..{}",
8153                        experts.expert_count
8154                    )
8155                    .into());
8156                }
8157                let owner = expert / per_rank;
8158                let local_expert = expert - experts.ranks[owner].gate.expert_range.start;
8159                if rank_inputs[owner].is_none() {
8160                    let peer_input = {
8161                        let root_input = rank_inputs[0]
8162                            .as_ref()
8163                            .ok_or("native EP lost its root input")?;
8164                        let engine = &self.ranks[owner];
8165                        let _main = engine.gpu.enter_main()?;
8166                        let mut peer_input = engine.uninit(experts.input_width)?;
8167                        engine.stream().memcpy_dtod(root_input, &mut peer_input)?;
8168                        peer_input
8169                    };
8170                    rank_inputs[owner] = Some(peer_input);
8171                }
8172
8173                let rank = &experts.ranks[owner];
8174                let engine = &self.ranks[owner];
8175                let owner_input = rank_inputs[owner]
8176                    .as_ref()
8177                    .ok_or("native EP owner input is absent after dispatch")?;
8178                let gate = run_resident_bank_expert_device(
8179                    engine,
8180                    &rank.gate,
8181                    local_expert,
8182                    owner_input,
8183                    1,
8184                )?;
8185                let up = run_resident_bank_expert_device(
8186                    engine,
8187                    &rank.up,
8188                    local_expert,
8189                    owner_input,
8190                    1,
8191                )?;
8192                let activated = {
8193                    let _main = engine.gpu.enter_main()?;
8194                    let mut activated = engine.uninit(experts.expert_width)?;
8195                    if let Some(limit) = activation_limit {
8196                        engine.silu_clamped_mul_host_expf(
8197                            &gate,
8198                            &up,
8199                            limit,
8200                            &mut activated,
8201                            experts.expert_width,
8202                        )?;
8203                    } else {
8204                        engine.silu_mul_host_expf(
8205                            &gate,
8206                            &up,
8207                            &mut activated,
8208                            experts.expert_width,
8209                        )?;
8210                    }
8211                    activated
8212                };
8213                let down = run_resident_bank_expert_device(
8214                    engine,
8215                    &rank.down,
8216                    local_expert,
8217                    &activated,
8218                    1,
8219                )?;
8220                let root_down = if owner == 0 {
8221                    down
8222                } else {
8223                    let _main = root.gpu.enter_main()?;
8224                    let mut root_down = root.uninit(experts.input_width)?;
8225                    root.stream().memcpy_dtod(&down, &mut root_down)?;
8226                    // The peer copy runs on the root stream. Keep its remote source alive until
8227                    // the final root readback synchronizes that stream; otherwise async free can
8228                    // recycle the owner's allocation while cuMemcpyPeerAsync is still reading it.
8229                    remote_down_keepalive.push(down);
8230                    root_down
8231                };
8232                let _main = root.gpu.enter_main()?;
8233                let mut destination = root_output.slice_mut(0..experts.input_width);
8234                root.axpy_host_into(
8235                    &root_down.slice(0..root_down.len()),
8236                    route_weights[pair],
8237                    &mut destination,
8238                    experts.input_width,
8239                )?;
8240            }
8241
8242            let _main = root.gpu.enter_main()?;
8243            let root_output = root.dtoh(&root_output)?;
8244            drop(remote_down_keepalive);
8245            output.extend(root_output);
8246        }
8247        Ok(output)
8248    }
8249}
8250
8251#[allow(clippy::manual_is_multiple_of)] // allow: divisor is runtime-derived; the modulo form keeps a zero divisor loud (a panic), where is_multiple_of would return false silently
8252fn validate_column_shape(matrix: E4m3BlockMatrix<'_>, tp: usize) -> Result<(), String> {
8253    if matrix.out_features % tp != 0 {
8254        return Err(format!(
8255            "column-parallel out_features {} is not divisible by TP={tp}",
8256            matrix.out_features
8257        ));
8258    }
8259    let local_out = matrix.out_features / tp;
8260    if !local_out.is_multiple_of(FP8_BLOCK) {
8261        return Err(format!(
8262            "column-parallel output shard {local_out} cuts through a {FP8_BLOCK}-row \
8263             E4M3 scale block"
8264        ));
8265    }
8266    Ok(())
8267}
8268
8269#[allow(clippy::manual_is_multiple_of)] // allow: divisor is runtime-derived; the modulo form keeps a zero divisor loud (a panic), where is_multiple_of would return false silently
8270fn step_bf16_canonical_chunk_rows(out_features: usize, tp: usize) -> Result<usize, String> {
8271    if !matches!(tp, 1 | 2 | 4 | 8) {
8272        return Err(format!(
8273            "Step BF16 canonical projection requires TP1/TP2/TP4/TP8, got TP={tp}"
8274        ));
8275    }
8276    if out_features == 0 || !out_features.is_multiple_of(PRODUCT_MAX_CARDS) {
8277        return Err(format!(
8278            "Step BF16 output width {out_features} is not divisible by the TP8 product envelope"
8279        ));
8280    }
8281    let canonical_rows = out_features / PRODUCT_MAX_CARDS;
8282    let local_out = out_features / tp;
8283    if local_out % canonical_rows != 0 {
8284        return Err(format!(
8285            "Step BF16 TP={tp} output shard {local_out} is not divisible by canonical \
8286             {canonical_rows}-row chunks"
8287        ));
8288    }
8289    Ok(canonical_rows)
8290}
8291
8292#[allow(clippy::manual_is_multiple_of)] // allow: divisor is runtime-derived; the modulo form keeps a zero divisor loud (a panic), where is_multiple_of would return false silently
8293fn step_bf16_canonical_chunk_cols(in_features: usize, tp: usize) -> Result<usize, String> {
8294    if !matches!(tp, 1 | 2 | 4 | 8) {
8295        return Err(format!(
8296            "Step BF16 canonical row projection requires TP1/TP2/TP4/TP8, got TP={tp}"
8297        ));
8298    }
8299    if in_features == 0 || !in_features.is_multiple_of(PRODUCT_MAX_CARDS) {
8300        return Err(format!(
8301            "Step BF16 input width {in_features} is not divisible by the TP8 product envelope"
8302        ));
8303    }
8304    let canonical_cols = in_features / PRODUCT_MAX_CARDS;
8305    let local_in = in_features / tp;
8306    if local_in % canonical_cols != 0 {
8307        return Err(format!(
8308            "Step BF16 TP={tp} input shard {local_in} is not divisible by canonical \
8309             {canonical_cols}-column chunks"
8310        ));
8311    }
8312    Ok(canonical_cols)
8313}
8314
8315#[allow(clippy::manual_is_multiple_of)] // allow: divisor is runtime-derived; the modulo form keeps a zero divisor loud (a panic), where is_multiple_of would return false silently
8316fn validate_row_shape(matrix: E4m3BlockMatrix<'_>, tp: usize) -> Result<(), String> {
8317    if matrix.in_features % tp != 0 {
8318        return Err(format!(
8319            "row-parallel in_features {} is not divisible by TP={tp}",
8320            matrix.in_features
8321        ));
8322    }
8323    let local_in = matrix.in_features / tp;
8324    if !local_in.is_multiple_of(FP8_BLOCK) {
8325        return Err(format!(
8326            "row-parallel input shard {local_in} cuts through a {FP8_BLOCK}-column \
8327             E4M3 scale block"
8328        ));
8329    }
8330    Ok(())
8331}
8332
8333fn upload_rank(
8334    engine: &Engine,
8335    matrix: E4m3BlockMatrix<'_>,
8336) -> Result<ResidentE4m3Rank, Box<dyn std::error::Error>> {
8337    let _main = engine.gpu.enter_main()?;
8338    matrix.validate()?;
8339    Ok(ResidentE4m3Rank {
8340        codes: engine.htod_bytes(matrix.codes)?,
8341        scales: engine.htod(matrix.scales)?,
8342        out_features: matrix.out_features,
8343        in_features: matrix.in_features,
8344    })
8345}
8346
8347fn upload_bf16_rank(
8348    engine: &Engine,
8349    matrix: Bf16Matrix<'_>,
8350    f32_mirror: bool,
8351) -> Result<ResidentBf16Rank, Box<dyn std::error::Error>> {
8352    let _main = engine.gpu.enter_main()?;
8353    matrix.validate()?;
8354    let bytes = engine.htod_bytes(matrix.bytes)?;
8355    let weight = if f32_mirror {
8356        let values = matrix
8357            .out_features
8358            .checked_mul(matrix.in_features)
8359            .ok_or("resident BF16 mirror element count overflow")?;
8360        ResidentBf16Weight::F32(engine.bf16_to_f32(&bytes.slice(0..bytes.len()), values)?)
8361    } else {
8362        ResidentBf16Weight::Bf16(bytes)
8363    };
8364    // MEMRA_STEP_TP_W8: encode the q8_0 decode mirror once, here, while the bf16 bytes are
8365    // already resident. Rows whose in_features is not a multiple of 32 have no q8_0 form and
8366    // simply keep the bf16 program (the decode arm checks for the mirror, never assumes it).
8367    let q8 = if crate::step_tp_w8_on() && matrix.in_features.is_multiple_of(32) {
8368        if let ResidentBf16Weight::Bf16(bytes) = &weight {
8369            // Two steps, because the mmvq rp kernel does NOT read ggml-interleaved 34-byte
8370            // blocks: it reads a PLANAR mirror (all quants, then all half scales — the
8371            // q4_0/NVFP4 rp convention). The encoder writes the interleaved form and
8372            // `build_q8_rp4_raw` — the same kernel the GGUF loader uses — splits it into
8373            // planes. Skipping the split is what made the first W8 gate return zeros
8374            // (verify-prefill argmax=0, maxdiff=0.000e0).
8375            let row_bytes = Engine::q8_0_row_bytes(matrix.in_features);
8376            let mut interleaved = engine.alloc_u8_uninit(matrix.out_features * row_bytes)?;
8377            engine.encode_q8_0_from_bf16(
8378                bytes,
8379                &mut interleaved,
8380                matrix.in_features,
8381                matrix.out_features,
8382            )?;
8383            let mirror =
8384                engine.build_q8_rp4_raw(&interleaved, matrix.in_features, matrix.out_features)?;
8385            Some(mirror)
8386        } else {
8387            None
8388        }
8389    } else {
8390        None
8391    };
8392    Ok(ResidentBf16Rank {
8393        weight,
8394        out_features: matrix.out_features,
8395        in_features: matrix.in_features,
8396        q8,
8397    })
8398}
8399
8400fn upload_expert_bank_rank(
8401    engine: &Engine,
8402    bank: E4m3ExpertBank<'_>,
8403    expert_range: Range<usize>,
8404) -> Result<ResidentE4m3ExpertBankRank, Box<dyn std::error::Error>> {
8405    let _main = engine.gpu.enter_main()?;
8406    bank.validate()?;
8407    if expert_range.start >= expert_range.end || expert_range.end > bank.expert_count {
8408        return Err(format!(
8409            "invalid EP expert range {expert_range:?} for {} experts",
8410            bank.expert_count
8411        )
8412        .into());
8413    }
8414    let code_stride = bank.out_features * bank.in_features;
8415    let scale_stride = bank.out_features.div_ceil(FP8_BLOCK) * bank.in_features.div_ceil(FP8_BLOCK);
8416    Ok(ResidentE4m3ExpertBankRank {
8417        codes: engine.htod_bytes(
8418            &bank.codes[expert_range.start * code_stride..expert_range.end * code_stride],
8419        )?,
8420        scales: engine.htod(
8421            &bank.scales[expert_range.start * scale_stride..expert_range.end * scale_stride],
8422        )?,
8423        expert_range,
8424        out_features: bank.out_features,
8425        in_features: bank.in_features,
8426        code_stride,
8427        scale_stride,
8428        k_blocks: None,
8429    })
8430}
8431
8432#[allow(clippy::manual_is_multiple_of)] // allow: divisor is runtime-derived; the modulo form keeps a zero divisor loud (a panic), where is_multiple_of would return false silently
8433fn validate_column_bank_shape(bank: E4m3ExpertBank<'_>, tp: usize) -> Result<(), String> {
8434    if bank.out_features % tp != 0 {
8435        return Err(format!(
8436            "TP expert output width {} is not divisible by TP={tp}",
8437            bank.out_features
8438        ));
8439    }
8440    let local_out = bank.out_features / tp;
8441    if !local_out.is_multiple_of(FP8_BLOCK) {
8442        return Err(format!(
8443            "TP expert output shard {local_out} cuts through a {FP8_BLOCK}-row E4M3 scale block"
8444        ));
8445    }
8446    Ok(())
8447}
8448
8449#[allow(clippy::manual_is_multiple_of)] // allow: divisor is runtime-derived; the modulo form keeps a zero divisor loud (a panic), where is_multiple_of would return false silently
8450fn validate_row_bank_shape(bank: E4m3ExpertBank<'_>, tp: usize) -> Result<(), String> {
8451    if bank.in_features % tp != 0 {
8452        return Err(format!(
8453            "TP expert input width {} is not divisible by TP={tp}",
8454            bank.in_features
8455        ));
8456    }
8457    let local_in = bank.in_features / tp;
8458    if !local_in.is_multiple_of(FP8_BLOCK) {
8459        return Err(format!(
8460            "TP expert input shard {local_in} cuts through a {FP8_BLOCK}-column E4M3 scale block"
8461        ));
8462    }
8463    Ok(())
8464}
8465
8466fn upload_column_bank_rank(
8467    engine: &Engine,
8468    bank: E4m3ExpertBank<'_>,
8469    tp: usize,
8470    rank: usize,
8471) -> Result<ResidentE4m3ExpertBankRank, Box<dyn std::error::Error>> {
8472    let _main = engine.gpu.enter_main()?;
8473    let packed = pack_column_bank_rank(bank, tp, rank)?;
8474    Ok(ResidentE4m3ExpertBankRank {
8475        codes: engine.htod_bytes(&packed.codes)?,
8476        scales: engine.htod(&packed.scales)?,
8477        expert_range: packed.expert_range,
8478        out_features: packed.out_features,
8479        in_features: packed.in_features,
8480        code_stride: packed.code_stride,
8481        scale_stride: packed.scale_stride,
8482        k_blocks: packed.k_blocks,
8483    })
8484}
8485
8486fn pack_column_bank_rank(
8487    bank: E4m3ExpertBank<'_>,
8488    tp: usize,
8489    rank: usize,
8490) -> Result<PackedE4m3ExpertBankRank, String> {
8491    bank.validate()?;
8492    validate_column_bank_shape(bank, tp)?;
8493    if rank >= tp {
8494        return Err(format!("TP rank {rank} outside 0..{tp}"));
8495    }
8496    let local_out = bank.out_features / tp;
8497    let full_code_stride = bank.out_features * bank.in_features;
8498    let local_code_stride = local_out * bank.in_features;
8499    let scale_cols = bank.in_features.div_ceil(FP8_BLOCK);
8500    let full_scale_stride = bank.out_features.div_ceil(FP8_BLOCK) * scale_cols;
8501    let local_scale_rows = local_out / FP8_BLOCK;
8502    let local_scale_stride = local_scale_rows * scale_cols;
8503    let mut codes = Vec::with_capacity(bank.expert_count * local_code_stride);
8504    let mut scales = Vec::with_capacity(bank.expert_count * local_scale_stride);
8505    let row_start = rank * local_out;
8506    let scale_row_start = rank * local_scale_rows;
8507    for expert in 0..bank.expert_count {
8508        let code_start = expert * full_code_stride + row_start * bank.in_features;
8509        codes.extend_from_slice(&bank.codes[code_start..code_start + local_code_stride]);
8510        let scale_start = expert * full_scale_stride + scale_row_start * scale_cols;
8511        scales.extend_from_slice(&bank.scales[scale_start..scale_start + local_scale_stride]);
8512    }
8513    Ok(PackedE4m3ExpertBankRank {
8514        codes,
8515        scales,
8516        expert_range: 0..bank.expert_count,
8517        out_features: local_out,
8518        in_features: bank.in_features,
8519        code_stride: local_code_stride,
8520        scale_stride: local_scale_stride,
8521        k_blocks: None,
8522    })
8523}
8524
8525fn upload_row_bank_rank(
8526    engine: &Engine,
8527    bank: E4m3ExpertBank<'_>,
8528    tp: usize,
8529    rank: usize,
8530) -> Result<ResidentE4m3ExpertBankRank, Box<dyn std::error::Error>> {
8531    let _main = engine.gpu.enter_main()?;
8532    let packed = pack_row_bank_rank(bank, tp, rank)?;
8533    Ok(ResidentE4m3ExpertBankRank {
8534        codes: engine.htod_bytes(&packed.codes)?,
8535        scales: engine.htod(&packed.scales)?,
8536        expert_range: packed.expert_range,
8537        out_features: packed.out_features,
8538        in_features: packed.in_features,
8539        code_stride: packed.code_stride,
8540        scale_stride: packed.scale_stride,
8541        k_blocks: packed.k_blocks,
8542    })
8543}
8544
8545fn pack_row_bank_rank(
8546    bank: E4m3ExpertBank<'_>,
8547    tp: usize,
8548    rank: usize,
8549) -> Result<PackedE4m3ExpertBankRank, String> {
8550    bank.validate()?;
8551    validate_row_bank_shape(bank, tp)?;
8552    if rank >= tp {
8553        return Err(format!("TP rank {rank} outside 0..{tp}"));
8554    }
8555    let local_in = bank.in_features / tp;
8556    let full_code_stride = bank.out_features * bank.in_features;
8557    let local_code_stride = bank.out_features * local_in;
8558    let full_scale_cols = bank.in_features.div_ceil(FP8_BLOCK);
8559    let local_scale_cols = local_in / FP8_BLOCK;
8560    let scale_rows = bank.out_features.div_ceil(FP8_BLOCK);
8561    let full_scale_stride = scale_rows * full_scale_cols;
8562    let local_scale_stride = scale_rows * local_scale_cols;
8563    let global_block_start = rank * local_scale_cols;
8564    let mut codes = Vec::with_capacity(bank.expert_count * local_code_stride);
8565    let mut scales = Vec::with_capacity(bank.expert_count * local_scale_stride);
8566    for expert in 0..bank.expert_count {
8567        let expert_code_start = expert * full_code_stride;
8568        let expert_scale_start = expert * full_scale_stride;
8569        for local_block in 0..local_scale_cols {
8570            let global_block = global_block_start + local_block;
8571            let column_start = global_block * FP8_BLOCK;
8572            for row in 0..bank.out_features {
8573                let start = expert_code_start + row * bank.in_features + column_start;
8574                codes.extend_from_slice(&bank.codes[start..start + FP8_BLOCK]);
8575            }
8576            for row in 0..scale_rows {
8577                scales.push(bank.scales[expert_scale_start + row * full_scale_cols + global_block]);
8578            }
8579        }
8580    }
8581    Ok(PackedE4m3ExpertBankRank {
8582        codes,
8583        scales,
8584        expert_range: 0..bank.expert_count,
8585        out_features: bank.out_features,
8586        in_features: local_in,
8587        code_stride: local_code_stride,
8588        scale_stride: local_scale_stride,
8589        k_blocks: Some(local_scale_cols),
8590    })
8591}
8592
8593fn validate_resident_ranks(engines: &[Engine], ranks: &[ResidentE4m3Rank]) -> Result<(), String> {
8594    if engines.len() != ranks.len() {
8595        return Err(format!(
8596            "resident TP rank count {} != runtime rank count {}",
8597            ranks.len(),
8598            engines.len()
8599        ));
8600    }
8601    for (rank, (engine, matrix)) in engines.iter().zip(ranks).enumerate() {
8602        let device = engine.ctx().ordinal();
8603        if matrix.codes.ordinal() != device || matrix.scales.ordinal() != device {
8604            return Err(format!(
8605                "resident TP rank {rank} is not owned by runtime device {device}"
8606            ));
8607        }
8608    }
8609    Ok(())
8610}
8611
8612fn validate_tp_bank_residency(
8613    engines: &[Engine],
8614    experts: &ResidentTpExpertBank,
8615) -> Result<(), String> {
8616    if engines.len() != experts.gate.len()
8617        || engines.len() != experts.up.len()
8618        || engines.len() != experts.down.len()
8619    {
8620        return Err(format!(
8621            "resident TP expert-bank rank counts gate={} up={} down={} != runtime {}",
8622            experts.gate.len(),
8623            experts.up.len(),
8624            experts.down.len(),
8625            engines.len()
8626        ));
8627    }
8628    for (rank, engine) in engines.iter().enumerate() {
8629        let device = engine.ctx().ordinal();
8630        for (projection, bank) in [
8631            ("gate", &experts.gate[rank]),
8632            ("up", &experts.up[rank]),
8633            ("down", &experts.down[rank]),
8634        ] {
8635            if bank.codes.ordinal() != device || bank.scales.ordinal() != device {
8636                return Err(format!(
8637                    "resident TP rank {rank} {projection} bank is not owned by runtime device \
8638                     {device}"
8639                ));
8640            }
8641        }
8642    }
8643    Ok(())
8644}
8645
8646fn validate_ep_residency(
8647    engines: &[Engine],
8648    experts: &ResidentExpertParallel,
8649) -> Result<(), String> {
8650    if engines.len() != experts.ranks.len() {
8651        return Err(format!(
8652            "resident EP rank count {} != runtime rank count {}",
8653            experts.ranks.len(),
8654            engines.len()
8655        ));
8656    }
8657    for (rank, (engine, resident)) in engines.iter().zip(&experts.ranks).enumerate() {
8658        let device = engine.ctx().ordinal();
8659        for (projection, bank) in [
8660            ("gate", &resident.gate),
8661            ("up", &resident.up),
8662            ("down", &resident.down),
8663        ] {
8664            if bank.codes.ordinal() != device || bank.scales.ordinal() != device {
8665                return Err(format!(
8666                    "resident EP rank {rank} {projection} bank is not owned by runtime device \
8667                     {device}"
8668                ));
8669            }
8670        }
8671    }
8672    Ok(())
8673}
8674
8675fn run_rank(
8676    engine: &Engine,
8677    matrix: E4m3BlockMatrix<'_>,
8678    activations: &[f32],
8679    tokens: usize,
8680) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
8681    let _main = engine.gpu.enter_main()?;
8682    let codes = engine.htod_bytes(matrix.codes)?;
8683    let scales = engine.htod(matrix.scales)?;
8684    let activations = engine.htod(activations)?;
8685    let output = engine.qmatvec_mmq_fp8_blk(
8686        &codes,
8687        &scales,
8688        &activations,
8689        tokens,
8690        matrix.in_features,
8691        matrix.out_features,
8692    )?;
8693    engine.dtoh(&output)
8694}
8695
8696fn run_resident_rank(
8697    engine: &Engine,
8698    matrix: &ResidentE4m3Rank,
8699    activations: &[f32],
8700    tokens: usize,
8701) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
8702    let _main = engine.gpu.enter_main()?;
8703    let activations = engine.htod(activations)?;
8704    let output = engine.qmatvec_mmq_fp8_blk(
8705        &matrix.codes,
8706        &matrix.scales,
8707        &activations,
8708        tokens,
8709        matrix.in_features,
8710        matrix.out_features,
8711    )?;
8712    engine.dtoh(&output)
8713}
8714
8715fn run_resident_bf16_rank(
8716    engine: &Engine,
8717    matrix: &ResidentBf16Rank,
8718    activations: &[f32],
8719    tokens: usize,
8720    canonical_chunk_rows: Option<usize>,
8721) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
8722    let _main = engine.gpu.enter_main()?;
8723    let activations = engine.htod(activations)?;
8724    let output = run_resident_bf16_rank_device(
8725        engine,
8726        matrix,
8727        &activations,
8728        tokens,
8729        canonical_chunk_rows,
8730        false,
8731    )?;
8732    engine.dtoh(&output)
8733}
8734
8735fn run_resident_bf16_rank_device(
8736    engine: &Engine,
8737    matrix: &ResidentBf16Rank,
8738    activations: &CudaSlice<f32>,
8739    tokens: usize,
8740    canonical_chunk_rows: Option<usize>,
8741    strided_chunk_output: bool,
8742) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
8743    let _main = engine.gpu.enter_main()?;
8744    if activations.ordinal() != engine.ctx().ordinal() {
8745        return Err(format!(
8746            "resident BF16 activation device {} != rank device {}",
8747            activations.ordinal(),
8748            engine.ctx().ordinal()
8749        )
8750        .into());
8751    }
8752    if activations.len() != tokens * matrix.in_features {
8753        return Err(format!(
8754            "resident BF16 activation count {} != {tokens}x{}",
8755            activations.len(),
8756            matrix.in_features
8757        )
8758        .into());
8759    }
8760    match (&matrix.weight, canonical_chunk_rows) {
8761        (ResidentBf16Weight::Bf16(bytes), Some(rows)) => engine
8762            .linear_bf16_resident_canonical_rows(
8763                activations,
8764                bytes,
8765                tokens,
8766                matrix.in_features,
8767                matrix.out_features,
8768                rows,
8769            ),
8770        (ResidentBf16Weight::Bf16(bytes), None) => engine.linear_bf16_resident(
8771            activations,
8772            bytes,
8773            tokens,
8774            matrix.in_features,
8775            matrix.out_features,
8776        ),
8777        (ResidentBf16Weight::F32(values), Some(rows)) if strided_chunk_output => engine
8778            .linear_f32_resident_canonical_rows_strided(
8779                activations,
8780                values,
8781                tokens,
8782                matrix.in_features,
8783                matrix.out_features,
8784                rows,
8785            ),
8786        (ResidentBf16Weight::F32(values), Some(rows)) => engine.linear_f32_resident_canonical_rows(
8787            activations,
8788            values,
8789            tokens,
8790            matrix.in_features,
8791            matrix.out_features,
8792            rows,
8793        ),
8794        (ResidentBf16Weight::F32(values), None) => engine.linear(
8795            activations,
8796            values,
8797            tokens,
8798            matrix.in_features,
8799            matrix.out_features,
8800        ),
8801    }
8802}
8803
8804fn validate_resident_bf16_ranks(
8805    engines: &[Engine],
8806    ranks: &[ResidentBf16Rank],
8807) -> Result<(), String> {
8808    if engines.len() != ranks.len() {
8809        return Err(format!(
8810            "resident BF16 TP rank count {} != runtime rank count {}",
8811            ranks.len(),
8812            engines.len(),
8813        ));
8814    }
8815    for (rank, (engine, matrix)) in engines.iter().zip(ranks).enumerate() {
8816        let device = engine.ctx().ordinal();
8817        if matrix.weight.ordinal() != device {
8818            return Err(format!(
8819                "resident BF16 TP rank {rank} is not owned by runtime device {device}"
8820            ));
8821        }
8822    }
8823    Ok(())
8824}
8825
8826fn validate_step_bf16_row_residency(
8827    engines: &[Engine],
8828    matrix: &ResidentStepBf16RowParallel,
8829) -> Result<(), String> {
8830    if engines.len() != matrix.ranks.len() {
8831        return Err(format!(
8832            "resident Step BF16 row rank count {} != runtime rank count {}",
8833            matrix.ranks.len(),
8834            engines.len(),
8835        ));
8836    }
8837    let canonical_cols = step_bf16_canonical_chunk_cols(matrix.in_features, engines.len())?;
8838    if matrix.canonical_chunk_cols != canonical_cols {
8839        return Err(format!(
8840            "resident Step BF16 row canonical columns {} != registered {canonical_cols}",
8841            matrix.canonical_chunk_cols
8842        ));
8843    }
8844    let blocks_per_rank = PRODUCT_MAX_CARDS / engines.len();
8845    for (rank, (engine, blocks)) in engines.iter().zip(&matrix.ranks).enumerate() {
8846        if blocks.len() != blocks_per_rank {
8847            return Err(format!(
8848                "resident Step BF16 row rank {rank} has {} blocks, expected {blocks_per_rank}",
8849                blocks.len()
8850            ));
8851        }
8852        let device = engine.ctx().ordinal();
8853        for (block, resident) in blocks.iter().enumerate() {
8854            if resident.weight.ordinal() != device
8855                || resident.in_features != canonical_cols
8856                || resident.out_features != matrix.out_features
8857            {
8858                return Err(format!(
8859                    "resident Step BF16 row rank {rank} block {block} has inconsistent \
8860                     device or geometry"
8861                ));
8862            }
8863        }
8864    }
8865    Ok(())
8866}
8867
8868fn validate_replicated_device_rows(
8869    engines: &[Engine],
8870    rows: &ResidentReplicatedDeviceRows,
8871) -> Result<(), String> {
8872    let rank_lengths = rows
8873        .ranks
8874        .iter()
8875        .map(|rank_rows| rank_rows.len())
8876        .collect::<Vec<_>>();
8877    replicated_device_row_values(rows.tokens, rows.width, engines.len(), &rank_lengths)?;
8878    if rows
8879        .ranks
8880        .iter()
8881        .zip(engines)
8882        .any(|(rank_rows, engine)| rank_rows.ordinal() != engine.ctx().ordinal())
8883    {
8884        return Err("replicated device rows are owned by the wrong CUDA contexts".into());
8885    }
8886    Ok(())
8887}
8888
8889fn replicated_device_row_values(
8890    tokens: usize,
8891    width: usize,
8892    expected_ranks: usize,
8893    rank_lengths: &[usize],
8894) -> Result<usize, String> {
8895    let values = tokens
8896        .checked_mul(width)
8897        .ok_or("replicated device row size overflow")?;
8898    if tokens == 0
8899        || width == 0
8900        || expected_ranks == 0
8901        || rank_lengths.len() != expected_ranks
8902        || rank_lengths.iter().any(|&rank_len| rank_len != values)
8903    {
8904        return Err(format!(
8905            "replicated device rows have inconsistent geometry tokens={} width={} ranks={}/{}",
8906            tokens,
8907            width,
8908            rank_lengths.len(),
8909            expected_ranks
8910        ));
8911    }
8912    Ok(values)
8913}
8914
8915fn replicated_device_row_source_values(
8916    tokens: usize,
8917    width: usize,
8918    source_len: usize,
8919    source_device: usize,
8920    root_device: usize,
8921) -> Result<usize, String> {
8922    let values = tokens
8923        .checked_mul(width)
8924        .ok_or("replicated device row size overflow")?;
8925    if tokens == 0 || width == 0 || source_len != values || source_device != root_device {
8926        return Err(format!(
8927            "replicated device row source has inconsistent geometry/device \
8928             tokens={tokens} width={width} source={source_len}@{source_device} root={root_device}"
8929        ));
8930    }
8931    Ok(values)
8932}
8933
8934#[allow(clippy::manual_is_multiple_of)] // allow: divisor is runtime-derived; the modulo form keeps a zero divisor loud (a panic), where is_multiple_of would return false silently
8935fn bf16_column_shard(
8936    matrix: Bf16Matrix<'_>,
8937    tp: usize,
8938    rank: usize,
8939) -> Result<Bf16Matrix<'_>, String> {
8940    matrix.validate()?;
8941    if tp == 0 || rank >= tp || matrix.out_features % tp != 0 {
8942        return Err(format!(
8943            "invalid BF16 column shard out={} TP={tp} rank={rank}",
8944            matrix.out_features
8945        ));
8946    }
8947    let local_out = matrix.out_features / tp;
8948    let row_bytes = matrix.in_features * 2;
8949    let start = rank * local_out * row_bytes;
8950    Ok(Bf16Matrix {
8951        bytes: &matrix.bytes[start..start + local_out * row_bytes],
8952        out_features: local_out,
8953        in_features: matrix.in_features,
8954    })
8955}
8956
8957#[allow(clippy::manual_is_multiple_of)] // allow: divisor is runtime-derived; the modulo form keeps a zero divisor loud (a panic), where is_multiple_of would return false silently
8958fn bf16_row_shard(matrix: Bf16Matrix<'_>, tp: usize, rank: usize) -> Result<Vec<u8>, String> {
8959    matrix.validate()?;
8960    if tp == 0 || rank >= tp || matrix.in_features % tp != 0 {
8961        return Err(format!(
8962            "invalid BF16 row shard in={} TP={tp} rank={rank}",
8963            matrix.in_features
8964        ));
8965    }
8966    let local_in = matrix.in_features / tp;
8967    let mut bytes = Vec::with_capacity(matrix.out_features * local_in * 2);
8968    for row in 0..matrix.out_features {
8969        let start = (row * matrix.in_features + rank * local_in) * 2;
8970        bytes.extend_from_slice(&matrix.bytes[start..start + local_in * 2]);
8971    }
8972    Ok(bytes)
8973}
8974
8975fn bf16_row_block(
8976    matrix: Bf16Matrix<'_>,
8977    col_start: usize,
8978    block_cols: usize,
8979) -> Result<Vec<u8>, String> {
8980    matrix.validate()?;
8981    let col_end = col_start
8982        .checked_add(block_cols)
8983        .ok_or("BF16 row block column overflow")?;
8984    if block_cols == 0 || col_end > matrix.in_features {
8985        return Err(format!(
8986            "invalid BF16 row block columns {col_start}..{col_end} for input width {}",
8987            matrix.in_features
8988        ));
8989    }
8990    let mut bytes = Vec::with_capacity(matrix.out_features * block_cols * 2);
8991    for row in 0..matrix.out_features {
8992        let start = (row * matrix.in_features + col_start) * 2;
8993        bytes.extend_from_slice(&matrix.bytes[start..start + block_cols * 2]);
8994    }
8995    Ok(bytes)
8996}
8997
8998fn run_resident_bank_expert(
8999    engine: &Engine,
9000    bank: &ResidentE4m3ExpertBankRank,
9001    local_expert: usize,
9002    activations: &[f32],
9003    tokens: usize,
9004) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
9005    let _main = engine.gpu.enter_main()?;
9006    if bank.k_blocks.is_some() {
9007        return Err("block-major TP row bank requires canonical block execution".into());
9008    }
9009    let local_count = bank.expert_range.end - bank.expert_range.start;
9010    if local_expert >= local_count {
9011        return Err(format!(
9012            "local EP expert {local_expert} outside 0..{local_count} for range {:?}",
9013            bank.expert_range
9014        )
9015        .into());
9016    }
9017    validate_activations(activations, tokens, bank.in_features)?;
9018    let activations = engine.htod(activations)?;
9019    let weight = bank
9020        .codes
9021        .slice(local_expert * bank.code_stride..(local_expert + 1) * bank.code_stride);
9022    let scales = bank
9023        .scales
9024        .slice(local_expert * bank.scale_stride..(local_expert + 1) * bank.scale_stride);
9025    let input = activations.slice(0..activations.len());
9026    let output = engine.qmatvec_mmq_fp8_blk_view(
9027        &weight,
9028        &scales,
9029        &input,
9030        tokens,
9031        bank.in_features,
9032        bank.out_features,
9033    )?;
9034    engine.dtoh(&output)
9035}
9036
9037fn run_resident_bank_expert_block(
9038    engine: &Engine,
9039    bank: &ResidentE4m3ExpertBankRank,
9040    local_expert: usize,
9041    block: usize,
9042    activations: &[f32],
9043) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
9044    let _main = engine.gpu.enter_main()?;
9045    let local_count = bank.expert_range.end - bank.expert_range.start;
9046    if local_expert >= local_count {
9047        return Err(format!(
9048            "local TP expert {local_expert} outside 0..{local_count} for range {:?}",
9049            bank.expert_range
9050        )
9051        .into());
9052    }
9053    let blocks = bank
9054        .k_blocks
9055        .ok_or("TP row bank is not packed in native K-block order")?;
9056    if block >= blocks {
9057        return Err(format!("TP row block {block} outside 0..{blocks}").into());
9058    }
9059    validate_activations(activations, 1, FP8_BLOCK)?;
9060    let block_code_stride = bank.out_features * FP8_BLOCK;
9061    let block_scale_stride = bank.out_features.div_ceil(FP8_BLOCK);
9062    if bank.in_features != blocks * FP8_BLOCK
9063        || bank.code_stride != blocks * block_code_stride
9064        || bank.scale_stride != blocks * block_scale_stride
9065    {
9066        return Err("TP row bank block-major geometry is inconsistent".into());
9067    }
9068
9069    let expert_code_start = local_expert * bank.code_stride;
9070    let expert_scale_start = local_expert * bank.scale_stride;
9071    let weight = bank.codes.slice(
9072        expert_code_start + block * block_code_stride
9073            ..expert_code_start + (block + 1) * block_code_stride,
9074    );
9075    let scales = bank.scales.slice(
9076        expert_scale_start + block * block_scale_stride
9077            ..expert_scale_start + (block + 1) * block_scale_stride,
9078    );
9079    let activations = engine.htod(activations)?;
9080    let input = activations.slice(0..activations.len());
9081    let output = engine.qmatvec_mmq_fp8_blk_view(
9082        &weight,
9083        &scales,
9084        &input,
9085        1,
9086        FP8_BLOCK,
9087        bank.out_features,
9088    )?;
9089    engine.dtoh(&output)
9090}
9091
9092fn run_resident_bank_expert_device(
9093    engine: &Engine,
9094    bank: &ResidentE4m3ExpertBankRank,
9095    local_expert: usize,
9096    activations: &CudaSlice<f32>,
9097    tokens: usize,
9098) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
9099    let _main = engine.gpu.enter_main()?;
9100    if bank.k_blocks.is_some() {
9101        return Err("block-major TP row bank requires canonical block execution".into());
9102    }
9103    let local_count = bank.expert_range.end - bank.expert_range.start;
9104    if local_expert >= local_count {
9105        return Err(format!(
9106            "local TP expert {local_expert} outside 0..{local_count} for range {:?}",
9107            bank.expert_range
9108        )
9109        .into());
9110    }
9111    let expected = tokens
9112        .checked_mul(bank.in_features)
9113        .ok_or("native TP activation size overflow")?;
9114    if activations.len() != expected || activations.ordinal() != engine.ctx().ordinal() {
9115        return Err(format!(
9116            "native TP activation len/device {}/{} != expected {expected}/{}",
9117            activations.len(),
9118            activations.ordinal(),
9119            engine.ctx().ordinal()
9120        )
9121        .into());
9122    }
9123    let weight = bank
9124        .codes
9125        .slice(local_expert * bank.code_stride..(local_expert + 1) * bank.code_stride);
9126    let scales = bank
9127        .scales
9128        .slice(local_expert * bank.scale_stride..(local_expert + 1) * bank.scale_stride);
9129    let input = activations.slice(0..activations.len());
9130    engine.qmatvec_mmq_fp8_blk_view(
9131        &weight,
9132        &scales,
9133        &input,
9134        tokens,
9135        bank.in_features,
9136        bank.out_features,
9137    )
9138}
9139
9140fn run_resident_bank_expert_block_device(
9141    engine: &Engine,
9142    bank: &ResidentE4m3ExpertBankRank,
9143    local_expert: usize,
9144    block: usize,
9145    activations: &cudarc::driver::CudaView<'_, f32>,
9146) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
9147    let _main = engine.gpu.enter_main()?;
9148    let local_count = bank.expert_range.end - bank.expert_range.start;
9149    if local_expert >= local_count {
9150        return Err(format!(
9151            "local TP expert {local_expert} outside 0..{local_count} for range {:?}",
9152            bank.expert_range
9153        )
9154        .into());
9155    }
9156    let blocks = bank
9157        .k_blocks
9158        .ok_or("native TP row bank is not packed in checkpoint-block order")?;
9159    if block >= blocks {
9160        return Err(format!("native TP row block {block} outside 0..{blocks}").into());
9161    }
9162    let activation_device = activations.stream().context().ordinal();
9163    if activations.len() != FP8_BLOCK || activation_device != engine.ctx().ordinal() {
9164        return Err(format!(
9165            "native TP block activation len/device {}/{} != expected {FP8_BLOCK}/{}",
9166            activations.len(),
9167            activation_device,
9168            engine.ctx().ordinal()
9169        )
9170        .into());
9171    }
9172    let block_code_stride = bank.out_features * FP8_BLOCK;
9173    let block_scale_stride = bank.out_features.div_ceil(FP8_BLOCK);
9174    if bank.in_features != blocks * FP8_BLOCK
9175        || bank.code_stride != blocks * block_code_stride
9176        || bank.scale_stride != blocks * block_scale_stride
9177    {
9178        return Err("native TP row bank block-major geometry is inconsistent".into());
9179    }
9180    let expert_code_start = local_expert * bank.code_stride;
9181    let expert_scale_start = local_expert * bank.scale_stride;
9182    let weight = bank.codes.slice(
9183        expert_code_start + block * block_code_stride
9184            ..expert_code_start + (block + 1) * block_code_stride,
9185    );
9186    let scales = bank.scales.slice(
9187        expert_scale_start + block * block_scale_stride
9188            ..expert_scale_start + (block + 1) * block_scale_stride,
9189    );
9190    engine.qmatvec_mmq_fp8_blk_view(
9191        &weight,
9192        &scales,
9193        activations,
9194        1,
9195        FP8_BLOCK,
9196        bank.out_features,
9197    )
9198}
9199
9200/// Grant `accessor` the right to reach `owner`'s memory — BOTH halves of the grant, which is
9201/// the part every caller gets wrong exactly once:
9202///
9203///   1. `cuCtxEnablePeerAccess`, which covers legacy `cuMemAlloc` allocations, and
9204///   2. `cuMemPoolSetAccess` on `owner`'s DEFAULT MEMORY POOL, because
9205///      `cuCtxEnablePeerAccess` does NOT map STREAM-ORDERED POOL allocations and every
9206///      normal memra buffer is one (the same note `pp.rs:1543`/`pp.rs:1578` carries).
9207///
9208/// Extracted from [`configure_native_p2p`] (which now calls it per ordered pair) so a seam
9209/// holding two `&Engine` rather than a `&[Engine]` — the glm5 TP-2 runtime — reuses the exact
9210/// grant sequence instead of growing a second, drifting copy of it. Directed: call it once
9211/// per direction. Refuses by name when `cuDeviceCanAccessPeer` says the pair has no path,
9212/// which is the only honest answer: this card class is NOT uniformly peer-connected. Some
9213/// 8-GPU host classes present PEER ISLANDS OF TWO — every cross-island cell of a peer-transfer
9214/// matrix reads `N/A` — so a TP group placed across an island boundary has no peer path at all
9215/// and must either stay inside one island or go through host memory. The per-host island map is
9216/// fleet data and lives in the private deployment repo, never here; the engine's job is to
9217/// refuse by name rather than to know which host it is on.
9218pub(crate) fn grant_peer_access(
9219    accessor: &Engine,
9220    owner: &Engine,
9221    label: &str,
9222) -> Result<(), Box<dyn std::error::Error>> {
9223    let (a_dev, o_dev) = (accessor.ctx().ordinal(), owner.ctx().ordinal());
9224    let mut can_access = 0;
9225    unsafe {
9226        cudarc::driver::sys::cuDeviceCanAccessPeer(
9227            &mut can_access,
9228            accessor.ctx().cu_device(),
9229            owner.ctx().cu_device(),
9230        )
9231        .result()?;
9232    }
9233    if can_access == 0 {
9234        return Err(
9235            format!("{label} requires P2P, but dev{a_dev} cannot access dev{o_dev}").into(),
9236        );
9237    }
9238    accessor.ctx().bind_to_thread()?;
9239    let rc = unsafe { cudarc::driver::sys::cuCtxEnablePeerAccess(owner.ctx().cu_ctx(), 0) };
9240    use cudarc::driver::sys::cudaError_enum as E;
9241    if rc != E::CUDA_SUCCESS && rc != E::CUDA_ERROR_PEER_ACCESS_ALREADY_ENABLED {
9242        return Err(format!(
9243            "{label} cuCtxEnablePeerAccess(dev{a_dev} -> dev{o_dev}) failed: {rc:?}"
9244        )
9245        .into());
9246    }
9247    let device = cudarc::driver::result::device::get(o_dev as i32)?;
9248    let mut pool: cudarc::driver::sys::CUmemoryPool = std::ptr::null_mut();
9249    unsafe {
9250        cudarc::driver::sys::cuDeviceGetDefaultMemPool(&mut pool, device).result()?;
9251    }
9252    let desc = cudarc::driver::sys::CUmemAccessDesc {
9253        location: cudarc::driver::sys::CUmemLocation {
9254            type_: cudarc::driver::sys::CUmemLocationType::CU_MEM_LOCATION_TYPE_DEVICE,
9255            id: a_dev as i32,
9256        },
9257        flags: cudarc::driver::sys::CUmemAccess_flags::CU_MEM_ACCESS_FLAGS_PROT_READWRITE,
9258    };
9259    let rc = unsafe { cudarc::driver::sys::cuMemPoolSetAccess(pool, &desc, 1) };
9260    if rc != cudarc::driver::sys::cudaError_enum::CUDA_SUCCESS {
9261        return Err(format!(
9262            "{label} cuMemPoolSetAccess(dev{o_dev} pool -> dev{a_dev}) failed: {rc:?}"
9263        )
9264        .into());
9265    }
9266    Ok(())
9267}
9268
9269fn configure_native_p2p(
9270    ranks: &[Engine],
9271    devices: &[usize],
9272) -> Result<(), Box<dyn std::error::Error>> {
9273    if ranks.len() != devices.len() || ranks.len() < 2 {
9274        return Err("native TP P2P setup requires matching multi-rank devices".into());
9275    }
9276    for (rank, (&device, engine)) in devices.iter().zip(ranks).enumerate() {
9277        if engine.ctx().ordinal() != device {
9278            return Err(format!(
9279                "native TP rank {rank} context device {} != requested device {device}",
9280                engine.ctx().ordinal()
9281            )
9282            .into());
9283        }
9284    }
9285
9286    for src in 0..ranks.len() {
9287        for dst in 0..ranks.len() {
9288            if src == dst {
9289                continue;
9290            }
9291            grant_peer_access(&ranks[src], &ranks[dst], "native TP")?;
9292        }
9293    }
9294
9295    for src in 0..ranks.len() {
9296        for dst in 0..ranks.len() {
9297            if src == dst {
9298                continue;
9299            }
9300            for &words in NATIVE_P2P_PROBE_WORDS {
9301                let expected = (0..words)
9302                    .map(|index| {
9303                        (index as u32)
9304                            .wrapping_mul(0x9e37_79b9)
9305                            .wrapping_add(((src as u32) << 16) | dst as u32)
9306                    })
9307                    .collect::<Vec<_>>();
9308                let poison = expected.iter().map(|value| !value).collect::<Vec<_>>();
9309                let source = ranks[src].htod_u32_v(&expected)?;
9310                let mut destination = ranks[dst].htod_u32_v(&poison)?;
9311                ranks[dst].stream().memcpy_dtod(&source, &mut destination)?;
9312                let actual = ranks[dst].dtoh_u32(&destination)?;
9313                if actual != expected {
9314                    let mismatches = actual
9315                        .iter()
9316                        .zip(&expected)
9317                        .filter(|(actual, expected)| actual != expected)
9318                        .count();
9319                    return Err(format!(
9320                        "native TP peer probe dev{}->dev{} failed at {} bytes: \
9321                         {mismatches}/{} words differ",
9322                        devices[src],
9323                        devices[dst],
9324                        words * std::mem::size_of::<u32>(),
9325                        expected.len()
9326                    )
9327                    .into());
9328                }
9329            }
9330        }
9331    }
9332    ranks[0].ctx().bind_to_thread()?;
9333    eprintln!(
9334        "[tp] native peer byte-integrity probe PASS: devices={devices:?} \
9335         directions={} byte_ladder={:?} mismatches=0",
9336        ranks.len() * (ranks.len() - 1),
9337        NATIVE_P2P_PROBE_WORDS
9338            .iter()
9339            .map(|words| words * std::mem::size_of::<u32>())
9340            .collect::<Vec<_>>(),
9341    );
9342    Ok(())
9343}
9344
9345fn validate_activations(
9346    activations: &[f32],
9347    tokens: usize,
9348    in_features: usize,
9349) -> Result<(), String> {
9350    let expected = tokens
9351        .checked_mul(in_features)
9352        .ok_or_else(|| "activation size overflow".to_string())?;
9353    if activations.len() != expected {
9354        return Err(format!(
9355            "activation count {} != {tokens}x{in_features} ({expected})",
9356            activations.len()
9357        ));
9358    }
9359    if !activations.iter().all(|value| value.is_finite()) {
9360        return Err("activations contain a non-finite value".to_string());
9361    }
9362    Ok(())
9363}
9364
9365fn column_shard(
9366    matrix: E4m3BlockMatrix<'_>,
9367    tp: usize,
9368    rank: usize,
9369) -> Result<E4m3BlockMatrix<'_>, String> {
9370    let local_out = matrix.out_features / tp;
9371    let row_start = rank * local_out;
9372    let code_start = row_start * matrix.in_features;
9373    let code_end = code_start + local_out * matrix.in_features;
9374    let scale_cols = matrix.in_features.div_ceil(FP8_BLOCK);
9375    let local_scale_rows = local_out / FP8_BLOCK;
9376    let scale_start = rank * local_scale_rows * scale_cols;
9377    let scale_end = scale_start + local_scale_rows * scale_cols;
9378    Ok(E4m3BlockMatrix {
9379        codes: &matrix.codes[code_start..code_end],
9380        scales: &matrix.scales[scale_start..scale_end],
9381        out_features: local_out,
9382        in_features: matrix.in_features,
9383    })
9384}
9385
9386fn row_shard(
9387    matrix: E4m3BlockMatrix<'_>,
9388    tp: usize,
9389    rank: usize,
9390) -> Result<(Vec<u8>, Vec<f32>), String> {
9391    let local_in = matrix.in_features / tp;
9392    let col_start = rank * local_in;
9393    let mut codes = Vec::with_capacity(matrix.out_features * local_in);
9394    for row in 0..matrix.out_features {
9395        let start = row * matrix.in_features + col_start;
9396        codes.extend_from_slice(&matrix.codes[start..start + local_in]);
9397    }
9398
9399    let scale_rows = matrix.out_features.div_ceil(FP8_BLOCK);
9400    let scale_cols = matrix.in_features.div_ceil(FP8_BLOCK);
9401    let local_scale_cols = local_in / FP8_BLOCK;
9402    let scale_col_start = rank * local_scale_cols;
9403    let mut scales = Vec::with_capacity(scale_rows * local_scale_cols);
9404    for row in 0..scale_rows {
9405        let start = row * scale_cols + scale_col_start;
9406        scales.extend_from_slice(&matrix.scales[start..start + local_scale_cols]);
9407    }
9408    Ok((codes, scales))
9409}
9410
9411fn activation_shard(
9412    activations: &[f32],
9413    tokens: usize,
9414    in_features: usize,
9415    tp: usize,
9416    rank: usize,
9417) -> Vec<f32> {
9418    let local_in = in_features / tp;
9419    let col_start = rank * local_in;
9420    let mut shard = Vec::with_capacity(tokens * local_in);
9421    for token in 0..tokens {
9422        let start = token * in_features + col_start;
9423        shard.extend_from_slice(&activations[start..start + local_in]);
9424    }
9425    shard
9426}
9427
9428// ─── Step NVFP4 expert TP program (official Step-3.7-Flash-NVFP4 checkpoint class) ─────────────
9429//
9430// The routed experts of the NVFP4 checkpoint are modelopt-packed: e2m1 codes (2/byte), per-16
9431// UE4M3 sub-scales, and a per-EXPERT `weight_scale_2` f32 macro (~1e-5..1e-4, LOAD-BEARING).
9432// Rank compute repacks each shard host-side into memra block_nvfp4 rows (nibble reorder only —
9433// value-exact, see nvfp4_repack.rs) and runs the proven `qmatvec_nvfp4_fast` dp4a kernel; the
9434// activation q8_1 quantization uses per-32 blocks, and every shard cut here is 64-aligned, so a
9435// rank-local partial is bit-identical to the corresponding slice of the unsharded kernel.
9436//
9437// MACRO CANONICAL ORDER: the macro multiplies each assembled f32 output exactly ONCE — after the
9438// column gather (gate/up) and after the FULL row-parallel reduce (down), never per-partial.
9439// `(a + b) * m` and `a * m + b * m` differ in f32, so applying it per-rank would break the
9440// TP1-vs-TP2 bit gate. Every entry point below follows this order.
9441//
9442// TP2 shard legality is NVFP4-native: column parallelism splits whole output rows (scale rows
9443// ride along, nothing cuts), row parallelism splits input columns at 64-element superblock
9444// boundaries (16-element scale groups nest inside). The 128-block E4M3 constraint does not apply.
9445
9446/// One expert's modelopt NVFP4 projection: packed codes + per-16 UE4M3 scale bytes + macro.
9447#[derive(Clone, Copy)]
9448pub struct Nvfp4BlockMatrix<'a> {
9449    pub codes: &'a [u8],  // [out_features, in_features/2] packed e2m1, row-major
9450    pub scales: &'a [u8], // [out_features, in_features/16] UE4M3 bytes, row-major
9451    pub macro_scale: f32, // per-expert weight_scale_2 dequant multiplier
9452    pub out_features: usize,
9453    pub in_features: usize,
9454}
9455
9456impl Nvfp4BlockMatrix<'_> {
9457    pub fn validate(&self) -> Result<(), String> {
9458        if self.in_features == 0 || self.out_features == 0 {
9459            return Err("NVFP4 matrix has a zero dimension".to_string());
9460        }
9461        if !self.in_features.is_multiple_of(64) {
9462            return Err(format!(
9463                "NVFP4 in_features {} is not 64-aligned (memra block_nvfp4 superblock)",
9464                self.in_features
9465            ));
9466        }
9467        if self.codes.len() != self.out_features * self.in_features / 2 {
9468            return Err(format!(
9469                "NVFP4 code bytes {} != {}x{}/2",
9470                self.codes.len(),
9471                self.out_features,
9472                self.in_features
9473            ));
9474        }
9475        if self.scales.len() != self.out_features * self.in_features / 16 {
9476            return Err(format!(
9477                "NVFP4 scale bytes {} != {}x{}/16",
9478                self.scales.len(),
9479                self.out_features,
9480                self.in_features
9481            ));
9482        }
9483        if !self.macro_scale.is_finite() || self.macro_scale <= 0.0 {
9484            return Err(format!(
9485                "NVFP4 macro scale {} is not finite-positive",
9486                self.macro_scale
9487            ));
9488        }
9489        Ok(())
9490    }
9491}
9492
9493/// Stacked modelopt NVFP4 expert bank (host view over the checkpoint bytes).
9494#[derive(Clone, Copy)]
9495pub struct Nvfp4ExpertBank<'a> {
9496    pub codes: &'a [u8],   // [expert_count, out_features, in_features/2]
9497    pub scales: &'a [u8],  // [expert_count, out_features, in_features/16]
9498    pub macros: &'a [f32], // [expert_count] weight_scale_2
9499    pub expert_count: usize,
9500    pub out_features: usize,
9501    pub in_features: usize,
9502}
9503
9504impl Nvfp4ExpertBank<'_> {
9505    pub fn validate(&self) -> Result<(), String> {
9506        if self.expert_count == 0 {
9507            return Err("NVFP4 expert bank is empty".to_string());
9508        }
9509        if self.macros.len() != self.expert_count {
9510            return Err(format!(
9511                "NVFP4 bank macros {} != expert count {}",
9512                self.macros.len(),
9513                self.expert_count
9514            ));
9515        }
9516        self.expert(0).map(|_| ())
9517    }
9518
9519    pub fn expert(&self, expert: usize) -> Result<Nvfp4BlockMatrix<'_>, String> {
9520        if expert >= self.expert_count {
9521            return Err(format!("expert {expert} outside 0..{}", self.expert_count));
9522        }
9523        let code_stride = self.out_features * self.in_features / 2;
9524        let scale_stride = self.out_features * self.in_features / 16;
9525        if self.codes.len() != self.expert_count * code_stride
9526            || self.scales.len() != self.expert_count * scale_stride
9527        {
9528            return Err("NVFP4 bank byte extents do not match the declared geometry".to_string());
9529        }
9530        let matrix = Nvfp4BlockMatrix {
9531            codes: &self.codes[expert * code_stride..(expert + 1) * code_stride],
9532            scales: &self.scales[expert * scale_stride..(expert + 1) * scale_stride],
9533            macro_scale: self.macros[expert],
9534            out_features: self.out_features,
9535            in_features: self.in_features,
9536        };
9537        matrix.validate()?;
9538        Ok(matrix)
9539    }
9540}
9541
9542/// One rank's resident repacked NVFP4 shard: memra block_nvfp4 rows on device.
9543pub struct ResidentNvfp4Rank {
9544    blocks: crate::CudaSlice<u8>,
9545    macro_scale: f32,
9546    out_features: usize,
9547    in_features: usize,
9548    row_bytes: usize,
9549}
9550
9551pub struct ResidentNvfp4ColumnParallel {
9552    ranks: Vec<ResidentNvfp4Rank>,
9553    pub out_features: usize,
9554    pub in_features: usize,
9555}
9556
9557pub struct ResidentNvfp4RowParallel {
9558    ranks: Vec<ResidentNvfp4Rank>,
9559    pub out_features: usize,
9560    pub in_features: usize,
9561}
9562
9563pub struct ResidentTpNvfp4Expert {
9564    gate: ResidentNvfp4ColumnParallel,
9565    up: ResidentNvfp4ColumnParallel,
9566    down: ResidentNvfp4RowParallel,
9567    pub input_width: usize,
9568    pub expert_width: usize,
9569}
9570
9571/// One rank's resident NVFP4 expert bank shard: one repacked block buffer PER expert (per-expert
9572/// device allocations keep this increment off any new strided-kernel API; the strided twin is a
9573/// later perf rung, mirroring the FP8 bank's history).
9574pub struct ResidentNvfp4ColumnBankRank {
9575    /// Contiguous per-rank expert bank: `expert_count` repacked shards of `expert_bytes` each.
9576    /// Contiguity is what lets the device-routes program cover every selected expert with ONE
9577    /// launch (`qmatvec_nvfp4_dp4a_sel` indexes `sel[t] * expert_bytes`).
9578    bank: crate::CudaSlice<u8>,
9579    expert_bytes: usize,
9580    local_out: usize,
9581    in_features: usize,
9582    row_bytes: usize,
9583    /// TRUE when these bytes are the slot-major permutation (`nvfp4_matrix_v2_permute`) and the
9584    /// `_v2` readers must be used; FALSE when they are block_nvfp4 v1. Recorded at BUILD from
9585    /// `ep2 || bank_slot_major_on()` and never re-derived: the layout travels with the pointer,
9586    /// so no reader can consult an env door that disagrees with the resident bytes. Feeding v1
9587    /// bytes to a `_v2` reader (or the reverse) is a garbage-output bug, and the 2026-08-29
9588    /// step37 incident was its neighbour — a piece of layout geometry a caller failed to supply.
9589    slot_major: bool,
9590}
9591
9592impl ResidentNvfp4ColumnBankRank {
9593    /// THE host-canonical reader for this bank, selected from the layout the bank RECORDS. One
9594    /// place maps layout -> reader for the column banks; every oracle goes through it, so a new
9595    /// producer cannot leave a reader behind (the failure mode that put v1 bytes under a `_v2`
9596    /// reader, called out in the `run_tensor_parallel_routes_nvfp4_prime_grouped` receipt).
9597    fn host_canonical_expert(
9598        &self,
9599        engine: &Engine,
9600        expert: usize,
9601        activations: &crate::CudaSlice<f32>,
9602    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
9603        let w = self.expert(expert);
9604        if self.slot_major {
9605            engine.qmatvec_nvfp4_fast_v2(
9606                &w,
9607                activations,
9608                1,
9609                self.in_features,
9610                self.local_out,
9611                self.row_bytes,
9612            )
9613        } else {
9614            engine.qmatvec_nvfp4_fast(
9615                &w,
9616                activations,
9617                1,
9618                self.in_features,
9619                self.local_out,
9620                self.row_bytes,
9621            )
9622        }
9623    }
9624
9625    fn expert(&self, index: usize) -> cudarc::driver::CudaView<'_, u8> {
9626        self.bank
9627            .slice(index * self.expert_bytes..(index + 1) * self.expert_bytes)
9628    }
9629}
9630
9631/// Canonical row-shard count for the NVFP4 down projection. The down reduction ALWAYS executes
9632/// as exactly this many input-column windows summed in shard order, at every world size: a
9633/// single full-width dot and a two-half-dots-plus-add differ in f32 parenthesization, so pinning
9634/// the shard grid (not the world size) is what makes the TP1-oracle-vs-TP2 bit gate meaningful.
9635/// This is the NVFP4 twin of the FP8 bank's canonical checkpoint-block reduction.
9636pub const NVFP4_CANONICAL_ROW_SHARDS: usize = 2;
9637
9638pub struct ResidentNvfp4RowBankRank {
9639    /// Contiguous per-shard expert bank (see `ResidentNvfp4ColumnBankRank::bank`).
9640    bank: crate::CudaSlice<u8>,
9641    expert_bytes: usize,
9642    device_rank: usize, // index into the runtime's rank engines this canonical shard lives on
9643    out_features: usize,
9644    local_in: usize,
9645    row_bytes: usize,
9646    /// Slot-major layout marker — see `ResidentNvfp4ColumnBankRank::slot_major`.
9647    slot_major: bool,
9648}
9649
9650impl ResidentNvfp4RowBankRank {
9651    /// THE host-canonical reader for this down shard — see
9652    /// `ResidentNvfp4ColumnBankRank::host_canonical_expert`.
9653    fn host_canonical_expert(
9654        &self,
9655        engine: &Engine,
9656        expert: usize,
9657        activations: &crate::CudaSlice<f32>,
9658    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
9659        let w = self.expert(expert);
9660        if self.slot_major {
9661            engine.qmatvec_nvfp4_fast_v2(
9662                &w,
9663                activations,
9664                1,
9665                self.local_in,
9666                self.out_features,
9667                self.row_bytes,
9668            )
9669        } else {
9670            engine.qmatvec_nvfp4_fast(
9671                &w,
9672                activations,
9673                1,
9674                self.local_in,
9675                self.out_features,
9676                self.row_bytes,
9677            )
9678        }
9679    }
9680
9681    fn expert(&self, index: usize) -> cudarc::driver::CudaView<'_, u8> {
9682        self.bank
9683            .slice(index * self.expert_bytes..(index + 1) * self.expert_bytes)
9684    }
9685}
9686
9687impl ResidentNvfp4TensorParallel {
9688    pub(crate) fn device_workspace_handle(
9689        &self,
9690    ) -> &std::sync::Mutex<Option<Nvfp4DeviceRoutesWorkspace>> {
9691        &self.device_workspace
9692    }
9693}
9694
9695pub struct ResidentNvfp4TensorParallel {
9696    gate: Vec<ResidentNvfp4ColumnBankRank>,
9697    up: Vec<ResidentNvfp4ColumnBankRank>,
9698    down: Vec<ResidentNvfp4RowBankRank>,
9699    macros_gate: Vec<f32>,
9700    macros_up: Vec<f32>,
9701    macros_down: Vec<f32>,
9702    /// Per-rank device copies of the gate/up macro-scales (E f32 each), indexed by the
9703    /// batched SwiGLU kernel via the selection array. Down macros stay host-side — they fold
9704    /// into the route-weight axpy scalar.
9705    macros_gate_dev: Vec<crate::CudaSlice<f32>>,
9706    macros_up_dev: Vec<crate::CudaSlice<f32>>,
9707    macros_down_dev: Vec<crate::CudaSlice<f32>>,
9708    pub expert_count: usize,
9709    pub input_width: usize,
9710    pub expert_width: usize,
9711    /// Lazily-built persistent decode workspace (device routes program). Interior mutability
9712    /// mirrors StepEpGroupedDecode: the forward holds the bank behind a shared reference.
9713    device_workspace: std::sync::Mutex<Option<Nvfp4DeviceRoutesWorkspace>>,
9714    /// Grouped-prime per-rank slot-major pointer tables (gate/up/down x n_expert), built once.
9715    /// The banks are resident and never move, so rebuilding + re-uploading 3*n_expert u64s per
9716    /// rank per LAYER was pure per-call host churn on the prime path.
9717    prime_tables: std::sync::Mutex<Vec<crate::CudaSlice<u64>>>,
9718    /// MEMRA_STEP_NVFP4_EP2: the rank banks above hold WHOLE experts (owner = id & 1,
9719    /// slot = id >> 1) at full width instead of TP shards. Consumers must branch on this;
9720    /// shard-semantics paths refuse loudly.
9721    pub(crate) ep2: bool,
9722}
9723
9724/// Persistent per-call device buffers for the NVFP4 device routes program: one gate/up output,
9725/// one down partial, and one shard accumulator per rank, plus root combine staging. Reused every
9726/// (token, layer) call so the decode loop performs zero output allocations.
9727/// A stitched multi-device parent graph for one layer's device-routed expert program, plus
9728/// the children it was built from (retained: AddChildGraphNode clones, but the probe retains
9729/// conservatively) and the persistent e-context input staging its copies read.
9730struct RoutesGraph {
9731    exec: cudarc::driver::sys::CUgraphExec,
9732    parent: cudarc::driver::sys::CUgraph,
9733    _children: Vec<cudarc::driver::CudaGraph>,
9734}
9735// SAFETY: the raw handles are only used from the single decode thread; CUDA graph handles are
9736// context-agnostic process handles.
9737unsafe impl Send for RoutesGraph {}
9738
9739impl Drop for RoutesGraph {
9740    fn drop(&mut self) {
9741        unsafe {
9742            let _ = cudarc::driver::sys::cuGraphExecDestroy(self.exec);
9743            let _ = cudarc::driver::sys::cuGraphDestroy(self.parent);
9744        }
9745    }
9746}
9747
9748impl Nvfp4DeviceRoutesWorkspace {
9749    pub(crate) fn in_stage_handle(&self) -> Option<&crate::CudaSlice<f32>> {
9750        self.in_stage_e.as_ref()
9751    }
9752    pub(crate) fn in_stage_mut(&mut self) -> Option<&mut crate::CudaSlice<f32>> {
9753        self.in_stage_e.as_mut()
9754    }
9755    #[allow(dead_code)] // allow: accessor twin of in_stage_mut; kept for the workspace API symmetry
9756    pub(crate) fn out_stage_mut(&mut self) -> Option<&mut crate::CudaSlice<f32>> {
9757        self.out_stage_e.as_mut()
9758    }
9759    /// Arm the e-context stages + router staging pair when absent (token-graph entry).
9760    pub(crate) fn arm_stages(
9761        &mut self,
9762        e: &Engine,
9763        width: usize,
9764        n_sel: usize,
9765    ) -> Result<(), Box<dyn std::error::Error>> {
9766        let _main = e.gpu.enter_main()?;
9767        if self.in_stage_e.is_none() {
9768            self.in_stage_e = Some(e.htod(&vec![0.0f32; width])?);
9769            self.out_stage_e = Some(e.htod(&vec![0.0f32; width])?);
9770        }
9771        if self.dev_route_e.is_none() {
9772            self.dev_route_e = Some((
9773                e.htod_i32(&vec![0i32; n_sel])?,
9774                e.htod(&vec![0.0f32; n_sel])?,
9775            ));
9776        }
9777        Ok(())
9778    }
9779
9780    /// Split-borrow: the routes input (shared) + output (mut) stages together.
9781    pub(crate) fn in_and_out_stages_mut(
9782        &mut self,
9783    ) -> Option<(&crate::CudaSlice<f32>, &mut crate::CudaSlice<f32>)> {
9784        match (self.in_stage_e.as_ref(), self.out_stage_e.as_mut()) {
9785            (Some(input), Some(output)) => Some((input, output)),
9786            _ => None,
9787        }
9788    }
9789    pub(crate) fn dev_route_e_mut(
9790        &mut self,
9791    ) -> Option<(&mut crate::CudaSlice<i32>, &mut crate::CudaSlice<f32>)> {
9792        self.dev_route_e.as_mut().map(|(a, b)| (a, b))
9793    }
9794}
9795
9796pub struct Nvfp4DeviceRoutesWorkspace {
9797    /// [n_sel, local_out] batched gate/up outputs and the SwiGLU q8_1 pair; [n_sel, width]
9798    /// down partials. Sized for `n_sel` selected experts per token (pinned at first call).
9799    gate_out: Vec<crate::CudaSlice<f32>>,
9800    up_out: Vec<crate::CudaSlice<f32>>,
9801    act_q: Vec<crate::CudaSlice<i8>>,
9802    act_d: Vec<crate::CudaSlice<f32>>,
9803    sel: Vec<crate::CudaSlice<i32>>,
9804    partial: Vec<crate::CudaSlice<f32>>,
9805    accumulator: Vec<crate::CudaSlice<f32>>,
9806    /// Per-rank folded combine weights (route_weight x down macro), one htod per call.
9807    combine_w: Vec<crate::CudaSlice<f32>>,
9808    /// Device-routed extension: per-rank raw route weights (the down-macro fold happens
9809    /// in-kernel via sel + macros_down_dev).
9810    route_w: Vec<crate::CudaSlice<f32>>,
9811    /// Persistent q8_1 pair of the shared layer input (one quantize per rank per call, no
9812    /// per-call allocation).
9813    in_q: Vec<crate::CudaSlice<i8>>,
9814    in_d: Vec<crate::CudaSlice<f32>>,
9815    /// e-context staging for the device router outputs (persistent — rank streams peer-read
9816    /// them, so the router's fresh outputs are copied here on e's stream first; the pp.rs
9817    /// never-free discipline).
9818    dev_route_e: Option<(crate::CudaSlice<i32>, crate::CudaSlice<f32>)>,
9819    /// Prestage door state: input pull + quantize already issued for this layer's call
9820    /// (nvfp4_routes_prestage), so the routed run skips them. Reset per call.
9821    prestaged: bool,
9822    /// Peer-router door state: rank1's sel/route_w were computed locally in prestage;
9823    /// the routed run skips rank1's sel pull. Reset per call.
9824    rank1_routed: bool,
9825    /// Doorbell fences (MEMRA_FENCE_MEMOPS): raw cuMemAlloc'd [rank1_flag, root_flag]
9826    /// u32 pair in ROOT memory (async-pool memory is memop-INELIGIBLE — receipted
9827    /// CUDA_ERROR_INVALID_VALUE) + the host-side monotonic ticket. 0 = unarmed.
9828    fence_flags_raw: u64,
9829    fence_ticket: u32,
9830    /// Prestage input fence, recorded on e after the input's producer.
9831    ev_input: Option<(CudaEvent, usize)>,
9832    /// Graph-door staging: persistent e-context input row + output row (fixed addresses the
9833    /// captured copies read/write), and the per-layer stitched parent.
9834    in_stage_e: Option<crate::CudaSlice<f32>>,
9835    out_stage_e: Option<crate::CudaSlice<f32>>,
9836    routes_graph: Option<RoutesGraph>,
9837    /// Token-graph raw pointer sets (armed once by routes_arm_raw).
9838    raw_dev_route_e: Option<(u64, u64)>,
9839    raw_combine: Option<(u64, u64, u64, u64)>,
9840    raw_input: Vec<u64>,
9841    raw_sel: Vec<u64>,
9842    raw_route_w: Vec<u64>,
9843    remote: crate::CudaSlice<f32>,
9844    combined: crate::CudaSlice<f32>,
9845    n_sel: usize,
9846    /// Device-IO extension (lazily built by `run_tensor_parallel_routes_nvfp4_device_io`):
9847    /// persistent per-rank input rows plus the evented ordering pair — the pp.rs
9848    /// BoundarySlot discipline, same as the v2 attention workspace.
9849    input: Vec<crate::CudaSlice<f32>>,
9850    ev_rank: Vec<CudaEvent>,
9851    ev_done: Option<CudaEvent>,
9852    ev_entry: Option<(CudaEvent, usize)>,
9853}
9854
9855/// One rank's whole-expert NVFP4 residency (expert-parallel ownership).
9856struct ResidentNvfp4EpRank {
9857    gate: crate::CudaSlice<u8>,
9858    up: crate::CudaSlice<u8>,
9859    down: crate::CudaSlice<u8>,
9860    gate_expert_bytes: usize,
9861    down_expert_bytes: usize,
9862    macros_gate: crate::CudaSlice<f32>,
9863    macros_up: crate::CudaSlice<f32>,
9864    macros_down: crate::CudaSlice<f32>,
9865    expert_range: Range<usize>,
9866}
9867
9868struct Nvfp4EpDeviceWorkspace {
9869    input: Vec<crate::CudaSlice<f32>>,
9870    input_bf16: Vec<crate::CudaSlice<u8>>,
9871    input_q8: Vec<crate::CudaSlice<i8>>,
9872    input_q8_scales: Vec<crate::CudaSlice<f32>>,
9873    sel: Vec<crate::CudaSlice<i32>>,
9874    token_rows: Vec<crate::CudaSlice<i32>>,
9875    global_pairs: Vec<crate::CudaSlice<i32>>,
9876    route_w: Vec<crate::CudaSlice<f32>>,
9877    gate_out: Vec<crate::CudaSlice<f32>>,
9878    up_out: Vec<crate::CudaSlice<f32>>,
9879    activation_bf16: Vec<crate::CudaSlice<u8>>,
9880    activation_q8: Vec<crate::CudaSlice<i8>>,
9881    activation_q8_scales: Vec<crate::CudaSlice<f32>>,
9882    slot_rows: crate::CudaSlice<f32>,
9883    slot_rows_raw: u64,
9884    route_weights: crate::CudaSlice<f32>,
9885    graph_input: crate::CudaSlice<f32>,
9886    graph_output: crate::CudaSlice<f32>,
9887    graph_routes: Option<(u64, u64)>,
9888    graphs: Vec<Option<RoutesGraph>>,
9889    ev_entry: CudaEvent,
9890    ev_entry_device: usize,
9891    ev_rank: Vec<CudaEvent>,
9892    phase_events: Option<Nvfp4EpPhaseEvents>,
9893    capacity_tokens: usize,
9894    experts_per_token: usize,
9895}
9896
9897struct Nvfp4EpPhaseEvents {
9898    head: Vec<CudaEvent>,
9899    copy_done: Vec<CudaEvent>,
9900    gate_up_done: Vec<CudaEvent>,
9901    activation_done: Vec<CudaEvent>,
9902    down_done: Vec<CudaEvent>,
9903}
9904
9905pub(crate) const NVFP4_EP_DEVICE_BATCH_CAP: usize = 128;
9906pub(crate) const NVFP4_EP_DEVICE_ROUTER_BATCH_CAP: usize = 32;
9907pub(crate) const NVFP4_EP_Q8_BATCH_CAP: usize = 32;
9908const NVFP4_EP_GRAPH_BATCH_CAP: usize = 1;
9909
9910fn nvfp4_ep_active_input_values(
9911    input_values: usize,
9912    tokens: usize,
9913    input_width: usize,
9914) -> Result<usize, String> {
9915    if !(1..=NVFP4_EP_DEVICE_BATCH_CAP).contains(&tokens) {
9916        return Err(format!(
9917            "W4A16 NVFP4 device EP batch {tokens} is outside 1..={NVFP4_EP_DEVICE_BATCH_CAP}"
9918        ));
9919    }
9920    let active_values = tokens
9921        .checked_mul(input_width)
9922        .ok_or("W4A16 NVFP4 device EP active input size overflows usize")?;
9923    if input_values < active_values {
9924        return Err(format!(
9925            "W4A16 NVFP4 device EP input {input_values} is smaller than active \
9926             tokens {tokens} x width {input_width} ({active_values})"
9927        ));
9928    }
9929    Ok(active_values)
9930}
9931
9932pub struct ResidentNvfp4ExpertParallel {
9933    ranks: Vec<ResidentNvfp4EpRank>,
9934    macros_gate: Vec<f32>,
9935    macros_up: Vec<f32>,
9936    macros_down: Vec<f32>,
9937    pub expert_count: usize,
9938    pub input_width: usize,
9939    pub expert_width: usize,
9940    gate_row_bytes: usize,
9941    down_row_bytes: usize,
9942    device_workspace: std::sync::Mutex<Option<Nvfp4EpDeviceWorkspace>>,
9943}
9944
9945fn nvfp4_repack_matrix(matrix: Nvfp4BlockMatrix<'_>) -> Vec<u8> {
9946    memra_gguf::nvfp4_repack::repack_modelopt_to_gguf(
9947        matrix.codes,
9948        matrix.scales,
9949        matrix.out_features,
9950        matrix.in_features,
9951    )
9952}
9953
9954fn nvfp4_row_bytes(in_features: usize) -> usize {
9955    in_features / 64 * 36 // memra block_nvfp4: 64 elems -> 36 bytes (4 UE4M3 + 32 packed e2m1)
9956}
9957
9958/// MEMRA_NO_LOCAL_SHADOW=1: skip the per-layer local-KV shadow gathers and appends in the
9959/// eager v2 decode (lengths still advance) — the graph door proved contents-stale local KV
9960/// is decode-identical (12/12). The local contents feed spec/MTP scratch only.
9961/// MEMRA_FUSE_ROPE_APPEND=1: fuse qk norms + rope + dcw KV append + len inc into one
9962/// launch per rank per layer (bit-identical; identity-gated). dcw path only.
9963pub(crate) fn fuse_rope_append_on() -> bool {
9964    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
9965    *ON.get_or_init(|| std::env::var("MEMRA_FUSE_ROPE_APPEND").as_deref() == Ok("1"))
9966}
9967
9968pub(crate) fn no_local_shadow_on() -> bool {
9969    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
9970    *ON.get_or_init(|| std::env::var("MEMRA_NO_LOCAL_SHADOW").as_deref() == Ok("1"))
9971}
9972
9973/// Permute one repacked block_nvfp4 matrix (out_features rows of `nvfp4_row_bytes(in_f)`)
9974/// into the slot-major row layout the EP2 kernels read: per row, slot g's 16 qs bytes at
9975/// g*16, then the two UE4M3 scale bytes per slot at nslots*16 + g*2. Row byte count
9976/// unchanged. This layout USED to be an env door (`MEMRA_NVFP4_BANK_V2`, removed 2026-08-29
9977/// after its ON arm changed generated text in serving, see
9978/// research/step37-bankv2-removal-20260829); it survives ONLY as the fixed layout of the
9979/// EP2 whole-expert banks, whose `*_ep` kernels read it unconditionally.
9980///
9981/// PUBLIC because it is the SINGLE SOURCE OF TRUTH for this byte map. Every reader — the
9982/// `*_ep` decode kernels, `kq_fetch<QT_NVFP4_V2>` in the grouped GEMM,
9983/// `dequant_nvfp4v2_f16_kernel` — is defined as "reads what this function writes", and the
9984/// `nvfp4-bank-oracle` bin is what proves it, on device, per kernel arm. Do not reimplement
9985/// the map anywhere: the two failures that appeared only on v2 readers were geometry-plumbing
9986/// bugs around a byte map that was itself correct in two separate places. The layout was
9987/// innocent; one live failure was the grouped-prefill sktail call site defaulting `in_f` to zero.
9988pub fn nvfp4_matrix_v2_permute(v1: &[u8], out_features: usize, in_features: usize) -> Vec<u8> {
9989    // The output row is n_slots*18 bytes; the stride every reader uses is
9990    // nvfp4_row_bytes(in_features) = (in_features/64)*36. Those are equal only when
9991    // in_features is a whole number of 64-element superblocks. At in_features % 64 == 32 the
9992    // permute would silently emit a LONGER row than the stride and every row after row 0
9993    // would be read at the wrong offset, so refuse instead of trusting the caller.
9994    assert_eq!(
9995        in_features % 64,
9996        0,
9997        "v2 permute needs whole 64-element superblocks, got in_features={in_features}"
9998    );
9999    let row_bytes = nvfp4_row_bytes(in_features);
10000    assert_eq!(v1.len(), out_features * row_bytes, "v2 permute geometry");
10001    let n_slots = in_features / 32;
10002    let mut out = Vec::with_capacity(v1.len());
10003    for row in 0..out_features {
10004        let r = &v1[row * row_bytes..(row + 1) * row_bytes];
10005        for g in 0..n_slots {
10006            let (sblk, h) = (g / 2, g % 2);
10007            let b = &r[sblk * 36..sblk * 36 + 36];
10008            out.extend_from_slice(&b[4 + 16 * h..4 + 16 * h + 16]);
10009        }
10010        for g in 0..n_slots {
10011            let (sblk, h) = (g / 2, g % 2);
10012            let b = &r[sblk * 36..sblk * 36 + 36];
10013            out.push(b[2 * h]);
10014            out.push(b[2 * h + 1]);
10015        }
10016    }
10017    out
10018}
10019
10020/// Repack one expert shard for the contiguous banks. `slot_major` is true ONLY for the EP2
10021/// whole-expert banks, whose `*_ep` kernels read the slot-major permutation; the TP
10022/// column/row shard banks stay in the block_nvfp4 v1 layout every other kernel reads.
10023fn nvfp4_repack_bank_matrix(matrix: Nvfp4BlockMatrix<'_>, slot_major: bool) -> Vec<u8> {
10024    let (out_features, in_features) = (matrix.out_features, matrix.in_features);
10025    let v1 = nvfp4_repack_matrix(matrix);
10026    if slot_major {
10027        nvfp4_matrix_v2_permute(&v1, out_features, in_features)
10028    } else {
10029        v1
10030    }
10031}
10032
10033/// Column shard: whole output rows per rank (codes and scales are row-major, so both slices are
10034/// contiguous borrows). The macro rides unchanged — it is applied post-gather by the caller.
10035#[allow(clippy::manual_is_multiple_of)] // allow: divisor is runtime-derived; the modulo form keeps a zero divisor loud (a panic), where is_multiple_of would return false silently
10036fn nvfp4_column_shard<'a>(
10037    matrix: Nvfp4BlockMatrix<'a>,
10038    tp: usize,
10039    rank: usize,
10040) -> Result<Nvfp4BlockMatrix<'a>, String> {
10041    if matrix.out_features % tp != 0 {
10042        return Err(format!(
10043            "NVFP4 column-parallel out_features {} is not divisible by TP={tp}",
10044            matrix.out_features
10045        ));
10046    }
10047    let local_out = matrix.out_features / tp;
10048    let code_row = matrix.in_features / 2;
10049    let scale_row = matrix.in_features / 16;
10050    Ok(Nvfp4BlockMatrix {
10051        codes: &matrix.codes[rank * local_out * code_row..(rank + 1) * local_out * code_row],
10052        scales: &matrix.scales[rank * local_out * scale_row..(rank + 1) * local_out * scale_row],
10053        macro_scale: matrix.macro_scale,
10054        out_features: local_out,
10055        in_features: matrix.in_features,
10056    })
10057}
10058
10059/// Row shard: input-column windows per rank, 64-superblock aligned. Owned buffers: each output
10060/// row contributes one contiguous byte window, gathered across rows.
10061#[allow(clippy::manual_is_multiple_of)] // allow: divisor is runtime-derived; the modulo form keeps a zero divisor loud (a panic), where is_multiple_of would return false silently
10062fn nvfp4_row_shard(
10063    matrix: Nvfp4BlockMatrix<'_>,
10064    tp: usize,
10065    rank: usize,
10066) -> Result<(Vec<u8>, Vec<u8>, usize), String> {
10067    if matrix.in_features % tp != 0 {
10068        return Err(format!(
10069            "NVFP4 row-parallel in_features {} is not divisible by TP={tp}",
10070            matrix.in_features
10071        ));
10072    }
10073    let local_in = matrix.in_features / tp;
10074    if !local_in.is_multiple_of(64) {
10075        return Err(format!(
10076            "NVFP4 row-parallel input shard {local_in} cuts through a 64-element superblock"
10077        ));
10078    }
10079    let code_row = matrix.in_features / 2;
10080    let scale_row = matrix.in_features / 16;
10081    let local_code = local_in / 2;
10082    let local_scale = local_in / 16;
10083    let mut codes = Vec::with_capacity(matrix.out_features * local_code);
10084    let mut scales = Vec::with_capacity(matrix.out_features * local_scale);
10085    for row in 0..matrix.out_features {
10086        let code_start = row * code_row + rank * local_code;
10087        codes.extend_from_slice(&matrix.codes[code_start..code_start + local_code]);
10088        let scale_start = row * scale_row + rank * local_scale;
10089        scales.extend_from_slice(&matrix.scales[scale_start..scale_start + local_scale]);
10090    }
10091    Ok((codes, scales, local_in))
10092}
10093
10094/// Rank compute leaf: repack modelopt -> block_nvfp4, upload, run the proven dp4a kernel. The
10095/// macro is NOT applied here — callers apply it once at the canonical post-gather/post-reduce
10096/// point (see the section header).
10097fn run_rank_nvfp4(
10098    engine: &Engine,
10099    matrix: Nvfp4BlockMatrix<'_>,
10100    activations: &[f32],
10101    tokens: usize,
10102) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10103    matrix.validate()?;
10104    validate_activations(activations, tokens, matrix.in_features)?;
10105    let _main = engine.gpu.enter_main()?;
10106    let blocks = engine.htod_bytes(&nvfp4_repack_matrix(matrix))?;
10107    let activations = engine.htod(activations)?;
10108    let output = engine.qmatvec_nvfp4_fast(
10109        &blocks.slice(0..blocks.len()),
10110        &activations,
10111        tokens,
10112        matrix.in_features,
10113        matrix.out_features,
10114        nvfp4_row_bytes(matrix.in_features),
10115    )?;
10116    engine.dtoh(&output)
10117}
10118
10119fn upload_rank_nvfp4(
10120    engine: &Engine,
10121    matrix: Nvfp4BlockMatrix<'_>,
10122) -> Result<ResidentNvfp4Rank, Box<dyn std::error::Error>> {
10123    matrix.validate()?;
10124    let _main = engine.gpu.enter_main()?;
10125    Ok(ResidentNvfp4Rank {
10126        blocks: engine.htod_bytes(&nvfp4_repack_matrix(matrix))?,
10127        macro_scale: matrix.macro_scale,
10128        out_features: matrix.out_features,
10129        in_features: matrix.in_features,
10130        row_bytes: nvfp4_row_bytes(matrix.in_features),
10131    })
10132}
10133
10134fn run_resident_rank_nvfp4(
10135    engine: &Engine,
10136    rank: &ResidentNvfp4Rank,
10137    activations: &[f32],
10138    tokens: usize,
10139) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10140    validate_activations(activations, tokens, rank.in_features)?;
10141    let _main = engine.gpu.enter_main()?;
10142    let activations = engine.htod(activations)?;
10143    let output = engine.qmatvec_nvfp4_fast(
10144        &rank.blocks.slice(0..rank.blocks.len()),
10145        &activations,
10146        tokens,
10147        rank.in_features,
10148        rank.out_features,
10149        rank.row_bytes,
10150    )?;
10151    engine.dtoh(&output)
10152}
10153
10154fn apply_macro(values: &mut [f32], macro_scale: f32) {
10155    for value in values.iter_mut() {
10156        *value *= macro_scale;
10157    }
10158}
10159
10160impl TpE4m3HostBounce {
10161    /// Unsharded NVFP4 projection on rank 0 (compatibility oracle). Macro applied post-kernel.
10162    pub fn full_nvfp4(
10163        &self,
10164        matrix: Nvfp4BlockMatrix<'_>,
10165        activations: &[f32],
10166        tokens: usize,
10167    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10168        let mut output = run_rank_nvfp4(&self.ranks[0], matrix, activations, tokens)?;
10169        apply_macro(&mut output, matrix.macro_scale);
10170        Ok(output)
10171    }
10172
10173    /// Column-parallel NVFP4 projection: output rows partition across ranks, host gather in rank
10174    /// order, macro applied ONCE post-gather.
10175    pub fn column_parallel_nvfp4(
10176        &self,
10177        matrix: Nvfp4BlockMatrix<'_>,
10178        activations: &[f32],
10179        tokens: usize,
10180    ) -> Result<ColumnParallelResult, Box<dyn std::error::Error>> {
10181        matrix.validate()?;
10182        validate_activations(activations, tokens, matrix.in_features)?;
10183        let tp = self.ranks.len();
10184        let local_out = matrix.out_features / tp;
10185        let mut gathered = vec![0.0f32; tokens * matrix.out_features];
10186        let mut rank_outputs = Vec::with_capacity(tp);
10187        for (rank_index, rank) in self.ranks.iter().enumerate() {
10188            let shard = nvfp4_column_shard(matrix, tp, rank_index)?;
10189            let output = run_rank_nvfp4(rank, shard, activations, tokens)?;
10190            let row_start = rank_index * local_out;
10191            for token in 0..tokens {
10192                gathered[token * matrix.out_features + row_start
10193                    ..token * matrix.out_features + row_start + local_out]
10194                    .copy_from_slice(&output[token * local_out..(token + 1) * local_out]);
10195            }
10196            rank_outputs.push(output);
10197        }
10198        apply_macro(&mut gathered, matrix.macro_scale);
10199        Ok(ColumnParallelResult {
10200            gathered,
10201            rank_outputs,
10202        })
10203    }
10204
10205    /// Row-parallel NVFP4 projection: input columns partition at 64-superblock boundaries,
10206    /// rank-local partials reduce in stable rank order, macro applied ONCE post-reduce.
10207    pub fn row_parallel_nvfp4(
10208        &self,
10209        matrix: Nvfp4BlockMatrix<'_>,
10210        activations: &[f32],
10211        tokens: usize,
10212    ) -> Result<RowParallelResult, Box<dyn std::error::Error>> {
10213        matrix.validate()?;
10214        validate_activations(activations, tokens, matrix.in_features)?;
10215        let tp = self.ranks.len();
10216        let mut reduced = vec![0.0f32; tokens * matrix.out_features];
10217        let mut rank_partials = Vec::with_capacity(tp);
10218        for (rank_index, rank) in self.ranks.iter().enumerate() {
10219            let (codes, scales, local_in) = nvfp4_row_shard(matrix, tp, rank_index)?;
10220            let local_activations =
10221                activation_shard(activations, tokens, matrix.in_features, tp, rank_index);
10222            let shard = Nvfp4BlockMatrix {
10223                codes: &codes,
10224                scales: &scales,
10225                macro_scale: matrix.macro_scale,
10226                out_features: matrix.out_features,
10227                in_features: local_in,
10228            };
10229            let partial = run_rank_nvfp4(rank, shard, &local_activations, tokens)?;
10230            for (sum, value) in reduced.iter_mut().zip(&partial) {
10231                *sum += *value;
10232            }
10233            rank_partials.push(partial);
10234        }
10235        apply_macro(&mut reduced, matrix.macro_scale);
10236        Ok(RowParallelResult {
10237            reduced,
10238            rank_partials,
10239        })
10240    }
10241
10242    pub fn upload_expert_nvfp4(
10243        &self,
10244        gate: Nvfp4BlockMatrix<'_>,
10245        up: Nvfp4BlockMatrix<'_>,
10246        down: Nvfp4BlockMatrix<'_>,
10247    ) -> Result<ResidentTpNvfp4Expert, Box<dyn std::error::Error>> {
10248        if gate.in_features != up.in_features || gate.out_features != up.out_features {
10249            return Err("NVFP4 TP expert gate/up dimensions differ".into());
10250        }
10251        if down.in_features != gate.out_features || down.out_features != gate.in_features {
10252            return Err(format!(
10253                "NVFP4 TP expert down {}x{} does not invert gate/up {}x{}",
10254                down.out_features, down.in_features, gate.out_features, gate.in_features
10255            )
10256            .into());
10257        }
10258        let tp = self.ranks.len();
10259        let mut gate_ranks = Vec::with_capacity(tp);
10260        let mut up_ranks = Vec::with_capacity(tp);
10261        let mut down_ranks = Vec::with_capacity(tp);
10262        for (rank_index, engine) in self.ranks.iter().enumerate() {
10263            gate_ranks.push(upload_rank_nvfp4(
10264                engine,
10265                nvfp4_column_shard(gate, tp, rank_index)?,
10266            )?);
10267            up_ranks.push(upload_rank_nvfp4(
10268                engine,
10269                nvfp4_column_shard(up, tp, rank_index)?,
10270            )?);
10271            let (codes, scales, local_in) = nvfp4_row_shard(down, tp, rank_index)?;
10272            down_ranks.push(upload_rank_nvfp4(
10273                engine,
10274                Nvfp4BlockMatrix {
10275                    codes: &codes,
10276                    scales: &scales,
10277                    macro_scale: down.macro_scale,
10278                    out_features: down.out_features,
10279                    in_features: local_in,
10280                },
10281            )?);
10282        }
10283        Ok(ResidentTpNvfp4Expert {
10284            gate: ResidentNvfp4ColumnParallel {
10285                ranks: gate_ranks,
10286                out_features: gate.out_features,
10287                in_features: gate.in_features,
10288            },
10289            up: ResidentNvfp4ColumnParallel {
10290                ranks: up_ranks,
10291                out_features: up.out_features,
10292                in_features: up.in_features,
10293            },
10294            down: ResidentNvfp4RowParallel {
10295                ranks: down_ranks,
10296                out_features: down.out_features,
10297                in_features: down.in_features,
10298            },
10299            input_width: gate.in_features,
10300            expert_width: gate.out_features,
10301        })
10302    }
10303
10304    fn column_parallel_resident_nvfp4(
10305        &self,
10306        matrix: &ResidentNvfp4ColumnParallel,
10307        activations: &[f32],
10308        tokens: usize,
10309    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10310        validate_activations(activations, tokens, matrix.in_features)?;
10311        let local_out = matrix.out_features / self.ranks.len();
10312        let mut gathered = vec![0.0f32; tokens * matrix.out_features];
10313        let mut macro_scale = None;
10314        for (rank_index, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
10315            let output = run_resident_rank_nvfp4(engine, shard, activations, tokens)?;
10316            let row_start = rank_index * local_out;
10317            for token in 0..tokens {
10318                gathered[token * matrix.out_features + row_start
10319                    ..token * matrix.out_features + row_start + local_out]
10320                    .copy_from_slice(&output[token * local_out..(token + 1) * local_out]);
10321            }
10322            macro_scale = Some(shard.macro_scale);
10323        }
10324        apply_macro(
10325            &mut gathered,
10326            macro_scale.ok_or("NVFP4 column-parallel matrix has no ranks")?,
10327        );
10328        Ok(gathered)
10329    }
10330
10331    fn row_parallel_resident_nvfp4(
10332        &self,
10333        matrix: &ResidentNvfp4RowParallel,
10334        activations: &[f32],
10335        tokens: usize,
10336    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10337        validate_activations(activations, tokens, matrix.in_features)?;
10338        let tp = self.ranks.len();
10339        let local_in = matrix.in_features / tp;
10340        let mut reduced = vec![0.0f32; tokens * matrix.out_features];
10341        let mut macro_scale = None;
10342        for (rank_index, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
10343            if shard.in_features != local_in {
10344                return Err(format!(
10345                    "NVFP4 resident row shard in_features {} != expected {local_in}",
10346                    shard.in_features
10347                )
10348                .into());
10349            }
10350            let local_activations =
10351                activation_shard(activations, tokens, matrix.in_features, tp, rank_index);
10352            let partial = run_resident_rank_nvfp4(engine, shard, &local_activations, tokens)?;
10353            for (sum, value) in reduced.iter_mut().zip(&partial) {
10354                *sum += *value;
10355            }
10356            macro_scale = Some(shard.macro_scale);
10357        }
10358        apply_macro(
10359            &mut reduced,
10360            macro_scale.ok_or("NVFP4 row-parallel matrix has no ranks")?,
10361        );
10362        Ok(reduced)
10363    }
10364
10365    pub fn run_expert_nvfp4(
10366        &self,
10367        expert: &ResidentTpNvfp4Expert,
10368        input: &[f32],
10369        tokens: usize,
10370    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10371        validate_activations(input, tokens, expert.input_width)?;
10372        let gate = self.column_parallel_resident_nvfp4(&expert.gate, input, tokens)?;
10373        let up = self.column_parallel_resident_nvfp4(&expert.up, input, tokens)?;
10374        let activated: Vec<f32> = gate
10375            .iter()
10376            .zip(&up)
10377            .map(|(&gate, &up)| gate / (1.0 + (-gate).exp()) * up)
10378            .collect();
10379        debug_assert_eq!(activated.len(), tokens * expert.expert_width);
10380        self.row_parallel_resident_nvfp4(&expert.down, &activated, tokens)
10381    }
10382
10383    /// Upload every expert's TP shards resident (one repacked block buffer per expert per rank).
10384    #[allow(clippy::manual_is_multiple_of)] // allow: divisor is runtime-derived; the modulo form keeps a zero divisor loud (a panic), where is_multiple_of would return false silently
10385    pub fn upload_tensor_parallel_nvfp4(
10386        &self,
10387        gate: Nvfp4ExpertBank<'_>,
10388        up: Nvfp4ExpertBank<'_>,
10389        down: Nvfp4ExpertBank<'_>,
10390    ) -> Result<ResidentNvfp4TensorParallel, Box<dyn std::error::Error>> {
10391        gate.validate()?;
10392        up.validate()?;
10393        down.validate()?;
10394        if gate.expert_count != up.expert_count || gate.expert_count != down.expert_count {
10395            return Err("NVFP4 TP gate/up/down expert counts differ".into());
10396        }
10397        if gate.in_features != up.in_features || gate.out_features != up.out_features {
10398            return Err("NVFP4 TP gate/up dimensions differ".into());
10399        }
10400        if down.in_features != gate.out_features || down.out_features != gate.in_features {
10401            return Err(format!(
10402                "NVFP4 TP down {}x{} does not invert gate/up {}x{}",
10403                down.out_features, down.in_features, gate.out_features, gate.in_features
10404            )
10405            .into());
10406        }
10407        let tp = self.ranks.len();
10408        if gate.out_features % tp != 0 {
10409            return Err(format!(
10410                "NVFP4 TP expert output width {} is not divisible by TP={tp}",
10411                gate.out_features
10412            )
10413            .into());
10414        }
10415        if !down.in_features.is_multiple_of(NVFP4_CANONICAL_ROW_SHARDS)
10416            || !(down.in_features / NVFP4_CANONICAL_ROW_SHARDS).is_multiple_of(64)
10417        {
10418            return Err(format!(
10419                "NVFP4 TP expert input width {} does not split into 64-aligned canonical \
10420                 shards ({NVFP4_CANONICAL_ROW_SHARDS})",
10421                down.in_features
10422            )
10423            .into());
10424        }
10425        if tp > NVFP4_CANONICAL_ROW_SHARDS {
10426            return Err(format!(
10427                "NVFP4 TP world {tp} exceeds the canonical row-shard grid \
10428                 ({NVFP4_CANONICAL_ROW_SHARDS})"
10429            )
10430            .into());
10431        }
10432
10433        let ep2 = step_nvfp4_ep2_on() && tp == 2;
10434        // LAYOUT DECISION, MADE ONCE PER BANK BUILD. EP2 whole-expert banks are ALWAYS
10435        // slot-major (their `*_ep` kernels read that mapping unconditionally); TP shard banks
10436        // are slot-major only under PROGRAM 1's door. Every reader below takes this from the
10437        // bank it is reading, never from `bank_slot_major_on()` again.
10438        let slot_major = ep2 || bank_slot_major_on();
10439        // ENGAGEMENT RECEIPT, not a debug line. A pricing cell that proves only that the env var
10440        // is SET measures nothing: if the door fails to reach the code, the cell reports "the
10441        // program is worth 0%" when the truth is "the program never ran". That exact defect is
10442        // banked -- the MEMRA_BF16_MMV lane's first sweep grepped for engagement, got 0 in BOTH
10443        // arms, and the missing line was mistaken for a no-engagement result until an announce
10444        // was added. So the layout decision announces itself, WITH ITS SOURCE, so a receipt can
10445        // distinguish "armed by the door" from "armed because EP2" from "not armed".
10446        eprintln!(
10447            "[nvfp4-bank] layout={} source={} tp={tp} experts={} in_f={} out_f={}",
10448            if slot_major {
10449                "slot-major"
10450            } else {
10451                "block-nvfp4-v1"
10452            },
10453            // The source string distinguishes "armed by the 2026-09-01 DEFAULT" from "armed by
10454            // an explicit recipe" from "rolled back by the seam" from "armed because EP2". A
10455            // default flip whose receipt cannot say which of those happened cannot prove the
10456            // DEFAULT was what got measured.
10457            if ep2 {
10458                "ep2-always"
10459            } else {
10460                bank_slot_major_source().1
10461            },
10462            gate.expert_count,
10463            gate.in_features,
10464            gate.out_features
10465        );
10466        let mut gate_ranks = Vec::with_capacity(tp);
10467        let mut up_ranks = Vec::with_capacity(tp);
10468        let mut macros_gate_dev = Vec::with_capacity(tp);
10469        let mut macros_up_dev = Vec::with_capacity(tp);
10470        let mut macros_down_dev = Vec::with_capacity(tp);
10471        for (rank_index, engine) in self.ranks.iter().enumerate() {
10472            let _main = engine.gpu.enter_main()?;
10473            // Contiguous per-rank banks: repack every expert shard into one host buffer, one
10474            // upload. Contiguity feeds the batched selected-experts launch; per-expert bytes
10475            // are unchanged (same repack).
10476            // EP2: this rank holds the FULL matrices of the experts it owns (id & 1 ==
10477            // rank_index), stacked at slot id >> 1 — same total bytes as the shard bank.
10478            let mut gate_host: Vec<u8> = Vec::new();
10479            let mut up_host: Vec<u8> = Vec::new();
10480            let mut owned = 0usize;
10481            for expert in 0..gate.expert_count {
10482                if ep2 {
10483                    if expert % 2 != rank_index {
10484                        continue;
10485                    }
10486                    owned += 1;
10487                    gate_host.extend_from_slice(&nvfp4_repack_bank_matrix(
10488                        gate.expert(expert)?,
10489                        slot_major,
10490                    ));
10491                    up_host.extend_from_slice(&nvfp4_repack_bank_matrix(
10492                        up.expert(expert)?,
10493                        slot_major,
10494                    ));
10495                } else {
10496                    let gate_shard = nvfp4_column_shard(gate.expert(expert)?, tp, rank_index)?;
10497                    gate_host.extend_from_slice(&nvfp4_repack_bank_matrix(gate_shard, slot_major));
10498                    let up_shard = nvfp4_column_shard(up.expert(expert)?, tp, rank_index)?;
10499                    up_host.extend_from_slice(&nvfp4_repack_bank_matrix(up_shard, slot_major));
10500                }
10501            }
10502            let bank_experts = if ep2 { owned } else { gate.expert_count };
10503            let gate_expert_bytes = gate_host.len() / bank_experts.max(1);
10504            let up_expert_bytes = up_host.len() / bank_experts.max(1);
10505            let local_out = if ep2 {
10506                gate.out_features
10507            } else {
10508                gate.out_features / tp
10509            };
10510            gate_ranks.push(ResidentNvfp4ColumnBankRank {
10511                bank: engine.htod_bytes(&gate_host)?,
10512                expert_bytes: gate_expert_bytes,
10513                local_out,
10514                in_features: gate.in_features,
10515                row_bytes: nvfp4_row_bytes(gate.in_features),
10516                slot_major,
10517            });
10518            up_ranks.push(ResidentNvfp4ColumnBankRank {
10519                bank: engine.htod_bytes(&up_host)?,
10520                expert_bytes: up_expert_bytes,
10521                local_out,
10522                in_features: up.in_features,
10523                row_bytes: nvfp4_row_bytes(up.in_features),
10524                slot_major,
10525            });
10526            macros_gate_dev.push(engine.htod(gate.macros)?);
10527            macros_up_dev.push(engine.htod(up.macros)?);
10528            macros_down_dev.push(engine.htod(down.macros)?);
10529        }
10530        // Down: canonical shard grid, NOT the world size (see NVFP4_CANONICAL_ROW_SHARDS).
10531        // Shard s lives on rank s % world, so TP1 holds both shards and TP2 one each, while the
10532        // execution and reduction order stay identical.
10533        let mut down_ranks = Vec::with_capacity(NVFP4_CANONICAL_ROW_SHARDS);
10534        for shard_index in 0..NVFP4_CANONICAL_ROW_SHARDS {
10535            let device_rank = shard_index % tp;
10536            let engine = &self.ranks[device_rank];
10537            let _main = engine.gpu.enter_main()?;
10538            let mut down_host: Vec<u8> = Vec::new();
10539            let mut owned = 0usize;
10540            for expert in 0..down.expert_count {
10541                let down_matrix = down.expert(expert)?;
10542                if ep2 {
10543                    // EP2: shard_index doubles as the owner rank; full-width down matrices
10544                    // of the owned experts, stacked at slot id >> 1.
10545                    if expert % 2 != device_rank {
10546                        continue;
10547                    }
10548                    owned += 1;
10549                    down_host.extend_from_slice(&nvfp4_repack_bank_matrix(down_matrix, slot_major));
10550                } else {
10551                    let (codes, scales, local_in) =
10552                        nvfp4_row_shard(down_matrix, NVFP4_CANONICAL_ROW_SHARDS, shard_index)?;
10553                    down_host.extend_from_slice(&nvfp4_repack_bank_matrix(
10554                        Nvfp4BlockMatrix {
10555                            codes: &codes,
10556                            scales: &scales,
10557                            macro_scale: down_matrix.macro_scale,
10558                            out_features: down_matrix.out_features,
10559                            in_features: local_in,
10560                        },
10561                        slot_major,
10562                    ));
10563                }
10564            }
10565            let bank_experts = if ep2 { owned } else { down.expert_count };
10566            let down_expert_bytes = down_host.len() / bank_experts.max(1);
10567            let local_in = if ep2 {
10568                down.in_features
10569            } else {
10570                down.in_features / NVFP4_CANONICAL_ROW_SHARDS
10571            };
10572            down_ranks.push(ResidentNvfp4RowBankRank {
10573                bank: engine.htod_bytes(&down_host)?,
10574                expert_bytes: down_expert_bytes,
10575                device_rank,
10576                out_features: down.out_features,
10577                local_in,
10578                row_bytes: nvfp4_row_bytes(local_in),
10579                slot_major,
10580            });
10581        }
10582        Ok(ResidentNvfp4TensorParallel {
10583            gate: gate_ranks,
10584            up: up_ranks,
10585            down: down_ranks,
10586            macros_gate: gate.macros.to_vec(),
10587            macros_up: up.macros.to_vec(),
10588            macros_down: down.macros.to_vec(),
10589            macros_gate_dev,
10590            macros_up_dev,
10591            macros_down_dev,
10592            expert_count: gate.expert_count,
10593            input_width: gate.in_features,
10594            expert_width: gate.out_features,
10595            device_workspace: std::sync::Mutex::new(None),
10596            prime_tables: std::sync::Mutex::new(Vec::new()),
10597            ep2,
10598        })
10599    }
10600
10601    /// EP2 host-canonical: the whole expert executes on its owning rank at full width
10602    /// (owner = expert & 1, bank slot = expert >> 1). Per-row program == the column-bank
10603    /// path's kernel, so gate/up are bit-equal to the TP layout.
10604    fn run_full_bank_expert_nvfp4(
10605        &self,
10606        ranks: &[ResidentNvfp4ColumnBankRank],
10607        macros: &[f32],
10608        expert: usize,
10609        input: &[f32],
10610    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10611        let owner = expert & 1;
10612        let slot = expert >> 1;
10613        let bank = ranks
10614            .get(owner)
10615            .ok_or("NVFP4 EP2 column bank missing owner rank")?;
10616        let engine = &self.ranks[owner];
10617        let _main = engine.gpu.enter_main()?;
10618        let activations = engine.htod(input)?;
10619        let output = bank.host_canonical_expert(engine, slot, &activations)?;
10620        let mut out = engine.dtoh(&output)?;
10621        apply_macro(&mut out, macros[expert]);
10622        Ok(out)
10623    }
10624
10625    /// EP2 host-canonical down: one full-width dot on the owner (NUMERIC-CLASS vs the
10626    /// canonical 2-shard sum — the parenthesization this door declares).
10627    fn run_full_down_expert_nvfp4(
10628        &self,
10629        shards: &[ResidentNvfp4RowBankRank],
10630        macros: &[f32],
10631        expert: usize,
10632        input: &[f32],
10633    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10634        let owner = expert & 1;
10635        let slot = expert >> 1;
10636        let shard = shards
10637            .get(owner)
10638            .ok_or("NVFP4 EP2 down bank missing owner rank")?;
10639        let engine = &self.ranks[owner];
10640        let _main = engine.gpu.enter_main()?;
10641        let activations = engine.htod(input)?;
10642        let output = shard.host_canonical_expert(engine, slot, &activations)?;
10643        let mut out = engine.dtoh(&output)?;
10644        apply_macro(&mut out, macros[expert]);
10645        Ok(out)
10646    }
10647
10648    fn run_column_bank_expert_nvfp4(
10649        &self,
10650        ranks: &[ResidentNvfp4ColumnBankRank],
10651        macros: &[f32],
10652        expert: usize,
10653        input: &[f32],
10654    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10655        let local_out = ranks
10656            .first()
10657            .ok_or("NVFP4 TP column bank has no ranks")?
10658            .local_out;
10659        let mut gathered = vec![0.0f32; local_out * ranks.len()];
10660        for (rank_index, (engine, bank)) in self.ranks.iter().zip(ranks).enumerate() {
10661            let _main = engine.gpu.enter_main()?;
10662            let activations = engine.htod(input)?;
10663            let output = bank.host_canonical_expert(engine, expert, &activations)?;
10664            let output = engine.dtoh(&output)?;
10665            gathered[rank_index * local_out..(rank_index + 1) * local_out].copy_from_slice(&output);
10666        }
10667        apply_macro(&mut gathered, macros[expert]);
10668        Ok(gathered)
10669    }
10670
10671    /// Canonical-shard row reduction: iterate the FIXED shard grid in shard order (each shard
10672    /// executes on its owning rank engine), so the reduction parenthesization is identical at
10673    /// every world size — that identity is what the TP1-oracle-vs-TP2 bit gate proves.
10674    fn run_row_bank_expert_nvfp4(
10675        &self,
10676        shards: &[ResidentNvfp4RowBankRank],
10677        macros: &[f32],
10678        expert: usize,
10679        input: &[f32],
10680    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10681        let out_features = shards
10682            .first()
10683            .ok_or("NVFP4 TP row bank has no canonical shards")?
10684            .out_features;
10685        let in_features = shards.iter().map(|shard| shard.local_in).sum::<usize>();
10686        let mut reduced = vec![0.0f32; out_features];
10687        for (shard_index, shard) in shards.iter().enumerate() {
10688            let engine = self
10689                .ranks
10690                .get(shard.device_rank)
10691                .ok_or("NVFP4 canonical shard names a rank outside this runtime")?;
10692            let _main = engine.gpu.enter_main()?;
10693            let local_activations =
10694                activation_shard(input, 1, in_features, shards.len(), shard_index);
10695            let activations = engine.htod(&local_activations)?;
10696            let output = shard.host_canonical_expert(engine, expert, &activations)?;
10697            let partial = engine.dtoh(&output)?;
10698            for (sum, value) in reduced.iter_mut().zip(&partial) {
10699                *sum += *value;
10700            }
10701        }
10702        apply_macro(&mut reduced, macros[expert]);
10703        Ok(reduced)
10704    }
10705
10706    /// Upload whole experts per owning rank (NVFP4 expert-parallel: the layout the clamped tail
10707    /// layers require — clamp semantics do not distribute across a tensor shard). Each owned
10708    /// expert keeps its full gate/up/down as one repacked block buffer on its owner.
10709    #[allow(clippy::manual_is_multiple_of)] // allow: divisor is runtime-derived; the modulo form keeps a zero divisor loud (a panic), where is_multiple_of would return false silently
10710    pub fn upload_expert_parallel_nvfp4(
10711        &self,
10712        gate: Nvfp4ExpertBank<'_>,
10713        up: Nvfp4ExpertBank<'_>,
10714        down: Nvfp4ExpertBank<'_>,
10715    ) -> Result<ResidentNvfp4ExpertParallel, Box<dyn std::error::Error>> {
10716        gate.validate()?;
10717        up.validate()?;
10718        down.validate()?;
10719        if gate.expert_count != up.expert_count || gate.expert_count != down.expert_count {
10720            return Err("NVFP4 EP gate/up/down expert counts differ".into());
10721        }
10722        if gate.in_features != up.in_features || gate.out_features != up.out_features {
10723            return Err("NVFP4 EP gate/up dimensions differ".into());
10724        }
10725        if down.in_features != gate.out_features || down.out_features != gate.in_features {
10726            return Err(format!(
10727                "NVFP4 EP down {}x{} does not invert gate/up {}x{}",
10728                down.out_features, down.in_features, gate.out_features, gate.in_features
10729            )
10730            .into());
10731        }
10732        let world = self.ranks.len();
10733        if gate.expert_count % world != 0 {
10734            return Err(format!(
10735                "NVFP4 EP expert count {} is not divisible by {world} ranks",
10736                gate.expert_count
10737            )
10738            .into());
10739        }
10740        let experts_per_rank = gate.expert_count / world;
10741        let mut ranks = Vec::with_capacity(world);
10742        for (rank_index, engine) in self.ranks.iter().enumerate() {
10743            let _main = engine.gpu.enter_main()?;
10744            let expert_range = rank_index * experts_per_rank..(rank_index + 1) * experts_per_rank;
10745            let mut gate_host = Vec::new();
10746            let mut up_host = Vec::new();
10747            let mut down_host = Vec::new();
10748            for expert in expert_range.clone() {
10749                gate_host.extend_from_slice(&nvfp4_repack_matrix(gate.expert(expert)?));
10750                up_host.extend_from_slice(&nvfp4_repack_matrix(up.expert(expert)?));
10751                down_host.extend_from_slice(&nvfp4_repack_matrix(down.expert(expert)?));
10752            }
10753            let gate_expert_bytes = gate_host.len() / experts_per_rank;
10754            let up_expert_bytes = up_host.len() / experts_per_rank;
10755            if gate_expert_bytes != up_expert_bytes {
10756                return Err("NVFP4 EP gate/up packed expert bytes differ".into());
10757            }
10758            let down_expert_bytes = down_host.len() / experts_per_rank;
10759            ranks.push(ResidentNvfp4EpRank {
10760                gate: engine.htod_bytes(&gate_host)?,
10761                up: engine.htod_bytes(&up_host)?,
10762                down: engine.htod_bytes(&down_host)?,
10763                gate_expert_bytes,
10764                down_expert_bytes,
10765                macros_gate: engine.htod(&gate.macros[expert_range.clone()])?,
10766                macros_up: engine.htod(&up.macros[expert_range.clone()])?,
10767                macros_down: engine.htod(&down.macros[expert_range.clone()])?,
10768                expert_range,
10769            });
10770        }
10771        Ok(ResidentNvfp4ExpertParallel {
10772            ranks,
10773            macros_gate: gate.macros.to_vec(),
10774            macros_up: up.macros.to_vec(),
10775            macros_down: down.macros.to_vec(),
10776            expert_count: gate.expert_count,
10777            input_width: gate.in_features,
10778            expert_width: gate.out_features,
10779            gate_row_bytes: nvfp4_row_bytes(gate.in_features),
10780            down_row_bytes: nvfp4_row_bytes(down.in_features),
10781            device_workspace: std::sync::Mutex::new(None),
10782        })
10783    }
10784
10785    /// Upload an already-normalized NVFP4 expert bank.
10786    ///
10787    /// `HostExps` is the physical-format boundary: stacked checkpoint tensors, gathered
10788    /// per-expert tensors, and manifest-backed overlays all become the same contiguous
10789    /// block_nvfp4 expert representation before the parallel backend sees them.
10790    pub fn upload_expert_parallel_nvfp4_normalized(
10791        &self,
10792        gate: &crate::model::HostExps,
10793        up: &crate::model::HostExps,
10794        down: &crate::model::HostExps,
10795    ) -> Result<ResidentNvfp4ExpertParallel, Box<dyn std::error::Error>> {
10796        for (label, bank) in [("gate", gate), ("up", up), ("down", down)] {
10797            if bank.qtype != crate::QT_NVFP4 || !bank.is_uniform_layout() {
10798                return Err(format!(
10799                    "NVFP4 EP normalized {label} bank requires one uniform NVFP4 layout, \
10800                     got qtype={} uniform={}",
10801                    bank.qtype,
10802                    bank.is_uniform_layout()
10803                )
10804                .into());
10805            }
10806            if bank.n_expert == 0
10807                || bank.expert_stride != bank.out_f * bank.row_bytes
10808                || (0..bank.n_expert)
10809                    .any(|expert| bank.expert_bytes(expert).len() != bank.expert_stride)
10810            {
10811                return Err(format!("NVFP4 EP normalized {label} bank geometry is invalid").into());
10812            }
10813        }
10814        if gate.n_expert != up.n_expert || gate.n_expert != down.n_expert {
10815            return Err("NVFP4 EP normalized gate/up/down expert counts differ".into());
10816        }
10817        if gate.in_f != up.in_f || gate.out_f != up.out_f {
10818            return Err("NVFP4 EP normalized gate/up dimensions differ".into());
10819        }
10820        if down.in_f != gate.out_f || down.out_f != gate.in_f {
10821            return Err(format!(
10822                "NVFP4 EP normalized down {}x{} does not invert gate/up {}x{}",
10823                down.out_f, down.in_f, gate.out_f, gate.in_f
10824            )
10825            .into());
10826        }
10827        let macros = |bank: &crate::model::HostExps| -> Result<Vec<f32>, String> {
10828            let values = bank
10829                .macros
10830                .clone()
10831                .unwrap_or_else(|| vec![1.0; bank.n_expert]);
10832            if values.len() != bank.n_expert
10833                || !values.iter().all(|value| value.is_finite() && *value > 0.0)
10834            {
10835                return Err("NVFP4 EP normalized macro row is not finite-positive".to_string());
10836            }
10837            Ok(values)
10838        };
10839        let macros_gate = macros(gate)?;
10840        let macros_up = macros(up)?;
10841        let macros_down = macros(down)?;
10842        let world = self.ranks.len();
10843        if !gate.n_expert.is_multiple_of(world) {
10844            return Err(format!(
10845                "NVFP4 EP normalized expert count {} is not divisible by {world} ranks",
10846                gate.n_expert
10847            )
10848            .into());
10849        }
10850        let experts_per_rank = gate.n_expert / world;
10851        let mut ranks = Vec::with_capacity(world);
10852        for (rank_index, engine) in self.ranks.iter().enumerate() {
10853            let _main = engine.gpu.enter_main()?;
10854            let expert_range = rank_index * experts_per_rank..(rank_index + 1) * experts_per_rank;
10855            let mut gate_host = Vec::with_capacity(experts_per_rank * gate.expert_stride);
10856            let mut up_host = Vec::with_capacity(experts_per_rank * up.expert_stride);
10857            let mut down_host = Vec::with_capacity(experts_per_rank * down.expert_stride);
10858            for expert in expert_range.clone() {
10859                gate_host.extend_from_slice(gate.expert_bytes(expert));
10860                up_host.extend_from_slice(up.expert_bytes(expert));
10861                down_host.extend_from_slice(down.expert_bytes(expert));
10862            }
10863            ranks.push(ResidentNvfp4EpRank {
10864                gate: engine.htod_bytes(&gate_host)?,
10865                up: engine.htod_bytes(&up_host)?,
10866                down: engine.htod_bytes(&down_host)?,
10867                gate_expert_bytes: gate.expert_stride,
10868                down_expert_bytes: down.expert_stride,
10869                macros_gate: engine.htod(&macros_gate[expert_range.clone()])?,
10870                macros_up: engine.htod(&macros_up[expert_range.clone()])?,
10871                macros_down: engine.htod(&macros_down[expert_range.clone()])?,
10872                expert_range,
10873            });
10874        }
10875        Ok(ResidentNvfp4ExpertParallel {
10876            ranks,
10877            macros_gate,
10878            macros_up,
10879            macros_down,
10880            expert_count: gate.n_expert,
10881            input_width: gate.in_f,
10882            expert_width: gate.out_f,
10883            gate_row_bytes: gate.row_bytes,
10884            down_row_bytes: down.row_bytes,
10885            device_workspace: std::sync::Mutex::new(None),
10886        })
10887    }
10888
10889    /// Routed NVFP4 expert-parallel program, host-canonical: every selected expert executes WHOLE
10890    /// on its owning rank (gate -> up -> clamped-or-plain SwiGLU on host -> down), each projection
10891    /// macro applied once post-kernel, route-weighted accumulate on the host in slot order. The
10892    /// activation uses `step_expert_activation_host`, so the clamped tail layers keep the official
10893    /// contract. Exactness-first; no throughput claim.
10894    #[allow(clippy::too_many_arguments)]
10895    pub fn run_routed_experts_nvfp4(
10896        &self,
10897        experts: &ResidentNvfp4ExpertParallel,
10898        input: &[f32],
10899        tokens: usize,
10900        selected: &[usize],
10901        route_weights: &[f32],
10902        experts_per_token: usize,
10903        activation_limit: Option<f32>,
10904    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10905        validate_activations(input, tokens, experts.input_width)?;
10906        let pairs = tokens
10907            .checked_mul(experts_per_token)
10908            .ok_or("NVFP4 EP route count overflow")?;
10909        if selected.len() != pairs || route_weights.len() != pairs {
10910            return Err(format!(
10911                "NVFP4 EP routes selected={} weights={} != tokens {tokens} x experts/token \
10912                 {experts_per_token} ({pairs})",
10913                selected.len(),
10914                route_weights.len(),
10915            )
10916            .into());
10917        }
10918        if !route_weights.iter().all(|weight| weight.is_finite()) {
10919            return Err("NVFP4 EP route weights contain a non-finite value".into());
10920        }
10921        let experts_per_rank = experts.expert_count / experts.ranks.len();
10922        let mut output = vec![0.0f32; tokens * experts.input_width];
10923        for token in 0..tokens {
10924            let input_row = &input[token * experts.input_width..(token + 1) * experts.input_width];
10925            for slot in 0..experts_per_token {
10926                let pair = token * experts_per_token + slot;
10927                let expert = selected[pair];
10928                if expert >= experts.expert_count {
10929                    return Err(format!(
10930                        "NVFP4 EP selected expert {expert} outside 0..{}",
10931                        experts.expert_count
10932                    )
10933                    .into());
10934                }
10935                let owner = expert / experts_per_rank;
10936                let local = expert - owner * experts_per_rank;
10937                let rank = &experts.ranks[owner];
10938                let engine = &self.ranks[owner];
10939                let _main = engine.gpu.enter_main()?;
10940                let device_input = engine.htod(input_row)?;
10941                let gate_out = engine.qmatvec_nvfp4_fast(
10942                    &rank.gate.slice(
10943                        local * rank.gate_expert_bytes..(local + 1) * rank.gate_expert_bytes,
10944                    ),
10945                    &device_input,
10946                    1,
10947                    experts.input_width,
10948                    experts.expert_width,
10949                    experts.gate_row_bytes,
10950                )?;
10951                let up_out = engine.qmatvec_nvfp4_fast(
10952                    &rank.up.slice(
10953                        local * rank.gate_expert_bytes..(local + 1) * rank.gate_expert_bytes,
10954                    ),
10955                    &device_input,
10956                    1,
10957                    experts.input_width,
10958                    experts.expert_width,
10959                    experts.gate_row_bytes,
10960                )?;
10961                let mut gate_host = engine.dtoh(&gate_out)?;
10962                let mut up_host = engine.dtoh(&up_out)?;
10963                apply_macro(&mut gate_host, experts.macros_gate[expert]);
10964                apply_macro(&mut up_host, experts.macros_up[expert]);
10965                let activated: Vec<f32> = gate_host
10966                    .iter()
10967                    .zip(&up_host)
10968                    .map(|(&gate, &up)| step_expert_activation_host(gate, up, activation_limit))
10969                    .collect();
10970                let device_activated = engine.htod(&activated)?;
10971                let down_out = engine.qmatvec_nvfp4_fast(
10972                    &rank.down.slice(
10973                        local * rank.down_expert_bytes..(local + 1) * rank.down_expert_bytes,
10974                    ),
10975                    &device_activated,
10976                    1,
10977                    experts.expert_width,
10978                    experts.input_width,
10979                    experts.down_row_bytes,
10980                )?;
10981                let mut down_host = engine.dtoh(&down_out)?;
10982                apply_macro(&mut down_host, experts.macros_down[expert]);
10983                let weight = route_weights[pair];
10984                for (sum, value) in output
10985                    [token * experts.input_width..(token + 1) * experts.input_width]
10986                    .iter_mut()
10987                    .zip(down_host)
10988                {
10989                    *sum += weight * value;
10990                }
10991            }
10992        }
10993        Ok(output)
10994    }
10995
10996    /// Device-resident W4A16 expert parallelism for one scheduler/prefill batch (1..=128 rows).
10997    ///
10998    /// The host router partitions token/slot pairs by contiguous expert owner. Each rank
10999    /// peer-reads the whole batch input once, rounds it to BF16, and executes its owner-local
11000    /// selected gate/up -> host-expf SwiGLU -> BF16 -> down program. Down rows scatter directly
11001    /// into canonical token-major pair positions in the model engine's peer-accessible pool at
11002    /// every batch width; the root reduces each token's slots in original order. Thus batching
11003    /// and owner assignment do not change route-reduction parenthesization.
11004    #[allow(clippy::too_many_arguments)]
11005    pub fn run_routed_experts_nvfp4_w4a16_device_io(
11006        &self,
11007        experts: &ResidentNvfp4ExpertParallel,
11008        e: &Engine,
11009        input_dev: &crate::CudaSlice<f32>,
11010        tokens: usize,
11011        selected: &[usize],
11012        route_weights: &[f32],
11013        experts_per_token: usize,
11014        activation_limit: Option<f32>,
11015    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
11016        // Diagnostic attribution only: force the returned root event chain to completion so the
11017        // caller's shared-expert timer does not absorb routed-EP work. The normal path remains
11018        // fully asynchronous.
11019        static TIMING_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11020        static TIMING_CALLS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11021        let timing = std::env::var("MEMRA_STEP_TP_TIMING").as_deref() == Ok("1");
11022        let started = timing.then(std::time::Instant::now);
11023        if !self.native_p2p {
11024            return Err("W4A16 NVFP4 device EP requires native P2P".into());
11025        }
11026        if self.devices.first().copied() != Some(e.ctx().ordinal()) {
11027            return Err(format!(
11028                "W4A16 NVFP4 device EP root device {:?} != model engine device {}",
11029                self.devices.first(),
11030                e.ctx().ordinal()
11031            )
11032            .into());
11033        }
11034        // Prime/cache scratch buffers are grow-only: a 160-token host-oracle chunk can be
11035        // followed by a 44-token device-EP tail using the same 160-row allocation. Consume the
11036        // active prefix rather than requiring allocation length == active length.
11037        let active_input_values =
11038            nvfp4_ep_active_input_values(input_dev.len(), tokens, experts.input_width)?;
11039        let pairs = tokens
11040            .checked_mul(experts_per_token)
11041            .ok_or("W4A16 NVFP4 device EP route count overflow")?;
11042        if selected.len() != pairs || route_weights.len() != pairs {
11043            return Err(format!(
11044                "W4A16 NVFP4 device EP routes selected={} weights={} != tokens {tokens} x \
11045                 experts/token {experts_per_token} ({pairs})",
11046                selected.len(),
11047                route_weights.len(),
11048            )
11049            .into());
11050        }
11051        if !route_weights.iter().all(|weight| weight.is_finite()) {
11052            return Err("W4A16 NVFP4 device EP route weights contain a non-finite value".into());
11053        }
11054        let world = self.ranks.len();
11055        if world != experts.ranks.len() || !(2..=PRODUCT_MAX_CARDS).contains(&world) {
11056            return Err(format!(
11057                "W4A16 NVFP4 device EP runtime ranks {world} != bank ranks {}",
11058                experts.ranks.len()
11059            )
11060            .into());
11061        }
11062        let owner_routes = partition_expert_owner_routes(
11063            experts.expert_count,
11064            world,
11065            tokens,
11066            experts_per_token,
11067            selected,
11068        )?;
11069
11070        let mut workspace_guard = experts
11071            .device_workspace
11072            .lock()
11073            .map_err(|_| "W4A16 NVFP4 device EP workspace lock is poisoned")?;
11074        if workspace_guard.is_none() {
11075            let capacity_tokens = NVFP4_EP_DEVICE_BATCH_CAP;
11076            let capacity_pairs = capacity_tokens * experts_per_token;
11077            let mut input = Vec::with_capacity(world);
11078            let mut input_bf16 = Vec::with_capacity(world);
11079            let mut input_q8 = Vec::with_capacity(world);
11080            let mut input_q8_scales = Vec::with_capacity(world);
11081            let mut sel = Vec::with_capacity(world);
11082            let mut token_rows = Vec::with_capacity(world);
11083            let mut global_pairs = Vec::with_capacity(world);
11084            let mut route_w = Vec::with_capacity(world);
11085            let mut gate_out = Vec::with_capacity(world);
11086            let mut up_out = Vec::with_capacity(world);
11087            let mut activation_bf16 = Vec::with_capacity(world);
11088            let mut activation_q8 = Vec::with_capacity(world);
11089            let mut activation_q8_scales = Vec::with_capacity(world);
11090            let mut ev_rank = Vec::with_capacity(world);
11091            for engine in &self.ranks {
11092                let _main = engine.gpu.enter_main()?;
11093                input.push(engine.uninit(capacity_tokens * experts.input_width)?);
11094                input_bf16.push(engine.alloc_u8_uninit(2 * capacity_tokens * experts.input_width)?);
11095                input_q8.push(engine.alloc_i8_uninit(capacity_tokens * experts.input_width)?);
11096                input_q8_scales
11097                    .push(engine.uninit(capacity_tokens * experts.input_width.div_ceil(32))?);
11098                sel.push(engine.htod_i32(&vec![0i32; capacity_pairs])?);
11099                token_rows.push(engine.htod_i32(&vec![0i32; capacity_pairs])?);
11100                global_pairs.push(engine.htod_i32(&vec![0i32; capacity_pairs])?);
11101                route_w.push(engine.htod(&vec![0.0f32; capacity_pairs])?);
11102                gate_out.push(engine.uninit(capacity_pairs * experts.expert_width)?);
11103                up_out.push(engine.uninit(capacity_pairs * experts.expert_width)?);
11104                activation_bf16
11105                    .push(engine.alloc_u8_uninit(2 * capacity_pairs * experts.expert_width)?);
11106                activation_q8.push(engine.alloc_i8_uninit(capacity_pairs * experts.expert_width)?);
11107                activation_q8_scales
11108                    .push(engine.uninit(capacity_pairs * experts.expert_width.div_ceil(32))?);
11109                ev_rank.push(engine.ctx().new_event(None)?);
11110            }
11111            let _main = e.gpu.enter_main()?;
11112            let slot_rows = e.uninit(capacity_pairs * experts.input_width)?;
11113            let slot_rows_raw = {
11114                use cudarc::driver::DevicePtr;
11115                let stream = e.stream();
11116                let (pointer, _guard) = slot_rows.device_ptr(&stream);
11117                pointer
11118            };
11119            *workspace_guard = Some(Nvfp4EpDeviceWorkspace {
11120                input,
11121                input_bf16,
11122                input_q8,
11123                input_q8_scales,
11124                sel,
11125                token_rows,
11126                global_pairs,
11127                route_w,
11128                gate_out,
11129                up_out,
11130                activation_bf16,
11131                activation_q8,
11132                activation_q8_scales,
11133                slot_rows,
11134                slot_rows_raw,
11135                route_weights: e.htod(&vec![0.0f32; capacity_pairs])?,
11136                graph_input: e.uninit(NVFP4_EP_GRAPH_BATCH_CAP * experts.input_width)?,
11137                graph_output: e.uninit(NVFP4_EP_GRAPH_BATCH_CAP * experts.input_width)?,
11138                graph_routes: None,
11139                graphs: std::iter::repeat_with(|| None)
11140                    .take(NVFP4_EP_GRAPH_BATCH_CAP + 1)
11141                    .collect(),
11142                ev_entry: e.ctx().new_event(None)?,
11143                ev_entry_device: e.ctx().ordinal(),
11144                ev_rank,
11145                phase_events: None,
11146                capacity_tokens,
11147                experts_per_token,
11148            });
11149        }
11150        let workspace = workspace_guard
11151            .as_mut()
11152            .expect("W4A16 NVFP4 device EP workspace initialized above");
11153        if workspace.experts_per_token != experts_per_token || tokens > workspace.capacity_tokens {
11154            return Err(format!(
11155                "W4A16 NVFP4 device EP workspace tokens={} experts/token={} cannot serve \
11156                 tokens={tokens} experts/token={experts_per_token}",
11157                workspace.capacity_tokens, workspace.experts_per_token,
11158            )
11159            .into());
11160        }
11161        if workspace.ev_entry_device != e.ctx().ordinal() {
11162            return Err("W4A16 NVFP4 device EP model engine changed".into());
11163        }
11164
11165        {
11166            let _main = e.gpu.enter_main()?;
11167            let mut destination = workspace.route_weights.slice_mut(0..pairs);
11168            e.stream()
11169                .memcpy_htod(&route_weights[..pairs], &mut destination)?;
11170            workspace.ev_entry.record(&e.stream())?;
11171        }
11172        for (rank_index, engine) in self.ranks.iter().enumerate() {
11173            let _main = engine.gpu.enter_main()?;
11174            engine.stream().wait(&workspace.ev_entry)?;
11175            {
11176                let mut destination = workspace.input[rank_index].slice_mut(0..active_input_values);
11177                engine
11178                    .stream()
11179                    .memcpy_dtod(&input_dev.slice(0..active_input_values), &mut destination)?;
11180            }
11181            engine.f32_to_bf16_into(
11182                &workspace.input[rank_index],
11183                &mut workspace.input_bf16[rank_index],
11184                tokens * experts.input_width,
11185            )?;
11186            let owner = &owner_routes[rank_index];
11187            debug_assert_eq!(owner.rank, rank_index);
11188            let local_count = owner.selected.len();
11189            if local_count > 0 {
11190                let local_selected = owner
11191                    .selected
11192                    .iter()
11193                    .map(|&expert| expert as i32)
11194                    .collect::<Vec<_>>();
11195                let local_token_rows = owner
11196                    .token_rows
11197                    .iter()
11198                    .map(|&token| token as i32)
11199                    .collect::<Vec<_>>();
11200                let local_global_pairs = owner
11201                    .global_pairs
11202                    .iter()
11203                    .map(|&pair| pair as i32)
11204                    .collect::<Vec<_>>();
11205                {
11206                    let mut destination = workspace.sel[rank_index].slice_mut(0..local_count);
11207                    engine
11208                        .stream()
11209                        .memcpy_htod(&local_selected, &mut destination)?;
11210                }
11211                {
11212                    let mut destination =
11213                        workspace.token_rows[rank_index].slice_mut(0..local_count);
11214                    engine
11215                        .stream()
11216                        .memcpy_htod(&local_token_rows, &mut destination)?;
11217                }
11218                {
11219                    let mut destination =
11220                        workspace.global_pairs[rank_index].slice_mut(0..local_count);
11221                    engine
11222                        .stream()
11223                        .memcpy_htod(&local_global_pairs, &mut destination)?;
11224                }
11225                let rank = &experts.ranks[rank_index];
11226                engine.qmatvec_nvfp4_bf16_sel_dual_rows_into(
11227                    &rank.gate,
11228                    &rank.up,
11229                    &workspace.sel[rank_index],
11230                    &workspace.token_rows[rank_index],
11231                    &workspace.input_bf16[rank_index],
11232                    &mut workspace.gate_out[rank_index],
11233                    &mut workspace.up_out[rank_index],
11234                    local_count,
11235                    experts.input_width,
11236                    experts.expert_width,
11237                    experts.gate_row_bytes,
11238                    rank.gate_expert_bytes,
11239                    tokens,
11240                )?;
11241                engine.silu_mul_scaled_host_expf_bf16_sel_into(
11242                    &workspace.gate_out[rank_index],
11243                    &workspace.up_out[rank_index],
11244                    &rank.macros_gate,
11245                    &rank.macros_up,
11246                    &workspace.sel[rank_index],
11247                    activation_limit,
11248                    &mut workspace.activation_bf16[rank_index],
11249                    experts.expert_width,
11250                    local_count,
11251                )?;
11252                engine.qmatvec_nvfp4_bf16_sel_down_rows_raw(
11253                    &rank.down,
11254                    &workspace.sel[rank_index],
11255                    &workspace.global_pairs[rank_index],
11256                    &workspace.activation_bf16[rank_index],
11257                    &rank.macros_down,
11258                    workspace.slot_rows_raw,
11259                    local_count,
11260                    experts.expert_width,
11261                    experts.input_width,
11262                    experts.down_row_bytes,
11263                    rank.down_expert_bytes,
11264                    pairs,
11265                )?;
11266            }
11267            workspace.ev_rank[rank_index].record(&engine.stream())?;
11268        }
11269
11270        let output = {
11271            let _main = e.gpu.enter_main()?;
11272            for event in &workspace.ev_rank {
11273                e.stream().wait(event)?;
11274            }
11275            let mut output = e.uninit(tokens * experts.input_width)?;
11276            e.axpy_rows_seq_tokens_into(
11277                &workspace.slot_rows,
11278                &workspace.route_weights,
11279                &mut output,
11280                experts.input_width,
11281                experts_per_token,
11282                tokens,
11283            )?;
11284            output
11285        };
11286        if let Some(started) = started {
11287            use std::sync::atomic::Ordering;
11288            e.stream().synchronize()?;
11289            let elapsed = started.elapsed().as_nanos() as u64;
11290            let ns = TIMING_NS.fetch_add(elapsed, Ordering::Relaxed) + elapsed;
11291            let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
11292            if calls.is_multiple_of(430) {
11293                eprintln!(
11294                    "[nvfp4-ep-w4a16-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
11295                    ns as f64 / 1.0e6,
11296                    ns as f64 / calls as f64 / 1.0e3,
11297                );
11298            }
11299        }
11300        Ok(output)
11301    }
11302
11303    /// Fully device-routed W4A16 expert parallelism. Router ids/weights stay on the model GPU;
11304    /// each rank receives the fixed token/slot metadata, rejects non-owned experts in-kernel, and
11305    /// writes canonical token-major slot rows back to the root at every batch width. Preserving
11306    /// that one accumulation program is required by speculative verification: the former t=1
11307    /// owner-grouped FMA was a distinct numeric class and failed real HY3 MTP self-consistency.
11308    #[allow(clippy::too_many_arguments)]
11309    pub fn run_routed_experts_nvfp4_w4a16_device_routed(
11310        &self,
11311        experts: &ResidentNvfp4ExpertParallel,
11312        e: &Engine,
11313        input_dev: &crate::CudaSlice<f32>,
11314        selected_dev: &crate::CudaSlice<i32>,
11315        route_weights_dev: &crate::CudaSlice<f32>,
11316        tokens: usize,
11317        experts_per_token: usize,
11318        activation_limit: Option<f32>,
11319    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
11320        self.run_routed_experts_nvfp4_w4a16_device_routed_inner(
11321            experts,
11322            e,
11323            input_dev,
11324            selected_dev,
11325            route_weights_dev,
11326            tokens,
11327            experts_per_token,
11328            activation_limit,
11329            None,
11330        )
11331    }
11332
11333    /// Automatic whole-expert EP with a PREJOIN hook. The hook runs after every rank's routed
11334    /// chain has been issued and before the root waits for rank completion, so independent
11335    /// root-device work can fill the peer drain without changing the routed accumulation order.
11336    #[allow(clippy::too_many_arguments)]
11337    pub fn run_routed_experts_nvfp4_w4a16_device_routed_prejoin(
11338        &self,
11339        experts: &ResidentNvfp4ExpertParallel,
11340        e: &Engine,
11341        input_dev: &crate::CudaSlice<f32>,
11342        selected_dev: &crate::CudaSlice<i32>,
11343        route_weights_dev: &crate::CudaSlice<f32>,
11344        tokens: usize,
11345        experts_per_token: usize,
11346        activation_limit: Option<f32>,
11347        mut pre_join: impl FnMut() -> Result<(), Box<dyn std::error::Error>>,
11348    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
11349        self.run_routed_experts_nvfp4_w4a16_device_routed_inner(
11350            experts,
11351            e,
11352            input_dev,
11353            selected_dev,
11354            route_weights_dev,
11355            tokens,
11356            experts_per_token,
11357            activation_limit,
11358            Some(&mut pre_join),
11359        )
11360    }
11361
11362    #[allow(clippy::too_many_arguments)]
11363    fn run_routed_experts_nvfp4_w4a16_device_routed_inner(
11364        &self,
11365        experts: &ResidentNvfp4ExpertParallel,
11366        e: &Engine,
11367        input_dev: &crate::CudaSlice<f32>,
11368        selected_dev: &crate::CudaSlice<i32>,
11369        route_weights_dev: &crate::CudaSlice<f32>,
11370        tokens: usize,
11371        experts_per_token: usize,
11372        activation_limit: Option<f32>,
11373        mut pre_join: Option<&mut dyn FnMut() -> Result<(), Box<dyn std::error::Error>>>,
11374    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
11375        if !self.native_p2p {
11376            return Err("W4A16 device-routed EP requires native P2P".into());
11377        }
11378        if self.devices.first().copied() != Some(e.ctx().ordinal()) {
11379            return Err(format!(
11380                "W4A16 device-routed EP root device {:?} != model engine device {}",
11381                self.devices.first(),
11382                e.ctx().ordinal()
11383            )
11384            .into());
11385        }
11386        let active_input_values =
11387            nvfp4_ep_active_input_values(input_dev.len(), tokens, experts.input_width)?;
11388        let pairs = tokens
11389            .checked_mul(experts_per_token)
11390            .ok_or("W4A16 device-routed EP route count overflow")?;
11391        if selected_dev.len() < pairs || route_weights_dev.len() < pairs {
11392            return Err(format!(
11393                "W4A16 device-routed EP metadata selected={} weights={} < pairs={pairs}",
11394                selected_dev.len(),
11395                route_weights_dev.len(),
11396            )
11397            .into());
11398        }
11399        let world = self.ranks.len();
11400        if world != experts.ranks.len() || !(2..=PRODUCT_MAX_CARDS).contains(&world) {
11401            return Err(format!(
11402                "W4A16 device-routed EP runtime ranks {world} != bank ranks {}",
11403                experts.ranks.len()
11404            )
11405            .into());
11406        }
11407
11408        static TIMING_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11409        static TIMING_CALLS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11410        static ISSUE_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11411        static JOIN_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11412        static COPY_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11413        static GATE_UP_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11414        static ACTIVATION_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11415        static DOWN_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11416        static RANK_SPAN_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11417        let timing = std::env::var("MEMRA_STEP_TP_TIMING").as_deref() == Ok("1");
11418        let started = timing.then(std::time::Instant::now);
11419        let graph_enabled = parallel_ep_graph_enabled()?;
11420        let pair_down_enabled = parallel_ep_pair_down_enabled()?;
11421
11422        let mut workspace_guard = experts
11423            .device_workspace
11424            .lock()
11425            .map_err(|_| "W4A16 device-routed EP workspace lock is poisoned")?;
11426        if workspace_guard.is_none() {
11427            let capacity_tokens = NVFP4_EP_DEVICE_BATCH_CAP;
11428            let capacity_pairs = capacity_tokens * experts_per_token;
11429            let mut input = Vec::with_capacity(world);
11430            let mut input_bf16 = Vec::with_capacity(world);
11431            let mut input_q8 = Vec::with_capacity(world);
11432            let mut input_q8_scales = Vec::with_capacity(world);
11433            let mut sel = Vec::with_capacity(world);
11434            let mut token_rows = Vec::with_capacity(world);
11435            let mut global_pairs = Vec::with_capacity(world);
11436            let mut route_w = Vec::with_capacity(world);
11437            let mut gate_out = Vec::with_capacity(world);
11438            let mut up_out = Vec::with_capacity(world);
11439            let mut activation_bf16 = Vec::with_capacity(world);
11440            let mut activation_q8 = Vec::with_capacity(world);
11441            let mut activation_q8_scales = Vec::with_capacity(world);
11442            let mut ev_rank = Vec::with_capacity(world);
11443            let mut phase_head = Vec::with_capacity(world);
11444            let mut phase_copy_done = Vec::with_capacity(world);
11445            let mut phase_gate_up_done = Vec::with_capacity(world);
11446            let mut phase_activation_done = Vec::with_capacity(world);
11447            let mut phase_down_done = Vec::with_capacity(world);
11448            for engine in &self.ranks {
11449                let _main = engine.gpu.enter_main()?;
11450                input.push(engine.uninit(capacity_tokens * experts.input_width)?);
11451                input_bf16.push(engine.alloc_u8_uninit(2 * capacity_tokens * experts.input_width)?);
11452                input_q8.push(engine.alloc_i8_uninit(capacity_tokens * experts.input_width)?);
11453                input_q8_scales
11454                    .push(engine.uninit(capacity_tokens * experts.input_width.div_ceil(32))?);
11455                sel.push(engine.htod_i32(&vec![0i32; capacity_pairs])?);
11456                token_rows.push(engine.htod_i32(&vec![0i32; capacity_pairs])?);
11457                global_pairs.push(engine.htod_i32(&vec![0i32; capacity_pairs])?);
11458                route_w.push(engine.htod(&vec![0.0f32; capacity_pairs])?);
11459                gate_out.push(engine.uninit(capacity_pairs * experts.expert_width)?);
11460                up_out.push(engine.uninit(capacity_pairs * experts.expert_width)?);
11461                activation_bf16
11462                    .push(engine.alloc_u8_uninit(2 * capacity_pairs * experts.expert_width)?);
11463                activation_q8.push(engine.alloc_i8_uninit(capacity_pairs * experts.expert_width)?);
11464                activation_q8_scales
11465                    .push(engine.uninit(capacity_pairs * experts.expert_width.div_ceil(32))?);
11466                ev_rank.push(engine.ctx().new_event(None)?);
11467                if timing {
11468                    phase_head.push(
11469                        engine.ctx().new_event(Some(
11470                            cudarc::driver::sys::CUevent_flags::CU_EVENT_DEFAULT,
11471                        ))?,
11472                    );
11473                    phase_copy_done.push(
11474                        engine.ctx().new_event(Some(
11475                            cudarc::driver::sys::CUevent_flags::CU_EVENT_DEFAULT,
11476                        ))?,
11477                    );
11478                    phase_gate_up_done.push(
11479                        engine.ctx().new_event(Some(
11480                            cudarc::driver::sys::CUevent_flags::CU_EVENT_DEFAULT,
11481                        ))?,
11482                    );
11483                    phase_activation_done.push(
11484                        engine.ctx().new_event(Some(
11485                            cudarc::driver::sys::CUevent_flags::CU_EVENT_DEFAULT,
11486                        ))?,
11487                    );
11488                    phase_down_done.push(
11489                        engine.ctx().new_event(Some(
11490                            cudarc::driver::sys::CUevent_flags::CU_EVENT_DEFAULT,
11491                        ))?,
11492                    );
11493                }
11494            }
11495            let _main = e.gpu.enter_main()?;
11496            let slot_rows = e.uninit(capacity_pairs * experts.input_width)?;
11497            let slot_rows_raw = {
11498                use cudarc::driver::DevicePtr;
11499                let stream = e.stream();
11500                let (pointer, _guard) = slot_rows.device_ptr(&stream);
11501                pointer
11502            };
11503            *workspace_guard = Some(Nvfp4EpDeviceWorkspace {
11504                input,
11505                input_bf16,
11506                input_q8,
11507                input_q8_scales,
11508                sel,
11509                token_rows,
11510                global_pairs,
11511                route_w,
11512                gate_out,
11513                up_out,
11514                activation_bf16,
11515                activation_q8,
11516                activation_q8_scales,
11517                slot_rows,
11518                slot_rows_raw,
11519                route_weights: e.htod(&vec![0.0f32; capacity_pairs])?,
11520                graph_input: e.uninit(NVFP4_EP_GRAPH_BATCH_CAP * experts.input_width)?,
11521                graph_output: e.uninit(NVFP4_EP_GRAPH_BATCH_CAP * experts.input_width)?,
11522                graph_routes: None,
11523                graphs: std::iter::repeat_with(|| None)
11524                    .take(NVFP4_EP_GRAPH_BATCH_CAP + 1)
11525                    .collect(),
11526                ev_entry: e.ctx().new_event(None)?,
11527                ev_entry_device: e.ctx().ordinal(),
11528                ev_rank,
11529                phase_events: timing.then_some(Nvfp4EpPhaseEvents {
11530                    head: phase_head,
11531                    copy_done: phase_copy_done,
11532                    gate_up_done: phase_gate_up_done,
11533                    activation_done: phase_activation_done,
11534                    down_done: phase_down_done,
11535                }),
11536                capacity_tokens,
11537                experts_per_token,
11538            });
11539        }
11540        let workspace = workspace_guard
11541            .as_mut()
11542            .expect("W4A16 device-routed EP workspace initialized above");
11543        if workspace.experts_per_token != experts_per_token || tokens > workspace.capacity_tokens {
11544            return Err(format!(
11545                "W4A16 device-routed EP workspace tokens={} experts/token={} cannot serve \
11546                 tokens={tokens} experts/token={experts_per_token}",
11547                workspace.capacity_tokens, workspace.experts_per_token,
11548            )
11549            .into());
11550        }
11551
11552        if tokens <= NVFP4_EP_Q8_BATCH_CAP && parallel_ep_q8_act_enabled()? {
11553            if graph_enabled {
11554                return Err("MEMRA_PARALLEL_EP_GRAPH=1 is exact W4A16-only; disable \
11555                     MEMRA_PARALLEL_EP_Q8_ACT or the graph door"
11556                    .into());
11557            }
11558            return self.run_routed_experts_nvfp4_w4a8_device_routed(
11559                experts,
11560                e,
11561                input_dev,
11562                selected_dev,
11563                route_weights_dev,
11564                workspace,
11565                tokens,
11566                experts_per_token,
11567                activation_limit,
11568                pre_join,
11569            );
11570        }
11571
11572        if graph_enabled && !timing && pre_join.is_none() && tokens <= NVFP4_EP_GRAPH_BATCH_CAP {
11573            use cudarc::driver::DevicePtr;
11574            let route_ptrs = {
11575                let stream = e.stream();
11576                let (sel_ptr, _sel_guard) = selected_dev.device_ptr(&stream);
11577                let (weight_ptr, _weight_guard) = route_weights_dev.device_ptr(&stream);
11578                (sel_ptr, weight_ptr)
11579            };
11580            if let Some(graph_exec) = workspace.graphs[tokens].as_ref().map(|graph| graph.exec) {
11581                if workspace.graph_routes != Some(route_ptrs) {
11582                    return Err(format!(
11583                        "W4A16 EP graph route buffers moved: built={:?} current={route_ptrs:?}",
11584                        workspace.graph_routes,
11585                    )
11586                    .into());
11587                }
11588                let _main = e.gpu.enter_main()?;
11589                e.stream().memcpy_dtod(
11590                    &input_dev.slice(0..active_input_values),
11591                    &mut workspace.graph_input.slice_mut(0..active_input_values),
11592                )?;
11593                e.memset_zeros_view(
11594                    &mut workspace
11595                        .slot_rows
11596                        .slice_mut(0..pairs * experts.input_width),
11597                )?;
11598                unsafe {
11599                    let result = cudarc::driver::sys::cuGraphLaunch(
11600                        graph_exec,
11601                        e.stream().cu_stream() as cudarc::driver::sys::CUstream,
11602                    );
11603                    if result != cudarc::driver::sys::CUresult::CUDA_SUCCESS {
11604                        return Err(format!("W4A16 EP graph launch: {result:?}").into());
11605                    }
11606                }
11607                let mut output = e.uninit(active_input_values)?;
11608                e.stream().memcpy_dtod(
11609                    &workspace.graph_output.slice(0..active_input_values),
11610                    &mut output.slice_mut(0..active_input_values),
11611                )?;
11612                return Ok(output);
11613            }
11614        }
11615
11616        {
11617            let _main = e.gpu.enter_main()?;
11618            e.memset_zeros_view(
11619                &mut workspace
11620                    .slot_rows
11621                    .slice_mut(0..pairs * experts.input_width),
11622            )?;
11623            workspace.ev_entry.record(&e.stream())?;
11624        }
11625
11626        for (rank_index, engine) in self.ranks.iter().enumerate() {
11627            let _main = engine.gpu.enter_main()?;
11628            if let Some(events) = workspace.phase_events.as_ref() {
11629                events.head[rank_index].record(&engine.stream())?;
11630            }
11631            engine.stream().wait(&workspace.ev_entry)?;
11632            let Nvfp4EpDeviceWorkspace {
11633                input_bf16,
11634                sel,
11635                route_w,
11636                ..
11637            } = &mut *workspace;
11638            engine.nvfp4_ep_stage_inputs(
11639                input_dev,
11640                selected_dev,
11641                route_weights_dev,
11642                &mut input_bf16[rank_index],
11643                &mut sel[rank_index],
11644                &mut route_w[rank_index],
11645                active_input_values,
11646                pairs,
11647                false,
11648            )?;
11649            if let Some(events) = workspace.phase_events.as_ref() {
11650                events.copy_done[rank_index].record(&engine.stream())?;
11651            }
11652            let rank = &experts.ranks[rank_index];
11653            let owner_start = rank.expert_range.start;
11654            let owner_end = rank.expert_range.end;
11655            engine.qmatvec_nvfp4_bf16_ep_dual_slots_into(
11656                &rank.gate,
11657                &rank.up,
11658                &workspace.sel[rank_index],
11659                &workspace.input_bf16[rank_index],
11660                &mut workspace.gate_out[rank_index],
11661                &mut workspace.up_out[rank_index],
11662                pairs,
11663                experts_per_token,
11664                experts.input_width,
11665                experts.expert_width,
11666                owner_start,
11667                owner_end,
11668                experts.gate_row_bytes,
11669                rank.gate_expert_bytes,
11670            )?;
11671            if let Some(events) = workspace.phase_events.as_ref() {
11672                events.gate_up_done[rank_index].record(&engine.stream())?;
11673            }
11674            engine.silu_mul_scaled_host_expf_bf16_ep_slots_into(
11675                &workspace.gate_out[rank_index],
11676                &workspace.up_out[rank_index],
11677                &rank.macros_gate,
11678                &rank.macros_up,
11679                &workspace.sel[rank_index],
11680                owner_start,
11681                owner_end,
11682                activation_limit,
11683                &mut workspace.activation_bf16[rank_index],
11684                experts.expert_width,
11685                pairs,
11686            )?;
11687            if let Some(events) = workspace.phase_events.as_ref() {
11688                events.activation_done[rank_index].record(&engine.stream())?;
11689            }
11690            if tokens > 1 && pair_down_enabled {
11691                engine.qmatvec_nvfp4_bf16_ep_down_pairs_raw(
11692                    &rank.down,
11693                    &workspace.sel[rank_index],
11694                    &workspace.activation_bf16[rank_index],
11695                    &rank.macros_down,
11696                    workspace.slot_rows_raw,
11697                    pairs,
11698                    experts.expert_width,
11699                    experts.input_width,
11700                    owner_start,
11701                    owner_end,
11702                    experts.down_row_bytes,
11703                    rank.down_expert_bytes,
11704                )?;
11705            } else {
11706                engine.qmatvec_nvfp4_bf16_ep_down_slots_raw(
11707                    &rank.down,
11708                    &workspace.sel[rank_index],
11709                    &workspace.activation_bf16[rank_index],
11710                    &rank.macros_down,
11711                    workspace.slot_rows_raw,
11712                    pairs,
11713                    experts.expert_width,
11714                    experts.input_width,
11715                    owner_start,
11716                    owner_end,
11717                    experts.down_row_bytes,
11718                    rank.down_expert_bytes,
11719                )?;
11720            }
11721            if let Some(events) = workspace.phase_events.as_ref() {
11722                events.down_done[rank_index].record(&engine.stream())?;
11723            }
11724            workspace.ev_rank[rank_index].record(&engine.stream())?;
11725        }
11726
11727        if let Some(pre_join) = pre_join.as_mut() {
11728            pre_join()?;
11729        }
11730        let issue_ns_this = started
11731            .as_ref()
11732            .map(|started| started.elapsed().as_nanos() as u64);
11733        let join_started = timing.then(std::time::Instant::now);
11734        let output = {
11735            let _main = e.gpu.enter_main()?;
11736            for event in &workspace.ev_rank {
11737                e.stream().wait(event)?;
11738            }
11739            let mut output = e.uninit(tokens * experts.input_width)?;
11740            e.axpy_rows_seq_tokens_into(
11741                &workspace.slot_rows,
11742                route_weights_dev,
11743                &mut output,
11744                experts.input_width,
11745                experts_per_token,
11746                tokens,
11747            )?;
11748            output
11749        };
11750
11751        if let Some(started) = started {
11752            use std::sync::atomic::Ordering;
11753            e.stream().synchronize()?;
11754            let elapsed = started.elapsed().as_nanos() as u64;
11755            let join_ns_this = join_started
11756                .expect("timing join starts with total timing")
11757                .elapsed()
11758                .as_nanos() as u64;
11759            let mut phase_max_ms = [0.0f32; 5];
11760            if let Some(events) = workspace.phase_events.as_ref() {
11761                for rank_index in 0..world {
11762                    let engine = &self.ranks[rank_index];
11763                    let _main = engine.gpu.enter_main()?;
11764                    phase_max_ms[0] = phase_max_ms[0]
11765                        .max(events.head[rank_index].elapsed_ms(&events.copy_done[rank_index])?);
11766                    phase_max_ms[1] = phase_max_ms[1].max(
11767                        events.copy_done[rank_index]
11768                            .elapsed_ms(&events.gate_up_done[rank_index])?,
11769                    );
11770                    phase_max_ms[2] = phase_max_ms[2].max(
11771                        events.gate_up_done[rank_index]
11772                            .elapsed_ms(&events.activation_done[rank_index])?,
11773                    );
11774                    phase_max_ms[3] = phase_max_ms[3].max(
11775                        events.activation_done[rank_index]
11776                            .elapsed_ms(&events.down_done[rank_index])?,
11777                    );
11778                    phase_max_ms[4] = phase_max_ms[4]
11779                        .max(events.head[rank_index].elapsed_ms(&events.down_done[rank_index])?);
11780                }
11781            }
11782            let phase_ns = phase_max_ms.map(|ms| (ms as f64 * 1.0e6) as u64);
11783            let ns = TIMING_NS.fetch_add(elapsed, Ordering::Relaxed) + elapsed;
11784            let issue_ns = ISSUE_NS.fetch_add(
11785                issue_ns_this.expect("timing issue starts with total timing"),
11786                Ordering::Relaxed,
11787            ) + issue_ns_this.expect("timing issue starts with total timing");
11788            let join_ns = JOIN_NS.fetch_add(join_ns_this, Ordering::Relaxed) + join_ns_this;
11789            let copy_ns = COPY_NS.fetch_add(phase_ns[0], Ordering::Relaxed) + phase_ns[0];
11790            let gate_up_ns = GATE_UP_NS.fetch_add(phase_ns[1], Ordering::Relaxed) + phase_ns[1];
11791            let activation_ns =
11792                ACTIVATION_NS.fetch_add(phase_ns[2], Ordering::Relaxed) + phase_ns[2];
11793            let down_ns = DOWN_NS.fetch_add(phase_ns[3], Ordering::Relaxed) + phase_ns[3];
11794            let rank_span_ns = RANK_SPAN_NS.fetch_add(phase_ns[4], Ordering::Relaxed) + phase_ns[4];
11795            let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
11796            if calls.is_multiple_of(430) {
11797                eprintln!(
11798                    "[nvfp4-ep-device-router-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
11799                    ns as f64 / 1.0e6,
11800                    ns as f64 / calls as f64 / 1.0e3,
11801                );
11802                eprintln!(
11803                    "[nvfp4-ep-device-router-phases] calls={calls} issue_us={:.1} \
11804                     join_us={:.1} rank_span_us={:.1} copy_us={:.1} gate_up_us={:.1} \
11805                     activation_us={:.1} down_us={:.1}",
11806                    issue_ns as f64 / calls as f64 / 1.0e3,
11807                    join_ns as f64 / calls as f64 / 1.0e3,
11808                    rank_span_ns as f64 / calls as f64 / 1.0e3,
11809                    copy_ns as f64 / calls as f64 / 1.0e3,
11810                    gate_up_ns as f64 / calls as f64 / 1.0e3,
11811                    activation_ns as f64 / calls as f64 / 1.0e3,
11812                    down_ns as f64 / calls as f64 / 1.0e3,
11813                );
11814            }
11815        }
11816        if graph_enabled
11817            && !timing
11818            && pre_join.is_none()
11819            && tokens <= NVFP4_EP_GRAPH_BATCH_CAP
11820            && workspace.graphs[tokens].is_none()
11821        {
11822            e.stream().synchronize()?;
11823            let graph = self.build_nvfp4_ep_routes_graph(
11824                experts,
11825                e,
11826                workspace,
11827                selected_dev,
11828                route_weights_dev,
11829                tokens,
11830                experts_per_token,
11831                activation_limit,
11832            )?;
11833            workspace.graphs[tokens] = Some(graph);
11834            eprintln!(
11835                "[parallel-ep-graph] captured devices={:?} tokens={tokens} \
11836                 experts/token={experts_per_token} input=staged routes=fixed \
11837                 device_arithmetic=unchanged performance_claim=false",
11838                self.devices,
11839            );
11840        }
11841        Ok(output)
11842    }
11843
11844    #[allow(clippy::too_many_arguments)]
11845    fn run_routed_experts_nvfp4_w4a8_device_routed(
11846        &self,
11847        experts: &ResidentNvfp4ExpertParallel,
11848        e: &Engine,
11849        input_dev: &crate::CudaSlice<f32>,
11850        selected_dev: &crate::CudaSlice<i32>,
11851        route_weights_dev: &crate::CudaSlice<f32>,
11852        workspace: &mut Nvfp4EpDeviceWorkspace,
11853        tokens: usize,
11854        experts_per_token: usize,
11855        activation_limit: Option<f32>,
11856        mut pre_join: Option<&mut dyn FnMut() -> Result<(), Box<dyn std::error::Error>>>,
11857    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
11858        static TIMING_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11859        static TIMING_CALLS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11860        static ISSUE_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11861        static JOIN_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11862        static COPY_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11863        static GATE_UP_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11864        static ACTIVATION_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11865        static DOWN_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11866        static RANK_SPAN_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11867        let timing = std::env::var("MEMRA_STEP_TP_TIMING").as_deref() == Ok("1");
11868        let started = timing.then(std::time::Instant::now);
11869        let pairs = tokens
11870            .checked_mul(experts_per_token)
11871            .ok_or("W4A8 device-routed EP route count overflow")?;
11872        let input_values = tokens
11873            .checked_mul(experts.input_width)
11874            .ok_or("W4A8 device-routed EP input size overflow")?;
11875        let scope = parallel_ep_q8_scope()?.unwrap_or(ParallelEpQ8Scope::All);
11876        let gate_up_paired = parallel_ep_q8_gu_paired_enabled(true, Some(scope))?;
11877
11878        {
11879            let _main = e.gpu.enter_main()?;
11880            e.memset_zeros_view(
11881                &mut workspace
11882                    .slot_rows
11883                    .slice_mut(0..pairs * experts.input_width),
11884            )?;
11885            workspace.ev_entry.record(&e.stream())?;
11886        }
11887        for (rank_index, engine) in self.ranks.iter().enumerate() {
11888            let _main = engine.gpu.enter_main()?;
11889            if let Some(events) = workspace.phase_events.as_ref() {
11890                events.head[rank_index].record(&engine.stream())?;
11891            }
11892            engine.stream().wait(&workspace.ev_entry)?;
11893            let rank = &experts.ranks[rank_index];
11894            let owner_start = rank.expert_range.start;
11895            let owner_end = rank.expert_range.end;
11896            match scope {
11897                ParallelEpQ8Scope::All | ParallelEpQ8Scope::GateUp => {
11898                    engine.quantize_q8_1_into(
11899                        input_dev,
11900                        tokens,
11901                        experts.input_width,
11902                        &mut workspace.input_q8[rank_index],
11903                        &mut workspace.input_q8_scales[rank_index],
11904                    )?;
11905                    engine.moe_sel_w_mirror(
11906                        selected_dev,
11907                        route_weights_dev,
11908                        &mut workspace.sel[rank_index],
11909                        &mut workspace.route_w[rank_index],
11910                        pairs,
11911                    )?;
11912                    if let Some(events) = workspace.phase_events.as_ref() {
11913                        events.copy_done[rank_index].record(&engine.stream())?;
11914                    }
11915                    if gate_up_paired {
11916                        engine.qmatvec_nvfp4_q8_ep_paired_slots_into(
11917                            &rank.gate,
11918                            &rank.up,
11919                            &workspace.sel[rank_index],
11920                            &workspace.input_q8[rank_index],
11921                            &workspace.input_q8_scales[rank_index],
11922                            &mut workspace.gate_out[rank_index],
11923                            &mut workspace.up_out[rank_index],
11924                            pairs,
11925                            experts_per_token,
11926                            experts.input_width,
11927                            experts.expert_width,
11928                            owner_start,
11929                            owner_end,
11930                            experts.gate_row_bytes,
11931                            rank.gate_expert_bytes,
11932                        )?;
11933                    } else {
11934                        engine.qmatvec_nvfp4_q8_ep_dual_slots_into(
11935                            &rank.gate,
11936                            &rank.up,
11937                            &workspace.sel[rank_index],
11938                            &workspace.input_q8[rank_index],
11939                            &workspace.input_q8_scales[rank_index],
11940                            &mut workspace.gate_out[rank_index],
11941                            &mut workspace.up_out[rank_index],
11942                            pairs,
11943                            experts_per_token,
11944                            experts.input_width,
11945                            experts.expert_width,
11946                            owner_start,
11947                            owner_end,
11948                            experts.gate_row_bytes,
11949                            rank.gate_expert_bytes,
11950                        )?;
11951                    }
11952                }
11953                ParallelEpQ8Scope::Down => {
11954                    engine.nvfp4_ep_stage_inputs(
11955                        input_dev,
11956                        selected_dev,
11957                        route_weights_dev,
11958                        &mut workspace.input_bf16[rank_index],
11959                        &mut workspace.sel[rank_index],
11960                        &mut workspace.route_w[rank_index],
11961                        input_values,
11962                        pairs,
11963                        false,
11964                    )?;
11965                    if let Some(events) = workspace.phase_events.as_ref() {
11966                        events.copy_done[rank_index].record(&engine.stream())?;
11967                    }
11968                    engine.qmatvec_nvfp4_bf16_ep_dual_slots_into(
11969                        &rank.gate,
11970                        &rank.up,
11971                        &workspace.sel[rank_index],
11972                        &workspace.input_bf16[rank_index],
11973                        &mut workspace.gate_out[rank_index],
11974                        &mut workspace.up_out[rank_index],
11975                        pairs,
11976                        experts_per_token,
11977                        experts.input_width,
11978                        experts.expert_width,
11979                        owner_start,
11980                        owner_end,
11981                        experts.gate_row_bytes,
11982                        rank.gate_expert_bytes,
11983                    )?;
11984                }
11985            }
11986            if let Some(events) = workspace.phase_events.as_ref() {
11987                events.gate_up_done[rank_index].record(&engine.stream())?;
11988            }
11989            match scope {
11990                ParallelEpQ8Scope::All | ParallelEpQ8Scope::Down => {
11991                    engine.silu_mul_scaled_host_expf_q8_ep_slots_into(
11992                        &workspace.gate_out[rank_index],
11993                        &workspace.up_out[rank_index],
11994                        &rank.macros_gate,
11995                        &rank.macros_up,
11996                        &workspace.sel[rank_index],
11997                        owner_start,
11998                        owner_end,
11999                        activation_limit,
12000                        &mut workspace.activation_q8[rank_index],
12001                        &mut workspace.activation_q8_scales[rank_index],
12002                        experts.expert_width,
12003                        pairs,
12004                    )?;
12005                    if let Some(events) = workspace.phase_events.as_ref() {
12006                        events.activation_done[rank_index].record(&engine.stream())?;
12007                    }
12008                    engine.qmatvec_nvfp4_q8_ep_down_slots_raw(
12009                        &rank.down,
12010                        &workspace.sel[rank_index],
12011                        &workspace.activation_q8[rank_index],
12012                        &workspace.activation_q8_scales[rank_index],
12013                        &rank.macros_down,
12014                        workspace.slot_rows_raw,
12015                        pairs,
12016                        experts.expert_width,
12017                        experts.input_width,
12018                        owner_start,
12019                        owner_end,
12020                        experts.down_row_bytes,
12021                        rank.down_expert_bytes,
12022                    )?;
12023                }
12024                ParallelEpQ8Scope::GateUp => {
12025                    engine.silu_mul_scaled_host_expf_bf16_ep_slots_into(
12026                        &workspace.gate_out[rank_index],
12027                        &workspace.up_out[rank_index],
12028                        &rank.macros_gate,
12029                        &rank.macros_up,
12030                        &workspace.sel[rank_index],
12031                        owner_start,
12032                        owner_end,
12033                        activation_limit,
12034                        &mut workspace.activation_bf16[rank_index],
12035                        experts.expert_width,
12036                        pairs,
12037                    )?;
12038                    if let Some(events) = workspace.phase_events.as_ref() {
12039                        events.activation_done[rank_index].record(&engine.stream())?;
12040                    }
12041                    engine.qmatvec_nvfp4_bf16_ep_down_slots_raw(
12042                        &rank.down,
12043                        &workspace.sel[rank_index],
12044                        &workspace.activation_bf16[rank_index],
12045                        &rank.macros_down,
12046                        workspace.slot_rows_raw,
12047                        pairs,
12048                        experts.expert_width,
12049                        experts.input_width,
12050                        owner_start,
12051                        owner_end,
12052                        experts.down_row_bytes,
12053                        rank.down_expert_bytes,
12054                    )?;
12055                }
12056            }
12057            if let Some(events) = workspace.phase_events.as_ref() {
12058                events.down_done[rank_index].record(&engine.stream())?;
12059            }
12060            workspace.ev_rank[rank_index].record(&engine.stream())?;
12061        }
12062
12063        if let Some(pre_join) = pre_join.as_mut() {
12064            pre_join()?;
12065        }
12066        let issue_ns_this = started
12067            .as_ref()
12068            .map(|started| started.elapsed().as_nanos() as u64);
12069        let join_started = timing.then(std::time::Instant::now);
12070        let output = {
12071            let _main = e.gpu.enter_main()?;
12072            for event in &workspace.ev_rank {
12073                e.stream().wait(event)?;
12074            }
12075            let mut output = e.uninit(input_values)?;
12076            e.axpy_rows_seq_tokens_into(
12077                &workspace.slot_rows,
12078                route_weights_dev,
12079                &mut output,
12080                experts.input_width,
12081                experts_per_token,
12082                tokens,
12083            )?;
12084            output
12085        };
12086        if let Some(started) = started {
12087            use std::sync::atomic::Ordering;
12088            e.stream().synchronize()?;
12089            let elapsed = started.elapsed().as_nanos() as u64;
12090            let join_ns_this = join_started
12091                .expect("timing join starts with total timing")
12092                .elapsed()
12093                .as_nanos() as u64;
12094            let mut phase_max_ms = [0.0f32; 5];
12095            if let Some(events) = workspace.phase_events.as_ref() {
12096                for rank_index in 0..self.ranks.len() {
12097                    let engine = &self.ranks[rank_index];
12098                    let _main = engine.gpu.enter_main()?;
12099                    phase_max_ms[0] = phase_max_ms[0]
12100                        .max(events.head[rank_index].elapsed_ms(&events.copy_done[rank_index])?);
12101                    phase_max_ms[1] = phase_max_ms[1].max(
12102                        events.copy_done[rank_index]
12103                            .elapsed_ms(&events.gate_up_done[rank_index])?,
12104                    );
12105                    phase_max_ms[2] = phase_max_ms[2].max(
12106                        events.gate_up_done[rank_index]
12107                            .elapsed_ms(&events.activation_done[rank_index])?,
12108                    );
12109                    phase_max_ms[3] = phase_max_ms[3].max(
12110                        events.activation_done[rank_index]
12111                            .elapsed_ms(&events.down_done[rank_index])?,
12112                    );
12113                    phase_max_ms[4] = phase_max_ms[4]
12114                        .max(events.head[rank_index].elapsed_ms(&events.down_done[rank_index])?);
12115                }
12116            }
12117            let phase_ns = phase_max_ms.map(|ms| (ms as f64 * 1.0e6) as u64);
12118            let ns = TIMING_NS.fetch_add(elapsed, Ordering::Relaxed) + elapsed;
12119            let issue_ns = ISSUE_NS.fetch_add(
12120                issue_ns_this.expect("timing issue starts with total timing"),
12121                Ordering::Relaxed,
12122            ) + issue_ns_this.expect("timing issue starts with total timing");
12123            let join_ns = JOIN_NS.fetch_add(join_ns_this, Ordering::Relaxed) + join_ns_this;
12124            let copy_ns = COPY_NS.fetch_add(phase_ns[0], Ordering::Relaxed) + phase_ns[0];
12125            let gate_up_ns = GATE_UP_NS.fetch_add(phase_ns[1], Ordering::Relaxed) + phase_ns[1];
12126            let activation_ns =
12127                ACTIVATION_NS.fetch_add(phase_ns[2], Ordering::Relaxed) + phase_ns[2];
12128            let down_ns = DOWN_NS.fetch_add(phase_ns[3], Ordering::Relaxed) + phase_ns[3];
12129            let rank_span_ns = RANK_SPAN_NS.fetch_add(phase_ns[4], Ordering::Relaxed) + phase_ns[4];
12130            let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
12131            if calls.is_multiple_of(430) {
12132                eprintln!(
12133                    "[nvfp4-ep-q8-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
12134                    ns as f64 / 1.0e6,
12135                    ns as f64 / calls as f64 / 1.0e3,
12136                );
12137                eprintln!(
12138                    "[nvfp4-ep-q8-phases] calls={calls} issue_us={:.1} join_us={:.1} \
12139                     rank_span_us={:.1} copy_us={:.1} gate_up_us={:.1} \
12140                     activation_us={:.1} down_us={:.1}",
12141                    issue_ns as f64 / calls as f64 / 1.0e3,
12142                    join_ns as f64 / calls as f64 / 1.0e3,
12143                    rank_span_ns as f64 / calls as f64 / 1.0e3,
12144                    copy_ns as f64 / calls as f64 / 1.0e3,
12145                    gate_up_ns as f64 / calls as f64 / 1.0e3,
12146                    activation_ns as f64 / calls as f64 / 1.0e3,
12147                    down_ns as f64 / calls as f64 / 1.0e3,
12148                );
12149            }
12150        }
12151        static LOGGED: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
12152        if !LOGGED.swap(true, std::sync::atomic::Ordering::Relaxed) {
12153            let (expert_input, post_activation, numeric_class) = match scope {
12154                ParallelEpQ8Scope::All => ("q8_1", "q8_1", "w4a8-internal"),
12155                ParallelEpQ8Scope::GateUp => ("q8_1", "bf16", "w4a8-gate-up-internal"),
12156                ParallelEpQ8Scope::Down => ("bf16", "q8_1", "w4a8-down-internal"),
12157            };
12158            eprintln!(
12159                "[parallel-ep-q8] devices={:?} tokens={tokens} scope={} \
12160                 expert_input={expert_input} post_activation={post_activation} \
12161                 gate_up_schedule={} \
12162                 external_boundary=bf16 numeric_class={numeric_class} \
12163                 host_expf=true accumulation=token-slot-order performance_claim=false",
12164                self.devices,
12165                scope.label(),
12166                if gate_up_paired {
12167                    "paired-cta"
12168                } else {
12169                    "separate-cta"
12170                },
12171            );
12172        }
12173        Ok(output)
12174    }
12175
12176    #[allow(clippy::too_many_arguments)]
12177    fn build_nvfp4_ep_routes_graph(
12178        &self,
12179        experts: &ResidentNvfp4ExpertParallel,
12180        e: &Engine,
12181        workspace: &mut Nvfp4EpDeviceWorkspace,
12182        selected_dev: &crate::CudaSlice<i32>,
12183        route_weights_dev: &crate::CudaSlice<f32>,
12184        tokens: usize,
12185        experts_per_token: usize,
12186        activation_limit: Option<f32>,
12187    ) -> Result<RoutesGraph, Box<dyn std::error::Error>> {
12188        use cudarc::driver::DevicePtr;
12189        use cudarc::driver::sys;
12190
12191        fn cu_try(result: sys::CUresult, context: &str) -> Result<(), Box<dyn std::error::Error>> {
12192            if result == sys::CUresult::CUDA_SUCCESS {
12193                Ok(())
12194            } else {
12195                Err(format!("{context}: {result:?}").into())
12196            }
12197        }
12198
12199        let world = self.ranks.len();
12200        if world != experts.ranks.len() || !(2..=PRODUCT_MAX_CARDS).contains(&world) {
12201            return Err(format!(
12202                "W4A16 EP graph world {world} != expert ranks {}",
12203                experts.ranks.len()
12204            )
12205            .into());
12206        }
12207        let width = experts.input_width;
12208        if !(1..=NVFP4_EP_GRAPH_BATCH_CAP).contains(&tokens) {
12209            return Err(format!(
12210                "W4A16 EP graph tokens {tokens} outside 1..={NVFP4_EP_GRAPH_BATCH_CAP}"
12211            )
12212            .into());
12213        }
12214        let pairs = tokens
12215            .checked_mul(experts_per_token)
12216            .ok_or("W4A16 EP graph pair count overflow")?;
12217        let input_values = tokens
12218            .checked_mul(width)
12219            .ok_or("W4A16 EP graph input size overflow")?;
12220        let root_stream = e.stream();
12221        let (input_ptr, _input_guard) = workspace.graph_input.device_ptr(&root_stream);
12222        let (selected_ptr, _selected_guard) = selected_dev.device_ptr(&root_stream);
12223        let (weights_ptr, _weights_guard) = route_weights_dev.device_ptr(&root_stream);
12224        let route_ptrs = (selected_ptr, weights_ptr);
12225
12226        let mut children = Vec::with_capacity(world + 1);
12227        for rank_index in 0..world {
12228            let engine = &self.ranks[rank_index];
12229            let rank = &experts.ranks[rank_index];
12230            let owner_start = rank.expert_range.start;
12231            let owner_end = rank.expert_range.end;
12232            let _main = engine.gpu.enter_main()?;
12233            let (child, _retained) = engine.capture_graph_retained(|_| {
12234                engine.nvfp4_ep_stage_inputs_raw(
12235                    input_ptr,
12236                    selected_ptr,
12237                    weights_ptr,
12238                    &mut workspace.input_bf16[rank_index],
12239                    &mut workspace.sel[rank_index],
12240                    &mut workspace.route_w[rank_index],
12241                    input_values,
12242                    pairs,
12243                    false,
12244                )?;
12245                engine.qmatvec_nvfp4_bf16_ep_dual_slots_into(
12246                    &rank.gate,
12247                    &rank.up,
12248                    &workspace.sel[rank_index],
12249                    &workspace.input_bf16[rank_index],
12250                    &mut workspace.gate_out[rank_index],
12251                    &mut workspace.up_out[rank_index],
12252                    pairs,
12253                    experts_per_token,
12254                    width,
12255                    experts.expert_width,
12256                    owner_start,
12257                    owner_end,
12258                    experts.gate_row_bytes,
12259                    rank.gate_expert_bytes,
12260                )?;
12261                engine.silu_mul_scaled_host_expf_bf16_ep_slots_into(
12262                    &workspace.gate_out[rank_index],
12263                    &workspace.up_out[rank_index],
12264                    &rank.macros_gate,
12265                    &rank.macros_up,
12266                    &workspace.sel[rank_index],
12267                    owner_start,
12268                    owner_end,
12269                    activation_limit,
12270                    &mut workspace.activation_bf16[rank_index],
12271                    experts.expert_width,
12272                    pairs,
12273                )?;
12274                engine.qmatvec_nvfp4_bf16_ep_down_slots_raw(
12275                    &rank.down,
12276                    &workspace.sel[rank_index],
12277                    &workspace.activation_bf16[rank_index],
12278                    &rank.macros_down,
12279                    workspace.slot_rows_raw,
12280                    pairs,
12281                    experts.expert_width,
12282                    width,
12283                    owner_start,
12284                    owner_end,
12285                    experts.down_row_bytes,
12286                    rank.down_expert_bytes,
12287                )?;
12288                Ok(())
12289            })?;
12290            children.push(child);
12291        }
12292
12293        {
12294            let _main = e.gpu.enter_main()?;
12295            let (child, _retained) = e.capture_graph_retained(|_| {
12296                e.axpy_rows_seq_tokens_into(
12297                    &workspace.slot_rows,
12298                    route_weights_dev,
12299                    &mut workspace.graph_output,
12300                    width,
12301                    experts_per_token,
12302                    tokens,
12303                )
12304            })?;
12305            children.push(child);
12306        }
12307
12308        let mut parent: sys::CUgraph = std::ptr::null_mut();
12309        unsafe {
12310            cu_try(sys::cuGraphCreate(&mut parent, 0), "W4A16 EP cuGraphCreate")?;
12311        }
12312        let mut rank_nodes = Vec::with_capacity(world);
12313        for (rank_index, child) in children.iter().take(world).enumerate() {
12314            let mut node: sys::CUgraphNode = std::ptr::null_mut();
12315            unsafe {
12316                cu_try(
12317                    sys::cuGraphAddChildGraphNode(
12318                        &mut node,
12319                        parent,
12320                        std::ptr::null(),
12321                        0,
12322                        child.cu_graph(),
12323                    ),
12324                    &format!("W4A16 EP graph rank {rank_index}"),
12325                )?;
12326            }
12327            rank_nodes.push(node);
12328        }
12329        let mut combine_node: sys::CUgraphNode = std::ptr::null_mut();
12330        unsafe {
12331            cu_try(
12332                sys::cuGraphAddChildGraphNode(
12333                    &mut combine_node,
12334                    parent,
12335                    rank_nodes.as_ptr(),
12336                    rank_nodes.len(),
12337                    children[world].cu_graph(),
12338                ),
12339                "W4A16 EP graph combine",
12340            )?;
12341        }
12342        let mut exec: sys::CUgraphExec = std::ptr::null_mut();
12343        unsafe {
12344            cu_try(
12345                sys::cuGraphInstantiateWithFlags(&mut exec, parent, 0),
12346                "W4A16 EP graph instantiate",
12347            )?;
12348        }
12349        workspace.graph_routes = Some(route_ptrs);
12350        Ok(RoutesGraph {
12351            exec,
12352            parent,
12353            _children: children,
12354        })
12355    }
12356
12357    /// Device-resident routed NVFP4 expert program (decode shape, t=1 rows). The geometry gift
12358    /// this exploits: gate/up column halves land on the SAME rank that owns the matching down
12359    /// canonical shard (act[rank r] is exactly down-shard r's input-column window), so the whole
12360    /// expert interior — gate, up, macro-scaled SwiGLU, down partial, route-weighted accumulate —
12361    /// runs rank-local with ZERO cross-rank transfer. Per (token, layer): one input upload per
12362    /// rank, one fenced peer copy of the remote accumulator, one root add, one readback.
12363    ///
12364    /// Numeric class: device silu (silu_mul_scaled) with gate/up macros folded as gs/us and the
12365    /// down macro folded into the accumulate scalar (weight * macro_down — exact, both are
12366    /// per-expert constants). This matches the owning-stage MoE dev-path semantics, NOT the
12367    /// host-canonical program bit-for-bit; gate it with argmax + relative bounds against the
12368    /// host-canonical oracle, and with repeat determinism against itself.
12369    /// Clamped layers refuse (they stay on the EP program).
12370    pub fn run_tensor_parallel_routes_nvfp4_device(
12371        &self,
12372        experts: &ResidentNvfp4TensorParallel,
12373        input: &[f32],
12374        selected: &[usize],
12375        route_weights: &[f32],
12376        experts_per_token: usize,
12377        activation_limit: Option<f32>,
12378    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
12379        validate_activations(input, 1, experts.input_width)?;
12380        if selected.len() != experts_per_token || route_weights.len() != experts_per_token {
12381            return Err(format!(
12382                "NVFP4 device routes selected={} weights={} != experts/token {experts_per_token}",
12383                selected.len(),
12384                route_weights.len(),
12385            )
12386            .into());
12387        }
12388        if !route_weights.iter().all(|weight| weight.is_finite()) {
12389            return Err("NVFP4 device route weights contain a non-finite value".into());
12390        }
12391        let world = self.ranks.len();
12392        if world != NVFP4_CANONICAL_ROW_SHARDS {
12393            return Err(format!(
12394                "NVFP4 device routes require world == canonical shard grid \
12395                 ({NVFP4_CANONICAL_ROW_SHARDS}), got {world}"
12396            )
12397            .into());
12398        }
12399        let local_out = if experts.ep2 {
12400            experts.expert_width
12401        } else {
12402            experts.expert_width / world
12403        };
12404
12405        // MEMRA_STEP_TP_TIMING=1: cumulative wall-clock of this program, printed every 430 calls
12406        // (~one 43-layer decode step's worth) so a bench run decomposes expert-program time vs
12407        // everything else without Nsight.
12408        static TIMING_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
12409        static TIMING_CALLS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
12410        let timing = std::env::var("MEMRA_STEP_TP_TIMING").as_deref() == Ok("1");
12411        let started = timing.then(std::time::Instant::now);
12412
12413        let n_sel = experts_per_token;
12414        let mut workspace_guard = experts
12415            .device_workspace
12416            .lock()
12417            .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
12418        if workspace_guard.is_none() {
12419            let mut gate_out = Vec::with_capacity(world);
12420            let mut up_out = Vec::with_capacity(world);
12421            let mut act_q = Vec::with_capacity(world);
12422            let mut act_d = Vec::with_capacity(world);
12423            let mut sel = Vec::with_capacity(world);
12424            let mut partial = Vec::with_capacity(world);
12425            let mut accumulator = Vec::with_capacity(world);
12426            let mut combine_w = Vec::with_capacity(world);
12427            let mut route_w = Vec::with_capacity(world);
12428            let mut in_q = Vec::with_capacity(world);
12429            let mut in_d = Vec::with_capacity(world);
12430            let mut input = Vec::with_capacity(world);
12431            let mut ev_rank = Vec::with_capacity(world);
12432            let moe_direct = moe_direct_on();
12433            for (rank, engine) in self.ranks.iter().enumerate() {
12434                let _main = engine.gpu.enter_main()?;
12435                gate_out.push(engine.uninit(n_sel * local_out)?);
12436                up_out.push(engine.uninit(n_sel * local_out)?);
12437                act_q.push(engine.uninit_i8(n_sel * local_out)?);
12438                act_d.push(engine.uninit(n_sel * local_out / 32)?);
12439                sel.push(engine.htod_i32(&vec![0i32; n_sel])?);
12440                partial.push(engine.uninit(n_sel * experts.input_width)?);
12441                // Direct join: peer accumulators live on ROOT (single P2P store pass).
12442                if moe_direct && rank != 0 {
12443                    let root = &self.ranks[0];
12444                    let _root_main = root.gpu.enter_main()?;
12445                    accumulator.push(root.zeros(experts.input_width)?);
12446                } else {
12447                    accumulator.push(engine.zeros(experts.input_width)?);
12448                }
12449                combine_w.push(engine.htod(&vec![0.0f32; n_sel])?);
12450                route_w.push(engine.htod(&vec![0.0f32; n_sel])?);
12451                in_q.push(engine.uninit_i8(experts.input_width)?);
12452                in_d.push(engine.uninit(experts.input_width / 32)?);
12453                input.push(engine.uninit(experts.input_width)?);
12454                ev_rank.push(engine.ctx().new_event(None)?);
12455            }
12456            let root = &self.ranks[0];
12457            let _main = root.gpu.enter_main()?;
12458            *workspace_guard = Some(Nvfp4DeviceRoutesWorkspace {
12459                prestaged: false,
12460                rank1_routed: false,
12461                ev_input: None,
12462                fence_flags_raw: 0,
12463                fence_ticket: 0,
12464                gate_out,
12465                up_out,
12466                act_q,
12467                act_d,
12468                sel,
12469                partial,
12470                accumulator,
12471                combine_w,
12472                route_w,
12473                in_q,
12474                in_d,
12475                dev_route_e: None,
12476                in_stage_e: None,
12477                out_stage_e: None,
12478                routes_graph: None,
12479                raw_dev_route_e: None,
12480                raw_combine: None,
12481                raw_input: Vec::new(),
12482                raw_sel: Vec::new(),
12483                raw_route_w: Vec::new(),
12484                remote: root.uninit(experts.input_width)?,
12485                combined: root.uninit(experts.input_width)?,
12486                n_sel,
12487                input,
12488                ev_rank,
12489                ev_done: Some(root.ctx().new_event(None)?),
12490                ev_entry: None,
12491            });
12492        }
12493        let workspace = workspace_guard
12494            .as_mut()
12495            .expect("NVFP4 device routes workspace initialized above");
12496        // EP2 uses this call only as the workspace-arming warmup (the prejoin path drives
12497        // decode); its host-routed sweep semantics do not apply to whole-expert banks.
12498        if experts.ep2 {
12499            return Ok(vec![0.0f32; experts.input_width]);
12500        }
12501        if workspace.n_sel != n_sel {
12502            return Err(format!(
12503                "NVFP4 device routes experts/token changed: workspace {} != call {n_sel}",
12504                workspace.n_sel
12505            )
12506            .into());
12507        }
12508        for &expert in selected {
12509            if expert >= experts.expert_count {
12510                return Err(format!(
12511                    "NVFP4 device selected expert {expert} outside 0..{}",
12512                    experts.expert_count
12513                )
12514                .into());
12515            }
12516        }
12517        let sel_i32 = selected
12518            .iter()
12519            .map(|&expert| expert as i32)
12520            .collect::<Vec<_>>();
12521
12522        // BATCHED program (2026-08-20): per rank, ONE launch per sweep (gate, up, SwiGLU,
12523        // down) covers every selected expert via the selection array and the contiguous bank —
12524        // the per-expert launch loop was pure host latency (~100 sequential launches/layer,
12525        // 291us wall for ~35us of arithmetic). Per (expert, row) the kernels are bit-identical
12526        // to the per-expert forms, and the route-weight axpy chain keeps its exact sequential
12527        // accumulation order — the program's values are unchanged.
12528        for (rank_index, engine) in self.ranks.iter().enumerate() {
12529            let _main = engine.gpu.enter_main()?;
12530            let device_input = engine.htod(input)?;
12531            let Nvfp4DeviceRoutesWorkspace { in_q, in_d, .. } = &mut *workspace;
12532            engine.quantize_q8_1_into(
12533                &device_input,
12534                1,
12535                experts.input_width,
12536                &mut in_q[rank_index],
12537                &mut in_d[rank_index],
12538            )?;
12539            // device_input frees on this rank's stream after the quantize — same-stream order.
12540        }
12541        self.nvfp4_routes_batched_sweeps(
12542            experts,
12543            workspace,
12544            selected,
12545            route_weights,
12546            &sel_i32,
12547            local_out,
12548            n_sel,
12549            activation_limit,
12550            false,
12551        )?;
12552
12553        // Combine: fence the remote shard's producer stream, peer-copy its accumulator to root,
12554        // reduce in canonical shard order, read back once.
12555        let root = &self.ranks[0];
12556        for engine in &self.ranks[1..] {
12557            let _main = engine.gpu.enter_main()?;
12558            engine.stream().synchronize()?;
12559        }
12560        let _main = root.gpu.enter_main()?;
12561        root.stream()
12562            .memcpy_dtod(&workspace.accumulator[1], &mut workspace.remote)?;
12563        root.add(
12564            &workspace.accumulator[0],
12565            &workspace.remote,
12566            &mut workspace.combined,
12567            experts.input_width,
12568        )?;
12569        let output = root.dtoh(&workspace.combined)?;
12570        if let Some(started) = started {
12571            use std::sync::atomic::Ordering;
12572            let ns = TIMING_NS.fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
12573                + started.elapsed().as_nanos() as u64;
12574            let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
12575            if calls.is_multiple_of(430) {
12576                eprintln!(
12577                    "[nvfp4-dev-routes-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
12578                    ns as f64 / 1.0e6,
12579                    ns as f64 / calls as f64 / 1.0e3,
12580                );
12581            }
12582        }
12583        Ok(output)
12584    }
12585
12586    /// The shared batched sweeps of the device routes program: per rank, upload the selection,
12587    /// reset the accumulator, run the gate/up/SwiGLU/down batched launches, then the
12588    /// route-weight axpy chain in exact sequential per-pair order. Every op queues on the
12589    /// owning rank's stream; callers own input acquisition and the combine.
12590    #[allow(clippy::too_many_arguments)]
12591    fn nvfp4_routes_batched_sweeps(
12592        &self,
12593        experts: &ResidentNvfp4TensorParallel,
12594        workspace: &mut Nvfp4DeviceRoutesWorkspace,
12595        selected: &[usize],
12596        route_weights: &[f32],
12597        sel_i32: &[i32],
12598        local_out: usize,
12599        n_sel: usize,
12600        activation_limit: Option<f32>,
12601        device_routed: bool,
12602    ) -> Result<(), Box<dyn std::error::Error>> {
12603        for rank_index in 0..self.ranks.len() {
12604            self.nvfp4_routes_batched_sweeps_rank(
12605                experts,
12606                workspace,
12607                selected,
12608                route_weights,
12609                sel_i32,
12610                local_out,
12611                n_sel,
12612                activation_limit,
12613                device_routed,
12614                rank_index,
12615            )?;
12616        }
12617        Ok(())
12618    }
12619
12620    /// One rank's sweeps (the per-rank body of `nvfp4_routes_batched_sweeps`) — separated so
12621    /// the graph door can capture each rank's segment on its own stream.
12622    #[allow(clippy::too_many_arguments)]
12623    fn nvfp4_routes_batched_sweeps_rank(
12624        &self,
12625        experts: &ResidentNvfp4TensorParallel,
12626        workspace: &mut Nvfp4DeviceRoutesWorkspace,
12627        selected: &[usize],
12628        route_weights: &[f32],
12629        sel_i32: &[i32],
12630        local_out: usize,
12631        n_sel: usize,
12632        activation_limit: Option<f32>,
12633        device_routed: bool,
12634        rank_index: usize,
12635    ) -> Result<(), Box<dyn std::error::Error>> {
12636        {
12637            let engine = &self.ranks[rank_index];
12638            let _main = engine.gpu.enter_main()?;
12639            // EP2: whole-expert full-width sweep, owner-guarded; down+combine fused writes
12640            // this rank's slot-ordered partial straight into its accumulator (the join is
12641            // unchanged). Device-routed only — the host-routed arm and the graph door refuse
12642            // at the caller.
12643            if experts.ep2 {
12644                if !device_routed {
12645                    return Err("NVFP4 EP2 banks support the device-routed decode arm only".into());
12646                }
12647                let gate_bank = &experts.gate[rank_index];
12648                let up_bank = &experts.up[rank_index];
12649                if gate_bank.local_out != experts.expert_width
12650                    || gate_bank.expert_bytes != up_bank.expert_bytes
12651                {
12652                    return Err("NVFP4 EP2 bank geometry drifted".into());
12653                }
12654                {
12655                    let Nvfp4DeviceRoutesWorkspace {
12656                        sel,
12657                        gate_out,
12658                        up_out,
12659                        in_q,
12660                        in_d,
12661                        ..
12662                    } = &mut *workspace;
12663                    engine.qmatvec_nvfp4_sel_gu_ep_into(
12664                        &gate_bank.bank,
12665                        &up_bank.bank,
12666                        &sel[rank_index],
12667                        &in_q[rank_index],
12668                        &in_d[rank_index],
12669                        &mut gate_out[rank_index],
12670                        &mut up_out[rank_index],
12671                        n_sel,
12672                        gate_bank.in_features,
12673                        gate_bank.local_out,
12674                        gate_bank.row_bytes,
12675                        gate_bank.expert_bytes,
12676                        rank_index,
12677                    )?;
12678                }
12679                {
12680                    let Nvfp4DeviceRoutesWorkspace {
12681                        gate_out,
12682                        up_out,
12683                        sel,
12684                        act_q,
12685                        act_d,
12686                        ..
12687                    } = &mut *workspace;
12688                    engine.silu_mul_scaled_q8_1_sel_ep_into(
12689                        &gate_out[rank_index],
12690                        &up_out[rank_index],
12691                        &experts.macros_gate_dev[rank_index],
12692                        &experts.macros_up_dev[rank_index],
12693                        &sel[rank_index],
12694                        activation_limit,
12695                        &mut act_q[rank_index],
12696                        &mut act_d[rank_index],
12697                        local_out,
12698                        n_sel,
12699                        rank_index,
12700                    )?;
12701                }
12702                let shard = &experts.down[rank_index];
12703                if shard.device_rank != rank_index || shard.local_in != local_out {
12704                    return Err("NVFP4 EP2 down bank placement drifted".into());
12705                }
12706                {
12707                    let Nvfp4DeviceRoutesWorkspace {
12708                        sel,
12709                        act_q,
12710                        act_d,
12711                        route_w,
12712                        accumulator,
12713                        ..
12714                    } = &mut *workspace;
12715                    engine.qmatvec_nvfp4_sel_down8_ep_into(
12716                        &shard.bank,
12717                        &sel[rank_index],
12718                        &act_q[rank_index],
12719                        &act_d[rank_index],
12720                        &route_w[rank_index],
12721                        &experts.macros_down_dev[rank_index],
12722                        &mut accumulator[rank_index],
12723                        n_sel,
12724                        shard.local_in,
12725                        shard.out_features,
12726                        shard.row_bytes,
12727                        shard.expert_bytes,
12728                        local_out,
12729                        local_out / 32,
12730                        rank_index,
12731                    )?;
12732                }
12733                return Ok(());
12734            }
12735            if !device_routed {
12736                engine.htod_i32_into(&mut workspace.sel[rank_index], sel_i32)?;
12737                // Folded combine weights (route_weight x down macro) — one 40-byte upload
12738                // replaces the accumulator reset + n_sel sequential axpy launches below.
12739                let folded = (0..n_sel)
12740                    .map(|pair| route_weights[pair] * experts.macros_down[selected[pair]])
12741                    .collect::<Vec<_>>();
12742                let mut view = workspace.combine_w[rank_index].slice_mut(0..n_sel);
12743                engine.stream().memcpy_htod(&folded, &mut view)?;
12744            }
12745            let gate_bank = &experts.gate[rank_index];
12746            let up_bank = &experts.up[rank_index];
12747            let (aq, ad) = (&workspace.in_q[rank_index], &workspace.in_d[rank_index]);
12748            // PROGRAM 2 (`MEMRA_NVFP4_SEL_GU`): the two sweeps share sel/aq/ad and, when the
12749            // geometry matches exactly, one launch covers both — per-row bit-identical, double
12750            // the grid fill. Armed by ITS OWN door, and additionally guarded on both banks
12751            // reporting slot-major, because the fused kernel reads only that byte map. Its door
12752            // is separate from PROGRAM 1's on purpose: in the removed implementation it armed
12753            // silently on the bank predicate, so the bank layout and this fusion could never be
12754            // priced apart (DIAGNOSIS.md, "the bisect could not name the mechanism").
12755            let gu_fused = sel_gu_fused_on()
12756                && gate_bank.slot_major
12757                && up_bank.slot_major
12758                && gate_bank.in_features == up_bank.in_features
12759                && gate_bank.local_out == up_bank.local_out
12760                && gate_bank.row_bytes == up_bank.row_bytes
12761                && gate_bank.expert_bytes == up_bank.expert_bytes;
12762            // ENGAGEMENT RECEIPT for PROGRAM 2, one line per DISTINCT decision combo. The
12763            // removed implementation had this behind MEMRA_SWEEP_TRACE and its own comment said
12764            // why it existed: "a silently-dead fusion reads as roofline physics without it".
12765            // It is unconditional here, because a perf row whose fusion never armed is worse
12766            // than no row -- it is a number that looks like evidence.
12767            {
12768                static SEEN_GU: std::sync::Mutex<Vec<(bool, bool, bool)>> =
12769                    std::sync::Mutex::new(Vec::new());
12770                let combo = (gu_fused, sel_gu_fused_on(), gate_bank.slot_major);
12771                let mut seen = SEEN_GU.lock().unwrap();
12772                if !seen.contains(&combo) {
12773                    seen.push(combo);
12774                    eprintln!(
12775                        "[nvfp4-sweep] gu_fused={} door={} slot_major={} geometry_match={} \
12776                         in_f={} out_f={} n_sel={n_sel}",
12777                        gu_fused,
12778                        sel_gu_fused_on(),
12779                        gate_bank.slot_major,
12780                        gate_bank.in_features == up_bank.in_features
12781                            && gate_bank.local_out == up_bank.local_out
12782                            && gate_bank.row_bytes == up_bank.row_bytes
12783                            && gate_bank.expert_bytes == up_bank.expert_bytes,
12784                        gate_bank.in_features,
12785                        gate_bank.local_out
12786                    );
12787                }
12788            }
12789            if gu_fused {
12790                let Nvfp4DeviceRoutesWorkspace {
12791                    sel,
12792                    gate_out,
12793                    up_out,
12794                    in_q,
12795                    in_d,
12796                    ..
12797                } = &mut *workspace;
12798                engine.qmatvec_nvfp4_sel_gu_into(
12799                    &gate_bank.bank,
12800                    &up_bank.bank,
12801                    &sel[rank_index],
12802                    &in_q[rank_index],
12803                    &in_d[rank_index],
12804                    &mut gate_out[rank_index],
12805                    &mut up_out[rank_index],
12806                    n_sel,
12807                    gate_bank.in_features,
12808                    gate_bank.local_out,
12809                    gate_bank.row_bytes,
12810                    gate_bank.expert_bytes,
12811                    gate_bank.slot_major,
12812                )?;
12813            } else {
12814                engine.qmatvec_nvfp4_sel_into(
12815                    &gate_bank.bank,
12816                    &workspace.sel[rank_index],
12817                    aq,
12818                    ad,
12819                    &mut workspace.gate_out[rank_index],
12820                    n_sel,
12821                    gate_bank.in_features,
12822                    gate_bank.local_out,
12823                    gate_bank.row_bytes,
12824                    gate_bank.expert_bytes,
12825                    0,
12826                    0,
12827                    gate_bank.slot_major,
12828                )?;
12829                engine.qmatvec_nvfp4_sel_into(
12830                    &up_bank.bank,
12831                    &workspace.sel[rank_index],
12832                    aq,
12833                    ad,
12834                    &mut workspace.up_out[rank_index],
12835                    n_sel,
12836                    up_bank.in_features,
12837                    up_bank.local_out,
12838                    up_bank.row_bytes,
12839                    up_bank.expert_bytes,
12840                    0,
12841                    0,
12842                    up_bank.slot_major,
12843                )?;
12844            }
12845            // Fused macro-scaled SwiGLU that EMITS q8_1 directly — down consumes it with no
12846            // separate quantize launch. act[rank] IS down canonical shard `rank_index`'s
12847            // input-column window (the geometry gift; see the method doc).
12848            {
12849                let Nvfp4DeviceRoutesWorkspace {
12850                    gate_out,
12851                    up_out,
12852                    sel,
12853                    act_q,
12854                    act_d,
12855                    ..
12856                } = &mut *workspace;
12857                engine.silu_mul_scaled_q8_1_sel_into(
12858                    &gate_out[rank_index],
12859                    &up_out[rank_index],
12860                    &experts.macros_gate_dev[rank_index],
12861                    &experts.macros_up_dev[rank_index],
12862                    &sel[rank_index],
12863                    activation_limit,
12864                    &mut act_q[rank_index],
12865                    &mut act_d[rank_index],
12866                    local_out,
12867                    n_sel,
12868                )?;
12869            }
12870            let shard = &experts.down[rank_index];
12871            if shard.device_rank != rank_index || shard.local_in != local_out {
12872                return Err(
12873                    "NVFP4 device routes: down canonical shard placement drifted from \
12874                     the gate/up column split"
12875                        .into(),
12876                );
12877            }
12878            // PROGRAM 3 (`MEMRA_NVFP4_SEL_DOWN8`): the down sweep and the route-weight combine
12879            // in ONE launch, one warp per SLOT instead of one warp per (row, slot), and the
12880            // `n_sel x out_f` partial round trip gone. Device-routed only — the host-routed arm
12881            // folds the macro into `combine_w` instead of reading `md` on device — and
12882            // slot-major only, read off the shard. `nsb <= 32` is the fit-block class the reduce
12883            // identity is argued at. Its own door, priced LAST and only on green gates for the
12884            // programs beneath it (lane mandate, milestone 5).
12885            let down8 =
12886                device_routed && sel_down8_on() && shard.slot_major && (shard.local_in >> 5) <= 32;
12887            // ENGAGEMENT RECEIPT for PROGRAM 3, one line per distinct combo. `device_routed`
12888            // and `nsb <= 32` are printed because they are the two eligibility conditions that
12889            // can silently disqualify the arm on a geometry or a route the operator did not
12890            // expect -- exactly the case where a flat perf row would be misread as "no win".
12891            {
12892                static SEEN_D8: std::sync::Mutex<Vec<(bool, bool, bool, bool)>> =
12893                    std::sync::Mutex::new(Vec::new());
12894                let combo = (down8, sel_down8_on(), device_routed, shard.slot_major);
12895                let mut seen = SEEN_D8.lock().unwrap();
12896                if !seen.contains(&combo) {
12897                    seen.push(combo);
12898                    // `door_source` is what makes this line a DEFAULT-flip receipt rather than
12899                    // only an engagement receipt: `door=true door_source=default-on` is the
12900                    // flip doing the work, `env=1` is a recipe doing it, and
12901                    // `down8=false door=true` is the silent-no-op shape that PROGRAM 1's
12902                    // default exists to prevent.
12903                    eprintln!(
12904                        "[nvfp4-sweep] down8={} door={} door_source={} device_routed={} \
12905                         slot_major={} nsb={} in_class={} n_sel={n_sel}",
12906                        down8,
12907                        sel_down8_on(),
12908                        sel_down8_source().1,
12909                        device_routed,
12910                        shard.slot_major,
12911                        shard.local_in >> 5,
12912                        (shard.local_in >> 5) <= 32
12913                    );
12914                }
12915            }
12916            if down8 {
12917                let Nvfp4DeviceRoutesWorkspace {
12918                    sel,
12919                    act_q,
12920                    act_d,
12921                    route_w,
12922                    accumulator,
12923                    ..
12924                } = &mut *workspace;
12925                engine.qmatvec_nvfp4_sel_down8_into(
12926                    &shard.bank,
12927                    &sel[rank_index],
12928                    &act_q[rank_index],
12929                    &act_d[rank_index],
12930                    &route_w[rank_index],
12931                    &experts.macros_down_dev[rank_index],
12932                    &mut accumulator[rank_index],
12933                    n_sel,
12934                    shard.local_in,
12935                    shard.out_features,
12936                    shard.row_bytes,
12937                    shard.expert_bytes,
12938                    local_out,
12939                    local_out / 32,
12940                    shard.slot_major,
12941                )?;
12942            } else {
12943                let Nvfp4DeviceRoutesWorkspace {
12944                    sel,
12945                    act_q,
12946                    act_d,
12947                    partial,
12948                    ..
12949                } = &mut *workspace;
12950                engine.qmatvec_nvfp4_sel_into(
12951                    &shard.bank,
12952                    &sel[rank_index],
12953                    &act_q[rank_index],
12954                    &act_d[rank_index],
12955                    &mut partial[rank_index],
12956                    n_sel,
12957                    shard.local_in,
12958                    shard.out_features,
12959                    shard.row_bytes,
12960                    shard.expert_bytes,
12961                    local_out,
12962                    local_out / 32,
12963                    shard.slot_major,
12964                )?;
12965            }
12966            // Route-weight accumulation: axpy_rows_seq keeps the exact sequential per-pair
12967            // FP chain of the reset + n_sel axpy launches in ONE launch. Device-routed calls
12968            // fold the down macro in-kernel from the device selection. (down8 already produced
12969            // the accumulator inside the sweep.)
12970            if !down8 {
12971                let Nvfp4DeviceRoutesWorkspace {
12972                    partial,
12973                    combine_w,
12974                    route_w,
12975                    sel,
12976                    accumulator,
12977                    ..
12978                } = &mut *workspace;
12979                if device_routed {
12980                    engine.axpy_rows_seq_md_into(
12981                        &partial[rank_index],
12982                        &route_w[rank_index],
12983                        &experts.macros_down_dev[rank_index],
12984                        &sel[rank_index],
12985                        &mut accumulator[rank_index],
12986                        experts.input_width,
12987                        n_sel,
12988                    )?;
12989                } else {
12990                    engine.axpy_rows_seq_into(
12991                        &partial[rank_index],
12992                        &combine_w[rank_index],
12993                        &mut accumulator[rank_index],
12994                        experts.input_width,
12995                        n_sel,
12996                    )?;
12997                }
12998            }
12999        }
13000        Ok(())
13001    }
13002
13003    /// Device-IO twin of `run_tensor_parallel_routes_nvfp4_device`: the layer input arrives as
13004    /// a device row on the model engine `e` and the combined output returns as a fresh
13005    /// `e`-context row — no host round-trip, no host stream sync. Ordering is evented (the v2
13006    /// attention discipline): `ev_entry` is recorded on `e`'s stream AFTER the caller queued
13007    /// the input's producer; each rank waits it before its peer read; the root reduce waits
13008    /// every rank's done event; `e` waits the root's done event before copying out. The
13009    /// program bytes are identical to the host-IO twin — dtoh/htod and dtod preserve f32 bits.
13010    #[allow(clippy::too_many_arguments)] // allow: the parameter list mirrors the kernel/FFI/call contract; bundling into a struct is a refactor, not a lint fix
13011    pub fn run_tensor_parallel_routes_nvfp4_device_io(
13012        &self,
13013        experts: &ResidentNvfp4TensorParallel,
13014        e: &Engine,
13015        input_dev: &crate::CudaSlice<f32>,
13016        selected: &[usize],
13017        route_weights: &[f32],
13018        experts_per_token: usize,
13019        activation_limit: Option<f32>,
13020    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
13021        if input_dev.len() != experts.input_width {
13022            return Err(format!(
13023                "NVFP4 device-io routes input {} != width {}",
13024                input_dev.len(),
13025                experts.input_width
13026            )
13027            .into());
13028        }
13029        if selected.len() != experts_per_token || route_weights.len() != experts_per_token {
13030            return Err(format!(
13031                "NVFP4 device-io routes selected={} weights={} != experts/token {experts_per_token}",
13032                selected.len(),
13033                route_weights.len(),
13034            )
13035            .into());
13036        }
13037        if !route_weights.iter().all(|weight| weight.is_finite()) {
13038            return Err("NVFP4 device route weights contain a non-finite value".into());
13039        }
13040        let world = self.ranks.len();
13041        if world != NVFP4_CANONICAL_ROW_SHARDS {
13042            return Err(format!(
13043                "NVFP4 device routes require world == canonical shard grid \
13044                 ({NVFP4_CANONICAL_ROW_SHARDS}), got {world}"
13045            )
13046            .into());
13047        }
13048        let local_out = experts.expert_width / world;
13049        let n_sel = experts_per_token;
13050
13051        static TIMING_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
13052        static TIMING_CALLS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
13053        let timing = std::env::var("MEMRA_STEP_TP_TIMING").as_deref() == Ok("1");
13054        let started = timing.then(std::time::Instant::now);
13055
13056        let mut workspace_guard = experts
13057            .device_workspace
13058            .lock()
13059            .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
13060        if workspace_guard.is_none() {
13061            drop(workspace_guard);
13062            // Build through the host-IO ensure path exactly once: run it with a zero input.
13063            // Cheaper than duplicating the init; the first real call overwrites everything.
13064            let zero = vec![0.0f32; experts.input_width];
13065            let zero_sel = vec![0usize; n_sel];
13066            let zero_w = vec![0.0f32; n_sel];
13067            let _ = self.run_tensor_parallel_routes_nvfp4_device(
13068                experts,
13069                &zero,
13070                &zero_sel,
13071                &zero_w,
13072                n_sel,
13073                activation_limit,
13074            )?;
13075            workspace_guard = experts
13076                .device_workspace
13077                .lock()
13078                .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
13079        }
13080        let workspace = workspace_guard
13081            .as_mut()
13082            .expect("NVFP4 device routes workspace initialized above");
13083        if workspace.n_sel != n_sel {
13084            return Err(format!(
13085                "NVFP4 device routes experts/token changed: workspace {} != call {n_sel}",
13086                workspace.n_sel
13087            )
13088            .into());
13089        }
13090        for &expert in selected {
13091            if expert >= experts.expert_count {
13092                return Err(format!(
13093                    "NVFP4 device selected expert {expert} outside 0..{}",
13094                    experts.expert_count
13095                )
13096                .into());
13097            }
13098        }
13099        let sel_i32 = selected
13100            .iter()
13101            .map(|&expert| expert as i32)
13102            .collect::<Vec<_>>();
13103
13104        // Entry fence: e's stream position covers the input's producer AND every consumer of
13105        // the previous layer's output (queued on e's stream before this call), guarding the
13106        // workspace reuse exactly like the v2 attention driver.
13107        if let Some((_, device)) = workspace.ev_entry.as_ref() {
13108            if *device != e.ctx().ordinal() {
13109                return Err("NVFP4 device-io routes engine changed".into());
13110            }
13111        } else {
13112            let _main = e.gpu.enter_main()?;
13113            workspace.ev_entry = Some((e.ctx().new_event(None)?, e.ctx().ordinal()));
13114        }
13115        {
13116            let _main = e.gpu.enter_main()?;
13117            let (ev_entry, _) = workspace.ev_entry.as_ref().expect("entry event set above");
13118            ev_entry.record(&e.stream())?;
13119        }
13120        for (rank_index, engine) in self.ranks.iter().enumerate() {
13121            let _main = engine.gpu.enter_main()?;
13122            let (ev_entry, _) = workspace.ev_entry.as_ref().expect("entry event set above");
13123            engine.stream().wait(ev_entry)?;
13124            {
13125                let mut destination = workspace.input[rank_index].slice_mut(0..experts.input_width);
13126                engine
13127                    .stream()
13128                    .memcpy_dtod(&input_dev.slice(0..experts.input_width), &mut destination)?;
13129            }
13130            {
13131                let Nvfp4DeviceRoutesWorkspace {
13132                    input, in_q, in_d, ..
13133                } = &mut *workspace;
13134                engine.quantize_q8_1_into(
13135                    &input[rank_index],
13136                    1,
13137                    experts.input_width,
13138                    &mut in_q[rank_index],
13139                    &mut in_d[rank_index],
13140                )?;
13141            }
13142        }
13143        self.nvfp4_routes_batched_sweeps(
13144            experts,
13145            workspace,
13146            selected,
13147            route_weights,
13148            &sel_i32,
13149            local_out,
13150            n_sel,
13151            activation_limit,
13152            false,
13153        )?;
13154
13155        // Evented combine: rank done events replace the host stream syncs, the reduce runs on
13156        // the root stream in canonical shard order, and e copies the combined row out behind
13157        // the root's done event.
13158        // rank0 == root: its own stream order already covers its sweep; only the PEER
13159        // ranks need the record/wait pair (host-op diet at the #1 eager seam, 2026-08-21).
13160        for (rank_index, engine) in self.ranks.iter().enumerate().skip(1) {
13161            let _main = engine.gpu.enter_main()?;
13162            workspace.ev_rank[rank_index].record(&engine.stream())?;
13163        }
13164        if moe_direct_on() && self.ranks.len() == 2 {
13165            // DIRECT JOIN: rank1's accumulator is root-resident (P2P single-store pass);
13166            // rank0's is root-stream-ordered. One root event + rank1's own event order
13167            // the model engine's single add — same operand order as root's add
13168            // (accumulator[0] + accumulator[1]): BIT-IDENTICAL. Output is a FRESH
13169            // e-context row (NOT an alias of ws state — the reverted zero-copy handoff's
13170            // hazard class does not apply).
13171            {
13172                let root = &self.ranks[0];
13173                let _main = root.gpu.enter_main()?;
13174                workspace
13175                    .ev_done
13176                    .as_ref()
13177                    .expect("device routes done event")
13178                    .record(&root.stream())?;
13179            }
13180            let _main = e.gpu.enter_main()?;
13181            e.stream().wait(
13182                workspace
13183                    .ev_done
13184                    .as_ref()
13185                    .expect("device routes done event"),
13186            )?;
13187            for ev in workspace.ev_rank.iter().skip(1) {
13188                e.stream().wait(ev)?;
13189            }
13190            let mut output = e.uninit(experts.input_width)?;
13191            e.add(
13192                &workspace.accumulator[0],
13193                &workspace.accumulator[1],
13194                &mut output,
13195                experts.input_width,
13196            )?;
13197            let output = output;
13198            if let Some(started) = started {
13199                use std::sync::atomic::Ordering;
13200                let ns = TIMING_NS
13201                    .fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
13202                    + started.elapsed().as_nanos() as u64;
13203                let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
13204                if calls.is_multiple_of(430) {
13205                    eprintln!(
13206                        "[nvfp4-dev-routes-direct-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
13207                        ns as f64 / 1.0e6,
13208                        ns as f64 / calls as f64 / 1.0e3,
13209                    );
13210                }
13211            }
13212            return Ok(output);
13213        }
13214        {
13215            let root = &self.ranks[0];
13216            let _main = root.gpu.enter_main()?;
13217            for ev in workspace.ev_rank.iter().skip(1) {
13218                root.stream().wait(ev)?;
13219            }
13220            root.stream()
13221                .memcpy_dtod(&workspace.accumulator[1], &mut workspace.remote)?;
13222            {
13223                let Nvfp4DeviceRoutesWorkspace {
13224                    accumulator,
13225                    remote,
13226                    combined,
13227                    ..
13228                } = &mut *workspace;
13229                root.add(&accumulator[0], remote, combined, experts.input_width)?;
13230            }
13231            workspace
13232                .ev_done
13233                .as_ref()
13234                .expect("device routes done event")
13235                .record(&root.stream())?;
13236        }
13237        let output = {
13238            let _main = e.gpu.enter_main()?;
13239            e.stream().wait(
13240                workspace
13241                    .ev_done
13242                    .as_ref()
13243                    .expect("device routes done event"),
13244            )?;
13245            // (Zero-copy clone handoff REVERTED 2026-08-21: identity mismatch in the
13246            // routes-diet bisect. The alloc+copy stays until the hazard is understood.)
13247            let mut output = e.uninit(experts.input_width)?;
13248            e.stream().memcpy_dtod(
13249                &workspace.combined.slice(0..experts.input_width),
13250                &mut output.slice_mut(0..experts.input_width),
13251            )?;
13252            output
13253        };
13254        if let Some(started) = started {
13255            use std::sync::atomic::Ordering;
13256            let ns = TIMING_NS.fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
13257                + started.elapsed().as_nanos() as u64;
13258            let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
13259            if calls.is_multiple_of(430) {
13260                eprintln!(
13261                    "[nvfp4-dev-routes-io-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
13262                    ns as f64 / 1.0e6,
13263                    ns as f64 / calls as f64 / 1.0e3,
13264                );
13265            }
13266        }
13267        Ok(output)
13268    }
13269
13270    /// Device-routed twin of `run_tensor_parallel_routes_nvfp4_device_io`: the selection and
13271    /// route weights arrive as the device router's e-context outputs — the per-layer host
13272    /// logits readback disappears. The fresh router outputs are staged into persistent
13273    /// e-context buffers on e's stream (never-free discipline) before the entry event; each
13274    /// rank peer-reads them behind it. The down-macro fold happens in-kernel.
13275    #[allow(clippy::too_many_arguments)]
13276    /// Prestage the routed-expert input: pull the shared row to every rank and quantize it
13277    /// there, WITHOUT the selection — callable before the router so the rank chains overlap
13278    /// it. No-op (returns false) when the workspace is not built yet or the door is off;
13279    /// the routed run then does its own staging as before.
13280    pub fn nvfp4_routes_prestage(
13281        &self,
13282        experts: &ResidentNvfp4TensorParallel,
13283        e: &Engine,
13284        input_dev: &crate::CudaSlice<f32>,
13285    ) -> Result<bool, Box<dyn std::error::Error>> {
13286        self.nvfp4_routes_prestage_with(experts, e, input_dev, |_, _, _, _| Ok(false))
13287    }
13288
13289    /// `nvfp4_routes_prestage` with a PEER-ROUTER hook: after rank1's input pull +
13290    /// quantize, the hook may compute rank1's route selection LOCALLY (replicated router —
13291    /// deterministic kernels on identical input bits produce identical sel/w, so the
13292    /// selection is bit-equal to the root's). Returns true when it wrote sel/route_w; the
13293    /// routed run then skips rank1's sel pull.
13294    pub fn nvfp4_routes_prestage_with(
13295        &self,
13296        experts: &ResidentNvfp4TensorParallel,
13297        e: &Engine,
13298        input_dev: &crate::CudaSlice<f32>,
13299        rank1_router: impl FnOnce(
13300            &Engine,
13301            &crate::CudaSlice<f32>,
13302            &mut crate::CudaSlice<i32>,
13303            &mut crate::CudaSlice<f32>,
13304        ) -> Result<bool, Box<dyn std::error::Error>>,
13305    ) -> Result<bool, Box<dyn std::error::Error>> {
13306        if !routes_prestage_on() || step_tp_graph_enabled()? {
13307            return Ok(false);
13308        }
13309        if input_dev.len() != experts.input_width {
13310            return Err("NVFP4 prestage input width mismatch".into());
13311        }
13312        let mut workspace_guard = experts
13313            .device_workspace
13314            .lock()
13315            .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
13316        let Some(workspace) = workspace_guard.as_mut() else {
13317            return Ok(false);
13318        };
13319        if workspace.ev_input.is_none() {
13320            let _main = e.gpu.enter_main()?;
13321            workspace.ev_input = Some((e.ctx().new_event(None)?, e.ctx().ordinal()));
13322        } else if workspace.ev_input.as_ref().map(|(_, d)| *d) != Some(e.ctx().ordinal()) {
13323            return Err("NVFP4 prestage engine changed".into());
13324        }
13325        {
13326            let _main = e.gpu.enter_main()?;
13327            let (ev, _) = workspace.ev_input.as_ref().expect("armed above");
13328            ev.record(&e.stream())?;
13329        }
13330        for (rank_index, engine) in self.ranks.iter().enumerate() {
13331            let _main = engine.gpu.enter_main()?;
13332            let (ev, _) = workspace.ev_input.as_ref().expect("armed above");
13333            engine.stream().wait(ev)?;
13334            {
13335                let mut destination = workspace.input[rank_index].slice_mut(0..experts.input_width);
13336                engine
13337                    .stream()
13338                    .memcpy_dtod(&input_dev.slice(0..experts.input_width), &mut destination)?;
13339            }
13340            {
13341                let Nvfp4DeviceRoutesWorkspace {
13342                    input, in_q, in_d, ..
13343                } = &mut *workspace;
13344                engine.quantize_q8_1_into(
13345                    &input[rank_index],
13346                    1,
13347                    experts.input_width,
13348                    &mut in_q[rank_index],
13349                    &mut in_d[rank_index],
13350                )?;
13351            }
13352        }
13353        if self.ranks.len() == 2 {
13354            let rank1 = &self.ranks[1];
13355            let _r1 = rank1.gpu.enter_main()?;
13356            let Nvfp4DeviceRoutesWorkspace {
13357                input,
13358                sel,
13359                route_w,
13360                ..
13361            } = &mut *workspace;
13362            let (in1, rest_sel) = (&input[1], &mut sel[1]);
13363            if rank1_router(rank1, in1, rest_sel, &mut route_w[1])? {
13364                workspace.rank1_routed = true;
13365            }
13366        }
13367        workspace.prestaged = true;
13368        Ok(true)
13369    }
13370
13371    /// STEP TP2 GEMM PRIME (`MEMRA_STEP_GEMM_PRIME`, 2026-08-27, TTFT lane): one grouped
13372    /// f16 GEMM per projection over the RESIDENT NVFP4 banks for a prime chunk of `t` tokens.
13373    ///
13374    /// WHY: the t-row walk primes a 4,092-token prompt in 19.8 s at its widest (GEMV-bound) and
13375    /// the generic batch prime's decode-class MoE takes 240 s; the CUTLASS sizing rows put
13376    /// GEMM-class expert math at 170-270 TFLOP/s on this silicon, i.e. a sub-second cold prime.
13377    /// This reuses the grouped f16 lane end to end (`moe_f16g_act` -> `moe_f16_grouped`
13378    /// direct-from-NVFP4 -> silu pairs -> grouped down) once per RANK against that rank's bank
13379    /// half: gate/up are column-halves (silu runs on matching halves), down is the canonical
13380    /// row-shard pair producing partials joined in the pinned shard order, and the final
13381    /// weighted scatter runs a fixed slot-0..n_used-1 sum per token - no atomics anywhere.
13382    /// Per-expert NVFP4 macro scales land where they must: gate/up BEFORE silu (nonlinear),
13383    /// down folded into the scatter weight.
13384    ///
13385    /// NUMERIC CLASS: the f16-mirror grouped-prefill class other families already serve -
13386    /// admission is the prefill-KV acceptance gate plus the ship-shape tape, not byte identity.
13387    #[allow(clippy::too_many_arguments)]
13388    /// MEMRA_MOE_DETERM_STAGE=1: checksum a stage's device buffer so two back-to-back calls of the
13389    /// grouped routine can be compared STAGE BY STAGE. The routine's OUTPUT is nondeterministic above
13390    /// ~400 tokens on the direct lane (1.9e-7 / 99% of elements at t=4096) while its GEMM kernels are
13391    /// bit-exact in isolation, so the divergence enters somewhere between. The first stage whose
13392    /// checksum differs across the two calls is where.
13393    ///
13394    /// Sum-of-bits, not sum-of-floats: float addition would itself reorder and could mask exactly the
13395    /// class of difference being hunted.
13396    fn determ_stage_bytes(v: &[u8]) -> u64 {
13397        v.iter().fold(0u64, |a, b| {
13398            a.wrapping_mul(1_000_003).wrapping_add(*b as u64)
13399        })
13400    }
13401
13402    /// Checksum an i32 index/offset buffer. The CSR, the active-expert ids and the group
13403    /// offsets are inputs the gate kernel dereferences just as much as the activations are;
13404    /// leaving them unchecksummed is what let "identical inputs, different output" stand on a
13405    /// SUBSET of the inputs for six rounds of this investigation.
13406    fn determ_stage_i32(v: &[i32]) -> u64 {
13407        v.iter().fold(0u64, |a, b| {
13408            a.wrapping_mul(1_000_003).wrapping_add(*b as u32 as u64)
13409        })
13410    }
13411
13412    fn determ_stage_sum(v: &[f32]) -> u64 {
13413        v.iter().fold(0u64, |a, x| {
13414            a.wrapping_mul(1_000_003).wrapping_add(x.to_bits() as u64)
13415        })
13416    }
13417
13418    #[allow(clippy::too_many_arguments)] // allow: the parameter list mirrors the kernel/FFI/call contract; bundling into a struct is a refactor, not a lint fix
13419    pub fn run_tensor_parallel_routes_nvfp4_prime_grouped(
13420        &self,
13421        experts: &ResidentNvfp4TensorParallel,
13422        e: &Engine,
13423        z_t: &crate::CudaSlice<f32>,
13424        t: usize,
13425        sel: &[i32],
13426        w: &[f32],
13427        n_used: usize,
13428        activation_limit: Option<f32>,
13429    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
13430        let world = self.ranks.len();
13431        if world != NVFP4_CANONICAL_ROW_SHARDS {
13432            return Err("NVFP4 grouped prime requires the canonical 2-shard grid".into());
13433        }
13434        // The dequant must read the layout the bank was BUILT in (feeding slot-major bytes to
13435        // the v1 kernel was a garbage-output bug this line exists for). Taken from the BANK,
13436        // never from the environment: EP2 banks are always slot-major, TP shard banks are
13437        // slot-major only under PROGRAM 1 (`MEMRA_NVFP4_BANK_SM`). All three banks share one
13438        // decision at build (`nvfp4_repack_bank_matrix`), and the assert below refuses to run a
13439        // prime over banks that disagree instead of silently priming one of them wrong.
13440        //
13441        // THIS IS THE LINE THE 2026-08-29 CORRUPTION WENT THROUGH. `QT_NVFP4_V2` selects the
13442        // `kq_fetch` branch whose two prefetch callers omitted `in_f`; the codes stayed right
13443        // and the per-16 scale came from inside the packed-codes region, so the prime produced
13444        // fluent WRONG text. No v2 gate had ever run this GEMM. It is now covered device-side by
13445        // `nvfp4-bank-oracle` (both step37 layer geometries, all four tile forms) and end-to-end
13446        // by a prefill-heavy byte gate. Keep both: a decode-only byte gate proved nothing here.
13447        let slot_major = experts.gate.iter().all(|b| b.slot_major)
13448            && experts.up.iter().all(|b| b.slot_major)
13449            && experts.down.iter().all(|b| b.slot_major);
13450        let any_slot_major = experts.gate.iter().any(|b| b.slot_major)
13451            || experts.up.iter().any(|b| b.slot_major)
13452            || experts.down.iter().any(|b| b.slot_major);
13453        if any_slot_major != slot_major {
13454            return Err(
13455                "NVFP4 grouped prime: gate/up/down banks disagree on the row layout — \
13456                        one grouped GEMM cannot serve two byte maps"
13457                    .into(),
13458            );
13459        }
13460        let bank_qt = if slot_major {
13461            crate::QT_NVFP4_V2
13462        } else {
13463            crate::QT_NVFP4
13464        };
13465        let width = experts.input_width;
13466        let n_expert = experts.expert_count;
13467        let n_pairs = t * n_used;
13468        if sel.len() < n_pairs || w.len() < n_pairs || z_t.len() < t * width {
13469            return Err("NVFP4 grouped prime geometry".into());
13470        }
13471        // MEMRA_PRIME_PROF=1 sub-split of the grouped prime (2026-08-28). The [moe-prof] mark
13472        // around this whole call reads 90% of the MoE bucket, but the call is not just GEMMs:
13473        // it host-builds the CSR, allocates ~6 large device buffers per rank per layer (z_r is
13474        // 67 MB, act is 84 MB at t=4096), and does 5 H2D copies per rank. Tile form, occupancy,
13475        // padding, B double-buffering and register pressure have ALL come back null, which is
13476        // the signature of time that is not in the kernel. So measure HOST wall with no syncs
13477        // for the build and the issue, and let the join wait absorb the GPU time: host-bound and
13478        // GPU-bound then read differently instead of summing into one opaque number.
13479        let gprof = std::env::var("MEMRA_PRIME_PROF").as_deref() == Ok("1") && t >= 16;
13480        let g_t0 = std::time::Instant::now();
13481        // CSR: expert-major pair lists. Host-built - prime is chunk-granular, and the router
13482        // selections arrive host-side from the sigmoid router oracle.
13483        let mut buckets: Vec<Vec<i32>> = vec![Vec::new(); n_expert];
13484        for (p, &s_id) in sel.iter().take(n_pairs).enumerate() {
13485            let s_id = s_id as usize;
13486            if s_id >= n_expert {
13487                return Err(format!("grouped prime selection {s_id} >= {n_expert}").into());
13488            }
13489            buckets[s_id].push(p as i32);
13490        }
13491        let mut ex_ids: Vec<i32> = Vec::new();
13492        let mut ex_off: Vec<i32> = vec![0];
13493        let mut ex_pairs: Vec<i32> = Vec::new();
13494        for (e_id, b) in buckets.iter().enumerate() {
13495            if !b.is_empty() {
13496                ex_ids.push(e_id as i32);
13497                ex_pairs.extend_from_slice(b);
13498                ex_off.push(ex_pairs.len() as i32);
13499            }
13500        }
13501        let n_active = ex_ids.len();
13502        if n_active == 0 {
13503            return e.zeros(t * width);
13504        }
13505        if n_active > 512 {
13506            return Err("grouped prime n_active > 512 (direct lane cap)".into());
13507        }
13508        let csr_tok: Vec<i32> = ex_pairs.iter().map(|&p| p / n_used as i32).collect();
13509        // pair-id -> CSR row: lets the fused tail read the partials in place, so the prime skips
13510        // a whole [n_pairs, width] permute (532 MB read + write per rank per layer at 4k).
13511        let mut inv = vec![0i32; n_pairs];
13512        for (row, &pair) in ex_pairs.iter().enumerate() {
13513            inv[pair as usize] = row as i32;
13514        }
13515        // Per-CSR-row gate/up macro scales (before silu); down macro folds into the scatter w.
13516        let mg: Vec<f32> = ex_pairs
13517            .iter()
13518            .map(|&p| experts.macros_gate[sel[p as usize] as usize])
13519            .collect();
13520        let mu: Vec<f32> = ex_pairs
13521            .iter()
13522            .map(|&p| experts.macros_up[sel[p as usize] as usize])
13523            .collect();
13524        let wd: Vec<f32> = (0..n_pairs)
13525            .map(|p| w[p] * experts.macros_down[sel[p] as usize])
13526            .collect();
13527        // Pointer tables: built on first use and kept on the bank. Resident banks never move,
13528        // so the old per-rank-per-LAYER rebuild+upload of 3*n_expert u64s was pure prime-path
13529        // host churn (45 layers x 2 ranks x 864 entries per prime).
13530        {
13531            let mut tabs = experts
13532                .prime_tables
13533                .lock()
13534                .map_err(|_| "grouped prime table cache is poisoned")?;
13535            if tabs.len() != world {
13536                tabs.clear();
13537                for rank in 0..world {
13538                    let engine = &self.ranks[rank];
13539                    let _main = engine.gpu.enter_main()?;
13540                    let (gb, ub, db) =
13541                        (&experts.gate[rank], &experts.up[rank], &experts.down[rank]);
13542                    let mut tab = vec![0u64; 3 * n_expert];
13543                    {
13544                        use cudarc::driver::DevicePtr;
13545                        let stream = engine.stream();
13546                        let (pg, _g0) = gb.bank.device_ptr(&stream);
13547                        let (pu, _g1) = ub.bank.device_ptr(&stream);
13548                        let (pd, _g2) = db.bank.device_ptr(&stream);
13549                        for ex in 0..n_expert {
13550                            tab[ex] = pg + (ex * gb.expert_bytes) as u64;
13551                            tab[n_expert + ex] = pu + (ex * ub.expert_bytes) as u64;
13552                            tab[2 * n_expert + ex] = pd + (ex * db.expert_bytes) as u64;
13553                        }
13554                    }
13555                    tabs.push(engine.htod_u64(&tab)?);
13556                }
13557            }
13558        }
13559        let g_csr = g_t0.elapsed().as_secs_f64() * 1e3;
13560        let g_t1 = std::time::Instant::now();
13561        // WHAT ARE THESE RANKS, ACTUALLY (2026-08-28)? The grouped MoE measures join ~ span_sum
13562        // (strictly serialized) at t=4096 while the same kernel hits 40 TFLOP/s standalone, and
13563        // one intervention based on cudarc's peer-copy event was refuted. Before proposing an
13564        // eleventh mechanism, verify the premise the whole question rests on: that the two ranks
13565        // are on DISTINCT devices, contexts and streams. If they share any of those, the
13566        // serialization needs no further explanation. One line per process.
13567        {
13568            static SAID: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
13569            if gprof && !SAID.swap(true, std::sync::atomic::Ordering::Relaxed) {
13570                for rank in 0..world {
13571                    let e_r = &self.ranks[rank];
13572                    let _m = e_r.gpu.enter_main();
13573                    eprintln!(
13574                        "[rank-id] rank={rank} ordinal={} ctx={:?} stream={:?} root_ordinal={} \
13575                         root_stream={:?}",
13576                        e_r.ctx().ordinal(),
13577                        std::sync::Arc::as_ptr(e_r.ctx()),
13578                        e_r.stream().cu_stream(),
13579                        e.ctx().ordinal(),
13580                        e.stream().cu_stream(),
13581                    );
13582                }
13583            }
13584        }
13585
13586        let mut partials: Vec<crate::CudaSlice<f32>> = Vec::with_capacity(world);
13587        let mut ev_rank: Vec<CudaEvent> = Vec::with_capacity(world);
13588        let mut ev_head: Vec<CudaEvent> = Vec::with_capacity(world);
13589        let mut ev_tail_prof: Vec<CudaEvent> = Vec::with_capacity(world);
13590        for rank in 0..world {
13591            let engine = &self.ranks[rank];
13592            let _main = engine.gpu.enter_main()?;
13593            if gprof {
13594                // CU_EVENT_DEFAULT, not None: cudarc's new_event(None) creates the event with
13595                // CU_EVENT_DISABLE_TIMING, and cuEventElapsedTime then returns INVALID_HANDLE.
13596                // That is what failed every span query for two build cycles — the ordering
13597                // events below correctly keep the default, since they are never timed.
13598                let h = engine
13599                    .ctx()
13600                    .new_event(Some(cudarc::driver::sys::CUevent_flags::CU_EVENT_DEFAULT))?;
13601                h.record(&engine.stream())?;
13602                ev_head.push(h);
13603            }
13604            // The grouped-MoE FFI's raw launches follow the RUNTIME API's current device, not
13605            // the pushed driver context — bind it per rank or rank-1 calls die InvalidValue.
13606            engine.bind_runtime_device(engine.ctx().ordinal() as i32)?;
13607            let gb = &experts.gate[rank];
13608            let ub = &experts.up[rank];
13609            let db = &experts.down[rank];
13610            if db.device_rank != rank {
13611                return Err("grouped prime: down shard placement drifted".into());
13612            }
13613            let local_ff = gb.local_out;
13614            if ub.local_out != local_ff || db.local_in != local_ff || db.out_features != width {
13615                return Err("grouped prime: bank width mismatch".into());
13616            }
13617            // All of the rank's host-side staging lands before its first kernel, so the
13618            // launch chain below issues without host copies interleaved.
13619            let csr_tok_d = engine.htod_i32(&csr_tok)?;
13620            let exi_d = engine.htod_i32(&ex_ids)?;
13621            let exoff_d = engine.htod_i32(&ex_off)?;
13622            let mg_d = engine.htod(&mg)?;
13623            let mu_d = engine.htod(&mu)?;
13624            // Per-rank pointer table into the bank shards, slot-major like DevExps::ptr_row.
13625            let tabs_guard = experts
13626                .prime_tables
13627                .lock()
13628                .map_err(|_| "grouped prime table cache is poisoned")?;
13629            let tab_d = &tabs_guard[rank];
13630            let mut z_r = engine.uninit(t * width)?;
13631            {
13632                let mut dst = z_r.slice_mut(0..t * width);
13633                engine
13634                    .stream()
13635                    .memcpy_dtod(&z_t.slice(0..t * width), &mut dst)?;
13636            }
13637            let dstage = std::env::var("MEMRA_MOE_DETERM_STAGE").as_deref() == Ok("1") && t >= 16;
13638            let (z16, zs) = engine.moe_f16g_act(&z_r, Some(&csr_tok_d), width, n_pairs)?;
13639            if dstage {
13640                // z16 is the GEMM's actual DATA input and is a byte buffer; checksumming only
13641                // z_r and zs left "identical inputs" unestablished and produced a localization
13642                // that outran the measurement. Checksum it as bytes.
13643                let zr = engine.dtoh(&z_r)?;
13644                let zsv = engine.dtoh(&zs)?;
13645                let z16v = engine.dtoh_u8(&z16)?;
13646                eprintln!(
13647                    "[determ-stage] rank={rank} t={t} z_r={:016x} zs={:016x} z16={:016x}",
13648                    Self::determ_stage_sum(&zr),
13649                    Self::determ_stage_sum(&zsv),
13650                    Self::determ_stage_bytes(&z16v)
13651                );
13652            }
13653            if dstage {
13654                // INPUT CLOSURE. Everything the gate kernel dereferences, plus the launch
13655                // geometry that decides how it is summed, checksummed in ONE place. A kernel
13656                // proven bit-deterministic on live data, with no atomics, can only diverge if
13657                // (A) some byte it reads differs, (B) the launch differs, or (C) it reads
13658                // outside its declared inputs. This closes A and B; C is what compute-sanitizer
13659                // is for. Partial input sets are how the divergence kept retreating into the
13660                // part that was never measured.
13661                engine.stream().synchronize()?;
13662                let csr_v = engine.dtoh_i32(&csr_tok_d)?;
13663                let exi_v = engine.dtoh_i32(&exi_d)?;
13664                let exo_v = engine.dtoh_i32(&exoff_d)?;
13665                let mg_v = engine.dtoh(&mg_d)?;
13666                let mu_v = engine.dtoh(&mu_d)?;
13667                let tab_v = engine.dtoh_u64(tab_d)?;
13668                eprintln!(
13669                    "[determ-closure] rank={rank} t={t} csr_tok={:016x} exi={:016x} exoff={:016x}                      ex_off_host={:016x} mg={:016x} mu={:016x} tab={:016x} | n_active={n_active}                      n_pairs={n_pairs} width={width} local_ff={local_ff} n_expert={n_expert}                      qt={bank_qt} rb={}",
13670                    Self::determ_stage_i32(&csr_v),
13671                    Self::determ_stage_i32(&exi_v),
13672                    Self::determ_stage_i32(&exo_v),
13673                    Self::determ_stage_i32(&ex_off),
13674                    Self::determ_stage_sum(&mg_v),
13675                    Self::determ_stage_sum(&mu_v),
13676                    tab_v
13677                        .iter()
13678                        .fold(0u64, |a, b| a.wrapping_mul(1_000_003).wrapping_add(*b)),
13679                    gb.row_bytes
13680                );
13681                // The resident weight bank is the GEMM's OTHER operand and was never checked.
13682                // Opt-in because it is a ~424 MB dtoh per rank per layer.
13683                if std::env::var("MEMRA_MOE_DETERM_BANK").as_deref() == Ok("1") {
13684                    let bank_v = engine.dtoh_u8(&gb.bank)?;
13685                    eprintln!(
13686                        "[determ-closure] rank={rank} t={t} gate_bank={:016x} bytes={}",
13687                        Self::determ_stage_bytes(&bank_v),
13688                        bank_v.len()
13689                    );
13690                }
13691            }
13692            let mut g = engine.moe_f16_grouped(
13693                tab_d,
13694                0,
13695                n_expert,
13696                &exi_d,
13697                &ex_off,
13698                &exoff_d,
13699                &z16,
13700                &zs,
13701                width,
13702                local_ff,
13703                n_active,
13704                n_pairs,
13705                bank_qt,
13706                gb.row_bytes,
13707            )?;
13708            engine.scale_rows(&mut g, &mg_d, local_ff, n_pairs)?;
13709            let mut u = engine.moe_f16_grouped(
13710                tab_d,
13711                1,
13712                n_expert,
13713                &exi_d,
13714                &ex_off,
13715                &exoff_d,
13716                &z16,
13717                &zs,
13718                width,
13719                local_ff,
13720                n_active,
13721                n_pairs,
13722                bank_qt,
13723                ub.row_bytes,
13724            )?;
13725            engine.scale_rows(&mut u, &mu_d, local_ff, n_pairs)?;
13726            // step35 routed SwiGLU clamp (per-layer; live only on layers 43/44 for this
13727            // family): min(silu(g), lim) * clamp(u, +-lim). Dropping it was the second
13728            // correctness bug of the first engaged run.
13729            let act = match activation_limit.filter(|l| *l > 1e-6) {
13730                Some(lim) => {
13731                    let mut a = engine.uninit(n_pairs * local_ff)?;
13732                    engine.swiglu_clamped_mul_scaled(
13733                        &g,
13734                        &u,
13735                        1.0,
13736                        1.0,
13737                        lim,
13738                        &mut a,
13739                        n_pairs * local_ff,
13740                    )?;
13741                    a
13742                }
13743                None => engine.moe_pairs_silu_mul(&g, &u, n_pairs * local_ff)?,
13744            };
13745            if dstage {
13746                let gv = engine.dtoh(&g)?;
13747                let uv = engine.dtoh(&u)?;
13748                let av = engine.dtoh(&act)?;
13749                // A SUM tells you THAT gate differs; it does not tell you HOW. ULP-dense diffs
13750                // (nearly every element, ~1e-8) are an ordering/precision class; a handful of
13751                // huge ones are a corruption class. They need different hunts, so measure the
13752                // shape here instead of inferring it later.
13753                let key = (rank, t);
13754                let mut prev_map = DETERM_PREV
13755                    .get_or_init(|| std::sync::Mutex::new(std::collections::HashMap::new()))
13756                    .lock()
13757                    .map_err(|_| "determ prev map poisoned")?;
13758                let shape = match prev_map.get(&key) {
13759                    Some(prev) if prev.len() == gv.len() => {
13760                        let mut md = 0.0f32;
13761                        let mut n_diff = 0usize;
13762                        let mut n_big = 0usize;
13763                        for (a, b) in prev.iter().zip(gv.iter()) {
13764                            let d = (a - b).abs();
13765                            if d > 0.0 {
13766                                n_diff += 1;
13767                            }
13768                            if d > 1e-3 {
13769                                n_big += 1;
13770                            }
13771                            if d > md {
13772                                md = d;
13773                            }
13774                        }
13775                        format!(
13776                            " | vs_prev maxdiff={md:.3e} differing={n_diff}/{} big(>1e-3)={n_big}",
13777                            gv.len()
13778                        )
13779                    }
13780                    _ => String::new(),
13781                };
13782                prev_map.insert(key, gv.clone());
13783                drop(prev_map);
13784                eprintln!(
13785                    "[determ-stage] rank={rank} t={t} gate={:016x} up={:016x} silu={:016x}{shape}",
13786                    Self::determ_stage_sum(&gv),
13787                    Self::determ_stage_sum(&uv),
13788                    Self::determ_stage_sum(&av)
13789                );
13790            }
13791            let (a16, a_s) = engine.moe_f16g_act(&act, None, local_ff, n_pairs)?;
13792            let d_csr = engine.moe_f16_grouped(
13793                tab_d,
13794                2,
13795                n_expert,
13796                &exi_d,
13797                &ex_off,
13798                &exoff_d,
13799                &a16,
13800                &a_s,
13801                local_ff,
13802                width,
13803                n_active,
13804                n_pairs,
13805                bank_qt,
13806                db.row_bytes,
13807            )?;
13808
13809            // No host sync: both ranks' chains must be in flight before anything waits.
13810            // The rank's tail event orders the root's cross-device pulls below.
13811            if dstage {
13812                engine.stream().synchronize()?;
13813                let a16v = engine.dtoh_u8(&a16)?;
13814                let dv = engine.dtoh(&d_csr)?;
13815                eprintln!(
13816                    "[determ-stage] rank={rank} t={t} a16={:016x} down_partial={:016x}",
13817                    Self::determ_stage_bytes(&a16v),
13818                    Self::determ_stage_sum(&dv)
13819                );
13820            }
13821            let ev = engine.ctx().new_event(None)?;
13822            ev.record(&engine.stream())?;
13823            if gprof {
13824                // Per-rank GPU SPAN (2026-08-28). Keep the tail event; the elapsed time is read
13825                // AFTER the join sync below. Reading it here returns NOT_READY (the work has only
13826                // been queued) and cudarc's elapsed_ms synchronizes, which serialized the very
13827                // ranks this is meant to test: host issue jumped 1.9 ms -> 34-47 ms per call and
13828                // the join wall fell to match. A probe that changes the schedule measures its own
13829                // perturbation.
13830                // CudaEvent is not Clone, so record a second tail event on the same stream —
13831                // adjacent to `ev`, so it carries the same completion timestamp for timing.
13832                let tp = engine
13833                    .ctx()
13834                    .new_event(Some(cudarc::driver::sys::CUevent_flags::CU_EVENT_DEFAULT))?;
13835                tp.record(&engine.stream())?;
13836                ev_tail_prof.push(tp);
13837            }
13838            ev_rank.push(ev);
13839            partials.push(d_csr);
13840        }
13841        let _main = e.gpu.enter_main()?;
13842        e.bind_runtime_device(e.ctx().ordinal() as i32)?;
13843        // Host-only: every rank's chain is queued, nothing has been waited on yet.
13844        let g_issue = g_t1.elapsed().as_secs_f64() * 1e3;
13845        let g_t2 = std::time::Instant::now();
13846        for ev in &ev_rank {
13847            e.stream().wait(ev)?;
13848        }
13849        // Both partials land on the root (rank 1's crosses the link once), then ONE fused pass
13850        // does join + CSR permute + weight + scatter. Shard order stays pinned as (y0 + y1).
13851        let mut y0 = e.uninit(n_pairs * width)?;
13852        {
13853            let mut dst = y0.slice_mut(0..n_pairs * width);
13854            e.stream()
13855                .memcpy_dtod(&partials[0].slice(0..n_pairs * width), &mut dst)?;
13856        }
13857        let mut y1 = e.uninit(n_pairs * width)?;
13858        {
13859            let mut dst = y1.slice_mut(0..n_pairs * width);
13860            e.stream()
13861                .memcpy_dtod(&partials[1].slice(0..n_pairs * width), &mut dst)?;
13862        }
13863        let inv_d = e.htod_i32(&inv)?;
13864        let wd_d = e.htod(&wd)?;
13865        let mut out = e.uninit(t * width)?;
13866        e.moe_prime_join_scatter(&y0, &y1, &inv_d, &wd_d, &mut out, width, n_used, t)?;
13867        if gprof {
13868            let _ = e.stream().synchronize();
13869            let g_join = g_t2.elapsed().as_secs_f64() * 1e3;
13870            // Everything has completed, so both events of every pair are ready and elapsed_ms
13871            // cannot block. A negative entry means the query itself failed and the row must be
13872            // read as missing data, never as a zero-length span.
13873            // cuEventElapsedTime needs the events' OWN context current — computing it under the
13874            // root's pushed context returned an error for every pair, and the first version
13875            // swallowed that into -1.0 with no reason attached. Enter each rank's context, and
13876            // print the failure once so a dead probe can never again look like a zero-length span.
13877            let mut span_ms: Vec<f32> = Vec::with_capacity(world);
13878            for (rank, (h, tp)) in ev_head.iter().zip(ev_tail_prof.iter()).enumerate() {
13879                let guard = self.ranks[rank].gpu.enter_main();
13880                match guard.and_then(|_g| h.elapsed_ms(tp).map_err(|e| e.into())) {
13881                    Ok(v) => span_ms.push(v),
13882                    Err(err) => {
13883                        static SAID: std::sync::atomic::AtomicBool =
13884                            std::sync::atomic::AtomicBool::new(false);
13885                        if !SAID.swap(true, std::sync::atomic::Ordering::Relaxed) {
13886                            eprintln!("[grp-prof] span query failed on rank {rank}: {err}");
13887                        }
13888                        span_ms.push(-1.0);
13889                    }
13890                }
13891            }
13892            eprintln!(
13893                "[grp-prof] t={t} n_active={n_active} csr={g_csr:.1}ms issue={g_issue:.1}ms \
13894                 join={g_join:.1}ms spans={span_ms:?} span_sum={:.1}ms span_max={:.1}ms",
13895                span_ms.iter().sum::<f32>(),
13896                span_ms.iter().cloned().fold(0.0f32, f32::max)
13897            );
13898        }
13899        Ok(out)
13900    }
13901
13902    #[allow(clippy::too_many_arguments)] // allow: the parameter list mirrors the kernel/FFI/call contract; bundling into a struct is a refactor, not a lint fix
13903    pub fn run_tensor_parallel_routes_nvfp4_device_routed(
13904        &self,
13905        experts: &ResidentNvfp4TensorParallel,
13906        e: &Engine,
13907        input_dev: &crate::CudaSlice<f32>,
13908        sel_d: &crate::CudaSlice<i32>,
13909        w_d: &crate::CudaSlice<f32>,
13910        experts_per_token: usize,
13911        activation_limit: Option<f32>,
13912    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
13913        self.run_tensor_parallel_routes_nvfp4_device_routed_prejoin(
13914            experts,
13915            e,
13916            input_dev,
13917            sel_d,
13918            w_d,
13919            experts_per_token,
13920            activation_limit,
13921            || Ok(()),
13922        )
13923    }
13924
13925    /// `run_tensor_parallel_routes_nvfp4_device_routed` with a PREJOIN hook: `pre_join`
13926    /// runs on the host right before the join wait is enqueued on e's stream — work it
13927    /// issues there (e.g. the shexp overlap) executes WHILE the peer rank finishes its
13928    /// sweep, instead of after the join. Value-neutral by construction (the hook only
13929    /// reorders independent host issue).
13930    #[allow(clippy::too_many_arguments)]
13931    pub fn run_tensor_parallel_routes_nvfp4_device_routed_prejoin(
13932        &self,
13933        experts: &ResidentNvfp4TensorParallel,
13934        e: &Engine,
13935        input_dev: &crate::CudaSlice<f32>,
13936        sel_d: &crate::CudaSlice<i32>,
13937        w_d: &crate::CudaSlice<f32>,
13938        experts_per_token: usize,
13939        activation_limit: Option<f32>,
13940        pre_join: impl FnOnce() -> Result<(), Box<dyn std::error::Error>>,
13941    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
13942        self.run_tensor_parallel_routes_nvfp4_device_routed_prejoin_add3(
13943            experts,
13944            e,
13945            input_dev,
13946            sel_d,
13947            w_d,
13948            experts_per_token,
13949            activation_limit,
13950            pre_join,
13951            None,
13952        )
13953    }
13954
13955    /// The prejoin variant with MOE TAIL FUSION M1: when `post_add = Some((sh_raw,
13956    /// scale_raw))`, the direct-join arm folds the shexp apply into the join add
13957    /// (`dst = (acc0+acc1) + sh*scale[0]`, exact split-pair sequence) — the caller skips
13958    /// its apply launch. Raw UVA pointers so no lock is held across the call.
13959    #[allow(clippy::too_many_arguments)]
13960    pub fn run_tensor_parallel_routes_nvfp4_device_routed_prejoin_add3(
13961        &self,
13962        experts: &ResidentNvfp4TensorParallel,
13963        e: &Engine,
13964        input_dev: &crate::CudaSlice<f32>,
13965        sel_d: &crate::CudaSlice<i32>,
13966        w_d: &crate::CudaSlice<f32>,
13967        experts_per_token: usize,
13968        activation_limit: Option<f32>,
13969        pre_join: impl FnOnce() -> Result<(), Box<dyn std::error::Error>>,
13970        post_add: Option<(u64, u64)>,
13971    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
13972        if input_dev.len() != experts.input_width {
13973            return Err(format!(
13974                "NVFP4 device-routed input {} != width {}",
13975                input_dev.len(),
13976                experts.input_width
13977            )
13978            .into());
13979        }
13980        let n_sel = experts_per_token;
13981        if sel_d.len() < n_sel || w_d.len() < n_sel {
13982            return Err(format!(
13983                "NVFP4 device-routed routes sel={} w={} < experts/token {n_sel}",
13984                sel_d.len(),
13985                w_d.len()
13986            )
13987            .into());
13988        }
13989        let world = self.ranks.len();
13990        if world != NVFP4_CANONICAL_ROW_SHARDS {
13991            return Err(format!(
13992                "NVFP4 device routes require world == canonical shard grid \
13993                 ({NVFP4_CANONICAL_ROW_SHARDS}), got {world}"
13994            )
13995            .into());
13996        }
13997        let local_out = if experts.ep2 {
13998            experts.expert_width
13999        } else {
14000            experts.expert_width / world
14001        };
14002
14003        static TIMING_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
14004        static TIMING_CALLS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
14005        let timing = std::env::var("MEMRA_STEP_TP_TIMING").as_deref() == Ok("1");
14006        let started = timing.then(std::time::Instant::now);
14007
14008        let mut workspace_guard = experts
14009            .device_workspace
14010            .lock()
14011            .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
14012        if workspace_guard.is_none() {
14013            drop(workspace_guard);
14014            let zero = vec![0.0f32; experts.input_width];
14015            let zero_sel = vec![0usize; n_sel];
14016            let zero_w = vec![0.0f32; n_sel];
14017            let _ = self.run_tensor_parallel_routes_nvfp4_device(
14018                experts,
14019                &zero,
14020                &zero_sel,
14021                &zero_w,
14022                n_sel,
14023                activation_limit,
14024            )?;
14025            workspace_guard = experts
14026                .device_workspace
14027                .lock()
14028                .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
14029        }
14030        let workspace = workspace_guard
14031            .as_mut()
14032            .expect("NVFP4 device routes workspace initialized above");
14033        if workspace.n_sel != n_sel {
14034            return Err(format!(
14035                "NVFP4 device routes experts/token changed: workspace {} != call {n_sel}",
14036                workspace.n_sel
14037            )
14038            .into());
14039        }
14040
14041        // GRAPH DOOR (MEMRA_STEP_TP_GRAPH=1): the whole rank+root segment replays as one
14042        // stitched multi-device parent launched on e's stream — no events, no per-token node
14043        // updates (every address is persistent staging). VALUE-IDENTICAL to the eager path:
14044        // the children replay exactly the same kernel/copy sequence.
14045        //
14046        // GRAPH-LAUNCH HEADROOM GUARD (see spec::GRAPH_LAUNCH_MIN_FREE): below the
14047        // driver-free floor on the launching device this call falls through to the
14048        // eager routes path below — the exact body the graph captures, stateless per
14049        // call — instead of feeding cuGraphLaunch an exhausted card
14050        // (lane/graph-launch-guard-sweep-20260831).
14051        if step_tp_graph_enabled()? && step_tp_graph_headroom_ok(e) {
14052            if experts.ep2 {
14053                return Err(
14054                    "MEMRA_STEP_TP_GRAPH=1 with MEMRA_STEP_NVFP4_EP2=1 has never been \
14055                     co-gated; unset one"
14056                        .into(),
14057                );
14058            }
14059            if workspace.dev_route_e.is_none() {
14060                let _main = e.gpu.enter_main()?;
14061                workspace.dev_route_e = Some((
14062                    e.htod_i32(&vec![0i32; n_sel])?,
14063                    e.htod(&vec![0.0f32; n_sel])?,
14064                ));
14065            }
14066            if workspace.in_stage_e.is_none() {
14067                let _main = e.gpu.enter_main()?;
14068                workspace.in_stage_e = Some(e.htod(&vec![0.0f32; experts.input_width])?);
14069                workspace.out_stage_e = Some(e.htod(&vec![0.0f32; experts.input_width])?);
14070            }
14071            if workspace.routes_graph.is_none() {
14072                let graph = self.nvfp4_routes_build_graph(
14073                    experts,
14074                    workspace,
14075                    local_out,
14076                    n_sel,
14077                    activation_limit,
14078                )?;
14079                workspace.routes_graph = Some(graph);
14080                eprintln!(
14081                    "[step-tp-graph] routes segment captured: ranks={world} n_sel={n_sel} \
14082                     children=3 updates=none performance_claim=false"
14083                );
14084            }
14085            let output = {
14086                let _main = e.gpu.enter_main()?;
14087                {
14088                    let (sel_e, w_e) = workspace
14089                        .dev_route_e
14090                        .as_mut()
14091                        .expect("device route staging set above");
14092                    {
14093                        let mut dst = sel_e.slice_mut(0..n_sel);
14094                        e.stream().memcpy_dtod(&sel_d.slice(0..n_sel), &mut dst)?;
14095                    }
14096                    {
14097                        let mut dst = w_e.slice_mut(0..n_sel);
14098                        e.stream().memcpy_dtod(&w_d.slice(0..n_sel), &mut dst)?;
14099                    }
14100                }
14101                {
14102                    let in_stage = workspace
14103                        .in_stage_e
14104                        .as_mut()
14105                        .expect("graph staging set above");
14106                    let mut dst = in_stage.slice_mut(0..experts.input_width);
14107                    e.stream()
14108                        .memcpy_dtod(&input_dev.slice(0..experts.input_width), &mut dst)?;
14109                }
14110                unsafe {
14111                    let r = cudarc::driver::sys::cuGraphLaunch(
14112                        workspace
14113                            .routes_graph
14114                            .as_ref()
14115                            .expect("routes graph built above")
14116                            .exec,
14117                        e.stream().cu_stream() as cudarc::driver::sys::CUstream,
14118                    );
14119                    if r != cudarc::driver::sys::CUresult::CUDA_SUCCESS {
14120                        return Err(format!("routes graph launch: {r:?}").into());
14121                    }
14122                }
14123                let mut output = e.uninit(experts.input_width)?;
14124                {
14125                    let out_stage = workspace
14126                        .out_stage_e
14127                        .as_ref()
14128                        .expect("graph staging set above");
14129                    e.stream().memcpy_dtod(
14130                        &out_stage.slice(0..experts.input_width),
14131                        &mut output.slice_mut(0..experts.input_width),
14132                    )?;
14133                }
14134                output
14135            };
14136            if let Some(started) = started {
14137                use std::sync::atomic::Ordering;
14138                let ns = TIMING_NS
14139                    .fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
14140                    + started.elapsed().as_nanos() as u64;
14141                let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
14142                if calls.is_multiple_of(430) {
14143                    eprintln!(
14144                        "[nvfp4-dev-routed-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
14145                        ns as f64 / 1.0e6,
14146                        ns as f64 / calls as f64 / 1.0e3,
14147                    );
14148                }
14149            }
14150            return Ok(output);
14151        }
14152
14153        // Entry fence + router-output staging, all on e's stream: the fresh sel/w slices are
14154        // copied into the persistent e-context pair, then the event is recorded — the caller's
14155        // sel_d/w_d can free on e's stream with no cross-stream reader.
14156        if let Some((_, device)) = workspace.ev_entry.as_ref() {
14157            if *device != e.ctx().ordinal() {
14158                return Err("NVFP4 device-routed routes engine changed".into());
14159            }
14160        } else {
14161            let _main = e.gpu.enter_main()?;
14162            workspace.ev_entry = Some((e.ctx().new_event(None)?, e.ctx().ordinal()));
14163        }
14164        if workspace.dev_route_e.is_none() {
14165            let _main = e.gpu.enter_main()?;
14166            workspace.dev_route_e = Some((
14167                e.htod_i32(&vec![0i32; n_sel])?,
14168                e.htod(&vec![0.0f32; n_sel])?,
14169            ));
14170        }
14171        // MEMRA_SEL_MIRROR: the staging pair exists so the rank streams read a persistent
14172        // e-context address. The caller's sel_d/w_d ARE persistent (the process-static
14173        // selection rows), so when every consuming rank shares e's device the ranks can read
14174        // them directly and this hop disappears. The graph door keeps the staging (its
14175        // captured copies read the fixed addresses).
14176        let mirror = sel_mirror_on() && !step_tp_graph_enabled()?;
14177        let e_device = e.ctx().ordinal();
14178        // rank1_routed is consumed (taken) below; peek it here for the staging decision.
14179        let rank1_routed_peek = workspace.rank1_routed;
14180        let stage_needed = !mirror
14181            || self.ranks.iter().enumerate().any(|(rank_index, engine)| {
14182                !(rank1_routed_peek && rank_index == 1) && engine.ctx().ordinal() != e_device
14183            });
14184        {
14185            let _main = e.gpu.enter_main()?;
14186            if stage_needed {
14187                let (sel_e, w_e) = workspace
14188                    .dev_route_e
14189                    .as_mut()
14190                    .expect("device route staging set above");
14191                {
14192                    let mut dst = sel_e.slice_mut(0..n_sel);
14193                    e.stream().memcpy_dtod(&sel_d.slice(0..n_sel), &mut dst)?;
14194                }
14195                {
14196                    let mut dst = w_e.slice_mut(0..n_sel);
14197                    e.stream().memcpy_dtod(&w_d.slice(0..n_sel), &mut dst)?;
14198                }
14199            }
14200            let (ev_entry, _) = workspace.ev_entry.as_ref().expect("entry event set above");
14201            ev_entry.record(&e.stream())?;
14202        }
14203        // Prestage door: input pull + quantize were already issued on the rank streams
14204        // (before the router) — the rank stream order suffices, skip them here.
14205        let prestaged = std::mem::take(&mut workspace.prestaged);
14206        let rank1_routed = std::mem::take(&mut workspace.rank1_routed);
14207        for (rank_index, engine) in self.ranks.iter().enumerate() {
14208            let _main = engine.gpu.enter_main()?;
14209            let (ev_entry, _) = workspace.ev_entry.as_ref().expect("entry event set above");
14210            engine.stream().wait(ev_entry)?;
14211            if !prestaged {
14212                let mut destination = workspace.input[rank_index].slice_mut(0..experts.input_width);
14213                engine
14214                    .stream()
14215                    .memcpy_dtod(&input_dev.slice(0..experts.input_width), &mut destination)?;
14216            }
14217            if !(rank1_routed && rank_index == 1) {
14218                // ONE mirror launch instead of two 32-byte copy-engine dispatches; source is
14219                // the caller's persistent rows when this rank shares e's device (UVA, ordered
14220                // by ev_entry), else the staged e-context pair.
14221                let same_dev = engine.ctx().ordinal() == e_device;
14222                if mirror {
14223                    // Split the workspace borrow so the source (the staged pair, when this
14224                    // rank is off-device) and the destination rows coexist.
14225                    let Nvfp4DeviceRoutesWorkspace {
14226                        sel,
14227                        route_w,
14228                        dev_route_e,
14229                        ..
14230                    } = &mut *workspace;
14231                    let (src_sel, src_w): (&crate::CudaSlice<i32>, &crate::CudaSlice<f32>) =
14232                        if same_dev {
14233                            (sel_d, w_d)
14234                        } else {
14235                            let (sel_e, w_e) = dev_route_e
14236                                .as_ref()
14237                                .expect("device route staging set above");
14238                            (sel_e, w_e)
14239                        };
14240                    engine.moe_sel_w_mirror(
14241                        src_sel,
14242                        src_w,
14243                        &mut sel[rank_index],
14244                        &mut route_w[rank_index],
14245                        n_sel,
14246                    )?;
14247                } else {
14248                    let (sel_e, w_e) = workspace
14249                        .dev_route_e
14250                        .as_ref()
14251                        .expect("device route staging set above");
14252                    {
14253                        let mut dst = workspace.sel[rank_index].slice_mut(0..n_sel);
14254                        engine
14255                            .stream()
14256                            .memcpy_dtod(&sel_e.slice(0..n_sel), &mut dst)?;
14257                    }
14258                    {
14259                        let mut dst = workspace.route_w[rank_index].slice_mut(0..n_sel);
14260                        engine
14261                            .stream()
14262                            .memcpy_dtod(&w_e.slice(0..n_sel), &mut dst)?;
14263                    }
14264                }
14265            }
14266            if !prestaged {
14267                let Nvfp4DeviceRoutesWorkspace {
14268                    input, in_q, in_d, ..
14269                } = &mut *workspace;
14270                engine.quantize_q8_1_into(
14271                    &input[rank_index],
14272                    1,
14273                    experts.input_width,
14274                    &mut in_q[rank_index],
14275                    &mut in_d[rank_index],
14276                )?;
14277            }
14278        }
14279        self.nvfp4_routes_batched_sweeps(
14280            experts,
14281            workspace,
14282            &[],
14283            &[],
14284            &[],
14285            local_out,
14286            n_sel,
14287            activation_limit,
14288            true,
14289        )?;
14290
14291        // rank0 == root: its own stream order already covers its sweep; only the PEER
14292        // ranks need the record/wait pair (host-op diet at the #1 eager seam, 2026-08-21).
14293        for (rank_index, engine) in self.ranks.iter().enumerate().skip(1) {
14294            let _main = engine.gpu.enter_main()?;
14295            workspace.ev_rank[rank_index].record(&engine.stream())?;
14296        }
14297        // Doorbell fences (MEMRA_FENCE_MEMOPS=1): rank1 + root ring their flags; e waits
14298        // the tickets instead of the two events. Arm lazily; 0-len = unsupported.
14299        let memops = fence_memops_on() && moe_direct_on() && self.ranks.len() == 2;
14300        let mut ticket = 0u32;
14301        if memops {
14302            use cudarc::driver::sys;
14303            if workspace.fence_flags_raw == 0 {
14304                let root = &self.ranks[0];
14305                let _main = root.gpu.enter_main()?;
14306                let mut ptr: sys::CUdeviceptr = 0;
14307                let r = unsafe { sys::cuMemAlloc_v2(&mut ptr, 8) };
14308                if r != sys::CUresult::CUDA_SUCCESS {
14309                    return Err(format!("fence flag alloc: {r:?}").into());
14310                }
14311                let r = unsafe { sys::cuMemsetD8_v2(ptr, 0, 8) };
14312                if r != sys::CUresult::CUDA_SUCCESS {
14313                    return Err(format!("fence flag memset: {r:?}").into());
14314                }
14315                workspace.fence_flags_raw = ptr as u64;
14316            }
14317            workspace.fence_ticket = workspace.fence_ticket.wrapping_add(1).max(1);
14318            ticket = workspace.fence_ticket;
14319            let base = workspace.fence_flags_raw;
14320            // rank1's fence: a peer stream MEMOP is rejected over PCIe P2P
14321            // (CUDA_ERROR_INVALID_VALUE, receipted 2026-08-23), but a peer KERNEL STORE into
14322            // root memory is legal — the direct join already relies on it. Under
14323            // MEMRA_FENCE_RANK1 rank1 rings flag[0] that way and e waits it same-device,
14324            // replacing the cross-device event wait below.
14325            if fence_rank1_on() {
14326                let peer = &self.ranks[1];
14327                let _pmain = peer.gpu.enter_main()?;
14328                peer.ring_flag_raw(base, ticket)?;
14329            }
14330            {
14331                let root = &self.ranks[0];
14332                let _main = root.gpu.enter_main()?;
14333                let r = unsafe {
14334                    sys::cuStreamWriteValue32_v2(
14335                        root.stream().cu_stream() as sys::CUstream,
14336                        (base + 4) as sys::CUdeviceptr,
14337                        ticket,
14338                        0,
14339                    )
14340                };
14341                if r != sys::CUresult::CUDA_SUCCESS {
14342                    return Err(format!("fence write root: {r:?}").into());
14343                }
14344            }
14345        }
14346        // PREJOIN hook: rank work is fully issued (dev1 running); independent e-stream
14347        // kernels queued here execute while the peer rank drains its sweep.
14348        pre_join()?;
14349
14350        if moe_direct_on() && self.ranks.len() == 2 {
14351            // DIRECT JOIN: rank1's accumulator is root-resident (P2P single-store pass);
14352            // rank0's is root-stream-ordered. One root event + rank1's own event order
14353            // the model engine's single add — same operand order as root's add
14354            // (accumulator[0] + accumulator[1]): BIT-IDENTICAL. Output is a FRESH
14355            // e-context row (NOT an alias of ws state — the reverted zero-copy handoff's
14356            // hazard class does not apply).
14357            let _main = e.gpu.enter_main()?;
14358            if memops {
14359                use cudarc::driver::sys;
14360                let base = workspace.fence_flags_raw;
14361                let r = unsafe {
14362                    sys::cuStreamWaitValue32_v2(
14363                        e.stream().cu_stream() as sys::CUstream,
14364                        (base + 4) as sys::CUdeviceptr,
14365                        ticket,
14366                        sys::CUstreamWaitValue_flags::CU_STREAM_WAIT_VALUE_GEQ as u32,
14367                    )
14368                };
14369                if r != sys::CUresult::CUDA_SUCCESS {
14370                    return Err(format!("fence wait: {r:?}").into());
14371                }
14372                if fence_rank1_on() {
14373                    // Same-device wait on the flag rank1 rang over P2P.
14374                    let r = unsafe {
14375                        sys::cuStreamWaitValue32_v2(
14376                            e.stream().cu_stream() as sys::CUstream,
14377                            base as sys::CUdeviceptr,
14378                            ticket,
14379                            sys::CUstreamWaitValue_flags::CU_STREAM_WAIT_VALUE_GEQ as u32,
14380                        )
14381                    };
14382                    if r != sys::CUresult::CUDA_SUCCESS {
14383                        return Err(format!("fence wait rank1: {r:?}").into());
14384                    }
14385                } else {
14386                    for ev in workspace.ev_rank.iter().skip(1) {
14387                        e.stream().wait(ev)?;
14388                    }
14389                }
14390            } else {
14391                {
14392                    let root = &self.ranks[0];
14393                    let _rmain = root.gpu.enter_main()?;
14394                    workspace
14395                        .ev_done
14396                        .as_ref()
14397                        .expect("device routes done event")
14398                        .record(&root.stream())?;
14399                }
14400                e.stream().wait(
14401                    workspace
14402                        .ev_done
14403                        .as_ref()
14404                        .expect("device routes done event"),
14405                )?;
14406                for ev in workspace.ev_rank.iter().skip(1) {
14407                    e.stream().wait(ev)?;
14408                }
14409            }
14410            let mut output = e.uninit(experts.input_width)?;
14411            if let Some((sh_raw, scale_raw)) = post_add {
14412                // MOE TAIL FUSION M1: fold the shexp apply into the join add —
14413                // dst = (acc0 + acc1) + sh*scale[0], the exact split-pair sequence.
14414                e.add3_raw(
14415                    &workspace.accumulator[0],
14416                    &workspace.accumulator[1],
14417                    sh_raw,
14418                    scale_raw,
14419                    &mut output,
14420                    experts.input_width,
14421                )?;
14422            } else {
14423                e.add(
14424                    &workspace.accumulator[0],
14425                    &workspace.accumulator[1],
14426                    &mut output,
14427                    experts.input_width,
14428                )?;
14429            }
14430            let output = output;
14431            if let Some(started) = started {
14432                use std::sync::atomic::Ordering;
14433                let ns = TIMING_NS
14434                    .fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
14435                    + started.elapsed().as_nanos() as u64;
14436                let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
14437                if calls.is_multiple_of(430) {
14438                    eprintln!(
14439                        "[nvfp4-dev-routes-direct-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
14440                        ns as f64 / 1.0e6,
14441                        ns as f64 / calls as f64 / 1.0e3,
14442                    );
14443                }
14444            }
14445            return Ok(output);
14446        }
14447        {
14448            let root = &self.ranks[0];
14449            let _main = root.gpu.enter_main()?;
14450            for ev in workspace.ev_rank.iter().skip(1) {
14451                root.stream().wait(ev)?;
14452            }
14453            root.stream()
14454                .memcpy_dtod(&workspace.accumulator[1], &mut workspace.remote)?;
14455            {
14456                let Nvfp4DeviceRoutesWorkspace {
14457                    accumulator,
14458                    remote,
14459                    combined,
14460                    ..
14461                } = &mut *workspace;
14462                root.add(&accumulator[0], remote, combined, experts.input_width)?;
14463            }
14464            workspace
14465                .ev_done
14466                .as_ref()
14467                .expect("device routes done event")
14468                .record(&root.stream())?;
14469        }
14470        let output = {
14471            let _main = e.gpu.enter_main()?;
14472            e.stream().wait(
14473                workspace
14474                    .ev_done
14475                    .as_ref()
14476                    .expect("device routes done event"),
14477            )?;
14478            // (Zero-copy clone handoff REVERTED 2026-08-21: identity mismatch in the
14479            // routes-diet bisect. The alloc+copy stays until the hazard is understood.)
14480            let mut output = e.uninit(experts.input_width)?;
14481            e.stream().memcpy_dtod(
14482                &workspace.combined.slice(0..experts.input_width),
14483                &mut output.slice_mut(0..experts.input_width),
14484            )?;
14485            output
14486        };
14487        if let Some(started) = started {
14488            use std::sync::atomic::Ordering;
14489            let ns = TIMING_NS.fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
14490                + started.elapsed().as_nanos() as u64;
14491            let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
14492            if calls.is_multiple_of(430) {
14493                eprintln!(
14494                    "[nvfp4-dev-routed-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
14495                    ns as f64 / 1.0e6,
14496                    ns as f64 / calls as f64 / 1.0e3,
14497                );
14498            }
14499        }
14500        Ok(output)
14501    }
14502
14503    /// The fused finish's ROOT section (combine + shadow gathers), event-free: the eager
14504    /// caller wraps it with rank-event waits + the done record; the token graph captures it
14505    /// verbatim (parent edges provide the ordering).
14506    pub(crate) fn decode_v2_finish_root_fused(
14507        &self,
14508        ws: &mut StepTpDecodeV2Ws,
14509    ) -> Result<(), Box<dyn std::error::Error>> {
14510        let root = &self.ranks[0];
14511        let _main = root.gpu.enter_main()?;
14512        if ws.raw_peer_partial != 0 {
14513            // Capture-safe raw seams (arming happened in the stage flow).
14514            raw_copy_bytes(ws.raw_peer_partial, ws.raw_o_partial1, ws.o_out * 4, root)?;
14515        } else {
14516            root.stream()
14517                .memcpy_dtod(&ws.o_partials[1][0], &mut ws.peer_partial)?;
14518        }
14519        {
14520            let StepTpDecodeV2Ws {
14521                o_partials,
14522                peer_partial,
14523                reduce_a,
14524                o_out,
14525                ..
14526            } = &mut *ws;
14527            root.add(&o_partials[0][0], peer_partial, reduce_a, *o_out)?;
14528        }
14529        let shadows = !no_local_shadow_on() || ws.raw_mixed_stage_e != 0;
14530        if shadows {
14531            // rank0's shadows are same-context (root) copies; rank1's cross-context reads go
14532            // raw when armed.
14533            let mut k_dst = ws.k_shadow.slice_mut(0..ws.local_kv_dim);
14534            root.stream().memcpy_dtod(&ws.k[0], &mut k_dst)?;
14535            let mut v_dst = ws.v_shadow.slice_mut(0..ws.local_kv_dim);
14536            root.stream().memcpy_dtod(&ws.v_raw[0], &mut v_dst)?;
14537        }
14538        if shadows && ws.raw_peer_partial != 0 {
14539            raw_copy_bytes(
14540                ws.raw_k_shadow + (ws.local_kv_dim * 4) as u64,
14541                ws.raw_k1,
14542                ws.local_kv_dim * 4,
14543                root,
14544            )?;
14545            raw_copy_bytes(
14546                ws.raw_v_shadow + (ws.local_kv_dim * 4) as u64,
14547                ws.raw_v1,
14548                ws.local_kv_dim * 4,
14549                root,
14550            )?;
14551        } else if shadows {
14552            let start = ws.local_kv_dim;
14553            let mut k_dst = ws.k_shadow.slice_mut(start..start + ws.local_kv_dim);
14554            root.stream().memcpy_dtod(&ws.k[1], &mut k_dst)?;
14555            let mut v_dst = ws.v_shadow.slice_mut(start..start + ws.local_kv_dim);
14556            root.stream().memcpy_dtod(&ws.v_raw[1], &mut v_dst)?;
14557        }
14558        if ws.raw_mixed_stage_e != 0 {
14559            // Token-graph mirrors: the e-glue children read same-context copies of the
14560            // root-produced rows.
14561            raw_copy_bytes(ws.raw_mixed_stage_e, ws.raw_reduce_a, ws.o_out * 4, root)?;
14562            let (k_stage, v_stage) = ws.raw_shadow_stage_e;
14563            raw_copy_bytes(k_stage, ws.raw_k_shadow, 2 * ws.local_kv_dim * 4, root)?;
14564            raw_copy_bytes(v_stage, ws.raw_v_shadow, 2 * ws.local_kv_dim * 4, root)?;
14565        }
14566        Ok(())
14567    }
14568
14569    /// Arm the token-graph e-context mirrors (orchestrator-supplied fixed addresses) plus
14570    /// reduce_a's own pointer.
14571    pub(crate) fn decode_v2_arm_token_mirrors(
14572        &self,
14573        ws: &mut StepTpDecodeV2Ws,
14574        mixed_stage_e: u64,
14575        shadow_stage_e: (u64, u64),
14576    ) -> Result<(), Box<dyn std::error::Error>> {
14577        use cudarc::driver::DevicePtr;
14578        let root = &self.ranks[0];
14579        let _main = root.gpu.enter_main()?;
14580        let stream = root.stream();
14581        let (a, _g) = ws.reduce_a.device_ptr(&stream);
14582        ws.raw_reduce_a = a;
14583        ws.raw_mixed_stage_e = mixed_stage_e;
14584        ws.raw_shadow_stage_e = shadow_stage_e;
14585        Ok(())
14586    }
14587
14588    /// Build one layer's stitched routes graph: per-rank children captured on their own
14589    /// streams (raw cuMemcpyAsync at every cross-context seam — cudarc's slice tracking is
14590    /// capture-illegal there), a root combine child, and a multi-device parent with
14591    /// {rank0, rank1} -> root dependency edges. Zero per-token updates: every address the
14592    /// nodes touch is persistent workspace/staging.
14593    fn nvfp4_routes_build_graph(
14594        &self,
14595        experts: &ResidentNvfp4TensorParallel,
14596        workspace: &mut Nvfp4DeviceRoutesWorkspace,
14597        local_out: usize,
14598        n_sel: usize,
14599        activation_limit: Option<f32>,
14600    ) -> Result<RoutesGraph, Box<dyn std::error::Error>> {
14601        use cudarc::driver::DevicePtr;
14602        use cudarc::driver::sys;
14603        fn cu_try(r: sys::CUresult, what: &str) -> Result<(), Box<dyn std::error::Error>> {
14604            if r == sys::CUresult::CUDA_SUCCESS {
14605                Ok(())
14606            } else {
14607                Err(format!("{what}: {r:?}").into())
14608            }
14609        }
14610        let world = self.ranks.len();
14611        if world != 2 {
14612            return Err("routes graph door is built for the TP2 pair".into());
14613        }
14614        let width = experts.input_width;
14615
14616        // Raw pointers cached before capture (each read with its owner's stream).
14617        let ptr_f32 = |buf: &crate::CudaSlice<f32>, engine: &Engine| -> u64 {
14618            let stream = engine.stream();
14619            let (ptr, _g) = buf.device_ptr(&stream);
14620            ptr
14621        };
14622        let ptr_i32 = |buf: &crate::CudaSlice<i32>, engine: &Engine| -> u64 {
14623            let stream = engine.stream();
14624            let (ptr, _g) = buf.device_ptr(&stream);
14625            ptr
14626        };
14627        let (sel_e, w_e) = workspace
14628            .dev_route_e
14629            .as_ref()
14630            .expect("device route staging set before graph build");
14631        let root_engine = &self.ranks[0];
14632        let p_in_stage = ptr_f32(
14633            workspace.in_stage_e.as_ref().expect("graph staging"),
14634            root_engine,
14635        );
14636        let p_out_stage = ptr_f32(
14637            workspace.out_stage_e.as_ref().expect("graph staging"),
14638            root_engine,
14639        );
14640        let p_sel_e = ptr_i32(sel_e, root_engine);
14641        let p_w_e = ptr_f32(w_e, root_engine);
14642        let p_input: Vec<u64> = (0..world)
14643            .map(|r| ptr_f32(&workspace.input[r], &self.ranks[r]))
14644            .collect();
14645        let p_sel: Vec<u64> = (0..world)
14646            .map(|r| ptr_i32(&workspace.sel[r], &self.ranks[r]))
14647            .collect();
14648        let p_route_w: Vec<u64> = (0..world)
14649            .map(|r| ptr_f32(&workspace.route_w[r], &self.ranks[r]))
14650            .collect();
14651        let p_acc1 = ptr_f32(&workspace.accumulator[1], &self.ranks[1]);
14652        let p_remote = ptr_f32(&workspace.remote, root_engine);
14653        let p_combined = ptr_f32(&workspace.combined, root_engine);
14654
14655        let raw_copy = |dst: u64,
14656                        src: u64,
14657                        bytes: usize,
14658                        engine: &Engine|
14659         -> Result<(), Box<dyn std::error::Error>> {
14660            unsafe {
14661                cu_try(
14662                    sys::cuMemcpyAsync(
14663                        dst as sys::CUdeviceptr,
14664                        src as sys::CUdeviceptr,
14665                        bytes,
14666                        engine.stream().cu_stream() as sys::CUstream,
14667                    ),
14668                    "routes graph cuMemcpyAsync",
14669                )
14670            }
14671        };
14672
14673        let mut children = Vec::with_capacity(3);
14674        for rank in 0..world {
14675            let engine = &self.ranks[rank];
14676            let _main = engine.gpu.enter_main()?;
14677            let (child, _retained) = engine.capture_graph_retained(|_| {
14678                raw_copy(p_input[rank], p_in_stage, width * 4, engine)?;
14679                raw_copy(p_sel[rank], p_sel_e, n_sel * 4, engine)?;
14680                raw_copy(p_route_w[rank], p_w_e, n_sel * 4, engine)?;
14681                {
14682                    let Nvfp4DeviceRoutesWorkspace {
14683                        input, in_q, in_d, ..
14684                    } = &mut *workspace;
14685                    engine.quantize_q8_1_into(
14686                        &input[rank],
14687                        1,
14688                        width,
14689                        &mut in_q[rank],
14690                        &mut in_d[rank],
14691                    )?;
14692                }
14693                self.nvfp4_routes_batched_sweeps_rank(
14694                    experts,
14695                    workspace,
14696                    &[],
14697                    &[],
14698                    &[],
14699                    local_out,
14700                    n_sel,
14701                    activation_limit,
14702                    true,
14703                    rank,
14704                )?;
14705                Ok(())
14706            })?;
14707            children.push(child);
14708        }
14709        {
14710            let root = &self.ranks[0];
14711            let _main = root.gpu.enter_main()?;
14712            let (child, _retained) = root.capture_graph_retained(|_| {
14713                raw_copy(p_remote, p_acc1, width * 4, root)?;
14714                {
14715                    let Nvfp4DeviceRoutesWorkspace {
14716                        accumulator,
14717                        remote,
14718                        combined,
14719                        ..
14720                    } = &mut *workspace;
14721                    root.add(&accumulator[0], remote, combined, width)?;
14722                }
14723                raw_copy(p_out_stage, p_combined, width * 4, root)?;
14724                Ok(())
14725            })?;
14726            children.push(child);
14727        }
14728
14729        let mut parent: sys::CUgraph = std::ptr::null_mut();
14730        unsafe {
14731            cu_try(sys::cuGraphCreate(&mut parent, 0), "routes cuGraphCreate")?;
14732        }
14733        let mut n0: sys::CUgraphNode = std::ptr::null_mut();
14734        let mut n1: sys::CUgraphNode = std::ptr::null_mut();
14735        let mut n2: sys::CUgraphNode = std::ptr::null_mut();
14736        unsafe {
14737            cu_try(
14738                sys::cuGraphAddChildGraphNode(
14739                    &mut n0,
14740                    parent,
14741                    std::ptr::null(),
14742                    0,
14743                    children[0].cu_graph(),
14744                ),
14745                "routes child r0",
14746            )?;
14747            cu_try(
14748                sys::cuGraphAddChildGraphNode(
14749                    &mut n1,
14750                    parent,
14751                    std::ptr::null(),
14752                    0,
14753                    children[1].cu_graph(),
14754                ),
14755                "routes child r1",
14756            )?;
14757            let deps = [n0, n1];
14758            cu_try(
14759                sys::cuGraphAddChildGraphNode(
14760                    &mut n2,
14761                    parent,
14762                    deps.as_ptr(),
14763                    2,
14764                    children[2].cu_graph(),
14765                ),
14766                "routes child root",
14767            )?;
14768        }
14769        let mut exec: sys::CUgraphExec = std::ptr::null_mut();
14770        unsafe {
14771            cu_try(
14772                sys::cuGraphInstantiateWithFlags(&mut exec, parent, 0),
14773                "routes instantiate",
14774            )?;
14775        }
14776        Ok(RoutesGraph {
14777            exec,
14778            parent,
14779            _children: children,
14780        })
14781    }
14782
14783    /// One rank's routes section for the token graph (event-free): staged input copy (raw
14784    /// when the caller supplies the source pointer), quantize, and the batched sweeps.
14785    /// Eager device_routed wraps it with the entry-event wait.
14786    #[allow(clippy::too_many_arguments)]
14787    pub(crate) fn routes_rank_section(
14788        &self,
14789        experts: &ResidentNvfp4TensorParallel,
14790        workspace: &mut Nvfp4DeviceRoutesWorkspace,
14791        raw_input_src: u64,
14792        local_out: usize,
14793        n_sel: usize,
14794        activation_limit: Option<f32>,
14795        rank_index: usize,
14796    ) -> Result<(), Box<dyn std::error::Error>> {
14797        let engine = &self.ranks[rank_index];
14798        {
14799            let _main = engine.gpu.enter_main()?;
14800            // sel/route_w land via raw copies from the e staging (fixed addresses).
14801            let (sel_e_ptr, w_e_ptr) = workspace
14802                .raw_dev_route_e
14803                .ok_or("routes rank section requires armed staging pointers")?;
14804            raw_copy_bytes(
14805                workspace.raw_input[rank_index],
14806                raw_input_src,
14807                experts.input_width * 4,
14808                engine,
14809            )?;
14810            raw_copy_bytes(workspace.raw_sel[rank_index], sel_e_ptr, n_sel * 4, engine)?;
14811            raw_copy_bytes(
14812                workspace.raw_route_w[rank_index],
14813                w_e_ptr,
14814                n_sel * 4,
14815                engine,
14816            )?;
14817            {
14818                let Nvfp4DeviceRoutesWorkspace {
14819                    input, in_q, in_d, ..
14820                } = &mut *workspace;
14821                engine.quantize_q8_1_into(
14822                    &input[rank_index],
14823                    1,
14824                    experts.input_width,
14825                    &mut in_q[rank_index],
14826                    &mut in_d[rank_index],
14827                )?;
14828            }
14829        }
14830        self.nvfp4_routes_batched_sweeps_rank(
14831            experts,
14832            workspace,
14833            &[],
14834            &[],
14835            &[],
14836            local_out,
14837            n_sel,
14838            activation_limit,
14839            true,
14840            rank_index,
14841        )
14842    }
14843
14844    /// The routes ROOT combine section (event-free): peer accumulator read (raw), canonical
14845    /// add, combined row raw-copied into the fixed e-context out stage.
14846    pub(crate) fn routes_root_section(
14847        &self,
14848        experts: &ResidentNvfp4TensorParallel,
14849        workspace: &mut Nvfp4DeviceRoutesWorkspace,
14850    ) -> Result<(), Box<dyn std::error::Error>> {
14851        let root = &self.ranks[0];
14852        let _main = root.gpu.enter_main()?;
14853        let (acc1_ptr, remote_ptr, combined_ptr, out_stage_ptr) = workspace
14854            .raw_combine
14855            .ok_or("routes root section requires armed combine pointers")?;
14856        raw_copy_bytes(remote_ptr, acc1_ptr, experts.input_width * 4, root)?;
14857        {
14858            let Nvfp4DeviceRoutesWorkspace {
14859                accumulator,
14860                remote,
14861                combined,
14862                ..
14863            } = &mut *workspace;
14864            root.add(&accumulator[0], remote, combined, experts.input_width)?;
14865        }
14866        raw_copy_bytes(out_stage_ptr, combined_ptr, experts.input_width * 4, root)?;
14867        Ok(())
14868    }
14869
14870    /// Arm the routes raw pointers (once): staging pair, per-rank input/sel/route_w, and the
14871    /// combine set. Requires dev_route_e + in/out stages already allocated.
14872    pub(crate) fn routes_arm_raw(
14873        &self,
14874        experts: &ResidentNvfp4TensorParallel,
14875        workspace: &mut Nvfp4DeviceRoutesWorkspace,
14876    ) -> Result<(), Box<dyn std::error::Error>> {
14877        use cudarc::driver::DevicePtr;
14878        if workspace.raw_dev_route_e.is_some() {
14879            return Ok(());
14880        }
14881        let _ = experts;
14882        let (sel_e, w_e) = workspace
14883            .dev_route_e
14884            .as_ref()
14885            .ok_or("routes staging not armed")?;
14886        let root = &self.ranks[0];
14887        {
14888            let _main = root.gpu.enter_main()?;
14889            let stream = root.stream();
14890            let (a, _g) = sel_e.device_ptr(&stream);
14891            let (b, _g) = w_e.device_ptr(&stream);
14892            workspace.raw_dev_route_e = Some((a, b));
14893            let (c, _g) = workspace.accumulator[1].device_ptr(&stream);
14894            let (d, _g) = workspace.remote.device_ptr(&stream);
14895            let (f, _g) = workspace.combined.device_ptr(&stream);
14896            let out_stage = workspace
14897                .out_stage_e
14898                .as_ref()
14899                .ok_or("routes out stage not armed")?;
14900            let (g_, _g) = out_stage.device_ptr(&stream);
14901            workspace.raw_combine = Some((c, d, f, g_));
14902        }
14903        for rank in 0..self.ranks.len() {
14904            let engine = &self.ranks[rank];
14905            let _main = engine.gpu.enter_main()?;
14906            let stream = engine.stream();
14907            let (a, _g) = workspace.input[rank].device_ptr(&stream);
14908            let (b, _g) = workspace.sel[rank].device_ptr(&stream);
14909            let (c, _g) = workspace.route_w[rank].device_ptr(&stream);
14910            workspace.raw_input.push(a);
14911            workspace.raw_sel.push(b);
14912            workspace.raw_route_w.push(c);
14913        }
14914        Ok(())
14915    }
14916
14917    /// Routed NVFP4 expert program, host-canonical transport. Native/bulk P2P transport for the
14918    /// NVFP4 bank is a separate increment; this entry point is exactness-first and reports no
14919    /// throughput claim.
14920    #[allow(clippy::too_many_arguments)] // allow: the parameter list mirrors the kernel/FFI/call contract; bundling into a struct is a refactor, not a lint fix
14921    pub fn run_tensor_parallel_routes_nvfp4(
14922        &self,
14923        experts: &ResidentNvfp4TensorParallel,
14924        input: &[f32],
14925        tokens: usize,
14926        selected: &[usize],
14927        route_weights: &[f32],
14928        experts_per_token: usize,
14929        activation_limit: Option<f32>,
14930    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
14931        validate_activations(input, tokens, experts.input_width)?;
14932        let pairs = tokens
14933            .checked_mul(experts_per_token)
14934            .ok_or("NVFP4 TP route count overflow")?;
14935        if selected.len() != pairs || route_weights.len() != pairs {
14936            return Err(format!(
14937                "NVFP4 TP routes selected={} weights={} != tokens {tokens} x experts/token \
14938                 {experts_per_token} ({pairs})",
14939                selected.len(),
14940                route_weights.len(),
14941            )
14942            .into());
14943        }
14944        if !route_weights.iter().all(|weight| weight.is_finite()) {
14945            return Err("NVFP4 TP route weights contain a non-finite value".into());
14946        }
14947
14948        let mut output = vec![0.0f32; tokens * experts.input_width];
14949        for token in 0..tokens {
14950            let input_row = &input[token * experts.input_width..(token + 1) * experts.input_width];
14951            for slot in 0..experts_per_token {
14952                let pair = token * experts_per_token + slot;
14953                let expert = selected[pair];
14954                if expert >= experts.expert_count {
14955                    return Err(format!(
14956                        "NVFP4 TP selected expert {expert} outside 0..{}",
14957                        experts.expert_count
14958                    )
14959                    .into());
14960                }
14961                // EP2 banks hold the WHOLE expert on rank (expert & 1) at slot (expert >> 1);
14962                // per-row dots are the same full-width program either way (a column shard
14963                // splits ROWS, not the dot), so gate/up are bit-equal across layouts. Only
14964                // down's parenthesization moves (full-width dot vs canonical 2-shard sum) —
14965                // the numeric-class this door declares.
14966                let gate = if experts.ep2 {
14967                    self.run_full_bank_expert_nvfp4(
14968                        &experts.gate,
14969                        &experts.macros_gate,
14970                        expert,
14971                        input_row,
14972                    )?
14973                } else {
14974                    self.run_column_bank_expert_nvfp4(
14975                        &experts.gate,
14976                        &experts.macros_gate,
14977                        expert,
14978                        input_row,
14979                    )?
14980                };
14981                let up = if experts.ep2 {
14982                    self.run_full_bank_expert_nvfp4(
14983                        &experts.up,
14984                        &experts.macros_up,
14985                        expert,
14986                        input_row,
14987                    )?
14988                } else {
14989                    self.run_column_bank_expert_nvfp4(
14990                        &experts.up,
14991                        &experts.macros_up,
14992                        expert,
14993                        input_row,
14994                    )?
14995                };
14996                let activated: Vec<f32> = gate
14997                    .iter()
14998                    .zip(&up)
14999                    .map(|(&gate, &up)| step_expert_activation_host(gate, up, activation_limit))
15000                    .collect();
15001                debug_assert_eq!(activated.len(), experts.expert_width);
15002                let down = if experts.ep2 {
15003                    self.run_full_down_expert_nvfp4(
15004                        &experts.down,
15005                        &experts.macros_down,
15006                        expert,
15007                        &activated,
15008                    )?
15009                } else {
15010                    self.run_row_bank_expert_nvfp4(
15011                        &experts.down,
15012                        &experts.macros_down,
15013                        expert,
15014                        &activated,
15015                    )?
15016                };
15017                let weight = route_weights[pair];
15018                for (sum, value) in output
15019                    [token * experts.input_width..(token + 1) * experts.input_width]
15020                    .iter_mut()
15021                    .zip(down)
15022                {
15023                    *sum += weight * value;
15024                }
15025            }
15026        }
15027        Ok(output)
15028    }
15029}
15030
15031#[cfg(test)]
15032mod default_on_door_tests {
15033    use super::door_default_on_value;
15034
15035    /// The DEFAULT-ON parse, pinned in every state — including the two that only matter because
15036    /// the default is ON.
15037    ///
15038    /// While these doors were default OFF the parse was `== Ok("1")` and its failure mode was
15039    /// benign: any typo read as the default, which was OFF, which was the safe program. Flipping
15040    /// the default INVERTS that. Under a naive `!= Ok("0")` rule, `MEMRA_NVFP4_BANK_SM=false`
15041    /// (or `=off`, or `=no`) would leave the program ARMED while the operator believed they had
15042    /// rolled it back — a rollback seam that silently does nothing, on the exact door whose
15043    /// predecessor shipped fluent wrong text. So the unrecognized-value case is a named,
15044    /// tested branch that keeps the default AND warns, rather than an accident of `!=`.
15045    #[test]
15046    fn the_default_on_door_parses_every_state_and_names_its_source() {
15047        // unset: the flip is what arms it, and the source string says so — this is the string a
15048        // default-flip receipt needs, because in the flip arms there is no env var to point at.
15049        assert_eq!(
15050            door_default_on_value("MEMRA_TEST_DOOR", None),
15051            (true, "default-on")
15052        );
15053        // explicit 1: armed by a RECIPE, not by the default. Different fact, different label.
15054        assert_eq!(
15055            door_default_on_value("MEMRA_TEST_DOOR", Some("1")),
15056            (true, "env=1")
15057        );
15058        // THE ROLLBACK SEAM. This is the assertion the flip's safety rests on.
15059        assert_eq!(
15060            door_default_on_value("MEMRA_TEST_DOOR", Some("0")),
15061            (false, "env=0 (rollback seam)")
15062        );
15063        // Unrecognized values keep the DEFAULT (ON) and are flagged as such, for every shape an
15064        // operator plausibly types when they mean "off". Every one of these MUST still read ON:
15065        // a parse that guessed "off" from `false` would be a second, undocumented seam, and a
15066        // parse that guessed "off" from `2` would make a typo a silent program change.
15067        for bad in [
15068            "false", "off", "no", "", " 0", "0 ", "00", "true", "2", "-1",
15069        ] {
15070            let (on, source) = door_default_on_value("MEMRA_TEST_DOOR", Some(bad));
15071            assert!(on, "value {bad:?} must NOT disarm a default-ON door");
15072            assert!(
15073                source.contains("default-on") && source.contains("unrecognized"),
15074                "value {bad:?} gave source {source:?}, which does not announce itself as an \
15075                 ignored value — a receipt reader would take it for a clean default"
15076            );
15077        }
15078    }
15079}
15080
15081#[cfg(test)]
15082mod bank_v2_layout_tests {
15083    use super::{nvfp4_matrix_v2_permute, nvfp4_row_bytes};
15084
15085    /// The slot-major permutation had NO test at all until 2026-08-29, while its (since
15086    /// removed) `MEMRA_NVFP4_BANK_V2` FLAGS row carried a bit-identity claim and the live
15087    /// serving env pinned it on. This pins the DOCUMENTED mapping so a reader can be checked
15088    /// against something: per row, slot g's 16 qs bytes land contiguously at `g*16`, and its
15089    /// two UE4M3 scale bytes at `nslots*16 + g*2`. Source layout is memra `block_nvfp4`:
15090    /// 36-byte superblocks of [4 scale bytes | 32 packed e2m1], two 32-value slots per
15091    /// superblock. Since the 2026-08-29 door removal the permutation's ONLY consumer is the
15092    /// EP2 whole-expert bank build (`nvfp4_repack_bank_matrix(_, true)`), whose `*_ep`
15093    /// kernels and `qmatvec_nvfp4_fast_v2` oracle read this exact mapping.
15094    #[test]
15095    fn the_v2_bank_row_is_the_documented_slot_major_permutation() {
15096        // two rows, in_features 128 => 2 superblocks/row, 4 slots/row, 72 bytes/row.
15097        let (out_f, in_f) = (2usize, 128usize);
15098        let row_bytes = nvfp4_row_bytes(in_f);
15099        assert_eq!(row_bytes, 72);
15100        let v1: Vec<u8> = (0..out_f * row_bytes).map(|i| (i % 251) as u8).collect();
15101        let v2 = nvfp4_matrix_v2_permute(&v1, out_f, in_f);
15102        assert_eq!(v2.len(), v1.len(), "a permutation cannot change the size");
15103        let n_slots = in_f / 32;
15104        for row in 0..out_f {
15105            let src = &v1[row * row_bytes..(row + 1) * row_bytes];
15106            let dst = &v2[row * row_bytes..(row + 1) * row_bytes];
15107            for g in 0..n_slots {
15108                let (sblk, h) = (g / 2, g % 2);
15109                let sb = &src[sblk * 36..sblk * 36 + 36];
15110                assert_eq!(
15111                    &dst[g * 16..g * 16 + 16],
15112                    &sb[4 + 16 * h..4 + 16 * h + 16],
15113                    "row {row} slot {g} codes"
15114                );
15115                assert_eq!(
15116                    &dst[n_slots * 16 + g * 2..n_slots * 16 + g * 2 + 2],
15117                    &sb[2 * h..2 * h + 2],
15118                    "row {row} slot {g} scales"
15119                );
15120            }
15121            // and it moves bytes only: same multiset per row, rows never cross.
15122            let (mut a, mut b) = (src.to_vec(), dst.to_vec());
15123            a.sort_unstable();
15124            b.sort_unstable();
15125            assert_eq!(a, b, "row {row} is not a byte permutation");
15126        }
15127    }
15128}
15129
15130#[cfg(test)]
15131mod tests {
15132
15133    #[test]
15134    fn door_composition_refuses_first_armed_flag_by_name() {
15135        let table: [(&str, &str); 2] = [
15136            ("MEMRA_DOOR_A", "gated on the unsharded walk only"),
15137            ("MEMRA_DOOR_B", "no sharded branches"),
15138        ];
15139        // cold doors pass
15140        super::refuse_door_composition("MEMRA_X_TP", &table, |_| false).expect("cold doors pass");
15141        // an armed door refuses with the exact byte format the glm5 gate asserts on
15142        let err = super::refuse_door_composition("MEMRA_X_TP", &table, |f| f == "MEMRA_DOOR_B")
15143            .expect_err("armed door must refuse");
15144        assert_eq!(
15145            err,
15146            "MEMRA_X_TP + MEMRA_DOOR_B: unproven composition, refused (no sharded branches)"
15147        );
15148        // a flag outside the table never trips it
15149        super::refuse_door_composition("MEMRA_X_TP", &table, |f| f == "MEMRA_DOOR_C")
15150            .expect("foreign flags are not the matrix");
15151    }
15152
15153    /// THE DEFECT, ASSERTED SO IT CANNOT COME BACK. The retired memo key hashed only the K
15154    /// pointer, the base pointer, the layer and t, while the table it returned ALSO carried
15155    /// the V and LEN pointers. Two different allocation generations that happen to share a K
15156    /// address therefore collide, and the entry the map hands back sends a live launch at
15157    /// another allocation's V and len. This test does not assert the key is fine; it asserts
15158    /// the key is BLIND, which is why `rows_tab_restage_on` exists and defaults ON.
15159    #[test]
15160    fn the_retired_rows_tab_key_cannot_see_the_v_and_len_pointers_it_hands_back() {
15161        let (kp, bp) = (0xdead_0000u64, 0u64);
15162        let live = [[kp, 0x00b1_0000u64, 0x00c1_0000u64, bp]];
15163        let recycled = [[kp, 0x00b2_0000u64, 0x00c2_0000u64, bp]];
15164        assert_eq!(
15165            super::retired_rows_tab_key(kp, bp, 20, 2),
15166            super::retired_rows_tab_key(kp, bp, 20, 2),
15167            "same layer and t must hash the same, or the test proves nothing"
15168        );
15169        let a = super::rows_tab_host(&live, 0x9000, true, 1);
15170        let b = super::rows_tab_host(&recycled, 0x9000, true, 1);
15171        assert_ne!(a, b, "the two generations write DIFFERENT tables");
15172        // ... yet one key covers both, which is exactly the use-after-free.
15173        assert_eq!(
15174            super::retired_rows_tab_key(live[0][0], live[0][3], 20, 1),
15175            super::retired_rows_tab_key(recycled[0][0], recycled[0][3], 20, 1),
15176            "the retired key collides across allocation generations"
15177        );
15178    }
15179
15180    /// The restage must be VALUE-NEUTRAL: on a fresh lookup the memo and the restage produce
15181    /// identical bytes, which is what makes spec-on output byte-identical to spec-off.
15182    #[test]
15183    fn rows_tab_layout_is_the_same_bytes_the_memo_would_have_cached() {
15184        let parts = [
15185            [0x00a0u64, 0x00b0u64, 0x00c0u64, 0x00d0u64],
15186            [0x00a1u64, 0x00b1u64, 0x00c1u64, 0x00d1u64],
15187        ];
15188        let same = super::rows_tab_host(&parts, 0x7000, true, 2);
15189        assert_eq!(
15190            same,
15191            vec![
15192                0x00a0u64, 0x00b0u64, 0x00c0u64, 0x00d0u64, 0x7000,
15193                1, // row 0: back = t-1-r = 1
15194                0x00a1u64, 0x00b1u64, 0x00c1u64, 0x00d1u64, 0x7000, 0, // row 1: back = 0
15195            ],
15196            "same-session rows share one counter cell and step back t-1-r"
15197        );
15198        let cross = super::rows_tab_host(&parts, 0x7000, false, 2);
15199        assert_eq!(
15200            cross,
15201            vec![
15202                0x00a0u64, 0x00b0u64, 0x00c0u64, 0x00d0u64, 0x7000, 0, 0x00a1u64, 0x00b1u64,
15203                0x00c1u64, 0x00d1u64, 0x7004, 0,
15204            ],
15205            "cross-session rows get their own counter cell and no step back"
15206        );
15207    }
15208    use super::*;
15209
15210    #[test]
15211    fn step_expert_activation_clamps_each_arm_by_the_official_contract() {
15212        let limit = Some(7.0);
15213        assert_eq!(step_expert_activation_host(20.0, 9.0, limit), 49.0);
15214        assert_eq!(step_expert_activation_host(20.0, -9.0, limit), -49.0);
15215        assert!(
15216            step_expert_activation_host(-20.0, 9.0, limit).abs()
15217                < step_expert_activation_host(-20.0, 9.0, None).abs()
15218        );
15219        assert!(validate_step_expert_activation_limit(Some(f32::NAN)).is_err());
15220        assert!(validate_step_expert_activation_limit(Some(0.0)).is_err());
15221        assert!(validate_step_expert_activation_limit(limit).is_ok());
15222    }
15223
15224    #[test]
15225    fn moe_residual_host_preserves_official_add_order() {
15226        let output = moe_residual_host(&[1.0e20], &[-1.0e20], &[1.0]).unwrap();
15227        assert_eq!(output, [0.0]);
15228        assert_eq!(
15229            moe_residual_host(&[0.0], &[0.0, 1.0], &[0.0]).unwrap_err(),
15230            "MoE residual lengths residual=1 routed=2 shared=1"
15231        );
15232    }
15233
15234    #[test]
15235    fn expert_owner_routes_preserve_global_pair_order_with_local_expert_ids() {
15236        let selected = [0, 36, 72, 108, 144, 180, 216, 252];
15237        let owners = partition_expert_owner_routes(288, 4, 1, 8, &selected).unwrap();
15238        assert_eq!(owners.len(), 4);
15239        for (rank, owner) in owners.iter().enumerate() {
15240            assert_eq!(owner.rank, rank);
15241            assert_eq!(owner.selected, vec![0, 36]);
15242            assert_eq!(owner.token_rows, vec![0, 0]);
15243            assert_eq!(owner.global_pairs, vec![rank * 2, rank * 2 + 1]);
15244        }
15245    }
15246
15247    #[test]
15248    fn expert_owner_routes_validate_geometry_and_selected_experts() {
15249        assert!(partition_expert_owner_routes(288, 5, 1, 8, &[0; 8]).is_err());
15250        assert!(partition_expert_owner_routes(288, 4, 2, 8, &[0; 8]).is_err());
15251        let error = partition_expert_owner_routes(288, 4, 1, 8, &[288; 8]).unwrap_err();
15252        assert!(error.contains("outside 0..288"));
15253    }
15254
15255    #[test]
15256    fn step_grouped_owner_routes_validate_dynamic_top8_shapes() {
15257        let selected = [
15258            1, 73, 80, 145, 152, 159, 217, 224, 12, 84, 91, 156, 163, 170, 228, 235,
15259        ];
15260        assert_eq!(
15261            validate_step_grouped_owner_routes(288, 2, &selected).unwrap(),
15262            16
15263        );
15264        let owners = partition_expert_owner_routes(288, 4, 2, 8, &selected).unwrap();
15265        assert_eq!(
15266            owners
15267                .iter()
15268                .map(|owner| owner.selected.len())
15269                .collect::<Vec<_>>(),
15270            vec![2, 4, 6, 4]
15271        );
15272        assert!(validate_step_grouped_owner_routes(288, 2, &selected[..8]).is_err());
15273        assert!(validate_step_grouped_owner_routes(288, 1, &[0; 8]).is_err());
15274        assert!(validate_step_grouped_owner_routes(287, 2, &selected).is_err());
15275    }
15276
15277    #[test]
15278    fn weighted_route_combine_requires_a_canonical_pair_permutation() {
15279        let owner0 = [0usize, 3];
15280        let owner1 = [1usize, 2];
15281        let owners = [owner0.as_slice(), owner1.as_slice()];
15282        assert_eq!(
15283            validate_weighted_route_combine(4096, 4, 3, 1, &owners, &[0.1, 0.2, 0.3, 0.4],)
15284                .unwrap(),
15285            WeightedRouteCombineShape {
15286                pairs: 4,
15287                max_pairs: 12,
15288            }
15289        );
15290        let duplicate = [owner0.as_slice(), &[1usize, 1][..]];
15291        assert!(
15292            validate_weighted_route_combine(4096, 4, 3, 1, &duplicate, &[0.1, 0.2, 0.3, 0.4],)
15293                .is_err()
15294        );
15295        assert!(
15296            validate_weighted_route_combine(4096, 4, 3, 1, &owners, &[0.1, f32::NAN, 0.3, 0.4],)
15297                .is_err()
15298        );
15299        assert!(
15300            validate_weighted_route_combine(4096, 4, 1, 2, &owners, &[0.1, 0.2, 0.3, 0.4],)
15301                .is_err()
15302        );
15303    }
15304
15305    #[test]
15306    fn native_p2p_door_is_strict_and_default_off() {
15307        assert!(!parse_step_tp_native_p2p(None).unwrap());
15308        assert!(!parse_step_tp_native_p2p(Some("")).unwrap());
15309        assert!(!parse_step_tp_native_p2p(Some("0")).unwrap());
15310        assert!(parse_step_tp_native_p2p(Some("1")).unwrap());
15311        assert!(parse_step_tp_native_p2p(Some("true")).is_err());
15312        assert!(parse_step_tp_native_p2p(Some("2")).is_err());
15313    }
15314
15315    #[test]
15316    fn bulk_p2p_door_is_strict_and_default_off() {
15317        assert!(!parse_step_tp_bulk_p2p(None).unwrap());
15318        assert!(!parse_step_tp_bulk_p2p(Some("")).unwrap());
15319        assert!(!parse_step_tp_bulk_p2p(Some("0")).unwrap());
15320        assert!(parse_step_tp_bulk_p2p(Some("1")).unwrap());
15321        assert!(parse_step_tp_bulk_p2p(Some("true")).is_err());
15322        assert!(parse_step_tp_bulk_p2p(Some("2")).is_err());
15323    }
15324
15325    #[test]
15326    fn ep_device_arithmetic_door_is_strict_and_default_off() {
15327        assert!(!parse_step_ep_device_arithmetic(None).unwrap());
15328        assert!(!parse_step_ep_device_arithmetic(Some("")).unwrap());
15329        assert!(!parse_step_ep_device_arithmetic(Some("0")).unwrap());
15330        assert!(parse_step_ep_device_arithmetic(Some("1")).unwrap());
15331        assert!(parse_step_ep_device_arithmetic(Some("true")).is_err());
15332        assert!(parse_step_ep_device_arithmetic(Some("2")).is_err());
15333    }
15334
15335    #[test]
15336    fn f32_mirror_door_is_strict_and_default_off() {
15337        assert!(!parse_step_tp_f32_mirror(None).unwrap());
15338        assert!(!parse_step_tp_f32_mirror(Some("")).unwrap());
15339        assert!(!parse_step_tp_f32_mirror(Some("0")).unwrap());
15340        assert!(parse_step_tp_f32_mirror(Some("1")).unwrap());
15341        assert!(parse_step_tp_f32_mirror(Some("true")).is_err());
15342        assert!(parse_step_tp_f32_mirror(Some("2")).is_err());
15343    }
15344
15345    fn matrix(out_features: usize, in_features: usize) -> (Vec<u8>, Vec<f32>) {
15346        let codes = (0..out_features * in_features)
15347            .map(|index| (index % 251) as u8)
15348            .collect();
15349        let scales = (0..out_features.div_ceil(FP8_BLOCK) * in_features.div_ceil(FP8_BLOCK))
15350            .map(|index| index as f32 + 1.0)
15351            .collect();
15352        (codes, scales)
15353    }
15354
15355    fn bf16_matrix_bytes(out_features: usize, in_features: usize) -> Vec<u8> {
15356        (0..out_features * in_features)
15357            .flat_map(|value| (value as u16).to_le_bytes())
15358            .collect()
15359    }
15360
15361    fn decode_u16(bytes: &[u8]) -> Vec<u16> {
15362        bytes
15363            .chunks_exact(2)
15364            .map(|bytes| u16::from_le_bytes([bytes[0], bytes[1]]))
15365            .collect()
15366    }
15367
15368    #[test]
15369    fn bf16_matrix_rejects_wrong_byte_count() {
15370        let bytes = vec![0u8; 4 * 4 * 2 - 1];
15371        let matrix = Bf16Matrix {
15372            bytes: &bytes,
15373            out_features: 4,
15374            in_features: 4,
15375        };
15376        assert!(matrix.validate().unwrap_err().contains("4x4x2"));
15377    }
15378
15379    #[test]
15380    fn replicated_device_rows_require_exact_rank_local_shapes() {
15381        assert_eq!(
15382            replicated_device_row_values(3, 4096, 4, &[12_288; 4]).unwrap(),
15383            12_288
15384        );
15385        assert!(replicated_device_row_values(0, 4096, 4, &[0; 4]).is_err());
15386        assert!(replicated_device_row_values(3, 0, 4, &[0; 4]).is_err());
15387        assert!(replicated_device_row_values(3, 4096, 4, &[12_288; 3]).is_err());
15388        assert!(
15389            replicated_device_row_values(3, 4096, 4, &[12_288, 12_288, 12_287, 12_288]).is_err()
15390        );
15391        assert!(replicated_device_row_values(usize::MAX, 2, 1, &[0]).is_err());
15392    }
15393
15394    #[test]
15395    fn replicated_device_row_refresh_requires_exact_root_source() {
15396        assert_eq!(
15397            replicated_device_row_source_values(1, 12_288, 12_288, 3, 3).unwrap(),
15398            12_288
15399        );
15400        assert!(replicated_device_row_source_values(0, 12_288, 0, 3, 3).is_err());
15401        assert!(replicated_device_row_source_values(1, 0, 0, 3, 3).is_err());
15402        assert!(replicated_device_row_source_values(1, 12_288, 12_287, 3, 3).is_err());
15403        assert!(replicated_device_row_source_values(1, 12_288, 12_288, 2, 3).is_err());
15404        assert!(replicated_device_row_source_values(usize::MAX, 2, 0, 3, 3).is_err());
15405    }
15406
15407    #[test]
15408    fn step_bf16_canonical_rows_are_topology_invariant_through_tp8() {
15409        for tp in [1, 2, 4, 8] {
15410            assert_eq!(step_bf16_canonical_chunk_rows(8_192, tp).unwrap(), 1_024);
15411            assert_eq!(step_bf16_canonical_chunk_rows(12_288, tp).unwrap(), 1_536);
15412            assert_eq!(step_bf16_canonical_chunk_rows(1_024, tp).unwrap(), 128);
15413            assert_eq!(step_bf16_canonical_chunk_cols(8_192, tp).unwrap(), 1_024);
15414            assert_eq!(step_bf16_canonical_chunk_cols(12_288, tp).unwrap(), 1_536);
15415        }
15416        assert!(step_bf16_canonical_chunk_rows(12_288, 3).is_err());
15417        assert!(step_bf16_canonical_chunk_rows(1_001, 2).is_err());
15418        assert!(step_bf16_canonical_chunk_cols(12_288, 3).is_err());
15419        assert!(step_bf16_canonical_chunk_cols(1_001, 2).is_err());
15420    }
15421
15422    #[test]
15423    fn cache_rows_split_by_token_then_rank() {
15424        let rows = (0u8..24).collect::<Vec<_>>();
15425        assert_eq!(
15426            cache_rank_rows(&rows, 3, 4, 2, 0).unwrap(),
15427            vec![0, 1, 2, 3, 8, 9, 10, 11, 16, 17, 18, 19]
15428        );
15429        assert_eq!(
15430            cache_rank_rows(&rows, 3, 4, 2, 1).unwrap(),
15431            vec![4, 5, 6, 7, 12, 13, 14, 15, 20, 21, 22, 23]
15432        );
15433        assert!(cache_rank_rows(&rows[..23], 3, 4, 2, 0).is_err());
15434        assert!(cache_rank_rows(&rows, 3, 4, 2, 2).is_err());
15435    }
15436
15437    #[test]
15438    fn bf16_column_shard_preserves_contiguous_output_rows() {
15439        let bytes = bf16_matrix_bytes(4, 4);
15440        let matrix = Bf16Matrix {
15441            bytes: &bytes,
15442            out_features: 4,
15443            in_features: 4,
15444        };
15445        let shard = bf16_column_shard(matrix, 2, 1).unwrap();
15446        assert_eq!(shard.out_features, 2);
15447        assert_eq!(shard.in_features, 4);
15448        assert_eq!(decode_u16(shard.bytes), (8..16).collect::<Vec<_>>());
15449    }
15450
15451    #[test]
15452    fn bf16_row_shard_preserves_each_input_column_window() {
15453        let bytes = bf16_matrix_bytes(3, 4);
15454        let matrix = Bf16Matrix {
15455            bytes: &bytes,
15456            out_features: 3,
15457            in_features: 4,
15458        };
15459        let shard = bf16_row_shard(matrix, 2, 1).unwrap();
15460        assert_eq!(decode_u16(&shard), vec![2, 3, 6, 7, 10, 11]);
15461    }
15462
15463    #[test]
15464    fn bf16_row_block_preserves_global_column_order() {
15465        let bytes = bf16_matrix_bytes(3, 8);
15466        let matrix = Bf16Matrix {
15467            bytes: &bytes,
15468            out_features: 3,
15469            in_features: 8,
15470        };
15471        let block = bf16_row_block(matrix, 2, 3).unwrap();
15472        assert_eq!(decode_u16(&block), vec![2, 3, 4, 10, 11, 12, 18, 19, 20]);
15473    }
15474
15475    #[test]
15476    fn column_shard_preserves_contiguous_weight_and_scale_rows() {
15477        let (codes, scales) = matrix(1280, 4096);
15478        let matrix = E4m3BlockMatrix {
15479            codes: &codes,
15480            scales: &scales,
15481            out_features: 1280,
15482            in_features: 4096,
15483        };
15484        let shard = column_shard(matrix, 2, 1).unwrap();
15485        assert_eq!(shard.out_features, 640);
15486        assert_eq!(shard.codes, &codes[640 * 4096..]);
15487        assert_eq!(shard.scales, &scales[5 * 32..]);
15488    }
15489
15490    #[test]
15491    fn row_shard_preserves_each_weight_and_scale_column_window() {
15492        let (codes, scales) = matrix(4096, 1280);
15493        let matrix = E4m3BlockMatrix {
15494            codes: &codes,
15495            scales: &scales,
15496            out_features: 4096,
15497            in_features: 1280,
15498        };
15499        let (shard_codes, shard_scales) = row_shard(matrix, 2, 1).unwrap();
15500        assert_eq!(shard_codes.len(), 4096 * 640);
15501        assert_eq!(&shard_codes[..640], &codes[640..1280]);
15502        assert_eq!(&shard_codes[640..1280], &codes[1280 + 640..2560]);
15503        assert_eq!(shard_scales.len(), 32 * 5);
15504        assert_eq!(&shard_scales[..5], &scales[5..10]);
15505        assert_eq!(&shard_scales[5..10], &scales[15..20]);
15506    }
15507
15508    #[test]
15509    fn activation_shards_keep_token_rows_separate() {
15510        let activations: Vec<f32> = (0..2 * 8).map(|value| value as f32).collect();
15511        assert_eq!(
15512            activation_shard(&activations, 2, 8, 2, 1),
15513            vec![4.0, 5.0, 6.0, 7.0, 12.0, 13.0, 14.0, 15.0],
15514        );
15515    }
15516
15517    #[test]
15518    fn expert_bank_selects_expert_major_code_and_scale_planes() {
15519        let expert_count = 2;
15520        let out_features = 128;
15521        let in_features = 128;
15522        let code_stride = out_features * in_features;
15523        let codes: Vec<u8> = (0..expert_count * code_stride)
15524            .map(|index| (index % 251) as u8)
15525            .collect();
15526        let scales = vec![1.0f32, 2.0];
15527        let bank = E4m3ExpertBank {
15528            codes: &codes,
15529            scales: &scales,
15530            expert_count,
15531            out_features,
15532            in_features,
15533        };
15534        bank.validate().unwrap();
15535        let expert = bank.expert(1).unwrap();
15536        assert_eq!(expert.codes, &codes[code_stride..]);
15537        assert_eq!(expert.scales, &[2.0]);
15538    }
15539
15540    #[test]
15541    fn expert_bank_rejects_non_positive_scale() {
15542        let codes = vec![0u8; 128 * 128];
15543        let scales = vec![0.0f32];
15544        let bank = E4m3ExpertBank {
15545            codes: &codes,
15546            scales: &scales,
15547            expert_count: 1,
15548            out_features: 128,
15549            in_features: 128,
15550        };
15551        assert!(bank.validate().unwrap_err().contains("non-positive"));
15552    }
15553
15554    #[test]
15555    fn tensor_parallel_column_bank_keeps_each_expert_scale_plane_separate() {
15556        let expert_count = 2;
15557        let out_features = 256;
15558        let in_features = 128;
15559        let code_stride = out_features * in_features;
15560        let scale_stride = 2;
15561        let codes = (0..expert_count * code_stride)
15562            .map(|index| (index % 251) as u8)
15563            .collect::<Vec<_>>();
15564        let scales = vec![10.0f32, 11.0, 20.0, 21.0];
15565        let bank = E4m3ExpertBank {
15566            codes: &codes,
15567            scales: &scales,
15568            expert_count,
15569            out_features,
15570            in_features,
15571        };
15572
15573        let rank = pack_column_bank_rank(bank, 2, 1).unwrap();
15574        assert_eq!(rank.out_features, 128);
15575        assert_eq!(rank.in_features, 128);
15576        assert_eq!(rank.codes.len(), expert_count * 128 * 128);
15577        assert_eq!(rank.scales, vec![11.0, 21.0]);
15578        assert_eq!(&rank.codes[..128 * 128], &codes[128 * 128..256 * 128]);
15579        assert_eq!(
15580            &rank.codes[128 * 128..],
15581            &codes[code_stride + 128 * 128..2 * code_stride]
15582        );
15583        assert_eq!(scale_stride, scales.len() / expert_count);
15584    }
15585
15586    #[test]
15587    fn tensor_parallel_row_bank_keeps_each_expert_scale_plane_separate() {
15588        let expert_count = 2;
15589        let out_features = 128;
15590        let in_features = 256;
15591        let code_stride = out_features * in_features;
15592        let codes = (0..expert_count * code_stride)
15593            .map(|index| (index % 251) as u8)
15594            .collect::<Vec<_>>();
15595        let scales = vec![10.0f32, 11.0, 20.0, 21.0];
15596        let bank = E4m3ExpertBank {
15597            codes: &codes,
15598            scales: &scales,
15599            expert_count,
15600            out_features,
15601            in_features,
15602        };
15603
15604        let rank = pack_row_bank_rank(bank, 2, 1).unwrap();
15605        assert_eq!(rank.out_features, 128);
15606        assert_eq!(rank.in_features, 128);
15607        assert_eq!(rank.k_blocks, Some(1));
15608        assert_eq!(rank.codes.len(), expert_count * 128 * 128);
15609        assert_eq!(rank.scales, vec![11.0, 21.0]);
15610        assert_eq!(&rank.codes[..128], &codes[128..256]);
15611        assert_eq!(
15612            &rank.codes[128 * 128..128 * 128 + 128],
15613            &codes[code_stride + 128..code_stride + 256]
15614        );
15615    }
15616
15617    #[test]
15618    fn tensor_parallel_row_bank_preserves_global_k_block_order() {
15619        let expert_count = 2;
15620        let out_features = 256;
15621        let in_features = 512;
15622        let code_stride = out_features * in_features;
15623        let mut codes = vec![0u8; expert_count * code_stride];
15624        for expert in 0..expert_count {
15625            for row in 0..out_features {
15626                for block in 0..4 {
15627                    let value = (expert * 80 + block * 16 + row % 16) as u8;
15628                    let start = expert * code_stride + row * in_features + block * FP8_BLOCK;
15629                    codes[start..start + FP8_BLOCK].fill(value);
15630                }
15631            }
15632        }
15633        let scales = vec![
15634            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,
15635            112.0, 113.0, 114.0,
15636        ];
15637        let bank = E4m3ExpertBank {
15638            codes: &codes,
15639            scales: &scales,
15640            expert_count,
15641            out_features,
15642            in_features,
15643        };
15644
15645        let rank = pack_row_bank_rank(bank, 2, 1).unwrap();
15646        assert_eq!(rank.out_features, out_features);
15647        assert_eq!(rank.in_features, 256);
15648        assert_eq!(rank.k_blocks, Some(2));
15649        assert_eq!(rank.code_stride, out_features * 256);
15650        assert_eq!(rank.scale_stride, 4);
15651        assert_eq!(&rank.scales[..4], &[3.0, 13.0, 4.0, 14.0]);
15652        assert_eq!(&rank.scales[4..], &[103.0, 113.0, 104.0, 114.0]);
15653
15654        let block_stride = out_features * FP8_BLOCK;
15655        assert!(rank.codes[..FP8_BLOCK].iter().all(|&code| code == 32));
15656        assert!(
15657            rank.codes[block_stride..block_stride + FP8_BLOCK]
15658                .iter()
15659                .all(|&code| code == 48)
15660        );
15661        assert!(
15662            rank.codes[rank.code_stride..rank.code_stride + FP8_BLOCK]
15663                .iter()
15664                .all(|&code| code == 112)
15665        );
15666        assert!(
15667            rank.codes
15668                [rank.code_stride + block_stride..rank.code_stride + block_stride + FP8_BLOCK]
15669                .iter()
15670                .all(|&code| code == 128)
15671        );
15672    }
15673
15674    #[test]
15675    fn automatic_parallel_policy_needs_only_one_device_set_not_layer_recipes() {
15676        assert_eq!(parse_auto_parallel_devices(None, None).unwrap(), None);
15677        assert_eq!(
15678            parse_auto_parallel_devices(Some("auto"), Some("0,1,2,3")).unwrap(),
15679            Some(vec![0, 1, 2, 3])
15680        );
15681        assert!(parse_auto_parallel_devices(Some("auto"), None).is_err());
15682        assert!(parse_auto_parallel_devices(Some("auto"), Some("0,1,1")).is_err());
15683        assert!(parse_auto_parallel_devices(Some("auto"), Some("0,1,2,3,4")).is_err());
15684        assert!(parse_auto_parallel_devices(Some("ep"), Some("0,1")).is_err());
15685    }
15686
15687    #[test]
15688    fn automatic_ep_device_router_flag_is_strict() {
15689        assert!(!parse_parallel_ep_device_router(None).unwrap());
15690        assert!(!parse_parallel_ep_device_router(Some("0")).unwrap());
15691        assert!(parse_parallel_ep_device_router(Some("1")).unwrap());
15692        assert!(parse_parallel_ep_device_router(Some("true")).is_err());
15693    }
15694
15695    #[test]
15696    fn automatic_ep_graph_flag_is_strict_and_defaults_off() {
15697        assert!(!parse_parallel_ep_graph(None).unwrap());
15698        assert!(!parse_parallel_ep_graph(Some("0")).unwrap());
15699        assert!(parse_parallel_ep_graph(Some("1")).unwrap());
15700        assert!(parse_parallel_ep_graph(Some("true")).is_err());
15701    }
15702
15703    #[test]
15704    fn automatic_ep_pair_down_flag_is_strict_and_defaults_off() {
15705        assert!(!parse_parallel_ep_pair_down(None).unwrap());
15706        assert!(!parse_parallel_ep_pair_down(Some("0")).unwrap());
15707        assert!(parse_parallel_ep_pair_down(Some("1")).unwrap());
15708        assert!(parse_parallel_ep_pair_down(Some("true")).is_err());
15709    }
15710
15711    #[test]
15712    fn automatic_ep_q8_activation_flag_is_strict() {
15713        assert!(!parse_parallel_ep_q8_act(None).unwrap());
15714        assert!(!parse_parallel_ep_q8_act(Some("0")).unwrap());
15715        assert!(parse_parallel_ep_q8_act(Some("1")).unwrap());
15716        assert!(parse_parallel_ep_q8_act(Some("true")).is_err());
15717    }
15718
15719    #[test]
15720    fn automatic_ep_q8_scope_is_explicit_and_strict() {
15721        assert_eq!(parse_parallel_ep_q8_scope(None).unwrap(), None);
15722        assert_eq!(
15723            parse_parallel_ep_q8_scope(Some("all")).unwrap(),
15724            Some(ParallelEpQ8Scope::All)
15725        );
15726        assert_eq!(
15727            parse_parallel_ep_q8_scope(Some("gate-up")).unwrap(),
15728            Some(ParallelEpQ8Scope::GateUp)
15729        );
15730        assert_eq!(
15731            parse_parallel_ep_q8_scope(Some("down")).unwrap(),
15732            Some(ParallelEpQ8Scope::Down)
15733        );
15734        assert!(parse_parallel_ep_q8_scope(Some("input")).is_err());
15735    }
15736
15737    #[test]
15738    fn automatic_ep_q8_gate_up_paired_is_parent_scoped_and_strict() {
15739        assert_eq!(parse_parallel_ep_q8_gu_paired(None).unwrap(), None);
15740        assert_eq!(parse_parallel_ep_q8_gu_paired(Some("")).unwrap(), None);
15741        assert_eq!(
15742            parse_parallel_ep_q8_gu_paired(Some("0")).unwrap(),
15743            Some(false)
15744        );
15745        assert_eq!(
15746            parse_parallel_ep_q8_gu_paired(Some("1")).unwrap(),
15747            Some(true)
15748        );
15749        assert!(parse_parallel_ep_q8_gu_paired(Some("paired")).is_err());
15750        assert!(parse_parallel_ep_q8_gu_paired(Some("true")).is_err());
15751
15752        assert!(!resolve_parallel_ep_q8_gu_paired(None, false, None).unwrap());
15753        assert!(resolve_parallel_ep_q8_gu_paired(None, true, None).unwrap());
15754        assert!(
15755            resolve_parallel_ep_q8_gu_paired(None, true, Some(ParallelEpQ8Scope::GateUp)).unwrap()
15756        );
15757        assert!(
15758            !resolve_parallel_ep_q8_gu_paired(None, true, Some(ParallelEpQ8Scope::Down)).unwrap()
15759        );
15760        assert!(!resolve_parallel_ep_q8_gu_paired(Some("0"), false, None).unwrap());
15761        assert!(!resolve_parallel_ep_q8_gu_paired(Some("0"), true, None).unwrap());
15762        assert!(resolve_parallel_ep_q8_gu_paired(Some("1"), false, None).is_err());
15763        assert!(
15764            resolve_parallel_ep_q8_gu_paired(Some("1"), true, Some(ParallelEpQ8Scope::Down))
15765                .is_err()
15766        );
15767    }
15768
15769    #[test]
15770    fn w4a16_device_ep_accepts_a_capacity_backed_active_prefix() {
15771        let width = 4096;
15772        assert_eq!(
15773            nvfp4_ep_active_input_values(160 * width, 44, width).unwrap(),
15774            44 * width
15775        );
15776        assert_eq!(
15777            nvfp4_ep_active_input_values(44 * width, 44, width).unwrap(),
15778            44 * width
15779        );
15780        assert!(nvfp4_ep_active_input_values(43 * width, 44, width).is_err());
15781        assert!(
15782            nvfp4_ep_active_input_values(160 * width, NVFP4_EP_DEVICE_BATCH_CAP + 1, width)
15783                .is_err()
15784        );
15785    }
15786
15787    #[test]
15788    fn step_ep_layer_specs_are_literal_and_fail_closed() {
15789        assert!(parse_step_ep_layer_specs(None).unwrap().is_empty());
15790        assert!(parse_step_ep_layer_specs(Some("0")).unwrap().is_empty());
15791        assert_eq!(
15792            parse_step_ep_layer_specs(Some("24@1,2")).unwrap(),
15793            vec![StepEpLayerSpec {
15794                layer: 24,
15795                devices: vec![1, 2],
15796            }]
15797        );
15798        assert_eq!(
15799            parse_step_ep_layer_specs(Some("24-25@1,2;31@0,2")).unwrap(),
15800            vec![
15801                StepEpLayerSpec {
15802                    layer: 24,
15803                    devices: vec![1, 2],
15804                },
15805                StepEpLayerSpec {
15806                    layer: 25,
15807                    devices: vec![1, 2],
15808                },
15809                StepEpLayerSpec {
15810                    layer: 31,
15811                    devices: vec![0, 2],
15812                },
15813            ]
15814        );
15815        assert!(parse_step_ep_layer_specs(Some("24@1")).is_err());
15816        assert!(parse_step_ep_layer_specs(Some("24@1,1")).is_err());
15817        assert!(parse_step_ep_layer_specs(Some("layer@1,2")).is_err());
15818        assert!(parse_step_ep_layer_specs(Some("25-24@1,2")).is_err());
15819        assert!(parse_step_ep_layer_specs(Some("0-128@1,2")).is_err());
15820        assert!(parse_step_ep_layer_specs(Some("24-25@1,2;25@0,2")).is_err());
15821        assert!(parse_step_ep_layer_specs(Some("all@0,1")).is_err());
15822    }
15823
15824    #[test]
15825    fn step_tp_layer_specs_share_the_fail_closed_layer_contract() {
15826        assert!(parse_step_tp_layer_specs(None).unwrap().is_empty());
15827        assert!(parse_step_tp_layer_specs(Some("0")).unwrap().is_empty());
15828        assert_eq!(
15829            parse_step_tp_layer_specs(Some("24-25@1,2")).unwrap(),
15830            vec![
15831                StepTpLayerSpec {
15832                    layer: 24,
15833                    devices: vec![1, 2],
15834                },
15835                StepTpLayerSpec {
15836                    layer: 25,
15837                    devices: vec![1, 2],
15838                },
15839            ]
15840        );
15841        let error = parse_step_tp_layer_specs(Some("24@1")).unwrap_err();
15842        assert!(error.contains("MEMRA_STEP_TP"));
15843        assert!(parse_step_tp_layer_specs(Some("24@1,1")).is_err());
15844        assert!(parse_step_tp_layer_specs(Some("24-25@1,2;25@0,2")).is_err());
15845
15846        let all = parse_step_tp_layer_specs(Some("all@0,1,2,3,4,5,6,7")).unwrap();
15847        assert_eq!(all.len(), STEP37_TRUNK_LAYERS);
15848        assert_eq!(all.first().unwrap().layer, 0);
15849        assert_eq!(all.last().unwrap().layer, STEP37_TRUNK_LAYERS - 1);
15850        let devices = (0..8).collect::<Vec<_>>();
15851        assert!(all.iter().all(|spec| spec.devices == devices));
15852        assert!(parse_step_tp_layer_specs(Some("all@0,1;44@0,1")).is_err());
15853    }
15854}
15855
15856// ===== Whole-token graph builder (increment B) ==================================================
15857//
15858// The decode fns are already sectioned at every e/rank/root seam (the stage flow, sweeps_rank,
15859// finish splits, the dcw arm). `graph_section` is the one annotation those seams call: eager
15860// mode runs the closure verbatim; build mode wraps it in a stream capture on the section's
15861// device and records a child + its dependency edges. A token then assembles as ONE multi-device
15862// parent (children per section per layer), launched once per token — the launch-collapse the
15863// per-layer minis could not reach (routes-mini negative, 2026-08-21).
15864
15865/// One captured section: the child graph plus which parent node it became, and the CUDA
15866/// context it was captured under (exec memset updates need it).
15867struct TokenGraphChild {
15868    #[allow(dead_code)]
15869    // allow: keep-alive: the child graph must outlive the exec instantiated from it
15870    graph: cudarc::driver::CudaGraph,
15871    node: cudarc::driver::sys::CUgraphNode,
15872    ctx: cudarc::driver::sys::CUcontext,
15873}
15874
15875/// Exec-updatable fa geometry discovered in one attention rank child: the three partial-pool
15876/// memsets, the dcw fa kernel, and its combine — everything a bucket change touches. Node
15877/// handles address the parent's CLONED child graphs (the M1-probed update path).
15878struct TokenGraphFaSite {
15879    ctx: cudarc::driver::sys::CUcontext,
15880    memset_o: cudarc::driver::sys::CUgraphNode,
15881    memset_m: [cudarc::driver::sys::CUgraphNode; 2],
15882    fa: cudarc::driver::sys::CUgraphNode,
15883    combine: cudarc::driver::sys::CUgraphNode,
15884    window: usize,
15885    n_head: usize,
15886    n_head_kv: usize,
15887    head_dim: usize,
15888}
15889
15890pub struct TokenGraphBuilder {
15891    parent: cudarc::driver::sys::CUgraph,
15892    children: Vec<TokenGraphChild>,
15893    /// Nodes every NEXT section must depend on (the frontier): one node for serial flow,
15894    /// several while a parallel group is open.
15895    frontier: Vec<cudarc::driver::sys::CUgraphNode>,
15896    /// Detached sections: forked from the frontier at issue time, joined ONLY by the next
15897    /// non-group section (they never gate a parallel group merge — the SH1 shape).
15898    pending_detached: Vec<cudarc::driver::sys::CUgraphNode>,
15899    /// Open parallel group: sections issued under the same group id fork from the SAME
15900    /// predecessor set and merge into the frontier together when the group closes.
15901    group: Option<(
15902        u32,
15903        Vec<cudarc::driver::sys::CUgraphNode>,
15904        Vec<cudarc::driver::sys::CUgraphNode>,
15905    )>,
15906}
15907
15908// SAFETY: single decode thread; graph handles are process handles.
15909unsafe impl Send for TokenGraphBuilder {}
15910
15911impl TokenGraphBuilder {
15912    pub fn new() -> Result<Self, Box<dyn std::error::Error>> {
15913        use cudarc::driver::sys;
15914        let mut parent: sys::CUgraph = std::ptr::null_mut();
15915        let r = unsafe { sys::cuGraphCreate(&mut parent, 0) };
15916        if r != sys::CUresult::CUDA_SUCCESS {
15917            return Err(format!("token graph create: {r:?}").into());
15918        }
15919        Ok(Self {
15920            parent,
15921            children: Vec::new(),
15922            frontier: Vec::new(),
15923            pending_detached: Vec::new(),
15924            group: None,
15925        })
15926    }
15927
15928    fn push_child(
15929        &mut self,
15930        graph: cudarc::driver::CudaGraph,
15931        parallel_group: Option<u32>,
15932        detached: bool,
15933        absorb: bool,
15934        ctx: cudarc::driver::sys::CUcontext,
15935    ) -> Result<(), Box<dyn std::error::Error>> {
15936        use cudarc::driver::sys;
15937        // Resolve the dependency set: serial sections depend on the current frontier; a
15938        // parallel-group section depends on the frontier AS OF the group opening; a
15939        // DETACHED section forks like a group member but joins only the next serial section.
15940        let deps: Vec<sys::CUgraphNode> = match (&mut self.group, parallel_group) {
15941            (Some((open, base, _)), Some(group)) if *open == group => base.clone(),
15942            (state, Some(group)) => {
15943                // opening a new group (closing any previous one first)
15944                if let Some((_, _, members)) = state.take() {
15945                    self.frontier = members;
15946                }
15947                let base = self.frontier.clone();
15948                *state = Some((group, base.clone(), Vec::new()));
15949                base
15950            }
15951            (state, None) if detached => match state.as_ref() {
15952                Some((_, base, _)) => base.clone(),
15953                None => self.frontier.clone(),
15954            },
15955            (state, None) => {
15956                if let Some((_, _, members)) = state.take() {
15957                    self.frontier = members;
15958                }
15959                let mut deps = self.frontier.clone();
15960                if absorb {
15961                    deps.append(&mut self.pending_detached);
15962                }
15963                deps
15964            }
15965        };
15966        let mut node: sys::CUgraphNode = std::ptr::null_mut();
15967        let r = unsafe {
15968            sys::cuGraphAddChildGraphNode(
15969                &mut node,
15970                self.parent,
15971                if deps.is_empty() {
15972                    std::ptr::null()
15973                } else {
15974                    deps.as_ptr()
15975                },
15976                deps.len(),
15977                graph.cu_graph(),
15978            )
15979        };
15980        if r != sys::CUresult::CUDA_SUCCESS {
15981            return Err(format!("token graph child: {r:?}").into());
15982        }
15983        match (&mut self.group, parallel_group, detached) {
15984            (_, None, true) => self.pending_detached.push(node),
15985            (Some((_, _, members)), Some(_), _) => members.push(node),
15986            _ => self.frontier = vec![node],
15987        }
15988        self.children.push(TokenGraphChild { graph, node, ctx });
15989        Ok(())
15990    }
15991
15992    pub fn finish(mut self) -> Result<TokenGraph, Box<dyn std::error::Error>> {
15993        use cudarc::driver::sys;
15994        if let Some((_, _, members)) = self.group.take() {
15995            self.frontier = members;
15996        }
15997        // Discover the fa sites BEFORE instantiate: the parent's cloned child graphs hold
15998        // the node handles the exec update path (M1) addresses.
15999        let mut fa_sites = Vec::new();
16000        for child in &self.children {
16001            if let Some(site) = discover_fa_site(child.node, child.ctx)? {
16002                fa_sites.push(site);
16003            }
16004        }
16005        let mut exec: sys::CUgraphExec = std::ptr::null_mut();
16006        let r = unsafe { sys::cuGraphInstantiateWithFlags(&mut exec, self.parent, 0) };
16007        if r != sys::CUresult::CUDA_SUCCESS {
16008            return Err(format!("token graph instantiate: {r:?}").into());
16009        }
16010        Ok(TokenGraph {
16011            exec,
16012            parent: self.parent,
16013            _children: self.children,
16014            fa_sites,
16015        })
16016    }
16017}
16018
16019/// Walk one child graph; if it carries the attention-section signature (exactly three MEMSET
16020/// nodes chained memset->memset->memset->fa_kernel->combine_kernel), return its update site.
16021fn discover_fa_site(
16022    child_node: cudarc::driver::sys::CUgraphNode,
16023    ctx: cudarc::driver::sys::CUcontext,
16024) -> Result<Option<TokenGraphFaSite>, Box<dyn std::error::Error>> {
16025    use cudarc::driver::sys;
16026    fn cu_try(r: sys::CUresult, what: &str) -> Result<(), Box<dyn std::error::Error>> {
16027        if r == sys::CUresult::CUDA_SUCCESS {
16028            Ok(())
16029        } else {
16030            Err(format!("{what}: {r:?}").into())
16031        }
16032    }
16033    let mut graph: sys::CUgraph = std::ptr::null_mut();
16034    unsafe {
16035        cu_try(
16036            sys::cuGraphChildGraphNodeGetGraph(child_node, &mut graph),
16037            "fa-site child GetGraph",
16038        )?;
16039    }
16040    let mut count: usize = 0;
16041    unsafe {
16042        cu_try(
16043            sys::cuGraphGetNodes(graph, std::ptr::null_mut(), &mut count),
16044            "fa-site GetNodes(count)",
16045        )?;
16046    }
16047    let mut nodes: Vec<sys::CUgraphNode> = vec![std::ptr::null_mut(); count];
16048    unsafe {
16049        cu_try(
16050            sys::cuGraphGetNodes(graph, nodes.as_mut_ptr(), &mut count),
16051            "fa-site GetNodes",
16052        )?;
16053    }
16054    nodes.truncate(count);
16055    let node_type =
16056        |node: sys::CUgraphNode| -> Result<sys::CUgraphNodeType, Box<dyn std::error::Error>> {
16057            let mut ty = sys::CUgraphNodeType::CU_GRAPH_NODE_TYPE_EMPTY;
16058            unsafe {
16059                cu_try(
16060                    sys::cuGraphNodeGetType(node, &mut ty),
16061                    "fa-site NodeGetType",
16062                )?;
16063            }
16064            Ok(ty)
16065        };
16066    let memsets: Vec<sys::CUgraphNode> = {
16067        let mut v = Vec::new();
16068        for &node in &nodes {
16069            if node_type(node)? == sys::CUgraphNodeType::CU_GRAPH_NODE_TYPE_MEMSET {
16070                v.push(node);
16071            }
16072        }
16073        v
16074    };
16075    if memsets.len() != 3 {
16076        return Ok(None);
16077    }
16078    // Single-stream capture makes the chain linear: follow dependent edges from each memset.
16079    let dependents =
16080        |node: sys::CUgraphNode| -> Result<Vec<sys::CUgraphNode>, Box<dyn std::error::Error>> {
16081            let mut n: usize = 0;
16082            unsafe {
16083                cu_try(
16084                    sys::cuGraphNodeGetDependentNodes_v2(
16085                        node,
16086                        std::ptr::null_mut(),
16087                        std::ptr::null_mut(),
16088                        &mut n,
16089                    ),
16090                    "fa-site GetDependentNodes(count)",
16091                )?;
16092            }
16093            let mut v: Vec<sys::CUgraphNode> = vec![std::ptr::null_mut(); n];
16094            unsafe {
16095                cu_try(
16096                    sys::cuGraphNodeGetDependentNodes_v2(
16097                        node,
16098                        v.as_mut_ptr(),
16099                        std::ptr::null_mut(),
16100                        &mut n,
16101                    ),
16102                    "fa-site GetDependentNodes",
16103                )?;
16104            }
16105            v.truncate(n);
16106            Ok(v)
16107        };
16108    // The LAST memset is the one whose direct dependent is a kernel (fa); the other two are
16109    // ordered among themselves but interchangeable for width updates.
16110    let mut fa: Option<sys::CUgraphNode> = None;
16111    let mut last_memset: Option<sys::CUgraphNode> = None;
16112    for &ms in &memsets {
16113        for dep in dependents(ms)? {
16114            if node_type(dep)? == sys::CUgraphNodeType::CU_GRAPH_NODE_TYPE_KERNEL {
16115                fa = Some(dep);
16116                last_memset = Some(ms);
16117            }
16118        }
16119    }
16120    let (Some(fa), Some(_last)) = (fa, last_memset) else {
16121        return Ok(None);
16122    };
16123    let mut combine: Option<sys::CUgraphNode> = None;
16124    for dep in dependents(fa)? {
16125        if node_type(dep)? == sys::CUgraphNodeType::CU_GRAPH_NODE_TYPE_KERNEL {
16126            combine = Some(dep);
16127        }
16128    }
16129    let Some(combine) = combine else {
16130        return Ok(None);
16131    };
16132    // Read the fa launch geometry from its baked args (arg order pinned by fa_decode_dcw):
16133    // 6=hd 7=nh 8=nhkv 11=win 13=nsp 14=ski.
16134    let mut params: sys::CUDA_KERNEL_NODE_PARAMS = unsafe { std::mem::zeroed() };
16135    unsafe {
16136        cu_try(
16137            sys::cuGraphKernelNodeGetParams_v2(fa, &mut params),
16138            "fa-site KernelNodeGetParams",
16139        )?;
16140    }
16141    let arg_i32 =
16142        |slot: usize| -> i32 { unsafe { *(*params.kernelParams.add(slot) as *const i32) } };
16143    let (hd, nh, nhkv, win) = (arg_i32(6), arg_i32(7), arg_i32(8), arg_i32(11));
16144    // Identify the o-partial memset (hd x wider than the m/l pair).
16145    let width_of = |node: sys::CUgraphNode| -> Result<usize, Box<dyn std::error::Error>> {
16146        let mut mp: sys::CUDA_MEMSET_NODE_PARAMS = unsafe { std::mem::zeroed() };
16147        unsafe {
16148            cu_try(
16149                sys::cuGraphMemsetNodeGetParams(node, &mut mp),
16150                "fa-site MemsetNodeGetParams",
16151            )?;
16152        }
16153        Ok(mp.width)
16154    };
16155    let mut widest = memsets[0];
16156    for &ms in &memsets[1..] {
16157        if width_of(ms)? > width_of(widest)? {
16158            widest = ms;
16159        }
16160    }
16161    let memset_m: Vec<sys::CUgraphNode> =
16162        memsets.iter().copied().filter(|&m| m != widest).collect();
16163    Ok(Some(TokenGraphFaSite {
16164        ctx,
16165        memset_o: widest,
16166        memset_m: [memset_m[0], memset_m[1]],
16167        fa,
16168        combine,
16169        window: win as usize,
16170        n_head: nh as usize,
16171        n_head_kv: nhkv as usize,
16172        head_dim: hd as usize,
16173    }))
16174}
16175
16176pub struct TokenGraph {
16177    exec: cudarc::driver::sys::CUgraphExec,
16178    parent: cudarc::driver::sys::CUgraph,
16179    _children: Vec<TokenGraphChild>,
16180    fa_sites: Vec<TokenGraphFaSite>,
16181}
16182
16183unsafe impl Send for TokenGraph {}
16184
16185impl TokenGraph {
16186    /// Retarget every fa site to a new bucket via exec param updates (M1 path) — replaces the
16187    /// per-bucket whole-graph rebuild (~55ms) with ~450 node updates (~1ms). Per site the
16188    /// bucket caps at the layer window; nsp/ski/gridDimY and the partial-pool memset widths
16189    /// move together so the exec always matches what a fresh build at `bucket` would bake.
16190    pub fn retarget_bucket(&mut self, bucket: usize) -> Result<(), Box<dyn std::error::Error>> {
16191        use cudarc::driver::sys;
16192        fn cu_try(r: sys::CUresult, what: &str) -> Result<(), Box<dyn std::error::Error>> {
16193            if r == sys::CUresult::CUDA_SUCCESS {
16194                Ok(())
16195            } else {
16196                Err(format!("{what}: {r:?}").into())
16197            }
16198        }
16199        for site in &self.fa_sites {
16200            let layer_bucket = if site.window > 0 {
16201                bucket.min(site.window)
16202            } else {
16203                bucket
16204            };
16205            let sp = crate::fa_split_keys(layer_bucket, site.n_head_kv);
16206            let nsp = layer_bucket.div_ceil(sp).max(1);
16207            // fa kernel: nsp (slot 13), ski (slot 14), gridDimY = nsp.
16208            let mut params: sys::CUDA_KERNEL_NODE_PARAMS = unsafe { std::mem::zeroed() };
16209            unsafe {
16210                cu_try(
16211                    sys::cuGraphKernelNodeGetParams_v2(site.fa, &mut params),
16212                    "retarget fa GetParams",
16213                )?;
16214                *(*params.kernelParams.add(13) as *mut i32) = nsp as i32;
16215                *(*params.kernelParams.add(14) as *mut i32) = sp as i32;
16216                params.gridDimY = nsp as u32;
16217                cu_try(
16218                    sys::cuGraphExecKernelNodeSetParams_v2(self.exec, site.fa, &params),
16219                    "retarget fa SetParams",
16220                )?;
16221            }
16222            // combine: nsp (slot 6).
16223            let mut cparams: sys::CUDA_KERNEL_NODE_PARAMS = unsafe { std::mem::zeroed() };
16224            unsafe {
16225                cu_try(
16226                    sys::cuGraphKernelNodeGetParams_v2(site.combine, &mut cparams),
16227                    "retarget combine GetParams",
16228                )?;
16229                *(*cparams.kernelParams.add(6) as *mut i32) = nsp as i32;
16230                cu_try(
16231                    sys::cuGraphExecKernelNodeSetParams_v2(self.exec, site.combine, &cparams),
16232                    "retarget combine SetParams",
16233                )?;
16234            }
16235            // partial-pool memsets: o = nh*nsp*hd elements, m/l = nh*nsp.
16236            let set_width =
16237                |node: sys::CUgraphNode, width: usize| -> Result<(), Box<dyn std::error::Error>> {
16238                    let mut mp: sys::CUDA_MEMSET_NODE_PARAMS = unsafe { std::mem::zeroed() };
16239                    unsafe {
16240                        cu_try(
16241                            sys::cuGraphMemsetNodeGetParams(node, &mut mp),
16242                            "retarget memset GetParams",
16243                        )?;
16244                    }
16245                    mp.width = width;
16246                    unsafe {
16247                        cu_try(
16248                            sys::cuGraphExecMemsetNodeSetParams(self.exec, node, &mp, site.ctx),
16249                            "retarget memset SetParams",
16250                        )?;
16251                    }
16252                    Ok(())
16253                };
16254            set_width(site.memset_o, site.n_head * nsp * site.head_dim)?;
16255            set_width(site.memset_m[0], site.n_head * nsp)?;
16256            set_width(site.memset_m[1], site.n_head * nsp)?;
16257        }
16258        Ok(())
16259    }
16260
16261    pub fn launch(&self, e: &Engine) -> Result<(), Box<dyn std::error::Error>> {
16262        use cudarc::driver::sys;
16263        let _main = e.gpu.enter_main()?;
16264        let r = unsafe { sys::cuGraphLaunch(self.exec, e.stream().cu_stream() as sys::CUstream) };
16265        if r != sys::CUresult::CUDA_SUCCESS {
16266            return Err(format!("token graph launch: {r:?}").into());
16267        }
16268        Ok(())
16269    }
16270}
16271
16272impl Drop for TokenGraph {
16273    fn drop(&mut self) {
16274        unsafe {
16275            let _ = cudarc::driver::sys::cuGraphExecDestroy(self.exec);
16276            let _ = cudarc::driver::sys::cuGraphDestroy(self.parent);
16277        }
16278    }
16279}
16280
16281std::thread_local! {
16282    static TOKEN_GRAPH_BUILDER: std::cell::RefCell<Option<TokenGraphBuilder>> =
16283        const { std::cell::RefCell::new(None) };
16284}
16285
16286/// Arm the thread-local builder (build mode) — the next `graph_section` calls capture.
16287pub fn token_graph_build_begin() -> Result<(), Box<dyn std::error::Error>> {
16288    let builder = TokenGraphBuilder::new()?;
16289    TOKEN_GRAPH_BUILDER.with(|cell| *cell.borrow_mut() = Some(builder));
16290    Ok(())
16291}
16292
16293/// Take the finished parent (ends build mode).
16294pub fn token_graph_build_finish() -> Result<TokenGraph, Box<dyn std::error::Error>> {
16295    let builder = TOKEN_GRAPH_BUILDER
16296        .with(|cell| cell.borrow_mut().take())
16297        .ok_or("token graph build was not begun")?;
16298    builder.finish()
16299}
16300
16301/// True while the thread-local builder is armed.
16302pub fn token_graph_building() -> bool {
16303    TOKEN_GRAPH_BUILDER.with(|cell| cell.borrow().is_some())
16304}
16305
16306/// The section annotation: eager mode runs the closure verbatim; build mode wraps it in a
16307/// stream capture on `engine`'s stream and records the child. Sections sharing a
16308/// `parallel_group` id fork from the same predecessor set and merge together. The closure
16309/// must be capture-safe (raw copies at cross-context seams, no host syncs, no events).
16310pub fn graph_section<F>(
16311    engine: &Engine,
16312    parallel_group: Option<u32>,
16313    f: F,
16314) -> Result<(), Box<dyn std::error::Error>>
16315where
16316    F: FnMut() -> Result<(), Box<dyn std::error::Error>>,
16317{
16318    graph_section_opts(engine, parallel_group, false, false, f)
16319}
16320
16321/// Serial section that ALSO joins every pending detached section (the SH1 consumer shape).
16322pub fn graph_section_absorbing<F>(engine: &Engine, f: F) -> Result<(), Box<dyn std::error::Error>>
16323where
16324    F: FnMut() -> Result<(), Box<dyn std::error::Error>>,
16325{
16326    graph_section_opts(engine, None, false, true, f)
16327}
16328
16329/// `graph_section` with the DETACHED shape: forks from the current frontier (or the open
16330/// group base) and is joined only by the next serial section — never gates a group merge.
16331pub fn graph_section_detached<F>(engine: &Engine, f: F) -> Result<(), Box<dyn std::error::Error>>
16332where
16333    F: FnMut() -> Result<(), Box<dyn std::error::Error>>,
16334{
16335    graph_section_opts(engine, None, true, false, f)
16336}
16337
16338pub fn graph_section_opts<F>(
16339    engine: &Engine,
16340    parallel_group: Option<u32>,
16341    detached: bool,
16342    absorb: bool,
16343    f: F,
16344) -> Result<(), Box<dyn std::error::Error>>
16345where
16346    F: FnMut() -> Result<(), Box<dyn std::error::Error>>,
16347{
16348    let building = token_graph_building();
16349    if !building {
16350        let mut f = f;
16351        return f();
16352    }
16353    let (child, ctx) = {
16354        let _main = engine.gpu.enter_main()?;
16355        let mut ctx: cudarc::driver::sys::CUcontext = std::ptr::null_mut();
16356        let r = unsafe { cudarc::driver::sys::cuCtxGetCurrent(&mut ctx) };
16357        if r != cudarc::driver::sys::CUresult::CUDA_SUCCESS {
16358            return Err(format!("graph section ctx query: {r:?}").into());
16359        }
16360        let mut f = f;
16361        // NO WARMUP RUNS: section bodies carry device side effects (dcw appends, counter
16362        // incs) that a warmup would really execute — the len_d-drift crash of 2026-08-21.
16363        let (child, _retained) = engine.capture_graph_retained_nowarm(|_| f())?;
16364        (child, ctx)
16365    };
16366    TOKEN_GRAPH_BUILDER.with(|cell| {
16367        cell.borrow_mut()
16368            .as_mut()
16369            .expect("builder checked above")
16370            .push_child(child, parallel_group, detached, absorb, ctx)
16371    })
16372}