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_step_layer_specs(
1023    flag: &str,
1024    value: Option<&str>,
1025    allow_full_model: bool,
1026) -> Result<Vec<StepEpLayerSpec>, String> {
1027    let trunk = allow_full_model.then_some(STEP37_TRUNK_LAYERS);
1028    parse_layer_specs_for_trunk(flag, value, trunk)
1029}
1030
1031/// The pure composition-refusal law behind every parallel door's UNPROVEN-pair matrix
1032/// (hoisted from the glm5 TP door, lane/glm5-extract-general): the first armed flag in
1033/// `table` refuses by name, BEFORE any parallel CUDA state exists. Each family owns its
1034/// own TABLE of `(flag, why)` rows — the reasons are gate receipts, part of the law; a
1035/// pair unlocks only with its own composition gate (the primary flag's FLAGS.md row
1036/// carries the matrix). `armed` reports whether a flag is set to `"1"` (env in
1037/// production; a plain set in unit tests — the pattern keeps tests env-mutation-free).
1038pub(crate) fn refuse_door_composition(
1039    primary: &str,
1040    table: &[(&str, &str)],
1041    armed: impl Fn(&str) -> bool,
1042) -> Result<(), String> {
1043    for (flag, why) in table {
1044        if armed(flag) {
1045            return Err(format!(
1046                "{primary} + {flag}: unproven composition, refused ({why})"
1047            ));
1048        }
1049    }
1050    Ok(())
1051}
1052
1053/// The shared `LAYER[-LAYER]@DEVICE,DEVICE[;...]` grammar behind every per-layer parallel
1054/// door. `full_model_trunk` enables the `all` shorthand and names the trunk it expands to —
1055/// the caller's model contract owns that constant, never this parser (the step door passes
1056/// `STEP37_TRUNK_LAYERS`; the glm5 door passes its own trunk length at load time).
1057pub(crate) fn parse_layer_specs_for_trunk(
1058    flag: &str,
1059    value: Option<&str>,
1060    full_model_trunk: Option<usize>,
1061) -> Result<Vec<StepEpLayerSpec>, String> {
1062    let Some(value) = value else {
1063        return Ok(Vec::new());
1064    };
1065    if value.is_empty() || value == "0" {
1066        return Ok(Vec::new());
1067    }
1068
1069    let mut specs = Vec::new();
1070    for item in value.split(';') {
1071        let (layers, devices) = item.split_once('@').ok_or_else(|| {
1072            let layers = if full_model_trunk.is_some() {
1073                "LAYER[-LAYER] or all"
1074            } else {
1075                "LAYER[-LAYER]"
1076            };
1077            format!("{flag} must be {layers}@DEVICE,DEVICE[;...]")
1078        })?;
1079        let (first, last) = if layers == "all" {
1080            let Some(trunk) = full_model_trunk else {
1081                return Err(format!(
1082                    "{flag} does not support the full-model shorthand; assign routed layers \
1083                     explicitly"
1084                ));
1085            };
1086            (0, trunk - 1)
1087        } else {
1088            match layers.split_once('-') {
1089                Some((first, last)) => {
1090                    let first = first
1091                        .parse::<usize>()
1092                        .map_err(|_| format!("{flag} layer {first:?} is not an integer"))?;
1093                    let last = last
1094                        .parse::<usize>()
1095                        .map_err(|_| format!("{flag} layer {last:?} is not an integer"))?;
1096                    if first > last {
1097                        return Err(format!("{flag} layer range {first}-{last} is reversed"));
1098                    }
1099                    if last - first + 1 > 128 {
1100                        return Err(format!(
1101                            "{flag} layer range {first}-{last} exceeds the 128-layer parser cap"
1102                        ));
1103                    }
1104                    (first, last)
1105                }
1106                None => {
1107                    let layer = layers
1108                        .parse::<usize>()
1109                        .map_err(|_| format!("{flag} layer {layers:?} is not an integer"))?;
1110                    (layer, layer)
1111                }
1112            }
1113        };
1114        let devices = devices
1115            .split(',')
1116            .map(|device| {
1117                device
1118                    .parse::<usize>()
1119                    .map_err(|_| format!("{flag} device {device:?} is not an integer"))
1120            })
1121            .collect::<Result<Vec<_>, _>>()?;
1122        if !(2..=8).contains(&devices.len()) {
1123            return Err(format!(
1124                "{flag} requires 2..=8 devices, got {}",
1125                devices.len()
1126            ));
1127        }
1128        let mut unique = devices.clone();
1129        unique.sort_unstable();
1130        unique.dedup();
1131        if unique.len() != devices.len() {
1132            return Err(format!("{flag} devices must be distinct, got {devices:?}"));
1133        }
1134        for layer in first..=last {
1135            if specs
1136                .iter()
1137                .any(|existing: &StepEpLayerSpec| existing.layer == layer)
1138            {
1139                return Err(format!("{flag} assigns layer {layer} more than once"));
1140            }
1141            specs.push(StepEpLayerSpec {
1142                layer,
1143                devices: devices.clone(),
1144            });
1145        }
1146    }
1147    Ok(specs)
1148}
1149
1150pub fn parse_step_ep_layer_specs(value: Option<&str>) -> Result<Vec<StepEpLayerSpec>, String> {
1151    parse_step_layer_specs("MEMRA_STEP_EP", value, false)
1152}
1153
1154pub fn step_ep_layer_specs() -> Result<Vec<StepEpLayerSpec>, String> {
1155    parse_step_ep_layer_specs(std::env::var("MEMRA_STEP_EP").ok().as_deref())
1156}
1157
1158pub fn parse_step_tp_layer_specs(value: Option<&str>) -> Result<Vec<StepTpLayerSpec>, String> {
1159    parse_step_layer_specs("MEMRA_STEP_TP", value, true)
1160}
1161
1162pub fn step_tp_layer_specs() -> Result<Vec<StepTpLayerSpec>, String> {
1163    parse_step_tp_layer_specs(std::env::var("MEMRA_STEP_TP").ok().as_deref())
1164}
1165
1166#[derive(Clone, Copy)]
1167pub struct E4m3BlockMatrix<'a> {
1168    pub codes: &'a [u8],
1169    pub scales: &'a [f32],
1170    pub out_features: usize,
1171    pub in_features: usize,
1172}
1173
1174impl E4m3BlockMatrix<'_> {
1175    fn validate(&self) -> Result<(), String> {
1176        let code_count = self
1177            .out_features
1178            .checked_mul(self.in_features)
1179            .ok_or_else(|| "E4M3 matrix size overflow".to_string())?;
1180        if self.codes.len() != code_count {
1181            return Err(format!(
1182                "E4M3 code count {} != {}x{} ({code_count})",
1183                self.codes.len(),
1184                self.out_features,
1185                self.in_features,
1186            ));
1187        }
1188        let scale_count =
1189            self.out_features.div_ceil(FP8_BLOCK) * self.in_features.div_ceil(FP8_BLOCK);
1190        if self.scales.len() != scale_count {
1191            return Err(format!(
1192                "E4M3 scale count {} != {scale_count} for {}x{}",
1193                self.scales.len(),
1194                self.out_features,
1195                self.in_features,
1196            ));
1197        }
1198        if !self
1199            .scales
1200            .iter()
1201            .all(|scale| scale.is_finite() && *scale > 0.0)
1202        {
1203            return Err("E4M3 scale grid contains a non-finite or non-positive value".to_string());
1204        }
1205        Ok(())
1206    }
1207}
1208
1209#[derive(Clone, Copy)]
1210pub struct E4m3ExpertBank<'a> {
1211    pub codes: &'a [u8],
1212    pub scales: &'a [f32],
1213    pub expert_count: usize,
1214    pub out_features: usize,
1215    pub in_features: usize,
1216}
1217
1218impl E4m3ExpertBank<'_> {
1219    fn validate(&self) -> Result<(), String> {
1220        if self.expert_count == 0 {
1221            return Err("E4M3 expert bank is empty".to_string());
1222        }
1223        let code_stride = self
1224            .out_features
1225            .checked_mul(self.in_features)
1226            .ok_or_else(|| "E4M3 expert code stride overflow".to_string())?;
1227        let code_count = self
1228            .expert_count
1229            .checked_mul(code_stride)
1230            .ok_or_else(|| "E4M3 expert code count overflow".to_string())?;
1231        if self.codes.len() != code_count {
1232            return Err(format!(
1233                "E4M3 expert code count {} != {}x{} ({code_count})",
1234                self.codes.len(),
1235                self.expert_count,
1236                code_stride,
1237            ));
1238        }
1239        let scale_stride =
1240            self.out_features.div_ceil(FP8_BLOCK) * self.in_features.div_ceil(FP8_BLOCK);
1241        let scale_count = self
1242            .expert_count
1243            .checked_mul(scale_stride)
1244            .ok_or_else(|| "E4M3 expert scale count overflow".to_string())?;
1245        if self.scales.len() != scale_count {
1246            return Err(format!(
1247                "E4M3 expert scale count {} != {}x{} ({scale_count})",
1248                self.scales.len(),
1249                self.expert_count,
1250                scale_stride,
1251            ));
1252        }
1253        if !self
1254            .scales
1255            .iter()
1256            .all(|scale| scale.is_finite() && *scale > 0.0)
1257        {
1258            return Err(
1259                "E4M3 expert scale grid contains a non-finite or non-positive value".to_string(),
1260            );
1261        }
1262        Ok(())
1263    }
1264
1265    pub fn expert(&self, expert: usize) -> Result<E4m3BlockMatrix<'_>, String> {
1266        if expert >= self.expert_count {
1267            return Err(format!("expert {expert} outside 0..{}", self.expert_count));
1268        }
1269        let code_stride = self.out_features * self.in_features;
1270        let scale_stride =
1271            self.out_features.div_ceil(FP8_BLOCK) * self.in_features.div_ceil(FP8_BLOCK);
1272        Ok(E4m3BlockMatrix {
1273            codes: &self.codes[expert * code_stride..(expert + 1) * code_stride],
1274            scales: &self.scales[expert * scale_stride..(expert + 1) * scale_stride],
1275            out_features: self.out_features,
1276            in_features: self.in_features,
1277        })
1278    }
1279}
1280
1281pub struct ColumnParallelResult {
1282    pub gathered: Vec<f32>,
1283    pub rank_outputs: Vec<Vec<f32>>,
1284}
1285
1286pub struct RowParallelResult {
1287    pub reduced: Vec<f32>,
1288    pub rank_partials: Vec<Vec<f32>>,
1289}
1290
1291#[derive(Clone, Copy)]
1292pub struct Bf16Matrix<'a> {
1293    pub bytes: &'a [u8],
1294    pub out_features: usize,
1295    pub in_features: usize,
1296}
1297
1298impl Bf16Matrix<'_> {
1299    pub fn validate(&self) -> Result<(), String> {
1300        if self.out_features == 0 || self.in_features == 0 {
1301            return Err("BF16 matrix dimensions must be nonzero".into());
1302        }
1303        let expected = self
1304            .out_features
1305            .checked_mul(self.in_features)
1306            .and_then(|values| values.checked_mul(2))
1307            .ok_or("BF16 matrix byte count overflow")?;
1308        if self.bytes.len() != expected {
1309            return Err(format!(
1310                "BF16 matrix bytes {} != {}x{}x2 ({expected})",
1311                self.bytes.len(),
1312                self.out_features,
1313                self.in_features,
1314            ));
1315        }
1316        Ok(())
1317    }
1318}
1319
1320struct ResidentE4m3Rank {
1321    codes: CudaSlice<u8>,
1322    scales: CudaSlice<f32>,
1323    out_features: usize,
1324    in_features: usize,
1325}
1326
1327enum ResidentBf16Weight {
1328    Bf16(CudaSlice<u8>),
1329    F32(CudaSlice<f32>),
1330}
1331
1332impl ResidentBf16Weight {
1333    fn ordinal(&self) -> usize {
1334        match self {
1335            Self::Bf16(bytes) => bytes.ordinal(),
1336            Self::F32(values) => values.ordinal(),
1337        }
1338    }
1339}
1340
1341struct ResidentBf16Rank {
1342    weight: ResidentBf16Weight,
1343    out_features: usize,
1344    in_features: usize,
1345    /// q8_0 mirror built at load under MEMRA_STEP_TP_W8 (numeric-class door; the bf16 slab
1346    /// stays resident because every prefill/verify path is qualified against it).
1347    q8: Option<CudaSlice<u8>>,
1348}
1349
1350pub struct ResidentColumnParallel {
1351    ranks: Vec<ResidentE4m3Rank>,
1352    out_features: usize,
1353    in_features: usize,
1354}
1355
1356pub struct ResidentRowParallel {
1357    ranks: Vec<ResidentE4m3Rank>,
1358    out_features: usize,
1359    in_features: usize,
1360}
1361
1362pub struct ResidentBf16ColumnParallel {
1363    ranks: Vec<ResidentBf16Rank>,
1364    out_features: usize,
1365    in_features: usize,
1366    canonical_chunk_rows: Option<usize>,
1367}
1368
1369pub struct ResidentBf16RowParallel {
1370    ranks: Vec<ResidentBf16Rank>,
1371    out_features: usize,
1372    in_features: usize,
1373}
1374
1375pub struct ResidentStepBf16RowParallel {
1376    ranks: Vec<Vec<ResidentBf16Rank>>,
1377    out_features: usize,
1378    in_features: usize,
1379    canonical_chunk_cols: usize,
1380}
1381
1382/// Root-owned BF16 sigmoid router with persistent F32 weight, bias, and active mask.
1383pub struct ResidentSigmoidTopKRouter {
1384    weight: CudaSlice<f32>,
1385    correction_bias: CudaSlice<f32>,
1386    active: CudaSlice<u8>,
1387    root_device: usize,
1388    input_width: usize,
1389    expert_count: usize,
1390    experts_per_token: usize,
1391    active_count: usize,
1392    scaling_factor: f32,
1393    route_norm: bool,
1394}
1395
1396pub struct SigmoidTopKHostOutput {
1397    pub logits: Vec<f32>,
1398    pub selected: Vec<u32>,
1399    pub weights: Vec<f32>,
1400}
1401
1402/// Full BF16 SwiGLU weights replicated independently on every runtime rank.
1403pub struct ResidentReplicatedBf16SwiGlu {
1404    gate: Vec<ResidentBf16Rank>,
1405    up: Vec<ResidentBf16Rank>,
1406    down: Vec<ResidentBf16Rank>,
1407    input_width: usize,
1408    intermediate_width: usize,
1409}
1410
1411/// One token-major F32 batch replicated across a native-P2P rank group.
1412///
1413/// Every allocation is owned by its matching rank CUDA context. This is the generic handoff
1414/// substrate between independently sharded operators; it carries no model or topology claim.
1415pub struct ResidentReplicatedDeviceRows {
1416    ranks: Vec<CudaSlice<f32>>,
1417    tokens: usize,
1418    width: usize,
1419}
1420
1421impl ResidentReplicatedDeviceRows {
1422    pub fn tokens(&self) -> usize {
1423        self.tokens
1424    }
1425
1426    pub fn width(&self) -> usize {
1427        self.width
1428    }
1429
1430    pub fn ranks(&self) -> usize {
1431        self.ranks.len()
1432    }
1433}
1434
1435/// Canonical MoE output order: routed plus shared, then add the layer residual.
1436pub fn moe_residual_host(
1437    residual: &[f32],
1438    routed: &[f32],
1439    shared: &[f32],
1440) -> Result<Vec<f32>, String> {
1441    if residual.len() != routed.len() || residual.len() != shared.len() {
1442        return Err(format!(
1443            "MoE residual lengths residual={} routed={} shared={}",
1444            residual.len(),
1445            routed.len(),
1446            shared.len()
1447        ));
1448    }
1449    let ffn = routed
1450        .iter()
1451        .zip(shared)
1452        .map(|(&routed, &shared)| routed + shared)
1453        .collect::<Vec<_>>();
1454    Ok(residual
1455        .iter()
1456        .zip(ffn)
1457        .map(|(&residual, ffn)| residual + ffn)
1458        .collect())
1459}
1460
1461pub use memra_kv::{
1462    KvRingAppend, ResidentTpKvCache, ResidentTpKvCacheRank, TpKvAppendPlan, TpKvTransaction,
1463};
1464
1465/// Persistent TP2/TP4/TP8 routed-expert reference.
1466///
1467/// Rank-local checkpoint shards are uploaded once and remain tied to their owning CUDA context.
1468/// Activations and deterministic host-staged collectives remain per invocation. This is the
1469/// correctness substrate for serving TP/EP, not product-throughput evidence.
1470pub struct ResidentTpExpert {
1471    gate: ResidentColumnParallel,
1472    up: ResidentColumnParallel,
1473    down: ResidentRowParallel,
1474    input_width: usize,
1475    expert_width: usize,
1476}
1477
1478struct ResidentE4m3ExpertBankRank {
1479    codes: CudaSlice<u8>,
1480    scales: CudaSlice<f32>,
1481    expert_range: Range<usize>,
1482    out_features: usize,
1483    in_features: usize,
1484    code_stride: usize,
1485    scale_stride: usize,
1486    /// TP row banks are packed by native 128-wide K block so reduction can replay the
1487    /// checkpoint's global block order exactly. Other banks remain row-major.
1488    k_blocks: Option<usize>,
1489}
1490
1491struct PackedE4m3ExpertBankRank {
1492    codes: Vec<u8>,
1493    scales: Vec<f32>,
1494    expert_range: Range<usize>,
1495    out_features: usize,
1496    in_features: usize,
1497    code_stride: usize,
1498    scale_stride: usize,
1499    k_blocks: Option<usize>,
1500}
1501
1502struct ResidentEpRank {
1503    gate: ResidentE4m3ExpertBankRank,
1504    up: ResidentE4m3ExpertBankRank,
1505    down: ResidentE4m3ExpertBankRank,
1506}
1507
1508/// Persistent expert-parallel reference.
1509///
1510/// Every routed expert has exactly one owner rank. Shared experts are deliberately absent from
1511/// this object because Step replicates them per rank. Routes execute on the owner CUDA context.
1512/// The default oracle stages through host memory; the native path peer-dispatches inputs and
1513/// peer-returns owner outputs while preserving host-canonical activation and accumulation.
1514pub struct ResidentExpertParallel {
1515    ranks: Vec<ResidentEpRank>,
1516    expert_count: usize,
1517    input_width: usize,
1518    expert_width: usize,
1519}
1520
1521/// Projection-level output from the opt-in official Step grouped-FP8 gate.
1522///
1523/// Rows remain pair-major. Routing, weighted combine, and production integration are deliberately
1524/// outside this gate-only adapter.
1525pub struct StepGroupedFp8ProjectionOutput {
1526    pub gate: Vec<f32>,
1527    pub up: Vec<f32>,
1528    pub down: Vec<f32>,
1529}
1530
1531/// Prepared official Step grouped-FP8 projection gate.
1532///
1533/// The complete tensor banks, both CSR schedules, input, activation buffer, and three projection
1534/// workspaces are uploaded or allocated once. Repeated execution performs no device allocation.
1535pub struct PreparedStepGroupedFp8Gate {
1536    device: usize,
1537    gate: ResidentE4m3ExpertBankRank,
1538    up: ResidentE4m3ExpertBankRank,
1539    down: ResidentE4m3ExpertBankRank,
1540    input: CudaSlice<f32>,
1541    route_csr: DeviceExpertCsr,
1542    down_csr: DeviceExpertCsr,
1543    gate_workspace: Fp8GroupedWorkspace,
1544    up_workspace: Fp8GroupedWorkspace,
1545    down_workspace: Fp8GroupedWorkspace,
1546    activation: CudaSlice<f32>,
1547    activation_limit: Option<f32>,
1548    tokens: usize,
1549    pairs: usize,
1550}
1551
1552impl PreparedStepGroupedFp8Gate {
1553    pub fn tokens(&self) -> usize {
1554        self.tokens
1555    }
1556
1557    pub fn pairs(&self) -> usize {
1558        self.pairs
1559    }
1560}
1561
1562struct PreparedStepGroupedExpertOwner {
1563    rank: usize,
1564    global_pairs: Vec<usize>,
1565    route_csr: DeviceExpertCsr,
1566    down_csr: DeviceExpertCsr,
1567    gate_workspace: Fp8GroupedWorkspace,
1568    up_workspace: Fp8GroupedWorkspace,
1569    down_workspace: Fp8GroupedWorkspace,
1570    activation: CudaSlice<f32>,
1571}
1572
1573struct StepGroupedExpertOwnerSchedule {
1574    global_pairs: Vec<usize>,
1575    route_csr: ExpertCsr,
1576    down_csr: ExpertCsr,
1577}
1578
1579/// Prepared official Step expert-owner grouped-FP8 projection gate.
1580///
1581/// Route partitioning, owner-local CSR uploads, input dispatch, activation buffers, and grouped
1582/// workspaces are persistent. Projection rows are scattered back to canonical pair order only
1583/// after every owner has completed its rank-local program.
1584pub struct PreparedStepGroupedExpertParallelGate {
1585    rank_inputs: Vec<CudaSlice<f32>>,
1586    owners: Vec<PreparedStepGroupedExpertOwner>,
1587    activation_limit: Option<f32>,
1588    tokens: usize,
1589    pairs: usize,
1590    max_tokens: usize,
1591    max_pairs: usize,
1592    input_width: usize,
1593    expert_width: usize,
1594    generation: u64,
1595    executed_generation: Option<u64>,
1596    ready: bool,
1597}
1598
1599impl PreparedStepGroupedExpertParallelGate {
1600    pub fn tokens(&self) -> usize {
1601        self.tokens
1602    }
1603
1604    pub fn pairs(&self) -> usize {
1605        self.pairs
1606    }
1607
1608    pub fn max_tokens(&self) -> usize {
1609        self.max_tokens
1610    }
1611
1612    pub fn input_width(&self) -> usize {
1613        self.input_width
1614    }
1615
1616    pub fn expert_width(&self) -> usize {
1617        self.expert_width
1618    }
1619
1620    pub fn set_activation_limit(&mut self, limit: Option<f32>) -> Result<(), String> {
1621        validate_step_expert_activation_limit(limit)?;
1622        self.activation_limit = limit;
1623        self.executed_generation = None;
1624        Ok(())
1625    }
1626
1627    pub fn active_owners(&self) -> usize {
1628        self.owners
1629            .iter()
1630            .filter(|owner| !owner.global_pairs.is_empty())
1631            .count()
1632    }
1633
1634    pub fn owner_pair_counts(&self) -> Vec<usize> {
1635        self.owners
1636            .iter()
1637            .map(|owner| owner.global_pairs.len())
1638            .collect()
1639    }
1640
1641    pub fn generation(&self) -> u64 {
1642        self.generation
1643    }
1644}
1645
1646struct PreparedPeerWeightedRouteOwner {
1647    token_rows: CudaSlice<i32>,
1648    slots: CudaSlice<i32>,
1649    weights: CudaSlice<f32>,
1650    active_pairs: usize,
1651}
1652
1653/// Persistent root-side weighted combine for peer-owned canonical route rows.
1654///
1655/// Owner metadata, one reusable peer staging buffer, the canonical slot bank, weight bank, and
1656/// output are allocated once. Refreshes update metadata prefixes; execution peer-copies active
1657/// rows, scatters them by canonical token/slot, and reduces in the requested numeric order.
1658pub struct PreparedPeerWeightedRouteCombine {
1659    root_device: usize,
1660    owners: Vec<PreparedPeerWeightedRouteOwner>,
1661    peer_staging: CudaSlice<f32>,
1662    slots: CudaSlice<f32>,
1663    weights: CudaSlice<f32>,
1664    output: CudaSlice<f32>,
1665    peer_devices: Vec<usize>,
1666    peer_outputs: Vec<CudaSlice<f32>>,
1667    width: usize,
1668    experts_per_token: usize,
1669    max_tokens: usize,
1670    max_pairs: usize,
1671    tokens: usize,
1672    pairs: usize,
1673    projection_generation: u64,
1674    output_generation: Option<u64>,
1675    broadcast_generation: Option<u64>,
1676    ready: bool,
1677}
1678
1679impl PreparedPeerWeightedRouteCombine {
1680    pub fn tokens(&self) -> usize {
1681        self.tokens
1682    }
1683
1684    pub fn pairs(&self) -> usize {
1685        self.pairs
1686    }
1687
1688    pub fn owner_pair_counts(&self) -> Vec<usize> {
1689        self.owners.iter().map(|owner| owner.active_pairs).collect()
1690    }
1691
1692    pub fn distributed_ranks(&self) -> usize {
1693        1 + self.peer_outputs.len()
1694    }
1695}
1696
1697struct ResidentTpExpertBank {
1698    gate: Vec<ResidentE4m3ExpertBankRank>,
1699    up: Vec<ResidentE4m3ExpertBankRank>,
1700    down: Vec<ResidentE4m3ExpertBankRank>,
1701    expert_count: usize,
1702    input_width: usize,
1703    expert_width: usize,
1704}
1705
1706/// Persistent tensor-parallel expert bank.
1707///
1708/// Every rank owns a checkpoint-aligned output-row shard of every gate/up projection and an
1709/// input-column shard of every down projection. Activations cross deterministic host-staged
1710/// collectives on hosts where native peer copies are unavailable or corrupt.
1711pub struct ResidentTensorParallel {
1712    bank: ResidentTpExpertBank,
1713}
1714
1715/// Multi-context TP correctness runtime. Each rank owns an independent `Engine` and CUDA context.
1716///
1717/// Host bounce is the default oracle. Native P2P is opt-in and preserves the oracle's global
1718/// checkpoint-block reduction order; it remains a correctness path until serving gates and
1719/// repeated performance evidence qualify it.
1720pub struct TpE4m3HostBounce {
1721    devices: Vec<usize>,
1722    ranks: Vec<Engine>,
1723    native_p2p: bool,
1724    ep_device_arithmetic: bool,
1725    bulk_p2p: bool,
1726    /// v2 decode-attention workspace (MEMRA_STEP_TP_DECODE_V2). One per runtime, shared by
1727    /// every TP attention layer — the buffer shapes are geometry-constant across the trunk.
1728    decode_v2: std::sync::Mutex<Vec<StepTpDecodeV2Ws>>,
1729}
1730
1731/// Persistent workspace of the v2 rank-local decode-attention driver.
1732///
1733/// Buffers live in their producing rank's CUDA context, are never freed, and events are
1734/// re-recorded per call — the pp.rs `BoundarySlot` discipline — so the per-token path has no
1735/// cuMemAlloc, no cross-stream free, and no host round-trip. Every buffer is fully overwritten
1736/// before its consumers run in the same call; nothing carries state between tokens.
1737/// Per-rank attn_gate row shards for the fused QKV+gate kernel, in the weight class the
1738/// fused kernels read (F32 mirror or raw checkpoint bf16).
1739pub enum StepTpGateShards<'a> {
1740    F32(&'a [crate::CudaSlice<f32>]),
1741    Bf16(&'a [crate::CudaSlice<u8>]),
1742}
1743
1744pub struct StepTpDecodeV2Ws {
1745    /// T-COLUMN verify slabs (spec MTP): per-rank [t, local_dim] projections computed by
1746    /// the weight-amortized qkvg_tcol kernel; the col-select door copies one column into
1747    /// the single-row buffers and everything downstream runs the unmodified t=1 program.
1748    pub(crate) tcol_q: Vec<CudaSlice<f32>>,
1749    pub(crate) tcol_k: Vec<CudaSlice<f32>>,
1750    pub(crate) tcol_v: Vec<CudaSlice<f32>>,
1751    pub(crate) tcol_g: Vec<CudaSlice<f32>>,
1752    pub(crate) tcol_in: Vec<CudaSlice<f32>>,
1753    pub(crate) tcol_cap: usize,
1754    /// MEMRA_STEP_TP_W8 activation scratch: per-rank q8_1 quantized attention input
1755    /// ([in_f] i8 + one f32 scale pair per 32). Persistent because the alternative is an
1756    /// allocation per rank per layer per token.
1757    w8_aq: Vec<CudaSlice<i8>>,
1758    w8_ad: Vec<CudaSlice<f32>>,
1759    w8_in: usize,
1760    /// o_proj-side twin of the same scratch (its activation is the gated attention output,
1761    /// a different vector from the QKV input, so it needs its own buffers).
1762    w8o_aq: Vec<CudaSlice<i8>>,
1763    w8o_ad: Vec<CudaSlice<f32>>,
1764    w8o_in: usize,
1765    /// VERIFY-WALK q8_1 activation scratch, t columns wide (the decode scratch above is one
1766    /// row). Two sets because the QKV input and the gated attention output are different
1767    /// vectors of different widths.
1768    w8t_aq: Vec<CudaSlice<i8>>,
1769    w8t_ad: Vec<CudaSlice<f32>>,
1770    w8t_in: usize,
1771    w8t_oaq: Vec<CudaSlice<i8>>,
1772    w8t_oad: Vec<CudaSlice<f32>>,
1773    w8t_oin: usize,
1774    w8t_cap: usize,
1775    /// MEMRA_TCOL_OPROJ slabs: per-rank stashed `gated` rows ([8, local_q_dim]), per-rank
1776    /// b4_tcol partials ([8, o_out]), a root-side peer pull of rank1's partial slab, and
1777    /// the root-side joined `mixed` slab. Armed lazily by the first stash.
1778    /// MEMRA_SPEC_FA2 slabs: per-rank stashed post-rope q rows ([2, local_q_dim]), gate
1779    /// rows ([2, heads/ranks]) and the two gated outputs the per-row combine writes
1780    /// ([2, local_q_dim]). Armed lazily by the first stash.
1781    pub(crate) fa2_q: Vec<CudaSlice<f32>>,
1782    pub(crate) fa2_gate: Vec<CudaSlice<f32>>,
1783    pub(crate) fa2_gated: Vec<CudaSlice<f32>>,
1784    pub(crate) fa2_cap: usize,
1785    /// T-ROW rope/append twin scratch: per-rank roped-k rows ([8, local_kv]), per-row
1786    /// last-block counters ([8]) and the per-tick position slab ([8]). Armed with the
1787    /// fa2 slabs.
1788    rope_k_t: Vec<CudaSlice<f32>>,
1789    rope_ctr_t: Vec<CudaSlice<u32>>,
1790    rope_pos_t: Vec<CudaSlice<i32>>,
1791    /// Per-rank combined 6-word row tables, keyed by the caller's (layer, session-set,
1792    /// base-arming) signature. LEGACY: only the `MEMRA_ROWS_TAB_RESTAGE=0` rollback arm
1793    /// reads this. See `rows_tab_t` for why the key cannot be made safe.
1794    rows_tabs: Vec<std::collections::HashMap<u64, CudaSlice<u64>>>,
1795    /// Per-rank PERSISTENT 6-word row-table slab ([32, 6] u64), RESTAGED from the live
1796    /// distributed cache before every launch. Replaces the `rows_tabs` memo, whose key was
1797    /// a hash of (k pointer, base pointer, layer, t) while the table it returned also
1798    /// carried the V and LEN pointers: a session whose K buffer address was recycled hit
1799    /// another session's table and the append kernel wrote its K/V through the FREED
1800    /// pointers the entry still held. Same defect and same cure as the row-table twin in
1801    /// `step35_verify_fa_rows_join` (8c8397e0b2, Hermes `11339f5cd3c132a3`), which this
1802    /// path was left out of. One 32-word htod per rank per layer replaces the map lookup;
1803    /// no allocation, and the staging is stream-ordered exactly like `rope_pos_t`.
1804    rows_tab_t: Vec<CudaSlice<u64>>,
1805    /// HOST shadow of the last table staged under each retired memo key, used ONLY by
1806    /// `MEMRA_ROWS_TAB_STALE_SCAN=1` to prove that the retired key would have handed a live
1807    /// launch another allocation's pointers. Never read by a kernel.
1808    rows_tab_shadow: Vec<std::collections::HashMap<u64, Vec<u64>>>,
1809    tcol_gated: Vec<CudaSlice<f32>>,
1810    tcol_opart: Vec<CudaSlice<f32>>,
1811    tcol_opeer: Option<CudaSlice<f32>>,
1812    tcol_omix: Option<CudaSlice<f32>>,
1813    tcol_ocap: usize,
1814    // rank-context buffers, indexed by rank (pub(crate): the v2 driver in hybrid_forward
1815    // feeds them to the KV transaction and attention kernels between the two v2 phases)
1816    pub(crate) q_raw: Vec<CudaSlice<f32>>,
1817    pub(crate) k_raw: Vec<CudaSlice<f32>>,
1818    pub(crate) v_raw: Vec<CudaSlice<f32>>,
1819    pub(crate) q: Vec<CudaSlice<f32>>,
1820    pub(crate) k: Vec<CudaSlice<f32>>,
1821    pub(crate) pos: Vec<CudaSlice<i32>>,
1822    /// FUSION #1 last-block counters (one per rank; atomicInc auto-resets per launch).
1823    pub(crate) fuse_ctr: Vec<CudaSlice<u32>>,
1824    pub(crate) gate: Vec<CudaSlice<f32>>,
1825    pub(crate) attn_out: Vec<CudaSlice<f32>>,
1826    pub(crate) gated: Vec<CudaSlice<f32>>,
1827    /// [rank][block] O partials, each `o_out` wide, in the owning rank's context.
1828    o_partials: Vec<Vec<CudaSlice<f32>>>,
1829    /// Stable workspace pointers for the rank-done-fenced raw P2P gather. Safe
1830    /// `memcpy_dtod` creates a fresh source event for every cross-context copy; the v2
1831    /// driver already records one persistent `ev_rank` after all three source families.
1832    raw_o_partials: Vec<Vec<u64>>,
1833    raw_k: Vec<u64>,
1834    raw_v_raw: Vec<u64>,
1835    /// Recorded on each rank's stream after its per-call work; root waits before peer reads.
1836    ev_rank: Vec<CudaEvent>,
1837    // root-context buffers
1838    peer_partial: CudaSlice<f32>,
1839    reduce_a: CudaSlice<f32>,
1840    reduce_b: CudaSlice<f32>,
1841    /// Never written; the canonical zero start of the v1 add chain.
1842    zeros: CudaSlice<f32>,
1843    pub(crate) k_shadow: CudaSlice<f32>,
1844    pub(crate) v_shadow: CudaSlice<f32>,
1845    ev_refresh: CudaEvent,
1846    ev_oproj: CudaEvent,
1847    // model-engine (e) context
1848    gate_e: CudaSlice<f32>,
1849    /// Per-token stages (e-ctx, fixed addresses): one eager e-stream copy each per layer; the
1850    /// rank flows raw-copy FROM them, which is exactly the shape graph capture needs.
1851    pub(crate) h_stage: Option<CudaSlice<f32>>,
1852    pub(crate) pos_stage: Option<CudaSlice<i32>>,
1853    /// Workspace-owned per-rank attention input rows (the stage flow copies into THESE, not
1854    /// the per-layer decode_input buffers — the workspace is shared across layers, so every
1855    /// captured/raw address it uses must be layer-invariant).
1856    attn_in: Vec<CudaSlice<f32>>,
1857    /// Cached raw pointers of the stage-flow operands (set when the stages arm).
1858    raw_h_stage: u64,
1859    raw_pos_stage: u64,
1860    raw_attn_in: Vec<u64>,
1861    raw_pos: Vec<u64>,
1862    raw_o_partial1: u64,
1863    raw_peer_partial: u64,
1864    raw_k1: u64,
1865    raw_v1: u64,
1866    raw_k_shadow: u64,
1867    raw_v_shadow: u64,
1868    /// Token-graph e-context mirrors (armed by the orchestrator): the root section
1869    /// raw-copies the reduced attention output and the shadow rows here so the e-glue
1870    /// children read same-context memory (cross-context kernel args are capture-illegal).
1871    raw_mixed_stage_e: u64,
1872    raw_reduce_a: u64,
1873    raw_shadow_stage_e: (u64, u64),
1874    ev_entry: CudaEvent,
1875    e_device: usize,
1876    // geometry pins
1877    local_q_dim: usize,
1878    local_kv_dim: usize,
1879    heads: usize,
1880    pub(crate) o_out: usize,
1881    o_block_cols: usize,
1882    blocks_per_rank: usize,
1883}
1884
1885impl TpE4m3HostBounce {
1886    pub fn new(devices: &[usize]) -> Result<Self, Box<dyn std::error::Error>> {
1887        Self::new_inner(devices, false, false, false, false)
1888    }
1889
1890    pub fn new_native_p2p(devices: &[usize]) -> Result<Self, Box<dyn std::error::Error>> {
1891        Self::new_inner(devices, false, true, false, false)
1892    }
1893
1894    pub fn new_native_p2p_device_arithmetic(
1895        devices: &[usize],
1896    ) -> Result<Self, Box<dyn std::error::Error>> {
1897        Self::new_inner(devices, false, true, true, false)
1898    }
1899
1900    pub(crate) fn new_configured(
1901        devices: &[usize],
1902        native_p2p: bool,
1903        ep_device_arithmetic: bool,
1904        bulk_p2p: bool,
1905    ) -> Result<Self, Box<dyn std::error::Error>> {
1906        Self::new_inner(devices, false, native_p2p, ep_device_arithmetic, bulk_p2p)
1907    }
1908
1909    /// Single-rank execution of the canonical checkpoint-block TP program.
1910    ///
1911    /// This is an oracle for distributed exactness, not a serving topology. It lets gates compare
1912    /// TP=1 and TP>1 with the same packing, kernel launches, and deterministic reduction order.
1913    pub fn new_single_rank_oracle(device: usize) -> Result<Self, Box<dyn std::error::Error>> {
1914        Self::new_inner(&[device], true, false, false, false)
1915    }
1916
1917    fn new_inner(
1918        devices: &[usize],
1919        allow_single_rank: bool,
1920        native_p2p: bool,
1921        ep_device_arithmetic: bool,
1922        bulk_p2p: bool,
1923    ) -> Result<Self, Box<dyn std::error::Error>> {
1924        if ep_device_arithmetic && !native_p2p {
1925            return Err("device-resident EP arithmetic requires native P2P".into());
1926        }
1927        if bulk_p2p && !native_p2p {
1928            return Err("bulk TP transport requires native P2P".into());
1929        }
1930        let minimum = if allow_single_rank { 1 } else { 2 };
1931        if !(minimum..=8).contains(&devices.len()) {
1932            return Err(format!(
1933                "TP reference requires {minimum}..=8 devices, got {}",
1934                devices.len()
1935            )
1936            .into());
1937        }
1938        let mut unique = devices.to_vec();
1939        unique.sort_unstable();
1940        unique.dedup();
1941        if unique.len() != devices.len() {
1942            return Err(format!("TP devices must be distinct, got {devices:?}").into());
1943        }
1944        let ranks = devices
1945            .iter()
1946            .map(|&device| Engine::new(device))
1947            .collect::<Result<Vec<_>, _>>()?;
1948        if native_p2p {
1949            configure_native_p2p(&ranks, devices)?;
1950        }
1951        if allow_single_rank {
1952            eprintln!(
1953                "[tp] canonical oracle transport=local device={} performance_claim=false",
1954                devices[0]
1955            );
1956        } else if native_p2p {
1957            if ep_device_arithmetic {
1958                eprintln!(
1959                    "[tp] correctness transport=native-p2p devices={devices:?} \
1960                     native_p2p=true activation=device-host-exact \
1961                     accumulation=device-host-exact output=root-readback \
1962                     bulk_p2p={bulk_p2p} performance_claim=false"
1963                );
1964            } else {
1965                eprintln!(
1966                    "[tp] correctness transport=native-p2p devices={devices:?} \
1967                     native_p2p=true activation=host-canonical bulk_p2p={bulk_p2p} \
1968                     performance_claim=false"
1969                );
1970            }
1971        } else {
1972            eprintln!(
1973                "[tp] correctness transport=host-bounce devices={devices:?} \
1974                 native_p2p=false performance_claim=false"
1975            );
1976        }
1977        Ok(Self {
1978            devices: devices.to_vec(),
1979            ranks,
1980            native_p2p,
1981            ep_device_arithmetic,
1982            bulk_p2p,
1983            decode_v2: std::sync::Mutex::new(Vec::new()),
1984        })
1985    }
1986
1987    pub fn devices(&self) -> &[usize] {
1988        &self.devices
1989    }
1990
1991    pub fn native_p2p(&self) -> bool {
1992        self.native_p2p
1993    }
1994
1995    pub fn bulk_p2p(&self) -> bool {
1996        self.bulk_p2p
1997    }
1998
1999    pub fn expert_activation_label(&self) -> &'static str {
2000        if self.ep_device_arithmetic {
2001            "device-host-exact"
2002        } else {
2003            "host-canonical"
2004        }
2005    }
2006
2007    pub fn expert_accumulation_label(&self) -> &'static str {
2008        self.expert_activation_label()
2009    }
2010
2011    pub fn expert_output_label(&self) -> &'static str {
2012        if self.ep_device_arithmetic {
2013            "root-readback"
2014        } else {
2015            "host-accumulated"
2016        }
2017    }
2018
2019    pub fn transport_label(&self) -> &'static str {
2020        if self.devices.len() == 1 {
2021            "local"
2022        } else if self.native_p2p {
2023            "native-p2p"
2024        } else {
2025            "host-bounce"
2026        }
2027    }
2028
2029    pub fn device_names(&self) -> Result<Vec<String>, Box<dyn std::error::Error>> {
2030        self.ranks
2031            .iter()
2032            .map(|rank| rank.ctx().name().map_err(Into::into))
2033            .collect()
2034    }
2035
2036    /// Correctness-gate access to the engine that owns one TP rank.
2037    ///
2038    /// Model execution should prefer collective methods on this runtime. This accessor exists so
2039    /// focused gates can prove that the rank-local projection outputs remain device-resident
2040    /// through the next ownership boundary before that boundary is wired into serving.
2041    pub fn rank_engine(&self, rank: usize) -> Option<&Engine> {
2042        self.ranks.get(rank)
2043    }
2044
2045    pub fn allocate_tp_kv_cache(
2046        &self,
2047        kv_dim_k: usize,
2048        kv_dim_v: usize,
2049        capacity: usize,
2050    ) -> Result<ResidentTpKvCache, Box<dyn std::error::Error>> {
2051        self.allocate_tp_kv_cache_inner(kv_dim_k, kv_dim_v, capacity, None)
2052    }
2053
2054    pub fn allocate_tp_swa_kv_cache(
2055        &self,
2056        kv_dim_k: usize,
2057        kv_dim_v: usize,
2058        capacity: usize,
2059        window: usize,
2060    ) -> Result<ResidentTpKvCache, Box<dyn std::error::Error>> {
2061        if window == 0 {
2062            return Err("TP SWA KV window must be nonzero".into());
2063        }
2064        self.allocate_tp_kv_cache_inner(kv_dim_k, kv_dim_v, capacity, Some(window))
2065    }
2066
2067    fn allocate_tp_kv_cache_inner(
2068        &self,
2069        kv_dim_k: usize,
2070        kv_dim_v: usize,
2071        capacity: usize,
2072        window: Option<usize>,
2073    ) -> Result<ResidentTpKvCache, Box<dyn std::error::Error>> {
2074        if capacity == 0 || capacity > i32::MAX as usize {
2075            return Err(
2076                format!("TP KV capacity must be in 1..={}, got {capacity}", i32::MAX).into(),
2077            );
2078        }
2079        let tp = self.ranks.len();
2080        let shape = crate::cache::tp_kv_rank_allocation_shape(kv_dim_k, kv_dim_v, tp)?;
2081        let physical_rows = window
2082            .map(|window| crate::cache::swa_ring_rows(window, capacity))
2083            .unwrap_or(capacity);
2084        let k_plane_bytes = physical_rows
2085            .checked_mul(shape.k_token_bytes)
2086            .and_then(|bytes| bytes.checked_add(8))
2087            .ok_or("TP KV K plane-byte overflow")?;
2088        let v_plane_bytes = physical_rows
2089            .checked_mul(shape.v_token_bytes)
2090            .and_then(|bytes| bytes.checked_add(8))
2091            .ok_or("TP KV V plane-byte overflow")?;
2092        let mut ranks = Vec::with_capacity(tp);
2093        for engine in &self.ranks {
2094            let _main = engine.gpu.enter_main()?;
2095            ranks.push(ResidentTpKvCacheRank::new(
2096                engine.alloc_u8(k_plane_bytes)?,
2097                engine.alloc_u8(v_plane_bytes)?,
2098                engine.htod_i32(&[0])?,
2099            ));
2100        }
2101        Ok(match window {
2102            Some(window) => ResidentTpKvCache::new_swa(
2103                ranks,
2104                shape.kv_dim_k,
2105                shape.kv_dim_v,
2106                shape.k_token_bytes,
2107                shape.v_token_bytes,
2108                capacity,
2109                window,
2110            ),
2111            None => ResidentTpKvCache::new(
2112                ranks,
2113                shape.kv_dim_k,
2114                shape.kv_dim_v,
2115                shape.k_token_bytes,
2116                shape.v_token_bytes,
2117                capacity,
2118            ),
2119        })
2120    }
2121
2122    pub fn grow_tp_kv_cache(
2123        &self,
2124        source: &ResidentTpKvCache,
2125        target_capacity: usize,
2126        rows: usize,
2127    ) -> Result<ResidentTpKvCache, Box<dyn std::error::Error>> {
2128        self.validate_tp_kv_cache(source)?;
2129        let plan = source.prepare_grow(target_capacity, rows)?;
2130        let ranks = self.ranks.len();
2131        let global_k = source
2132            .kv_dim_k()
2133            .checked_mul(ranks)
2134            .ok_or("TP KV grow global K dimension overflow")?;
2135        let global_v = source
2136            .kv_dim_v()
2137            .checked_mul(ranks)
2138            .ok_or("TP KV grow global V dimension overflow")?;
2139        let mut target = match source.ring_window() {
2140            Some(window) => {
2141                self.allocate_tp_swa_kv_cache(global_k, global_v, target_capacity, window)?
2142            }
2143            None => self.allocate_tp_kv_cache(global_k, global_v, target_capacity)?,
2144        };
2145        self.validate_tp_kv_cache(&target)?;
2146
2147        for (rank, engine) in self.ranks.iter().enumerate() {
2148            let _main = engine.gpu.enter_main()?;
2149            let src = source
2150                .rank(rank)
2151                .ok_or_else(|| format!("TP KV grow source has no rank {rank}"))?;
2152            let dst = target
2153                .rank_mut(rank)
2154                .ok_or_else(|| format!("TP KV grow target has no rank {rank}"))?;
2155            if plan.k_bytes() > 0 {
2156                engine.copy_u8_range_into(
2157                    dst.k_mut(),
2158                    0,
2159                    src.k(),
2160                    plan.source_row() * source.k_tok_bytes(),
2161                    plan.k_bytes(),
2162                )?;
2163            }
2164            if plan.v_bytes() > 0 {
2165                engine.copy_u8_range_into(
2166                    dst.v_mut(),
2167                    0,
2168                    src.v(),
2169                    plan.source_row() * source.v_tok_bytes(),
2170                    plan.v_bytes(),
2171                )?;
2172            }
2173        }
2174        self.set_tp_kv_len_mirrors(&mut target, plan.rows())?;
2175
2176        // The caller publishes `target` and immediately drops `source`. Drain every rank's
2177        // stream so an async-pool free cannot recycle a source plane under an in-flight D2D copy.
2178        for engine in &self.ranks {
2179            let _main = engine.gpu.enter_main()?;
2180            engine.stream().synchronize()?;
2181        }
2182        let physical_copy_rows = plan.copy_rows();
2183        target.publish_grow(plan)?;
2184        eprintln!(
2185            "[step-tp-kv-grow] rows={} source_capacity={} target_capacity={} ranks={} \
2186             physical_copy_rows={} ring_window={:?} copy=rank-local-dtod \
2187             rank_streams_synchronized=true generation_preserved=true",
2188            rows,
2189            source.capacity(),
2190            target_capacity,
2191            ranks,
2192            physical_copy_rows,
2193            source.ring_window(),
2194        );
2195        Ok(target)
2196    }
2197
2198    pub fn hydrate_tp_kv_cache(
2199        &self,
2200        cache: &mut ResidentTpKvCache,
2201        rows: usize,
2202        k_rows: &[u8],
2203        v_rows: &[u8],
2204    ) -> Result<(), Box<dyn std::error::Error>> {
2205        self.hydrate_tp_kv_cache_from(cache, rows, 0, k_rows, v_rows)
2206    }
2207
2208    pub fn hydrate_tp_kv_cache_from(
2209        &self,
2210        cache: &mut ResidentTpKvCache,
2211        logical_len: usize,
2212        resident_start: usize,
2213        k_rows: &[u8],
2214        v_rows: &[u8],
2215    ) -> Result<(), Box<dyn std::error::Error>> {
2216        self.validate_tp_kv_cache(cache)?;
2217        if cache.committed_len() != 0 || cache.staged_len() != 0 {
2218            return Err(format!(
2219                "TP KV hydration requires an empty cache, got committed/staged={}/{}",
2220                cache.committed_len(),
2221                cache.staged_len()
2222            )
2223            .into());
2224        }
2225        if resident_start > logical_len || logical_len > cache.capacity() {
2226            return Err(format!(
2227                "TP KV hydration range [{resident_start},{logical_len}) exceeds capacity {}",
2228                cache.capacity(),
2229            )
2230            .into());
2231        }
2232        let rows = logical_len - resident_start;
2233        if rows > cache.physical_capacity() {
2234            return Err(format!(
2235                "TP KV hydration rows {rows} exceed physical capacity {}",
2236                cache.physical_capacity()
2237            )
2238            .into());
2239        }
2240        for rank in 0..self.ranks.len() {
2241            let k_rank =
2242                cache_rank_rows(k_rows, rows, cache.k_tok_bytes(), self.ranks.len(), rank)?;
2243            let v_rank =
2244                cache_rank_rows(v_rows, rows, cache.v_tok_bytes(), self.ranks.len(), rank)?;
2245            let engine = &self.ranks[rank];
2246            let _main = engine.gpu.enter_main()?;
2247            let rank_cache = cache
2248                .rank_mut(rank)
2249                .ok_or_else(|| format!("TP KV cache has no rank {rank}"))?;
2250            engine.htod_u8_into(rank_cache.k_mut(), 0, &k_rank)?;
2251            engine.htod_u8_into(rank_cache.v_mut(), 0, &v_rank)?;
2252        }
2253        cache.publish_hydration(logical_len, resident_start)?;
2254        Ok(())
2255    }
2256
2257    pub fn append_tp_kv_transaction(
2258        &self,
2259        cache: &mut ResidentTpKvCache,
2260        transaction: TpKvTransaction,
2261        k_shards: &[CudaSlice<f32>],
2262        v_shards: &[CudaSlice<f32>],
2263        rows: usize,
2264    ) -> Result<(), Box<dyn std::error::Error>> {
2265        self.append_tp_kv_transaction_inner(cache, transaction, k_shards, v_shards, rows, false)
2266    }
2267
2268    /// `external_rank_appends`: the dcw path already wrote the rank rows (device-counter
2269    /// append) — run everything EXCEPT the per-rank quantize/append loop (plan validation,
2270    /// rebase arm — unreachable when the caller peeked — and the absolute len-mirror sets,
2271    /// which land the same value the in-stream inc produced).
2272    #[allow(clippy::too_many_arguments)]
2273    pub fn append_tp_kv_transaction_inner(
2274        &self,
2275        cache: &mut ResidentTpKvCache,
2276        transaction: TpKvTransaction,
2277        k_shards: &[CudaSlice<f32>],
2278        v_shards: &[CudaSlice<f32>],
2279        rows: usize,
2280        external_rank_appends: bool,
2281    ) -> Result<(), Box<dyn std::error::Error>> {
2282        self.validate_tp_kv_cache(cache)?;
2283        let plan = cache.prepare_append(transaction, rows)?;
2284        let target = plan.target();
2285        let expected_k = rows
2286            .checked_mul(cache.kv_dim_k())
2287            .ok_or("TP KV K append size overflow")?;
2288        let expected_v = rows
2289            .checked_mul(cache.kv_dim_v())
2290            .ok_or("TP KV V append size overflow")?;
2291        // external_rank_appends passes no shards — the graph's dcw appends already wrote
2292        // the rank rows, so this call is bookkeeping-only and the shard slices are unused.
2293        if !external_rank_appends
2294            && (k_shards.len() != self.ranks.len() || v_shards.len() != self.ranks.len())
2295        {
2296            return Err(format!(
2297                "TP KV append shard counts k={} v={} != ranks {}",
2298                k_shards.len(),
2299                v_shards.len(),
2300                self.ranks.len()
2301            )
2302            .into());
2303        }
2304        let kv_dim_k = cache.kv_dim_k();
2305        let kv_dim_v = cache.kv_dim_v();
2306        let k_tok_bytes = cache.k_tok_bytes();
2307        let v_tok_bytes = cache.v_tok_bytes();
2308        if let Some(KvRingAppend::Rebase {
2309            src_row,
2310            keep_rows,
2311            new_base,
2312            ..
2313        }) = plan.ring_append()
2314        {
2315            for rank in 0..self.ranks.len() {
2316                let engine = &self.ranks[rank];
2317                let _main = engine.gpu.enter_main()?;
2318                let rank_cache = cache
2319                    .rank_mut(rank)
2320                    .ok_or_else(|| format!("TP KV cache has no rank {rank}"))?;
2321                if keep_rows > 0 {
2322                    let k_len = keep_rows
2323                        .checked_mul(k_tok_bytes)
2324                        .ok_or("TP KV K rebase-byte overflow")?;
2325                    let v_len = keep_rows
2326                        .checked_mul(v_tok_bytes)
2327                        .ok_or("TP KV V rebase-byte overflow")?;
2328                    let mut k_tmp = engine.alloc_u8_uninit(k_len)?;
2329                    let mut v_tmp = engine.alloc_u8_uninit(v_len)?;
2330                    engine.copy_u8_range_into(
2331                        &mut k_tmp,
2332                        0,
2333                        rank_cache.k(),
2334                        src_row * k_tok_bytes,
2335                        k_len,
2336                    )?;
2337                    engine.copy_u8_range_into(
2338                        &mut v_tmp,
2339                        0,
2340                        rank_cache.v(),
2341                        src_row * v_tok_bytes,
2342                        v_len,
2343                    )?;
2344                    engine.copy_u8_into(rank_cache.k_mut(), 0, &k_tmp, k_len)?;
2345                    engine.copy_u8_into(rank_cache.v_mut(), 0, &v_tmp, v_len)?;
2346                }
2347                // dcw base mirror (graph increment A): physical row 0 now holds logical
2348                // row `new_base`; armed device mirrors track it (rebases are rare host
2349                // events, so a host set here is the whole maintenance cost).
2350                if rank_cache.base_d().is_some() {
2351                    let value = new_base as i32;
2352                    let rank_cache = cache
2353                        .rank_mut(rank)
2354                        .ok_or_else(|| format!("TP KV cache has no rank {rank}"))?;
2355                    if let Some(base_d) = rank_cache.base_d_mut() {
2356                        engine.set_i32_one(base_d, value)?;
2357                    }
2358                }
2359            }
2360        }
2361        cache.publish_append_rebase(plan)?;
2362        let write_row = plan.write_row();
2363        for rank in 0..self.ranks.len() {
2364            if external_rank_appends {
2365                break;
2366            }
2367            let engine = &self.ranks[rank];
2368            let _main = engine.gpu.enter_main()?;
2369            if k_shards[rank].len() != expected_k
2370                || v_shards[rank].len() != expected_v
2371                || k_shards[rank].ordinal() != engine.ctx().ordinal()
2372                || v_shards[rank].ordinal() != engine.ctx().ordinal()
2373            {
2374                return Err(format!(
2375                    "TP KV rank {rank} shard geometry/device k={}/{} v={}/{} \
2376                     != expected {expected_k}/{expected_v} on device {}",
2377                    k_shards[rank].len(),
2378                    k_shards[rank].ordinal(),
2379                    v_shards[rank].len(),
2380                    v_shards[rank].ordinal(),
2381                    engine.ctx().ordinal(),
2382                )
2383                .into());
2384            }
2385            let rank_cache = cache
2386                .rank_mut(rank)
2387                .ok_or_else(|| format!("TP KV cache has no rank {rank}"))?;
2388            let (rank_k, rank_v) = rank_cache.planes_mut();
2389            engine.append_kv_quantized_rows(
2390                &k_shards[rank],
2391                &v_shards[rank],
2392                rank_k,
2393                rank_v,
2394                write_row,
2395                rows,
2396                kv_dim_k,
2397                kv_dim_v,
2398                k_tok_bytes,
2399                v_tok_bytes,
2400                Engine::kv_fp8_on(),
2401            )?;
2402        }
2403        if !external_rank_appends {
2404            // dcw appends advance the device counters with in-stream inc_i32; an absolute set
2405            // here would race the merged per-rank append (it reads len_d for its write row).
2406            self.set_tp_kv_len_mirrors(cache, target)?;
2407        }
2408        cache.publish_append_plan(plan)?;
2409        Ok(())
2410    }
2411
2412    pub fn commit_tp_kv_transaction(
2413        &self,
2414        cache: &mut ResidentTpKvCache,
2415        transaction: TpKvTransaction,
2416        accepted_rows: usize,
2417    ) -> Result<(), Box<dyn std::error::Error>> {
2418        self.validate_tp_kv_cache(cache)?;
2419        let target = cache.commit_target(transaction, accepted_rows)?;
2420        self.set_tp_kv_len_mirrors(cache, target)?;
2421        cache.publish_finalize(transaction, target)?;
2422        Ok(())
2423    }
2424
2425    /// Commit for the external-appends (token graph) path: host bookkeeping only, NO absolute
2426    /// len-mirror sets. The graph's in-stream inc_i32 owns the device counters; a rank-stream
2427    /// set here has no ordering edge against the NEXT token's graph launch (graph children do
2428    /// not wait on the rank streams), so it can land AFTER that graph's inc and drag the
2429    /// counter backward mid-token.
2430    pub fn commit_tp_kv_transaction_external(
2431        &self,
2432        cache: &mut ResidentTpKvCache,
2433        transaction: TpKvTransaction,
2434        accepted_rows: usize,
2435    ) -> Result<(), Box<dyn std::error::Error>> {
2436        self.validate_tp_kv_cache(cache)?;
2437        let target = cache.commit_target(transaction, accepted_rows)?;
2438        cache.publish_finalize(transaction, target)?;
2439        Ok(())
2440    }
2441
2442    pub fn rollback_tp_kv_transaction(
2443        &self,
2444        cache: &mut ResidentTpKvCache,
2445        transaction: TpKvTransaction,
2446    ) -> Result<(), Box<dyn std::error::Error>> {
2447        self.validate_tp_kv_cache(cache)?;
2448        cache.validate_transaction(transaction)?;
2449        let target = transaction.base_len();
2450        self.set_tp_kv_len_mirrors(cache, target)?;
2451        cache.publish_finalize(transaction, target)?;
2452        Ok(())
2453    }
2454
2455    pub fn tp_kv_device_lengths(
2456        &self,
2457        cache: &ResidentTpKvCache,
2458    ) -> Result<Vec<i32>, Box<dyn std::error::Error>> {
2459        self.validate_tp_kv_cache(cache)?;
2460        let mut lengths = Vec::with_capacity(self.ranks.len());
2461        for (engine, rank_cache) in self.ranks.iter().zip(cache.ranks()) {
2462            let _main = engine.gpu.enter_main()?;
2463            lengths.push(engine.dtoh_i32_one(rank_cache.len_d())?);
2464        }
2465        Ok(lengths)
2466    }
2467
2468    fn set_tp_kv_len_mirrors(
2469        &self,
2470        cache: &mut ResidentTpKvCache,
2471        len: usize,
2472    ) -> Result<(), Box<dyn std::error::Error>> {
2473        let len = i32::try_from(len).map_err(|_| "TP KV length exceeds i32 device mirror")?;
2474        for (engine, rank_cache) in self.ranks.iter().zip(cache.ranks_mut()) {
2475            let _main = engine.gpu.enter_main()?;
2476            engine.set_i32_one(rank_cache.len_d_mut(), len)?;
2477        }
2478        Ok(())
2479    }
2480
2481    fn validate_tp_kv_cache(
2482        &self,
2483        cache: &ResidentTpKvCache,
2484    ) -> Result<(), Box<dyn std::error::Error>> {
2485        if cache.ranks_len() != self.ranks.len() {
2486            return Err(format!(
2487                "TP KV cache ranks {} != runtime ranks {}",
2488                cache.ranks_len(),
2489                self.ranks.len()
2490            )
2491            .into());
2492        }
2493        let expected_k = cache
2494            .physical_capacity()
2495            .checked_mul(cache.k_tok_bytes())
2496            .and_then(|bytes| bytes.checked_add(8))
2497            .ok_or("TP KV K plane validation overflow")?;
2498        let expected_v = cache
2499            .physical_capacity()
2500            .checked_mul(cache.v_tok_bytes())
2501            .and_then(|bytes| bytes.checked_add(8))
2502            .ok_or("TP KV V plane validation overflow")?;
2503        for (rank, (engine, rank_cache)) in self.ranks.iter().zip(cache.ranks()).enumerate() {
2504            let device = engine.ctx().ordinal();
2505            if rank_cache.k().len() != expected_k
2506                || rank_cache.v().len() != expected_v
2507                || rank_cache.len_d().len() != 1
2508                || rank_cache.k().ordinal() != device
2509                || rank_cache.v().ordinal() != device
2510                || rank_cache.len_d().ordinal() != device
2511            {
2512                return Err(format!(
2513                    "TP KV rank {rank} residency does not match device {device} or plane geometry"
2514                )
2515                .into());
2516            }
2517        }
2518        Ok(())
2519    }
2520
2521    pub fn full(
2522        &self,
2523        matrix: E4m3BlockMatrix<'_>,
2524        activations: &[f32],
2525        tokens: usize,
2526    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
2527        matrix.validate()?;
2528        validate_activations(activations, tokens, matrix.in_features)?;
2529        run_rank(&self.ranks[0], matrix, activations, tokens)
2530    }
2531
2532    /// Column-parallel projection. Weight output rows and their scale rows are partitioned across
2533    /// ranks. The input is host-broadcast, rank-local projections execute independently, and the
2534    /// output is host-gathered in rank order.
2535    #[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
2536    pub fn column_parallel(
2537        &self,
2538        matrix: E4m3BlockMatrix<'_>,
2539        activations: &[f32],
2540        tokens: usize,
2541    ) -> Result<ColumnParallelResult, Box<dyn std::error::Error>> {
2542        matrix.validate()?;
2543        validate_activations(activations, tokens, matrix.in_features)?;
2544        let tp = self.ranks.len();
2545        if matrix.out_features % tp != 0 {
2546            return Err(format!(
2547                "column-parallel out_features {} is not divisible by TP={tp}",
2548                matrix.out_features
2549            )
2550            .into());
2551        }
2552        let local_out = matrix.out_features / tp;
2553        if !local_out.is_multiple_of(FP8_BLOCK) {
2554            return Err(format!(
2555                "column-parallel output shard {local_out} cuts through a {FP8_BLOCK}-row \
2556                 E4M3 scale block"
2557            )
2558            .into());
2559        }
2560
2561        let mut gathered = vec![0.0f32; tokens * matrix.out_features];
2562        let mut rank_outputs = Vec::with_capacity(tp);
2563        for (rank_index, rank) in self.ranks.iter().enumerate() {
2564            let shard = column_shard(matrix, tp, rank_index)?;
2565            let output = run_rank(rank, shard, activations, tokens)?;
2566            let row_start = rank_index * local_out;
2567            for token in 0..tokens {
2568                gathered[token * matrix.out_features + row_start
2569                    ..token * matrix.out_features + row_start + local_out]
2570                    .copy_from_slice(&output[token * local_out..(token + 1) * local_out]);
2571            }
2572            rank_outputs.push(output);
2573        }
2574        Ok(ColumnParallelResult {
2575            gathered,
2576            rank_outputs,
2577        })
2578    }
2579
2580    pub fn upload_column_parallel(
2581        &self,
2582        matrix: E4m3BlockMatrix<'_>,
2583    ) -> Result<ResidentColumnParallel, Box<dyn std::error::Error>> {
2584        matrix.validate()?;
2585        let tp = self.ranks.len();
2586        validate_column_shape(matrix, tp)?;
2587        let mut ranks = Vec::with_capacity(tp);
2588        for (rank_index, engine) in self.ranks.iter().enumerate() {
2589            ranks.push(upload_rank(engine, column_shard(matrix, tp, rank_index)?)?);
2590        }
2591        Ok(ResidentColumnParallel {
2592            ranks,
2593            out_features: matrix.out_features,
2594            in_features: matrix.in_features,
2595        })
2596    }
2597
2598    pub fn column_parallel_resident(
2599        &self,
2600        matrix: &ResidentColumnParallel,
2601        activations: &[f32],
2602        tokens: usize,
2603    ) -> Result<ColumnParallelResult, Box<dyn std::error::Error>> {
2604        validate_resident_ranks(&self.ranks, &matrix.ranks)?;
2605        validate_activations(activations, tokens, matrix.in_features)?;
2606        let local_out = matrix.out_features / self.ranks.len();
2607        let mut gathered = vec![0.0f32; tokens * matrix.out_features];
2608        let mut rank_outputs = Vec::with_capacity(self.ranks.len());
2609        for (rank_index, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
2610            let output = run_resident_rank(engine, shard, activations, tokens)?;
2611            let row_start = rank_index * local_out;
2612            for token in 0..tokens {
2613                gathered[token * matrix.out_features + row_start
2614                    ..token * matrix.out_features + row_start + local_out]
2615                    .copy_from_slice(&output[token * local_out..(token + 1) * local_out]);
2616            }
2617            rank_outputs.push(output);
2618        }
2619        Ok(ColumnParallelResult {
2620            gathered,
2621            rank_outputs,
2622        })
2623    }
2624
2625    /// Row-parallel projection. Weight/input columns and their scale columns are partitioned
2626    /// across ranks. Rank-local partials return through host memory and are reduced in stable
2627    /// rank order.
2628    #[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
2629    pub fn row_parallel(
2630        &self,
2631        matrix: E4m3BlockMatrix<'_>,
2632        activations: &[f32],
2633        tokens: usize,
2634    ) -> Result<RowParallelResult, Box<dyn std::error::Error>> {
2635        matrix.validate()?;
2636        validate_activations(activations, tokens, matrix.in_features)?;
2637        let tp = self.ranks.len();
2638        if matrix.in_features % tp != 0 {
2639            return Err(format!(
2640                "row-parallel in_features {} is not divisible by TP={tp}",
2641                matrix.in_features
2642            )
2643            .into());
2644        }
2645        let local_in = matrix.in_features / tp;
2646        if !local_in.is_multiple_of(FP8_BLOCK) {
2647            return Err(format!(
2648                "row-parallel input shard {local_in} cuts through a {FP8_BLOCK}-column \
2649                 E4M3 scale block"
2650            )
2651            .into());
2652        }
2653
2654        let mut reduced = vec![0.0f32; tokens * matrix.out_features];
2655        let mut rank_partials = Vec::with_capacity(tp);
2656        for (rank_index, rank) in self.ranks.iter().enumerate() {
2657            let (codes, scales) = row_shard(matrix, tp, rank_index)?;
2658            let local_activations =
2659                activation_shard(activations, tokens, matrix.in_features, tp, rank_index);
2660            let shard = E4m3BlockMatrix {
2661                codes: &codes,
2662                scales: &scales,
2663                out_features: matrix.out_features,
2664                in_features: local_in,
2665            };
2666            let partial = run_rank(rank, shard, &local_activations, tokens)?;
2667            for (sum, value) in reduced.iter_mut().zip(&partial) {
2668                *sum += *value;
2669            }
2670            rank_partials.push(partial);
2671        }
2672        Ok(RowParallelResult {
2673            reduced,
2674            rank_partials,
2675        })
2676    }
2677
2678    pub fn upload_row_parallel(
2679        &self,
2680        matrix: E4m3BlockMatrix<'_>,
2681    ) -> Result<ResidentRowParallel, Box<dyn std::error::Error>> {
2682        matrix.validate()?;
2683        let tp = self.ranks.len();
2684        validate_row_shape(matrix, tp)?;
2685        let local_in = matrix.in_features / tp;
2686        let mut ranks = Vec::with_capacity(tp);
2687        for (rank_index, engine) in self.ranks.iter().enumerate() {
2688            let (codes, scales) = row_shard(matrix, tp, rank_index)?;
2689            ranks.push(upload_rank(
2690                engine,
2691                E4m3BlockMatrix {
2692                    codes: &codes,
2693                    scales: &scales,
2694                    out_features: matrix.out_features,
2695                    in_features: local_in,
2696                },
2697            )?);
2698        }
2699        Ok(ResidentRowParallel {
2700            ranks,
2701            out_features: matrix.out_features,
2702            in_features: matrix.in_features,
2703        })
2704    }
2705
2706    pub fn row_parallel_resident(
2707        &self,
2708        matrix: &ResidentRowParallel,
2709        activations: &[f32],
2710        tokens: usize,
2711    ) -> Result<RowParallelResult, Box<dyn std::error::Error>> {
2712        validate_resident_ranks(&self.ranks, &matrix.ranks)?;
2713        validate_activations(activations, tokens, matrix.in_features)?;
2714        let tp = self.ranks.len();
2715        let mut reduced = vec![0.0f32; tokens * matrix.out_features];
2716        let mut rank_partials = Vec::with_capacity(tp);
2717        for (rank_index, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
2718            let local_activations =
2719                activation_shard(activations, tokens, matrix.in_features, tp, rank_index);
2720            let partial = run_resident_rank(engine, shard, &local_activations, tokens)?;
2721            for (sum, value) in reduced.iter_mut().zip(&partial) {
2722                *sum += *value;
2723            }
2724            rank_partials.push(partial);
2725        }
2726        Ok(RowParallelResult {
2727            reduced,
2728            rank_partials,
2729        })
2730    }
2731
2732    pub fn upload_bf16_column_parallel(
2733        &self,
2734        matrix: Bf16Matrix<'_>,
2735    ) -> Result<ResidentBf16ColumnParallel, Box<dyn std::error::Error>> {
2736        self.upload_bf16_column_parallel_inner(matrix, None, false)
2737    }
2738
2739    /// Step-3.7 column projection with one numerical program across TP1/TP2/TP4/TP8.
2740    pub fn upload_step_bf16_column_parallel(
2741        &self,
2742        matrix: Bf16Matrix<'_>,
2743    ) -> Result<ResidentBf16ColumnParallel, Box<dyn std::error::Error>> {
2744        self.upload_step_bf16_column_parallel_inner(matrix, false)
2745    }
2746
2747    /// Load-time exact F32 expansion of a Step BF16 shard.
2748    ///
2749    /// The original BF16 allocation is released after the stream-ordered conversion. Decode then
2750    /// reuses the resident F32 values with the same topology-invariant output-row chunks.
2751    pub fn upload_step_bf16_column_parallel_f32_mirror(
2752        &self,
2753        matrix: Bf16Matrix<'_>,
2754    ) -> Result<ResidentBf16ColumnParallel, Box<dyn std::error::Error>> {
2755        self.upload_step_bf16_column_parallel_inner(matrix, true)
2756    }
2757
2758    fn upload_step_bf16_column_parallel_inner(
2759        &self,
2760        matrix: Bf16Matrix<'_>,
2761        f32_mirror: bool,
2762    ) -> Result<ResidentBf16ColumnParallel, Box<dyn std::error::Error>> {
2763        let canonical_chunk_rows =
2764            step_bf16_canonical_chunk_rows(matrix.out_features, self.ranks.len())?;
2765        self.upload_bf16_column_parallel_inner(matrix, Some(canonical_chunk_rows), f32_mirror)
2766    }
2767
2768    #[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
2769    fn upload_bf16_column_parallel_inner(
2770        &self,
2771        matrix: Bf16Matrix<'_>,
2772        canonical_chunk_rows: Option<usize>,
2773        f32_mirror: bool,
2774    ) -> Result<ResidentBf16ColumnParallel, Box<dyn std::error::Error>> {
2775        matrix.validate()?;
2776        let tp = self.ranks.len();
2777        if matrix.out_features % tp != 0 {
2778            return Err(format!(
2779                "BF16 column-parallel out_features {} is not divisible by TP={tp}",
2780                matrix.out_features
2781            )
2782            .into());
2783        }
2784        let mut ranks = Vec::with_capacity(tp);
2785        for (rank, engine) in self.ranks.iter().enumerate() {
2786            ranks.push(upload_bf16_rank(
2787                engine,
2788                bf16_column_shard(matrix, tp, rank)?,
2789                f32_mirror,
2790            )?);
2791        }
2792        Ok(ResidentBf16ColumnParallel {
2793            ranks,
2794            out_features: matrix.out_features,
2795            in_features: matrix.in_features,
2796            canonical_chunk_rows,
2797        })
2798    }
2799
2800    pub fn bf16_column_parallel_resident(
2801        &self,
2802        matrix: &ResidentBf16ColumnParallel,
2803        activations: &[f32],
2804        tokens: usize,
2805    ) -> Result<ColumnParallelResult, Box<dyn std::error::Error>> {
2806        validate_resident_bf16_ranks(&self.ranks, &matrix.ranks)?;
2807        validate_activations(activations, tokens, matrix.in_features)?;
2808        let local_out = matrix.out_features / self.ranks.len();
2809        let mut gathered = vec![0.0f32; tokens * matrix.out_features];
2810        let mut rank_outputs = Vec::with_capacity(self.ranks.len());
2811        for (rank, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
2812            let output = run_resident_bf16_rank(
2813                engine,
2814                shard,
2815                activations,
2816                tokens,
2817                matrix.canonical_chunk_rows,
2818            )?;
2819            for token in 0..tokens {
2820                let src = &output[token * local_out..(token + 1) * local_out];
2821                let dst_start = token * matrix.out_features + rank * local_out;
2822                gathered[dst_start..dst_start + local_out].copy_from_slice(src);
2823            }
2824            rank_outputs.push(output);
2825        }
2826        Ok(ColumnParallelResult {
2827            gathered,
2828            rank_outputs,
2829        })
2830    }
2831
2832    /// Native-P2P twin of [`Self::bf16_column_parallel_resident`].
2833    ///
2834    /// The host-canonical activation is uploaded once on rank zero and peer-broadcast to the
2835    /// remaining ranks. Rank-local outputs are peer-gathered in token-major order before one root
2836    /// readback. This removes per-rank host staging but deliberately still returns a host oracle;
2837    /// attention and KV ownership are separate milestones.
2838    pub fn bf16_column_parallel_resident_native(
2839        &self,
2840        matrix: &ResidentBf16ColumnParallel,
2841        activations: &[f32],
2842        tokens: usize,
2843    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
2844        let rank_outputs =
2845            self.bf16_column_parallel_resident_device_shards(matrix, activations, tokens)?;
2846        let local_out = matrix.out_features / self.ranks.len();
2847        self.gather_native_column_shards(&rank_outputs, tokens, local_out)
2848    }
2849
2850    /// Does the serving engine live in the SAME CUDA context as this runtime's root rank?
2851    /// The device-resident input/output seams below hand raw device buffers across the
2852    /// Engine boundary, which is only addressable when both sides share the root device's
2853    /// primary context — the generic full-attention TP seam keys its residency dispatch on.
2854    pub fn root_shares_ctx(&self, e: &Engine) -> bool {
2855        self.ranks
2856            .first()
2857            .is_some_and(|root| root.ctx().cu_ctx() == e.ctx().cu_ctx())
2858    }
2859
2860    /// Device-input twin of [`Self::bf16_column_parallel_resident_native`] (lane/
2861    /// hermes-perf-fixes, 2026-08-23 — the step QKV TP host-bounce finding). The activation
2862    /// arrives as a ROOT-DEVICE buffer (first `tokens * in_features` values) instead of a
2863    /// host slice, and the gathered output stays root-resident: no DtoH of the hidden state,
2864    /// no host q/k/v staging, no re-upload. BYTE-IDENTICAL to the host-canonical native arm
2865    /// by construction — the root input bytes are dtod-copied where the host arm htod'd the
2866    /// same bytes, and every kernel, peer copy, and gather order is shared.
2867    ///
2868    /// FENCES: caller must have synchronized the producer stream that wrote
2869    /// `root_activation` (the serving engine's — a DIFFERENT stream in the same context);
2870    /// this method synchronizes the root stream before returning so the caller's stream can
2871    /// consume the gathered output immediately.
2872    pub fn bf16_column_parallel_resident_native_device(
2873        &self,
2874        matrix: &ResidentBf16ColumnParallel,
2875        root_activation: &CudaSlice<f32>,
2876        tokens: usize,
2877    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
2878        let rank_outputs = self.bf16_column_parallel_resident_device_shards_from_root(
2879            matrix,
2880            root_activation,
2881            tokens,
2882        )?;
2883        let local_out = matrix.out_features / self.ranks.len();
2884        let gathered = self.gather_native_column_shards_device(&rank_outputs, tokens, local_out)?;
2885        let root = &self.ranks[0];
2886        let _main = root.gpu.enter_main()?;
2887        root.stream().synchronize()?;
2888        Ok(gathered)
2889    }
2890
2891    /// Root-device-input twin of [`Self::bf16_column_parallel_resident_device_shards`]:
2892    /// the canonical activation is already resident on the root device (len >=
2893    /// `tokens * in_features`; extra tail values beyond the active prefix are ignored,
2894    /// the reused-prime-slab contract of `active_matrix_values`).
2895    pub fn bf16_column_parallel_resident_device_shards_from_root(
2896        &self,
2897        matrix: &ResidentBf16ColumnParallel,
2898        root_activation: &CudaSlice<f32>,
2899        tokens: usize,
2900    ) -> Result<Vec<CudaSlice<f32>>, Box<dyn std::error::Error>> {
2901        if self.ranks.len() > 1 && !self.native_p2p {
2902            return Err("device-resident BF16 column parallelism requires native P2P ranks".into());
2903        }
2904        validate_resident_bf16_ranks(&self.ranks, &matrix.ranks)?;
2905        let values = tokens
2906            .checked_mul(matrix.in_features)
2907            .ok_or("device BF16 column activation size overflow")?;
2908        let root = &self.ranks[0];
2909        if tokens == 0
2910            || root_activation.len() < values
2911            || root_activation.ordinal() != root.ctx().ordinal()
2912        {
2913            return Err("device BF16 column root activation geometry mismatch".into());
2914        }
2915
2916        let mut rank_inputs = Vec::with_capacity(self.ranks.len());
2917        let root_input = {
2918            let _main = root.gpu.enter_main()?;
2919            let mut root_input = root.uninit(values)?;
2920            root.stream()
2921                .memcpy_dtod(&root_activation.slice(0..values), &mut root_input)?;
2922            root_input
2923        };
2924        // PRODUCER FENCE (same discipline as the host-input twin): the peer broadcast
2925        // below reads this buffer from the OTHER ranks' streams while the root dtod may
2926        // still be in flight.
2927        {
2928            let _main = root.gpu.enter_main()?;
2929            root.stream().synchronize()?;
2930        }
2931        rank_inputs.push(root_input);
2932        for engine in &self.ranks[1..] {
2933            let peer_input = {
2934                let _main = engine.gpu.enter_main()?;
2935                let mut peer_input = engine.uninit(values)?;
2936                engine
2937                    .stream()
2938                    .memcpy_dtod(&rank_inputs[0], &mut peer_input)?;
2939                peer_input
2940            };
2941            rank_inputs.push(peer_input);
2942        }
2943
2944        let mut rank_outputs = Vec::with_capacity(self.ranks.len());
2945        #[allow(clippy::needless_range_loop)]
2946        // allow: the explicit index loop keeps the offset arithmetic visible and aligned with the device-side indexing
2947        for rank in 0..self.ranks.len() {
2948            rank_outputs.push(run_resident_bf16_rank_device(
2949                &self.ranks[rank],
2950                &matrix.ranks[rank],
2951                &rank_inputs[rank],
2952                tokens,
2953                matrix.canonical_chunk_rows,
2954                self.bulk_p2p,
2955            )?);
2956        }
2957        Ok(rank_outputs)
2958    }
2959
2960    /// Keep Step BF16 column outputs resident on their owning TP ranks.
2961    ///
2962    /// Rank zero receives the host-canonical activation once and peer-broadcasts it when TP>1.
2963    /// Unlike [`Self::bf16_column_parallel_resident_native`], this method performs no output
2964    /// gather or readback. It is the correctness substrate for rank-local norm, RoPE, attention,
2965    /// and cache ownership; callers must not treat its existence as serving qualification.
2966    pub fn bf16_column_parallel_resident_device_shards(
2967        &self,
2968        matrix: &ResidentBf16ColumnParallel,
2969        activations: &[f32],
2970        tokens: usize,
2971    ) -> Result<Vec<CudaSlice<f32>>, Box<dyn std::error::Error>> {
2972        if self.ranks.len() > 1 && !self.native_p2p {
2973            return Err("device-resident BF16 column parallelism requires native P2P ranks".into());
2974        }
2975        validate_resident_bf16_ranks(&self.ranks, &matrix.ranks)?;
2976        validate_activations(activations, tokens, matrix.in_features)?;
2977
2978        let mut rank_inputs = Vec::with_capacity(self.ranks.len());
2979        let root_input = {
2980            let root = &self.ranks[0];
2981            let _main = root.gpu.enter_main()?;
2982            root.htod(activations)?
2983        };
2984        // PRODUCER FENCE (2026-08-20 flake fix): the peer broadcast below reads this buffer from
2985        // the OTHER ranks' streams, and clone_htod is asynchronous on the root stream. Without
2986        // this fence a peer copy can overtake the in-flight H2D and replicate stale bytes — the
2987        // measured ~30%-of-boots prefill/decode argmax flake. Same discipline as
2988        // `upload_replicated_device_rows`.
2989        {
2990            let root = &self.ranks[0];
2991            let _main = root.gpu.enter_main()?;
2992            root.stream().synchronize()?;
2993        }
2994        rank_inputs.push(root_input);
2995        for engine in &self.ranks[1..] {
2996            let peer_input = {
2997                let _main = engine.gpu.enter_main()?;
2998                let mut peer_input = engine.uninit(activations.len())?;
2999                engine
3000                    .stream()
3001                    .memcpy_dtod(&rank_inputs[0], &mut peer_input)?;
3002                peer_input
3003            };
3004            rank_inputs.push(peer_input);
3005        }
3006
3007        let mut rank_outputs = Vec::with_capacity(self.ranks.len());
3008        #[allow(clippy::needless_range_loop)]
3009        // allow: the explicit index loop keeps the offset arithmetic visible and aligned with the device-side indexing
3010        for rank in 0..self.ranks.len() {
3011            rank_outputs.push(run_resident_bf16_rank_device(
3012                &self.ranks[rank],
3013                &matrix.ranks[rank],
3014                &rank_inputs[rank],
3015                tokens,
3016                matrix.canonical_chunk_rows,
3017                self.bulk_p2p,
3018            )?);
3019        }
3020        Ok(rank_outputs)
3021    }
3022
3023    /// Allocate one fixed-shape replicated batch without initializing its contents.
3024    ///
3025    /// Callers must refresh every rank before passing the batch to an operator.
3026    pub fn allocate_replicated_device_rows(
3027        &self,
3028        tokens: usize,
3029        width: usize,
3030    ) -> Result<ResidentReplicatedDeviceRows, Box<dyn std::error::Error>> {
3031        if self.ranks.len() > 1 && !self.native_p2p {
3032            return Err("replicated device rows require native P2P ranks".into());
3033        }
3034        let values = tokens
3035            .checked_mul(width)
3036            .ok_or("replicated device row size overflow")?;
3037        let rank_lengths = vec![values; self.ranks.len()];
3038        replicated_device_row_values(tokens, width, self.ranks.len(), &rank_lengths)?;
3039        let mut ranks = Vec::with_capacity(self.ranks.len());
3040        for engine in &self.ranks {
3041            let _main = engine.gpu.enter_main()?;
3042            ranks.push(engine.uninit(values)?);
3043        }
3044        Ok(ResidentReplicatedDeviceRows {
3045            ranks,
3046            tokens,
3047            width,
3048        })
3049    }
3050
3051    /// Replace a fixed-shape replicated batch from a root-device source.
3052    pub fn refresh_replicated_device_rows_from_root(
3053        &self,
3054        rows: &mut ResidentReplicatedDeviceRows,
3055        source: &CudaSlice<f32>,
3056    ) -> Result<(), Box<dyn std::error::Error>> {
3057        if self.ranks.len() > 1 && !self.native_p2p {
3058            return Err("replicated device rows require native P2P ranks".into());
3059        }
3060        validate_replicated_device_rows(&self.ranks, rows)?;
3061        let root = self
3062            .ranks
3063            .first()
3064            .ok_or("replicated rows have no root rank")?;
3065        let values = replicated_device_row_source_values(
3066            rows.tokens,
3067            rows.width,
3068            source.len(),
3069            source.ordinal(),
3070            root.ctx().ordinal(),
3071        )?;
3072        let (root_rows, peer_rows) = rows
3073            .ranks
3074            .split_first_mut()
3075            .ok_or("replicated rows have no root allocation")?;
3076        {
3077            let _main = root.gpu.enter_main()?;
3078            let mut destination = root_rows.slice_mut(0..values);
3079            root.stream()
3080                .memcpy_dtod(&source.slice(0..values), &mut destination)?;
3081            root.stream().synchronize()?;
3082        }
3083        for (engine, peer_rows) in self.ranks.iter().skip(1).zip(peer_rows) {
3084            let _main = engine.gpu.enter_main()?;
3085            let mut destination = peer_rows.slice_mut(0..values);
3086            engine
3087                .stream()
3088                .memcpy_dtod(&root_rows.slice(0..values), &mut destination)?;
3089        }
3090        Ok(())
3091    }
3092
3093    /// Upload one canonical batch on rank zero and replicate it over native P2P.
3094    pub fn upload_replicated_device_rows(
3095        &self,
3096        rows: &[f32],
3097        tokens: usize,
3098        width: usize,
3099    ) -> Result<ResidentReplicatedDeviceRows, 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_activations(rows, tokens, width)?;
3104        let root = self
3105            .ranks
3106            .first()
3107            .ok_or("replicated rows have no root rank")?;
3108        let root_rows = {
3109            let _main = root.gpu.enter_main()?;
3110            root.htod(rows)?
3111        };
3112        {
3113            let _main = root.gpu.enter_main()?;
3114            root.stream().synchronize()?;
3115        }
3116        let mut ranks = Vec::with_capacity(self.ranks.len());
3117        ranks.push(root_rows);
3118        for engine in self.ranks.iter().skip(1) {
3119            let _main = engine.gpu.enter_main()?;
3120            let mut peer_rows = engine.uninit(rows.len())?;
3121            engine.stream().memcpy_dtod(&ranks[0], &mut peer_rows)?;
3122            ranks.push(peer_rows);
3123        }
3124        Ok(ResidentReplicatedDeviceRows {
3125            ranks,
3126            tokens,
3127            width,
3128        })
3129    }
3130
3131    /// Execute a column-parallel BF16 matrix directly from rank-local replicated inputs.
3132    pub fn bf16_column_parallel_resident_replicated_device_shards(
3133        &self,
3134        matrix: &ResidentBf16ColumnParallel,
3135        activations: &ResidentReplicatedDeviceRows,
3136    ) -> Result<Vec<CudaSlice<f32>>, Box<dyn std::error::Error>> {
3137        validate_resident_bf16_ranks(&self.ranks, &matrix.ranks)?;
3138        validate_replicated_device_rows(&self.ranks, activations)?;
3139        if activations.width != matrix.in_features {
3140            return Err(format!(
3141                "replicated BF16 column input width {} != matrix width {}",
3142                activations.width, matrix.in_features
3143            )
3144            .into());
3145        }
3146        let mut outputs = Vec::with_capacity(self.ranks.len());
3147        for rank in 0..self.ranks.len() {
3148            outputs.push(run_resident_bf16_rank_device(
3149                &self.ranks[rank],
3150                &matrix.ranks[rank],
3151                &activations.ranks[rank],
3152                activations.tokens,
3153                matrix.canonical_chunk_rows,
3154                self.bulk_p2p,
3155            )?);
3156        }
3157        Ok(outputs)
3158    }
3159
3160    /// Upload a BF16 router once on rank zero and retain its exact F32 expansion.
3161    #[allow(clippy::too_many_arguments)]
3162    pub fn upload_sigmoid_topk_router(
3163        &self,
3164        weight: Bf16Matrix<'_>,
3165        correction_bias: &[f32],
3166        active: Option<&[bool]>,
3167        experts_per_token: usize,
3168        scaling_factor: f32,
3169        route_norm: bool,
3170    ) -> Result<ResidentSigmoidTopKRouter, Box<dyn std::error::Error>> {
3171        weight.validate()?;
3172        if correction_bias.len() != weight.out_features
3173            || experts_per_token == 0
3174            || experts_per_token > weight.out_features
3175            || !correction_bias.iter().all(|value| value.is_finite())
3176            || !scaling_factor.is_finite()
3177            || scaling_factor <= 0.0
3178        {
3179            return Err(format!(
3180                "sigmoid router geometry weight={}x{} bias={} top_k={} scale={scaling_factor}",
3181                weight.out_features,
3182                weight.in_features,
3183                correction_bias.len(),
3184                experts_per_token,
3185            )
3186            .into());
3187        }
3188        let active_row = active
3189            .map(|mask| {
3190                if mask.len() != weight.out_features {
3191                    return Err(format!(
3192                        "sigmoid router active mask {} != experts {}",
3193                        mask.len(),
3194                        weight.out_features
3195                    ));
3196                }
3197                Ok(mask
3198                    .iter()
3199                    .map(|&enabled| u8::from(enabled))
3200                    .collect::<Vec<_>>())
3201            })
3202            .transpose()?
3203            .unwrap_or_else(|| vec![1; weight.out_features]);
3204        let active_count = active_row.iter().filter(|&&enabled| enabled != 0).count();
3205        crate::sigrouter_contract::validate_active_count(experts_per_token, active_count)?;
3206
3207        let root = self
3208            .ranks
3209            .first()
3210            .ok_or("sigmoid router runtime has no root rank")?;
3211        let _main = root.gpu.enter_main()?;
3212        let bf16 = root.htod_bytes(weight.bytes)?;
3213        let weight_f32 = root.bf16_to_f32(
3214            &bf16.slice(0..bf16.len()),
3215            weight.out_features * weight.in_features,
3216        )?;
3217        Ok(ResidentSigmoidTopKRouter {
3218            weight: weight_f32,
3219            correction_bias: root.htod(correction_bias)?,
3220            active: root.htod_bytes(&active_row)?,
3221            root_device: root.ctx().ordinal(),
3222            input_width: weight.in_features,
3223            expert_count: weight.out_features,
3224            experts_per_token,
3225            active_count,
3226            scaling_factor,
3227            route_norm,
3228        })
3229    }
3230
3231    /// Route rank-zero replicated rows and return the narrow host control result plus logits.
3232    ///
3233    /// The logits readback exists for independent oracle comparison. This method is a correctness
3234    /// surface; a serving scheduler may retain logits and selected routes on device.
3235    pub fn sigmoid_topk_replicated_device_rows_host(
3236        &self,
3237        router: &ResidentSigmoidTopKRouter,
3238        input: &ResidentReplicatedDeviceRows,
3239    ) -> Result<SigmoidTopKHostOutput, Box<dyn std::error::Error>> {
3240        validate_replicated_device_rows(&self.ranks, input)?;
3241        if input.width != router.input_width {
3242            return Err(format!(
3243                "sigmoid router input width {} != resident width {}",
3244                input.width, router.input_width
3245            )
3246            .into());
3247        }
3248        let root = self
3249            .ranks
3250            .first()
3251            .ok_or("sigmoid router runtime has no root rank")?;
3252        let _main = root.gpu.enter_main()?;
3253        if root.ctx().ordinal() != router.root_device
3254            || router.weight.ordinal() != router.root_device
3255            || router.correction_bias.ordinal() != router.root_device
3256            || router.active.ordinal() != router.root_device
3257        {
3258            return Err("sigmoid router root residency changed".into());
3259        }
3260        let logits = root.router_gemv(
3261            &router.weight,
3262            &input.ranks[0],
3263            router.input_width,
3264            router.expert_count,
3265            input.tokens,
3266        )?;
3267        let (selected, weights) = root.moe_router_sigmoid_topk_host(
3268            &logits,
3269            input.tokens,
3270            router.expert_count,
3271            router.experts_per_token,
3272            router.active_count,
3273            &router.correction_bias,
3274            &router.active,
3275            router.scaling_factor,
3276            router.route_norm,
3277        )?;
3278        Ok(SigmoidTopKHostOutput {
3279            logits: root.dtoh(&logits)?,
3280            selected,
3281            weights,
3282        })
3283    }
3284
3285    /// Replicate a full BF16 SwiGLU bank on every rank.
3286    pub fn upload_replicated_bf16_swiglu(
3287        &self,
3288        gate: Bf16Matrix<'_>,
3289        up: Bf16Matrix<'_>,
3290        down: Bf16Matrix<'_>,
3291    ) -> Result<ResidentReplicatedBf16SwiGlu, Box<dyn std::error::Error>> {
3292        gate.validate()?;
3293        up.validate()?;
3294        down.validate()?;
3295        if gate.in_features != up.in_features
3296            || gate.out_features != up.out_features
3297            || down.in_features != gate.out_features
3298            || down.out_features != gate.in_features
3299        {
3300            return Err(format!(
3301                "replicated BF16 SwiGLU geometry gate={}x{} up={}x{} down={}x{}",
3302                gate.out_features,
3303                gate.in_features,
3304                up.out_features,
3305                up.in_features,
3306                down.out_features,
3307                down.in_features,
3308            )
3309            .into());
3310        }
3311        let mut gate_ranks = Vec::with_capacity(self.ranks.len());
3312        let mut up_ranks = Vec::with_capacity(self.ranks.len());
3313        let mut down_ranks = Vec::with_capacity(self.ranks.len());
3314        for engine in &self.ranks {
3315            gate_ranks.push(upload_bf16_rank(engine, gate, false)?);
3316            up_ranks.push(upload_bf16_rank(engine, up, false)?);
3317            down_ranks.push(upload_bf16_rank(engine, down, false)?);
3318        }
3319        Ok(ResidentReplicatedBf16SwiGlu {
3320            gate: gate_ranks,
3321            up: up_ranks,
3322            down: down_ranks,
3323            input_width: gate.in_features,
3324            intermediate_width: gate.out_features,
3325        })
3326    }
3327
3328    /// Execute a fully replicated BF16 SwiGLU directly from replicated device rows.
3329    pub fn replicated_bf16_swiglu_resident_device(
3330        &self,
3331        mlp: &ResidentReplicatedBf16SwiGlu,
3332        input: &ResidentReplicatedDeviceRows,
3333        activation_limit: Option<f32>,
3334    ) -> Result<ResidentReplicatedDeviceRows, Box<dyn std::error::Error>> {
3335        validate_step_expert_activation_limit(activation_limit)?;
3336        validate_replicated_device_rows(&self.ranks, input)?;
3337        validate_resident_bf16_ranks(&self.ranks, &mlp.gate)?;
3338        validate_resident_bf16_ranks(&self.ranks, &mlp.up)?;
3339        validate_resident_bf16_ranks(&self.ranks, &mlp.down)?;
3340        if input.width != mlp.input_width
3341            || mlp.gate.len() != self.ranks.len()
3342            || mlp.up.len() != self.ranks.len()
3343            || mlp.down.len() != self.ranks.len()
3344        {
3345            return Err("replicated BF16 SwiGLU residency or input width changed".into());
3346        }
3347
3348        let mut outputs = Vec::with_capacity(self.ranks.len());
3349        for rank in 0..self.ranks.len() {
3350            let engine = &self.ranks[rank];
3351            let gate = run_resident_bf16_rank_device(
3352                engine,
3353                &mlp.gate[rank],
3354                &input.ranks[rank],
3355                input.tokens,
3356                None,
3357                self.bulk_p2p,
3358            )?;
3359            let up = run_resident_bf16_rank_device(
3360                engine,
3361                &mlp.up[rank],
3362                &input.ranks[rank],
3363                input.tokens,
3364                None,
3365                self.bulk_p2p,
3366            )?;
3367            let _main = engine.gpu.enter_main()?;
3368            let values = input
3369                .tokens
3370                .checked_mul(mlp.intermediate_width)
3371                .ok_or("replicated BF16 SwiGLU activation size overflow")?;
3372            let mut activation = engine.uninit(values)?;
3373            if let Some(limit) = activation_limit {
3374                engine.silu_clamped_mul_host_expf(&gate, &up, limit, &mut activation, values)?;
3375            } else {
3376                engine.silu_mul_host_expf(&gate, &up, &mut activation, values)?;
3377            }
3378            outputs.push(run_resident_bf16_rank_device(
3379                engine,
3380                &mlp.down[rank],
3381                &activation,
3382                input.tokens,
3383                None,
3384                self.bulk_p2p,
3385            )?);
3386        }
3387        Ok(ResidentReplicatedDeviceRows {
3388            ranks: outputs,
3389            tokens: input.tokens,
3390            width: mlp.input_width,
3391        })
3392    }
3393
3394    /// Apply the same RMS-norm row program independently on every replicated rank.
3395    pub fn rms_norm_replicated_device_rows(
3396        &self,
3397        input: &ResidentReplicatedDeviceRows,
3398        weight: &[f32],
3399        eps: f32,
3400    ) -> Result<ResidentReplicatedDeviceRows, Box<dyn std::error::Error>> {
3401        validate_replicated_device_rows(&self.ranks, input)?;
3402        if weight.len() != input.width || !eps.is_finite() || eps <= 0.0 {
3403            return Err(format!(
3404                "replicated RMS norm weight/eps {}/{} != width {}",
3405                weight.len(),
3406                eps,
3407                input.width
3408            )
3409            .into());
3410        }
3411        let mut ranks = Vec::with_capacity(self.ranks.len());
3412        for (rank, engine) in self.ranks.iter().enumerate() {
3413            let _main = engine.gpu.enter_main()?;
3414            let weight = engine.htod(weight)?;
3415            let mut output = engine.uninit(input.tokens * input.width)?;
3416            engine.rms_norm(
3417                &input.ranks[rank],
3418                &weight,
3419                &mut output,
3420                input.width,
3421                input.tokens,
3422                eps,
3423            )?;
3424            ranks.push(output);
3425        }
3426        Ok(ResidentReplicatedDeviceRows {
3427            ranks,
3428            tokens: input.tokens,
3429            width: input.width,
3430        })
3431    }
3432
3433    /// Add two replicated batches and RMS-normalize the exact residual on every rank.
3434    pub fn add_rms_norm_replicated_device_rows(
3435        &self,
3436        input: &ResidentReplicatedDeviceRows,
3437        update: &ResidentReplicatedDeviceRows,
3438        weight: &[f32],
3439        eps: f32,
3440    ) -> Result<
3441        (ResidentReplicatedDeviceRows, ResidentReplicatedDeviceRows),
3442        Box<dyn std::error::Error>,
3443    > {
3444        validate_replicated_device_rows(&self.ranks, input)?;
3445        validate_replicated_device_rows(&self.ranks, update)?;
3446        if input.tokens != update.tokens
3447            || input.width != update.width
3448            || weight.len() != input.width
3449            || !eps.is_finite()
3450            || eps <= 0.0
3451        {
3452            return Err(format!(
3453                "replicated add/RMS geometry input={}x{} update={}x{} weight={} eps={eps}",
3454                input.tokens,
3455                input.width,
3456                update.tokens,
3457                update.width,
3458                weight.len(),
3459            )
3460            .into());
3461        }
3462        let values = input.tokens * input.width;
3463        let mut residual_ranks = Vec::with_capacity(self.ranks.len());
3464        let mut normalized_ranks = Vec::with_capacity(self.ranks.len());
3465        for (rank, engine) in self.ranks.iter().enumerate() {
3466            let _main = engine.gpu.enter_main()?;
3467            let weight = engine.htod(weight)?;
3468            let mut residual = engine.uninit(values)?;
3469            let mut normalized = engine.uninit(values)?;
3470            engine.add_rms_norm(
3471                &input.ranks[rank],
3472                &update.ranks[rank],
3473                &weight,
3474                &mut residual,
3475                &mut normalized,
3476                input.width,
3477                input.tokens,
3478                eps,
3479            )?;
3480            residual_ranks.push(residual);
3481            normalized_ranks.push(normalized);
3482        }
3483        Ok((
3484            ResidentReplicatedDeviceRows {
3485                ranks: residual_ranks,
3486                tokens: input.tokens,
3487                width: input.width,
3488            },
3489            ResidentReplicatedDeviceRows {
3490                ranks: normalized_ranks,
3491                tokens: input.tokens,
3492                width: input.width,
3493            },
3494        ))
3495    }
3496
3497    pub fn collect_replicated_device_rows(
3498        &self,
3499        rows: &ResidentReplicatedDeviceRows,
3500    ) -> Result<Vec<Vec<f32>>, Box<dyn std::error::Error>> {
3501        validate_replicated_device_rows(&self.ranks, rows)?;
3502        let mut outputs = Vec::with_capacity(self.ranks.len());
3503        for (rank, engine) in self.ranks.iter().enumerate() {
3504            let _main = engine.gpu.enter_main()?;
3505            outputs.push(engine.dtoh(&rows.ranks[rank])?);
3506        }
3507        Ok(outputs)
3508    }
3509
3510    #[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
3511    pub fn upload_bf16_row_parallel(
3512        &self,
3513        matrix: Bf16Matrix<'_>,
3514    ) -> Result<ResidentBf16RowParallel, Box<dyn std::error::Error>> {
3515        matrix.validate()?;
3516        let tp = self.ranks.len();
3517        if matrix.in_features % tp != 0 {
3518            return Err(format!(
3519                "BF16 row-parallel in_features {} is not divisible by TP={tp}",
3520                matrix.in_features
3521            )
3522            .into());
3523        }
3524        let mut ranks = Vec::with_capacity(tp);
3525        for (rank, engine) in self.ranks.iter().enumerate() {
3526            let shard = bf16_row_shard(matrix, tp, rank)?;
3527            ranks.push(upload_bf16_rank(
3528                engine,
3529                Bf16Matrix {
3530                    bytes: &shard,
3531                    out_features: matrix.out_features,
3532                    in_features: matrix.in_features / tp,
3533                },
3534                false,
3535            )?);
3536        }
3537        Ok(ResidentBf16RowParallel {
3538            ranks,
3539            out_features: matrix.out_features,
3540            in_features: matrix.in_features,
3541        })
3542    }
3543
3544    pub fn bf16_row_parallel_resident(
3545        &self,
3546        matrix: &ResidentBf16RowParallel,
3547        activations: &[f32],
3548        tokens: usize,
3549    ) -> Result<RowParallelResult, Box<dyn std::error::Error>> {
3550        validate_resident_bf16_ranks(&self.ranks, &matrix.ranks)?;
3551        validate_activations(activations, tokens, matrix.in_features)?;
3552        let tp = self.ranks.len();
3553        let mut reduced = vec![0.0f32; tokens * matrix.out_features];
3554        let mut rank_partials = Vec::with_capacity(tp);
3555        for (rank, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
3556            let local_activations =
3557                activation_shard(activations, tokens, matrix.in_features, tp, rank);
3558            let partial = run_resident_bf16_rank(engine, shard, &local_activations, tokens, None)?;
3559            for (sum, value) in reduced.iter_mut().zip(&partial) {
3560                *sum += value;
3561            }
3562            rank_partials.push(partial);
3563        }
3564        Ok(RowParallelResult {
3565            reduced,
3566            rank_partials,
3567        })
3568    }
3569
3570    /// Step-3.7 row projection split into the same eight global K blocks for TP1/TP2/TP4/TP8.
3571    pub fn upload_step_bf16_row_parallel(
3572        &self,
3573        matrix: Bf16Matrix<'_>,
3574    ) -> Result<ResidentStepBf16RowParallel, Box<dyn std::error::Error>> {
3575        self.upload_step_bf16_row_parallel_inner(matrix, false)
3576    }
3577
3578    pub fn upload_step_bf16_row_parallel_f32_mirror(
3579        &self,
3580        matrix: Bf16Matrix<'_>,
3581    ) -> Result<ResidentStepBf16RowParallel, Box<dyn std::error::Error>> {
3582        self.upload_step_bf16_row_parallel_inner(matrix, true)
3583    }
3584
3585    fn upload_step_bf16_row_parallel_inner(
3586        &self,
3587        matrix: Bf16Matrix<'_>,
3588        f32_mirror: bool,
3589    ) -> Result<ResidentStepBf16RowParallel, Box<dyn std::error::Error>> {
3590        matrix.validate()?;
3591        let tp = self.ranks.len();
3592        let canonical_chunk_cols = step_bf16_canonical_chunk_cols(matrix.in_features, tp)?;
3593        let local_in = matrix.in_features / tp;
3594        let blocks_per_rank = local_in / canonical_chunk_cols;
3595        let mut ranks = Vec::with_capacity(tp);
3596        for (rank, engine) in self.ranks.iter().enumerate() {
3597            let mut blocks = Vec::with_capacity(blocks_per_rank);
3598            for block in 0..blocks_per_rank {
3599                let global_block = rank * blocks_per_rank + block;
3600                let col_start = global_block * canonical_chunk_cols;
3601                let bytes = bf16_row_block(matrix, col_start, canonical_chunk_cols)?;
3602                blocks.push(upload_bf16_rank(
3603                    engine,
3604                    Bf16Matrix {
3605                        bytes: &bytes,
3606                        out_features: matrix.out_features,
3607                        in_features: canonical_chunk_cols,
3608                    },
3609                    f32_mirror,
3610                )?);
3611            }
3612            ranks.push(blocks);
3613        }
3614        Ok(ResidentStepBf16RowParallel {
3615            ranks,
3616            out_features: matrix.out_features,
3617            in_features: matrix.in_features,
3618            canonical_chunk_cols,
3619        })
3620    }
3621
3622    /// Host-staged exactness twin of [`Self::step_bf16_row_parallel_resident_native`].
3623    ///
3624    /// Block inputs and partials cross host memory, but every partial is added on the root device
3625    /// in global checkpoint-column order. Native transport must reproduce this result bitwise.
3626    pub fn step_bf16_row_parallel_resident(
3627        &self,
3628        matrix: &ResidentStepBf16RowParallel,
3629        activations: &[f32],
3630        tokens: usize,
3631    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
3632        validate_step_bf16_row_residency(&self.ranks, matrix)?;
3633        validate_activations(activations, tokens, matrix.in_features)?;
3634        let root = &self.ranks[0];
3635        let output_len = tokens
3636            .checked_mul(matrix.out_features)
3637            .ok_or("Step BF16 row output size overflow")?;
3638        let mut reduced = {
3639            let _main = root.gpu.enter_main()?;
3640            root.htod(&vec![0.0f32; output_len])?
3641        };
3642        let blocks_per_rank = PRODUCT_MAX_CARDS / self.ranks.len();
3643        for (rank, blocks) in matrix.ranks.iter().enumerate() {
3644            for (block, resident) in blocks.iter().enumerate() {
3645                let global_block = rank * blocks_per_rank + block;
3646                let input = activation_shard(
3647                    activations,
3648                    tokens,
3649                    matrix.in_features,
3650                    PRODUCT_MAX_CARDS,
3651                    global_block,
3652                );
3653                let partial =
3654                    run_resident_bf16_rank(&self.ranks[rank], resident, &input, tokens, None)?;
3655                let next = {
3656                    let _main = root.gpu.enter_main()?;
3657                    let partial = root.htod(&partial)?;
3658                    let mut next = root.uninit(output_len)?;
3659                    root.add(&reduced, &partial, &mut next, output_len)?;
3660                    next
3661                };
3662                reduced = next;
3663            }
3664        }
3665        let _main = root.gpu.enter_main()?;
3666        root.dtoh(&reduced)
3667    }
3668
3669    /// Native-P2P Step row projection with canonical global K-block reduction.
3670    ///
3671    /// The full activation is uploaded once on the root. Each TP8-sized block is peer-scattered
3672    /// to its owning rank, its BF16 partial is peer-returned to the root, and root-device adds
3673    /// replay the same eight-block order as TP1 and the host-staged oracle.
3674    pub fn step_bf16_row_parallel_resident_native(
3675        &self,
3676        matrix: &ResidentStepBf16RowParallel,
3677        activations: &[f32],
3678        tokens: usize,
3679    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
3680        if self.ranks.len() > 1 && !self.native_p2p {
3681            return Err("native Step BF16 row parallelism requires P2P ranks".into());
3682        }
3683        validate_step_bf16_row_residency(&self.ranks, matrix)?;
3684        validate_activations(activations, tokens, matrix.in_features)?;
3685        let root = &self.ranks[0];
3686        let root_input = {
3687            let _main = root.gpu.enter_main()?;
3688            root.htod(activations)?
3689        };
3690        // PRODUCER FENCE (2026-08-20 flake fix): the non-bulk arm below peer-reads root_input
3691        // from the other ranks' streams while root's clone_htod may still be in flight.
3692        {
3693            let _main = root.gpu.enter_main()?;
3694            root.stream().synchronize()?;
3695        }
3696        let reduced = self.step_bf16_row_native_reduce_from_root(matrix, &root_input, tokens)?;
3697        let _main = root.gpu.enter_main()?;
3698        root.dtoh(&reduced)
3699    }
3700
3701    /// Device-input twin of [`Self::step_bf16_row_parallel_resident_native`] (lane/
3702    /// hermes-perf-fixes, 2026-08-23): the full activation arrives as a ROOT-DEVICE buffer
3703    /// and the reduced output stays root-resident — no DtoH of the attention output, no
3704    /// host O staging, no re-upload. Byte-identical to the host-canonical arm by
3705    /// construction (same block scatter, kernels, and global TP8 reduction order; the root
3706    /// bytes are dtod-copied where the host arm htod'd the same bytes). Caller must have
3707    /// synchronized the producer stream; the root stream is synchronized before returning.
3708    pub fn step_bf16_row_parallel_resident_native_device(
3709        &self,
3710        matrix: &ResidentStepBf16RowParallel,
3711        root_activation: &CudaSlice<f32>,
3712        tokens: usize,
3713    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
3714        if self.ranks.len() > 1 && !self.native_p2p {
3715            return Err("native Step BF16 row parallelism requires P2P ranks".into());
3716        }
3717        validate_step_bf16_row_residency(&self.ranks, matrix)?;
3718        let values = tokens
3719            .checked_mul(matrix.in_features)
3720            .ok_or("device Step BF16 row activation size overflow")?;
3721        let root = &self.ranks[0];
3722        if tokens == 0
3723            || root_activation.len() < values
3724            || root_activation.ordinal() != root.ctx().ordinal()
3725        {
3726            return Err("device Step BF16 row root activation geometry mismatch".into());
3727        }
3728        let root_input = {
3729            let _main = root.gpu.enter_main()?;
3730            let mut root_input = root.uninit(values)?;
3731            root.stream()
3732                .memcpy_dtod(&root_activation.slice(0..values), &mut root_input)?;
3733            root.stream().synchronize()?; // producer fence, as the host-input twin
3734            root_input
3735        };
3736        let reduced = self.step_bf16_row_native_reduce_from_root(matrix, &root_input, tokens)?;
3737        let _main = root.gpu.enter_main()?;
3738        root.stream().synchronize()?;
3739        Ok(reduced)
3740    }
3741
3742    /// Shared core of the two native Step row arms above: block scatter + rank GEMMs +
3743    /// canonical global TP8-order root reduction, from a root-resident input, returning the
3744    /// root-resident reduced output. Extracted verbatim so the host and device twins cannot
3745    /// drift numerically.
3746    fn step_bf16_row_native_reduce_from_root(
3747        &self,
3748        matrix: &ResidentStepBf16RowParallel,
3749        root_input: &CudaSlice<f32>,
3750        tokens: usize,
3751    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
3752        let root = &self.ranks[0];
3753        let output_len = tokens
3754            .checked_mul(matrix.out_features)
3755            .ok_or("native Step BF16 row output size overflow")?;
3756        let mut reduced = {
3757            let _main = root.gpu.enter_main()?;
3758            root.htod(&vec![0.0f32; output_len])?
3759        };
3760        let blocks_per_rank = PRODUCT_MAX_CARDS / self.ranks.len();
3761        let mut block_input_keepalive = Vec::with_capacity(PRODUCT_MAX_CARDS);
3762        let mut root_packed_keepalive = Vec::with_capacity(PRODUCT_MAX_CARDS);
3763        let mut remote_partial_keepalive = Vec::new();
3764        for (rank, blocks) in matrix.ranks.iter().enumerate() {
3765            for (block, resident) in blocks.iter().enumerate() {
3766                let global_block = rank * blocks_per_rank + block;
3767                let col_start = global_block * matrix.canonical_chunk_cols;
3768                let block_len = tokens
3769                    .checked_mul(matrix.canonical_chunk_cols)
3770                    .ok_or("native Step BF16 row block size overflow")?;
3771                let block_input = if self.bulk_p2p {
3772                    let root_packed = {
3773                        let _main = root.gpu.enter_main()?;
3774                        let mut root_packed = root.uninit(block_len)?;
3775                        root.copy_rows_strided(
3776                            root_input,
3777                            &mut root_packed,
3778                            matrix.canonical_chunk_cols,
3779                            tokens,
3780                            matrix.in_features,
3781                            col_start,
3782                        )?;
3783                        root_packed
3784                    };
3785                    if rank == 0 {
3786                        root_packed
3787                    } else {
3788                        // PRODUCER FENCE (2026-08-20 flake fix): the pack kernel runs on the
3789                        // root stream; this rank's peer read must not overtake it.
3790                        {
3791                            let _main = root.gpu.enter_main()?;
3792                            root.stream().synchronize()?;
3793                        }
3794                        let engine = &self.ranks[rank];
3795                        let _main = engine.gpu.enter_main()?;
3796                        let mut block_input = engine.uninit(block_len)?;
3797                        engine
3798                            .stream()
3799                            .memcpy_dtod(&root_packed, &mut block_input)?;
3800                        root_packed_keepalive.push(root_packed);
3801                        block_input
3802                    }
3803                } else {
3804                    let engine = &self.ranks[rank];
3805                    let _main = engine.gpu.enter_main()?;
3806                    let mut block_input = engine.uninit(block_len)?;
3807                    for token in 0..tokens {
3808                        let source_start = token * matrix.in_features + col_start;
3809                        let source = root_input
3810                            .slice(source_start..source_start + matrix.canonical_chunk_cols);
3811                        let destination_start = token * matrix.canonical_chunk_cols;
3812                        let mut destination = block_input.slice_mut(
3813                            destination_start..destination_start + matrix.canonical_chunk_cols,
3814                        );
3815                        engine.stream().memcpy_dtod(&source, &mut destination)?;
3816                    }
3817                    block_input
3818                };
3819                let partial = run_resident_bf16_rank_device(
3820                    &self.ranks[rank],
3821                    resident,
3822                    &block_input,
3823                    tokens,
3824                    None,
3825                    self.bulk_p2p,
3826                )?;
3827                block_input_keepalive.push(block_input);
3828                let root_partial = if rank == 0 {
3829                    partial
3830                } else {
3831                    // PRODUCER FENCE (2026-08-20 flake fix): the partial was produced by this
3832                    // rank's kernel on its own stream; root's peer read must not overtake it.
3833                    {
3834                        let engine = &self.ranks[rank];
3835                        let _main = engine.gpu.enter_main()?;
3836                        engine.stream().synchronize()?;
3837                    }
3838                    let _main = root.gpu.enter_main()?;
3839                    let mut peer_partial = root.uninit(output_len)?;
3840                    root.stream().memcpy_dtod(&partial, &mut peer_partial)?;
3841                    remote_partial_keepalive.push(partial);
3842                    peer_partial
3843                };
3844                let next = {
3845                    let _main = root.gpu.enter_main()?;
3846                    let mut next = root.uninit(output_len)?;
3847                    root.add(&reduced, &root_partial, &mut next, output_len)?;
3848                    next
3849                };
3850                reduced = next;
3851            }
3852        }
3853        {
3854            let _main = root.gpu.enter_main()?;
3855            root.stream().synchronize()?;
3856        }
3857        drop(remote_partial_keepalive);
3858        drop(root_packed_keepalive);
3859        drop(block_input_keepalive);
3860        Ok(reduced)
3861    }
3862
3863    /// Reduce rank-local Step attention shards in canonical TP8 K-block order and keep the result
3864    /// on the root device.
3865    pub fn step_bf16_row_parallel_resident_root_device(
3866        &self,
3867        matrix: &ResidentStepBf16RowParallel,
3868        rank_activations: &[CudaSlice<f32>],
3869        tokens: usize,
3870    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
3871        if self.ranks.len() > 1 && !self.native_p2p {
3872            return Err(
3873                "device-resident Step BF16 row parallelism requires native P2P ranks".into(),
3874            );
3875        }
3876        validate_step_bf16_row_residency(&self.ranks, matrix)?;
3877        let local_width = matrix.in_features / self.ranks.len();
3878        let shard_len = tokens
3879            .checked_mul(local_width)
3880            .ok_or("device Step BF16 row shard size overflow")?;
3881        if tokens == 0
3882            || rank_activations.len() != self.ranks.len()
3883            || rank_activations
3884                .iter()
3885                .zip(&self.ranks)
3886                .any(|(rows, engine)| {
3887                    rows.len() != shard_len || rows.ordinal() != engine.ctx().ordinal()
3888                })
3889        {
3890            return Err("device Step BF16 row activation shard geometry changed".into());
3891        }
3892
3893        let blocks_per_rank = PRODUCT_MAX_CARDS / self.ranks.len();
3894        let mut block_inputs = Vec::with_capacity(self.ranks.len());
3895        let mut partials = Vec::with_capacity(self.ranks.len());
3896        for (rank, blocks) in matrix.ranks.iter().enumerate() {
3897            if blocks.len() != blocks_per_rank {
3898                return Err(format!(
3899                    "device Step BF16 row rank {rank} blocks {} != {blocks_per_rank}",
3900                    blocks.len()
3901                )
3902                .into());
3903            }
3904            let engine = &self.ranks[rank];
3905            let _main = engine.gpu.enter_main()?;
3906            let mut rank_inputs = Vec::with_capacity(blocks_per_rank);
3907            let mut rank_partials = Vec::with_capacity(blocks_per_rank);
3908            for (block, resident) in blocks.iter().enumerate() {
3909                let block_len = tokens
3910                    .checked_mul(matrix.canonical_chunk_cols)
3911                    .ok_or("device Step BF16 row block size overflow")?;
3912                let mut block_input = engine.uninit(block_len)?;
3913                let local_col_start = block * matrix.canonical_chunk_cols;
3914                if self.bulk_p2p {
3915                    engine.copy_rows_strided(
3916                        &rank_activations[rank],
3917                        &mut block_input,
3918                        matrix.canonical_chunk_cols,
3919                        tokens,
3920                        local_width,
3921                        local_col_start,
3922                    )?;
3923                } else {
3924                    for token in 0..tokens {
3925                        let source_start = token * local_width + local_col_start;
3926                        let source = rank_activations[rank]
3927                            .slice(source_start..source_start + matrix.canonical_chunk_cols);
3928                        let destination_start = token * matrix.canonical_chunk_cols;
3929                        let mut destination = block_input.slice_mut(
3930                            destination_start..destination_start + matrix.canonical_chunk_cols,
3931                        );
3932                        engine.stream().memcpy_dtod(&source, &mut destination)?;
3933                    }
3934                }
3935                let partial = run_resident_bf16_rank_device(
3936                    engine,
3937                    resident,
3938                    &block_input,
3939                    tokens,
3940                    None,
3941                    self.bulk_p2p,
3942                )?;
3943                rank_inputs.push(block_input);
3944                rank_partials.push(partial);
3945            }
3946            block_inputs.push(rank_inputs);
3947            partials.push(rank_partials);
3948        }
3949        for engine in self.ranks.iter().skip(1) {
3950            let _main = engine.gpu.enter_main()?;
3951            engine.stream().synchronize()?;
3952        }
3953
3954        let output_len = tokens
3955            .checked_mul(matrix.out_features)
3956            .ok_or("device Step BF16 row output size overflow")?;
3957        let root = &self.ranks[0];
3958        let _main = root.gpu.enter_main()?;
3959        let mut reduced = root.htod(&vec![0.0f32; output_len])?;
3960        let mut remote_partials = Vec::new();
3961        for (rank, rank_partials) in partials.into_iter().enumerate() {
3962            for partial in rank_partials {
3963                let root_partial = if rank == 0 {
3964                    partial
3965                } else {
3966                    let mut peer_partial = root.uninit(output_len)?;
3967                    root.stream().memcpy_dtod(&partial, &mut peer_partial)?;
3968                    remote_partials.push(partial);
3969                    peer_partial
3970                };
3971                let mut next = root.uninit(output_len)?;
3972                root.add(&reduced, &root_partial, &mut next, output_len)?;
3973                reduced = next;
3974            }
3975        }
3976        root.stream().synchronize()?;
3977        drop(remote_partials);
3978        drop(block_inputs);
3979        Ok(reduced)
3980    }
3981
3982    /// Reduce rank-local Step attention shards, then replicate the canonical root result.
3983    pub fn step_bf16_row_parallel_resident_replicated_device(
3984        &self,
3985        matrix: &ResidentStepBf16RowParallel,
3986        rank_activations: &[CudaSlice<f32>],
3987        tokens: usize,
3988    ) -> Result<ResidentReplicatedDeviceRows, Box<dyn std::error::Error>> {
3989        let reduced =
3990            self.step_bf16_row_parallel_resident_root_device(matrix, rank_activations, tokens)?;
3991        let output_len = tokens
3992            .checked_mul(matrix.out_features)
3993            .ok_or("device Step BF16 row output size overflow")?;
3994        let mut ranks = Vec::with_capacity(self.ranks.len());
3995        ranks.push(reduced);
3996        for engine in self.ranks.iter().skip(1) {
3997            let _main = engine.gpu.enter_main()?;
3998            let mut peer_output = engine.uninit(output_len)?;
3999            engine.stream().memcpy_dtod(&ranks[0], &mut peer_output)?;
4000            ranks.push(peer_output);
4001        }
4002        Ok(ResidentReplicatedDeviceRows {
4003            ranks,
4004            tokens,
4005            width: matrix.out_features,
4006        })
4007    }
4008
4009    pub fn upload_expert(
4010        &self,
4011        gate: E4m3BlockMatrix<'_>,
4012        up: E4m3BlockMatrix<'_>,
4013        down: E4m3BlockMatrix<'_>,
4014    ) -> Result<ResidentTpExpert, Box<dyn std::error::Error>> {
4015        if gate.in_features != up.in_features || gate.out_features != up.out_features {
4016            return Err("TP expert gate/up dimensions differ".into());
4017        }
4018        if down.in_features != gate.out_features || down.out_features != gate.in_features {
4019            return Err(format!(
4020                "TP expert down {}x{} does not invert gate/up {}x{}",
4021                down.out_features, down.in_features, gate.out_features, gate.in_features
4022            )
4023            .into());
4024        }
4025        Ok(ResidentTpExpert {
4026            gate: self.upload_column_parallel(gate)?,
4027            up: self.upload_column_parallel(up)?,
4028            down: self.upload_row_parallel(down)?,
4029            input_width: gate.in_features,
4030            expert_width: gate.out_features,
4031        })
4032    }
4033
4034    pub fn run_expert(
4035        &self,
4036        expert: &ResidentTpExpert,
4037        input: &[f32],
4038        tokens: usize,
4039    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
4040        validate_activations(input, tokens, expert.input_width)?;
4041        let gate = self.column_parallel_resident(&expert.gate, input, tokens)?;
4042        let up = self.column_parallel_resident(&expert.up, input, tokens)?;
4043        let activated: Vec<f32> = gate
4044            .gathered
4045            .iter()
4046            .zip(&up.gathered)
4047            .map(|(&gate, &up)| gate / (1.0 + (-gate).exp()) * up)
4048            .collect();
4049        debug_assert_eq!(activated.len(), tokens * expert.expert_width);
4050        Ok(self
4051            .row_parallel_resident(&expert.down, &activated, tokens)?
4052            .reduced)
4053    }
4054
4055    #[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
4056    pub fn upload_expert_parallel(
4057        &self,
4058        gate: E4m3ExpertBank<'_>,
4059        up: E4m3ExpertBank<'_>,
4060        down: E4m3ExpertBank<'_>,
4061    ) -> Result<ResidentExpertParallel, Box<dyn std::error::Error>> {
4062        gate.validate()?;
4063        up.validate()?;
4064        down.validate()?;
4065        if gate.expert_count != up.expert_count || gate.expert_count != down.expert_count {
4066            return Err("EP gate/up/down expert counts differ".into());
4067        }
4068        if gate.in_features != up.in_features || gate.out_features != up.out_features {
4069            return Err("EP gate/up dimensions differ".into());
4070        }
4071        if down.in_features != gate.out_features || down.out_features != gate.in_features {
4072            return Err(format!(
4073                "EP down {}x{} does not invert gate/up {}x{}",
4074                down.out_features, down.in_features, gate.out_features, gate.in_features
4075            )
4076            .into());
4077        }
4078        if gate.expert_count % self.ranks.len() != 0 {
4079            return Err(format!(
4080                "EP expert count {} is not divisible by {} ranks",
4081                gate.expert_count,
4082                self.ranks.len()
4083            )
4084            .into());
4085        }
4086
4087        let per_rank = gate.expert_count / self.ranks.len();
4088        let mut ranks = Vec::with_capacity(self.ranks.len());
4089        for (rank, engine) in self.ranks.iter().enumerate() {
4090            let expert_range = rank * per_rank..(rank + 1) * per_rank;
4091            ranks.push(ResidentEpRank {
4092                gate: upload_expert_bank_rank(engine, gate, expert_range.clone())?,
4093                up: upload_expert_bank_rank(engine, up, expert_range.clone())?,
4094                down: upload_expert_bank_rank(engine, down, expert_range)?,
4095            });
4096        }
4097        Ok(ResidentExpertParallel {
4098            ranks,
4099            expert_count: gate.expert_count,
4100            input_width: gate.in_features,
4101            expert_width: gate.out_features,
4102        })
4103    }
4104
4105    /// Prepare the official Step gate-only grouped-FP8 projection oracle on rank zero.
4106    ///
4107    /// This intentionally does not alter the resident EP path. It owns a full rank-local tensor
4108    /// bank solely so the grouped projection can be compared with the existing per-route oracle
4109    /// without routing, transport, or combine changing underneath it.
4110    #[allow(clippy::too_many_arguments)]
4111    pub fn prepare_step_grouped_fp8_gate(
4112        &self,
4113        gate: E4m3ExpertBank<'_>,
4114        up: E4m3ExpertBank<'_>,
4115        down: E4m3ExpertBank<'_>,
4116        input: &[f32],
4117        tokens: usize,
4118        selected: &[usize],
4119        activation_limit: Option<f32>,
4120    ) -> Result<PreparedStepGroupedFp8Gate, Box<dyn std::error::Error>> {
4121        gate.validate()?;
4122        up.validate()?;
4123        down.validate()?;
4124        validate_step_expert_activation_limit(activation_limit)?;
4125        if gate.expert_count != STEP_GROUPED_FP8_EXPERTS
4126            || up.expert_count != STEP_GROUPED_FP8_EXPERTS
4127            || down.expert_count != STEP_GROUPED_FP8_EXPERTS
4128        {
4129            return Err(format!(
4130                "official Step grouped FP8 gate requires {STEP_GROUPED_FP8_EXPERTS} experts, \
4131                 got gate/up/down={}/{}/{}",
4132                gate.expert_count, up.expert_count, down.expert_count,
4133            )
4134            .into());
4135        }
4136        if gate.in_features != up.in_features
4137            || gate.out_features != STEP_GROUPED_FP8_WIDTH
4138            || up.out_features != STEP_GROUPED_FP8_WIDTH
4139            || down.in_features != STEP_GROUPED_FP8_WIDTH
4140            || down.out_features != gate.in_features
4141        {
4142            return Err(format!(
4143                "official Step grouped FP8 geometry gate={}x{} up={}x{} down={}x{}",
4144                gate.out_features,
4145                gate.in_features,
4146                up.out_features,
4147                up.in_features,
4148                down.out_features,
4149                down.in_features,
4150            )
4151            .into());
4152        }
4153        validate_activations(input, tokens, gate.in_features)?;
4154        let pairs = tokens
4155            .checked_mul(STEP_GROUPED_FP8_TOP_K)
4156            .ok_or("official Step grouped FP8 route count overflow")?;
4157        if selected.len() != pairs {
4158            return Err(format!(
4159                "official Step grouped FP8 routes {} != {tokens}x{STEP_GROUPED_FP8_TOP_K} \
4160                 ({pairs})",
4161                selected.len()
4162            )
4163            .into());
4164        }
4165        for (token, routes) in selected.chunks_exact(STEP_GROUPED_FP8_TOP_K).enumerate() {
4166            let mut unique = routes.to_vec();
4167            unique.sort_unstable();
4168            unique.dedup();
4169            if unique.len() != STEP_GROUPED_FP8_TOP_K {
4170                return Err(format!(
4171                    "official Step grouped FP8 token {token} routes are not top-8 unique: \
4172                     {routes:?}"
4173                )
4174                .into());
4175            }
4176        }
4177
4178        let engine = self
4179            .ranks
4180            .first()
4181            .ok_or("official Step grouped FP8 gate has no rank-zero engine")?;
4182        let _main = engine.gpu.enter_main()?;
4183        let expert_range = 0..STEP_GROUPED_FP8_EXPERTS;
4184        let gate = upload_expert_bank_rank(engine, gate, expert_range.clone())?;
4185        let up = upload_expert_bank_rank(engine, up, expert_range.clone())?;
4186        let down = upload_expert_bank_rank(engine, down, expert_range)?;
4187        let input = engine.htod(input)?;
4188        let route_csr = ExpertCsr::from_token_routes(
4189            STEP_GROUPED_FP8_EXPERTS,
4190            tokens,
4191            STEP_GROUPED_FP8_TOP_K,
4192            selected,
4193        )?
4194        .upload(engine)?;
4195        let pair_rows = (0..pairs).collect::<Vec<_>>();
4196        let down_csr =
4197            ExpertCsr::from_pair_rows(STEP_GROUPED_FP8_EXPERTS, pairs, selected, &pair_rows)?
4198                .upload(engine)?;
4199        let gate_workspace =
4200            Fp8GroupedWorkspace::new(engine, gate.in_features, gate.out_features, tokens, pairs)?;
4201        let up_workspace =
4202            Fp8GroupedWorkspace::new(engine, up.in_features, up.out_features, tokens, pairs)?;
4203        let down_workspace =
4204            Fp8GroupedWorkspace::new(engine, down.in_features, down.out_features, pairs, pairs)?;
4205        let activation = engine.uninit(pairs * STEP_GROUPED_FP8_WIDTH)?;
4206        Ok(PreparedStepGroupedFp8Gate {
4207            device: engine.ctx().ordinal(),
4208            gate,
4209            up,
4210            down,
4211            input,
4212            route_csr,
4213            down_csr,
4214            gate_workspace,
4215            up_workspace,
4216            down_workspace,
4217            activation,
4218            activation_limit,
4219            tokens,
4220            pairs,
4221        })
4222    }
4223
4224    /// Execute one prepared gate/up/activation/down projection sequence on rank zero.
4225    pub fn run_step_grouped_fp8_gate(
4226        &self,
4227        plan: &mut PreparedStepGroupedFp8Gate,
4228    ) -> Result<StepGroupedFp8ProjectionOutput, Box<dyn std::error::Error>> {
4229        let engine = self
4230            .ranks
4231            .first()
4232            .ok_or("official Step grouped FP8 gate has no rank-zero engine")?;
4233        if engine.ctx().ordinal() != plan.device {
4234            return Err(format!(
4235                "official Step grouped FP8 plan device {} != rank-zero device {}",
4236                plan.device,
4237                engine.ctx().ordinal()
4238            )
4239            .into());
4240        }
4241        let _main = engine.gpu.enter_main()?;
4242
4243        plan.gate_workspace.quantize(engine, &plan.input)?;
4244        plan.gate_workspace.project(
4245            engine,
4246            &plan.gate.codes,
4247            &plan.gate.scales,
4248            &plan.route_csr,
4249            plan.gate.code_stride,
4250            plan.gate.scale_stride,
4251            1.0,
4252        )?;
4253        plan.up_workspace.quantize(engine, &plan.input)?;
4254        plan.up_workspace.project(
4255            engine,
4256            &plan.up.codes,
4257            &plan.up.scales,
4258            &plan.route_csr,
4259            plan.up.code_stride,
4260            plan.up.scale_stride,
4261            1.0,
4262        )?;
4263        if let Some(limit) = plan.activation_limit {
4264            engine.silu_clamped_mul_host_expf(
4265                plan.gate_workspace.output(),
4266                plan.up_workspace.output(),
4267                limit,
4268                &mut plan.activation,
4269                plan.pairs * STEP_GROUPED_FP8_WIDTH,
4270            )?;
4271        } else {
4272            engine.silu_mul_host_expf(
4273                plan.gate_workspace.output(),
4274                plan.up_workspace.output(),
4275                &mut plan.activation,
4276                plan.pairs * STEP_GROUPED_FP8_WIDTH,
4277            )?;
4278        }
4279        plan.down_workspace.quantize(engine, &plan.activation)?;
4280        plan.down_workspace.project(
4281            engine,
4282            &plan.down.codes,
4283            &plan.down.scales,
4284            &plan.down_csr,
4285            plan.down.code_stride,
4286            plan.down.scale_stride,
4287            1.0,
4288        )?;
4289
4290        Ok(StepGroupedFp8ProjectionOutput {
4291            gate: engine.dtoh(plan.gate_workspace.output())?,
4292            up: engine.dtoh(plan.up_workspace.output())?,
4293            down: engine.dtoh(plan.down_workspace.output())?,
4294        })
4295    }
4296
4297    pub fn prepare_step_grouped_expert_parallel_gate(
4298        &self,
4299        experts: &ResidentExpertParallel,
4300        input: &[f32],
4301        tokens: usize,
4302        selected: &[usize],
4303        activation_limit: Option<f32>,
4304    ) -> Result<PreparedStepGroupedExpertParallelGate, Box<dyn std::error::Error>> {
4305        self.prepare_step_grouped_expert_parallel_gate_with_capacity(
4306            experts,
4307            input,
4308            tokens,
4309            selected,
4310            activation_limit,
4311            tokens,
4312        )
4313    }
4314
4315    #[allow(clippy::too_many_arguments)]
4316    pub fn prepare_step_grouped_expert_parallel_gate_with_capacity(
4317        &self,
4318        experts: &ResidentExpertParallel,
4319        input: &[f32],
4320        tokens: usize,
4321        selected: &[usize],
4322        activation_limit: Option<f32>,
4323        max_tokens: usize,
4324    ) -> Result<PreparedStepGroupedExpertParallelGate, Box<dyn std::error::Error>> {
4325        if !self.native_p2p || !self.ep_device_arithmetic {
4326            return Err(
4327                "Step owner-grouped FP8 requires native P2P and device-resident arithmetic".into(),
4328            );
4329        }
4330        validate_step_expert_activation_limit(activation_limit)?;
4331        validate_ep_residency(&self.ranks, experts)?;
4332        validate_activations(input, tokens, experts.input_width)?;
4333        if max_tokens < tokens || max_tokens > i32::MAX as usize {
4334            return Err(format!(
4335                "official Step owner-grouped FP8 tokens {tokens} exceed capacity {max_tokens}"
4336            )
4337            .into());
4338        }
4339        if experts.expert_count != STEP_GROUPED_FP8_EXPERTS
4340            || experts.expert_width != STEP_GROUPED_FP8_WIDTH
4341        {
4342            return Err(format!(
4343                "official Step owner-grouped FP8 requires {} experts at width {}, got {} at {}",
4344                STEP_GROUPED_FP8_EXPERTS,
4345                STEP_GROUPED_FP8_WIDTH,
4346                experts.expert_count,
4347                experts.expert_width,
4348            )
4349            .into());
4350        }
4351        validate_step_grouped_owner_routes(experts.expert_count, tokens, selected)?;
4352        let max_pairs = max_tokens
4353            .checked_mul(STEP_GROUPED_FP8_TOP_K)
4354            .ok_or("official Step owner-grouped FP8 capacity route count overflow")?;
4355        let input_capacity = max_tokens
4356            .checked_mul(experts.input_width)
4357            .ok_or("official Step owner-grouped FP8 input capacity overflow")?;
4358
4359        let mut rank_inputs = Vec::with_capacity(self.ranks.len());
4360        for engine in &self.ranks {
4361            let _main = engine.gpu.enter_main()?;
4362            rank_inputs.push(engine.uninit(input_capacity)?);
4363        }
4364
4365        let mut owners = Vec::with_capacity(self.ranks.len());
4366        for (owner_rank, rank) in experts.ranks.iter().enumerate() {
4367            if rank.gate.expert_range != rank.up.expert_range
4368                || rank.gate.expert_range != rank.down.expert_range
4369            {
4370                return Err(format!(
4371                    "owner-grouped FP8 rank {} gate/up/down expert ranges differ",
4372                    owner_rank
4373                )
4374                .into());
4375            }
4376            let local_experts = rank.gate.expert_range.len();
4377            let engine = &self.ranks[owner_rank];
4378            let _main = engine.gpu.enter_main()?;
4379            let route_csr =
4380                DeviceExpertCsr::with_capacity(engine, local_experts, max_tokens, max_pairs)?;
4381            let down_csr =
4382                DeviceExpertCsr::with_capacity(engine, local_experts, max_pairs, max_pairs)?;
4383            let gate_workspace = Fp8GroupedWorkspace::new(
4384                engine,
4385                experts.input_width,
4386                experts.expert_width,
4387                max_tokens,
4388                max_pairs,
4389            )?;
4390            let up_workspace = Fp8GroupedWorkspace::new(
4391                engine,
4392                experts.input_width,
4393                experts.expert_width,
4394                max_tokens,
4395                max_pairs,
4396            )?;
4397            let down_workspace = Fp8GroupedWorkspace::new(
4398                engine,
4399                experts.expert_width,
4400                experts.input_width,
4401                max_pairs,
4402                max_pairs,
4403            )?;
4404            let activation = engine.uninit(
4405                max_pairs
4406                    .checked_mul(experts.expert_width)
4407                    .ok_or("official Step owner-grouped FP8 activation capacity overflow")?,
4408            )?;
4409            owners.push(PreparedStepGroupedExpertOwner {
4410                rank: owner_rank,
4411                global_pairs: Vec::new(),
4412                route_csr,
4413                down_csr,
4414                gate_workspace,
4415                up_workspace,
4416                down_workspace,
4417                activation,
4418            });
4419        }
4420
4421        let mut plan = PreparedStepGroupedExpertParallelGate {
4422            rank_inputs,
4423            owners,
4424            activation_limit,
4425            tokens: 0,
4426            pairs: 0,
4427            max_tokens,
4428            max_pairs,
4429            input_width: experts.input_width,
4430            expert_width: experts.expert_width,
4431            generation: 0,
4432            executed_generation: None,
4433            ready: false,
4434        };
4435        self.refresh_step_grouped_expert_parallel_gate(
4436            experts, &mut plan, input, tokens, selected,
4437        )?;
4438        Ok(plan)
4439    }
4440
4441    #[allow(clippy::type_complexity)] // allow: one-shot composite type; naming it would hide the shape that matters at the call site
4442    fn prepare_step_grouped_expert_parallel_refresh(
4443        &self,
4444        experts: &ResidentExpertParallel,
4445        plan: &PreparedStepGroupedExpertParallelGate,
4446        tokens: usize,
4447        selected: &[usize],
4448    ) -> Result<(usize, u64, Vec<Option<StepGroupedExpertOwnerSchedule>>), Box<dyn std::error::Error>>
4449    {
4450        validate_ep_residency(&self.ranks, experts)?;
4451        if plan.rank_inputs.len() != self.ranks.len()
4452            || plan.owners.len() != self.ranks.len()
4453            || plan.input_width != experts.input_width
4454            || plan.expert_width != experts.expert_width
4455            || tokens > plan.max_tokens
4456        {
4457            return Err(format!(
4458                "Step owner-grouped FP8 refresh geometry changed ranks={}/{} owners={}/{} \
4459                 input={}/{} expert={}/{} tokens={}/{}",
4460                plan.rank_inputs.len(),
4461                self.ranks.len(),
4462                plan.owners.len(),
4463                self.ranks.len(),
4464                plan.input_width,
4465                experts.input_width,
4466                plan.expert_width,
4467                experts.expert_width,
4468                tokens,
4469                plan.max_tokens,
4470            )
4471            .into());
4472        }
4473        let pairs = validate_step_grouped_owner_routes(experts.expert_count, tokens, selected)?;
4474        if pairs > plan.max_pairs {
4475            return Err(format!(
4476                "Step owner-grouped FP8 route count {pairs} exceeds capacity {}",
4477                plan.max_pairs
4478            )
4479            .into());
4480        }
4481        let next_generation = plan
4482            .generation
4483            .checked_add(1)
4484            .ok_or("Step owner-grouped FP8 plan generation overflow")?;
4485        let owner_routes = partition_expert_owner_routes(
4486            experts.expert_count,
4487            self.ranks.len(),
4488            tokens,
4489            STEP_GROUPED_FP8_TOP_K,
4490            selected,
4491        )?;
4492        let mut schedules = Vec::with_capacity(self.ranks.len());
4493        for routes in owner_routes {
4494            if routes.selected.is_empty() {
4495                schedules.push(None);
4496                continue;
4497            }
4498            let local_experts = experts.ranks[routes.rank].gate.expert_range.len();
4499            let local_pairs = routes.selected.len();
4500            let route_csr = ExpertCsr::from_pair_rows(
4501                local_experts,
4502                tokens,
4503                &routes.selected,
4504                &routes.token_rows,
4505            )?;
4506            let down_rows = (0..local_pairs).collect::<Vec<_>>();
4507            let down_csr = ExpertCsr::from_pair_rows(
4508                local_experts,
4509                local_pairs,
4510                &routes.selected,
4511                &down_rows,
4512            )?;
4513            schedules.push(Some(StepGroupedExpertOwnerSchedule {
4514                global_pairs: routes.global_pairs,
4515                route_csr,
4516                down_csr,
4517            }));
4518        }
4519        Ok((pairs, next_generation, schedules))
4520    }
4521
4522    fn commit_step_grouped_expert_parallel_refresh(
4523        &self,
4524        plan: &mut PreparedStepGroupedExpertParallelGate,
4525        tokens: usize,
4526        pairs: usize,
4527        next_generation: u64,
4528        schedules: Vec<Option<StepGroupedExpertOwnerSchedule>>,
4529    ) -> Result<(), Box<dyn std::error::Error>> {
4530        for (owner, schedule) in plan.owners.iter_mut().zip(schedules) {
4531            let engine = &self.ranks[owner.rank];
4532            let _main = engine.gpu.enter_main()?;
4533            if let Some(schedule) = schedule {
4534                owner.route_csr.refresh(engine, &schedule.route_csr)?;
4535                owner.down_csr.refresh(engine, &schedule.down_csr)?;
4536                owner.global_pairs = schedule.global_pairs;
4537            } else {
4538                owner.route_csr.clear();
4539                owner.down_csr.clear();
4540                owner.global_pairs.clear();
4541            }
4542        }
4543        plan.tokens = tokens;
4544        plan.pairs = pairs;
4545        plan.generation = next_generation;
4546        plan.ready = true;
4547        Ok(())
4548    }
4549
4550    pub fn refresh_step_grouped_expert_parallel_gate(
4551        &self,
4552        experts: &ResidentExpertParallel,
4553        plan: &mut PreparedStepGroupedExpertParallelGate,
4554        input: &[f32],
4555        tokens: usize,
4556        selected: &[usize],
4557    ) -> Result<(), Box<dyn std::error::Error>> {
4558        validate_activations(input, tokens, experts.input_width)?;
4559        let (pairs, next_generation, schedules) =
4560            self.prepare_step_grouped_expert_parallel_refresh(experts, plan, tokens, selected)?;
4561
4562        plan.ready = false;
4563        plan.executed_generation = None;
4564        {
4565            let root = &self.ranks[0];
4566            let _main = root.gpu.enter_main()?;
4567            let mut destination = plan.rank_inputs[0].slice_mut(0..input.len());
4568            root.stream().memcpy_htod(input, &mut destination)?;
4569            root.stream().synchronize()?;
4570        }
4571        let (root_inputs, peer_inputs) = plan.rank_inputs.split_at_mut(1);
4572        let root_input = &root_inputs[0];
4573        for (rank, peer_input) in peer_inputs.iter_mut().enumerate() {
4574            let engine = &self.ranks[rank + 1];
4575            let _main = engine.gpu.enter_main()?;
4576            let mut destination = peer_input.slice_mut(0..input.len());
4577            engine
4578                .stream()
4579                .memcpy_dtod(&root_input.slice(0..input.len()), &mut destination)?;
4580        }
4581        self.commit_step_grouped_expert_parallel_refresh(
4582            plan,
4583            tokens,
4584            pairs,
4585            next_generation,
4586            schedules,
4587        )
4588    }
4589
4590    /// Refresh routes and inputs from an already-resident rank-zero activation.
4591    ///
4592    /// The caller must order the source producer before this call. The root copy is completed
4593    /// before peer dispatch, while CSR and workspace allocations retain their stable addresses.
4594    pub fn refresh_step_grouped_expert_parallel_gate_from_root_device(
4595        &self,
4596        experts: &ResidentExpertParallel,
4597        plan: &mut PreparedStepGroupedExpertParallelGate,
4598        input: &CudaSlice<f32>,
4599        tokens: usize,
4600        selected: &[usize],
4601    ) -> Result<(), Box<dyn std::error::Error>> {
4602        let input_values = tokens
4603            .checked_mul(experts.input_width)
4604            .ok_or("Step owner-grouped FP8 input size overflow")?;
4605        let root = self
4606            .ranks
4607            .first()
4608            .ok_or("Step owner-grouped FP8 runtime has no root rank")?;
4609        if input.len() < input_values || input.ordinal() != root.ctx().ordinal() {
4610            return Err(format!(
4611                "Step owner-grouped FP8 root input len/device {}/{} does not cover {} values on \
4612                 device {}",
4613                input.len(),
4614                input.ordinal(),
4615                input_values,
4616                root.ctx().ordinal(),
4617            )
4618            .into());
4619        }
4620        let (pairs, next_generation, schedules) =
4621            self.prepare_step_grouped_expert_parallel_refresh(experts, plan, tokens, selected)?;
4622
4623        plan.ready = false;
4624        plan.executed_generation = None;
4625        {
4626            let _main = root.gpu.enter_main()?;
4627            let mut destination = plan.rank_inputs[0].slice_mut(0..input_values);
4628            root.stream()
4629                .memcpy_dtod(&input.slice(0..input_values), &mut destination)?;
4630            root.stream().synchronize()?;
4631        }
4632        let (root_inputs, peer_inputs) = plan.rank_inputs.split_at_mut(1);
4633        let root_input = &root_inputs[0];
4634        for (rank, peer_input) in peer_inputs.iter_mut().enumerate() {
4635            let engine = &self.ranks[rank + 1];
4636            let _main = engine.gpu.enter_main()?;
4637            let mut destination = peer_input.slice_mut(0..input_values);
4638            engine
4639                .stream()
4640                .memcpy_dtod(&root_input.slice(0..input_values), &mut destination)?;
4641        }
4642        self.commit_step_grouped_expert_parallel_refresh(
4643            plan,
4644            tokens,
4645            pairs,
4646            next_generation,
4647            schedules,
4648        )
4649    }
4650
4651    /// Replace a fixed route plan's rank inputs from an already replicated device batch.
4652    ///
4653    /// Route CSR remains unchanged. Advancing the generation invalidates every prior projection
4654    /// and combine result, so callers must refresh combine metadata before executing again.
4655    pub fn refresh_step_grouped_expert_parallel_inputs_from_replicated(
4656        &self,
4657        experts: &ResidentExpertParallel,
4658        plan: &mut PreparedStepGroupedExpertParallelGate,
4659        input: &ResidentReplicatedDeviceRows,
4660    ) -> Result<(), Box<dyn std::error::Error>> {
4661        validate_ep_residency(&self.ranks, experts)?;
4662        validate_replicated_device_rows(&self.ranks, input)?;
4663        if !plan.ready
4664            || input.tokens != plan.tokens
4665            || input.width != plan.input_width
4666            || input.tokens > plan.max_tokens
4667            || plan.rank_inputs.len() != self.ranks.len()
4668            || plan.owners.len() != self.ranks.len()
4669            || plan.input_width != experts.input_width
4670            || plan.expert_width != experts.expert_width
4671        {
4672            return Err("Step owner-grouped replicated input geometry changed".into());
4673        }
4674        let values = input
4675            .tokens
4676            .checked_mul(input.width)
4677            .ok_or("Step owner-grouped replicated input size overflow")?;
4678        let next_generation = plan
4679            .generation
4680            .checked_add(1)
4681            .ok_or("Step owner-grouped FP8 plan generation overflow")?;
4682        plan.ready = false;
4683        plan.executed_generation = None;
4684        for (rank, engine) in self.ranks.iter().enumerate() {
4685            let _main = engine.gpu.enter_main()?;
4686            let mut destination = plan.rank_inputs[rank].slice_mut(0..values);
4687            engine
4688                .stream()
4689                .memcpy_dtod(&input.ranks[rank], &mut destination)?;
4690        }
4691        plan.generation = next_generation;
4692        plan.ready = true;
4693        Ok(())
4694    }
4695
4696    pub fn execute_step_grouped_expert_parallel_gate(
4697        &self,
4698        experts: &ResidentExpertParallel,
4699        plan: &mut PreparedStepGroupedExpertParallelGate,
4700    ) -> Result<(), Box<dyn std::error::Error>> {
4701        validate_ep_residency(&self.ranks, experts)?;
4702        if !plan.ready
4703            || plan.rank_inputs.len() != self.ranks.len()
4704            || plan.owners.len() != self.ranks.len()
4705            || plan.input_width != experts.input_width
4706            || plan.expert_width != experts.expert_width
4707        {
4708            return Err("Step owner-grouped FP8 plan is not ready or its geometry changed".into());
4709        }
4710        plan.executed_generation = None;
4711
4712        for owner in &mut plan.owners {
4713            if owner.global_pairs.is_empty() {
4714                continue;
4715            }
4716            let engine = &self.ranks[owner.rank];
4717            let bank = &experts.ranks[owner.rank];
4718            let _main = engine.gpu.enter_main()?;
4719            let local_pairs = owner.global_pairs.len();
4720            owner.gate_workspace.quantize_for_shape(
4721                engine,
4722                &plan.rank_inputs[owner.rank],
4723                plan.tokens,
4724                local_pairs,
4725            )?;
4726            owner.gate_workspace.project(
4727                engine,
4728                &bank.gate.codes,
4729                &bank.gate.scales,
4730                &owner.route_csr,
4731                bank.gate.code_stride,
4732                bank.gate.scale_stride,
4733                1.0,
4734            )?;
4735            owner.up_workspace.quantize_for_shape(
4736                engine,
4737                &plan.rank_inputs[owner.rank],
4738                plan.tokens,
4739                local_pairs,
4740            )?;
4741            owner.up_workspace.project(
4742                engine,
4743                &bank.up.codes,
4744                &bank.up.scales,
4745                &owner.route_csr,
4746                bank.up.code_stride,
4747                bank.up.scale_stride,
4748                1.0,
4749            )?;
4750        }
4751        for owner in &mut plan.owners {
4752            if owner.global_pairs.is_empty() {
4753                continue;
4754            }
4755            let engine = &self.ranks[owner.rank];
4756            let _main = engine.gpu.enter_main()?;
4757            let values = owner.global_pairs.len() * plan.expert_width;
4758            if let Some(limit) = plan.activation_limit {
4759                engine.silu_clamped_mul_host_expf(
4760                    owner.gate_workspace.output(),
4761                    owner.up_workspace.output(),
4762                    limit,
4763                    &mut owner.activation,
4764                    values,
4765                )?;
4766            } else {
4767                engine.silu_mul_host_expf(
4768                    owner.gate_workspace.output(),
4769                    owner.up_workspace.output(),
4770                    &mut owner.activation,
4771                    values,
4772                )?;
4773            }
4774        }
4775        for owner in &mut plan.owners {
4776            if owner.global_pairs.is_empty() {
4777                continue;
4778            }
4779            let engine = &self.ranks[owner.rank];
4780            let bank = &experts.ranks[owner.rank];
4781            let _main = engine.gpu.enter_main()?;
4782            let local_pairs = owner.global_pairs.len();
4783            owner.down_workspace.quantize_for_shape(
4784                engine,
4785                &owner.activation,
4786                local_pairs,
4787                local_pairs,
4788            )?;
4789            owner.down_workspace.project(
4790                engine,
4791                &bank.down.codes,
4792                &bank.down.scales,
4793                &owner.down_csr,
4794                bank.down.code_stride,
4795                bank.down.scale_stride,
4796                1.0,
4797            )?;
4798        }
4799        plan.executed_generation = Some(plan.generation);
4800        Ok(())
4801    }
4802
4803    pub fn collect_step_grouped_expert_parallel_gate(
4804        &self,
4805        plan: &PreparedStepGroupedExpertParallelGate,
4806    ) -> Result<StepGroupedFp8ProjectionOutput, Box<dyn std::error::Error>> {
4807        if !plan.ready || plan.executed_generation != Some(plan.generation) {
4808            return Err("Step owner-grouped FP8 projection is stale or has not executed".into());
4809        }
4810        let mut gate = vec![0.0f32; plan.pairs * plan.expert_width];
4811        let mut up = vec![0.0f32; plan.pairs * plan.expert_width];
4812        let mut down = vec![0.0f32; plan.pairs * plan.input_width];
4813        for owner in &plan.owners {
4814            if owner.global_pairs.is_empty() {
4815                continue;
4816            }
4817            let engine = &self.ranks[owner.rank];
4818            let _main = engine.gpu.enter_main()?;
4819            let owner_gate = engine.dtoh_view(
4820                &owner
4821                    .gate_workspace
4822                    .output()
4823                    .slice(0..owner.gate_workspace.output_len()),
4824            )?;
4825            let owner_up = engine.dtoh_view(
4826                &owner
4827                    .up_workspace
4828                    .output()
4829                    .slice(0..owner.up_workspace.output_len()),
4830            )?;
4831            let owner_down = engine.dtoh_view(
4832                &owner
4833                    .down_workspace
4834                    .output()
4835                    .slice(0..owner.down_workspace.output_len()),
4836            )?;
4837            for (local_pair, &global_pair) in owner.global_pairs.iter().enumerate() {
4838                let local_expert = local_pair * plan.expert_width;
4839                let global_expert = global_pair * plan.expert_width;
4840                gate[global_expert..global_expert + plan.expert_width]
4841                    .copy_from_slice(&owner_gate[local_expert..local_expert + plan.expert_width]);
4842                up[global_expert..global_expert + plan.expert_width]
4843                    .copy_from_slice(&owner_up[local_expert..local_expert + plan.expert_width]);
4844
4845                let local_hidden = local_pair * plan.input_width;
4846                let global_hidden = global_pair * plan.input_width;
4847                down[global_hidden..global_hidden + plan.input_width]
4848                    .copy_from_slice(&owner_down[local_hidden..local_hidden + plan.input_width]);
4849            }
4850        }
4851        Ok(StepGroupedFp8ProjectionOutput { gate, up, down })
4852    }
4853
4854    pub fn run_step_grouped_expert_parallel_gate(
4855        &self,
4856        experts: &ResidentExpertParallel,
4857        plan: &mut PreparedStepGroupedExpertParallelGate,
4858    ) -> Result<StepGroupedFp8ProjectionOutput, Box<dyn std::error::Error>> {
4859        self.execute_step_grouped_expert_parallel_gate(experts, plan)?;
4860        self.collect_step_grouped_expert_parallel_gate(plan)
4861    }
4862
4863    pub fn prepare_step_grouped_expert_parallel_combine(
4864        &self,
4865        plan: &PreparedStepGroupedExpertParallelGate,
4866        route_weights: &[f32],
4867    ) -> Result<PreparedPeerWeightedRouteCombine, Box<dyn std::error::Error>> {
4868        if !self.native_p2p || !self.ep_device_arithmetic || !plan.ready {
4869            return Err(
4870                "Step owner-grouped combine requires a ready native-P2P device plan".into(),
4871            );
4872        }
4873        let owner_pairs = plan
4874            .owners
4875            .iter()
4876            .map(|owner| owner.global_pairs.as_slice())
4877            .collect::<Vec<_>>();
4878        let shape = validate_weighted_route_combine(
4879            plan.input_width,
4880            STEP_GROUPED_FP8_TOP_K,
4881            plan.max_tokens,
4882            plan.tokens,
4883            &owner_pairs,
4884            route_weights,
4885        )?;
4886        if shape.max_pairs != plan.max_pairs {
4887            return Err(format!(
4888                "Step owner-grouped combine capacity {} != projection capacity {}",
4889                shape.max_pairs, plan.max_pairs
4890            )
4891            .into());
4892        }
4893        let root = self
4894            .ranks
4895            .first()
4896            .ok_or("Step owner-grouped combine has no root rank")?;
4897        let slot_values = shape
4898            .max_pairs
4899            .checked_mul(plan.input_width)
4900            .ok_or("Step owner-grouped combine slot capacity overflow")?;
4901        let output_values = plan
4902            .max_tokens
4903            .checked_mul(plan.input_width)
4904            .ok_or("Step owner-grouped combine output capacity overflow")?;
4905        let (root_device, owners, peer_staging, slots, weights, output) = {
4906            let _main = root.gpu.enter_main()?;
4907            let mut owners = Vec::with_capacity(plan.owners.len());
4908            for _ in &plan.owners {
4909                owners.push(PreparedPeerWeightedRouteOwner {
4910                    token_rows: root.htod_i32(&vec![0; shape.max_pairs])?,
4911                    slots: root.htod_i32(&vec![0; shape.max_pairs])?,
4912                    weights: root.htod(&vec![0.0; shape.max_pairs])?,
4913                    active_pairs: 0,
4914                });
4915            }
4916            (
4917                root.ctx().ordinal(),
4918                owners,
4919                root.uninit(slot_values)?,
4920                root.uninit(slot_values)?,
4921                root.uninit(shape.max_pairs)?,
4922                root.uninit(output_values)?,
4923            )
4924        };
4925        let mut peer_devices = Vec::with_capacity(self.ranks.len().saturating_sub(1));
4926        let mut peer_outputs = Vec::with_capacity(self.ranks.len().saturating_sub(1));
4927        for engine in self.ranks.iter().skip(1) {
4928            let _main = engine.gpu.enter_main()?;
4929            peer_devices.push(engine.ctx().ordinal());
4930            peer_outputs.push(engine.uninit(output_values)?);
4931        }
4932        let mut combine = PreparedPeerWeightedRouteCombine {
4933            root_device,
4934            owners,
4935            peer_staging,
4936            slots,
4937            weights,
4938            output,
4939            peer_devices,
4940            peer_outputs,
4941            width: plan.input_width,
4942            experts_per_token: STEP_GROUPED_FP8_TOP_K,
4943            max_tokens: plan.max_tokens,
4944            max_pairs: shape.max_pairs,
4945            tokens: 0,
4946            pairs: 0,
4947            projection_generation: 0,
4948            output_generation: None,
4949            broadcast_generation: None,
4950            ready: false,
4951        };
4952        self.refresh_step_grouped_expert_parallel_combine(plan, &mut combine, route_weights)?;
4953        Ok(combine)
4954    }
4955
4956    pub fn refresh_step_grouped_expert_parallel_combine(
4957        &self,
4958        plan: &PreparedStepGroupedExpertParallelGate,
4959        combine: &mut PreparedPeerWeightedRouteCombine,
4960        route_weights: &[f32],
4961    ) -> Result<(), Box<dyn std::error::Error>> {
4962        let output_capacity = combine
4963            .max_tokens
4964            .checked_mul(combine.width)
4965            .ok_or("Step owner-grouped combine output capacity overflow")?;
4966        if !plan.ready
4967            || combine.owners.len() != plan.owners.len()
4968            || combine.peer_devices.len() + 1 != self.ranks.len()
4969            || combine.peer_outputs.len() + 1 != self.ranks.len()
4970            || combine.width != plan.input_width
4971            || combine.experts_per_token != STEP_GROUPED_FP8_TOP_K
4972            || combine.max_tokens != plan.max_tokens
4973            || combine.max_pairs != plan.max_pairs
4974            || combine.output.len() < output_capacity
4975            || combine
4976                .peer_outputs
4977                .iter()
4978                .any(|output| output.len() < output_capacity)
4979        {
4980            return Err("Step owner-grouped combine/projection geometry changed".into());
4981        }
4982        if self
4983            .ranks
4984            .iter()
4985            .skip(1)
4986            .zip(&combine.peer_devices)
4987            .any(|(engine, &device)| engine.ctx().ordinal() != device)
4988        {
4989            return Err("Step owner-grouped combine peer devices changed".into());
4990        }
4991        let owner_pairs = plan
4992            .owners
4993            .iter()
4994            .map(|owner| owner.global_pairs.as_slice())
4995            .collect::<Vec<_>>();
4996        let shape = validate_weighted_route_combine(
4997            combine.width,
4998            combine.experts_per_token,
4999            combine.max_tokens,
5000            plan.tokens,
5001            &owner_pairs,
5002            route_weights,
5003        )?;
5004        if shape.max_pairs != combine.max_pairs {
5005            return Err("Step owner-grouped combine capacity changed during refresh".into());
5006        }
5007        let metadata = owner_pairs
5008            .iter()
5009            .map(|pairs| {
5010                let token_rows = pairs
5011                    .iter()
5012                    .map(|&pair| (pair / combine.experts_per_token) as i32)
5013                    .collect::<Vec<_>>();
5014                let slots = pairs
5015                    .iter()
5016                    .map(|&pair| (pair % combine.experts_per_token) as i32)
5017                    .collect::<Vec<_>>();
5018                let weights = pairs
5019                    .iter()
5020                    .map(|&pair| route_weights[pair])
5021                    .collect::<Vec<_>>();
5022                (token_rows, slots, weights)
5023            })
5024            .collect::<Vec<_>>();
5025
5026        combine.ready = false;
5027        combine.output_generation = None;
5028        combine.broadcast_generation = None;
5029        let root = self
5030            .ranks
5031            .first()
5032            .ok_or("Step owner-grouped combine has no root rank")?;
5033        let _main = root.gpu.enter_main()?;
5034        if root.ctx().ordinal() != combine.root_device {
5035            return Err(format!(
5036                "Step owner-grouped combine root device changed {} != {}",
5037                root.ctx().ordinal(),
5038                combine.root_device
5039            )
5040            .into());
5041        }
5042        for (owner, (token_rows, slots, weights)) in combine.owners.iter_mut().zip(metadata) {
5043            if token_rows.is_empty() {
5044                owner.active_pairs = 0;
5045                continue;
5046            }
5047            root.htod_i32_into(&mut owner.token_rows, &token_rows)?;
5048            root.htod_i32_into(&mut owner.slots, &slots)?;
5049            let mut weight_prefix = owner.weights.slice_mut(0..weights.len());
5050            root.stream().memcpy_htod(&weights, &mut weight_prefix)?;
5051            owner.active_pairs = token_rows.len();
5052        }
5053        combine.tokens = plan.tokens;
5054        combine.pairs = shape.pairs;
5055        combine.projection_generation = plan.generation;
5056        combine.ready = true;
5057        Ok(())
5058    }
5059
5060    pub fn execute_step_grouped_expert_parallel_combine(
5061        &self,
5062        plan: &PreparedStepGroupedExpertParallelGate,
5063        combine: &mut PreparedPeerWeightedRouteCombine,
5064    ) -> Result<(), Box<dyn std::error::Error>> {
5065        if !plan.ready
5066            || plan.executed_generation != Some(plan.generation)
5067            || !combine.ready
5068            || combine.tokens != plan.tokens
5069            || combine.pairs != plan.pairs
5070            || combine.width != plan.input_width
5071            || combine.owners.len() != plan.owners.len()
5072            || combine.projection_generation != plan.generation
5073        {
5074            return Err("Step owner-grouped combine is stale or its geometry changed".into());
5075        }
5076        combine.output_generation = None;
5077        combine.broadcast_generation = None;
5078        for owner in &plan.owners {
5079            if owner.rank == 0 || owner.global_pairs.is_empty() {
5080                continue;
5081            }
5082            let engine = &self.ranks[owner.rank];
5083            let _main = engine.gpu.enter_main()?;
5084            engine.stream().synchronize()?;
5085        }
5086        let root = self
5087            .ranks
5088            .first()
5089            .ok_or("Step owner-grouped combine has no root rank")?;
5090        let _main = root.gpu.enter_main()?;
5091        if root.ctx().ordinal() != combine.root_device {
5092            return Err("Step owner-grouped combine is not resident on the root device".into());
5093        }
5094        for (index, owner) in plan.owners.iter().enumerate() {
5095            let metadata = &combine.owners[index];
5096            if owner.global_pairs.len() != metadata.active_pairs {
5097                return Err(format!(
5098                    "Step owner-grouped combine owner {index} rows {} != metadata {}",
5099                    owner.global_pairs.len(),
5100                    metadata.active_pairs
5101                )
5102                .into());
5103            }
5104            if metadata.active_pairs == 0 {
5105                continue;
5106            }
5107            let values = metadata
5108                .active_pairs
5109                .checked_mul(combine.width)
5110                .ok_or("Step owner-grouped combine peer value count overflow")?;
5111            if owner.rank == 0 {
5112                root.scatter_slot(
5113                    owner.down_workspace.output(),
5114                    &metadata.token_rows,
5115                    &metadata.slots,
5116                    &metadata.weights,
5117                    &mut combine.slots,
5118                    &mut combine.weights,
5119                    combine.width,
5120                    combine.experts_per_token,
5121                    metadata.active_pairs,
5122                )?;
5123            } else {
5124                let source = owner.down_workspace.output().slice(0..values);
5125                let mut destination = combine.peer_staging.slice_mut(0..values);
5126                root.stream().memcpy_dtod(&source, &mut destination)?;
5127                root.scatter_slot(
5128                    &combine.peer_staging,
5129                    &metadata.token_rows,
5130                    &metadata.slots,
5131                    &metadata.weights,
5132                    &mut combine.slots,
5133                    &mut combine.weights,
5134                    combine.width,
5135                    combine.experts_per_token,
5136                    metadata.active_pairs,
5137                )?;
5138            }
5139        }
5140        root.reduce_slots_host(
5141            &combine.slots,
5142            &combine.weights,
5143            &mut combine.output,
5144            combine.width,
5145            combine.experts_per_token,
5146            combine.tokens,
5147        )?;
5148        combine.output_generation = Some(plan.generation);
5149        Ok(())
5150    }
5151
5152    pub fn collect_step_grouped_expert_parallel_combine(
5153        &self,
5154        plan: &PreparedStepGroupedExpertParallelGate,
5155        combine: &PreparedPeerWeightedRouteCombine,
5156    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
5157        if !plan.ready
5158            || combine.output_generation != Some(plan.generation)
5159            || combine.projection_generation != plan.generation
5160        {
5161            return Err("Step owner-grouped combine output is stale or has not executed".into());
5162        }
5163        let root = self
5164            .ranks
5165            .first()
5166            .ok_or("Step owner-grouped combine has no root rank")?;
5167        let _main = root.gpu.enter_main()?;
5168        if root.ctx().ordinal() != combine.root_device {
5169            return Err("Step owner-grouped combine is not resident on the root device".into());
5170        }
5171        root.dtoh_view(&combine.output.slice(0..combine.tokens * combine.width))
5172    }
5173
5174    /// Copy the active root combine result into a caller-owned engine on the same CUDA device.
5175    ///
5176    /// The persistent combine buffer remains reusable by the next route generation; the returned
5177    /// allocation follows the serving runtime's ordinary transient-output ownership.
5178    pub fn copy_step_grouped_expert_parallel_combine_root(
5179        &self,
5180        plan: &PreparedStepGroupedExpertParallelGate,
5181        combine: &PreparedPeerWeightedRouteCombine,
5182        destination: &Engine,
5183    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
5184        if !plan.ready
5185            || combine.output_generation != Some(plan.generation)
5186            || combine.projection_generation != plan.generation
5187        {
5188            return Err("Step owner-grouped combine output is stale or has not executed".into());
5189        }
5190        let root = self
5191            .ranks
5192            .first()
5193            .ok_or("Step owner-grouped combine has no root rank")?;
5194        if root.ctx().ordinal() != combine.root_device
5195            || destination.ctx().ordinal() != combine.root_device
5196        {
5197            return Err(format!(
5198                "Step owner-grouped combine root/destination devices {}/{} != {}",
5199                root.ctx().ordinal(),
5200                destination.ctx().ordinal(),
5201                combine.root_device,
5202            )
5203            .into());
5204        }
5205        let values = combine
5206            .tokens
5207            .checked_mul(combine.width)
5208            .ok_or("Step owner-grouped combine copy size overflow")?;
5209        {
5210            let _main = root.gpu.enter_main()?;
5211            root.stream().synchronize()?;
5212        }
5213        let _main = destination.gpu.enter_main()?;
5214        let mut output = destination.uninit(values)?;
5215        destination
5216            .stream()
5217            .memcpy_dtod(&combine.output.slice(0..values), &mut output)?;
5218        Ok(output)
5219    }
5220
5221    pub fn broadcast_step_grouped_expert_parallel_combine(
5222        &self,
5223        plan: &PreparedStepGroupedExpertParallelGate,
5224        combine: &mut PreparedPeerWeightedRouteCombine,
5225    ) -> Result<(), Box<dyn std::error::Error>> {
5226        if !plan.ready
5227            || combine.output_generation != Some(plan.generation)
5228            || combine.projection_generation != plan.generation
5229            || combine.peer_devices.len() + 1 != self.ranks.len()
5230            || combine.peer_outputs.len() + 1 != self.ranks.len()
5231        {
5232            return Err("Step owner-grouped combine output cannot be broadcast".into());
5233        }
5234        combine.broadcast_generation = None;
5235        let values = combine
5236            .tokens
5237            .checked_mul(combine.width)
5238            .ok_or("Step owner-grouped combine broadcast size overflow")?;
5239        {
5240            let root = self
5241                .ranks
5242                .first()
5243                .ok_or("Step owner-grouped combine has no root rank")?;
5244            let _main = root.gpu.enter_main()?;
5245            if root.ctx().ordinal() != combine.root_device {
5246                return Err("Step owner-grouped combine root device changed".into());
5247            }
5248            root.stream().synchronize()?;
5249        }
5250        let source = &combine.output;
5251        for (index, destination_buffer) in combine.peer_outputs.iter_mut().enumerate() {
5252            let engine = &self.ranks[index + 1];
5253            let _main = engine.gpu.enter_main()?;
5254            if engine.ctx().ordinal() != combine.peer_devices[index] {
5255                return Err(format!(
5256                    "Step owner-grouped combine peer {} device changed",
5257                    index + 1
5258                )
5259                .into());
5260            }
5261            let mut destination = destination_buffer.slice_mut(0..values);
5262            engine
5263                .stream()
5264                .memcpy_dtod(&source.slice(0..values), &mut destination)?;
5265        }
5266        combine.broadcast_generation = Some(plan.generation);
5267        Ok(())
5268    }
5269
5270    pub fn collect_step_grouped_expert_parallel_broadcast(
5271        &self,
5272        plan: &PreparedStepGroupedExpertParallelGate,
5273        combine: &PreparedPeerWeightedRouteCombine,
5274    ) -> Result<Vec<Vec<f32>>, Box<dyn std::error::Error>> {
5275        if !plan.ready
5276            || combine.output_generation != Some(plan.generation)
5277            || combine.broadcast_generation != Some(plan.generation)
5278            || combine.peer_outputs.len() + 1 != self.ranks.len()
5279        {
5280            return Err("Step owner-grouped combine broadcast is stale or incomplete".into());
5281        }
5282        let values = combine
5283            .tokens
5284            .checked_mul(combine.width)
5285            .ok_or("Step owner-grouped combine collection size overflow")?;
5286        let mut outputs = Vec::with_capacity(self.ranks.len());
5287        {
5288            let root = &self.ranks[0];
5289            let _main = root.gpu.enter_main()?;
5290            outputs.push(root.dtoh_view(&combine.output.slice(0..values))?);
5291        }
5292        for (index, output) in combine.peer_outputs.iter().enumerate() {
5293            let engine = &self.ranks[index + 1];
5294            let _main = engine.gpu.enter_main()?;
5295            outputs.push(engine.dtoh_view(&output.slice(0..values))?);
5296        }
5297        Ok(outputs)
5298    }
5299
5300    /// Add routed and replicated shared-expert outputs, then add the attention residual.
5301    pub fn finish_step_grouped_expert_parallel_layer(
5302        &self,
5303        plan: &PreparedStepGroupedExpertParallelGate,
5304        combine: &PreparedPeerWeightedRouteCombine,
5305        shared: &ResidentReplicatedDeviceRows,
5306        residual: &ResidentReplicatedDeviceRows,
5307    ) -> Result<ResidentReplicatedDeviceRows, Box<dyn std::error::Error>> {
5308        validate_replicated_device_rows(&self.ranks, shared)?;
5309        validate_replicated_device_rows(&self.ranks, residual)?;
5310        if !plan.ready
5311            || plan.executed_generation != Some(plan.generation)
5312            || combine.output_generation != Some(plan.generation)
5313            || combine.broadcast_generation != Some(plan.generation)
5314            || combine.projection_generation != plan.generation
5315            || combine.peer_outputs.len() + 1 != self.ranks.len()
5316            || shared.tokens != combine.tokens
5317            || residual.tokens != combine.tokens
5318            || shared.width != combine.width
5319            || residual.width != combine.width
5320        {
5321            return Err("Step full-layer finish inputs are stale or their geometry changed".into());
5322        }
5323        let values = combine
5324            .tokens
5325            .checked_mul(combine.width)
5326            .ok_or("Step full-layer output size overflow")?;
5327        let mut ranks = Vec::with_capacity(self.ranks.len());
5328        for rank in 0..self.ranks.len() {
5329            let engine = &self.ranks[rank];
5330            let _main = engine.gpu.enter_main()?;
5331            let routed = if rank == 0 {
5332                &combine.output
5333            } else {
5334                &combine.peer_outputs[rank - 1]
5335            };
5336            let mut ffn = engine.uninit(values)?;
5337            engine.add(routed, &shared.ranks[rank], &mut ffn, values)?;
5338            let mut output = engine.uninit(values)?;
5339            engine.add(&residual.ranks[rank], &ffn, &mut output, values)?;
5340            ranks.push(output);
5341        }
5342        Ok(ResidentReplicatedDeviceRows {
5343            ranks,
5344            tokens: combine.tokens,
5345            width: combine.width,
5346        })
5347    }
5348
5349    pub fn run_step_grouped_expert_parallel_combine(
5350        &self,
5351        plan: &PreparedStepGroupedExpertParallelGate,
5352        combine: &mut PreparedPeerWeightedRouteCombine,
5353    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
5354        self.execute_step_grouped_expert_parallel_combine(plan, combine)?;
5355        self.collect_step_grouped_expert_parallel_combine(plan, combine)
5356    }
5357
5358    pub fn upload_tensor_parallel(
5359        &self,
5360        gate: E4m3ExpertBank<'_>,
5361        up: E4m3ExpertBank<'_>,
5362        down: E4m3ExpertBank<'_>,
5363    ) -> Result<ResidentTensorParallel, Box<dyn std::error::Error>> {
5364        gate.validate()?;
5365        up.validate()?;
5366        down.validate()?;
5367        if gate.expert_count != up.expert_count || gate.expert_count != down.expert_count {
5368            return Err("TP gate/up/down expert counts differ".into());
5369        }
5370        if gate.in_features != up.in_features || gate.out_features != up.out_features {
5371            return Err("TP gate/up dimensions differ".into());
5372        }
5373        if down.in_features != gate.out_features || down.out_features != gate.in_features {
5374            return Err(format!(
5375                "TP down {}x{} does not invert gate/up {}x{}",
5376                down.out_features, down.in_features, gate.out_features, gate.in_features
5377            )
5378            .into());
5379        }
5380        let tp = self.ranks.len();
5381        validate_column_bank_shape(gate, tp)?;
5382        validate_column_bank_shape(up, tp)?;
5383        validate_row_bank_shape(down, tp)?;
5384
5385        let mut gate_ranks = Vec::with_capacity(tp);
5386        let mut up_ranks = Vec::with_capacity(tp);
5387        let mut down_ranks = Vec::with_capacity(tp);
5388        for (rank, engine) in self.ranks.iter().enumerate() {
5389            gate_ranks.push(upload_column_bank_rank(engine, gate, tp, rank)?);
5390            up_ranks.push(upload_column_bank_rank(engine, up, tp, rank)?);
5391            down_ranks.push(upload_row_bank_rank(engine, down, tp, rank)?);
5392        }
5393        Ok(ResidentTensorParallel {
5394            bank: ResidentTpExpertBank {
5395                gate: gate_ranks,
5396                up: up_ranks,
5397                down: down_ranks,
5398                expert_count: gate.expert_count,
5399                input_width: gate.in_features,
5400                expert_width: gate.out_features,
5401            },
5402        })
5403    }
5404
5405    pub fn run_tensor_parallel_routes(
5406        &self,
5407        experts: &ResidentTensorParallel,
5408        input: &[f32],
5409        tokens: usize,
5410        selected: &[usize],
5411        route_weights: &[f32],
5412        experts_per_token: usize,
5413    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
5414        validate_tp_bank_residency(&self.ranks, &experts.bank)?;
5415        validate_activations(input, tokens, experts.bank.input_width)?;
5416        let pairs = tokens
5417            .checked_mul(experts_per_token)
5418            .ok_or("TP route count overflow")?;
5419        if selected.len() != pairs || route_weights.len() != pairs {
5420            return Err(format!(
5421                "TP routes selected={} weights={} != tokens {tokens} x experts/token \
5422                 {experts_per_token} ({pairs})",
5423                selected.len(),
5424                route_weights.len(),
5425            )
5426            .into());
5427        }
5428        if !route_weights.iter().all(|weight| weight.is_finite()) {
5429            return Err("TP route weights contain a non-finite value".into());
5430        }
5431
5432        let mut output = vec![0.0f32; tokens * experts.bank.input_width];
5433        for token in 0..tokens {
5434            let input_row =
5435                &input[token * experts.bank.input_width..(token + 1) * experts.bank.input_width];
5436            for slot in 0..experts_per_token {
5437                let pair = token * experts_per_token + slot;
5438                let expert = selected[pair];
5439                if expert >= experts.bank.expert_count {
5440                    return Err(format!(
5441                        "TP selected expert {expert} outside 0..{}",
5442                        experts.bank.expert_count
5443                    )
5444                    .into());
5445                }
5446                let down = if self.native_p2p {
5447                    self.run_tensor_parallel_expert_native(&experts.bank, expert, input_row)?
5448                } else {
5449                    let gate =
5450                        self.run_column_bank_expert(&experts.bank.gate, expert, input_row)?;
5451                    let up = self.run_column_bank_expert(&experts.bank.up, expert, input_row)?;
5452                    let activated: Vec<f32> = gate
5453                        .iter()
5454                        .zip(&up)
5455                        .map(|(&gate, &up)| gate / (1.0 + (-gate).exp()) * up)
5456                        .collect();
5457                    debug_assert_eq!(activated.len(), experts.bank.expert_width);
5458                    self.run_row_bank_expert(&experts.bank.down, expert, &activated)?
5459                };
5460                let weight = route_weights[pair];
5461                for (sum, value) in output
5462                    [token * experts.bank.input_width..(token + 1) * experts.bank.input_width]
5463                    .iter_mut()
5464                    .zip(down)
5465                {
5466                    *sum += weight * value;
5467                }
5468            }
5469        }
5470        Ok(output)
5471    }
5472
5473    fn run_column_bank_expert(
5474        &self,
5475        ranks: &[ResidentE4m3ExpertBankRank],
5476        expert: usize,
5477        input: &[f32],
5478    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
5479        let local_out = ranks
5480            .first()
5481            .ok_or("TP column bank has no ranks")?
5482            .out_features;
5483        let mut gathered = vec![0.0f32; local_out * ranks.len()];
5484        for (rank, (engine, bank)) in self.ranks.iter().zip(ranks).enumerate() {
5485            let shard = run_resident_bank_expert(engine, bank, expert, input, 1)?;
5486            gathered[rank * local_out..(rank + 1) * local_out].copy_from_slice(&shard);
5487        }
5488        Ok(gathered)
5489    }
5490
5491    fn run_row_bank_expert(
5492        &self,
5493        ranks: &[ResidentE4m3ExpertBankRank],
5494        expert: usize,
5495        input: &[f32],
5496    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
5497        let local_in = ranks.first().ok_or("TP row bank has no ranks")?.in_features;
5498        if input.len() != local_in * ranks.len() {
5499            return Err(format!(
5500                "TP row input {} != {} ranks x {local_in}",
5501                input.len(),
5502                ranks.len()
5503            )
5504            .into());
5505        }
5506        let out_features = ranks[0].out_features;
5507        let mut reduced = vec![0.0f32; out_features];
5508        for (rank, (engine, bank)) in self.ranks.iter().zip(ranks).enumerate() {
5509            let blocks = bank
5510                .k_blocks
5511                .ok_or("TP row bank is not packed in native K-block order")?;
5512            if blocks * FP8_BLOCK != local_in {
5513                return Err(format!(
5514                    "TP row bank has {blocks} blocks but local input width is {local_in}"
5515                )
5516                .into());
5517            }
5518            for block in 0..blocks {
5519                let global_start = rank * local_in + block * FP8_BLOCK;
5520                let partial = run_resident_bank_expert_block(
5521                    engine,
5522                    bank,
5523                    expert,
5524                    block,
5525                    &input[global_start..global_start + FP8_BLOCK],
5526                )?;
5527                for (sum, value) in reduced.iter_mut().zip(partial) {
5528                    *sum += value;
5529                }
5530            }
5531        }
5532        Ok(reduced)
5533    }
5534
5535    fn run_tensor_parallel_expert_native(
5536        &self,
5537        bank: &ResidentTpExpertBank,
5538        expert: usize,
5539        input: &[f32],
5540    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
5541        if !self.native_p2p || self.ranks.len() < 2 {
5542            return Err("native TP expert execution requires at least two P2P ranks".into());
5543        }
5544        let local_out = bank
5545            .gate
5546            .first()
5547            .ok_or("native TP gate bank has no ranks")?
5548            .out_features;
5549        if local_out * self.ranks.len() != bank.expert_width {
5550            return Err(format!(
5551                "native TP gate shards {}x{local_out} != expert width {}",
5552                self.ranks.len(),
5553                bank.expert_width
5554            )
5555            .into());
5556        }
5557
5558        // The caller's routed input is already host-canonical. Upload once on rank zero, then
5559        // broadcast over peer copies so no other rank receives a host-staged duplicate.
5560        let mut rank_inputs = Vec::with_capacity(self.ranks.len());
5561        let root_input = {
5562            let root = &self.ranks[0];
5563            let _main = root.gpu.enter_main()?;
5564            root.htod(input)?
5565        };
5566        rank_inputs.push(root_input);
5567        for engine in &self.ranks[1..] {
5568            let peer_input = {
5569                let _main = engine.gpu.enter_main()?;
5570                let mut peer_input = engine.uninit(input.len())?;
5571                engine
5572                    .stream()
5573                    .memcpy_dtod(&rank_inputs[0], &mut peer_input)?;
5574                peer_input
5575            };
5576            rank_inputs.push(peer_input);
5577        }
5578
5579        let mut gate_shards = Vec::with_capacity(self.ranks.len());
5580        let mut up_shards = Vec::with_capacity(self.ranks.len());
5581        #[allow(clippy::needless_range_loop)]
5582        // allow: the explicit index loop keeps the offset arithmetic visible and aligned with the device-side indexing
5583        for rank in 0..self.ranks.len() {
5584            gate_shards.push(run_resident_bank_expert_device(
5585                &self.ranks[rank],
5586                &bank.gate[rank],
5587                expert,
5588                &rank_inputs[rank],
5589                1,
5590            )?);
5591            up_shards.push(run_resident_bank_expert_device(
5592                &self.ranks[rank],
5593                &bank.up[rank],
5594                expert,
5595                &rank_inputs[rank],
5596                1,
5597            )?);
5598        }
5599
5600        // Preserve the established canonical activation program for the first native transport
5601        // milestone. The shards move to rank zero over P2P; only the scalar activation expression
5602        // executes on host. A later device-activation increment must earn its own exactness gate.
5603        let gate = self.gather_native_column_shards(&gate_shards, 1, local_out)?;
5604        let up = self.gather_native_column_shards(&up_shards, 1, local_out)?;
5605        let activated = gate
5606            .iter()
5607            .zip(&up)
5608            .map(|(&gate, &up)| gate / (1.0 + (-gate).exp()) * up)
5609            .collect::<Vec<_>>();
5610        debug_assert_eq!(activated.len(), bank.expert_width);
5611
5612        let root_activated = {
5613            let root = &self.ranks[0];
5614            let _main = root.gpu.enter_main()?;
5615            root.htod(&activated)?
5616        };
5617        let mut rank_activated = Vec::with_capacity(self.ranks.len());
5618        for (rank, engine) in self.ranks.iter().enumerate() {
5619            let start = rank * local_out;
5620            let source = root_activated.slice(start..start + local_out);
5621            let local = {
5622                let _main = engine.gpu.enter_main()?;
5623                let mut local = engine.uninit(local_out)?;
5624                engine.stream().memcpy_dtod(&source, &mut local)?;
5625                local
5626            };
5627            rank_activated.push(local);
5628        }
5629
5630        let out_features = bank
5631            .down
5632            .first()
5633            .ok_or("native TP down bank has no ranks")?
5634            .out_features;
5635        let mut reduced = {
5636            let root = &self.ranks[0];
5637            let _main = root.gpu.enter_main()?;
5638            root.htod(&vec![0.0f32; out_features])?
5639        };
5640        let mut remote_partial_keepalive = Vec::new();
5641        #[allow(clippy::needless_range_loop)]
5642        // allow: the explicit index loop keeps the offset arithmetic visible and aligned with the device-side indexing
5643        for rank in 0..self.ranks.len() {
5644            let down = &bank.down[rank];
5645            let blocks = down
5646                .k_blocks
5647                .ok_or("native TP row bank is not packed in checkpoint-block order")?;
5648            if blocks * FP8_BLOCK != local_out {
5649                return Err(format!(
5650                    "native TP rank {rank} has {blocks} blocks but local activation width is \
5651                     {local_out}"
5652                )
5653                .into());
5654            }
5655            for block in 0..blocks {
5656                let start = block * FP8_BLOCK;
5657                let input_block = rank_activated[rank].slice(start..start + FP8_BLOCK);
5658                let partial = run_resident_bank_expert_block_device(
5659                    &self.ranks[rank],
5660                    down,
5661                    expert,
5662                    block,
5663                    &input_block,
5664                )?;
5665                let root_partial = if rank == 0 {
5666                    partial
5667                } else {
5668                    let root = &self.ranks[0];
5669                    let _main = root.gpu.enter_main()?;
5670                    let mut peer_partial = root.uninit(out_features)?;
5671                    root.stream().memcpy_dtod(&partial, &mut peer_partial)?;
5672                    remote_partial_keepalive.push(partial);
5673                    peer_partial
5674                };
5675                let next = {
5676                    let root = &self.ranks[0];
5677                    let _main = root.gpu.enter_main()?;
5678                    let mut next = root.uninit(out_features)?;
5679                    root.add(&reduced, &root_partial, &mut next, out_features)?;
5680                    next
5681                };
5682                reduced = next;
5683            }
5684        }
5685        let output = {
5686            let root = &self.ranks[0];
5687            let _main = root.gpu.enter_main()?;
5688            root.dtoh(&reduced)?
5689        };
5690        drop(remote_partial_keepalive);
5691        Ok(output)
5692    }
5693
5694    /// Gather token-major rank-local columns into one canonical root-device matrix.
5695    pub fn gather_native_column_shards_device(
5696        &self,
5697        shards: &[CudaSlice<f32>],
5698        tokens: usize,
5699        local_out: usize,
5700    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
5701        let shard_len = tokens
5702            .checked_mul(local_out)
5703            .ok_or("native TP gather shard size overflow")?;
5704        if shards.len() != self.ranks.len() || shards.iter().any(|shard| shard.len() != shard_len) {
5705            return Err("native TP gather shard geometry mismatch".into());
5706        }
5707        // PRODUCER FENCE (2026-08-20 flake fix): the root stream peer-reads shards produced on
5708        // the other ranks' streams; without fencing those producers the copy can read a partial
5709        // kernel output.
5710        for engine in &self.ranks[1..] {
5711            let _main = engine.gpu.enter_main()?;
5712            engine.stream().synchronize()?;
5713        }
5714        let root = &self.ranks[0];
5715        let _main = root.gpu.enter_main()?;
5716        let global_out = shards
5717            .len()
5718            .checked_mul(local_out)
5719            .ok_or("native TP gather output width overflow")?;
5720        let gathered_len = tokens
5721            .checked_mul(global_out)
5722            .ok_or("native TP gather output size overflow")?;
5723        let mut gathered = root.uninit(gathered_len)?;
5724        if self.bulk_p2p {
5725            root.place_rows_strided(&shards[0], &mut gathered, local_out, tokens, global_out, 0)?;
5726            if shards.len() > 1 {
5727                let mut staging = root.uninit(shard_len)?;
5728                for (rank, shard) in shards.iter().enumerate().skip(1) {
5729                    root.stream().memcpy_dtod(shard, &mut staging)?;
5730                    root.place_rows_strided(
5731                        &staging,
5732                        &mut gathered,
5733                        local_out,
5734                        tokens,
5735                        global_out,
5736                        rank * local_out,
5737                    )?;
5738                }
5739            }
5740        } else {
5741            for token in 0..tokens {
5742                for (rank, shard) in shards.iter().enumerate() {
5743                    let source = shard.slice(token * local_out..(token + 1) * local_out);
5744                    let start = token * global_out + rank * local_out;
5745                    let mut destination = gathered.slice_mut(start..start + local_out);
5746                    root.stream().memcpy_dtod(&source, &mut destination)?;
5747                }
5748            }
5749        }
5750        Ok(gathered)
5751    }
5752
5753    pub fn gather_native_column_shards(
5754        &self,
5755        shards: &[CudaSlice<f32>],
5756        tokens: usize,
5757        local_out: usize,
5758    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
5759        let gathered = self.gather_native_column_shards_device(shards, tokens, local_out)?;
5760        let root = &self.ranks[0];
5761        let _main = root.gpu.enter_main()?;
5762        root.dtoh(&gathered)
5763    }
5764
5765    pub(crate) fn decode_v2_workspace(&self) -> &std::sync::Mutex<Vec<StepTpDecodeV2Ws>> {
5766        &self.decode_v2
5767    }
5768
5769    /// Build the v2 decode-attention workspace for this layer's geometry on first use, or
5770    /// return the index of the matching one. Attention geometry varies across the trunk
5771    /// (per-layer query-head counts), so workspaces are keyed by their geometry pins — a
5772    /// handful exist per model, never one per layer.
5773    ///
5774    /// Refuses non-F32-resident projections: the v2 driver's bit-exactness claim against v1
5775    /// holds per residency class, and only the mirror class has no per-call weight expansion
5776    /// to hide allocation churn behind.
5777    #[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
5778    pub(crate) fn decode_v2_ensure(
5779        &self,
5780        e: &Engine,
5781        q_m: &ResidentBf16ColumnParallel,
5782        k_m: &ResidentBf16ColumnParallel,
5783        v_m: &ResidentBf16ColumnParallel,
5784        o_m: &ResidentStepBf16RowParallel,
5785        heads: usize,
5786    ) -> Result<usize, Box<dyn std::error::Error>> {
5787        if self.ranks.len() > 1 && !self.native_p2p {
5788            return Err("step TP decode v2 requires native P2P ranks".into());
5789        }
5790        let ranks = self.ranks.len();
5791        // Residency contract: the canonical-chunk (non-fused) program needs the F32 mirror;
5792        // the fused-kernel door also reads raw checkpoint bf16 directly (halving the weight
5793        // traffic), so bf16 residency is accepted when that door is on.
5794        let fused_door = step_tp_qkv_fused_enabled()?;
5795        let arm_ok = |weight: &ResidentBf16Weight| match weight {
5796            ResidentBf16Weight::F32(_) => true,
5797            ResidentBf16Weight::Bf16(_) => fused_door,
5798        };
5799        for matrix in [q_m, k_m, v_m] {
5800            validate_resident_bf16_ranks(&self.ranks, &matrix.ranks)?;
5801            if matrix.out_features % ranks != 0 || matrix.in_features != q_m.in_features {
5802                return Err("step TP decode v2 QKV geometry mismatch".into());
5803            }
5804            for rank in &matrix.ranks {
5805                if !arm_ok(&rank.weight) {
5806                    return Err("step TP decode v2 requires MEMRA_STEP_TP_F32_MIRROR=1 or \
5807                                MEMRA_STEP_TP_QKV_FUSED=1 (bf16-resident fused kernels)"
5808                        .into());
5809                }
5810            }
5811        }
5812        validate_step_bf16_row_residency(&self.ranks, o_m)?;
5813        for blocks in &o_m.ranks {
5814            for block in blocks {
5815                if !arm_ok(&block.weight) {
5816                    return Err("step TP decode v2 requires MEMRA_STEP_TP_F32_MIRROR=1 or \
5817                                MEMRA_STEP_TP_QKV_FUSED=1 (bf16-resident fused kernels)"
5818                        .into());
5819                }
5820            }
5821        }
5822        if v_m.out_features != k_m.out_features
5823            || o_m.in_features != q_m.out_features
5824            || heads == 0
5825            || heads % ranks != 0
5826        {
5827            return Err("step TP decode v2 K/V/O geometry mismatch".into());
5828        }
5829        let local_q_dim = q_m.out_features / ranks;
5830        let local_kv_dim = k_m.out_features / ranks;
5831        let o_out = o_m.out_features;
5832        let o_block_cols = o_m.canonical_chunk_cols;
5833        let blocks_per_rank = o_m.ranks.first().map(Vec::len).unwrap_or(0);
5834        if blocks_per_rank == 0
5835            || o_m
5836                .ranks
5837                .iter()
5838                .any(|blocks| blocks.len() != blocks_per_rank)
5839            || blocks_per_rank * o_block_cols * ranks != o_m.in_features
5840        {
5841            return Err("step TP decode v2 O canonical block grid mismatch".into());
5842        }
5843
5844        let mut guard = self
5845            .decode_v2
5846            .lock()
5847            .map_err(|_| "step TP decode v2 workspace lock is poisoned")?;
5848        if let Some(index) = guard.iter().position(|ws| {
5849            ws.local_q_dim == local_q_dim
5850                && ws.local_kv_dim == local_kv_dim
5851                && ws.heads == heads
5852                && ws.o_out == o_out
5853                && ws.o_block_cols == o_block_cols
5854                && ws.blocks_per_rank == blocks_per_rank
5855                && ws.e_device == e.ctx().ordinal()
5856                && ws.q.len() == ranks
5857        }) {
5858            return Ok(index);
5859        }
5860
5861        let mut q_raw = Vec::with_capacity(ranks);
5862        let mut k_raw = Vec::with_capacity(ranks);
5863        let mut v_raw = Vec::with_capacity(ranks);
5864        let mut q = Vec::with_capacity(ranks);
5865        let mut k = Vec::with_capacity(ranks);
5866        let mut pos = Vec::with_capacity(ranks);
5867        let mut gate = Vec::with_capacity(ranks);
5868        let mut attn_out = Vec::with_capacity(ranks);
5869        let mut gated = Vec::with_capacity(ranks);
5870        let mut fuse_ctr = Vec::with_capacity(ranks);
5871        let mut o_partials = Vec::with_capacity(ranks);
5872        let mut ev_rank = Vec::with_capacity(ranks);
5873        let direct_join = oproj_direct_on();
5874        for (rank, engine) in self.ranks.iter().enumerate() {
5875            let _main = engine.gpu.enter_main()?;
5876            q_raw.push(engine.uninit(local_q_dim)?);
5877            k_raw.push(engine.uninit(local_kv_dim)?);
5878            v_raw.push(engine.uninit(local_kv_dim)?);
5879            q.push(engine.uninit(local_q_dim)?);
5880            k.push(engine.uninit(local_kv_dim)?);
5881            pos.push(engine.htod_i32(&[0])?);
5882            fuse_ctr.push(engine.stream().clone_htod(&[0u32])?);
5883            gate.push(engine.uninit(heads / ranks)?);
5884            attn_out.push(engine.uninit(local_q_dim)?);
5885            gated.push(engine.uninit(local_q_dim)?);
5886            let mut rank_partials = Vec::with_capacity(blocks_per_rank);
5887            for _ in 0..blocks_per_rank {
5888                // Direct join: peer ranks' partials live on ROOT so the b4 kernel's
5889                // stores land there over P2P (UVA) and no pull copy is needed.
5890                if direct_join && rank != 0 {
5891                    let root = &self.ranks[0];
5892                    let _root_main = root.gpu.enter_main()?;
5893                    rank_partials.push(root.uninit(o_out)?);
5894                } else {
5895                    rank_partials.push(engine.uninit(o_out)?);
5896                }
5897            }
5898            o_partials.push(rank_partials);
5899            ev_rank.push(engine.ctx().new_event(None)?);
5900        }
5901        use cudarc::driver::DevicePtr;
5902        let mut raw_o_partials = Vec::with_capacity(ranks);
5903        let mut raw_k = Vec::with_capacity(ranks);
5904        let mut raw_v_raw = Vec::with_capacity(ranks);
5905        for rank in 0..ranks {
5906            let engine = &self.ranks[rank];
5907            {
5908                let _main = engine.gpu.enter_main()?;
5909                let stream = engine.stream();
5910                let (k_ptr, _k_guard) = k[rank].device_ptr(&stream);
5911                let (v_ptr, _v_guard) = v_raw[rank].device_ptr(&stream);
5912                raw_k.push(k_ptr as u64);
5913                raw_v_raw.push(v_ptr as u64);
5914            }
5915            let partial_engine = if direct_join && rank != 0 {
5916                &self.ranks[0]
5917            } else {
5918                engine
5919            };
5920            let _main = partial_engine.gpu.enter_main()?;
5921            let stream = partial_engine.stream();
5922            let mut rank_raw = Vec::with_capacity(blocks_per_rank);
5923            for partial in &o_partials[rank] {
5924                let (ptr, _guard) = partial.device_ptr(&stream);
5925                rank_raw.push(ptr as u64);
5926            }
5927            raw_o_partials.push(rank_raw);
5928        }
5929        let root = &self.ranks[0];
5930        let (peer_partial, reduce_a, reduce_b, zeros, k_shadow, v_shadow, ev_refresh, ev_oproj) = {
5931            let _main = root.gpu.enter_main()?;
5932            (
5933                root.uninit(o_out)?,
5934                root.uninit(o_out)?,
5935                root.uninit(o_out)?,
5936                root.htod(&vec![0.0f32; o_out])?,
5937                root.uninit(ranks * local_kv_dim)?,
5938                root.uninit(ranks * local_kv_dim)?,
5939                root.ctx().new_event(None)?,
5940                root.ctx().new_event(None)?,
5941            )
5942        };
5943        let (raw_peer_partial, raw_k_shadow, raw_v_shadow) = {
5944            let _main = root.gpu.enter_main()?;
5945            let stream = root.stream();
5946            let (peer, _peer_guard) = peer_partial.device_ptr(&stream);
5947            let (k, _k_guard) = k_shadow.device_ptr(&stream);
5948            let (v, _v_guard) = v_shadow.device_ptr(&stream);
5949            (peer as u64, k as u64, v as u64)
5950        };
5951        let (gate_e, ev_entry) = {
5952            let _main = e.gpu.enter_main()?;
5953            (e.uninit(heads)?, e.ctx().new_event(None)?)
5954        };
5955        let raw_attn_in = Vec::new();
5956        let raw_pos = Vec::new();
5957        guard.push(StepTpDecodeV2Ws {
5958            tcol_q: Vec::new(),
5959            tcol_k: Vec::new(),
5960            tcol_v: Vec::new(),
5961            tcol_g: Vec::new(),
5962            tcol_in: Vec::new(),
5963            tcol_cap: 0,
5964            w8_aq: Vec::new(),
5965            w8_ad: Vec::new(),
5966            w8_in: 0,
5967            w8o_aq: Vec::new(),
5968            w8o_ad: Vec::new(),
5969            w8o_in: 0,
5970            w8t_aq: Vec::new(),
5971            w8t_ad: Vec::new(),
5972            w8t_in: 0,
5973            w8t_oaq: Vec::new(),
5974            w8t_oad: Vec::new(),
5975            w8t_oin: 0,
5976            w8t_cap: 0,
5977            fa2_q: Vec::new(),
5978            fa2_gate: Vec::new(),
5979            fa2_gated: Vec::new(),
5980            fa2_cap: 0,
5981            rope_k_t: Vec::new(),
5982            rope_ctr_t: Vec::new(),
5983            rope_pos_t: Vec::new(),
5984            rows_tabs: Vec::new(),
5985            rows_tab_t: Vec::new(),
5986            rows_tab_shadow: Vec::new(),
5987            tcol_gated: Vec::new(),
5988            tcol_opart: Vec::new(),
5989            tcol_opeer: None,
5990            tcol_omix: None,
5991            tcol_ocap: 0,
5992            q_raw,
5993            k_raw,
5994            v_raw,
5995            q,
5996            k,
5997            pos,
5998            fuse_ctr,
5999            gate,
6000            attn_out,
6001            gated,
6002            o_partials,
6003            raw_o_partials,
6004            raw_k,
6005            raw_v_raw,
6006            ev_rank,
6007            peer_partial,
6008            reduce_a,
6009            reduce_b,
6010            zeros,
6011            k_shadow,
6012            v_shadow,
6013            ev_refresh,
6014            ev_oproj,
6015            gate_e,
6016            attn_in: Vec::new(),
6017            h_stage: None,
6018            pos_stage: None,
6019            raw_h_stage: 0,
6020            raw_pos_stage: 0,
6021            raw_attn_in,
6022            raw_pos,
6023            raw_o_partial1: 0,
6024            raw_peer_partial,
6025            raw_k1: 0,
6026            raw_v1: 0,
6027            raw_k_shadow,
6028            raw_v_shadow,
6029            raw_mixed_stage_e: 0,
6030            raw_reduce_a: 0,
6031            raw_shadow_stage_e: (0, 0),
6032            ev_entry,
6033            e_device: e.ctx().ordinal(),
6034            local_q_dim,
6035            local_kv_dim,
6036            heads,
6037            o_out,
6038            o_block_cols,
6039            blocks_per_rank,
6040        });
6041        eprintln!(
6042            "[step-tp-decode-v2] workspace ranks={ranks} local_q={local_q_dim} \
6043             local_kv={local_kv_dim} heads={heads} o_blocks={blocks_per_rank}x{o_block_cols} \
6044             residency=persistent ordering=evented performance_claim=false"
6045        );
6046        Ok(guard.len() - 1)
6047    }
6048
6049    /// v2 phase 1: replicate the layer input, project QKV, norm, rope, and stage the gate —
6050    /// all into the persistent workspace, ordered by events instead of host syncs.
6051    ///
6052    /// The caller must have queued every producer of `h`, `pos_d`, and `gate_raw` on `e`'s
6053    /// stream BEFORE this call: `ev_entry` is recorded once here and every rank stream waits
6054    /// on it (the entry fence also guards workspace reuse across layers — any consumer of the
6055    /// previous layer's outputs was queued on `e`'s stream before this record).
6056    #[allow(clippy::too_many_arguments)]
6057    /// T-COLUMN verify precompute (spec MTP): stage T input rows to every rank and run the
6058    /// weight-amortized qkvg_tcol per rank into the ws slabs. Rope/norm/append stay per
6059    /// column in the unmodified t=1 program (defer_norm_rope contract). Bit-exact per
6060    /// column vs the t=1 kernel by construction.
6061    #[allow(clippy::too_many_arguments)]
6062    pub fn decode_v2_input_qkv_tcol(
6063        &self,
6064        ws_index: usize,
6065        e: &Engine,
6066        h_t: &CudaSlice<f32>,
6067        t: usize,
6068        q_m: &ResidentBf16ColumnParallel,
6069        k_m: &ResidentBf16ColumnParallel,
6070        v_m: &ResidentBf16ColumnParallel,
6071        gate_shards: Option<StepTpGateShards<'_>>,
6072    ) -> Result<(), Box<dyn std::error::Error>> {
6073        let ranks = self.ranks.len();
6074        let mut guard = self
6075            .decode_v2
6076            .lock()
6077            .map_err(|_| "step TP decode v2 workspace lock is poisoned")?;
6078        let ws = guard
6079            .get_mut(ws_index)
6080            .ok_or("step TP decode v2 workspace index out of range")?;
6081        let in_f = q_m.in_features;
6082        if h_t.len() < t * in_f || t == 0 || t > 32 {
6083            return Err("decode_v2_input_qkv_tcol geometry".into());
6084        }
6085        // Lazily arm the slabs to capacity.
6086        if ws.tcol_cap < t || ws.tcol_q.len() != ranks {
6087            ws.tcol_q.clear();
6088            ws.tcol_k.clear();
6089            ws.tcol_v.clear();
6090            ws.tcol_g.clear();
6091            ws.tcol_in.clear();
6092            for engine in &self.ranks {
6093                let _m = engine.gpu.enter_main()?;
6094                ws.tcol_q.push(engine.uninit(32 * ws.local_q_dim)?);
6095                ws.tcol_k.push(engine.uninit(32 * ws.local_kv_dim)?);
6096                ws.tcol_v.push(engine.uninit(32 * ws.local_kv_dim)?);
6097                ws.tcol_g
6098                    .push(engine.uninit(32 * (ws.heads / ranks).max(1))?);
6099                ws.tcol_in.push(engine.uninit(32 * in_f)?);
6100            }
6101            ws.tcol_cap = 32;
6102        }
6103        // Stage the T input rows on e, fence, per-rank pull + tcol launch.
6104        use cudarc::driver::DevicePtr;
6105        let raw_src = {
6106            let _main = e.gpu.enter_main()?;
6107            let stream = e.stream();
6108            let (p, _g) = h_t.device_ptr(&stream);
6109            ws.ev_entry.record(&stream)?;
6110            p
6111        };
6112        for rank in 0..ranks {
6113            let engine = &self.ranks[rank];
6114            let _main = engine.gpu.enter_main()?;
6115            engine.stream().wait(&ws.ev_entry)?;
6116            let raw_dst = {
6117                let stream = engine.stream();
6118                let (p, _g) = ws.tcol_in[rank].device_ptr(&stream);
6119                p
6120            };
6121            raw_copy_bytes(raw_dst, raw_src, t * in_f * 4, engine)?;
6122            let out_g = match &gate_shards {
6123                Some(_) => ws.heads / ranks,
6124                None => 0,
6125            };
6126            match (
6127                &q_m.ranks[rank].weight,
6128                &k_m.ranks[rank].weight,
6129                &v_m.ranks[rank].weight,
6130            ) {
6131                (
6132                    ResidentBf16Weight::Bf16(wq),
6133                    ResidentBf16Weight::Bf16(wk),
6134                    ResidentBf16Weight::Bf16(wv),
6135                ) => {
6136                    let wg = match &gate_shards {
6137                        Some(StepTpGateShards::Bf16(shards)) => &shards[rank],
6138                        Some(StepTpGateShards::F32(_)) => {
6139                            return Err(
6140                                "tcol verify: gate shard class does not match bf16 QKV".into()
6141                            );
6142                        }
6143                        None => wq,
6144                    };
6145                    let StepTpDecodeV2Ws {
6146                        tcol_q,
6147                        tcol_k,
6148                        tcol_v,
6149                        tcol_g,
6150                        tcol_in,
6151                        local_q_dim,
6152                        local_kv_dim,
6153                        w8t_aq,
6154                        w8t_ad,
6155                        w8t_in,
6156                        w8t_cap,
6157                        ..
6158                    } = &mut *ws;
6159                    // MEMRA_TCOL_REFKERN=1 (bisect): fill the slabs via the t=1 kernel per
6160                    // column — separates driver bugs from tcol-kernel bugs.
6161                    static REFK: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
6162                    let refk = *REFK
6163                        .get_or_init(|| std::env::var("MEMRA_TCOL_REFKERN").as_deref() == Ok("1"));
6164                    if refk {
6165                        let lq = *local_q_dim;
6166                        let lkv = *local_kv_dim;
6167                        let mut hrow = engine.uninit(in_f)?;
6168                        let mut qr = engine.uninit(lq)?;
6169                        let mut kr = engine.uninit(lkv)?;
6170                        let mut vr = engine.uninit(lkv)?;
6171                        let mut gr = engine.uninit(out_g.max(1))?;
6172                        for c in 0..t {
6173                            {
6174                                let mut dst = hrow.slice_mut(0..in_f);
6175                                engine.stream().memcpy_dtod(
6176                                    &tcol_in[rank].slice(c * in_f..(c + 1) * in_f),
6177                                    &mut dst,
6178                                )?;
6179                            }
6180                            engine.matvec_bf16_qkvg_into(
6181                                wq, wk, wv, wg, &hrow, &mut qr, &mut kr, &mut vr, &mut gr, in_f,
6182                                lq, lkv, out_g,
6183                            )?;
6184                            let stream = engine.stream();
6185                            {
6186                                let mut dst = tcol_q[rank].slice_mut(c * lq..(c + 1) * lq);
6187                                stream.memcpy_dtod(&qr.slice(0..lq), &mut dst)?;
6188                            }
6189                            {
6190                                let mut dst = tcol_k[rank].slice_mut(c * lkv..(c + 1) * lkv);
6191                                stream.memcpy_dtod(&kr.slice(0..lkv), &mut dst)?;
6192                            }
6193                            {
6194                                let mut dst = tcol_v[rank].slice_mut(c * lkv..(c + 1) * lkv);
6195                                stream.memcpy_dtod(&vr.slice(0..lkv), &mut dst)?;
6196                            }
6197                            if out_g > 0 {
6198                                let mut dst = tcol_g[rank].slice_mut(c * out_g..(c + 1) * out_g);
6199                                stream.memcpy_dtod(&gr.slice(0..out_g), &mut dst)?;
6200                            }
6201                        }
6202                    } else if crate::step_tp_w8_on()
6203                        && q_m.ranks[rank].q8.is_some()
6204                        && k_m.ranks[rank].q8.is_some()
6205                        && v_m.ranks[rank].q8.is_some()
6206                        && in_f.is_multiple_of(32)
6207                    {
6208                        // MEMRA_STEP_TP_W8 on the VERIFY walk. nsys put the bf16 tcol QKV at
6209                        // 12.3% of spec GPU time and the bf16 tcol o_proj at 24.8% — the door
6210                        // had only ever replaced the DECODE kernels, so 37% of the verify still
6211                        // streamed bf16 weights. One q8 launch over all t columns; the gate rows
6212                        // stay bf16 as on the decode side.
6213                        if *w8t_in != in_f || *w8t_cap < t || w8t_aq.len() != ranks {
6214                            w8t_aq.clear();
6215                            w8t_ad.clear();
6216                            for e_rank in &self.ranks {
6217                                let _m = e_rank.gpu.enter_main()?;
6218                                w8t_aq.push(e_rank.alloc_i8_uninit(32 * in_f)?);
6219                                w8t_ad.push(e_rank.alloc_uninit::<f32>(32 * (in_f / 32))?);
6220                            }
6221                            *w8t_in = in_f;
6222                            *w8t_cap = 32;
6223                        }
6224                        engine.quantize_q8_1_into(
6225                            &tcol_in[rank],
6226                            t,
6227                            in_f,
6228                            &mut w8t_aq[rank],
6229                            &mut w8t_ad[rank],
6230                        )?;
6231                        engine.qmatvec_q8_0_qkv_rp_t_into(
6232                            q_m.ranks[rank].q8.as_ref().unwrap(),
6233                            k_m.ranks[rank].q8.as_ref().unwrap(),
6234                            v_m.ranks[rank].q8.as_ref().unwrap(),
6235                            &w8t_aq[rank],
6236                            &w8t_ad[rank],
6237                            &mut tcol_q[rank],
6238                            &mut tcol_k[rank],
6239                            &mut tcol_v[rank],
6240                            in_f,
6241                            *local_q_dim,
6242                            *local_kv_dim,
6243                            t,
6244                        )?;
6245                        if out_g > 0 {
6246                            engine.matvec_bf16_rows_into(
6247                                wg,
6248                                &tcol_in[rank],
6249                                &mut tcol_g[rank],
6250                                in_f,
6251                                out_g,
6252                                t,
6253                            )?;
6254                        }
6255                    } else {
6256                        engine.matvec_bf16_qkvg_tcol_into(
6257                            wq,
6258                            wk,
6259                            wv,
6260                            wg,
6261                            &tcol_in[rank],
6262                            &mut tcol_q[rank],
6263                            &mut tcol_k[rank],
6264                            &mut tcol_v[rank],
6265                            &mut tcol_g[rank],
6266                            in_f,
6267                            *local_q_dim,
6268                            *local_kv_dim,
6269                            out_g,
6270                            t,
6271                        )?;
6272                    }
6273                }
6274                _ => return Err("tcol verify requires bf16-resident fused QKV".into()),
6275            }
6276        }
6277        Ok(())
6278    }
6279
6280    /// MEMRA_TCOL_OPROJ eligibility: the defer replaces exactly the o_fused direct-join
6281    /// finish (bf16 b4 kernel, 2 ranks, 4 canonical blocks) with the shadow gathers
6282    /// skipped — so it requires the same doors that arm dictate that finish shape.
6283    pub(crate) fn decode_v2_oproj_tcol_eligible(
6284        &self,
6285        ws: &StepTpDecodeV2Ws,
6286        o_m: &ResidentStepBf16RowParallel,
6287    ) -> bool {
6288        self.ranks.len() == 2
6289            && ws.blocks_per_rank == 4
6290            && step_tp_qkv_fused_enabled().unwrap_or(false)
6291            && no_local_shadow_on()
6292            && std::env::var("MEMRA_B4_X2").as_deref() != Ok("1")
6293            && o_m
6294                .ranks
6295                .iter()
6296                .flatten()
6297                .all(|block| matches!(block.weight, ResidentBf16Weight::Bf16(_)))
6298    }
6299
6300    /// MEMRA_SPEC_FA2 stash: copy this column's per-rank post-rope q and gate rows into
6301    /// the fa2 slabs (rank-stream ordered behind the rope/append that produced them), and
6302    /// give `e` the same anti-dependency wait the skipped finish provided (next column's
6303    /// h/pos re-staging must not overtake this column's rank pulls).
6304    pub(crate) fn decode_v2_stash_fa2(
6305        &self,
6306        ws: &mut StepTpDecodeV2Ws,
6307        e: &Engine,
6308        col: usize,
6309    ) -> Result<(), Box<dyn std::error::Error>> {
6310        let ranks = self.ranks.len();
6311        if col >= 32 {
6312            return Err("decode_v2_stash_fa2 column out of range".into());
6313        }
6314        let lq = ws.local_q_dim;
6315        let lg = (ws.heads / ranks).max(1);
6316        if ws.fa2_cap < 32 || ws.fa2_q.len() != ranks || ws.rows_tab_t.len() != ranks {
6317            ws.fa2_q.clear();
6318            ws.fa2_gate.clear();
6319            ws.fa2_gated.clear();
6320            ws.rope_k_t.clear();
6321            ws.rope_ctr_t.clear();
6322            ws.rope_pos_t.clear();
6323            ws.rows_tab_t.clear();
6324            for engine in &self.ranks {
6325                let _m = engine.gpu.enter_main()?;
6326                ws.fa2_q.push(engine.uninit(32 * lq)?);
6327                ws.fa2_gate.push(engine.uninit(32 * lg)?);
6328                ws.fa2_gated.push(engine.uninit(32 * lq)?);
6329                ws.rope_k_t.push(engine.uninit(32 * ws.local_kv_dim)?);
6330                ws.rope_ctr_t.push(engine.stream().clone_htod(&[0u32; 32])?);
6331                ws.rope_pos_t.push(engine.htod_i32(&[0i32; 32])?);
6332                ws.rows_tab_t
6333                    .push(engine.stream().clone_htod(&[0u64; 32 * 6])?);
6334            }
6335            ws.rows_tabs = (0..ranks).map(|_| Default::default()).collect();
6336            ws.fa2_cap = 32;
6337        }
6338        for rank in 0..ranks {
6339            let engine = &self.ranks[rank];
6340            let _main = engine.gpu.enter_main()?;
6341            {
6342                let mut dst = ws.fa2_q[rank].slice_mut(col * lq..(col + 1) * lq);
6343                engine
6344                    .stream()
6345                    .memcpy_dtod(&ws.q[rank].slice(0..lq), &mut dst)?;
6346            }
6347            {
6348                let mut dst = ws.fa2_gate[rank].slice_mut(col * lg..(col + 1) * lg);
6349                engine
6350                    .stream()
6351                    .memcpy_dtod(&ws.gate[rank].slice(0..lg), &mut dst)?;
6352            }
6353            ws.ev_rank[rank].record(&engine.stream())?;
6354        }
6355        {
6356            let _main = e.gpu.enter_main()?;
6357            for ev in ws.ev_rank.iter() {
6358                e.stream().wait(ev)?;
6359            }
6360        }
6361        Ok(())
6362    }
6363
6364    /// MEMRA_SPEC_FA2 join: after BOTH verify columns stashed (their appends landed in
6365    /// rank-stream order), run ONE fa_decode_dcw2 per rank over the shared KV stream —
6366    /// two query rows, per-row causal bounds, per-row combine+gate — then land the two
6367    /// gated rows in the o-tcol slabs and reuse the weight-amortized o_proj join.
6368    /// Returns the [2, o_out] `mixed` slab on `e`. The caller's precheck enforced the
6369    /// equal-partition guard (boundary rounds never arm the defer).
6370    #[allow(clippy::too_many_arguments)]
6371    #[allow(dead_code)] // allow: banked MEMRA_SPEC_FA2 arm; kept as the named seam its precheck twin documents
6372    pub(crate) fn decode_v2_spec_fa2_join(
6373        &self,
6374        ws_index: usize,
6375        e: &Engine,
6376        o_m: &ResidentStepBf16RowParallel,
6377        kv: &ResidentTpKvCache,
6378        head_dim: usize,
6379        window: usize,
6380        bucket_max: usize,
6381        scale: f32,
6382    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
6383        let ranks = self.ranks.len();
6384        // Engagement receipt: a vacuous gate (precheck never passing) must be visible.
6385        static ONCE: std::sync::Once = std::sync::Once::new();
6386        ONCE.call_once(|| eprintln!("[spec-fa2] joined T=2 attention ENGAGED"));
6387        {
6388            let mut guard = self
6389                .decode_v2
6390                .lock()
6391                .map_err(|_| "step TP decode v2 workspace lock is poisoned")?;
6392            let ws = guard
6393                .get_mut(ws_index)
6394                .ok_or("step TP decode v2 workspace index out of range")?;
6395            if ws.fa2_cap < 2 || ws.fa2_q.len() != ranks {
6396                return Err("spec fa2 join without stashed columns".into());
6397            }
6398            let lq = ws.local_q_dim;
6399            let local_heads = (ws.heads / ranks).max(1);
6400            let local_kv_heads = (ws.local_kv_dim / head_dim).max(1);
6401            let capacity = kv.physical_capacity();
6402            let (k_tok_bytes, v_tok_bytes) = (kv.k_tok_bytes(), kv.v_tok_bytes());
6403            // Arm the o-tcol slabs if the oproj door never ran this boot (same shapes).
6404            if ws.tcol_ocap < 2 || ws.tcol_gated.len() != ranks {
6405                ws.tcol_gated.clear();
6406                ws.tcol_opart.clear();
6407                for engine in &self.ranks {
6408                    let _m = engine.gpu.enter_main()?;
6409                    ws.tcol_gated.push(engine.uninit(32 * lq)?);
6410                    ws.tcol_opart.push(engine.uninit(32 * ws.o_out)?);
6411                }
6412                let root = &self.ranks[0];
6413                let _m = root.gpu.enter_main()?;
6414                ws.tcol_opeer = Some(root.uninit(32 * ws.o_out)?);
6415                ws.tcol_omix = Some(root.uninit(32 * ws.o_out)?);
6416                ws.tcol_ocap = 32;
6417            }
6418            for rank in 0..ranks {
6419                let engine = &self.ranks[rank];
6420                let _main = engine.gpu.enter_main()?;
6421                let rank_cache = kv
6422                    .rank(rank)
6423                    .ok_or("spec fa2 join lost its KV cache rank")?;
6424                let k_ring = engine.view_u8_range(rank_cache.k(), 0, capacity * k_tok_bytes);
6425                let v_ring = engine.view_u8_range(rank_cache.v(), 0, capacity * v_tok_bytes);
6426                {
6427                    let StepTpDecodeV2Ws {
6428                        fa2_q,
6429                        fa2_gate,
6430                        fa2_gated,
6431                        ..
6432                    } = &mut *ws;
6433                    engine.fa_decode_dcw2(
6434                        &fa2_q[rank],
6435                        &k_ring,
6436                        &v_ring,
6437                        &mut fa2_gated[rank],
6438                        head_dim,
6439                        local_heads,
6440                        local_kv_heads,
6441                        rank_cache.len_d(),
6442                        rank_cache.base_d(),
6443                        window,
6444                        bucket_max,
6445                        scale,
6446                        k_tok_bytes,
6447                        v_tok_bytes,
6448                        &fa2_gate[rank],
6449                    )?;
6450                }
6451                // Both gated rows are contiguous [2, lq] — exactly columns 0..2 of the
6452                // o-tcol slab layout. One dtod, in rank-stream order behind the fa.
6453                let StepTpDecodeV2Ws {
6454                    fa2_gated,
6455                    tcol_gated,
6456                    ..
6457                } = &mut *ws;
6458                let mut dst = tcol_gated[rank].slice_mut(0..2 * lq);
6459                engine
6460                    .stream()
6461                    .memcpy_dtod(&fa2_gated[rank].slice(0..2 * lq), &mut dst)?;
6462            }
6463        }
6464        self.decode_v2_oproj_tcol(ws_index, e, o_m, 2)
6465    }
6466
6467    /// FULL T-ROW ATTENTION PASS over per-row session tables (batched serving): reads
6468    /// the tcol raw-projection slabs, runs ONE rope/append rows launch + ONE fa rows
6469    /// launch + ONE combine per rank (gate straight from the tcol gate slab), then the
6470    /// o_proj tcol join — the whole per-row attention loop in 3 launches/rank/layer.
6471    /// Per-(row, head) programs are the t=1 kernels verbatim; each row appends to and
6472    /// attends its OWN session. `session_parts[rank][row]` = {k_plane, v_plane, len_ptr,
6473    /// base_ptr}; `tab_keys[rank]` keys the per-rank combined-table cache (caller folds
6474    /// layer + session-set + base-arming into it); `stage_pos` stages the position slab
6475    /// (positions are constant across layers within a tick — stage on the first layer).
6476    #[allow(clippy::too_many_arguments)]
6477    pub(crate) fn decode_v2_rope_fa_rows(
6478        &self,
6479        ws_index: usize,
6480        e: &Engine,
6481        o_m: &ResidentStepBf16RowParallel,
6482        session_parts: &[Vec<[u64; 4]>],
6483        tab_keys: &[u64],
6484        positions: &[i32],
6485        stage_pos: bool,
6486        same_session: bool,
6487        q_norms: &[CudaSlice<f32>],
6488        k_norms: &[CudaSlice<f32>],
6489        rope_freqs: &[Option<&crate::CudaSlice<f32>>],
6490        t: usize,
6491        head_dim: usize,
6492        n_rot: usize,
6493        window: usize,
6494        max_ns: usize,
6495        scale: f32,
6496        k_tok_bytes: usize,
6497        v_tok_bytes: usize,
6498        eps: f32,
6499        rope_base: f32,
6500    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
6501        use cudarc::driver::DevicePtr;
6502        let ranks = self.ranks.len();
6503        if session_parts.len() != ranks || tab_keys.len() != ranks || positions.len() < t {
6504            return Err("rope fa rows geometry".into());
6505        }
6506        {
6507            let mut guard = self
6508                .decode_v2
6509                .lock()
6510                .map_err(|_| "step TP decode v2 workspace lock is poisoned")?;
6511            let ws = guard
6512                .get_mut(ws_index)
6513                .ok_or("step TP decode v2 workspace index out of range")?;
6514            if ws.tcol_cap < t || ws.tcol_q.len() != ranks {
6515                return Err("rope fa rows without tcol slabs".into());
6516            }
6517            let lq = ws.local_q_dim;
6518            let lkv = ws.local_kv_dim;
6519            let lg = (ws.heads / ranks).max(1);
6520            let local_heads = (ws.heads / ranks).max(1);
6521            let local_kv_heads = (lkv / head_dim).max(1);
6522            // Arm the fa2/rope slabs (shared with the stash path).
6523            if ws.fa2_cap < 32 || ws.fa2_q.len() != ranks || ws.rows_tab_t.len() != ranks {
6524                ws.fa2_q.clear();
6525                ws.fa2_gate.clear();
6526                ws.fa2_gated.clear();
6527                ws.rope_k_t.clear();
6528                ws.rope_ctr_t.clear();
6529                ws.rope_pos_t.clear();
6530                ws.rows_tab_t.clear();
6531                for engine in &self.ranks {
6532                    let _m = engine.gpu.enter_main()?;
6533                    ws.fa2_q.push(engine.uninit(32 * lq)?);
6534                    ws.fa2_gate.push(engine.uninit(32 * lg)?);
6535                    ws.fa2_gated.push(engine.uninit(32 * lq)?);
6536                    ws.rope_k_t.push(engine.uninit(32 * lkv)?);
6537                    ws.rope_ctr_t.push(engine.stream().clone_htod(&[0u32; 32])?);
6538                    ws.rope_pos_t.push(engine.htod_i32(&[0i32; 32])?);
6539                    ws.rows_tab_t
6540                        .push(engine.stream().clone_htod(&[0u64; 32 * 6])?);
6541                }
6542                ws.rows_tabs = (0..ranks).map(|_| Default::default()).collect();
6543                ws.fa2_cap = 32;
6544            }
6545            if ws.tcol_ocap < t || ws.tcol_gated.len() != ranks {
6546                ws.tcol_gated.clear();
6547                ws.tcol_opart.clear();
6548                for engine in &self.ranks {
6549                    let _m = engine.gpu.enter_main()?;
6550                    ws.tcol_gated.push(engine.uninit(32 * lq)?);
6551                    ws.tcol_opart.push(engine.uninit(32 * ws.o_out)?);
6552                }
6553                let root = &self.ranks[0];
6554                let _m = root.gpu.enter_main()?;
6555                ws.tcol_opeer = Some(root.uninit(32 * ws.o_out)?);
6556                ws.tcol_omix = Some(root.uninit(32 * ws.o_out)?);
6557                ws.tcol_ocap = 32;
6558            }
6559            for rank in 0..ranks {
6560                let engine = &self.ranks[rank];
6561                let _main = engine.gpu.enter_main()?;
6562                if stage_pos {
6563                    let host: Vec<i32> = positions[..t].to_vec();
6564                    let mut view = ws.rope_pos_t[rank].slice_mut(0..t);
6565                    engine.stream().memcpy_htod(&host, &mut view)?;
6566                }
6567                // Combined 6-word table {k, v, len, base, ctr, back}; ctr = this rank's
6568                // per-row counter slab. Built from the pointers the CALLER just read off
6569                // the live distributed cache, and RESTAGED into a persistent slab before
6570                // every launch (MEMRA_ROWS_TAB_RESTAGE, default ON).
6571                //
6572                // The `rows_tabs` memo this replaces was keyed by a hash of
6573                // (k pointer, base pointer, layer, t) but the table it handed back ALSO
6574                // carried the V and LEN pointers, and nothing invalidated it when a
6575                // session's KV cache was dropped. A later session whose K buffer landed on
6576                // a recycled address therefore hit a dead entry, and
6577                // `qk_norm_rope_append_inc_dcw_rows` WROTE this session's K/V rows through
6578                // the freed V/len pointers it still held while `fa_decode_dcw_rows` read
6579                // them back: a whole non-finite row when the freed pages were re-mapped,
6580                // CUDA_ERROR_ILLEGAL_ADDRESS when they were not. The row-table twin in
6581                // `step35_verify_fa_rows_join` was cured of exactly this in 8c8397e0b2
6582                // ("a process-lifetime map cannot prove allocation generation", Hermes
6583                // `11339f5cd3c132a3`); this fused rope+append+fa path was left out of it,
6584                // and MEMRA_FUSE_ROPE_APPEND=1 makes it the arm that actually runs.
6585                let ctr_base = {
6586                    let s = engine.stream();
6587                    let (p, _g) = ws.rope_ctr_t[rank].device_ptr(&s);
6588                    p
6589                };
6590                let host = rows_tab_host(&session_parts[rank], ctr_base, same_session, t);
6591                // STALE-HIT RECEIPT (MEMRA_ROWS_TAB_STALE_SCAN=1, default OFF): replay the
6592                // retired key against the contents we are about to stage. `engaged` proves
6593                // this path executes at all; `STALE` proves the retired memo would have
6594                // handed a live launch another allocation's pointers, and names which word
6595                // moved. Diagnostic only: it never feeds a kernel.
6596                if rows_tab_stale_scan() {
6597                    if ws.rows_tab_shadow.len() != ranks {
6598                        ws.rows_tab_shadow = (0..ranks).map(|_| Default::default()).collect();
6599                    }
6600                    let n = ROWS_TAB_ENGAGED.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
6601                    if let Some(prev) = ws.rows_tab_shadow[rank].get(&tab_keys[rank])
6602                        && prev != &host
6603                    {
6604                        let words = ["k", "v", "len", "base", "ctr", "back"];
6605                        let moved: Vec<String> = (0..host.len())
6606                            .filter(|&i| prev.get(i) != Some(&host[i]))
6607                            .map(|i| format!("{}[row{}]", words[i % 6], i / 6))
6608                            .collect();
6609                        let stale =
6610                            ROWS_TAB_STALE.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
6611                        eprintln!(
6612                            "[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",
6613                            tab_keys[rank],
6614                            moved.join(",")
6615                        );
6616                    }
6617                    ws.rows_tab_shadow[rank].insert(tab_keys[rank], host.clone());
6618                }
6619                let legacy_memo = !rows_tab_restage_on();
6620                if legacy_memo && !ws.rows_tabs[rank].contains_key(&tab_keys[rank]) {
6621                    let tab = engine.stream().clone_htod(&host)?;
6622                    ws.rows_tabs[rank].insert(tab_keys[rank], tab);
6623                }
6624                if !legacy_memo {
6625                    let mut view = ws.rows_tab_t[rank].slice_mut(0..t * 6);
6626                    engine.stream().memcpy_htod(&host, &mut view)?;
6627                }
6628                let StepTpDecodeV2Ws {
6629                    tcol_q,
6630                    tcol_k,
6631                    tcol_v,
6632                    tcol_g,
6633                    fa2_q,
6634                    fa2_gated,
6635                    rope_k_t,
6636                    rope_pos_t,
6637                    rows_tabs,
6638                    rows_tab_t,
6639                    ..
6640                } = &mut *ws;
6641                let tab = if legacy_memo {
6642                    rows_tabs[rank]
6643                        .get(&tab_keys[rank])
6644                        .ok_or("rows tab memo lost its entry")?
6645                } else {
6646                    &rows_tab_t[rank]
6647                };
6648                engine.qk_norm_rope_append_inc_dcw_rows(
6649                    &tcol_q[rank],
6650                    &tcol_k[rank],
6651                    &tcol_v[rank],
6652                    &q_norms[rank],
6653                    &k_norms[rank],
6654                    &mut fa2_q[rank],
6655                    &mut rope_k_t[rank],
6656                    tab,
6657                    &rope_pos_t[rank],
6658                    same_session,
6659                    t,
6660                    lkv,
6661                    lkv,
6662                    k_tok_bytes,
6663                    v_tok_bytes,
6664                    head_dim,
6665                    n_rot,
6666                    local_heads,
6667                    local_kv_heads,
6668                    eps,
6669                    rope_base,
6670                    1.0,
6671                    rope_freqs[rank],
6672                )?;
6673                engine.fa_decode_dcw_rows(
6674                    &fa2_q[rank],
6675                    tab,
6676                    &mut fa2_gated[rank],
6677                    t,
6678                    head_dim,
6679                    local_heads,
6680                    local_kv_heads,
6681                    window,
6682                    max_ns,
6683                    scale,
6684                    k_tok_bytes,
6685                    v_tok_bytes,
6686                    &tcol_g[rank],
6687                )?;
6688                let StepTpDecodeV2Ws {
6689                    fa2_gated,
6690                    tcol_gated,
6691                    ..
6692                } = &mut *ws;
6693                let mut dst = tcol_gated[rank].slice_mut(0..t * lq);
6694                engine
6695                    .stream()
6696                    .memcpy_dtod(&fa2_gated[rank].slice(0..t * lq), &mut dst)?;
6697            }
6698        }
6699        self.decode_v2_oproj_tcol(ws_index, e, o_m, t)
6700    }
6701
6702    /// T-ROW fa join over per-row session tables (the per-session distributed-KV
6703    /// primitive): after all t rows stashed q+gate (their appends landed in rank-stream
6704    /// order), ONE fa_decode_dcw_rows per rank walks every row's own ring with its own
6705    /// geometry — bit-identical per row to its per-row launch — then the o_proj tcol
6706    /// join lands the [t, o_out] `mixed` slab on `e`. `tabs[rank]` is the pre-staged
6707    /// device table on that rank.
6708    #[allow(clippy::too_many_arguments)]
6709    pub(crate) fn decode_v2_fa_rows_join(
6710        &self,
6711        ws_index: usize,
6712        e: &Engine,
6713        o_m: &ResidentStepBf16RowParallel,
6714        tabs: &[&crate::CudaSlice<u64>],
6715        t: usize,
6716        head_dim: usize,
6717        window: usize,
6718        max_ns: usize,
6719        scale: f32,
6720        k_tok_bytes: usize,
6721        v_tok_bytes: usize,
6722    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
6723        let ranks = self.ranks.len();
6724        if tabs.len() != ranks {
6725            return Err("fa rows join needs one table per rank".into());
6726        }
6727        {
6728            let mut guard = self
6729                .decode_v2
6730                .lock()
6731                .map_err(|_| "step TP decode v2 workspace lock is poisoned")?;
6732            let ws = guard
6733                .get_mut(ws_index)
6734                .ok_or("step TP decode v2 workspace index out of range")?;
6735            if ws.fa2_cap < t || ws.fa2_q.len() != ranks {
6736                return Err("fa rows join without stashed rows".into());
6737            }
6738            let lq = ws.local_q_dim;
6739            let local_heads = (ws.heads / ranks).max(1);
6740            let local_kv_heads = (ws.local_kv_dim / head_dim).max(1);
6741            if ws.tcol_ocap < t || ws.tcol_gated.len() != ranks {
6742                ws.tcol_gated.clear();
6743                ws.tcol_opart.clear();
6744                for engine in &self.ranks {
6745                    let _m = engine.gpu.enter_main()?;
6746                    ws.tcol_gated.push(engine.uninit(32 * lq)?);
6747                    ws.tcol_opart.push(engine.uninit(32 * ws.o_out)?);
6748                }
6749                let root = &self.ranks[0];
6750                let _m = root.gpu.enter_main()?;
6751                ws.tcol_opeer = Some(root.uninit(32 * ws.o_out)?);
6752                ws.tcol_omix = Some(root.uninit(32 * ws.o_out)?);
6753                ws.tcol_ocap = 32;
6754            }
6755            for rank in 0..ranks {
6756                let engine = &self.ranks[rank];
6757                let _main = engine.gpu.enter_main()?;
6758                {
6759                    let StepTpDecodeV2Ws {
6760                        fa2_q,
6761                        fa2_gate,
6762                        fa2_gated,
6763                        ..
6764                    } = &mut *ws;
6765                    engine.fa_decode_dcw_rows(
6766                        &fa2_q[rank],
6767                        tabs[rank],
6768                        &mut fa2_gated[rank],
6769                        t,
6770                        head_dim,
6771                        local_heads,
6772                        local_kv_heads,
6773                        window,
6774                        max_ns,
6775                        scale,
6776                        k_tok_bytes,
6777                        v_tok_bytes,
6778                        &fa2_gate[rank],
6779                    )?;
6780                }
6781                let StepTpDecodeV2Ws {
6782                    fa2_gated,
6783                    tcol_gated,
6784                    ..
6785                } = &mut *ws;
6786                let mut dst = tcol_gated[rank].slice_mut(0..t * lq);
6787                engine
6788                    .stream()
6789                    .memcpy_dtod(&fa2_gated[rank].slice(0..t * lq), &mut dst)?;
6790            }
6791        }
6792        self.decode_v2_oproj_tcol(ws_index, e, o_m, t)
6793    }
6794
6795    /// MEMRA_TCOL_OPROJ stash: copy this column's per-rank `gated` rows into the o-tcol
6796    /// slabs (rank-stream ordered behind the attention kernels that produced them). The
6797    /// per-column finish choreography is skipped entirely; `decode_v2_oproj_tcol` joins
6798    /// every column afterwards.
6799    pub(crate) fn decode_v2_stash_gated(
6800        &self,
6801        ws: &mut StepTpDecodeV2Ws,
6802        e: &Engine,
6803        col: usize,
6804    ) -> Result<(), Box<dyn std::error::Error>> {
6805        let ranks = self.ranks.len();
6806        // 32, not 8: the slabs below have been 32 rows since the slab-width fix, and the walk now
6807        // runs chunks up to t=32 (the w=16 arm died here on a guard three widths staler than its
6808        // own allocation, 2026-08-27).
6809        if col >= 32 {
6810            return Err("decode_v2_stash_gated column out of range".into());
6811        }
6812        let lq = ws.local_q_dim;
6813        if ws.tcol_ocap == 0 || ws.tcol_gated.len() != ranks {
6814            ws.tcol_gated.clear();
6815            ws.tcol_opart.clear();
6816            for engine in &self.ranks {
6817                let _m = engine.gpu.enter_main()?;
6818                ws.tcol_gated.push(engine.uninit(32 * lq)?);
6819                ws.tcol_opart.push(engine.uninit(32 * ws.o_out)?);
6820            }
6821            let root = &self.ranks[0];
6822            let _m = root.gpu.enter_main()?;
6823            ws.tcol_opeer = Some(root.uninit(32 * ws.o_out)?);
6824            ws.tcol_omix = Some(root.uninit(32 * ws.o_out)?);
6825            ws.tcol_ocap = 32;
6826        }
6827        for rank in 0..ranks {
6828            let engine = &self.ranks[rank];
6829            let _main = engine.gpu.enter_main()?;
6830            let mut dst = ws.tcol_gated[rank].slice_mut(col * lq..(col + 1) * lq);
6831            engine
6832                .stream()
6833                .memcpy_dtod(&ws.gated[rank].slice(0..lq), &mut dst)?;
6834            // The skipped finish's e-wait was ALSO the anti-dependency guard: it ordered
6835            // e's NEXT column's h/pos re-staging behind this column's rank-side raw pulls.
6836            // Record each rank here and make e wait — same protection, no o_proj work.
6837            ws.ev_rank[rank].record(&engine.stream())?;
6838        }
6839        {
6840            let _main = e.gpu.enter_main()?;
6841            for ev in ws.ev_rank.iter() {
6842                e.stream().wait(ev)?;
6843            }
6844        }
6845        Ok(())
6846    }
6847
6848    /// MEMRA_TCOL_OPROJ join: one weight-amortized b4_tcol per rank over the stashed
6849    /// `gated` slabs (per-column FP order == the t=1 b4 kernel), one peer pull of rank1's
6850    /// partial slab, one elementwise slab add on the root (independent elements — each
6851    /// column's add is the exact direct-join `add(p0, p1)`), then the joined `mixed` slab
6852    /// lands on `e`. Returns [t, o_out] on the model engine.
6853    pub(crate) fn decode_v2_oproj_tcol(
6854        &self,
6855        ws_index: usize,
6856        e: &Engine,
6857        o_m: &ResidentStepBf16RowParallel,
6858        t: usize,
6859    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
6860        let ranks = self.ranks.len();
6861        let mut guard = self
6862            .decode_v2
6863            .lock()
6864            .map_err(|_| "step TP decode v2 workspace lock is poisoned")?;
6865        let ws = guard
6866            .get_mut(ws_index)
6867            .ok_or("step TP decode v2 workspace index out of range")?;
6868        if ranks != 2 || ws.blocks_per_rank != 4 || t == 0 || t > 32 || ws.tcol_ocap < t {
6869            return Err("decode_v2_oproj_tcol geometry".into());
6870        }
6871        for rank in 0..ranks {
6872            let engine = &self.ranks[rank];
6873            let _main = engine.gpu.enter_main()?;
6874            let mut weights = Vec::with_capacity(4);
6875            for block in 0..4 {
6876                let ResidentBf16Weight::Bf16(weight) = &o_m.ranks[rank][block].weight else {
6877                    return Err("tcol o_proj requires bf16-resident O blocks".into());
6878                };
6879                weights.push(weight);
6880            }
6881            {
6882                let StepTpDecodeV2Ws {
6883                    tcol_gated,
6884                    tcol_opart,
6885                    local_q_dim,
6886                    o_block_cols,
6887                    o_out,
6888                    w8t_oaq,
6889                    w8t_oad,
6890                    w8t_oin,
6891                    w8t_cap,
6892                    ..
6893                } = &mut *ws;
6894                // MEMRA_TCOL_OPROJ_REF=1 (bisect): fill the partial slab via the t=1 b4
6895                // kernel per column — separates choreography bugs from tcol-kernel bugs.
6896                static REFK: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
6897                let refk = *REFK
6898                    .get_or_init(|| std::env::var("MEMRA_TCOL_OPROJ_REF").as_deref() == Ok("1"));
6899                if refk {
6900                    let lq = *local_q_dim;
6901                    let mut xr = engine.uninit(lq)?;
6902                    let mut yr = engine.uninit(*o_out)?;
6903                    for c in 0..t {
6904                        {
6905                            let mut dst = xr.slice_mut(0..lq);
6906                            engine.stream().memcpy_dtod(
6907                                &tcol_gated[rank].slice(c * lq..(c + 1) * lq),
6908                                &mut dst,
6909                            )?;
6910                        }
6911                        engine.matvec_bf16_b4_into(
6912                            [weights[0], weights[1], weights[2], weights[3]],
6913                            &xr,
6914                            &mut yr,
6915                            *o_block_cols,
6916                            *o_out,
6917                        )?;
6918                        let mut dst = tcol_opart[rank].slice_mut(c * *o_out..(c + 1) * *o_out);
6919                        engine
6920                            .stream()
6921                            .memcpy_dtod(&yr.slice(0..*o_out), &mut dst)?;
6922                    }
6923                } else if crate::step_tp_w8_on()
6924                    && (0..4).all(|b| o_m.ranks[rank][b].q8.is_some())
6925                    && (4 * *o_block_cols) % 32 == 0
6926                {
6927                    // The verify walk's biggest single kernel: bf16 tcol o_proj was 24.8% of
6928                    // spec GPU time. Same planar q8_0 mirrors the decode arm uses, one launch
6929                    // over all t columns.
6930                    let in_f = 4 * *o_block_cols;
6931                    if *w8t_oin != in_f || *w8t_cap < t || w8t_oaq.len() != ranks {
6932                        w8t_oaq.clear();
6933                        w8t_oad.clear();
6934                        for e_rank in &self.ranks {
6935                            let _m = e_rank.gpu.enter_main()?;
6936                            w8t_oaq.push(e_rank.alloc_i8_uninit(32 * in_f)?);
6937                            w8t_oad.push(e_rank.alloc_uninit::<f32>(32 * (in_f / 32))?);
6938                        }
6939                        *w8t_oin = in_f;
6940                        *w8t_cap = (*w8t_cap).max(32);
6941                    }
6942                    engine.quantize_q8_1_into(
6943                        &tcol_gated[rank],
6944                        t,
6945                        in_f,
6946                        &mut w8t_oaq[rank],
6947                        &mut w8t_oad[rank],
6948                    )?;
6949                    engine.qmatvec_q8_0_b4_rp_t_into(
6950                        [
6951                            o_m.ranks[rank][0].q8.as_ref().unwrap(),
6952                            o_m.ranks[rank][1].q8.as_ref().unwrap(),
6953                            o_m.ranks[rank][2].q8.as_ref().unwrap(),
6954                            o_m.ranks[rank][3].q8.as_ref().unwrap(),
6955                        ],
6956                        &w8t_oaq[rank],
6957                        &w8t_oad[rank],
6958                        &mut tcol_opart[rank],
6959                        *o_block_cols,
6960                        *o_out,
6961                        t,
6962                    )?;
6963                } else {
6964                    engine.matvec_bf16_b4_tcol_into(
6965                        [weights[0], weights[1], weights[2], weights[3]],
6966                        &tcol_gated[rank],
6967                        &mut tcol_opart[rank],
6968                        *o_block_cols,
6969                        *o_out,
6970                        t,
6971                    )?;
6972                }
6973            }
6974            if rank != 0 {
6975                ws.ev_rank[rank].record(&engine.stream())?;
6976            }
6977        }
6978        let root = &self.ranks[0];
6979        {
6980            let _main = root.gpu.enter_main()?;
6981            for ev in ws.ev_rank.iter().skip(1) {
6982                root.stream().wait(ev)?;
6983            }
6984            {
6985                let StepTpDecodeV2Ws {
6986                    tcol_opart,
6987                    tcol_opeer,
6988                    tcol_omix,
6989                    o_out,
6990                    ..
6991                } = &mut *ws;
6992                let opeer = tcol_opeer.as_mut().ok_or("tcol o_proj slabs not armed")?;
6993                let omix = tcol_omix.as_mut().ok_or("tcol o_proj slabs not armed")?;
6994                {
6995                    let mut dst = opeer.slice_mut(0..t * *o_out);
6996                    root.stream()
6997                        .memcpy_dtod(&tcol_opart[1].slice(0..t * *o_out), &mut dst)?;
6998                }
6999                // Elementwise over the whole slab: per element identical to the per-column
7000                // direct-join add (independent lanes, same operand values).
7001                root.add(&tcol_opart[0], opeer, omix, t * *o_out)?;
7002            }
7003            ws.ev_oproj.record(&root.stream())?;
7004        }
7005        let _main = e.gpu.enter_main()?;
7006        e.stream().wait(&ws.ev_oproj)?;
7007        let mut out = e.uninit(t * ws.o_out)?;
7008        let omix = ws.tcol_omix.as_ref().ok_or("tcol o_proj slabs not armed")?;
7009        e.stream().memcpy_dtod(
7010            &omix.slice(0..t * ws.o_out),
7011            &mut out.slice_mut(0..t * ws.o_out),
7012        )?;
7013        Ok(out)
7014    }
7015
7016    #[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
7017    pub(crate) fn decode_v2_input_qkv(
7018        &self,
7019        ws: &mut StepTpDecodeV2Ws,
7020        e: &Engine,
7021        h: &CudaSlice<f32>,
7022        pos_d: &CudaSlice<i32>,
7023        gate_raw: Option<&CudaSlice<f32>>,
7024        gate_shards: Option<StepTpGateShards<'_>>,
7025        decode_input: &mut ResidentReplicatedDeviceRows,
7026        q_m: &ResidentBf16ColumnParallel,
7027        k_m: &ResidentBf16ColumnParallel,
7028        v_m: &ResidentBf16ColumnParallel,
7029        q_norm: &[CudaSlice<f32>],
7030        k_norm: &[CudaSlice<f32>],
7031        head_dim: usize,
7032        n_rot: usize,
7033        rope_base: f32,
7034        rope_freqs: &[Option<&CudaSlice<f32>>],
7035        rms_eps: f32,
7036        has_gate: bool,
7037        defer_norm_rope: bool,
7038        tcol_col: Option<usize>,
7039    ) -> Result<(), Box<dyn std::error::Error>> {
7040        let ranks = self.ranks.len();
7041        validate_replicated_device_rows(&self.ranks, decode_input)?;
7042        let gate_sources = usize::from(gate_raw.is_some()) + usize::from(gate_shards.is_some());
7043        if decode_input.tokens != 1
7044            || decode_input.width != q_m.in_features
7045            || pos_d.len() != 1
7046            || gate_raw.is_some_and(|gate| gate.len() != ws.heads)
7047            || (has_gate && gate_sources != 1)
7048            || (!has_gate && gate_sources != 0)
7049            || gate_shards.as_ref().is_some_and(|shards| match shards {
7050                StepTpGateShards::F32(shards) => shards.len() != ranks,
7051                StepTpGateShards::Bf16(shards) => shards.len() != ranks,
7052            })
7053            || q_norm.len() != ranks
7054            || k_norm.len() != ranks
7055            || rope_freqs.len() != ranks
7056            || e.ctx().ordinal() != ws.e_device
7057        {
7058            return Err("step TP decode v2 input geometry mismatch".into());
7059        }
7060
7061        let qkv_fused = step_tp_qkv_fused_enabled()?;
7062        if gate_shards.is_some() && !qkv_fused {
7063            return Err("step TP decode v2 gate shards require MEMRA_STEP_TP_QKV_FUSED=1".into());
7064        }
7065        let values = decode_input.width;
7066        if h.len() != values {
7067            return Err(format!(
7068                "step TP decode v2 hidden width {} != replicated width {values}",
7069                h.len()
7070            )
7071            .into());
7072        }
7073
7074        if qkv_fused {
7075            // STAGE-BASED flow (graph increment A): h and pos land in fixed e-context stages
7076            // (one e-stream copy each), the entry event covers them, and every rank raw-copies
7077            // from the stages on its own stream — exactly the shape graph capture wraps.
7078            if ws.h_stage.is_none() {
7079                use cudarc::driver::DevicePtr;
7080                let _main = e.gpu.enter_main()?;
7081                let h_stage = e.uninit(values)?;
7082                let pos_stage = e.htod_i32(&[0])?;
7083                {
7084                    let stream = e.stream();
7085                    let (hp, _g0) = h_stage.device_ptr(&stream);
7086                    let (pp, _g1) = pos_stage.device_ptr(&stream);
7087                    ws.raw_h_stage = hp;
7088                    ws.raw_pos_stage = pp;
7089                }
7090                ws.h_stage = Some(h_stage);
7091                ws.pos_stage = Some(pos_stage);
7092                for rank in 0..ranks {
7093                    use cudarc::driver::DevicePtr;
7094                    let engine = &self.ranks[rank];
7095                    let _rmain = engine.gpu.enter_main()?;
7096                    let attn_in = engine.uninit(values)?;
7097                    let (dp, pp) = {
7098                        let stream = engine.stream();
7099                        let (dp, _g2) = attn_in.device_ptr(&stream);
7100                        let (pp, _g3) = ws.pos[rank].device_ptr(&stream);
7101                        (dp, pp)
7102                    };
7103                    ws.raw_attn_in.push(dp);
7104                    ws.raw_pos.push(pp);
7105                    ws.attn_in.push(attn_in);
7106                }
7107                {
7108                    use cudarc::driver::DevicePtr;
7109                    let root = &self.ranks[0];
7110                    let _rmain = root.gpu.enter_main()?;
7111                    let stream = root.stream();
7112                    let (a, _g) = ws.peer_partial.device_ptr(&stream);
7113                    let (b, _g) = ws.k_shadow.device_ptr(&stream);
7114                    let (c, _g) = ws.v_shadow.device_ptr(&stream);
7115                    ws.raw_peer_partial = a;
7116                    ws.raw_k_shadow = b;
7117                    ws.raw_v_shadow = c;
7118                }
7119                {
7120                    use cudarc::driver::DevicePtr;
7121                    let rank1 = &self.ranks[1];
7122                    let _rmain = rank1.gpu.enter_main()?;
7123                    let stream = rank1.stream();
7124                    let (a, _g) = ws.o_partials[1][0].device_ptr(&stream);
7125                    let (b, _g) = ws.k[1].device_ptr(&stream);
7126                    let (c, _g) = ws.v_raw[1].device_ptr(&stream);
7127                    ws.raw_o_partial1 = a;
7128                    ws.raw_k1 = b;
7129                    ws.raw_v1 = c;
7130                }
7131            }
7132            {
7133                let _main = e.gpu.enter_main()?;
7134                {
7135                    // (Always staged: a tcol column below the dcw floor falls back to the
7136                    // normal fused arm, which reads h through this stage.)
7137                    let h_stage = ws.h_stage.as_mut().expect("stage armed above");
7138                    let mut dst = h_stage.slice_mut(0..values);
7139                    e.stream().memcpy_dtod(&h.slice(0..values), &mut dst)?;
7140                }
7141                {
7142                    let pos_stage = ws.pos_stage.as_mut().expect("stage armed above");
7143                    let mut dst = pos_stage.slice_mut(0..1);
7144                    e.stream().memcpy_dtod(&pos_d.slice(0..1), &mut dst)?;
7145                }
7146                ws.ev_entry.record(&e.stream())?;
7147            }
7148            for rank in 0..ranks {
7149                let engine = &self.ranks[rank];
7150                let _main = engine.gpu.enter_main()?;
7151                engine.stream().wait(&ws.ev_entry)?;
7152            }
7153        } else {
7154            // Evented replicate flow (the pre-stage shape, kept for the non-fused class).
7155            {
7156                let _main = e.gpu.enter_main()?;
7157                if let Some(gate_raw) = gate_raw {
7158                    let mut gate_dst = ws.gate_e.slice_mut(0..ws.heads);
7159                    e.stream()
7160                        .memcpy_dtod(&gate_raw.slice(0..ws.heads), &mut gate_dst)?;
7161                }
7162                ws.ev_entry.record(&e.stream())?;
7163            }
7164            {
7165                let root = &self.ranks[0];
7166                let _main = root.gpu.enter_main()?;
7167                root.stream().wait(&ws.ev_entry)?;
7168                let mut destination = decode_input.ranks[0].slice_mut(0..values);
7169                root.stream()
7170                    .memcpy_dtod(&h.slice(0..values), &mut destination)?;
7171                ws.ev_refresh.record(&root.stream())?;
7172            }
7173            for rank in 1..ranks {
7174                let engine = &self.ranks[rank];
7175                let _main = engine.gpu.enter_main()?;
7176                engine.stream().wait(&ws.ev_refresh)?;
7177                let (root_rows, peer_rows) = decode_input.ranks.split_at_mut(rank);
7178                let mut destination = peer_rows[0].slice_mut(0..values);
7179                engine
7180                    .stream()
7181                    .memcpy_dtod(&root_rows[0].slice(0..values), &mut destination)?;
7182            }
7183        }
7184        for rank in 0..ranks {
7185            self.decode_v2_input_qkv_rank(
7186                ws,
7187                pos_d,
7188                decode_input,
7189                q_m,
7190                k_m,
7191                v_m,
7192                q_norm,
7193                k_norm,
7194                head_dim,
7195                n_rot,
7196                rope_base,
7197                rope_freqs,
7198                rms_eps,
7199                gate_shards.as_ref(),
7200                has_gate,
7201                qkv_fused,
7202                defer_norm_rope,
7203                rank,
7204                tcol_col,
7205            )?;
7206        }
7207        Ok(())
7208    }
7209
7210    /// One rank's slice of `decode_v2_input_qkv` (projection, norm+rope, gate staging) — the
7211    /// per-device issue unit the whole-token graph captures on that rank's stream.
7212    #[allow(clippy::too_many_arguments)]
7213    pub(crate) fn decode_v2_input_qkv_rank(
7214        &self,
7215        ws: &mut StepTpDecodeV2Ws,
7216        pos_d: &CudaSlice<i32>,
7217        decode_input: &mut ResidentReplicatedDeviceRows,
7218        q_m: &ResidentBf16ColumnParallel,
7219        k_m: &ResidentBf16ColumnParallel,
7220        v_m: &ResidentBf16ColumnParallel,
7221        q_norm: &[CudaSlice<f32>],
7222        k_norm: &[CudaSlice<f32>],
7223        head_dim: usize,
7224        n_rot: usize,
7225        rope_base: f32,
7226        rope_freqs: &[Option<&CudaSlice<f32>>],
7227        rms_eps: f32,
7228        gate_shards: Option<&StepTpGateShards<'_>>,
7229        has_gate: bool,
7230        qkv_fused: bool,
7231        defer_norm_rope: bool,
7232        rank: usize,
7233        tcol_col: Option<usize>,
7234    ) -> Result<(), Box<dyn std::error::Error>> {
7235        let ranks = self.ranks.len();
7236        let local_heads = ws.local_q_dim / head_dim;
7237        let local_kv_heads = ws.local_kv_dim / head_dim;
7238        let engine = &self.ranks[rank];
7239        let _main = engine.gpu.enter_main()?;
7240        let ws_e_device = ws.e_device;
7241        // T-COLUMN SELECT (spec verify): the projections for this column were precomputed
7242        // by the weight-amortized tcol kernel — copy the column into the single-row buffers
7243        // (pure f32 moves, bit-exact) and skip the per-column matvec. Rope/norm/append run
7244        // below exactly as in the t=1 program.
7245        if qkv_fused && tcol_col.is_some() {
7246            #[allow(clippy::unnecessary_unwrap)]
7247            // allow: the Some-guard sits in a multi-clause regime gate; if-let would reshape the arm structure
7248            let c = tcol_col.expect("checked");
7249            if ws.tcol_cap == 0 || ws.tcol_q.len() != ranks {
7250                return Err("tcol select without precompute".into());
7251            }
7252            // The select skips the matvec but NOT the position: rope/append below still
7253            // read this rank's pos buffer, which only the (skipped) stage path fills for
7254            // peer-device ranks. Stage it here or rank1 ropes at the previous position.
7255            if engine.ctx().ordinal() != ws_e_device {
7256                raw_copy_bytes(ws.raw_pos[rank], ws.raw_pos_stage, 4, engine)?;
7257            }
7258            let StepTpDecodeV2Ws {
7259                tcol_q,
7260                tcol_k,
7261                tcol_v,
7262                tcol_g,
7263                q_raw,
7264                k_raw,
7265                v_raw,
7266                gate,
7267                local_q_dim,
7268                local_kv_dim,
7269                heads,
7270                ..
7271            } = &mut *ws;
7272            let lg = *heads / ranks;
7273            let stream = engine.stream();
7274            {
7275                let mut dst = q_raw[rank].slice_mut(0..*local_q_dim);
7276                stream.memcpy_dtod(
7277                    &tcol_q[rank].slice(c * *local_q_dim..(c + 1) * *local_q_dim),
7278                    &mut dst,
7279                )?;
7280            }
7281            {
7282                let mut dst = k_raw[rank].slice_mut(0..*local_kv_dim);
7283                stream.memcpy_dtod(
7284                    &tcol_k[rank].slice(c * *local_kv_dim..(c + 1) * *local_kv_dim),
7285                    &mut dst,
7286                )?;
7287            }
7288            {
7289                let mut dst = v_raw[rank].slice_mut(0..*local_kv_dim);
7290                stream.memcpy_dtod(
7291                    &tcol_v[rank].slice(c * *local_kv_dim..(c + 1) * *local_kv_dim),
7292                    &mut dst,
7293                )?;
7294            }
7295            if has_gate && lg > 0 {
7296                let mut dst = gate[rank].slice_mut(0..lg);
7297                stream.memcpy_dtod(&tcol_g[rank].slice(c * lg..(c + 1) * lg), &mut dst)?;
7298            }
7299            if !defer_norm_rope {
7300                // Below the dcw floor (or a non-defer shape) the col-select cannot apply:
7301                // fall through and recompute this column's QKV from the REAL h row — the
7302                // caller always passes it. The slab copies above are dead stores.
7303            } else {
7304                return Ok(());
7305            }
7306        }
7307        if qkv_fused {
7308            // Stage-based input: raw copies from the fixed e-context stages (capture-safe;
7309            // eager ordering comes from the caller's ev_entry wait on this stream). The rank
7310            // SHARING e's device reads the stages directly — same context (probed), ordering
7311            // identical (ev_entry / graph edge), bytes identical: the copies are pure waste.
7312            let same_dev = engine.ctx().ordinal() == ws.e_device;
7313            if !same_dev {
7314                raw_copy_bytes(
7315                    ws.raw_attn_in[rank],
7316                    ws.raw_h_stage,
7317                    q_m.in_features * 4,
7318                    engine,
7319                )?;
7320                raw_copy_bytes(ws.raw_pos[rank], ws.raw_pos_stage, 4, engine)?;
7321            }
7322            let StepTpDecodeV2Ws {
7323                q_raw,
7324                k_raw,
7325                v_raw,
7326                gate,
7327                gate_e,
7328                attn_in,
7329                h_stage,
7330                heads,
7331                local_q_dim,
7332                local_kv_dim,
7333                w8_aq,
7334                w8_ad,
7335                w8_in,
7336                ..
7337            } = &mut *ws;
7338            let input_ref: &CudaSlice<f32> = if same_dev {
7339                h_stage
7340                    .as_ref()
7341                    .ok_or("step TP decode v2 stage not armed")?
7342            } else {
7343                &attn_in[rank]
7344            };
7345            match (
7346                &q_m.ranks[rank].weight,
7347                &k_m.ranks[rank].weight,
7348                &v_m.ranks[rank].weight,
7349            ) {
7350                (
7351                    ResidentBf16Weight::F32(wq),
7352                    ResidentBf16Weight::F32(wk),
7353                    ResidentBf16Weight::F32(wv),
7354                ) => {
7355                    let (wg, out_g) = match &gate_shards {
7356                        Some(StepTpGateShards::F32(shards)) => (&shards[rank], *heads / ranks),
7357                        Some(StepTpGateShards::Bf16(_)) => {
7358                            return Err("step TP decode v2 gate shard class does not \
7359                                            match the F32 projections"
7360                                .into());
7361                        }
7362                        // out_g = 0: the kernel never reads wg; any resident buffer works.
7363                        None => (&*gate_e, 0),
7364                    };
7365                    engine.matvec_f32_qkv_into(
7366                        wq,
7367                        wk,
7368                        wv,
7369                        wg,
7370                        input_ref,
7371                        &mut q_raw[rank],
7372                        &mut k_raw[rank],
7373                        &mut v_raw[rank],
7374                        &mut gate[rank],
7375                        q_m.in_features,
7376                        *local_q_dim,
7377                        *local_kv_dim,
7378                        out_g,
7379                    )?;
7380                }
7381                (
7382                    ResidentBf16Weight::Bf16(wq),
7383                    ResidentBf16Weight::Bf16(wk),
7384                    ResidentBf16Weight::Bf16(wv),
7385                ) => {
7386                    let (wg, out_g) = match &gate_shards {
7387                        Some(StepTpGateShards::Bf16(shards)) => (&shards[rank], *heads / ranks),
7388                        Some(StepTpGateShards::F32(_)) => {
7389                            return Err("step TP decode v2 gate shard class does not \
7390                                            match the bf16 projections"
7391                                .into());
7392                        }
7393                        None => (wq, 0),
7394                    };
7395                    // MEMRA_STEP_TP_W8: q8_0 weights + q8_1 activation through mmvq instead of
7396                    // the fused bf16 qkvg. NUMERIC CLASS (int8 dp4a with per-32 scales, not a
7397                    // bf16 fma chain) — argmax-gated, never a bit-tape flip. Q, K and V each
7398                    // get their own launch because the fused kernel has no q8 twin; the gate
7399                    // rows stay bf16 (32 rows, ~0.3 MB, nothing to win and one less class to
7400                    // qualify). Measured motive: 23.0 us bf16 -> 14.0 us q8 at this shape.
7401                    let in_f = q_m.in_features;
7402                    let q8_ready = crate::step_tp_w8_on()
7403                        && q_m.ranks[rank].q8.is_some()
7404                        && k_m.ranks[rank].q8.is_some()
7405                        && v_m.ranks[rank].q8.is_some();
7406                    if q8_ready {
7407                        if *w8_in != in_f || w8_aq.len() != ranks {
7408                            w8_aq.clear();
7409                            w8_ad.clear();
7410                            for e_rank in &self.ranks {
7411                                let _m = e_rank.gpu.enter_main()?;
7412                                w8_aq.push(e_rank.alloc_uninit::<i8>(in_f)?);
7413                                w8_ad.push(e_rank.alloc_uninit::<f32>(in_f / 32)?);
7414                            }
7415                            *w8_in = in_f;
7416                        }
7417                        engine.quantize_q8_1_into(
7418                            input_ref,
7419                            1,
7420                            in_f,
7421                            &mut w8_aq[rank],
7422                            &mut w8_ad[rank],
7423                        )?;
7424                        // ONE launch over the stacked q/k/v rows. The three-call version
7425                        // measured 79.52 vs 80.72 tok/s — SLOWER than the bf16 fused kernel —
7426                        // because three launches plus the activation quantize cost more than
7427                        // the halved weight bytes save. Bit-identical to those three calls.
7428                        engine.qmatvec_q8_0_qkv_rp_into(
7429                            q_m.ranks[rank].q8.as_ref().unwrap(),
7430                            k_m.ranks[rank].q8.as_ref().unwrap(),
7431                            v_m.ranks[rank].q8.as_ref().unwrap(),
7432                            &w8_aq[rank],
7433                            &w8_ad[rank],
7434                            &mut q_raw[rank],
7435                            &mut k_raw[rank],
7436                            &mut v_raw[rank],
7437                            in_f,
7438                            *local_q_dim,
7439                            *local_kv_dim,
7440                        )?;
7441                        if out_g > 0 {
7442                            engine.matvec_bf16_into(wg, input_ref, &mut gate[rank], in_f, out_g)?;
7443                        }
7444                    } else {
7445                        engine.matvec_bf16_qkvg_into(
7446                            wq,
7447                            wk,
7448                            wv,
7449                            wg,
7450                            input_ref,
7451                            &mut q_raw[rank],
7452                            &mut k_raw[rank],
7453                            &mut v_raw[rank],
7454                            &mut gate[rank],
7455                            q_m.in_features,
7456                            *local_q_dim,
7457                            *local_kv_dim,
7458                            out_g,
7459                        )?;
7460                    }
7461                }
7462                _ => {
7463                    return Err("step TP decode v2 QKV projections mix residency classes".into());
7464                }
7465            }
7466        } else {
7467            for (matrix, local_out, raw) in [
7468                (q_m, ws.local_q_dim, &mut ws.q_raw),
7469                (k_m, ws.local_kv_dim, &mut ws.k_raw),
7470                (v_m, ws.local_kv_dim, &mut ws.v_raw),
7471            ] {
7472                let ResidentBf16Weight::F32(values_w) = &matrix.ranks[rank].weight else {
7473                    return Err("step TP decode v2 lost its F32 projection residency".into());
7474                };
7475                let chunk_rows = matrix.canonical_chunk_rows.unwrap_or(local_out);
7476                engine.linear_f32_resident_canonical_rows_t1_into(
7477                    &decode_input.ranks[rank],
7478                    values_w,
7479                    &mut raw[rank],
7480                    matrix.in_features,
7481                    local_out,
7482                    chunk_rows,
7483                )?;
7484            }
7485        }
7486        if qkv_fused && defer_norm_rope {
7487            // FUSION #1 defers norm+rope to the caller's fused rope+append+inc launch.
7488        } else if qkv_fused {
7489            // Fused norm+rope: one launch; the position comes from the rank-local staged
7490            // copy (raw-copied above from the fixed e-context pos stage — capture-safe).
7491            let StepTpDecodeV2Ws {
7492                q_raw,
7493                k_raw,
7494                q,
7495                k,
7496                pos,
7497                pos_stage,
7498                ..
7499            } = &mut *ws;
7500            let same_dev = engine.ctx().ordinal() == ws_e_device;
7501            let pos_ref: &CudaSlice<i32> = if same_dev {
7502                pos_stage
7503                    .as_ref()
7504                    .ok_or("step TP decode v2 pos stage not armed")?
7505            } else {
7506                &pos[rank]
7507            };
7508            engine.qk_norm_rope_into(
7509                &q_raw[rank],
7510                &k_raw[rank],
7511                &q_norm[rank],
7512                &k_norm[rank],
7513                &mut q[rank],
7514                &mut k[rank],
7515                pos_ref,
7516                head_dim,
7517                n_rot,
7518                local_heads,
7519                local_kv_heads,
7520                rms_eps,
7521                rope_base,
7522                1.0,
7523                rope_freqs[rank],
7524            )?;
7525        } else {
7526            engine.rms_norm(
7527                &ws.q_raw[rank],
7528                &q_norm[rank],
7529                &mut ws.q[rank],
7530                head_dim,
7531                local_heads,
7532                rms_eps,
7533            )?;
7534            engine.rms_norm(
7535                &ws.k_raw[rank],
7536                &k_norm[rank],
7537                &mut ws.k[rank],
7538                head_dim,
7539                local_kv_heads,
7540                rms_eps,
7541            )?;
7542            {
7543                let mut pos_dst = ws.pos[rank].slice_mut(0..1);
7544                engine
7545                    .stream()
7546                    .memcpy_dtod(&pos_d.slice(0..1), &mut pos_dst)?;
7547            }
7548            engine.rope_neox2(
7549                &mut ws.q[rank],
7550                &mut ws.k[rank],
7551                &ws.pos[rank],
7552                head_dim,
7553                n_rot,
7554                local_heads,
7555                local_kv_heads,
7556                1,
7557                rope_base,
7558                1.0,
7559                rope_freqs[rank],
7560            )?;
7561        }
7562        if has_gate && gate_shards.is_none() {
7563            let gate_start = rank * (ws.heads / ranks);
7564            let mut gate_dst = ws.gate[rank].slice_mut(0..ws.heads / ranks);
7565            engine.stream().memcpy_dtod(
7566                &ws.gate_e.slice(gate_start..gate_start + ws.heads / ranks),
7567                &mut gate_dst,
7568            )?;
7569        }
7570        Ok(())
7571    }
7572
7573    /// One rank's O-partial slice of `decode_v2_finish` — the per-device issue unit the
7574    /// whole-token graph captures on that rank's stream (the rank-done event stays with the
7575    /// eager caller; graphs order via parent edges instead).
7576    pub(crate) fn decode_v2_finish_rank_partial(
7577        &self,
7578        ws: &mut StepTpDecodeV2Ws,
7579        o_m: &ResidentStepBf16RowParallel,
7580        o_fused: bool,
7581        rank: usize,
7582    ) -> Result<(), Box<dyn std::error::Error>> {
7583        let engine = &self.ranks[rank];
7584        let _main = engine.gpu.enter_main()?;
7585        if o_fused {
7586            let StepTpDecodeV2Ws {
7587                gated,
7588                o_partials,
7589                o_block_cols,
7590                o_out,
7591                w8o_aq,
7592                w8o_ad,
7593                w8o_in,
7594                ..
7595            } = &mut *ws;
7596            let all_f32 = o_m.ranks[rank]
7597                .iter()
7598                .all(|block| matches!(block.weight, ResidentBf16Weight::F32(_)));
7599            if all_f32 {
7600                let mut weights = Vec::with_capacity(4);
7601                for block in 0..4 {
7602                    let ResidentBf16Weight::F32(weight) = &o_m.ranks[rank][block].weight else {
7603                        unreachable!("all_f32 checked above");
7604                    };
7605                    weights.push(weight);
7606                }
7607                engine.matvec_f32_b4_into(
7608                    [weights[0], weights[1], weights[2], weights[3]],
7609                    &gated[rank],
7610                    &mut o_partials[rank][0],
7611                    *o_block_cols,
7612                    *o_out,
7613                )?;
7614            } else if crate::step_tp_w8_on() && (0..4).all(|b| o_m.ranks[rank][b].q8.is_some()) {
7615                // MEMRA_STEP_TP_W8, o_proj half: quantize the gated attention output once and
7616                // run all four HEAD_SPLIT blocks in one q8 launch. Measured motive: bf16 b4 is
7617                // 24.2 us/layer against 11.7 for the q8 shape — the largest decode line left
7618                // after the QKV arm banked +2.9%.
7619                let in_f = 4 * *o_block_cols;
7620                if *w8o_in != in_f || w8o_aq.len() != self.ranks.len() {
7621                    w8o_aq.clear();
7622                    w8o_ad.clear();
7623                    for e_rank in &self.ranks {
7624                        let _m = e_rank.gpu.enter_main()?;
7625                        w8o_aq.push(e_rank.alloc_uninit::<i8>(in_f)?);
7626                        w8o_ad.push(e_rank.alloc_uninit::<f32>(in_f / 32)?);
7627                    }
7628                    *w8o_in = in_f;
7629                }
7630                engine.quantize_q8_1_into(
7631                    &gated[rank],
7632                    1,
7633                    in_f,
7634                    &mut w8o_aq[rank],
7635                    &mut w8o_ad[rank],
7636                )?;
7637                engine.qmatvec_q8_0_b4_rp_into(
7638                    [
7639                        o_m.ranks[rank][0].q8.as_ref().unwrap(),
7640                        o_m.ranks[rank][1].q8.as_ref().unwrap(),
7641                        o_m.ranks[rank][2].q8.as_ref().unwrap(),
7642                        o_m.ranks[rank][3].q8.as_ref().unwrap(),
7643                    ],
7644                    &w8o_aq[rank],
7645                    &w8o_ad[rank],
7646                    &mut o_partials[rank][0],
7647                    *o_block_cols,
7648                    *o_out,
7649                )?;
7650            } else {
7651                let mut weights = Vec::with_capacity(4);
7652                for block in 0..4 {
7653                    let ResidentBf16Weight::Bf16(weight) = &o_m.ranks[rank][block].weight else {
7654                        return Err("step TP decode v2 O projections mix residency classes".into());
7655                    };
7656                    weights.push(weight);
7657                }
7658                engine.matvec_bf16_b4_into(
7659                    [weights[0], weights[1], weights[2], weights[3]],
7660                    &gated[rank],
7661                    &mut o_partials[rank][0],
7662                    *o_block_cols,
7663                    *o_out,
7664                )?;
7665            }
7666        } else {
7667            for block in 0..ws.blocks_per_rank {
7668                let x =
7669                    ws.gated[rank].slice(block * ws.o_block_cols..(block + 1) * ws.o_block_cols);
7670                let mut y = ws.o_partials[rank][block].slice_mut(0..ws.o_out);
7671                match &o_m.ranks[rank][block].weight {
7672                    ResidentBf16Weight::F32(weight) => {
7673                        let w = weight.slice(0..weight.len());
7674                        engine.linear_t1_into(&x, &w, &mut y, ws.o_block_cols, ws.o_out)?;
7675                    }
7676                    ResidentBf16Weight::Bf16(weight) => {
7677                        engine.matvec_bf16_views_into(
7678                            weight,
7679                            &x,
7680                            &mut y,
7681                            ws.o_block_cols,
7682                            ws.o_out,
7683                        )?;
7684                    }
7685                }
7686            }
7687        }
7688        Ok(())
7689    }
7690
7691    /// v2 phase 2: canonical-block O reduction on the root device plus the K/V shadow gathers,
7692    /// returning a fresh model-engine output ordered behind `ev_oproj` on `e`'s stream.
7693    ///
7694    /// The caller must have queued every rank's attention work (reading `ws.gated`, `ws.k`,
7695    /// `ws.v_raw`) on the rank streams before this call. Reduction order is identical to
7696    /// `step_bf16_row_parallel_resident_native`: zeros, then rank 0's blocks, then each peer
7697    /// rank's blocks, one `add` per block.
7698    pub(crate) fn decode_v2_finish(
7699        &self,
7700        ws: &mut StepTpDecodeV2Ws,
7701        e: &Engine,
7702        o_m: &ResidentStepBf16RowParallel,
7703    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
7704        let ranks = self.ranks.len();
7705        if e.ctx().ordinal() != ws.e_device {
7706            return Err("step TP decode v2 finish engine changed".into());
7707        }
7708        // MEMRA_STEP_TP_QKV_FUSED extends to the O path: one matvec_f32_b4 launch per rank
7709        // (in-order canonical block accumulation per element) and a single peer-copy + add on
7710        // the root, replacing 4 cuBLASLt launches per rank + the 4-copy/8-add chain. Same
7711        // numeric-class door and gate as the fused QKV projection.
7712        let o_fused = step_tp_qkv_fused_enabled()? && ws.blocks_per_rank == 4 && ranks == 2;
7713
7714        // Per-rank O block partials on the owning rank's stream (serial after the attention
7715        // kernels the driver queued there), then the rank-done event for root's peer reads.
7716        for rank in 0..ranks {
7717            self.decode_v2_finish_rank_partial(ws, o_m, o_fused, rank)?;
7718            if rank == 0 {
7719                // root == rank0: its own stream order covers the partial; only peers need
7720                // the record/wait pair (host-op diet, matches the routes-arm skip).
7721                continue;
7722            }
7723            let engine = &self.ranks[rank];
7724            let _main = engine.gpu.enter_main()?;
7725            ws.ev_rank[rank].record(&engine.stream())?;
7726        }
7727
7728        // Root reduce in canonical order + shadow gathers, all on the root stream.
7729        let root = &self.ranks[0];
7730        #[allow(unused_assignments)]
7731        let mut final_in_a = false;
7732        {
7733            let _main = root.gpu.enter_main()?;
7734            for ev in ws.ev_rank.iter().skip(1) {
7735                root.stream().wait(ev)?;
7736            }
7737            if o_fused && oproj_direct_on() && ranks == 2 && no_local_shadow_on() {
7738                // DIRECT JOIN: rank1's partial already sits in root memory (P2P kernel
7739                // stores; visibility guaranteed by the ev_rank[1] wait above), rank0's
7740                // partial is root-stream-ordered — record ONE event and let the model
7741                // engine do the single add itself, straight into its own output row.
7742                // Same operands, same add order as finish_root_fused: BIT-IDENTICAL.
7743                ws.ev_oproj.record(&root.stream())?;
7744                let _main = e.gpu.enter_main()?;
7745                e.stream().wait(&ws.ev_oproj)?;
7746                let mut output = e.uninit(ws.o_out)?;
7747                if oproj_tail_on() && oproj_tail_eligible() {
7748                    // M2: defer the add into the residual+norm consumer (waits stay HERE;
7749                    // only the arithmetic moves). `output` is returned unwritten.
7750                    use cudarc::driver::DevicePtr;
7751                    let stream = e.stream();
7752                    let (p0, _g0) = ws.o_partials[0][0].device_ptr(&stream);
7753                    let (p1, _g1) = ws.o_partials[1][0].device_ptr(&stream);
7754                    set_oproj_tail((p0, p1));
7755                    return Ok(output);
7756                }
7757                e.add(
7758                    &ws.o_partials[0][0],
7759                    &ws.o_partials[1][0],
7760                    &mut output,
7761                    ws.o_out,
7762                )?;
7763                return Ok(output);
7764            }
7765            if o_fused {
7766                self.decode_v2_finish_root_fused(ws)?;
7767                ws.ev_oproj.record(&root.stream())?;
7768                let _main = e.gpu.enter_main()?;
7769                e.stream().wait(&ws.ev_oproj)?;
7770                let mut output = e.uninit(ws.o_out)?;
7771                e.stream().memcpy_dtod(
7772                    &ws.reduce_a.slice(0..ws.o_out),
7773                    &mut output.slice_mut(0..ws.o_out),
7774                )?;
7775                return Ok(output);
7776            }
7777            let mut first = true;
7778            let mut current_is_a = false;
7779            for rank in 0..ranks {
7780                for block in 0..ws.blocks_per_rank {
7781                    let use_peer = rank != 0;
7782                    if use_peer {
7783                        raw_copy_bytes(
7784                            ws.raw_peer_partial,
7785                            ws.raw_o_partials[rank][block],
7786                            ws.o_out * std::mem::size_of::<f32>(),
7787                            root,
7788                        )?;
7789                    }
7790                    // add(prev, partial) -> the other reduce buffer, exactly one add per block
7791                    match (first, current_is_a, use_peer) {
7792                        (true, _, true) => {
7793                            root.add(&ws.zeros, &ws.peer_partial, &mut ws.reduce_a, ws.o_out)?
7794                        }
7795                        (true, _, false) => root.add(
7796                            &ws.zeros,
7797                            &ws.o_partials[0][block],
7798                            &mut ws.reduce_a,
7799                            ws.o_out,
7800                        )?,
7801                        (false, true, true) => {
7802                            root.add(&ws.reduce_a, &ws.peer_partial, &mut ws.reduce_b, ws.o_out)?
7803                        }
7804                        (false, true, false) => root.add(
7805                            &ws.reduce_a,
7806                            &ws.o_partials[0][block],
7807                            &mut ws.reduce_b,
7808                            ws.o_out,
7809                        )?,
7810                        (false, false, true) => {
7811                            root.add(&ws.reduce_b, &ws.peer_partial, &mut ws.reduce_a, ws.o_out)?
7812                        }
7813                        (false, false, false) => root.add(
7814                            &ws.reduce_b,
7815                            &ws.o_partials[0][block],
7816                            &mut ws.reduce_a,
7817                            ws.o_out,
7818                        )?,
7819                    }
7820                    current_is_a = first || !current_is_a;
7821                    first = false;
7822                }
7823            }
7824            final_in_a = current_is_a;
7825
7826            if !no_local_shadow_on() {
7827                let bytes = ws.local_kv_dim * std::mem::size_of::<f32>();
7828                for rank in 0..ranks {
7829                    let offset = rank * bytes;
7830                    raw_copy_bytes(ws.raw_k_shadow + offset as u64, ws.raw_k[rank], bytes, root)?;
7831                    raw_copy_bytes(
7832                        ws.raw_v_shadow + offset as u64,
7833                        ws.raw_v_raw[rank],
7834                        bytes,
7835                        root,
7836                    )?;
7837                }
7838            }
7839            ws.ev_oproj.record(&root.stream())?;
7840        }
7841
7842        // Model-engine output: e waits the root event, then copies the reduced row into a
7843        // fresh e-context buffer (same ownership contract as v1's `e.htod`). The same wait
7844        // orders the driver's shadow append (it reads ws.k_shadow/ws.v_shadow on e's stream).
7845        let _main = e.gpu.enter_main()?;
7846        e.stream().wait(&ws.ev_oproj)?;
7847        let mut output = e.uninit(ws.o_out)?;
7848        let source = if final_in_a {
7849            &ws.reduce_a
7850        } else {
7851            &ws.reduce_b
7852        };
7853        e.stream().memcpy_dtod(
7854            &source.slice(0..ws.o_out),
7855            &mut output.slice_mut(0..ws.o_out),
7856        )?;
7857        Ok(output)
7858    }
7859
7860    #[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
7861    pub fn run_routed_experts(
7862        &self,
7863        experts: &ResidentExpertParallel,
7864        input: &[f32],
7865        tokens: usize,
7866        selected: &[usize],
7867        route_weights: &[f32],
7868        experts_per_token: usize,
7869        activation_limit: Option<f32>,
7870    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
7871        validate_step_expert_activation_limit(activation_limit)?;
7872        validate_ep_residency(&self.ranks, experts)?;
7873        validate_activations(input, tokens, experts.input_width)?;
7874        let pairs = tokens
7875            .checked_mul(experts_per_token)
7876            .ok_or("EP route count overflow")?;
7877        if selected.len() != pairs || route_weights.len() != pairs {
7878            return Err(format!(
7879                "EP routes selected={} weights={} != tokens {tokens} x experts/token \
7880                 {experts_per_token} ({pairs})",
7881                selected.len(),
7882                route_weights.len(),
7883            )
7884            .into());
7885        }
7886        if !route_weights.iter().all(|weight| weight.is_finite()) {
7887            return Err("EP route weights contain a non-finite value".into());
7888        }
7889        if self.native_p2p {
7890            return self.run_routed_experts_native(
7891                experts,
7892                input,
7893                tokens,
7894                selected,
7895                route_weights,
7896                experts_per_token,
7897                activation_limit,
7898            );
7899        }
7900
7901        let mut output = vec![0.0f32; tokens * experts.input_width];
7902        let per_rank = experts.expert_count / experts.ranks.len();
7903        for token in 0..tokens {
7904            let input_row = &input[token * experts.input_width..(token + 1) * experts.input_width];
7905            for slot in 0..experts_per_token {
7906                let pair = token * experts_per_token + slot;
7907                let expert = selected[pair];
7908                if expert >= experts.expert_count {
7909                    return Err(format!(
7910                        "EP selected expert {expert} outside 0..{}",
7911                        experts.expert_count
7912                    )
7913                    .into());
7914                }
7915                let owner = expert / per_rank;
7916                let local_expert = expert - experts.ranks[owner].gate.expert_range.start;
7917                let rank = &experts.ranks[owner];
7918                let engine = &self.ranks[owner];
7919                let gate =
7920                    run_resident_bank_expert(engine, &rank.gate, local_expert, input_row, 1)?;
7921                let up = run_resident_bank_expert(engine, &rank.up, local_expert, input_row, 1)?;
7922                let activated: Vec<f32> = gate
7923                    .iter()
7924                    .zip(&up)
7925                    .map(|(&gate, &up)| step_expert_activation_host(gate, up, activation_limit))
7926                    .collect();
7927                debug_assert_eq!(activated.len(), experts.expert_width);
7928                let down =
7929                    run_resident_bank_expert(engine, &rank.down, local_expert, &activated, 1)?;
7930                let weight = route_weights[pair];
7931                for (sum, value) in output
7932                    [token * experts.input_width..(token + 1) * experts.input_width]
7933                    .iter_mut()
7934                    .zip(down)
7935                {
7936                    *sum += weight * value;
7937                }
7938            }
7939        }
7940        Ok(output)
7941    }
7942
7943    #[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
7944    fn run_routed_experts_native(
7945        &self,
7946        experts: &ResidentExpertParallel,
7947        input: &[f32],
7948        tokens: usize,
7949        selected: &[usize],
7950        route_weights: &[f32],
7951        experts_per_token: usize,
7952        activation_limit: Option<f32>,
7953    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
7954        if !self.native_p2p || self.ranks.len() < 2 {
7955            return Err("native EP execution requires at least two P2P ranks".into());
7956        }
7957        if self.ep_device_arithmetic {
7958            return self.run_routed_experts_native_device(
7959                experts,
7960                input,
7961                tokens,
7962                selected,
7963                route_weights,
7964                experts_per_token,
7965                activation_limit,
7966            );
7967        }
7968        let mut output = vec![0.0f32; tokens * experts.input_width];
7969        let per_rank = experts.expert_count / experts.ranks.len();
7970        for token in 0..tokens {
7971            let input_row = &input[token * experts.input_width..(token + 1) * experts.input_width];
7972            let mut rank_inputs = (0..self.ranks.len())
7973                .map(|_| None)
7974                .collect::<Vec<Option<CudaSlice<f32>>>>();
7975            rank_inputs[0] = Some({
7976                let root = &self.ranks[0];
7977                let _main = root.gpu.enter_main()?;
7978                root.htod(input_row)?
7979            });
7980
7981            for slot in 0..experts_per_token {
7982                let pair = token * experts_per_token + slot;
7983                let expert = selected[pair];
7984                if expert >= experts.expert_count {
7985                    return Err(format!(
7986                        "EP selected expert {expert} outside 0..{}",
7987                        experts.expert_count
7988                    )
7989                    .into());
7990                }
7991                let owner = expert / per_rank;
7992                let local_expert = expert - experts.ranks[owner].gate.expert_range.start;
7993                if rank_inputs[owner].is_none() {
7994                    let peer_input = {
7995                        let root_input = rank_inputs[0]
7996                            .as_ref()
7997                            .ok_or("native EP lost its root input")?;
7998                        let engine = &self.ranks[owner];
7999                        let _main = engine.gpu.enter_main()?;
8000                        let mut peer_input = engine.uninit(experts.input_width)?;
8001                        engine.stream().memcpy_dtod(root_input, &mut peer_input)?;
8002                        peer_input
8003                    };
8004                    rank_inputs[owner] = Some(peer_input);
8005                }
8006
8007                let rank = &experts.ranks[owner];
8008                let engine = &self.ranks[owner];
8009                let owner_input = rank_inputs[owner]
8010                    .as_ref()
8011                    .ok_or("native EP owner input is absent after dispatch")?;
8012                let gate = run_resident_bank_expert_device(
8013                    engine,
8014                    &rank.gate,
8015                    local_expert,
8016                    owner_input,
8017                    1,
8018                )?;
8019                let up = run_resident_bank_expert_device(
8020                    engine,
8021                    &rank.up,
8022                    local_expert,
8023                    owner_input,
8024                    1,
8025                )?;
8026                let (gate, up) = {
8027                    let _main = engine.gpu.enter_main()?;
8028                    (engine.dtoh(&gate)?, engine.dtoh(&up)?)
8029                };
8030                let activated = gate
8031                    .iter()
8032                    .zip(&up)
8033                    .map(|(&gate, &up)| step_expert_activation_host(gate, up, activation_limit))
8034                    .collect::<Vec<_>>();
8035                debug_assert_eq!(activated.len(), experts.expert_width);
8036                let activated = {
8037                    let _main = engine.gpu.enter_main()?;
8038                    engine.htod(&activated)?
8039                };
8040                let down = run_resident_bank_expert_device(
8041                    engine,
8042                    &rank.down,
8043                    local_expert,
8044                    &activated,
8045                    1,
8046                )?;
8047                let down = if owner == 0 {
8048                    let _main = engine.gpu.enter_main()?;
8049                    engine.dtoh(&down)?
8050                } else {
8051                    let root = &self.ranks[0];
8052                    let _main = root.gpu.enter_main()?;
8053                    let mut root_down = root.uninit(experts.input_width)?;
8054                    root.stream().memcpy_dtod(&down, &mut root_down)?;
8055                    root.dtoh(&root_down)?
8056                };
8057                let weight = route_weights[pair];
8058                for (sum, value) in output
8059                    [token * experts.input_width..(token + 1) * experts.input_width]
8060                    .iter_mut()
8061                    .zip(down)
8062                {
8063                    *sum += weight * value;
8064                }
8065            }
8066        }
8067        Ok(output)
8068    }
8069
8070    #[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
8071    fn run_routed_experts_native_device(
8072        &self,
8073        experts: &ResidentExpertParallel,
8074        input: &[f32],
8075        tokens: usize,
8076        selected: &[usize],
8077        route_weights: &[f32],
8078        experts_per_token: usize,
8079        activation_limit: Option<f32>,
8080    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
8081        if !self.native_p2p || !self.ep_device_arithmetic || self.ranks.len() < 2 {
8082            return Err(
8083                "device-resident EP arithmetic requires at least two native P2P ranks".into(),
8084            );
8085        }
8086        let mut output = Vec::with_capacity(tokens * experts.input_width);
8087        let per_rank = experts.expert_count / experts.ranks.len();
8088        let root = &self.ranks[0];
8089        for token in 0..tokens {
8090            let input_row = &input[token * experts.input_width..(token + 1) * experts.input_width];
8091            let mut rank_inputs = (0..self.ranks.len())
8092                .map(|_| None)
8093                .collect::<Vec<Option<CudaSlice<f32>>>>();
8094            rank_inputs[0] = Some({
8095                let _main = root.gpu.enter_main()?;
8096                root.htod(input_row)?
8097            });
8098            let mut root_output = {
8099                let _main = root.gpu.enter_main()?;
8100                root.zeros(experts.input_width)?
8101            };
8102            let mut remote_down_keepalive = Vec::new();
8103
8104            for slot in 0..experts_per_token {
8105                let pair = token * experts_per_token + slot;
8106                let expert = selected[pair];
8107                if expert >= experts.expert_count {
8108                    return Err(format!(
8109                        "EP selected expert {expert} outside 0..{}",
8110                        experts.expert_count
8111                    )
8112                    .into());
8113                }
8114                let owner = expert / per_rank;
8115                let local_expert = expert - experts.ranks[owner].gate.expert_range.start;
8116                if rank_inputs[owner].is_none() {
8117                    let peer_input = {
8118                        let root_input = rank_inputs[0]
8119                            .as_ref()
8120                            .ok_or("native EP lost its root input")?;
8121                        let engine = &self.ranks[owner];
8122                        let _main = engine.gpu.enter_main()?;
8123                        let mut peer_input = engine.uninit(experts.input_width)?;
8124                        engine.stream().memcpy_dtod(root_input, &mut peer_input)?;
8125                        peer_input
8126                    };
8127                    rank_inputs[owner] = Some(peer_input);
8128                }
8129
8130                let rank = &experts.ranks[owner];
8131                let engine = &self.ranks[owner];
8132                let owner_input = rank_inputs[owner]
8133                    .as_ref()
8134                    .ok_or("native EP owner input is absent after dispatch")?;
8135                let gate = run_resident_bank_expert_device(
8136                    engine,
8137                    &rank.gate,
8138                    local_expert,
8139                    owner_input,
8140                    1,
8141                )?;
8142                let up = run_resident_bank_expert_device(
8143                    engine,
8144                    &rank.up,
8145                    local_expert,
8146                    owner_input,
8147                    1,
8148                )?;
8149                let activated = {
8150                    let _main = engine.gpu.enter_main()?;
8151                    let mut activated = engine.uninit(experts.expert_width)?;
8152                    if let Some(limit) = activation_limit {
8153                        engine.silu_clamped_mul_host_expf(
8154                            &gate,
8155                            &up,
8156                            limit,
8157                            &mut activated,
8158                            experts.expert_width,
8159                        )?;
8160                    } else {
8161                        engine.silu_mul_host_expf(
8162                            &gate,
8163                            &up,
8164                            &mut activated,
8165                            experts.expert_width,
8166                        )?;
8167                    }
8168                    activated
8169                };
8170                let down = run_resident_bank_expert_device(
8171                    engine,
8172                    &rank.down,
8173                    local_expert,
8174                    &activated,
8175                    1,
8176                )?;
8177                let root_down = if owner == 0 {
8178                    down
8179                } else {
8180                    let _main = root.gpu.enter_main()?;
8181                    let mut root_down = root.uninit(experts.input_width)?;
8182                    root.stream().memcpy_dtod(&down, &mut root_down)?;
8183                    // The peer copy runs on the root stream. Keep its remote source alive until
8184                    // the final root readback synchronizes that stream; otherwise async free can
8185                    // recycle the owner's allocation while cuMemcpyPeerAsync is still reading it.
8186                    remote_down_keepalive.push(down);
8187                    root_down
8188                };
8189                let _main = root.gpu.enter_main()?;
8190                let mut destination = root_output.slice_mut(0..experts.input_width);
8191                root.axpy_host_into(
8192                    &root_down.slice(0..root_down.len()),
8193                    route_weights[pair],
8194                    &mut destination,
8195                    experts.input_width,
8196                )?;
8197            }
8198
8199            let _main = root.gpu.enter_main()?;
8200            let root_output = root.dtoh(&root_output)?;
8201            drop(remote_down_keepalive);
8202            output.extend(root_output);
8203        }
8204        Ok(output)
8205    }
8206}
8207
8208#[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
8209fn validate_column_shape(matrix: E4m3BlockMatrix<'_>, tp: usize) -> Result<(), String> {
8210    if matrix.out_features % tp != 0 {
8211        return Err(format!(
8212            "column-parallel out_features {} is not divisible by TP={tp}",
8213            matrix.out_features
8214        ));
8215    }
8216    let local_out = matrix.out_features / tp;
8217    if !local_out.is_multiple_of(FP8_BLOCK) {
8218        return Err(format!(
8219            "column-parallel output shard {local_out} cuts through a {FP8_BLOCK}-row \
8220             E4M3 scale block"
8221        ));
8222    }
8223    Ok(())
8224}
8225
8226#[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
8227fn step_bf16_canonical_chunk_rows(out_features: usize, tp: usize) -> Result<usize, String> {
8228    if !matches!(tp, 1 | 2 | 4 | 8) {
8229        return Err(format!(
8230            "Step BF16 canonical projection requires TP1/TP2/TP4/TP8, got TP={tp}"
8231        ));
8232    }
8233    if out_features == 0 || !out_features.is_multiple_of(PRODUCT_MAX_CARDS) {
8234        return Err(format!(
8235            "Step BF16 output width {out_features} is not divisible by the TP8 product envelope"
8236        ));
8237    }
8238    let canonical_rows = out_features / PRODUCT_MAX_CARDS;
8239    let local_out = out_features / tp;
8240    if local_out % canonical_rows != 0 {
8241        return Err(format!(
8242            "Step BF16 TP={tp} output shard {local_out} is not divisible by canonical \
8243             {canonical_rows}-row chunks"
8244        ));
8245    }
8246    Ok(canonical_rows)
8247}
8248
8249#[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
8250fn step_bf16_canonical_chunk_cols(in_features: usize, tp: usize) -> Result<usize, String> {
8251    if !matches!(tp, 1 | 2 | 4 | 8) {
8252        return Err(format!(
8253            "Step BF16 canonical row projection requires TP1/TP2/TP4/TP8, got TP={tp}"
8254        ));
8255    }
8256    if in_features == 0 || !in_features.is_multiple_of(PRODUCT_MAX_CARDS) {
8257        return Err(format!(
8258            "Step BF16 input width {in_features} is not divisible by the TP8 product envelope"
8259        ));
8260    }
8261    let canonical_cols = in_features / PRODUCT_MAX_CARDS;
8262    let local_in = in_features / tp;
8263    if local_in % canonical_cols != 0 {
8264        return Err(format!(
8265            "Step BF16 TP={tp} input shard {local_in} is not divisible by canonical \
8266             {canonical_cols}-column chunks"
8267        ));
8268    }
8269    Ok(canonical_cols)
8270}
8271
8272#[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
8273fn validate_row_shape(matrix: E4m3BlockMatrix<'_>, tp: usize) -> Result<(), String> {
8274    if matrix.in_features % tp != 0 {
8275        return Err(format!(
8276            "row-parallel in_features {} is not divisible by TP={tp}",
8277            matrix.in_features
8278        ));
8279    }
8280    let local_in = matrix.in_features / tp;
8281    if !local_in.is_multiple_of(FP8_BLOCK) {
8282        return Err(format!(
8283            "row-parallel input shard {local_in} cuts through a {FP8_BLOCK}-column \
8284             E4M3 scale block"
8285        ));
8286    }
8287    Ok(())
8288}
8289
8290fn upload_rank(
8291    engine: &Engine,
8292    matrix: E4m3BlockMatrix<'_>,
8293) -> Result<ResidentE4m3Rank, Box<dyn std::error::Error>> {
8294    let _main = engine.gpu.enter_main()?;
8295    matrix.validate()?;
8296    Ok(ResidentE4m3Rank {
8297        codes: engine.htod_bytes(matrix.codes)?,
8298        scales: engine.htod(matrix.scales)?,
8299        out_features: matrix.out_features,
8300        in_features: matrix.in_features,
8301    })
8302}
8303
8304fn upload_bf16_rank(
8305    engine: &Engine,
8306    matrix: Bf16Matrix<'_>,
8307    f32_mirror: bool,
8308) -> Result<ResidentBf16Rank, Box<dyn std::error::Error>> {
8309    let _main = engine.gpu.enter_main()?;
8310    matrix.validate()?;
8311    let bytes = engine.htod_bytes(matrix.bytes)?;
8312    let weight = if f32_mirror {
8313        let values = matrix
8314            .out_features
8315            .checked_mul(matrix.in_features)
8316            .ok_or("resident BF16 mirror element count overflow")?;
8317        ResidentBf16Weight::F32(engine.bf16_to_f32(&bytes.slice(0..bytes.len()), values)?)
8318    } else {
8319        ResidentBf16Weight::Bf16(bytes)
8320    };
8321    // MEMRA_STEP_TP_W8: encode the q8_0 decode mirror once, here, while the bf16 bytes are
8322    // already resident. Rows whose in_features is not a multiple of 32 have no q8_0 form and
8323    // simply keep the bf16 program (the decode arm checks for the mirror, never assumes it).
8324    let q8 = if crate::step_tp_w8_on() && matrix.in_features.is_multiple_of(32) {
8325        if let ResidentBf16Weight::Bf16(bytes) = &weight {
8326            // Two steps, because the mmvq rp kernel does NOT read ggml-interleaved 34-byte
8327            // blocks: it reads a PLANAR mirror (all quants, then all half scales — the
8328            // q4_0/NVFP4 rp convention). The encoder writes the interleaved form and
8329            // `build_q8_rp4_raw` — the same kernel the GGUF loader uses — splits it into
8330            // planes. Skipping the split is what made the first W8 gate return zeros
8331            // (verify-prefill argmax=0, maxdiff=0.000e0).
8332            let row_bytes = Engine::q8_0_row_bytes(matrix.in_features);
8333            let mut interleaved = engine.alloc_u8_uninit(matrix.out_features * row_bytes)?;
8334            engine.encode_q8_0_from_bf16(
8335                bytes,
8336                &mut interleaved,
8337                matrix.in_features,
8338                matrix.out_features,
8339            )?;
8340            let mirror =
8341                engine.build_q8_rp4_raw(&interleaved, matrix.in_features, matrix.out_features)?;
8342            Some(mirror)
8343        } else {
8344            None
8345        }
8346    } else {
8347        None
8348    };
8349    Ok(ResidentBf16Rank {
8350        weight,
8351        out_features: matrix.out_features,
8352        in_features: matrix.in_features,
8353        q8,
8354    })
8355}
8356
8357fn upload_expert_bank_rank(
8358    engine: &Engine,
8359    bank: E4m3ExpertBank<'_>,
8360    expert_range: Range<usize>,
8361) -> Result<ResidentE4m3ExpertBankRank, Box<dyn std::error::Error>> {
8362    let _main = engine.gpu.enter_main()?;
8363    bank.validate()?;
8364    if expert_range.start >= expert_range.end || expert_range.end > bank.expert_count {
8365        return Err(format!(
8366            "invalid EP expert range {expert_range:?} for {} experts",
8367            bank.expert_count
8368        )
8369        .into());
8370    }
8371    let code_stride = bank.out_features * bank.in_features;
8372    let scale_stride = bank.out_features.div_ceil(FP8_BLOCK) * bank.in_features.div_ceil(FP8_BLOCK);
8373    Ok(ResidentE4m3ExpertBankRank {
8374        codes: engine.htod_bytes(
8375            &bank.codes[expert_range.start * code_stride..expert_range.end * code_stride],
8376        )?,
8377        scales: engine.htod(
8378            &bank.scales[expert_range.start * scale_stride..expert_range.end * scale_stride],
8379        )?,
8380        expert_range,
8381        out_features: bank.out_features,
8382        in_features: bank.in_features,
8383        code_stride,
8384        scale_stride,
8385        k_blocks: None,
8386    })
8387}
8388
8389#[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
8390fn validate_column_bank_shape(bank: E4m3ExpertBank<'_>, tp: usize) -> Result<(), String> {
8391    if bank.out_features % tp != 0 {
8392        return Err(format!(
8393            "TP expert output width {} is not divisible by TP={tp}",
8394            bank.out_features
8395        ));
8396    }
8397    let local_out = bank.out_features / tp;
8398    if !local_out.is_multiple_of(FP8_BLOCK) {
8399        return Err(format!(
8400            "TP expert output shard {local_out} cuts through a {FP8_BLOCK}-row E4M3 scale block"
8401        ));
8402    }
8403    Ok(())
8404}
8405
8406#[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
8407fn validate_row_bank_shape(bank: E4m3ExpertBank<'_>, tp: usize) -> Result<(), String> {
8408    if bank.in_features % tp != 0 {
8409        return Err(format!(
8410            "TP expert input width {} is not divisible by TP={tp}",
8411            bank.in_features
8412        ));
8413    }
8414    let local_in = bank.in_features / tp;
8415    if !local_in.is_multiple_of(FP8_BLOCK) {
8416        return Err(format!(
8417            "TP expert input shard {local_in} cuts through a {FP8_BLOCK}-column E4M3 scale block"
8418        ));
8419    }
8420    Ok(())
8421}
8422
8423fn upload_column_bank_rank(
8424    engine: &Engine,
8425    bank: E4m3ExpertBank<'_>,
8426    tp: usize,
8427    rank: usize,
8428) -> Result<ResidentE4m3ExpertBankRank, Box<dyn std::error::Error>> {
8429    let _main = engine.gpu.enter_main()?;
8430    let packed = pack_column_bank_rank(bank, tp, rank)?;
8431    Ok(ResidentE4m3ExpertBankRank {
8432        codes: engine.htod_bytes(&packed.codes)?,
8433        scales: engine.htod(&packed.scales)?,
8434        expert_range: packed.expert_range,
8435        out_features: packed.out_features,
8436        in_features: packed.in_features,
8437        code_stride: packed.code_stride,
8438        scale_stride: packed.scale_stride,
8439        k_blocks: packed.k_blocks,
8440    })
8441}
8442
8443fn pack_column_bank_rank(
8444    bank: E4m3ExpertBank<'_>,
8445    tp: usize,
8446    rank: usize,
8447) -> Result<PackedE4m3ExpertBankRank, String> {
8448    bank.validate()?;
8449    validate_column_bank_shape(bank, tp)?;
8450    if rank >= tp {
8451        return Err(format!("TP rank {rank} outside 0..{tp}"));
8452    }
8453    let local_out = bank.out_features / tp;
8454    let full_code_stride = bank.out_features * bank.in_features;
8455    let local_code_stride = local_out * bank.in_features;
8456    let scale_cols = bank.in_features.div_ceil(FP8_BLOCK);
8457    let full_scale_stride = bank.out_features.div_ceil(FP8_BLOCK) * scale_cols;
8458    let local_scale_rows = local_out / FP8_BLOCK;
8459    let local_scale_stride = local_scale_rows * scale_cols;
8460    let mut codes = Vec::with_capacity(bank.expert_count * local_code_stride);
8461    let mut scales = Vec::with_capacity(bank.expert_count * local_scale_stride);
8462    let row_start = rank * local_out;
8463    let scale_row_start = rank * local_scale_rows;
8464    for expert in 0..bank.expert_count {
8465        let code_start = expert * full_code_stride + row_start * bank.in_features;
8466        codes.extend_from_slice(&bank.codes[code_start..code_start + local_code_stride]);
8467        let scale_start = expert * full_scale_stride + scale_row_start * scale_cols;
8468        scales.extend_from_slice(&bank.scales[scale_start..scale_start + local_scale_stride]);
8469    }
8470    Ok(PackedE4m3ExpertBankRank {
8471        codes,
8472        scales,
8473        expert_range: 0..bank.expert_count,
8474        out_features: local_out,
8475        in_features: bank.in_features,
8476        code_stride: local_code_stride,
8477        scale_stride: local_scale_stride,
8478        k_blocks: None,
8479    })
8480}
8481
8482fn upload_row_bank_rank(
8483    engine: &Engine,
8484    bank: E4m3ExpertBank<'_>,
8485    tp: usize,
8486    rank: usize,
8487) -> Result<ResidentE4m3ExpertBankRank, Box<dyn std::error::Error>> {
8488    let _main = engine.gpu.enter_main()?;
8489    let packed = pack_row_bank_rank(bank, tp, rank)?;
8490    Ok(ResidentE4m3ExpertBankRank {
8491        codes: engine.htod_bytes(&packed.codes)?,
8492        scales: engine.htod(&packed.scales)?,
8493        expert_range: packed.expert_range,
8494        out_features: packed.out_features,
8495        in_features: packed.in_features,
8496        code_stride: packed.code_stride,
8497        scale_stride: packed.scale_stride,
8498        k_blocks: packed.k_blocks,
8499    })
8500}
8501
8502fn pack_row_bank_rank(
8503    bank: E4m3ExpertBank<'_>,
8504    tp: usize,
8505    rank: usize,
8506) -> Result<PackedE4m3ExpertBankRank, String> {
8507    bank.validate()?;
8508    validate_row_bank_shape(bank, tp)?;
8509    if rank >= tp {
8510        return Err(format!("TP rank {rank} outside 0..{tp}"));
8511    }
8512    let local_in = bank.in_features / tp;
8513    let full_code_stride = bank.out_features * bank.in_features;
8514    let local_code_stride = bank.out_features * local_in;
8515    let full_scale_cols = bank.in_features.div_ceil(FP8_BLOCK);
8516    let local_scale_cols = local_in / FP8_BLOCK;
8517    let scale_rows = bank.out_features.div_ceil(FP8_BLOCK);
8518    let full_scale_stride = scale_rows * full_scale_cols;
8519    let local_scale_stride = scale_rows * local_scale_cols;
8520    let global_block_start = rank * local_scale_cols;
8521    let mut codes = Vec::with_capacity(bank.expert_count * local_code_stride);
8522    let mut scales = Vec::with_capacity(bank.expert_count * local_scale_stride);
8523    for expert in 0..bank.expert_count {
8524        let expert_code_start = expert * full_code_stride;
8525        let expert_scale_start = expert * full_scale_stride;
8526        for local_block in 0..local_scale_cols {
8527            let global_block = global_block_start + local_block;
8528            let column_start = global_block * FP8_BLOCK;
8529            for row in 0..bank.out_features {
8530                let start = expert_code_start + row * bank.in_features + column_start;
8531                codes.extend_from_slice(&bank.codes[start..start + FP8_BLOCK]);
8532            }
8533            for row in 0..scale_rows {
8534                scales.push(bank.scales[expert_scale_start + row * full_scale_cols + global_block]);
8535            }
8536        }
8537    }
8538    Ok(PackedE4m3ExpertBankRank {
8539        codes,
8540        scales,
8541        expert_range: 0..bank.expert_count,
8542        out_features: bank.out_features,
8543        in_features: local_in,
8544        code_stride: local_code_stride,
8545        scale_stride: local_scale_stride,
8546        k_blocks: Some(local_scale_cols),
8547    })
8548}
8549
8550fn validate_resident_ranks(engines: &[Engine], ranks: &[ResidentE4m3Rank]) -> Result<(), String> {
8551    if engines.len() != ranks.len() {
8552        return Err(format!(
8553            "resident TP rank count {} != runtime rank count {}",
8554            ranks.len(),
8555            engines.len()
8556        ));
8557    }
8558    for (rank, (engine, matrix)) in engines.iter().zip(ranks).enumerate() {
8559        let device = engine.ctx().ordinal();
8560        if matrix.codes.ordinal() != device || matrix.scales.ordinal() != device {
8561            return Err(format!(
8562                "resident TP rank {rank} is not owned by runtime device {device}"
8563            ));
8564        }
8565    }
8566    Ok(())
8567}
8568
8569fn validate_tp_bank_residency(
8570    engines: &[Engine],
8571    experts: &ResidentTpExpertBank,
8572) -> Result<(), String> {
8573    if engines.len() != experts.gate.len()
8574        || engines.len() != experts.up.len()
8575        || engines.len() != experts.down.len()
8576    {
8577        return Err(format!(
8578            "resident TP expert-bank rank counts gate={} up={} down={} != runtime {}",
8579            experts.gate.len(),
8580            experts.up.len(),
8581            experts.down.len(),
8582            engines.len()
8583        ));
8584    }
8585    for (rank, engine) in engines.iter().enumerate() {
8586        let device = engine.ctx().ordinal();
8587        for (projection, bank) in [
8588            ("gate", &experts.gate[rank]),
8589            ("up", &experts.up[rank]),
8590            ("down", &experts.down[rank]),
8591        ] {
8592            if bank.codes.ordinal() != device || bank.scales.ordinal() != device {
8593                return Err(format!(
8594                    "resident TP rank {rank} {projection} bank is not owned by runtime device \
8595                     {device}"
8596                ));
8597            }
8598        }
8599    }
8600    Ok(())
8601}
8602
8603fn validate_ep_residency(
8604    engines: &[Engine],
8605    experts: &ResidentExpertParallel,
8606) -> Result<(), String> {
8607    if engines.len() != experts.ranks.len() {
8608        return Err(format!(
8609            "resident EP rank count {} != runtime rank count {}",
8610            experts.ranks.len(),
8611            engines.len()
8612        ));
8613    }
8614    for (rank, (engine, resident)) in engines.iter().zip(&experts.ranks).enumerate() {
8615        let device = engine.ctx().ordinal();
8616        for (projection, bank) in [
8617            ("gate", &resident.gate),
8618            ("up", &resident.up),
8619            ("down", &resident.down),
8620        ] {
8621            if bank.codes.ordinal() != device || bank.scales.ordinal() != device {
8622                return Err(format!(
8623                    "resident EP rank {rank} {projection} bank is not owned by runtime device \
8624                     {device}"
8625                ));
8626            }
8627        }
8628    }
8629    Ok(())
8630}
8631
8632fn run_rank(
8633    engine: &Engine,
8634    matrix: E4m3BlockMatrix<'_>,
8635    activations: &[f32],
8636    tokens: usize,
8637) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
8638    let _main = engine.gpu.enter_main()?;
8639    let codes = engine.htod_bytes(matrix.codes)?;
8640    let scales = engine.htod(matrix.scales)?;
8641    let activations = engine.htod(activations)?;
8642    let output = engine.qmatvec_mmq_fp8_blk(
8643        &codes,
8644        &scales,
8645        &activations,
8646        tokens,
8647        matrix.in_features,
8648        matrix.out_features,
8649    )?;
8650    engine.dtoh(&output)
8651}
8652
8653fn run_resident_rank(
8654    engine: &Engine,
8655    matrix: &ResidentE4m3Rank,
8656    activations: &[f32],
8657    tokens: usize,
8658) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
8659    let _main = engine.gpu.enter_main()?;
8660    let activations = engine.htod(activations)?;
8661    let output = engine.qmatvec_mmq_fp8_blk(
8662        &matrix.codes,
8663        &matrix.scales,
8664        &activations,
8665        tokens,
8666        matrix.in_features,
8667        matrix.out_features,
8668    )?;
8669    engine.dtoh(&output)
8670}
8671
8672fn run_resident_bf16_rank(
8673    engine: &Engine,
8674    matrix: &ResidentBf16Rank,
8675    activations: &[f32],
8676    tokens: usize,
8677    canonical_chunk_rows: Option<usize>,
8678) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
8679    let _main = engine.gpu.enter_main()?;
8680    let activations = engine.htod(activations)?;
8681    let output = run_resident_bf16_rank_device(
8682        engine,
8683        matrix,
8684        &activations,
8685        tokens,
8686        canonical_chunk_rows,
8687        false,
8688    )?;
8689    engine.dtoh(&output)
8690}
8691
8692fn run_resident_bf16_rank_device(
8693    engine: &Engine,
8694    matrix: &ResidentBf16Rank,
8695    activations: &CudaSlice<f32>,
8696    tokens: usize,
8697    canonical_chunk_rows: Option<usize>,
8698    strided_chunk_output: bool,
8699) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
8700    let _main = engine.gpu.enter_main()?;
8701    if activations.ordinal() != engine.ctx().ordinal() {
8702        return Err(format!(
8703            "resident BF16 activation device {} != rank device {}",
8704            activations.ordinal(),
8705            engine.ctx().ordinal()
8706        )
8707        .into());
8708    }
8709    if activations.len() != tokens * matrix.in_features {
8710        return Err(format!(
8711            "resident BF16 activation count {} != {tokens}x{}",
8712            activations.len(),
8713            matrix.in_features
8714        )
8715        .into());
8716    }
8717    match (&matrix.weight, canonical_chunk_rows) {
8718        (ResidentBf16Weight::Bf16(bytes), Some(rows)) => engine
8719            .linear_bf16_resident_canonical_rows(
8720                activations,
8721                bytes,
8722                tokens,
8723                matrix.in_features,
8724                matrix.out_features,
8725                rows,
8726            ),
8727        (ResidentBf16Weight::Bf16(bytes), None) => engine.linear_bf16_resident(
8728            activations,
8729            bytes,
8730            tokens,
8731            matrix.in_features,
8732            matrix.out_features,
8733        ),
8734        (ResidentBf16Weight::F32(values), Some(rows)) if strided_chunk_output => engine
8735            .linear_f32_resident_canonical_rows_strided(
8736                activations,
8737                values,
8738                tokens,
8739                matrix.in_features,
8740                matrix.out_features,
8741                rows,
8742            ),
8743        (ResidentBf16Weight::F32(values), Some(rows)) => engine.linear_f32_resident_canonical_rows(
8744            activations,
8745            values,
8746            tokens,
8747            matrix.in_features,
8748            matrix.out_features,
8749            rows,
8750        ),
8751        (ResidentBf16Weight::F32(values), None) => engine.linear(
8752            activations,
8753            values,
8754            tokens,
8755            matrix.in_features,
8756            matrix.out_features,
8757        ),
8758    }
8759}
8760
8761fn validate_resident_bf16_ranks(
8762    engines: &[Engine],
8763    ranks: &[ResidentBf16Rank],
8764) -> Result<(), String> {
8765    if engines.len() != ranks.len() {
8766        return Err(format!(
8767            "resident BF16 TP rank count {} != runtime rank count {}",
8768            ranks.len(),
8769            engines.len(),
8770        ));
8771    }
8772    for (rank, (engine, matrix)) in engines.iter().zip(ranks).enumerate() {
8773        let device = engine.ctx().ordinal();
8774        if matrix.weight.ordinal() != device {
8775            return Err(format!(
8776                "resident BF16 TP rank {rank} is not owned by runtime device {device}"
8777            ));
8778        }
8779    }
8780    Ok(())
8781}
8782
8783fn validate_step_bf16_row_residency(
8784    engines: &[Engine],
8785    matrix: &ResidentStepBf16RowParallel,
8786) -> Result<(), String> {
8787    if engines.len() != matrix.ranks.len() {
8788        return Err(format!(
8789            "resident Step BF16 row rank count {} != runtime rank count {}",
8790            matrix.ranks.len(),
8791            engines.len(),
8792        ));
8793    }
8794    let canonical_cols = step_bf16_canonical_chunk_cols(matrix.in_features, engines.len())?;
8795    if matrix.canonical_chunk_cols != canonical_cols {
8796        return Err(format!(
8797            "resident Step BF16 row canonical columns {} != registered {canonical_cols}",
8798            matrix.canonical_chunk_cols
8799        ));
8800    }
8801    let blocks_per_rank = PRODUCT_MAX_CARDS / engines.len();
8802    for (rank, (engine, blocks)) in engines.iter().zip(&matrix.ranks).enumerate() {
8803        if blocks.len() != blocks_per_rank {
8804            return Err(format!(
8805                "resident Step BF16 row rank {rank} has {} blocks, expected {blocks_per_rank}",
8806                blocks.len()
8807            ));
8808        }
8809        let device = engine.ctx().ordinal();
8810        for (block, resident) in blocks.iter().enumerate() {
8811            if resident.weight.ordinal() != device
8812                || resident.in_features != canonical_cols
8813                || resident.out_features != matrix.out_features
8814            {
8815                return Err(format!(
8816                    "resident Step BF16 row rank {rank} block {block} has inconsistent \
8817                     device or geometry"
8818                ));
8819            }
8820        }
8821    }
8822    Ok(())
8823}
8824
8825fn validate_replicated_device_rows(
8826    engines: &[Engine],
8827    rows: &ResidentReplicatedDeviceRows,
8828) -> Result<(), String> {
8829    let rank_lengths = rows
8830        .ranks
8831        .iter()
8832        .map(|rank_rows| rank_rows.len())
8833        .collect::<Vec<_>>();
8834    replicated_device_row_values(rows.tokens, rows.width, engines.len(), &rank_lengths)?;
8835    if rows
8836        .ranks
8837        .iter()
8838        .zip(engines)
8839        .any(|(rank_rows, engine)| rank_rows.ordinal() != engine.ctx().ordinal())
8840    {
8841        return Err("replicated device rows are owned by the wrong CUDA contexts".into());
8842    }
8843    Ok(())
8844}
8845
8846fn replicated_device_row_values(
8847    tokens: usize,
8848    width: usize,
8849    expected_ranks: usize,
8850    rank_lengths: &[usize],
8851) -> Result<usize, String> {
8852    let values = tokens
8853        .checked_mul(width)
8854        .ok_or("replicated device row size overflow")?;
8855    if tokens == 0
8856        || width == 0
8857        || expected_ranks == 0
8858        || rank_lengths.len() != expected_ranks
8859        || rank_lengths.iter().any(|&rank_len| rank_len != values)
8860    {
8861        return Err(format!(
8862            "replicated device rows have inconsistent geometry tokens={} width={} ranks={}/{}",
8863            tokens,
8864            width,
8865            rank_lengths.len(),
8866            expected_ranks
8867        ));
8868    }
8869    Ok(values)
8870}
8871
8872fn replicated_device_row_source_values(
8873    tokens: usize,
8874    width: usize,
8875    source_len: usize,
8876    source_device: usize,
8877    root_device: usize,
8878) -> Result<usize, String> {
8879    let values = tokens
8880        .checked_mul(width)
8881        .ok_or("replicated device row size overflow")?;
8882    if tokens == 0 || width == 0 || source_len != values || source_device != root_device {
8883        return Err(format!(
8884            "replicated device row source has inconsistent geometry/device \
8885             tokens={tokens} width={width} source={source_len}@{source_device} root={root_device}"
8886        ));
8887    }
8888    Ok(values)
8889}
8890
8891#[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
8892fn bf16_column_shard(
8893    matrix: Bf16Matrix<'_>,
8894    tp: usize,
8895    rank: usize,
8896) -> Result<Bf16Matrix<'_>, String> {
8897    matrix.validate()?;
8898    if tp == 0 || rank >= tp || matrix.out_features % tp != 0 {
8899        return Err(format!(
8900            "invalid BF16 column shard out={} TP={tp} rank={rank}",
8901            matrix.out_features
8902        ));
8903    }
8904    let local_out = matrix.out_features / tp;
8905    let row_bytes = matrix.in_features * 2;
8906    let start = rank * local_out * row_bytes;
8907    Ok(Bf16Matrix {
8908        bytes: &matrix.bytes[start..start + local_out * row_bytes],
8909        out_features: local_out,
8910        in_features: matrix.in_features,
8911    })
8912}
8913
8914#[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
8915fn bf16_row_shard(matrix: Bf16Matrix<'_>, tp: usize, rank: usize) -> Result<Vec<u8>, String> {
8916    matrix.validate()?;
8917    if tp == 0 || rank >= tp || matrix.in_features % tp != 0 {
8918        return Err(format!(
8919            "invalid BF16 row shard in={} TP={tp} rank={rank}",
8920            matrix.in_features
8921        ));
8922    }
8923    let local_in = matrix.in_features / tp;
8924    let mut bytes = Vec::with_capacity(matrix.out_features * local_in * 2);
8925    for row in 0..matrix.out_features {
8926        let start = (row * matrix.in_features + rank * local_in) * 2;
8927        bytes.extend_from_slice(&matrix.bytes[start..start + local_in * 2]);
8928    }
8929    Ok(bytes)
8930}
8931
8932fn bf16_row_block(
8933    matrix: Bf16Matrix<'_>,
8934    col_start: usize,
8935    block_cols: usize,
8936) -> Result<Vec<u8>, String> {
8937    matrix.validate()?;
8938    let col_end = col_start
8939        .checked_add(block_cols)
8940        .ok_or("BF16 row block column overflow")?;
8941    if block_cols == 0 || col_end > matrix.in_features {
8942        return Err(format!(
8943            "invalid BF16 row block columns {col_start}..{col_end} for input width {}",
8944            matrix.in_features
8945        ));
8946    }
8947    let mut bytes = Vec::with_capacity(matrix.out_features * block_cols * 2);
8948    for row in 0..matrix.out_features {
8949        let start = (row * matrix.in_features + col_start) * 2;
8950        bytes.extend_from_slice(&matrix.bytes[start..start + block_cols * 2]);
8951    }
8952    Ok(bytes)
8953}
8954
8955fn run_resident_bank_expert(
8956    engine: &Engine,
8957    bank: &ResidentE4m3ExpertBankRank,
8958    local_expert: usize,
8959    activations: &[f32],
8960    tokens: usize,
8961) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
8962    let _main = engine.gpu.enter_main()?;
8963    if bank.k_blocks.is_some() {
8964        return Err("block-major TP row bank requires canonical block execution".into());
8965    }
8966    let local_count = bank.expert_range.end - bank.expert_range.start;
8967    if local_expert >= local_count {
8968        return Err(format!(
8969            "local EP expert {local_expert} outside 0..{local_count} for range {:?}",
8970            bank.expert_range
8971        )
8972        .into());
8973    }
8974    validate_activations(activations, tokens, bank.in_features)?;
8975    let activations = engine.htod(activations)?;
8976    let weight = bank
8977        .codes
8978        .slice(local_expert * bank.code_stride..(local_expert + 1) * bank.code_stride);
8979    let scales = bank
8980        .scales
8981        .slice(local_expert * bank.scale_stride..(local_expert + 1) * bank.scale_stride);
8982    let input = activations.slice(0..activations.len());
8983    let output = engine.qmatvec_mmq_fp8_blk_view(
8984        &weight,
8985        &scales,
8986        &input,
8987        tokens,
8988        bank.in_features,
8989        bank.out_features,
8990    )?;
8991    engine.dtoh(&output)
8992}
8993
8994fn run_resident_bank_expert_block(
8995    engine: &Engine,
8996    bank: &ResidentE4m3ExpertBankRank,
8997    local_expert: usize,
8998    block: usize,
8999    activations: &[f32],
9000) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
9001    let _main = engine.gpu.enter_main()?;
9002    let local_count = bank.expert_range.end - bank.expert_range.start;
9003    if local_expert >= local_count {
9004        return Err(format!(
9005            "local TP expert {local_expert} outside 0..{local_count} for range {:?}",
9006            bank.expert_range
9007        )
9008        .into());
9009    }
9010    let blocks = bank
9011        .k_blocks
9012        .ok_or("TP row bank is not packed in native K-block order")?;
9013    if block >= blocks {
9014        return Err(format!("TP row block {block} outside 0..{blocks}").into());
9015    }
9016    validate_activations(activations, 1, FP8_BLOCK)?;
9017    let block_code_stride = bank.out_features * FP8_BLOCK;
9018    let block_scale_stride = bank.out_features.div_ceil(FP8_BLOCK);
9019    if bank.in_features != blocks * FP8_BLOCK
9020        || bank.code_stride != blocks * block_code_stride
9021        || bank.scale_stride != blocks * block_scale_stride
9022    {
9023        return Err("TP row bank block-major geometry is inconsistent".into());
9024    }
9025
9026    let expert_code_start = local_expert * bank.code_stride;
9027    let expert_scale_start = local_expert * bank.scale_stride;
9028    let weight = bank.codes.slice(
9029        expert_code_start + block * block_code_stride
9030            ..expert_code_start + (block + 1) * block_code_stride,
9031    );
9032    let scales = bank.scales.slice(
9033        expert_scale_start + block * block_scale_stride
9034            ..expert_scale_start + (block + 1) * block_scale_stride,
9035    );
9036    let activations = engine.htod(activations)?;
9037    let input = activations.slice(0..activations.len());
9038    let output = engine.qmatvec_mmq_fp8_blk_view(
9039        &weight,
9040        &scales,
9041        &input,
9042        1,
9043        FP8_BLOCK,
9044        bank.out_features,
9045    )?;
9046    engine.dtoh(&output)
9047}
9048
9049fn run_resident_bank_expert_device(
9050    engine: &Engine,
9051    bank: &ResidentE4m3ExpertBankRank,
9052    local_expert: usize,
9053    activations: &CudaSlice<f32>,
9054    tokens: usize,
9055) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
9056    let _main = engine.gpu.enter_main()?;
9057    if bank.k_blocks.is_some() {
9058        return Err("block-major TP row bank requires canonical block execution".into());
9059    }
9060    let local_count = bank.expert_range.end - bank.expert_range.start;
9061    if local_expert >= local_count {
9062        return Err(format!(
9063            "local TP expert {local_expert} outside 0..{local_count} for range {:?}",
9064            bank.expert_range
9065        )
9066        .into());
9067    }
9068    let expected = tokens
9069        .checked_mul(bank.in_features)
9070        .ok_or("native TP activation size overflow")?;
9071    if activations.len() != expected || activations.ordinal() != engine.ctx().ordinal() {
9072        return Err(format!(
9073            "native TP activation len/device {}/{} != expected {expected}/{}",
9074            activations.len(),
9075            activations.ordinal(),
9076            engine.ctx().ordinal()
9077        )
9078        .into());
9079    }
9080    let weight = bank
9081        .codes
9082        .slice(local_expert * bank.code_stride..(local_expert + 1) * bank.code_stride);
9083    let scales = bank
9084        .scales
9085        .slice(local_expert * bank.scale_stride..(local_expert + 1) * bank.scale_stride);
9086    let input = activations.slice(0..activations.len());
9087    engine.qmatvec_mmq_fp8_blk_view(
9088        &weight,
9089        &scales,
9090        &input,
9091        tokens,
9092        bank.in_features,
9093        bank.out_features,
9094    )
9095}
9096
9097fn run_resident_bank_expert_block_device(
9098    engine: &Engine,
9099    bank: &ResidentE4m3ExpertBankRank,
9100    local_expert: usize,
9101    block: usize,
9102    activations: &cudarc::driver::CudaView<'_, f32>,
9103) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
9104    let _main = engine.gpu.enter_main()?;
9105    let local_count = bank.expert_range.end - bank.expert_range.start;
9106    if local_expert >= local_count {
9107        return Err(format!(
9108            "local TP expert {local_expert} outside 0..{local_count} for range {:?}",
9109            bank.expert_range
9110        )
9111        .into());
9112    }
9113    let blocks = bank
9114        .k_blocks
9115        .ok_or("native TP row bank is not packed in checkpoint-block order")?;
9116    if block >= blocks {
9117        return Err(format!("native TP row block {block} outside 0..{blocks}").into());
9118    }
9119    let activation_device = activations.stream().context().ordinal();
9120    if activations.len() != FP8_BLOCK || activation_device != engine.ctx().ordinal() {
9121        return Err(format!(
9122            "native TP block activation len/device {}/{} != expected {FP8_BLOCK}/{}",
9123            activations.len(),
9124            activation_device,
9125            engine.ctx().ordinal()
9126        )
9127        .into());
9128    }
9129    let block_code_stride = bank.out_features * FP8_BLOCK;
9130    let block_scale_stride = bank.out_features.div_ceil(FP8_BLOCK);
9131    if bank.in_features != blocks * FP8_BLOCK
9132        || bank.code_stride != blocks * block_code_stride
9133        || bank.scale_stride != blocks * block_scale_stride
9134    {
9135        return Err("native TP row bank block-major geometry is inconsistent".into());
9136    }
9137    let expert_code_start = local_expert * bank.code_stride;
9138    let expert_scale_start = local_expert * bank.scale_stride;
9139    let weight = bank.codes.slice(
9140        expert_code_start + block * block_code_stride
9141            ..expert_code_start + (block + 1) * block_code_stride,
9142    );
9143    let scales = bank.scales.slice(
9144        expert_scale_start + block * block_scale_stride
9145            ..expert_scale_start + (block + 1) * block_scale_stride,
9146    );
9147    engine.qmatvec_mmq_fp8_blk_view(
9148        &weight,
9149        &scales,
9150        activations,
9151        1,
9152        FP8_BLOCK,
9153        bank.out_features,
9154    )
9155}
9156
9157/// Grant `accessor` the right to reach `owner`'s memory — BOTH halves of the grant, which is
9158/// the part every caller gets wrong exactly once:
9159///
9160///   1. `cuCtxEnablePeerAccess`, which covers legacy `cuMemAlloc` allocations, and
9161///   2. `cuMemPoolSetAccess` on `owner`'s DEFAULT MEMORY POOL, because
9162///      `cuCtxEnablePeerAccess` does NOT map STREAM-ORDERED POOL allocations and every
9163///      normal memra buffer is one (the same note `pp.rs:1543`/`pp.rs:1578` carries).
9164///
9165/// Extracted from [`configure_native_p2p`] (which now calls it per ordered pair) so a seam
9166/// holding two `&Engine` rather than a `&[Engine]` — the glm5 TP-2 runtime — reuses the exact
9167/// grant sequence instead of growing a second, drifting copy of it. Directed: call it once
9168/// per direction. Refuses by name when `cuDeviceCanAccessPeer` says the pair has no path,
9169/// which is the only honest answer: this card class is NOT uniformly peer-connected. Some
9170/// 8-GPU host classes present PEER ISLANDS OF TWO — every cross-island cell of a peer-transfer
9171/// matrix reads `N/A` — so a TP group placed across an island boundary has no peer path at all
9172/// and must either stay inside one island or go through host memory. The per-host island map is
9173/// fleet data and lives in the private deployment repo, never here; the engine's job is to
9174/// refuse by name rather than to know which host it is on.
9175pub(crate) fn grant_peer_access(
9176    accessor: &Engine,
9177    owner: &Engine,
9178    label: &str,
9179) -> Result<(), Box<dyn std::error::Error>> {
9180    let (a_dev, o_dev) = (accessor.ctx().ordinal(), owner.ctx().ordinal());
9181    let mut can_access = 0;
9182    unsafe {
9183        cudarc::driver::sys::cuDeviceCanAccessPeer(
9184            &mut can_access,
9185            accessor.ctx().cu_device(),
9186            owner.ctx().cu_device(),
9187        )
9188        .result()?;
9189    }
9190    if can_access == 0 {
9191        return Err(
9192            format!("{label} requires P2P, but dev{a_dev} cannot access dev{o_dev}").into(),
9193        );
9194    }
9195    accessor.ctx().bind_to_thread()?;
9196    let rc = unsafe { cudarc::driver::sys::cuCtxEnablePeerAccess(owner.ctx().cu_ctx(), 0) };
9197    use cudarc::driver::sys::cudaError_enum as E;
9198    if rc != E::CUDA_SUCCESS && rc != E::CUDA_ERROR_PEER_ACCESS_ALREADY_ENABLED {
9199        return Err(format!(
9200            "{label} cuCtxEnablePeerAccess(dev{a_dev} -> dev{o_dev}) failed: {rc:?}"
9201        )
9202        .into());
9203    }
9204    let device = cudarc::driver::result::device::get(o_dev as i32)?;
9205    let mut pool: cudarc::driver::sys::CUmemoryPool = std::ptr::null_mut();
9206    unsafe {
9207        cudarc::driver::sys::cuDeviceGetDefaultMemPool(&mut pool, device).result()?;
9208    }
9209    let desc = cudarc::driver::sys::CUmemAccessDesc {
9210        location: cudarc::driver::sys::CUmemLocation {
9211            type_: cudarc::driver::sys::CUmemLocationType::CU_MEM_LOCATION_TYPE_DEVICE,
9212            id: a_dev as i32,
9213        },
9214        flags: cudarc::driver::sys::CUmemAccess_flags::CU_MEM_ACCESS_FLAGS_PROT_READWRITE,
9215    };
9216    let rc = unsafe { cudarc::driver::sys::cuMemPoolSetAccess(pool, &desc, 1) };
9217    if rc != cudarc::driver::sys::cudaError_enum::CUDA_SUCCESS {
9218        return Err(format!(
9219            "{label} cuMemPoolSetAccess(dev{o_dev} pool -> dev{a_dev}) failed: {rc:?}"
9220        )
9221        .into());
9222    }
9223    Ok(())
9224}
9225
9226fn configure_native_p2p(
9227    ranks: &[Engine],
9228    devices: &[usize],
9229) -> Result<(), Box<dyn std::error::Error>> {
9230    if ranks.len() != devices.len() || ranks.len() < 2 {
9231        return Err("native TP P2P setup requires matching multi-rank devices".into());
9232    }
9233    for (rank, (&device, engine)) in devices.iter().zip(ranks).enumerate() {
9234        if engine.ctx().ordinal() != device {
9235            return Err(format!(
9236                "native TP rank {rank} context device {} != requested device {device}",
9237                engine.ctx().ordinal()
9238            )
9239            .into());
9240        }
9241    }
9242
9243    for src in 0..ranks.len() {
9244        for dst in 0..ranks.len() {
9245            if src == dst {
9246                continue;
9247            }
9248            grant_peer_access(&ranks[src], &ranks[dst], "native TP")?;
9249        }
9250    }
9251
9252    for src in 0..ranks.len() {
9253        for dst in 0..ranks.len() {
9254            if src == dst {
9255                continue;
9256            }
9257            for &words in NATIVE_P2P_PROBE_WORDS {
9258                let expected = (0..words)
9259                    .map(|index| {
9260                        (index as u32)
9261                            .wrapping_mul(0x9e37_79b9)
9262                            .wrapping_add(((src as u32) << 16) | dst as u32)
9263                    })
9264                    .collect::<Vec<_>>();
9265                let poison = expected.iter().map(|value| !value).collect::<Vec<_>>();
9266                let source = ranks[src].htod_u32_v(&expected)?;
9267                let mut destination = ranks[dst].htod_u32_v(&poison)?;
9268                ranks[dst].stream().memcpy_dtod(&source, &mut destination)?;
9269                let actual = ranks[dst].dtoh_u32(&destination)?;
9270                if actual != expected {
9271                    let mismatches = actual
9272                        .iter()
9273                        .zip(&expected)
9274                        .filter(|(actual, expected)| actual != expected)
9275                        .count();
9276                    return Err(format!(
9277                        "native TP peer probe dev{}->dev{} failed at {} bytes: \
9278                         {mismatches}/{} words differ",
9279                        devices[src],
9280                        devices[dst],
9281                        words * std::mem::size_of::<u32>(),
9282                        expected.len()
9283                    )
9284                    .into());
9285                }
9286            }
9287        }
9288    }
9289    ranks[0].ctx().bind_to_thread()?;
9290    eprintln!(
9291        "[tp] native peer byte-integrity probe PASS: devices={devices:?} \
9292         directions={} byte_ladder={:?} mismatches=0",
9293        ranks.len() * (ranks.len() - 1),
9294        NATIVE_P2P_PROBE_WORDS
9295            .iter()
9296            .map(|words| words * std::mem::size_of::<u32>())
9297            .collect::<Vec<_>>(),
9298    );
9299    Ok(())
9300}
9301
9302fn validate_activations(
9303    activations: &[f32],
9304    tokens: usize,
9305    in_features: usize,
9306) -> Result<(), String> {
9307    let expected = tokens
9308        .checked_mul(in_features)
9309        .ok_or_else(|| "activation size overflow".to_string())?;
9310    if activations.len() != expected {
9311        return Err(format!(
9312            "activation count {} != {tokens}x{in_features} ({expected})",
9313            activations.len()
9314        ));
9315    }
9316    if !activations.iter().all(|value| value.is_finite()) {
9317        return Err("activations contain a non-finite value".to_string());
9318    }
9319    Ok(())
9320}
9321
9322fn column_shard(
9323    matrix: E4m3BlockMatrix<'_>,
9324    tp: usize,
9325    rank: usize,
9326) -> Result<E4m3BlockMatrix<'_>, String> {
9327    let local_out = matrix.out_features / tp;
9328    let row_start = rank * local_out;
9329    let code_start = row_start * matrix.in_features;
9330    let code_end = code_start + local_out * matrix.in_features;
9331    let scale_cols = matrix.in_features.div_ceil(FP8_BLOCK);
9332    let local_scale_rows = local_out / FP8_BLOCK;
9333    let scale_start = rank * local_scale_rows * scale_cols;
9334    let scale_end = scale_start + local_scale_rows * scale_cols;
9335    Ok(E4m3BlockMatrix {
9336        codes: &matrix.codes[code_start..code_end],
9337        scales: &matrix.scales[scale_start..scale_end],
9338        out_features: local_out,
9339        in_features: matrix.in_features,
9340    })
9341}
9342
9343fn row_shard(
9344    matrix: E4m3BlockMatrix<'_>,
9345    tp: usize,
9346    rank: usize,
9347) -> Result<(Vec<u8>, Vec<f32>), String> {
9348    let local_in = matrix.in_features / tp;
9349    let col_start = rank * local_in;
9350    let mut codes = Vec::with_capacity(matrix.out_features * local_in);
9351    for row in 0..matrix.out_features {
9352        let start = row * matrix.in_features + col_start;
9353        codes.extend_from_slice(&matrix.codes[start..start + local_in]);
9354    }
9355
9356    let scale_rows = matrix.out_features.div_ceil(FP8_BLOCK);
9357    let scale_cols = matrix.in_features.div_ceil(FP8_BLOCK);
9358    let local_scale_cols = local_in / FP8_BLOCK;
9359    let scale_col_start = rank * local_scale_cols;
9360    let mut scales = Vec::with_capacity(scale_rows * local_scale_cols);
9361    for row in 0..scale_rows {
9362        let start = row * scale_cols + scale_col_start;
9363        scales.extend_from_slice(&matrix.scales[start..start + local_scale_cols]);
9364    }
9365    Ok((codes, scales))
9366}
9367
9368fn activation_shard(
9369    activations: &[f32],
9370    tokens: usize,
9371    in_features: usize,
9372    tp: usize,
9373    rank: usize,
9374) -> Vec<f32> {
9375    let local_in = in_features / tp;
9376    let col_start = rank * local_in;
9377    let mut shard = Vec::with_capacity(tokens * local_in);
9378    for token in 0..tokens {
9379        let start = token * in_features + col_start;
9380        shard.extend_from_slice(&activations[start..start + local_in]);
9381    }
9382    shard
9383}
9384
9385// ─── Step NVFP4 expert TP program (official Step-3.7-Flash-NVFP4 checkpoint class) ─────────────
9386//
9387// The routed experts of the NVFP4 checkpoint are modelopt-packed: e2m1 codes (2/byte), per-16
9388// UE4M3 sub-scales, and a per-EXPERT `weight_scale_2` f32 macro (~1e-5..1e-4, LOAD-BEARING).
9389// Rank compute repacks each shard host-side into memra block_nvfp4 rows (nibble reorder only —
9390// value-exact, see nvfp4_repack.rs) and runs the proven `qmatvec_nvfp4_fast` dp4a kernel; the
9391// activation q8_1 quantization uses per-32 blocks, and every shard cut here is 64-aligned, so a
9392// rank-local partial is bit-identical to the corresponding slice of the unsharded kernel.
9393//
9394// MACRO CANONICAL ORDER: the macro multiplies each assembled f32 output exactly ONCE — after the
9395// column gather (gate/up) and after the FULL row-parallel reduce (down), never per-partial.
9396// `(a + b) * m` and `a * m + b * m` differ in f32, so applying it per-rank would break the
9397// TP1-vs-TP2 bit gate. Every entry point below follows this order.
9398//
9399// TP2 shard legality is NVFP4-native: column parallelism splits whole output rows (scale rows
9400// ride along, nothing cuts), row parallelism splits input columns at 64-element superblock
9401// boundaries (16-element scale groups nest inside). The 128-block E4M3 constraint does not apply.
9402
9403/// One expert's modelopt NVFP4 projection: packed codes + per-16 UE4M3 scale bytes + macro.
9404#[derive(Clone, Copy)]
9405pub struct Nvfp4BlockMatrix<'a> {
9406    pub codes: &'a [u8],  // [out_features, in_features/2] packed e2m1, row-major
9407    pub scales: &'a [u8], // [out_features, in_features/16] UE4M3 bytes, row-major
9408    pub macro_scale: f32, // per-expert weight_scale_2 dequant multiplier
9409    pub out_features: usize,
9410    pub in_features: usize,
9411}
9412
9413impl Nvfp4BlockMatrix<'_> {
9414    pub fn validate(&self) -> Result<(), String> {
9415        if self.in_features == 0 || self.out_features == 0 {
9416            return Err("NVFP4 matrix has a zero dimension".to_string());
9417        }
9418        if !self.in_features.is_multiple_of(64) {
9419            return Err(format!(
9420                "NVFP4 in_features {} is not 64-aligned (memra block_nvfp4 superblock)",
9421                self.in_features
9422            ));
9423        }
9424        if self.codes.len() != self.out_features * self.in_features / 2 {
9425            return Err(format!(
9426                "NVFP4 code bytes {} != {}x{}/2",
9427                self.codes.len(),
9428                self.out_features,
9429                self.in_features
9430            ));
9431        }
9432        if self.scales.len() != self.out_features * self.in_features / 16 {
9433            return Err(format!(
9434                "NVFP4 scale bytes {} != {}x{}/16",
9435                self.scales.len(),
9436                self.out_features,
9437                self.in_features
9438            ));
9439        }
9440        if !self.macro_scale.is_finite() || self.macro_scale <= 0.0 {
9441            return Err(format!(
9442                "NVFP4 macro scale {} is not finite-positive",
9443                self.macro_scale
9444            ));
9445        }
9446        Ok(())
9447    }
9448}
9449
9450/// Stacked modelopt NVFP4 expert bank (host view over the checkpoint bytes).
9451#[derive(Clone, Copy)]
9452pub struct Nvfp4ExpertBank<'a> {
9453    pub codes: &'a [u8],   // [expert_count, out_features, in_features/2]
9454    pub scales: &'a [u8],  // [expert_count, out_features, in_features/16]
9455    pub macros: &'a [f32], // [expert_count] weight_scale_2
9456    pub expert_count: usize,
9457    pub out_features: usize,
9458    pub in_features: usize,
9459}
9460
9461impl Nvfp4ExpertBank<'_> {
9462    pub fn validate(&self) -> Result<(), String> {
9463        if self.expert_count == 0 {
9464            return Err("NVFP4 expert bank is empty".to_string());
9465        }
9466        if self.macros.len() != self.expert_count {
9467            return Err(format!(
9468                "NVFP4 bank macros {} != expert count {}",
9469                self.macros.len(),
9470                self.expert_count
9471            ));
9472        }
9473        self.expert(0).map(|_| ())
9474    }
9475
9476    pub fn expert(&self, expert: usize) -> Result<Nvfp4BlockMatrix<'_>, String> {
9477        if expert >= self.expert_count {
9478            return Err(format!("expert {expert} outside 0..{}", self.expert_count));
9479        }
9480        let code_stride = self.out_features * self.in_features / 2;
9481        let scale_stride = self.out_features * self.in_features / 16;
9482        if self.codes.len() != self.expert_count * code_stride
9483            || self.scales.len() != self.expert_count * scale_stride
9484        {
9485            return Err("NVFP4 bank byte extents do not match the declared geometry".to_string());
9486        }
9487        let matrix = Nvfp4BlockMatrix {
9488            codes: &self.codes[expert * code_stride..(expert + 1) * code_stride],
9489            scales: &self.scales[expert * scale_stride..(expert + 1) * scale_stride],
9490            macro_scale: self.macros[expert],
9491            out_features: self.out_features,
9492            in_features: self.in_features,
9493        };
9494        matrix.validate()?;
9495        Ok(matrix)
9496    }
9497}
9498
9499/// One rank's resident repacked NVFP4 shard: memra block_nvfp4 rows on device.
9500pub struct ResidentNvfp4Rank {
9501    blocks: crate::CudaSlice<u8>,
9502    macro_scale: f32,
9503    out_features: usize,
9504    in_features: usize,
9505    row_bytes: usize,
9506}
9507
9508pub struct ResidentNvfp4ColumnParallel {
9509    ranks: Vec<ResidentNvfp4Rank>,
9510    pub out_features: usize,
9511    pub in_features: usize,
9512}
9513
9514pub struct ResidentNvfp4RowParallel {
9515    ranks: Vec<ResidentNvfp4Rank>,
9516    pub out_features: usize,
9517    pub in_features: usize,
9518}
9519
9520pub struct ResidentTpNvfp4Expert {
9521    gate: ResidentNvfp4ColumnParallel,
9522    up: ResidentNvfp4ColumnParallel,
9523    down: ResidentNvfp4RowParallel,
9524    pub input_width: usize,
9525    pub expert_width: usize,
9526}
9527
9528/// One rank's resident NVFP4 expert bank shard: one repacked block buffer PER expert (per-expert
9529/// device allocations keep this increment off any new strided-kernel API; the strided twin is a
9530/// later perf rung, mirroring the FP8 bank's history).
9531pub struct ResidentNvfp4ColumnBankRank {
9532    /// Contiguous per-rank expert bank: `expert_count` repacked shards of `expert_bytes` each.
9533    /// Contiguity is what lets the device-routes program cover every selected expert with ONE
9534    /// launch (`qmatvec_nvfp4_dp4a_sel` indexes `sel[t] * expert_bytes`).
9535    bank: crate::CudaSlice<u8>,
9536    expert_bytes: usize,
9537    local_out: usize,
9538    in_features: usize,
9539    row_bytes: usize,
9540    /// TRUE when these bytes are the slot-major permutation (`nvfp4_matrix_v2_permute`) and the
9541    /// `_v2` readers must be used; FALSE when they are block_nvfp4 v1. Recorded at BUILD from
9542    /// `ep2 || bank_slot_major_on()` and never re-derived: the layout travels with the pointer,
9543    /// so no reader can consult an env door that disagrees with the resident bytes. Feeding v1
9544    /// bytes to a `_v2` reader (or the reverse) is a garbage-output bug, and the 2026-08-29
9545    /// step37 incident was its neighbour — a piece of layout geometry a caller failed to supply.
9546    slot_major: bool,
9547}
9548
9549impl ResidentNvfp4ColumnBankRank {
9550    /// THE host-canonical reader for this bank, selected from the layout the bank RECORDS. One
9551    /// place maps layout -> reader for the column banks; every oracle goes through it, so a new
9552    /// producer cannot leave a reader behind (the failure mode that put v1 bytes under a `_v2`
9553    /// reader, called out in the `run_tensor_parallel_routes_nvfp4_prime_grouped` receipt).
9554    fn host_canonical_expert(
9555        &self,
9556        engine: &Engine,
9557        expert: usize,
9558        activations: &crate::CudaSlice<f32>,
9559    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
9560        let w = self.expert(expert);
9561        if self.slot_major {
9562            engine.qmatvec_nvfp4_fast_v2(
9563                &w,
9564                activations,
9565                1,
9566                self.in_features,
9567                self.local_out,
9568                self.row_bytes,
9569            )
9570        } else {
9571            engine.qmatvec_nvfp4_fast(
9572                &w,
9573                activations,
9574                1,
9575                self.in_features,
9576                self.local_out,
9577                self.row_bytes,
9578            )
9579        }
9580    }
9581
9582    fn expert(&self, index: usize) -> cudarc::driver::CudaView<'_, u8> {
9583        self.bank
9584            .slice(index * self.expert_bytes..(index + 1) * self.expert_bytes)
9585    }
9586}
9587
9588/// Canonical row-shard count for the NVFP4 down projection. The down reduction ALWAYS executes
9589/// as exactly this many input-column windows summed in shard order, at every world size: a
9590/// single full-width dot and a two-half-dots-plus-add differ in f32 parenthesization, so pinning
9591/// the shard grid (not the world size) is what makes the TP1-oracle-vs-TP2 bit gate meaningful.
9592/// This is the NVFP4 twin of the FP8 bank's canonical checkpoint-block reduction.
9593pub const NVFP4_CANONICAL_ROW_SHARDS: usize = 2;
9594
9595pub struct ResidentNvfp4RowBankRank {
9596    /// Contiguous per-shard expert bank (see `ResidentNvfp4ColumnBankRank::bank`).
9597    bank: crate::CudaSlice<u8>,
9598    expert_bytes: usize,
9599    device_rank: usize, // index into the runtime's rank engines this canonical shard lives on
9600    out_features: usize,
9601    local_in: usize,
9602    row_bytes: usize,
9603    /// Slot-major layout marker — see `ResidentNvfp4ColumnBankRank::slot_major`.
9604    slot_major: bool,
9605}
9606
9607impl ResidentNvfp4RowBankRank {
9608    /// THE host-canonical reader for this down shard — see
9609    /// `ResidentNvfp4ColumnBankRank::host_canonical_expert`.
9610    fn host_canonical_expert(
9611        &self,
9612        engine: &Engine,
9613        expert: usize,
9614        activations: &crate::CudaSlice<f32>,
9615    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
9616        let w = self.expert(expert);
9617        if self.slot_major {
9618            engine.qmatvec_nvfp4_fast_v2(
9619                &w,
9620                activations,
9621                1,
9622                self.local_in,
9623                self.out_features,
9624                self.row_bytes,
9625            )
9626        } else {
9627            engine.qmatvec_nvfp4_fast(
9628                &w,
9629                activations,
9630                1,
9631                self.local_in,
9632                self.out_features,
9633                self.row_bytes,
9634            )
9635        }
9636    }
9637
9638    fn expert(&self, index: usize) -> cudarc::driver::CudaView<'_, u8> {
9639        self.bank
9640            .slice(index * self.expert_bytes..(index + 1) * self.expert_bytes)
9641    }
9642}
9643
9644impl ResidentNvfp4TensorParallel {
9645    pub(crate) fn device_workspace_handle(
9646        &self,
9647    ) -> &std::sync::Mutex<Option<Nvfp4DeviceRoutesWorkspace>> {
9648        &self.device_workspace
9649    }
9650}
9651
9652pub struct ResidentNvfp4TensorParallel {
9653    gate: Vec<ResidentNvfp4ColumnBankRank>,
9654    up: Vec<ResidentNvfp4ColumnBankRank>,
9655    down: Vec<ResidentNvfp4RowBankRank>,
9656    macros_gate: Vec<f32>,
9657    macros_up: Vec<f32>,
9658    macros_down: Vec<f32>,
9659    /// Per-rank device copies of the gate/up macro-scales (E f32 each), indexed by the
9660    /// batched SwiGLU kernel via the selection array. Down macros stay host-side — they fold
9661    /// into the route-weight axpy scalar.
9662    macros_gate_dev: Vec<crate::CudaSlice<f32>>,
9663    macros_up_dev: Vec<crate::CudaSlice<f32>>,
9664    macros_down_dev: Vec<crate::CudaSlice<f32>>,
9665    pub expert_count: usize,
9666    pub input_width: usize,
9667    pub expert_width: usize,
9668    /// Lazily-built persistent decode workspace (device routes program). Interior mutability
9669    /// mirrors StepEpGroupedDecode: the forward holds the bank behind a shared reference.
9670    device_workspace: std::sync::Mutex<Option<Nvfp4DeviceRoutesWorkspace>>,
9671    /// Grouped-prime per-rank slot-major pointer tables (gate/up/down x n_expert), built once.
9672    /// The banks are resident and never move, so rebuilding + re-uploading 3*n_expert u64s per
9673    /// rank per LAYER was pure per-call host churn on the prime path.
9674    prime_tables: std::sync::Mutex<Vec<crate::CudaSlice<u64>>>,
9675    /// MEMRA_STEP_NVFP4_EP2: the rank banks above hold WHOLE experts (owner = id & 1,
9676    /// slot = id >> 1) at full width instead of TP shards. Consumers must branch on this;
9677    /// shard-semantics paths refuse loudly.
9678    pub(crate) ep2: bool,
9679}
9680
9681/// Persistent per-call device buffers for the NVFP4 device routes program: one gate/up output,
9682/// one down partial, and one shard accumulator per rank, plus root combine staging. Reused every
9683/// (token, layer) call so the decode loop performs zero output allocations.
9684/// A stitched multi-device parent graph for one layer's device-routed expert program, plus
9685/// the children it was built from (retained: AddChildGraphNode clones, but the probe retains
9686/// conservatively) and the persistent e-context input staging its copies read.
9687struct RoutesGraph {
9688    exec: cudarc::driver::sys::CUgraphExec,
9689    parent: cudarc::driver::sys::CUgraph,
9690    _children: Vec<cudarc::driver::CudaGraph>,
9691}
9692// SAFETY: the raw handles are only used from the single decode thread; CUDA graph handles are
9693// context-agnostic process handles.
9694unsafe impl Send for RoutesGraph {}
9695
9696impl Drop for RoutesGraph {
9697    fn drop(&mut self) {
9698        unsafe {
9699            let _ = cudarc::driver::sys::cuGraphExecDestroy(self.exec);
9700            let _ = cudarc::driver::sys::cuGraphDestroy(self.parent);
9701        }
9702    }
9703}
9704
9705impl Nvfp4DeviceRoutesWorkspace {
9706    pub(crate) fn in_stage_handle(&self) -> Option<&crate::CudaSlice<f32>> {
9707        self.in_stage_e.as_ref()
9708    }
9709    pub(crate) fn in_stage_mut(&mut self) -> Option<&mut crate::CudaSlice<f32>> {
9710        self.in_stage_e.as_mut()
9711    }
9712    #[allow(dead_code)] // allow: accessor twin of in_stage_mut; kept for the workspace API symmetry
9713    pub(crate) fn out_stage_mut(&mut self) -> Option<&mut crate::CudaSlice<f32>> {
9714        self.out_stage_e.as_mut()
9715    }
9716    /// Arm the e-context stages + router staging pair when absent (token-graph entry).
9717    pub(crate) fn arm_stages(
9718        &mut self,
9719        e: &Engine,
9720        width: usize,
9721        n_sel: usize,
9722    ) -> Result<(), Box<dyn std::error::Error>> {
9723        let _main = e.gpu.enter_main()?;
9724        if self.in_stage_e.is_none() {
9725            self.in_stage_e = Some(e.htod(&vec![0.0f32; width])?);
9726            self.out_stage_e = Some(e.htod(&vec![0.0f32; width])?);
9727        }
9728        if self.dev_route_e.is_none() {
9729            self.dev_route_e = Some((
9730                e.htod_i32(&vec![0i32; n_sel])?,
9731                e.htod(&vec![0.0f32; n_sel])?,
9732            ));
9733        }
9734        Ok(())
9735    }
9736
9737    /// Split-borrow: the routes input (shared) + output (mut) stages together.
9738    pub(crate) fn in_and_out_stages_mut(
9739        &mut self,
9740    ) -> Option<(&crate::CudaSlice<f32>, &mut crate::CudaSlice<f32>)> {
9741        match (self.in_stage_e.as_ref(), self.out_stage_e.as_mut()) {
9742            (Some(input), Some(output)) => Some((input, output)),
9743            _ => None,
9744        }
9745    }
9746    pub(crate) fn dev_route_e_mut(
9747        &mut self,
9748    ) -> Option<(&mut crate::CudaSlice<i32>, &mut crate::CudaSlice<f32>)> {
9749        self.dev_route_e.as_mut().map(|(a, b)| (a, b))
9750    }
9751}
9752
9753pub struct Nvfp4DeviceRoutesWorkspace {
9754    /// [n_sel, local_out] batched gate/up outputs and the SwiGLU q8_1 pair; [n_sel, width]
9755    /// down partials. Sized for `n_sel` selected experts per token (pinned at first call).
9756    gate_out: Vec<crate::CudaSlice<f32>>,
9757    up_out: Vec<crate::CudaSlice<f32>>,
9758    act_q: Vec<crate::CudaSlice<i8>>,
9759    act_d: Vec<crate::CudaSlice<f32>>,
9760    sel: Vec<crate::CudaSlice<i32>>,
9761    partial: Vec<crate::CudaSlice<f32>>,
9762    accumulator: Vec<crate::CudaSlice<f32>>,
9763    /// Per-rank folded combine weights (route_weight x down macro), one htod per call.
9764    combine_w: Vec<crate::CudaSlice<f32>>,
9765    /// Device-routed extension: per-rank raw route weights (the down-macro fold happens
9766    /// in-kernel via sel + macros_down_dev).
9767    route_w: Vec<crate::CudaSlice<f32>>,
9768    /// Persistent q8_1 pair of the shared layer input (one quantize per rank per call, no
9769    /// per-call allocation).
9770    in_q: Vec<crate::CudaSlice<i8>>,
9771    in_d: Vec<crate::CudaSlice<f32>>,
9772    /// e-context staging for the device router outputs (persistent — rank streams peer-read
9773    /// them, so the router's fresh outputs are copied here on e's stream first; the pp.rs
9774    /// never-free discipline).
9775    dev_route_e: Option<(crate::CudaSlice<i32>, crate::CudaSlice<f32>)>,
9776    /// Prestage door state: input pull + quantize already issued for this layer's call
9777    /// (nvfp4_routes_prestage), so the routed run skips them. Reset per call.
9778    prestaged: bool,
9779    /// Peer-router door state: rank1's sel/route_w were computed locally in prestage;
9780    /// the routed run skips rank1's sel pull. Reset per call.
9781    rank1_routed: bool,
9782    /// Doorbell fences (MEMRA_FENCE_MEMOPS): raw cuMemAlloc'd [rank1_flag, root_flag]
9783    /// u32 pair in ROOT memory (async-pool memory is memop-INELIGIBLE — receipted
9784    /// CUDA_ERROR_INVALID_VALUE) + the host-side monotonic ticket. 0 = unarmed.
9785    fence_flags_raw: u64,
9786    fence_ticket: u32,
9787    /// Prestage input fence, recorded on e after the input's producer.
9788    ev_input: Option<(CudaEvent, usize)>,
9789    /// Graph-door staging: persistent e-context input row + output row (fixed addresses the
9790    /// captured copies read/write), and the per-layer stitched parent.
9791    in_stage_e: Option<crate::CudaSlice<f32>>,
9792    out_stage_e: Option<crate::CudaSlice<f32>>,
9793    routes_graph: Option<RoutesGraph>,
9794    /// Token-graph raw pointer sets (armed once by routes_arm_raw).
9795    raw_dev_route_e: Option<(u64, u64)>,
9796    raw_combine: Option<(u64, u64, u64, u64)>,
9797    raw_input: Vec<u64>,
9798    raw_sel: Vec<u64>,
9799    raw_route_w: Vec<u64>,
9800    remote: crate::CudaSlice<f32>,
9801    combined: crate::CudaSlice<f32>,
9802    n_sel: usize,
9803    /// Device-IO extension (lazily built by `run_tensor_parallel_routes_nvfp4_device_io`):
9804    /// persistent per-rank input rows plus the evented ordering pair — the pp.rs
9805    /// BoundarySlot discipline, same as the v2 attention workspace.
9806    input: Vec<crate::CudaSlice<f32>>,
9807    ev_rank: Vec<CudaEvent>,
9808    ev_done: Option<CudaEvent>,
9809    ev_entry: Option<(CudaEvent, usize)>,
9810}
9811
9812/// One rank's whole-expert NVFP4 residency (expert-parallel ownership).
9813struct ResidentNvfp4EpRank {
9814    gate: crate::CudaSlice<u8>,
9815    up: crate::CudaSlice<u8>,
9816    down: crate::CudaSlice<u8>,
9817    gate_expert_bytes: usize,
9818    down_expert_bytes: usize,
9819    macros_gate: crate::CudaSlice<f32>,
9820    macros_up: crate::CudaSlice<f32>,
9821    macros_down: crate::CudaSlice<f32>,
9822    expert_range: Range<usize>,
9823}
9824
9825struct Nvfp4EpDeviceWorkspace {
9826    input: Vec<crate::CudaSlice<f32>>,
9827    input_bf16: Vec<crate::CudaSlice<u8>>,
9828    input_q8: Vec<crate::CudaSlice<i8>>,
9829    input_q8_scales: Vec<crate::CudaSlice<f32>>,
9830    sel: Vec<crate::CudaSlice<i32>>,
9831    token_rows: Vec<crate::CudaSlice<i32>>,
9832    global_pairs: Vec<crate::CudaSlice<i32>>,
9833    route_w: Vec<crate::CudaSlice<f32>>,
9834    gate_out: Vec<crate::CudaSlice<f32>>,
9835    up_out: Vec<crate::CudaSlice<f32>>,
9836    activation_bf16: Vec<crate::CudaSlice<u8>>,
9837    activation_q8: Vec<crate::CudaSlice<i8>>,
9838    activation_q8_scales: Vec<crate::CudaSlice<f32>>,
9839    slot_rows: crate::CudaSlice<f32>,
9840    slot_rows_raw: u64,
9841    route_weights: crate::CudaSlice<f32>,
9842    graph_input: crate::CudaSlice<f32>,
9843    graph_output: crate::CudaSlice<f32>,
9844    graph_routes: Option<(u64, u64)>,
9845    graphs: Vec<Option<RoutesGraph>>,
9846    ev_entry: CudaEvent,
9847    ev_entry_device: usize,
9848    ev_rank: Vec<CudaEvent>,
9849    phase_events: Option<Nvfp4EpPhaseEvents>,
9850    capacity_tokens: usize,
9851    experts_per_token: usize,
9852}
9853
9854struct Nvfp4EpPhaseEvents {
9855    head: Vec<CudaEvent>,
9856    copy_done: Vec<CudaEvent>,
9857    gate_up_done: Vec<CudaEvent>,
9858    activation_done: Vec<CudaEvent>,
9859    down_done: Vec<CudaEvent>,
9860}
9861
9862pub(crate) const NVFP4_EP_DEVICE_BATCH_CAP: usize = 128;
9863pub(crate) const NVFP4_EP_DEVICE_ROUTER_BATCH_CAP: usize = 32;
9864pub(crate) const NVFP4_EP_Q8_BATCH_CAP: usize = 32;
9865const NVFP4_EP_GRAPH_BATCH_CAP: usize = 1;
9866
9867fn nvfp4_ep_active_input_values(
9868    input_values: usize,
9869    tokens: usize,
9870    input_width: usize,
9871) -> Result<usize, String> {
9872    if !(1..=NVFP4_EP_DEVICE_BATCH_CAP).contains(&tokens) {
9873        return Err(format!(
9874            "W4A16 NVFP4 device EP batch {tokens} is outside 1..={NVFP4_EP_DEVICE_BATCH_CAP}"
9875        ));
9876    }
9877    let active_values = tokens
9878        .checked_mul(input_width)
9879        .ok_or("W4A16 NVFP4 device EP active input size overflows usize")?;
9880    if input_values < active_values {
9881        return Err(format!(
9882            "W4A16 NVFP4 device EP input {input_values} is smaller than active \
9883             tokens {tokens} x width {input_width} ({active_values})"
9884        ));
9885    }
9886    Ok(active_values)
9887}
9888
9889pub struct ResidentNvfp4ExpertParallel {
9890    ranks: Vec<ResidentNvfp4EpRank>,
9891    macros_gate: Vec<f32>,
9892    macros_up: Vec<f32>,
9893    macros_down: Vec<f32>,
9894    pub expert_count: usize,
9895    pub input_width: usize,
9896    pub expert_width: usize,
9897    gate_row_bytes: usize,
9898    down_row_bytes: usize,
9899    device_workspace: std::sync::Mutex<Option<Nvfp4EpDeviceWorkspace>>,
9900}
9901
9902fn nvfp4_repack_matrix(matrix: Nvfp4BlockMatrix<'_>) -> Vec<u8> {
9903    memra_gguf::nvfp4_repack::repack_modelopt_to_gguf(
9904        matrix.codes,
9905        matrix.scales,
9906        matrix.out_features,
9907        matrix.in_features,
9908    )
9909}
9910
9911fn nvfp4_row_bytes(in_features: usize) -> usize {
9912    in_features / 64 * 36 // memra block_nvfp4: 64 elems -> 36 bytes (4 UE4M3 + 32 packed e2m1)
9913}
9914
9915/// MEMRA_NO_LOCAL_SHADOW=1: skip the per-layer local-KV shadow gathers and appends in the
9916/// eager v2 decode (lengths still advance) — the graph door proved contents-stale local KV
9917/// is decode-identical (12/12). The local contents feed spec/MTP scratch only.
9918/// MEMRA_FUSE_ROPE_APPEND=1: fuse qk norms + rope + dcw KV append + len inc into one
9919/// launch per rank per layer (bit-identical; identity-gated). dcw path only.
9920pub(crate) fn fuse_rope_append_on() -> bool {
9921    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
9922    *ON.get_or_init(|| std::env::var("MEMRA_FUSE_ROPE_APPEND").as_deref() == Ok("1"))
9923}
9924
9925pub(crate) fn no_local_shadow_on() -> bool {
9926    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
9927    *ON.get_or_init(|| std::env::var("MEMRA_NO_LOCAL_SHADOW").as_deref() == Ok("1"))
9928}
9929
9930/// Permute one repacked block_nvfp4 matrix (out_features rows of `nvfp4_row_bytes(in_f)`)
9931/// into the slot-major row layout the EP2 kernels read: per row, slot g's 16 qs bytes at
9932/// g*16, then the two UE4M3 scale bytes per slot at nslots*16 + g*2. Row byte count
9933/// unchanged. This layout USED to be an env door (`MEMRA_NVFP4_BANK_V2`, removed 2026-08-29
9934/// after its ON arm changed generated text in serving, see
9935/// research/step37-bankv2-removal-20260829); it survives ONLY as the fixed layout of the
9936/// EP2 whole-expert banks, whose `*_ep` kernels read it unconditionally.
9937///
9938/// PUBLIC because it is the SINGLE SOURCE OF TRUTH for this byte map. Every reader — the
9939/// `*_ep` decode kernels, `kq_fetch<QT_NVFP4_V2>` in the grouped GEMM,
9940/// `dequant_nvfp4v2_f16_kernel` — is defined as "reads what this function writes", and the
9941/// `nvfp4-bank-oracle` bin is what proves it, on device, per kernel arm. Do not reimplement
9942/// the map anywhere: the two failures that appeared only on v2 readers were geometry-plumbing
9943/// bugs around a byte map that was itself correct in two separate places. The layout was
9944/// innocent; one live failure was the grouped-prefill sktail call site defaulting `in_f` to zero.
9945pub fn nvfp4_matrix_v2_permute(v1: &[u8], out_features: usize, in_features: usize) -> Vec<u8> {
9946    // The output row is n_slots*18 bytes; the stride every reader uses is
9947    // nvfp4_row_bytes(in_features) = (in_features/64)*36. Those are equal only when
9948    // in_features is a whole number of 64-element superblocks. At in_features % 64 == 32 the
9949    // permute would silently emit a LONGER row than the stride and every row after row 0
9950    // would be read at the wrong offset, so refuse instead of trusting the caller.
9951    assert_eq!(
9952        in_features % 64,
9953        0,
9954        "v2 permute needs whole 64-element superblocks, got in_features={in_features}"
9955    );
9956    let row_bytes = nvfp4_row_bytes(in_features);
9957    assert_eq!(v1.len(), out_features * row_bytes, "v2 permute geometry");
9958    let n_slots = in_features / 32;
9959    let mut out = Vec::with_capacity(v1.len());
9960    for row in 0..out_features {
9961        let r = &v1[row * row_bytes..(row + 1) * row_bytes];
9962        for g in 0..n_slots {
9963            let (sblk, h) = (g / 2, g % 2);
9964            let b = &r[sblk * 36..sblk * 36 + 36];
9965            out.extend_from_slice(&b[4 + 16 * h..4 + 16 * h + 16]);
9966        }
9967        for g in 0..n_slots {
9968            let (sblk, h) = (g / 2, g % 2);
9969            let b = &r[sblk * 36..sblk * 36 + 36];
9970            out.push(b[2 * h]);
9971            out.push(b[2 * h + 1]);
9972        }
9973    }
9974    out
9975}
9976
9977/// Repack one expert shard for the contiguous banks. `slot_major` is true ONLY for the EP2
9978/// whole-expert banks, whose `*_ep` kernels read the slot-major permutation; the TP
9979/// column/row shard banks stay in the block_nvfp4 v1 layout every other kernel reads.
9980fn nvfp4_repack_bank_matrix(matrix: Nvfp4BlockMatrix<'_>, slot_major: bool) -> Vec<u8> {
9981    let (out_features, in_features) = (matrix.out_features, matrix.in_features);
9982    let v1 = nvfp4_repack_matrix(matrix);
9983    if slot_major {
9984        nvfp4_matrix_v2_permute(&v1, out_features, in_features)
9985    } else {
9986        v1
9987    }
9988}
9989
9990/// Column shard: whole output rows per rank (codes and scales are row-major, so both slices are
9991/// contiguous borrows). The macro rides unchanged — it is applied post-gather by the caller.
9992#[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
9993fn nvfp4_column_shard<'a>(
9994    matrix: Nvfp4BlockMatrix<'a>,
9995    tp: usize,
9996    rank: usize,
9997) -> Result<Nvfp4BlockMatrix<'a>, String> {
9998    if matrix.out_features % tp != 0 {
9999        return Err(format!(
10000            "NVFP4 column-parallel out_features {} is not divisible by TP={tp}",
10001            matrix.out_features
10002        ));
10003    }
10004    let local_out = matrix.out_features / tp;
10005    let code_row = matrix.in_features / 2;
10006    let scale_row = matrix.in_features / 16;
10007    Ok(Nvfp4BlockMatrix {
10008        codes: &matrix.codes[rank * local_out * code_row..(rank + 1) * local_out * code_row],
10009        scales: &matrix.scales[rank * local_out * scale_row..(rank + 1) * local_out * scale_row],
10010        macro_scale: matrix.macro_scale,
10011        out_features: local_out,
10012        in_features: matrix.in_features,
10013    })
10014}
10015
10016/// Row shard: input-column windows per rank, 64-superblock aligned. Owned buffers: each output
10017/// row contributes one contiguous byte window, gathered across rows.
10018#[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
10019fn nvfp4_row_shard(
10020    matrix: Nvfp4BlockMatrix<'_>,
10021    tp: usize,
10022    rank: usize,
10023) -> Result<(Vec<u8>, Vec<u8>, usize), String> {
10024    if matrix.in_features % tp != 0 {
10025        return Err(format!(
10026            "NVFP4 row-parallel in_features {} is not divisible by TP={tp}",
10027            matrix.in_features
10028        ));
10029    }
10030    let local_in = matrix.in_features / tp;
10031    if !local_in.is_multiple_of(64) {
10032        return Err(format!(
10033            "NVFP4 row-parallel input shard {local_in} cuts through a 64-element superblock"
10034        ));
10035    }
10036    let code_row = matrix.in_features / 2;
10037    let scale_row = matrix.in_features / 16;
10038    let local_code = local_in / 2;
10039    let local_scale = local_in / 16;
10040    let mut codes = Vec::with_capacity(matrix.out_features * local_code);
10041    let mut scales = Vec::with_capacity(matrix.out_features * local_scale);
10042    for row in 0..matrix.out_features {
10043        let code_start = row * code_row + rank * local_code;
10044        codes.extend_from_slice(&matrix.codes[code_start..code_start + local_code]);
10045        let scale_start = row * scale_row + rank * local_scale;
10046        scales.extend_from_slice(&matrix.scales[scale_start..scale_start + local_scale]);
10047    }
10048    Ok((codes, scales, local_in))
10049}
10050
10051/// Rank compute leaf: repack modelopt -> block_nvfp4, upload, run the proven dp4a kernel. The
10052/// macro is NOT applied here — callers apply it once at the canonical post-gather/post-reduce
10053/// point (see the section header).
10054fn run_rank_nvfp4(
10055    engine: &Engine,
10056    matrix: Nvfp4BlockMatrix<'_>,
10057    activations: &[f32],
10058    tokens: usize,
10059) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10060    matrix.validate()?;
10061    validate_activations(activations, tokens, matrix.in_features)?;
10062    let _main = engine.gpu.enter_main()?;
10063    let blocks = engine.htod_bytes(&nvfp4_repack_matrix(matrix))?;
10064    let activations = engine.htod(activations)?;
10065    let output = engine.qmatvec_nvfp4_fast(
10066        &blocks.slice(0..blocks.len()),
10067        &activations,
10068        tokens,
10069        matrix.in_features,
10070        matrix.out_features,
10071        nvfp4_row_bytes(matrix.in_features),
10072    )?;
10073    engine.dtoh(&output)
10074}
10075
10076fn upload_rank_nvfp4(
10077    engine: &Engine,
10078    matrix: Nvfp4BlockMatrix<'_>,
10079) -> Result<ResidentNvfp4Rank, Box<dyn std::error::Error>> {
10080    matrix.validate()?;
10081    let _main = engine.gpu.enter_main()?;
10082    Ok(ResidentNvfp4Rank {
10083        blocks: engine.htod_bytes(&nvfp4_repack_matrix(matrix))?,
10084        macro_scale: matrix.macro_scale,
10085        out_features: matrix.out_features,
10086        in_features: matrix.in_features,
10087        row_bytes: nvfp4_row_bytes(matrix.in_features),
10088    })
10089}
10090
10091fn run_resident_rank_nvfp4(
10092    engine: &Engine,
10093    rank: &ResidentNvfp4Rank,
10094    activations: &[f32],
10095    tokens: usize,
10096) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10097    validate_activations(activations, tokens, rank.in_features)?;
10098    let _main = engine.gpu.enter_main()?;
10099    let activations = engine.htod(activations)?;
10100    let output = engine.qmatvec_nvfp4_fast(
10101        &rank.blocks.slice(0..rank.blocks.len()),
10102        &activations,
10103        tokens,
10104        rank.in_features,
10105        rank.out_features,
10106        rank.row_bytes,
10107    )?;
10108    engine.dtoh(&output)
10109}
10110
10111fn apply_macro(values: &mut [f32], macro_scale: f32) {
10112    for value in values.iter_mut() {
10113        *value *= macro_scale;
10114    }
10115}
10116
10117impl TpE4m3HostBounce {
10118    /// Unsharded NVFP4 projection on rank 0 (compatibility oracle). Macro applied post-kernel.
10119    pub fn full_nvfp4(
10120        &self,
10121        matrix: Nvfp4BlockMatrix<'_>,
10122        activations: &[f32],
10123        tokens: usize,
10124    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10125        let mut output = run_rank_nvfp4(&self.ranks[0], matrix, activations, tokens)?;
10126        apply_macro(&mut output, matrix.macro_scale);
10127        Ok(output)
10128    }
10129
10130    /// Column-parallel NVFP4 projection: output rows partition across ranks, host gather in rank
10131    /// order, macro applied ONCE post-gather.
10132    pub fn column_parallel_nvfp4(
10133        &self,
10134        matrix: Nvfp4BlockMatrix<'_>,
10135        activations: &[f32],
10136        tokens: usize,
10137    ) -> Result<ColumnParallelResult, Box<dyn std::error::Error>> {
10138        matrix.validate()?;
10139        validate_activations(activations, tokens, matrix.in_features)?;
10140        let tp = self.ranks.len();
10141        let local_out = matrix.out_features / tp;
10142        let mut gathered = vec![0.0f32; tokens * matrix.out_features];
10143        let mut rank_outputs = Vec::with_capacity(tp);
10144        for (rank_index, rank) in self.ranks.iter().enumerate() {
10145            let shard = nvfp4_column_shard(matrix, tp, rank_index)?;
10146            let output = run_rank_nvfp4(rank, shard, activations, tokens)?;
10147            let row_start = rank_index * local_out;
10148            for token in 0..tokens {
10149                gathered[token * matrix.out_features + row_start
10150                    ..token * matrix.out_features + row_start + local_out]
10151                    .copy_from_slice(&output[token * local_out..(token + 1) * local_out]);
10152            }
10153            rank_outputs.push(output);
10154        }
10155        apply_macro(&mut gathered, matrix.macro_scale);
10156        Ok(ColumnParallelResult {
10157            gathered,
10158            rank_outputs,
10159        })
10160    }
10161
10162    /// Row-parallel NVFP4 projection: input columns partition at 64-superblock boundaries,
10163    /// rank-local partials reduce in stable rank order, macro applied ONCE post-reduce.
10164    pub fn row_parallel_nvfp4(
10165        &self,
10166        matrix: Nvfp4BlockMatrix<'_>,
10167        activations: &[f32],
10168        tokens: usize,
10169    ) -> Result<RowParallelResult, Box<dyn std::error::Error>> {
10170        matrix.validate()?;
10171        validate_activations(activations, tokens, matrix.in_features)?;
10172        let tp = self.ranks.len();
10173        let mut reduced = vec![0.0f32; tokens * matrix.out_features];
10174        let mut rank_partials = Vec::with_capacity(tp);
10175        for (rank_index, rank) in self.ranks.iter().enumerate() {
10176            let (codes, scales, local_in) = nvfp4_row_shard(matrix, tp, rank_index)?;
10177            let local_activations =
10178                activation_shard(activations, tokens, matrix.in_features, tp, rank_index);
10179            let shard = Nvfp4BlockMatrix {
10180                codes: &codes,
10181                scales: &scales,
10182                macro_scale: matrix.macro_scale,
10183                out_features: matrix.out_features,
10184                in_features: local_in,
10185            };
10186            let partial = run_rank_nvfp4(rank, shard, &local_activations, tokens)?;
10187            for (sum, value) in reduced.iter_mut().zip(&partial) {
10188                *sum += *value;
10189            }
10190            rank_partials.push(partial);
10191        }
10192        apply_macro(&mut reduced, matrix.macro_scale);
10193        Ok(RowParallelResult {
10194            reduced,
10195            rank_partials,
10196        })
10197    }
10198
10199    pub fn upload_expert_nvfp4(
10200        &self,
10201        gate: Nvfp4BlockMatrix<'_>,
10202        up: Nvfp4BlockMatrix<'_>,
10203        down: Nvfp4BlockMatrix<'_>,
10204    ) -> Result<ResidentTpNvfp4Expert, Box<dyn std::error::Error>> {
10205        if gate.in_features != up.in_features || gate.out_features != up.out_features {
10206            return Err("NVFP4 TP expert gate/up dimensions differ".into());
10207        }
10208        if down.in_features != gate.out_features || down.out_features != gate.in_features {
10209            return Err(format!(
10210                "NVFP4 TP expert down {}x{} does not invert gate/up {}x{}",
10211                down.out_features, down.in_features, gate.out_features, gate.in_features
10212            )
10213            .into());
10214        }
10215        let tp = self.ranks.len();
10216        let mut gate_ranks = Vec::with_capacity(tp);
10217        let mut up_ranks = Vec::with_capacity(tp);
10218        let mut down_ranks = Vec::with_capacity(tp);
10219        for (rank_index, engine) in self.ranks.iter().enumerate() {
10220            gate_ranks.push(upload_rank_nvfp4(
10221                engine,
10222                nvfp4_column_shard(gate, tp, rank_index)?,
10223            )?);
10224            up_ranks.push(upload_rank_nvfp4(
10225                engine,
10226                nvfp4_column_shard(up, tp, rank_index)?,
10227            )?);
10228            let (codes, scales, local_in) = nvfp4_row_shard(down, tp, rank_index)?;
10229            down_ranks.push(upload_rank_nvfp4(
10230                engine,
10231                Nvfp4BlockMatrix {
10232                    codes: &codes,
10233                    scales: &scales,
10234                    macro_scale: down.macro_scale,
10235                    out_features: down.out_features,
10236                    in_features: local_in,
10237                },
10238            )?);
10239        }
10240        Ok(ResidentTpNvfp4Expert {
10241            gate: ResidentNvfp4ColumnParallel {
10242                ranks: gate_ranks,
10243                out_features: gate.out_features,
10244                in_features: gate.in_features,
10245            },
10246            up: ResidentNvfp4ColumnParallel {
10247                ranks: up_ranks,
10248                out_features: up.out_features,
10249                in_features: up.in_features,
10250            },
10251            down: ResidentNvfp4RowParallel {
10252                ranks: down_ranks,
10253                out_features: down.out_features,
10254                in_features: down.in_features,
10255            },
10256            input_width: gate.in_features,
10257            expert_width: gate.out_features,
10258        })
10259    }
10260
10261    fn column_parallel_resident_nvfp4(
10262        &self,
10263        matrix: &ResidentNvfp4ColumnParallel,
10264        activations: &[f32],
10265        tokens: usize,
10266    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10267        validate_activations(activations, tokens, matrix.in_features)?;
10268        let local_out = matrix.out_features / self.ranks.len();
10269        let mut gathered = vec![0.0f32; tokens * matrix.out_features];
10270        let mut macro_scale = None;
10271        for (rank_index, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
10272            let output = run_resident_rank_nvfp4(engine, shard, activations, tokens)?;
10273            let row_start = rank_index * local_out;
10274            for token in 0..tokens {
10275                gathered[token * matrix.out_features + row_start
10276                    ..token * matrix.out_features + row_start + local_out]
10277                    .copy_from_slice(&output[token * local_out..(token + 1) * local_out]);
10278            }
10279            macro_scale = Some(shard.macro_scale);
10280        }
10281        apply_macro(
10282            &mut gathered,
10283            macro_scale.ok_or("NVFP4 column-parallel matrix has no ranks")?,
10284        );
10285        Ok(gathered)
10286    }
10287
10288    fn row_parallel_resident_nvfp4(
10289        &self,
10290        matrix: &ResidentNvfp4RowParallel,
10291        activations: &[f32],
10292        tokens: usize,
10293    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10294        validate_activations(activations, tokens, matrix.in_features)?;
10295        let tp = self.ranks.len();
10296        let local_in = matrix.in_features / tp;
10297        let mut reduced = vec![0.0f32; tokens * matrix.out_features];
10298        let mut macro_scale = None;
10299        for (rank_index, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
10300            if shard.in_features != local_in {
10301                return Err(format!(
10302                    "NVFP4 resident row shard in_features {} != expected {local_in}",
10303                    shard.in_features
10304                )
10305                .into());
10306            }
10307            let local_activations =
10308                activation_shard(activations, tokens, matrix.in_features, tp, rank_index);
10309            let partial = run_resident_rank_nvfp4(engine, shard, &local_activations, tokens)?;
10310            for (sum, value) in reduced.iter_mut().zip(&partial) {
10311                *sum += *value;
10312            }
10313            macro_scale = Some(shard.macro_scale);
10314        }
10315        apply_macro(
10316            &mut reduced,
10317            macro_scale.ok_or("NVFP4 row-parallel matrix has no ranks")?,
10318        );
10319        Ok(reduced)
10320    }
10321
10322    pub fn run_expert_nvfp4(
10323        &self,
10324        expert: &ResidentTpNvfp4Expert,
10325        input: &[f32],
10326        tokens: usize,
10327    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10328        validate_activations(input, tokens, expert.input_width)?;
10329        let gate = self.column_parallel_resident_nvfp4(&expert.gate, input, tokens)?;
10330        let up = self.column_parallel_resident_nvfp4(&expert.up, input, tokens)?;
10331        let activated: Vec<f32> = gate
10332            .iter()
10333            .zip(&up)
10334            .map(|(&gate, &up)| gate / (1.0 + (-gate).exp()) * up)
10335            .collect();
10336        debug_assert_eq!(activated.len(), tokens * expert.expert_width);
10337        self.row_parallel_resident_nvfp4(&expert.down, &activated, tokens)
10338    }
10339
10340    /// Upload every expert's TP shards resident (one repacked block buffer per expert per rank).
10341    #[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
10342    pub fn upload_tensor_parallel_nvfp4(
10343        &self,
10344        gate: Nvfp4ExpertBank<'_>,
10345        up: Nvfp4ExpertBank<'_>,
10346        down: Nvfp4ExpertBank<'_>,
10347    ) -> Result<ResidentNvfp4TensorParallel, Box<dyn std::error::Error>> {
10348        gate.validate()?;
10349        up.validate()?;
10350        down.validate()?;
10351        if gate.expert_count != up.expert_count || gate.expert_count != down.expert_count {
10352            return Err("NVFP4 TP gate/up/down expert counts differ".into());
10353        }
10354        if gate.in_features != up.in_features || gate.out_features != up.out_features {
10355            return Err("NVFP4 TP gate/up dimensions differ".into());
10356        }
10357        if down.in_features != gate.out_features || down.out_features != gate.in_features {
10358            return Err(format!(
10359                "NVFP4 TP down {}x{} does not invert gate/up {}x{}",
10360                down.out_features, down.in_features, gate.out_features, gate.in_features
10361            )
10362            .into());
10363        }
10364        let tp = self.ranks.len();
10365        if gate.out_features % tp != 0 {
10366            return Err(format!(
10367                "NVFP4 TP expert output width {} is not divisible by TP={tp}",
10368                gate.out_features
10369            )
10370            .into());
10371        }
10372        if !down.in_features.is_multiple_of(NVFP4_CANONICAL_ROW_SHARDS)
10373            || !(down.in_features / NVFP4_CANONICAL_ROW_SHARDS).is_multiple_of(64)
10374        {
10375            return Err(format!(
10376                "NVFP4 TP expert input width {} does not split into 64-aligned canonical \
10377                 shards ({NVFP4_CANONICAL_ROW_SHARDS})",
10378                down.in_features
10379            )
10380            .into());
10381        }
10382        if tp > NVFP4_CANONICAL_ROW_SHARDS {
10383            return Err(format!(
10384                "NVFP4 TP world {tp} exceeds the canonical row-shard grid \
10385                 ({NVFP4_CANONICAL_ROW_SHARDS})"
10386            )
10387            .into());
10388        }
10389
10390        let ep2 = step_nvfp4_ep2_on() && tp == 2;
10391        // LAYOUT DECISION, MADE ONCE PER BANK BUILD. EP2 whole-expert banks are ALWAYS
10392        // slot-major (their `*_ep` kernels read that mapping unconditionally); TP shard banks
10393        // are slot-major only under PROGRAM 1's door. Every reader below takes this from the
10394        // bank it is reading, never from `bank_slot_major_on()` again.
10395        let slot_major = ep2 || bank_slot_major_on();
10396        // ENGAGEMENT RECEIPT, not a debug line. A pricing cell that proves only that the env var
10397        // is SET measures nothing: if the door fails to reach the code, the cell reports "the
10398        // program is worth 0%" when the truth is "the program never ran". That exact defect is
10399        // banked -- the MEMRA_BF16_MMV lane's first sweep grepped for engagement, got 0 in BOTH
10400        // arms, and the missing line was mistaken for a no-engagement result until an announce
10401        // was added. So the layout decision announces itself, WITH ITS SOURCE, so a receipt can
10402        // distinguish "armed by the door" from "armed because EP2" from "not armed".
10403        eprintln!(
10404            "[nvfp4-bank] layout={} source={} tp={tp} experts={} in_f={} out_f={}",
10405            if slot_major {
10406                "slot-major"
10407            } else {
10408                "block-nvfp4-v1"
10409            },
10410            // The source string distinguishes "armed by the 2026-09-01 DEFAULT" from "armed by
10411            // an explicit recipe" from "rolled back by the seam" from "armed because EP2". A
10412            // default flip whose receipt cannot say which of those happened cannot prove the
10413            // DEFAULT was what got measured.
10414            if ep2 {
10415                "ep2-always"
10416            } else {
10417                bank_slot_major_source().1
10418            },
10419            gate.expert_count,
10420            gate.in_features,
10421            gate.out_features
10422        );
10423        let mut gate_ranks = Vec::with_capacity(tp);
10424        let mut up_ranks = Vec::with_capacity(tp);
10425        let mut macros_gate_dev = Vec::with_capacity(tp);
10426        let mut macros_up_dev = Vec::with_capacity(tp);
10427        let mut macros_down_dev = Vec::with_capacity(tp);
10428        for (rank_index, engine) in self.ranks.iter().enumerate() {
10429            let _main = engine.gpu.enter_main()?;
10430            // Contiguous per-rank banks: repack every expert shard into one host buffer, one
10431            // upload. Contiguity feeds the batched selected-experts launch; per-expert bytes
10432            // are unchanged (same repack).
10433            // EP2: this rank holds the FULL matrices of the experts it owns (id & 1 ==
10434            // rank_index), stacked at slot id >> 1 — same total bytes as the shard bank.
10435            let mut gate_host: Vec<u8> = Vec::new();
10436            let mut up_host: Vec<u8> = Vec::new();
10437            let mut owned = 0usize;
10438            for expert in 0..gate.expert_count {
10439                if ep2 {
10440                    if expert % 2 != rank_index {
10441                        continue;
10442                    }
10443                    owned += 1;
10444                    gate_host.extend_from_slice(&nvfp4_repack_bank_matrix(
10445                        gate.expert(expert)?,
10446                        slot_major,
10447                    ));
10448                    up_host.extend_from_slice(&nvfp4_repack_bank_matrix(
10449                        up.expert(expert)?,
10450                        slot_major,
10451                    ));
10452                } else {
10453                    let gate_shard = nvfp4_column_shard(gate.expert(expert)?, tp, rank_index)?;
10454                    gate_host.extend_from_slice(&nvfp4_repack_bank_matrix(gate_shard, slot_major));
10455                    let up_shard = nvfp4_column_shard(up.expert(expert)?, tp, rank_index)?;
10456                    up_host.extend_from_slice(&nvfp4_repack_bank_matrix(up_shard, slot_major));
10457                }
10458            }
10459            let bank_experts = if ep2 { owned } else { gate.expert_count };
10460            let gate_expert_bytes = gate_host.len() / bank_experts.max(1);
10461            let up_expert_bytes = up_host.len() / bank_experts.max(1);
10462            let local_out = if ep2 {
10463                gate.out_features
10464            } else {
10465                gate.out_features / tp
10466            };
10467            gate_ranks.push(ResidentNvfp4ColumnBankRank {
10468                bank: engine.htod_bytes(&gate_host)?,
10469                expert_bytes: gate_expert_bytes,
10470                local_out,
10471                in_features: gate.in_features,
10472                row_bytes: nvfp4_row_bytes(gate.in_features),
10473                slot_major,
10474            });
10475            up_ranks.push(ResidentNvfp4ColumnBankRank {
10476                bank: engine.htod_bytes(&up_host)?,
10477                expert_bytes: up_expert_bytes,
10478                local_out,
10479                in_features: up.in_features,
10480                row_bytes: nvfp4_row_bytes(up.in_features),
10481                slot_major,
10482            });
10483            macros_gate_dev.push(engine.htod(gate.macros)?);
10484            macros_up_dev.push(engine.htod(up.macros)?);
10485            macros_down_dev.push(engine.htod(down.macros)?);
10486        }
10487        // Down: canonical shard grid, NOT the world size (see NVFP4_CANONICAL_ROW_SHARDS).
10488        // Shard s lives on rank s % world, so TP1 holds both shards and TP2 one each, while the
10489        // execution and reduction order stay identical.
10490        let mut down_ranks = Vec::with_capacity(NVFP4_CANONICAL_ROW_SHARDS);
10491        for shard_index in 0..NVFP4_CANONICAL_ROW_SHARDS {
10492            let device_rank = shard_index % tp;
10493            let engine = &self.ranks[device_rank];
10494            let _main = engine.gpu.enter_main()?;
10495            let mut down_host: Vec<u8> = Vec::new();
10496            let mut owned = 0usize;
10497            for expert in 0..down.expert_count {
10498                let down_matrix = down.expert(expert)?;
10499                if ep2 {
10500                    // EP2: shard_index doubles as the owner rank; full-width down matrices
10501                    // of the owned experts, stacked at slot id >> 1.
10502                    if expert % 2 != device_rank {
10503                        continue;
10504                    }
10505                    owned += 1;
10506                    down_host.extend_from_slice(&nvfp4_repack_bank_matrix(down_matrix, slot_major));
10507                } else {
10508                    let (codes, scales, local_in) =
10509                        nvfp4_row_shard(down_matrix, NVFP4_CANONICAL_ROW_SHARDS, shard_index)?;
10510                    down_host.extend_from_slice(&nvfp4_repack_bank_matrix(
10511                        Nvfp4BlockMatrix {
10512                            codes: &codes,
10513                            scales: &scales,
10514                            macro_scale: down_matrix.macro_scale,
10515                            out_features: down_matrix.out_features,
10516                            in_features: local_in,
10517                        },
10518                        slot_major,
10519                    ));
10520                }
10521            }
10522            let bank_experts = if ep2 { owned } else { down.expert_count };
10523            let down_expert_bytes = down_host.len() / bank_experts.max(1);
10524            let local_in = if ep2 {
10525                down.in_features
10526            } else {
10527                down.in_features / NVFP4_CANONICAL_ROW_SHARDS
10528            };
10529            down_ranks.push(ResidentNvfp4RowBankRank {
10530                bank: engine.htod_bytes(&down_host)?,
10531                expert_bytes: down_expert_bytes,
10532                device_rank,
10533                out_features: down.out_features,
10534                local_in,
10535                row_bytes: nvfp4_row_bytes(local_in),
10536                slot_major,
10537            });
10538        }
10539        Ok(ResidentNvfp4TensorParallel {
10540            gate: gate_ranks,
10541            up: up_ranks,
10542            down: down_ranks,
10543            macros_gate: gate.macros.to_vec(),
10544            macros_up: up.macros.to_vec(),
10545            macros_down: down.macros.to_vec(),
10546            macros_gate_dev,
10547            macros_up_dev,
10548            macros_down_dev,
10549            expert_count: gate.expert_count,
10550            input_width: gate.in_features,
10551            expert_width: gate.out_features,
10552            device_workspace: std::sync::Mutex::new(None),
10553            prime_tables: std::sync::Mutex::new(Vec::new()),
10554            ep2,
10555        })
10556    }
10557
10558    /// EP2 host-canonical: the whole expert executes on its owning rank at full width
10559    /// (owner = expert & 1, bank slot = expert >> 1). Per-row program == the column-bank
10560    /// path's kernel, so gate/up are bit-equal to the TP layout.
10561    fn run_full_bank_expert_nvfp4(
10562        &self,
10563        ranks: &[ResidentNvfp4ColumnBankRank],
10564        macros: &[f32],
10565        expert: usize,
10566        input: &[f32],
10567    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10568        let owner = expert & 1;
10569        let slot = expert >> 1;
10570        let bank = ranks
10571            .get(owner)
10572            .ok_or("NVFP4 EP2 column bank missing owner rank")?;
10573        let engine = &self.ranks[owner];
10574        let _main = engine.gpu.enter_main()?;
10575        let activations = engine.htod(input)?;
10576        let output = bank.host_canonical_expert(engine, slot, &activations)?;
10577        let mut out = engine.dtoh(&output)?;
10578        apply_macro(&mut out, macros[expert]);
10579        Ok(out)
10580    }
10581
10582    /// EP2 host-canonical down: one full-width dot on the owner (NUMERIC-CLASS vs the
10583    /// canonical 2-shard sum — the parenthesization this door declares).
10584    fn run_full_down_expert_nvfp4(
10585        &self,
10586        shards: &[ResidentNvfp4RowBankRank],
10587        macros: &[f32],
10588        expert: usize,
10589        input: &[f32],
10590    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10591        let owner = expert & 1;
10592        let slot = expert >> 1;
10593        let shard = shards
10594            .get(owner)
10595            .ok_or("NVFP4 EP2 down bank missing owner rank")?;
10596        let engine = &self.ranks[owner];
10597        let _main = engine.gpu.enter_main()?;
10598        let activations = engine.htod(input)?;
10599        let output = shard.host_canonical_expert(engine, slot, &activations)?;
10600        let mut out = engine.dtoh(&output)?;
10601        apply_macro(&mut out, macros[expert]);
10602        Ok(out)
10603    }
10604
10605    fn run_column_bank_expert_nvfp4(
10606        &self,
10607        ranks: &[ResidentNvfp4ColumnBankRank],
10608        macros: &[f32],
10609        expert: usize,
10610        input: &[f32],
10611    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10612        let local_out = ranks
10613            .first()
10614            .ok_or("NVFP4 TP column bank has no ranks")?
10615            .local_out;
10616        let mut gathered = vec![0.0f32; local_out * ranks.len()];
10617        for (rank_index, (engine, bank)) in self.ranks.iter().zip(ranks).enumerate() {
10618            let _main = engine.gpu.enter_main()?;
10619            let activations = engine.htod(input)?;
10620            let output = bank.host_canonical_expert(engine, expert, &activations)?;
10621            let output = engine.dtoh(&output)?;
10622            gathered[rank_index * local_out..(rank_index + 1) * local_out].copy_from_slice(&output);
10623        }
10624        apply_macro(&mut gathered, macros[expert]);
10625        Ok(gathered)
10626    }
10627
10628    /// Canonical-shard row reduction: iterate the FIXED shard grid in shard order (each shard
10629    /// executes on its owning rank engine), so the reduction parenthesization is identical at
10630    /// every world size — that identity is what the TP1-oracle-vs-TP2 bit gate proves.
10631    fn run_row_bank_expert_nvfp4(
10632        &self,
10633        shards: &[ResidentNvfp4RowBankRank],
10634        macros: &[f32],
10635        expert: usize,
10636        input: &[f32],
10637    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10638        let out_features = shards
10639            .first()
10640            .ok_or("NVFP4 TP row bank has no canonical shards")?
10641            .out_features;
10642        let in_features = shards.iter().map(|shard| shard.local_in).sum::<usize>();
10643        let mut reduced = vec![0.0f32; out_features];
10644        for (shard_index, shard) in shards.iter().enumerate() {
10645            let engine = self
10646                .ranks
10647                .get(shard.device_rank)
10648                .ok_or("NVFP4 canonical shard names a rank outside this runtime")?;
10649            let _main = engine.gpu.enter_main()?;
10650            let local_activations =
10651                activation_shard(input, 1, in_features, shards.len(), shard_index);
10652            let activations = engine.htod(&local_activations)?;
10653            let output = shard.host_canonical_expert(engine, expert, &activations)?;
10654            let partial = engine.dtoh(&output)?;
10655            for (sum, value) in reduced.iter_mut().zip(&partial) {
10656                *sum += *value;
10657            }
10658        }
10659        apply_macro(&mut reduced, macros[expert]);
10660        Ok(reduced)
10661    }
10662
10663    /// Upload whole experts per owning rank (NVFP4 expert-parallel: the layout the clamped tail
10664    /// layers require — clamp semantics do not distribute across a tensor shard). Each owned
10665    /// expert keeps its full gate/up/down as one repacked block buffer on its owner.
10666    #[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
10667    pub fn upload_expert_parallel_nvfp4(
10668        &self,
10669        gate: Nvfp4ExpertBank<'_>,
10670        up: Nvfp4ExpertBank<'_>,
10671        down: Nvfp4ExpertBank<'_>,
10672    ) -> Result<ResidentNvfp4ExpertParallel, Box<dyn std::error::Error>> {
10673        gate.validate()?;
10674        up.validate()?;
10675        down.validate()?;
10676        if gate.expert_count != up.expert_count || gate.expert_count != down.expert_count {
10677            return Err("NVFP4 EP gate/up/down expert counts differ".into());
10678        }
10679        if gate.in_features != up.in_features || gate.out_features != up.out_features {
10680            return Err("NVFP4 EP gate/up dimensions differ".into());
10681        }
10682        if down.in_features != gate.out_features || down.out_features != gate.in_features {
10683            return Err(format!(
10684                "NVFP4 EP down {}x{} does not invert gate/up {}x{}",
10685                down.out_features, down.in_features, gate.out_features, gate.in_features
10686            )
10687            .into());
10688        }
10689        let world = self.ranks.len();
10690        if gate.expert_count % world != 0 {
10691            return Err(format!(
10692                "NVFP4 EP expert count {} is not divisible by {world} ranks",
10693                gate.expert_count
10694            )
10695            .into());
10696        }
10697        let experts_per_rank = gate.expert_count / world;
10698        let mut ranks = Vec::with_capacity(world);
10699        for (rank_index, engine) in self.ranks.iter().enumerate() {
10700            let _main = engine.gpu.enter_main()?;
10701            let expert_range = rank_index * experts_per_rank..(rank_index + 1) * experts_per_rank;
10702            let mut gate_host = Vec::new();
10703            let mut up_host = Vec::new();
10704            let mut down_host = Vec::new();
10705            for expert in expert_range.clone() {
10706                gate_host.extend_from_slice(&nvfp4_repack_matrix(gate.expert(expert)?));
10707                up_host.extend_from_slice(&nvfp4_repack_matrix(up.expert(expert)?));
10708                down_host.extend_from_slice(&nvfp4_repack_matrix(down.expert(expert)?));
10709            }
10710            let gate_expert_bytes = gate_host.len() / experts_per_rank;
10711            let up_expert_bytes = up_host.len() / experts_per_rank;
10712            if gate_expert_bytes != up_expert_bytes {
10713                return Err("NVFP4 EP gate/up packed expert bytes differ".into());
10714            }
10715            let down_expert_bytes = down_host.len() / experts_per_rank;
10716            ranks.push(ResidentNvfp4EpRank {
10717                gate: engine.htod_bytes(&gate_host)?,
10718                up: engine.htod_bytes(&up_host)?,
10719                down: engine.htod_bytes(&down_host)?,
10720                gate_expert_bytes,
10721                down_expert_bytes,
10722                macros_gate: engine.htod(&gate.macros[expert_range.clone()])?,
10723                macros_up: engine.htod(&up.macros[expert_range.clone()])?,
10724                macros_down: engine.htod(&down.macros[expert_range.clone()])?,
10725                expert_range,
10726            });
10727        }
10728        Ok(ResidentNvfp4ExpertParallel {
10729            ranks,
10730            macros_gate: gate.macros.to_vec(),
10731            macros_up: up.macros.to_vec(),
10732            macros_down: down.macros.to_vec(),
10733            expert_count: gate.expert_count,
10734            input_width: gate.in_features,
10735            expert_width: gate.out_features,
10736            gate_row_bytes: nvfp4_row_bytes(gate.in_features),
10737            down_row_bytes: nvfp4_row_bytes(down.in_features),
10738            device_workspace: std::sync::Mutex::new(None),
10739        })
10740    }
10741
10742    /// Upload an already-normalized NVFP4 expert bank.
10743    ///
10744    /// `HostExps` is the physical-format boundary: stacked checkpoint tensors, gathered
10745    /// per-expert tensors, and manifest-backed overlays all become the same contiguous
10746    /// block_nvfp4 expert representation before the parallel backend sees them.
10747    pub fn upload_expert_parallel_nvfp4_normalized(
10748        &self,
10749        gate: &crate::model::HostExps,
10750        up: &crate::model::HostExps,
10751        down: &crate::model::HostExps,
10752    ) -> Result<ResidentNvfp4ExpertParallel, Box<dyn std::error::Error>> {
10753        for (label, bank) in [("gate", gate), ("up", up), ("down", down)] {
10754            if bank.qtype != crate::QT_NVFP4 || !bank.is_uniform_layout() {
10755                return Err(format!(
10756                    "NVFP4 EP normalized {label} bank requires one uniform NVFP4 layout, \
10757                     got qtype={} uniform={}",
10758                    bank.qtype,
10759                    bank.is_uniform_layout()
10760                )
10761                .into());
10762            }
10763            if bank.n_expert == 0
10764                || bank.expert_stride != bank.out_f * bank.row_bytes
10765                || (0..bank.n_expert)
10766                    .any(|expert| bank.expert_bytes(expert).len() != bank.expert_stride)
10767            {
10768                return Err(format!("NVFP4 EP normalized {label} bank geometry is invalid").into());
10769            }
10770        }
10771        if gate.n_expert != up.n_expert || gate.n_expert != down.n_expert {
10772            return Err("NVFP4 EP normalized gate/up/down expert counts differ".into());
10773        }
10774        if gate.in_f != up.in_f || gate.out_f != up.out_f {
10775            return Err("NVFP4 EP normalized gate/up dimensions differ".into());
10776        }
10777        if down.in_f != gate.out_f || down.out_f != gate.in_f {
10778            return Err(format!(
10779                "NVFP4 EP normalized down {}x{} does not invert gate/up {}x{}",
10780                down.out_f, down.in_f, gate.out_f, gate.in_f
10781            )
10782            .into());
10783        }
10784        let macros = |bank: &crate::model::HostExps| -> Result<Vec<f32>, String> {
10785            let values = bank
10786                .macros
10787                .clone()
10788                .unwrap_or_else(|| vec![1.0; bank.n_expert]);
10789            if values.len() != bank.n_expert
10790                || !values.iter().all(|value| value.is_finite() && *value > 0.0)
10791            {
10792                return Err("NVFP4 EP normalized macro row is not finite-positive".to_string());
10793            }
10794            Ok(values)
10795        };
10796        let macros_gate = macros(gate)?;
10797        let macros_up = macros(up)?;
10798        let macros_down = macros(down)?;
10799        let world = self.ranks.len();
10800        if !gate.n_expert.is_multiple_of(world) {
10801            return Err(format!(
10802                "NVFP4 EP normalized expert count {} is not divisible by {world} ranks",
10803                gate.n_expert
10804            )
10805            .into());
10806        }
10807        let experts_per_rank = gate.n_expert / world;
10808        let mut ranks = Vec::with_capacity(world);
10809        for (rank_index, engine) in self.ranks.iter().enumerate() {
10810            let _main = engine.gpu.enter_main()?;
10811            let expert_range = rank_index * experts_per_rank..(rank_index + 1) * experts_per_rank;
10812            let mut gate_host = Vec::with_capacity(experts_per_rank * gate.expert_stride);
10813            let mut up_host = Vec::with_capacity(experts_per_rank * up.expert_stride);
10814            let mut down_host = Vec::with_capacity(experts_per_rank * down.expert_stride);
10815            for expert in expert_range.clone() {
10816                gate_host.extend_from_slice(gate.expert_bytes(expert));
10817                up_host.extend_from_slice(up.expert_bytes(expert));
10818                down_host.extend_from_slice(down.expert_bytes(expert));
10819            }
10820            ranks.push(ResidentNvfp4EpRank {
10821                gate: engine.htod_bytes(&gate_host)?,
10822                up: engine.htod_bytes(&up_host)?,
10823                down: engine.htod_bytes(&down_host)?,
10824                gate_expert_bytes: gate.expert_stride,
10825                down_expert_bytes: down.expert_stride,
10826                macros_gate: engine.htod(&macros_gate[expert_range.clone()])?,
10827                macros_up: engine.htod(&macros_up[expert_range.clone()])?,
10828                macros_down: engine.htod(&macros_down[expert_range.clone()])?,
10829                expert_range,
10830            });
10831        }
10832        Ok(ResidentNvfp4ExpertParallel {
10833            ranks,
10834            macros_gate,
10835            macros_up,
10836            macros_down,
10837            expert_count: gate.n_expert,
10838            input_width: gate.in_f,
10839            expert_width: gate.out_f,
10840            gate_row_bytes: gate.row_bytes,
10841            down_row_bytes: down.row_bytes,
10842            device_workspace: std::sync::Mutex::new(None),
10843        })
10844    }
10845
10846    /// Routed NVFP4 expert-parallel program, host-canonical: every selected expert executes WHOLE
10847    /// on its owning rank (gate -> up -> clamped-or-plain SwiGLU on host -> down), each projection
10848    /// macro applied once post-kernel, route-weighted accumulate on the host in slot order. The
10849    /// activation uses `step_expert_activation_host`, so the clamped tail layers keep the official
10850    /// contract. Exactness-first; no throughput claim.
10851    #[allow(clippy::too_many_arguments)]
10852    pub fn run_routed_experts_nvfp4(
10853        &self,
10854        experts: &ResidentNvfp4ExpertParallel,
10855        input: &[f32],
10856        tokens: usize,
10857        selected: &[usize],
10858        route_weights: &[f32],
10859        experts_per_token: usize,
10860        activation_limit: Option<f32>,
10861    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10862        validate_activations(input, tokens, experts.input_width)?;
10863        let pairs = tokens
10864            .checked_mul(experts_per_token)
10865            .ok_or("NVFP4 EP route count overflow")?;
10866        if selected.len() != pairs || route_weights.len() != pairs {
10867            return Err(format!(
10868                "NVFP4 EP routes selected={} weights={} != tokens {tokens} x experts/token \
10869                 {experts_per_token} ({pairs})",
10870                selected.len(),
10871                route_weights.len(),
10872            )
10873            .into());
10874        }
10875        if !route_weights.iter().all(|weight| weight.is_finite()) {
10876            return Err("NVFP4 EP route weights contain a non-finite value".into());
10877        }
10878        let experts_per_rank = experts.expert_count / experts.ranks.len();
10879        let mut output = vec![0.0f32; tokens * experts.input_width];
10880        for token in 0..tokens {
10881            let input_row = &input[token * experts.input_width..(token + 1) * experts.input_width];
10882            for slot in 0..experts_per_token {
10883                let pair = token * experts_per_token + slot;
10884                let expert = selected[pair];
10885                if expert >= experts.expert_count {
10886                    return Err(format!(
10887                        "NVFP4 EP selected expert {expert} outside 0..{}",
10888                        experts.expert_count
10889                    )
10890                    .into());
10891                }
10892                let owner = expert / experts_per_rank;
10893                let local = expert - owner * experts_per_rank;
10894                let rank = &experts.ranks[owner];
10895                let engine = &self.ranks[owner];
10896                let _main = engine.gpu.enter_main()?;
10897                let device_input = engine.htod(input_row)?;
10898                let gate_out = engine.qmatvec_nvfp4_fast(
10899                    &rank.gate.slice(
10900                        local * rank.gate_expert_bytes..(local + 1) * rank.gate_expert_bytes,
10901                    ),
10902                    &device_input,
10903                    1,
10904                    experts.input_width,
10905                    experts.expert_width,
10906                    experts.gate_row_bytes,
10907                )?;
10908                let up_out = engine.qmatvec_nvfp4_fast(
10909                    &rank.up.slice(
10910                        local * rank.gate_expert_bytes..(local + 1) * rank.gate_expert_bytes,
10911                    ),
10912                    &device_input,
10913                    1,
10914                    experts.input_width,
10915                    experts.expert_width,
10916                    experts.gate_row_bytes,
10917                )?;
10918                let mut gate_host = engine.dtoh(&gate_out)?;
10919                let mut up_host = engine.dtoh(&up_out)?;
10920                apply_macro(&mut gate_host, experts.macros_gate[expert]);
10921                apply_macro(&mut up_host, experts.macros_up[expert]);
10922                let activated: Vec<f32> = gate_host
10923                    .iter()
10924                    .zip(&up_host)
10925                    .map(|(&gate, &up)| step_expert_activation_host(gate, up, activation_limit))
10926                    .collect();
10927                let device_activated = engine.htod(&activated)?;
10928                let down_out = engine.qmatvec_nvfp4_fast(
10929                    &rank.down.slice(
10930                        local * rank.down_expert_bytes..(local + 1) * rank.down_expert_bytes,
10931                    ),
10932                    &device_activated,
10933                    1,
10934                    experts.expert_width,
10935                    experts.input_width,
10936                    experts.down_row_bytes,
10937                )?;
10938                let mut down_host = engine.dtoh(&down_out)?;
10939                apply_macro(&mut down_host, experts.macros_down[expert]);
10940                let weight = route_weights[pair];
10941                for (sum, value) in output
10942                    [token * experts.input_width..(token + 1) * experts.input_width]
10943                    .iter_mut()
10944                    .zip(down_host)
10945                {
10946                    *sum += weight * value;
10947                }
10948            }
10949        }
10950        Ok(output)
10951    }
10952
10953    /// Device-resident W4A16 expert parallelism for one scheduler/prefill batch (1..=128 rows).
10954    ///
10955    /// The host router partitions token/slot pairs by contiguous expert owner. Each rank
10956    /// peer-reads the whole batch input once, rounds it to BF16, and executes its owner-local
10957    /// selected gate/up -> host-expf SwiGLU -> BF16 -> down program. Down rows scatter directly
10958    /// into canonical token-major pair positions in the model engine's peer-accessible pool at
10959    /// every batch width; the root reduces each token's slots in original order. Thus batching
10960    /// and owner assignment do not change route-reduction parenthesization.
10961    #[allow(clippy::too_many_arguments)]
10962    pub fn run_routed_experts_nvfp4_w4a16_device_io(
10963        &self,
10964        experts: &ResidentNvfp4ExpertParallel,
10965        e: &Engine,
10966        input_dev: &crate::CudaSlice<f32>,
10967        tokens: usize,
10968        selected: &[usize],
10969        route_weights: &[f32],
10970        experts_per_token: usize,
10971        activation_limit: Option<f32>,
10972    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
10973        // Diagnostic attribution only: force the returned root event chain to completion so the
10974        // caller's shared-expert timer does not absorb routed-EP work. The normal path remains
10975        // fully asynchronous.
10976        static TIMING_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
10977        static TIMING_CALLS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
10978        let timing = std::env::var("MEMRA_STEP_TP_TIMING").as_deref() == Ok("1");
10979        let started = timing.then(std::time::Instant::now);
10980        if !self.native_p2p {
10981            return Err("W4A16 NVFP4 device EP requires native P2P".into());
10982        }
10983        if self.devices.first().copied() != Some(e.ctx().ordinal()) {
10984            return Err(format!(
10985                "W4A16 NVFP4 device EP root device {:?} != model engine device {}",
10986                self.devices.first(),
10987                e.ctx().ordinal()
10988            )
10989            .into());
10990        }
10991        // Prime/cache scratch buffers are grow-only: a 160-token host-oracle chunk can be
10992        // followed by a 44-token device-EP tail using the same 160-row allocation. Consume the
10993        // active prefix rather than requiring allocation length == active length.
10994        let active_input_values =
10995            nvfp4_ep_active_input_values(input_dev.len(), tokens, experts.input_width)?;
10996        let pairs = tokens
10997            .checked_mul(experts_per_token)
10998            .ok_or("W4A16 NVFP4 device EP route count overflow")?;
10999        if selected.len() != pairs || route_weights.len() != pairs {
11000            return Err(format!(
11001                "W4A16 NVFP4 device EP routes selected={} weights={} != tokens {tokens} x \
11002                 experts/token {experts_per_token} ({pairs})",
11003                selected.len(),
11004                route_weights.len(),
11005            )
11006            .into());
11007        }
11008        if !route_weights.iter().all(|weight| weight.is_finite()) {
11009            return Err("W4A16 NVFP4 device EP route weights contain a non-finite value".into());
11010        }
11011        let world = self.ranks.len();
11012        if world != experts.ranks.len() || !(2..=PRODUCT_MAX_CARDS).contains(&world) {
11013            return Err(format!(
11014                "W4A16 NVFP4 device EP runtime ranks {world} != bank ranks {}",
11015                experts.ranks.len()
11016            )
11017            .into());
11018        }
11019        let owner_routes = partition_expert_owner_routes(
11020            experts.expert_count,
11021            world,
11022            tokens,
11023            experts_per_token,
11024            selected,
11025        )?;
11026
11027        let mut workspace_guard = experts
11028            .device_workspace
11029            .lock()
11030            .map_err(|_| "W4A16 NVFP4 device EP workspace lock is poisoned")?;
11031        if workspace_guard.is_none() {
11032            let capacity_tokens = NVFP4_EP_DEVICE_BATCH_CAP;
11033            let capacity_pairs = capacity_tokens * experts_per_token;
11034            let mut input = Vec::with_capacity(world);
11035            let mut input_bf16 = Vec::with_capacity(world);
11036            let mut input_q8 = Vec::with_capacity(world);
11037            let mut input_q8_scales = Vec::with_capacity(world);
11038            let mut sel = Vec::with_capacity(world);
11039            let mut token_rows = Vec::with_capacity(world);
11040            let mut global_pairs = Vec::with_capacity(world);
11041            let mut route_w = Vec::with_capacity(world);
11042            let mut gate_out = Vec::with_capacity(world);
11043            let mut up_out = Vec::with_capacity(world);
11044            let mut activation_bf16 = Vec::with_capacity(world);
11045            let mut activation_q8 = Vec::with_capacity(world);
11046            let mut activation_q8_scales = Vec::with_capacity(world);
11047            let mut ev_rank = Vec::with_capacity(world);
11048            for engine in &self.ranks {
11049                let _main = engine.gpu.enter_main()?;
11050                input.push(engine.uninit(capacity_tokens * experts.input_width)?);
11051                input_bf16.push(engine.alloc_u8_uninit(2 * capacity_tokens * experts.input_width)?);
11052                input_q8.push(engine.alloc_i8_uninit(capacity_tokens * experts.input_width)?);
11053                input_q8_scales
11054                    .push(engine.uninit(capacity_tokens * experts.input_width.div_ceil(32))?);
11055                sel.push(engine.htod_i32(&vec![0i32; capacity_pairs])?);
11056                token_rows.push(engine.htod_i32(&vec![0i32; capacity_pairs])?);
11057                global_pairs.push(engine.htod_i32(&vec![0i32; capacity_pairs])?);
11058                route_w.push(engine.htod(&vec![0.0f32; capacity_pairs])?);
11059                gate_out.push(engine.uninit(capacity_pairs * experts.expert_width)?);
11060                up_out.push(engine.uninit(capacity_pairs * experts.expert_width)?);
11061                activation_bf16
11062                    .push(engine.alloc_u8_uninit(2 * capacity_pairs * experts.expert_width)?);
11063                activation_q8.push(engine.alloc_i8_uninit(capacity_pairs * experts.expert_width)?);
11064                activation_q8_scales
11065                    .push(engine.uninit(capacity_pairs * experts.expert_width.div_ceil(32))?);
11066                ev_rank.push(engine.ctx().new_event(None)?);
11067            }
11068            let _main = e.gpu.enter_main()?;
11069            let slot_rows = e.uninit(capacity_pairs * experts.input_width)?;
11070            let slot_rows_raw = {
11071                use cudarc::driver::DevicePtr;
11072                let stream = e.stream();
11073                let (pointer, _guard) = slot_rows.device_ptr(&stream);
11074                pointer
11075            };
11076            *workspace_guard = Some(Nvfp4EpDeviceWorkspace {
11077                input,
11078                input_bf16,
11079                input_q8,
11080                input_q8_scales,
11081                sel,
11082                token_rows,
11083                global_pairs,
11084                route_w,
11085                gate_out,
11086                up_out,
11087                activation_bf16,
11088                activation_q8,
11089                activation_q8_scales,
11090                slot_rows,
11091                slot_rows_raw,
11092                route_weights: e.htod(&vec![0.0f32; capacity_pairs])?,
11093                graph_input: e.uninit(NVFP4_EP_GRAPH_BATCH_CAP * experts.input_width)?,
11094                graph_output: e.uninit(NVFP4_EP_GRAPH_BATCH_CAP * experts.input_width)?,
11095                graph_routes: None,
11096                graphs: std::iter::repeat_with(|| None)
11097                    .take(NVFP4_EP_GRAPH_BATCH_CAP + 1)
11098                    .collect(),
11099                ev_entry: e.ctx().new_event(None)?,
11100                ev_entry_device: e.ctx().ordinal(),
11101                ev_rank,
11102                phase_events: None,
11103                capacity_tokens,
11104                experts_per_token,
11105            });
11106        }
11107        let workspace = workspace_guard
11108            .as_mut()
11109            .expect("W4A16 NVFP4 device EP workspace initialized above");
11110        if workspace.experts_per_token != experts_per_token || tokens > workspace.capacity_tokens {
11111            return Err(format!(
11112                "W4A16 NVFP4 device EP workspace tokens={} experts/token={} cannot serve \
11113                 tokens={tokens} experts/token={experts_per_token}",
11114                workspace.capacity_tokens, workspace.experts_per_token,
11115            )
11116            .into());
11117        }
11118        if workspace.ev_entry_device != e.ctx().ordinal() {
11119            return Err("W4A16 NVFP4 device EP model engine changed".into());
11120        }
11121
11122        {
11123            let _main = e.gpu.enter_main()?;
11124            let mut destination = workspace.route_weights.slice_mut(0..pairs);
11125            e.stream()
11126                .memcpy_htod(&route_weights[..pairs], &mut destination)?;
11127            workspace.ev_entry.record(&e.stream())?;
11128        }
11129        for (rank_index, engine) in self.ranks.iter().enumerate() {
11130            let _main = engine.gpu.enter_main()?;
11131            engine.stream().wait(&workspace.ev_entry)?;
11132            {
11133                let mut destination = workspace.input[rank_index].slice_mut(0..active_input_values);
11134                engine
11135                    .stream()
11136                    .memcpy_dtod(&input_dev.slice(0..active_input_values), &mut destination)?;
11137            }
11138            engine.f32_to_bf16_into(
11139                &workspace.input[rank_index],
11140                &mut workspace.input_bf16[rank_index],
11141                tokens * experts.input_width,
11142            )?;
11143            let owner = &owner_routes[rank_index];
11144            debug_assert_eq!(owner.rank, rank_index);
11145            let local_count = owner.selected.len();
11146            if local_count > 0 {
11147                let local_selected = owner
11148                    .selected
11149                    .iter()
11150                    .map(|&expert| expert as i32)
11151                    .collect::<Vec<_>>();
11152                let local_token_rows = owner
11153                    .token_rows
11154                    .iter()
11155                    .map(|&token| token as i32)
11156                    .collect::<Vec<_>>();
11157                let local_global_pairs = owner
11158                    .global_pairs
11159                    .iter()
11160                    .map(|&pair| pair as i32)
11161                    .collect::<Vec<_>>();
11162                {
11163                    let mut destination = workspace.sel[rank_index].slice_mut(0..local_count);
11164                    engine
11165                        .stream()
11166                        .memcpy_htod(&local_selected, &mut destination)?;
11167                }
11168                {
11169                    let mut destination =
11170                        workspace.token_rows[rank_index].slice_mut(0..local_count);
11171                    engine
11172                        .stream()
11173                        .memcpy_htod(&local_token_rows, &mut destination)?;
11174                }
11175                {
11176                    let mut destination =
11177                        workspace.global_pairs[rank_index].slice_mut(0..local_count);
11178                    engine
11179                        .stream()
11180                        .memcpy_htod(&local_global_pairs, &mut destination)?;
11181                }
11182                let rank = &experts.ranks[rank_index];
11183                engine.qmatvec_nvfp4_bf16_sel_dual_rows_into(
11184                    &rank.gate,
11185                    &rank.up,
11186                    &workspace.sel[rank_index],
11187                    &workspace.token_rows[rank_index],
11188                    &workspace.input_bf16[rank_index],
11189                    &mut workspace.gate_out[rank_index],
11190                    &mut workspace.up_out[rank_index],
11191                    local_count,
11192                    experts.input_width,
11193                    experts.expert_width,
11194                    experts.gate_row_bytes,
11195                    rank.gate_expert_bytes,
11196                    tokens,
11197                )?;
11198                engine.silu_mul_scaled_host_expf_bf16_sel_into(
11199                    &workspace.gate_out[rank_index],
11200                    &workspace.up_out[rank_index],
11201                    &rank.macros_gate,
11202                    &rank.macros_up,
11203                    &workspace.sel[rank_index],
11204                    activation_limit,
11205                    &mut workspace.activation_bf16[rank_index],
11206                    experts.expert_width,
11207                    local_count,
11208                )?;
11209                engine.qmatvec_nvfp4_bf16_sel_down_rows_raw(
11210                    &rank.down,
11211                    &workspace.sel[rank_index],
11212                    &workspace.global_pairs[rank_index],
11213                    &workspace.activation_bf16[rank_index],
11214                    &rank.macros_down,
11215                    workspace.slot_rows_raw,
11216                    local_count,
11217                    experts.expert_width,
11218                    experts.input_width,
11219                    experts.down_row_bytes,
11220                    rank.down_expert_bytes,
11221                    pairs,
11222                )?;
11223            }
11224            workspace.ev_rank[rank_index].record(&engine.stream())?;
11225        }
11226
11227        let output = {
11228            let _main = e.gpu.enter_main()?;
11229            for event in &workspace.ev_rank {
11230                e.stream().wait(event)?;
11231            }
11232            let mut output = e.uninit(tokens * experts.input_width)?;
11233            e.axpy_rows_seq_tokens_into(
11234                &workspace.slot_rows,
11235                &workspace.route_weights,
11236                &mut output,
11237                experts.input_width,
11238                experts_per_token,
11239                tokens,
11240            )?;
11241            output
11242        };
11243        if let Some(started) = started {
11244            use std::sync::atomic::Ordering;
11245            e.stream().synchronize()?;
11246            let elapsed = started.elapsed().as_nanos() as u64;
11247            let ns = TIMING_NS.fetch_add(elapsed, Ordering::Relaxed) + elapsed;
11248            let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
11249            if calls.is_multiple_of(430) {
11250                eprintln!(
11251                    "[nvfp4-ep-w4a16-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
11252                    ns as f64 / 1.0e6,
11253                    ns as f64 / calls as f64 / 1.0e3,
11254                );
11255            }
11256        }
11257        Ok(output)
11258    }
11259
11260    /// Fully device-routed W4A16 expert parallelism. Router ids/weights stay on the model GPU;
11261    /// each rank receives the fixed token/slot metadata, rejects non-owned experts in-kernel, and
11262    /// writes canonical token-major slot rows back to the root at every batch width. Preserving
11263    /// that one accumulation program is required by speculative verification: the former t=1
11264    /// owner-grouped FMA was a distinct numeric class and failed real HY3 MTP self-consistency.
11265    #[allow(clippy::too_many_arguments)]
11266    pub fn run_routed_experts_nvfp4_w4a16_device_routed(
11267        &self,
11268        experts: &ResidentNvfp4ExpertParallel,
11269        e: &Engine,
11270        input_dev: &crate::CudaSlice<f32>,
11271        selected_dev: &crate::CudaSlice<i32>,
11272        route_weights_dev: &crate::CudaSlice<f32>,
11273        tokens: usize,
11274        experts_per_token: usize,
11275        activation_limit: Option<f32>,
11276    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
11277        self.run_routed_experts_nvfp4_w4a16_device_routed_inner(
11278            experts,
11279            e,
11280            input_dev,
11281            selected_dev,
11282            route_weights_dev,
11283            tokens,
11284            experts_per_token,
11285            activation_limit,
11286            None,
11287        )
11288    }
11289
11290    /// Automatic whole-expert EP with a PREJOIN hook. The hook runs after every rank's routed
11291    /// chain has been issued and before the root waits for rank completion, so independent
11292    /// root-device work can fill the peer drain without changing the routed accumulation order.
11293    #[allow(clippy::too_many_arguments)]
11294    pub fn run_routed_experts_nvfp4_w4a16_device_routed_prejoin(
11295        &self,
11296        experts: &ResidentNvfp4ExpertParallel,
11297        e: &Engine,
11298        input_dev: &crate::CudaSlice<f32>,
11299        selected_dev: &crate::CudaSlice<i32>,
11300        route_weights_dev: &crate::CudaSlice<f32>,
11301        tokens: usize,
11302        experts_per_token: usize,
11303        activation_limit: Option<f32>,
11304        mut pre_join: impl FnMut() -> Result<(), Box<dyn std::error::Error>>,
11305    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
11306        self.run_routed_experts_nvfp4_w4a16_device_routed_inner(
11307            experts,
11308            e,
11309            input_dev,
11310            selected_dev,
11311            route_weights_dev,
11312            tokens,
11313            experts_per_token,
11314            activation_limit,
11315            Some(&mut pre_join),
11316        )
11317    }
11318
11319    #[allow(clippy::too_many_arguments)]
11320    fn run_routed_experts_nvfp4_w4a16_device_routed_inner(
11321        &self,
11322        experts: &ResidentNvfp4ExpertParallel,
11323        e: &Engine,
11324        input_dev: &crate::CudaSlice<f32>,
11325        selected_dev: &crate::CudaSlice<i32>,
11326        route_weights_dev: &crate::CudaSlice<f32>,
11327        tokens: usize,
11328        experts_per_token: usize,
11329        activation_limit: Option<f32>,
11330        mut pre_join: Option<&mut dyn FnMut() -> Result<(), Box<dyn std::error::Error>>>,
11331    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
11332        if !self.native_p2p {
11333            return Err("W4A16 device-routed EP requires native P2P".into());
11334        }
11335        if self.devices.first().copied() != Some(e.ctx().ordinal()) {
11336            return Err(format!(
11337                "W4A16 device-routed EP root device {:?} != model engine device {}",
11338                self.devices.first(),
11339                e.ctx().ordinal()
11340            )
11341            .into());
11342        }
11343        let active_input_values =
11344            nvfp4_ep_active_input_values(input_dev.len(), tokens, experts.input_width)?;
11345        let pairs = tokens
11346            .checked_mul(experts_per_token)
11347            .ok_or("W4A16 device-routed EP route count overflow")?;
11348        if selected_dev.len() < pairs || route_weights_dev.len() < pairs {
11349            return Err(format!(
11350                "W4A16 device-routed EP metadata selected={} weights={} < pairs={pairs}",
11351                selected_dev.len(),
11352                route_weights_dev.len(),
11353            )
11354            .into());
11355        }
11356        let world = self.ranks.len();
11357        if world != experts.ranks.len() || !(2..=PRODUCT_MAX_CARDS).contains(&world) {
11358            return Err(format!(
11359                "W4A16 device-routed EP runtime ranks {world} != bank ranks {}",
11360                experts.ranks.len()
11361            )
11362            .into());
11363        }
11364
11365        static TIMING_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11366        static TIMING_CALLS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11367        static ISSUE_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11368        static JOIN_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11369        static COPY_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11370        static GATE_UP_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11371        static ACTIVATION_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11372        static DOWN_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11373        static RANK_SPAN_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11374        let timing = std::env::var("MEMRA_STEP_TP_TIMING").as_deref() == Ok("1");
11375        let started = timing.then(std::time::Instant::now);
11376        let graph_enabled = parallel_ep_graph_enabled()?;
11377        let pair_down_enabled = parallel_ep_pair_down_enabled()?;
11378
11379        let mut workspace_guard = experts
11380            .device_workspace
11381            .lock()
11382            .map_err(|_| "W4A16 device-routed EP workspace lock is poisoned")?;
11383        if workspace_guard.is_none() {
11384            let capacity_tokens = NVFP4_EP_DEVICE_BATCH_CAP;
11385            let capacity_pairs = capacity_tokens * experts_per_token;
11386            let mut input = Vec::with_capacity(world);
11387            let mut input_bf16 = Vec::with_capacity(world);
11388            let mut input_q8 = Vec::with_capacity(world);
11389            let mut input_q8_scales = Vec::with_capacity(world);
11390            let mut sel = Vec::with_capacity(world);
11391            let mut token_rows = Vec::with_capacity(world);
11392            let mut global_pairs = Vec::with_capacity(world);
11393            let mut route_w = Vec::with_capacity(world);
11394            let mut gate_out = Vec::with_capacity(world);
11395            let mut up_out = Vec::with_capacity(world);
11396            let mut activation_bf16 = Vec::with_capacity(world);
11397            let mut activation_q8 = Vec::with_capacity(world);
11398            let mut activation_q8_scales = Vec::with_capacity(world);
11399            let mut ev_rank = Vec::with_capacity(world);
11400            let mut phase_head = Vec::with_capacity(world);
11401            let mut phase_copy_done = Vec::with_capacity(world);
11402            let mut phase_gate_up_done = Vec::with_capacity(world);
11403            let mut phase_activation_done = Vec::with_capacity(world);
11404            let mut phase_down_done = Vec::with_capacity(world);
11405            for engine in &self.ranks {
11406                let _main = engine.gpu.enter_main()?;
11407                input.push(engine.uninit(capacity_tokens * experts.input_width)?);
11408                input_bf16.push(engine.alloc_u8_uninit(2 * capacity_tokens * experts.input_width)?);
11409                input_q8.push(engine.alloc_i8_uninit(capacity_tokens * experts.input_width)?);
11410                input_q8_scales
11411                    .push(engine.uninit(capacity_tokens * experts.input_width.div_ceil(32))?);
11412                sel.push(engine.htod_i32(&vec![0i32; capacity_pairs])?);
11413                token_rows.push(engine.htod_i32(&vec![0i32; capacity_pairs])?);
11414                global_pairs.push(engine.htod_i32(&vec![0i32; capacity_pairs])?);
11415                route_w.push(engine.htod(&vec![0.0f32; capacity_pairs])?);
11416                gate_out.push(engine.uninit(capacity_pairs * experts.expert_width)?);
11417                up_out.push(engine.uninit(capacity_pairs * experts.expert_width)?);
11418                activation_bf16
11419                    .push(engine.alloc_u8_uninit(2 * capacity_pairs * experts.expert_width)?);
11420                activation_q8.push(engine.alloc_i8_uninit(capacity_pairs * experts.expert_width)?);
11421                activation_q8_scales
11422                    .push(engine.uninit(capacity_pairs * experts.expert_width.div_ceil(32))?);
11423                ev_rank.push(engine.ctx().new_event(None)?);
11424                if timing {
11425                    phase_head.push(
11426                        engine.ctx().new_event(Some(
11427                            cudarc::driver::sys::CUevent_flags::CU_EVENT_DEFAULT,
11428                        ))?,
11429                    );
11430                    phase_copy_done.push(
11431                        engine.ctx().new_event(Some(
11432                            cudarc::driver::sys::CUevent_flags::CU_EVENT_DEFAULT,
11433                        ))?,
11434                    );
11435                    phase_gate_up_done.push(
11436                        engine.ctx().new_event(Some(
11437                            cudarc::driver::sys::CUevent_flags::CU_EVENT_DEFAULT,
11438                        ))?,
11439                    );
11440                    phase_activation_done.push(
11441                        engine.ctx().new_event(Some(
11442                            cudarc::driver::sys::CUevent_flags::CU_EVENT_DEFAULT,
11443                        ))?,
11444                    );
11445                    phase_down_done.push(
11446                        engine.ctx().new_event(Some(
11447                            cudarc::driver::sys::CUevent_flags::CU_EVENT_DEFAULT,
11448                        ))?,
11449                    );
11450                }
11451            }
11452            let _main = e.gpu.enter_main()?;
11453            let slot_rows = e.uninit(capacity_pairs * experts.input_width)?;
11454            let slot_rows_raw = {
11455                use cudarc::driver::DevicePtr;
11456                let stream = e.stream();
11457                let (pointer, _guard) = slot_rows.device_ptr(&stream);
11458                pointer
11459            };
11460            *workspace_guard = Some(Nvfp4EpDeviceWorkspace {
11461                input,
11462                input_bf16,
11463                input_q8,
11464                input_q8_scales,
11465                sel,
11466                token_rows,
11467                global_pairs,
11468                route_w,
11469                gate_out,
11470                up_out,
11471                activation_bf16,
11472                activation_q8,
11473                activation_q8_scales,
11474                slot_rows,
11475                slot_rows_raw,
11476                route_weights: e.htod(&vec![0.0f32; capacity_pairs])?,
11477                graph_input: e.uninit(NVFP4_EP_GRAPH_BATCH_CAP * experts.input_width)?,
11478                graph_output: e.uninit(NVFP4_EP_GRAPH_BATCH_CAP * experts.input_width)?,
11479                graph_routes: None,
11480                graphs: std::iter::repeat_with(|| None)
11481                    .take(NVFP4_EP_GRAPH_BATCH_CAP + 1)
11482                    .collect(),
11483                ev_entry: e.ctx().new_event(None)?,
11484                ev_entry_device: e.ctx().ordinal(),
11485                ev_rank,
11486                phase_events: timing.then_some(Nvfp4EpPhaseEvents {
11487                    head: phase_head,
11488                    copy_done: phase_copy_done,
11489                    gate_up_done: phase_gate_up_done,
11490                    activation_done: phase_activation_done,
11491                    down_done: phase_down_done,
11492                }),
11493                capacity_tokens,
11494                experts_per_token,
11495            });
11496        }
11497        let workspace = workspace_guard
11498            .as_mut()
11499            .expect("W4A16 device-routed EP workspace initialized above");
11500        if workspace.experts_per_token != experts_per_token || tokens > workspace.capacity_tokens {
11501            return Err(format!(
11502                "W4A16 device-routed EP workspace tokens={} experts/token={} cannot serve \
11503                 tokens={tokens} experts/token={experts_per_token}",
11504                workspace.capacity_tokens, workspace.experts_per_token,
11505            )
11506            .into());
11507        }
11508
11509        if tokens <= NVFP4_EP_Q8_BATCH_CAP && parallel_ep_q8_act_enabled()? {
11510            if graph_enabled {
11511                return Err("MEMRA_PARALLEL_EP_GRAPH=1 is exact W4A16-only; disable \
11512                     MEMRA_PARALLEL_EP_Q8_ACT or the graph door"
11513                    .into());
11514            }
11515            return self.run_routed_experts_nvfp4_w4a8_device_routed(
11516                experts,
11517                e,
11518                input_dev,
11519                selected_dev,
11520                route_weights_dev,
11521                workspace,
11522                tokens,
11523                experts_per_token,
11524                activation_limit,
11525                pre_join,
11526            );
11527        }
11528
11529        if graph_enabled && !timing && pre_join.is_none() && tokens <= NVFP4_EP_GRAPH_BATCH_CAP {
11530            use cudarc::driver::DevicePtr;
11531            let route_ptrs = {
11532                let stream = e.stream();
11533                let (sel_ptr, _sel_guard) = selected_dev.device_ptr(&stream);
11534                let (weight_ptr, _weight_guard) = route_weights_dev.device_ptr(&stream);
11535                (sel_ptr, weight_ptr)
11536            };
11537            if let Some(graph_exec) = workspace.graphs[tokens].as_ref().map(|graph| graph.exec) {
11538                if workspace.graph_routes != Some(route_ptrs) {
11539                    return Err(format!(
11540                        "W4A16 EP graph route buffers moved: built={:?} current={route_ptrs:?}",
11541                        workspace.graph_routes,
11542                    )
11543                    .into());
11544                }
11545                let _main = e.gpu.enter_main()?;
11546                e.stream().memcpy_dtod(
11547                    &input_dev.slice(0..active_input_values),
11548                    &mut workspace.graph_input.slice_mut(0..active_input_values),
11549                )?;
11550                e.memset_zeros_view(
11551                    &mut workspace
11552                        .slot_rows
11553                        .slice_mut(0..pairs * experts.input_width),
11554                )?;
11555                unsafe {
11556                    let result = cudarc::driver::sys::cuGraphLaunch(
11557                        graph_exec,
11558                        e.stream().cu_stream() as cudarc::driver::sys::CUstream,
11559                    );
11560                    if result != cudarc::driver::sys::CUresult::CUDA_SUCCESS {
11561                        return Err(format!("W4A16 EP graph launch: {result:?}").into());
11562                    }
11563                }
11564                let mut output = e.uninit(active_input_values)?;
11565                e.stream().memcpy_dtod(
11566                    &workspace.graph_output.slice(0..active_input_values),
11567                    &mut output.slice_mut(0..active_input_values),
11568                )?;
11569                return Ok(output);
11570            }
11571        }
11572
11573        {
11574            let _main = e.gpu.enter_main()?;
11575            e.memset_zeros_view(
11576                &mut workspace
11577                    .slot_rows
11578                    .slice_mut(0..pairs * experts.input_width),
11579            )?;
11580            workspace.ev_entry.record(&e.stream())?;
11581        }
11582
11583        for (rank_index, engine) in self.ranks.iter().enumerate() {
11584            let _main = engine.gpu.enter_main()?;
11585            if let Some(events) = workspace.phase_events.as_ref() {
11586                events.head[rank_index].record(&engine.stream())?;
11587            }
11588            engine.stream().wait(&workspace.ev_entry)?;
11589            let Nvfp4EpDeviceWorkspace {
11590                input_bf16,
11591                sel,
11592                route_w,
11593                ..
11594            } = &mut *workspace;
11595            engine.nvfp4_ep_stage_inputs(
11596                input_dev,
11597                selected_dev,
11598                route_weights_dev,
11599                &mut input_bf16[rank_index],
11600                &mut sel[rank_index],
11601                &mut route_w[rank_index],
11602                active_input_values,
11603                pairs,
11604                false,
11605            )?;
11606            if let Some(events) = workspace.phase_events.as_ref() {
11607                events.copy_done[rank_index].record(&engine.stream())?;
11608            }
11609            let rank = &experts.ranks[rank_index];
11610            let owner_start = rank.expert_range.start;
11611            let owner_end = rank.expert_range.end;
11612            engine.qmatvec_nvfp4_bf16_ep_dual_slots_into(
11613                &rank.gate,
11614                &rank.up,
11615                &workspace.sel[rank_index],
11616                &workspace.input_bf16[rank_index],
11617                &mut workspace.gate_out[rank_index],
11618                &mut workspace.up_out[rank_index],
11619                pairs,
11620                experts_per_token,
11621                experts.input_width,
11622                experts.expert_width,
11623                owner_start,
11624                owner_end,
11625                experts.gate_row_bytes,
11626                rank.gate_expert_bytes,
11627            )?;
11628            if let Some(events) = workspace.phase_events.as_ref() {
11629                events.gate_up_done[rank_index].record(&engine.stream())?;
11630            }
11631            engine.silu_mul_scaled_host_expf_bf16_ep_slots_into(
11632                &workspace.gate_out[rank_index],
11633                &workspace.up_out[rank_index],
11634                &rank.macros_gate,
11635                &rank.macros_up,
11636                &workspace.sel[rank_index],
11637                owner_start,
11638                owner_end,
11639                activation_limit,
11640                &mut workspace.activation_bf16[rank_index],
11641                experts.expert_width,
11642                pairs,
11643            )?;
11644            if let Some(events) = workspace.phase_events.as_ref() {
11645                events.activation_done[rank_index].record(&engine.stream())?;
11646            }
11647            if tokens > 1 && pair_down_enabled {
11648                engine.qmatvec_nvfp4_bf16_ep_down_pairs_raw(
11649                    &rank.down,
11650                    &workspace.sel[rank_index],
11651                    &workspace.activation_bf16[rank_index],
11652                    &rank.macros_down,
11653                    workspace.slot_rows_raw,
11654                    pairs,
11655                    experts.expert_width,
11656                    experts.input_width,
11657                    owner_start,
11658                    owner_end,
11659                    experts.down_row_bytes,
11660                    rank.down_expert_bytes,
11661                )?;
11662            } else {
11663                engine.qmatvec_nvfp4_bf16_ep_down_slots_raw(
11664                    &rank.down,
11665                    &workspace.sel[rank_index],
11666                    &workspace.activation_bf16[rank_index],
11667                    &rank.macros_down,
11668                    workspace.slot_rows_raw,
11669                    pairs,
11670                    experts.expert_width,
11671                    experts.input_width,
11672                    owner_start,
11673                    owner_end,
11674                    experts.down_row_bytes,
11675                    rank.down_expert_bytes,
11676                )?;
11677            }
11678            if let Some(events) = workspace.phase_events.as_ref() {
11679                events.down_done[rank_index].record(&engine.stream())?;
11680            }
11681            workspace.ev_rank[rank_index].record(&engine.stream())?;
11682        }
11683
11684        if let Some(pre_join) = pre_join.as_mut() {
11685            pre_join()?;
11686        }
11687        let issue_ns_this = started
11688            .as_ref()
11689            .map(|started| started.elapsed().as_nanos() as u64);
11690        let join_started = timing.then(std::time::Instant::now);
11691        let output = {
11692            let _main = e.gpu.enter_main()?;
11693            for event in &workspace.ev_rank {
11694                e.stream().wait(event)?;
11695            }
11696            let mut output = e.uninit(tokens * experts.input_width)?;
11697            e.axpy_rows_seq_tokens_into(
11698                &workspace.slot_rows,
11699                route_weights_dev,
11700                &mut output,
11701                experts.input_width,
11702                experts_per_token,
11703                tokens,
11704            )?;
11705            output
11706        };
11707
11708        if let Some(started) = started {
11709            use std::sync::atomic::Ordering;
11710            e.stream().synchronize()?;
11711            let elapsed = started.elapsed().as_nanos() as u64;
11712            let join_ns_this = join_started
11713                .expect("timing join starts with total timing")
11714                .elapsed()
11715                .as_nanos() as u64;
11716            let mut phase_max_ms = [0.0f32; 5];
11717            if let Some(events) = workspace.phase_events.as_ref() {
11718                for rank_index in 0..world {
11719                    let engine = &self.ranks[rank_index];
11720                    let _main = engine.gpu.enter_main()?;
11721                    phase_max_ms[0] = phase_max_ms[0]
11722                        .max(events.head[rank_index].elapsed_ms(&events.copy_done[rank_index])?);
11723                    phase_max_ms[1] = phase_max_ms[1].max(
11724                        events.copy_done[rank_index]
11725                            .elapsed_ms(&events.gate_up_done[rank_index])?,
11726                    );
11727                    phase_max_ms[2] = phase_max_ms[2].max(
11728                        events.gate_up_done[rank_index]
11729                            .elapsed_ms(&events.activation_done[rank_index])?,
11730                    );
11731                    phase_max_ms[3] = phase_max_ms[3].max(
11732                        events.activation_done[rank_index]
11733                            .elapsed_ms(&events.down_done[rank_index])?,
11734                    );
11735                    phase_max_ms[4] = phase_max_ms[4]
11736                        .max(events.head[rank_index].elapsed_ms(&events.down_done[rank_index])?);
11737                }
11738            }
11739            let phase_ns = phase_max_ms.map(|ms| (ms as f64 * 1.0e6) as u64);
11740            let ns = TIMING_NS.fetch_add(elapsed, Ordering::Relaxed) + elapsed;
11741            let issue_ns = ISSUE_NS.fetch_add(
11742                issue_ns_this.expect("timing issue starts with total timing"),
11743                Ordering::Relaxed,
11744            ) + issue_ns_this.expect("timing issue starts with total timing");
11745            let join_ns = JOIN_NS.fetch_add(join_ns_this, Ordering::Relaxed) + join_ns_this;
11746            let copy_ns = COPY_NS.fetch_add(phase_ns[0], Ordering::Relaxed) + phase_ns[0];
11747            let gate_up_ns = GATE_UP_NS.fetch_add(phase_ns[1], Ordering::Relaxed) + phase_ns[1];
11748            let activation_ns =
11749                ACTIVATION_NS.fetch_add(phase_ns[2], Ordering::Relaxed) + phase_ns[2];
11750            let down_ns = DOWN_NS.fetch_add(phase_ns[3], Ordering::Relaxed) + phase_ns[3];
11751            let rank_span_ns = RANK_SPAN_NS.fetch_add(phase_ns[4], Ordering::Relaxed) + phase_ns[4];
11752            let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
11753            if calls.is_multiple_of(430) {
11754                eprintln!(
11755                    "[nvfp4-ep-device-router-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
11756                    ns as f64 / 1.0e6,
11757                    ns as f64 / calls as f64 / 1.0e3,
11758                );
11759                eprintln!(
11760                    "[nvfp4-ep-device-router-phases] calls={calls} issue_us={:.1} \
11761                     join_us={:.1} rank_span_us={:.1} copy_us={:.1} gate_up_us={:.1} \
11762                     activation_us={:.1} down_us={:.1}",
11763                    issue_ns as f64 / calls as f64 / 1.0e3,
11764                    join_ns as f64 / calls as f64 / 1.0e3,
11765                    rank_span_ns as f64 / calls as f64 / 1.0e3,
11766                    copy_ns as f64 / calls as f64 / 1.0e3,
11767                    gate_up_ns as f64 / calls as f64 / 1.0e3,
11768                    activation_ns as f64 / calls as f64 / 1.0e3,
11769                    down_ns as f64 / calls as f64 / 1.0e3,
11770                );
11771            }
11772        }
11773        if graph_enabled
11774            && !timing
11775            && pre_join.is_none()
11776            && tokens <= NVFP4_EP_GRAPH_BATCH_CAP
11777            && workspace.graphs[tokens].is_none()
11778        {
11779            e.stream().synchronize()?;
11780            let graph = self.build_nvfp4_ep_routes_graph(
11781                experts,
11782                e,
11783                workspace,
11784                selected_dev,
11785                route_weights_dev,
11786                tokens,
11787                experts_per_token,
11788                activation_limit,
11789            )?;
11790            workspace.graphs[tokens] = Some(graph);
11791            eprintln!(
11792                "[parallel-ep-graph] captured devices={:?} tokens={tokens} \
11793                 experts/token={experts_per_token} input=staged routes=fixed \
11794                 device_arithmetic=unchanged performance_claim=false",
11795                self.devices,
11796            );
11797        }
11798        Ok(output)
11799    }
11800
11801    #[allow(clippy::too_many_arguments)]
11802    fn run_routed_experts_nvfp4_w4a8_device_routed(
11803        &self,
11804        experts: &ResidentNvfp4ExpertParallel,
11805        e: &Engine,
11806        input_dev: &crate::CudaSlice<f32>,
11807        selected_dev: &crate::CudaSlice<i32>,
11808        route_weights_dev: &crate::CudaSlice<f32>,
11809        workspace: &mut Nvfp4EpDeviceWorkspace,
11810        tokens: usize,
11811        experts_per_token: usize,
11812        activation_limit: Option<f32>,
11813        mut pre_join: Option<&mut dyn FnMut() -> Result<(), Box<dyn std::error::Error>>>,
11814    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
11815        static TIMING_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11816        static TIMING_CALLS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11817        static ISSUE_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11818        static JOIN_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11819        static COPY_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11820        static GATE_UP_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11821        static ACTIVATION_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11822        static DOWN_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11823        static RANK_SPAN_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11824        let timing = std::env::var("MEMRA_STEP_TP_TIMING").as_deref() == Ok("1");
11825        let started = timing.then(std::time::Instant::now);
11826        let pairs = tokens
11827            .checked_mul(experts_per_token)
11828            .ok_or("W4A8 device-routed EP route count overflow")?;
11829        let input_values = tokens
11830            .checked_mul(experts.input_width)
11831            .ok_or("W4A8 device-routed EP input size overflow")?;
11832        let scope = parallel_ep_q8_scope()?.unwrap_or(ParallelEpQ8Scope::All);
11833
11834        {
11835            let _main = e.gpu.enter_main()?;
11836            e.memset_zeros_view(
11837                &mut workspace
11838                    .slot_rows
11839                    .slice_mut(0..pairs * experts.input_width),
11840            )?;
11841            workspace.ev_entry.record(&e.stream())?;
11842        }
11843        for (rank_index, engine) in self.ranks.iter().enumerate() {
11844            let _main = engine.gpu.enter_main()?;
11845            if let Some(events) = workspace.phase_events.as_ref() {
11846                events.head[rank_index].record(&engine.stream())?;
11847            }
11848            engine.stream().wait(&workspace.ev_entry)?;
11849            let rank = &experts.ranks[rank_index];
11850            let owner_start = rank.expert_range.start;
11851            let owner_end = rank.expert_range.end;
11852            match scope {
11853                ParallelEpQ8Scope::All | ParallelEpQ8Scope::GateUp => {
11854                    engine.quantize_q8_1_into(
11855                        input_dev,
11856                        tokens,
11857                        experts.input_width,
11858                        &mut workspace.input_q8[rank_index],
11859                        &mut workspace.input_q8_scales[rank_index],
11860                    )?;
11861                    engine.moe_sel_w_mirror(
11862                        selected_dev,
11863                        route_weights_dev,
11864                        &mut workspace.sel[rank_index],
11865                        &mut workspace.route_w[rank_index],
11866                        pairs,
11867                    )?;
11868                    if let Some(events) = workspace.phase_events.as_ref() {
11869                        events.copy_done[rank_index].record(&engine.stream())?;
11870                    }
11871                    engine.qmatvec_nvfp4_q8_ep_dual_slots_into(
11872                        &rank.gate,
11873                        &rank.up,
11874                        &workspace.sel[rank_index],
11875                        &workspace.input_q8[rank_index],
11876                        &workspace.input_q8_scales[rank_index],
11877                        &mut workspace.gate_out[rank_index],
11878                        &mut workspace.up_out[rank_index],
11879                        pairs,
11880                        experts_per_token,
11881                        experts.input_width,
11882                        experts.expert_width,
11883                        owner_start,
11884                        owner_end,
11885                        experts.gate_row_bytes,
11886                        rank.gate_expert_bytes,
11887                    )?;
11888                }
11889                ParallelEpQ8Scope::Down => {
11890                    engine.nvfp4_ep_stage_inputs(
11891                        input_dev,
11892                        selected_dev,
11893                        route_weights_dev,
11894                        &mut workspace.input_bf16[rank_index],
11895                        &mut workspace.sel[rank_index],
11896                        &mut workspace.route_w[rank_index],
11897                        input_values,
11898                        pairs,
11899                        false,
11900                    )?;
11901                    if let Some(events) = workspace.phase_events.as_ref() {
11902                        events.copy_done[rank_index].record(&engine.stream())?;
11903                    }
11904                    engine.qmatvec_nvfp4_bf16_ep_dual_slots_into(
11905                        &rank.gate,
11906                        &rank.up,
11907                        &workspace.sel[rank_index],
11908                        &workspace.input_bf16[rank_index],
11909                        &mut workspace.gate_out[rank_index],
11910                        &mut workspace.up_out[rank_index],
11911                        pairs,
11912                        experts_per_token,
11913                        experts.input_width,
11914                        experts.expert_width,
11915                        owner_start,
11916                        owner_end,
11917                        experts.gate_row_bytes,
11918                        rank.gate_expert_bytes,
11919                    )?;
11920                }
11921            }
11922            if let Some(events) = workspace.phase_events.as_ref() {
11923                events.gate_up_done[rank_index].record(&engine.stream())?;
11924            }
11925            match scope {
11926                ParallelEpQ8Scope::All | ParallelEpQ8Scope::Down => {
11927                    engine.silu_mul_scaled_host_expf_q8_ep_slots_into(
11928                        &workspace.gate_out[rank_index],
11929                        &workspace.up_out[rank_index],
11930                        &rank.macros_gate,
11931                        &rank.macros_up,
11932                        &workspace.sel[rank_index],
11933                        owner_start,
11934                        owner_end,
11935                        activation_limit,
11936                        &mut workspace.activation_q8[rank_index],
11937                        &mut workspace.activation_q8_scales[rank_index],
11938                        experts.expert_width,
11939                        pairs,
11940                    )?;
11941                    if let Some(events) = workspace.phase_events.as_ref() {
11942                        events.activation_done[rank_index].record(&engine.stream())?;
11943                    }
11944                    engine.qmatvec_nvfp4_q8_ep_down_slots_raw(
11945                        &rank.down,
11946                        &workspace.sel[rank_index],
11947                        &workspace.activation_q8[rank_index],
11948                        &workspace.activation_q8_scales[rank_index],
11949                        &rank.macros_down,
11950                        workspace.slot_rows_raw,
11951                        pairs,
11952                        experts.expert_width,
11953                        experts.input_width,
11954                        owner_start,
11955                        owner_end,
11956                        experts.down_row_bytes,
11957                        rank.down_expert_bytes,
11958                    )?;
11959                }
11960                ParallelEpQ8Scope::GateUp => {
11961                    engine.silu_mul_scaled_host_expf_bf16_ep_slots_into(
11962                        &workspace.gate_out[rank_index],
11963                        &workspace.up_out[rank_index],
11964                        &rank.macros_gate,
11965                        &rank.macros_up,
11966                        &workspace.sel[rank_index],
11967                        owner_start,
11968                        owner_end,
11969                        activation_limit,
11970                        &mut workspace.activation_bf16[rank_index],
11971                        experts.expert_width,
11972                        pairs,
11973                    )?;
11974                    if let Some(events) = workspace.phase_events.as_ref() {
11975                        events.activation_done[rank_index].record(&engine.stream())?;
11976                    }
11977                    engine.qmatvec_nvfp4_bf16_ep_down_slots_raw(
11978                        &rank.down,
11979                        &workspace.sel[rank_index],
11980                        &workspace.activation_bf16[rank_index],
11981                        &rank.macros_down,
11982                        workspace.slot_rows_raw,
11983                        pairs,
11984                        experts.expert_width,
11985                        experts.input_width,
11986                        owner_start,
11987                        owner_end,
11988                        experts.down_row_bytes,
11989                        rank.down_expert_bytes,
11990                    )?;
11991                }
11992            }
11993            if let Some(events) = workspace.phase_events.as_ref() {
11994                events.down_done[rank_index].record(&engine.stream())?;
11995            }
11996            workspace.ev_rank[rank_index].record(&engine.stream())?;
11997        }
11998
11999        if let Some(pre_join) = pre_join.as_mut() {
12000            pre_join()?;
12001        }
12002        let issue_ns_this = started
12003            .as_ref()
12004            .map(|started| started.elapsed().as_nanos() as u64);
12005        let join_started = timing.then(std::time::Instant::now);
12006        let output = {
12007            let _main = e.gpu.enter_main()?;
12008            for event in &workspace.ev_rank {
12009                e.stream().wait(event)?;
12010            }
12011            let mut output = e.uninit(input_values)?;
12012            e.axpy_rows_seq_tokens_into(
12013                &workspace.slot_rows,
12014                route_weights_dev,
12015                &mut output,
12016                experts.input_width,
12017                experts_per_token,
12018                tokens,
12019            )?;
12020            output
12021        };
12022        if let Some(started) = started {
12023            use std::sync::atomic::Ordering;
12024            e.stream().synchronize()?;
12025            let elapsed = started.elapsed().as_nanos() as u64;
12026            let join_ns_this = join_started
12027                .expect("timing join starts with total timing")
12028                .elapsed()
12029                .as_nanos() as u64;
12030            let mut phase_max_ms = [0.0f32; 5];
12031            if let Some(events) = workspace.phase_events.as_ref() {
12032                for rank_index in 0..self.ranks.len() {
12033                    let engine = &self.ranks[rank_index];
12034                    let _main = engine.gpu.enter_main()?;
12035                    phase_max_ms[0] = phase_max_ms[0]
12036                        .max(events.head[rank_index].elapsed_ms(&events.copy_done[rank_index])?);
12037                    phase_max_ms[1] = phase_max_ms[1].max(
12038                        events.copy_done[rank_index]
12039                            .elapsed_ms(&events.gate_up_done[rank_index])?,
12040                    );
12041                    phase_max_ms[2] = phase_max_ms[2].max(
12042                        events.gate_up_done[rank_index]
12043                            .elapsed_ms(&events.activation_done[rank_index])?,
12044                    );
12045                    phase_max_ms[3] = phase_max_ms[3].max(
12046                        events.activation_done[rank_index]
12047                            .elapsed_ms(&events.down_done[rank_index])?,
12048                    );
12049                    phase_max_ms[4] = phase_max_ms[4]
12050                        .max(events.head[rank_index].elapsed_ms(&events.down_done[rank_index])?);
12051                }
12052            }
12053            let phase_ns = phase_max_ms.map(|ms| (ms as f64 * 1.0e6) as u64);
12054            let ns = TIMING_NS.fetch_add(elapsed, Ordering::Relaxed) + elapsed;
12055            let issue_ns = ISSUE_NS.fetch_add(
12056                issue_ns_this.expect("timing issue starts with total timing"),
12057                Ordering::Relaxed,
12058            ) + issue_ns_this.expect("timing issue starts with total timing");
12059            let join_ns = JOIN_NS.fetch_add(join_ns_this, Ordering::Relaxed) + join_ns_this;
12060            let copy_ns = COPY_NS.fetch_add(phase_ns[0], Ordering::Relaxed) + phase_ns[0];
12061            let gate_up_ns = GATE_UP_NS.fetch_add(phase_ns[1], Ordering::Relaxed) + phase_ns[1];
12062            let activation_ns =
12063                ACTIVATION_NS.fetch_add(phase_ns[2], Ordering::Relaxed) + phase_ns[2];
12064            let down_ns = DOWN_NS.fetch_add(phase_ns[3], Ordering::Relaxed) + phase_ns[3];
12065            let rank_span_ns = RANK_SPAN_NS.fetch_add(phase_ns[4], Ordering::Relaxed) + phase_ns[4];
12066            let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
12067            if calls.is_multiple_of(430) {
12068                eprintln!(
12069                    "[nvfp4-ep-q8-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
12070                    ns as f64 / 1.0e6,
12071                    ns as f64 / calls as f64 / 1.0e3,
12072                );
12073                eprintln!(
12074                    "[nvfp4-ep-q8-phases] calls={calls} issue_us={:.1} join_us={:.1} \
12075                     rank_span_us={:.1} copy_us={:.1} gate_up_us={:.1} \
12076                     activation_us={:.1} down_us={:.1}",
12077                    issue_ns as f64 / calls as f64 / 1.0e3,
12078                    join_ns as f64 / calls as f64 / 1.0e3,
12079                    rank_span_ns as f64 / calls as f64 / 1.0e3,
12080                    copy_ns as f64 / calls as f64 / 1.0e3,
12081                    gate_up_ns as f64 / calls as f64 / 1.0e3,
12082                    activation_ns as f64 / calls as f64 / 1.0e3,
12083                    down_ns as f64 / calls as f64 / 1.0e3,
12084                );
12085            }
12086        }
12087        static LOGGED: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
12088        if !LOGGED.swap(true, std::sync::atomic::Ordering::Relaxed) {
12089            let (expert_input, post_activation, numeric_class) = match scope {
12090                ParallelEpQ8Scope::All => ("q8_1", "q8_1", "w4a8-internal"),
12091                ParallelEpQ8Scope::GateUp => ("q8_1", "bf16", "w4a8-gate-up-internal"),
12092                ParallelEpQ8Scope::Down => ("bf16", "q8_1", "w4a8-down-internal"),
12093            };
12094            eprintln!(
12095                "[parallel-ep-q8] devices={:?} tokens={tokens} scope={} \
12096                 expert_input={expert_input} post_activation={post_activation} \
12097                 external_boundary=bf16 numeric_class={numeric_class} \
12098                 host_expf=true accumulation=token-slot-order performance_claim=false",
12099                self.devices,
12100                scope.label(),
12101            );
12102        }
12103        Ok(output)
12104    }
12105
12106    #[allow(clippy::too_many_arguments)]
12107    fn build_nvfp4_ep_routes_graph(
12108        &self,
12109        experts: &ResidentNvfp4ExpertParallel,
12110        e: &Engine,
12111        workspace: &mut Nvfp4EpDeviceWorkspace,
12112        selected_dev: &crate::CudaSlice<i32>,
12113        route_weights_dev: &crate::CudaSlice<f32>,
12114        tokens: usize,
12115        experts_per_token: usize,
12116        activation_limit: Option<f32>,
12117    ) -> Result<RoutesGraph, Box<dyn std::error::Error>> {
12118        use cudarc::driver::DevicePtr;
12119        use cudarc::driver::sys;
12120
12121        fn cu_try(result: sys::CUresult, context: &str) -> Result<(), Box<dyn std::error::Error>> {
12122            if result == sys::CUresult::CUDA_SUCCESS {
12123                Ok(())
12124            } else {
12125                Err(format!("{context}: {result:?}").into())
12126            }
12127        }
12128
12129        let world = self.ranks.len();
12130        if world != experts.ranks.len() || !(2..=PRODUCT_MAX_CARDS).contains(&world) {
12131            return Err(format!(
12132                "W4A16 EP graph world {world} != expert ranks {}",
12133                experts.ranks.len()
12134            )
12135            .into());
12136        }
12137        let width = experts.input_width;
12138        if !(1..=NVFP4_EP_GRAPH_BATCH_CAP).contains(&tokens) {
12139            return Err(format!(
12140                "W4A16 EP graph tokens {tokens} outside 1..={NVFP4_EP_GRAPH_BATCH_CAP}"
12141            )
12142            .into());
12143        }
12144        let pairs = tokens
12145            .checked_mul(experts_per_token)
12146            .ok_or("W4A16 EP graph pair count overflow")?;
12147        let input_values = tokens
12148            .checked_mul(width)
12149            .ok_or("W4A16 EP graph input size overflow")?;
12150        let root_stream = e.stream();
12151        let (input_ptr, _input_guard) = workspace.graph_input.device_ptr(&root_stream);
12152        let (selected_ptr, _selected_guard) = selected_dev.device_ptr(&root_stream);
12153        let (weights_ptr, _weights_guard) = route_weights_dev.device_ptr(&root_stream);
12154        let route_ptrs = (selected_ptr, weights_ptr);
12155
12156        let mut children = Vec::with_capacity(world + 1);
12157        for rank_index in 0..world {
12158            let engine = &self.ranks[rank_index];
12159            let rank = &experts.ranks[rank_index];
12160            let owner_start = rank.expert_range.start;
12161            let owner_end = rank.expert_range.end;
12162            let _main = engine.gpu.enter_main()?;
12163            let (child, _retained) = engine.capture_graph_retained(|_| {
12164                engine.nvfp4_ep_stage_inputs_raw(
12165                    input_ptr,
12166                    selected_ptr,
12167                    weights_ptr,
12168                    &mut workspace.input_bf16[rank_index],
12169                    &mut workspace.sel[rank_index],
12170                    &mut workspace.route_w[rank_index],
12171                    input_values,
12172                    pairs,
12173                    false,
12174                )?;
12175                engine.qmatvec_nvfp4_bf16_ep_dual_slots_into(
12176                    &rank.gate,
12177                    &rank.up,
12178                    &workspace.sel[rank_index],
12179                    &workspace.input_bf16[rank_index],
12180                    &mut workspace.gate_out[rank_index],
12181                    &mut workspace.up_out[rank_index],
12182                    pairs,
12183                    experts_per_token,
12184                    width,
12185                    experts.expert_width,
12186                    owner_start,
12187                    owner_end,
12188                    experts.gate_row_bytes,
12189                    rank.gate_expert_bytes,
12190                )?;
12191                engine.silu_mul_scaled_host_expf_bf16_ep_slots_into(
12192                    &workspace.gate_out[rank_index],
12193                    &workspace.up_out[rank_index],
12194                    &rank.macros_gate,
12195                    &rank.macros_up,
12196                    &workspace.sel[rank_index],
12197                    owner_start,
12198                    owner_end,
12199                    activation_limit,
12200                    &mut workspace.activation_bf16[rank_index],
12201                    experts.expert_width,
12202                    pairs,
12203                )?;
12204                engine.qmatvec_nvfp4_bf16_ep_down_slots_raw(
12205                    &rank.down,
12206                    &workspace.sel[rank_index],
12207                    &workspace.activation_bf16[rank_index],
12208                    &rank.macros_down,
12209                    workspace.slot_rows_raw,
12210                    pairs,
12211                    experts.expert_width,
12212                    width,
12213                    owner_start,
12214                    owner_end,
12215                    experts.down_row_bytes,
12216                    rank.down_expert_bytes,
12217                )?;
12218                Ok(())
12219            })?;
12220            children.push(child);
12221        }
12222
12223        {
12224            let _main = e.gpu.enter_main()?;
12225            let (child, _retained) = e.capture_graph_retained(|_| {
12226                e.axpy_rows_seq_tokens_into(
12227                    &workspace.slot_rows,
12228                    route_weights_dev,
12229                    &mut workspace.graph_output,
12230                    width,
12231                    experts_per_token,
12232                    tokens,
12233                )
12234            })?;
12235            children.push(child);
12236        }
12237
12238        let mut parent: sys::CUgraph = std::ptr::null_mut();
12239        unsafe {
12240            cu_try(sys::cuGraphCreate(&mut parent, 0), "W4A16 EP cuGraphCreate")?;
12241        }
12242        let mut rank_nodes = Vec::with_capacity(world);
12243        for (rank_index, child) in children.iter().take(world).enumerate() {
12244            let mut node: sys::CUgraphNode = std::ptr::null_mut();
12245            unsafe {
12246                cu_try(
12247                    sys::cuGraphAddChildGraphNode(
12248                        &mut node,
12249                        parent,
12250                        std::ptr::null(),
12251                        0,
12252                        child.cu_graph(),
12253                    ),
12254                    &format!("W4A16 EP graph rank {rank_index}"),
12255                )?;
12256            }
12257            rank_nodes.push(node);
12258        }
12259        let mut combine_node: sys::CUgraphNode = std::ptr::null_mut();
12260        unsafe {
12261            cu_try(
12262                sys::cuGraphAddChildGraphNode(
12263                    &mut combine_node,
12264                    parent,
12265                    rank_nodes.as_ptr(),
12266                    rank_nodes.len(),
12267                    children[world].cu_graph(),
12268                ),
12269                "W4A16 EP graph combine",
12270            )?;
12271        }
12272        let mut exec: sys::CUgraphExec = std::ptr::null_mut();
12273        unsafe {
12274            cu_try(
12275                sys::cuGraphInstantiateWithFlags(&mut exec, parent, 0),
12276                "W4A16 EP graph instantiate",
12277            )?;
12278        }
12279        workspace.graph_routes = Some(route_ptrs);
12280        Ok(RoutesGraph {
12281            exec,
12282            parent,
12283            _children: children,
12284        })
12285    }
12286
12287    /// Device-resident routed NVFP4 expert program (decode shape, t=1 rows). The geometry gift
12288    /// this exploits: gate/up column halves land on the SAME rank that owns the matching down
12289    /// canonical shard (act[rank r] is exactly down-shard r's input-column window), so the whole
12290    /// expert interior — gate, up, macro-scaled SwiGLU, down partial, route-weighted accumulate —
12291    /// runs rank-local with ZERO cross-rank transfer. Per (token, layer): one input upload per
12292    /// rank, one fenced peer copy of the remote accumulator, one root add, one readback.
12293    ///
12294    /// Numeric class: device silu (silu_mul_scaled) with gate/up macros folded as gs/us and the
12295    /// down macro folded into the accumulate scalar (weight * macro_down — exact, both are
12296    /// per-expert constants). This matches the owning-stage MoE dev-path semantics, NOT the
12297    /// host-canonical program bit-for-bit; gate it with argmax + relative bounds against the
12298    /// host-canonical oracle, and with repeat determinism against itself.
12299    /// Clamped layers refuse (they stay on the EP program).
12300    pub fn run_tensor_parallel_routes_nvfp4_device(
12301        &self,
12302        experts: &ResidentNvfp4TensorParallel,
12303        input: &[f32],
12304        selected: &[usize],
12305        route_weights: &[f32],
12306        experts_per_token: usize,
12307        activation_limit: Option<f32>,
12308    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
12309        validate_activations(input, 1, experts.input_width)?;
12310        if selected.len() != experts_per_token || route_weights.len() != experts_per_token {
12311            return Err(format!(
12312                "NVFP4 device routes selected={} weights={} != experts/token {experts_per_token}",
12313                selected.len(),
12314                route_weights.len(),
12315            )
12316            .into());
12317        }
12318        if !route_weights.iter().all(|weight| weight.is_finite()) {
12319            return Err("NVFP4 device route weights contain a non-finite value".into());
12320        }
12321        let world = self.ranks.len();
12322        if world != NVFP4_CANONICAL_ROW_SHARDS {
12323            return Err(format!(
12324                "NVFP4 device routes require world == canonical shard grid \
12325                 ({NVFP4_CANONICAL_ROW_SHARDS}), got {world}"
12326            )
12327            .into());
12328        }
12329        let local_out = if experts.ep2 {
12330            experts.expert_width
12331        } else {
12332            experts.expert_width / world
12333        };
12334
12335        // MEMRA_STEP_TP_TIMING=1: cumulative wall-clock of this program, printed every 430 calls
12336        // (~one 43-layer decode step's worth) so a bench run decomposes expert-program time vs
12337        // everything else without Nsight.
12338        static TIMING_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
12339        static TIMING_CALLS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
12340        let timing = std::env::var("MEMRA_STEP_TP_TIMING").as_deref() == Ok("1");
12341        let started = timing.then(std::time::Instant::now);
12342
12343        let n_sel = experts_per_token;
12344        let mut workspace_guard = experts
12345            .device_workspace
12346            .lock()
12347            .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
12348        if workspace_guard.is_none() {
12349            let mut gate_out = Vec::with_capacity(world);
12350            let mut up_out = Vec::with_capacity(world);
12351            let mut act_q = Vec::with_capacity(world);
12352            let mut act_d = Vec::with_capacity(world);
12353            let mut sel = Vec::with_capacity(world);
12354            let mut partial = Vec::with_capacity(world);
12355            let mut accumulator = Vec::with_capacity(world);
12356            let mut combine_w = Vec::with_capacity(world);
12357            let mut route_w = Vec::with_capacity(world);
12358            let mut in_q = Vec::with_capacity(world);
12359            let mut in_d = Vec::with_capacity(world);
12360            let mut input = Vec::with_capacity(world);
12361            let mut ev_rank = Vec::with_capacity(world);
12362            let moe_direct = moe_direct_on();
12363            for (rank, engine) in self.ranks.iter().enumerate() {
12364                let _main = engine.gpu.enter_main()?;
12365                gate_out.push(engine.uninit(n_sel * local_out)?);
12366                up_out.push(engine.uninit(n_sel * local_out)?);
12367                act_q.push(engine.uninit_i8(n_sel * local_out)?);
12368                act_d.push(engine.uninit(n_sel * local_out / 32)?);
12369                sel.push(engine.htod_i32(&vec![0i32; n_sel])?);
12370                partial.push(engine.uninit(n_sel * experts.input_width)?);
12371                // Direct join: peer accumulators live on ROOT (single P2P store pass).
12372                if moe_direct && rank != 0 {
12373                    let root = &self.ranks[0];
12374                    let _root_main = root.gpu.enter_main()?;
12375                    accumulator.push(root.zeros(experts.input_width)?);
12376                } else {
12377                    accumulator.push(engine.zeros(experts.input_width)?);
12378                }
12379                combine_w.push(engine.htod(&vec![0.0f32; n_sel])?);
12380                route_w.push(engine.htod(&vec![0.0f32; n_sel])?);
12381                in_q.push(engine.uninit_i8(experts.input_width)?);
12382                in_d.push(engine.uninit(experts.input_width / 32)?);
12383                input.push(engine.uninit(experts.input_width)?);
12384                ev_rank.push(engine.ctx().new_event(None)?);
12385            }
12386            let root = &self.ranks[0];
12387            let _main = root.gpu.enter_main()?;
12388            *workspace_guard = Some(Nvfp4DeviceRoutesWorkspace {
12389                prestaged: false,
12390                rank1_routed: false,
12391                ev_input: None,
12392                fence_flags_raw: 0,
12393                fence_ticket: 0,
12394                gate_out,
12395                up_out,
12396                act_q,
12397                act_d,
12398                sel,
12399                partial,
12400                accumulator,
12401                combine_w,
12402                route_w,
12403                in_q,
12404                in_d,
12405                dev_route_e: None,
12406                in_stage_e: None,
12407                out_stage_e: None,
12408                routes_graph: None,
12409                raw_dev_route_e: None,
12410                raw_combine: None,
12411                raw_input: Vec::new(),
12412                raw_sel: Vec::new(),
12413                raw_route_w: Vec::new(),
12414                remote: root.uninit(experts.input_width)?,
12415                combined: root.uninit(experts.input_width)?,
12416                n_sel,
12417                input,
12418                ev_rank,
12419                ev_done: Some(root.ctx().new_event(None)?),
12420                ev_entry: None,
12421            });
12422        }
12423        let workspace = workspace_guard
12424            .as_mut()
12425            .expect("NVFP4 device routes workspace initialized above");
12426        // EP2 uses this call only as the workspace-arming warmup (the prejoin path drives
12427        // decode); its host-routed sweep semantics do not apply to whole-expert banks.
12428        if experts.ep2 {
12429            return Ok(vec![0.0f32; experts.input_width]);
12430        }
12431        if workspace.n_sel != n_sel {
12432            return Err(format!(
12433                "NVFP4 device routes experts/token changed: workspace {} != call {n_sel}",
12434                workspace.n_sel
12435            )
12436            .into());
12437        }
12438        for &expert in selected {
12439            if expert >= experts.expert_count {
12440                return Err(format!(
12441                    "NVFP4 device selected expert {expert} outside 0..{}",
12442                    experts.expert_count
12443                )
12444                .into());
12445            }
12446        }
12447        let sel_i32 = selected
12448            .iter()
12449            .map(|&expert| expert as i32)
12450            .collect::<Vec<_>>();
12451
12452        // BATCHED program (2026-08-20): per rank, ONE launch per sweep (gate, up, SwiGLU,
12453        // down) covers every selected expert via the selection array and the contiguous bank —
12454        // the per-expert launch loop was pure host latency (~100 sequential launches/layer,
12455        // 291us wall for ~35us of arithmetic). Per (expert, row) the kernels are bit-identical
12456        // to the per-expert forms, and the route-weight axpy chain keeps its exact sequential
12457        // accumulation order — the program's values are unchanged.
12458        for (rank_index, engine) in self.ranks.iter().enumerate() {
12459            let _main = engine.gpu.enter_main()?;
12460            let device_input = engine.htod(input)?;
12461            let Nvfp4DeviceRoutesWorkspace { in_q, in_d, .. } = &mut *workspace;
12462            engine.quantize_q8_1_into(
12463                &device_input,
12464                1,
12465                experts.input_width,
12466                &mut in_q[rank_index],
12467                &mut in_d[rank_index],
12468            )?;
12469            // device_input frees on this rank's stream after the quantize — same-stream order.
12470        }
12471        self.nvfp4_routes_batched_sweeps(
12472            experts,
12473            workspace,
12474            selected,
12475            route_weights,
12476            &sel_i32,
12477            local_out,
12478            n_sel,
12479            activation_limit,
12480            false,
12481        )?;
12482
12483        // Combine: fence the remote shard's producer stream, peer-copy its accumulator to root,
12484        // reduce in canonical shard order, read back once.
12485        let root = &self.ranks[0];
12486        for engine in &self.ranks[1..] {
12487            let _main = engine.gpu.enter_main()?;
12488            engine.stream().synchronize()?;
12489        }
12490        let _main = root.gpu.enter_main()?;
12491        root.stream()
12492            .memcpy_dtod(&workspace.accumulator[1], &mut workspace.remote)?;
12493        root.add(
12494            &workspace.accumulator[0],
12495            &workspace.remote,
12496            &mut workspace.combined,
12497            experts.input_width,
12498        )?;
12499        let output = root.dtoh(&workspace.combined)?;
12500        if let Some(started) = started {
12501            use std::sync::atomic::Ordering;
12502            let ns = TIMING_NS.fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
12503                + started.elapsed().as_nanos() as u64;
12504            let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
12505            if calls.is_multiple_of(430) {
12506                eprintln!(
12507                    "[nvfp4-dev-routes-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
12508                    ns as f64 / 1.0e6,
12509                    ns as f64 / calls as f64 / 1.0e3,
12510                );
12511            }
12512        }
12513        Ok(output)
12514    }
12515
12516    /// The shared batched sweeps of the device routes program: per rank, upload the selection,
12517    /// reset the accumulator, run the gate/up/SwiGLU/down batched launches, then the
12518    /// route-weight axpy chain in exact sequential per-pair order. Every op queues on the
12519    /// owning rank's stream; callers own input acquisition and the combine.
12520    #[allow(clippy::too_many_arguments)]
12521    fn nvfp4_routes_batched_sweeps(
12522        &self,
12523        experts: &ResidentNvfp4TensorParallel,
12524        workspace: &mut Nvfp4DeviceRoutesWorkspace,
12525        selected: &[usize],
12526        route_weights: &[f32],
12527        sel_i32: &[i32],
12528        local_out: usize,
12529        n_sel: usize,
12530        activation_limit: Option<f32>,
12531        device_routed: bool,
12532    ) -> Result<(), Box<dyn std::error::Error>> {
12533        for rank_index in 0..self.ranks.len() {
12534            self.nvfp4_routes_batched_sweeps_rank(
12535                experts,
12536                workspace,
12537                selected,
12538                route_weights,
12539                sel_i32,
12540                local_out,
12541                n_sel,
12542                activation_limit,
12543                device_routed,
12544                rank_index,
12545            )?;
12546        }
12547        Ok(())
12548    }
12549
12550    /// One rank's sweeps (the per-rank body of `nvfp4_routes_batched_sweeps`) — separated so
12551    /// the graph door can capture each rank's segment on its own stream.
12552    #[allow(clippy::too_many_arguments)]
12553    fn nvfp4_routes_batched_sweeps_rank(
12554        &self,
12555        experts: &ResidentNvfp4TensorParallel,
12556        workspace: &mut Nvfp4DeviceRoutesWorkspace,
12557        selected: &[usize],
12558        route_weights: &[f32],
12559        sel_i32: &[i32],
12560        local_out: usize,
12561        n_sel: usize,
12562        activation_limit: Option<f32>,
12563        device_routed: bool,
12564        rank_index: usize,
12565    ) -> Result<(), Box<dyn std::error::Error>> {
12566        {
12567            let engine = &self.ranks[rank_index];
12568            let _main = engine.gpu.enter_main()?;
12569            // EP2: whole-expert full-width sweep, owner-guarded; down+combine fused writes
12570            // this rank's slot-ordered partial straight into its accumulator (the join is
12571            // unchanged). Device-routed only — the host-routed arm and the graph door refuse
12572            // at the caller.
12573            if experts.ep2 {
12574                if !device_routed {
12575                    return Err("NVFP4 EP2 banks support the device-routed decode arm only".into());
12576                }
12577                let gate_bank = &experts.gate[rank_index];
12578                let up_bank = &experts.up[rank_index];
12579                if gate_bank.local_out != experts.expert_width
12580                    || gate_bank.expert_bytes != up_bank.expert_bytes
12581                {
12582                    return Err("NVFP4 EP2 bank geometry drifted".into());
12583                }
12584                {
12585                    let Nvfp4DeviceRoutesWorkspace {
12586                        sel,
12587                        gate_out,
12588                        up_out,
12589                        in_q,
12590                        in_d,
12591                        ..
12592                    } = &mut *workspace;
12593                    engine.qmatvec_nvfp4_sel_gu_ep_into(
12594                        &gate_bank.bank,
12595                        &up_bank.bank,
12596                        &sel[rank_index],
12597                        &in_q[rank_index],
12598                        &in_d[rank_index],
12599                        &mut gate_out[rank_index],
12600                        &mut up_out[rank_index],
12601                        n_sel,
12602                        gate_bank.in_features,
12603                        gate_bank.local_out,
12604                        gate_bank.row_bytes,
12605                        gate_bank.expert_bytes,
12606                        rank_index,
12607                    )?;
12608                }
12609                {
12610                    let Nvfp4DeviceRoutesWorkspace {
12611                        gate_out,
12612                        up_out,
12613                        sel,
12614                        act_q,
12615                        act_d,
12616                        ..
12617                    } = &mut *workspace;
12618                    engine.silu_mul_scaled_q8_1_sel_ep_into(
12619                        &gate_out[rank_index],
12620                        &up_out[rank_index],
12621                        &experts.macros_gate_dev[rank_index],
12622                        &experts.macros_up_dev[rank_index],
12623                        &sel[rank_index],
12624                        activation_limit,
12625                        &mut act_q[rank_index],
12626                        &mut act_d[rank_index],
12627                        local_out,
12628                        n_sel,
12629                        rank_index,
12630                    )?;
12631                }
12632                let shard = &experts.down[rank_index];
12633                if shard.device_rank != rank_index || shard.local_in != local_out {
12634                    return Err("NVFP4 EP2 down bank placement drifted".into());
12635                }
12636                {
12637                    let Nvfp4DeviceRoutesWorkspace {
12638                        sel,
12639                        act_q,
12640                        act_d,
12641                        route_w,
12642                        accumulator,
12643                        ..
12644                    } = &mut *workspace;
12645                    engine.qmatvec_nvfp4_sel_down8_ep_into(
12646                        &shard.bank,
12647                        &sel[rank_index],
12648                        &act_q[rank_index],
12649                        &act_d[rank_index],
12650                        &route_w[rank_index],
12651                        &experts.macros_down_dev[rank_index],
12652                        &mut accumulator[rank_index],
12653                        n_sel,
12654                        shard.local_in,
12655                        shard.out_features,
12656                        shard.row_bytes,
12657                        shard.expert_bytes,
12658                        local_out,
12659                        local_out / 32,
12660                        rank_index,
12661                    )?;
12662                }
12663                return Ok(());
12664            }
12665            if !device_routed {
12666                engine.htod_i32_into(&mut workspace.sel[rank_index], sel_i32)?;
12667                // Folded combine weights (route_weight x down macro) — one 40-byte upload
12668                // replaces the accumulator reset + n_sel sequential axpy launches below.
12669                let folded = (0..n_sel)
12670                    .map(|pair| route_weights[pair] * experts.macros_down[selected[pair]])
12671                    .collect::<Vec<_>>();
12672                let mut view = workspace.combine_w[rank_index].slice_mut(0..n_sel);
12673                engine.stream().memcpy_htod(&folded, &mut view)?;
12674            }
12675            let gate_bank = &experts.gate[rank_index];
12676            let up_bank = &experts.up[rank_index];
12677            let (aq, ad) = (&workspace.in_q[rank_index], &workspace.in_d[rank_index]);
12678            // PROGRAM 2 (`MEMRA_NVFP4_SEL_GU`): the two sweeps share sel/aq/ad and, when the
12679            // geometry matches exactly, one launch covers both — per-row bit-identical, double
12680            // the grid fill. Armed by ITS OWN door, and additionally guarded on both banks
12681            // reporting slot-major, because the fused kernel reads only that byte map. Its door
12682            // is separate from PROGRAM 1's on purpose: in the removed implementation it armed
12683            // silently on the bank predicate, so the bank layout and this fusion could never be
12684            // priced apart (DIAGNOSIS.md, "the bisect could not name the mechanism").
12685            let gu_fused = sel_gu_fused_on()
12686                && gate_bank.slot_major
12687                && up_bank.slot_major
12688                && gate_bank.in_features == up_bank.in_features
12689                && gate_bank.local_out == up_bank.local_out
12690                && gate_bank.row_bytes == up_bank.row_bytes
12691                && gate_bank.expert_bytes == up_bank.expert_bytes;
12692            // ENGAGEMENT RECEIPT for PROGRAM 2, one line per DISTINCT decision combo. The
12693            // removed implementation had this behind MEMRA_SWEEP_TRACE and its own comment said
12694            // why it existed: "a silently-dead fusion reads as roofline physics without it".
12695            // It is unconditional here, because a perf row whose fusion never armed is worse
12696            // than no row -- it is a number that looks like evidence.
12697            {
12698                static SEEN_GU: std::sync::Mutex<Vec<(bool, bool, bool)>> =
12699                    std::sync::Mutex::new(Vec::new());
12700                let combo = (gu_fused, sel_gu_fused_on(), gate_bank.slot_major);
12701                let mut seen = SEEN_GU.lock().unwrap();
12702                if !seen.contains(&combo) {
12703                    seen.push(combo);
12704                    eprintln!(
12705                        "[nvfp4-sweep] gu_fused={} door={} slot_major={} geometry_match={} \
12706                         in_f={} out_f={} n_sel={n_sel}",
12707                        gu_fused,
12708                        sel_gu_fused_on(),
12709                        gate_bank.slot_major,
12710                        gate_bank.in_features == up_bank.in_features
12711                            && gate_bank.local_out == up_bank.local_out
12712                            && gate_bank.row_bytes == up_bank.row_bytes
12713                            && gate_bank.expert_bytes == up_bank.expert_bytes,
12714                        gate_bank.in_features,
12715                        gate_bank.local_out
12716                    );
12717                }
12718            }
12719            if gu_fused {
12720                let Nvfp4DeviceRoutesWorkspace {
12721                    sel,
12722                    gate_out,
12723                    up_out,
12724                    in_q,
12725                    in_d,
12726                    ..
12727                } = &mut *workspace;
12728                engine.qmatvec_nvfp4_sel_gu_into(
12729                    &gate_bank.bank,
12730                    &up_bank.bank,
12731                    &sel[rank_index],
12732                    &in_q[rank_index],
12733                    &in_d[rank_index],
12734                    &mut gate_out[rank_index],
12735                    &mut up_out[rank_index],
12736                    n_sel,
12737                    gate_bank.in_features,
12738                    gate_bank.local_out,
12739                    gate_bank.row_bytes,
12740                    gate_bank.expert_bytes,
12741                    gate_bank.slot_major,
12742                )?;
12743            } else {
12744                engine.qmatvec_nvfp4_sel_into(
12745                    &gate_bank.bank,
12746                    &workspace.sel[rank_index],
12747                    aq,
12748                    ad,
12749                    &mut workspace.gate_out[rank_index],
12750                    n_sel,
12751                    gate_bank.in_features,
12752                    gate_bank.local_out,
12753                    gate_bank.row_bytes,
12754                    gate_bank.expert_bytes,
12755                    0,
12756                    0,
12757                    gate_bank.slot_major,
12758                )?;
12759                engine.qmatvec_nvfp4_sel_into(
12760                    &up_bank.bank,
12761                    &workspace.sel[rank_index],
12762                    aq,
12763                    ad,
12764                    &mut workspace.up_out[rank_index],
12765                    n_sel,
12766                    up_bank.in_features,
12767                    up_bank.local_out,
12768                    up_bank.row_bytes,
12769                    up_bank.expert_bytes,
12770                    0,
12771                    0,
12772                    up_bank.slot_major,
12773                )?;
12774            }
12775            // Fused macro-scaled SwiGLU that EMITS q8_1 directly — down consumes it with no
12776            // separate quantize launch. act[rank] IS down canonical shard `rank_index`'s
12777            // input-column window (the geometry gift; see the method doc).
12778            {
12779                let Nvfp4DeviceRoutesWorkspace {
12780                    gate_out,
12781                    up_out,
12782                    sel,
12783                    act_q,
12784                    act_d,
12785                    ..
12786                } = &mut *workspace;
12787                engine.silu_mul_scaled_q8_1_sel_into(
12788                    &gate_out[rank_index],
12789                    &up_out[rank_index],
12790                    &experts.macros_gate_dev[rank_index],
12791                    &experts.macros_up_dev[rank_index],
12792                    &sel[rank_index],
12793                    activation_limit,
12794                    &mut act_q[rank_index],
12795                    &mut act_d[rank_index],
12796                    local_out,
12797                    n_sel,
12798                )?;
12799            }
12800            let shard = &experts.down[rank_index];
12801            if shard.device_rank != rank_index || shard.local_in != local_out {
12802                return Err(
12803                    "NVFP4 device routes: down canonical shard placement drifted from \
12804                     the gate/up column split"
12805                        .into(),
12806                );
12807            }
12808            // PROGRAM 3 (`MEMRA_NVFP4_SEL_DOWN8`): the down sweep and the route-weight combine
12809            // in ONE launch, one warp per SLOT instead of one warp per (row, slot), and the
12810            // `n_sel x out_f` partial round trip gone. Device-routed only — the host-routed arm
12811            // folds the macro into `combine_w` instead of reading `md` on device — and
12812            // slot-major only, read off the shard. `nsb <= 32` is the fit-block class the reduce
12813            // identity is argued at. Its own door, priced LAST and only on green gates for the
12814            // programs beneath it (lane mandate, milestone 5).
12815            let down8 =
12816                device_routed && sel_down8_on() && shard.slot_major && (shard.local_in >> 5) <= 32;
12817            // ENGAGEMENT RECEIPT for PROGRAM 3, one line per distinct combo. `device_routed`
12818            // and `nsb <= 32` are printed because they are the two eligibility conditions that
12819            // can silently disqualify the arm on a geometry or a route the operator did not
12820            // expect -- exactly the case where a flat perf row would be misread as "no win".
12821            {
12822                static SEEN_D8: std::sync::Mutex<Vec<(bool, bool, bool, bool)>> =
12823                    std::sync::Mutex::new(Vec::new());
12824                let combo = (down8, sel_down8_on(), device_routed, shard.slot_major);
12825                let mut seen = SEEN_D8.lock().unwrap();
12826                if !seen.contains(&combo) {
12827                    seen.push(combo);
12828                    // `door_source` is what makes this line a DEFAULT-flip receipt rather than
12829                    // only an engagement receipt: `door=true door_source=default-on` is the
12830                    // flip doing the work, `env=1` is a recipe doing it, and
12831                    // `down8=false door=true` is the silent-no-op shape that PROGRAM 1's
12832                    // default exists to prevent.
12833                    eprintln!(
12834                        "[nvfp4-sweep] down8={} door={} door_source={} device_routed={} \
12835                         slot_major={} nsb={} in_class={} n_sel={n_sel}",
12836                        down8,
12837                        sel_down8_on(),
12838                        sel_down8_source().1,
12839                        device_routed,
12840                        shard.slot_major,
12841                        shard.local_in >> 5,
12842                        (shard.local_in >> 5) <= 32
12843                    );
12844                }
12845            }
12846            if down8 {
12847                let Nvfp4DeviceRoutesWorkspace {
12848                    sel,
12849                    act_q,
12850                    act_d,
12851                    route_w,
12852                    accumulator,
12853                    ..
12854                } = &mut *workspace;
12855                engine.qmatvec_nvfp4_sel_down8_into(
12856                    &shard.bank,
12857                    &sel[rank_index],
12858                    &act_q[rank_index],
12859                    &act_d[rank_index],
12860                    &route_w[rank_index],
12861                    &experts.macros_down_dev[rank_index],
12862                    &mut accumulator[rank_index],
12863                    n_sel,
12864                    shard.local_in,
12865                    shard.out_features,
12866                    shard.row_bytes,
12867                    shard.expert_bytes,
12868                    local_out,
12869                    local_out / 32,
12870                    shard.slot_major,
12871                )?;
12872            } else {
12873                let Nvfp4DeviceRoutesWorkspace {
12874                    sel,
12875                    act_q,
12876                    act_d,
12877                    partial,
12878                    ..
12879                } = &mut *workspace;
12880                engine.qmatvec_nvfp4_sel_into(
12881                    &shard.bank,
12882                    &sel[rank_index],
12883                    &act_q[rank_index],
12884                    &act_d[rank_index],
12885                    &mut partial[rank_index],
12886                    n_sel,
12887                    shard.local_in,
12888                    shard.out_features,
12889                    shard.row_bytes,
12890                    shard.expert_bytes,
12891                    local_out,
12892                    local_out / 32,
12893                    shard.slot_major,
12894                )?;
12895            }
12896            // Route-weight accumulation: axpy_rows_seq keeps the exact sequential per-pair
12897            // FP chain of the reset + n_sel axpy launches in ONE launch. Device-routed calls
12898            // fold the down macro in-kernel from the device selection. (down8 already produced
12899            // the accumulator inside the sweep.)
12900            if !down8 {
12901                let Nvfp4DeviceRoutesWorkspace {
12902                    partial,
12903                    combine_w,
12904                    route_w,
12905                    sel,
12906                    accumulator,
12907                    ..
12908                } = &mut *workspace;
12909                if device_routed {
12910                    engine.axpy_rows_seq_md_into(
12911                        &partial[rank_index],
12912                        &route_w[rank_index],
12913                        &experts.macros_down_dev[rank_index],
12914                        &sel[rank_index],
12915                        &mut accumulator[rank_index],
12916                        experts.input_width,
12917                        n_sel,
12918                    )?;
12919                } else {
12920                    engine.axpy_rows_seq_into(
12921                        &partial[rank_index],
12922                        &combine_w[rank_index],
12923                        &mut accumulator[rank_index],
12924                        experts.input_width,
12925                        n_sel,
12926                    )?;
12927                }
12928            }
12929        }
12930        Ok(())
12931    }
12932
12933    /// Device-IO twin of `run_tensor_parallel_routes_nvfp4_device`: the layer input arrives as
12934    /// a device row on the model engine `e` and the combined output returns as a fresh
12935    /// `e`-context row — no host round-trip, no host stream sync. Ordering is evented (the v2
12936    /// attention discipline): `ev_entry` is recorded on `e`'s stream AFTER the caller queued
12937    /// the input's producer; each rank waits it before its peer read; the root reduce waits
12938    /// every rank's done event; `e` waits the root's done event before copying out. The
12939    /// program bytes are identical to the host-IO twin — dtoh/htod and dtod preserve f32 bits.
12940    #[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
12941    pub fn run_tensor_parallel_routes_nvfp4_device_io(
12942        &self,
12943        experts: &ResidentNvfp4TensorParallel,
12944        e: &Engine,
12945        input_dev: &crate::CudaSlice<f32>,
12946        selected: &[usize],
12947        route_weights: &[f32],
12948        experts_per_token: usize,
12949        activation_limit: Option<f32>,
12950    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
12951        if input_dev.len() != experts.input_width {
12952            return Err(format!(
12953                "NVFP4 device-io routes input {} != width {}",
12954                input_dev.len(),
12955                experts.input_width
12956            )
12957            .into());
12958        }
12959        if selected.len() != experts_per_token || route_weights.len() != experts_per_token {
12960            return Err(format!(
12961                "NVFP4 device-io routes selected={} weights={} != experts/token {experts_per_token}",
12962                selected.len(),
12963                route_weights.len(),
12964            )
12965            .into());
12966        }
12967        if !route_weights.iter().all(|weight| weight.is_finite()) {
12968            return Err("NVFP4 device route weights contain a non-finite value".into());
12969        }
12970        let world = self.ranks.len();
12971        if world != NVFP4_CANONICAL_ROW_SHARDS {
12972            return Err(format!(
12973                "NVFP4 device routes require world == canonical shard grid \
12974                 ({NVFP4_CANONICAL_ROW_SHARDS}), got {world}"
12975            )
12976            .into());
12977        }
12978        let local_out = experts.expert_width / world;
12979        let n_sel = experts_per_token;
12980
12981        static TIMING_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
12982        static TIMING_CALLS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
12983        let timing = std::env::var("MEMRA_STEP_TP_TIMING").as_deref() == Ok("1");
12984        let started = timing.then(std::time::Instant::now);
12985
12986        let mut workspace_guard = experts
12987            .device_workspace
12988            .lock()
12989            .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
12990        if workspace_guard.is_none() {
12991            drop(workspace_guard);
12992            // Build through the host-IO ensure path exactly once: run it with a zero input.
12993            // Cheaper than duplicating the init; the first real call overwrites everything.
12994            let zero = vec![0.0f32; experts.input_width];
12995            let zero_sel = vec![0usize; n_sel];
12996            let zero_w = vec![0.0f32; n_sel];
12997            let _ = self.run_tensor_parallel_routes_nvfp4_device(
12998                experts,
12999                &zero,
13000                &zero_sel,
13001                &zero_w,
13002                n_sel,
13003                activation_limit,
13004            )?;
13005            workspace_guard = experts
13006                .device_workspace
13007                .lock()
13008                .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
13009        }
13010        let workspace = workspace_guard
13011            .as_mut()
13012            .expect("NVFP4 device routes workspace initialized above");
13013        if workspace.n_sel != n_sel {
13014            return Err(format!(
13015                "NVFP4 device routes experts/token changed: workspace {} != call {n_sel}",
13016                workspace.n_sel
13017            )
13018            .into());
13019        }
13020        for &expert in selected {
13021            if expert >= experts.expert_count {
13022                return Err(format!(
13023                    "NVFP4 device selected expert {expert} outside 0..{}",
13024                    experts.expert_count
13025                )
13026                .into());
13027            }
13028        }
13029        let sel_i32 = selected
13030            .iter()
13031            .map(|&expert| expert as i32)
13032            .collect::<Vec<_>>();
13033
13034        // Entry fence: e's stream position covers the input's producer AND every consumer of
13035        // the previous layer's output (queued on e's stream before this call), guarding the
13036        // workspace reuse exactly like the v2 attention driver.
13037        if let Some((_, device)) = workspace.ev_entry.as_ref() {
13038            if *device != e.ctx().ordinal() {
13039                return Err("NVFP4 device-io routes engine changed".into());
13040            }
13041        } else {
13042            let _main = e.gpu.enter_main()?;
13043            workspace.ev_entry = Some((e.ctx().new_event(None)?, e.ctx().ordinal()));
13044        }
13045        {
13046            let _main = e.gpu.enter_main()?;
13047            let (ev_entry, _) = workspace.ev_entry.as_ref().expect("entry event set above");
13048            ev_entry.record(&e.stream())?;
13049        }
13050        for (rank_index, engine) in self.ranks.iter().enumerate() {
13051            let _main = engine.gpu.enter_main()?;
13052            let (ev_entry, _) = workspace.ev_entry.as_ref().expect("entry event set above");
13053            engine.stream().wait(ev_entry)?;
13054            {
13055                let mut destination = workspace.input[rank_index].slice_mut(0..experts.input_width);
13056                engine
13057                    .stream()
13058                    .memcpy_dtod(&input_dev.slice(0..experts.input_width), &mut destination)?;
13059            }
13060            {
13061                let Nvfp4DeviceRoutesWorkspace {
13062                    input, in_q, in_d, ..
13063                } = &mut *workspace;
13064                engine.quantize_q8_1_into(
13065                    &input[rank_index],
13066                    1,
13067                    experts.input_width,
13068                    &mut in_q[rank_index],
13069                    &mut in_d[rank_index],
13070                )?;
13071            }
13072        }
13073        self.nvfp4_routes_batched_sweeps(
13074            experts,
13075            workspace,
13076            selected,
13077            route_weights,
13078            &sel_i32,
13079            local_out,
13080            n_sel,
13081            activation_limit,
13082            false,
13083        )?;
13084
13085        // Evented combine: rank done events replace the host stream syncs, the reduce runs on
13086        // the root stream in canonical shard order, and e copies the combined row out behind
13087        // the root's done event.
13088        // rank0 == root: its own stream order already covers its sweep; only the PEER
13089        // ranks need the record/wait pair (host-op diet at the #1 eager seam, 2026-08-21).
13090        for (rank_index, engine) in self.ranks.iter().enumerate().skip(1) {
13091            let _main = engine.gpu.enter_main()?;
13092            workspace.ev_rank[rank_index].record(&engine.stream())?;
13093        }
13094        if moe_direct_on() && self.ranks.len() == 2 {
13095            // DIRECT JOIN: rank1's accumulator is root-resident (P2P single-store pass);
13096            // rank0's is root-stream-ordered. One root event + rank1's own event order
13097            // the model engine's single add — same operand order as root's add
13098            // (accumulator[0] + accumulator[1]): BIT-IDENTICAL. Output is a FRESH
13099            // e-context row (NOT an alias of ws state — the reverted zero-copy handoff's
13100            // hazard class does not apply).
13101            {
13102                let root = &self.ranks[0];
13103                let _main = root.gpu.enter_main()?;
13104                workspace
13105                    .ev_done
13106                    .as_ref()
13107                    .expect("device routes done event")
13108                    .record(&root.stream())?;
13109            }
13110            let _main = e.gpu.enter_main()?;
13111            e.stream().wait(
13112                workspace
13113                    .ev_done
13114                    .as_ref()
13115                    .expect("device routes done event"),
13116            )?;
13117            for ev in workspace.ev_rank.iter().skip(1) {
13118                e.stream().wait(ev)?;
13119            }
13120            let mut output = e.uninit(experts.input_width)?;
13121            e.add(
13122                &workspace.accumulator[0],
13123                &workspace.accumulator[1],
13124                &mut output,
13125                experts.input_width,
13126            )?;
13127            let output = output;
13128            if let Some(started) = started {
13129                use std::sync::atomic::Ordering;
13130                let ns = TIMING_NS
13131                    .fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
13132                    + started.elapsed().as_nanos() as u64;
13133                let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
13134                if calls.is_multiple_of(430) {
13135                    eprintln!(
13136                        "[nvfp4-dev-routes-direct-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
13137                        ns as f64 / 1.0e6,
13138                        ns as f64 / calls as f64 / 1.0e3,
13139                    );
13140                }
13141            }
13142            return Ok(output);
13143        }
13144        {
13145            let root = &self.ranks[0];
13146            let _main = root.gpu.enter_main()?;
13147            for ev in workspace.ev_rank.iter().skip(1) {
13148                root.stream().wait(ev)?;
13149            }
13150            root.stream()
13151                .memcpy_dtod(&workspace.accumulator[1], &mut workspace.remote)?;
13152            {
13153                let Nvfp4DeviceRoutesWorkspace {
13154                    accumulator,
13155                    remote,
13156                    combined,
13157                    ..
13158                } = &mut *workspace;
13159                root.add(&accumulator[0], remote, combined, experts.input_width)?;
13160            }
13161            workspace
13162                .ev_done
13163                .as_ref()
13164                .expect("device routes done event")
13165                .record(&root.stream())?;
13166        }
13167        let output = {
13168            let _main = e.gpu.enter_main()?;
13169            e.stream().wait(
13170                workspace
13171                    .ev_done
13172                    .as_ref()
13173                    .expect("device routes done event"),
13174            )?;
13175            // (Zero-copy clone handoff REVERTED 2026-08-21: identity mismatch in the
13176            // routes-diet bisect. The alloc+copy stays until the hazard is understood.)
13177            let mut output = e.uninit(experts.input_width)?;
13178            e.stream().memcpy_dtod(
13179                &workspace.combined.slice(0..experts.input_width),
13180                &mut output.slice_mut(0..experts.input_width),
13181            )?;
13182            output
13183        };
13184        if let Some(started) = started {
13185            use std::sync::atomic::Ordering;
13186            let ns = TIMING_NS.fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
13187                + started.elapsed().as_nanos() as u64;
13188            let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
13189            if calls.is_multiple_of(430) {
13190                eprintln!(
13191                    "[nvfp4-dev-routes-io-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
13192                    ns as f64 / 1.0e6,
13193                    ns as f64 / calls as f64 / 1.0e3,
13194                );
13195            }
13196        }
13197        Ok(output)
13198    }
13199
13200    /// Device-routed twin of `run_tensor_parallel_routes_nvfp4_device_io`: the selection and
13201    /// route weights arrive as the device router's e-context outputs — the per-layer host
13202    /// logits readback disappears. The fresh router outputs are staged into persistent
13203    /// e-context buffers on e's stream (never-free discipline) before the entry event; each
13204    /// rank peer-reads them behind it. The down-macro fold happens in-kernel.
13205    #[allow(clippy::too_many_arguments)]
13206    /// Prestage the routed-expert input: pull the shared row to every rank and quantize it
13207    /// there, WITHOUT the selection — callable before the router so the rank chains overlap
13208    /// it. No-op (returns false) when the workspace is not built yet or the door is off;
13209    /// the routed run then does its own staging as before.
13210    pub fn nvfp4_routes_prestage(
13211        &self,
13212        experts: &ResidentNvfp4TensorParallel,
13213        e: &Engine,
13214        input_dev: &crate::CudaSlice<f32>,
13215    ) -> Result<bool, Box<dyn std::error::Error>> {
13216        self.nvfp4_routes_prestage_with(experts, e, input_dev, |_, _, _, _| Ok(false))
13217    }
13218
13219    /// `nvfp4_routes_prestage` with a PEER-ROUTER hook: after rank1's input pull +
13220    /// quantize, the hook may compute rank1's route selection LOCALLY (replicated router —
13221    /// deterministic kernels on identical input bits produce identical sel/w, so the
13222    /// selection is bit-equal to the root's). Returns true when it wrote sel/route_w; the
13223    /// routed run then skips rank1's sel pull.
13224    pub fn nvfp4_routes_prestage_with(
13225        &self,
13226        experts: &ResidentNvfp4TensorParallel,
13227        e: &Engine,
13228        input_dev: &crate::CudaSlice<f32>,
13229        rank1_router: impl FnOnce(
13230            &Engine,
13231            &crate::CudaSlice<f32>,
13232            &mut crate::CudaSlice<i32>,
13233            &mut crate::CudaSlice<f32>,
13234        ) -> Result<bool, Box<dyn std::error::Error>>,
13235    ) -> Result<bool, Box<dyn std::error::Error>> {
13236        if !routes_prestage_on() || step_tp_graph_enabled()? {
13237            return Ok(false);
13238        }
13239        if input_dev.len() != experts.input_width {
13240            return Err("NVFP4 prestage input width mismatch".into());
13241        }
13242        let mut workspace_guard = experts
13243            .device_workspace
13244            .lock()
13245            .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
13246        let Some(workspace) = workspace_guard.as_mut() else {
13247            return Ok(false);
13248        };
13249        if workspace.ev_input.is_none() {
13250            let _main = e.gpu.enter_main()?;
13251            workspace.ev_input = Some((e.ctx().new_event(None)?, e.ctx().ordinal()));
13252        } else if workspace.ev_input.as_ref().map(|(_, d)| *d) != Some(e.ctx().ordinal()) {
13253            return Err("NVFP4 prestage engine changed".into());
13254        }
13255        {
13256            let _main = e.gpu.enter_main()?;
13257            let (ev, _) = workspace.ev_input.as_ref().expect("armed above");
13258            ev.record(&e.stream())?;
13259        }
13260        for (rank_index, engine) in self.ranks.iter().enumerate() {
13261            let _main = engine.gpu.enter_main()?;
13262            let (ev, _) = workspace.ev_input.as_ref().expect("armed above");
13263            engine.stream().wait(ev)?;
13264            {
13265                let mut destination = workspace.input[rank_index].slice_mut(0..experts.input_width);
13266                engine
13267                    .stream()
13268                    .memcpy_dtod(&input_dev.slice(0..experts.input_width), &mut destination)?;
13269            }
13270            {
13271                let Nvfp4DeviceRoutesWorkspace {
13272                    input, in_q, in_d, ..
13273                } = &mut *workspace;
13274                engine.quantize_q8_1_into(
13275                    &input[rank_index],
13276                    1,
13277                    experts.input_width,
13278                    &mut in_q[rank_index],
13279                    &mut in_d[rank_index],
13280                )?;
13281            }
13282        }
13283        if self.ranks.len() == 2 {
13284            let rank1 = &self.ranks[1];
13285            let _r1 = rank1.gpu.enter_main()?;
13286            let Nvfp4DeviceRoutesWorkspace {
13287                input,
13288                sel,
13289                route_w,
13290                ..
13291            } = &mut *workspace;
13292            let (in1, rest_sel) = (&input[1], &mut sel[1]);
13293            if rank1_router(rank1, in1, rest_sel, &mut route_w[1])? {
13294                workspace.rank1_routed = true;
13295            }
13296        }
13297        workspace.prestaged = true;
13298        Ok(true)
13299    }
13300
13301    /// STEP TP2 GEMM PRIME (`MEMRA_STEP_GEMM_PRIME`, 2026-08-27, TTFT lane): one grouped
13302    /// f16 GEMM per projection over the RESIDENT NVFP4 banks for a prime chunk of `t` tokens.
13303    ///
13304    /// WHY: the t-row walk primes a 4,092-token prompt in 19.8 s at its widest (GEMV-bound) and
13305    /// the generic batch prime's decode-class MoE takes 240 s; the CUTLASS sizing rows put
13306    /// GEMM-class expert math at 170-270 TFLOP/s on this silicon, i.e. a sub-second cold prime.
13307    /// This reuses the grouped f16 lane end to end (`moe_f16g_act` -> `moe_f16_grouped`
13308    /// direct-from-NVFP4 -> silu pairs -> grouped down) once per RANK against that rank's bank
13309    /// half: gate/up are column-halves (silu runs on matching halves), down is the canonical
13310    /// row-shard pair producing partials joined in the pinned shard order, and the final
13311    /// weighted scatter runs a fixed slot-0..n_used-1 sum per token - no atomics anywhere.
13312    /// Per-expert NVFP4 macro scales land where they must: gate/up BEFORE silu (nonlinear),
13313    /// down folded into the scatter weight.
13314    ///
13315    /// NUMERIC CLASS: the f16-mirror grouped-prefill class other families already serve -
13316    /// admission is the prefill-KV acceptance gate plus the ship-shape tape, not byte identity.
13317    #[allow(clippy::too_many_arguments)]
13318    /// MEMRA_MOE_DETERM_STAGE=1: checksum a stage's device buffer so two back-to-back calls of the
13319    /// grouped routine can be compared STAGE BY STAGE. The routine's OUTPUT is nondeterministic above
13320    /// ~400 tokens on the direct lane (1.9e-7 / 99% of elements at t=4096) while its GEMM kernels are
13321    /// bit-exact in isolation, so the divergence enters somewhere between. The first stage whose
13322    /// checksum differs across the two calls is where.
13323    ///
13324    /// Sum-of-bits, not sum-of-floats: float addition would itself reorder and could mask exactly the
13325    /// class of difference being hunted.
13326    fn determ_stage_bytes(v: &[u8]) -> u64 {
13327        v.iter().fold(0u64, |a, b| {
13328            a.wrapping_mul(1_000_003).wrapping_add(*b as u64)
13329        })
13330    }
13331
13332    /// Checksum an i32 index/offset buffer. The CSR, the active-expert ids and the group
13333    /// offsets are inputs the gate kernel dereferences just as much as the activations are;
13334    /// leaving them unchecksummed is what let "identical inputs, different output" stand on a
13335    /// SUBSET of the inputs for six rounds of this investigation.
13336    fn determ_stage_i32(v: &[i32]) -> u64 {
13337        v.iter().fold(0u64, |a, b| {
13338            a.wrapping_mul(1_000_003).wrapping_add(*b as u32 as u64)
13339        })
13340    }
13341
13342    fn determ_stage_sum(v: &[f32]) -> u64 {
13343        v.iter().fold(0u64, |a, x| {
13344            a.wrapping_mul(1_000_003).wrapping_add(x.to_bits() as u64)
13345        })
13346    }
13347
13348    #[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
13349    pub fn run_tensor_parallel_routes_nvfp4_prime_grouped(
13350        &self,
13351        experts: &ResidentNvfp4TensorParallel,
13352        e: &Engine,
13353        z_t: &crate::CudaSlice<f32>,
13354        t: usize,
13355        sel: &[i32],
13356        w: &[f32],
13357        n_used: usize,
13358        activation_limit: Option<f32>,
13359    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
13360        let world = self.ranks.len();
13361        if world != NVFP4_CANONICAL_ROW_SHARDS {
13362            return Err("NVFP4 grouped prime requires the canonical 2-shard grid".into());
13363        }
13364        // The dequant must read the layout the bank was BUILT in (feeding slot-major bytes to
13365        // the v1 kernel was a garbage-output bug this line exists for). Taken from the BANK,
13366        // never from the environment: EP2 banks are always slot-major, TP shard banks are
13367        // slot-major only under PROGRAM 1 (`MEMRA_NVFP4_BANK_SM`). All three banks share one
13368        // decision at build (`nvfp4_repack_bank_matrix`), and the assert below refuses to run a
13369        // prime over banks that disagree instead of silently priming one of them wrong.
13370        //
13371        // THIS IS THE LINE THE 2026-08-29 CORRUPTION WENT THROUGH. `QT_NVFP4_V2` selects the
13372        // `kq_fetch` branch whose two prefetch callers omitted `in_f`; the codes stayed right
13373        // and the per-16 scale came from inside the packed-codes region, so the prime produced
13374        // fluent WRONG text. No v2 gate had ever run this GEMM. It is now covered device-side by
13375        // `nvfp4-bank-oracle` (both step37 layer geometries, all four tile forms) and end-to-end
13376        // by a prefill-heavy byte gate. Keep both: a decode-only byte gate proved nothing here.
13377        let slot_major = experts.gate.iter().all(|b| b.slot_major)
13378            && experts.up.iter().all(|b| b.slot_major)
13379            && experts.down.iter().all(|b| b.slot_major);
13380        let any_slot_major = experts.gate.iter().any(|b| b.slot_major)
13381            || experts.up.iter().any(|b| b.slot_major)
13382            || experts.down.iter().any(|b| b.slot_major);
13383        if any_slot_major != slot_major {
13384            return Err(
13385                "NVFP4 grouped prime: gate/up/down banks disagree on the row layout — \
13386                        one grouped GEMM cannot serve two byte maps"
13387                    .into(),
13388            );
13389        }
13390        let bank_qt = if slot_major {
13391            crate::QT_NVFP4_V2
13392        } else {
13393            crate::QT_NVFP4
13394        };
13395        let width = experts.input_width;
13396        let n_expert = experts.expert_count;
13397        let n_pairs = t * n_used;
13398        if sel.len() < n_pairs || w.len() < n_pairs || z_t.len() < t * width {
13399            return Err("NVFP4 grouped prime geometry".into());
13400        }
13401        // MEMRA_PRIME_PROF=1 sub-split of the grouped prime (2026-08-28). The [moe-prof] mark
13402        // around this whole call reads 90% of the MoE bucket, but the call is not just GEMMs:
13403        // it host-builds the CSR, allocates ~6 large device buffers per rank per layer (z_r is
13404        // 67 MB, act is 84 MB at t=4096), and does 5 H2D copies per rank. Tile form, occupancy,
13405        // padding, B double-buffering and register pressure have ALL come back null, which is
13406        // the signature of time that is not in the kernel. So measure HOST wall with no syncs
13407        // for the build and the issue, and let the join wait absorb the GPU time: host-bound and
13408        // GPU-bound then read differently instead of summing into one opaque number.
13409        let gprof = std::env::var("MEMRA_PRIME_PROF").as_deref() == Ok("1") && t >= 16;
13410        let g_t0 = std::time::Instant::now();
13411        // CSR: expert-major pair lists. Host-built - prime is chunk-granular, and the router
13412        // selections arrive host-side from the sigmoid router oracle.
13413        let mut buckets: Vec<Vec<i32>> = vec![Vec::new(); n_expert];
13414        for (p, &s_id) in sel.iter().take(n_pairs).enumerate() {
13415            let s_id = s_id as usize;
13416            if s_id >= n_expert {
13417                return Err(format!("grouped prime selection {s_id} >= {n_expert}").into());
13418            }
13419            buckets[s_id].push(p as i32);
13420        }
13421        let mut ex_ids: Vec<i32> = Vec::new();
13422        let mut ex_off: Vec<i32> = vec![0];
13423        let mut ex_pairs: Vec<i32> = Vec::new();
13424        for (e_id, b) in buckets.iter().enumerate() {
13425            if !b.is_empty() {
13426                ex_ids.push(e_id as i32);
13427                ex_pairs.extend_from_slice(b);
13428                ex_off.push(ex_pairs.len() as i32);
13429            }
13430        }
13431        let n_active = ex_ids.len();
13432        if n_active == 0 {
13433            return e.zeros(t * width);
13434        }
13435        if n_active > 512 {
13436            return Err("grouped prime n_active > 512 (direct lane cap)".into());
13437        }
13438        let csr_tok: Vec<i32> = ex_pairs.iter().map(|&p| p / n_used as i32).collect();
13439        // pair-id -> CSR row: lets the fused tail read the partials in place, so the prime skips
13440        // a whole [n_pairs, width] permute (532 MB read + write per rank per layer at 4k).
13441        let mut inv = vec![0i32; n_pairs];
13442        for (row, &pair) in ex_pairs.iter().enumerate() {
13443            inv[pair as usize] = row as i32;
13444        }
13445        // Per-CSR-row gate/up macro scales (before silu); down macro folds into the scatter w.
13446        let mg: Vec<f32> = ex_pairs
13447            .iter()
13448            .map(|&p| experts.macros_gate[sel[p as usize] as usize])
13449            .collect();
13450        let mu: Vec<f32> = ex_pairs
13451            .iter()
13452            .map(|&p| experts.macros_up[sel[p as usize] as usize])
13453            .collect();
13454        let wd: Vec<f32> = (0..n_pairs)
13455            .map(|p| w[p] * experts.macros_down[sel[p] as usize])
13456            .collect();
13457        // Pointer tables: built on first use and kept on the bank. Resident banks never move,
13458        // so the old per-rank-per-LAYER rebuild+upload of 3*n_expert u64s was pure prime-path
13459        // host churn (45 layers x 2 ranks x 864 entries per prime).
13460        {
13461            let mut tabs = experts
13462                .prime_tables
13463                .lock()
13464                .map_err(|_| "grouped prime table cache is poisoned")?;
13465            if tabs.len() != world {
13466                tabs.clear();
13467                for rank in 0..world {
13468                    let engine = &self.ranks[rank];
13469                    let _main = engine.gpu.enter_main()?;
13470                    let (gb, ub, db) =
13471                        (&experts.gate[rank], &experts.up[rank], &experts.down[rank]);
13472                    let mut tab = vec![0u64; 3 * n_expert];
13473                    {
13474                        use cudarc::driver::DevicePtr;
13475                        let stream = engine.stream();
13476                        let (pg, _g0) = gb.bank.device_ptr(&stream);
13477                        let (pu, _g1) = ub.bank.device_ptr(&stream);
13478                        let (pd, _g2) = db.bank.device_ptr(&stream);
13479                        for ex in 0..n_expert {
13480                            tab[ex] = pg + (ex * gb.expert_bytes) as u64;
13481                            tab[n_expert + ex] = pu + (ex * ub.expert_bytes) as u64;
13482                            tab[2 * n_expert + ex] = pd + (ex * db.expert_bytes) as u64;
13483                        }
13484                    }
13485                    tabs.push(engine.htod_u64(&tab)?);
13486                }
13487            }
13488        }
13489        let g_csr = g_t0.elapsed().as_secs_f64() * 1e3;
13490        let g_t1 = std::time::Instant::now();
13491        // WHAT ARE THESE RANKS, ACTUALLY (2026-08-28)? The grouped MoE measures join ~ span_sum
13492        // (strictly serialized) at t=4096 while the same kernel hits 40 TFLOP/s standalone, and
13493        // one intervention based on cudarc's peer-copy event was refuted. Before proposing an
13494        // eleventh mechanism, verify the premise the whole question rests on: that the two ranks
13495        // are on DISTINCT devices, contexts and streams. If they share any of those, the
13496        // serialization needs no further explanation. One line per process.
13497        {
13498            static SAID: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
13499            if gprof && !SAID.swap(true, std::sync::atomic::Ordering::Relaxed) {
13500                for rank in 0..world {
13501                    let e_r = &self.ranks[rank];
13502                    let _m = e_r.gpu.enter_main();
13503                    eprintln!(
13504                        "[rank-id] rank={rank} ordinal={} ctx={:?} stream={:?} root_ordinal={} \
13505                         root_stream={:?}",
13506                        e_r.ctx().ordinal(),
13507                        std::sync::Arc::as_ptr(e_r.ctx()),
13508                        e_r.stream().cu_stream(),
13509                        e.ctx().ordinal(),
13510                        e.stream().cu_stream(),
13511                    );
13512                }
13513            }
13514        }
13515
13516        let mut partials: Vec<crate::CudaSlice<f32>> = Vec::with_capacity(world);
13517        let mut ev_rank: Vec<CudaEvent> = Vec::with_capacity(world);
13518        let mut ev_head: Vec<CudaEvent> = Vec::with_capacity(world);
13519        let mut ev_tail_prof: Vec<CudaEvent> = Vec::with_capacity(world);
13520        for rank in 0..world {
13521            let engine = &self.ranks[rank];
13522            let _main = engine.gpu.enter_main()?;
13523            if gprof {
13524                // CU_EVENT_DEFAULT, not None: cudarc's new_event(None) creates the event with
13525                // CU_EVENT_DISABLE_TIMING, and cuEventElapsedTime then returns INVALID_HANDLE.
13526                // That is what failed every span query for two build cycles — the ordering
13527                // events below correctly keep the default, since they are never timed.
13528                let h = engine
13529                    .ctx()
13530                    .new_event(Some(cudarc::driver::sys::CUevent_flags::CU_EVENT_DEFAULT))?;
13531                h.record(&engine.stream())?;
13532                ev_head.push(h);
13533            }
13534            // The grouped-MoE FFI's raw launches follow the RUNTIME API's current device, not
13535            // the pushed driver context — bind it per rank or rank-1 calls die InvalidValue.
13536            engine.bind_runtime_device(engine.ctx().ordinal() as i32)?;
13537            let gb = &experts.gate[rank];
13538            let ub = &experts.up[rank];
13539            let db = &experts.down[rank];
13540            if db.device_rank != rank {
13541                return Err("grouped prime: down shard placement drifted".into());
13542            }
13543            let local_ff = gb.local_out;
13544            if ub.local_out != local_ff || db.local_in != local_ff || db.out_features != width {
13545                return Err("grouped prime: bank width mismatch".into());
13546            }
13547            // All of the rank's host-side staging lands before its first kernel, so the
13548            // launch chain below issues without host copies interleaved.
13549            let csr_tok_d = engine.htod_i32(&csr_tok)?;
13550            let exi_d = engine.htod_i32(&ex_ids)?;
13551            let exoff_d = engine.htod_i32(&ex_off)?;
13552            let mg_d = engine.htod(&mg)?;
13553            let mu_d = engine.htod(&mu)?;
13554            // Per-rank pointer table into the bank shards, slot-major like DevExps::ptr_row.
13555            let tabs_guard = experts
13556                .prime_tables
13557                .lock()
13558                .map_err(|_| "grouped prime table cache is poisoned")?;
13559            let tab_d = &tabs_guard[rank];
13560            let mut z_r = engine.uninit(t * width)?;
13561            {
13562                let mut dst = z_r.slice_mut(0..t * width);
13563                engine
13564                    .stream()
13565                    .memcpy_dtod(&z_t.slice(0..t * width), &mut dst)?;
13566            }
13567            let dstage = std::env::var("MEMRA_MOE_DETERM_STAGE").as_deref() == Ok("1") && t >= 16;
13568            let (z16, zs) = engine.moe_f16g_act(&z_r, Some(&csr_tok_d), width, n_pairs)?;
13569            if dstage {
13570                // z16 is the GEMM's actual DATA input and is a byte buffer; checksumming only
13571                // z_r and zs left "identical inputs" unestablished and produced a localization
13572                // that outran the measurement. Checksum it as bytes.
13573                let zr = engine.dtoh(&z_r)?;
13574                let zsv = engine.dtoh(&zs)?;
13575                let z16v = engine.dtoh_u8(&z16)?;
13576                eprintln!(
13577                    "[determ-stage] rank={rank} t={t} z_r={:016x} zs={:016x} z16={:016x}",
13578                    Self::determ_stage_sum(&zr),
13579                    Self::determ_stage_sum(&zsv),
13580                    Self::determ_stage_bytes(&z16v)
13581                );
13582            }
13583            if dstage {
13584                // INPUT CLOSURE. Everything the gate kernel dereferences, plus the launch
13585                // geometry that decides how it is summed, checksummed in ONE place. A kernel
13586                // proven bit-deterministic on live data, with no atomics, can only diverge if
13587                // (A) some byte it reads differs, (B) the launch differs, or (C) it reads
13588                // outside its declared inputs. This closes A and B; C is what compute-sanitizer
13589                // is for. Partial input sets are how the divergence kept retreating into the
13590                // part that was never measured.
13591                engine.stream().synchronize()?;
13592                let csr_v = engine.dtoh_i32(&csr_tok_d)?;
13593                let exi_v = engine.dtoh_i32(&exi_d)?;
13594                let exo_v = engine.dtoh_i32(&exoff_d)?;
13595                let mg_v = engine.dtoh(&mg_d)?;
13596                let mu_v = engine.dtoh(&mu_d)?;
13597                let tab_v = engine.dtoh_u64(tab_d)?;
13598                eprintln!(
13599                    "[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={}",
13600                    Self::determ_stage_i32(&csr_v),
13601                    Self::determ_stage_i32(&exi_v),
13602                    Self::determ_stage_i32(&exo_v),
13603                    Self::determ_stage_i32(&ex_off),
13604                    Self::determ_stage_sum(&mg_v),
13605                    Self::determ_stage_sum(&mu_v),
13606                    tab_v
13607                        .iter()
13608                        .fold(0u64, |a, b| a.wrapping_mul(1_000_003).wrapping_add(*b)),
13609                    gb.row_bytes
13610                );
13611                // The resident weight bank is the GEMM's OTHER operand and was never checked.
13612                // Opt-in because it is a ~424 MB dtoh per rank per layer.
13613                if std::env::var("MEMRA_MOE_DETERM_BANK").as_deref() == Ok("1") {
13614                    let bank_v = engine.dtoh_u8(&gb.bank)?;
13615                    eprintln!(
13616                        "[determ-closure] rank={rank} t={t} gate_bank={:016x} bytes={}",
13617                        Self::determ_stage_bytes(&bank_v),
13618                        bank_v.len()
13619                    );
13620                }
13621            }
13622            let mut g = engine.moe_f16_grouped(
13623                tab_d,
13624                0,
13625                n_expert,
13626                &exi_d,
13627                &ex_off,
13628                &exoff_d,
13629                &z16,
13630                &zs,
13631                width,
13632                local_ff,
13633                n_active,
13634                n_pairs,
13635                bank_qt,
13636                gb.row_bytes,
13637            )?;
13638            engine.scale_rows(&mut g, &mg_d, local_ff, n_pairs)?;
13639            let mut u = engine.moe_f16_grouped(
13640                tab_d,
13641                1,
13642                n_expert,
13643                &exi_d,
13644                &ex_off,
13645                &exoff_d,
13646                &z16,
13647                &zs,
13648                width,
13649                local_ff,
13650                n_active,
13651                n_pairs,
13652                bank_qt,
13653                ub.row_bytes,
13654            )?;
13655            engine.scale_rows(&mut u, &mu_d, local_ff, n_pairs)?;
13656            // step35 routed SwiGLU clamp (per-layer; live only on layers 43/44 for this
13657            // family): min(silu(g), lim) * clamp(u, +-lim). Dropping it was the second
13658            // correctness bug of the first engaged run.
13659            let act = match activation_limit.filter(|l| *l > 1e-6) {
13660                Some(lim) => {
13661                    let mut a = engine.uninit(n_pairs * local_ff)?;
13662                    engine.swiglu_clamped_mul_scaled(
13663                        &g,
13664                        &u,
13665                        1.0,
13666                        1.0,
13667                        lim,
13668                        &mut a,
13669                        n_pairs * local_ff,
13670                    )?;
13671                    a
13672                }
13673                None => engine.moe_pairs_silu_mul(&g, &u, n_pairs * local_ff)?,
13674            };
13675            if dstage {
13676                let gv = engine.dtoh(&g)?;
13677                let uv = engine.dtoh(&u)?;
13678                let av = engine.dtoh(&act)?;
13679                // A SUM tells you THAT gate differs; it does not tell you HOW. ULP-dense diffs
13680                // (nearly every element, ~1e-8) are an ordering/precision class; a handful of
13681                // huge ones are a corruption class. They need different hunts, so measure the
13682                // shape here instead of inferring it later.
13683                let key = (rank, t);
13684                let mut prev_map = DETERM_PREV
13685                    .get_or_init(|| std::sync::Mutex::new(std::collections::HashMap::new()))
13686                    .lock()
13687                    .map_err(|_| "determ prev map poisoned")?;
13688                let shape = match prev_map.get(&key) {
13689                    Some(prev) if prev.len() == gv.len() => {
13690                        let mut md = 0.0f32;
13691                        let mut n_diff = 0usize;
13692                        let mut n_big = 0usize;
13693                        for (a, b) in prev.iter().zip(gv.iter()) {
13694                            let d = (a - b).abs();
13695                            if d > 0.0 {
13696                                n_diff += 1;
13697                            }
13698                            if d > 1e-3 {
13699                                n_big += 1;
13700                            }
13701                            if d > md {
13702                                md = d;
13703                            }
13704                        }
13705                        format!(
13706                            " | vs_prev maxdiff={md:.3e} differing={n_diff}/{} big(>1e-3)={n_big}",
13707                            gv.len()
13708                        )
13709                    }
13710                    _ => String::new(),
13711                };
13712                prev_map.insert(key, gv.clone());
13713                drop(prev_map);
13714                eprintln!(
13715                    "[determ-stage] rank={rank} t={t} gate={:016x} up={:016x} silu={:016x}{shape}",
13716                    Self::determ_stage_sum(&gv),
13717                    Self::determ_stage_sum(&uv),
13718                    Self::determ_stage_sum(&av)
13719                );
13720            }
13721            let (a16, a_s) = engine.moe_f16g_act(&act, None, local_ff, n_pairs)?;
13722            let d_csr = engine.moe_f16_grouped(
13723                tab_d,
13724                2,
13725                n_expert,
13726                &exi_d,
13727                &ex_off,
13728                &exoff_d,
13729                &a16,
13730                &a_s,
13731                local_ff,
13732                width,
13733                n_active,
13734                n_pairs,
13735                bank_qt,
13736                db.row_bytes,
13737            )?;
13738
13739            // No host sync: both ranks' chains must be in flight before anything waits.
13740            // The rank's tail event orders the root's cross-device pulls below.
13741            if dstage {
13742                engine.stream().synchronize()?;
13743                let a16v = engine.dtoh_u8(&a16)?;
13744                let dv = engine.dtoh(&d_csr)?;
13745                eprintln!(
13746                    "[determ-stage] rank={rank} t={t} a16={:016x} down_partial={:016x}",
13747                    Self::determ_stage_bytes(&a16v),
13748                    Self::determ_stage_sum(&dv)
13749                );
13750            }
13751            let ev = engine.ctx().new_event(None)?;
13752            ev.record(&engine.stream())?;
13753            if gprof {
13754                // Per-rank GPU SPAN (2026-08-28). Keep the tail event; the elapsed time is read
13755                // AFTER the join sync below. Reading it here returns NOT_READY (the work has only
13756                // been queued) and cudarc's elapsed_ms synchronizes, which serialized the very
13757                // ranks this is meant to test: host issue jumped 1.9 ms -> 34-47 ms per call and
13758                // the join wall fell to match. A probe that changes the schedule measures its own
13759                // perturbation.
13760                // CudaEvent is not Clone, so record a second tail event on the same stream —
13761                // adjacent to `ev`, so it carries the same completion timestamp for timing.
13762                let tp = engine
13763                    .ctx()
13764                    .new_event(Some(cudarc::driver::sys::CUevent_flags::CU_EVENT_DEFAULT))?;
13765                tp.record(&engine.stream())?;
13766                ev_tail_prof.push(tp);
13767            }
13768            ev_rank.push(ev);
13769            partials.push(d_csr);
13770        }
13771        let _main = e.gpu.enter_main()?;
13772        e.bind_runtime_device(e.ctx().ordinal() as i32)?;
13773        // Host-only: every rank's chain is queued, nothing has been waited on yet.
13774        let g_issue = g_t1.elapsed().as_secs_f64() * 1e3;
13775        let g_t2 = std::time::Instant::now();
13776        for ev in &ev_rank {
13777            e.stream().wait(ev)?;
13778        }
13779        // Both partials land on the root (rank 1's crosses the link once), then ONE fused pass
13780        // does join + CSR permute + weight + scatter. Shard order stays pinned as (y0 + y1).
13781        let mut y0 = e.uninit(n_pairs * width)?;
13782        {
13783            let mut dst = y0.slice_mut(0..n_pairs * width);
13784            e.stream()
13785                .memcpy_dtod(&partials[0].slice(0..n_pairs * width), &mut dst)?;
13786        }
13787        let mut y1 = e.uninit(n_pairs * width)?;
13788        {
13789            let mut dst = y1.slice_mut(0..n_pairs * width);
13790            e.stream()
13791                .memcpy_dtod(&partials[1].slice(0..n_pairs * width), &mut dst)?;
13792        }
13793        let inv_d = e.htod_i32(&inv)?;
13794        let wd_d = e.htod(&wd)?;
13795        let mut out = e.uninit(t * width)?;
13796        e.moe_prime_join_scatter(&y0, &y1, &inv_d, &wd_d, &mut out, width, n_used, t)?;
13797        if gprof {
13798            let _ = e.stream().synchronize();
13799            let g_join = g_t2.elapsed().as_secs_f64() * 1e3;
13800            // Everything has completed, so both events of every pair are ready and elapsed_ms
13801            // cannot block. A negative entry means the query itself failed and the row must be
13802            // read as missing data, never as a zero-length span.
13803            // cuEventElapsedTime needs the events' OWN context current — computing it under the
13804            // root's pushed context returned an error for every pair, and the first version
13805            // swallowed that into -1.0 with no reason attached. Enter each rank's context, and
13806            // print the failure once so a dead probe can never again look like a zero-length span.
13807            let mut span_ms: Vec<f32> = Vec::with_capacity(world);
13808            for (rank, (h, tp)) in ev_head.iter().zip(ev_tail_prof.iter()).enumerate() {
13809                let guard = self.ranks[rank].gpu.enter_main();
13810                match guard.and_then(|_g| h.elapsed_ms(tp).map_err(|e| e.into())) {
13811                    Ok(v) => span_ms.push(v),
13812                    Err(err) => {
13813                        static SAID: std::sync::atomic::AtomicBool =
13814                            std::sync::atomic::AtomicBool::new(false);
13815                        if !SAID.swap(true, std::sync::atomic::Ordering::Relaxed) {
13816                            eprintln!("[grp-prof] span query failed on rank {rank}: {err}");
13817                        }
13818                        span_ms.push(-1.0);
13819                    }
13820                }
13821            }
13822            eprintln!(
13823                "[grp-prof] t={t} n_active={n_active} csr={g_csr:.1}ms issue={g_issue:.1}ms \
13824                 join={g_join:.1}ms spans={span_ms:?} span_sum={:.1}ms span_max={:.1}ms",
13825                span_ms.iter().sum::<f32>(),
13826                span_ms.iter().cloned().fold(0.0f32, f32::max)
13827            );
13828        }
13829        Ok(out)
13830    }
13831
13832    #[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
13833    pub fn run_tensor_parallel_routes_nvfp4_device_routed(
13834        &self,
13835        experts: &ResidentNvfp4TensorParallel,
13836        e: &Engine,
13837        input_dev: &crate::CudaSlice<f32>,
13838        sel_d: &crate::CudaSlice<i32>,
13839        w_d: &crate::CudaSlice<f32>,
13840        experts_per_token: usize,
13841        activation_limit: Option<f32>,
13842    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
13843        self.run_tensor_parallel_routes_nvfp4_device_routed_prejoin(
13844            experts,
13845            e,
13846            input_dev,
13847            sel_d,
13848            w_d,
13849            experts_per_token,
13850            activation_limit,
13851            || Ok(()),
13852        )
13853    }
13854
13855    /// `run_tensor_parallel_routes_nvfp4_device_routed` with a PREJOIN hook: `pre_join`
13856    /// runs on the host right before the join wait is enqueued on e's stream — work it
13857    /// issues there (e.g. the shexp overlap) executes WHILE the peer rank finishes its
13858    /// sweep, instead of after the join. Value-neutral by construction (the hook only
13859    /// reorders independent host issue).
13860    #[allow(clippy::too_many_arguments)]
13861    pub fn run_tensor_parallel_routes_nvfp4_device_routed_prejoin(
13862        &self,
13863        experts: &ResidentNvfp4TensorParallel,
13864        e: &Engine,
13865        input_dev: &crate::CudaSlice<f32>,
13866        sel_d: &crate::CudaSlice<i32>,
13867        w_d: &crate::CudaSlice<f32>,
13868        experts_per_token: usize,
13869        activation_limit: Option<f32>,
13870        pre_join: impl FnOnce() -> Result<(), Box<dyn std::error::Error>>,
13871    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
13872        self.run_tensor_parallel_routes_nvfp4_device_routed_prejoin_add3(
13873            experts,
13874            e,
13875            input_dev,
13876            sel_d,
13877            w_d,
13878            experts_per_token,
13879            activation_limit,
13880            pre_join,
13881            None,
13882        )
13883    }
13884
13885    /// The prejoin variant with MOE TAIL FUSION M1: when `post_add = Some((sh_raw,
13886    /// scale_raw))`, the direct-join arm folds the shexp apply into the join add
13887    /// (`dst = (acc0+acc1) + sh*scale[0]`, exact split-pair sequence) — the caller skips
13888    /// its apply launch. Raw UVA pointers so no lock is held across the call.
13889    #[allow(clippy::too_many_arguments)]
13890    pub fn run_tensor_parallel_routes_nvfp4_device_routed_prejoin_add3(
13891        &self,
13892        experts: &ResidentNvfp4TensorParallel,
13893        e: &Engine,
13894        input_dev: &crate::CudaSlice<f32>,
13895        sel_d: &crate::CudaSlice<i32>,
13896        w_d: &crate::CudaSlice<f32>,
13897        experts_per_token: usize,
13898        activation_limit: Option<f32>,
13899        pre_join: impl FnOnce() -> Result<(), Box<dyn std::error::Error>>,
13900        post_add: Option<(u64, u64)>,
13901    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
13902        if input_dev.len() != experts.input_width {
13903            return Err(format!(
13904                "NVFP4 device-routed input {} != width {}",
13905                input_dev.len(),
13906                experts.input_width
13907            )
13908            .into());
13909        }
13910        let n_sel = experts_per_token;
13911        if sel_d.len() < n_sel || w_d.len() < n_sel {
13912            return Err(format!(
13913                "NVFP4 device-routed routes sel={} w={} < experts/token {n_sel}",
13914                sel_d.len(),
13915                w_d.len()
13916            )
13917            .into());
13918        }
13919        let world = self.ranks.len();
13920        if world != NVFP4_CANONICAL_ROW_SHARDS {
13921            return Err(format!(
13922                "NVFP4 device routes require world == canonical shard grid \
13923                 ({NVFP4_CANONICAL_ROW_SHARDS}), got {world}"
13924            )
13925            .into());
13926        }
13927        let local_out = if experts.ep2 {
13928            experts.expert_width
13929        } else {
13930            experts.expert_width / world
13931        };
13932
13933        static TIMING_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
13934        static TIMING_CALLS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
13935        let timing = std::env::var("MEMRA_STEP_TP_TIMING").as_deref() == Ok("1");
13936        let started = timing.then(std::time::Instant::now);
13937
13938        let mut workspace_guard = experts
13939            .device_workspace
13940            .lock()
13941            .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
13942        if workspace_guard.is_none() {
13943            drop(workspace_guard);
13944            let zero = vec![0.0f32; experts.input_width];
13945            let zero_sel = vec![0usize; n_sel];
13946            let zero_w = vec![0.0f32; n_sel];
13947            let _ = self.run_tensor_parallel_routes_nvfp4_device(
13948                experts,
13949                &zero,
13950                &zero_sel,
13951                &zero_w,
13952                n_sel,
13953                activation_limit,
13954            )?;
13955            workspace_guard = experts
13956                .device_workspace
13957                .lock()
13958                .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
13959        }
13960        let workspace = workspace_guard
13961            .as_mut()
13962            .expect("NVFP4 device routes workspace initialized above");
13963        if workspace.n_sel != n_sel {
13964            return Err(format!(
13965                "NVFP4 device routes experts/token changed: workspace {} != call {n_sel}",
13966                workspace.n_sel
13967            )
13968            .into());
13969        }
13970
13971        // GRAPH DOOR (MEMRA_STEP_TP_GRAPH=1): the whole rank+root segment replays as one
13972        // stitched multi-device parent launched on e's stream — no events, no per-token node
13973        // updates (every address is persistent staging). VALUE-IDENTICAL to the eager path:
13974        // the children replay exactly the same kernel/copy sequence.
13975        //
13976        // GRAPH-LAUNCH HEADROOM GUARD (see spec::GRAPH_LAUNCH_MIN_FREE): below the
13977        // driver-free floor on the launching device this call falls through to the
13978        // eager routes path below — the exact body the graph captures, stateless per
13979        // call — instead of feeding cuGraphLaunch an exhausted card
13980        // (lane/graph-launch-guard-sweep-20260831).
13981        if step_tp_graph_enabled()? && step_tp_graph_headroom_ok(e) {
13982            if experts.ep2 {
13983                return Err(
13984                    "MEMRA_STEP_TP_GRAPH=1 with MEMRA_STEP_NVFP4_EP2=1 has never been \
13985                     co-gated; unset one"
13986                        .into(),
13987                );
13988            }
13989            if workspace.dev_route_e.is_none() {
13990                let _main = e.gpu.enter_main()?;
13991                workspace.dev_route_e = Some((
13992                    e.htod_i32(&vec![0i32; n_sel])?,
13993                    e.htod(&vec![0.0f32; n_sel])?,
13994                ));
13995            }
13996            if workspace.in_stage_e.is_none() {
13997                let _main = e.gpu.enter_main()?;
13998                workspace.in_stage_e = Some(e.htod(&vec![0.0f32; experts.input_width])?);
13999                workspace.out_stage_e = Some(e.htod(&vec![0.0f32; experts.input_width])?);
14000            }
14001            if workspace.routes_graph.is_none() {
14002                let graph = self.nvfp4_routes_build_graph(
14003                    experts,
14004                    workspace,
14005                    local_out,
14006                    n_sel,
14007                    activation_limit,
14008                )?;
14009                workspace.routes_graph = Some(graph);
14010                eprintln!(
14011                    "[step-tp-graph] routes segment captured: ranks={world} n_sel={n_sel} \
14012                     children=3 updates=none performance_claim=false"
14013                );
14014            }
14015            let output = {
14016                let _main = e.gpu.enter_main()?;
14017                {
14018                    let (sel_e, w_e) = workspace
14019                        .dev_route_e
14020                        .as_mut()
14021                        .expect("device route staging set above");
14022                    {
14023                        let mut dst = sel_e.slice_mut(0..n_sel);
14024                        e.stream().memcpy_dtod(&sel_d.slice(0..n_sel), &mut dst)?;
14025                    }
14026                    {
14027                        let mut dst = w_e.slice_mut(0..n_sel);
14028                        e.stream().memcpy_dtod(&w_d.slice(0..n_sel), &mut dst)?;
14029                    }
14030                }
14031                {
14032                    let in_stage = workspace
14033                        .in_stage_e
14034                        .as_mut()
14035                        .expect("graph staging set above");
14036                    let mut dst = in_stage.slice_mut(0..experts.input_width);
14037                    e.stream()
14038                        .memcpy_dtod(&input_dev.slice(0..experts.input_width), &mut dst)?;
14039                }
14040                unsafe {
14041                    let r = cudarc::driver::sys::cuGraphLaunch(
14042                        workspace
14043                            .routes_graph
14044                            .as_ref()
14045                            .expect("routes graph built above")
14046                            .exec,
14047                        e.stream().cu_stream() as cudarc::driver::sys::CUstream,
14048                    );
14049                    if r != cudarc::driver::sys::CUresult::CUDA_SUCCESS {
14050                        return Err(format!("routes graph launch: {r:?}").into());
14051                    }
14052                }
14053                let mut output = e.uninit(experts.input_width)?;
14054                {
14055                    let out_stage = workspace
14056                        .out_stage_e
14057                        .as_ref()
14058                        .expect("graph staging set above");
14059                    e.stream().memcpy_dtod(
14060                        &out_stage.slice(0..experts.input_width),
14061                        &mut output.slice_mut(0..experts.input_width),
14062                    )?;
14063                }
14064                output
14065            };
14066            if let Some(started) = started {
14067                use std::sync::atomic::Ordering;
14068                let ns = TIMING_NS
14069                    .fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
14070                    + started.elapsed().as_nanos() as u64;
14071                let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
14072                if calls.is_multiple_of(430) {
14073                    eprintln!(
14074                        "[nvfp4-dev-routed-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
14075                        ns as f64 / 1.0e6,
14076                        ns as f64 / calls as f64 / 1.0e3,
14077                    );
14078                }
14079            }
14080            return Ok(output);
14081        }
14082
14083        // Entry fence + router-output staging, all on e's stream: the fresh sel/w slices are
14084        // copied into the persistent e-context pair, then the event is recorded — the caller's
14085        // sel_d/w_d can free on e's stream with no cross-stream reader.
14086        if let Some((_, device)) = workspace.ev_entry.as_ref() {
14087            if *device != e.ctx().ordinal() {
14088                return Err("NVFP4 device-routed routes engine changed".into());
14089            }
14090        } else {
14091            let _main = e.gpu.enter_main()?;
14092            workspace.ev_entry = Some((e.ctx().new_event(None)?, e.ctx().ordinal()));
14093        }
14094        if workspace.dev_route_e.is_none() {
14095            let _main = e.gpu.enter_main()?;
14096            workspace.dev_route_e = Some((
14097                e.htod_i32(&vec![0i32; n_sel])?,
14098                e.htod(&vec![0.0f32; n_sel])?,
14099            ));
14100        }
14101        // MEMRA_SEL_MIRROR: the staging pair exists so the rank streams read a persistent
14102        // e-context address. The caller's sel_d/w_d ARE persistent (the process-static
14103        // selection rows), so when every consuming rank shares e's device the ranks can read
14104        // them directly and this hop disappears. The graph door keeps the staging (its
14105        // captured copies read the fixed addresses).
14106        let mirror = sel_mirror_on() && !step_tp_graph_enabled()?;
14107        let e_device = e.ctx().ordinal();
14108        // rank1_routed is consumed (taken) below; peek it here for the staging decision.
14109        let rank1_routed_peek = workspace.rank1_routed;
14110        let stage_needed = !mirror
14111            || self.ranks.iter().enumerate().any(|(rank_index, engine)| {
14112                !(rank1_routed_peek && rank_index == 1) && engine.ctx().ordinal() != e_device
14113            });
14114        {
14115            let _main = e.gpu.enter_main()?;
14116            if stage_needed {
14117                let (sel_e, w_e) = workspace
14118                    .dev_route_e
14119                    .as_mut()
14120                    .expect("device route staging set above");
14121                {
14122                    let mut dst = sel_e.slice_mut(0..n_sel);
14123                    e.stream().memcpy_dtod(&sel_d.slice(0..n_sel), &mut dst)?;
14124                }
14125                {
14126                    let mut dst = w_e.slice_mut(0..n_sel);
14127                    e.stream().memcpy_dtod(&w_d.slice(0..n_sel), &mut dst)?;
14128                }
14129            }
14130            let (ev_entry, _) = workspace.ev_entry.as_ref().expect("entry event set above");
14131            ev_entry.record(&e.stream())?;
14132        }
14133        // Prestage door: input pull + quantize were already issued on the rank streams
14134        // (before the router) — the rank stream order suffices, skip them here.
14135        let prestaged = std::mem::take(&mut workspace.prestaged);
14136        let rank1_routed = std::mem::take(&mut workspace.rank1_routed);
14137        for (rank_index, engine) in self.ranks.iter().enumerate() {
14138            let _main = engine.gpu.enter_main()?;
14139            let (ev_entry, _) = workspace.ev_entry.as_ref().expect("entry event set above");
14140            engine.stream().wait(ev_entry)?;
14141            if !prestaged {
14142                let mut destination = workspace.input[rank_index].slice_mut(0..experts.input_width);
14143                engine
14144                    .stream()
14145                    .memcpy_dtod(&input_dev.slice(0..experts.input_width), &mut destination)?;
14146            }
14147            if !(rank1_routed && rank_index == 1) {
14148                // ONE mirror launch instead of two 32-byte copy-engine dispatches; source is
14149                // the caller's persistent rows when this rank shares e's device (UVA, ordered
14150                // by ev_entry), else the staged e-context pair.
14151                let same_dev = engine.ctx().ordinal() == e_device;
14152                if mirror {
14153                    // Split the workspace borrow so the source (the staged pair, when this
14154                    // rank is off-device) and the destination rows coexist.
14155                    let Nvfp4DeviceRoutesWorkspace {
14156                        sel,
14157                        route_w,
14158                        dev_route_e,
14159                        ..
14160                    } = &mut *workspace;
14161                    let (src_sel, src_w): (&crate::CudaSlice<i32>, &crate::CudaSlice<f32>) =
14162                        if same_dev {
14163                            (sel_d, w_d)
14164                        } else {
14165                            let (sel_e, w_e) = dev_route_e
14166                                .as_ref()
14167                                .expect("device route staging set above");
14168                            (sel_e, w_e)
14169                        };
14170                    engine.moe_sel_w_mirror(
14171                        src_sel,
14172                        src_w,
14173                        &mut sel[rank_index],
14174                        &mut route_w[rank_index],
14175                        n_sel,
14176                    )?;
14177                } else {
14178                    let (sel_e, w_e) = workspace
14179                        .dev_route_e
14180                        .as_ref()
14181                        .expect("device route staging set above");
14182                    {
14183                        let mut dst = workspace.sel[rank_index].slice_mut(0..n_sel);
14184                        engine
14185                            .stream()
14186                            .memcpy_dtod(&sel_e.slice(0..n_sel), &mut dst)?;
14187                    }
14188                    {
14189                        let mut dst = workspace.route_w[rank_index].slice_mut(0..n_sel);
14190                        engine
14191                            .stream()
14192                            .memcpy_dtod(&w_e.slice(0..n_sel), &mut dst)?;
14193                    }
14194                }
14195            }
14196            if !prestaged {
14197                let Nvfp4DeviceRoutesWorkspace {
14198                    input, in_q, in_d, ..
14199                } = &mut *workspace;
14200                engine.quantize_q8_1_into(
14201                    &input[rank_index],
14202                    1,
14203                    experts.input_width,
14204                    &mut in_q[rank_index],
14205                    &mut in_d[rank_index],
14206                )?;
14207            }
14208        }
14209        self.nvfp4_routes_batched_sweeps(
14210            experts,
14211            workspace,
14212            &[],
14213            &[],
14214            &[],
14215            local_out,
14216            n_sel,
14217            activation_limit,
14218            true,
14219        )?;
14220
14221        // rank0 == root: its own stream order already covers its sweep; only the PEER
14222        // ranks need the record/wait pair (host-op diet at the #1 eager seam, 2026-08-21).
14223        for (rank_index, engine) in self.ranks.iter().enumerate().skip(1) {
14224            let _main = engine.gpu.enter_main()?;
14225            workspace.ev_rank[rank_index].record(&engine.stream())?;
14226        }
14227        // Doorbell fences (MEMRA_FENCE_MEMOPS=1): rank1 + root ring their flags; e waits
14228        // the tickets instead of the two events. Arm lazily; 0-len = unsupported.
14229        let memops = fence_memops_on() && moe_direct_on() && self.ranks.len() == 2;
14230        let mut ticket = 0u32;
14231        if memops {
14232            use cudarc::driver::sys;
14233            if workspace.fence_flags_raw == 0 {
14234                let root = &self.ranks[0];
14235                let _main = root.gpu.enter_main()?;
14236                let mut ptr: sys::CUdeviceptr = 0;
14237                let r = unsafe { sys::cuMemAlloc_v2(&mut ptr, 8) };
14238                if r != sys::CUresult::CUDA_SUCCESS {
14239                    return Err(format!("fence flag alloc: {r:?}").into());
14240                }
14241                let r = unsafe { sys::cuMemsetD8_v2(ptr, 0, 8) };
14242                if r != sys::CUresult::CUDA_SUCCESS {
14243                    return Err(format!("fence flag memset: {r:?}").into());
14244                }
14245                workspace.fence_flags_raw = ptr as u64;
14246            }
14247            workspace.fence_ticket = workspace.fence_ticket.wrapping_add(1).max(1);
14248            ticket = workspace.fence_ticket;
14249            let base = workspace.fence_flags_raw;
14250            // rank1's fence: a peer stream MEMOP is rejected over PCIe P2P
14251            // (CUDA_ERROR_INVALID_VALUE, receipted 2026-08-23), but a peer KERNEL STORE into
14252            // root memory is legal — the direct join already relies on it. Under
14253            // MEMRA_FENCE_RANK1 rank1 rings flag[0] that way and e waits it same-device,
14254            // replacing the cross-device event wait below.
14255            if fence_rank1_on() {
14256                let peer = &self.ranks[1];
14257                let _pmain = peer.gpu.enter_main()?;
14258                peer.ring_flag_raw(base, ticket)?;
14259            }
14260            {
14261                let root = &self.ranks[0];
14262                let _main = root.gpu.enter_main()?;
14263                let r = unsafe {
14264                    sys::cuStreamWriteValue32_v2(
14265                        root.stream().cu_stream() as sys::CUstream,
14266                        (base + 4) as sys::CUdeviceptr,
14267                        ticket,
14268                        0,
14269                    )
14270                };
14271                if r != sys::CUresult::CUDA_SUCCESS {
14272                    return Err(format!("fence write root: {r:?}").into());
14273                }
14274            }
14275        }
14276        // PREJOIN hook: rank work is fully issued (dev1 running); independent e-stream
14277        // kernels queued here execute while the peer rank drains its sweep.
14278        pre_join()?;
14279
14280        if moe_direct_on() && self.ranks.len() == 2 {
14281            // DIRECT JOIN: rank1's accumulator is root-resident (P2P single-store pass);
14282            // rank0's is root-stream-ordered. One root event + rank1's own event order
14283            // the model engine's single add — same operand order as root's add
14284            // (accumulator[0] + accumulator[1]): BIT-IDENTICAL. Output is a FRESH
14285            // e-context row (NOT an alias of ws state — the reverted zero-copy handoff's
14286            // hazard class does not apply).
14287            let _main = e.gpu.enter_main()?;
14288            if memops {
14289                use cudarc::driver::sys;
14290                let base = workspace.fence_flags_raw;
14291                let r = unsafe {
14292                    sys::cuStreamWaitValue32_v2(
14293                        e.stream().cu_stream() as sys::CUstream,
14294                        (base + 4) as sys::CUdeviceptr,
14295                        ticket,
14296                        sys::CUstreamWaitValue_flags::CU_STREAM_WAIT_VALUE_GEQ as u32,
14297                    )
14298                };
14299                if r != sys::CUresult::CUDA_SUCCESS {
14300                    return Err(format!("fence wait: {r:?}").into());
14301                }
14302                if fence_rank1_on() {
14303                    // Same-device wait on the flag rank1 rang over P2P.
14304                    let r = unsafe {
14305                        sys::cuStreamWaitValue32_v2(
14306                            e.stream().cu_stream() as sys::CUstream,
14307                            base as sys::CUdeviceptr,
14308                            ticket,
14309                            sys::CUstreamWaitValue_flags::CU_STREAM_WAIT_VALUE_GEQ as u32,
14310                        )
14311                    };
14312                    if r != sys::CUresult::CUDA_SUCCESS {
14313                        return Err(format!("fence wait rank1: {r:?}").into());
14314                    }
14315                } else {
14316                    for ev in workspace.ev_rank.iter().skip(1) {
14317                        e.stream().wait(ev)?;
14318                    }
14319                }
14320            } else {
14321                {
14322                    let root = &self.ranks[0];
14323                    let _rmain = root.gpu.enter_main()?;
14324                    workspace
14325                        .ev_done
14326                        .as_ref()
14327                        .expect("device routes done event")
14328                        .record(&root.stream())?;
14329                }
14330                e.stream().wait(
14331                    workspace
14332                        .ev_done
14333                        .as_ref()
14334                        .expect("device routes done event"),
14335                )?;
14336                for ev in workspace.ev_rank.iter().skip(1) {
14337                    e.stream().wait(ev)?;
14338                }
14339            }
14340            let mut output = e.uninit(experts.input_width)?;
14341            if let Some((sh_raw, scale_raw)) = post_add {
14342                // MOE TAIL FUSION M1: fold the shexp apply into the join add —
14343                // dst = (acc0 + acc1) + sh*scale[0], the exact split-pair sequence.
14344                e.add3_raw(
14345                    &workspace.accumulator[0],
14346                    &workspace.accumulator[1],
14347                    sh_raw,
14348                    scale_raw,
14349                    &mut output,
14350                    experts.input_width,
14351                )?;
14352            } else {
14353                e.add(
14354                    &workspace.accumulator[0],
14355                    &workspace.accumulator[1],
14356                    &mut output,
14357                    experts.input_width,
14358                )?;
14359            }
14360            let output = output;
14361            if let Some(started) = started {
14362                use std::sync::atomic::Ordering;
14363                let ns = TIMING_NS
14364                    .fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
14365                    + started.elapsed().as_nanos() as u64;
14366                let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
14367                if calls.is_multiple_of(430) {
14368                    eprintln!(
14369                        "[nvfp4-dev-routes-direct-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
14370                        ns as f64 / 1.0e6,
14371                        ns as f64 / calls as f64 / 1.0e3,
14372                    );
14373                }
14374            }
14375            return Ok(output);
14376        }
14377        {
14378            let root = &self.ranks[0];
14379            let _main = root.gpu.enter_main()?;
14380            for ev in workspace.ev_rank.iter().skip(1) {
14381                root.stream().wait(ev)?;
14382            }
14383            root.stream()
14384                .memcpy_dtod(&workspace.accumulator[1], &mut workspace.remote)?;
14385            {
14386                let Nvfp4DeviceRoutesWorkspace {
14387                    accumulator,
14388                    remote,
14389                    combined,
14390                    ..
14391                } = &mut *workspace;
14392                root.add(&accumulator[0], remote, combined, experts.input_width)?;
14393            }
14394            workspace
14395                .ev_done
14396                .as_ref()
14397                .expect("device routes done event")
14398                .record(&root.stream())?;
14399        }
14400        let output = {
14401            let _main = e.gpu.enter_main()?;
14402            e.stream().wait(
14403                workspace
14404                    .ev_done
14405                    .as_ref()
14406                    .expect("device routes done event"),
14407            )?;
14408            // (Zero-copy clone handoff REVERTED 2026-08-21: identity mismatch in the
14409            // routes-diet bisect. The alloc+copy stays until the hazard is understood.)
14410            let mut output = e.uninit(experts.input_width)?;
14411            e.stream().memcpy_dtod(
14412                &workspace.combined.slice(0..experts.input_width),
14413                &mut output.slice_mut(0..experts.input_width),
14414            )?;
14415            output
14416        };
14417        if let Some(started) = started {
14418            use std::sync::atomic::Ordering;
14419            let ns = TIMING_NS.fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
14420                + started.elapsed().as_nanos() as u64;
14421            let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
14422            if calls.is_multiple_of(430) {
14423                eprintln!(
14424                    "[nvfp4-dev-routed-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
14425                    ns as f64 / 1.0e6,
14426                    ns as f64 / calls as f64 / 1.0e3,
14427                );
14428            }
14429        }
14430        Ok(output)
14431    }
14432
14433    /// The fused finish's ROOT section (combine + shadow gathers), event-free: the eager
14434    /// caller wraps it with rank-event waits + the done record; the token graph captures it
14435    /// verbatim (parent edges provide the ordering).
14436    pub(crate) fn decode_v2_finish_root_fused(
14437        &self,
14438        ws: &mut StepTpDecodeV2Ws,
14439    ) -> Result<(), Box<dyn std::error::Error>> {
14440        let root = &self.ranks[0];
14441        let _main = root.gpu.enter_main()?;
14442        if ws.raw_peer_partial != 0 {
14443            // Capture-safe raw seams (arming happened in the stage flow).
14444            raw_copy_bytes(ws.raw_peer_partial, ws.raw_o_partial1, ws.o_out * 4, root)?;
14445        } else {
14446            root.stream()
14447                .memcpy_dtod(&ws.o_partials[1][0], &mut ws.peer_partial)?;
14448        }
14449        {
14450            let StepTpDecodeV2Ws {
14451                o_partials,
14452                peer_partial,
14453                reduce_a,
14454                o_out,
14455                ..
14456            } = &mut *ws;
14457            root.add(&o_partials[0][0], peer_partial, reduce_a, *o_out)?;
14458        }
14459        let shadows = !no_local_shadow_on() || ws.raw_mixed_stage_e != 0;
14460        if shadows {
14461            // rank0's shadows are same-context (root) copies; rank1's cross-context reads go
14462            // raw when armed.
14463            let mut k_dst = ws.k_shadow.slice_mut(0..ws.local_kv_dim);
14464            root.stream().memcpy_dtod(&ws.k[0], &mut k_dst)?;
14465            let mut v_dst = ws.v_shadow.slice_mut(0..ws.local_kv_dim);
14466            root.stream().memcpy_dtod(&ws.v_raw[0], &mut v_dst)?;
14467        }
14468        if shadows && ws.raw_peer_partial != 0 {
14469            raw_copy_bytes(
14470                ws.raw_k_shadow + (ws.local_kv_dim * 4) as u64,
14471                ws.raw_k1,
14472                ws.local_kv_dim * 4,
14473                root,
14474            )?;
14475            raw_copy_bytes(
14476                ws.raw_v_shadow + (ws.local_kv_dim * 4) as u64,
14477                ws.raw_v1,
14478                ws.local_kv_dim * 4,
14479                root,
14480            )?;
14481        } else if shadows {
14482            let start = ws.local_kv_dim;
14483            let mut k_dst = ws.k_shadow.slice_mut(start..start + ws.local_kv_dim);
14484            root.stream().memcpy_dtod(&ws.k[1], &mut k_dst)?;
14485            let mut v_dst = ws.v_shadow.slice_mut(start..start + ws.local_kv_dim);
14486            root.stream().memcpy_dtod(&ws.v_raw[1], &mut v_dst)?;
14487        }
14488        if ws.raw_mixed_stage_e != 0 {
14489            // Token-graph mirrors: the e-glue children read same-context copies of the
14490            // root-produced rows.
14491            raw_copy_bytes(ws.raw_mixed_stage_e, ws.raw_reduce_a, ws.o_out * 4, root)?;
14492            let (k_stage, v_stage) = ws.raw_shadow_stage_e;
14493            raw_copy_bytes(k_stage, ws.raw_k_shadow, 2 * ws.local_kv_dim * 4, root)?;
14494            raw_copy_bytes(v_stage, ws.raw_v_shadow, 2 * ws.local_kv_dim * 4, root)?;
14495        }
14496        Ok(())
14497    }
14498
14499    /// Arm the token-graph e-context mirrors (orchestrator-supplied fixed addresses) plus
14500    /// reduce_a's own pointer.
14501    pub(crate) fn decode_v2_arm_token_mirrors(
14502        &self,
14503        ws: &mut StepTpDecodeV2Ws,
14504        mixed_stage_e: u64,
14505        shadow_stage_e: (u64, u64),
14506    ) -> Result<(), Box<dyn std::error::Error>> {
14507        use cudarc::driver::DevicePtr;
14508        let root = &self.ranks[0];
14509        let _main = root.gpu.enter_main()?;
14510        let stream = root.stream();
14511        let (a, _g) = ws.reduce_a.device_ptr(&stream);
14512        ws.raw_reduce_a = a;
14513        ws.raw_mixed_stage_e = mixed_stage_e;
14514        ws.raw_shadow_stage_e = shadow_stage_e;
14515        Ok(())
14516    }
14517
14518    /// Build one layer's stitched routes graph: per-rank children captured on their own
14519    /// streams (raw cuMemcpyAsync at every cross-context seam — cudarc's slice tracking is
14520    /// capture-illegal there), a root combine child, and a multi-device parent with
14521    /// {rank0, rank1} -> root dependency edges. Zero per-token updates: every address the
14522    /// nodes touch is persistent workspace/staging.
14523    fn nvfp4_routes_build_graph(
14524        &self,
14525        experts: &ResidentNvfp4TensorParallel,
14526        workspace: &mut Nvfp4DeviceRoutesWorkspace,
14527        local_out: usize,
14528        n_sel: usize,
14529        activation_limit: Option<f32>,
14530    ) -> Result<RoutesGraph, Box<dyn std::error::Error>> {
14531        use cudarc::driver::DevicePtr;
14532        use cudarc::driver::sys;
14533        fn cu_try(r: sys::CUresult, what: &str) -> Result<(), Box<dyn std::error::Error>> {
14534            if r == sys::CUresult::CUDA_SUCCESS {
14535                Ok(())
14536            } else {
14537                Err(format!("{what}: {r:?}").into())
14538            }
14539        }
14540        let world = self.ranks.len();
14541        if world != 2 {
14542            return Err("routes graph door is built for the TP2 pair".into());
14543        }
14544        let width = experts.input_width;
14545
14546        // Raw pointers cached before capture (each read with its owner's stream).
14547        let ptr_f32 = |buf: &crate::CudaSlice<f32>, engine: &Engine| -> u64 {
14548            let stream = engine.stream();
14549            let (ptr, _g) = buf.device_ptr(&stream);
14550            ptr
14551        };
14552        let ptr_i32 = |buf: &crate::CudaSlice<i32>, engine: &Engine| -> u64 {
14553            let stream = engine.stream();
14554            let (ptr, _g) = buf.device_ptr(&stream);
14555            ptr
14556        };
14557        let (sel_e, w_e) = workspace
14558            .dev_route_e
14559            .as_ref()
14560            .expect("device route staging set before graph build");
14561        let root_engine = &self.ranks[0];
14562        let p_in_stage = ptr_f32(
14563            workspace.in_stage_e.as_ref().expect("graph staging"),
14564            root_engine,
14565        );
14566        let p_out_stage = ptr_f32(
14567            workspace.out_stage_e.as_ref().expect("graph staging"),
14568            root_engine,
14569        );
14570        let p_sel_e = ptr_i32(sel_e, root_engine);
14571        let p_w_e = ptr_f32(w_e, root_engine);
14572        let p_input: Vec<u64> = (0..world)
14573            .map(|r| ptr_f32(&workspace.input[r], &self.ranks[r]))
14574            .collect();
14575        let p_sel: Vec<u64> = (0..world)
14576            .map(|r| ptr_i32(&workspace.sel[r], &self.ranks[r]))
14577            .collect();
14578        let p_route_w: Vec<u64> = (0..world)
14579            .map(|r| ptr_f32(&workspace.route_w[r], &self.ranks[r]))
14580            .collect();
14581        let p_acc1 = ptr_f32(&workspace.accumulator[1], &self.ranks[1]);
14582        let p_remote = ptr_f32(&workspace.remote, root_engine);
14583        let p_combined = ptr_f32(&workspace.combined, root_engine);
14584
14585        let raw_copy = |dst: u64,
14586                        src: u64,
14587                        bytes: usize,
14588                        engine: &Engine|
14589         -> Result<(), Box<dyn std::error::Error>> {
14590            unsafe {
14591                cu_try(
14592                    sys::cuMemcpyAsync(
14593                        dst as sys::CUdeviceptr,
14594                        src as sys::CUdeviceptr,
14595                        bytes,
14596                        engine.stream().cu_stream() as sys::CUstream,
14597                    ),
14598                    "routes graph cuMemcpyAsync",
14599                )
14600            }
14601        };
14602
14603        let mut children = Vec::with_capacity(3);
14604        for rank in 0..world {
14605            let engine = &self.ranks[rank];
14606            let _main = engine.gpu.enter_main()?;
14607            let (child, _retained) = engine.capture_graph_retained(|_| {
14608                raw_copy(p_input[rank], p_in_stage, width * 4, engine)?;
14609                raw_copy(p_sel[rank], p_sel_e, n_sel * 4, engine)?;
14610                raw_copy(p_route_w[rank], p_w_e, n_sel * 4, engine)?;
14611                {
14612                    let Nvfp4DeviceRoutesWorkspace {
14613                        input, in_q, in_d, ..
14614                    } = &mut *workspace;
14615                    engine.quantize_q8_1_into(
14616                        &input[rank],
14617                        1,
14618                        width,
14619                        &mut in_q[rank],
14620                        &mut in_d[rank],
14621                    )?;
14622                }
14623                self.nvfp4_routes_batched_sweeps_rank(
14624                    experts,
14625                    workspace,
14626                    &[],
14627                    &[],
14628                    &[],
14629                    local_out,
14630                    n_sel,
14631                    activation_limit,
14632                    true,
14633                    rank,
14634                )?;
14635                Ok(())
14636            })?;
14637            children.push(child);
14638        }
14639        {
14640            let root = &self.ranks[0];
14641            let _main = root.gpu.enter_main()?;
14642            let (child, _retained) = root.capture_graph_retained(|_| {
14643                raw_copy(p_remote, p_acc1, width * 4, root)?;
14644                {
14645                    let Nvfp4DeviceRoutesWorkspace {
14646                        accumulator,
14647                        remote,
14648                        combined,
14649                        ..
14650                    } = &mut *workspace;
14651                    root.add(&accumulator[0], remote, combined, width)?;
14652                }
14653                raw_copy(p_out_stage, p_combined, width * 4, root)?;
14654                Ok(())
14655            })?;
14656            children.push(child);
14657        }
14658
14659        let mut parent: sys::CUgraph = std::ptr::null_mut();
14660        unsafe {
14661            cu_try(sys::cuGraphCreate(&mut parent, 0), "routes cuGraphCreate")?;
14662        }
14663        let mut n0: sys::CUgraphNode = std::ptr::null_mut();
14664        let mut n1: sys::CUgraphNode = std::ptr::null_mut();
14665        let mut n2: sys::CUgraphNode = std::ptr::null_mut();
14666        unsafe {
14667            cu_try(
14668                sys::cuGraphAddChildGraphNode(
14669                    &mut n0,
14670                    parent,
14671                    std::ptr::null(),
14672                    0,
14673                    children[0].cu_graph(),
14674                ),
14675                "routes child r0",
14676            )?;
14677            cu_try(
14678                sys::cuGraphAddChildGraphNode(
14679                    &mut n1,
14680                    parent,
14681                    std::ptr::null(),
14682                    0,
14683                    children[1].cu_graph(),
14684                ),
14685                "routes child r1",
14686            )?;
14687            let deps = [n0, n1];
14688            cu_try(
14689                sys::cuGraphAddChildGraphNode(
14690                    &mut n2,
14691                    parent,
14692                    deps.as_ptr(),
14693                    2,
14694                    children[2].cu_graph(),
14695                ),
14696                "routes child root",
14697            )?;
14698        }
14699        let mut exec: sys::CUgraphExec = std::ptr::null_mut();
14700        unsafe {
14701            cu_try(
14702                sys::cuGraphInstantiateWithFlags(&mut exec, parent, 0),
14703                "routes instantiate",
14704            )?;
14705        }
14706        Ok(RoutesGraph {
14707            exec,
14708            parent,
14709            _children: children,
14710        })
14711    }
14712
14713    /// One rank's routes section for the token graph (event-free): staged input copy (raw
14714    /// when the caller supplies the source pointer), quantize, and the batched sweeps.
14715    /// Eager device_routed wraps it with the entry-event wait.
14716    #[allow(clippy::too_many_arguments)]
14717    pub(crate) fn routes_rank_section(
14718        &self,
14719        experts: &ResidentNvfp4TensorParallel,
14720        workspace: &mut Nvfp4DeviceRoutesWorkspace,
14721        raw_input_src: u64,
14722        local_out: usize,
14723        n_sel: usize,
14724        activation_limit: Option<f32>,
14725        rank_index: usize,
14726    ) -> Result<(), Box<dyn std::error::Error>> {
14727        let engine = &self.ranks[rank_index];
14728        {
14729            let _main = engine.gpu.enter_main()?;
14730            // sel/route_w land via raw copies from the e staging (fixed addresses).
14731            let (sel_e_ptr, w_e_ptr) = workspace
14732                .raw_dev_route_e
14733                .ok_or("routes rank section requires armed staging pointers")?;
14734            raw_copy_bytes(
14735                workspace.raw_input[rank_index],
14736                raw_input_src,
14737                experts.input_width * 4,
14738                engine,
14739            )?;
14740            raw_copy_bytes(workspace.raw_sel[rank_index], sel_e_ptr, n_sel * 4, engine)?;
14741            raw_copy_bytes(
14742                workspace.raw_route_w[rank_index],
14743                w_e_ptr,
14744                n_sel * 4,
14745                engine,
14746            )?;
14747            {
14748                let Nvfp4DeviceRoutesWorkspace {
14749                    input, in_q, in_d, ..
14750                } = &mut *workspace;
14751                engine.quantize_q8_1_into(
14752                    &input[rank_index],
14753                    1,
14754                    experts.input_width,
14755                    &mut in_q[rank_index],
14756                    &mut in_d[rank_index],
14757                )?;
14758            }
14759        }
14760        self.nvfp4_routes_batched_sweeps_rank(
14761            experts,
14762            workspace,
14763            &[],
14764            &[],
14765            &[],
14766            local_out,
14767            n_sel,
14768            activation_limit,
14769            true,
14770            rank_index,
14771        )
14772    }
14773
14774    /// The routes ROOT combine section (event-free): peer accumulator read (raw), canonical
14775    /// add, combined row raw-copied into the fixed e-context out stage.
14776    pub(crate) fn routes_root_section(
14777        &self,
14778        experts: &ResidentNvfp4TensorParallel,
14779        workspace: &mut Nvfp4DeviceRoutesWorkspace,
14780    ) -> Result<(), Box<dyn std::error::Error>> {
14781        let root = &self.ranks[0];
14782        let _main = root.gpu.enter_main()?;
14783        let (acc1_ptr, remote_ptr, combined_ptr, out_stage_ptr) = workspace
14784            .raw_combine
14785            .ok_or("routes root section requires armed combine pointers")?;
14786        raw_copy_bytes(remote_ptr, acc1_ptr, experts.input_width * 4, root)?;
14787        {
14788            let Nvfp4DeviceRoutesWorkspace {
14789                accumulator,
14790                remote,
14791                combined,
14792                ..
14793            } = &mut *workspace;
14794            root.add(&accumulator[0], remote, combined, experts.input_width)?;
14795        }
14796        raw_copy_bytes(out_stage_ptr, combined_ptr, experts.input_width * 4, root)?;
14797        Ok(())
14798    }
14799
14800    /// Arm the routes raw pointers (once): staging pair, per-rank input/sel/route_w, and the
14801    /// combine set. Requires dev_route_e + in/out stages already allocated.
14802    pub(crate) fn routes_arm_raw(
14803        &self,
14804        experts: &ResidentNvfp4TensorParallel,
14805        workspace: &mut Nvfp4DeviceRoutesWorkspace,
14806    ) -> Result<(), Box<dyn std::error::Error>> {
14807        use cudarc::driver::DevicePtr;
14808        if workspace.raw_dev_route_e.is_some() {
14809            return Ok(());
14810        }
14811        let _ = experts;
14812        let (sel_e, w_e) = workspace
14813            .dev_route_e
14814            .as_ref()
14815            .ok_or("routes staging not armed")?;
14816        let root = &self.ranks[0];
14817        {
14818            let _main = root.gpu.enter_main()?;
14819            let stream = root.stream();
14820            let (a, _g) = sel_e.device_ptr(&stream);
14821            let (b, _g) = w_e.device_ptr(&stream);
14822            workspace.raw_dev_route_e = Some((a, b));
14823            let (c, _g) = workspace.accumulator[1].device_ptr(&stream);
14824            let (d, _g) = workspace.remote.device_ptr(&stream);
14825            let (f, _g) = workspace.combined.device_ptr(&stream);
14826            let out_stage = workspace
14827                .out_stage_e
14828                .as_ref()
14829                .ok_or("routes out stage not armed")?;
14830            let (g_, _g) = out_stage.device_ptr(&stream);
14831            workspace.raw_combine = Some((c, d, f, g_));
14832        }
14833        for rank in 0..self.ranks.len() {
14834            let engine = &self.ranks[rank];
14835            let _main = engine.gpu.enter_main()?;
14836            let stream = engine.stream();
14837            let (a, _g) = workspace.input[rank].device_ptr(&stream);
14838            let (b, _g) = workspace.sel[rank].device_ptr(&stream);
14839            let (c, _g) = workspace.route_w[rank].device_ptr(&stream);
14840            workspace.raw_input.push(a);
14841            workspace.raw_sel.push(b);
14842            workspace.raw_route_w.push(c);
14843        }
14844        Ok(())
14845    }
14846
14847    /// Routed NVFP4 expert program, host-canonical transport. Native/bulk P2P transport for the
14848    /// NVFP4 bank is a separate increment; this entry point is exactness-first and reports no
14849    /// throughput claim.
14850    #[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
14851    pub fn run_tensor_parallel_routes_nvfp4(
14852        &self,
14853        experts: &ResidentNvfp4TensorParallel,
14854        input: &[f32],
14855        tokens: usize,
14856        selected: &[usize],
14857        route_weights: &[f32],
14858        experts_per_token: usize,
14859        activation_limit: Option<f32>,
14860    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
14861        validate_activations(input, tokens, experts.input_width)?;
14862        let pairs = tokens
14863            .checked_mul(experts_per_token)
14864            .ok_or("NVFP4 TP route count overflow")?;
14865        if selected.len() != pairs || route_weights.len() != pairs {
14866            return Err(format!(
14867                "NVFP4 TP routes selected={} weights={} != tokens {tokens} x experts/token \
14868                 {experts_per_token} ({pairs})",
14869                selected.len(),
14870                route_weights.len(),
14871            )
14872            .into());
14873        }
14874        if !route_weights.iter().all(|weight| weight.is_finite()) {
14875            return Err("NVFP4 TP route weights contain a non-finite value".into());
14876        }
14877
14878        let mut output = vec![0.0f32; tokens * experts.input_width];
14879        for token in 0..tokens {
14880            let input_row = &input[token * experts.input_width..(token + 1) * experts.input_width];
14881            for slot in 0..experts_per_token {
14882                let pair = token * experts_per_token + slot;
14883                let expert = selected[pair];
14884                if expert >= experts.expert_count {
14885                    return Err(format!(
14886                        "NVFP4 TP selected expert {expert} outside 0..{}",
14887                        experts.expert_count
14888                    )
14889                    .into());
14890                }
14891                // EP2 banks hold the WHOLE expert on rank (expert & 1) at slot (expert >> 1);
14892                // per-row dots are the same full-width program either way (a column shard
14893                // splits ROWS, not the dot), so gate/up are bit-equal across layouts. Only
14894                // down's parenthesization moves (full-width dot vs canonical 2-shard sum) —
14895                // the numeric-class this door declares.
14896                let gate = if experts.ep2 {
14897                    self.run_full_bank_expert_nvfp4(
14898                        &experts.gate,
14899                        &experts.macros_gate,
14900                        expert,
14901                        input_row,
14902                    )?
14903                } else {
14904                    self.run_column_bank_expert_nvfp4(
14905                        &experts.gate,
14906                        &experts.macros_gate,
14907                        expert,
14908                        input_row,
14909                    )?
14910                };
14911                let up = if experts.ep2 {
14912                    self.run_full_bank_expert_nvfp4(
14913                        &experts.up,
14914                        &experts.macros_up,
14915                        expert,
14916                        input_row,
14917                    )?
14918                } else {
14919                    self.run_column_bank_expert_nvfp4(
14920                        &experts.up,
14921                        &experts.macros_up,
14922                        expert,
14923                        input_row,
14924                    )?
14925                };
14926                let activated: Vec<f32> = gate
14927                    .iter()
14928                    .zip(&up)
14929                    .map(|(&gate, &up)| step_expert_activation_host(gate, up, activation_limit))
14930                    .collect();
14931                debug_assert_eq!(activated.len(), experts.expert_width);
14932                let down = if experts.ep2 {
14933                    self.run_full_down_expert_nvfp4(
14934                        &experts.down,
14935                        &experts.macros_down,
14936                        expert,
14937                        &activated,
14938                    )?
14939                } else {
14940                    self.run_row_bank_expert_nvfp4(
14941                        &experts.down,
14942                        &experts.macros_down,
14943                        expert,
14944                        &activated,
14945                    )?
14946                };
14947                let weight = route_weights[pair];
14948                for (sum, value) in output
14949                    [token * experts.input_width..(token + 1) * experts.input_width]
14950                    .iter_mut()
14951                    .zip(down)
14952                {
14953                    *sum += weight * value;
14954                }
14955            }
14956        }
14957        Ok(output)
14958    }
14959}
14960
14961#[cfg(test)]
14962mod default_on_door_tests {
14963    use super::door_default_on_value;
14964
14965    /// The DEFAULT-ON parse, pinned in every state — including the two that only matter because
14966    /// the default is ON.
14967    ///
14968    /// While these doors were default OFF the parse was `== Ok("1")` and its failure mode was
14969    /// benign: any typo read as the default, which was OFF, which was the safe program. Flipping
14970    /// the default INVERTS that. Under a naive `!= Ok("0")` rule, `MEMRA_NVFP4_BANK_SM=false`
14971    /// (or `=off`, or `=no`) would leave the program ARMED while the operator believed they had
14972    /// rolled it back — a rollback seam that silently does nothing, on the exact door whose
14973    /// predecessor shipped fluent wrong text. So the unrecognized-value case is a named,
14974    /// tested branch that keeps the default AND warns, rather than an accident of `!=`.
14975    #[test]
14976    fn the_default_on_door_parses_every_state_and_names_its_source() {
14977        // unset: the flip is what arms it, and the source string says so — this is the string a
14978        // default-flip receipt needs, because in the flip arms there is no env var to point at.
14979        assert_eq!(
14980            door_default_on_value("MEMRA_TEST_DOOR", None),
14981            (true, "default-on")
14982        );
14983        // explicit 1: armed by a RECIPE, not by the default. Different fact, different label.
14984        assert_eq!(
14985            door_default_on_value("MEMRA_TEST_DOOR", Some("1")),
14986            (true, "env=1")
14987        );
14988        // THE ROLLBACK SEAM. This is the assertion the flip's safety rests on.
14989        assert_eq!(
14990            door_default_on_value("MEMRA_TEST_DOOR", Some("0")),
14991            (false, "env=0 (rollback seam)")
14992        );
14993        // Unrecognized values keep the DEFAULT (ON) and are flagged as such, for every shape an
14994        // operator plausibly types when they mean "off". Every one of these MUST still read ON:
14995        // a parse that guessed "off" from `false` would be a second, undocumented seam, and a
14996        // parse that guessed "off" from `2` would make a typo a silent program change.
14997        for bad in [
14998            "false", "off", "no", "", " 0", "0 ", "00", "true", "2", "-1",
14999        ] {
15000            let (on, source) = door_default_on_value("MEMRA_TEST_DOOR", Some(bad));
15001            assert!(on, "value {bad:?} must NOT disarm a default-ON door");
15002            assert!(
15003                source.contains("default-on") && source.contains("unrecognized"),
15004                "value {bad:?} gave source {source:?}, which does not announce itself as an \
15005                 ignored value — a receipt reader would take it for a clean default"
15006            );
15007        }
15008    }
15009}
15010
15011#[cfg(test)]
15012mod bank_v2_layout_tests {
15013    use super::{nvfp4_matrix_v2_permute, nvfp4_row_bytes};
15014
15015    /// The slot-major permutation had NO test at all until 2026-08-29, while its (since
15016    /// removed) `MEMRA_NVFP4_BANK_V2` FLAGS row carried a bit-identity claim and the live
15017    /// serving env pinned it on. This pins the DOCUMENTED mapping so a reader can be checked
15018    /// against something: per row, slot g's 16 qs bytes land contiguously at `g*16`, and its
15019    /// two UE4M3 scale bytes at `nslots*16 + g*2`. Source layout is memra `block_nvfp4`:
15020    /// 36-byte superblocks of [4 scale bytes | 32 packed e2m1], two 32-value slots per
15021    /// superblock. Since the 2026-08-29 door removal the permutation's ONLY consumer is the
15022    /// EP2 whole-expert bank build (`nvfp4_repack_bank_matrix(_, true)`), whose `*_ep`
15023    /// kernels and `qmatvec_nvfp4_fast_v2` oracle read this exact mapping.
15024    #[test]
15025    fn the_v2_bank_row_is_the_documented_slot_major_permutation() {
15026        // two rows, in_features 128 => 2 superblocks/row, 4 slots/row, 72 bytes/row.
15027        let (out_f, in_f) = (2usize, 128usize);
15028        let row_bytes = nvfp4_row_bytes(in_f);
15029        assert_eq!(row_bytes, 72);
15030        let v1: Vec<u8> = (0..out_f * row_bytes).map(|i| (i % 251) as u8).collect();
15031        let v2 = nvfp4_matrix_v2_permute(&v1, out_f, in_f);
15032        assert_eq!(v2.len(), v1.len(), "a permutation cannot change the size");
15033        let n_slots = in_f / 32;
15034        for row in 0..out_f {
15035            let src = &v1[row * row_bytes..(row + 1) * row_bytes];
15036            let dst = &v2[row * row_bytes..(row + 1) * row_bytes];
15037            for g in 0..n_slots {
15038                let (sblk, h) = (g / 2, g % 2);
15039                let sb = &src[sblk * 36..sblk * 36 + 36];
15040                assert_eq!(
15041                    &dst[g * 16..g * 16 + 16],
15042                    &sb[4 + 16 * h..4 + 16 * h + 16],
15043                    "row {row} slot {g} codes"
15044                );
15045                assert_eq!(
15046                    &dst[n_slots * 16 + g * 2..n_slots * 16 + g * 2 + 2],
15047                    &sb[2 * h..2 * h + 2],
15048                    "row {row} slot {g} scales"
15049                );
15050            }
15051            // and it moves bytes only: same multiset per row, rows never cross.
15052            let (mut a, mut b) = (src.to_vec(), dst.to_vec());
15053            a.sort_unstable();
15054            b.sort_unstable();
15055            assert_eq!(a, b, "row {row} is not a byte permutation");
15056        }
15057    }
15058}
15059
15060#[cfg(test)]
15061mod tests {
15062
15063    #[test]
15064    fn door_composition_refuses_first_armed_flag_by_name() {
15065        let table: [(&str, &str); 2] = [
15066            ("MEMRA_DOOR_A", "gated on the unsharded walk only"),
15067            ("MEMRA_DOOR_B", "no sharded branches"),
15068        ];
15069        // cold doors pass
15070        super::refuse_door_composition("MEMRA_X_TP", &table, |_| false).expect("cold doors pass");
15071        // an armed door refuses with the exact byte format the glm5 gate asserts on
15072        let err = super::refuse_door_composition("MEMRA_X_TP", &table, |f| f == "MEMRA_DOOR_B")
15073            .expect_err("armed door must refuse");
15074        assert_eq!(
15075            err,
15076            "MEMRA_X_TP + MEMRA_DOOR_B: unproven composition, refused (no sharded branches)"
15077        );
15078        // a flag outside the table never trips it
15079        super::refuse_door_composition("MEMRA_X_TP", &table, |f| f == "MEMRA_DOOR_C")
15080            .expect("foreign flags are not the matrix");
15081    }
15082
15083    /// THE DEFECT, ASSERTED SO IT CANNOT COME BACK. The retired memo key hashed only the K
15084    /// pointer, the base pointer, the layer and t, while the table it returned ALSO carried
15085    /// the V and LEN pointers. Two different allocation generations that happen to share a K
15086    /// address therefore collide, and the entry the map hands back sends a live launch at
15087    /// another allocation's V and len. This test does not assert the key is fine; it asserts
15088    /// the key is BLIND, which is why `rows_tab_restage_on` exists and defaults ON.
15089    #[test]
15090    fn the_retired_rows_tab_key_cannot_see_the_v_and_len_pointers_it_hands_back() {
15091        let (kp, bp) = (0xdead_0000u64, 0u64);
15092        let live = [[kp, 0x00b1_0000u64, 0x00c1_0000u64, bp]];
15093        let recycled = [[kp, 0x00b2_0000u64, 0x00c2_0000u64, bp]];
15094        assert_eq!(
15095            super::retired_rows_tab_key(kp, bp, 20, 2),
15096            super::retired_rows_tab_key(kp, bp, 20, 2),
15097            "same layer and t must hash the same, or the test proves nothing"
15098        );
15099        let a = super::rows_tab_host(&live, 0x9000, true, 1);
15100        let b = super::rows_tab_host(&recycled, 0x9000, true, 1);
15101        assert_ne!(a, b, "the two generations write DIFFERENT tables");
15102        // ... yet one key covers both, which is exactly the use-after-free.
15103        assert_eq!(
15104            super::retired_rows_tab_key(live[0][0], live[0][3], 20, 1),
15105            super::retired_rows_tab_key(recycled[0][0], recycled[0][3], 20, 1),
15106            "the retired key collides across allocation generations"
15107        );
15108    }
15109
15110    /// The restage must be VALUE-NEUTRAL: on a fresh lookup the memo and the restage produce
15111    /// identical bytes, which is what makes spec-on output byte-identical to spec-off.
15112    #[test]
15113    fn rows_tab_layout_is_the_same_bytes_the_memo_would_have_cached() {
15114        let parts = [
15115            [0x00a0u64, 0x00b0u64, 0x00c0u64, 0x00d0u64],
15116            [0x00a1u64, 0x00b1u64, 0x00c1u64, 0x00d1u64],
15117        ];
15118        let same = super::rows_tab_host(&parts, 0x7000, true, 2);
15119        assert_eq!(
15120            same,
15121            vec![
15122                0x00a0u64, 0x00b0u64, 0x00c0u64, 0x00d0u64, 0x7000,
15123                1, // row 0: back = t-1-r = 1
15124                0x00a1u64, 0x00b1u64, 0x00c1u64, 0x00d1u64, 0x7000, 0, // row 1: back = 0
15125            ],
15126            "same-session rows share one counter cell and step back t-1-r"
15127        );
15128        let cross = super::rows_tab_host(&parts, 0x7000, false, 2);
15129        assert_eq!(
15130            cross,
15131            vec![
15132                0x00a0u64, 0x00b0u64, 0x00c0u64, 0x00d0u64, 0x7000, 0, 0x00a1u64, 0x00b1u64,
15133                0x00c1u64, 0x00d1u64, 0x7004, 0,
15134            ],
15135            "cross-session rows get their own counter cell and no step back"
15136        );
15137    }
15138    use super::*;
15139
15140    #[test]
15141    fn step_expert_activation_clamps_each_arm_by_the_official_contract() {
15142        let limit = Some(7.0);
15143        assert_eq!(step_expert_activation_host(20.0, 9.0, limit), 49.0);
15144        assert_eq!(step_expert_activation_host(20.0, -9.0, limit), -49.0);
15145        assert!(
15146            step_expert_activation_host(-20.0, 9.0, limit).abs()
15147                < step_expert_activation_host(-20.0, 9.0, None).abs()
15148        );
15149        assert!(validate_step_expert_activation_limit(Some(f32::NAN)).is_err());
15150        assert!(validate_step_expert_activation_limit(Some(0.0)).is_err());
15151        assert!(validate_step_expert_activation_limit(limit).is_ok());
15152    }
15153
15154    #[test]
15155    fn moe_residual_host_preserves_official_add_order() {
15156        let output = moe_residual_host(&[1.0e20], &[-1.0e20], &[1.0]).unwrap();
15157        assert_eq!(output, [0.0]);
15158        assert_eq!(
15159            moe_residual_host(&[0.0], &[0.0, 1.0], &[0.0]).unwrap_err(),
15160            "MoE residual lengths residual=1 routed=2 shared=1"
15161        );
15162    }
15163
15164    #[test]
15165    fn expert_owner_routes_preserve_global_pair_order_with_local_expert_ids() {
15166        let selected = [0, 36, 72, 108, 144, 180, 216, 252];
15167        let owners = partition_expert_owner_routes(288, 4, 1, 8, &selected).unwrap();
15168        assert_eq!(owners.len(), 4);
15169        for (rank, owner) in owners.iter().enumerate() {
15170            assert_eq!(owner.rank, rank);
15171            assert_eq!(owner.selected, vec![0, 36]);
15172            assert_eq!(owner.token_rows, vec![0, 0]);
15173            assert_eq!(owner.global_pairs, vec![rank * 2, rank * 2 + 1]);
15174        }
15175    }
15176
15177    #[test]
15178    fn expert_owner_routes_validate_geometry_and_selected_experts() {
15179        assert!(partition_expert_owner_routes(288, 5, 1, 8, &[0; 8]).is_err());
15180        assert!(partition_expert_owner_routes(288, 4, 2, 8, &[0; 8]).is_err());
15181        let error = partition_expert_owner_routes(288, 4, 1, 8, &[288; 8]).unwrap_err();
15182        assert!(error.contains("outside 0..288"));
15183    }
15184
15185    #[test]
15186    fn step_grouped_owner_routes_validate_dynamic_top8_shapes() {
15187        let selected = [
15188            1, 73, 80, 145, 152, 159, 217, 224, 12, 84, 91, 156, 163, 170, 228, 235,
15189        ];
15190        assert_eq!(
15191            validate_step_grouped_owner_routes(288, 2, &selected).unwrap(),
15192            16
15193        );
15194        let owners = partition_expert_owner_routes(288, 4, 2, 8, &selected).unwrap();
15195        assert_eq!(
15196            owners
15197                .iter()
15198                .map(|owner| owner.selected.len())
15199                .collect::<Vec<_>>(),
15200            vec![2, 4, 6, 4]
15201        );
15202        assert!(validate_step_grouped_owner_routes(288, 2, &selected[..8]).is_err());
15203        assert!(validate_step_grouped_owner_routes(288, 1, &[0; 8]).is_err());
15204        assert!(validate_step_grouped_owner_routes(287, 2, &selected).is_err());
15205    }
15206
15207    #[test]
15208    fn weighted_route_combine_requires_a_canonical_pair_permutation() {
15209        let owner0 = [0usize, 3];
15210        let owner1 = [1usize, 2];
15211        let owners = [owner0.as_slice(), owner1.as_slice()];
15212        assert_eq!(
15213            validate_weighted_route_combine(4096, 4, 3, 1, &owners, &[0.1, 0.2, 0.3, 0.4],)
15214                .unwrap(),
15215            WeightedRouteCombineShape {
15216                pairs: 4,
15217                max_pairs: 12,
15218            }
15219        );
15220        let duplicate = [owner0.as_slice(), &[1usize, 1][..]];
15221        assert!(
15222            validate_weighted_route_combine(4096, 4, 3, 1, &duplicate, &[0.1, 0.2, 0.3, 0.4],)
15223                .is_err()
15224        );
15225        assert!(
15226            validate_weighted_route_combine(4096, 4, 3, 1, &owners, &[0.1, f32::NAN, 0.3, 0.4],)
15227                .is_err()
15228        );
15229        assert!(
15230            validate_weighted_route_combine(4096, 4, 1, 2, &owners, &[0.1, 0.2, 0.3, 0.4],)
15231                .is_err()
15232        );
15233    }
15234
15235    #[test]
15236    fn native_p2p_door_is_strict_and_default_off() {
15237        assert!(!parse_step_tp_native_p2p(None).unwrap());
15238        assert!(!parse_step_tp_native_p2p(Some("")).unwrap());
15239        assert!(!parse_step_tp_native_p2p(Some("0")).unwrap());
15240        assert!(parse_step_tp_native_p2p(Some("1")).unwrap());
15241        assert!(parse_step_tp_native_p2p(Some("true")).is_err());
15242        assert!(parse_step_tp_native_p2p(Some("2")).is_err());
15243    }
15244
15245    #[test]
15246    fn bulk_p2p_door_is_strict_and_default_off() {
15247        assert!(!parse_step_tp_bulk_p2p(None).unwrap());
15248        assert!(!parse_step_tp_bulk_p2p(Some("")).unwrap());
15249        assert!(!parse_step_tp_bulk_p2p(Some("0")).unwrap());
15250        assert!(parse_step_tp_bulk_p2p(Some("1")).unwrap());
15251        assert!(parse_step_tp_bulk_p2p(Some("true")).is_err());
15252        assert!(parse_step_tp_bulk_p2p(Some("2")).is_err());
15253    }
15254
15255    #[test]
15256    fn ep_device_arithmetic_door_is_strict_and_default_off() {
15257        assert!(!parse_step_ep_device_arithmetic(None).unwrap());
15258        assert!(!parse_step_ep_device_arithmetic(Some("")).unwrap());
15259        assert!(!parse_step_ep_device_arithmetic(Some("0")).unwrap());
15260        assert!(parse_step_ep_device_arithmetic(Some("1")).unwrap());
15261        assert!(parse_step_ep_device_arithmetic(Some("true")).is_err());
15262        assert!(parse_step_ep_device_arithmetic(Some("2")).is_err());
15263    }
15264
15265    #[test]
15266    fn f32_mirror_door_is_strict_and_default_off() {
15267        assert!(!parse_step_tp_f32_mirror(None).unwrap());
15268        assert!(!parse_step_tp_f32_mirror(Some("")).unwrap());
15269        assert!(!parse_step_tp_f32_mirror(Some("0")).unwrap());
15270        assert!(parse_step_tp_f32_mirror(Some("1")).unwrap());
15271        assert!(parse_step_tp_f32_mirror(Some("true")).is_err());
15272        assert!(parse_step_tp_f32_mirror(Some("2")).is_err());
15273    }
15274
15275    fn matrix(out_features: usize, in_features: usize) -> (Vec<u8>, Vec<f32>) {
15276        let codes = (0..out_features * in_features)
15277            .map(|index| (index % 251) as u8)
15278            .collect();
15279        let scales = (0..out_features.div_ceil(FP8_BLOCK) * in_features.div_ceil(FP8_BLOCK))
15280            .map(|index| index as f32 + 1.0)
15281            .collect();
15282        (codes, scales)
15283    }
15284
15285    fn bf16_matrix_bytes(out_features: usize, in_features: usize) -> Vec<u8> {
15286        (0..out_features * in_features)
15287            .flat_map(|value| (value as u16).to_le_bytes())
15288            .collect()
15289    }
15290
15291    fn decode_u16(bytes: &[u8]) -> Vec<u16> {
15292        bytes
15293            .chunks_exact(2)
15294            .map(|bytes| u16::from_le_bytes([bytes[0], bytes[1]]))
15295            .collect()
15296    }
15297
15298    #[test]
15299    fn bf16_matrix_rejects_wrong_byte_count() {
15300        let bytes = vec![0u8; 4 * 4 * 2 - 1];
15301        let matrix = Bf16Matrix {
15302            bytes: &bytes,
15303            out_features: 4,
15304            in_features: 4,
15305        };
15306        assert!(matrix.validate().unwrap_err().contains("4x4x2"));
15307    }
15308
15309    #[test]
15310    fn replicated_device_rows_require_exact_rank_local_shapes() {
15311        assert_eq!(
15312            replicated_device_row_values(3, 4096, 4, &[12_288; 4]).unwrap(),
15313            12_288
15314        );
15315        assert!(replicated_device_row_values(0, 4096, 4, &[0; 4]).is_err());
15316        assert!(replicated_device_row_values(3, 0, 4, &[0; 4]).is_err());
15317        assert!(replicated_device_row_values(3, 4096, 4, &[12_288; 3]).is_err());
15318        assert!(
15319            replicated_device_row_values(3, 4096, 4, &[12_288, 12_288, 12_287, 12_288]).is_err()
15320        );
15321        assert!(replicated_device_row_values(usize::MAX, 2, 1, &[0]).is_err());
15322    }
15323
15324    #[test]
15325    fn replicated_device_row_refresh_requires_exact_root_source() {
15326        assert_eq!(
15327            replicated_device_row_source_values(1, 12_288, 12_288, 3, 3).unwrap(),
15328            12_288
15329        );
15330        assert!(replicated_device_row_source_values(0, 12_288, 0, 3, 3).is_err());
15331        assert!(replicated_device_row_source_values(1, 0, 0, 3, 3).is_err());
15332        assert!(replicated_device_row_source_values(1, 12_288, 12_287, 3, 3).is_err());
15333        assert!(replicated_device_row_source_values(1, 12_288, 12_288, 2, 3).is_err());
15334        assert!(replicated_device_row_source_values(usize::MAX, 2, 0, 3, 3).is_err());
15335    }
15336
15337    #[test]
15338    fn step_bf16_canonical_rows_are_topology_invariant_through_tp8() {
15339        for tp in [1, 2, 4, 8] {
15340            assert_eq!(step_bf16_canonical_chunk_rows(8_192, tp).unwrap(), 1_024);
15341            assert_eq!(step_bf16_canonical_chunk_rows(12_288, tp).unwrap(), 1_536);
15342            assert_eq!(step_bf16_canonical_chunk_rows(1_024, tp).unwrap(), 128);
15343            assert_eq!(step_bf16_canonical_chunk_cols(8_192, tp).unwrap(), 1_024);
15344            assert_eq!(step_bf16_canonical_chunk_cols(12_288, tp).unwrap(), 1_536);
15345        }
15346        assert!(step_bf16_canonical_chunk_rows(12_288, 3).is_err());
15347        assert!(step_bf16_canonical_chunk_rows(1_001, 2).is_err());
15348        assert!(step_bf16_canonical_chunk_cols(12_288, 3).is_err());
15349        assert!(step_bf16_canonical_chunk_cols(1_001, 2).is_err());
15350    }
15351
15352    #[test]
15353    fn cache_rows_split_by_token_then_rank() {
15354        let rows = (0u8..24).collect::<Vec<_>>();
15355        assert_eq!(
15356            cache_rank_rows(&rows, 3, 4, 2, 0).unwrap(),
15357            vec![0, 1, 2, 3, 8, 9, 10, 11, 16, 17, 18, 19]
15358        );
15359        assert_eq!(
15360            cache_rank_rows(&rows, 3, 4, 2, 1).unwrap(),
15361            vec![4, 5, 6, 7, 12, 13, 14, 15, 20, 21, 22, 23]
15362        );
15363        assert!(cache_rank_rows(&rows[..23], 3, 4, 2, 0).is_err());
15364        assert!(cache_rank_rows(&rows, 3, 4, 2, 2).is_err());
15365    }
15366
15367    #[test]
15368    fn bf16_column_shard_preserves_contiguous_output_rows() {
15369        let bytes = bf16_matrix_bytes(4, 4);
15370        let matrix = Bf16Matrix {
15371            bytes: &bytes,
15372            out_features: 4,
15373            in_features: 4,
15374        };
15375        let shard = bf16_column_shard(matrix, 2, 1).unwrap();
15376        assert_eq!(shard.out_features, 2);
15377        assert_eq!(shard.in_features, 4);
15378        assert_eq!(decode_u16(shard.bytes), (8..16).collect::<Vec<_>>());
15379    }
15380
15381    #[test]
15382    fn bf16_row_shard_preserves_each_input_column_window() {
15383        let bytes = bf16_matrix_bytes(3, 4);
15384        let matrix = Bf16Matrix {
15385            bytes: &bytes,
15386            out_features: 3,
15387            in_features: 4,
15388        };
15389        let shard = bf16_row_shard(matrix, 2, 1).unwrap();
15390        assert_eq!(decode_u16(&shard), vec![2, 3, 6, 7, 10, 11]);
15391    }
15392
15393    #[test]
15394    fn bf16_row_block_preserves_global_column_order() {
15395        let bytes = bf16_matrix_bytes(3, 8);
15396        let matrix = Bf16Matrix {
15397            bytes: &bytes,
15398            out_features: 3,
15399            in_features: 8,
15400        };
15401        let block = bf16_row_block(matrix, 2, 3).unwrap();
15402        assert_eq!(decode_u16(&block), vec![2, 3, 4, 10, 11, 12, 18, 19, 20]);
15403    }
15404
15405    #[test]
15406    fn column_shard_preserves_contiguous_weight_and_scale_rows() {
15407        let (codes, scales) = matrix(1280, 4096);
15408        let matrix = E4m3BlockMatrix {
15409            codes: &codes,
15410            scales: &scales,
15411            out_features: 1280,
15412            in_features: 4096,
15413        };
15414        let shard = column_shard(matrix, 2, 1).unwrap();
15415        assert_eq!(shard.out_features, 640);
15416        assert_eq!(shard.codes, &codes[640 * 4096..]);
15417        assert_eq!(shard.scales, &scales[5 * 32..]);
15418    }
15419
15420    #[test]
15421    fn row_shard_preserves_each_weight_and_scale_column_window() {
15422        let (codes, scales) = matrix(4096, 1280);
15423        let matrix = E4m3BlockMatrix {
15424            codes: &codes,
15425            scales: &scales,
15426            out_features: 4096,
15427            in_features: 1280,
15428        };
15429        let (shard_codes, shard_scales) = row_shard(matrix, 2, 1).unwrap();
15430        assert_eq!(shard_codes.len(), 4096 * 640);
15431        assert_eq!(&shard_codes[..640], &codes[640..1280]);
15432        assert_eq!(&shard_codes[640..1280], &codes[1280 + 640..2560]);
15433        assert_eq!(shard_scales.len(), 32 * 5);
15434        assert_eq!(&shard_scales[..5], &scales[5..10]);
15435        assert_eq!(&shard_scales[5..10], &scales[15..20]);
15436    }
15437
15438    #[test]
15439    fn activation_shards_keep_token_rows_separate() {
15440        let activations: Vec<f32> = (0..2 * 8).map(|value| value as f32).collect();
15441        assert_eq!(
15442            activation_shard(&activations, 2, 8, 2, 1),
15443            vec![4.0, 5.0, 6.0, 7.0, 12.0, 13.0, 14.0, 15.0],
15444        );
15445    }
15446
15447    #[test]
15448    fn expert_bank_selects_expert_major_code_and_scale_planes() {
15449        let expert_count = 2;
15450        let out_features = 128;
15451        let in_features = 128;
15452        let code_stride = out_features * in_features;
15453        let codes: Vec<u8> = (0..expert_count * code_stride)
15454            .map(|index| (index % 251) as u8)
15455            .collect();
15456        let scales = vec![1.0f32, 2.0];
15457        let bank = E4m3ExpertBank {
15458            codes: &codes,
15459            scales: &scales,
15460            expert_count,
15461            out_features,
15462            in_features,
15463        };
15464        bank.validate().unwrap();
15465        let expert = bank.expert(1).unwrap();
15466        assert_eq!(expert.codes, &codes[code_stride..]);
15467        assert_eq!(expert.scales, &[2.0]);
15468    }
15469
15470    #[test]
15471    fn expert_bank_rejects_non_positive_scale() {
15472        let codes = vec![0u8; 128 * 128];
15473        let scales = vec![0.0f32];
15474        let bank = E4m3ExpertBank {
15475            codes: &codes,
15476            scales: &scales,
15477            expert_count: 1,
15478            out_features: 128,
15479            in_features: 128,
15480        };
15481        assert!(bank.validate().unwrap_err().contains("non-positive"));
15482    }
15483
15484    #[test]
15485    fn tensor_parallel_column_bank_keeps_each_expert_scale_plane_separate() {
15486        let expert_count = 2;
15487        let out_features = 256;
15488        let in_features = 128;
15489        let code_stride = out_features * in_features;
15490        let scale_stride = 2;
15491        let codes = (0..expert_count * code_stride)
15492            .map(|index| (index % 251) as u8)
15493            .collect::<Vec<_>>();
15494        let scales = vec![10.0f32, 11.0, 20.0, 21.0];
15495        let bank = E4m3ExpertBank {
15496            codes: &codes,
15497            scales: &scales,
15498            expert_count,
15499            out_features,
15500            in_features,
15501        };
15502
15503        let rank = pack_column_bank_rank(bank, 2, 1).unwrap();
15504        assert_eq!(rank.out_features, 128);
15505        assert_eq!(rank.in_features, 128);
15506        assert_eq!(rank.codes.len(), expert_count * 128 * 128);
15507        assert_eq!(rank.scales, vec![11.0, 21.0]);
15508        assert_eq!(&rank.codes[..128 * 128], &codes[128 * 128..256 * 128]);
15509        assert_eq!(
15510            &rank.codes[128 * 128..],
15511            &codes[code_stride + 128 * 128..2 * code_stride]
15512        );
15513        assert_eq!(scale_stride, scales.len() / expert_count);
15514    }
15515
15516    #[test]
15517    fn tensor_parallel_row_bank_keeps_each_expert_scale_plane_separate() {
15518        let expert_count = 2;
15519        let out_features = 128;
15520        let in_features = 256;
15521        let code_stride = out_features * in_features;
15522        let codes = (0..expert_count * code_stride)
15523            .map(|index| (index % 251) as u8)
15524            .collect::<Vec<_>>();
15525        let scales = vec![10.0f32, 11.0, 20.0, 21.0];
15526        let bank = E4m3ExpertBank {
15527            codes: &codes,
15528            scales: &scales,
15529            expert_count,
15530            out_features,
15531            in_features,
15532        };
15533
15534        let rank = pack_row_bank_rank(bank, 2, 1).unwrap();
15535        assert_eq!(rank.out_features, 128);
15536        assert_eq!(rank.in_features, 128);
15537        assert_eq!(rank.k_blocks, Some(1));
15538        assert_eq!(rank.codes.len(), expert_count * 128 * 128);
15539        assert_eq!(rank.scales, vec![11.0, 21.0]);
15540        assert_eq!(&rank.codes[..128], &codes[128..256]);
15541        assert_eq!(
15542            &rank.codes[128 * 128..128 * 128 + 128],
15543            &codes[code_stride + 128..code_stride + 256]
15544        );
15545    }
15546
15547    #[test]
15548    fn tensor_parallel_row_bank_preserves_global_k_block_order() {
15549        let expert_count = 2;
15550        let out_features = 256;
15551        let in_features = 512;
15552        let code_stride = out_features * in_features;
15553        let mut codes = vec![0u8; expert_count * code_stride];
15554        for expert in 0..expert_count {
15555            for row in 0..out_features {
15556                for block in 0..4 {
15557                    let value = (expert * 80 + block * 16 + row % 16) as u8;
15558                    let start = expert * code_stride + row * in_features + block * FP8_BLOCK;
15559                    codes[start..start + FP8_BLOCK].fill(value);
15560                }
15561            }
15562        }
15563        let scales = vec![
15564            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,
15565            112.0, 113.0, 114.0,
15566        ];
15567        let bank = E4m3ExpertBank {
15568            codes: &codes,
15569            scales: &scales,
15570            expert_count,
15571            out_features,
15572            in_features,
15573        };
15574
15575        let rank = pack_row_bank_rank(bank, 2, 1).unwrap();
15576        assert_eq!(rank.out_features, out_features);
15577        assert_eq!(rank.in_features, 256);
15578        assert_eq!(rank.k_blocks, Some(2));
15579        assert_eq!(rank.code_stride, out_features * 256);
15580        assert_eq!(rank.scale_stride, 4);
15581        assert_eq!(&rank.scales[..4], &[3.0, 13.0, 4.0, 14.0]);
15582        assert_eq!(&rank.scales[4..], &[103.0, 113.0, 104.0, 114.0]);
15583
15584        let block_stride = out_features * FP8_BLOCK;
15585        assert!(rank.codes[..FP8_BLOCK].iter().all(|&code| code == 32));
15586        assert!(
15587            rank.codes[block_stride..block_stride + FP8_BLOCK]
15588                .iter()
15589                .all(|&code| code == 48)
15590        );
15591        assert!(
15592            rank.codes[rank.code_stride..rank.code_stride + FP8_BLOCK]
15593                .iter()
15594                .all(|&code| code == 112)
15595        );
15596        assert!(
15597            rank.codes
15598                [rank.code_stride + block_stride..rank.code_stride + block_stride + FP8_BLOCK]
15599                .iter()
15600                .all(|&code| code == 128)
15601        );
15602    }
15603
15604    #[test]
15605    fn automatic_parallel_policy_needs_only_one_device_set_not_layer_recipes() {
15606        assert_eq!(parse_auto_parallel_devices(None, None).unwrap(), None);
15607        assert_eq!(
15608            parse_auto_parallel_devices(Some("auto"), Some("0,1,2,3")).unwrap(),
15609            Some(vec![0, 1, 2, 3])
15610        );
15611        assert!(parse_auto_parallel_devices(Some("auto"), None).is_err());
15612        assert!(parse_auto_parallel_devices(Some("auto"), Some("0,1,1")).is_err());
15613        assert!(parse_auto_parallel_devices(Some("auto"), Some("0,1,2,3,4")).is_err());
15614        assert!(parse_auto_parallel_devices(Some("ep"), Some("0,1")).is_err());
15615    }
15616
15617    #[test]
15618    fn automatic_ep_device_router_flag_is_strict() {
15619        assert!(!parse_parallel_ep_device_router(None).unwrap());
15620        assert!(!parse_parallel_ep_device_router(Some("0")).unwrap());
15621        assert!(parse_parallel_ep_device_router(Some("1")).unwrap());
15622        assert!(parse_parallel_ep_device_router(Some("true")).is_err());
15623    }
15624
15625    #[test]
15626    fn automatic_ep_graph_flag_is_strict_and_defaults_off() {
15627        assert!(!parse_parallel_ep_graph(None).unwrap());
15628        assert!(!parse_parallel_ep_graph(Some("0")).unwrap());
15629        assert!(parse_parallel_ep_graph(Some("1")).unwrap());
15630        assert!(parse_parallel_ep_graph(Some("true")).is_err());
15631    }
15632
15633    #[test]
15634    fn automatic_ep_pair_down_flag_is_strict_and_defaults_off() {
15635        assert!(!parse_parallel_ep_pair_down(None).unwrap());
15636        assert!(!parse_parallel_ep_pair_down(Some("0")).unwrap());
15637        assert!(parse_parallel_ep_pair_down(Some("1")).unwrap());
15638        assert!(parse_parallel_ep_pair_down(Some("true")).is_err());
15639    }
15640
15641    #[test]
15642    fn automatic_ep_q8_activation_flag_is_strict() {
15643        assert!(!parse_parallel_ep_q8_act(None).unwrap());
15644        assert!(!parse_parallel_ep_q8_act(Some("0")).unwrap());
15645        assert!(parse_parallel_ep_q8_act(Some("1")).unwrap());
15646        assert!(parse_parallel_ep_q8_act(Some("true")).is_err());
15647    }
15648
15649    #[test]
15650    fn automatic_ep_q8_scope_is_explicit_and_strict() {
15651        assert_eq!(parse_parallel_ep_q8_scope(None).unwrap(), None);
15652        assert_eq!(
15653            parse_parallel_ep_q8_scope(Some("all")).unwrap(),
15654            Some(ParallelEpQ8Scope::All)
15655        );
15656        assert_eq!(
15657            parse_parallel_ep_q8_scope(Some("gate-up")).unwrap(),
15658            Some(ParallelEpQ8Scope::GateUp)
15659        );
15660        assert_eq!(
15661            parse_parallel_ep_q8_scope(Some("down")).unwrap(),
15662            Some(ParallelEpQ8Scope::Down)
15663        );
15664        assert!(parse_parallel_ep_q8_scope(Some("input")).is_err());
15665    }
15666
15667    #[test]
15668    fn w4a16_device_ep_accepts_a_capacity_backed_active_prefix() {
15669        let width = 4096;
15670        assert_eq!(
15671            nvfp4_ep_active_input_values(160 * width, 44, width).unwrap(),
15672            44 * width
15673        );
15674        assert_eq!(
15675            nvfp4_ep_active_input_values(44 * width, 44, width).unwrap(),
15676            44 * width
15677        );
15678        assert!(nvfp4_ep_active_input_values(43 * width, 44, width).is_err());
15679        assert!(
15680            nvfp4_ep_active_input_values(160 * width, NVFP4_EP_DEVICE_BATCH_CAP + 1, width)
15681                .is_err()
15682        );
15683    }
15684
15685    #[test]
15686    fn step_ep_layer_specs_are_literal_and_fail_closed() {
15687        assert!(parse_step_ep_layer_specs(None).unwrap().is_empty());
15688        assert!(parse_step_ep_layer_specs(Some("0")).unwrap().is_empty());
15689        assert_eq!(
15690            parse_step_ep_layer_specs(Some("24@1,2")).unwrap(),
15691            vec![StepEpLayerSpec {
15692                layer: 24,
15693                devices: vec![1, 2],
15694            }]
15695        );
15696        assert_eq!(
15697            parse_step_ep_layer_specs(Some("24-25@1,2;31@0,2")).unwrap(),
15698            vec![
15699                StepEpLayerSpec {
15700                    layer: 24,
15701                    devices: vec![1, 2],
15702                },
15703                StepEpLayerSpec {
15704                    layer: 25,
15705                    devices: vec![1, 2],
15706                },
15707                StepEpLayerSpec {
15708                    layer: 31,
15709                    devices: vec![0, 2],
15710                },
15711            ]
15712        );
15713        assert!(parse_step_ep_layer_specs(Some("24@1")).is_err());
15714        assert!(parse_step_ep_layer_specs(Some("24@1,1")).is_err());
15715        assert!(parse_step_ep_layer_specs(Some("layer@1,2")).is_err());
15716        assert!(parse_step_ep_layer_specs(Some("25-24@1,2")).is_err());
15717        assert!(parse_step_ep_layer_specs(Some("0-128@1,2")).is_err());
15718        assert!(parse_step_ep_layer_specs(Some("24-25@1,2;25@0,2")).is_err());
15719        assert!(parse_step_ep_layer_specs(Some("all@0,1")).is_err());
15720    }
15721
15722    #[test]
15723    fn step_tp_layer_specs_share_the_fail_closed_layer_contract() {
15724        assert!(parse_step_tp_layer_specs(None).unwrap().is_empty());
15725        assert!(parse_step_tp_layer_specs(Some("0")).unwrap().is_empty());
15726        assert_eq!(
15727            parse_step_tp_layer_specs(Some("24-25@1,2")).unwrap(),
15728            vec![
15729                StepTpLayerSpec {
15730                    layer: 24,
15731                    devices: vec![1, 2],
15732                },
15733                StepTpLayerSpec {
15734                    layer: 25,
15735                    devices: vec![1, 2],
15736                },
15737            ]
15738        );
15739        let error = parse_step_tp_layer_specs(Some("24@1")).unwrap_err();
15740        assert!(error.contains("MEMRA_STEP_TP"));
15741        assert!(parse_step_tp_layer_specs(Some("24@1,1")).is_err());
15742        assert!(parse_step_tp_layer_specs(Some("24-25@1,2;25@0,2")).is_err());
15743
15744        let all = parse_step_tp_layer_specs(Some("all@0,1,2,3,4,5,6,7")).unwrap();
15745        assert_eq!(all.len(), STEP37_TRUNK_LAYERS);
15746        assert_eq!(all.first().unwrap().layer, 0);
15747        assert_eq!(all.last().unwrap().layer, STEP37_TRUNK_LAYERS - 1);
15748        let devices = (0..8).collect::<Vec<_>>();
15749        assert!(all.iter().all(|spec| spec.devices == devices));
15750        assert!(parse_step_tp_layer_specs(Some("all@0,1;44@0,1")).is_err());
15751    }
15752}
15753
15754// ===== Whole-token graph builder (increment B) ==================================================
15755//
15756// The decode fns are already sectioned at every e/rank/root seam (the stage flow, sweeps_rank,
15757// finish splits, the dcw arm). `graph_section` is the one annotation those seams call: eager
15758// mode runs the closure verbatim; build mode wraps it in a stream capture on the section's
15759// device and records a child + its dependency edges. A token then assembles as ONE multi-device
15760// parent (children per section per layer), launched once per token — the launch-collapse the
15761// per-layer minis could not reach (routes-mini negative, 2026-08-21).
15762
15763/// One captured section: the child graph plus which parent node it became, and the CUDA
15764/// context it was captured under (exec memset updates need it).
15765struct TokenGraphChild {
15766    #[allow(dead_code)]
15767    // allow: keep-alive: the child graph must outlive the exec instantiated from it
15768    graph: cudarc::driver::CudaGraph,
15769    node: cudarc::driver::sys::CUgraphNode,
15770    ctx: cudarc::driver::sys::CUcontext,
15771}
15772
15773/// Exec-updatable fa geometry discovered in one attention rank child: the three partial-pool
15774/// memsets, the dcw fa kernel, and its combine — everything a bucket change touches. Node
15775/// handles address the parent's CLONED child graphs (the M1-probed update path).
15776struct TokenGraphFaSite {
15777    ctx: cudarc::driver::sys::CUcontext,
15778    memset_o: cudarc::driver::sys::CUgraphNode,
15779    memset_m: [cudarc::driver::sys::CUgraphNode; 2],
15780    fa: cudarc::driver::sys::CUgraphNode,
15781    combine: cudarc::driver::sys::CUgraphNode,
15782    window: usize,
15783    n_head: usize,
15784    n_head_kv: usize,
15785    head_dim: usize,
15786}
15787
15788pub struct TokenGraphBuilder {
15789    parent: cudarc::driver::sys::CUgraph,
15790    children: Vec<TokenGraphChild>,
15791    /// Nodes every NEXT section must depend on (the frontier): one node for serial flow,
15792    /// several while a parallel group is open.
15793    frontier: Vec<cudarc::driver::sys::CUgraphNode>,
15794    /// Detached sections: forked from the frontier at issue time, joined ONLY by the next
15795    /// non-group section (they never gate a parallel group merge — the SH1 shape).
15796    pending_detached: Vec<cudarc::driver::sys::CUgraphNode>,
15797    /// Open parallel group: sections issued under the same group id fork from the SAME
15798    /// predecessor set and merge into the frontier together when the group closes.
15799    group: Option<(
15800        u32,
15801        Vec<cudarc::driver::sys::CUgraphNode>,
15802        Vec<cudarc::driver::sys::CUgraphNode>,
15803    )>,
15804}
15805
15806// SAFETY: single decode thread; graph handles are process handles.
15807unsafe impl Send for TokenGraphBuilder {}
15808
15809impl TokenGraphBuilder {
15810    pub fn new() -> Result<Self, Box<dyn std::error::Error>> {
15811        use cudarc::driver::sys;
15812        let mut parent: sys::CUgraph = std::ptr::null_mut();
15813        let r = unsafe { sys::cuGraphCreate(&mut parent, 0) };
15814        if r != sys::CUresult::CUDA_SUCCESS {
15815            return Err(format!("token graph create: {r:?}").into());
15816        }
15817        Ok(Self {
15818            parent,
15819            children: Vec::new(),
15820            frontier: Vec::new(),
15821            pending_detached: Vec::new(),
15822            group: None,
15823        })
15824    }
15825
15826    fn push_child(
15827        &mut self,
15828        graph: cudarc::driver::CudaGraph,
15829        parallel_group: Option<u32>,
15830        detached: bool,
15831        absorb: bool,
15832        ctx: cudarc::driver::sys::CUcontext,
15833    ) -> Result<(), Box<dyn std::error::Error>> {
15834        use cudarc::driver::sys;
15835        // Resolve the dependency set: serial sections depend on the current frontier; a
15836        // parallel-group section depends on the frontier AS OF the group opening; a
15837        // DETACHED section forks like a group member but joins only the next serial section.
15838        let deps: Vec<sys::CUgraphNode> = match (&mut self.group, parallel_group) {
15839            (Some((open, base, _)), Some(group)) if *open == group => base.clone(),
15840            (state, Some(group)) => {
15841                // opening a new group (closing any previous one first)
15842                if let Some((_, _, members)) = state.take() {
15843                    self.frontier = members;
15844                }
15845                let base = self.frontier.clone();
15846                *state = Some((group, base.clone(), Vec::new()));
15847                base
15848            }
15849            (state, None) if detached => match state.as_ref() {
15850                Some((_, base, _)) => base.clone(),
15851                None => self.frontier.clone(),
15852            },
15853            (state, None) => {
15854                if let Some((_, _, members)) = state.take() {
15855                    self.frontier = members;
15856                }
15857                let mut deps = self.frontier.clone();
15858                if absorb {
15859                    deps.append(&mut self.pending_detached);
15860                }
15861                deps
15862            }
15863        };
15864        let mut node: sys::CUgraphNode = std::ptr::null_mut();
15865        let r = unsafe {
15866            sys::cuGraphAddChildGraphNode(
15867                &mut node,
15868                self.parent,
15869                if deps.is_empty() {
15870                    std::ptr::null()
15871                } else {
15872                    deps.as_ptr()
15873                },
15874                deps.len(),
15875                graph.cu_graph(),
15876            )
15877        };
15878        if r != sys::CUresult::CUDA_SUCCESS {
15879            return Err(format!("token graph child: {r:?}").into());
15880        }
15881        match (&mut self.group, parallel_group, detached) {
15882            (_, None, true) => self.pending_detached.push(node),
15883            (Some((_, _, members)), Some(_), _) => members.push(node),
15884            _ => self.frontier = vec![node],
15885        }
15886        self.children.push(TokenGraphChild { graph, node, ctx });
15887        Ok(())
15888    }
15889
15890    pub fn finish(mut self) -> Result<TokenGraph, Box<dyn std::error::Error>> {
15891        use cudarc::driver::sys;
15892        if let Some((_, _, members)) = self.group.take() {
15893            self.frontier = members;
15894        }
15895        // Discover the fa sites BEFORE instantiate: the parent's cloned child graphs hold
15896        // the node handles the exec update path (M1) addresses.
15897        let mut fa_sites = Vec::new();
15898        for child in &self.children {
15899            if let Some(site) = discover_fa_site(child.node, child.ctx)? {
15900                fa_sites.push(site);
15901            }
15902        }
15903        let mut exec: sys::CUgraphExec = std::ptr::null_mut();
15904        let r = unsafe { sys::cuGraphInstantiateWithFlags(&mut exec, self.parent, 0) };
15905        if r != sys::CUresult::CUDA_SUCCESS {
15906            return Err(format!("token graph instantiate: {r:?}").into());
15907        }
15908        Ok(TokenGraph {
15909            exec,
15910            parent: self.parent,
15911            _children: self.children,
15912            fa_sites,
15913        })
15914    }
15915}
15916
15917/// Walk one child graph; if it carries the attention-section signature (exactly three MEMSET
15918/// nodes chained memset->memset->memset->fa_kernel->combine_kernel), return its update site.
15919fn discover_fa_site(
15920    child_node: cudarc::driver::sys::CUgraphNode,
15921    ctx: cudarc::driver::sys::CUcontext,
15922) -> Result<Option<TokenGraphFaSite>, Box<dyn std::error::Error>> {
15923    use cudarc::driver::sys;
15924    fn cu_try(r: sys::CUresult, what: &str) -> Result<(), Box<dyn std::error::Error>> {
15925        if r == sys::CUresult::CUDA_SUCCESS {
15926            Ok(())
15927        } else {
15928            Err(format!("{what}: {r:?}").into())
15929        }
15930    }
15931    let mut graph: sys::CUgraph = std::ptr::null_mut();
15932    unsafe {
15933        cu_try(
15934            sys::cuGraphChildGraphNodeGetGraph(child_node, &mut graph),
15935            "fa-site child GetGraph",
15936        )?;
15937    }
15938    let mut count: usize = 0;
15939    unsafe {
15940        cu_try(
15941            sys::cuGraphGetNodes(graph, std::ptr::null_mut(), &mut count),
15942            "fa-site GetNodes(count)",
15943        )?;
15944    }
15945    let mut nodes: Vec<sys::CUgraphNode> = vec![std::ptr::null_mut(); count];
15946    unsafe {
15947        cu_try(
15948            sys::cuGraphGetNodes(graph, nodes.as_mut_ptr(), &mut count),
15949            "fa-site GetNodes",
15950        )?;
15951    }
15952    nodes.truncate(count);
15953    let node_type =
15954        |node: sys::CUgraphNode| -> Result<sys::CUgraphNodeType, Box<dyn std::error::Error>> {
15955            let mut ty = sys::CUgraphNodeType::CU_GRAPH_NODE_TYPE_EMPTY;
15956            unsafe {
15957                cu_try(
15958                    sys::cuGraphNodeGetType(node, &mut ty),
15959                    "fa-site NodeGetType",
15960                )?;
15961            }
15962            Ok(ty)
15963        };
15964    let memsets: Vec<sys::CUgraphNode> = {
15965        let mut v = Vec::new();
15966        for &node in &nodes {
15967            if node_type(node)? == sys::CUgraphNodeType::CU_GRAPH_NODE_TYPE_MEMSET {
15968                v.push(node);
15969            }
15970        }
15971        v
15972    };
15973    if memsets.len() != 3 {
15974        return Ok(None);
15975    }
15976    // Single-stream capture makes the chain linear: follow dependent edges from each memset.
15977    let dependents =
15978        |node: sys::CUgraphNode| -> Result<Vec<sys::CUgraphNode>, Box<dyn std::error::Error>> {
15979            let mut n: usize = 0;
15980            unsafe {
15981                cu_try(
15982                    sys::cuGraphNodeGetDependentNodes_v2(
15983                        node,
15984                        std::ptr::null_mut(),
15985                        std::ptr::null_mut(),
15986                        &mut n,
15987                    ),
15988                    "fa-site GetDependentNodes(count)",
15989                )?;
15990            }
15991            let mut v: Vec<sys::CUgraphNode> = vec![std::ptr::null_mut(); n];
15992            unsafe {
15993                cu_try(
15994                    sys::cuGraphNodeGetDependentNodes_v2(
15995                        node,
15996                        v.as_mut_ptr(),
15997                        std::ptr::null_mut(),
15998                        &mut n,
15999                    ),
16000                    "fa-site GetDependentNodes",
16001                )?;
16002            }
16003            v.truncate(n);
16004            Ok(v)
16005        };
16006    // The LAST memset is the one whose direct dependent is a kernel (fa); the other two are
16007    // ordered among themselves but interchangeable for width updates.
16008    let mut fa: Option<sys::CUgraphNode> = None;
16009    let mut last_memset: Option<sys::CUgraphNode> = None;
16010    for &ms in &memsets {
16011        for dep in dependents(ms)? {
16012            if node_type(dep)? == sys::CUgraphNodeType::CU_GRAPH_NODE_TYPE_KERNEL {
16013                fa = Some(dep);
16014                last_memset = Some(ms);
16015            }
16016        }
16017    }
16018    let (Some(fa), Some(_last)) = (fa, last_memset) else {
16019        return Ok(None);
16020    };
16021    let mut combine: Option<sys::CUgraphNode> = None;
16022    for dep in dependents(fa)? {
16023        if node_type(dep)? == sys::CUgraphNodeType::CU_GRAPH_NODE_TYPE_KERNEL {
16024            combine = Some(dep);
16025        }
16026    }
16027    let Some(combine) = combine else {
16028        return Ok(None);
16029    };
16030    // Read the fa launch geometry from its baked args (arg order pinned by fa_decode_dcw):
16031    // 6=hd 7=nh 8=nhkv 11=win 13=nsp 14=ski.
16032    let mut params: sys::CUDA_KERNEL_NODE_PARAMS = unsafe { std::mem::zeroed() };
16033    unsafe {
16034        cu_try(
16035            sys::cuGraphKernelNodeGetParams_v2(fa, &mut params),
16036            "fa-site KernelNodeGetParams",
16037        )?;
16038    }
16039    let arg_i32 =
16040        |slot: usize| -> i32 { unsafe { *(*params.kernelParams.add(slot) as *const i32) } };
16041    let (hd, nh, nhkv, win) = (arg_i32(6), arg_i32(7), arg_i32(8), arg_i32(11));
16042    // Identify the o-partial memset (hd x wider than the m/l pair).
16043    let width_of = |node: sys::CUgraphNode| -> Result<usize, Box<dyn std::error::Error>> {
16044        let mut mp: sys::CUDA_MEMSET_NODE_PARAMS = unsafe { std::mem::zeroed() };
16045        unsafe {
16046            cu_try(
16047                sys::cuGraphMemsetNodeGetParams(node, &mut mp),
16048                "fa-site MemsetNodeGetParams",
16049            )?;
16050        }
16051        Ok(mp.width)
16052    };
16053    let mut widest = memsets[0];
16054    for &ms in &memsets[1..] {
16055        if width_of(ms)? > width_of(widest)? {
16056            widest = ms;
16057        }
16058    }
16059    let memset_m: Vec<sys::CUgraphNode> =
16060        memsets.iter().copied().filter(|&m| m != widest).collect();
16061    Ok(Some(TokenGraphFaSite {
16062        ctx,
16063        memset_o: widest,
16064        memset_m: [memset_m[0], memset_m[1]],
16065        fa,
16066        combine,
16067        window: win as usize,
16068        n_head: nh as usize,
16069        n_head_kv: nhkv as usize,
16070        head_dim: hd as usize,
16071    }))
16072}
16073
16074pub struct TokenGraph {
16075    exec: cudarc::driver::sys::CUgraphExec,
16076    parent: cudarc::driver::sys::CUgraph,
16077    _children: Vec<TokenGraphChild>,
16078    fa_sites: Vec<TokenGraphFaSite>,
16079}
16080
16081unsafe impl Send for TokenGraph {}
16082
16083impl TokenGraph {
16084    /// Retarget every fa site to a new bucket via exec param updates (M1 path) — replaces the
16085    /// per-bucket whole-graph rebuild (~55ms) with ~450 node updates (~1ms). Per site the
16086    /// bucket caps at the layer window; nsp/ski/gridDimY and the partial-pool memset widths
16087    /// move together so the exec always matches what a fresh build at `bucket` would bake.
16088    pub fn retarget_bucket(&mut self, bucket: usize) -> Result<(), Box<dyn std::error::Error>> {
16089        use cudarc::driver::sys;
16090        fn cu_try(r: sys::CUresult, what: &str) -> Result<(), Box<dyn std::error::Error>> {
16091            if r == sys::CUresult::CUDA_SUCCESS {
16092                Ok(())
16093            } else {
16094                Err(format!("{what}: {r:?}").into())
16095            }
16096        }
16097        for site in &self.fa_sites {
16098            let layer_bucket = if site.window > 0 {
16099                bucket.min(site.window)
16100            } else {
16101                bucket
16102            };
16103            let sp = crate::fa_split_keys(layer_bucket, site.n_head_kv);
16104            let nsp = layer_bucket.div_ceil(sp).max(1);
16105            // fa kernel: nsp (slot 13), ski (slot 14), gridDimY = nsp.
16106            let mut params: sys::CUDA_KERNEL_NODE_PARAMS = unsafe { std::mem::zeroed() };
16107            unsafe {
16108                cu_try(
16109                    sys::cuGraphKernelNodeGetParams_v2(site.fa, &mut params),
16110                    "retarget fa GetParams",
16111                )?;
16112                *(*params.kernelParams.add(13) as *mut i32) = nsp as i32;
16113                *(*params.kernelParams.add(14) as *mut i32) = sp as i32;
16114                params.gridDimY = nsp as u32;
16115                cu_try(
16116                    sys::cuGraphExecKernelNodeSetParams_v2(self.exec, site.fa, &params),
16117                    "retarget fa SetParams",
16118                )?;
16119            }
16120            // combine: nsp (slot 6).
16121            let mut cparams: sys::CUDA_KERNEL_NODE_PARAMS = unsafe { std::mem::zeroed() };
16122            unsafe {
16123                cu_try(
16124                    sys::cuGraphKernelNodeGetParams_v2(site.combine, &mut cparams),
16125                    "retarget combine GetParams",
16126                )?;
16127                *(*cparams.kernelParams.add(6) as *mut i32) = nsp as i32;
16128                cu_try(
16129                    sys::cuGraphExecKernelNodeSetParams_v2(self.exec, site.combine, &cparams),
16130                    "retarget combine SetParams",
16131                )?;
16132            }
16133            // partial-pool memsets: o = nh*nsp*hd elements, m/l = nh*nsp.
16134            let set_width =
16135                |node: sys::CUgraphNode, width: usize| -> Result<(), Box<dyn std::error::Error>> {
16136                    let mut mp: sys::CUDA_MEMSET_NODE_PARAMS = unsafe { std::mem::zeroed() };
16137                    unsafe {
16138                        cu_try(
16139                            sys::cuGraphMemsetNodeGetParams(node, &mut mp),
16140                            "retarget memset GetParams",
16141                        )?;
16142                    }
16143                    mp.width = width;
16144                    unsafe {
16145                        cu_try(
16146                            sys::cuGraphExecMemsetNodeSetParams(self.exec, node, &mp, site.ctx),
16147                            "retarget memset SetParams",
16148                        )?;
16149                    }
16150                    Ok(())
16151                };
16152            set_width(site.memset_o, site.n_head * nsp * site.head_dim)?;
16153            set_width(site.memset_m[0], site.n_head * nsp)?;
16154            set_width(site.memset_m[1], site.n_head * nsp)?;
16155        }
16156        Ok(())
16157    }
16158
16159    pub fn launch(&self, e: &Engine) -> Result<(), Box<dyn std::error::Error>> {
16160        use cudarc::driver::sys;
16161        let _main = e.gpu.enter_main()?;
16162        let r = unsafe { sys::cuGraphLaunch(self.exec, e.stream().cu_stream() as sys::CUstream) };
16163        if r != sys::CUresult::CUDA_SUCCESS {
16164            return Err(format!("token graph launch: {r:?}").into());
16165        }
16166        Ok(())
16167    }
16168}
16169
16170impl Drop for TokenGraph {
16171    fn drop(&mut self) {
16172        unsafe {
16173            let _ = cudarc::driver::sys::cuGraphExecDestroy(self.exec);
16174            let _ = cudarc::driver::sys::cuGraphDestroy(self.parent);
16175        }
16176    }
16177}
16178
16179std::thread_local! {
16180    static TOKEN_GRAPH_BUILDER: std::cell::RefCell<Option<TokenGraphBuilder>> =
16181        const { std::cell::RefCell::new(None) };
16182}
16183
16184/// Arm the thread-local builder (build mode) — the next `graph_section` calls capture.
16185pub fn token_graph_build_begin() -> Result<(), Box<dyn std::error::Error>> {
16186    let builder = TokenGraphBuilder::new()?;
16187    TOKEN_GRAPH_BUILDER.with(|cell| *cell.borrow_mut() = Some(builder));
16188    Ok(())
16189}
16190
16191/// Take the finished parent (ends build mode).
16192pub fn token_graph_build_finish() -> Result<TokenGraph, Box<dyn std::error::Error>> {
16193    let builder = TOKEN_GRAPH_BUILDER
16194        .with(|cell| cell.borrow_mut().take())
16195        .ok_or("token graph build was not begun")?;
16196    builder.finish()
16197}
16198
16199/// True while the thread-local builder is armed.
16200pub fn token_graph_building() -> bool {
16201    TOKEN_GRAPH_BUILDER.with(|cell| cell.borrow().is_some())
16202}
16203
16204/// The section annotation: eager mode runs the closure verbatim; build mode wraps it in a
16205/// stream capture on `engine`'s stream and records the child. Sections sharing a
16206/// `parallel_group` id fork from the same predecessor set and merge together. The closure
16207/// must be capture-safe (raw copies at cross-context seams, no host syncs, no events).
16208pub fn graph_section<F>(
16209    engine: &Engine,
16210    parallel_group: Option<u32>,
16211    f: F,
16212) -> Result<(), Box<dyn std::error::Error>>
16213where
16214    F: FnMut() -> Result<(), Box<dyn std::error::Error>>,
16215{
16216    graph_section_opts(engine, parallel_group, false, false, f)
16217}
16218
16219/// Serial section that ALSO joins every pending detached section (the SH1 consumer shape).
16220pub fn graph_section_absorbing<F>(engine: &Engine, f: F) -> Result<(), Box<dyn std::error::Error>>
16221where
16222    F: FnMut() -> Result<(), Box<dyn std::error::Error>>,
16223{
16224    graph_section_opts(engine, None, false, true, f)
16225}
16226
16227/// `graph_section` with the DETACHED shape: forks from the current frontier (or the open
16228/// group base) and is joined only by the next serial section — never gates a group merge.
16229pub fn graph_section_detached<F>(engine: &Engine, f: F) -> Result<(), Box<dyn std::error::Error>>
16230where
16231    F: FnMut() -> Result<(), Box<dyn std::error::Error>>,
16232{
16233    graph_section_opts(engine, None, true, false, f)
16234}
16235
16236pub fn graph_section_opts<F>(
16237    engine: &Engine,
16238    parallel_group: Option<u32>,
16239    detached: bool,
16240    absorb: bool,
16241    f: F,
16242) -> Result<(), Box<dyn std::error::Error>>
16243where
16244    F: FnMut() -> Result<(), Box<dyn std::error::Error>>,
16245{
16246    let building = token_graph_building();
16247    if !building {
16248        let mut f = f;
16249        return f();
16250    }
16251    let (child, ctx) = {
16252        let _main = engine.gpu.enter_main()?;
16253        let mut ctx: cudarc::driver::sys::CUcontext = std::ptr::null_mut();
16254        let r = unsafe { cudarc::driver::sys::cuCtxGetCurrent(&mut ctx) };
16255        if r != cudarc::driver::sys::CUresult::CUDA_SUCCESS {
16256            return Err(format!("graph section ctx query: {r:?}").into());
16257        }
16258        let mut f = f;
16259        // NO WARMUP RUNS: section bodies carry device side effects (dcw appends, counter
16260        // incs) that a warmup would really execute — the len_d-drift crash of 2026-08-21.
16261        let (child, _retained) = engine.capture_graph_retained_nowarm(|_| f())?;
16262        (child, ctx)
16263    };
16264    TOKEN_GRAPH_BUILDER.with(|cell| {
16265        cell.borrow_mut()
16266            .as_mut()
16267            .expect("builder checked above")
16268            .push_child(child, parallel_group, detached, absorb, ctx)
16269    })
16270}