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, DevicePtr, DeviceSlice, LaunchConfig, PushKernelArg};
12use std::ops::Range;
13
14/// Previous gate output per (rank, t), so the determ probe can report the SHAPE of a divergence
15/// (dense-ULP vs sparse-huge) and not merely that a checksum moved. Probe-only state.
16#[allow(clippy::type_complexity)] // allow: one-shot composite type; naming it would hide the shape that matters at the call site
17static DETERM_PREV: std::sync::OnceLock<
18    std::sync::Mutex<std::collections::HashMap<(usize, usize), Vec<f32>>>,
19> = std::sync::OnceLock::new();
20
21const FP8_BLOCK: usize = 128;
22const NATIVE_P2P_PROBE_WORDS: &[usize] = &[4096, 16_384, 262_144, 16_777_216];
23const STEP_GROUPED_FP8_EXPERTS: usize = 288;
24const STEP_GROUPED_FP8_TOP_K: usize = 8;
25const STEP_GROUPED_FP8_WIDTH: usize = 1280;
26
27fn validate_step_expert_activation_limit(limit: Option<f32>) -> Result<(), String> {
28    if let Some(limit) = limit
29        && (!limit.is_finite() || limit <= 0.0)
30    {
31        return Err(format!(
32            "Step routed-expert activation limit must be positive and finite, got {limit}"
33        ));
34    }
35    Ok(())
36}
37
38/// Host-canonical Step routed-expert SwiGLU operation.
39///
40/// Step's final routed layers clamp the linear arm symmetrically and the SiLU arm only above.
41/// Keeping this scalar order explicit also defines the device-host-exact CUDA gate.
42/// Raw stream-ordered device copy for capture-safe cross-context seams (cudarc's slice-use
43/// tracking creates capture-illegal dependencies there). Pointers must be pre-cached with
44/// their owners' streams; bytes flow identically to the tracked copy.
45/// MEMRA_OPROJ_DIRECT=1 (o-proj direct join, default OFF until gated): peer ranks write
46/// their fused O partial OVER P2P into a root-resident buffer (UVA kernel stores), and the
47/// model engine adds the two partials itself — the root stream leaves the join entirely
48/// (no peer pull copy, no root add, no second event hop, no final 16KB ownership copy).
49/// Reduction order and kernel programs are unchanged, so the row is BIT-IDENTICAL.
50/// MEMRA_MOE_DIRECT=1 (moe direct join, default OFF until gated): the o-proj direct-join
51/// recipe on the expert combine — peer ranks' accumulators live root-side (the axpy twin
52/// register-accumulates and stores ONCE, so the P2P cost is a single 16KB store pass), and
53/// the model engine adds the two shard rows itself. Operand order matches root's add:
54/// BIT-IDENTICAL.
55/// MEMRA_ROUTES_PRESTAGE=1 (default OFF until gated): stage the shared layer input to
56/// every rank and quantize it BEFORE the router runs — neither depends on the selection,
57/// so the rank streams' pull+quantize overlaps dev0's router gemv+topk instead of chaining
58/// behind it (the router->quantize and axpy->add gap edges). Same copies, same quantize
59/// kernel, same operands: BIT-IDENTICAL.
60pub(crate) fn routes_prestage_on() -> bool {
61    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
62    *ON.get_or_init(|| std::env::var("MEMRA_ROUTES_PRESTAGE").as_deref() == Ok("1"))
63}
64
65/// MEMRA_FENCE_MEMOPS=1 (default OFF until gated): the moe direct join's two event
66/// fences become cuStreamWriteValue32/cuStreamWaitValue32 doorbells — hardware stream
67/// memops with lower signal->wake latency than cross-device cuStreamWaitEvent. Ordering:
68/// PCIe posted writes from one device arrive in order, so rank1's accumulator stores are
69/// visible before its flag write lands; e's GEQ wait then covers them. Falls back to
70/// events when the device rejects stream memops. Scheduling-only: BIT-IDENTICAL values.
71/// MEMRA_LEN_MIRROR_LAZY=1 (default OFF until gated): skip redundant per-layer 4B len
72/// htods — the local device mirror is unread in TP decode, and under FUSE_ROPE_APPEND the
73/// fused append's atomicInc owns the rank counters. Every one of those tiny copies is a
74/// compute->copy engine turnaround in the middle of the layer stream.
75/// MEMRA_RANK0_MERGE=1 (default OFF until gated): same-device rank0 rides e's stream via
76/// the runtime redirect — see decode_step_h.
77/// MEMRA_OPROJ_TAIL=1 (default OFF until gated): the o-proj direct-join add is DEFERRED —
78/// the finish arm keeps its waits, stores the two partial pointers here, and the residual
79/// add_rms_norm consumer composes mixed = a0+a1 in-register (join_add_rms_norm, verbatim
80/// program: BIT-IDENTICAL). The returned `mixed` buffer is UNWRITTEN in this mode; its
81/// only live consumer is the residual_norm_ffn seam, which takes the handoff.
82pub(crate) fn oproj_tail_on() -> bool {
83    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
84    *ON.get_or_init(|| std::env::var("MEMRA_OPROJ_TAIL").as_deref() == Ok("1"))
85}
86thread_local! {
87    static OPROJ_TAIL_PENDING: std::cell::Cell<Option<(u64, u64)>> =
88        const { std::cell::Cell::new(None) };
89}
90thread_local! {
91    /// The deferral is legal ONLY under callers whose walk flows into
92    /// residual_norm_ffn (decode_step_h / decode_step_chain arm this) — the verify
93    /// prefill reaches the same finish and would consume unwritten `mixed` otherwise
94    /// (M2-MISMATCH receipt: prefill argmax corrupted while decode stayed exact).
95    static OPROJ_TAIL_ELIGIBLE: std::cell::Cell<bool> = const { std::cell::Cell::new(false) };
96}
97/// RAII eligibility scope for the o-proj tail deferral.
98pub(crate) struct OprojTailScope(());
99pub(crate) fn oproj_tail_scope() -> OprojTailScope {
100    OPROJ_TAIL_ELIGIBLE.with(|c| c.set(true));
101    OprojTailScope(())
102}
103impl Drop for OprojTailScope {
104    fn drop(&mut self) {
105        OPROJ_TAIL_ELIGIBLE.with(|c| c.set(false));
106        // A leftover un-consumed handoff must never leak across calls.
107        OPROJ_TAIL_PENDING.with(|c| c.set(None));
108    }
109}
110thread_local! {
111    /// T-COLUMN verify select: the verify driver sets the column before each per-column
112    /// attention call; decode_v2_input_qkv takes it (once) and selects from the slabs.
113    static VERIFY_TCOL: std::cell::Cell<Option<usize>> = const { std::cell::Cell::new(None) };
114}
115pub(crate) fn set_verify_tcol(c: Option<usize>) {
116    VERIFY_TCOL.with(|x| x.set(c));
117}
118pub(crate) fn take_verify_tcol() -> Option<usize> {
119    VERIFY_TCOL.with(|x| x.take())
120}
121
122/// MEMRA_TCOL_OPROJ=1 (spec verify): defer each column's o_proj out of the per-column
123/// walk — the finish seam stashes the column's `gated` rows instead of running the
124/// per-column finish choreography (rank events, P2P join, engine handoff), and one
125/// weight-amortized b4_tcol per rank + one elementwise join produce every column's
126/// `mixed` afterwards. Bit-exact per column: the tcol kernel is the t=1 b4 program per
127/// column, and the slab join adds the same operand values elementwise.
128pub(crate) fn tcol_oproj_on() -> bool {
129    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
130    *ON.get_or_init(|| std::env::var("MEMRA_TCOL_OPROJ").as_deref() == Ok("1"))
131}
132thread_local! {
133    /// The verify driver arms the column before each per-column attention call; the
134    /// finish seam takes it (once). Stashed=true reports the defer actually happened
135    /// (the seam falls back to the normal finish when the config is ineligible).
136    static TCOL_OPROJ_DEFER: std::cell::Cell<Option<usize>> = const { std::cell::Cell::new(None) };
137    static TCOL_OPROJ_STASHED: std::cell::Cell<bool> = const { std::cell::Cell::new(false) };
138}
139pub(crate) fn set_tcol_oproj_defer(c: Option<usize>) {
140    TCOL_OPROJ_DEFER.with(|x| x.set(c));
141}
142pub(crate) fn take_tcol_oproj_defer() -> Option<usize> {
143    TCOL_OPROJ_DEFER.with(|x| x.take())
144}
145pub(crate) fn set_tcol_oproj_stashed() {
146    TCOL_OPROJ_STASHED.with(|x| x.set(true));
147}
148pub(crate) fn take_tcol_oproj_stashed() -> bool {
149    TCOL_OPROJ_STASHED.with(|x| x.replace(false))
150}
151
152pub(crate) fn oproj_tail_eligible() -> bool {
153    OPROJ_TAIL_ELIGIBLE.with(|c| c.get())
154}
155pub(crate) fn take_oproj_tail() -> Option<(u64, u64)> {
156    OPROJ_TAIL_PENDING.with(|c| c.take())
157}
158pub(crate) fn set_oproj_tail(v: (u64, u64)) {
159    OPROJ_TAIL_PENDING.with(|c| c.set(Some(v)));
160}
161
162pub(crate) fn rank0_merge_on() -> bool {
163    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
164    *ON.get_or_init(|| std::env::var("MEMRA_RANK0_MERGE").as_deref() == Ok("1"))
165}
166
167pub(crate) fn len_mirror_lazy_on() -> bool {
168    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
169    *ON.get_or_init(|| std::env::var("MEMRA_LEN_MIRROR_LAZY").as_deref() == Ok("1"))
170}
171
172pub(crate) fn fence_memops_on() -> bool {
173    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
174    *ON.get_or_init(|| std::env::var("MEMRA_FENCE_MEMOPS").as_deref() == Ok("1"))
175}
176
177pub(crate) fn moe_direct_on() -> bool {
178    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
179    *ON.get_or_init(|| std::env::var("MEMRA_MOE_DIRECT").as_deref() == Ok("1"))
180}
181
182/// MEMRA_SEL_MIRROR=1: the per-rank routed-selection pull runs as ONE `moe_sel_w_mirror`
183/// launch instead of two 32-byte D2D copies, and when every consuming rank shares e's device
184/// the intermediate e-context staging pair is skipped entirely (the caller's sel/route_w rows
185/// are process-persistent, so the ranks read them directly). Bit-identical: same bytes, one
186/// fewer hop. Refused under the graph door, whose captured copies need the fixed staging
187/// addresses. Default OFF until receipted.
188/// MEMRA_FENCE_RANK1=1: the peer rank rings a doorbell in ROOT memory with a kernel store
189/// (`memra_ring_flag`) and the model engine waits it with a SAME-DEVICE stream memop, instead
190/// of waiting a cross-device event. Completes the half the memops receipt left open (peer
191/// memops are rejected; peer kernel stores are the direct-join mechanism). Ordering only —
192/// values are untouched. Requires MEMRA_FENCE_MEMOPS=1 (it owns the flag allocation).
193pub(crate) fn fence_rank1_on() -> bool {
194    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
195    *ON.get_or_init(|| std::env::var("MEMRA_FENCE_RANK1").as_deref() == Ok("1"))
196}
197
198/// MEMRA_SPEC_FA2=1 (the DSpark verify lesson): the T=2 verify walk defers each column's
199/// ATTENTION CORE — the dcw arm appends the column's K/V and stashes its post-rope q and
200/// gate rows, then ONE fa_decode_dcw2 per rank walks the KV stream once for both columns
201/// (per-row causal bounds; bit-identical per row under the equal-partition guard), the
202/// per-row combine writes both gated rows, and the o_proj join runs on the TCOL slabs.
203/// ROW-TABLE RESTAGE (`MEMRA_ROWS_TAB_RESTAGE`, DEFAULT ON since this lane).
204///
205/// ON: `decode_v2_rope_fa_rows` builds the 6-word-per-row pointer table from the caller's
206/// freshly-read live cache pointers and stages it into a persistent per-rank slab before
207/// every launch. OFF (`=0`): the retired process-lifetime `rows_tabs` memo, keyed by a hash
208/// of (k pointer, base pointer, layer, t) that could not see the V or LEN pointers the
209/// entry also carried, and that nothing invalidated when a session's KV cache was dropped.
210///
211/// Default ON because the OFF arm is a proven use-after-free, not a slower correct path:
212/// on step37-flash with MEMRA_FUSE_ROPE_APPEND=1 it made speculative decoding unservable
213/// (whole non-finite verify rows, then CUDA_ERROR_ILLEGAL_ADDRESS). ON is value-neutral on
214/// every fresh lookup by construction: identical bytes reach the same kernels. Rollback
215/// seam: `MEMRA_ROWS_TAB_RESTAGE=0`.
216/// The 6-word-per-row launch table `{k, v, len, base, ctr, back}` the fused rope/append/fa
217/// kernels dereference. Pure so it can be tested: the words come from the caller's live
218/// per-row `[k, v, len, base]` pointers, `ctr` is this rank's counter slab (one shared cell
219/// for same-session rows, one cell per row otherwise) and `back` is the same-session causal
220/// step-back `t-1-r` (0 across sessions, where each row owns its own len).
221pub(crate) fn rows_tab_host(
222    parts_rank: &[[u64; 4]],
223    ctr_base: u64,
224    same_session: bool,
225    t: usize,
226) -> Vec<u64> {
227    let mut host = Vec::with_capacity(t * 6);
228    for (r, parts) in parts_rank.iter().enumerate().take(t) {
229        host.extend_from_slice(&[
230            parts[0],
231            parts[1],
232            parts[2],
233            parts[3],
234            if same_session {
235                ctr_base
236            } else {
237                ctr_base + (r as u64) * 4
238            },
239            if same_session {
240                (t - 1 - r) as u64
241            } else {
242                0u64
243            },
244        ]);
245    }
246    host
247}
248
249/// The RETIRED memo key, kept ONLY so a test can assert what it cannot see. Both historical
250/// call sites hashed a SUBSET of the pointers the table carries; this reproduces the verify
251/// site's formula verbatim.
252#[cfg(test)]
253pub(crate) fn retired_rows_tab_key(kp: u64, bp: u64, il: usize, t: usize) -> u64 {
254    kp.rotate_left(17)
255        .wrapping_add(bp)
256        .wrapping_add((il as u64) << 32)
257        .wrapping_add(t as u64)
258        .wrapping_add(1 << 63)
259}
260
261pub(crate) fn rows_tab_restage_on() -> bool {
262    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
263    *ON.get_or_init(|| std::env::var("MEMRA_ROWS_TAB_RESTAGE").as_deref() != Ok("0"))
264}
265
266/// STALE-HIT RECEIPT (`MEMRA_ROWS_TAB_STALE_SCAN`, DEFAULT OFF, diagnostic only).
267///
268/// Keeps a HOST shadow of the last table staged under each retired memo key and prints one
269/// line whenever the key repeats with different contents, naming the words that moved. It
270/// costs a host hash lookup and a small clone per rank per layer per verify round, so it is
271/// off in serving. `[rows-tab] engaged=` on the counter proves the path executes at all,
272/// which is what separates "the memo was innocent" from "the memo never ran".
273/// Rollback seam: unset it (or `=0`).
274pub(crate) fn rows_tab_stale_scan() -> bool {
275    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
276    *ON.get_or_init(|| std::env::var("MEMRA_ROWS_TAB_STALE_SCAN").as_deref() == Ok("1"))
277}
278
279pub(crate) static ROWS_TAB_ENGAGED: std::sync::atomic::AtomicU64 =
280    std::sync::atomic::AtomicU64::new(0);
281pub(crate) static ROWS_TAB_STALE: std::sync::atomic::AtomicU64 =
282    std::sync::atomic::AtomicU64::new(0);
283
284pub(crate) fn spec_fa2_on() -> bool {
285    static ENV: std::sync::OnceLock<Option<bool>> = std::sync::OnceLock::new();
286    crate::step37_door(&ENV, "MEMRA_SPEC_FA2")
287}
288thread_local! {
289    /// The verify driver arms the column before each per-column attention call; the dcw
290    /// arm takes it (once) and stashes q/gate instead of running fa+finish.
291    static SPEC_FA2_DEFER: std::cell::Cell<Option<usize>> = const { std::cell::Cell::new(None) };
292    static SPEC_FA2_STASHED: std::cell::Cell<bool> = const { std::cell::Cell::new(false) };
293}
294pub(crate) fn set_spec_fa2_defer(c: Option<usize>) {
295    SPEC_FA2_DEFER.with(|x| x.set(c));
296}
297pub(crate) fn take_spec_fa2_defer() -> Option<usize> {
298    SPEC_FA2_DEFER.with(|x| x.take())
299}
300pub(crate) fn set_spec_fa2_stashed() {
301    SPEC_FA2_STASHED.with(|x| x.set(true));
302}
303pub(crate) fn take_spec_fa2_stashed() -> bool {
304    SPEC_FA2_STASHED.with(|x| x.replace(false))
305}
306
307pub(crate) fn sel_mirror_on() -> bool {
308    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
309    *ON.get_or_init(|| std::env::var("MEMRA_SEL_MIRROR").as_deref() == Ok("1"))
310}
311
312/// MEMRA_STEP_NVFP4_EP2=1: whole-expert (expert-parallel) NVFP4 banks at 2 ranks — expert e
313/// lives ENTIRE on rank (e & 1) at bank slot (e >> 1), replacing the TP column/row shards
314/// (same total VRAM; both sets cannot coexist). Decode rides owner-guarded full-width
315/// sweeps with per-rank slot-ordered partial sums; the cross-rank join is unchanged.
316/// NUMERIC-CLASS door (the slot chain regroups per rank): run-gen argmax gate + battery +
317/// fresh tape, the DEV_ROUTES acceptance class.
318pub(crate) fn step_nvfp4_ep2_on() -> bool {
319    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
320    *ON.get_or_init(|| std::env::var("MEMRA_STEP_NVFP4_EP2").as_deref() == Ok("1"))
321}
322
323pub(crate) fn oproj_direct_on() -> bool {
324    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
325    *ON.get_or_init(|| std::env::var("MEMRA_OPROJ_DIRECT").as_deref() == Ok("1"))
326}
327
328// ─── Slot-major NVFP4 expert-bank programs: THREE independent doors ───────────────────────────
329//
330// These restore, under separate flags, the three programs that the 2026-08-29 removal
331// (`fd0a175ab`) deleted behind ONE env var (`MEMRA_NVFP4_BANK_V2`). That coupling is why the
332// incident's bisect could not name a mechanism: toggling one var moved the bank layout, the
333// gate+up fusion (which auto-armed on the same predicate with no door of its own) and the fused
334// down+combine (which hard-refused without the layout) all at once, so the priced -21.5% wall /
335// -23.7% decode (research/perf-chain-20260831 cell 1) was an unattributable bundle.
336//
337// The corruption they were removed for was NOT any of them: it was a defaulted `in_f = 0`
338// argument at two `kq_fetch` call sites in the PREFILL grouped-GEMM tail
339// (research/step37-bankv3-20260901/DIAGNOSIS.md), fixed compiler-enforced at `1b18a61e8` and
340// gated device-side by the `nvfp4-bank-oracle` bin. Each door below is strict `0`/`1` and
341// admitted separately so its contribution is a number; BANK_SM and SEL_DOWN8 default ON since
342// 2026-09-01 (one coupled decision, PR #76 battery), SEL_GU and the sub-doors default OFF.
343//
344// LAYOUT IS A PROPERTY OF THE BANK. `bank_slot_major_on()` is read ONCE, at bank BUILD, and
345// recorded on the resident bank (`ResidentNvfp4{Column,Row}BankRank::slot_major`). Every reader
346// branches on that stored field, never on the env door. The removed implementation read
347// `nvfp4_bank_v2_on()` at each reader site instead, which is the same class of hole as the
348// defaulted `in_f`: a piece of layout geometry that a caller can fail to supply or can supply
349// inconsistently with the bytes actually resident.
350
351/// Read a DEFAULT-ON door strictly, and report the SOURCE of the answer rather than only the
352/// answer. `0` disables (the rollback seam), `1` re-states the default, unset takes the default.
353///
354/// Two properties this buys, both learned the hard way in this lane's own archaeology:
355///
356/// * **A typo cannot silently disarm a rollback seam.** The default-OFF doors here parse as
357///   `== Ok("1")`, which is safe when the default is OFF (a typo reads as the default) and
358///   DANGEROUS when the default is ON: `MEMRA_NVFP4_BANK_SM=false` under a `!= Ok("0")` rule
359///   would keep the program armed while the operator believed it was rolled back. So an
360///   unrecognized value is reported as such and the default is kept, loudly.
361/// * **The engagement receipt can name the source.** `default-on` and `MEMRA_..=1` are
362///   different facts about the same boot: one says the flip is doing the work, the other says
363///   a recipe is. A pricing or post-deploy receipt that cannot tell them apart cannot prove a
364///   DEFAULT was measured (TRAP:corrupt-arm-inflates-its-own-perf-price's sibling: an arm that
365///   cannot name what armed it is not an arm).
366fn door_default_on(name: &'static str) -> (bool, &'static str) {
367    let raw = std::env::var(name).ok();
368    door_default_on_value(name, raw.as_deref())
369}
370
371/// The parse, separated from the environment so it can be TESTED. `std::env` is process-global
372/// state and these doors are `OnceLock`-cached, so an env-var test would be both racy under
373/// `cargo test`'s thread pool and unrepeatable within one process — i.e. exactly the kind of
374/// gate that passes because it never really ran.
375fn door_default_on_value(name: &str, value: Option<&str>) -> (bool, &'static str) {
376    match value {
377        Some("0") => (false, "env=0 (rollback seam)"),
378        Some("1") => (true, "env=1"),
379        None => (true, "default-on"),
380        Some(_) => {
381            eprintln!(
382                "[nvfp4-door] WARN {name} has an unrecognized value; only `0` and `1` are \
383                 accepted and the DEFAULT-ON answer is kept. To roll back, set {name}=0."
384            );
385            (true, "default-on (unrecognized value ignored)")
386        }
387    }
388}
389
390/// MEMRA_NVFP4_BANK_SM (PROGRAM 1, **default ON since 2026-09-01**): build the step TP
391/// contiguous NVFP4 expert banks (gate/up/down) in the SLOT-MAJOR row layout — slot g's 16 qs
392/// bytes contiguous at `g*16` (one coalesced 512B warp wave) and the two UE4M3 scale bytes at
393/// `nslots*16 + g*2` — and dispatch the `_sel_v2` decode readers over them. Pure byte
394/// permutation, so BIT-IDENTICAL per row; the claim is gated by `nvfp4-bank-oracle`
395/// (device-side, prefill GEMM included) and by end-to-end greedy byte identity, never by a
396/// comment.
397///
398/// **WHY A BIT-IDENTICAL, MEASURABLY-FREE PROGRAM DEFAULTS ON.** On its own this layout earns
399/// nothing: x5 interleaved, 105.35 vs 106.78 decode tok/s, per-boot range `[104.66, 107.95]`
400/// overlapping the OFF arm's `[105.11, 107.09]`. It defaults ON for exactly one reason —
401/// `MEMRA_NVFP4_SEL_DOWN8` (PROGRAM 3), the one program that DOES separate (+5.48% decode), is
402/// gated at its call site on `shard.slot_major`, so with this door off PROGRAM 3's default-ON
403/// is a SILENT NO-OP: `down8=false door=true`, no refusal, no warning, and the win simply does
404/// not happen. The deployable unit is the two together, which makes this one coupled default
405/// decision and not two independent ones. Receipts:
406/// `research/step37-bankv3-20260901/RESULTS.md` (the down8 default-ON qualification battery).
407///
408/// ROLLBACK SEAM: `MEMRA_NVFP4_BANK_SM=0`, which also disarms PROGRAM 3 by construction.
409pub(crate) fn bank_slot_major_on() -> bool {
410    bank_slot_major_source().0
411}
412
413/// `bank_slot_major_on()` plus the SOURCE of the answer, for the engagement receipt.
414pub(crate) fn bank_slot_major_source() -> (bool, &'static str) {
415    static ON: std::sync::OnceLock<(bool, &'static str)> = std::sync::OnceLock::new();
416    *ON.get_or_init(|| door_default_on("MEMRA_NVFP4_BANK_SM"))
417}
418
419/// MEMRA_NVFP4_SEL_GU=1 (PROGRAM 2, default OFF): run the routed gate and up sweeps as ONE
420/// launch (`qmatvec_nvfp4_dp4a_sel_v2_gu`) instead of two — the two sweeps share sel/aq/ad and
421/// have identical geometry, so blocks `[0,out_f)` take the gate bank and `[out_f,2*out_f)` the
422/// up bank. Per-row bit-identical; halves the sweep launch count and doubles grid fill.
423/// Subordinate to PROGRAM 1 by construction: it reads slot-major rows, so the caller arms it
424/// only when both banks report `slot_major`. In the removed implementation this fusion had NO
425/// door of its own and auto-armed on the bank predicate, which is one third of why the bundle
426/// was unattributable.
427pub(crate) fn sel_gu_fused_on() -> bool {
428    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
429    *ON.get_or_init(|| std::env::var("MEMRA_NVFP4_SEL_GU").as_deref() == Ok("1"))
430}
431
432/// MEMRA_NVFP4_SEL_DOWN8 (PROGRAM 3, default ON since 2026-09-01; `=0` is the rollback seam): fuse the routed DOWN sweep with the
433/// route-weight combine into one launch (`qmatvec_nvfp4_dp4a_sel_v2_down8`, the q8 `down8 w8`
434/// occupancy arm ported to the NVFP4 banks) — one warp per routed slot instead of one warp per
435/// (row, slot), and the `n_sel x out_f` partial-buffer round trip disappears. Bit-identical
436/// (same dot program, same reduce tree, same slot-ordered combine chain). Also subordinate to
437/// PROGRAM 1: the caller arms it only when the down shard reports `slot_major`, and only on the
438/// device-routed arm at `nsb <= 32` (the fit-block class the reduce identity is argued at).
439/// Rides LAST per the lane mandate: it is priced only on green gates for the layers beneath it.
440///
441/// **DEFAULT ON since 2026-09-01**, and it is the reason PROGRAM 1 defaults ON too. This is the
442/// only one of the three restored programs that separates from noise: +5.48% decode / +5.09%
443/// wall, x5 interleaved vendor-default sampled, per-boot range `[112.59, 114.82]` with NO
444/// overlap against either the OFF arm or the arm directly beneath it, re-qualified at deploy
445/// grade in `research/step37-bankv3-20260901/RESULTS.md`.
446///
447/// ELIGIBILITY IS NARROWER THAN THE DEFAULT, and the engagement receipt below prints every
448/// condition: the arm needs `device_routed`, `shard.slot_major` (i.e. PROGRAM 1) and
449/// `nsb <= 32`. On any other geometry or route the default is INERT, which is correct-by-
450/// refusal and NOT a regression — but it does mean "default ON" and "engaged" are two facts,
451/// and only the `[nvfp4-sweep]` line settles the second.
452///
453/// ROLLBACK SEAM: `MEMRA_NVFP4_SEL_DOWN8=0` (or `MEMRA_NVFP4_BANK_SM=0`, which disarms it by
454/// construction).
455pub(crate) fn sel_down8_on() -> bool {
456    sel_down8_source().0
457}
458
459/// `sel_down8_on()` plus the SOURCE of the answer, for the engagement receipt.
460pub(crate) fn sel_down8_source() -> (bool, &'static str) {
461    static ON: std::sync::OnceLock<(bool, &'static str)> = std::sync::OnceLock::new();
462    *ON.get_or_init(|| door_default_on("MEMRA_NVFP4_SEL_DOWN8"))
463}
464
465pub(crate) fn raw_copy_bytes(
466    dst: u64,
467    src: u64,
468    bytes: usize,
469    engine: &Engine,
470) -> Result<(), Box<dyn std::error::Error>> {
471    use cudarc::driver::sys;
472    let r = unsafe {
473        sys::cuMemcpyAsync(
474            dst as sys::CUdeviceptr,
475            src as sys::CUdeviceptr,
476            bytes,
477            engine.stream().cu_stream() as sys::CUstream,
478        )
479    };
480    if r == sys::CUresult::CUDA_SUCCESS {
481        Ok(())
482    } else {
483        // MEMRA_RAW_COPY_TRACE=1: a raw D2D failure carries no call site by itself, and
484        // every slab-width bug in the t-row family surfaces here. Operands + backtrace.
485        if std::env::var("MEMRA_RAW_COPY_TRACE").as_deref() == Ok("1") {
486            eprintln!(
487                "[raw-copy-fail] dst={dst:#x} src={src:#x} bytes={bytes} {r:?}\n{}",
488                std::backtrace::Backtrace::force_capture()
489            );
490        }
491        Err(format!("raw_copy_bytes: {r:?} bytes={bytes} dst={dst:#x} src={src:#x}").into())
492    }
493}
494
495pub fn step_expert_activation_host(gate: f32, up: f32, limit: Option<f32>) -> f32 {
496    let silu = gate / (1.0 + (-gate).exp());
497    match limit {
498        Some(limit) => silu.min(limit) * up.clamp(-limit, limit),
499        None => silu * up,
500    }
501}
502
503#[derive(Debug, Clone, PartialEq, Eq)]
504struct ExpertOwnerRoutes {
505    rank: usize,
506    selected: Vec<usize>,
507    token_rows: Vec<usize>,
508    global_pairs: Vec<usize>,
509}
510
511#[allow(clippy::manual_is_multiple_of)] // allow: divisor is runtime-derived; the modulo form keeps a zero divisor loud (a panic), where is_multiple_of would return false silently
512fn partition_expert_owner_routes(
513    expert_count: usize,
514    ranks: usize,
515    tokens: usize,
516    experts_per_token: usize,
517    selected: &[usize],
518) -> Result<Vec<ExpertOwnerRoutes>, String> {
519    if expert_count == 0
520        || ranks == 0
521        || tokens == 0
522        || experts_per_token == 0
523        || expert_count % ranks != 0
524    {
525        return Err(format!(
526            "invalid expert-owner route geometry experts={expert_count} ranks={ranks} \
527             tokens={tokens} experts_per_token={experts_per_token}"
528        ));
529    }
530    let pairs = tokens
531        .checked_mul(experts_per_token)
532        .ok_or("expert-owner route count overflow")?;
533    if selected.len() != pairs {
534        return Err(format!(
535            "expert-owner routes {} != {tokens}x{experts_per_token} ({pairs})",
536            selected.len()
537        ));
538    }
539    let per_rank = expert_count / ranks;
540    let mut owners = (0..ranks)
541        .map(|rank| ExpertOwnerRoutes {
542            rank,
543            selected: Vec::new(),
544            token_rows: Vec::new(),
545            global_pairs: Vec::new(),
546        })
547        .collect::<Vec<_>>();
548    for (pair, &expert) in selected.iter().enumerate() {
549        if expert >= expert_count {
550            return Err(format!(
551                "expert-owner route {pair} selects expert {expert} outside 0..{expert_count}"
552            ));
553        }
554        let rank = expert / per_rank;
555        owners[rank].selected.push(expert - rank * per_rank);
556        owners[rank].token_rows.push(pair / experts_per_token);
557        owners[rank].global_pairs.push(pair);
558    }
559    Ok(owners)
560}
561
562fn validate_step_grouped_owner_routes(
563    expert_count: usize,
564    tokens: usize,
565    selected: &[usize],
566) -> Result<usize, String> {
567    if expert_count != STEP_GROUPED_FP8_EXPERTS || tokens == 0 {
568        return Err(format!(
569            "official Step owner-grouped FP8 requires {} experts and nonzero tokens, got \
570             experts={expert_count} tokens={tokens}",
571            STEP_GROUPED_FP8_EXPERTS
572        ));
573    }
574    let pairs = tokens
575        .checked_mul(STEP_GROUPED_FP8_TOP_K)
576        .ok_or("official Step owner-grouped FP8 route count overflow")?;
577    if selected.len() != pairs {
578        return Err(format!(
579            "official Step owner-grouped FP8 routes {} != {tokens}x{} ({pairs})",
580            selected.len(),
581            STEP_GROUPED_FP8_TOP_K,
582        ));
583    }
584    for (token, routes) in selected.chunks_exact(STEP_GROUPED_FP8_TOP_K).enumerate() {
585        let mut unique = routes.to_vec();
586        unique.sort_unstable();
587        unique.dedup();
588        if unique.len() != STEP_GROUPED_FP8_TOP_K {
589            return Err(format!(
590                "official Step owner-grouped FP8 token {token} routes are not top-8 unique: \
591                 {routes:?}"
592            ));
593        }
594    }
595    Ok(pairs)
596}
597
598#[derive(Debug, Clone, Copy, PartialEq, Eq)]
599struct WeightedRouteCombineShape {
600    pairs: usize,
601    max_pairs: usize,
602}
603
604fn validate_weighted_route_combine(
605    width: usize,
606    experts_per_token: usize,
607    max_tokens: usize,
608    tokens: usize,
609    owner_global_pairs: &[&[usize]],
610    route_weights: &[f32],
611) -> Result<WeightedRouteCombineShape, String> {
612    if width == 0
613        || experts_per_token == 0
614        || max_tokens == 0
615        || tokens == 0
616        || tokens > max_tokens
617        || width > i32::MAX as usize
618        || experts_per_token > i32::MAX as usize
619        || tokens > i32::MAX as usize
620    {
621        return Err(format!(
622            "invalid weighted route combine geometry width={width} experts_per_token=\
623             {experts_per_token} tokens={tokens}/{max_tokens}"
624        ));
625    }
626    let pairs = tokens
627        .checked_mul(experts_per_token)
628        .ok_or("weighted route combine pair count overflow")?;
629    let max_pairs = max_tokens
630        .checked_mul(experts_per_token)
631        .ok_or("weighted route combine capacity overflow")?;
632    if route_weights.len() != pairs || !route_weights.iter().all(|weight| weight.is_finite()) {
633        return Err(format!(
634            "weighted route combine weights {} != pairs {pairs} or contain a non-finite value",
635            route_weights.len()
636        ));
637    }
638    let mut seen = vec![false; pairs];
639    let mut observed = 0usize;
640    for pairs_for_owner in owner_global_pairs {
641        observed = observed
642            .checked_add(pairs_for_owner.len())
643            .ok_or("weighted route combine observed pair count overflow")?;
644        for &pair in *pairs_for_owner {
645            if pair >= pairs || std::mem::replace(&mut seen[pair], true) {
646                return Err(format!(
647                    "weighted route combine pair {pair} is outside 0..{pairs} or duplicated"
648                ));
649            }
650        }
651    }
652    if observed != pairs || seen.iter().any(|present| !present) {
653        return Err(format!(
654            "weighted route combine owner schedules cover {observed} of {pairs} canonical pairs"
655        ));
656    }
657    Ok(WeightedRouteCombineShape { pairs, max_pairs })
658}
659
660fn cache_rank_rows(
661    rows: &[u8],
662    tokens: usize,
663    local_token_bytes: usize,
664    ranks: usize,
665    rank: usize,
666) -> Result<Vec<u8>, String> {
667    if ranks == 0 || rank >= ranks {
668        return Err(format!(
669            "TP cache rank {rank} is outside a {ranks}-rank layout"
670        ));
671    }
672    let global_token_bytes = local_token_bytes
673        .checked_mul(ranks)
674        .ok_or("TP cache global token-byte overflow")?;
675    let expected = tokens
676        .checked_mul(global_token_bytes)
677        .ok_or("TP cache row-byte overflow")?;
678    if rows.len() != expected {
679        return Err(format!(
680            "TP cache rows contain {} bytes, expected {tokens}x{global_token_bytes}={expected}",
681            rows.len()
682        ));
683    }
684    let mut shard = Vec::with_capacity(tokens * local_token_bytes);
685    for token in 0..tokens {
686        let start = token * global_token_bytes + rank * local_token_bytes;
687        shard.extend_from_slice(&rows[start..start + local_token_bytes]);
688    }
689    Ok(shard)
690}
691
692fn parse_step_tp_native_p2p(value: Option<&str>) -> Result<bool, String> {
693    match value {
694        None | Some("") | Some("0") => Ok(false),
695        Some("1") => Ok(true),
696        Some(value) => Err(format!(
697            "MEMRA_STEP_TP_NATIVE_P2P={value:?} is invalid; expected 0 or 1"
698        )),
699    }
700}
701
702pub fn step_tp_native_p2p_enabled() -> Result<bool, String> {
703    parse_step_tp_native_p2p(std::env::var("MEMRA_STEP_TP_NATIVE_P2P").ok().as_deref())
704}
705
706fn parse_step_tp_bulk_p2p(value: Option<&str>) -> Result<bool, String> {
707    match value {
708        None | Some("") | Some("0") => Ok(false),
709        Some("1") => Ok(true),
710        Some(value) => Err(format!(
711            "MEMRA_STEP_TP_BULK_P2P={value:?} is invalid; expected 0 or 1"
712        )),
713    }
714}
715
716pub fn step_tp_bulk_p2p_enabled() -> Result<bool, String> {
717    parse_step_tp_bulk_p2p(std::env::var("MEMRA_STEP_TP_BULK_P2P").ok().as_deref())
718}
719
720fn parse_step_ep_device_arithmetic(value: Option<&str>) -> Result<bool, String> {
721    match value {
722        None | Some("") | Some("0") => Ok(false),
723        Some("1") => Ok(true),
724        Some(value) => Err(format!(
725            "MEMRA_STEP_EP_DEVICE_ARITHMETIC={value:?} is invalid; expected 0 or 1"
726        )),
727    }
728}
729
730fn parse_step_nvfp4_dev_routes(value: Option<&str>) -> Result<bool, String> {
731    match value {
732        None | Some("") | Some("0") => Ok(false),
733        Some("1") => Ok(true),
734        Some(value) => Err(format!(
735            "MEMRA_STEP_NVFP4_DEV_ROUTES={value:?} is invalid; expected 0 or 1"
736        )),
737    }
738}
739
740/// Opt-in door for the device-resident NVFP4 TP routed-expert decode program. Default OFF; the
741/// host-canonical program remains the oracle until the device path carries its own gates.
742pub fn step_nvfp4_dev_routes_enabled() -> Result<bool, String> {
743    parse_step_nvfp4_dev_routes(std::env::var("MEMRA_STEP_NVFP4_DEV_ROUTES").ok().as_deref())
744}
745
746pub fn step_ep_device_arithmetic_enabled() -> Result<bool, String> {
747    parse_step_ep_device_arithmetic(
748        std::env::var("MEMRA_STEP_EP_DEVICE_ARITHMETIC")
749            .ok()
750            .as_deref(),
751    )
752}
753
754fn parse_step_tp_f32_mirror(value: Option<&str>) -> Result<bool, String> {
755    match value {
756        None | Some("") | Some("0") => Ok(false),
757        Some("1") => Ok(true),
758        Some(value) => Err(format!(
759            "MEMRA_STEP_TP_F32_MIRROR={value:?} is invalid; expected 0 or 1"
760        )),
761    }
762}
763
764pub fn step_tp_f32_mirror_enabled() -> Result<bool, String> {
765    parse_step_tp_f32_mirror(std::env::var("MEMRA_STEP_TP_F32_MIRROR").ok().as_deref())
766}
767
768fn parse_step_tp_decode_v2(value: Option<&str>) -> Result<bool, String> {
769    match value {
770        None | Some("") | Some("0") => Ok(false),
771        Some("1") => Ok(true),
772        Some(value) => Err(format!(
773            "MEMRA_STEP_TP_DECODE_V2={value:?} is invalid; expected 0 or 1"
774        )),
775    }
776}
777
778/// The v2 rank-local Step decode-attention driver: persistent workspaces, evented cross-stream
779/// ordering, and a root-device O reduction — same kernels, values, and canonical reduction order
780/// as the v1 driver (it requires the F32 mirror so no per-call weight expansion exists on either
781/// side of the comparison).
782pub fn step_tp_decode_v2_enabled() -> Result<bool, String> {
783    parse_step_tp_decode_v2(std::env::var("MEMRA_STEP_TP_DECODE_V2").ok().as_deref())
784}
785
786fn parse_step_tp_qkv_fused(value: Option<&str>) -> Result<bool, String> {
787    match value {
788        None | Some("") | Some("0") => Ok(false),
789        Some("1") => Ok(true),
790        Some(value) => Err(format!(
791            "MEMRA_STEP_TP_QKV_FUSED={value:?} is invalid; expected 0 or 1"
792        )),
793    }
794}
795
796fn parse_step_tp_dev_router(value: Option<&str>) -> Result<bool, String> {
797    match value {
798        None | Some("") | Some("0") => Ok(false),
799        Some("1") => Ok(true),
800        Some(value) => Err(format!(
801            "MEMRA_STEP_TP_DEV_ROUTER={value:?} is invalid; expected 0 or 1"
802        )),
803    }
804}
805
806/// Device-side sigmoid top-k routing for the TP device-IO expert program: the per-layer host
807/// logits readback (the last per-layer host sync) disappears. Selection tie-breaking may
808/// differ from the host router — NUMERIC-CLASS door, run-gen argmax gate + boot battery.
809pub fn step_tp_dev_router_enabled() -> Result<bool, String> {
810    parse_step_tp_dev_router(std::env::var("MEMRA_STEP_TP_DEV_ROUTER").ok().as_deref())
811}
812
813fn parse_step_tp_graph(value: Option<&str>) -> Result<bool, String> {
814    match value {
815        None | Some("") | Some("0") => Ok(false),
816        Some("1") => Ok(true),
817        Some(value) => Err(format!(
818            "MEMRA_STEP_TP_GRAPH={value:?} is invalid; expected 0 or 1"
819        )),
820    }
821}
822
823fn parse_step_tp_dcw(value: Option<&str>) -> Result<bool, String> {
824    match value {
825        None | Some("") | Some("0") => Ok(false),
826        Some("1") => Ok(true),
827        Some(value) => Err(format!(
828            "MEMRA_STEP_TP_DCW={value:?} is invalid; expected 0 or 1"
829        )),
830    }
831}
832
833/// Device-counter attention path (graph increment A run EAGERLY): append at len_d - base_d,
834/// inc_i32, fa over the counter-derived window — with bucket = the effective t_kv this is
835/// bit-identical to the host-row + kvmod path (the one-partition law), and it is the exact
836/// child content the capture wraps. Rebase tokens and sub-vec-floor contexts fall back.
837pub fn step_tp_dcw_enabled() -> Result<bool, String> {
838    parse_step_tp_dcw(std::env::var("MEMRA_STEP_TP_DCW").ok().as_deref())
839}
840
841/// CUDA-graph door for the shape-stable TP segments (first increment: the device-routed
842/// expert program — per-layer multi-device parents built from per-rank children, launched on
843/// the model engine's stream; zero per-token node updates). Mechanism proven by
844/// tp_graph_probe. VALUE-IDENTICAL: the graphs replay exactly the eager kernel/copy sequence.
845pub fn step_tp_graph_enabled() -> Result<bool, String> {
846    parse_step_tp_graph(std::env::var("MEMRA_STEP_TP_GRAPH").ok().as_deref())
847}
848
849/// GRAPH-LAUNCH HEADROOM GUARD for the routed-prejoin graph door (see
850/// `spec::GRAPH_LAUNCH_MIN_FREE`): checked on the launching engine only when the door
851/// is armed (short-circuit after `step_tp_graph_enabled`), noting once per process with
852/// the sweep's grep-stable `graph replay suspended:` key.
853fn step_tp_graph_headroom_ok(e: &Engine) -> bool {
854    let ok = crate::spec::graph_launch_headroom_ok(e);
855    if !ok {
856        static NOTED: std::sync::Once = std::sync::Once::new();
857        NOTED.call_once(|| crate::spec::graph_replay_suspended_note("step-tp-routes"));
858    }
859    ok
860}
861
862/// Fused single-launch QKV projection inside the v2 decode driver — a NUMERIC-CLASS door
863/// (per-row deterministic tree reduce instead of the chunked cuBLASLt program), default OFF,
864/// gated by the run-gen argmax gate + boot battery like MEMRA_STEP_NVFP4_DEV_ROUTES.
865pub fn step_tp_qkv_fused_enabled() -> Result<bool, String> {
866    parse_step_tp_qkv_fused(std::env::var("MEMRA_STEP_TP_QKV_FUSED").ok().as_deref())
867}
868
869#[derive(Debug, Clone, PartialEq, Eq)]
870pub struct StepEpLayerSpec {
871    pub layer: usize,
872    pub devices: Vec<usize>,
873}
874
875pub type StepTpLayerSpec = StepEpLayerSpec;
876
877/// ModelPlan-driven whole-model parallel policy. `auto` removes per-layer family recipes; the
878/// loader derives its scope from dense/MoE operations and selects a registered numeric backend
879/// from the artifact tensor/activation contract.
880fn parse_auto_parallel_devices(
881    mode: Option<&str>,
882    raw_devices: Option<&str>,
883) -> Result<Option<Vec<usize>>, String> {
884    let mode = match mode {
885        None | Some("") | Some("0") | Some("off") => return Ok(None),
886        Some("auto") => "auto",
887        Some(value) => {
888            return Err(format!(
889                "MEMRA_PARALLEL={value:?} is invalid; expected off or auto"
890            ));
891        }
892    };
893    let raw = raw_devices.ok_or_else(|| {
894        format!("{mode} parallel placement requires MEMRA_PARALLEL_DEVICES=DEVICE,DEVICE[...]")
895    })?;
896    let devices =
897        raw.split(',')
898            .map(|device| {
899                device.trim().parse::<usize>().map_err(|_| {
900                    format!("MEMRA_PARALLEL_DEVICES entry {device:?} is not an integer")
901                })
902            })
903            .collect::<Result<Vec<_>, _>>()?;
904    if !(2..=crate::parallel::AUTO_PARALLEL_MAX_CARDS).contains(&devices.len()) {
905        return Err(format!(
906            "MEMRA_PARALLEL=auto requires 2..={} devices, got {}",
907            crate::parallel::AUTO_PARALLEL_MAX_CARDS,
908            devices.len()
909        ));
910    }
911    let mut unique = devices.clone();
912    unique.sort_unstable();
913    unique.dedup();
914    if unique.len() != devices.len() {
915        return Err(format!(
916            "MEMRA_PARALLEL_DEVICES must be distinct, got {devices:?}"
917        ));
918    }
919    Ok(Some(devices))
920}
921
922pub fn auto_parallel_devices() -> Result<Option<Vec<usize>>, String> {
923    parse_auto_parallel_devices(
924        std::env::var("MEMRA_PARALLEL").ok().as_deref(),
925        std::env::var("MEMRA_PARALLEL_DEVICES").ok().as_deref(),
926    )
927}
928
929fn parse_parallel_ep_device_router(value: Option<&str>) -> Result<bool, String> {
930    match value {
931        None | Some("") | Some("0") => Ok(false),
932        Some("1") => Ok(true),
933        Some(value) => Err(format!(
934            "MEMRA_PARALLEL_EP_DEVICE_ROUTER={value:?} is invalid; expected 0 or 1"
935        )),
936    }
937}
938
939pub fn parallel_ep_device_router_enabled() -> Result<bool, String> {
940    parse_parallel_ep_device_router(
941        std::env::var("MEMRA_PARALLEL_EP_DEVICE_ROUTER")
942            .ok()
943            .as_deref(),
944    )
945}
946
947fn parse_parallel_ep_graph(value: Option<&str>) -> Result<bool, String> {
948    match value {
949        None | Some("") | Some("0") => Ok(false),
950        Some("1") => Ok(true),
951        Some(value) => Err(format!(
952            "MEMRA_PARALLEL_EP_GRAPH={value:?} is invalid; expected 0 or 1"
953        )),
954    }
955}
956
957pub fn parallel_ep_graph_enabled() -> Result<bool, String> {
958    parse_parallel_ep_graph(std::env::var("MEMRA_PARALLEL_EP_GRAPH").ok().as_deref())
959}
960
961fn parse_parallel_ep_pair_down(value: Option<&str>) -> Result<bool, String> {
962    match value {
963        None | Some("") | Some("0") => Ok(false),
964        Some("1") => Ok(true),
965        Some(value) => Err(format!(
966            "MEMRA_PARALLEL_EP_PAIR_DOWN={value:?} is invalid; expected 0 or 1"
967        )),
968    }
969}
970
971pub fn parallel_ep_pair_down_enabled() -> Result<bool, String> {
972    parse_parallel_ep_pair_down(std::env::var("MEMRA_PARALLEL_EP_PAIR_DOWN").ok().as_deref())
973}
974
975fn parse_parallel_ep_q8_act(value: Option<&str>) -> Result<bool, String> {
976    match value {
977        None | Some("") | Some("0") => Ok(false),
978        Some("1") => Ok(true),
979        Some(value) => Err(format!(
980            "MEMRA_PARALLEL_EP_Q8_ACT={value:?} is invalid; expected 0 or 1"
981        )),
982    }
983}
984
985pub fn parallel_ep_q8_act_enabled() -> Result<bool, String> {
986    parse_parallel_ep_q8_act(std::env::var("MEMRA_PARALLEL_EP_Q8_ACT").ok().as_deref())
987}
988
989#[derive(Clone, Copy, Debug, PartialEq, Eq)]
990pub(crate) enum ParallelEpQ8Scope {
991    All,
992    GateUp,
993    Down,
994}
995
996impl ParallelEpQ8Scope {
997    fn label(self) -> &'static str {
998        match self {
999            Self::All => "all",
1000            Self::GateUp => "gate-up",
1001            Self::Down => "down",
1002        }
1003    }
1004}
1005
1006fn parse_parallel_ep_q8_scope(value: Option<&str>) -> Result<Option<ParallelEpQ8Scope>, String> {
1007    match value {
1008        None | Some("") => Ok(None),
1009        Some("all") => Ok(Some(ParallelEpQ8Scope::All)),
1010        Some("gate-up") => Ok(Some(ParallelEpQ8Scope::GateUp)),
1011        Some("down") => Ok(Some(ParallelEpQ8Scope::Down)),
1012        Some(value) => Err(format!(
1013            "MEMRA_PARALLEL_EP_Q8_SCOPE={value:?} is invalid; expected all, gate-up, or down"
1014        )),
1015    }
1016}
1017
1018pub(crate) fn parallel_ep_q8_scope() -> Result<Option<ParallelEpQ8Scope>, String> {
1019    parse_parallel_ep_q8_scope(std::env::var("MEMRA_PARALLEL_EP_Q8_SCOPE").ok().as_deref())
1020}
1021
1022fn parse_parallel_ep_q8_gu_paired(value: Option<&str>) -> Result<Option<bool>, String> {
1023    match value {
1024        None | Some("") => Ok(None),
1025        Some("0") => Ok(Some(false)),
1026        Some("1") => Ok(Some(true)),
1027        Some(value) => Err(format!(
1028            "MEMRA_PARALLEL_EP_Q8_GU_PAIRED={value:?} is invalid; expected 0 or 1"
1029        )),
1030    }
1031}
1032
1033fn resolve_parallel_ep_q8_gu_paired(
1034    value: Option<&str>,
1035    q8_active: bool,
1036    scope: Option<ParallelEpQ8Scope>,
1037) -> Result<bool, String> {
1038    let configured = parse_parallel_ep_q8_gu_paired(value)?;
1039    if configured == Some(true) && !q8_active {
1040        return Err("MEMRA_PARALLEL_EP_Q8_GU_PAIRED=1 requires MEMRA_PARALLEL_EP_Q8_ACT=1".into());
1041    }
1042    if configured == Some(true) && scope == Some(ParallelEpQ8Scope::Down) {
1043        return Err(
1044            "MEMRA_PARALLEL_EP_Q8_GU_PAIRED=1 requires Q8 gate/up arithmetic; \
1045             MEMRA_PARALLEL_EP_Q8_SCOPE=down keeps gate/up BF16"
1046                .into(),
1047        );
1048    }
1049    Ok(q8_active && scope != Some(ParallelEpQ8Scope::Down) && configured.unwrap_or(true))
1050}
1051
1052pub(crate) fn parallel_ep_q8_gu_paired_enabled(
1053    q8_active: bool,
1054    scope: Option<ParallelEpQ8Scope>,
1055) -> Result<bool, String> {
1056    resolve_parallel_ep_q8_gu_paired(
1057        std::env::var("MEMRA_PARALLEL_EP_Q8_GU_PAIRED")
1058            .ok()
1059            .as_deref(),
1060        q8_active,
1061        scope,
1062    )
1063}
1064
1065fn parse_step_layer_specs(
1066    flag: &str,
1067    value: Option<&str>,
1068    allow_full_model: bool,
1069) -> Result<Vec<StepEpLayerSpec>, String> {
1070    let trunk = allow_full_model.then_some(STEP37_TRUNK_LAYERS);
1071    parse_layer_specs_for_trunk(flag, value, trunk)
1072}
1073
1074/// The pure composition-refusal law behind every parallel door's UNPROVEN-pair matrix
1075/// (hoisted from the glm5 TP door, lane/glm5-extract-general): the first armed flag in
1076/// `table` refuses by name, BEFORE any parallel CUDA state exists. Each family owns its
1077/// own TABLE of `(flag, why)` rows — the reasons are gate receipts, part of the law; a
1078/// pair unlocks only with its own composition gate (the primary flag's FLAGS.md row
1079/// carries the matrix). `armed` reports whether a flag is set to `"1"` (env in
1080/// production; a plain set in unit tests — the pattern keeps tests env-mutation-free).
1081pub(crate) fn refuse_door_composition(
1082    primary: &str,
1083    table: &[(&str, &str)],
1084    armed: impl Fn(&str) -> bool,
1085) -> Result<(), String> {
1086    for (flag, why) in table {
1087        if armed(flag) {
1088            return Err(format!(
1089                "{primary} + {flag}: unproven composition, refused ({why})"
1090            ));
1091        }
1092    }
1093    Ok(())
1094}
1095
1096/// The shared `LAYER[-LAYER]@DEVICE,DEVICE[;...]` grammar behind every per-layer parallel
1097/// door. `full_model_trunk` enables the `all` shorthand and names the trunk it expands to —
1098/// the caller's model contract owns that constant, never this parser (the step door passes
1099/// `STEP37_TRUNK_LAYERS`; the glm5 door passes its own trunk length at load time).
1100pub(crate) fn parse_layer_specs_for_trunk(
1101    flag: &str,
1102    value: Option<&str>,
1103    full_model_trunk: Option<usize>,
1104) -> Result<Vec<StepEpLayerSpec>, String> {
1105    let Some(value) = value else {
1106        return Ok(Vec::new());
1107    };
1108    if value.is_empty() || value == "0" {
1109        return Ok(Vec::new());
1110    }
1111
1112    let mut specs = Vec::new();
1113    for item in value.split(';') {
1114        let (layers, devices) = item.split_once('@').ok_or_else(|| {
1115            let layers = if full_model_trunk.is_some() {
1116                "LAYER[-LAYER] or all"
1117            } else {
1118                "LAYER[-LAYER]"
1119            };
1120            format!("{flag} must be {layers}@DEVICE,DEVICE[;...]")
1121        })?;
1122        let (first, last) = if layers == "all" {
1123            let Some(trunk) = full_model_trunk else {
1124                return Err(format!(
1125                    "{flag} does not support the full-model shorthand; assign routed layers \
1126                     explicitly"
1127                ));
1128            };
1129            (0, trunk - 1)
1130        } else {
1131            match layers.split_once('-') {
1132                Some((first, last)) => {
1133                    let first = first
1134                        .parse::<usize>()
1135                        .map_err(|_| format!("{flag} layer {first:?} is not an integer"))?;
1136                    let last = last
1137                        .parse::<usize>()
1138                        .map_err(|_| format!("{flag} layer {last:?} is not an integer"))?;
1139                    if first > last {
1140                        return Err(format!("{flag} layer range {first}-{last} is reversed"));
1141                    }
1142                    if last - first + 1 > 128 {
1143                        return Err(format!(
1144                            "{flag} layer range {first}-{last} exceeds the 128-layer parser cap"
1145                        ));
1146                    }
1147                    (first, last)
1148                }
1149                None => {
1150                    let layer = layers
1151                        .parse::<usize>()
1152                        .map_err(|_| format!("{flag} layer {layers:?} is not an integer"))?;
1153                    (layer, layer)
1154                }
1155            }
1156        };
1157        let devices = devices
1158            .split(',')
1159            .map(|device| {
1160                device
1161                    .parse::<usize>()
1162                    .map_err(|_| format!("{flag} device {device:?} is not an integer"))
1163            })
1164            .collect::<Result<Vec<_>, _>>()?;
1165        if !(2..=8).contains(&devices.len()) {
1166            return Err(format!(
1167                "{flag} requires 2..=8 devices, got {}",
1168                devices.len()
1169            ));
1170        }
1171        let mut unique = devices.clone();
1172        unique.sort_unstable();
1173        unique.dedup();
1174        if unique.len() != devices.len() {
1175            return Err(format!("{flag} devices must be distinct, got {devices:?}"));
1176        }
1177        for layer in first..=last {
1178            if specs
1179                .iter()
1180                .any(|existing: &StepEpLayerSpec| existing.layer == layer)
1181            {
1182                return Err(format!("{flag} assigns layer {layer} more than once"));
1183            }
1184            specs.push(StepEpLayerSpec {
1185                layer,
1186                devices: devices.clone(),
1187            });
1188        }
1189    }
1190    Ok(specs)
1191}
1192
1193pub fn parse_step_ep_layer_specs(value: Option<&str>) -> Result<Vec<StepEpLayerSpec>, String> {
1194    parse_step_layer_specs("MEMRA_STEP_EP", value, false)
1195}
1196
1197pub fn step_ep_layer_specs() -> Result<Vec<StepEpLayerSpec>, String> {
1198    parse_step_ep_layer_specs(std::env::var("MEMRA_STEP_EP").ok().as_deref())
1199}
1200
1201pub fn parse_step_tp_layer_specs(value: Option<&str>) -> Result<Vec<StepTpLayerSpec>, String> {
1202    parse_step_layer_specs("MEMRA_STEP_TP", value, true)
1203}
1204
1205pub fn step_tp_layer_specs() -> Result<Vec<StepTpLayerSpec>, String> {
1206    parse_step_tp_layer_specs(std::env::var("MEMRA_STEP_TP").ok().as_deref())
1207}
1208
1209#[derive(Clone, Copy)]
1210pub struct E4m3BlockMatrix<'a> {
1211    pub codes: &'a [u8],
1212    pub scales: &'a [f32],
1213    pub out_features: usize,
1214    pub in_features: usize,
1215}
1216
1217impl E4m3BlockMatrix<'_> {
1218    fn validate(&self) -> Result<(), String> {
1219        let code_count = self
1220            .out_features
1221            .checked_mul(self.in_features)
1222            .ok_or_else(|| "E4M3 matrix size overflow".to_string())?;
1223        if self.codes.len() != code_count {
1224            return Err(format!(
1225                "E4M3 code count {} != {}x{} ({code_count})",
1226                self.codes.len(),
1227                self.out_features,
1228                self.in_features,
1229            ));
1230        }
1231        let scale_count =
1232            self.out_features.div_ceil(FP8_BLOCK) * self.in_features.div_ceil(FP8_BLOCK);
1233        if self.scales.len() != scale_count {
1234            return Err(format!(
1235                "E4M3 scale count {} != {scale_count} for {}x{}",
1236                self.scales.len(),
1237                self.out_features,
1238                self.in_features,
1239            ));
1240        }
1241        if !self
1242            .scales
1243            .iter()
1244            .all(|scale| scale.is_finite() && *scale > 0.0)
1245        {
1246            return Err("E4M3 scale grid contains a non-finite or non-positive value".to_string());
1247        }
1248        Ok(())
1249    }
1250}
1251
1252#[derive(Clone, Copy)]
1253pub struct E4m3ExpertBank<'a> {
1254    pub codes: &'a [u8],
1255    pub scales: &'a [f32],
1256    pub expert_count: usize,
1257    pub out_features: usize,
1258    pub in_features: usize,
1259}
1260
1261impl E4m3ExpertBank<'_> {
1262    fn validate(&self) -> Result<(), String> {
1263        if self.expert_count == 0 {
1264            return Err("E4M3 expert bank is empty".to_string());
1265        }
1266        let code_stride = self
1267            .out_features
1268            .checked_mul(self.in_features)
1269            .ok_or_else(|| "E4M3 expert code stride overflow".to_string())?;
1270        let code_count = self
1271            .expert_count
1272            .checked_mul(code_stride)
1273            .ok_or_else(|| "E4M3 expert code count overflow".to_string())?;
1274        if self.codes.len() != code_count {
1275            return Err(format!(
1276                "E4M3 expert code count {} != {}x{} ({code_count})",
1277                self.codes.len(),
1278                self.expert_count,
1279                code_stride,
1280            ));
1281        }
1282        let scale_stride =
1283            self.out_features.div_ceil(FP8_BLOCK) * self.in_features.div_ceil(FP8_BLOCK);
1284        let scale_count = self
1285            .expert_count
1286            .checked_mul(scale_stride)
1287            .ok_or_else(|| "E4M3 expert scale count overflow".to_string())?;
1288        if self.scales.len() != scale_count {
1289            return Err(format!(
1290                "E4M3 expert scale count {} != {}x{} ({scale_count})",
1291                self.scales.len(),
1292                self.expert_count,
1293                scale_stride,
1294            ));
1295        }
1296        if !self
1297            .scales
1298            .iter()
1299            .all(|scale| scale.is_finite() && *scale > 0.0)
1300        {
1301            return Err(
1302                "E4M3 expert scale grid contains a non-finite or non-positive value".to_string(),
1303            );
1304        }
1305        Ok(())
1306    }
1307
1308    pub fn expert(&self, expert: usize) -> Result<E4m3BlockMatrix<'_>, String> {
1309        if expert >= self.expert_count {
1310            return Err(format!("expert {expert} outside 0..{}", self.expert_count));
1311        }
1312        let code_stride = self.out_features * self.in_features;
1313        let scale_stride =
1314            self.out_features.div_ceil(FP8_BLOCK) * self.in_features.div_ceil(FP8_BLOCK);
1315        Ok(E4m3BlockMatrix {
1316            codes: &self.codes[expert * code_stride..(expert + 1) * code_stride],
1317            scales: &self.scales[expert * scale_stride..(expert + 1) * scale_stride],
1318            out_features: self.out_features,
1319            in_features: self.in_features,
1320        })
1321    }
1322}
1323
1324pub struct ColumnParallelResult {
1325    pub gathered: Vec<f32>,
1326    pub rank_outputs: Vec<Vec<f32>>,
1327}
1328
1329pub struct RowParallelResult {
1330    pub reduced: Vec<f32>,
1331    pub rank_partials: Vec<Vec<f32>>,
1332}
1333
1334#[derive(Clone, Copy)]
1335pub struct Bf16Matrix<'a> {
1336    pub bytes: &'a [u8],
1337    pub out_features: usize,
1338    pub in_features: usize,
1339}
1340
1341impl Bf16Matrix<'_> {
1342    pub fn validate(&self) -> Result<(), String> {
1343        if self.out_features == 0 || self.in_features == 0 {
1344            return Err("BF16 matrix dimensions must be nonzero".into());
1345        }
1346        let expected = self
1347            .out_features
1348            .checked_mul(self.in_features)
1349            .and_then(|values| values.checked_mul(2))
1350            .ok_or("BF16 matrix byte count overflow")?;
1351        if self.bytes.len() != expected {
1352            return Err(format!(
1353                "BF16 matrix bytes {} != {}x{}x2 ({expected})",
1354                self.bytes.len(),
1355                self.out_features,
1356                self.in_features,
1357            ));
1358        }
1359        Ok(())
1360    }
1361}
1362
1363struct ResidentE4m3Rank {
1364    codes: CudaSlice<u8>,
1365    scales: CudaSlice<f32>,
1366    out_features: usize,
1367    in_features: usize,
1368}
1369
1370enum ResidentBf16Weight {
1371    Bf16(CudaSlice<u8>),
1372    F32(CudaSlice<f32>),
1373}
1374
1375impl ResidentBf16Weight {
1376    fn ordinal(&self) -> usize {
1377        match self {
1378            Self::Bf16(bytes) => bytes.ordinal(),
1379            Self::F32(values) => values.ordinal(),
1380        }
1381    }
1382}
1383
1384struct ResidentBf16Rank {
1385    weight: ResidentBf16Weight,
1386    out_features: usize,
1387    in_features: usize,
1388    /// q8_0 mirror built at load under MEMRA_STEP_TP_W8 (numeric-class door; the bf16 slab
1389    /// stays resident because every prefill/verify path is qualified against it).
1390    q8: Option<CudaSlice<u8>>,
1391}
1392
1393pub struct ResidentColumnParallel {
1394    ranks: Vec<ResidentE4m3Rank>,
1395    out_features: usize,
1396    in_features: usize,
1397}
1398
1399pub struct ResidentRowParallel {
1400    ranks: Vec<ResidentE4m3Rank>,
1401    out_features: usize,
1402    in_features: usize,
1403}
1404
1405pub struct ResidentBf16ColumnParallel {
1406    ranks: Vec<ResidentBf16Rank>,
1407    out_features: usize,
1408    in_features: usize,
1409    canonical_chunk_rows: Option<usize>,
1410}
1411
1412pub struct ResidentBf16RowParallel {
1413    ranks: Vec<ResidentBf16Rank>,
1414    out_features: usize,
1415    in_features: usize,
1416}
1417
1418pub struct ResidentStepBf16RowParallel {
1419    ranks: Vec<Vec<ResidentBf16Rank>>,
1420    out_features: usize,
1421    in_features: usize,
1422    canonical_chunk_cols: usize,
1423}
1424
1425/// Root-owned BF16 sigmoid router with persistent F32 weight, bias, and active mask.
1426pub struct ResidentSigmoidTopKRouter {
1427    weight: CudaSlice<f32>,
1428    correction_bias: CudaSlice<f32>,
1429    active: CudaSlice<u8>,
1430    root_device: usize,
1431    input_width: usize,
1432    expert_count: usize,
1433    experts_per_token: usize,
1434    active_count: usize,
1435    scaling_factor: f32,
1436    route_norm: bool,
1437}
1438
1439pub struct SigmoidTopKHostOutput {
1440    pub logits: Vec<f32>,
1441    pub selected: Vec<u32>,
1442    pub weights: Vec<f32>,
1443}
1444
1445/// Full BF16 SwiGLU weights replicated independently on every runtime rank.
1446pub struct ResidentReplicatedBf16SwiGlu {
1447    gate: Vec<ResidentBf16Rank>,
1448    up: Vec<ResidentBf16Rank>,
1449    down: Vec<ResidentBf16Rank>,
1450    input_width: usize,
1451    intermediate_width: usize,
1452}
1453
1454/// One token-major F32 batch replicated across a native-P2P rank group.
1455///
1456/// Every allocation is owned by its matching rank CUDA context. This is the generic handoff
1457/// substrate between independently sharded operators; it carries no model or topology claim.
1458pub struct ResidentReplicatedDeviceRows {
1459    ranks: Vec<CudaSlice<f32>>,
1460    tokens: usize,
1461    width: usize,
1462}
1463
1464impl ResidentReplicatedDeviceRows {
1465    pub fn tokens(&self) -> usize {
1466        self.tokens
1467    }
1468
1469    pub fn width(&self) -> usize {
1470        self.width
1471    }
1472
1473    pub fn ranks(&self) -> usize {
1474        self.ranks.len()
1475    }
1476}
1477
1478/// Canonical MoE output order: routed plus shared, then add the layer residual.
1479pub fn moe_residual_host(
1480    residual: &[f32],
1481    routed: &[f32],
1482    shared: &[f32],
1483) -> Result<Vec<f32>, String> {
1484    if residual.len() != routed.len() || residual.len() != shared.len() {
1485        return Err(format!(
1486            "MoE residual lengths residual={} routed={} shared={}",
1487            residual.len(),
1488            routed.len(),
1489            shared.len()
1490        ));
1491    }
1492    let ffn = routed
1493        .iter()
1494        .zip(shared)
1495        .map(|(&routed, &shared)| routed + shared)
1496        .collect::<Vec<_>>();
1497    Ok(residual
1498        .iter()
1499        .zip(ffn)
1500        .map(|(&residual, ffn)| residual + ffn)
1501        .collect())
1502}
1503
1504pub use memra_kv::{
1505    KvRingAppend, ResidentTpKvCache, ResidentTpKvCacheRank, TpKvAppendPlan, TpKvTransaction,
1506};
1507
1508/// Persistent TP2/TP4/TP8 routed-expert reference.
1509///
1510/// Rank-local checkpoint shards are uploaded once and remain tied to their owning CUDA context.
1511/// Activations and deterministic host-staged collectives remain per invocation. This is the
1512/// correctness substrate for serving TP/EP, not product-throughput evidence.
1513pub struct ResidentTpExpert {
1514    gate: ResidentColumnParallel,
1515    up: ResidentColumnParallel,
1516    down: ResidentRowParallel,
1517    input_width: usize,
1518    expert_width: usize,
1519}
1520
1521struct ResidentE4m3ExpertBankRank {
1522    codes: CudaSlice<u8>,
1523    scales: CudaSlice<f32>,
1524    expert_range: Range<usize>,
1525    out_features: usize,
1526    in_features: usize,
1527    code_stride: usize,
1528    scale_stride: usize,
1529    /// TP row banks are packed by native 128-wide K block so reduction can replay the
1530    /// checkpoint's global block order exactly. Other banks remain row-major.
1531    k_blocks: Option<usize>,
1532}
1533
1534struct PackedE4m3ExpertBankRank {
1535    codes: Vec<u8>,
1536    scales: Vec<f32>,
1537    expert_range: Range<usize>,
1538    out_features: usize,
1539    in_features: usize,
1540    code_stride: usize,
1541    scale_stride: usize,
1542    k_blocks: Option<usize>,
1543}
1544
1545struct ResidentEpRank {
1546    gate: ResidentE4m3ExpertBankRank,
1547    up: ResidentE4m3ExpertBankRank,
1548    down: ResidentE4m3ExpertBankRank,
1549}
1550
1551/// Persistent expert-parallel reference.
1552///
1553/// Every routed expert has exactly one owner rank. Shared experts are deliberately absent from
1554/// this object because Step replicates them per rank. Routes execute on the owner CUDA context.
1555/// The default oracle stages through host memory; the native path peer-dispatches inputs and
1556/// peer-returns owner outputs while preserving host-canonical activation and accumulation.
1557pub struct ResidentExpertParallel {
1558    ranks: Vec<ResidentEpRank>,
1559    expert_count: usize,
1560    input_width: usize,
1561    expert_width: usize,
1562}
1563
1564/// Projection-level output from the opt-in official Step grouped-FP8 gate.
1565///
1566/// Rows remain pair-major. Routing, weighted combine, and production integration are deliberately
1567/// outside this gate-only adapter.
1568pub struct StepGroupedFp8ProjectionOutput {
1569    pub gate: Vec<f32>,
1570    pub up: Vec<f32>,
1571    pub down: Vec<f32>,
1572}
1573
1574/// Prepared official Step grouped-FP8 projection gate.
1575///
1576/// The complete tensor banks, both CSR schedules, input, activation buffer, and three projection
1577/// workspaces are uploaded or allocated once. Repeated execution performs no device allocation.
1578pub struct PreparedStepGroupedFp8Gate {
1579    device: usize,
1580    gate: ResidentE4m3ExpertBankRank,
1581    up: ResidentE4m3ExpertBankRank,
1582    down: ResidentE4m3ExpertBankRank,
1583    input: CudaSlice<f32>,
1584    route_csr: DeviceExpertCsr,
1585    down_csr: DeviceExpertCsr,
1586    gate_workspace: Fp8GroupedWorkspace,
1587    up_workspace: Fp8GroupedWorkspace,
1588    down_workspace: Fp8GroupedWorkspace,
1589    activation: CudaSlice<f32>,
1590    activation_limit: Option<f32>,
1591    tokens: usize,
1592    pairs: usize,
1593}
1594
1595impl PreparedStepGroupedFp8Gate {
1596    pub fn tokens(&self) -> usize {
1597        self.tokens
1598    }
1599
1600    pub fn pairs(&self) -> usize {
1601        self.pairs
1602    }
1603}
1604
1605struct PreparedStepGroupedExpertOwner {
1606    rank: usize,
1607    global_pairs: Vec<usize>,
1608    route_csr: DeviceExpertCsr,
1609    down_csr: DeviceExpertCsr,
1610    gate_workspace: Fp8GroupedWorkspace,
1611    up_workspace: Fp8GroupedWorkspace,
1612    down_workspace: Fp8GroupedWorkspace,
1613    activation: CudaSlice<f32>,
1614}
1615
1616struct StepGroupedExpertOwnerSchedule {
1617    global_pairs: Vec<usize>,
1618    route_csr: ExpertCsr,
1619    down_csr: ExpertCsr,
1620}
1621
1622/// Prepared official Step expert-owner grouped-FP8 projection gate.
1623///
1624/// Route partitioning, owner-local CSR uploads, input dispatch, activation buffers, and grouped
1625/// workspaces are persistent. Projection rows are scattered back to canonical pair order only
1626/// after every owner has completed its rank-local program.
1627pub struct PreparedStepGroupedExpertParallelGate {
1628    rank_inputs: Vec<CudaSlice<f32>>,
1629    owners: Vec<PreparedStepGroupedExpertOwner>,
1630    activation_limit: Option<f32>,
1631    tokens: usize,
1632    pairs: usize,
1633    max_tokens: usize,
1634    max_pairs: usize,
1635    input_width: usize,
1636    expert_width: usize,
1637    generation: u64,
1638    executed_generation: Option<u64>,
1639    ready: bool,
1640}
1641
1642impl PreparedStepGroupedExpertParallelGate {
1643    pub fn tokens(&self) -> usize {
1644        self.tokens
1645    }
1646
1647    pub fn pairs(&self) -> usize {
1648        self.pairs
1649    }
1650
1651    pub fn max_tokens(&self) -> usize {
1652        self.max_tokens
1653    }
1654
1655    pub fn input_width(&self) -> usize {
1656        self.input_width
1657    }
1658
1659    pub fn expert_width(&self) -> usize {
1660        self.expert_width
1661    }
1662
1663    pub fn set_activation_limit(&mut self, limit: Option<f32>) -> Result<(), String> {
1664        validate_step_expert_activation_limit(limit)?;
1665        self.activation_limit = limit;
1666        self.executed_generation = None;
1667        Ok(())
1668    }
1669
1670    pub fn active_owners(&self) -> usize {
1671        self.owners
1672            .iter()
1673            .filter(|owner| !owner.global_pairs.is_empty())
1674            .count()
1675    }
1676
1677    pub fn owner_pair_counts(&self) -> Vec<usize> {
1678        self.owners
1679            .iter()
1680            .map(|owner| owner.global_pairs.len())
1681            .collect()
1682    }
1683
1684    pub fn generation(&self) -> u64 {
1685        self.generation
1686    }
1687}
1688
1689struct PreparedPeerWeightedRouteOwner {
1690    token_rows: CudaSlice<i32>,
1691    slots: CudaSlice<i32>,
1692    weights: CudaSlice<f32>,
1693    active_pairs: usize,
1694}
1695
1696/// Persistent root-side weighted combine for peer-owned canonical route rows.
1697///
1698/// Owner metadata, one reusable peer staging buffer, the canonical slot bank, weight bank, and
1699/// output are allocated once. Refreshes update metadata prefixes; execution peer-copies active
1700/// rows, scatters them by canonical token/slot, and reduces in the requested numeric order.
1701pub struct PreparedPeerWeightedRouteCombine {
1702    root_device: usize,
1703    owners: Vec<PreparedPeerWeightedRouteOwner>,
1704    peer_staging: CudaSlice<f32>,
1705    slots: CudaSlice<f32>,
1706    weights: CudaSlice<f32>,
1707    output: CudaSlice<f32>,
1708    peer_devices: Vec<usize>,
1709    peer_outputs: Vec<CudaSlice<f32>>,
1710    width: usize,
1711    experts_per_token: usize,
1712    max_tokens: usize,
1713    max_pairs: usize,
1714    tokens: usize,
1715    pairs: usize,
1716    projection_generation: u64,
1717    output_generation: Option<u64>,
1718    broadcast_generation: Option<u64>,
1719    ready: bool,
1720}
1721
1722impl PreparedPeerWeightedRouteCombine {
1723    pub fn tokens(&self) -> usize {
1724        self.tokens
1725    }
1726
1727    pub fn pairs(&self) -> usize {
1728        self.pairs
1729    }
1730
1731    pub fn owner_pair_counts(&self) -> Vec<usize> {
1732        self.owners.iter().map(|owner| owner.active_pairs).collect()
1733    }
1734
1735    pub fn distributed_ranks(&self) -> usize {
1736        1 + self.peer_outputs.len()
1737    }
1738}
1739
1740struct ResidentTpExpertBank {
1741    gate: Vec<ResidentE4m3ExpertBankRank>,
1742    up: Vec<ResidentE4m3ExpertBankRank>,
1743    down: Vec<ResidentE4m3ExpertBankRank>,
1744    expert_count: usize,
1745    input_width: usize,
1746    expert_width: usize,
1747}
1748
1749/// Persistent tensor-parallel expert bank.
1750///
1751/// Every rank owns a checkpoint-aligned output-row shard of every gate/up projection and an
1752/// input-column shard of every down projection. Activations cross deterministic host-staged
1753/// collectives on hosts where native peer copies are unavailable or corrupt.
1754pub struct ResidentTensorParallel {
1755    bank: ResidentTpExpertBank,
1756}
1757
1758/// Multi-context TP correctness runtime. Each rank owns an independent `Engine` and CUDA context.
1759///
1760/// Host bounce is the default oracle. Native P2P is opt-in and preserves the oracle's global
1761/// checkpoint-block reduction order; it remains a correctness path until serving gates and
1762/// repeated performance evidence qualify it.
1763pub struct TpE4m3HostBounce {
1764    devices: Vec<usize>,
1765    ranks: Vec<Engine>,
1766    native_p2p: bool,
1767    ep_device_arithmetic: bool,
1768    bulk_p2p: bool,
1769    /// v2 decode-attention workspace (MEMRA_STEP_TP_DECODE_V2). One per runtime, shared by
1770    /// every TP attention layer — the buffer shapes are geometry-constant across the trunk.
1771    decode_v2: std::sync::Mutex<Vec<StepTpDecodeV2Ws>>,
1772}
1773
1774pub struct TpKvVerifiedLayer<'a> {
1775    pub cache: &'a mut ResidentTpKvCache,
1776    pub start: usize,
1777    pub logical_len: usize,
1778    pub source_k_raw: u64,
1779    pub source_v_raw: u64,
1780    pub source_k_tok_bytes: usize,
1781    pub source_v_tok_bytes: usize,
1782}
1783
1784/// Persistent two-rank all-reduce for one replicated f32 row.
1785///
1786/// Each rank pushes its local partial directly into a peer-resident staging row, records one
1787/// reusable event, waits for the peer's corresponding event, then adds `(rank0, rank1)` in that
1788/// same operand order on both devices. Two staging rows per direction are enough because join
1789/// `j + 1` is ordered after each rank's add at join `j`, so overwriting parity `j` cannot race its
1790/// peer consumer. The collective allocates nothing and performs no host synchronization per call.
1791pub struct Tp2ReplicatedRowJoin {
1792    width: usize,
1793    parity: usize,
1794    stage0: [CudaSlice<f32>; 2],
1795    stage1: [CudaSlice<f32>; 2],
1796    stage0_raw: [u64; 2],
1797    stage1_raw: [u64; 2],
1798    event0: [CudaEvent; 2],
1799    event1: [CudaEvent; 2],
1800}
1801
1802fn validate_tp2_replicated_row_join(
1803    ranks: usize,
1804    native_p2p: bool,
1805    width: usize,
1806) -> Result<(), String> {
1807    if ranks != 2 {
1808        return Err(format!(
1809            "replicated-row join requires exactly two ranks, got {ranks}"
1810        ));
1811    }
1812    if !native_p2p {
1813        return Err("replicated-row join requires native P2P".into());
1814    }
1815    if width == 0 || width > i32::MAX as usize {
1816        return Err(format!(
1817            "replicated-row join width must be in 1..={}, got {width}",
1818            i32::MAX
1819        ));
1820    }
1821    Ok(())
1822}
1823
1824fn launch_tp2_peer_push(
1825    engine: &Engine,
1826    source: &CudaSlice<f32>,
1827    destination: u64,
1828    width: usize,
1829) -> Result<(), Box<dyn std::error::Error>> {
1830    let function = engine.func("q4e_push_f32");
1831    let config = LaunchConfig::for_num_elems(width as u32);
1832    let width = width as i64;
1833    let stream = engine.gpu.stream();
1834    let mut launch = stream.launch_builder(&function);
1835    launch.arg(source).arg(&destination).arg(&width);
1836    unsafe {
1837        launch.launch(config)?;
1838    }
1839    Ok(())
1840}
1841
1842/// Persistent workspace of the v2 rank-local decode-attention driver.
1843///
1844/// Buffers live in their producing rank's CUDA context, are never freed, and events are
1845/// re-recorded per call — the pp.rs `BoundarySlot` discipline — so the per-token path has no
1846/// cuMemAlloc, no cross-stream free, and no host round-trip. Every buffer is fully overwritten
1847/// before its consumers run in the same call; nothing carries state between tokens.
1848/// Per-rank attn_gate row shards for the fused QKV+gate kernel, in the weight class the
1849/// fused kernels read (F32 mirror or raw checkpoint bf16).
1850pub enum StepTpGateShards<'a> {
1851    F32(&'a [crate::CudaSlice<f32>]),
1852    Bf16(&'a [crate::CudaSlice<u8>]),
1853}
1854
1855pub struct StepTpDecodeV2Ws {
1856    /// T-COLUMN verify slabs (spec MTP): per-rank [t, local_dim] projections computed by
1857    /// the weight-amortized qkvg_tcol kernel; the col-select door copies one column into
1858    /// the single-row buffers and everything downstream runs the unmodified t=1 program.
1859    pub(crate) tcol_q: Vec<CudaSlice<f32>>,
1860    pub(crate) tcol_k: Vec<CudaSlice<f32>>,
1861    pub(crate) tcol_v: Vec<CudaSlice<f32>>,
1862    pub(crate) tcol_g: Vec<CudaSlice<f32>>,
1863    pub(crate) tcol_in: Vec<CudaSlice<f32>>,
1864    pub(crate) tcol_cap: usize,
1865    /// MEMRA_STEP_TP_W8 activation scratch: per-rank q8_1 quantized attention input
1866    /// ([in_f] i8 + one f32 scale pair per 32). Persistent because the alternative is an
1867    /// allocation per rank per layer per token.
1868    w8_aq: Vec<CudaSlice<i8>>,
1869    w8_ad: Vec<CudaSlice<f32>>,
1870    w8_in: usize,
1871    /// o_proj-side twin of the same scratch (its activation is the gated attention output,
1872    /// a different vector from the QKV input, so it needs its own buffers).
1873    w8o_aq: Vec<CudaSlice<i8>>,
1874    w8o_ad: Vec<CudaSlice<f32>>,
1875    w8o_in: usize,
1876    /// VERIFY-WALK q8_1 activation scratch, t columns wide (the decode scratch above is one
1877    /// row). Two sets because the QKV input and the gated attention output are different
1878    /// vectors of different widths.
1879    w8t_aq: Vec<CudaSlice<i8>>,
1880    w8t_ad: Vec<CudaSlice<f32>>,
1881    w8t_in: usize,
1882    w8t_oaq: Vec<CudaSlice<i8>>,
1883    w8t_oad: Vec<CudaSlice<f32>>,
1884    w8t_oin: usize,
1885    w8t_cap: usize,
1886    /// MEMRA_TCOL_OPROJ slabs: per-rank stashed `gated` rows ([8, local_q_dim]), per-rank
1887    /// b4_tcol partials ([8, o_out]), a root-side peer pull of rank1's partial slab, and
1888    /// the root-side joined `mixed` slab. Armed lazily by the first stash.
1889    /// MEMRA_SPEC_FA2 slabs: per-rank stashed post-rope q rows ([2, local_q_dim]), gate
1890    /// rows ([2, heads/ranks]) and the two gated outputs the per-row combine writes
1891    /// ([2, local_q_dim]). Armed lazily by the first stash.
1892    pub(crate) fa2_q: Vec<CudaSlice<f32>>,
1893    pub(crate) fa2_gate: Vec<CudaSlice<f32>>,
1894    pub(crate) fa2_gated: Vec<CudaSlice<f32>>,
1895    pub(crate) fa2_cap: usize,
1896    /// T-ROW rope/append twin scratch: per-rank roped-k rows ([8, local_kv]), per-row
1897    /// last-block counters ([8]) and the per-tick position slab ([8]). Armed with the
1898    /// fa2 slabs.
1899    rope_k_t: Vec<CudaSlice<f32>>,
1900    rope_ctr_t: Vec<CudaSlice<u32>>,
1901    rope_pos_t: Vec<CudaSlice<i32>>,
1902    /// Per-rank combined 6-word row tables, keyed by the caller's (layer, session-set,
1903    /// base-arming) signature. LEGACY: only the `MEMRA_ROWS_TAB_RESTAGE=0` rollback arm
1904    /// reads this. See `rows_tab_t` for why the key cannot be made safe.
1905    rows_tabs: Vec<std::collections::HashMap<u64, CudaSlice<u64>>>,
1906    /// Per-rank PERSISTENT 6-word row-table slab ([32, 6] u64), RESTAGED from the live
1907    /// distributed cache before every launch. Replaces the `rows_tabs` memo, whose key was
1908    /// a hash of (k pointer, base pointer, layer, t) while the table it returned also
1909    /// carried the V and LEN pointers: a session whose K buffer address was recycled hit
1910    /// another session's table and the append kernel wrote its K/V through the FREED
1911    /// pointers the entry still held. Same defect and same cure as the row-table twin in
1912    /// `step35_verify_fa_rows_join` (8c8397e0b2, Hermes `11339f5cd3c132a3`), which this
1913    /// path was left out of. One 32-word htod per rank per layer replaces the map lookup;
1914    /// no allocation, and the staging is stream-ordered exactly like `rope_pos_t`.
1915    rows_tab_t: Vec<CudaSlice<u64>>,
1916    /// HOST shadow of the last table staged under each retired memo key, used ONLY by
1917    /// `MEMRA_ROWS_TAB_STALE_SCAN=1` to prove that the retired key would have handed a live
1918    /// launch another allocation's pointers. Never read by a kernel.
1919    rows_tab_shadow: Vec<std::collections::HashMap<u64, Vec<u64>>>,
1920    tcol_gated: Vec<CudaSlice<f32>>,
1921    tcol_opart: Vec<CudaSlice<f32>>,
1922    tcol_opeer: Option<CudaSlice<f32>>,
1923    tcol_omix: Option<CudaSlice<f32>>,
1924    tcol_ocap: usize,
1925    // rank-context buffers, indexed by rank (pub(crate): the v2 driver in hybrid_forward
1926    // feeds them to the KV transaction and attention kernels between the two v2 phases)
1927    pub(crate) q_raw: Vec<CudaSlice<f32>>,
1928    pub(crate) k_raw: Vec<CudaSlice<f32>>,
1929    pub(crate) v_raw: Vec<CudaSlice<f32>>,
1930    pub(crate) q: Vec<CudaSlice<f32>>,
1931    pub(crate) k: Vec<CudaSlice<f32>>,
1932    pub(crate) pos: Vec<CudaSlice<i32>>,
1933    /// FUSION #1 last-block counters (one per rank; atomicInc auto-resets per launch).
1934    pub(crate) fuse_ctr: Vec<CudaSlice<u32>>,
1935    pub(crate) gate: Vec<CudaSlice<f32>>,
1936    pub(crate) attn_out: Vec<CudaSlice<f32>>,
1937    pub(crate) gated: Vec<CudaSlice<f32>>,
1938    /// [rank][block] O partials, each `o_out` wide, in the owning rank's context.
1939    o_partials: Vec<Vec<CudaSlice<f32>>>,
1940    /// Stable workspace pointers for the rank-done-fenced raw P2P gather. Safe
1941    /// `memcpy_dtod` creates a fresh source event for every cross-context copy; the v2
1942    /// driver already records one persistent `ev_rank` after all three source families.
1943    raw_o_partials: Vec<Vec<u64>>,
1944    raw_k: Vec<u64>,
1945    raw_v_raw: Vec<u64>,
1946    /// Recorded on each rank's stream after its per-call work; root waits before peer reads.
1947    ev_rank: Vec<CudaEvent>,
1948    // root-context buffers
1949    peer_partial: CudaSlice<f32>,
1950    reduce_a: CudaSlice<f32>,
1951    reduce_b: CudaSlice<f32>,
1952    /// Never written; the canonical zero start of the v1 add chain.
1953    zeros: CudaSlice<f32>,
1954    pub(crate) k_shadow: CudaSlice<f32>,
1955    pub(crate) v_shadow: CudaSlice<f32>,
1956    ev_refresh: CudaEvent,
1957    ev_oproj: CudaEvent,
1958    // model-engine (e) context
1959    gate_e: CudaSlice<f32>,
1960    /// Per-token stages (e-ctx, fixed addresses): one eager e-stream copy each per layer; the
1961    /// rank flows raw-copy FROM them, which is exactly the shape graph capture needs.
1962    pub(crate) h_stage: Option<CudaSlice<f32>>,
1963    pub(crate) pos_stage: Option<CudaSlice<i32>>,
1964    /// Workspace-owned per-rank attention input rows (the stage flow copies into THESE, not
1965    /// the per-layer decode_input buffers — the workspace is shared across layers, so every
1966    /// captured/raw address it uses must be layer-invariant).
1967    attn_in: Vec<CudaSlice<f32>>,
1968    /// Cached raw pointers of the stage-flow operands (set when the stages arm).
1969    raw_h_stage: u64,
1970    raw_pos_stage: u64,
1971    raw_attn_in: Vec<u64>,
1972    raw_pos: Vec<u64>,
1973    raw_o_partial1: u64,
1974    raw_peer_partial: u64,
1975    raw_k1: u64,
1976    raw_v1: u64,
1977    raw_k_shadow: u64,
1978    raw_v_shadow: u64,
1979    /// Token-graph e-context mirrors (armed by the orchestrator): the root section
1980    /// raw-copies the reduced attention output and the shadow rows here so the e-glue
1981    /// children read same-context memory (cross-context kernel args are capture-illegal).
1982    raw_mixed_stage_e: u64,
1983    raw_reduce_a: u64,
1984    raw_shadow_stage_e: (u64, u64),
1985    ev_entry: CudaEvent,
1986    e_device: usize,
1987    // geometry pins
1988    local_q_dim: usize,
1989    local_kv_dim: usize,
1990    heads: usize,
1991    pub(crate) o_out: usize,
1992    o_block_cols: usize,
1993    blocks_per_rank: usize,
1994}
1995
1996impl TpE4m3HostBounce {
1997    pub fn new(devices: &[usize]) -> Result<Self, Box<dyn std::error::Error>> {
1998        Self::new_inner(devices, false, false, false, false)
1999    }
2000
2001    pub fn new_native_p2p(devices: &[usize]) -> Result<Self, Box<dyn std::error::Error>> {
2002        Self::new_inner(devices, false, true, false, false)
2003    }
2004
2005    pub fn new_native_p2p_device_arithmetic(
2006        devices: &[usize],
2007    ) -> Result<Self, Box<dyn std::error::Error>> {
2008        Self::new_inner(devices, false, true, true, false)
2009    }
2010
2011    pub(crate) fn new_configured(
2012        devices: &[usize],
2013        native_p2p: bool,
2014        ep_device_arithmetic: bool,
2015        bulk_p2p: bool,
2016    ) -> Result<Self, Box<dyn std::error::Error>> {
2017        Self::new_inner(devices, false, native_p2p, ep_device_arithmetic, bulk_p2p)
2018    }
2019
2020    /// Single-rank execution of the canonical checkpoint-block TP program.
2021    ///
2022    /// This is an oracle for distributed exactness, not a serving topology. It lets gates compare
2023    /// TP=1 and TP>1 with the same packing, kernel launches, and deterministic reduction order.
2024    pub fn new_single_rank_oracle(device: usize) -> Result<Self, Box<dyn std::error::Error>> {
2025        Self::new_inner(&[device], true, false, false, false)
2026    }
2027
2028    fn new_inner(
2029        devices: &[usize],
2030        allow_single_rank: bool,
2031        native_p2p: bool,
2032        ep_device_arithmetic: bool,
2033        bulk_p2p: bool,
2034    ) -> Result<Self, Box<dyn std::error::Error>> {
2035        if ep_device_arithmetic && !native_p2p {
2036            return Err("device-resident EP arithmetic requires native P2P".into());
2037        }
2038        if bulk_p2p && !native_p2p {
2039            return Err("bulk TP transport requires native P2P".into());
2040        }
2041        let minimum = if allow_single_rank { 1 } else { 2 };
2042        if !(minimum..=8).contains(&devices.len()) {
2043            return Err(format!(
2044                "TP reference requires {minimum}..=8 devices, got {}",
2045                devices.len()
2046            )
2047            .into());
2048        }
2049        let mut unique = devices.to_vec();
2050        unique.sort_unstable();
2051        unique.dedup();
2052        if unique.len() != devices.len() {
2053            return Err(format!("TP devices must be distinct, got {devices:?}").into());
2054        }
2055        let ranks = devices
2056            .iter()
2057            .map(|&device| Engine::new(device))
2058            .collect::<Result<Vec<_>, _>>()?;
2059        if native_p2p {
2060            configure_native_p2p(&ranks, devices)?;
2061        }
2062        if allow_single_rank {
2063            eprintln!(
2064                "[tp] canonical oracle transport=local device={} performance_claim=false",
2065                devices[0]
2066            );
2067        } else if native_p2p {
2068            if ep_device_arithmetic {
2069                eprintln!(
2070                    "[tp] correctness transport=native-p2p devices={devices:?} \
2071                     native_p2p=true activation=device-host-exact \
2072                     accumulation=device-host-exact output=root-readback \
2073                     bulk_p2p={bulk_p2p} performance_claim=false"
2074                );
2075            } else {
2076                eprintln!(
2077                    "[tp] correctness transport=native-p2p devices={devices:?} \
2078                     native_p2p=true activation=host-canonical bulk_p2p={bulk_p2p} \
2079                     performance_claim=false"
2080                );
2081            }
2082        } else {
2083            eprintln!(
2084                "[tp] correctness transport=host-bounce devices={devices:?} \
2085                 native_p2p=false performance_claim=false"
2086            );
2087        }
2088        Ok(Self {
2089            devices: devices.to_vec(),
2090            ranks,
2091            native_p2p,
2092            ep_device_arithmetic,
2093            bulk_p2p,
2094            decode_v2: std::sync::Mutex::new(Vec::new()),
2095        })
2096    }
2097
2098    pub fn devices(&self) -> &[usize] {
2099        &self.devices
2100    }
2101
2102    pub fn native_p2p(&self) -> bool {
2103        self.native_p2p
2104    }
2105
2106    pub fn bulk_p2p(&self) -> bool {
2107        self.bulk_p2p
2108    }
2109
2110    pub fn expert_activation_label(&self) -> &'static str {
2111        if self.ep_device_arithmetic {
2112            "device-host-exact"
2113        } else {
2114            "host-canonical"
2115        }
2116    }
2117
2118    pub fn expert_accumulation_label(&self) -> &'static str {
2119        self.expert_activation_label()
2120    }
2121
2122    pub fn expert_output_label(&self) -> &'static str {
2123        if self.ep_device_arithmetic {
2124            "root-readback"
2125        } else {
2126            "host-accumulated"
2127        }
2128    }
2129
2130    pub fn transport_label(&self) -> &'static str {
2131        if self.devices.len() == 1 {
2132            "local"
2133        } else if self.native_p2p {
2134            "native-p2p"
2135        } else {
2136            "host-bounce"
2137        }
2138    }
2139
2140    pub fn device_names(&self) -> Result<Vec<String>, Box<dyn std::error::Error>> {
2141        self.ranks
2142            .iter()
2143            .map(|rank| rank.ctx().name().map_err(Into::into))
2144            .collect()
2145    }
2146
2147    /// Correctness-gate access to the engine that owns one TP rank.
2148    ///
2149    /// Model execution should prefer collective methods on this runtime. This accessor exists so
2150    /// focused gates can prove that the rank-local projection outputs remain device-resident
2151    /// through the next ownership boundary before that boundary is wired into serving.
2152    pub fn rank_engine(&self, rank: usize) -> Option<&Engine> {
2153        self.ranks.get(rank)
2154    }
2155
2156    /// Allocate the persistent ping-pong staging and event state for a two-rank replicated-row
2157    /// all-reduce. The caller owns one instance per concurrently live collective sequence.
2158    pub fn prepare_tp2_replicated_row_join(
2159        &self,
2160        width: usize,
2161    ) -> Result<Tp2ReplicatedRowJoin, Box<dyn std::error::Error>> {
2162        validate_tp2_replicated_row_join(self.ranks.len(), self.native_p2p, width)?;
2163        let rank0 = &self.ranks[0];
2164        let rank1 = &self.ranks[1];
2165
2166        let (stage0, stage0_raw, event0) = {
2167            let _main = rank0.gpu.enter_main()?;
2168            let stage = [rank0.zeros(width)?, rank0.zeros(width)?];
2169            let stream = rank0.gpu.stream();
2170            let raw = [
2171                stage[0].device_ptr(&stream).0,
2172                stage[1].device_ptr(&stream).0,
2173            ];
2174            let events = [rank0.ctx().new_event(None)?, rank0.ctx().new_event(None)?];
2175            (stage, raw, events)
2176        };
2177        let (stage1, stage1_raw, event1) = {
2178            let _main = rank1.gpu.enter_main()?;
2179            let stage = [rank1.zeros(width)?, rank1.zeros(width)?];
2180            let stream = rank1.gpu.stream();
2181            let raw = [
2182                stage[0].device_ptr(&stream).0,
2183                stage[1].device_ptr(&stream).0,
2184            ];
2185            let events = [rank1.ctx().new_event(None)?, rank1.ctx().new_event(None)?];
2186            (stage, raw, events)
2187        };
2188        Ok(Tp2ReplicatedRowJoin {
2189            width,
2190            parity: 0,
2191            stage0,
2192            stage1,
2193            stage0_raw,
2194            stage1_raw,
2195            event0,
2196            event1,
2197        })
2198    }
2199
2200    /// Sum one rank-local partial from each of two ranks and publish the same canonical
2201    /// `(rank0 + rank1)` row on both devices. The method only enqueues work; subsequent work on
2202    /// each rank's stream consumes its corresponding output without a host fence.
2203    pub fn tp2_replicated_row_join(
2204        &self,
2205        join: &mut Tp2ReplicatedRowJoin,
2206        partial0: &CudaSlice<f32>,
2207        partial1: &CudaSlice<f32>,
2208        output0: &mut CudaSlice<f32>,
2209        output1: &mut CudaSlice<f32>,
2210    ) -> Result<(), Box<dyn std::error::Error>> {
2211        validate_tp2_replicated_row_join(self.ranks.len(), self.native_p2p, join.width)?;
2212        let rank0 = &self.ranks[0];
2213        let rank1 = &self.ranks[1];
2214        let width = join.width;
2215        if partial0.len() < width
2216            || partial1.len() < width
2217            || output0.len() < width
2218            || output1.len() < width
2219            || partial0.ordinal() != rank0.ctx().ordinal()
2220            || output0.ordinal() != rank0.ctx().ordinal()
2221            || partial1.ordinal() != rank1.ctx().ordinal()
2222            || output1.ordinal() != rank1.ctx().ordinal()
2223        {
2224            return Err("replicated-row join buffer geometry or ownership mismatch".into());
2225        }
2226
2227        let parity = join.parity;
2228        {
2229            let _main = rank0.gpu.enter_main()?;
2230            launch_tp2_peer_push(rank0, partial0, join.stage1_raw[parity], width)?;
2231            join.event0[parity].record(&rank0.gpu.stream())?;
2232        }
2233        {
2234            let _main = rank1.gpu.enter_main()?;
2235            launch_tp2_peer_push(rank1, partial1, join.stage0_raw[parity], width)?;
2236            join.event1[parity].record(&rank1.gpu.stream())?;
2237        }
2238        {
2239            let _main = rank0.gpu.enter_main()?;
2240            rank0.gpu.stream().wait(&join.event1[parity])?;
2241            rank0.add(partial0, &join.stage0[parity], output0, width)?;
2242        }
2243        {
2244            let _main = rank1.gpu.enter_main()?;
2245            rank1.gpu.stream().wait(&join.event0[parity])?;
2246            rank1.add(&join.stage1[parity], partial1, output1, width)?;
2247        }
2248        join.parity ^= 1;
2249        Ok(())
2250    }
2251
2252    pub fn allocate_tp_kv_cache(
2253        &self,
2254        kv_dim_k: usize,
2255        kv_dim_v: usize,
2256        capacity: usize,
2257    ) -> Result<ResidentTpKvCache, Box<dyn std::error::Error>> {
2258        self.allocate_tp_kv_cache_inner(kv_dim_k, kv_dim_v, capacity, None)
2259    }
2260
2261    pub fn allocate_tp_swa_kv_cache(
2262        &self,
2263        kv_dim_k: usize,
2264        kv_dim_v: usize,
2265        capacity: usize,
2266        window: usize,
2267    ) -> Result<ResidentTpKvCache, Box<dyn std::error::Error>> {
2268        if window == 0 {
2269            return Err("TP SWA KV window must be nonzero".into());
2270        }
2271        self.allocate_tp_kv_cache_inner(kv_dim_k, kv_dim_v, capacity, Some(window))
2272    }
2273
2274    fn allocate_tp_kv_cache_inner(
2275        &self,
2276        kv_dim_k: usize,
2277        kv_dim_v: usize,
2278        capacity: usize,
2279        window: Option<usize>,
2280    ) -> Result<ResidentTpKvCache, Box<dyn std::error::Error>> {
2281        if capacity == 0 || capacity > i32::MAX as usize {
2282            return Err(
2283                format!("TP KV capacity must be in 1..={}, got {capacity}", i32::MAX).into(),
2284            );
2285        }
2286        let tp = self.ranks.len();
2287        let shape = crate::cache::tp_kv_rank_allocation_shape(kv_dim_k, kv_dim_v, tp)?;
2288        let physical_rows = window
2289            .map(|window| crate::cache::swa_ring_rows(window, capacity))
2290            .unwrap_or(capacity);
2291        let k_plane_bytes = physical_rows
2292            .checked_mul(shape.k_token_bytes)
2293            .and_then(|bytes| bytes.checked_add(8))
2294            .ok_or("TP KV K plane-byte overflow")?;
2295        let v_plane_bytes = physical_rows
2296            .checked_mul(shape.v_token_bytes)
2297            .and_then(|bytes| bytes.checked_add(8))
2298            .ok_or("TP KV V plane-byte overflow")?;
2299        let mut ranks = Vec::with_capacity(tp);
2300        for engine in &self.ranks {
2301            let _main = engine.gpu.enter_main()?;
2302            ranks.push(ResidentTpKvCacheRank::new(
2303                engine.alloc_u8(k_plane_bytes)?,
2304                engine.alloc_u8(v_plane_bytes)?,
2305                engine.htod_i32(&[0])?,
2306            ));
2307        }
2308        Ok(match window {
2309            Some(window) => ResidentTpKvCache::new_swa(
2310                ranks,
2311                shape.kv_dim_k,
2312                shape.kv_dim_v,
2313                shape.k_token_bytes,
2314                shape.v_token_bytes,
2315                capacity,
2316                window,
2317            ),
2318            None => ResidentTpKvCache::new(
2319                ranks,
2320                shape.kv_dim_k,
2321                shape.kv_dim_v,
2322                shape.k_token_bytes,
2323                shape.v_token_bytes,
2324                capacity,
2325            ),
2326        })
2327    }
2328
2329    pub fn grow_tp_kv_cache(
2330        &self,
2331        source: &ResidentTpKvCache,
2332        target_capacity: usize,
2333        rows: usize,
2334    ) -> Result<ResidentTpKvCache, Box<dyn std::error::Error>> {
2335        self.validate_tp_kv_cache(source)?;
2336        let plan = source.prepare_grow(target_capacity, rows)?;
2337        let ranks = self.ranks.len();
2338        let global_k = source
2339            .kv_dim_k()
2340            .checked_mul(ranks)
2341            .ok_or("TP KV grow global K dimension overflow")?;
2342        let global_v = source
2343            .kv_dim_v()
2344            .checked_mul(ranks)
2345            .ok_or("TP KV grow global V dimension overflow")?;
2346        let mut target = match source.ring_window() {
2347            Some(window) => {
2348                self.allocate_tp_swa_kv_cache(global_k, global_v, target_capacity, window)?
2349            }
2350            None => self.allocate_tp_kv_cache(global_k, global_v, target_capacity)?,
2351        };
2352        self.validate_tp_kv_cache(&target)?;
2353
2354        for (rank, engine) in self.ranks.iter().enumerate() {
2355            let _main = engine.gpu.enter_main()?;
2356            let src = source
2357                .rank(rank)
2358                .ok_or_else(|| format!("TP KV grow source has no rank {rank}"))?;
2359            let dst = target
2360                .rank_mut(rank)
2361                .ok_or_else(|| format!("TP KV grow target has no rank {rank}"))?;
2362            if plan.k_bytes() > 0 {
2363                engine.copy_u8_range_into(
2364                    dst.k_mut(),
2365                    0,
2366                    src.k(),
2367                    plan.source_row() * source.k_tok_bytes(),
2368                    plan.k_bytes(),
2369                )?;
2370            }
2371            if plan.v_bytes() > 0 {
2372                engine.copy_u8_range_into(
2373                    dst.v_mut(),
2374                    0,
2375                    src.v(),
2376                    plan.source_row() * source.v_tok_bytes(),
2377                    plan.v_bytes(),
2378                )?;
2379            }
2380        }
2381        self.set_tp_kv_len_mirrors(&mut target, plan.rows())?;
2382
2383        // The caller publishes `target` and immediately drops `source`. Drain every rank's
2384        // stream so an async-pool free cannot recycle a source plane under an in-flight D2D copy.
2385        for engine in &self.ranks {
2386            let _main = engine.gpu.enter_main()?;
2387            engine.stream().synchronize()?;
2388        }
2389        let physical_copy_rows = plan.copy_rows();
2390        target.publish_grow(plan)?;
2391        eprintln!(
2392            "[step-tp-kv-grow] rows={} source_capacity={} target_capacity={} ranks={} \
2393             physical_copy_rows={} ring_window={:?} copy=rank-local-dtod \
2394             rank_streams_synchronized=true generation_preserved=true",
2395            rows,
2396            source.capacity(),
2397            target_capacity,
2398            ranks,
2399            physical_copy_rows,
2400            source.ring_window(),
2401        );
2402        Ok(target)
2403    }
2404
2405    pub fn hydrate_tp_kv_cache(
2406        &self,
2407        cache: &mut ResidentTpKvCache,
2408        rows: usize,
2409        k_rows: &[u8],
2410        v_rows: &[u8],
2411    ) -> Result<(), Box<dyn std::error::Error>> {
2412        self.hydrate_tp_kv_cache_from(cache, rows, 0, k_rows, v_rows)
2413    }
2414
2415    pub fn hydrate_tp_kv_cache_from(
2416        &self,
2417        cache: &mut ResidentTpKvCache,
2418        logical_len: usize,
2419        resident_start: usize,
2420        k_rows: &[u8],
2421        v_rows: &[u8],
2422    ) -> Result<(), Box<dyn std::error::Error>> {
2423        self.validate_tp_kv_cache(cache)?;
2424        if cache.committed_len() != 0 || cache.staged_len() != 0 {
2425            return Err(format!(
2426                "TP KV hydration requires an empty cache, got committed/staged={}/{}",
2427                cache.committed_len(),
2428                cache.staged_len()
2429            )
2430            .into());
2431        }
2432        if resident_start > logical_len || logical_len > cache.capacity() {
2433            return Err(format!(
2434                "TP KV hydration range [{resident_start},{logical_len}) exceeds capacity {}",
2435                cache.capacity(),
2436            )
2437            .into());
2438        }
2439        let rows = logical_len - resident_start;
2440        if rows > cache.physical_capacity() {
2441            return Err(format!(
2442                "TP KV hydration rows {rows} exceed physical capacity {}",
2443                cache.physical_capacity()
2444            )
2445            .into());
2446        }
2447        for rank in 0..self.ranks.len() {
2448            let k_rank =
2449                cache_rank_rows(k_rows, rows, cache.k_tok_bytes(), self.ranks.len(), rank)?;
2450            let v_rank =
2451                cache_rank_rows(v_rows, rows, cache.v_tok_bytes(), self.ranks.len(), rank)?;
2452            let engine = &self.ranks[rank];
2453            let _main = engine.gpu.enter_main()?;
2454            let rank_cache = cache
2455                .rank_mut(rank)
2456                .ok_or_else(|| format!("TP KV cache has no rank {rank}"))?;
2457            engine.htod_u8_into(rank_cache.k_mut(), 0, &k_rank)?;
2458            engine.htod_u8_into(rank_cache.v_mut(), 0, &v_rank)?;
2459        }
2460        cache.publish_hydration(logical_len, resident_start)?;
2461        Ok(())
2462    }
2463
2464    /// Restore rows retained from a speculative verify walk into an already-live distributed
2465    /// cache. The verify oracle appends canonical full-width quantized K/V rows on the model
2466    /// device. Each destination rank pulls its own contiguous KV-head slice over native P2P; its
2467    /// length mirror is published on that same rank stream after every row copy.
2468    #[allow(clippy::too_many_arguments)]
2469    pub fn restore_tp_kv_rows_from_device(
2470        &self,
2471        cache: &mut ResidentTpKvCache,
2472        start: usize,
2473        logical_len: usize,
2474        source_k_raw: u64,
2475        source_v_raw: u64,
2476        source_k_tok_bytes: usize,
2477        source_v_tok_bytes: usize,
2478    ) -> Result<(), Box<dyn std::error::Error>> {
2479        self.validate_tp_kv_cache(cache)?;
2480        if cache.committed_len() != cache.staged_len() {
2481            return Err(format!(
2482                "TP KV verify restore requires quiescent state, got committed/staged={}/{}",
2483                cache.committed_len(),
2484                cache.staged_len()
2485            )
2486            .into());
2487        }
2488        if start > logical_len || logical_len > cache.capacity() {
2489            return Err(format!(
2490                "TP KV verify restore range [{start},{logical_len}) exceeds capacity {}",
2491                cache.capacity()
2492            )
2493            .into());
2494        }
2495        let rows = logical_len - start;
2496        let physical = cache.physical_range(start, logical_len)?;
2497        if physical.len() != rows {
2498            return Err(format!(
2499                "TP KV verify restore range [{start},{logical_len}) is not physically contiguous"
2500            )
2501            .into());
2502        }
2503        let ranks = self.ranks.len();
2504        let k_tok_bytes = cache.k_tok_bytes();
2505        let v_tok_bytes = cache.v_tok_bytes();
2506        if source_k_tok_bytes != k_tok_bytes * ranks || source_v_tok_bytes != v_tok_bytes * ranks {
2507            return Err(format!(
2508                "TP KV verify source token bytes k={source_k_tok_bytes} v={source_v_tok_bytes} \
2509                 do not match distributed k={}x{ranks} v={}x{ranks}",
2510                k_tok_bytes, v_tok_bytes
2511            )
2512            .into());
2513        }
2514        for rank in 0..self.ranks.len() {
2515            let engine = &self.ranks[rank];
2516            let _main = engine.gpu.enter_main()?;
2517            use cudarc::driver::DevicePtr;
2518            let stream = engine.stream();
2519            let k_offset = physical
2520                .start
2521                .checked_mul(k_tok_bytes)
2522                .ok_or("TP KV verify K offset overflow")?;
2523            let v_offset = physical
2524                .start
2525                .checked_mul(v_tok_bytes)
2526                .ok_or("TP KV verify V offset overflow")?;
2527            let rank_cache = cache
2528                .rank_mut(rank)
2529                .ok_or_else(|| format!("TP KV cache has no rank {rank}"))?;
2530            let k_dst = {
2531                let (pointer, _guard) = rank_cache.k_mut().device_ptr(&stream);
2532                pointer
2533            };
2534            let v_dst = {
2535                let (pointer, _guard) = rank_cache.v_mut().device_ptr(&stream);
2536                pointer
2537            };
2538            for row in 0..rows {
2539                let k_src = source_k_raw + (row * source_k_tok_bytes + rank * k_tok_bytes) as u64;
2540                let v_src = source_v_raw + (row * source_v_tok_bytes + rank * v_tok_bytes) as u64;
2541                let k_out = k_dst + (k_offset + row * k_tok_bytes) as u64;
2542                let v_out = v_dst + (v_offset + row * v_tok_bytes) as u64;
2543                raw_copy_bytes(k_out, k_src, k_tok_bytes, engine)?;
2544                raw_copy_bytes(v_out, v_src, v_tok_bytes, engine)?;
2545            }
2546        }
2547        cache.rewind_to(logical_len)?;
2548        Ok(())
2549    }
2550
2551    /// Batch the accepted verify rows of every uniform TP-attention layer into one kernel per
2552    /// rank. Returns `false` before enqueueing anything when the layer group is not uniform, so
2553    /// the caller can use the existing per-layer repair without splitting semantics.
2554    pub fn restore_tp_kv_layers_from_device(
2555        &self,
2556        layers: &mut [TpKvVerifiedLayer<'_>],
2557    ) -> Result<bool, Box<dyn std::error::Error>> {
2558        let Some(first) = layers.first() else {
2559            return Ok(false);
2560        };
2561        if !self.native_p2p || first.start >= first.logical_len {
2562            return Ok(false);
2563        }
2564        let ranks = self.ranks.len();
2565        let rows = first.logical_len - first.start;
2566        let logical_len = first.logical_len;
2567        let k_row_bytes = first.cache.k_tok_bytes();
2568        let v_row_bytes = first.cache.v_tok_bytes();
2569        let k_src_stride = first.source_k_tok_bytes;
2570        let v_src_stride = first.source_v_tok_bytes;
2571        let Some(expected_k_stride) = k_row_bytes.checked_mul(ranks) else {
2572            return Ok(false);
2573        };
2574        let Some(expected_v_stride) = v_row_bytes.checked_mul(ranks) else {
2575            return Ok(false);
2576        };
2577        if k_src_stride != expected_k_stride || v_src_stride != expected_v_stride {
2578            return Ok(false);
2579        }
2580
2581        for layer in layers.iter() {
2582            self.validate_tp_kv_cache(layer.cache)?;
2583            if layer.cache.committed_len() != layer.cache.staged_len()
2584                || layer.start > layer.logical_len
2585                || layer.logical_len != logical_len
2586                || layer.logical_len - layer.start != rows
2587                || layer.cache.k_tok_bytes() != k_row_bytes
2588                || layer.cache.v_tok_bytes() != v_row_bytes
2589                || layer.source_k_tok_bytes != k_src_stride
2590                || layer.source_v_tok_bytes != v_src_stride
2591            {
2592                return Ok(false);
2593            }
2594            let physical = layer.cache.physical_range(layer.start, layer.logical_len)?;
2595            if physical.len() != rows {
2596                return Ok(false);
2597            }
2598        }
2599
2600        for rank in 0..ranks {
2601            let engine = &self.ranks[rank];
2602            let _main = engine.gpu.enter_main()?;
2603            let stream = engine.stream();
2604            let n = layers.len();
2605            let mut table = vec![0u64; 5 * n];
2606            for (index, layer) in layers.iter_mut().enumerate() {
2607                let physical = layer.cache.physical_range(layer.start, layer.logical_len)?;
2608                let rank_cache = layer
2609                    .cache
2610                    .rank_mut(rank)
2611                    .ok_or_else(|| format!("TP KV cache has no rank {rank}"))?;
2612                table[index] = layer.source_k_raw + (rank * k_row_bytes) as u64;
2613                table[n + index] = layer.source_v_raw + (rank * v_row_bytes) as u64;
2614                table[2 * n + index] = rank_cache.k_mut().device_ptr(&stream).0
2615                    + (physical.start * k_row_bytes) as u64;
2616                table[3 * n + index] = rank_cache.v_mut().device_ptr(&stream).0
2617                    + (physical.start * v_row_bytes) as u64;
2618                table[4 * n + index] = rank_cache.len_d_mut().device_ptr(&stream).0;
2619            }
2620            let table = engine.htod_u64(&table)?;
2621            engine.copy_batch_uniform_kv_u8_set_len(
2622                &table,
2623                n,
2624                rows,
2625                k_row_bytes,
2626                v_row_bytes,
2627                k_src_stride,
2628                v_src_stride,
2629                logical_len,
2630            )?;
2631        }
2632        let layer_count = layers.len();
2633        for layer in layers.iter_mut() {
2634            layer.cache.publish_device_rewind(logical_len)?;
2635        }
2636        static ANNOUNCED: std::sync::Once = std::sync::Once::new();
2637        ANNOUNCED.call_once(|| {
2638            eprintln!(
2639                "[tp-kv-verify-batch] engaged: layers={} ranks={ranks} rows={rows} \
2640                 k_row_bytes={k_row_bytes} v_row_bytes={v_row_bytes}",
2641                layer_count
2642            );
2643        });
2644        Ok(true)
2645    }
2646
2647    pub fn append_tp_kv_transaction(
2648        &self,
2649        cache: &mut ResidentTpKvCache,
2650        transaction: TpKvTransaction,
2651        k_shards: &[CudaSlice<f32>],
2652        v_shards: &[CudaSlice<f32>],
2653        rows: usize,
2654    ) -> Result<(), Box<dyn std::error::Error>> {
2655        self.append_tp_kv_transaction_inner(cache, transaction, k_shards, v_shards, rows, false)
2656    }
2657
2658    /// `external_rank_appends`: the dcw path already wrote the rank rows (device-counter
2659    /// append) — run everything EXCEPT the per-rank quantize/append loop (plan validation,
2660    /// rebase arm — unreachable when the caller peeked — and the absolute len-mirror sets,
2661    /// which land the same value the in-stream inc produced).
2662    #[allow(clippy::too_many_arguments)]
2663    pub fn append_tp_kv_transaction_inner(
2664        &self,
2665        cache: &mut ResidentTpKvCache,
2666        transaction: TpKvTransaction,
2667        k_shards: &[CudaSlice<f32>],
2668        v_shards: &[CudaSlice<f32>],
2669        rows: usize,
2670        external_rank_appends: bool,
2671    ) -> Result<(), Box<dyn std::error::Error>> {
2672        self.validate_tp_kv_cache(cache)?;
2673        let plan = cache.prepare_append(transaction, rows)?;
2674        let target = plan.target();
2675        let expected_k = rows
2676            .checked_mul(cache.kv_dim_k())
2677            .ok_or("TP KV K append size overflow")?;
2678        let expected_v = rows
2679            .checked_mul(cache.kv_dim_v())
2680            .ok_or("TP KV V append size overflow")?;
2681        // external_rank_appends passes no shards — the graph's dcw appends already wrote
2682        // the rank rows, so this call is bookkeeping-only and the shard slices are unused.
2683        if !external_rank_appends
2684            && (k_shards.len() != self.ranks.len() || v_shards.len() != self.ranks.len())
2685        {
2686            return Err(format!(
2687                "TP KV append shard counts k={} v={} != ranks {}",
2688                k_shards.len(),
2689                v_shards.len(),
2690                self.ranks.len()
2691            )
2692            .into());
2693        }
2694        let kv_dim_k = cache.kv_dim_k();
2695        let kv_dim_v = cache.kv_dim_v();
2696        let k_tok_bytes = cache.k_tok_bytes();
2697        let v_tok_bytes = cache.v_tok_bytes();
2698        if let Some(ring_base) = cache.ring_base() {
2699            let base_val = ring_base as i32;
2700            for rank in 0..self.ranks.len() {
2701                let engine = &self.ranks[rank];
2702                let _main = engine.gpu.enter_main()?;
2703                let rank_cache = cache
2704                    .rank_mut(rank)
2705                    .ok_or_else(|| format!("TP KV cache has no rank {rank}"))?;
2706                if rank_cache.base_d().is_none() {
2707                    rank_cache.arm_base_d(engine.htod_i32(&[base_val])?);
2708                }
2709            }
2710        }
2711        if let Some(KvRingAppend::Rebase {
2712            src_row,
2713            keep_rows,
2714            new_base,
2715            ..
2716        }) = plan.ring_append()
2717        {
2718            for rank in 0..self.ranks.len() {
2719                let engine = &self.ranks[rank];
2720                let _main = engine.gpu.enter_main()?;
2721                let rank_cache = cache
2722                    .rank_mut(rank)
2723                    .ok_or_else(|| format!("TP KV cache has no rank {rank}"))?;
2724                if keep_rows > 0 {
2725                    let k_len = keep_rows
2726                        .checked_mul(k_tok_bytes)
2727                        .ok_or("TP KV K rebase-byte overflow")?;
2728                    let v_len = keep_rows
2729                        .checked_mul(v_tok_bytes)
2730                        .ok_or("TP KV V rebase-byte overflow")?;
2731                    let mut k_tmp = engine.alloc_u8_uninit(k_len)?;
2732                    let mut v_tmp = engine.alloc_u8_uninit(v_len)?;
2733                    engine.copy_u8_range_into(
2734                        &mut k_tmp,
2735                        0,
2736                        rank_cache.k(),
2737                        src_row * k_tok_bytes,
2738                        k_len,
2739                    )?;
2740                    engine.copy_u8_range_into(
2741                        &mut v_tmp,
2742                        0,
2743                        rank_cache.v(),
2744                        src_row * v_tok_bytes,
2745                        v_len,
2746                    )?;
2747                    engine.copy_u8_into(rank_cache.k_mut(), 0, &k_tmp, k_len)?;
2748                    engine.copy_u8_into(rank_cache.v_mut(), 0, &v_tmp, v_len)?;
2749                }
2750                // dcw base mirror (graph increment A): physical row 0 now holds logical
2751                // row `new_base`; armed device mirrors track it (rebases are rare host
2752                // events, so a host set here is the whole maintenance cost).
2753                let value = new_base as i32;
2754                if let Some(base_d) = rank_cache.base_d_mut() {
2755                    engine.set_i32_one(base_d, value)?;
2756                } else {
2757                    rank_cache.arm_base_d(engine.htod_i32(&[value])?);
2758                }
2759            }
2760        }
2761        cache.publish_append_rebase(plan)?;
2762        let write_row = plan.write_row();
2763        for rank in 0..self.ranks.len() {
2764            if external_rank_appends {
2765                break;
2766            }
2767            let engine = &self.ranks[rank];
2768            let _main = engine.gpu.enter_main()?;
2769            if k_shards[rank].len() != expected_k
2770                || v_shards[rank].len() != expected_v
2771                || k_shards[rank].ordinal() != engine.ctx().ordinal()
2772                || v_shards[rank].ordinal() != engine.ctx().ordinal()
2773            {
2774                return Err(format!(
2775                    "TP KV rank {rank} shard geometry/device k={}/{} v={}/{} \
2776                     != expected {expected_k}/{expected_v} on device {}",
2777                    k_shards[rank].len(),
2778                    k_shards[rank].ordinal(),
2779                    v_shards[rank].len(),
2780                    v_shards[rank].ordinal(),
2781                    engine.ctx().ordinal(),
2782                )
2783                .into());
2784            }
2785            let rank_cache = cache
2786                .rank_mut(rank)
2787                .ok_or_else(|| format!("TP KV cache has no rank {rank}"))?;
2788            let (rank_k, rank_v) = rank_cache.planes_mut();
2789            engine.append_kv_quantized_rows(
2790                &k_shards[rank],
2791                &v_shards[rank],
2792                rank_k,
2793                rank_v,
2794                write_row,
2795                rows,
2796                kv_dim_k,
2797                kv_dim_v,
2798                k_tok_bytes,
2799                v_tok_bytes,
2800                Engine::kv_fp8_on(),
2801            )?;
2802        }
2803        if !external_rank_appends {
2804            // dcw appends advance the device counters with in-stream inc_i32; an absolute set
2805            // here would race the merged per-rank append (it reads len_d for its write row).
2806            self.set_tp_kv_len_mirrors(cache, target)?;
2807        }
2808        cache.publish_append_plan(plan)?;
2809        Ok(())
2810    }
2811
2812    pub fn commit_tp_kv_transaction(
2813        &self,
2814        cache: &mut ResidentTpKvCache,
2815        transaction: TpKvTransaction,
2816        accepted_rows: usize,
2817    ) -> Result<(), Box<dyn std::error::Error>> {
2818        self.validate_tp_kv_cache(cache)?;
2819        let target = cache.commit_target(transaction, accepted_rows)?;
2820        self.set_tp_kv_len_mirrors(cache, target)?;
2821        cache.publish_finalize(transaction, target)?;
2822        // This path derived the rank rows from the canonical rows, so a later restore from
2823        // the canonical cache is at worst redundant. See `rows_external`.
2824        cache.mark_rows_external(false);
2825        Ok(())
2826    }
2827
2828    /// Commit for the external-appends (token graph) path: host bookkeeping only, NO absolute
2829    /// len-mirror sets. The graph's in-stream inc_i32 owns the device counters; a rank-stream
2830    /// set here has no ordering edge against the NEXT token's graph launch (graph children do
2831    /// not wait on the rank streams), so it can land AFTER that graph's inc and drag the
2832    /// counter backward mid-token.
2833    pub fn commit_tp_kv_transaction_external(
2834        &self,
2835        cache: &mut ResidentTpKvCache,
2836        transaction: TpKvTransaction,
2837        accepted_rows: usize,
2838    ) -> Result<(), Box<dyn std::error::Error>> {
2839        self.validate_tp_kv_cache(cache)?;
2840        let target = cache.commit_target(transaction, accepted_rows)?;
2841        cache.publish_finalize(transaction, target)?;
2842        // The rank rows were written on-device by the caller (dcw / fa2 verify); the
2843        // canonical model-device cache only had its length advanced and holds stale content
2844        // for these rows. A verified-prefix restore must skip this layer (memra#128).
2845        cache.mark_rows_external(true);
2846        Ok(())
2847    }
2848
2849    pub fn rollback_tp_kv_transaction(
2850        &self,
2851        cache: &mut ResidentTpKvCache,
2852        transaction: TpKvTransaction,
2853    ) -> Result<(), Box<dyn std::error::Error>> {
2854        self.validate_tp_kv_cache(cache)?;
2855        cache.validate_transaction(transaction)?;
2856        let target = transaction.base_len();
2857        self.set_tp_kv_len_mirrors(cache, target)?;
2858        cache.publish_finalize(transaction, target)?;
2859        Ok(())
2860    }
2861
2862    pub fn tp_kv_device_lengths(
2863        &self,
2864        cache: &ResidentTpKvCache,
2865    ) -> Result<Vec<i32>, Box<dyn std::error::Error>> {
2866        self.validate_tp_kv_cache(cache)?;
2867        let mut lengths = Vec::with_capacity(self.ranks.len());
2868        for (engine, rank_cache) in self.ranks.iter().zip(cache.ranks()) {
2869            let _main = engine.gpu.enter_main()?;
2870            lengths.push(engine.dtoh_i32_one(rank_cache.len_d())?);
2871        }
2872        Ok(lengths)
2873    }
2874
2875    fn set_tp_kv_len_mirrors(
2876        &self,
2877        cache: &mut ResidentTpKvCache,
2878        len: usize,
2879    ) -> Result<(), Box<dyn std::error::Error>> {
2880        let len = i32::try_from(len).map_err(|_| "TP KV length exceeds i32 device mirror")?;
2881        for (engine, rank_cache) in self.ranks.iter().zip(cache.ranks_mut()) {
2882            let _main = engine.gpu.enter_main()?;
2883            engine.set_i32_one(rank_cache.len_d_mut(), len)?;
2884        }
2885        Ok(())
2886    }
2887
2888    fn validate_tp_kv_cache(
2889        &self,
2890        cache: &ResidentTpKvCache,
2891    ) -> Result<(), Box<dyn std::error::Error>> {
2892        if cache.ranks_len() != self.ranks.len() {
2893            return Err(format!(
2894                "TP KV cache ranks {} != runtime ranks {}",
2895                cache.ranks_len(),
2896                self.ranks.len()
2897            )
2898            .into());
2899        }
2900        let expected_k = cache
2901            .physical_capacity()
2902            .checked_mul(cache.k_tok_bytes())
2903            .and_then(|bytes| bytes.checked_add(8))
2904            .ok_or("TP KV K plane validation overflow")?;
2905        let expected_v = cache
2906            .physical_capacity()
2907            .checked_mul(cache.v_tok_bytes())
2908            .and_then(|bytes| bytes.checked_add(8))
2909            .ok_or("TP KV V plane validation overflow")?;
2910        for (rank, (engine, rank_cache)) in self.ranks.iter().zip(cache.ranks()).enumerate() {
2911            let device = engine.ctx().ordinal();
2912            if rank_cache.k().len() != expected_k
2913                || rank_cache.v().len() != expected_v
2914                || rank_cache.len_d().len() != 1
2915                || rank_cache.k().ordinal() != device
2916                || rank_cache.v().ordinal() != device
2917                || rank_cache.len_d().ordinal() != device
2918            {
2919                return Err(format!(
2920                    "TP KV rank {rank} residency does not match device {device} or plane geometry"
2921                )
2922                .into());
2923            }
2924        }
2925        Ok(())
2926    }
2927
2928    pub fn full(
2929        &self,
2930        matrix: E4m3BlockMatrix<'_>,
2931        activations: &[f32],
2932        tokens: usize,
2933    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
2934        matrix.validate()?;
2935        validate_activations(activations, tokens, matrix.in_features)?;
2936        run_rank(&self.ranks[0], matrix, activations, tokens)
2937    }
2938
2939    /// Column-parallel projection. Weight output rows and their scale rows are partitioned across
2940    /// ranks. The input is host-broadcast, rank-local projections execute independently, and the
2941    /// output is host-gathered in rank order.
2942    #[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
2943    pub fn column_parallel(
2944        &self,
2945        matrix: E4m3BlockMatrix<'_>,
2946        activations: &[f32],
2947        tokens: usize,
2948    ) -> Result<ColumnParallelResult, Box<dyn std::error::Error>> {
2949        matrix.validate()?;
2950        validate_activations(activations, tokens, matrix.in_features)?;
2951        let tp = self.ranks.len();
2952        if matrix.out_features % tp != 0 {
2953            return Err(format!(
2954                "column-parallel out_features {} is not divisible by TP={tp}",
2955                matrix.out_features
2956            )
2957            .into());
2958        }
2959        let local_out = matrix.out_features / tp;
2960        if !local_out.is_multiple_of(FP8_BLOCK) {
2961            return Err(format!(
2962                "column-parallel output shard {local_out} cuts through a {FP8_BLOCK}-row \
2963                 E4M3 scale block"
2964            )
2965            .into());
2966        }
2967
2968        let mut gathered = vec![0.0f32; tokens * matrix.out_features];
2969        let mut rank_outputs = Vec::with_capacity(tp);
2970        for (rank_index, rank) in self.ranks.iter().enumerate() {
2971            let shard = column_shard(matrix, tp, rank_index)?;
2972            let output = run_rank(rank, shard, activations, tokens)?;
2973            let row_start = rank_index * local_out;
2974            for token in 0..tokens {
2975                gathered[token * matrix.out_features + row_start
2976                    ..token * matrix.out_features + row_start + local_out]
2977                    .copy_from_slice(&output[token * local_out..(token + 1) * local_out]);
2978            }
2979            rank_outputs.push(output);
2980        }
2981        Ok(ColumnParallelResult {
2982            gathered,
2983            rank_outputs,
2984        })
2985    }
2986
2987    pub fn upload_column_parallel(
2988        &self,
2989        matrix: E4m3BlockMatrix<'_>,
2990    ) -> Result<ResidentColumnParallel, Box<dyn std::error::Error>> {
2991        matrix.validate()?;
2992        let tp = self.ranks.len();
2993        validate_column_shape(matrix, tp)?;
2994        let mut ranks = Vec::with_capacity(tp);
2995        for (rank_index, engine) in self.ranks.iter().enumerate() {
2996            ranks.push(upload_rank(engine, column_shard(matrix, tp, rank_index)?)?);
2997        }
2998        Ok(ResidentColumnParallel {
2999            ranks,
3000            out_features: matrix.out_features,
3001            in_features: matrix.in_features,
3002        })
3003    }
3004
3005    pub fn column_parallel_resident(
3006        &self,
3007        matrix: &ResidentColumnParallel,
3008        activations: &[f32],
3009        tokens: usize,
3010    ) -> Result<ColumnParallelResult, Box<dyn std::error::Error>> {
3011        validate_resident_ranks(&self.ranks, &matrix.ranks)?;
3012        validate_activations(activations, tokens, matrix.in_features)?;
3013        let local_out = matrix.out_features / self.ranks.len();
3014        let mut gathered = vec![0.0f32; tokens * matrix.out_features];
3015        let mut rank_outputs = Vec::with_capacity(self.ranks.len());
3016        for (rank_index, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
3017            let output = run_resident_rank(engine, shard, activations, tokens)?;
3018            let row_start = rank_index * local_out;
3019            for token in 0..tokens {
3020                gathered[token * matrix.out_features + row_start
3021                    ..token * matrix.out_features + row_start + local_out]
3022                    .copy_from_slice(&output[token * local_out..(token + 1) * local_out]);
3023            }
3024            rank_outputs.push(output);
3025        }
3026        Ok(ColumnParallelResult {
3027            gathered,
3028            rank_outputs,
3029        })
3030    }
3031
3032    /// Row-parallel projection. Weight/input columns and their scale columns are partitioned
3033    /// across ranks. Rank-local partials return through host memory and are reduced in stable
3034    /// rank order.
3035    #[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
3036    pub fn row_parallel(
3037        &self,
3038        matrix: E4m3BlockMatrix<'_>,
3039        activations: &[f32],
3040        tokens: usize,
3041    ) -> Result<RowParallelResult, Box<dyn std::error::Error>> {
3042        matrix.validate()?;
3043        validate_activations(activations, tokens, matrix.in_features)?;
3044        let tp = self.ranks.len();
3045        if matrix.in_features % tp != 0 {
3046            return Err(format!(
3047                "row-parallel in_features {} is not divisible by TP={tp}",
3048                matrix.in_features
3049            )
3050            .into());
3051        }
3052        let local_in = matrix.in_features / tp;
3053        if !local_in.is_multiple_of(FP8_BLOCK) {
3054            return Err(format!(
3055                "row-parallel input shard {local_in} cuts through a {FP8_BLOCK}-column \
3056                 E4M3 scale block"
3057            )
3058            .into());
3059        }
3060
3061        let mut reduced = vec![0.0f32; tokens * matrix.out_features];
3062        let mut rank_partials = Vec::with_capacity(tp);
3063        for (rank_index, rank) in self.ranks.iter().enumerate() {
3064            let (codes, scales) = row_shard(matrix, tp, rank_index)?;
3065            let local_activations =
3066                activation_shard(activations, tokens, matrix.in_features, tp, rank_index);
3067            let shard = E4m3BlockMatrix {
3068                codes: &codes,
3069                scales: &scales,
3070                out_features: matrix.out_features,
3071                in_features: local_in,
3072            };
3073            let partial = run_rank(rank, shard, &local_activations, tokens)?;
3074            for (sum, value) in reduced.iter_mut().zip(&partial) {
3075                *sum += *value;
3076            }
3077            rank_partials.push(partial);
3078        }
3079        Ok(RowParallelResult {
3080            reduced,
3081            rank_partials,
3082        })
3083    }
3084
3085    pub fn upload_row_parallel(
3086        &self,
3087        matrix: E4m3BlockMatrix<'_>,
3088    ) -> Result<ResidentRowParallel, Box<dyn std::error::Error>> {
3089        matrix.validate()?;
3090        let tp = self.ranks.len();
3091        validate_row_shape(matrix, tp)?;
3092        let local_in = matrix.in_features / tp;
3093        let mut ranks = Vec::with_capacity(tp);
3094        for (rank_index, engine) in self.ranks.iter().enumerate() {
3095            let (codes, scales) = row_shard(matrix, tp, rank_index)?;
3096            ranks.push(upload_rank(
3097                engine,
3098                E4m3BlockMatrix {
3099                    codes: &codes,
3100                    scales: &scales,
3101                    out_features: matrix.out_features,
3102                    in_features: local_in,
3103                },
3104            )?);
3105        }
3106        Ok(ResidentRowParallel {
3107            ranks,
3108            out_features: matrix.out_features,
3109            in_features: matrix.in_features,
3110        })
3111    }
3112
3113    pub fn row_parallel_resident(
3114        &self,
3115        matrix: &ResidentRowParallel,
3116        activations: &[f32],
3117        tokens: usize,
3118    ) -> Result<RowParallelResult, Box<dyn std::error::Error>> {
3119        validate_resident_ranks(&self.ranks, &matrix.ranks)?;
3120        validate_activations(activations, tokens, matrix.in_features)?;
3121        let tp = self.ranks.len();
3122        let mut reduced = vec![0.0f32; tokens * matrix.out_features];
3123        let mut rank_partials = Vec::with_capacity(tp);
3124        for (rank_index, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
3125            let local_activations =
3126                activation_shard(activations, tokens, matrix.in_features, tp, rank_index);
3127            let partial = run_resident_rank(engine, shard, &local_activations, tokens)?;
3128            for (sum, value) in reduced.iter_mut().zip(&partial) {
3129                *sum += *value;
3130            }
3131            rank_partials.push(partial);
3132        }
3133        Ok(RowParallelResult {
3134            reduced,
3135            rank_partials,
3136        })
3137    }
3138
3139    pub fn upload_bf16_column_parallel(
3140        &self,
3141        matrix: Bf16Matrix<'_>,
3142    ) -> Result<ResidentBf16ColumnParallel, Box<dyn std::error::Error>> {
3143        self.upload_bf16_column_parallel_inner(matrix, None, false)
3144    }
3145
3146    /// Step-3.7 column projection with one numerical program across TP1/TP2/TP4/TP8.
3147    pub fn upload_step_bf16_column_parallel(
3148        &self,
3149        matrix: Bf16Matrix<'_>,
3150    ) -> Result<ResidentBf16ColumnParallel, Box<dyn std::error::Error>> {
3151        self.upload_step_bf16_column_parallel_inner(matrix, false)
3152    }
3153
3154    /// Load-time exact F32 expansion of a Step BF16 shard.
3155    ///
3156    /// The original BF16 allocation is released after the stream-ordered conversion. Decode then
3157    /// reuses the resident F32 values with the same topology-invariant output-row chunks.
3158    pub fn upload_step_bf16_column_parallel_f32_mirror(
3159        &self,
3160        matrix: Bf16Matrix<'_>,
3161    ) -> Result<ResidentBf16ColumnParallel, Box<dyn std::error::Error>> {
3162        self.upload_step_bf16_column_parallel_inner(matrix, true)
3163    }
3164
3165    fn upload_step_bf16_column_parallel_inner(
3166        &self,
3167        matrix: Bf16Matrix<'_>,
3168        f32_mirror: bool,
3169    ) -> Result<ResidentBf16ColumnParallel, Box<dyn std::error::Error>> {
3170        let canonical_chunk_rows =
3171            step_bf16_canonical_chunk_rows(matrix.out_features, self.ranks.len())?;
3172        self.upload_bf16_column_parallel_inner(matrix, Some(canonical_chunk_rows), f32_mirror)
3173    }
3174
3175    #[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
3176    fn upload_bf16_column_parallel_inner(
3177        &self,
3178        matrix: Bf16Matrix<'_>,
3179        canonical_chunk_rows: Option<usize>,
3180        f32_mirror: bool,
3181    ) -> Result<ResidentBf16ColumnParallel, Box<dyn std::error::Error>> {
3182        matrix.validate()?;
3183        let tp = self.ranks.len();
3184        if matrix.out_features % tp != 0 {
3185            return Err(format!(
3186                "BF16 column-parallel out_features {} is not divisible by TP={tp}",
3187                matrix.out_features
3188            )
3189            .into());
3190        }
3191        let mut ranks = Vec::with_capacity(tp);
3192        for (rank, engine) in self.ranks.iter().enumerate() {
3193            ranks.push(upload_bf16_rank(
3194                engine,
3195                bf16_column_shard(matrix, tp, rank)?,
3196                f32_mirror,
3197            )?);
3198        }
3199        Ok(ResidentBf16ColumnParallel {
3200            ranks,
3201            out_features: matrix.out_features,
3202            in_features: matrix.in_features,
3203            canonical_chunk_rows,
3204        })
3205    }
3206
3207    pub fn bf16_column_parallel_resident(
3208        &self,
3209        matrix: &ResidentBf16ColumnParallel,
3210        activations: &[f32],
3211        tokens: usize,
3212    ) -> Result<ColumnParallelResult, Box<dyn std::error::Error>> {
3213        validate_resident_bf16_ranks(&self.ranks, &matrix.ranks)?;
3214        validate_activations(activations, tokens, matrix.in_features)?;
3215        let local_out = matrix.out_features / self.ranks.len();
3216        let mut gathered = vec![0.0f32; tokens * matrix.out_features];
3217        let mut rank_outputs = Vec::with_capacity(self.ranks.len());
3218        for (rank, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
3219            let output = run_resident_bf16_rank(
3220                engine,
3221                shard,
3222                activations,
3223                tokens,
3224                matrix.canonical_chunk_rows,
3225            )?;
3226            for token in 0..tokens {
3227                let src = &output[token * local_out..(token + 1) * local_out];
3228                let dst_start = token * matrix.out_features + rank * local_out;
3229                gathered[dst_start..dst_start + local_out].copy_from_slice(src);
3230            }
3231            rank_outputs.push(output);
3232        }
3233        Ok(ColumnParallelResult {
3234            gathered,
3235            rank_outputs,
3236        })
3237    }
3238
3239    /// Native-P2P twin of [`Self::bf16_column_parallel_resident`].
3240    ///
3241    /// The host-canonical activation is uploaded once on rank zero and peer-broadcast to the
3242    /// remaining ranks. Rank-local outputs are peer-gathered in token-major order before one root
3243    /// readback. This removes per-rank host staging but deliberately still returns a host oracle;
3244    /// attention and KV ownership are separate milestones.
3245    pub fn bf16_column_parallel_resident_native(
3246        &self,
3247        matrix: &ResidentBf16ColumnParallel,
3248        activations: &[f32],
3249        tokens: usize,
3250    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
3251        let rank_outputs =
3252            self.bf16_column_parallel_resident_device_shards(matrix, activations, tokens)?;
3253        let local_out = matrix.out_features / self.ranks.len();
3254        self.gather_native_column_shards(&rank_outputs, tokens, local_out)
3255    }
3256
3257    /// Does the serving engine live in the SAME CUDA context as this runtime's root rank?
3258    /// The device-resident input/output seams below hand raw device buffers across the
3259    /// Engine boundary, which is only addressable when both sides share the root device's
3260    /// primary context — the generic full-attention TP seam keys its residency dispatch on.
3261    pub fn root_shares_ctx(&self, e: &Engine) -> bool {
3262        self.ranks
3263            .first()
3264            .is_some_and(|root| root.ctx().cu_ctx() == e.ctx().cu_ctx())
3265    }
3266
3267    /// Device-input twin of [`Self::bf16_column_parallel_resident_native`] (lane/
3268    /// hermes-perf-fixes, 2026-08-23 — the step QKV TP host-bounce finding). The activation
3269    /// arrives as a ROOT-DEVICE buffer (first `tokens * in_features` values) instead of a
3270    /// host slice, and the gathered output stays root-resident: no DtoH of the hidden state,
3271    /// no host q/k/v staging, no re-upload. BYTE-IDENTICAL to the host-canonical native arm
3272    /// by construction — the root input bytes are dtod-copied where the host arm htod'd the
3273    /// same bytes, and every kernel, peer copy, and gather order is shared.
3274    ///
3275    /// FENCES: caller must have synchronized the producer stream that wrote
3276    /// `root_activation` (the serving engine's — a DIFFERENT stream in the same context);
3277    /// this method synchronizes the root stream before returning so the caller's stream can
3278    /// consume the gathered output immediately.
3279    pub fn bf16_column_parallel_resident_native_device(
3280        &self,
3281        matrix: &ResidentBf16ColumnParallel,
3282        root_activation: &CudaSlice<f32>,
3283        tokens: usize,
3284    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
3285        let rank_outputs = self.bf16_column_parallel_resident_device_shards_from_root(
3286            matrix,
3287            root_activation,
3288            tokens,
3289        )?;
3290        let local_out = matrix.out_features / self.ranks.len();
3291        let gathered = self.gather_native_column_shards_device(&rank_outputs, tokens, local_out)?;
3292        let root = &self.ranks[0];
3293        let _main = root.gpu.enter_main()?;
3294        root.stream().synchronize()?;
3295        Ok(gathered)
3296    }
3297
3298    /// Root-device-input twin of [`Self::bf16_column_parallel_resident_device_shards`]:
3299    /// the canonical activation is already resident on the root device (len >=
3300    /// `tokens * in_features`; extra tail values beyond the active prefix are ignored,
3301    /// the reused-prime-slab contract of `active_matrix_values`).
3302    pub fn bf16_column_parallel_resident_device_shards_from_root(
3303        &self,
3304        matrix: &ResidentBf16ColumnParallel,
3305        root_activation: &CudaSlice<f32>,
3306        tokens: usize,
3307    ) -> Result<Vec<CudaSlice<f32>>, Box<dyn std::error::Error>> {
3308        if self.ranks.len() > 1 && !self.native_p2p {
3309            return Err("device-resident BF16 column parallelism requires native P2P ranks".into());
3310        }
3311        validate_resident_bf16_ranks(&self.ranks, &matrix.ranks)?;
3312        let values = tokens
3313            .checked_mul(matrix.in_features)
3314            .ok_or("device BF16 column activation size overflow")?;
3315        let root = &self.ranks[0];
3316        if tokens == 0
3317            || root_activation.len() < values
3318            || root_activation.ordinal() != root.ctx().ordinal()
3319        {
3320            return Err("device BF16 column root activation geometry mismatch".into());
3321        }
3322
3323        let mut rank_inputs = Vec::with_capacity(self.ranks.len());
3324        let root_input = {
3325            let _main = root.gpu.enter_main()?;
3326            let mut root_input = root.uninit(values)?;
3327            root.stream()
3328                .memcpy_dtod(&root_activation.slice(0..values), &mut root_input)?;
3329            root_input
3330        };
3331        // PRODUCER FENCE (same discipline as the host-input twin): the peer broadcast
3332        // below reads this buffer from the OTHER ranks' streams while the root dtod may
3333        // still be in flight.
3334        {
3335            let _main = root.gpu.enter_main()?;
3336            root.stream().synchronize()?;
3337        }
3338        rank_inputs.push(root_input);
3339        for engine in &self.ranks[1..] {
3340            let peer_input = {
3341                let _main = engine.gpu.enter_main()?;
3342                let mut peer_input = engine.uninit(values)?;
3343                engine
3344                    .stream()
3345                    .memcpy_dtod(&rank_inputs[0], &mut peer_input)?;
3346                peer_input
3347            };
3348            rank_inputs.push(peer_input);
3349        }
3350
3351        let mut rank_outputs = Vec::with_capacity(self.ranks.len());
3352        #[allow(clippy::needless_range_loop)]
3353        // allow: the explicit index loop keeps the offset arithmetic visible and aligned with the device-side indexing
3354        for rank in 0..self.ranks.len() {
3355            rank_outputs.push(run_resident_bf16_rank_device(
3356                &self.ranks[rank],
3357                &matrix.ranks[rank],
3358                &rank_inputs[rank],
3359                tokens,
3360                matrix.canonical_chunk_rows,
3361                self.bulk_p2p,
3362            )?);
3363        }
3364        Ok(rank_outputs)
3365    }
3366
3367    /// Keep Step BF16 column outputs resident on their owning TP ranks.
3368    ///
3369    /// Rank zero receives the host-canonical activation once and peer-broadcasts it when TP>1.
3370    /// Unlike [`Self::bf16_column_parallel_resident_native`], this method performs no output
3371    /// gather or readback. It is the correctness substrate for rank-local norm, RoPE, attention,
3372    /// and cache ownership; callers must not treat its existence as serving qualification.
3373    pub fn bf16_column_parallel_resident_device_shards(
3374        &self,
3375        matrix: &ResidentBf16ColumnParallel,
3376        activations: &[f32],
3377        tokens: usize,
3378    ) -> Result<Vec<CudaSlice<f32>>, Box<dyn std::error::Error>> {
3379        if self.ranks.len() > 1 && !self.native_p2p {
3380            return Err("device-resident BF16 column parallelism requires native P2P ranks".into());
3381        }
3382        validate_resident_bf16_ranks(&self.ranks, &matrix.ranks)?;
3383        validate_activations(activations, tokens, matrix.in_features)?;
3384
3385        let mut rank_inputs = Vec::with_capacity(self.ranks.len());
3386        let root_input = {
3387            let root = &self.ranks[0];
3388            let _main = root.gpu.enter_main()?;
3389            root.htod(activations)?
3390        };
3391        // PRODUCER FENCE (2026-08-20 flake fix): the peer broadcast below reads this buffer from
3392        // the OTHER ranks' streams, and clone_htod is asynchronous on the root stream. Without
3393        // this fence a peer copy can overtake the in-flight H2D and replicate stale bytes — the
3394        // measured ~30%-of-boots prefill/decode argmax flake. Same discipline as
3395        // `upload_replicated_device_rows`.
3396        {
3397            let root = &self.ranks[0];
3398            let _main = root.gpu.enter_main()?;
3399            root.stream().synchronize()?;
3400        }
3401        rank_inputs.push(root_input);
3402        for engine in &self.ranks[1..] {
3403            let peer_input = {
3404                let _main = engine.gpu.enter_main()?;
3405                let mut peer_input = engine.uninit(activations.len())?;
3406                engine
3407                    .stream()
3408                    .memcpy_dtod(&rank_inputs[0], &mut peer_input)?;
3409                peer_input
3410            };
3411            rank_inputs.push(peer_input);
3412        }
3413
3414        let mut rank_outputs = Vec::with_capacity(self.ranks.len());
3415        #[allow(clippy::needless_range_loop)]
3416        // allow: the explicit index loop keeps the offset arithmetic visible and aligned with the device-side indexing
3417        for rank in 0..self.ranks.len() {
3418            rank_outputs.push(run_resident_bf16_rank_device(
3419                &self.ranks[rank],
3420                &matrix.ranks[rank],
3421                &rank_inputs[rank],
3422                tokens,
3423                matrix.canonical_chunk_rows,
3424                self.bulk_p2p,
3425            )?);
3426        }
3427        Ok(rank_outputs)
3428    }
3429
3430    /// Allocate one fixed-shape replicated batch without initializing its contents.
3431    ///
3432    /// Callers must refresh every rank before passing the batch to an operator.
3433    pub fn allocate_replicated_device_rows(
3434        &self,
3435        tokens: usize,
3436        width: usize,
3437    ) -> Result<ResidentReplicatedDeviceRows, Box<dyn std::error::Error>> {
3438        if self.ranks.len() > 1 && !self.native_p2p {
3439            return Err("replicated device rows require native P2P ranks".into());
3440        }
3441        let values = tokens
3442            .checked_mul(width)
3443            .ok_or("replicated device row size overflow")?;
3444        let rank_lengths = vec![values; self.ranks.len()];
3445        replicated_device_row_values(tokens, width, self.ranks.len(), &rank_lengths)?;
3446        let mut ranks = Vec::with_capacity(self.ranks.len());
3447        for engine in &self.ranks {
3448            let _main = engine.gpu.enter_main()?;
3449            ranks.push(engine.uninit(values)?);
3450        }
3451        Ok(ResidentReplicatedDeviceRows {
3452            ranks,
3453            tokens,
3454            width,
3455        })
3456    }
3457
3458    /// Replace a fixed-shape replicated batch from a root-device source.
3459    pub fn refresh_replicated_device_rows_from_root(
3460        &self,
3461        rows: &mut ResidentReplicatedDeviceRows,
3462        source: &CudaSlice<f32>,
3463    ) -> Result<(), Box<dyn std::error::Error>> {
3464        if self.ranks.len() > 1 && !self.native_p2p {
3465            return Err("replicated device rows require native P2P ranks".into());
3466        }
3467        validate_replicated_device_rows(&self.ranks, rows)?;
3468        let root = self
3469            .ranks
3470            .first()
3471            .ok_or("replicated rows have no root rank")?;
3472        let values = replicated_device_row_source_values(
3473            rows.tokens,
3474            rows.width,
3475            source.len(),
3476            source.ordinal(),
3477            root.ctx().ordinal(),
3478        )?;
3479        let (root_rows, peer_rows) = rows
3480            .ranks
3481            .split_first_mut()
3482            .ok_or("replicated rows have no root allocation")?;
3483        {
3484            let _main = root.gpu.enter_main()?;
3485            let mut destination = root_rows.slice_mut(0..values);
3486            root.stream()
3487                .memcpy_dtod(&source.slice(0..values), &mut destination)?;
3488            root.stream().synchronize()?;
3489        }
3490        for (engine, peer_rows) in self.ranks.iter().skip(1).zip(peer_rows) {
3491            let _main = engine.gpu.enter_main()?;
3492            let mut destination = peer_rows.slice_mut(0..values);
3493            engine
3494                .stream()
3495                .memcpy_dtod(&root_rows.slice(0..values), &mut destination)?;
3496        }
3497        Ok(())
3498    }
3499
3500    /// Upload one canonical batch on rank zero and replicate it over native P2P.
3501    pub fn upload_replicated_device_rows(
3502        &self,
3503        rows: &[f32],
3504        tokens: usize,
3505        width: usize,
3506    ) -> Result<ResidentReplicatedDeviceRows, Box<dyn std::error::Error>> {
3507        if self.ranks.len() > 1 && !self.native_p2p {
3508            return Err("replicated device rows require native P2P ranks".into());
3509        }
3510        validate_activations(rows, tokens, width)?;
3511        let root = self
3512            .ranks
3513            .first()
3514            .ok_or("replicated rows have no root rank")?;
3515        let root_rows = {
3516            let _main = root.gpu.enter_main()?;
3517            root.htod(rows)?
3518        };
3519        {
3520            let _main = root.gpu.enter_main()?;
3521            root.stream().synchronize()?;
3522        }
3523        let mut ranks = Vec::with_capacity(self.ranks.len());
3524        ranks.push(root_rows);
3525        for engine in self.ranks.iter().skip(1) {
3526            let _main = engine.gpu.enter_main()?;
3527            let mut peer_rows = engine.uninit(rows.len())?;
3528            engine.stream().memcpy_dtod(&ranks[0], &mut peer_rows)?;
3529            ranks.push(peer_rows);
3530        }
3531        Ok(ResidentReplicatedDeviceRows {
3532            ranks,
3533            tokens,
3534            width,
3535        })
3536    }
3537
3538    /// Execute a column-parallel BF16 matrix directly from rank-local replicated inputs.
3539    pub fn bf16_column_parallel_resident_replicated_device_shards(
3540        &self,
3541        matrix: &ResidentBf16ColumnParallel,
3542        activations: &ResidentReplicatedDeviceRows,
3543    ) -> Result<Vec<CudaSlice<f32>>, Box<dyn std::error::Error>> {
3544        validate_resident_bf16_ranks(&self.ranks, &matrix.ranks)?;
3545        validate_replicated_device_rows(&self.ranks, activations)?;
3546        if activations.width != matrix.in_features {
3547            return Err(format!(
3548                "replicated BF16 column input width {} != matrix width {}",
3549                activations.width, matrix.in_features
3550            )
3551            .into());
3552        }
3553        let mut outputs = Vec::with_capacity(self.ranks.len());
3554        for rank in 0..self.ranks.len() {
3555            outputs.push(run_resident_bf16_rank_device(
3556                &self.ranks[rank],
3557                &matrix.ranks[rank],
3558                &activations.ranks[rank],
3559                activations.tokens,
3560                matrix.canonical_chunk_rows,
3561                self.bulk_p2p,
3562            )?);
3563        }
3564        Ok(outputs)
3565    }
3566
3567    /// Upload a BF16 router once on rank zero and retain its exact F32 expansion.
3568    #[allow(clippy::too_many_arguments)]
3569    pub fn upload_sigmoid_topk_router(
3570        &self,
3571        weight: Bf16Matrix<'_>,
3572        correction_bias: &[f32],
3573        active: Option<&[bool]>,
3574        experts_per_token: usize,
3575        scaling_factor: f32,
3576        route_norm: bool,
3577    ) -> Result<ResidentSigmoidTopKRouter, Box<dyn std::error::Error>> {
3578        weight.validate()?;
3579        if correction_bias.len() != weight.out_features
3580            || experts_per_token == 0
3581            || experts_per_token > weight.out_features
3582            || !correction_bias.iter().all(|value| value.is_finite())
3583            || !scaling_factor.is_finite()
3584            || scaling_factor <= 0.0
3585        {
3586            return Err(format!(
3587                "sigmoid router geometry weight={}x{} bias={} top_k={} scale={scaling_factor}",
3588                weight.out_features,
3589                weight.in_features,
3590                correction_bias.len(),
3591                experts_per_token,
3592            )
3593            .into());
3594        }
3595        let active_row = active
3596            .map(|mask| {
3597                if mask.len() != weight.out_features {
3598                    return Err(format!(
3599                        "sigmoid router active mask {} != experts {}",
3600                        mask.len(),
3601                        weight.out_features
3602                    ));
3603                }
3604                Ok(mask
3605                    .iter()
3606                    .map(|&enabled| u8::from(enabled))
3607                    .collect::<Vec<_>>())
3608            })
3609            .transpose()?
3610            .unwrap_or_else(|| vec![1; weight.out_features]);
3611        let active_count = active_row.iter().filter(|&&enabled| enabled != 0).count();
3612        crate::sigrouter_contract::validate_active_count(experts_per_token, active_count)?;
3613
3614        let root = self
3615            .ranks
3616            .first()
3617            .ok_or("sigmoid router runtime has no root rank")?;
3618        let _main = root.gpu.enter_main()?;
3619        let bf16 = root.htod_bytes(weight.bytes)?;
3620        let weight_f32 = root.bf16_to_f32(
3621            &bf16.slice(0..bf16.len()),
3622            weight.out_features * weight.in_features,
3623        )?;
3624        Ok(ResidentSigmoidTopKRouter {
3625            weight: weight_f32,
3626            correction_bias: root.htod(correction_bias)?,
3627            active: root.htod_bytes(&active_row)?,
3628            root_device: root.ctx().ordinal(),
3629            input_width: weight.in_features,
3630            expert_count: weight.out_features,
3631            experts_per_token,
3632            active_count,
3633            scaling_factor,
3634            route_norm,
3635        })
3636    }
3637
3638    /// Route rank-zero replicated rows and return the narrow host control result plus logits.
3639    ///
3640    /// The logits readback exists for independent oracle comparison. This method is a correctness
3641    /// surface; a serving scheduler may retain logits and selected routes on device.
3642    pub fn sigmoid_topk_replicated_device_rows_host(
3643        &self,
3644        router: &ResidentSigmoidTopKRouter,
3645        input: &ResidentReplicatedDeviceRows,
3646    ) -> Result<SigmoidTopKHostOutput, Box<dyn std::error::Error>> {
3647        validate_replicated_device_rows(&self.ranks, input)?;
3648        if input.width != router.input_width {
3649            return Err(format!(
3650                "sigmoid router input width {} != resident width {}",
3651                input.width, router.input_width
3652            )
3653            .into());
3654        }
3655        let root = self
3656            .ranks
3657            .first()
3658            .ok_or("sigmoid router runtime has no root rank")?;
3659        let _main = root.gpu.enter_main()?;
3660        if root.ctx().ordinal() != router.root_device
3661            || router.weight.ordinal() != router.root_device
3662            || router.correction_bias.ordinal() != router.root_device
3663            || router.active.ordinal() != router.root_device
3664        {
3665            return Err("sigmoid router root residency changed".into());
3666        }
3667        let logits = root.router_gemv(
3668            &router.weight,
3669            &input.ranks[0],
3670            router.input_width,
3671            router.expert_count,
3672            input.tokens,
3673        )?;
3674        let (selected, weights) = root.moe_router_sigmoid_topk_host(
3675            &logits,
3676            input.tokens,
3677            router.expert_count,
3678            router.experts_per_token,
3679            router.active_count,
3680            &router.correction_bias,
3681            &router.active,
3682            router.scaling_factor,
3683            router.route_norm,
3684        )?;
3685        Ok(SigmoidTopKHostOutput {
3686            logits: root.dtoh(&logits)?,
3687            selected,
3688            weights,
3689        })
3690    }
3691
3692    /// Replicate a full BF16 SwiGLU bank on every rank.
3693    pub fn upload_replicated_bf16_swiglu(
3694        &self,
3695        gate: Bf16Matrix<'_>,
3696        up: Bf16Matrix<'_>,
3697        down: Bf16Matrix<'_>,
3698    ) -> Result<ResidentReplicatedBf16SwiGlu, Box<dyn std::error::Error>> {
3699        gate.validate()?;
3700        up.validate()?;
3701        down.validate()?;
3702        if gate.in_features != up.in_features
3703            || gate.out_features != up.out_features
3704            || down.in_features != gate.out_features
3705            || down.out_features != gate.in_features
3706        {
3707            return Err(format!(
3708                "replicated BF16 SwiGLU geometry gate={}x{} up={}x{} down={}x{}",
3709                gate.out_features,
3710                gate.in_features,
3711                up.out_features,
3712                up.in_features,
3713                down.out_features,
3714                down.in_features,
3715            )
3716            .into());
3717        }
3718        let mut gate_ranks = Vec::with_capacity(self.ranks.len());
3719        let mut up_ranks = Vec::with_capacity(self.ranks.len());
3720        let mut down_ranks = Vec::with_capacity(self.ranks.len());
3721        for engine in &self.ranks {
3722            gate_ranks.push(upload_bf16_rank(engine, gate, false)?);
3723            up_ranks.push(upload_bf16_rank(engine, up, false)?);
3724            down_ranks.push(upload_bf16_rank(engine, down, false)?);
3725        }
3726        Ok(ResidentReplicatedBf16SwiGlu {
3727            gate: gate_ranks,
3728            up: up_ranks,
3729            down: down_ranks,
3730            input_width: gate.in_features,
3731            intermediate_width: gate.out_features,
3732        })
3733    }
3734
3735    /// Execute a fully replicated BF16 SwiGLU directly from replicated device rows.
3736    pub fn replicated_bf16_swiglu_resident_device(
3737        &self,
3738        mlp: &ResidentReplicatedBf16SwiGlu,
3739        input: &ResidentReplicatedDeviceRows,
3740        activation_limit: Option<f32>,
3741    ) -> Result<ResidentReplicatedDeviceRows, Box<dyn std::error::Error>> {
3742        validate_step_expert_activation_limit(activation_limit)?;
3743        validate_replicated_device_rows(&self.ranks, input)?;
3744        validate_resident_bf16_ranks(&self.ranks, &mlp.gate)?;
3745        validate_resident_bf16_ranks(&self.ranks, &mlp.up)?;
3746        validate_resident_bf16_ranks(&self.ranks, &mlp.down)?;
3747        if input.width != mlp.input_width
3748            || mlp.gate.len() != self.ranks.len()
3749            || mlp.up.len() != self.ranks.len()
3750            || mlp.down.len() != self.ranks.len()
3751        {
3752            return Err("replicated BF16 SwiGLU residency or input width changed".into());
3753        }
3754
3755        let mut outputs = Vec::with_capacity(self.ranks.len());
3756        for rank in 0..self.ranks.len() {
3757            let engine = &self.ranks[rank];
3758            let gate = run_resident_bf16_rank_device(
3759                engine,
3760                &mlp.gate[rank],
3761                &input.ranks[rank],
3762                input.tokens,
3763                None,
3764                self.bulk_p2p,
3765            )?;
3766            let up = run_resident_bf16_rank_device(
3767                engine,
3768                &mlp.up[rank],
3769                &input.ranks[rank],
3770                input.tokens,
3771                None,
3772                self.bulk_p2p,
3773            )?;
3774            let _main = engine.gpu.enter_main()?;
3775            let values = input
3776                .tokens
3777                .checked_mul(mlp.intermediate_width)
3778                .ok_or("replicated BF16 SwiGLU activation size overflow")?;
3779            let mut activation = engine.uninit(values)?;
3780            if let Some(limit) = activation_limit {
3781                engine.silu_clamped_mul_host_expf(&gate, &up, limit, &mut activation, values)?;
3782            } else {
3783                engine.silu_mul_host_expf(&gate, &up, &mut activation, values)?;
3784            }
3785            outputs.push(run_resident_bf16_rank_device(
3786                engine,
3787                &mlp.down[rank],
3788                &activation,
3789                input.tokens,
3790                None,
3791                self.bulk_p2p,
3792            )?);
3793        }
3794        Ok(ResidentReplicatedDeviceRows {
3795            ranks: outputs,
3796            tokens: input.tokens,
3797            width: mlp.input_width,
3798        })
3799    }
3800
3801    /// Apply the same RMS-norm row program independently on every replicated rank.
3802    pub fn rms_norm_replicated_device_rows(
3803        &self,
3804        input: &ResidentReplicatedDeviceRows,
3805        weight: &[f32],
3806        eps: f32,
3807    ) -> Result<ResidentReplicatedDeviceRows, Box<dyn std::error::Error>> {
3808        validate_replicated_device_rows(&self.ranks, input)?;
3809        if weight.len() != input.width || !eps.is_finite() || eps <= 0.0 {
3810            return Err(format!(
3811                "replicated RMS norm weight/eps {}/{} != width {}",
3812                weight.len(),
3813                eps,
3814                input.width
3815            )
3816            .into());
3817        }
3818        let mut ranks = Vec::with_capacity(self.ranks.len());
3819        for (rank, engine) in self.ranks.iter().enumerate() {
3820            let _main = engine.gpu.enter_main()?;
3821            let weight = engine.htod(weight)?;
3822            let mut output = engine.uninit(input.tokens * input.width)?;
3823            engine.rms_norm(
3824                &input.ranks[rank],
3825                &weight,
3826                &mut output,
3827                input.width,
3828                input.tokens,
3829                eps,
3830            )?;
3831            ranks.push(output);
3832        }
3833        Ok(ResidentReplicatedDeviceRows {
3834            ranks,
3835            tokens: input.tokens,
3836            width: input.width,
3837        })
3838    }
3839
3840    /// Add two replicated batches and RMS-normalize the exact residual on every rank.
3841    pub fn add_rms_norm_replicated_device_rows(
3842        &self,
3843        input: &ResidentReplicatedDeviceRows,
3844        update: &ResidentReplicatedDeviceRows,
3845        weight: &[f32],
3846        eps: f32,
3847    ) -> Result<
3848        (ResidentReplicatedDeviceRows, ResidentReplicatedDeviceRows),
3849        Box<dyn std::error::Error>,
3850    > {
3851        validate_replicated_device_rows(&self.ranks, input)?;
3852        validate_replicated_device_rows(&self.ranks, update)?;
3853        if input.tokens != update.tokens
3854            || input.width != update.width
3855            || weight.len() != input.width
3856            || !eps.is_finite()
3857            || eps <= 0.0
3858        {
3859            return Err(format!(
3860                "replicated add/RMS geometry input={}x{} update={}x{} weight={} eps={eps}",
3861                input.tokens,
3862                input.width,
3863                update.tokens,
3864                update.width,
3865                weight.len(),
3866            )
3867            .into());
3868        }
3869        let values = input.tokens * input.width;
3870        let mut residual_ranks = Vec::with_capacity(self.ranks.len());
3871        let mut normalized_ranks = Vec::with_capacity(self.ranks.len());
3872        for (rank, engine) in self.ranks.iter().enumerate() {
3873            let _main = engine.gpu.enter_main()?;
3874            let weight = engine.htod(weight)?;
3875            let mut residual = engine.uninit(values)?;
3876            let mut normalized = engine.uninit(values)?;
3877            engine.add_rms_norm(
3878                &input.ranks[rank],
3879                &update.ranks[rank],
3880                &weight,
3881                &mut residual,
3882                &mut normalized,
3883                input.width,
3884                input.tokens,
3885                eps,
3886            )?;
3887            residual_ranks.push(residual);
3888            normalized_ranks.push(normalized);
3889        }
3890        Ok((
3891            ResidentReplicatedDeviceRows {
3892                ranks: residual_ranks,
3893                tokens: input.tokens,
3894                width: input.width,
3895            },
3896            ResidentReplicatedDeviceRows {
3897                ranks: normalized_ranks,
3898                tokens: input.tokens,
3899                width: input.width,
3900            },
3901        ))
3902    }
3903
3904    pub fn collect_replicated_device_rows(
3905        &self,
3906        rows: &ResidentReplicatedDeviceRows,
3907    ) -> Result<Vec<Vec<f32>>, Box<dyn std::error::Error>> {
3908        validate_replicated_device_rows(&self.ranks, rows)?;
3909        let mut outputs = Vec::with_capacity(self.ranks.len());
3910        for (rank, engine) in self.ranks.iter().enumerate() {
3911            let _main = engine.gpu.enter_main()?;
3912            outputs.push(engine.dtoh(&rows.ranks[rank])?);
3913        }
3914        Ok(outputs)
3915    }
3916
3917    #[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
3918    pub fn upload_bf16_row_parallel(
3919        &self,
3920        matrix: Bf16Matrix<'_>,
3921    ) -> Result<ResidentBf16RowParallel, Box<dyn std::error::Error>> {
3922        matrix.validate()?;
3923        let tp = self.ranks.len();
3924        if matrix.in_features % tp != 0 {
3925            return Err(format!(
3926                "BF16 row-parallel in_features {} is not divisible by TP={tp}",
3927                matrix.in_features
3928            )
3929            .into());
3930        }
3931        let mut ranks = Vec::with_capacity(tp);
3932        for (rank, engine) in self.ranks.iter().enumerate() {
3933            let shard = bf16_row_shard(matrix, tp, rank)?;
3934            ranks.push(upload_bf16_rank(
3935                engine,
3936                Bf16Matrix {
3937                    bytes: &shard,
3938                    out_features: matrix.out_features,
3939                    in_features: matrix.in_features / tp,
3940                },
3941                false,
3942            )?);
3943        }
3944        Ok(ResidentBf16RowParallel {
3945            ranks,
3946            out_features: matrix.out_features,
3947            in_features: matrix.in_features,
3948        })
3949    }
3950
3951    pub fn bf16_row_parallel_resident(
3952        &self,
3953        matrix: &ResidentBf16RowParallel,
3954        activations: &[f32],
3955        tokens: usize,
3956    ) -> Result<RowParallelResult, Box<dyn std::error::Error>> {
3957        validate_resident_bf16_ranks(&self.ranks, &matrix.ranks)?;
3958        validate_activations(activations, tokens, matrix.in_features)?;
3959        let tp = self.ranks.len();
3960        let mut reduced = vec![0.0f32; tokens * matrix.out_features];
3961        let mut rank_partials = Vec::with_capacity(tp);
3962        for (rank, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
3963            let local_activations =
3964                activation_shard(activations, tokens, matrix.in_features, tp, rank);
3965            let partial = run_resident_bf16_rank(engine, shard, &local_activations, tokens, None)?;
3966            for (sum, value) in reduced.iter_mut().zip(&partial) {
3967                *sum += value;
3968            }
3969            rank_partials.push(partial);
3970        }
3971        Ok(RowParallelResult {
3972            reduced,
3973            rank_partials,
3974        })
3975    }
3976
3977    /// Step-3.7 row projection split into the same eight global K blocks for TP1/TP2/TP4/TP8.
3978    pub fn upload_step_bf16_row_parallel(
3979        &self,
3980        matrix: Bf16Matrix<'_>,
3981    ) -> Result<ResidentStepBf16RowParallel, Box<dyn std::error::Error>> {
3982        self.upload_step_bf16_row_parallel_inner(matrix, false)
3983    }
3984
3985    pub fn upload_step_bf16_row_parallel_f32_mirror(
3986        &self,
3987        matrix: Bf16Matrix<'_>,
3988    ) -> Result<ResidentStepBf16RowParallel, Box<dyn std::error::Error>> {
3989        self.upload_step_bf16_row_parallel_inner(matrix, true)
3990    }
3991
3992    fn upload_step_bf16_row_parallel_inner(
3993        &self,
3994        matrix: Bf16Matrix<'_>,
3995        f32_mirror: bool,
3996    ) -> Result<ResidentStepBf16RowParallel, Box<dyn std::error::Error>> {
3997        matrix.validate()?;
3998        let tp = self.ranks.len();
3999        let canonical_chunk_cols = step_bf16_canonical_chunk_cols(matrix.in_features, tp)?;
4000        let local_in = matrix.in_features / tp;
4001        let blocks_per_rank = local_in / canonical_chunk_cols;
4002        let mut ranks = Vec::with_capacity(tp);
4003        for (rank, engine) in self.ranks.iter().enumerate() {
4004            let mut blocks = Vec::with_capacity(blocks_per_rank);
4005            for block in 0..blocks_per_rank {
4006                let global_block = rank * blocks_per_rank + block;
4007                let col_start = global_block * canonical_chunk_cols;
4008                let bytes = bf16_row_block(matrix, col_start, canonical_chunk_cols)?;
4009                blocks.push(upload_bf16_rank(
4010                    engine,
4011                    Bf16Matrix {
4012                        bytes: &bytes,
4013                        out_features: matrix.out_features,
4014                        in_features: canonical_chunk_cols,
4015                    },
4016                    f32_mirror,
4017                )?);
4018            }
4019            ranks.push(blocks);
4020        }
4021        Ok(ResidentStepBf16RowParallel {
4022            ranks,
4023            out_features: matrix.out_features,
4024            in_features: matrix.in_features,
4025            canonical_chunk_cols,
4026        })
4027    }
4028
4029    /// Host-staged exactness twin of [`Self::step_bf16_row_parallel_resident_native`].
4030    ///
4031    /// Block inputs and partials cross host memory, but every partial is added on the root device
4032    /// in global checkpoint-column order. Native transport must reproduce this result bitwise.
4033    pub fn step_bf16_row_parallel_resident(
4034        &self,
4035        matrix: &ResidentStepBf16RowParallel,
4036        activations: &[f32],
4037        tokens: usize,
4038    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
4039        validate_step_bf16_row_residency(&self.ranks, matrix)?;
4040        validate_activations(activations, tokens, matrix.in_features)?;
4041        let root = &self.ranks[0];
4042        let output_len = tokens
4043            .checked_mul(matrix.out_features)
4044            .ok_or("Step BF16 row output size overflow")?;
4045        let mut reduced = {
4046            let _main = root.gpu.enter_main()?;
4047            root.htod(&vec![0.0f32; output_len])?
4048        };
4049        let blocks_per_rank = PRODUCT_MAX_CARDS / self.ranks.len();
4050        for (rank, blocks) in matrix.ranks.iter().enumerate() {
4051            for (block, resident) in blocks.iter().enumerate() {
4052                let global_block = rank * blocks_per_rank + block;
4053                let input = activation_shard(
4054                    activations,
4055                    tokens,
4056                    matrix.in_features,
4057                    PRODUCT_MAX_CARDS,
4058                    global_block,
4059                );
4060                let partial =
4061                    run_resident_bf16_rank(&self.ranks[rank], resident, &input, tokens, None)?;
4062                let next = {
4063                    let _main = root.gpu.enter_main()?;
4064                    let partial = root.htod(&partial)?;
4065                    let mut next = root.uninit(output_len)?;
4066                    root.add(&reduced, &partial, &mut next, output_len)?;
4067                    next
4068                };
4069                reduced = next;
4070            }
4071        }
4072        let _main = root.gpu.enter_main()?;
4073        root.dtoh(&reduced)
4074    }
4075
4076    /// Native-P2P Step row projection with canonical global K-block reduction.
4077    ///
4078    /// The full activation is uploaded once on the root. Each TP8-sized block is peer-scattered
4079    /// to its owning rank, its BF16 partial is peer-returned to the root, and root-device adds
4080    /// replay the same eight-block order as TP1 and the host-staged oracle.
4081    pub fn step_bf16_row_parallel_resident_native(
4082        &self,
4083        matrix: &ResidentStepBf16RowParallel,
4084        activations: &[f32],
4085        tokens: usize,
4086    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
4087        if self.ranks.len() > 1 && !self.native_p2p {
4088            return Err("native Step BF16 row parallelism requires P2P ranks".into());
4089        }
4090        validate_step_bf16_row_residency(&self.ranks, matrix)?;
4091        validate_activations(activations, tokens, matrix.in_features)?;
4092        let root = &self.ranks[0];
4093        let root_input = {
4094            let _main = root.gpu.enter_main()?;
4095            root.htod(activations)?
4096        };
4097        // PRODUCER FENCE (2026-08-20 flake fix): the non-bulk arm below peer-reads root_input
4098        // from the other ranks' streams while root's clone_htod may still be in flight.
4099        {
4100            let _main = root.gpu.enter_main()?;
4101            root.stream().synchronize()?;
4102        }
4103        let reduced = self.step_bf16_row_native_reduce_from_root(matrix, &root_input, tokens)?;
4104        let _main = root.gpu.enter_main()?;
4105        root.dtoh(&reduced)
4106    }
4107
4108    /// Device-input twin of [`Self::step_bf16_row_parallel_resident_native`] (lane/
4109    /// hermes-perf-fixes, 2026-08-23): the full activation arrives as a ROOT-DEVICE buffer
4110    /// and the reduced output stays root-resident — no DtoH of the attention output, no
4111    /// host O staging, no re-upload. Byte-identical to the host-canonical arm by
4112    /// construction (same block scatter, kernels, and global TP8 reduction order; the root
4113    /// bytes are dtod-copied where the host arm htod'd the same bytes). Caller must have
4114    /// synchronized the producer stream; the root stream is synchronized before returning.
4115    pub fn step_bf16_row_parallel_resident_native_device(
4116        &self,
4117        matrix: &ResidentStepBf16RowParallel,
4118        root_activation: &CudaSlice<f32>,
4119        tokens: usize,
4120    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
4121        if self.ranks.len() > 1 && !self.native_p2p {
4122            return Err("native Step BF16 row parallelism requires P2P ranks".into());
4123        }
4124        validate_step_bf16_row_residency(&self.ranks, matrix)?;
4125        let values = tokens
4126            .checked_mul(matrix.in_features)
4127            .ok_or("device Step BF16 row activation size overflow")?;
4128        let root = &self.ranks[0];
4129        if tokens == 0
4130            || root_activation.len() < values
4131            || root_activation.ordinal() != root.ctx().ordinal()
4132        {
4133            return Err("device Step BF16 row root activation geometry mismatch".into());
4134        }
4135        let root_input = {
4136            let _main = root.gpu.enter_main()?;
4137            let mut root_input = root.uninit(values)?;
4138            root.stream()
4139                .memcpy_dtod(&root_activation.slice(0..values), &mut root_input)?;
4140            root.stream().synchronize()?; // producer fence, as the host-input twin
4141            root_input
4142        };
4143        let reduced = self.step_bf16_row_native_reduce_from_root(matrix, &root_input, tokens)?;
4144        let _main = root.gpu.enter_main()?;
4145        root.stream().synchronize()?;
4146        Ok(reduced)
4147    }
4148
4149    /// Shared core of the two native Step row arms above: block scatter + rank GEMMs +
4150    /// canonical global TP8-order root reduction, from a root-resident input, returning the
4151    /// root-resident reduced output. Extracted verbatim so the host and device twins cannot
4152    /// drift numerically.
4153    fn step_bf16_row_native_reduce_from_root(
4154        &self,
4155        matrix: &ResidentStepBf16RowParallel,
4156        root_input: &CudaSlice<f32>,
4157        tokens: usize,
4158    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
4159        let root = &self.ranks[0];
4160        let output_len = tokens
4161            .checked_mul(matrix.out_features)
4162            .ok_or("native Step BF16 row output size overflow")?;
4163        let mut reduced = {
4164            let _main = root.gpu.enter_main()?;
4165            root.htod(&vec![0.0f32; output_len])?
4166        };
4167        let blocks_per_rank = PRODUCT_MAX_CARDS / self.ranks.len();
4168        let mut block_input_keepalive = Vec::with_capacity(PRODUCT_MAX_CARDS);
4169        let mut root_packed_keepalive = Vec::with_capacity(PRODUCT_MAX_CARDS);
4170        let mut remote_partial_keepalive = Vec::new();
4171        for (rank, blocks) in matrix.ranks.iter().enumerate() {
4172            for (block, resident) in blocks.iter().enumerate() {
4173                let global_block = rank * blocks_per_rank + block;
4174                let col_start = global_block * matrix.canonical_chunk_cols;
4175                let block_len = tokens
4176                    .checked_mul(matrix.canonical_chunk_cols)
4177                    .ok_or("native Step BF16 row block size overflow")?;
4178                let block_input = if self.bulk_p2p {
4179                    let root_packed = {
4180                        let _main = root.gpu.enter_main()?;
4181                        let mut root_packed = root.uninit(block_len)?;
4182                        root.copy_rows_strided(
4183                            root_input,
4184                            &mut root_packed,
4185                            matrix.canonical_chunk_cols,
4186                            tokens,
4187                            matrix.in_features,
4188                            col_start,
4189                        )?;
4190                        root_packed
4191                    };
4192                    if rank == 0 {
4193                        root_packed
4194                    } else {
4195                        // PRODUCER FENCE (2026-08-20 flake fix): the pack kernel runs on the
4196                        // root stream; this rank's peer read must not overtake it.
4197                        {
4198                            let _main = root.gpu.enter_main()?;
4199                            root.stream().synchronize()?;
4200                        }
4201                        let engine = &self.ranks[rank];
4202                        let _main = engine.gpu.enter_main()?;
4203                        let mut block_input = engine.uninit(block_len)?;
4204                        engine
4205                            .stream()
4206                            .memcpy_dtod(&root_packed, &mut block_input)?;
4207                        root_packed_keepalive.push(root_packed);
4208                        block_input
4209                    }
4210                } else {
4211                    let engine = &self.ranks[rank];
4212                    let _main = engine.gpu.enter_main()?;
4213                    let mut block_input = engine.uninit(block_len)?;
4214                    for token in 0..tokens {
4215                        let source_start = token * matrix.in_features + col_start;
4216                        let source = root_input
4217                            .slice(source_start..source_start + matrix.canonical_chunk_cols);
4218                        let destination_start = token * matrix.canonical_chunk_cols;
4219                        let mut destination = block_input.slice_mut(
4220                            destination_start..destination_start + matrix.canonical_chunk_cols,
4221                        );
4222                        engine.stream().memcpy_dtod(&source, &mut destination)?;
4223                    }
4224                    block_input
4225                };
4226                let partial = run_resident_bf16_rank_device(
4227                    &self.ranks[rank],
4228                    resident,
4229                    &block_input,
4230                    tokens,
4231                    None,
4232                    self.bulk_p2p,
4233                )?;
4234                block_input_keepalive.push(block_input);
4235                let root_partial = if rank == 0 {
4236                    partial
4237                } else {
4238                    // PRODUCER FENCE (2026-08-20 flake fix): the partial was produced by this
4239                    // rank's kernel on its own stream; root's peer read must not overtake it.
4240                    {
4241                        let engine = &self.ranks[rank];
4242                        let _main = engine.gpu.enter_main()?;
4243                        engine.stream().synchronize()?;
4244                    }
4245                    let _main = root.gpu.enter_main()?;
4246                    let mut peer_partial = root.uninit(output_len)?;
4247                    root.stream().memcpy_dtod(&partial, &mut peer_partial)?;
4248                    remote_partial_keepalive.push(partial);
4249                    peer_partial
4250                };
4251                let next = {
4252                    let _main = root.gpu.enter_main()?;
4253                    let mut next = root.uninit(output_len)?;
4254                    root.add(&reduced, &root_partial, &mut next, output_len)?;
4255                    next
4256                };
4257                reduced = next;
4258            }
4259        }
4260        {
4261            let _main = root.gpu.enter_main()?;
4262            root.stream().synchronize()?;
4263        }
4264        drop(remote_partial_keepalive);
4265        drop(root_packed_keepalive);
4266        drop(block_input_keepalive);
4267        Ok(reduced)
4268    }
4269
4270    /// Reduce rank-local Step attention shards in canonical TP8 K-block order and keep the result
4271    /// on the root device.
4272    pub fn step_bf16_row_parallel_resident_root_device(
4273        &self,
4274        matrix: &ResidentStepBf16RowParallel,
4275        rank_activations: &[CudaSlice<f32>],
4276        tokens: usize,
4277    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
4278        if self.ranks.len() > 1 && !self.native_p2p {
4279            return Err(
4280                "device-resident Step BF16 row parallelism requires native P2P ranks".into(),
4281            );
4282        }
4283        validate_step_bf16_row_residency(&self.ranks, matrix)?;
4284        let local_width = matrix.in_features / self.ranks.len();
4285        let shard_len = tokens
4286            .checked_mul(local_width)
4287            .ok_or("device Step BF16 row shard size overflow")?;
4288        if tokens == 0
4289            || rank_activations.len() != self.ranks.len()
4290            || rank_activations
4291                .iter()
4292                .zip(&self.ranks)
4293                .any(|(rows, engine)| {
4294                    rows.len() != shard_len || rows.ordinal() != engine.ctx().ordinal()
4295                })
4296        {
4297            return Err("device Step BF16 row activation shard geometry changed".into());
4298        }
4299
4300        let blocks_per_rank = PRODUCT_MAX_CARDS / self.ranks.len();
4301        let mut block_inputs = Vec::with_capacity(self.ranks.len());
4302        let mut partials = Vec::with_capacity(self.ranks.len());
4303        for (rank, blocks) in matrix.ranks.iter().enumerate() {
4304            if blocks.len() != blocks_per_rank {
4305                return Err(format!(
4306                    "device Step BF16 row rank {rank} blocks {} != {blocks_per_rank}",
4307                    blocks.len()
4308                )
4309                .into());
4310            }
4311            let engine = &self.ranks[rank];
4312            let _main = engine.gpu.enter_main()?;
4313            let mut rank_inputs = Vec::with_capacity(blocks_per_rank);
4314            let mut rank_partials = Vec::with_capacity(blocks_per_rank);
4315            for (block, resident) in blocks.iter().enumerate() {
4316                let block_len = tokens
4317                    .checked_mul(matrix.canonical_chunk_cols)
4318                    .ok_or("device Step BF16 row block size overflow")?;
4319                let mut block_input = engine.uninit(block_len)?;
4320                let local_col_start = block * matrix.canonical_chunk_cols;
4321                if self.bulk_p2p {
4322                    engine.copy_rows_strided(
4323                        &rank_activations[rank],
4324                        &mut block_input,
4325                        matrix.canonical_chunk_cols,
4326                        tokens,
4327                        local_width,
4328                        local_col_start,
4329                    )?;
4330                } else {
4331                    for token in 0..tokens {
4332                        let source_start = token * local_width + local_col_start;
4333                        let source = rank_activations[rank]
4334                            .slice(source_start..source_start + matrix.canonical_chunk_cols);
4335                        let destination_start = token * matrix.canonical_chunk_cols;
4336                        let mut destination = block_input.slice_mut(
4337                            destination_start..destination_start + matrix.canonical_chunk_cols,
4338                        );
4339                        engine.stream().memcpy_dtod(&source, &mut destination)?;
4340                    }
4341                }
4342                let partial = run_resident_bf16_rank_device(
4343                    engine,
4344                    resident,
4345                    &block_input,
4346                    tokens,
4347                    None,
4348                    self.bulk_p2p,
4349                )?;
4350                rank_inputs.push(block_input);
4351                rank_partials.push(partial);
4352            }
4353            block_inputs.push(rank_inputs);
4354            partials.push(rank_partials);
4355        }
4356        for engine in self.ranks.iter().skip(1) {
4357            let _main = engine.gpu.enter_main()?;
4358            engine.stream().synchronize()?;
4359        }
4360
4361        let output_len = tokens
4362            .checked_mul(matrix.out_features)
4363            .ok_or("device Step BF16 row output size overflow")?;
4364        let root = &self.ranks[0];
4365        let _main = root.gpu.enter_main()?;
4366        let mut reduced = root.htod(&vec![0.0f32; output_len])?;
4367        let mut remote_partials = Vec::new();
4368        for (rank, rank_partials) in partials.into_iter().enumerate() {
4369            for partial in rank_partials {
4370                let root_partial = if rank == 0 {
4371                    partial
4372                } else {
4373                    let mut peer_partial = root.uninit(output_len)?;
4374                    root.stream().memcpy_dtod(&partial, &mut peer_partial)?;
4375                    remote_partials.push(partial);
4376                    peer_partial
4377                };
4378                let mut next = root.uninit(output_len)?;
4379                root.add(&reduced, &root_partial, &mut next, output_len)?;
4380                reduced = next;
4381            }
4382        }
4383        root.stream().synchronize()?;
4384        drop(remote_partials);
4385        drop(block_inputs);
4386        Ok(reduced)
4387    }
4388
4389    /// Reduce rank-local Step attention shards, then replicate the canonical root result.
4390    pub fn step_bf16_row_parallel_resident_replicated_device(
4391        &self,
4392        matrix: &ResidentStepBf16RowParallel,
4393        rank_activations: &[CudaSlice<f32>],
4394        tokens: usize,
4395    ) -> Result<ResidentReplicatedDeviceRows, Box<dyn std::error::Error>> {
4396        let reduced =
4397            self.step_bf16_row_parallel_resident_root_device(matrix, rank_activations, tokens)?;
4398        let output_len = tokens
4399            .checked_mul(matrix.out_features)
4400            .ok_or("device Step BF16 row output size overflow")?;
4401        let mut ranks = Vec::with_capacity(self.ranks.len());
4402        ranks.push(reduced);
4403        for engine in self.ranks.iter().skip(1) {
4404            let _main = engine.gpu.enter_main()?;
4405            let mut peer_output = engine.uninit(output_len)?;
4406            engine.stream().memcpy_dtod(&ranks[0], &mut peer_output)?;
4407            ranks.push(peer_output);
4408        }
4409        Ok(ResidentReplicatedDeviceRows {
4410            ranks,
4411            tokens,
4412            width: matrix.out_features,
4413        })
4414    }
4415
4416    pub fn upload_expert(
4417        &self,
4418        gate: E4m3BlockMatrix<'_>,
4419        up: E4m3BlockMatrix<'_>,
4420        down: E4m3BlockMatrix<'_>,
4421    ) -> Result<ResidentTpExpert, Box<dyn std::error::Error>> {
4422        if gate.in_features != up.in_features || gate.out_features != up.out_features {
4423            return Err("TP expert gate/up dimensions differ".into());
4424        }
4425        if down.in_features != gate.out_features || down.out_features != gate.in_features {
4426            return Err(format!(
4427                "TP expert down {}x{} does not invert gate/up {}x{}",
4428                down.out_features, down.in_features, gate.out_features, gate.in_features
4429            )
4430            .into());
4431        }
4432        Ok(ResidentTpExpert {
4433            gate: self.upload_column_parallel(gate)?,
4434            up: self.upload_column_parallel(up)?,
4435            down: self.upload_row_parallel(down)?,
4436            input_width: gate.in_features,
4437            expert_width: gate.out_features,
4438        })
4439    }
4440
4441    pub fn run_expert(
4442        &self,
4443        expert: &ResidentTpExpert,
4444        input: &[f32],
4445        tokens: usize,
4446    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
4447        validate_activations(input, tokens, expert.input_width)?;
4448        let gate = self.column_parallel_resident(&expert.gate, input, tokens)?;
4449        let up = self.column_parallel_resident(&expert.up, input, tokens)?;
4450        let activated: Vec<f32> = gate
4451            .gathered
4452            .iter()
4453            .zip(&up.gathered)
4454            .map(|(&gate, &up)| gate / (1.0 + (-gate).exp()) * up)
4455            .collect();
4456        debug_assert_eq!(activated.len(), tokens * expert.expert_width);
4457        Ok(self
4458            .row_parallel_resident(&expert.down, &activated, tokens)?
4459            .reduced)
4460    }
4461
4462    #[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
4463    pub fn upload_expert_parallel(
4464        &self,
4465        gate: E4m3ExpertBank<'_>,
4466        up: E4m3ExpertBank<'_>,
4467        down: E4m3ExpertBank<'_>,
4468    ) -> Result<ResidentExpertParallel, Box<dyn std::error::Error>> {
4469        gate.validate()?;
4470        up.validate()?;
4471        down.validate()?;
4472        if gate.expert_count != up.expert_count || gate.expert_count != down.expert_count {
4473            return Err("EP gate/up/down expert counts differ".into());
4474        }
4475        if gate.in_features != up.in_features || gate.out_features != up.out_features {
4476            return Err("EP gate/up dimensions differ".into());
4477        }
4478        if down.in_features != gate.out_features || down.out_features != gate.in_features {
4479            return Err(format!(
4480                "EP down {}x{} does not invert gate/up {}x{}",
4481                down.out_features, down.in_features, gate.out_features, gate.in_features
4482            )
4483            .into());
4484        }
4485        if gate.expert_count % self.ranks.len() != 0 {
4486            return Err(format!(
4487                "EP expert count {} is not divisible by {} ranks",
4488                gate.expert_count,
4489                self.ranks.len()
4490            )
4491            .into());
4492        }
4493
4494        let per_rank = gate.expert_count / self.ranks.len();
4495        let mut ranks = Vec::with_capacity(self.ranks.len());
4496        for (rank, engine) in self.ranks.iter().enumerate() {
4497            let expert_range = rank * per_rank..(rank + 1) * per_rank;
4498            ranks.push(ResidentEpRank {
4499                gate: upload_expert_bank_rank(engine, gate, expert_range.clone())?,
4500                up: upload_expert_bank_rank(engine, up, expert_range.clone())?,
4501                down: upload_expert_bank_rank(engine, down, expert_range)?,
4502            });
4503        }
4504        Ok(ResidentExpertParallel {
4505            ranks,
4506            expert_count: gate.expert_count,
4507            input_width: gate.in_features,
4508            expert_width: gate.out_features,
4509        })
4510    }
4511
4512    /// Prepare the official Step gate-only grouped-FP8 projection oracle on rank zero.
4513    ///
4514    /// This intentionally does not alter the resident EP path. It owns a full rank-local tensor
4515    /// bank solely so the grouped projection can be compared with the existing per-route oracle
4516    /// without routing, transport, or combine changing underneath it.
4517    #[allow(clippy::too_many_arguments)]
4518    pub fn prepare_step_grouped_fp8_gate(
4519        &self,
4520        gate: E4m3ExpertBank<'_>,
4521        up: E4m3ExpertBank<'_>,
4522        down: E4m3ExpertBank<'_>,
4523        input: &[f32],
4524        tokens: usize,
4525        selected: &[usize],
4526        activation_limit: Option<f32>,
4527    ) -> Result<PreparedStepGroupedFp8Gate, Box<dyn std::error::Error>> {
4528        gate.validate()?;
4529        up.validate()?;
4530        down.validate()?;
4531        validate_step_expert_activation_limit(activation_limit)?;
4532        if gate.expert_count != STEP_GROUPED_FP8_EXPERTS
4533            || up.expert_count != STEP_GROUPED_FP8_EXPERTS
4534            || down.expert_count != STEP_GROUPED_FP8_EXPERTS
4535        {
4536            return Err(format!(
4537                "official Step grouped FP8 gate requires {STEP_GROUPED_FP8_EXPERTS} experts, \
4538                 got gate/up/down={}/{}/{}",
4539                gate.expert_count, up.expert_count, down.expert_count,
4540            )
4541            .into());
4542        }
4543        if gate.in_features != up.in_features
4544            || gate.out_features != STEP_GROUPED_FP8_WIDTH
4545            || up.out_features != STEP_GROUPED_FP8_WIDTH
4546            || down.in_features != STEP_GROUPED_FP8_WIDTH
4547            || down.out_features != gate.in_features
4548        {
4549            return Err(format!(
4550                "official Step grouped FP8 geometry gate={}x{} up={}x{} down={}x{}",
4551                gate.out_features,
4552                gate.in_features,
4553                up.out_features,
4554                up.in_features,
4555                down.out_features,
4556                down.in_features,
4557            )
4558            .into());
4559        }
4560        validate_activations(input, tokens, gate.in_features)?;
4561        let pairs = tokens
4562            .checked_mul(STEP_GROUPED_FP8_TOP_K)
4563            .ok_or("official Step grouped FP8 route count overflow")?;
4564        if selected.len() != pairs {
4565            return Err(format!(
4566                "official Step grouped FP8 routes {} != {tokens}x{STEP_GROUPED_FP8_TOP_K} \
4567                 ({pairs})",
4568                selected.len()
4569            )
4570            .into());
4571        }
4572        for (token, routes) in selected.chunks_exact(STEP_GROUPED_FP8_TOP_K).enumerate() {
4573            let mut unique = routes.to_vec();
4574            unique.sort_unstable();
4575            unique.dedup();
4576            if unique.len() != STEP_GROUPED_FP8_TOP_K {
4577                return Err(format!(
4578                    "official Step grouped FP8 token {token} routes are not top-8 unique: \
4579                     {routes:?}"
4580                )
4581                .into());
4582            }
4583        }
4584
4585        let engine = self
4586            .ranks
4587            .first()
4588            .ok_or("official Step grouped FP8 gate has no rank-zero engine")?;
4589        let _main = engine.gpu.enter_main()?;
4590        let expert_range = 0..STEP_GROUPED_FP8_EXPERTS;
4591        let gate = upload_expert_bank_rank(engine, gate, expert_range.clone())?;
4592        let up = upload_expert_bank_rank(engine, up, expert_range.clone())?;
4593        let down = upload_expert_bank_rank(engine, down, expert_range)?;
4594        let input = engine.htod(input)?;
4595        let route_csr = ExpertCsr::from_token_routes(
4596            STEP_GROUPED_FP8_EXPERTS,
4597            tokens,
4598            STEP_GROUPED_FP8_TOP_K,
4599            selected,
4600        )?
4601        .upload(engine)?;
4602        let pair_rows = (0..pairs).collect::<Vec<_>>();
4603        let down_csr =
4604            ExpertCsr::from_pair_rows(STEP_GROUPED_FP8_EXPERTS, pairs, selected, &pair_rows)?
4605                .upload(engine)?;
4606        let gate_workspace =
4607            Fp8GroupedWorkspace::new(engine, gate.in_features, gate.out_features, tokens, pairs)?;
4608        let up_workspace =
4609            Fp8GroupedWorkspace::new(engine, up.in_features, up.out_features, tokens, pairs)?;
4610        let down_workspace =
4611            Fp8GroupedWorkspace::new(engine, down.in_features, down.out_features, pairs, pairs)?;
4612        let activation = engine.uninit(pairs * STEP_GROUPED_FP8_WIDTH)?;
4613        Ok(PreparedStepGroupedFp8Gate {
4614            device: engine.ctx().ordinal(),
4615            gate,
4616            up,
4617            down,
4618            input,
4619            route_csr,
4620            down_csr,
4621            gate_workspace,
4622            up_workspace,
4623            down_workspace,
4624            activation,
4625            activation_limit,
4626            tokens,
4627            pairs,
4628        })
4629    }
4630
4631    /// Execute one prepared gate/up/activation/down projection sequence on rank zero.
4632    pub fn run_step_grouped_fp8_gate(
4633        &self,
4634        plan: &mut PreparedStepGroupedFp8Gate,
4635    ) -> Result<StepGroupedFp8ProjectionOutput, Box<dyn std::error::Error>> {
4636        let engine = self
4637            .ranks
4638            .first()
4639            .ok_or("official Step grouped FP8 gate has no rank-zero engine")?;
4640        if engine.ctx().ordinal() != plan.device {
4641            return Err(format!(
4642                "official Step grouped FP8 plan device {} != rank-zero device {}",
4643                plan.device,
4644                engine.ctx().ordinal()
4645            )
4646            .into());
4647        }
4648        let _main = engine.gpu.enter_main()?;
4649
4650        plan.gate_workspace.quantize(engine, &plan.input)?;
4651        plan.gate_workspace.project(
4652            engine,
4653            &plan.gate.codes,
4654            &plan.gate.scales,
4655            &plan.route_csr,
4656            plan.gate.code_stride,
4657            plan.gate.scale_stride,
4658            1.0,
4659        )?;
4660        plan.up_workspace.quantize(engine, &plan.input)?;
4661        plan.up_workspace.project(
4662            engine,
4663            &plan.up.codes,
4664            &plan.up.scales,
4665            &plan.route_csr,
4666            plan.up.code_stride,
4667            plan.up.scale_stride,
4668            1.0,
4669        )?;
4670        if let Some(limit) = plan.activation_limit {
4671            engine.silu_clamped_mul_host_expf(
4672                plan.gate_workspace.output(),
4673                plan.up_workspace.output(),
4674                limit,
4675                &mut plan.activation,
4676                plan.pairs * STEP_GROUPED_FP8_WIDTH,
4677            )?;
4678        } else {
4679            engine.silu_mul_host_expf(
4680                plan.gate_workspace.output(),
4681                plan.up_workspace.output(),
4682                &mut plan.activation,
4683                plan.pairs * STEP_GROUPED_FP8_WIDTH,
4684            )?;
4685        }
4686        plan.down_workspace.quantize(engine, &plan.activation)?;
4687        plan.down_workspace.project(
4688            engine,
4689            &plan.down.codes,
4690            &plan.down.scales,
4691            &plan.down_csr,
4692            plan.down.code_stride,
4693            plan.down.scale_stride,
4694            1.0,
4695        )?;
4696
4697        Ok(StepGroupedFp8ProjectionOutput {
4698            gate: engine.dtoh(plan.gate_workspace.output())?,
4699            up: engine.dtoh(plan.up_workspace.output())?,
4700            down: engine.dtoh(plan.down_workspace.output())?,
4701        })
4702    }
4703
4704    pub fn prepare_step_grouped_expert_parallel_gate(
4705        &self,
4706        experts: &ResidentExpertParallel,
4707        input: &[f32],
4708        tokens: usize,
4709        selected: &[usize],
4710        activation_limit: Option<f32>,
4711    ) -> Result<PreparedStepGroupedExpertParallelGate, Box<dyn std::error::Error>> {
4712        self.prepare_step_grouped_expert_parallel_gate_with_capacity(
4713            experts,
4714            input,
4715            tokens,
4716            selected,
4717            activation_limit,
4718            tokens,
4719        )
4720    }
4721
4722    #[allow(clippy::too_many_arguments)]
4723    pub fn prepare_step_grouped_expert_parallel_gate_with_capacity(
4724        &self,
4725        experts: &ResidentExpertParallel,
4726        input: &[f32],
4727        tokens: usize,
4728        selected: &[usize],
4729        activation_limit: Option<f32>,
4730        max_tokens: usize,
4731    ) -> Result<PreparedStepGroupedExpertParallelGate, Box<dyn std::error::Error>> {
4732        if !self.native_p2p || !self.ep_device_arithmetic {
4733            return Err(
4734                "Step owner-grouped FP8 requires native P2P and device-resident arithmetic".into(),
4735            );
4736        }
4737        validate_step_expert_activation_limit(activation_limit)?;
4738        validate_ep_residency(&self.ranks, experts)?;
4739        validate_activations(input, tokens, experts.input_width)?;
4740        if max_tokens < tokens || max_tokens > i32::MAX as usize {
4741            return Err(format!(
4742                "official Step owner-grouped FP8 tokens {tokens} exceed capacity {max_tokens}"
4743            )
4744            .into());
4745        }
4746        if experts.expert_count != STEP_GROUPED_FP8_EXPERTS
4747            || experts.expert_width != STEP_GROUPED_FP8_WIDTH
4748        {
4749            return Err(format!(
4750                "official Step owner-grouped FP8 requires {} experts at width {}, got {} at {}",
4751                STEP_GROUPED_FP8_EXPERTS,
4752                STEP_GROUPED_FP8_WIDTH,
4753                experts.expert_count,
4754                experts.expert_width,
4755            )
4756            .into());
4757        }
4758        validate_step_grouped_owner_routes(experts.expert_count, tokens, selected)?;
4759        let max_pairs = max_tokens
4760            .checked_mul(STEP_GROUPED_FP8_TOP_K)
4761            .ok_or("official Step owner-grouped FP8 capacity route count overflow")?;
4762        let input_capacity = max_tokens
4763            .checked_mul(experts.input_width)
4764            .ok_or("official Step owner-grouped FP8 input capacity overflow")?;
4765
4766        let mut rank_inputs = Vec::with_capacity(self.ranks.len());
4767        for engine in &self.ranks {
4768            let _main = engine.gpu.enter_main()?;
4769            rank_inputs.push(engine.uninit(input_capacity)?);
4770        }
4771
4772        let mut owners = Vec::with_capacity(self.ranks.len());
4773        for (owner_rank, rank) in experts.ranks.iter().enumerate() {
4774            if rank.gate.expert_range != rank.up.expert_range
4775                || rank.gate.expert_range != rank.down.expert_range
4776            {
4777                return Err(format!(
4778                    "owner-grouped FP8 rank {} gate/up/down expert ranges differ",
4779                    owner_rank
4780                )
4781                .into());
4782            }
4783            let local_experts = rank.gate.expert_range.len();
4784            let engine = &self.ranks[owner_rank];
4785            let _main = engine.gpu.enter_main()?;
4786            let route_csr =
4787                DeviceExpertCsr::with_capacity(engine, local_experts, max_tokens, max_pairs)?;
4788            let down_csr =
4789                DeviceExpertCsr::with_capacity(engine, local_experts, max_pairs, max_pairs)?;
4790            let gate_workspace = Fp8GroupedWorkspace::new(
4791                engine,
4792                experts.input_width,
4793                experts.expert_width,
4794                max_tokens,
4795                max_pairs,
4796            )?;
4797            let up_workspace = Fp8GroupedWorkspace::new(
4798                engine,
4799                experts.input_width,
4800                experts.expert_width,
4801                max_tokens,
4802                max_pairs,
4803            )?;
4804            let down_workspace = Fp8GroupedWorkspace::new(
4805                engine,
4806                experts.expert_width,
4807                experts.input_width,
4808                max_pairs,
4809                max_pairs,
4810            )?;
4811            let activation = engine.uninit(
4812                max_pairs
4813                    .checked_mul(experts.expert_width)
4814                    .ok_or("official Step owner-grouped FP8 activation capacity overflow")?,
4815            )?;
4816            owners.push(PreparedStepGroupedExpertOwner {
4817                rank: owner_rank,
4818                global_pairs: Vec::new(),
4819                route_csr,
4820                down_csr,
4821                gate_workspace,
4822                up_workspace,
4823                down_workspace,
4824                activation,
4825            });
4826        }
4827
4828        let mut plan = PreparedStepGroupedExpertParallelGate {
4829            rank_inputs,
4830            owners,
4831            activation_limit,
4832            tokens: 0,
4833            pairs: 0,
4834            max_tokens,
4835            max_pairs,
4836            input_width: experts.input_width,
4837            expert_width: experts.expert_width,
4838            generation: 0,
4839            executed_generation: None,
4840            ready: false,
4841        };
4842        self.refresh_step_grouped_expert_parallel_gate(
4843            experts, &mut plan, input, tokens, selected,
4844        )?;
4845        Ok(plan)
4846    }
4847
4848    #[allow(clippy::type_complexity)] // allow: one-shot composite type; naming it would hide the shape that matters at the call site
4849    fn prepare_step_grouped_expert_parallel_refresh(
4850        &self,
4851        experts: &ResidentExpertParallel,
4852        plan: &PreparedStepGroupedExpertParallelGate,
4853        tokens: usize,
4854        selected: &[usize],
4855    ) -> Result<(usize, u64, Vec<Option<StepGroupedExpertOwnerSchedule>>), Box<dyn std::error::Error>>
4856    {
4857        validate_ep_residency(&self.ranks, experts)?;
4858        if plan.rank_inputs.len() != self.ranks.len()
4859            || plan.owners.len() != self.ranks.len()
4860            || plan.input_width != experts.input_width
4861            || plan.expert_width != experts.expert_width
4862            || tokens > plan.max_tokens
4863        {
4864            return Err(format!(
4865                "Step owner-grouped FP8 refresh geometry changed ranks={}/{} owners={}/{} \
4866                 input={}/{} expert={}/{} tokens={}/{}",
4867                plan.rank_inputs.len(),
4868                self.ranks.len(),
4869                plan.owners.len(),
4870                self.ranks.len(),
4871                plan.input_width,
4872                experts.input_width,
4873                plan.expert_width,
4874                experts.expert_width,
4875                tokens,
4876                plan.max_tokens,
4877            )
4878            .into());
4879        }
4880        let pairs = validate_step_grouped_owner_routes(experts.expert_count, tokens, selected)?;
4881        if pairs > plan.max_pairs {
4882            return Err(format!(
4883                "Step owner-grouped FP8 route count {pairs} exceeds capacity {}",
4884                plan.max_pairs
4885            )
4886            .into());
4887        }
4888        let next_generation = plan
4889            .generation
4890            .checked_add(1)
4891            .ok_or("Step owner-grouped FP8 plan generation overflow")?;
4892        let owner_routes = partition_expert_owner_routes(
4893            experts.expert_count,
4894            self.ranks.len(),
4895            tokens,
4896            STEP_GROUPED_FP8_TOP_K,
4897            selected,
4898        )?;
4899        let mut schedules = Vec::with_capacity(self.ranks.len());
4900        for routes in owner_routes {
4901            if routes.selected.is_empty() {
4902                schedules.push(None);
4903                continue;
4904            }
4905            let local_experts = experts.ranks[routes.rank].gate.expert_range.len();
4906            let local_pairs = routes.selected.len();
4907            let route_csr = ExpertCsr::from_pair_rows(
4908                local_experts,
4909                tokens,
4910                &routes.selected,
4911                &routes.token_rows,
4912            )?;
4913            let down_rows = (0..local_pairs).collect::<Vec<_>>();
4914            let down_csr = ExpertCsr::from_pair_rows(
4915                local_experts,
4916                local_pairs,
4917                &routes.selected,
4918                &down_rows,
4919            )?;
4920            schedules.push(Some(StepGroupedExpertOwnerSchedule {
4921                global_pairs: routes.global_pairs,
4922                route_csr,
4923                down_csr,
4924            }));
4925        }
4926        Ok((pairs, next_generation, schedules))
4927    }
4928
4929    fn commit_step_grouped_expert_parallel_refresh(
4930        &self,
4931        plan: &mut PreparedStepGroupedExpertParallelGate,
4932        tokens: usize,
4933        pairs: usize,
4934        next_generation: u64,
4935        schedules: Vec<Option<StepGroupedExpertOwnerSchedule>>,
4936    ) -> Result<(), Box<dyn std::error::Error>> {
4937        for (owner, schedule) in plan.owners.iter_mut().zip(schedules) {
4938            let engine = &self.ranks[owner.rank];
4939            let _main = engine.gpu.enter_main()?;
4940            if let Some(schedule) = schedule {
4941                owner.route_csr.refresh(engine, &schedule.route_csr)?;
4942                owner.down_csr.refresh(engine, &schedule.down_csr)?;
4943                owner.global_pairs = schedule.global_pairs;
4944            } else {
4945                owner.route_csr.clear();
4946                owner.down_csr.clear();
4947                owner.global_pairs.clear();
4948            }
4949        }
4950        plan.tokens = tokens;
4951        plan.pairs = pairs;
4952        plan.generation = next_generation;
4953        plan.ready = true;
4954        Ok(())
4955    }
4956
4957    pub fn refresh_step_grouped_expert_parallel_gate(
4958        &self,
4959        experts: &ResidentExpertParallel,
4960        plan: &mut PreparedStepGroupedExpertParallelGate,
4961        input: &[f32],
4962        tokens: usize,
4963        selected: &[usize],
4964    ) -> Result<(), Box<dyn std::error::Error>> {
4965        validate_activations(input, tokens, experts.input_width)?;
4966        let (pairs, next_generation, schedules) =
4967            self.prepare_step_grouped_expert_parallel_refresh(experts, plan, tokens, selected)?;
4968
4969        plan.ready = false;
4970        plan.executed_generation = None;
4971        {
4972            let root = &self.ranks[0];
4973            let _main = root.gpu.enter_main()?;
4974            let mut destination = plan.rank_inputs[0].slice_mut(0..input.len());
4975            root.stream().memcpy_htod(input, &mut destination)?;
4976            root.stream().synchronize()?;
4977        }
4978        let (root_inputs, peer_inputs) = plan.rank_inputs.split_at_mut(1);
4979        let root_input = &root_inputs[0];
4980        for (rank, peer_input) in peer_inputs.iter_mut().enumerate() {
4981            let engine = &self.ranks[rank + 1];
4982            let _main = engine.gpu.enter_main()?;
4983            let mut destination = peer_input.slice_mut(0..input.len());
4984            engine
4985                .stream()
4986                .memcpy_dtod(&root_input.slice(0..input.len()), &mut destination)?;
4987        }
4988        self.commit_step_grouped_expert_parallel_refresh(
4989            plan,
4990            tokens,
4991            pairs,
4992            next_generation,
4993            schedules,
4994        )
4995    }
4996
4997    /// Refresh routes and inputs from an already-resident rank-zero activation.
4998    ///
4999    /// The caller must order the source producer before this call. The root copy is completed
5000    /// before peer dispatch, while CSR and workspace allocations retain their stable addresses.
5001    pub fn refresh_step_grouped_expert_parallel_gate_from_root_device(
5002        &self,
5003        experts: &ResidentExpertParallel,
5004        plan: &mut PreparedStepGroupedExpertParallelGate,
5005        input: &CudaSlice<f32>,
5006        tokens: usize,
5007        selected: &[usize],
5008    ) -> Result<(), Box<dyn std::error::Error>> {
5009        let input_values = tokens
5010            .checked_mul(experts.input_width)
5011            .ok_or("Step owner-grouped FP8 input size overflow")?;
5012        let root = self
5013            .ranks
5014            .first()
5015            .ok_or("Step owner-grouped FP8 runtime has no root rank")?;
5016        if input.len() < input_values || input.ordinal() != root.ctx().ordinal() {
5017            return Err(format!(
5018                "Step owner-grouped FP8 root input len/device {}/{} does not cover {} values on \
5019                 device {}",
5020                input.len(),
5021                input.ordinal(),
5022                input_values,
5023                root.ctx().ordinal(),
5024            )
5025            .into());
5026        }
5027        let (pairs, next_generation, schedules) =
5028            self.prepare_step_grouped_expert_parallel_refresh(experts, plan, tokens, selected)?;
5029
5030        plan.ready = false;
5031        plan.executed_generation = None;
5032        {
5033            let _main = root.gpu.enter_main()?;
5034            let mut destination = plan.rank_inputs[0].slice_mut(0..input_values);
5035            root.stream()
5036                .memcpy_dtod(&input.slice(0..input_values), &mut destination)?;
5037            root.stream().synchronize()?;
5038        }
5039        let (root_inputs, peer_inputs) = plan.rank_inputs.split_at_mut(1);
5040        let root_input = &root_inputs[0];
5041        for (rank, peer_input) in peer_inputs.iter_mut().enumerate() {
5042            let engine = &self.ranks[rank + 1];
5043            let _main = engine.gpu.enter_main()?;
5044            let mut destination = peer_input.slice_mut(0..input_values);
5045            engine
5046                .stream()
5047                .memcpy_dtod(&root_input.slice(0..input_values), &mut destination)?;
5048        }
5049        self.commit_step_grouped_expert_parallel_refresh(
5050            plan,
5051            tokens,
5052            pairs,
5053            next_generation,
5054            schedules,
5055        )
5056    }
5057
5058    /// Replace a fixed route plan's rank inputs from an already replicated device batch.
5059    ///
5060    /// Route CSR remains unchanged. Advancing the generation invalidates every prior projection
5061    /// and combine result, so callers must refresh combine metadata before executing again.
5062    pub fn refresh_step_grouped_expert_parallel_inputs_from_replicated(
5063        &self,
5064        experts: &ResidentExpertParallel,
5065        plan: &mut PreparedStepGroupedExpertParallelGate,
5066        input: &ResidentReplicatedDeviceRows,
5067    ) -> Result<(), Box<dyn std::error::Error>> {
5068        validate_ep_residency(&self.ranks, experts)?;
5069        validate_replicated_device_rows(&self.ranks, input)?;
5070        if !plan.ready
5071            || input.tokens != plan.tokens
5072            || input.width != plan.input_width
5073            || input.tokens > plan.max_tokens
5074            || plan.rank_inputs.len() != self.ranks.len()
5075            || plan.owners.len() != self.ranks.len()
5076            || plan.input_width != experts.input_width
5077            || plan.expert_width != experts.expert_width
5078        {
5079            return Err("Step owner-grouped replicated input geometry changed".into());
5080        }
5081        let values = input
5082            .tokens
5083            .checked_mul(input.width)
5084            .ok_or("Step owner-grouped replicated input size overflow")?;
5085        let next_generation = plan
5086            .generation
5087            .checked_add(1)
5088            .ok_or("Step owner-grouped FP8 plan generation overflow")?;
5089        plan.ready = false;
5090        plan.executed_generation = None;
5091        for (rank, engine) in self.ranks.iter().enumerate() {
5092            let _main = engine.gpu.enter_main()?;
5093            let mut destination = plan.rank_inputs[rank].slice_mut(0..values);
5094            engine
5095                .stream()
5096                .memcpy_dtod(&input.ranks[rank], &mut destination)?;
5097        }
5098        plan.generation = next_generation;
5099        plan.ready = true;
5100        Ok(())
5101    }
5102
5103    pub fn execute_step_grouped_expert_parallel_gate(
5104        &self,
5105        experts: &ResidentExpertParallel,
5106        plan: &mut PreparedStepGroupedExpertParallelGate,
5107    ) -> Result<(), Box<dyn std::error::Error>> {
5108        validate_ep_residency(&self.ranks, experts)?;
5109        if !plan.ready
5110            || plan.rank_inputs.len() != self.ranks.len()
5111            || plan.owners.len() != self.ranks.len()
5112            || plan.input_width != experts.input_width
5113            || plan.expert_width != experts.expert_width
5114        {
5115            return Err("Step owner-grouped FP8 plan is not ready or its geometry changed".into());
5116        }
5117        plan.executed_generation = None;
5118
5119        for owner in &mut plan.owners {
5120            if owner.global_pairs.is_empty() {
5121                continue;
5122            }
5123            let engine = &self.ranks[owner.rank];
5124            let bank = &experts.ranks[owner.rank];
5125            let _main = engine.gpu.enter_main()?;
5126            let local_pairs = owner.global_pairs.len();
5127            owner.gate_workspace.quantize_for_shape(
5128                engine,
5129                &plan.rank_inputs[owner.rank],
5130                plan.tokens,
5131                local_pairs,
5132            )?;
5133            owner.gate_workspace.project(
5134                engine,
5135                &bank.gate.codes,
5136                &bank.gate.scales,
5137                &owner.route_csr,
5138                bank.gate.code_stride,
5139                bank.gate.scale_stride,
5140                1.0,
5141            )?;
5142            owner.up_workspace.quantize_for_shape(
5143                engine,
5144                &plan.rank_inputs[owner.rank],
5145                plan.tokens,
5146                local_pairs,
5147            )?;
5148            owner.up_workspace.project(
5149                engine,
5150                &bank.up.codes,
5151                &bank.up.scales,
5152                &owner.route_csr,
5153                bank.up.code_stride,
5154                bank.up.scale_stride,
5155                1.0,
5156            )?;
5157        }
5158        for owner in &mut plan.owners {
5159            if owner.global_pairs.is_empty() {
5160                continue;
5161            }
5162            let engine = &self.ranks[owner.rank];
5163            let _main = engine.gpu.enter_main()?;
5164            let values = owner.global_pairs.len() * plan.expert_width;
5165            if let Some(limit) = plan.activation_limit {
5166                engine.silu_clamped_mul_host_expf(
5167                    owner.gate_workspace.output(),
5168                    owner.up_workspace.output(),
5169                    limit,
5170                    &mut owner.activation,
5171                    values,
5172                )?;
5173            } else {
5174                engine.silu_mul_host_expf(
5175                    owner.gate_workspace.output(),
5176                    owner.up_workspace.output(),
5177                    &mut owner.activation,
5178                    values,
5179                )?;
5180            }
5181        }
5182        for owner in &mut plan.owners {
5183            if owner.global_pairs.is_empty() {
5184                continue;
5185            }
5186            let engine = &self.ranks[owner.rank];
5187            let bank = &experts.ranks[owner.rank];
5188            let _main = engine.gpu.enter_main()?;
5189            let local_pairs = owner.global_pairs.len();
5190            owner.down_workspace.quantize_for_shape(
5191                engine,
5192                &owner.activation,
5193                local_pairs,
5194                local_pairs,
5195            )?;
5196            owner.down_workspace.project(
5197                engine,
5198                &bank.down.codes,
5199                &bank.down.scales,
5200                &owner.down_csr,
5201                bank.down.code_stride,
5202                bank.down.scale_stride,
5203                1.0,
5204            )?;
5205        }
5206        plan.executed_generation = Some(plan.generation);
5207        Ok(())
5208    }
5209
5210    pub fn collect_step_grouped_expert_parallel_gate(
5211        &self,
5212        plan: &PreparedStepGroupedExpertParallelGate,
5213    ) -> Result<StepGroupedFp8ProjectionOutput, Box<dyn std::error::Error>> {
5214        if !plan.ready || plan.executed_generation != Some(plan.generation) {
5215            return Err("Step owner-grouped FP8 projection is stale or has not executed".into());
5216        }
5217        let mut gate = vec![0.0f32; plan.pairs * plan.expert_width];
5218        let mut up = vec![0.0f32; plan.pairs * plan.expert_width];
5219        let mut down = vec![0.0f32; plan.pairs * plan.input_width];
5220        for owner in &plan.owners {
5221            if owner.global_pairs.is_empty() {
5222                continue;
5223            }
5224            let engine = &self.ranks[owner.rank];
5225            let _main = engine.gpu.enter_main()?;
5226            let owner_gate = engine.dtoh_view(
5227                &owner
5228                    .gate_workspace
5229                    .output()
5230                    .slice(0..owner.gate_workspace.output_len()),
5231            )?;
5232            let owner_up = engine.dtoh_view(
5233                &owner
5234                    .up_workspace
5235                    .output()
5236                    .slice(0..owner.up_workspace.output_len()),
5237            )?;
5238            let owner_down = engine.dtoh_view(
5239                &owner
5240                    .down_workspace
5241                    .output()
5242                    .slice(0..owner.down_workspace.output_len()),
5243            )?;
5244            for (local_pair, &global_pair) in owner.global_pairs.iter().enumerate() {
5245                let local_expert = local_pair * plan.expert_width;
5246                let global_expert = global_pair * plan.expert_width;
5247                gate[global_expert..global_expert + plan.expert_width]
5248                    .copy_from_slice(&owner_gate[local_expert..local_expert + plan.expert_width]);
5249                up[global_expert..global_expert + plan.expert_width]
5250                    .copy_from_slice(&owner_up[local_expert..local_expert + plan.expert_width]);
5251
5252                let local_hidden = local_pair * plan.input_width;
5253                let global_hidden = global_pair * plan.input_width;
5254                down[global_hidden..global_hidden + plan.input_width]
5255                    .copy_from_slice(&owner_down[local_hidden..local_hidden + plan.input_width]);
5256            }
5257        }
5258        Ok(StepGroupedFp8ProjectionOutput { gate, up, down })
5259    }
5260
5261    pub fn run_step_grouped_expert_parallel_gate(
5262        &self,
5263        experts: &ResidentExpertParallel,
5264        plan: &mut PreparedStepGroupedExpertParallelGate,
5265    ) -> Result<StepGroupedFp8ProjectionOutput, Box<dyn std::error::Error>> {
5266        self.execute_step_grouped_expert_parallel_gate(experts, plan)?;
5267        self.collect_step_grouped_expert_parallel_gate(plan)
5268    }
5269
5270    pub fn prepare_step_grouped_expert_parallel_combine(
5271        &self,
5272        plan: &PreparedStepGroupedExpertParallelGate,
5273        route_weights: &[f32],
5274    ) -> Result<PreparedPeerWeightedRouteCombine, Box<dyn std::error::Error>> {
5275        if !self.native_p2p || !self.ep_device_arithmetic || !plan.ready {
5276            return Err(
5277                "Step owner-grouped combine requires a ready native-P2P device plan".into(),
5278            );
5279        }
5280        let owner_pairs = plan
5281            .owners
5282            .iter()
5283            .map(|owner| owner.global_pairs.as_slice())
5284            .collect::<Vec<_>>();
5285        let shape = validate_weighted_route_combine(
5286            plan.input_width,
5287            STEP_GROUPED_FP8_TOP_K,
5288            plan.max_tokens,
5289            plan.tokens,
5290            &owner_pairs,
5291            route_weights,
5292        )?;
5293        if shape.max_pairs != plan.max_pairs {
5294            return Err(format!(
5295                "Step owner-grouped combine capacity {} != projection capacity {}",
5296                shape.max_pairs, plan.max_pairs
5297            )
5298            .into());
5299        }
5300        let root = self
5301            .ranks
5302            .first()
5303            .ok_or("Step owner-grouped combine has no root rank")?;
5304        let slot_values = shape
5305            .max_pairs
5306            .checked_mul(plan.input_width)
5307            .ok_or("Step owner-grouped combine slot capacity overflow")?;
5308        let output_values = plan
5309            .max_tokens
5310            .checked_mul(plan.input_width)
5311            .ok_or("Step owner-grouped combine output capacity overflow")?;
5312        let (root_device, owners, peer_staging, slots, weights, output) = {
5313            let _main = root.gpu.enter_main()?;
5314            let mut owners = Vec::with_capacity(plan.owners.len());
5315            for _ in &plan.owners {
5316                owners.push(PreparedPeerWeightedRouteOwner {
5317                    token_rows: root.htod_i32(&vec![0; shape.max_pairs])?,
5318                    slots: root.htod_i32(&vec![0; shape.max_pairs])?,
5319                    weights: root.htod(&vec![0.0; shape.max_pairs])?,
5320                    active_pairs: 0,
5321                });
5322            }
5323            (
5324                root.ctx().ordinal(),
5325                owners,
5326                root.uninit(slot_values)?,
5327                root.uninit(slot_values)?,
5328                root.uninit(shape.max_pairs)?,
5329                root.uninit(output_values)?,
5330            )
5331        };
5332        let mut peer_devices = Vec::with_capacity(self.ranks.len().saturating_sub(1));
5333        let mut peer_outputs = Vec::with_capacity(self.ranks.len().saturating_sub(1));
5334        for engine in self.ranks.iter().skip(1) {
5335            let _main = engine.gpu.enter_main()?;
5336            peer_devices.push(engine.ctx().ordinal());
5337            peer_outputs.push(engine.uninit(output_values)?);
5338        }
5339        let mut combine = PreparedPeerWeightedRouteCombine {
5340            root_device,
5341            owners,
5342            peer_staging,
5343            slots,
5344            weights,
5345            output,
5346            peer_devices,
5347            peer_outputs,
5348            width: plan.input_width,
5349            experts_per_token: STEP_GROUPED_FP8_TOP_K,
5350            max_tokens: plan.max_tokens,
5351            max_pairs: shape.max_pairs,
5352            tokens: 0,
5353            pairs: 0,
5354            projection_generation: 0,
5355            output_generation: None,
5356            broadcast_generation: None,
5357            ready: false,
5358        };
5359        self.refresh_step_grouped_expert_parallel_combine(plan, &mut combine, route_weights)?;
5360        Ok(combine)
5361    }
5362
5363    pub fn refresh_step_grouped_expert_parallel_combine(
5364        &self,
5365        plan: &PreparedStepGroupedExpertParallelGate,
5366        combine: &mut PreparedPeerWeightedRouteCombine,
5367        route_weights: &[f32],
5368    ) -> Result<(), Box<dyn std::error::Error>> {
5369        let output_capacity = combine
5370            .max_tokens
5371            .checked_mul(combine.width)
5372            .ok_or("Step owner-grouped combine output capacity overflow")?;
5373        if !plan.ready
5374            || combine.owners.len() != plan.owners.len()
5375            || combine.peer_devices.len() + 1 != self.ranks.len()
5376            || combine.peer_outputs.len() + 1 != self.ranks.len()
5377            || combine.width != plan.input_width
5378            || combine.experts_per_token != STEP_GROUPED_FP8_TOP_K
5379            || combine.max_tokens != plan.max_tokens
5380            || combine.max_pairs != plan.max_pairs
5381            || combine.output.len() < output_capacity
5382            || combine
5383                .peer_outputs
5384                .iter()
5385                .any(|output| output.len() < output_capacity)
5386        {
5387            return Err("Step owner-grouped combine/projection geometry changed".into());
5388        }
5389        if self
5390            .ranks
5391            .iter()
5392            .skip(1)
5393            .zip(&combine.peer_devices)
5394            .any(|(engine, &device)| engine.ctx().ordinal() != device)
5395        {
5396            return Err("Step owner-grouped combine peer devices changed".into());
5397        }
5398        let owner_pairs = plan
5399            .owners
5400            .iter()
5401            .map(|owner| owner.global_pairs.as_slice())
5402            .collect::<Vec<_>>();
5403        let shape = validate_weighted_route_combine(
5404            combine.width,
5405            combine.experts_per_token,
5406            combine.max_tokens,
5407            plan.tokens,
5408            &owner_pairs,
5409            route_weights,
5410        )?;
5411        if shape.max_pairs != combine.max_pairs {
5412            return Err("Step owner-grouped combine capacity changed during refresh".into());
5413        }
5414        let metadata = owner_pairs
5415            .iter()
5416            .map(|pairs| {
5417                let token_rows = pairs
5418                    .iter()
5419                    .map(|&pair| (pair / combine.experts_per_token) as i32)
5420                    .collect::<Vec<_>>();
5421                let slots = pairs
5422                    .iter()
5423                    .map(|&pair| (pair % combine.experts_per_token) as i32)
5424                    .collect::<Vec<_>>();
5425                let weights = pairs
5426                    .iter()
5427                    .map(|&pair| route_weights[pair])
5428                    .collect::<Vec<_>>();
5429                (token_rows, slots, weights)
5430            })
5431            .collect::<Vec<_>>();
5432
5433        combine.ready = false;
5434        combine.output_generation = None;
5435        combine.broadcast_generation = None;
5436        let root = self
5437            .ranks
5438            .first()
5439            .ok_or("Step owner-grouped combine has no root rank")?;
5440        let _main = root.gpu.enter_main()?;
5441        if root.ctx().ordinal() != combine.root_device {
5442            return Err(format!(
5443                "Step owner-grouped combine root device changed {} != {}",
5444                root.ctx().ordinal(),
5445                combine.root_device
5446            )
5447            .into());
5448        }
5449        for (owner, (token_rows, slots, weights)) in combine.owners.iter_mut().zip(metadata) {
5450            if token_rows.is_empty() {
5451                owner.active_pairs = 0;
5452                continue;
5453            }
5454            root.htod_i32_into(&mut owner.token_rows, &token_rows)?;
5455            root.htod_i32_into(&mut owner.slots, &slots)?;
5456            let mut weight_prefix = owner.weights.slice_mut(0..weights.len());
5457            root.stream().memcpy_htod(&weights, &mut weight_prefix)?;
5458            owner.active_pairs = token_rows.len();
5459        }
5460        combine.tokens = plan.tokens;
5461        combine.pairs = shape.pairs;
5462        combine.projection_generation = plan.generation;
5463        combine.ready = true;
5464        Ok(())
5465    }
5466
5467    pub fn execute_step_grouped_expert_parallel_combine(
5468        &self,
5469        plan: &PreparedStepGroupedExpertParallelGate,
5470        combine: &mut PreparedPeerWeightedRouteCombine,
5471    ) -> Result<(), Box<dyn std::error::Error>> {
5472        if !plan.ready
5473            || plan.executed_generation != Some(plan.generation)
5474            || !combine.ready
5475            || combine.tokens != plan.tokens
5476            || combine.pairs != plan.pairs
5477            || combine.width != plan.input_width
5478            || combine.owners.len() != plan.owners.len()
5479            || combine.projection_generation != plan.generation
5480        {
5481            return Err("Step owner-grouped combine is stale or its geometry changed".into());
5482        }
5483        combine.output_generation = None;
5484        combine.broadcast_generation = None;
5485        for owner in &plan.owners {
5486            if owner.rank == 0 || owner.global_pairs.is_empty() {
5487                continue;
5488            }
5489            let engine = &self.ranks[owner.rank];
5490            let _main = engine.gpu.enter_main()?;
5491            engine.stream().synchronize()?;
5492        }
5493        let root = self
5494            .ranks
5495            .first()
5496            .ok_or("Step owner-grouped combine has no root rank")?;
5497        let _main = root.gpu.enter_main()?;
5498        if root.ctx().ordinal() != combine.root_device {
5499            return Err("Step owner-grouped combine is not resident on the root device".into());
5500        }
5501        for (index, owner) in plan.owners.iter().enumerate() {
5502            let metadata = &combine.owners[index];
5503            if owner.global_pairs.len() != metadata.active_pairs {
5504                return Err(format!(
5505                    "Step owner-grouped combine owner {index} rows {} != metadata {}",
5506                    owner.global_pairs.len(),
5507                    metadata.active_pairs
5508                )
5509                .into());
5510            }
5511            if metadata.active_pairs == 0 {
5512                continue;
5513            }
5514            let values = metadata
5515                .active_pairs
5516                .checked_mul(combine.width)
5517                .ok_or("Step owner-grouped combine peer value count overflow")?;
5518            if owner.rank == 0 {
5519                root.scatter_slot(
5520                    owner.down_workspace.output(),
5521                    &metadata.token_rows,
5522                    &metadata.slots,
5523                    &metadata.weights,
5524                    &mut combine.slots,
5525                    &mut combine.weights,
5526                    combine.width,
5527                    combine.experts_per_token,
5528                    metadata.active_pairs,
5529                )?;
5530            } else {
5531                let source = owner.down_workspace.output().slice(0..values);
5532                let mut destination = combine.peer_staging.slice_mut(0..values);
5533                root.stream().memcpy_dtod(&source, &mut destination)?;
5534                root.scatter_slot(
5535                    &combine.peer_staging,
5536                    &metadata.token_rows,
5537                    &metadata.slots,
5538                    &metadata.weights,
5539                    &mut combine.slots,
5540                    &mut combine.weights,
5541                    combine.width,
5542                    combine.experts_per_token,
5543                    metadata.active_pairs,
5544                )?;
5545            }
5546        }
5547        root.reduce_slots_host(
5548            &combine.slots,
5549            &combine.weights,
5550            &mut combine.output,
5551            combine.width,
5552            combine.experts_per_token,
5553            combine.tokens,
5554        )?;
5555        combine.output_generation = Some(plan.generation);
5556        Ok(())
5557    }
5558
5559    pub fn collect_step_grouped_expert_parallel_combine(
5560        &self,
5561        plan: &PreparedStepGroupedExpertParallelGate,
5562        combine: &PreparedPeerWeightedRouteCombine,
5563    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
5564        if !plan.ready
5565            || combine.output_generation != Some(plan.generation)
5566            || combine.projection_generation != plan.generation
5567        {
5568            return Err("Step owner-grouped combine output is stale or has not executed".into());
5569        }
5570        let root = self
5571            .ranks
5572            .first()
5573            .ok_or("Step owner-grouped combine has no root rank")?;
5574        let _main = root.gpu.enter_main()?;
5575        if root.ctx().ordinal() != combine.root_device {
5576            return Err("Step owner-grouped combine is not resident on the root device".into());
5577        }
5578        root.dtoh_view(&combine.output.slice(0..combine.tokens * combine.width))
5579    }
5580
5581    /// Copy the active root combine result into a caller-owned engine on the same CUDA device.
5582    ///
5583    /// The persistent combine buffer remains reusable by the next route generation; the returned
5584    /// allocation follows the serving runtime's ordinary transient-output ownership.
5585    pub fn copy_step_grouped_expert_parallel_combine_root(
5586        &self,
5587        plan: &PreparedStepGroupedExpertParallelGate,
5588        combine: &PreparedPeerWeightedRouteCombine,
5589        destination: &Engine,
5590    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
5591        if !plan.ready
5592            || combine.output_generation != Some(plan.generation)
5593            || combine.projection_generation != plan.generation
5594        {
5595            return Err("Step owner-grouped combine output is stale or has not executed".into());
5596        }
5597        let root = self
5598            .ranks
5599            .first()
5600            .ok_or("Step owner-grouped combine has no root rank")?;
5601        if root.ctx().ordinal() != combine.root_device
5602            || destination.ctx().ordinal() != combine.root_device
5603        {
5604            return Err(format!(
5605                "Step owner-grouped combine root/destination devices {}/{} != {}",
5606                root.ctx().ordinal(),
5607                destination.ctx().ordinal(),
5608                combine.root_device,
5609            )
5610            .into());
5611        }
5612        let values = combine
5613            .tokens
5614            .checked_mul(combine.width)
5615            .ok_or("Step owner-grouped combine copy size overflow")?;
5616        {
5617            let _main = root.gpu.enter_main()?;
5618            root.stream().synchronize()?;
5619        }
5620        let _main = destination.gpu.enter_main()?;
5621        let mut output = destination.uninit(values)?;
5622        destination
5623            .stream()
5624            .memcpy_dtod(&combine.output.slice(0..values), &mut output)?;
5625        Ok(output)
5626    }
5627
5628    pub fn broadcast_step_grouped_expert_parallel_combine(
5629        &self,
5630        plan: &PreparedStepGroupedExpertParallelGate,
5631        combine: &mut PreparedPeerWeightedRouteCombine,
5632    ) -> Result<(), Box<dyn std::error::Error>> {
5633        if !plan.ready
5634            || combine.output_generation != Some(plan.generation)
5635            || combine.projection_generation != plan.generation
5636            || combine.peer_devices.len() + 1 != self.ranks.len()
5637            || combine.peer_outputs.len() + 1 != self.ranks.len()
5638        {
5639            return Err("Step owner-grouped combine output cannot be broadcast".into());
5640        }
5641        combine.broadcast_generation = None;
5642        let values = combine
5643            .tokens
5644            .checked_mul(combine.width)
5645            .ok_or("Step owner-grouped combine broadcast size overflow")?;
5646        {
5647            let root = self
5648                .ranks
5649                .first()
5650                .ok_or("Step owner-grouped combine has no root rank")?;
5651            let _main = root.gpu.enter_main()?;
5652            if root.ctx().ordinal() != combine.root_device {
5653                return Err("Step owner-grouped combine root device changed".into());
5654            }
5655            root.stream().synchronize()?;
5656        }
5657        let source = &combine.output;
5658        for (index, destination_buffer) in combine.peer_outputs.iter_mut().enumerate() {
5659            let engine = &self.ranks[index + 1];
5660            let _main = engine.gpu.enter_main()?;
5661            if engine.ctx().ordinal() != combine.peer_devices[index] {
5662                return Err(format!(
5663                    "Step owner-grouped combine peer {} device changed",
5664                    index + 1
5665                )
5666                .into());
5667            }
5668            let mut destination = destination_buffer.slice_mut(0..values);
5669            engine
5670                .stream()
5671                .memcpy_dtod(&source.slice(0..values), &mut destination)?;
5672        }
5673        combine.broadcast_generation = Some(plan.generation);
5674        Ok(())
5675    }
5676
5677    pub fn collect_step_grouped_expert_parallel_broadcast(
5678        &self,
5679        plan: &PreparedStepGroupedExpertParallelGate,
5680        combine: &PreparedPeerWeightedRouteCombine,
5681    ) -> Result<Vec<Vec<f32>>, Box<dyn std::error::Error>> {
5682        if !plan.ready
5683            || combine.output_generation != Some(plan.generation)
5684            || combine.broadcast_generation != Some(plan.generation)
5685            || combine.peer_outputs.len() + 1 != self.ranks.len()
5686        {
5687            return Err("Step owner-grouped combine broadcast is stale or incomplete".into());
5688        }
5689        let values = combine
5690            .tokens
5691            .checked_mul(combine.width)
5692            .ok_or("Step owner-grouped combine collection size overflow")?;
5693        let mut outputs = Vec::with_capacity(self.ranks.len());
5694        {
5695            let root = &self.ranks[0];
5696            let _main = root.gpu.enter_main()?;
5697            outputs.push(root.dtoh_view(&combine.output.slice(0..values))?);
5698        }
5699        for (index, output) in combine.peer_outputs.iter().enumerate() {
5700            let engine = &self.ranks[index + 1];
5701            let _main = engine.gpu.enter_main()?;
5702            outputs.push(engine.dtoh_view(&output.slice(0..values))?);
5703        }
5704        Ok(outputs)
5705    }
5706
5707    /// Add routed and replicated shared-expert outputs, then add the attention residual.
5708    pub fn finish_step_grouped_expert_parallel_layer(
5709        &self,
5710        plan: &PreparedStepGroupedExpertParallelGate,
5711        combine: &PreparedPeerWeightedRouteCombine,
5712        shared: &ResidentReplicatedDeviceRows,
5713        residual: &ResidentReplicatedDeviceRows,
5714    ) -> Result<ResidentReplicatedDeviceRows, Box<dyn std::error::Error>> {
5715        validate_replicated_device_rows(&self.ranks, shared)?;
5716        validate_replicated_device_rows(&self.ranks, residual)?;
5717        if !plan.ready
5718            || plan.executed_generation != Some(plan.generation)
5719            || combine.output_generation != Some(plan.generation)
5720            || combine.broadcast_generation != Some(plan.generation)
5721            || combine.projection_generation != plan.generation
5722            || combine.peer_outputs.len() + 1 != self.ranks.len()
5723            || shared.tokens != combine.tokens
5724            || residual.tokens != combine.tokens
5725            || shared.width != combine.width
5726            || residual.width != combine.width
5727        {
5728            return Err("Step full-layer finish inputs are stale or their geometry changed".into());
5729        }
5730        let values = combine
5731            .tokens
5732            .checked_mul(combine.width)
5733            .ok_or("Step full-layer output size overflow")?;
5734        let mut ranks = Vec::with_capacity(self.ranks.len());
5735        for rank in 0..self.ranks.len() {
5736            let engine = &self.ranks[rank];
5737            let _main = engine.gpu.enter_main()?;
5738            let routed = if rank == 0 {
5739                &combine.output
5740            } else {
5741                &combine.peer_outputs[rank - 1]
5742            };
5743            let mut ffn = engine.uninit(values)?;
5744            engine.add(routed, &shared.ranks[rank], &mut ffn, values)?;
5745            let mut output = engine.uninit(values)?;
5746            engine.add(&residual.ranks[rank], &ffn, &mut output, values)?;
5747            ranks.push(output);
5748        }
5749        Ok(ResidentReplicatedDeviceRows {
5750            ranks,
5751            tokens: combine.tokens,
5752            width: combine.width,
5753        })
5754    }
5755
5756    pub fn run_step_grouped_expert_parallel_combine(
5757        &self,
5758        plan: &PreparedStepGroupedExpertParallelGate,
5759        combine: &mut PreparedPeerWeightedRouteCombine,
5760    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
5761        self.execute_step_grouped_expert_parallel_combine(plan, combine)?;
5762        self.collect_step_grouped_expert_parallel_combine(plan, combine)
5763    }
5764
5765    pub fn upload_tensor_parallel(
5766        &self,
5767        gate: E4m3ExpertBank<'_>,
5768        up: E4m3ExpertBank<'_>,
5769        down: E4m3ExpertBank<'_>,
5770    ) -> Result<ResidentTensorParallel, Box<dyn std::error::Error>> {
5771        gate.validate()?;
5772        up.validate()?;
5773        down.validate()?;
5774        if gate.expert_count != up.expert_count || gate.expert_count != down.expert_count {
5775            return Err("TP gate/up/down expert counts differ".into());
5776        }
5777        if gate.in_features != up.in_features || gate.out_features != up.out_features {
5778            return Err("TP gate/up dimensions differ".into());
5779        }
5780        if down.in_features != gate.out_features || down.out_features != gate.in_features {
5781            return Err(format!(
5782                "TP down {}x{} does not invert gate/up {}x{}",
5783                down.out_features, down.in_features, gate.out_features, gate.in_features
5784            )
5785            .into());
5786        }
5787        let tp = self.ranks.len();
5788        validate_column_bank_shape(gate, tp)?;
5789        validate_column_bank_shape(up, tp)?;
5790        validate_row_bank_shape(down, tp)?;
5791
5792        let mut gate_ranks = Vec::with_capacity(tp);
5793        let mut up_ranks = Vec::with_capacity(tp);
5794        let mut down_ranks = Vec::with_capacity(tp);
5795        for (rank, engine) in self.ranks.iter().enumerate() {
5796            gate_ranks.push(upload_column_bank_rank(engine, gate, tp, rank)?);
5797            up_ranks.push(upload_column_bank_rank(engine, up, tp, rank)?);
5798            down_ranks.push(upload_row_bank_rank(engine, down, tp, rank)?);
5799        }
5800        Ok(ResidentTensorParallel {
5801            bank: ResidentTpExpertBank {
5802                gate: gate_ranks,
5803                up: up_ranks,
5804                down: down_ranks,
5805                expert_count: gate.expert_count,
5806                input_width: gate.in_features,
5807                expert_width: gate.out_features,
5808            },
5809        })
5810    }
5811
5812    pub fn run_tensor_parallel_routes(
5813        &self,
5814        experts: &ResidentTensorParallel,
5815        input: &[f32],
5816        tokens: usize,
5817        selected: &[usize],
5818        route_weights: &[f32],
5819        experts_per_token: usize,
5820    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
5821        validate_tp_bank_residency(&self.ranks, &experts.bank)?;
5822        validate_activations(input, tokens, experts.bank.input_width)?;
5823        let pairs = tokens
5824            .checked_mul(experts_per_token)
5825            .ok_or("TP route count overflow")?;
5826        if selected.len() != pairs || route_weights.len() != pairs {
5827            return Err(format!(
5828                "TP routes selected={} weights={} != tokens {tokens} x experts/token \
5829                 {experts_per_token} ({pairs})",
5830                selected.len(),
5831                route_weights.len(),
5832            )
5833            .into());
5834        }
5835        if !route_weights.iter().all(|weight| weight.is_finite()) {
5836            return Err("TP route weights contain a non-finite value".into());
5837        }
5838
5839        let mut output = vec![0.0f32; tokens * experts.bank.input_width];
5840        for token in 0..tokens {
5841            let input_row =
5842                &input[token * experts.bank.input_width..(token + 1) * experts.bank.input_width];
5843            for slot in 0..experts_per_token {
5844                let pair = token * experts_per_token + slot;
5845                let expert = selected[pair];
5846                if expert >= experts.bank.expert_count {
5847                    return Err(format!(
5848                        "TP selected expert {expert} outside 0..{}",
5849                        experts.bank.expert_count
5850                    )
5851                    .into());
5852                }
5853                let down = if self.native_p2p {
5854                    self.run_tensor_parallel_expert_native(&experts.bank, expert, input_row)?
5855                } else {
5856                    let gate =
5857                        self.run_column_bank_expert(&experts.bank.gate, expert, input_row)?;
5858                    let up = self.run_column_bank_expert(&experts.bank.up, expert, input_row)?;
5859                    let activated: Vec<f32> = gate
5860                        .iter()
5861                        .zip(&up)
5862                        .map(|(&gate, &up)| gate / (1.0 + (-gate).exp()) * up)
5863                        .collect();
5864                    debug_assert_eq!(activated.len(), experts.bank.expert_width);
5865                    self.run_row_bank_expert(&experts.bank.down, expert, &activated)?
5866                };
5867                let weight = route_weights[pair];
5868                for (sum, value) in output
5869                    [token * experts.bank.input_width..(token + 1) * experts.bank.input_width]
5870                    .iter_mut()
5871                    .zip(down)
5872                {
5873                    *sum += weight * value;
5874                }
5875            }
5876        }
5877        Ok(output)
5878    }
5879
5880    fn run_column_bank_expert(
5881        &self,
5882        ranks: &[ResidentE4m3ExpertBankRank],
5883        expert: usize,
5884        input: &[f32],
5885    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
5886        let local_out = ranks
5887            .first()
5888            .ok_or("TP column bank has no ranks")?
5889            .out_features;
5890        let mut gathered = vec![0.0f32; local_out * ranks.len()];
5891        for (rank, (engine, bank)) in self.ranks.iter().zip(ranks).enumerate() {
5892            let shard = run_resident_bank_expert(engine, bank, expert, input, 1)?;
5893            gathered[rank * local_out..(rank + 1) * local_out].copy_from_slice(&shard);
5894        }
5895        Ok(gathered)
5896    }
5897
5898    fn run_row_bank_expert(
5899        &self,
5900        ranks: &[ResidentE4m3ExpertBankRank],
5901        expert: usize,
5902        input: &[f32],
5903    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
5904        let local_in = ranks.first().ok_or("TP row bank has no ranks")?.in_features;
5905        if input.len() != local_in * ranks.len() {
5906            return Err(format!(
5907                "TP row input {} != {} ranks x {local_in}",
5908                input.len(),
5909                ranks.len()
5910            )
5911            .into());
5912        }
5913        let out_features = ranks[0].out_features;
5914        let mut reduced = vec![0.0f32; out_features];
5915        for (rank, (engine, bank)) in self.ranks.iter().zip(ranks).enumerate() {
5916            let blocks = bank
5917                .k_blocks
5918                .ok_or("TP row bank is not packed in native K-block order")?;
5919            if blocks * FP8_BLOCK != local_in {
5920                return Err(format!(
5921                    "TP row bank has {blocks} blocks but local input width is {local_in}"
5922                )
5923                .into());
5924            }
5925            for block in 0..blocks {
5926                let global_start = rank * local_in + block * FP8_BLOCK;
5927                let partial = run_resident_bank_expert_block(
5928                    engine,
5929                    bank,
5930                    expert,
5931                    block,
5932                    &input[global_start..global_start + FP8_BLOCK],
5933                )?;
5934                for (sum, value) in reduced.iter_mut().zip(partial) {
5935                    *sum += value;
5936                }
5937            }
5938        }
5939        Ok(reduced)
5940    }
5941
5942    fn run_tensor_parallel_expert_native(
5943        &self,
5944        bank: &ResidentTpExpertBank,
5945        expert: usize,
5946        input: &[f32],
5947    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
5948        if !self.native_p2p || self.ranks.len() < 2 {
5949            return Err("native TP expert execution requires at least two P2P ranks".into());
5950        }
5951        let local_out = bank
5952            .gate
5953            .first()
5954            .ok_or("native TP gate bank has no ranks")?
5955            .out_features;
5956        if local_out * self.ranks.len() != bank.expert_width {
5957            return Err(format!(
5958                "native TP gate shards {}x{local_out} != expert width {}",
5959                self.ranks.len(),
5960                bank.expert_width
5961            )
5962            .into());
5963        }
5964
5965        // The caller's routed input is already host-canonical. Upload once on rank zero, then
5966        // broadcast over peer copies so no other rank receives a host-staged duplicate.
5967        let mut rank_inputs = Vec::with_capacity(self.ranks.len());
5968        let root_input = {
5969            let root = &self.ranks[0];
5970            let _main = root.gpu.enter_main()?;
5971            root.htod(input)?
5972        };
5973        rank_inputs.push(root_input);
5974        for engine in &self.ranks[1..] {
5975            let peer_input = {
5976                let _main = engine.gpu.enter_main()?;
5977                let mut peer_input = engine.uninit(input.len())?;
5978                engine
5979                    .stream()
5980                    .memcpy_dtod(&rank_inputs[0], &mut peer_input)?;
5981                peer_input
5982            };
5983            rank_inputs.push(peer_input);
5984        }
5985
5986        let mut gate_shards = Vec::with_capacity(self.ranks.len());
5987        let mut up_shards = Vec::with_capacity(self.ranks.len());
5988        #[allow(clippy::needless_range_loop)]
5989        // allow: the explicit index loop keeps the offset arithmetic visible and aligned with the device-side indexing
5990        for rank in 0..self.ranks.len() {
5991            gate_shards.push(run_resident_bank_expert_device(
5992                &self.ranks[rank],
5993                &bank.gate[rank],
5994                expert,
5995                &rank_inputs[rank],
5996                1,
5997            )?);
5998            up_shards.push(run_resident_bank_expert_device(
5999                &self.ranks[rank],
6000                &bank.up[rank],
6001                expert,
6002                &rank_inputs[rank],
6003                1,
6004            )?);
6005        }
6006
6007        // Preserve the established canonical activation program for the first native transport
6008        // milestone. The shards move to rank zero over P2P; only the scalar activation expression
6009        // executes on host. A later device-activation increment must earn its own exactness gate.
6010        let gate = self.gather_native_column_shards(&gate_shards, 1, local_out)?;
6011        let up = self.gather_native_column_shards(&up_shards, 1, local_out)?;
6012        let activated = gate
6013            .iter()
6014            .zip(&up)
6015            .map(|(&gate, &up)| gate / (1.0 + (-gate).exp()) * up)
6016            .collect::<Vec<_>>();
6017        debug_assert_eq!(activated.len(), bank.expert_width);
6018
6019        let root_activated = {
6020            let root = &self.ranks[0];
6021            let _main = root.gpu.enter_main()?;
6022            root.htod(&activated)?
6023        };
6024        let mut rank_activated = Vec::with_capacity(self.ranks.len());
6025        for (rank, engine) in self.ranks.iter().enumerate() {
6026            let start = rank * local_out;
6027            let source = root_activated.slice(start..start + local_out);
6028            let local = {
6029                let _main = engine.gpu.enter_main()?;
6030                let mut local = engine.uninit(local_out)?;
6031                engine.stream().memcpy_dtod(&source, &mut local)?;
6032                local
6033            };
6034            rank_activated.push(local);
6035        }
6036
6037        let out_features = bank
6038            .down
6039            .first()
6040            .ok_or("native TP down bank has no ranks")?
6041            .out_features;
6042        let mut reduced = {
6043            let root = &self.ranks[0];
6044            let _main = root.gpu.enter_main()?;
6045            root.htod(&vec![0.0f32; out_features])?
6046        };
6047        let mut remote_partial_keepalive = Vec::new();
6048        #[allow(clippy::needless_range_loop)]
6049        // allow: the explicit index loop keeps the offset arithmetic visible and aligned with the device-side indexing
6050        for rank in 0..self.ranks.len() {
6051            let down = &bank.down[rank];
6052            let blocks = down
6053                .k_blocks
6054                .ok_or("native TP row bank is not packed in checkpoint-block order")?;
6055            if blocks * FP8_BLOCK != local_out {
6056                return Err(format!(
6057                    "native TP rank {rank} has {blocks} blocks but local activation width is \
6058                     {local_out}"
6059                )
6060                .into());
6061            }
6062            for block in 0..blocks {
6063                let start = block * FP8_BLOCK;
6064                let input_block = rank_activated[rank].slice(start..start + FP8_BLOCK);
6065                let partial = run_resident_bank_expert_block_device(
6066                    &self.ranks[rank],
6067                    down,
6068                    expert,
6069                    block,
6070                    &input_block,
6071                )?;
6072                let root_partial = if rank == 0 {
6073                    partial
6074                } else {
6075                    let root = &self.ranks[0];
6076                    let _main = root.gpu.enter_main()?;
6077                    let mut peer_partial = root.uninit(out_features)?;
6078                    root.stream().memcpy_dtod(&partial, &mut peer_partial)?;
6079                    remote_partial_keepalive.push(partial);
6080                    peer_partial
6081                };
6082                let next = {
6083                    let root = &self.ranks[0];
6084                    let _main = root.gpu.enter_main()?;
6085                    let mut next = root.uninit(out_features)?;
6086                    root.add(&reduced, &root_partial, &mut next, out_features)?;
6087                    next
6088                };
6089                reduced = next;
6090            }
6091        }
6092        let output = {
6093            let root = &self.ranks[0];
6094            let _main = root.gpu.enter_main()?;
6095            root.dtoh(&reduced)?
6096        };
6097        drop(remote_partial_keepalive);
6098        Ok(output)
6099    }
6100
6101    /// Gather token-major rank-local columns into one canonical root-device matrix.
6102    pub fn gather_native_column_shards_device(
6103        &self,
6104        shards: &[CudaSlice<f32>],
6105        tokens: usize,
6106        local_out: usize,
6107    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
6108        let shard_len = tokens
6109            .checked_mul(local_out)
6110            .ok_or("native TP gather shard size overflow")?;
6111        if shards.len() != self.ranks.len() || shards.iter().any(|shard| shard.len() != shard_len) {
6112            return Err("native TP gather shard geometry mismatch".into());
6113        }
6114        // PRODUCER FENCE (2026-08-20 flake fix): the root stream peer-reads shards produced on
6115        // the other ranks' streams; without fencing those producers the copy can read a partial
6116        // kernel output.
6117        for engine in &self.ranks[1..] {
6118            let _main = engine.gpu.enter_main()?;
6119            engine.stream().synchronize()?;
6120        }
6121        let root = &self.ranks[0];
6122        let _main = root.gpu.enter_main()?;
6123        let global_out = shards
6124            .len()
6125            .checked_mul(local_out)
6126            .ok_or("native TP gather output width overflow")?;
6127        let gathered_len = tokens
6128            .checked_mul(global_out)
6129            .ok_or("native TP gather output size overflow")?;
6130        let mut gathered = root.uninit(gathered_len)?;
6131        if self.bulk_p2p {
6132            root.place_rows_strided(&shards[0], &mut gathered, local_out, tokens, global_out, 0)?;
6133            if shards.len() > 1 {
6134                let mut staging = root.uninit(shard_len)?;
6135                for (rank, shard) in shards.iter().enumerate().skip(1) {
6136                    root.stream().memcpy_dtod(shard, &mut staging)?;
6137                    root.place_rows_strided(
6138                        &staging,
6139                        &mut gathered,
6140                        local_out,
6141                        tokens,
6142                        global_out,
6143                        rank * local_out,
6144                    )?;
6145                }
6146            }
6147        } else {
6148            for token in 0..tokens {
6149                for (rank, shard) in shards.iter().enumerate() {
6150                    let source = shard.slice(token * local_out..(token + 1) * local_out);
6151                    let start = token * global_out + rank * local_out;
6152                    let mut destination = gathered.slice_mut(start..start + local_out);
6153                    root.stream().memcpy_dtod(&source, &mut destination)?;
6154                }
6155            }
6156        }
6157        Ok(gathered)
6158    }
6159
6160    pub fn gather_native_column_shards(
6161        &self,
6162        shards: &[CudaSlice<f32>],
6163        tokens: usize,
6164        local_out: usize,
6165    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
6166        let gathered = self.gather_native_column_shards_device(shards, tokens, local_out)?;
6167        let root = &self.ranks[0];
6168        let _main = root.gpu.enter_main()?;
6169        root.dtoh(&gathered)
6170    }
6171
6172    pub(crate) fn decode_v2_workspace(&self) -> &std::sync::Mutex<Vec<StepTpDecodeV2Ws>> {
6173        &self.decode_v2
6174    }
6175
6176    /// Build the v2 decode-attention workspace for this layer's geometry on first use, or
6177    /// return the index of the matching one. Attention geometry varies across the trunk
6178    /// (per-layer query-head counts), so workspaces are keyed by their geometry pins — a
6179    /// handful exist per model, never one per layer.
6180    ///
6181    /// Refuses non-F32-resident projections: the v2 driver's bit-exactness claim against v1
6182    /// holds per residency class, and only the mirror class has no per-call weight expansion
6183    /// to hide allocation churn behind.
6184    #[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
6185    pub(crate) fn decode_v2_ensure(
6186        &self,
6187        e: &Engine,
6188        q_m: &ResidentBf16ColumnParallel,
6189        k_m: &ResidentBf16ColumnParallel,
6190        v_m: &ResidentBf16ColumnParallel,
6191        o_m: &ResidentStepBf16RowParallel,
6192        heads: usize,
6193    ) -> Result<usize, Box<dyn std::error::Error>> {
6194        if self.ranks.len() > 1 && !self.native_p2p {
6195            return Err("step TP decode v2 requires native P2P ranks".into());
6196        }
6197        let ranks = self.ranks.len();
6198        // Residency contract: the canonical-chunk (non-fused) program needs the F32 mirror;
6199        // the fused-kernel door also reads raw checkpoint bf16 directly (halving the weight
6200        // traffic), so bf16 residency is accepted when that door is on.
6201        let fused_door = step_tp_qkv_fused_enabled()?;
6202        let arm_ok = |weight: &ResidentBf16Weight| match weight {
6203            ResidentBf16Weight::F32(_) => true,
6204            ResidentBf16Weight::Bf16(_) => fused_door,
6205        };
6206        for matrix in [q_m, k_m, v_m] {
6207            validate_resident_bf16_ranks(&self.ranks, &matrix.ranks)?;
6208            if matrix.out_features % ranks != 0 || matrix.in_features != q_m.in_features {
6209                return Err("step TP decode v2 QKV geometry mismatch".into());
6210            }
6211            for rank in &matrix.ranks {
6212                if !arm_ok(&rank.weight) {
6213                    return Err("step TP decode v2 requires MEMRA_STEP_TP_F32_MIRROR=1 or \
6214                                MEMRA_STEP_TP_QKV_FUSED=1 (bf16-resident fused kernels)"
6215                        .into());
6216                }
6217            }
6218        }
6219        validate_step_bf16_row_residency(&self.ranks, o_m)?;
6220        for blocks in &o_m.ranks {
6221            for block in blocks {
6222                if !arm_ok(&block.weight) {
6223                    return Err("step TP decode v2 requires MEMRA_STEP_TP_F32_MIRROR=1 or \
6224                                MEMRA_STEP_TP_QKV_FUSED=1 (bf16-resident fused kernels)"
6225                        .into());
6226                }
6227            }
6228        }
6229        if v_m.out_features != k_m.out_features
6230            || o_m.in_features != q_m.out_features
6231            || heads == 0
6232            || heads % ranks != 0
6233        {
6234            return Err("step TP decode v2 K/V/O geometry mismatch".into());
6235        }
6236        let local_q_dim = q_m.out_features / ranks;
6237        let local_kv_dim = k_m.out_features / ranks;
6238        let o_out = o_m.out_features;
6239        let o_block_cols = o_m.canonical_chunk_cols;
6240        let blocks_per_rank = o_m.ranks.first().map(Vec::len).unwrap_or(0);
6241        if blocks_per_rank == 0
6242            || o_m
6243                .ranks
6244                .iter()
6245                .any(|blocks| blocks.len() != blocks_per_rank)
6246            || blocks_per_rank * o_block_cols * ranks != o_m.in_features
6247        {
6248            return Err("step TP decode v2 O canonical block grid mismatch".into());
6249        }
6250
6251        let mut guard = self
6252            .decode_v2
6253            .lock()
6254            .map_err(|_| "step TP decode v2 workspace lock is poisoned")?;
6255        if let Some(index) = guard.iter().position(|ws| {
6256            ws.local_q_dim == local_q_dim
6257                && ws.local_kv_dim == local_kv_dim
6258                && ws.heads == heads
6259                && ws.o_out == o_out
6260                && ws.o_block_cols == o_block_cols
6261                && ws.blocks_per_rank == blocks_per_rank
6262                && ws.e_device == e.ctx().ordinal()
6263                && ws.q.len() == ranks
6264        }) {
6265            return Ok(index);
6266        }
6267
6268        let mut q_raw = Vec::with_capacity(ranks);
6269        let mut k_raw = Vec::with_capacity(ranks);
6270        let mut v_raw = Vec::with_capacity(ranks);
6271        let mut q = Vec::with_capacity(ranks);
6272        let mut k = Vec::with_capacity(ranks);
6273        let mut pos = Vec::with_capacity(ranks);
6274        let mut gate = Vec::with_capacity(ranks);
6275        let mut attn_out = Vec::with_capacity(ranks);
6276        let mut gated = Vec::with_capacity(ranks);
6277        let mut fuse_ctr = Vec::with_capacity(ranks);
6278        let mut o_partials = Vec::with_capacity(ranks);
6279        let mut ev_rank = Vec::with_capacity(ranks);
6280        let direct_join = oproj_direct_on();
6281        for (rank, engine) in self.ranks.iter().enumerate() {
6282            let _main = engine.gpu.enter_main()?;
6283            q_raw.push(engine.uninit(local_q_dim)?);
6284            k_raw.push(engine.uninit(local_kv_dim)?);
6285            v_raw.push(engine.uninit(local_kv_dim)?);
6286            q.push(engine.uninit(local_q_dim)?);
6287            k.push(engine.uninit(local_kv_dim)?);
6288            pos.push(engine.htod_i32(&[0])?);
6289            fuse_ctr.push(engine.stream().clone_htod(&[0u32])?);
6290            gate.push(engine.uninit(heads / ranks)?);
6291            attn_out.push(engine.uninit(local_q_dim)?);
6292            gated.push(engine.uninit(local_q_dim)?);
6293            let mut rank_partials = Vec::with_capacity(blocks_per_rank);
6294            for _ in 0..blocks_per_rank {
6295                // Direct join: peer ranks' partials live on ROOT so the b4 kernel's
6296                // stores land there over P2P (UVA) and no pull copy is needed.
6297                if direct_join && rank != 0 {
6298                    let root = &self.ranks[0];
6299                    let _root_main = root.gpu.enter_main()?;
6300                    rank_partials.push(root.uninit(o_out)?);
6301                } else {
6302                    rank_partials.push(engine.uninit(o_out)?);
6303                }
6304            }
6305            o_partials.push(rank_partials);
6306            ev_rank.push(engine.ctx().new_event(None)?);
6307        }
6308        use cudarc::driver::DevicePtr;
6309        let mut raw_o_partials = Vec::with_capacity(ranks);
6310        let mut raw_k = Vec::with_capacity(ranks);
6311        let mut raw_v_raw = Vec::with_capacity(ranks);
6312        for rank in 0..ranks {
6313            let engine = &self.ranks[rank];
6314            {
6315                let _main = engine.gpu.enter_main()?;
6316                let stream = engine.stream();
6317                let (k_ptr, _k_guard) = k[rank].device_ptr(&stream);
6318                let (v_ptr, _v_guard) = v_raw[rank].device_ptr(&stream);
6319                raw_k.push(k_ptr);
6320                raw_v_raw.push(v_ptr);
6321            }
6322            let partial_engine = if direct_join && rank != 0 {
6323                &self.ranks[0]
6324            } else {
6325                engine
6326            };
6327            let _main = partial_engine.gpu.enter_main()?;
6328            let stream = partial_engine.stream();
6329            let mut rank_raw = Vec::with_capacity(blocks_per_rank);
6330            for partial in &o_partials[rank] {
6331                let (ptr, _guard) = partial.device_ptr(&stream);
6332                rank_raw.push(ptr);
6333            }
6334            raw_o_partials.push(rank_raw);
6335        }
6336        let root = &self.ranks[0];
6337        let (peer_partial, reduce_a, reduce_b, zeros, k_shadow, v_shadow, ev_refresh, ev_oproj) = {
6338            let _main = root.gpu.enter_main()?;
6339            (
6340                root.uninit(o_out)?,
6341                root.uninit(o_out)?,
6342                root.uninit(o_out)?,
6343                root.htod(&vec![0.0f32; o_out])?,
6344                root.uninit(ranks * local_kv_dim)?,
6345                root.uninit(ranks * local_kv_dim)?,
6346                root.ctx().new_event(None)?,
6347                root.ctx().new_event(None)?,
6348            )
6349        };
6350        let (raw_peer_partial, raw_k_shadow, raw_v_shadow) = {
6351            let _main = root.gpu.enter_main()?;
6352            let stream = root.stream();
6353            let (peer, _peer_guard) = peer_partial.device_ptr(&stream);
6354            let (k, _k_guard) = k_shadow.device_ptr(&stream);
6355            let (v, _v_guard) = v_shadow.device_ptr(&stream);
6356            (peer, k, v)
6357        };
6358        let (gate_e, ev_entry) = {
6359            let _main = e.gpu.enter_main()?;
6360            (e.uninit(heads)?, e.ctx().new_event(None)?)
6361        };
6362        let raw_attn_in = Vec::new();
6363        let raw_pos = Vec::new();
6364        guard.push(StepTpDecodeV2Ws {
6365            tcol_q: Vec::new(),
6366            tcol_k: Vec::new(),
6367            tcol_v: Vec::new(),
6368            tcol_g: Vec::new(),
6369            tcol_in: Vec::new(),
6370            tcol_cap: 0,
6371            w8_aq: Vec::new(),
6372            w8_ad: Vec::new(),
6373            w8_in: 0,
6374            w8o_aq: Vec::new(),
6375            w8o_ad: Vec::new(),
6376            w8o_in: 0,
6377            w8t_aq: Vec::new(),
6378            w8t_ad: Vec::new(),
6379            w8t_in: 0,
6380            w8t_oaq: Vec::new(),
6381            w8t_oad: Vec::new(),
6382            w8t_oin: 0,
6383            w8t_cap: 0,
6384            fa2_q: Vec::new(),
6385            fa2_gate: Vec::new(),
6386            fa2_gated: Vec::new(),
6387            fa2_cap: 0,
6388            rope_k_t: Vec::new(),
6389            rope_ctr_t: Vec::new(),
6390            rope_pos_t: Vec::new(),
6391            rows_tabs: Vec::new(),
6392            rows_tab_t: Vec::new(),
6393            rows_tab_shadow: Vec::new(),
6394            tcol_gated: Vec::new(),
6395            tcol_opart: Vec::new(),
6396            tcol_opeer: None,
6397            tcol_omix: None,
6398            tcol_ocap: 0,
6399            q_raw,
6400            k_raw,
6401            v_raw,
6402            q,
6403            k,
6404            pos,
6405            fuse_ctr,
6406            gate,
6407            attn_out,
6408            gated,
6409            o_partials,
6410            raw_o_partials,
6411            raw_k,
6412            raw_v_raw,
6413            ev_rank,
6414            peer_partial,
6415            reduce_a,
6416            reduce_b,
6417            zeros,
6418            k_shadow,
6419            v_shadow,
6420            ev_refresh,
6421            ev_oproj,
6422            gate_e,
6423            attn_in: Vec::new(),
6424            h_stage: None,
6425            pos_stage: None,
6426            raw_h_stage: 0,
6427            raw_pos_stage: 0,
6428            raw_attn_in,
6429            raw_pos,
6430            raw_o_partial1: 0,
6431            raw_peer_partial,
6432            raw_k1: 0,
6433            raw_v1: 0,
6434            raw_k_shadow,
6435            raw_v_shadow,
6436            raw_mixed_stage_e: 0,
6437            raw_reduce_a: 0,
6438            raw_shadow_stage_e: (0, 0),
6439            ev_entry,
6440            e_device: e.ctx().ordinal(),
6441            local_q_dim,
6442            local_kv_dim,
6443            heads,
6444            o_out,
6445            o_block_cols,
6446            blocks_per_rank,
6447        });
6448        eprintln!(
6449            "[step-tp-decode-v2] workspace ranks={ranks} local_q={local_q_dim} \
6450             local_kv={local_kv_dim} heads={heads} o_blocks={blocks_per_rank}x{o_block_cols} \
6451             residency=persistent ordering=evented performance_claim=false"
6452        );
6453        Ok(guard.len() - 1)
6454    }
6455
6456    /// v2 phase 1: replicate the layer input, project QKV, norm, rope, and stage the gate —
6457    /// all into the persistent workspace, ordered by events instead of host syncs.
6458    ///
6459    /// The caller must have queued every producer of `h`, `pos_d`, and `gate_raw` on `e`'s
6460    /// stream BEFORE this call: `ev_entry` is recorded once here and every rank stream waits
6461    /// on it (the entry fence also guards workspace reuse across layers — any consumer of the
6462    /// previous layer's outputs was queued on `e`'s stream before this record).
6463    #[allow(clippy::too_many_arguments)]
6464    /// T-COLUMN verify precompute (spec MTP): stage T input rows to every rank and run the
6465    /// weight-amortized qkvg_tcol per rank into the ws slabs. Rope/norm/append stay per
6466    /// column in the unmodified t=1 program (defer_norm_rope contract). Bit-exact per
6467    /// column vs the t=1 kernel by construction.
6468    #[allow(clippy::too_many_arguments)]
6469    pub fn decode_v2_input_qkv_tcol(
6470        &self,
6471        ws_index: usize,
6472        e: &Engine,
6473        h_t: &CudaSlice<f32>,
6474        t: usize,
6475        q_m: &ResidentBf16ColumnParallel,
6476        k_m: &ResidentBf16ColumnParallel,
6477        v_m: &ResidentBf16ColumnParallel,
6478        gate_shards: Option<StepTpGateShards<'_>>,
6479    ) -> Result<(), Box<dyn std::error::Error>> {
6480        let ranks = self.ranks.len();
6481        let mut guard = self
6482            .decode_v2
6483            .lock()
6484            .map_err(|_| "step TP decode v2 workspace lock is poisoned")?;
6485        let ws = guard
6486            .get_mut(ws_index)
6487            .ok_or("step TP decode v2 workspace index out of range")?;
6488        let in_f = q_m.in_features;
6489        if h_t.len() < t * in_f || t == 0 || t > 32 {
6490            return Err("decode_v2_input_qkv_tcol geometry".into());
6491        }
6492        // Lazily arm the slabs to capacity.
6493        if ws.tcol_cap < t || ws.tcol_q.len() != ranks {
6494            ws.tcol_q.clear();
6495            ws.tcol_k.clear();
6496            ws.tcol_v.clear();
6497            ws.tcol_g.clear();
6498            ws.tcol_in.clear();
6499            for engine in &self.ranks {
6500                let _m = engine.gpu.enter_main()?;
6501                ws.tcol_q.push(engine.uninit(32 * ws.local_q_dim)?);
6502                ws.tcol_k.push(engine.uninit(32 * ws.local_kv_dim)?);
6503                ws.tcol_v.push(engine.uninit(32 * ws.local_kv_dim)?);
6504                ws.tcol_g
6505                    .push(engine.uninit(32 * (ws.heads / ranks).max(1))?);
6506                ws.tcol_in.push(engine.uninit(32 * in_f)?);
6507            }
6508            ws.tcol_cap = 32;
6509        }
6510        // Stage the T input rows on e, fence, per-rank pull + tcol launch.
6511        use cudarc::driver::DevicePtr;
6512        let raw_src = {
6513            let _main = e.gpu.enter_main()?;
6514            let stream = e.stream();
6515            let (p, _g) = h_t.device_ptr(&stream);
6516            ws.ev_entry.record(&stream)?;
6517            p
6518        };
6519        for rank in 0..ranks {
6520            let engine = &self.ranks[rank];
6521            let _main = engine.gpu.enter_main()?;
6522            engine.stream().wait(&ws.ev_entry)?;
6523            let raw_dst = {
6524                let stream = engine.stream();
6525                let (p, _g) = ws.tcol_in[rank].device_ptr(&stream);
6526                p
6527            };
6528            raw_copy_bytes(raw_dst, raw_src, t * in_f * 4, engine)?;
6529            let out_g = match &gate_shards {
6530                Some(_) => ws.heads / ranks,
6531                None => 0,
6532            };
6533            match (
6534                &q_m.ranks[rank].weight,
6535                &k_m.ranks[rank].weight,
6536                &v_m.ranks[rank].weight,
6537            ) {
6538                (
6539                    ResidentBf16Weight::Bf16(wq),
6540                    ResidentBf16Weight::Bf16(wk),
6541                    ResidentBf16Weight::Bf16(wv),
6542                ) => {
6543                    let wg = match &gate_shards {
6544                        Some(StepTpGateShards::Bf16(shards)) => &shards[rank],
6545                        Some(StepTpGateShards::F32(_)) => {
6546                            return Err(
6547                                "tcol verify: gate shard class does not match bf16 QKV".into()
6548                            );
6549                        }
6550                        None => wq,
6551                    };
6552                    let StepTpDecodeV2Ws {
6553                        tcol_q,
6554                        tcol_k,
6555                        tcol_v,
6556                        tcol_g,
6557                        tcol_in,
6558                        local_q_dim,
6559                        local_kv_dim,
6560                        w8t_aq,
6561                        w8t_ad,
6562                        w8t_in,
6563                        w8t_cap,
6564                        ..
6565                    } = &mut *ws;
6566                    // MEMRA_TCOL_REFKERN=1 (bisect): fill the slabs via the t=1 kernel per
6567                    // column — separates driver bugs from tcol-kernel bugs.
6568                    static REFK: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
6569                    let refk = *REFK
6570                        .get_or_init(|| std::env::var("MEMRA_TCOL_REFKERN").as_deref() == Ok("1"));
6571                    if refk {
6572                        let lq = *local_q_dim;
6573                        let lkv = *local_kv_dim;
6574                        let mut hrow = engine.uninit(in_f)?;
6575                        let mut qr = engine.uninit(lq)?;
6576                        let mut kr = engine.uninit(lkv)?;
6577                        let mut vr = engine.uninit(lkv)?;
6578                        let mut gr = engine.uninit(out_g.max(1))?;
6579                        for c in 0..t {
6580                            {
6581                                let mut dst = hrow.slice_mut(0..in_f);
6582                                engine.stream().memcpy_dtod(
6583                                    &tcol_in[rank].slice(c * in_f..(c + 1) * in_f),
6584                                    &mut dst,
6585                                )?;
6586                            }
6587                            engine.matvec_bf16_qkvg_into(
6588                                wq, wk, wv, wg, &hrow, &mut qr, &mut kr, &mut vr, &mut gr, in_f,
6589                                lq, lkv, out_g,
6590                            )?;
6591                            let stream = engine.stream();
6592                            {
6593                                let mut dst = tcol_q[rank].slice_mut(c * lq..(c + 1) * lq);
6594                                stream.memcpy_dtod(&qr.slice(0..lq), &mut dst)?;
6595                            }
6596                            {
6597                                let mut dst = tcol_k[rank].slice_mut(c * lkv..(c + 1) * lkv);
6598                                stream.memcpy_dtod(&kr.slice(0..lkv), &mut dst)?;
6599                            }
6600                            {
6601                                let mut dst = tcol_v[rank].slice_mut(c * lkv..(c + 1) * lkv);
6602                                stream.memcpy_dtod(&vr.slice(0..lkv), &mut dst)?;
6603                            }
6604                            if out_g > 0 {
6605                                let mut dst = tcol_g[rank].slice_mut(c * out_g..(c + 1) * out_g);
6606                                stream.memcpy_dtod(&gr.slice(0..out_g), &mut dst)?;
6607                            }
6608                        }
6609                    } else if crate::step_tp_w8_on()
6610                        && q_m.ranks[rank].q8.is_some()
6611                        && k_m.ranks[rank].q8.is_some()
6612                        && v_m.ranks[rank].q8.is_some()
6613                        && in_f.is_multiple_of(32)
6614                    {
6615                        // MEMRA_STEP_TP_W8 on the VERIFY walk. nsys put the bf16 tcol QKV at
6616                        // 12.3% of spec GPU time and the bf16 tcol o_proj at 24.8% — the door
6617                        // had only ever replaced the DECODE kernels, so 37% of the verify still
6618                        // streamed bf16 weights. One q8 launch over all t columns; the gate rows
6619                        // stay bf16 as on the decode side.
6620                        if *w8t_in != in_f || *w8t_cap < t || w8t_aq.len() != ranks {
6621                            w8t_aq.clear();
6622                            w8t_ad.clear();
6623                            for e_rank in &self.ranks {
6624                                let _m = e_rank.gpu.enter_main()?;
6625                                w8t_aq.push(e_rank.alloc_i8_uninit(32 * in_f)?);
6626                                w8t_ad.push(e_rank.alloc_uninit::<f32>(32 * (in_f / 32))?);
6627                            }
6628                            *w8t_in = in_f;
6629                            *w8t_cap = 32;
6630                        }
6631                        engine.quantize_q8_1_into(
6632                            &tcol_in[rank],
6633                            t,
6634                            in_f,
6635                            &mut w8t_aq[rank],
6636                            &mut w8t_ad[rank],
6637                        )?;
6638                        engine.qmatvec_q8_0_qkv_rp_t_into(
6639                            q_m.ranks[rank].q8.as_ref().unwrap(),
6640                            k_m.ranks[rank].q8.as_ref().unwrap(),
6641                            v_m.ranks[rank].q8.as_ref().unwrap(),
6642                            &w8t_aq[rank],
6643                            &w8t_ad[rank],
6644                            &mut tcol_q[rank],
6645                            &mut tcol_k[rank],
6646                            &mut tcol_v[rank],
6647                            in_f,
6648                            *local_q_dim,
6649                            *local_kv_dim,
6650                            t,
6651                        )?;
6652                        if out_g > 0 {
6653                            engine.matvec_bf16_rows_into(
6654                                wg,
6655                                &tcol_in[rank],
6656                                &mut tcol_g[rank],
6657                                in_f,
6658                                out_g,
6659                                t,
6660                            )?;
6661                        }
6662                    } else {
6663                        engine.matvec_bf16_qkvg_tcol_into(
6664                            wq,
6665                            wk,
6666                            wv,
6667                            wg,
6668                            &tcol_in[rank],
6669                            &mut tcol_q[rank],
6670                            &mut tcol_k[rank],
6671                            &mut tcol_v[rank],
6672                            &mut tcol_g[rank],
6673                            in_f,
6674                            *local_q_dim,
6675                            *local_kv_dim,
6676                            out_g,
6677                            t,
6678                        )?;
6679                    }
6680                }
6681                _ => return Err("tcol verify requires bf16-resident fused QKV".into()),
6682            }
6683        }
6684        Ok(())
6685    }
6686
6687    /// MEMRA_TCOL_OPROJ eligibility: the defer replaces exactly the o_fused direct-join
6688    /// finish (bf16 b4 kernel, 2 ranks, 4 canonical blocks) with the shadow gathers
6689    /// skipped — so it requires the same doors that arm dictate that finish shape.
6690    pub(crate) fn decode_v2_oproj_tcol_eligible(
6691        &self,
6692        ws: &StepTpDecodeV2Ws,
6693        o_m: &ResidentStepBf16RowParallel,
6694    ) -> bool {
6695        self.ranks.len() == 2
6696            && ws.blocks_per_rank == 4
6697            && step_tp_qkv_fused_enabled().unwrap_or(false)
6698            && no_local_shadow_on()
6699            && std::env::var("MEMRA_B4_X2").as_deref() != Ok("1")
6700            && o_m
6701                .ranks
6702                .iter()
6703                .flatten()
6704                .all(|block| matches!(block.weight, ResidentBf16Weight::Bf16(_)))
6705    }
6706
6707    /// MEMRA_SPEC_FA2 stash: copy this column's per-rank post-rope q and gate rows into
6708    /// the fa2 slabs (rank-stream ordered behind the rope/append that produced them), and
6709    /// give `e` the same anti-dependency wait the skipped finish provided (next column's
6710    /// h/pos re-staging must not overtake this column's rank pulls).
6711    pub(crate) fn decode_v2_stash_fa2(
6712        &self,
6713        ws: &mut StepTpDecodeV2Ws,
6714        e: &Engine,
6715        col: usize,
6716    ) -> Result<(), Box<dyn std::error::Error>> {
6717        let ranks = self.ranks.len();
6718        if col >= 32 {
6719            return Err("decode_v2_stash_fa2 column out of range".into());
6720        }
6721        let lq = ws.local_q_dim;
6722        let lg = (ws.heads / ranks).max(1);
6723        if ws.fa2_cap < 32 || ws.fa2_q.len() != ranks || ws.rows_tab_t.len() != ranks {
6724            ws.fa2_q.clear();
6725            ws.fa2_gate.clear();
6726            ws.fa2_gated.clear();
6727            ws.rope_k_t.clear();
6728            ws.rope_ctr_t.clear();
6729            ws.rope_pos_t.clear();
6730            ws.rows_tab_t.clear();
6731            for engine in &self.ranks {
6732                let _m = engine.gpu.enter_main()?;
6733                ws.fa2_q.push(engine.uninit(32 * lq)?);
6734                ws.fa2_gate.push(engine.uninit(32 * lg)?);
6735                ws.fa2_gated.push(engine.uninit(32 * lq)?);
6736                ws.rope_k_t.push(engine.uninit(32 * ws.local_kv_dim)?);
6737                ws.rope_ctr_t.push(engine.stream().clone_htod(&[0u32; 32])?);
6738                ws.rope_pos_t.push(engine.htod_i32(&[0i32; 32])?);
6739                ws.rows_tab_t
6740                    .push(engine.stream().clone_htod(&[0u64; 32 * 6])?);
6741            }
6742            ws.rows_tabs = (0..ranks).map(|_| Default::default()).collect();
6743            ws.fa2_cap = 32;
6744        }
6745        for rank in 0..ranks {
6746            let engine = &self.ranks[rank];
6747            let _main = engine.gpu.enter_main()?;
6748            {
6749                let mut dst = ws.fa2_q[rank].slice_mut(col * lq..(col + 1) * lq);
6750                engine
6751                    .stream()
6752                    .memcpy_dtod(&ws.q[rank].slice(0..lq), &mut dst)?;
6753            }
6754            {
6755                let mut dst = ws.fa2_gate[rank].slice_mut(col * lg..(col + 1) * lg);
6756                engine
6757                    .stream()
6758                    .memcpy_dtod(&ws.gate[rank].slice(0..lg), &mut dst)?;
6759            }
6760            ws.ev_rank[rank].record(&engine.stream())?;
6761        }
6762        {
6763            let _main = e.gpu.enter_main()?;
6764            for ev in ws.ev_rank.iter() {
6765                e.stream().wait(ev)?;
6766            }
6767        }
6768        Ok(())
6769    }
6770
6771    /// MEMRA_SPEC_FA2 join: after BOTH verify columns stashed (their appends landed in
6772    /// rank-stream order), run ONE fa_decode_dcw2 per rank over the shared KV stream —
6773    /// two query rows, per-row causal bounds, per-row combine+gate — then land the two
6774    /// gated rows in the o-tcol slabs and reuse the weight-amortized o_proj join.
6775    /// Returns the [2, o_out] `mixed` slab on `e`. The caller's precheck enforced the
6776    /// equal-partition guard (boundary rounds never arm the defer).
6777    #[allow(clippy::too_many_arguments)]
6778    #[allow(dead_code)] // allow: banked MEMRA_SPEC_FA2 arm; kept as the named seam its precheck twin documents
6779    pub(crate) fn decode_v2_spec_fa2_join(
6780        &self,
6781        ws_index: usize,
6782        e: &Engine,
6783        o_m: &ResidentStepBf16RowParallel,
6784        kv: &ResidentTpKvCache,
6785        head_dim: usize,
6786        window: usize,
6787        bucket_max: usize,
6788        scale: f32,
6789    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
6790        let ranks = self.ranks.len();
6791        // Engagement receipt: a vacuous gate (precheck never passing) must be visible.
6792        static ONCE: std::sync::Once = std::sync::Once::new();
6793        ONCE.call_once(|| eprintln!("[spec-fa2] joined T=2 attention ENGAGED"));
6794        {
6795            let mut guard = self
6796                .decode_v2
6797                .lock()
6798                .map_err(|_| "step TP decode v2 workspace lock is poisoned")?;
6799            let ws = guard
6800                .get_mut(ws_index)
6801                .ok_or("step TP decode v2 workspace index out of range")?;
6802            if ws.fa2_cap < 2 || ws.fa2_q.len() != ranks {
6803                return Err("spec fa2 join without stashed columns".into());
6804            }
6805            let lq = ws.local_q_dim;
6806            let local_heads = (ws.heads / ranks).max(1);
6807            let local_kv_heads = (ws.local_kv_dim / head_dim).max(1);
6808            let capacity = kv.physical_capacity();
6809            let (k_tok_bytes, v_tok_bytes) = (kv.k_tok_bytes(), kv.v_tok_bytes());
6810            // Arm the o-tcol slabs if the oproj door never ran this boot (same shapes).
6811            if ws.tcol_ocap < 2 || ws.tcol_gated.len() != ranks {
6812                ws.tcol_gated.clear();
6813                ws.tcol_opart.clear();
6814                for engine in &self.ranks {
6815                    let _m = engine.gpu.enter_main()?;
6816                    ws.tcol_gated.push(engine.uninit(32 * lq)?);
6817                    ws.tcol_opart.push(engine.uninit(32 * ws.o_out)?);
6818                }
6819                let root = &self.ranks[0];
6820                let _m = root.gpu.enter_main()?;
6821                ws.tcol_opeer = Some(root.uninit(32 * ws.o_out)?);
6822                ws.tcol_omix = Some(root.uninit(32 * ws.o_out)?);
6823                ws.tcol_ocap = 32;
6824            }
6825            for rank in 0..ranks {
6826                let engine = &self.ranks[rank];
6827                let _main = engine.gpu.enter_main()?;
6828                let rank_cache = kv
6829                    .rank(rank)
6830                    .ok_or("spec fa2 join lost its KV cache rank")?;
6831                let k_ring = engine.view_u8_range(rank_cache.k(), 0, capacity * k_tok_bytes);
6832                let v_ring = engine.view_u8_range(rank_cache.v(), 0, capacity * v_tok_bytes);
6833                {
6834                    let StepTpDecodeV2Ws {
6835                        fa2_q,
6836                        fa2_gate,
6837                        fa2_gated,
6838                        ..
6839                    } = &mut *ws;
6840                    engine.fa_decode_dcw2(
6841                        &fa2_q[rank],
6842                        &k_ring,
6843                        &v_ring,
6844                        &mut fa2_gated[rank],
6845                        head_dim,
6846                        local_heads,
6847                        local_kv_heads,
6848                        rank_cache.len_d(),
6849                        rank_cache.base_d(),
6850                        window,
6851                        bucket_max,
6852                        scale,
6853                        k_tok_bytes,
6854                        v_tok_bytes,
6855                        &fa2_gate[rank],
6856                    )?;
6857                }
6858                // Both gated rows are contiguous [2, lq] — exactly columns 0..2 of the
6859                // o-tcol slab layout. One dtod, in rank-stream order behind the fa.
6860                let StepTpDecodeV2Ws {
6861                    fa2_gated,
6862                    tcol_gated,
6863                    ..
6864                } = &mut *ws;
6865                let mut dst = tcol_gated[rank].slice_mut(0..2 * lq);
6866                engine
6867                    .stream()
6868                    .memcpy_dtod(&fa2_gated[rank].slice(0..2 * lq), &mut dst)?;
6869            }
6870        }
6871        self.decode_v2_oproj_tcol(ws_index, e, o_m, 2)
6872    }
6873
6874    /// FULL T-ROW ATTENTION PASS over per-row session tables (batched serving): reads
6875    /// the tcol raw-projection slabs, runs ONE rope/append rows launch + ONE fa rows
6876    /// launch + ONE combine per rank (gate straight from the tcol gate slab), then the
6877    /// o_proj tcol join — the whole per-row attention loop in 3 launches/rank/layer.
6878    /// Per-(row, head) programs are the t=1 kernels verbatim; each row appends to and
6879    /// attends its OWN session. `session_parts[rank][row]` = {k_plane, v_plane, len_ptr,
6880    /// base_ptr}; `tab_keys[rank]` keys the per-rank combined-table cache (caller folds
6881    /// layer + session-set + base-arming into it); `stage_pos` stages the position slab
6882    /// (positions are constant across layers within a tick — stage on the first layer).
6883    #[allow(clippy::too_many_arguments)]
6884    pub(crate) fn decode_v2_rope_fa_rows(
6885        &self,
6886        ws_index: usize,
6887        e: &Engine,
6888        o_m: &ResidentStepBf16RowParallel,
6889        session_parts: &[Vec<[u64; 4]>],
6890        tab_keys: &[u64],
6891        positions: &[i32],
6892        stage_pos: bool,
6893        same_session: bool,
6894        q_norms: &[CudaSlice<f32>],
6895        k_norms: &[CudaSlice<f32>],
6896        rope_freqs: &[Option<&crate::CudaSlice<f32>>],
6897        t: usize,
6898        head_dim: usize,
6899        n_rot: usize,
6900        window: usize,
6901        max_ns: usize,
6902        scale: f32,
6903        k_tok_bytes: usize,
6904        v_tok_bytes: usize,
6905        eps: f32,
6906        rope_base: f32,
6907    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
6908        use cudarc::driver::DevicePtr;
6909        let ranks = self.ranks.len();
6910        if session_parts.len() != ranks || tab_keys.len() != ranks || positions.len() < t {
6911            return Err("rope fa rows geometry".into());
6912        }
6913        {
6914            let mut guard = self
6915                .decode_v2
6916                .lock()
6917                .map_err(|_| "step TP decode v2 workspace lock is poisoned")?;
6918            let ws = guard
6919                .get_mut(ws_index)
6920                .ok_or("step TP decode v2 workspace index out of range")?;
6921            if ws.tcol_cap < t || ws.tcol_q.len() != ranks {
6922                return Err("rope fa rows without tcol slabs".into());
6923            }
6924            let lq = ws.local_q_dim;
6925            let lkv = ws.local_kv_dim;
6926            let lg = (ws.heads / ranks).max(1);
6927            let local_heads = (ws.heads / ranks).max(1);
6928            let local_kv_heads = (lkv / head_dim).max(1);
6929            // Arm the fa2/rope slabs (shared with the stash path).
6930            if ws.fa2_cap < 32 || ws.fa2_q.len() != ranks || ws.rows_tab_t.len() != ranks {
6931                ws.fa2_q.clear();
6932                ws.fa2_gate.clear();
6933                ws.fa2_gated.clear();
6934                ws.rope_k_t.clear();
6935                ws.rope_ctr_t.clear();
6936                ws.rope_pos_t.clear();
6937                ws.rows_tab_t.clear();
6938                for engine in &self.ranks {
6939                    let _m = engine.gpu.enter_main()?;
6940                    ws.fa2_q.push(engine.uninit(32 * lq)?);
6941                    ws.fa2_gate.push(engine.uninit(32 * lg)?);
6942                    ws.fa2_gated.push(engine.uninit(32 * lq)?);
6943                    ws.rope_k_t.push(engine.uninit(32 * lkv)?);
6944                    ws.rope_ctr_t.push(engine.stream().clone_htod(&[0u32; 32])?);
6945                    ws.rope_pos_t.push(engine.htod_i32(&[0i32; 32])?);
6946                    ws.rows_tab_t
6947                        .push(engine.stream().clone_htod(&[0u64; 32 * 6])?);
6948                }
6949                ws.rows_tabs = (0..ranks).map(|_| Default::default()).collect();
6950                ws.fa2_cap = 32;
6951            }
6952            if ws.tcol_ocap < t || ws.tcol_gated.len() != ranks {
6953                ws.tcol_gated.clear();
6954                ws.tcol_opart.clear();
6955                for engine in &self.ranks {
6956                    let _m = engine.gpu.enter_main()?;
6957                    ws.tcol_gated.push(engine.uninit(32 * lq)?);
6958                    ws.tcol_opart.push(engine.uninit(32 * ws.o_out)?);
6959                }
6960                let root = &self.ranks[0];
6961                let _m = root.gpu.enter_main()?;
6962                ws.tcol_opeer = Some(root.uninit(32 * ws.o_out)?);
6963                ws.tcol_omix = Some(root.uninit(32 * ws.o_out)?);
6964                ws.tcol_ocap = 32;
6965            }
6966            for rank in 0..ranks {
6967                let engine = &self.ranks[rank];
6968                let _main = engine.gpu.enter_main()?;
6969                if stage_pos {
6970                    let host: Vec<i32> = positions[..t].to_vec();
6971                    let mut view = ws.rope_pos_t[rank].slice_mut(0..t);
6972                    engine.stream().memcpy_htod(&host, &mut view)?;
6973                }
6974                // Combined 6-word table {k, v, len, base, ctr, back}; ctr = this rank's
6975                // per-row counter slab. Built from the pointers the CALLER just read off
6976                // the live distributed cache, and RESTAGED into a persistent slab before
6977                // every launch (MEMRA_ROWS_TAB_RESTAGE, default ON).
6978                //
6979                // The `rows_tabs` memo this replaces was keyed by a hash of
6980                // (k pointer, base pointer, layer, t) but the table it handed back ALSO
6981                // carried the V and LEN pointers, and nothing invalidated it when a
6982                // session's KV cache was dropped. A later session whose K buffer landed on
6983                // a recycled address therefore hit a dead entry, and
6984                // `qk_norm_rope_append_inc_dcw_rows` WROTE this session's K/V rows through
6985                // the freed V/len pointers it still held while `fa_decode_dcw_rows` read
6986                // them back: a whole non-finite row when the freed pages were re-mapped,
6987                // CUDA_ERROR_ILLEGAL_ADDRESS when they were not. The row-table twin in
6988                // `step35_verify_fa_rows_join` was cured of exactly this in 8c8397e0b2
6989                // ("a process-lifetime map cannot prove allocation generation", Hermes
6990                // `11339f5cd3c132a3`); this fused rope+append+fa path was left out of it,
6991                // and MEMRA_FUSE_ROPE_APPEND=1 makes it the arm that actually runs.
6992                let ctr_base = {
6993                    let s = engine.stream();
6994                    let (p, _g) = ws.rope_ctr_t[rank].device_ptr(&s);
6995                    p
6996                };
6997                let host = rows_tab_host(&session_parts[rank], ctr_base, same_session, t);
6998                // STALE-HIT RECEIPT (MEMRA_ROWS_TAB_STALE_SCAN=1, default OFF): replay the
6999                // retired key against the contents we are about to stage. `engaged` proves
7000                // this path executes at all; `STALE` proves the retired memo would have
7001                // handed a live launch another allocation's pointers, and names which word
7002                // moved. Diagnostic only: it never feeds a kernel.
7003                if rows_tab_stale_scan() {
7004                    if ws.rows_tab_shadow.len() != ranks {
7005                        ws.rows_tab_shadow = (0..ranks).map(|_| Default::default()).collect();
7006                    }
7007                    let n = ROWS_TAB_ENGAGED.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
7008                    if let Some(prev) = ws.rows_tab_shadow[rank].get(&tab_keys[rank])
7009                        && prev != &host
7010                    {
7011                        let words = ["k", "v", "len", "base", "ctr", "back"];
7012                        let moved: Vec<String> = (0..host.len())
7013                            .filter(|&i| prev.get(i) != Some(&host[i]))
7014                            .map(|i| format!("{}[row{}]", words[i % 6], i / 6))
7015                            .collect();
7016                        let stale =
7017                            ROWS_TAB_STALE.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
7018                        eprintln!(
7019                            "[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",
7020                            tab_keys[rank],
7021                            moved.join(",")
7022                        );
7023                    }
7024                    ws.rows_tab_shadow[rank].insert(tab_keys[rank], host.clone());
7025                }
7026                let legacy_memo = !rows_tab_restage_on();
7027                if legacy_memo && !ws.rows_tabs[rank].contains_key(&tab_keys[rank]) {
7028                    let tab = engine.stream().clone_htod(&host)?;
7029                    ws.rows_tabs[rank].insert(tab_keys[rank], tab);
7030                }
7031                if !legacy_memo {
7032                    let mut view = ws.rows_tab_t[rank].slice_mut(0..t * 6);
7033                    engine.stream().memcpy_htod(&host, &mut view)?;
7034                }
7035                let StepTpDecodeV2Ws {
7036                    tcol_q,
7037                    tcol_k,
7038                    tcol_v,
7039                    tcol_g,
7040                    fa2_q,
7041                    fa2_gated,
7042                    rope_k_t,
7043                    rope_pos_t,
7044                    rows_tabs,
7045                    rows_tab_t,
7046                    ..
7047                } = &mut *ws;
7048                let tab = if legacy_memo {
7049                    rows_tabs[rank]
7050                        .get(&tab_keys[rank])
7051                        .ok_or("rows tab memo lost its entry")?
7052                } else {
7053                    &rows_tab_t[rank]
7054                };
7055                engine.qk_norm_rope_append_inc_dcw_rows(
7056                    &tcol_q[rank],
7057                    &tcol_k[rank],
7058                    &tcol_v[rank],
7059                    &q_norms[rank],
7060                    &k_norms[rank],
7061                    &mut fa2_q[rank],
7062                    &mut rope_k_t[rank],
7063                    tab,
7064                    &rope_pos_t[rank],
7065                    same_session,
7066                    t,
7067                    lkv,
7068                    lkv,
7069                    k_tok_bytes,
7070                    v_tok_bytes,
7071                    head_dim,
7072                    n_rot,
7073                    local_heads,
7074                    local_kv_heads,
7075                    eps,
7076                    rope_base,
7077                    1.0,
7078                    rope_freqs[rank],
7079                )?;
7080                engine.fa_decode_dcw_rows(
7081                    &fa2_q[rank],
7082                    tab,
7083                    &mut fa2_gated[rank],
7084                    t,
7085                    head_dim,
7086                    local_heads,
7087                    local_kv_heads,
7088                    window,
7089                    max_ns,
7090                    scale,
7091                    k_tok_bytes,
7092                    v_tok_bytes,
7093                    &tcol_g[rank],
7094                )?;
7095                let StepTpDecodeV2Ws {
7096                    fa2_gated,
7097                    tcol_gated,
7098                    ..
7099                } = &mut *ws;
7100                let mut dst = tcol_gated[rank].slice_mut(0..t * lq);
7101                engine
7102                    .stream()
7103                    .memcpy_dtod(&fa2_gated[rank].slice(0..t * lq), &mut dst)?;
7104            }
7105        }
7106        self.decode_v2_oproj_tcol(ws_index, e, o_m, t)
7107    }
7108
7109    /// T-ROW fa join over per-row session tables (the per-session distributed-KV
7110    /// primitive): after all t rows stashed q+gate (their appends landed in rank-stream
7111    /// order), ONE fa_decode_dcw_rows per rank walks every row's own ring with its own
7112    /// geometry — bit-identical per row to its per-row launch — then the o_proj tcol
7113    /// join lands the [t, o_out] `mixed` slab on `e`. `tabs[rank]` is the pre-staged
7114    /// device table on that rank.
7115    #[allow(clippy::too_many_arguments)]
7116    pub(crate) fn decode_v2_fa_rows_join(
7117        &self,
7118        ws_index: usize,
7119        e: &Engine,
7120        o_m: &ResidentStepBf16RowParallel,
7121        tabs: &[&crate::CudaSlice<u64>],
7122        t: usize,
7123        head_dim: usize,
7124        window: usize,
7125        max_ns: usize,
7126        scale: f32,
7127        k_tok_bytes: usize,
7128        v_tok_bytes: usize,
7129    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
7130        let ranks = self.ranks.len();
7131        if tabs.len() != ranks {
7132            return Err("fa rows join needs one table per rank".into());
7133        }
7134        {
7135            let mut guard = self
7136                .decode_v2
7137                .lock()
7138                .map_err(|_| "step TP decode v2 workspace lock is poisoned")?;
7139            let ws = guard
7140                .get_mut(ws_index)
7141                .ok_or("step TP decode v2 workspace index out of range")?;
7142            if ws.fa2_cap < t || ws.fa2_q.len() != ranks {
7143                return Err("fa rows join without stashed rows".into());
7144            }
7145            let lq = ws.local_q_dim;
7146            let local_heads = (ws.heads / ranks).max(1);
7147            let local_kv_heads = (ws.local_kv_dim / head_dim).max(1);
7148            if ws.tcol_ocap < t || ws.tcol_gated.len() != ranks {
7149                ws.tcol_gated.clear();
7150                ws.tcol_opart.clear();
7151                for engine in &self.ranks {
7152                    let _m = engine.gpu.enter_main()?;
7153                    ws.tcol_gated.push(engine.uninit(32 * lq)?);
7154                    ws.tcol_opart.push(engine.uninit(32 * ws.o_out)?);
7155                }
7156                let root = &self.ranks[0];
7157                let _m = root.gpu.enter_main()?;
7158                ws.tcol_opeer = Some(root.uninit(32 * ws.o_out)?);
7159                ws.tcol_omix = Some(root.uninit(32 * ws.o_out)?);
7160                ws.tcol_ocap = 32;
7161            }
7162            for rank in 0..ranks {
7163                let engine = &self.ranks[rank];
7164                let _main = engine.gpu.enter_main()?;
7165                {
7166                    let StepTpDecodeV2Ws {
7167                        fa2_q,
7168                        fa2_gate,
7169                        fa2_gated,
7170                        ..
7171                    } = &mut *ws;
7172                    engine.fa_decode_dcw_rows(
7173                        &fa2_q[rank],
7174                        tabs[rank],
7175                        &mut fa2_gated[rank],
7176                        t,
7177                        head_dim,
7178                        local_heads,
7179                        local_kv_heads,
7180                        window,
7181                        max_ns,
7182                        scale,
7183                        k_tok_bytes,
7184                        v_tok_bytes,
7185                        &fa2_gate[rank],
7186                    )?;
7187                }
7188                let StepTpDecodeV2Ws {
7189                    fa2_gated,
7190                    tcol_gated,
7191                    ..
7192                } = &mut *ws;
7193                let mut dst = tcol_gated[rank].slice_mut(0..t * lq);
7194                engine
7195                    .stream()
7196                    .memcpy_dtod(&fa2_gated[rank].slice(0..t * lq), &mut dst)?;
7197            }
7198        }
7199        self.decode_v2_oproj_tcol(ws_index, e, o_m, t)
7200    }
7201
7202    /// MEMRA_TCOL_OPROJ stash: copy this column's per-rank `gated` rows into the o-tcol
7203    /// slabs (rank-stream ordered behind the attention kernels that produced them). The
7204    /// per-column finish choreography is skipped entirely; `decode_v2_oproj_tcol` joins
7205    /// every column afterwards.
7206    pub(crate) fn decode_v2_stash_gated(
7207        &self,
7208        ws: &mut StepTpDecodeV2Ws,
7209        e: &Engine,
7210        col: usize,
7211    ) -> Result<(), Box<dyn std::error::Error>> {
7212        let ranks = self.ranks.len();
7213        // 32, not 8: the slabs below have been 32 rows since the slab-width fix, and the walk now
7214        // runs chunks up to t=32 (the w=16 arm died here on a guard three widths staler than its
7215        // own allocation, 2026-08-27).
7216        if col >= 32 {
7217            return Err("decode_v2_stash_gated column out of range".into());
7218        }
7219        let lq = ws.local_q_dim;
7220        if ws.tcol_ocap == 0 || ws.tcol_gated.len() != ranks {
7221            ws.tcol_gated.clear();
7222            ws.tcol_opart.clear();
7223            for engine in &self.ranks {
7224                let _m = engine.gpu.enter_main()?;
7225                ws.tcol_gated.push(engine.uninit(32 * lq)?);
7226                ws.tcol_opart.push(engine.uninit(32 * ws.o_out)?);
7227            }
7228            let root = &self.ranks[0];
7229            let _m = root.gpu.enter_main()?;
7230            ws.tcol_opeer = Some(root.uninit(32 * ws.o_out)?);
7231            ws.tcol_omix = Some(root.uninit(32 * ws.o_out)?);
7232            ws.tcol_ocap = 32;
7233        }
7234        for rank in 0..ranks {
7235            let engine = &self.ranks[rank];
7236            let _main = engine.gpu.enter_main()?;
7237            let mut dst = ws.tcol_gated[rank].slice_mut(col * lq..(col + 1) * lq);
7238            engine
7239                .stream()
7240                .memcpy_dtod(&ws.gated[rank].slice(0..lq), &mut dst)?;
7241            // The skipped finish's e-wait was ALSO the anti-dependency guard: it ordered
7242            // e's NEXT column's h/pos re-staging behind this column's rank-side raw pulls.
7243            // Record each rank here and make e wait — same protection, no o_proj work.
7244            ws.ev_rank[rank].record(&engine.stream())?;
7245        }
7246        {
7247            let _main = e.gpu.enter_main()?;
7248            for ev in ws.ev_rank.iter() {
7249                e.stream().wait(ev)?;
7250            }
7251        }
7252        Ok(())
7253    }
7254
7255    /// MEMRA_TCOL_OPROJ join: one weight-amortized b4_tcol per rank over the stashed
7256    /// `gated` slabs (per-column FP order == the t=1 b4 kernel), one peer pull of rank1's
7257    /// partial slab, one elementwise slab add on the root (independent elements — each
7258    /// column's add is the exact direct-join `add(p0, p1)`), then the joined `mixed` slab
7259    /// lands on `e`. Returns [t, o_out] on the model engine.
7260    pub(crate) fn decode_v2_oproj_tcol(
7261        &self,
7262        ws_index: usize,
7263        e: &Engine,
7264        o_m: &ResidentStepBf16RowParallel,
7265        t: usize,
7266    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
7267        let ranks = self.ranks.len();
7268        let mut guard = self
7269            .decode_v2
7270            .lock()
7271            .map_err(|_| "step TP decode v2 workspace lock is poisoned")?;
7272        let ws = guard
7273            .get_mut(ws_index)
7274            .ok_or("step TP decode v2 workspace index out of range")?;
7275        if ranks != 2 || ws.blocks_per_rank != 4 || t == 0 || t > 32 || ws.tcol_ocap < t {
7276            return Err("decode_v2_oproj_tcol geometry".into());
7277        }
7278        for rank in 0..ranks {
7279            let engine = &self.ranks[rank];
7280            let _main = engine.gpu.enter_main()?;
7281            let mut weights = Vec::with_capacity(4);
7282            for block in 0..4 {
7283                let ResidentBf16Weight::Bf16(weight) = &o_m.ranks[rank][block].weight else {
7284                    return Err("tcol o_proj requires bf16-resident O blocks".into());
7285                };
7286                weights.push(weight);
7287            }
7288            {
7289                let StepTpDecodeV2Ws {
7290                    tcol_gated,
7291                    tcol_opart,
7292                    local_q_dim,
7293                    o_block_cols,
7294                    o_out,
7295                    w8t_oaq,
7296                    w8t_oad,
7297                    w8t_oin,
7298                    w8t_cap,
7299                    ..
7300                } = &mut *ws;
7301                // MEMRA_TCOL_OPROJ_REF=1 (bisect): fill the partial slab via the t=1 b4
7302                // kernel per column — separates choreography bugs from tcol-kernel bugs.
7303                static REFK: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
7304                let refk = *REFK
7305                    .get_or_init(|| std::env::var("MEMRA_TCOL_OPROJ_REF").as_deref() == Ok("1"));
7306                if refk {
7307                    let lq = *local_q_dim;
7308                    let mut xr = engine.uninit(lq)?;
7309                    let mut yr = engine.uninit(*o_out)?;
7310                    for c in 0..t {
7311                        {
7312                            let mut dst = xr.slice_mut(0..lq);
7313                            engine.stream().memcpy_dtod(
7314                                &tcol_gated[rank].slice(c * lq..(c + 1) * lq),
7315                                &mut dst,
7316                            )?;
7317                        }
7318                        engine.matvec_bf16_b4_into(
7319                            [weights[0], weights[1], weights[2], weights[3]],
7320                            &xr,
7321                            &mut yr,
7322                            *o_block_cols,
7323                            *o_out,
7324                        )?;
7325                        let mut dst = tcol_opart[rank].slice_mut(c * *o_out..(c + 1) * *o_out);
7326                        engine
7327                            .stream()
7328                            .memcpy_dtod(&yr.slice(0..*o_out), &mut dst)?;
7329                    }
7330                } else if crate::step_tp_w8_on()
7331                    && (0..4).all(|b| o_m.ranks[rank][b].q8.is_some())
7332                    && (4 * *o_block_cols) % 32 == 0
7333                {
7334                    // The verify walk's biggest single kernel: bf16 tcol o_proj was 24.8% of
7335                    // spec GPU time. Same planar q8_0 mirrors the decode arm uses, one launch
7336                    // over all t columns.
7337                    let in_f = 4 * *o_block_cols;
7338                    if *w8t_oin != in_f || *w8t_cap < t || w8t_oaq.len() != ranks {
7339                        w8t_oaq.clear();
7340                        w8t_oad.clear();
7341                        for e_rank in &self.ranks {
7342                            let _m = e_rank.gpu.enter_main()?;
7343                            w8t_oaq.push(e_rank.alloc_i8_uninit(32 * in_f)?);
7344                            w8t_oad.push(e_rank.alloc_uninit::<f32>(32 * (in_f / 32))?);
7345                        }
7346                        *w8t_oin = in_f;
7347                        *w8t_cap = (*w8t_cap).max(32);
7348                    }
7349                    engine.quantize_q8_1_into(
7350                        &tcol_gated[rank],
7351                        t,
7352                        in_f,
7353                        &mut w8t_oaq[rank],
7354                        &mut w8t_oad[rank],
7355                    )?;
7356                    engine.qmatvec_q8_0_b4_rp_t_into(
7357                        [
7358                            o_m.ranks[rank][0].q8.as_ref().unwrap(),
7359                            o_m.ranks[rank][1].q8.as_ref().unwrap(),
7360                            o_m.ranks[rank][2].q8.as_ref().unwrap(),
7361                            o_m.ranks[rank][3].q8.as_ref().unwrap(),
7362                        ],
7363                        &w8t_oaq[rank],
7364                        &w8t_oad[rank],
7365                        &mut tcol_opart[rank],
7366                        *o_block_cols,
7367                        *o_out,
7368                        t,
7369                    )?;
7370                } else {
7371                    engine.matvec_bf16_b4_tcol_into(
7372                        [weights[0], weights[1], weights[2], weights[3]],
7373                        &tcol_gated[rank],
7374                        &mut tcol_opart[rank],
7375                        *o_block_cols,
7376                        *o_out,
7377                        t,
7378                    )?;
7379                }
7380            }
7381            if rank != 0 {
7382                ws.ev_rank[rank].record(&engine.stream())?;
7383            }
7384        }
7385        let root = &self.ranks[0];
7386        {
7387            let _main = root.gpu.enter_main()?;
7388            for ev in ws.ev_rank.iter().skip(1) {
7389                root.stream().wait(ev)?;
7390            }
7391            {
7392                let StepTpDecodeV2Ws {
7393                    tcol_opart,
7394                    tcol_opeer,
7395                    tcol_omix,
7396                    o_out,
7397                    ..
7398                } = &mut *ws;
7399                let opeer = tcol_opeer.as_mut().ok_or("tcol o_proj slabs not armed")?;
7400                let omix = tcol_omix.as_mut().ok_or("tcol o_proj slabs not armed")?;
7401                {
7402                    let mut dst = opeer.slice_mut(0..t * *o_out);
7403                    root.stream()
7404                        .memcpy_dtod(&tcol_opart[1].slice(0..t * *o_out), &mut dst)?;
7405                }
7406                // Elementwise over the whole slab: per element identical to the per-column
7407                // direct-join add (independent lanes, same operand values).
7408                root.add(&tcol_opart[0], opeer, omix, t * *o_out)?;
7409            }
7410            ws.ev_oproj.record(&root.stream())?;
7411        }
7412        let _main = e.gpu.enter_main()?;
7413        e.stream().wait(&ws.ev_oproj)?;
7414        let mut out = e.uninit(t * ws.o_out)?;
7415        let omix = ws.tcol_omix.as_ref().ok_or("tcol o_proj slabs not armed")?;
7416        e.stream().memcpy_dtod(
7417            &omix.slice(0..t * ws.o_out),
7418            &mut out.slice_mut(0..t * ws.o_out),
7419        )?;
7420        Ok(out)
7421    }
7422
7423    #[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
7424    pub(crate) fn decode_v2_input_qkv(
7425        &self,
7426        ws: &mut StepTpDecodeV2Ws,
7427        e: &Engine,
7428        h: &CudaSlice<f32>,
7429        pos_d: &CudaSlice<i32>,
7430        gate_raw: Option<&CudaSlice<f32>>,
7431        gate_shards: Option<StepTpGateShards<'_>>,
7432        decode_input: &mut ResidentReplicatedDeviceRows,
7433        q_m: &ResidentBf16ColumnParallel,
7434        k_m: &ResidentBf16ColumnParallel,
7435        v_m: &ResidentBf16ColumnParallel,
7436        q_norm: &[CudaSlice<f32>],
7437        k_norm: &[CudaSlice<f32>],
7438        head_dim: usize,
7439        n_rot: usize,
7440        rope_base: f32,
7441        rope_freqs: &[Option<&CudaSlice<f32>>],
7442        rms_eps: f32,
7443        has_gate: bool,
7444        defer_norm_rope: bool,
7445        tcol_col: Option<usize>,
7446    ) -> Result<(), Box<dyn std::error::Error>> {
7447        let ranks = self.ranks.len();
7448        validate_replicated_device_rows(&self.ranks, decode_input)?;
7449        let gate_sources = usize::from(gate_raw.is_some()) + usize::from(gate_shards.is_some());
7450        if decode_input.tokens != 1
7451            || decode_input.width != q_m.in_features
7452            || pos_d.len() != 1
7453            || gate_raw.is_some_and(|gate| gate.len() != ws.heads)
7454            || (has_gate && gate_sources != 1)
7455            || (!has_gate && gate_sources != 0)
7456            || gate_shards.as_ref().is_some_and(|shards| match shards {
7457                StepTpGateShards::F32(shards) => shards.len() != ranks,
7458                StepTpGateShards::Bf16(shards) => shards.len() != ranks,
7459            })
7460            || q_norm.len() != ranks
7461            || k_norm.len() != ranks
7462            || rope_freqs.len() != ranks
7463            || e.ctx().ordinal() != ws.e_device
7464        {
7465            return Err("step TP decode v2 input geometry mismatch".into());
7466        }
7467
7468        let qkv_fused = step_tp_qkv_fused_enabled()?;
7469        if gate_shards.is_some() && !qkv_fused {
7470            return Err("step TP decode v2 gate shards require MEMRA_STEP_TP_QKV_FUSED=1".into());
7471        }
7472        let values = decode_input.width;
7473        if h.len() != values {
7474            return Err(format!(
7475                "step TP decode v2 hidden width {} != replicated width {values}",
7476                h.len()
7477            )
7478            .into());
7479        }
7480
7481        if qkv_fused {
7482            // STAGE-BASED flow (graph increment A): h and pos land in fixed e-context stages
7483            // (one e-stream copy each), the entry event covers them, and every rank raw-copies
7484            // from the stages on its own stream — exactly the shape graph capture wraps.
7485            if ws.h_stage.is_none() {
7486                use cudarc::driver::DevicePtr;
7487                let _main = e.gpu.enter_main()?;
7488                let h_stage = e.uninit(values)?;
7489                let pos_stage = e.htod_i32(&[0])?;
7490                {
7491                    let stream = e.stream();
7492                    let (hp, _g0) = h_stage.device_ptr(&stream);
7493                    let (pp, _g1) = pos_stage.device_ptr(&stream);
7494                    ws.raw_h_stage = hp;
7495                    ws.raw_pos_stage = pp;
7496                }
7497                ws.h_stage = Some(h_stage);
7498                ws.pos_stage = Some(pos_stage);
7499                for rank in 0..ranks {
7500                    use cudarc::driver::DevicePtr;
7501                    let engine = &self.ranks[rank];
7502                    let _rmain = engine.gpu.enter_main()?;
7503                    let attn_in = engine.uninit(values)?;
7504                    let (dp, pp) = {
7505                        let stream = engine.stream();
7506                        let (dp, _g2) = attn_in.device_ptr(&stream);
7507                        let (pp, _g3) = ws.pos[rank].device_ptr(&stream);
7508                        (dp, pp)
7509                    };
7510                    ws.raw_attn_in.push(dp);
7511                    ws.raw_pos.push(pp);
7512                    ws.attn_in.push(attn_in);
7513                }
7514                {
7515                    use cudarc::driver::DevicePtr;
7516                    let root = &self.ranks[0];
7517                    let _rmain = root.gpu.enter_main()?;
7518                    let stream = root.stream();
7519                    let (a, _g) = ws.peer_partial.device_ptr(&stream);
7520                    let (b, _g) = ws.k_shadow.device_ptr(&stream);
7521                    let (c, _g) = ws.v_shadow.device_ptr(&stream);
7522                    ws.raw_peer_partial = a;
7523                    ws.raw_k_shadow = b;
7524                    ws.raw_v_shadow = c;
7525                }
7526                {
7527                    use cudarc::driver::DevicePtr;
7528                    let rank1 = &self.ranks[1];
7529                    let _rmain = rank1.gpu.enter_main()?;
7530                    let stream = rank1.stream();
7531                    let (a, _g) = ws.o_partials[1][0].device_ptr(&stream);
7532                    let (b, _g) = ws.k[1].device_ptr(&stream);
7533                    let (c, _g) = ws.v_raw[1].device_ptr(&stream);
7534                    ws.raw_o_partial1 = a;
7535                    ws.raw_k1 = b;
7536                    ws.raw_v1 = c;
7537                }
7538            }
7539            {
7540                let _main = e.gpu.enter_main()?;
7541                {
7542                    // (Always staged: a tcol column below the dcw floor falls back to the
7543                    // normal fused arm, which reads h through this stage.)
7544                    let h_stage = ws.h_stage.as_mut().expect("stage armed above");
7545                    let mut dst = h_stage.slice_mut(0..values);
7546                    e.stream().memcpy_dtod(&h.slice(0..values), &mut dst)?;
7547                }
7548                {
7549                    let pos_stage = ws.pos_stage.as_mut().expect("stage armed above");
7550                    let mut dst = pos_stage.slice_mut(0..1);
7551                    e.stream().memcpy_dtod(&pos_d.slice(0..1), &mut dst)?;
7552                }
7553                ws.ev_entry.record(&e.stream())?;
7554            }
7555            for rank in 0..ranks {
7556                let engine = &self.ranks[rank];
7557                let _main = engine.gpu.enter_main()?;
7558                engine.stream().wait(&ws.ev_entry)?;
7559            }
7560        } else {
7561            // Evented replicate flow (the pre-stage shape, kept for the non-fused class).
7562            {
7563                let _main = e.gpu.enter_main()?;
7564                if let Some(gate_raw) = gate_raw {
7565                    let mut gate_dst = ws.gate_e.slice_mut(0..ws.heads);
7566                    e.stream()
7567                        .memcpy_dtod(&gate_raw.slice(0..ws.heads), &mut gate_dst)?;
7568                }
7569                ws.ev_entry.record(&e.stream())?;
7570            }
7571            {
7572                let root = &self.ranks[0];
7573                let _main = root.gpu.enter_main()?;
7574                root.stream().wait(&ws.ev_entry)?;
7575                let mut destination = decode_input.ranks[0].slice_mut(0..values);
7576                root.stream()
7577                    .memcpy_dtod(&h.slice(0..values), &mut destination)?;
7578                ws.ev_refresh.record(&root.stream())?;
7579            }
7580            for rank in 1..ranks {
7581                let engine = &self.ranks[rank];
7582                let _main = engine.gpu.enter_main()?;
7583                engine.stream().wait(&ws.ev_refresh)?;
7584                let (root_rows, peer_rows) = decode_input.ranks.split_at_mut(rank);
7585                let mut destination = peer_rows[0].slice_mut(0..values);
7586                engine
7587                    .stream()
7588                    .memcpy_dtod(&root_rows[0].slice(0..values), &mut destination)?;
7589            }
7590        }
7591        for rank in 0..ranks {
7592            self.decode_v2_input_qkv_rank(
7593                ws,
7594                pos_d,
7595                decode_input,
7596                q_m,
7597                k_m,
7598                v_m,
7599                q_norm,
7600                k_norm,
7601                head_dim,
7602                n_rot,
7603                rope_base,
7604                rope_freqs,
7605                rms_eps,
7606                gate_shards.as_ref(),
7607                has_gate,
7608                qkv_fused,
7609                defer_norm_rope,
7610                rank,
7611                tcol_col,
7612            )?;
7613        }
7614        Ok(())
7615    }
7616
7617    /// One rank's slice of `decode_v2_input_qkv` (projection, norm+rope, gate staging) — the
7618    /// per-device issue unit the whole-token graph captures on that rank's stream.
7619    #[allow(clippy::too_many_arguments)]
7620    pub(crate) fn decode_v2_input_qkv_rank(
7621        &self,
7622        ws: &mut StepTpDecodeV2Ws,
7623        pos_d: &CudaSlice<i32>,
7624        decode_input: &mut ResidentReplicatedDeviceRows,
7625        q_m: &ResidentBf16ColumnParallel,
7626        k_m: &ResidentBf16ColumnParallel,
7627        v_m: &ResidentBf16ColumnParallel,
7628        q_norm: &[CudaSlice<f32>],
7629        k_norm: &[CudaSlice<f32>],
7630        head_dim: usize,
7631        n_rot: usize,
7632        rope_base: f32,
7633        rope_freqs: &[Option<&CudaSlice<f32>>],
7634        rms_eps: f32,
7635        gate_shards: Option<&StepTpGateShards<'_>>,
7636        has_gate: bool,
7637        qkv_fused: bool,
7638        defer_norm_rope: bool,
7639        rank: usize,
7640        tcol_col: Option<usize>,
7641    ) -> Result<(), Box<dyn std::error::Error>> {
7642        let ranks = self.ranks.len();
7643        let local_heads = ws.local_q_dim / head_dim;
7644        let local_kv_heads = ws.local_kv_dim / head_dim;
7645        let engine = &self.ranks[rank];
7646        let _main = engine.gpu.enter_main()?;
7647        let ws_e_device = ws.e_device;
7648        // T-COLUMN SELECT (spec verify): the projections for this column were precomputed
7649        // by the weight-amortized tcol kernel — copy the column into the single-row buffers
7650        // (pure f32 moves, bit-exact) and skip the per-column matvec. Rope/norm/append run
7651        // below exactly as in the t=1 program.
7652        if qkv_fused && tcol_col.is_some() {
7653            #[allow(clippy::unnecessary_unwrap)]
7654            // allow: the Some-guard sits in a multi-clause regime gate; if-let would reshape the arm structure
7655            let c = tcol_col.expect("checked");
7656            if ws.tcol_cap == 0 || ws.tcol_q.len() != ranks {
7657                return Err("tcol select without precompute".into());
7658            }
7659            // The select skips the matvec but NOT the position: rope/append below still
7660            // read this rank's pos buffer, which only the (skipped) stage path fills for
7661            // peer-device ranks. Stage it here or rank1 ropes at the previous position.
7662            if engine.ctx().ordinal() != ws_e_device {
7663                raw_copy_bytes(ws.raw_pos[rank], ws.raw_pos_stage, 4, engine)?;
7664            }
7665            let StepTpDecodeV2Ws {
7666                tcol_q,
7667                tcol_k,
7668                tcol_v,
7669                tcol_g,
7670                q_raw,
7671                k_raw,
7672                v_raw,
7673                gate,
7674                local_q_dim,
7675                local_kv_dim,
7676                heads,
7677                ..
7678            } = &mut *ws;
7679            let lg = *heads / ranks;
7680            let stream = engine.stream();
7681            {
7682                let mut dst = q_raw[rank].slice_mut(0..*local_q_dim);
7683                stream.memcpy_dtod(
7684                    &tcol_q[rank].slice(c * *local_q_dim..(c + 1) * *local_q_dim),
7685                    &mut dst,
7686                )?;
7687            }
7688            {
7689                let mut dst = k_raw[rank].slice_mut(0..*local_kv_dim);
7690                stream.memcpy_dtod(
7691                    &tcol_k[rank].slice(c * *local_kv_dim..(c + 1) * *local_kv_dim),
7692                    &mut dst,
7693                )?;
7694            }
7695            {
7696                let mut dst = v_raw[rank].slice_mut(0..*local_kv_dim);
7697                stream.memcpy_dtod(
7698                    &tcol_v[rank].slice(c * *local_kv_dim..(c + 1) * *local_kv_dim),
7699                    &mut dst,
7700                )?;
7701            }
7702            if has_gate && lg > 0 {
7703                let mut dst = gate[rank].slice_mut(0..lg);
7704                stream.memcpy_dtod(&tcol_g[rank].slice(c * lg..(c + 1) * lg), &mut dst)?;
7705            }
7706            if !defer_norm_rope {
7707                // Below the dcw floor (or a non-defer shape) the col-select cannot apply:
7708                // fall through and recompute this column's QKV from the REAL h row — the
7709                // caller always passes it. The slab copies above are dead stores.
7710            } else {
7711                return Ok(());
7712            }
7713        }
7714        if qkv_fused {
7715            // Stage-based input: raw copies from the fixed e-context stages (capture-safe;
7716            // eager ordering comes from the caller's ev_entry wait on this stream). The rank
7717            // SHARING e's device reads the stages directly — same context (probed), ordering
7718            // identical (ev_entry / graph edge), bytes identical: the copies are pure waste.
7719            let same_dev = engine.ctx().ordinal() == ws.e_device;
7720            if !same_dev {
7721                raw_copy_bytes(
7722                    ws.raw_attn_in[rank],
7723                    ws.raw_h_stage,
7724                    q_m.in_features * 4,
7725                    engine,
7726                )?;
7727                raw_copy_bytes(ws.raw_pos[rank], ws.raw_pos_stage, 4, engine)?;
7728            }
7729            let StepTpDecodeV2Ws {
7730                q_raw,
7731                k_raw,
7732                v_raw,
7733                gate,
7734                gate_e,
7735                attn_in,
7736                h_stage,
7737                heads,
7738                local_q_dim,
7739                local_kv_dim,
7740                w8_aq,
7741                w8_ad,
7742                w8_in,
7743                ..
7744            } = &mut *ws;
7745            let input_ref: &CudaSlice<f32> = if same_dev {
7746                h_stage
7747                    .as_ref()
7748                    .ok_or("step TP decode v2 stage not armed")?
7749            } else {
7750                &attn_in[rank]
7751            };
7752            match (
7753                &q_m.ranks[rank].weight,
7754                &k_m.ranks[rank].weight,
7755                &v_m.ranks[rank].weight,
7756            ) {
7757                (
7758                    ResidentBf16Weight::F32(wq),
7759                    ResidentBf16Weight::F32(wk),
7760                    ResidentBf16Weight::F32(wv),
7761                ) => {
7762                    let (wg, out_g) = match &gate_shards {
7763                        Some(StepTpGateShards::F32(shards)) => (&shards[rank], *heads / ranks),
7764                        Some(StepTpGateShards::Bf16(_)) => {
7765                            return Err("step TP decode v2 gate shard class does not \
7766                                            match the F32 projections"
7767                                .into());
7768                        }
7769                        // out_g = 0: the kernel never reads wg; any resident buffer works.
7770                        None => (&*gate_e, 0),
7771                    };
7772                    engine.matvec_f32_qkv_into(
7773                        wq,
7774                        wk,
7775                        wv,
7776                        wg,
7777                        input_ref,
7778                        &mut q_raw[rank],
7779                        &mut k_raw[rank],
7780                        &mut v_raw[rank],
7781                        &mut gate[rank],
7782                        q_m.in_features,
7783                        *local_q_dim,
7784                        *local_kv_dim,
7785                        out_g,
7786                    )?;
7787                }
7788                (
7789                    ResidentBf16Weight::Bf16(wq),
7790                    ResidentBf16Weight::Bf16(wk),
7791                    ResidentBf16Weight::Bf16(wv),
7792                ) => {
7793                    let (wg, out_g) = match &gate_shards {
7794                        Some(StepTpGateShards::Bf16(shards)) => (&shards[rank], *heads / ranks),
7795                        Some(StepTpGateShards::F32(_)) => {
7796                            return Err("step TP decode v2 gate shard class does not \
7797                                            match the bf16 projections"
7798                                .into());
7799                        }
7800                        None => (wq, 0),
7801                    };
7802                    // MEMRA_STEP_TP_W8: q8_0 weights + q8_1 activation through mmvq instead of
7803                    // the fused bf16 qkvg. NUMERIC CLASS (int8 dp4a with per-32 scales, not a
7804                    // bf16 fma chain) — argmax-gated, never a bit-tape flip. Q, K and V each
7805                    // get their own launch because the fused kernel has no q8 twin; the gate
7806                    // rows stay bf16 (32 rows, ~0.3 MB, nothing to win and one less class to
7807                    // qualify). Measured motive: 23.0 us bf16 -> 14.0 us q8 at this shape.
7808                    let in_f = q_m.in_features;
7809                    let q8_ready = crate::step_tp_w8_on()
7810                        && q_m.ranks[rank].q8.is_some()
7811                        && k_m.ranks[rank].q8.is_some()
7812                        && v_m.ranks[rank].q8.is_some();
7813                    if q8_ready {
7814                        if *w8_in != in_f || w8_aq.len() != ranks {
7815                            w8_aq.clear();
7816                            w8_ad.clear();
7817                            for e_rank in &self.ranks {
7818                                let _m = e_rank.gpu.enter_main()?;
7819                                w8_aq.push(e_rank.alloc_uninit::<i8>(in_f)?);
7820                                w8_ad.push(e_rank.alloc_uninit::<f32>(in_f / 32)?);
7821                            }
7822                            *w8_in = in_f;
7823                        }
7824                        engine.quantize_q8_1_into(
7825                            input_ref,
7826                            1,
7827                            in_f,
7828                            &mut w8_aq[rank],
7829                            &mut w8_ad[rank],
7830                        )?;
7831                        // ONE launch over the stacked q/k/v rows. The three-call version
7832                        // measured 79.52 vs 80.72 tok/s — SLOWER than the bf16 fused kernel —
7833                        // because three launches plus the activation quantize cost more than
7834                        // the halved weight bytes save. Bit-identical to those three calls.
7835                        engine.qmatvec_q8_0_qkv_rp_into(
7836                            q_m.ranks[rank].q8.as_ref().unwrap(),
7837                            k_m.ranks[rank].q8.as_ref().unwrap(),
7838                            v_m.ranks[rank].q8.as_ref().unwrap(),
7839                            &w8_aq[rank],
7840                            &w8_ad[rank],
7841                            &mut q_raw[rank],
7842                            &mut k_raw[rank],
7843                            &mut v_raw[rank],
7844                            in_f,
7845                            *local_q_dim,
7846                            *local_kv_dim,
7847                        )?;
7848                        if out_g > 0 {
7849                            engine.matvec_bf16_into(wg, input_ref, &mut gate[rank], in_f, out_g)?;
7850                        }
7851                    } else {
7852                        engine.matvec_bf16_qkvg_into(
7853                            wq,
7854                            wk,
7855                            wv,
7856                            wg,
7857                            input_ref,
7858                            &mut q_raw[rank],
7859                            &mut k_raw[rank],
7860                            &mut v_raw[rank],
7861                            &mut gate[rank],
7862                            q_m.in_features,
7863                            *local_q_dim,
7864                            *local_kv_dim,
7865                            out_g,
7866                        )?;
7867                    }
7868                }
7869                _ => {
7870                    return Err("step TP decode v2 QKV projections mix residency classes".into());
7871                }
7872            }
7873        } else {
7874            for (matrix, local_out, raw) in [
7875                (q_m, ws.local_q_dim, &mut ws.q_raw),
7876                (k_m, ws.local_kv_dim, &mut ws.k_raw),
7877                (v_m, ws.local_kv_dim, &mut ws.v_raw),
7878            ] {
7879                let ResidentBf16Weight::F32(values_w) = &matrix.ranks[rank].weight else {
7880                    return Err("step TP decode v2 lost its F32 projection residency".into());
7881                };
7882                let chunk_rows = matrix.canonical_chunk_rows.unwrap_or(local_out);
7883                engine.linear_f32_resident_canonical_rows_t1_into(
7884                    &decode_input.ranks[rank],
7885                    values_w,
7886                    &mut raw[rank],
7887                    matrix.in_features,
7888                    local_out,
7889                    chunk_rows,
7890                )?;
7891            }
7892        }
7893        if qkv_fused && defer_norm_rope {
7894            // FUSION #1 defers norm+rope to the caller's fused rope+append+inc launch.
7895        } else if qkv_fused {
7896            // Fused norm+rope: one launch; the position comes from the rank-local staged
7897            // copy (raw-copied above from the fixed e-context pos stage — capture-safe).
7898            let StepTpDecodeV2Ws {
7899                q_raw,
7900                k_raw,
7901                q,
7902                k,
7903                pos,
7904                pos_stage,
7905                ..
7906            } = &mut *ws;
7907            let same_dev = engine.ctx().ordinal() == ws_e_device;
7908            let pos_ref: &CudaSlice<i32> = if same_dev {
7909                pos_stage
7910                    .as_ref()
7911                    .ok_or("step TP decode v2 pos stage not armed")?
7912            } else {
7913                &pos[rank]
7914            };
7915            engine.qk_norm_rope_into(
7916                &q_raw[rank],
7917                &k_raw[rank],
7918                &q_norm[rank],
7919                &k_norm[rank],
7920                &mut q[rank],
7921                &mut k[rank],
7922                pos_ref,
7923                head_dim,
7924                n_rot,
7925                local_heads,
7926                local_kv_heads,
7927                rms_eps,
7928                rope_base,
7929                1.0,
7930                rope_freqs[rank],
7931            )?;
7932        } else {
7933            engine.rms_norm(
7934                &ws.q_raw[rank],
7935                &q_norm[rank],
7936                &mut ws.q[rank],
7937                head_dim,
7938                local_heads,
7939                rms_eps,
7940            )?;
7941            engine.rms_norm(
7942                &ws.k_raw[rank],
7943                &k_norm[rank],
7944                &mut ws.k[rank],
7945                head_dim,
7946                local_kv_heads,
7947                rms_eps,
7948            )?;
7949            {
7950                let mut pos_dst = ws.pos[rank].slice_mut(0..1);
7951                engine
7952                    .stream()
7953                    .memcpy_dtod(&pos_d.slice(0..1), &mut pos_dst)?;
7954            }
7955            engine.rope_neox2(
7956                &mut ws.q[rank],
7957                &mut ws.k[rank],
7958                &ws.pos[rank],
7959                head_dim,
7960                n_rot,
7961                local_heads,
7962                local_kv_heads,
7963                1,
7964                rope_base,
7965                1.0,
7966                rope_freqs[rank],
7967            )?;
7968        }
7969        if has_gate && gate_shards.is_none() {
7970            let gate_start = rank * (ws.heads / ranks);
7971            let mut gate_dst = ws.gate[rank].slice_mut(0..ws.heads / ranks);
7972            engine.stream().memcpy_dtod(
7973                &ws.gate_e.slice(gate_start..gate_start + ws.heads / ranks),
7974                &mut gate_dst,
7975            )?;
7976        }
7977        Ok(())
7978    }
7979
7980    /// One rank's O-partial slice of `decode_v2_finish` — the per-device issue unit the
7981    /// whole-token graph captures on that rank's stream (the rank-done event stays with the
7982    /// eager caller; graphs order via parent edges instead).
7983    pub(crate) fn decode_v2_finish_rank_partial(
7984        &self,
7985        ws: &mut StepTpDecodeV2Ws,
7986        o_m: &ResidentStepBf16RowParallel,
7987        o_fused: bool,
7988        rank: usize,
7989    ) -> Result<(), Box<dyn std::error::Error>> {
7990        let engine = &self.ranks[rank];
7991        let _main = engine.gpu.enter_main()?;
7992        if o_fused {
7993            let StepTpDecodeV2Ws {
7994                gated,
7995                o_partials,
7996                o_block_cols,
7997                o_out,
7998                w8o_aq,
7999                w8o_ad,
8000                w8o_in,
8001                ..
8002            } = &mut *ws;
8003            let all_f32 = o_m.ranks[rank]
8004                .iter()
8005                .all(|block| matches!(block.weight, ResidentBf16Weight::F32(_)));
8006            if all_f32 {
8007                let mut weights = Vec::with_capacity(4);
8008                for block in 0..4 {
8009                    let ResidentBf16Weight::F32(weight) = &o_m.ranks[rank][block].weight else {
8010                        unreachable!("all_f32 checked above");
8011                    };
8012                    weights.push(weight);
8013                }
8014                engine.matvec_f32_b4_into(
8015                    [weights[0], weights[1], weights[2], weights[3]],
8016                    &gated[rank],
8017                    &mut o_partials[rank][0],
8018                    *o_block_cols,
8019                    *o_out,
8020                )?;
8021            } else if crate::step_tp_w8_on() && (0..4).all(|b| o_m.ranks[rank][b].q8.is_some()) {
8022                // MEMRA_STEP_TP_W8, o_proj half: quantize the gated attention output once and
8023                // run all four HEAD_SPLIT blocks in one q8 launch. Measured motive: bf16 b4 is
8024                // 24.2 us/layer against 11.7 for the q8 shape — the largest decode line left
8025                // after the QKV arm banked +2.9%.
8026                let in_f = 4 * *o_block_cols;
8027                if *w8o_in != in_f || w8o_aq.len() != self.ranks.len() {
8028                    w8o_aq.clear();
8029                    w8o_ad.clear();
8030                    for e_rank in &self.ranks {
8031                        let _m = e_rank.gpu.enter_main()?;
8032                        w8o_aq.push(e_rank.alloc_uninit::<i8>(in_f)?);
8033                        w8o_ad.push(e_rank.alloc_uninit::<f32>(in_f / 32)?);
8034                    }
8035                    *w8o_in = in_f;
8036                }
8037                engine.quantize_q8_1_into(
8038                    &gated[rank],
8039                    1,
8040                    in_f,
8041                    &mut w8o_aq[rank],
8042                    &mut w8o_ad[rank],
8043                )?;
8044                engine.qmatvec_q8_0_b4_rp_into(
8045                    [
8046                        o_m.ranks[rank][0].q8.as_ref().unwrap(),
8047                        o_m.ranks[rank][1].q8.as_ref().unwrap(),
8048                        o_m.ranks[rank][2].q8.as_ref().unwrap(),
8049                        o_m.ranks[rank][3].q8.as_ref().unwrap(),
8050                    ],
8051                    &w8o_aq[rank],
8052                    &w8o_ad[rank],
8053                    &mut o_partials[rank][0],
8054                    *o_block_cols,
8055                    *o_out,
8056                )?;
8057            } else {
8058                let mut weights = Vec::with_capacity(4);
8059                for block in 0..4 {
8060                    let ResidentBf16Weight::Bf16(weight) = &o_m.ranks[rank][block].weight else {
8061                        return Err("step TP decode v2 O projections mix residency classes".into());
8062                    };
8063                    weights.push(weight);
8064                }
8065                engine.matvec_bf16_b4_into(
8066                    [weights[0], weights[1], weights[2], weights[3]],
8067                    &gated[rank],
8068                    &mut o_partials[rank][0],
8069                    *o_block_cols,
8070                    *o_out,
8071                )?;
8072            }
8073        } else {
8074            for block in 0..ws.blocks_per_rank {
8075                let x =
8076                    ws.gated[rank].slice(block * ws.o_block_cols..(block + 1) * ws.o_block_cols);
8077                let mut y = ws.o_partials[rank][block].slice_mut(0..ws.o_out);
8078                match &o_m.ranks[rank][block].weight {
8079                    ResidentBf16Weight::F32(weight) => {
8080                        let w = weight.slice(0..weight.len());
8081                        engine.linear_t1_into(&x, &w, &mut y, ws.o_block_cols, ws.o_out)?;
8082                    }
8083                    ResidentBf16Weight::Bf16(weight) => {
8084                        engine.matvec_bf16_views_into(
8085                            weight,
8086                            &x,
8087                            &mut y,
8088                            ws.o_block_cols,
8089                            ws.o_out,
8090                        )?;
8091                    }
8092                }
8093            }
8094        }
8095        Ok(())
8096    }
8097
8098    /// v2 phase 2: canonical-block O reduction on the root device plus the K/V shadow gathers,
8099    /// returning a fresh model-engine output ordered behind `ev_oproj` on `e`'s stream.
8100    ///
8101    /// The caller must have queued every rank's attention work (reading `ws.gated`, `ws.k`,
8102    /// `ws.v_raw`) on the rank streams before this call. Reduction order is identical to
8103    /// `step_bf16_row_parallel_resident_native`: zeros, then rank 0's blocks, then each peer
8104    /// rank's blocks, one `add` per block.
8105    pub(crate) fn decode_v2_finish(
8106        &self,
8107        ws: &mut StepTpDecodeV2Ws,
8108        e: &Engine,
8109        o_m: &ResidentStepBf16RowParallel,
8110    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
8111        let ranks = self.ranks.len();
8112        if e.ctx().ordinal() != ws.e_device {
8113            return Err("step TP decode v2 finish engine changed".into());
8114        }
8115        // MEMRA_STEP_TP_QKV_FUSED extends to the O path: one matvec_f32_b4 launch per rank
8116        // (in-order canonical block accumulation per element) and a single peer-copy + add on
8117        // the root, replacing 4 cuBLASLt launches per rank + the 4-copy/8-add chain. Same
8118        // numeric-class door and gate as the fused QKV projection.
8119        let o_fused = step_tp_qkv_fused_enabled()? && ws.blocks_per_rank == 4 && ranks == 2;
8120
8121        // Per-rank O block partials on the owning rank's stream (serial after the attention
8122        // kernels the driver queued there), then the rank-done event for root's peer reads.
8123        for rank in 0..ranks {
8124            self.decode_v2_finish_rank_partial(ws, o_m, o_fused, rank)?;
8125            if rank == 0 {
8126                // root == rank0: its own stream order covers the partial; only peers need
8127                // the record/wait pair (host-op diet, matches the routes-arm skip).
8128                continue;
8129            }
8130            let engine = &self.ranks[rank];
8131            let _main = engine.gpu.enter_main()?;
8132            ws.ev_rank[rank].record(&engine.stream())?;
8133        }
8134
8135        // Root reduce in canonical order + shadow gathers, all on the root stream.
8136        let root = &self.ranks[0];
8137        #[allow(unused_assignments)]
8138        let mut final_in_a = false;
8139        {
8140            let _main = root.gpu.enter_main()?;
8141            for ev in ws.ev_rank.iter().skip(1) {
8142                root.stream().wait(ev)?;
8143            }
8144            if o_fused && oproj_direct_on() && ranks == 2 && no_local_shadow_on() {
8145                // DIRECT JOIN: rank1's partial already sits in root memory (P2P kernel
8146                // stores; visibility guaranteed by the ev_rank[1] wait above), rank0's
8147                // partial is root-stream-ordered — record ONE event and let the model
8148                // engine do the single add itself, straight into its own output row.
8149                // Same operands, same add order as finish_root_fused: BIT-IDENTICAL.
8150                ws.ev_oproj.record(&root.stream())?;
8151                let _main = e.gpu.enter_main()?;
8152                e.stream().wait(&ws.ev_oproj)?;
8153                let mut output = e.uninit(ws.o_out)?;
8154                if oproj_tail_on() && oproj_tail_eligible() {
8155                    // M2: defer the add into the residual+norm consumer (waits stay HERE;
8156                    // only the arithmetic moves). `output` is returned unwritten.
8157                    use cudarc::driver::DevicePtr;
8158                    let stream = e.stream();
8159                    let (p0, _g0) = ws.o_partials[0][0].device_ptr(&stream);
8160                    let (p1, _g1) = ws.o_partials[1][0].device_ptr(&stream);
8161                    set_oproj_tail((p0, p1));
8162                    return Ok(output);
8163                }
8164                e.add(
8165                    &ws.o_partials[0][0],
8166                    &ws.o_partials[1][0],
8167                    &mut output,
8168                    ws.o_out,
8169                )?;
8170                return Ok(output);
8171            }
8172            if o_fused {
8173                self.decode_v2_finish_root_fused(ws)?;
8174                ws.ev_oproj.record(&root.stream())?;
8175                let _main = e.gpu.enter_main()?;
8176                e.stream().wait(&ws.ev_oproj)?;
8177                let mut output = e.uninit(ws.o_out)?;
8178                e.stream().memcpy_dtod(
8179                    &ws.reduce_a.slice(0..ws.o_out),
8180                    &mut output.slice_mut(0..ws.o_out),
8181                )?;
8182                return Ok(output);
8183            }
8184            let mut first = true;
8185            let mut current_is_a = false;
8186            for rank in 0..ranks {
8187                for block in 0..ws.blocks_per_rank {
8188                    let use_peer = rank != 0;
8189                    if use_peer {
8190                        raw_copy_bytes(
8191                            ws.raw_peer_partial,
8192                            ws.raw_o_partials[rank][block],
8193                            ws.o_out * std::mem::size_of::<f32>(),
8194                            root,
8195                        )?;
8196                    }
8197                    // add(prev, partial) -> the other reduce buffer, exactly one add per block
8198                    match (first, current_is_a, use_peer) {
8199                        (true, _, true) => {
8200                            root.add(&ws.zeros, &ws.peer_partial, &mut ws.reduce_a, ws.o_out)?
8201                        }
8202                        (true, _, false) => root.add(
8203                            &ws.zeros,
8204                            &ws.o_partials[0][block],
8205                            &mut ws.reduce_a,
8206                            ws.o_out,
8207                        )?,
8208                        (false, true, true) => {
8209                            root.add(&ws.reduce_a, &ws.peer_partial, &mut ws.reduce_b, ws.o_out)?
8210                        }
8211                        (false, true, false) => root.add(
8212                            &ws.reduce_a,
8213                            &ws.o_partials[0][block],
8214                            &mut ws.reduce_b,
8215                            ws.o_out,
8216                        )?,
8217                        (false, false, true) => {
8218                            root.add(&ws.reduce_b, &ws.peer_partial, &mut ws.reduce_a, ws.o_out)?
8219                        }
8220                        (false, false, false) => root.add(
8221                            &ws.reduce_b,
8222                            &ws.o_partials[0][block],
8223                            &mut ws.reduce_a,
8224                            ws.o_out,
8225                        )?,
8226                    }
8227                    current_is_a = first || !current_is_a;
8228                    first = false;
8229                }
8230            }
8231            final_in_a = current_is_a;
8232
8233            if !no_local_shadow_on() {
8234                let bytes = ws.local_kv_dim * std::mem::size_of::<f32>();
8235                for rank in 0..ranks {
8236                    let offset = rank * bytes;
8237                    raw_copy_bytes(ws.raw_k_shadow + offset as u64, ws.raw_k[rank], bytes, root)?;
8238                    raw_copy_bytes(
8239                        ws.raw_v_shadow + offset as u64,
8240                        ws.raw_v_raw[rank],
8241                        bytes,
8242                        root,
8243                    )?;
8244                }
8245            }
8246            ws.ev_oproj.record(&root.stream())?;
8247        }
8248
8249        // Model-engine output: e waits the root event, then copies the reduced row into a
8250        // fresh e-context buffer (same ownership contract as v1's `e.htod`). The same wait
8251        // orders the driver's shadow append (it reads ws.k_shadow/ws.v_shadow on e's stream).
8252        let _main = e.gpu.enter_main()?;
8253        e.stream().wait(&ws.ev_oproj)?;
8254        let mut output = e.uninit(ws.o_out)?;
8255        let source = if final_in_a {
8256            &ws.reduce_a
8257        } else {
8258            &ws.reduce_b
8259        };
8260        e.stream().memcpy_dtod(
8261            &source.slice(0..ws.o_out),
8262            &mut output.slice_mut(0..ws.o_out),
8263        )?;
8264        Ok(output)
8265    }
8266
8267    #[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
8268    pub fn run_routed_experts(
8269        &self,
8270        experts: &ResidentExpertParallel,
8271        input: &[f32],
8272        tokens: usize,
8273        selected: &[usize],
8274        route_weights: &[f32],
8275        experts_per_token: usize,
8276        activation_limit: Option<f32>,
8277    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
8278        validate_step_expert_activation_limit(activation_limit)?;
8279        validate_ep_residency(&self.ranks, experts)?;
8280        validate_activations(input, tokens, experts.input_width)?;
8281        let pairs = tokens
8282            .checked_mul(experts_per_token)
8283            .ok_or("EP route count overflow")?;
8284        if selected.len() != pairs || route_weights.len() != pairs {
8285            return Err(format!(
8286                "EP routes selected={} weights={} != tokens {tokens} x experts/token \
8287                 {experts_per_token} ({pairs})",
8288                selected.len(),
8289                route_weights.len(),
8290            )
8291            .into());
8292        }
8293        if !route_weights.iter().all(|weight| weight.is_finite()) {
8294            return Err("EP route weights contain a non-finite value".into());
8295        }
8296        if self.native_p2p {
8297            return self.run_routed_experts_native(
8298                experts,
8299                input,
8300                tokens,
8301                selected,
8302                route_weights,
8303                experts_per_token,
8304                activation_limit,
8305            );
8306        }
8307
8308        let mut output = vec![0.0f32; tokens * experts.input_width];
8309        let per_rank = experts.expert_count / experts.ranks.len();
8310        for token in 0..tokens {
8311            let input_row = &input[token * experts.input_width..(token + 1) * experts.input_width];
8312            for slot in 0..experts_per_token {
8313                let pair = token * experts_per_token + slot;
8314                let expert = selected[pair];
8315                if expert >= experts.expert_count {
8316                    return Err(format!(
8317                        "EP selected expert {expert} outside 0..{}",
8318                        experts.expert_count
8319                    )
8320                    .into());
8321                }
8322                let owner = expert / per_rank;
8323                let local_expert = expert - experts.ranks[owner].gate.expert_range.start;
8324                let rank = &experts.ranks[owner];
8325                let engine = &self.ranks[owner];
8326                let gate =
8327                    run_resident_bank_expert(engine, &rank.gate, local_expert, input_row, 1)?;
8328                let up = run_resident_bank_expert(engine, &rank.up, local_expert, input_row, 1)?;
8329                let activated: Vec<f32> = gate
8330                    .iter()
8331                    .zip(&up)
8332                    .map(|(&gate, &up)| step_expert_activation_host(gate, up, activation_limit))
8333                    .collect();
8334                debug_assert_eq!(activated.len(), experts.expert_width);
8335                let down =
8336                    run_resident_bank_expert(engine, &rank.down, local_expert, &activated, 1)?;
8337                let weight = route_weights[pair];
8338                for (sum, value) in output
8339                    [token * experts.input_width..(token + 1) * experts.input_width]
8340                    .iter_mut()
8341                    .zip(down)
8342                {
8343                    *sum += weight * value;
8344                }
8345            }
8346        }
8347        Ok(output)
8348    }
8349
8350    #[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
8351    fn run_routed_experts_native(
8352        &self,
8353        experts: &ResidentExpertParallel,
8354        input: &[f32],
8355        tokens: usize,
8356        selected: &[usize],
8357        route_weights: &[f32],
8358        experts_per_token: usize,
8359        activation_limit: Option<f32>,
8360    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
8361        if !self.native_p2p || self.ranks.len() < 2 {
8362            return Err("native EP execution requires at least two P2P ranks".into());
8363        }
8364        if self.ep_device_arithmetic {
8365            return self.run_routed_experts_native_device(
8366                experts,
8367                input,
8368                tokens,
8369                selected,
8370                route_weights,
8371                experts_per_token,
8372                activation_limit,
8373            );
8374        }
8375        let mut output = vec![0.0f32; tokens * experts.input_width];
8376        let per_rank = experts.expert_count / experts.ranks.len();
8377        for token in 0..tokens {
8378            let input_row = &input[token * experts.input_width..(token + 1) * experts.input_width];
8379            let mut rank_inputs = (0..self.ranks.len())
8380                .map(|_| None)
8381                .collect::<Vec<Option<CudaSlice<f32>>>>();
8382            rank_inputs[0] = Some({
8383                let root = &self.ranks[0];
8384                let _main = root.gpu.enter_main()?;
8385                root.htod(input_row)?
8386            });
8387
8388            for slot in 0..experts_per_token {
8389                let pair = token * experts_per_token + slot;
8390                let expert = selected[pair];
8391                if expert >= experts.expert_count {
8392                    return Err(format!(
8393                        "EP selected expert {expert} outside 0..{}",
8394                        experts.expert_count
8395                    )
8396                    .into());
8397                }
8398                let owner = expert / per_rank;
8399                let local_expert = expert - experts.ranks[owner].gate.expert_range.start;
8400                if rank_inputs[owner].is_none() {
8401                    let peer_input = {
8402                        let root_input = rank_inputs[0]
8403                            .as_ref()
8404                            .ok_or("native EP lost its root input")?;
8405                        let engine = &self.ranks[owner];
8406                        let _main = engine.gpu.enter_main()?;
8407                        let mut peer_input = engine.uninit(experts.input_width)?;
8408                        engine.stream().memcpy_dtod(root_input, &mut peer_input)?;
8409                        peer_input
8410                    };
8411                    rank_inputs[owner] = Some(peer_input);
8412                }
8413
8414                let rank = &experts.ranks[owner];
8415                let engine = &self.ranks[owner];
8416                let owner_input = rank_inputs[owner]
8417                    .as_ref()
8418                    .ok_or("native EP owner input is absent after dispatch")?;
8419                let gate = run_resident_bank_expert_device(
8420                    engine,
8421                    &rank.gate,
8422                    local_expert,
8423                    owner_input,
8424                    1,
8425                )?;
8426                let up = run_resident_bank_expert_device(
8427                    engine,
8428                    &rank.up,
8429                    local_expert,
8430                    owner_input,
8431                    1,
8432                )?;
8433                let (gate, up) = {
8434                    let _main = engine.gpu.enter_main()?;
8435                    (engine.dtoh(&gate)?, engine.dtoh(&up)?)
8436                };
8437                let activated = gate
8438                    .iter()
8439                    .zip(&up)
8440                    .map(|(&gate, &up)| step_expert_activation_host(gate, up, activation_limit))
8441                    .collect::<Vec<_>>();
8442                debug_assert_eq!(activated.len(), experts.expert_width);
8443                let activated = {
8444                    let _main = engine.gpu.enter_main()?;
8445                    engine.htod(&activated)?
8446                };
8447                let down = run_resident_bank_expert_device(
8448                    engine,
8449                    &rank.down,
8450                    local_expert,
8451                    &activated,
8452                    1,
8453                )?;
8454                let down = if owner == 0 {
8455                    let _main = engine.gpu.enter_main()?;
8456                    engine.dtoh(&down)?
8457                } else {
8458                    let root = &self.ranks[0];
8459                    let _main = root.gpu.enter_main()?;
8460                    let mut root_down = root.uninit(experts.input_width)?;
8461                    root.stream().memcpy_dtod(&down, &mut root_down)?;
8462                    root.dtoh(&root_down)?
8463                };
8464                let weight = route_weights[pair];
8465                for (sum, value) in output
8466                    [token * experts.input_width..(token + 1) * experts.input_width]
8467                    .iter_mut()
8468                    .zip(down)
8469                {
8470                    *sum += weight * value;
8471                }
8472            }
8473        }
8474        Ok(output)
8475    }
8476
8477    #[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
8478    fn run_routed_experts_native_device(
8479        &self,
8480        experts: &ResidentExpertParallel,
8481        input: &[f32],
8482        tokens: usize,
8483        selected: &[usize],
8484        route_weights: &[f32],
8485        experts_per_token: usize,
8486        activation_limit: Option<f32>,
8487    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
8488        if !self.native_p2p || !self.ep_device_arithmetic || self.ranks.len() < 2 {
8489            return Err(
8490                "device-resident EP arithmetic requires at least two native P2P ranks".into(),
8491            );
8492        }
8493        let mut output = Vec::with_capacity(tokens * experts.input_width);
8494        let per_rank = experts.expert_count / experts.ranks.len();
8495        let root = &self.ranks[0];
8496        for token in 0..tokens {
8497            let input_row = &input[token * experts.input_width..(token + 1) * experts.input_width];
8498            let mut rank_inputs = (0..self.ranks.len())
8499                .map(|_| None)
8500                .collect::<Vec<Option<CudaSlice<f32>>>>();
8501            rank_inputs[0] = Some({
8502                let _main = root.gpu.enter_main()?;
8503                root.htod(input_row)?
8504            });
8505            let mut root_output = {
8506                let _main = root.gpu.enter_main()?;
8507                root.zeros(experts.input_width)?
8508            };
8509            let mut remote_down_keepalive = Vec::new();
8510
8511            for slot in 0..experts_per_token {
8512                let pair = token * experts_per_token + slot;
8513                let expert = selected[pair];
8514                if expert >= experts.expert_count {
8515                    return Err(format!(
8516                        "EP selected expert {expert} outside 0..{}",
8517                        experts.expert_count
8518                    )
8519                    .into());
8520                }
8521                let owner = expert / per_rank;
8522                let local_expert = expert - experts.ranks[owner].gate.expert_range.start;
8523                if rank_inputs[owner].is_none() {
8524                    let peer_input = {
8525                        let root_input = rank_inputs[0]
8526                            .as_ref()
8527                            .ok_or("native EP lost its root input")?;
8528                        let engine = &self.ranks[owner];
8529                        let _main = engine.gpu.enter_main()?;
8530                        let mut peer_input = engine.uninit(experts.input_width)?;
8531                        engine.stream().memcpy_dtod(root_input, &mut peer_input)?;
8532                        peer_input
8533                    };
8534                    rank_inputs[owner] = Some(peer_input);
8535                }
8536
8537                let rank = &experts.ranks[owner];
8538                let engine = &self.ranks[owner];
8539                let owner_input = rank_inputs[owner]
8540                    .as_ref()
8541                    .ok_or("native EP owner input is absent after dispatch")?;
8542                let gate = run_resident_bank_expert_device(
8543                    engine,
8544                    &rank.gate,
8545                    local_expert,
8546                    owner_input,
8547                    1,
8548                )?;
8549                let up = run_resident_bank_expert_device(
8550                    engine,
8551                    &rank.up,
8552                    local_expert,
8553                    owner_input,
8554                    1,
8555                )?;
8556                let activated = {
8557                    let _main = engine.gpu.enter_main()?;
8558                    let mut activated = engine.uninit(experts.expert_width)?;
8559                    if let Some(limit) = activation_limit {
8560                        engine.silu_clamped_mul_host_expf(
8561                            &gate,
8562                            &up,
8563                            limit,
8564                            &mut activated,
8565                            experts.expert_width,
8566                        )?;
8567                    } else {
8568                        engine.silu_mul_host_expf(
8569                            &gate,
8570                            &up,
8571                            &mut activated,
8572                            experts.expert_width,
8573                        )?;
8574                    }
8575                    activated
8576                };
8577                let down = run_resident_bank_expert_device(
8578                    engine,
8579                    &rank.down,
8580                    local_expert,
8581                    &activated,
8582                    1,
8583                )?;
8584                let root_down = if owner == 0 {
8585                    down
8586                } else {
8587                    let _main = root.gpu.enter_main()?;
8588                    let mut root_down = root.uninit(experts.input_width)?;
8589                    root.stream().memcpy_dtod(&down, &mut root_down)?;
8590                    // The peer copy runs on the root stream. Keep its remote source alive until
8591                    // the final root readback synchronizes that stream; otherwise async free can
8592                    // recycle the owner's allocation while cuMemcpyPeerAsync is still reading it.
8593                    remote_down_keepalive.push(down);
8594                    root_down
8595                };
8596                let _main = root.gpu.enter_main()?;
8597                let mut destination = root_output.slice_mut(0..experts.input_width);
8598                root.axpy_host_into(
8599                    &root_down.slice(0..root_down.len()),
8600                    route_weights[pair],
8601                    &mut destination,
8602                    experts.input_width,
8603                )?;
8604            }
8605
8606            let _main = root.gpu.enter_main()?;
8607            let root_output = root.dtoh(&root_output)?;
8608            drop(remote_down_keepalive);
8609            output.extend(root_output);
8610        }
8611        Ok(output)
8612    }
8613}
8614
8615#[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
8616fn validate_column_shape(matrix: E4m3BlockMatrix<'_>, tp: usize) -> Result<(), String> {
8617    if matrix.out_features % tp != 0 {
8618        return Err(format!(
8619            "column-parallel out_features {} is not divisible by TP={tp}",
8620            matrix.out_features
8621        ));
8622    }
8623    let local_out = matrix.out_features / tp;
8624    if !local_out.is_multiple_of(FP8_BLOCK) {
8625        return Err(format!(
8626            "column-parallel output shard {local_out} cuts through a {FP8_BLOCK}-row \
8627             E4M3 scale block"
8628        ));
8629    }
8630    Ok(())
8631}
8632
8633#[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
8634fn step_bf16_canonical_chunk_rows(out_features: usize, tp: usize) -> Result<usize, String> {
8635    if !matches!(tp, 1 | 2 | 4 | 8) {
8636        return Err(format!(
8637            "Step BF16 canonical projection requires TP1/TP2/TP4/TP8, got TP={tp}"
8638        ));
8639    }
8640    if out_features == 0 || !out_features.is_multiple_of(PRODUCT_MAX_CARDS) {
8641        return Err(format!(
8642            "Step BF16 output width {out_features} is not divisible by the TP8 product envelope"
8643        ));
8644    }
8645    let canonical_rows = out_features / PRODUCT_MAX_CARDS;
8646    let local_out = out_features / tp;
8647    if local_out % canonical_rows != 0 {
8648        return Err(format!(
8649            "Step BF16 TP={tp} output shard {local_out} is not divisible by canonical \
8650             {canonical_rows}-row chunks"
8651        ));
8652    }
8653    Ok(canonical_rows)
8654}
8655
8656#[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
8657fn step_bf16_canonical_chunk_cols(in_features: usize, tp: usize) -> Result<usize, String> {
8658    if !matches!(tp, 1 | 2 | 4 | 8) {
8659        return Err(format!(
8660            "Step BF16 canonical row projection requires TP1/TP2/TP4/TP8, got TP={tp}"
8661        ));
8662    }
8663    if in_features == 0 || !in_features.is_multiple_of(PRODUCT_MAX_CARDS) {
8664        return Err(format!(
8665            "Step BF16 input width {in_features} is not divisible by the TP8 product envelope"
8666        ));
8667    }
8668    let canonical_cols = in_features / PRODUCT_MAX_CARDS;
8669    let local_in = in_features / tp;
8670    if local_in % canonical_cols != 0 {
8671        return Err(format!(
8672            "Step BF16 TP={tp} input shard {local_in} is not divisible by canonical \
8673             {canonical_cols}-column chunks"
8674        ));
8675    }
8676    Ok(canonical_cols)
8677}
8678
8679#[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
8680fn validate_row_shape(matrix: E4m3BlockMatrix<'_>, tp: usize) -> Result<(), String> {
8681    if matrix.in_features % tp != 0 {
8682        return Err(format!(
8683            "row-parallel in_features {} is not divisible by TP={tp}",
8684            matrix.in_features
8685        ));
8686    }
8687    let local_in = matrix.in_features / tp;
8688    if !local_in.is_multiple_of(FP8_BLOCK) {
8689        return Err(format!(
8690            "row-parallel input shard {local_in} cuts through a {FP8_BLOCK}-column \
8691             E4M3 scale block"
8692        ));
8693    }
8694    Ok(())
8695}
8696
8697fn upload_rank(
8698    engine: &Engine,
8699    matrix: E4m3BlockMatrix<'_>,
8700) -> Result<ResidentE4m3Rank, Box<dyn std::error::Error>> {
8701    let _main = engine.gpu.enter_main()?;
8702    matrix.validate()?;
8703    Ok(ResidentE4m3Rank {
8704        codes: engine.htod_bytes(matrix.codes)?,
8705        scales: engine.htod(matrix.scales)?,
8706        out_features: matrix.out_features,
8707        in_features: matrix.in_features,
8708    })
8709}
8710
8711fn upload_bf16_rank(
8712    engine: &Engine,
8713    matrix: Bf16Matrix<'_>,
8714    f32_mirror: bool,
8715) -> Result<ResidentBf16Rank, Box<dyn std::error::Error>> {
8716    let _main = engine.gpu.enter_main()?;
8717    matrix.validate()?;
8718    let bytes = engine.htod_bytes(matrix.bytes)?;
8719    let weight = if f32_mirror {
8720        let values = matrix
8721            .out_features
8722            .checked_mul(matrix.in_features)
8723            .ok_or("resident BF16 mirror element count overflow")?;
8724        ResidentBf16Weight::F32(engine.bf16_to_f32(&bytes.slice(0..bytes.len()), values)?)
8725    } else {
8726        ResidentBf16Weight::Bf16(bytes)
8727    };
8728    // MEMRA_STEP_TP_W8: encode the q8_0 decode mirror once, here, while the bf16 bytes are
8729    // already resident. Rows whose in_features is not a multiple of 32 have no q8_0 form and
8730    // simply keep the bf16 program (the decode arm checks for the mirror, never assumes it).
8731    let q8 = if crate::step_tp_w8_on() && matrix.in_features.is_multiple_of(32) {
8732        if let ResidentBf16Weight::Bf16(bytes) = &weight {
8733            // Two steps, because the mmvq rp kernel does NOT read ggml-interleaved 34-byte
8734            // blocks: it reads a PLANAR mirror (all quants, then all half scales — the
8735            // q4_0/NVFP4 rp convention). The encoder writes the interleaved form and
8736            // `build_q8_rp4_raw` — the same kernel the GGUF loader uses — splits it into
8737            // planes. Skipping the split is what made the first W8 gate return zeros
8738            // (verify-prefill argmax=0, maxdiff=0.000e0).
8739            let row_bytes = Engine::q8_0_row_bytes(matrix.in_features);
8740            let mut interleaved = engine.alloc_u8_uninit(matrix.out_features * row_bytes)?;
8741            engine.encode_q8_0_from_bf16(
8742                bytes,
8743                &mut interleaved,
8744                matrix.in_features,
8745                matrix.out_features,
8746            )?;
8747            let mirror =
8748                engine.build_q8_rp4_raw(&interleaved, matrix.in_features, matrix.out_features)?;
8749            Some(mirror)
8750        } else {
8751            None
8752        }
8753    } else {
8754        None
8755    };
8756    Ok(ResidentBf16Rank {
8757        weight,
8758        out_features: matrix.out_features,
8759        in_features: matrix.in_features,
8760        q8,
8761    })
8762}
8763
8764fn upload_expert_bank_rank(
8765    engine: &Engine,
8766    bank: E4m3ExpertBank<'_>,
8767    expert_range: Range<usize>,
8768) -> Result<ResidentE4m3ExpertBankRank, Box<dyn std::error::Error>> {
8769    let _main = engine.gpu.enter_main()?;
8770    bank.validate()?;
8771    if expert_range.start >= expert_range.end || expert_range.end > bank.expert_count {
8772        return Err(format!(
8773            "invalid EP expert range {expert_range:?} for {} experts",
8774            bank.expert_count
8775        )
8776        .into());
8777    }
8778    let code_stride = bank.out_features * bank.in_features;
8779    let scale_stride = bank.out_features.div_ceil(FP8_BLOCK) * bank.in_features.div_ceil(FP8_BLOCK);
8780    Ok(ResidentE4m3ExpertBankRank {
8781        codes: engine.htod_bytes(
8782            &bank.codes[expert_range.start * code_stride..expert_range.end * code_stride],
8783        )?,
8784        scales: engine.htod(
8785            &bank.scales[expert_range.start * scale_stride..expert_range.end * scale_stride],
8786        )?,
8787        expert_range,
8788        out_features: bank.out_features,
8789        in_features: bank.in_features,
8790        code_stride,
8791        scale_stride,
8792        k_blocks: None,
8793    })
8794}
8795
8796#[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
8797fn validate_column_bank_shape(bank: E4m3ExpertBank<'_>, tp: usize) -> Result<(), String> {
8798    if bank.out_features % tp != 0 {
8799        return Err(format!(
8800            "TP expert output width {} is not divisible by TP={tp}",
8801            bank.out_features
8802        ));
8803    }
8804    let local_out = bank.out_features / tp;
8805    if !local_out.is_multiple_of(FP8_BLOCK) {
8806        return Err(format!(
8807            "TP expert output shard {local_out} cuts through a {FP8_BLOCK}-row E4M3 scale block"
8808        ));
8809    }
8810    Ok(())
8811}
8812
8813#[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
8814fn validate_row_bank_shape(bank: E4m3ExpertBank<'_>, tp: usize) -> Result<(), String> {
8815    if bank.in_features % tp != 0 {
8816        return Err(format!(
8817            "TP expert input width {} is not divisible by TP={tp}",
8818            bank.in_features
8819        ));
8820    }
8821    let local_in = bank.in_features / tp;
8822    if !local_in.is_multiple_of(FP8_BLOCK) {
8823        return Err(format!(
8824            "TP expert input shard {local_in} cuts through a {FP8_BLOCK}-column E4M3 scale block"
8825        ));
8826    }
8827    Ok(())
8828}
8829
8830fn upload_column_bank_rank(
8831    engine: &Engine,
8832    bank: E4m3ExpertBank<'_>,
8833    tp: usize,
8834    rank: usize,
8835) -> Result<ResidentE4m3ExpertBankRank, Box<dyn std::error::Error>> {
8836    let _main = engine.gpu.enter_main()?;
8837    let packed = pack_column_bank_rank(bank, tp, rank)?;
8838    Ok(ResidentE4m3ExpertBankRank {
8839        codes: engine.htod_bytes(&packed.codes)?,
8840        scales: engine.htod(&packed.scales)?,
8841        expert_range: packed.expert_range,
8842        out_features: packed.out_features,
8843        in_features: packed.in_features,
8844        code_stride: packed.code_stride,
8845        scale_stride: packed.scale_stride,
8846        k_blocks: packed.k_blocks,
8847    })
8848}
8849
8850fn pack_column_bank_rank(
8851    bank: E4m3ExpertBank<'_>,
8852    tp: usize,
8853    rank: usize,
8854) -> Result<PackedE4m3ExpertBankRank, String> {
8855    bank.validate()?;
8856    validate_column_bank_shape(bank, tp)?;
8857    if rank >= tp {
8858        return Err(format!("TP rank {rank} outside 0..{tp}"));
8859    }
8860    let local_out = bank.out_features / tp;
8861    let full_code_stride = bank.out_features * bank.in_features;
8862    let local_code_stride = local_out * bank.in_features;
8863    let scale_cols = bank.in_features.div_ceil(FP8_BLOCK);
8864    let full_scale_stride = bank.out_features.div_ceil(FP8_BLOCK) * scale_cols;
8865    let local_scale_rows = local_out / FP8_BLOCK;
8866    let local_scale_stride = local_scale_rows * scale_cols;
8867    let mut codes = Vec::with_capacity(bank.expert_count * local_code_stride);
8868    let mut scales = Vec::with_capacity(bank.expert_count * local_scale_stride);
8869    let row_start = rank * local_out;
8870    let scale_row_start = rank * local_scale_rows;
8871    for expert in 0..bank.expert_count {
8872        let code_start = expert * full_code_stride + row_start * bank.in_features;
8873        codes.extend_from_slice(&bank.codes[code_start..code_start + local_code_stride]);
8874        let scale_start = expert * full_scale_stride + scale_row_start * scale_cols;
8875        scales.extend_from_slice(&bank.scales[scale_start..scale_start + local_scale_stride]);
8876    }
8877    Ok(PackedE4m3ExpertBankRank {
8878        codes,
8879        scales,
8880        expert_range: 0..bank.expert_count,
8881        out_features: local_out,
8882        in_features: bank.in_features,
8883        code_stride: local_code_stride,
8884        scale_stride: local_scale_stride,
8885        k_blocks: None,
8886    })
8887}
8888
8889fn upload_row_bank_rank(
8890    engine: &Engine,
8891    bank: E4m3ExpertBank<'_>,
8892    tp: usize,
8893    rank: usize,
8894) -> Result<ResidentE4m3ExpertBankRank, Box<dyn std::error::Error>> {
8895    let _main = engine.gpu.enter_main()?;
8896    let packed = pack_row_bank_rank(bank, tp, rank)?;
8897    Ok(ResidentE4m3ExpertBankRank {
8898        codes: engine.htod_bytes(&packed.codes)?,
8899        scales: engine.htod(&packed.scales)?,
8900        expert_range: packed.expert_range,
8901        out_features: packed.out_features,
8902        in_features: packed.in_features,
8903        code_stride: packed.code_stride,
8904        scale_stride: packed.scale_stride,
8905        k_blocks: packed.k_blocks,
8906    })
8907}
8908
8909fn pack_row_bank_rank(
8910    bank: E4m3ExpertBank<'_>,
8911    tp: usize,
8912    rank: usize,
8913) -> Result<PackedE4m3ExpertBankRank, String> {
8914    bank.validate()?;
8915    validate_row_bank_shape(bank, tp)?;
8916    if rank >= tp {
8917        return Err(format!("TP rank {rank} outside 0..{tp}"));
8918    }
8919    let local_in = bank.in_features / tp;
8920    let full_code_stride = bank.out_features * bank.in_features;
8921    let local_code_stride = bank.out_features * local_in;
8922    let full_scale_cols = bank.in_features.div_ceil(FP8_BLOCK);
8923    let local_scale_cols = local_in / FP8_BLOCK;
8924    let scale_rows = bank.out_features.div_ceil(FP8_BLOCK);
8925    let full_scale_stride = scale_rows * full_scale_cols;
8926    let local_scale_stride = scale_rows * local_scale_cols;
8927    let global_block_start = rank * local_scale_cols;
8928    let mut codes = Vec::with_capacity(bank.expert_count * local_code_stride);
8929    let mut scales = Vec::with_capacity(bank.expert_count * local_scale_stride);
8930    for expert in 0..bank.expert_count {
8931        let expert_code_start = expert * full_code_stride;
8932        let expert_scale_start = expert * full_scale_stride;
8933        for local_block in 0..local_scale_cols {
8934            let global_block = global_block_start + local_block;
8935            let column_start = global_block * FP8_BLOCK;
8936            for row in 0..bank.out_features {
8937                let start = expert_code_start + row * bank.in_features + column_start;
8938                codes.extend_from_slice(&bank.codes[start..start + FP8_BLOCK]);
8939            }
8940            for row in 0..scale_rows {
8941                scales.push(bank.scales[expert_scale_start + row * full_scale_cols + global_block]);
8942            }
8943        }
8944    }
8945    Ok(PackedE4m3ExpertBankRank {
8946        codes,
8947        scales,
8948        expert_range: 0..bank.expert_count,
8949        out_features: bank.out_features,
8950        in_features: local_in,
8951        code_stride: local_code_stride,
8952        scale_stride: local_scale_stride,
8953        k_blocks: Some(local_scale_cols),
8954    })
8955}
8956
8957fn validate_resident_ranks(engines: &[Engine], ranks: &[ResidentE4m3Rank]) -> Result<(), String> {
8958    if engines.len() != ranks.len() {
8959        return Err(format!(
8960            "resident TP rank count {} != runtime rank count {}",
8961            ranks.len(),
8962            engines.len()
8963        ));
8964    }
8965    for (rank, (engine, matrix)) in engines.iter().zip(ranks).enumerate() {
8966        let device = engine.ctx().ordinal();
8967        if matrix.codes.ordinal() != device || matrix.scales.ordinal() != device {
8968            return Err(format!(
8969                "resident TP rank {rank} is not owned by runtime device {device}"
8970            ));
8971        }
8972    }
8973    Ok(())
8974}
8975
8976fn validate_tp_bank_residency(
8977    engines: &[Engine],
8978    experts: &ResidentTpExpertBank,
8979) -> Result<(), String> {
8980    if engines.len() != experts.gate.len()
8981        || engines.len() != experts.up.len()
8982        || engines.len() != experts.down.len()
8983    {
8984        return Err(format!(
8985            "resident TP expert-bank rank counts gate={} up={} down={} != runtime {}",
8986            experts.gate.len(),
8987            experts.up.len(),
8988            experts.down.len(),
8989            engines.len()
8990        ));
8991    }
8992    for (rank, engine) in engines.iter().enumerate() {
8993        let device = engine.ctx().ordinal();
8994        for (projection, bank) in [
8995            ("gate", &experts.gate[rank]),
8996            ("up", &experts.up[rank]),
8997            ("down", &experts.down[rank]),
8998        ] {
8999            if bank.codes.ordinal() != device || bank.scales.ordinal() != device {
9000                return Err(format!(
9001                    "resident TP rank {rank} {projection} bank is not owned by runtime device \
9002                     {device}"
9003                ));
9004            }
9005        }
9006    }
9007    Ok(())
9008}
9009
9010fn validate_ep_residency(
9011    engines: &[Engine],
9012    experts: &ResidentExpertParallel,
9013) -> Result<(), String> {
9014    if engines.len() != experts.ranks.len() {
9015        return Err(format!(
9016            "resident EP rank count {} != runtime rank count {}",
9017            experts.ranks.len(),
9018            engines.len()
9019        ));
9020    }
9021    for (rank, (engine, resident)) in engines.iter().zip(&experts.ranks).enumerate() {
9022        let device = engine.ctx().ordinal();
9023        for (projection, bank) in [
9024            ("gate", &resident.gate),
9025            ("up", &resident.up),
9026            ("down", &resident.down),
9027        ] {
9028            if bank.codes.ordinal() != device || bank.scales.ordinal() != device {
9029                return Err(format!(
9030                    "resident EP rank {rank} {projection} bank is not owned by runtime device \
9031                     {device}"
9032                ));
9033            }
9034        }
9035    }
9036    Ok(())
9037}
9038
9039fn run_rank(
9040    engine: &Engine,
9041    matrix: E4m3BlockMatrix<'_>,
9042    activations: &[f32],
9043    tokens: usize,
9044) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
9045    let _main = engine.gpu.enter_main()?;
9046    let codes = engine.htod_bytes(matrix.codes)?;
9047    let scales = engine.htod(matrix.scales)?;
9048    let activations = engine.htod(activations)?;
9049    let output = engine.qmatvec_mmq_fp8_blk(
9050        &codes,
9051        &scales,
9052        &activations,
9053        tokens,
9054        matrix.in_features,
9055        matrix.out_features,
9056    )?;
9057    engine.dtoh(&output)
9058}
9059
9060fn run_resident_rank(
9061    engine: &Engine,
9062    matrix: &ResidentE4m3Rank,
9063    activations: &[f32],
9064    tokens: usize,
9065) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
9066    let _main = engine.gpu.enter_main()?;
9067    let activations = engine.htod(activations)?;
9068    let output = engine.qmatvec_mmq_fp8_blk(
9069        &matrix.codes,
9070        &matrix.scales,
9071        &activations,
9072        tokens,
9073        matrix.in_features,
9074        matrix.out_features,
9075    )?;
9076    engine.dtoh(&output)
9077}
9078
9079fn run_resident_bf16_rank(
9080    engine: &Engine,
9081    matrix: &ResidentBf16Rank,
9082    activations: &[f32],
9083    tokens: usize,
9084    canonical_chunk_rows: Option<usize>,
9085) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
9086    let _main = engine.gpu.enter_main()?;
9087    let activations = engine.htod(activations)?;
9088    let output = run_resident_bf16_rank_device(
9089        engine,
9090        matrix,
9091        &activations,
9092        tokens,
9093        canonical_chunk_rows,
9094        false,
9095    )?;
9096    engine.dtoh(&output)
9097}
9098
9099fn run_resident_bf16_rank_device(
9100    engine: &Engine,
9101    matrix: &ResidentBf16Rank,
9102    activations: &CudaSlice<f32>,
9103    tokens: usize,
9104    canonical_chunk_rows: Option<usize>,
9105    strided_chunk_output: bool,
9106) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
9107    let _main = engine.gpu.enter_main()?;
9108    if activations.ordinal() != engine.ctx().ordinal() {
9109        return Err(format!(
9110            "resident BF16 activation device {} != rank device {}",
9111            activations.ordinal(),
9112            engine.ctx().ordinal()
9113        )
9114        .into());
9115    }
9116    if activations.len() != tokens * matrix.in_features {
9117        return Err(format!(
9118            "resident BF16 activation count {} != {tokens}x{}",
9119            activations.len(),
9120            matrix.in_features
9121        )
9122        .into());
9123    }
9124    match (&matrix.weight, canonical_chunk_rows) {
9125        (ResidentBf16Weight::Bf16(bytes), Some(rows)) => engine
9126            .linear_bf16_resident_canonical_rows(
9127                activations,
9128                bytes,
9129                tokens,
9130                matrix.in_features,
9131                matrix.out_features,
9132                rows,
9133            ),
9134        (ResidentBf16Weight::Bf16(bytes), None) => engine.linear_bf16_resident(
9135            activations,
9136            bytes,
9137            tokens,
9138            matrix.in_features,
9139            matrix.out_features,
9140        ),
9141        (ResidentBf16Weight::F32(values), Some(rows)) if strided_chunk_output => engine
9142            .linear_f32_resident_canonical_rows_strided(
9143                activations,
9144                values,
9145                tokens,
9146                matrix.in_features,
9147                matrix.out_features,
9148                rows,
9149            ),
9150        (ResidentBf16Weight::F32(values), Some(rows)) => engine.linear_f32_resident_canonical_rows(
9151            activations,
9152            values,
9153            tokens,
9154            matrix.in_features,
9155            matrix.out_features,
9156            rows,
9157        ),
9158        (ResidentBf16Weight::F32(values), None) => engine.linear(
9159            activations,
9160            values,
9161            tokens,
9162            matrix.in_features,
9163            matrix.out_features,
9164        ),
9165    }
9166}
9167
9168fn validate_resident_bf16_ranks(
9169    engines: &[Engine],
9170    ranks: &[ResidentBf16Rank],
9171) -> Result<(), String> {
9172    if engines.len() != ranks.len() {
9173        return Err(format!(
9174            "resident BF16 TP rank count {} != runtime rank count {}",
9175            ranks.len(),
9176            engines.len(),
9177        ));
9178    }
9179    for (rank, (engine, matrix)) in engines.iter().zip(ranks).enumerate() {
9180        let device = engine.ctx().ordinal();
9181        if matrix.weight.ordinal() != device {
9182            return Err(format!(
9183                "resident BF16 TP rank {rank} is not owned by runtime device {device}"
9184            ));
9185        }
9186    }
9187    Ok(())
9188}
9189
9190fn validate_step_bf16_row_residency(
9191    engines: &[Engine],
9192    matrix: &ResidentStepBf16RowParallel,
9193) -> Result<(), String> {
9194    if engines.len() != matrix.ranks.len() {
9195        return Err(format!(
9196            "resident Step BF16 row rank count {} != runtime rank count {}",
9197            matrix.ranks.len(),
9198            engines.len(),
9199        ));
9200    }
9201    let canonical_cols = step_bf16_canonical_chunk_cols(matrix.in_features, engines.len())?;
9202    if matrix.canonical_chunk_cols != canonical_cols {
9203        return Err(format!(
9204            "resident Step BF16 row canonical columns {} != registered {canonical_cols}",
9205            matrix.canonical_chunk_cols
9206        ));
9207    }
9208    let blocks_per_rank = PRODUCT_MAX_CARDS / engines.len();
9209    for (rank, (engine, blocks)) in engines.iter().zip(&matrix.ranks).enumerate() {
9210        if blocks.len() != blocks_per_rank {
9211            return Err(format!(
9212                "resident Step BF16 row rank {rank} has {} blocks, expected {blocks_per_rank}",
9213                blocks.len()
9214            ));
9215        }
9216        let device = engine.ctx().ordinal();
9217        for (block, resident) in blocks.iter().enumerate() {
9218            if resident.weight.ordinal() != device
9219                || resident.in_features != canonical_cols
9220                || resident.out_features != matrix.out_features
9221            {
9222                return Err(format!(
9223                    "resident Step BF16 row rank {rank} block {block} has inconsistent \
9224                     device or geometry"
9225                ));
9226            }
9227        }
9228    }
9229    Ok(())
9230}
9231
9232fn validate_replicated_device_rows(
9233    engines: &[Engine],
9234    rows: &ResidentReplicatedDeviceRows,
9235) -> Result<(), String> {
9236    let rank_lengths = rows
9237        .ranks
9238        .iter()
9239        .map(|rank_rows| rank_rows.len())
9240        .collect::<Vec<_>>();
9241    replicated_device_row_values(rows.tokens, rows.width, engines.len(), &rank_lengths)?;
9242    if rows
9243        .ranks
9244        .iter()
9245        .zip(engines)
9246        .any(|(rank_rows, engine)| rank_rows.ordinal() != engine.ctx().ordinal())
9247    {
9248        return Err("replicated device rows are owned by the wrong CUDA contexts".into());
9249    }
9250    Ok(())
9251}
9252
9253fn replicated_device_row_values(
9254    tokens: usize,
9255    width: usize,
9256    expected_ranks: usize,
9257    rank_lengths: &[usize],
9258) -> Result<usize, String> {
9259    let values = tokens
9260        .checked_mul(width)
9261        .ok_or("replicated device row size overflow")?;
9262    if tokens == 0
9263        || width == 0
9264        || expected_ranks == 0
9265        || rank_lengths.len() != expected_ranks
9266        || rank_lengths.iter().any(|&rank_len| rank_len != values)
9267    {
9268        return Err(format!(
9269            "replicated device rows have inconsistent geometry tokens={} width={} ranks={}/{}",
9270            tokens,
9271            width,
9272            rank_lengths.len(),
9273            expected_ranks
9274        ));
9275    }
9276    Ok(values)
9277}
9278
9279fn replicated_device_row_source_values(
9280    tokens: usize,
9281    width: usize,
9282    source_len: usize,
9283    source_device: usize,
9284    root_device: usize,
9285) -> Result<usize, String> {
9286    let values = tokens
9287        .checked_mul(width)
9288        .ok_or("replicated device row size overflow")?;
9289    if tokens == 0 || width == 0 || source_len != values || source_device != root_device {
9290        return Err(format!(
9291            "replicated device row source has inconsistent geometry/device \
9292             tokens={tokens} width={width} source={source_len}@{source_device} root={root_device}"
9293        ));
9294    }
9295    Ok(values)
9296}
9297
9298#[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
9299fn bf16_column_shard(
9300    matrix: Bf16Matrix<'_>,
9301    tp: usize,
9302    rank: usize,
9303) -> Result<Bf16Matrix<'_>, String> {
9304    matrix.validate()?;
9305    if tp == 0 || rank >= tp || matrix.out_features % tp != 0 {
9306        return Err(format!(
9307            "invalid BF16 column shard out={} TP={tp} rank={rank}",
9308            matrix.out_features
9309        ));
9310    }
9311    let local_out = matrix.out_features / tp;
9312    let row_bytes = matrix.in_features * 2;
9313    let start = rank * local_out * row_bytes;
9314    Ok(Bf16Matrix {
9315        bytes: &matrix.bytes[start..start + local_out * row_bytes],
9316        out_features: local_out,
9317        in_features: matrix.in_features,
9318    })
9319}
9320
9321#[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
9322fn bf16_row_shard(matrix: Bf16Matrix<'_>, tp: usize, rank: usize) -> Result<Vec<u8>, String> {
9323    matrix.validate()?;
9324    if tp == 0 || rank >= tp || matrix.in_features % tp != 0 {
9325        return Err(format!(
9326            "invalid BF16 row shard in={} TP={tp} rank={rank}",
9327            matrix.in_features
9328        ));
9329    }
9330    let local_in = matrix.in_features / tp;
9331    let mut bytes = Vec::with_capacity(matrix.out_features * local_in * 2);
9332    for row in 0..matrix.out_features {
9333        let start = (row * matrix.in_features + rank * local_in) * 2;
9334        bytes.extend_from_slice(&matrix.bytes[start..start + local_in * 2]);
9335    }
9336    Ok(bytes)
9337}
9338
9339fn bf16_row_block(
9340    matrix: Bf16Matrix<'_>,
9341    col_start: usize,
9342    block_cols: usize,
9343) -> Result<Vec<u8>, String> {
9344    matrix.validate()?;
9345    let col_end = col_start
9346        .checked_add(block_cols)
9347        .ok_or("BF16 row block column overflow")?;
9348    if block_cols == 0 || col_end > matrix.in_features {
9349        return Err(format!(
9350            "invalid BF16 row block columns {col_start}..{col_end} for input width {}",
9351            matrix.in_features
9352        ));
9353    }
9354    let mut bytes = Vec::with_capacity(matrix.out_features * block_cols * 2);
9355    for row in 0..matrix.out_features {
9356        let start = (row * matrix.in_features + col_start) * 2;
9357        bytes.extend_from_slice(&matrix.bytes[start..start + block_cols * 2]);
9358    }
9359    Ok(bytes)
9360}
9361
9362fn run_resident_bank_expert(
9363    engine: &Engine,
9364    bank: &ResidentE4m3ExpertBankRank,
9365    local_expert: usize,
9366    activations: &[f32],
9367    tokens: usize,
9368) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
9369    let _main = engine.gpu.enter_main()?;
9370    if bank.k_blocks.is_some() {
9371        return Err("block-major TP row bank requires canonical block execution".into());
9372    }
9373    let local_count = bank.expert_range.end - bank.expert_range.start;
9374    if local_expert >= local_count {
9375        return Err(format!(
9376            "local EP expert {local_expert} outside 0..{local_count} for range {:?}",
9377            bank.expert_range
9378        )
9379        .into());
9380    }
9381    validate_activations(activations, tokens, bank.in_features)?;
9382    let activations = engine.htod(activations)?;
9383    let weight = bank
9384        .codes
9385        .slice(local_expert * bank.code_stride..(local_expert + 1) * bank.code_stride);
9386    let scales = bank
9387        .scales
9388        .slice(local_expert * bank.scale_stride..(local_expert + 1) * bank.scale_stride);
9389    let input = activations.slice(0..activations.len());
9390    let output = engine.qmatvec_mmq_fp8_blk_view(
9391        &weight,
9392        &scales,
9393        &input,
9394        tokens,
9395        bank.in_features,
9396        bank.out_features,
9397    )?;
9398    engine.dtoh(&output)
9399}
9400
9401fn run_resident_bank_expert_block(
9402    engine: &Engine,
9403    bank: &ResidentE4m3ExpertBankRank,
9404    local_expert: usize,
9405    block: usize,
9406    activations: &[f32],
9407) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
9408    let _main = engine.gpu.enter_main()?;
9409    let local_count = bank.expert_range.end - bank.expert_range.start;
9410    if local_expert >= local_count {
9411        return Err(format!(
9412            "local TP expert {local_expert} outside 0..{local_count} for range {:?}",
9413            bank.expert_range
9414        )
9415        .into());
9416    }
9417    let blocks = bank
9418        .k_blocks
9419        .ok_or("TP row bank is not packed in native K-block order")?;
9420    if block >= blocks {
9421        return Err(format!("TP row block {block} outside 0..{blocks}").into());
9422    }
9423    validate_activations(activations, 1, FP8_BLOCK)?;
9424    let block_code_stride = bank.out_features * FP8_BLOCK;
9425    let block_scale_stride = bank.out_features.div_ceil(FP8_BLOCK);
9426    if bank.in_features != blocks * FP8_BLOCK
9427        || bank.code_stride != blocks * block_code_stride
9428        || bank.scale_stride != blocks * block_scale_stride
9429    {
9430        return Err("TP row bank block-major geometry is inconsistent".into());
9431    }
9432
9433    let expert_code_start = local_expert * bank.code_stride;
9434    let expert_scale_start = local_expert * bank.scale_stride;
9435    let weight = bank.codes.slice(
9436        expert_code_start + block * block_code_stride
9437            ..expert_code_start + (block + 1) * block_code_stride,
9438    );
9439    let scales = bank.scales.slice(
9440        expert_scale_start + block * block_scale_stride
9441            ..expert_scale_start + (block + 1) * block_scale_stride,
9442    );
9443    let activations = engine.htod(activations)?;
9444    let input = activations.slice(0..activations.len());
9445    let output = engine.qmatvec_mmq_fp8_blk_view(
9446        &weight,
9447        &scales,
9448        &input,
9449        1,
9450        FP8_BLOCK,
9451        bank.out_features,
9452    )?;
9453    engine.dtoh(&output)
9454}
9455
9456fn run_resident_bank_expert_device(
9457    engine: &Engine,
9458    bank: &ResidentE4m3ExpertBankRank,
9459    local_expert: usize,
9460    activations: &CudaSlice<f32>,
9461    tokens: usize,
9462) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
9463    let _main = engine.gpu.enter_main()?;
9464    if bank.k_blocks.is_some() {
9465        return Err("block-major TP row bank requires canonical block execution".into());
9466    }
9467    let local_count = bank.expert_range.end - bank.expert_range.start;
9468    if local_expert >= local_count {
9469        return Err(format!(
9470            "local TP expert {local_expert} outside 0..{local_count} for range {:?}",
9471            bank.expert_range
9472        )
9473        .into());
9474    }
9475    let expected = tokens
9476        .checked_mul(bank.in_features)
9477        .ok_or("native TP activation size overflow")?;
9478    if activations.len() != expected || activations.ordinal() != engine.ctx().ordinal() {
9479        return Err(format!(
9480            "native TP activation len/device {}/{} != expected {expected}/{}",
9481            activations.len(),
9482            activations.ordinal(),
9483            engine.ctx().ordinal()
9484        )
9485        .into());
9486    }
9487    let weight = bank
9488        .codes
9489        .slice(local_expert * bank.code_stride..(local_expert + 1) * bank.code_stride);
9490    let scales = bank
9491        .scales
9492        .slice(local_expert * bank.scale_stride..(local_expert + 1) * bank.scale_stride);
9493    let input = activations.slice(0..activations.len());
9494    engine.qmatvec_mmq_fp8_blk_view(
9495        &weight,
9496        &scales,
9497        &input,
9498        tokens,
9499        bank.in_features,
9500        bank.out_features,
9501    )
9502}
9503
9504fn run_resident_bank_expert_block_device(
9505    engine: &Engine,
9506    bank: &ResidentE4m3ExpertBankRank,
9507    local_expert: usize,
9508    block: usize,
9509    activations: &cudarc::driver::CudaView<'_, f32>,
9510) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
9511    let _main = engine.gpu.enter_main()?;
9512    let local_count = bank.expert_range.end - bank.expert_range.start;
9513    if local_expert >= local_count {
9514        return Err(format!(
9515            "local TP expert {local_expert} outside 0..{local_count} for range {:?}",
9516            bank.expert_range
9517        )
9518        .into());
9519    }
9520    let blocks = bank
9521        .k_blocks
9522        .ok_or("native TP row bank is not packed in checkpoint-block order")?;
9523    if block >= blocks {
9524        return Err(format!("native TP row block {block} outside 0..{blocks}").into());
9525    }
9526    let activation_device = activations.stream().context().ordinal();
9527    if activations.len() != FP8_BLOCK || activation_device != engine.ctx().ordinal() {
9528        return Err(format!(
9529            "native TP block activation len/device {}/{} != expected {FP8_BLOCK}/{}",
9530            activations.len(),
9531            activation_device,
9532            engine.ctx().ordinal()
9533        )
9534        .into());
9535    }
9536    let block_code_stride = bank.out_features * FP8_BLOCK;
9537    let block_scale_stride = bank.out_features.div_ceil(FP8_BLOCK);
9538    if bank.in_features != blocks * FP8_BLOCK
9539        || bank.code_stride != blocks * block_code_stride
9540        || bank.scale_stride != blocks * block_scale_stride
9541    {
9542        return Err("native TP row bank block-major geometry is inconsistent".into());
9543    }
9544    let expert_code_start = local_expert * bank.code_stride;
9545    let expert_scale_start = local_expert * bank.scale_stride;
9546    let weight = bank.codes.slice(
9547        expert_code_start + block * block_code_stride
9548            ..expert_code_start + (block + 1) * block_code_stride,
9549    );
9550    let scales = bank.scales.slice(
9551        expert_scale_start + block * block_scale_stride
9552            ..expert_scale_start + (block + 1) * block_scale_stride,
9553    );
9554    engine.qmatvec_mmq_fp8_blk_view(
9555        &weight,
9556        &scales,
9557        activations,
9558        1,
9559        FP8_BLOCK,
9560        bank.out_features,
9561    )
9562}
9563
9564/// Grant `accessor` the right to reach `owner`'s memory — BOTH halves of the grant, which is
9565/// the part every caller gets wrong exactly once:
9566///
9567///   1. `cuCtxEnablePeerAccess`, which covers legacy `cuMemAlloc` allocations, and
9568///   2. `cuMemPoolSetAccess` on `owner`'s DEFAULT MEMORY POOL, because
9569///      `cuCtxEnablePeerAccess` does NOT map STREAM-ORDERED POOL allocations and every
9570///      normal memra buffer is one (the same note `pp.rs:1543`/`pp.rs:1578` carries).
9571///
9572/// Extracted from [`configure_native_p2p`] (which now calls it per ordered pair) so a seam
9573/// holding two `&Engine` rather than a `&[Engine]` — the glm5 TP-2 runtime — reuses the exact
9574/// grant sequence instead of growing a second, drifting copy of it. Directed: call it once
9575/// per direction. Refuses by name when `cuDeviceCanAccessPeer` says the pair has no path,
9576/// which is the only honest answer: this card class is NOT uniformly peer-connected. Some
9577/// 8-GPU host classes present PEER ISLANDS OF TWO — every cross-island cell of a peer-transfer
9578/// matrix reads `N/A` — so a TP group placed across an island boundary has no peer path at all
9579/// and must either stay inside one island or go through host memory. The per-host island map is
9580/// fleet data and lives in the private deployment repo, never here; the engine's job is to
9581/// refuse by name rather than to know which host it is on.
9582pub(crate) fn grant_peer_access(
9583    accessor: &Engine,
9584    owner: &Engine,
9585    label: &str,
9586) -> Result<(), Box<dyn std::error::Error>> {
9587    let (a_dev, o_dev) = (accessor.ctx().ordinal(), owner.ctx().ordinal());
9588    let mut can_access = 0;
9589    unsafe {
9590        cudarc::driver::sys::cuDeviceCanAccessPeer(
9591            &mut can_access,
9592            accessor.ctx().cu_device(),
9593            owner.ctx().cu_device(),
9594        )
9595        .result()?;
9596    }
9597    if can_access == 0 {
9598        return Err(
9599            format!("{label} requires P2P, but dev{a_dev} cannot access dev{o_dev}").into(),
9600        );
9601    }
9602    accessor.ctx().bind_to_thread()?;
9603    let rc = unsafe { cudarc::driver::sys::cuCtxEnablePeerAccess(owner.ctx().cu_ctx(), 0) };
9604    use cudarc::driver::sys::cudaError_enum as E;
9605    if rc != E::CUDA_SUCCESS && rc != E::CUDA_ERROR_PEER_ACCESS_ALREADY_ENABLED {
9606        return Err(format!(
9607            "{label} cuCtxEnablePeerAccess(dev{a_dev} -> dev{o_dev}) failed: {rc:?}"
9608        )
9609        .into());
9610    }
9611    let device = cudarc::driver::result::device::get(o_dev as i32)?;
9612    let mut pool: cudarc::driver::sys::CUmemoryPool = std::ptr::null_mut();
9613    unsafe {
9614        cudarc::driver::sys::cuDeviceGetDefaultMemPool(&mut pool, device).result()?;
9615    }
9616    let desc = cudarc::driver::sys::CUmemAccessDesc {
9617        location: cudarc::driver::sys::CUmemLocation {
9618            type_: cudarc::driver::sys::CUmemLocationType::CU_MEM_LOCATION_TYPE_DEVICE,
9619            id: a_dev as i32,
9620        },
9621        flags: cudarc::driver::sys::CUmemAccess_flags::CU_MEM_ACCESS_FLAGS_PROT_READWRITE,
9622    };
9623    let rc = unsafe { cudarc::driver::sys::cuMemPoolSetAccess(pool, &desc, 1) };
9624    if rc != cudarc::driver::sys::cudaError_enum::CUDA_SUCCESS {
9625        return Err(format!(
9626            "{label} cuMemPoolSetAccess(dev{o_dev} pool -> dev{a_dev}) failed: {rc:?}"
9627        )
9628        .into());
9629    }
9630    Ok(())
9631}
9632
9633fn configure_native_p2p(
9634    ranks: &[Engine],
9635    devices: &[usize],
9636) -> Result<(), Box<dyn std::error::Error>> {
9637    if ranks.len() != devices.len() || ranks.len() < 2 {
9638        return Err("native TP P2P setup requires matching multi-rank devices".into());
9639    }
9640    for (rank, (&device, engine)) in devices.iter().zip(ranks).enumerate() {
9641        if engine.ctx().ordinal() != device {
9642            return Err(format!(
9643                "native TP rank {rank} context device {} != requested device {device}",
9644                engine.ctx().ordinal()
9645            )
9646            .into());
9647        }
9648    }
9649
9650    for src in 0..ranks.len() {
9651        for dst in 0..ranks.len() {
9652            if src == dst {
9653                continue;
9654            }
9655            grant_peer_access(&ranks[src], &ranks[dst], "native TP")?;
9656        }
9657    }
9658
9659    for src in 0..ranks.len() {
9660        for dst in 0..ranks.len() {
9661            if src == dst {
9662                continue;
9663            }
9664            for &words in NATIVE_P2P_PROBE_WORDS {
9665                let expected = (0..words)
9666                    .map(|index| {
9667                        (index as u32)
9668                            .wrapping_mul(0x9e37_79b9)
9669                            .wrapping_add(((src as u32) << 16) | dst as u32)
9670                    })
9671                    .collect::<Vec<_>>();
9672                let poison = expected.iter().map(|value| !value).collect::<Vec<_>>();
9673                let source = ranks[src].htod_u32_v(&expected)?;
9674                let mut destination = ranks[dst].htod_u32_v(&poison)?;
9675                ranks[dst].stream().memcpy_dtod(&source, &mut destination)?;
9676                let actual = ranks[dst].dtoh_u32(&destination)?;
9677                if actual != expected {
9678                    let mismatches = actual
9679                        .iter()
9680                        .zip(&expected)
9681                        .filter(|(actual, expected)| actual != expected)
9682                        .count();
9683                    return Err(format!(
9684                        "native TP peer probe dev{}->dev{} failed at {} bytes: \
9685                         {mismatches}/{} words differ",
9686                        devices[src],
9687                        devices[dst],
9688                        words * std::mem::size_of::<u32>(),
9689                        expected.len()
9690                    )
9691                    .into());
9692                }
9693            }
9694        }
9695    }
9696    ranks[0].ctx().bind_to_thread()?;
9697    eprintln!(
9698        "[tp] native peer byte-integrity probe PASS: devices={devices:?} \
9699         directions={} byte_ladder={:?} mismatches=0",
9700        ranks.len() * (ranks.len() - 1),
9701        NATIVE_P2P_PROBE_WORDS
9702            .iter()
9703            .map(|words| words * std::mem::size_of::<u32>())
9704            .collect::<Vec<_>>(),
9705    );
9706    Ok(())
9707}
9708
9709fn validate_activations(
9710    activations: &[f32],
9711    tokens: usize,
9712    in_features: usize,
9713) -> Result<(), String> {
9714    let expected = tokens
9715        .checked_mul(in_features)
9716        .ok_or_else(|| "activation size overflow".to_string())?;
9717    if activations.len() != expected {
9718        return Err(format!(
9719            "activation count {} != {tokens}x{in_features} ({expected})",
9720            activations.len()
9721        ));
9722    }
9723    if !activations.iter().all(|value| value.is_finite()) {
9724        return Err("activations contain a non-finite value".to_string());
9725    }
9726    Ok(())
9727}
9728
9729fn column_shard(
9730    matrix: E4m3BlockMatrix<'_>,
9731    tp: usize,
9732    rank: usize,
9733) -> Result<E4m3BlockMatrix<'_>, String> {
9734    let local_out = matrix.out_features / tp;
9735    let row_start = rank * local_out;
9736    let code_start = row_start * matrix.in_features;
9737    let code_end = code_start + local_out * matrix.in_features;
9738    let scale_cols = matrix.in_features.div_ceil(FP8_BLOCK);
9739    let local_scale_rows = local_out / FP8_BLOCK;
9740    let scale_start = rank * local_scale_rows * scale_cols;
9741    let scale_end = scale_start + local_scale_rows * scale_cols;
9742    Ok(E4m3BlockMatrix {
9743        codes: &matrix.codes[code_start..code_end],
9744        scales: &matrix.scales[scale_start..scale_end],
9745        out_features: local_out,
9746        in_features: matrix.in_features,
9747    })
9748}
9749
9750fn row_shard(
9751    matrix: E4m3BlockMatrix<'_>,
9752    tp: usize,
9753    rank: usize,
9754) -> Result<(Vec<u8>, Vec<f32>), String> {
9755    let local_in = matrix.in_features / tp;
9756    let col_start = rank * local_in;
9757    let mut codes = Vec::with_capacity(matrix.out_features * local_in);
9758    for row in 0..matrix.out_features {
9759        let start = row * matrix.in_features + col_start;
9760        codes.extend_from_slice(&matrix.codes[start..start + local_in]);
9761    }
9762
9763    let scale_rows = matrix.out_features.div_ceil(FP8_BLOCK);
9764    let scale_cols = matrix.in_features.div_ceil(FP8_BLOCK);
9765    let local_scale_cols = local_in / FP8_BLOCK;
9766    let scale_col_start = rank * local_scale_cols;
9767    let mut scales = Vec::with_capacity(scale_rows * local_scale_cols);
9768    for row in 0..scale_rows {
9769        let start = row * scale_cols + scale_col_start;
9770        scales.extend_from_slice(&matrix.scales[start..start + local_scale_cols]);
9771    }
9772    Ok((codes, scales))
9773}
9774
9775fn activation_shard(
9776    activations: &[f32],
9777    tokens: usize,
9778    in_features: usize,
9779    tp: usize,
9780    rank: usize,
9781) -> Vec<f32> {
9782    let local_in = in_features / tp;
9783    let col_start = rank * local_in;
9784    let mut shard = Vec::with_capacity(tokens * local_in);
9785    for token in 0..tokens {
9786        let start = token * in_features + col_start;
9787        shard.extend_from_slice(&activations[start..start + local_in]);
9788    }
9789    shard
9790}
9791
9792// ─── Step NVFP4 expert TP program (official Step-3.7-Flash-NVFP4 checkpoint class) ─────────────
9793//
9794// The routed experts of the NVFP4 checkpoint are modelopt-packed: e2m1 codes (2/byte), per-16
9795// UE4M3 sub-scales, and a per-EXPERT `weight_scale_2` f32 macro (~1e-5..1e-4, LOAD-BEARING).
9796// Rank compute repacks each shard host-side into memra block_nvfp4 rows (nibble reorder only —
9797// value-exact, see nvfp4_repack.rs) and runs the proven `qmatvec_nvfp4_fast` dp4a kernel; the
9798// activation q8_1 quantization uses per-32 blocks, and every shard cut here is 64-aligned, so a
9799// rank-local partial is bit-identical to the corresponding slice of the unsharded kernel.
9800//
9801// MACRO CANONICAL ORDER: the macro multiplies each assembled f32 output exactly ONCE — after the
9802// column gather (gate/up) and after the FULL row-parallel reduce (down), never per-partial.
9803// `(a + b) * m` and `a * m + b * m` differ in f32, so applying it per-rank would break the
9804// TP1-vs-TP2 bit gate. Every entry point below follows this order.
9805//
9806// TP2 shard legality is NVFP4-native: column parallelism splits whole output rows (scale rows
9807// ride along, nothing cuts), row parallelism splits input columns at 64-element superblock
9808// boundaries (16-element scale groups nest inside). The 128-block E4M3 constraint does not apply.
9809
9810/// One expert's modelopt NVFP4 projection: packed codes + per-16 UE4M3 scale bytes + macro.
9811#[derive(Clone, Copy)]
9812pub struct Nvfp4BlockMatrix<'a> {
9813    pub codes: &'a [u8],  // [out_features, in_features/2] packed e2m1, row-major
9814    pub scales: &'a [u8], // [out_features, in_features/16] UE4M3 bytes, row-major
9815    pub macro_scale: f32, // per-expert weight_scale_2 dequant multiplier
9816    pub out_features: usize,
9817    pub in_features: usize,
9818}
9819
9820impl Nvfp4BlockMatrix<'_> {
9821    pub fn validate(&self) -> Result<(), String> {
9822        if self.in_features == 0 || self.out_features == 0 {
9823            return Err("NVFP4 matrix has a zero dimension".to_string());
9824        }
9825        if !self.in_features.is_multiple_of(64) {
9826            return Err(format!(
9827                "NVFP4 in_features {} is not 64-aligned (memra block_nvfp4 superblock)",
9828                self.in_features
9829            ));
9830        }
9831        if self.codes.len() != self.out_features * self.in_features / 2 {
9832            return Err(format!(
9833                "NVFP4 code bytes {} != {}x{}/2",
9834                self.codes.len(),
9835                self.out_features,
9836                self.in_features
9837            ));
9838        }
9839        if self.scales.len() != self.out_features * self.in_features / 16 {
9840            return Err(format!(
9841                "NVFP4 scale bytes {} != {}x{}/16",
9842                self.scales.len(),
9843                self.out_features,
9844                self.in_features
9845            ));
9846        }
9847        if !self.macro_scale.is_finite() || self.macro_scale <= 0.0 {
9848            return Err(format!(
9849                "NVFP4 macro scale {} is not finite-positive",
9850                self.macro_scale
9851            ));
9852        }
9853        Ok(())
9854    }
9855}
9856
9857/// Stacked modelopt NVFP4 expert bank (host view over the checkpoint bytes).
9858#[derive(Clone, Copy)]
9859pub struct Nvfp4ExpertBank<'a> {
9860    pub codes: &'a [u8],   // [expert_count, out_features, in_features/2]
9861    pub scales: &'a [u8],  // [expert_count, out_features, in_features/16]
9862    pub macros: &'a [f32], // [expert_count] weight_scale_2
9863    pub expert_count: usize,
9864    pub out_features: usize,
9865    pub in_features: usize,
9866}
9867
9868impl Nvfp4ExpertBank<'_> {
9869    pub fn validate(&self) -> Result<(), String> {
9870        if self.expert_count == 0 {
9871            return Err("NVFP4 expert bank is empty".to_string());
9872        }
9873        if self.macros.len() != self.expert_count {
9874            return Err(format!(
9875                "NVFP4 bank macros {} != expert count {}",
9876                self.macros.len(),
9877                self.expert_count
9878            ));
9879        }
9880        self.expert(0).map(|_| ())
9881    }
9882
9883    pub fn expert(&self, expert: usize) -> Result<Nvfp4BlockMatrix<'_>, String> {
9884        if expert >= self.expert_count {
9885            return Err(format!("expert {expert} outside 0..{}", self.expert_count));
9886        }
9887        let code_stride = self.out_features * self.in_features / 2;
9888        let scale_stride = self.out_features * self.in_features / 16;
9889        if self.codes.len() != self.expert_count * code_stride
9890            || self.scales.len() != self.expert_count * scale_stride
9891        {
9892            return Err("NVFP4 bank byte extents do not match the declared geometry".to_string());
9893        }
9894        let matrix = Nvfp4BlockMatrix {
9895            codes: &self.codes[expert * code_stride..(expert + 1) * code_stride],
9896            scales: &self.scales[expert * scale_stride..(expert + 1) * scale_stride],
9897            macro_scale: self.macros[expert],
9898            out_features: self.out_features,
9899            in_features: self.in_features,
9900        };
9901        matrix.validate()?;
9902        Ok(matrix)
9903    }
9904}
9905
9906/// One rank's resident repacked NVFP4 shard: memra block_nvfp4 rows on device.
9907pub struct ResidentNvfp4Rank {
9908    blocks: crate::CudaSlice<u8>,
9909    macro_scale: f32,
9910    out_features: usize,
9911    in_features: usize,
9912    row_bytes: usize,
9913}
9914
9915pub struct ResidentNvfp4ColumnParallel {
9916    ranks: Vec<ResidentNvfp4Rank>,
9917    pub out_features: usize,
9918    pub in_features: usize,
9919}
9920
9921pub struct ResidentNvfp4RowParallel {
9922    ranks: Vec<ResidentNvfp4Rank>,
9923    pub out_features: usize,
9924    pub in_features: usize,
9925}
9926
9927pub struct ResidentTpNvfp4Expert {
9928    gate: ResidentNvfp4ColumnParallel,
9929    up: ResidentNvfp4ColumnParallel,
9930    down: ResidentNvfp4RowParallel,
9931    pub input_width: usize,
9932    pub expert_width: usize,
9933}
9934
9935/// One rank's resident NVFP4 expert bank shard: one repacked block buffer PER expert (per-expert
9936/// device allocations keep this increment off any new strided-kernel API; the strided twin is a
9937/// later perf rung, mirroring the FP8 bank's history).
9938pub struct ResidentNvfp4ColumnBankRank {
9939    /// Contiguous per-rank expert bank: `expert_count` repacked shards of `expert_bytes` each.
9940    /// Contiguity is what lets the device-routes program cover every selected expert with ONE
9941    /// launch (`qmatvec_nvfp4_dp4a_sel` indexes `sel[t] * expert_bytes`).
9942    bank: crate::CudaSlice<u8>,
9943    expert_bytes: usize,
9944    local_out: usize,
9945    in_features: usize,
9946    row_bytes: usize,
9947    /// TRUE when these bytes are the slot-major permutation (`nvfp4_matrix_v2_permute`) and the
9948    /// `_v2` readers must be used; FALSE when they are block_nvfp4 v1. Recorded at BUILD from
9949    /// `ep2 || bank_slot_major_on()` and never re-derived: the layout travels with the pointer,
9950    /// so no reader can consult an env door that disagrees with the resident bytes. Feeding v1
9951    /// bytes to a `_v2` reader (or the reverse) is a garbage-output bug, and the 2026-08-29
9952    /// step37 incident was its neighbour — a piece of layout geometry a caller failed to supply.
9953    slot_major: bool,
9954}
9955
9956impl ResidentNvfp4ColumnBankRank {
9957    /// THE host-canonical reader for this bank, selected from the layout the bank RECORDS. One
9958    /// place maps layout -> reader for the column banks; every oracle goes through it, so a new
9959    /// producer cannot leave a reader behind (the failure mode that put v1 bytes under a `_v2`
9960    /// reader, called out in the `run_tensor_parallel_routes_nvfp4_prime_grouped` receipt).
9961    fn host_canonical_expert(
9962        &self,
9963        engine: &Engine,
9964        expert: usize,
9965        activations: &crate::CudaSlice<f32>,
9966    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
9967        let w = self.expert(expert);
9968        if self.slot_major {
9969            engine.qmatvec_nvfp4_fast_v2(
9970                &w,
9971                activations,
9972                1,
9973                self.in_features,
9974                self.local_out,
9975                self.row_bytes,
9976            )
9977        } else {
9978            engine.qmatvec_nvfp4_fast(
9979                &w,
9980                activations,
9981                1,
9982                self.in_features,
9983                self.local_out,
9984                self.row_bytes,
9985            )
9986        }
9987    }
9988
9989    fn expert(&self, index: usize) -> cudarc::driver::CudaView<'_, u8> {
9990        self.bank
9991            .slice(index * self.expert_bytes..(index + 1) * self.expert_bytes)
9992    }
9993}
9994
9995/// Canonical row-shard count for the NVFP4 down projection. The down reduction ALWAYS executes
9996/// as exactly this many input-column windows summed in shard order, at every world size: a
9997/// single full-width dot and a two-half-dots-plus-add differ in f32 parenthesization, so pinning
9998/// the shard grid (not the world size) is what makes the TP1-oracle-vs-TP2 bit gate meaningful.
9999/// This is the NVFP4 twin of the FP8 bank's canonical checkpoint-block reduction.
10000pub const NVFP4_CANONICAL_ROW_SHARDS: usize = 2;
10001
10002pub struct ResidentNvfp4RowBankRank {
10003    /// Contiguous per-shard expert bank (see `ResidentNvfp4ColumnBankRank::bank`).
10004    bank: crate::CudaSlice<u8>,
10005    expert_bytes: usize,
10006    device_rank: usize, // index into the runtime's rank engines this canonical shard lives on
10007    out_features: usize,
10008    local_in: usize,
10009    row_bytes: usize,
10010    /// Slot-major layout marker — see `ResidentNvfp4ColumnBankRank::slot_major`.
10011    slot_major: bool,
10012}
10013
10014impl ResidentNvfp4RowBankRank {
10015    /// THE host-canonical reader for this down shard — see
10016    /// `ResidentNvfp4ColumnBankRank::host_canonical_expert`.
10017    fn host_canonical_expert(
10018        &self,
10019        engine: &Engine,
10020        expert: usize,
10021        activations: &crate::CudaSlice<f32>,
10022    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
10023        let w = self.expert(expert);
10024        if self.slot_major {
10025            engine.qmatvec_nvfp4_fast_v2(
10026                &w,
10027                activations,
10028                1,
10029                self.local_in,
10030                self.out_features,
10031                self.row_bytes,
10032            )
10033        } else {
10034            engine.qmatvec_nvfp4_fast(
10035                &w,
10036                activations,
10037                1,
10038                self.local_in,
10039                self.out_features,
10040                self.row_bytes,
10041            )
10042        }
10043    }
10044
10045    fn expert(&self, index: usize) -> cudarc::driver::CudaView<'_, u8> {
10046        self.bank
10047            .slice(index * self.expert_bytes..(index + 1) * self.expert_bytes)
10048    }
10049}
10050
10051impl ResidentNvfp4TensorParallel {
10052    pub(crate) fn device_workspace_handle(
10053        &self,
10054    ) -> &std::sync::Mutex<Option<Nvfp4DeviceRoutesWorkspace>> {
10055        &self.device_workspace
10056    }
10057}
10058
10059pub struct ResidentNvfp4TensorParallel {
10060    gate: Vec<ResidentNvfp4ColumnBankRank>,
10061    up: Vec<ResidentNvfp4ColumnBankRank>,
10062    down: Vec<ResidentNvfp4RowBankRank>,
10063    macros_gate: Vec<f32>,
10064    macros_up: Vec<f32>,
10065    macros_down: Vec<f32>,
10066    /// Per-rank device copies of the gate/up macro-scales (E f32 each), indexed by the
10067    /// batched SwiGLU kernel via the selection array. Down macros stay host-side — they fold
10068    /// into the route-weight axpy scalar.
10069    macros_gate_dev: Vec<crate::CudaSlice<f32>>,
10070    macros_up_dev: Vec<crate::CudaSlice<f32>>,
10071    macros_down_dev: Vec<crate::CudaSlice<f32>>,
10072    pub expert_count: usize,
10073    pub input_width: usize,
10074    pub expert_width: usize,
10075    /// Lazily-built persistent decode workspace (device routes program). Interior mutability
10076    /// mirrors StepEpGroupedDecode: the forward holds the bank behind a shared reference.
10077    device_workspace: std::sync::Mutex<Option<Nvfp4DeviceRoutesWorkspace>>,
10078    /// Grouped-prime per-rank slot-major pointer tables (gate/up/down x n_expert), built once.
10079    /// The banks are resident and never move, so rebuilding + re-uploading 3*n_expert u64s per
10080    /// rank per LAYER was pure per-call host churn on the prime path.
10081    prime_tables: std::sync::Mutex<Vec<crate::CudaSlice<u64>>>,
10082    /// MEMRA_STEP_NVFP4_EP2: the rank banks above hold WHOLE experts (owner = id & 1,
10083    /// slot = id >> 1) at full width instead of TP shards. Consumers must branch on this;
10084    /// shard-semantics paths refuse loudly.
10085    pub(crate) ep2: bool,
10086}
10087
10088/// Persistent per-call device buffers for the NVFP4 device routes program: one gate/up output,
10089/// one down partial, and one shard accumulator per rank, plus root combine staging. Reused every
10090/// (token, layer) call so the decode loop performs zero output allocations.
10091/// A stitched multi-device parent graph for one layer's device-routed expert program, plus
10092/// the children it was built from (retained: AddChildGraphNode clones, but the probe retains
10093/// conservatively) and the persistent e-context input staging its copies read.
10094struct RoutesGraph {
10095    exec: cudarc::driver::sys::CUgraphExec,
10096    parent: cudarc::driver::sys::CUgraph,
10097    _children: Vec<cudarc::driver::CudaGraph>,
10098}
10099// SAFETY: the raw handles are only used from the single decode thread; CUDA graph handles are
10100// context-agnostic process handles.
10101unsafe impl Send for RoutesGraph {}
10102
10103impl Drop for RoutesGraph {
10104    fn drop(&mut self) {
10105        unsafe {
10106            let _ = cudarc::driver::sys::cuGraphExecDestroy(self.exec);
10107            let _ = cudarc::driver::sys::cuGraphDestroy(self.parent);
10108        }
10109    }
10110}
10111
10112impl Nvfp4DeviceRoutesWorkspace {
10113    pub(crate) fn in_stage_handle(&self) -> Option<&crate::CudaSlice<f32>> {
10114        self.in_stage_e.as_ref()
10115    }
10116    pub(crate) fn in_stage_mut(&mut self) -> Option<&mut crate::CudaSlice<f32>> {
10117        self.in_stage_e.as_mut()
10118    }
10119    #[allow(dead_code)] // allow: accessor twin of in_stage_mut; kept for the workspace API symmetry
10120    pub(crate) fn out_stage_mut(&mut self) -> Option<&mut crate::CudaSlice<f32>> {
10121        self.out_stage_e.as_mut()
10122    }
10123    /// Arm the e-context stages + router staging pair when absent (token-graph entry).
10124    pub(crate) fn arm_stages(
10125        &mut self,
10126        e: &Engine,
10127        width: usize,
10128        n_sel: usize,
10129    ) -> Result<(), Box<dyn std::error::Error>> {
10130        let _main = e.gpu.enter_main()?;
10131        if self.in_stage_e.is_none() {
10132            self.in_stage_e = Some(e.htod(&vec![0.0f32; width])?);
10133            self.out_stage_e = Some(e.htod(&vec![0.0f32; width])?);
10134        }
10135        if self.dev_route_e.is_none() {
10136            self.dev_route_e = Some((
10137                e.htod_i32(&vec![0i32; n_sel])?,
10138                e.htod(&vec![0.0f32; n_sel])?,
10139            ));
10140        }
10141        Ok(())
10142    }
10143
10144    /// Split-borrow: the routes input (shared) + output (mut) stages together.
10145    pub(crate) fn in_and_out_stages_mut(
10146        &mut self,
10147    ) -> Option<(&crate::CudaSlice<f32>, &mut crate::CudaSlice<f32>)> {
10148        match (self.in_stage_e.as_ref(), self.out_stage_e.as_mut()) {
10149            (Some(input), Some(output)) => Some((input, output)),
10150            _ => None,
10151        }
10152    }
10153    pub(crate) fn dev_route_e_mut(
10154        &mut self,
10155    ) -> Option<(&mut crate::CudaSlice<i32>, &mut crate::CudaSlice<f32>)> {
10156        self.dev_route_e.as_mut().map(|(a, b)| (a, b))
10157    }
10158}
10159
10160pub struct Nvfp4DeviceRoutesWorkspace {
10161    /// [n_sel, local_out] batched gate/up outputs and the SwiGLU q8_1 pair; [n_sel, width]
10162    /// down partials. Sized for `n_sel` selected experts per token (pinned at first call).
10163    gate_out: Vec<crate::CudaSlice<f32>>,
10164    up_out: Vec<crate::CudaSlice<f32>>,
10165    act_q: Vec<crate::CudaSlice<i8>>,
10166    act_d: Vec<crate::CudaSlice<f32>>,
10167    sel: Vec<crate::CudaSlice<i32>>,
10168    partial: Vec<crate::CudaSlice<f32>>,
10169    accumulator: Vec<crate::CudaSlice<f32>>,
10170    /// Per-rank folded combine weights (route_weight x down macro), one htod per call.
10171    combine_w: Vec<crate::CudaSlice<f32>>,
10172    /// Device-routed extension: per-rank raw route weights (the down-macro fold happens
10173    /// in-kernel via sel + macros_down_dev).
10174    route_w: Vec<crate::CudaSlice<f32>>,
10175    /// Persistent q8_1 pair of the shared layer input (one quantize per rank per call, no
10176    /// per-call allocation).
10177    in_q: Vec<crate::CudaSlice<i8>>,
10178    in_d: Vec<crate::CudaSlice<f32>>,
10179    /// e-context staging for the device router outputs (persistent — rank streams peer-read
10180    /// them, so the router's fresh outputs are copied here on e's stream first; the pp.rs
10181    /// never-free discipline).
10182    dev_route_e: Option<(crate::CudaSlice<i32>, crate::CudaSlice<f32>)>,
10183    /// Prestage door state: input pull + quantize already issued for this layer's call
10184    /// (nvfp4_routes_prestage), so the routed run skips them. Reset per call.
10185    prestaged: bool,
10186    /// Peer-router door state: rank1's sel/route_w were computed locally in prestage;
10187    /// the routed run skips rank1's sel pull. Reset per call.
10188    rank1_routed: bool,
10189    /// Doorbell fences (MEMRA_FENCE_MEMOPS): raw cuMemAlloc'd [rank1_flag, root_flag]
10190    /// u32 pair in ROOT memory (async-pool memory is memop-INELIGIBLE — receipted
10191    /// CUDA_ERROR_INVALID_VALUE) + the host-side monotonic ticket. 0 = unarmed.
10192    fence_flags_raw: u64,
10193    fence_ticket: u32,
10194    /// Prestage input fence, recorded on e after the input's producer.
10195    ev_input: Option<(CudaEvent, usize)>,
10196    /// Graph-door staging: persistent e-context input row + output row (fixed addresses the
10197    /// captured copies read/write), and the per-layer stitched parent.
10198    in_stage_e: Option<crate::CudaSlice<f32>>,
10199    out_stage_e: Option<crate::CudaSlice<f32>>,
10200    routes_graph: Option<RoutesGraph>,
10201    /// Token-graph raw pointer sets (armed once by routes_arm_raw).
10202    raw_dev_route_e: Option<(u64, u64)>,
10203    raw_combine: Option<(u64, u64, u64, u64)>,
10204    raw_input: Vec<u64>,
10205    raw_sel: Vec<u64>,
10206    raw_route_w: Vec<u64>,
10207    remote: crate::CudaSlice<f32>,
10208    combined: crate::CudaSlice<f32>,
10209    n_sel: usize,
10210    /// Device-IO extension (lazily built by `run_tensor_parallel_routes_nvfp4_device_io`):
10211    /// persistent per-rank input rows plus the evented ordering pair — the pp.rs
10212    /// BoundarySlot discipline, same as the v2 attention workspace.
10213    input: Vec<crate::CudaSlice<f32>>,
10214    ev_rank: Vec<CudaEvent>,
10215    ev_done: Option<CudaEvent>,
10216    ev_entry: Option<(CudaEvent, usize)>,
10217}
10218
10219/// One rank's whole-expert NVFP4 residency (expert-parallel ownership).
10220struct ResidentNvfp4EpRank {
10221    gate: crate::CudaSlice<u8>,
10222    up: crate::CudaSlice<u8>,
10223    down: crate::CudaSlice<u8>,
10224    gate_expert_bytes: usize,
10225    down_expert_bytes: usize,
10226    macros_gate: crate::CudaSlice<f32>,
10227    macros_up: crate::CudaSlice<f32>,
10228    macros_down: crate::CudaSlice<f32>,
10229    expert_range: Range<usize>,
10230}
10231
10232struct Nvfp4EpDeviceWorkspace {
10233    input: Vec<crate::CudaSlice<f32>>,
10234    input_bf16: Vec<crate::CudaSlice<u8>>,
10235    input_q8: Vec<crate::CudaSlice<i8>>,
10236    input_q8_scales: Vec<crate::CudaSlice<f32>>,
10237    sel: Vec<crate::CudaSlice<i32>>,
10238    token_rows: Vec<crate::CudaSlice<i32>>,
10239    global_pairs: Vec<crate::CudaSlice<i32>>,
10240    route_w: Vec<crate::CudaSlice<f32>>,
10241    gate_out: Vec<crate::CudaSlice<f32>>,
10242    up_out: Vec<crate::CudaSlice<f32>>,
10243    activation_bf16: Vec<crate::CudaSlice<u8>>,
10244    activation_q8: Vec<crate::CudaSlice<i8>>,
10245    activation_q8_scales: Vec<crate::CudaSlice<f32>>,
10246    slot_rows: crate::CudaSlice<f32>,
10247    slot_rows_raw: u64,
10248    route_weights: crate::CudaSlice<f32>,
10249    graph_input: crate::CudaSlice<f32>,
10250    graph_output: crate::CudaSlice<f32>,
10251    graph_routes: Option<(u64, u64)>,
10252    graphs: Vec<Option<RoutesGraph>>,
10253    ev_entry: CudaEvent,
10254    ev_entry_device: usize,
10255    ev_rank: Vec<CudaEvent>,
10256    phase_events: Option<Nvfp4EpPhaseEvents>,
10257    capacity_tokens: usize,
10258    experts_per_token: usize,
10259}
10260
10261struct Nvfp4EpPhaseEvents {
10262    head: Vec<CudaEvent>,
10263    copy_done: Vec<CudaEvent>,
10264    gate_up_done: Vec<CudaEvent>,
10265    activation_done: Vec<CudaEvent>,
10266    down_done: Vec<CudaEvent>,
10267}
10268
10269pub(crate) const NVFP4_EP_DEVICE_BATCH_CAP: usize = 128;
10270pub(crate) const NVFP4_EP_DEVICE_ROUTER_BATCH_CAP: usize = 32;
10271pub(crate) const NVFP4_EP_Q8_BATCH_CAP: usize = 32;
10272const NVFP4_EP_GRAPH_BATCH_CAP: usize = 1;
10273
10274fn nvfp4_ep_active_input_values(
10275    input_values: usize,
10276    tokens: usize,
10277    input_width: usize,
10278) -> Result<usize, String> {
10279    if !(1..=NVFP4_EP_DEVICE_BATCH_CAP).contains(&tokens) {
10280        return Err(format!(
10281            "W4A16 NVFP4 device EP batch {tokens} is outside 1..={NVFP4_EP_DEVICE_BATCH_CAP}"
10282        ));
10283    }
10284    let active_values = tokens
10285        .checked_mul(input_width)
10286        .ok_or("W4A16 NVFP4 device EP active input size overflows usize")?;
10287    if input_values < active_values {
10288        return Err(format!(
10289            "W4A16 NVFP4 device EP input {input_values} is smaller than active \
10290             tokens {tokens} x width {input_width} ({active_values})"
10291        ));
10292    }
10293    Ok(active_values)
10294}
10295
10296pub struct ResidentNvfp4ExpertParallel {
10297    ranks: Vec<ResidentNvfp4EpRank>,
10298    macros_gate: Vec<f32>,
10299    macros_up: Vec<f32>,
10300    macros_down: Vec<f32>,
10301    pub expert_count: usize,
10302    pub input_width: usize,
10303    pub expert_width: usize,
10304    gate_row_bytes: usize,
10305    down_row_bytes: usize,
10306    device_workspace: std::sync::Mutex<Option<Nvfp4EpDeviceWorkspace>>,
10307}
10308
10309fn nvfp4_repack_matrix(matrix: Nvfp4BlockMatrix<'_>) -> Vec<u8> {
10310    memra_gguf::nvfp4_repack::repack_modelopt_to_gguf(
10311        matrix.codes,
10312        matrix.scales,
10313        matrix.out_features,
10314        matrix.in_features,
10315    )
10316}
10317
10318fn nvfp4_row_bytes(in_features: usize) -> usize {
10319    in_features / 64 * 36 // memra block_nvfp4: 64 elems -> 36 bytes (4 UE4M3 + 32 packed e2m1)
10320}
10321
10322/// MEMRA_NO_LOCAL_SHADOW=1: skip the per-layer local-KV shadow gathers and appends in the
10323/// eager v2 decode (lengths still advance) — the graph door proved contents-stale local KV
10324/// is decode-identical (12/12). The local contents feed spec/MTP scratch only.
10325/// MEMRA_FUSE_ROPE_APPEND=1: fuse qk norms + rope + dcw KV append + len inc into one
10326/// launch per rank per layer (bit-identical; identity-gated). dcw path only.
10327pub(crate) fn fuse_rope_append_on() -> bool {
10328    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
10329    *ON.get_or_init(|| std::env::var("MEMRA_FUSE_ROPE_APPEND").as_deref() == Ok("1"))
10330}
10331
10332pub(crate) fn no_local_shadow_on() -> bool {
10333    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
10334    *ON.get_or_init(|| std::env::var("MEMRA_NO_LOCAL_SHADOW").as_deref() == Ok("1"))
10335}
10336
10337/// Permute one repacked block_nvfp4 matrix (out_features rows of `nvfp4_row_bytes(in_f)`)
10338/// into the slot-major row layout the EP2 kernels read: per row, slot g's 16 qs bytes at
10339/// g*16, then the two UE4M3 scale bytes per slot at nslots*16 + g*2. Row byte count
10340/// unchanged. This layout USED to be an env door (`MEMRA_NVFP4_BANK_V2`, removed 2026-08-29
10341/// after its ON arm changed generated text in serving, see
10342/// research/step37-bankv2-removal-20260829); it survives ONLY as the fixed layout of the
10343/// EP2 whole-expert banks, whose `*_ep` kernels read it unconditionally.
10344///
10345/// PUBLIC because it is the SINGLE SOURCE OF TRUTH for this byte map. Every reader — the
10346/// `*_ep` decode kernels, `kq_fetch<QT_NVFP4_V2>` in the grouped GEMM,
10347/// `dequant_nvfp4v2_f16_kernel` — is defined as "reads what this function writes", and the
10348/// `nvfp4-bank-oracle` bin is what proves it, on device, per kernel arm. Do not reimplement
10349/// the map anywhere: the two failures that appeared only on v2 readers were geometry-plumbing
10350/// bugs around a byte map that was itself correct in two separate places. The layout was
10351/// innocent; one live failure was the grouped-prefill sktail call site defaulting `in_f` to zero.
10352pub fn nvfp4_matrix_v2_permute(v1: &[u8], out_features: usize, in_features: usize) -> Vec<u8> {
10353    // The output row is n_slots*18 bytes; the stride every reader uses is
10354    // nvfp4_row_bytes(in_features) = (in_features/64)*36. Those are equal only when
10355    // in_features is a whole number of 64-element superblocks. At in_features % 64 == 32 the
10356    // permute would silently emit a LONGER row than the stride and every row after row 0
10357    // would be read at the wrong offset, so refuse instead of trusting the caller.
10358    assert_eq!(
10359        in_features % 64,
10360        0,
10361        "v2 permute needs whole 64-element superblocks, got in_features={in_features}"
10362    );
10363    let row_bytes = nvfp4_row_bytes(in_features);
10364    assert_eq!(v1.len(), out_features * row_bytes, "v2 permute geometry");
10365    let n_slots = in_features / 32;
10366    let mut out = Vec::with_capacity(v1.len());
10367    for row in 0..out_features {
10368        let r = &v1[row * row_bytes..(row + 1) * row_bytes];
10369        for g in 0..n_slots {
10370            let (sblk, h) = (g / 2, g % 2);
10371            let b = &r[sblk * 36..sblk * 36 + 36];
10372            out.extend_from_slice(&b[4 + 16 * h..4 + 16 * h + 16]);
10373        }
10374        for g in 0..n_slots {
10375            let (sblk, h) = (g / 2, g % 2);
10376            let b = &r[sblk * 36..sblk * 36 + 36];
10377            out.push(b[2 * h]);
10378            out.push(b[2 * h + 1]);
10379        }
10380    }
10381    out
10382}
10383
10384/// Repack one expert shard for the contiguous banks. `slot_major` is true ONLY for the EP2
10385/// whole-expert banks, whose `*_ep` kernels read the slot-major permutation; the TP
10386/// column/row shard banks stay in the block_nvfp4 v1 layout every other kernel reads.
10387fn nvfp4_repack_bank_matrix(matrix: Nvfp4BlockMatrix<'_>, slot_major: bool) -> Vec<u8> {
10388    let (out_features, in_features) = (matrix.out_features, matrix.in_features);
10389    let v1 = nvfp4_repack_matrix(matrix);
10390    if slot_major {
10391        nvfp4_matrix_v2_permute(&v1, out_features, in_features)
10392    } else {
10393        v1
10394    }
10395}
10396
10397/// Column shard: whole output rows per rank (codes and scales are row-major, so both slices are
10398/// contiguous borrows). The macro rides unchanged — it is applied post-gather by the caller.
10399#[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
10400fn nvfp4_column_shard<'a>(
10401    matrix: Nvfp4BlockMatrix<'a>,
10402    tp: usize,
10403    rank: usize,
10404) -> Result<Nvfp4BlockMatrix<'a>, String> {
10405    if matrix.out_features % tp != 0 {
10406        return Err(format!(
10407            "NVFP4 column-parallel out_features {} is not divisible by TP={tp}",
10408            matrix.out_features
10409        ));
10410    }
10411    let local_out = matrix.out_features / tp;
10412    let code_row = matrix.in_features / 2;
10413    let scale_row = matrix.in_features / 16;
10414    Ok(Nvfp4BlockMatrix {
10415        codes: &matrix.codes[rank * local_out * code_row..(rank + 1) * local_out * code_row],
10416        scales: &matrix.scales[rank * local_out * scale_row..(rank + 1) * local_out * scale_row],
10417        macro_scale: matrix.macro_scale,
10418        out_features: local_out,
10419        in_features: matrix.in_features,
10420    })
10421}
10422
10423/// Row shard: input-column windows per rank, 64-superblock aligned. Owned buffers: each output
10424/// row contributes one contiguous byte window, gathered across rows.
10425#[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
10426fn nvfp4_row_shard(
10427    matrix: Nvfp4BlockMatrix<'_>,
10428    tp: usize,
10429    rank: usize,
10430) -> Result<(Vec<u8>, Vec<u8>, usize), String> {
10431    if matrix.in_features % tp != 0 {
10432        return Err(format!(
10433            "NVFP4 row-parallel in_features {} is not divisible by TP={tp}",
10434            matrix.in_features
10435        ));
10436    }
10437    let local_in = matrix.in_features / tp;
10438    if !local_in.is_multiple_of(64) {
10439        return Err(format!(
10440            "NVFP4 row-parallel input shard {local_in} cuts through a 64-element superblock"
10441        ));
10442    }
10443    let code_row = matrix.in_features / 2;
10444    let scale_row = matrix.in_features / 16;
10445    let local_code = local_in / 2;
10446    let local_scale = local_in / 16;
10447    let mut codes = Vec::with_capacity(matrix.out_features * local_code);
10448    let mut scales = Vec::with_capacity(matrix.out_features * local_scale);
10449    for row in 0..matrix.out_features {
10450        let code_start = row * code_row + rank * local_code;
10451        codes.extend_from_slice(&matrix.codes[code_start..code_start + local_code]);
10452        let scale_start = row * scale_row + rank * local_scale;
10453        scales.extend_from_slice(&matrix.scales[scale_start..scale_start + local_scale]);
10454    }
10455    Ok((codes, scales, local_in))
10456}
10457
10458/// Rank compute leaf: repack modelopt -> block_nvfp4, upload, run the proven dp4a kernel. The
10459/// macro is NOT applied here — callers apply it once at the canonical post-gather/post-reduce
10460/// point (see the section header).
10461fn run_rank_nvfp4(
10462    engine: &Engine,
10463    matrix: Nvfp4BlockMatrix<'_>,
10464    activations: &[f32],
10465    tokens: usize,
10466) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10467    matrix.validate()?;
10468    validate_activations(activations, tokens, matrix.in_features)?;
10469    let _main = engine.gpu.enter_main()?;
10470    let blocks = engine.htod_bytes(&nvfp4_repack_matrix(matrix))?;
10471    let activations = engine.htod(activations)?;
10472    let output = engine.qmatvec_nvfp4_fast(
10473        &blocks.slice(0..blocks.len()),
10474        &activations,
10475        tokens,
10476        matrix.in_features,
10477        matrix.out_features,
10478        nvfp4_row_bytes(matrix.in_features),
10479    )?;
10480    engine.dtoh(&output)
10481}
10482
10483fn upload_rank_nvfp4(
10484    engine: &Engine,
10485    matrix: Nvfp4BlockMatrix<'_>,
10486) -> Result<ResidentNvfp4Rank, Box<dyn std::error::Error>> {
10487    matrix.validate()?;
10488    let _main = engine.gpu.enter_main()?;
10489    Ok(ResidentNvfp4Rank {
10490        blocks: engine.htod_bytes(&nvfp4_repack_matrix(matrix))?,
10491        macro_scale: matrix.macro_scale,
10492        out_features: matrix.out_features,
10493        in_features: matrix.in_features,
10494        row_bytes: nvfp4_row_bytes(matrix.in_features),
10495    })
10496}
10497
10498fn run_resident_rank_nvfp4(
10499    engine: &Engine,
10500    rank: &ResidentNvfp4Rank,
10501    activations: &[f32],
10502    tokens: usize,
10503) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10504    validate_activations(activations, tokens, rank.in_features)?;
10505    let _main = engine.gpu.enter_main()?;
10506    let activations = engine.htod(activations)?;
10507    let output = engine.qmatvec_nvfp4_fast(
10508        &rank.blocks.slice(0..rank.blocks.len()),
10509        &activations,
10510        tokens,
10511        rank.in_features,
10512        rank.out_features,
10513        rank.row_bytes,
10514    )?;
10515    engine.dtoh(&output)
10516}
10517
10518fn apply_macro(values: &mut [f32], macro_scale: f32) {
10519    for value in values.iter_mut() {
10520        *value *= macro_scale;
10521    }
10522}
10523
10524impl TpE4m3HostBounce {
10525    /// Unsharded NVFP4 projection on rank 0 (compatibility oracle). Macro applied post-kernel.
10526    pub fn full_nvfp4(
10527        &self,
10528        matrix: Nvfp4BlockMatrix<'_>,
10529        activations: &[f32],
10530        tokens: usize,
10531    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10532        let mut output = run_rank_nvfp4(&self.ranks[0], matrix, activations, tokens)?;
10533        apply_macro(&mut output, matrix.macro_scale);
10534        Ok(output)
10535    }
10536
10537    /// Column-parallel NVFP4 projection: output rows partition across ranks, host gather in rank
10538    /// order, macro applied ONCE post-gather.
10539    pub fn column_parallel_nvfp4(
10540        &self,
10541        matrix: Nvfp4BlockMatrix<'_>,
10542        activations: &[f32],
10543        tokens: usize,
10544    ) -> Result<ColumnParallelResult, Box<dyn std::error::Error>> {
10545        matrix.validate()?;
10546        validate_activations(activations, tokens, matrix.in_features)?;
10547        let tp = self.ranks.len();
10548        let local_out = matrix.out_features / tp;
10549        let mut gathered = vec![0.0f32; tokens * matrix.out_features];
10550        let mut rank_outputs = Vec::with_capacity(tp);
10551        for (rank_index, rank) in self.ranks.iter().enumerate() {
10552            let shard = nvfp4_column_shard(matrix, tp, rank_index)?;
10553            let output = run_rank_nvfp4(rank, shard, activations, tokens)?;
10554            let row_start = rank_index * local_out;
10555            for token in 0..tokens {
10556                gathered[token * matrix.out_features + row_start
10557                    ..token * matrix.out_features + row_start + local_out]
10558                    .copy_from_slice(&output[token * local_out..(token + 1) * local_out]);
10559            }
10560            rank_outputs.push(output);
10561        }
10562        apply_macro(&mut gathered, matrix.macro_scale);
10563        Ok(ColumnParallelResult {
10564            gathered,
10565            rank_outputs,
10566        })
10567    }
10568
10569    /// Row-parallel NVFP4 projection: input columns partition at 64-superblock boundaries,
10570    /// rank-local partials reduce in stable rank order, macro applied ONCE post-reduce.
10571    pub fn row_parallel_nvfp4(
10572        &self,
10573        matrix: Nvfp4BlockMatrix<'_>,
10574        activations: &[f32],
10575        tokens: usize,
10576    ) -> Result<RowParallelResult, Box<dyn std::error::Error>> {
10577        matrix.validate()?;
10578        validate_activations(activations, tokens, matrix.in_features)?;
10579        let tp = self.ranks.len();
10580        let mut reduced = vec![0.0f32; tokens * matrix.out_features];
10581        let mut rank_partials = Vec::with_capacity(tp);
10582        for (rank_index, rank) in self.ranks.iter().enumerate() {
10583            let (codes, scales, local_in) = nvfp4_row_shard(matrix, tp, rank_index)?;
10584            let local_activations =
10585                activation_shard(activations, tokens, matrix.in_features, tp, rank_index);
10586            let shard = Nvfp4BlockMatrix {
10587                codes: &codes,
10588                scales: &scales,
10589                macro_scale: matrix.macro_scale,
10590                out_features: matrix.out_features,
10591                in_features: local_in,
10592            };
10593            let partial = run_rank_nvfp4(rank, shard, &local_activations, tokens)?;
10594            for (sum, value) in reduced.iter_mut().zip(&partial) {
10595                *sum += *value;
10596            }
10597            rank_partials.push(partial);
10598        }
10599        apply_macro(&mut reduced, matrix.macro_scale);
10600        Ok(RowParallelResult {
10601            reduced,
10602            rank_partials,
10603        })
10604    }
10605
10606    pub fn upload_expert_nvfp4(
10607        &self,
10608        gate: Nvfp4BlockMatrix<'_>,
10609        up: Nvfp4BlockMatrix<'_>,
10610        down: Nvfp4BlockMatrix<'_>,
10611    ) -> Result<ResidentTpNvfp4Expert, Box<dyn std::error::Error>> {
10612        if gate.in_features != up.in_features || gate.out_features != up.out_features {
10613            return Err("NVFP4 TP expert gate/up dimensions differ".into());
10614        }
10615        if down.in_features != gate.out_features || down.out_features != gate.in_features {
10616            return Err(format!(
10617                "NVFP4 TP expert down {}x{} does not invert gate/up {}x{}",
10618                down.out_features, down.in_features, gate.out_features, gate.in_features
10619            )
10620            .into());
10621        }
10622        let tp = self.ranks.len();
10623        let mut gate_ranks = Vec::with_capacity(tp);
10624        let mut up_ranks = Vec::with_capacity(tp);
10625        let mut down_ranks = Vec::with_capacity(tp);
10626        for (rank_index, engine) in self.ranks.iter().enumerate() {
10627            gate_ranks.push(upload_rank_nvfp4(
10628                engine,
10629                nvfp4_column_shard(gate, tp, rank_index)?,
10630            )?);
10631            up_ranks.push(upload_rank_nvfp4(
10632                engine,
10633                nvfp4_column_shard(up, tp, rank_index)?,
10634            )?);
10635            let (codes, scales, local_in) = nvfp4_row_shard(down, tp, rank_index)?;
10636            down_ranks.push(upload_rank_nvfp4(
10637                engine,
10638                Nvfp4BlockMatrix {
10639                    codes: &codes,
10640                    scales: &scales,
10641                    macro_scale: down.macro_scale,
10642                    out_features: down.out_features,
10643                    in_features: local_in,
10644                },
10645            )?);
10646        }
10647        Ok(ResidentTpNvfp4Expert {
10648            gate: ResidentNvfp4ColumnParallel {
10649                ranks: gate_ranks,
10650                out_features: gate.out_features,
10651                in_features: gate.in_features,
10652            },
10653            up: ResidentNvfp4ColumnParallel {
10654                ranks: up_ranks,
10655                out_features: up.out_features,
10656                in_features: up.in_features,
10657            },
10658            down: ResidentNvfp4RowParallel {
10659                ranks: down_ranks,
10660                out_features: down.out_features,
10661                in_features: down.in_features,
10662            },
10663            input_width: gate.in_features,
10664            expert_width: gate.out_features,
10665        })
10666    }
10667
10668    fn column_parallel_resident_nvfp4(
10669        &self,
10670        matrix: &ResidentNvfp4ColumnParallel,
10671        activations: &[f32],
10672        tokens: usize,
10673    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10674        validate_activations(activations, tokens, matrix.in_features)?;
10675        let local_out = matrix.out_features / self.ranks.len();
10676        let mut gathered = vec![0.0f32; tokens * matrix.out_features];
10677        let mut macro_scale = None;
10678        for (rank_index, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
10679            let output = run_resident_rank_nvfp4(engine, shard, activations, tokens)?;
10680            let row_start = rank_index * local_out;
10681            for token in 0..tokens {
10682                gathered[token * matrix.out_features + row_start
10683                    ..token * matrix.out_features + row_start + local_out]
10684                    .copy_from_slice(&output[token * local_out..(token + 1) * local_out]);
10685            }
10686            macro_scale = Some(shard.macro_scale);
10687        }
10688        apply_macro(
10689            &mut gathered,
10690            macro_scale.ok_or("NVFP4 column-parallel matrix has no ranks")?,
10691        );
10692        Ok(gathered)
10693    }
10694
10695    fn row_parallel_resident_nvfp4(
10696        &self,
10697        matrix: &ResidentNvfp4RowParallel,
10698        activations: &[f32],
10699        tokens: usize,
10700    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10701        validate_activations(activations, tokens, matrix.in_features)?;
10702        let tp = self.ranks.len();
10703        let local_in = matrix.in_features / tp;
10704        let mut reduced = vec![0.0f32; tokens * matrix.out_features];
10705        let mut macro_scale = None;
10706        for (rank_index, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
10707            if shard.in_features != local_in {
10708                return Err(format!(
10709                    "NVFP4 resident row shard in_features {} != expected {local_in}",
10710                    shard.in_features
10711                )
10712                .into());
10713            }
10714            let local_activations =
10715                activation_shard(activations, tokens, matrix.in_features, tp, rank_index);
10716            let partial = run_resident_rank_nvfp4(engine, shard, &local_activations, tokens)?;
10717            for (sum, value) in reduced.iter_mut().zip(&partial) {
10718                *sum += *value;
10719            }
10720            macro_scale = Some(shard.macro_scale);
10721        }
10722        apply_macro(
10723            &mut reduced,
10724            macro_scale.ok_or("NVFP4 row-parallel matrix has no ranks")?,
10725        );
10726        Ok(reduced)
10727    }
10728
10729    pub fn run_expert_nvfp4(
10730        &self,
10731        expert: &ResidentTpNvfp4Expert,
10732        input: &[f32],
10733        tokens: usize,
10734    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10735        validate_activations(input, tokens, expert.input_width)?;
10736        let gate = self.column_parallel_resident_nvfp4(&expert.gate, input, tokens)?;
10737        let up = self.column_parallel_resident_nvfp4(&expert.up, input, tokens)?;
10738        let activated: Vec<f32> = gate
10739            .iter()
10740            .zip(&up)
10741            .map(|(&gate, &up)| gate / (1.0 + (-gate).exp()) * up)
10742            .collect();
10743        debug_assert_eq!(activated.len(), tokens * expert.expert_width);
10744        self.row_parallel_resident_nvfp4(&expert.down, &activated, tokens)
10745    }
10746
10747    /// Upload every expert's TP shards resident (one repacked block buffer per expert per rank).
10748    #[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
10749    pub fn upload_tensor_parallel_nvfp4(
10750        &self,
10751        gate: Nvfp4ExpertBank<'_>,
10752        up: Nvfp4ExpertBank<'_>,
10753        down: Nvfp4ExpertBank<'_>,
10754    ) -> Result<ResidentNvfp4TensorParallel, Box<dyn std::error::Error>> {
10755        gate.validate()?;
10756        up.validate()?;
10757        down.validate()?;
10758        if gate.expert_count != up.expert_count || gate.expert_count != down.expert_count {
10759            return Err("NVFP4 TP gate/up/down expert counts differ".into());
10760        }
10761        if gate.in_features != up.in_features || gate.out_features != up.out_features {
10762            return Err("NVFP4 TP gate/up dimensions differ".into());
10763        }
10764        if down.in_features != gate.out_features || down.out_features != gate.in_features {
10765            return Err(format!(
10766                "NVFP4 TP down {}x{} does not invert gate/up {}x{}",
10767                down.out_features, down.in_features, gate.out_features, gate.in_features
10768            )
10769            .into());
10770        }
10771        let tp = self.ranks.len();
10772        if gate.out_features % tp != 0 {
10773            return Err(format!(
10774                "NVFP4 TP expert output width {} is not divisible by TP={tp}",
10775                gate.out_features
10776            )
10777            .into());
10778        }
10779        if !down.in_features.is_multiple_of(NVFP4_CANONICAL_ROW_SHARDS)
10780            || !(down.in_features / NVFP4_CANONICAL_ROW_SHARDS).is_multiple_of(64)
10781        {
10782            return Err(format!(
10783                "NVFP4 TP expert input width {} does not split into 64-aligned canonical \
10784                 shards ({NVFP4_CANONICAL_ROW_SHARDS})",
10785                down.in_features
10786            )
10787            .into());
10788        }
10789        if tp > NVFP4_CANONICAL_ROW_SHARDS {
10790            return Err(format!(
10791                "NVFP4 TP world {tp} exceeds the canonical row-shard grid \
10792                 ({NVFP4_CANONICAL_ROW_SHARDS})"
10793            )
10794            .into());
10795        }
10796
10797        let ep2 = step_nvfp4_ep2_on() && tp == 2;
10798        // LAYOUT DECISION, MADE ONCE PER BANK BUILD. EP2 whole-expert banks are ALWAYS
10799        // slot-major (their `*_ep` kernels read that mapping unconditionally); TP shard banks
10800        // are slot-major only under PROGRAM 1's door. Every reader below takes this from the
10801        // bank it is reading, never from `bank_slot_major_on()` again.
10802        let slot_major = ep2 || bank_slot_major_on();
10803        // ENGAGEMENT RECEIPT, not a debug line. A pricing cell that proves only that the env var
10804        // is SET measures nothing: if the door fails to reach the code, the cell reports "the
10805        // program is worth 0%" when the truth is "the program never ran". That exact defect is
10806        // banked -- the MEMRA_BF16_MMV lane's first sweep grepped for engagement, got 0 in BOTH
10807        // arms, and the missing line was mistaken for a no-engagement result until an announce
10808        // was added. So the layout decision announces itself, WITH ITS SOURCE, so a receipt can
10809        // distinguish "armed by the door" from "armed because EP2" from "not armed".
10810        eprintln!(
10811            "[nvfp4-bank] layout={} source={} tp={tp} experts={} in_f={} out_f={}",
10812            if slot_major {
10813                "slot-major"
10814            } else {
10815                "block-nvfp4-v1"
10816            },
10817            // The source string distinguishes "armed by the 2026-09-01 DEFAULT" from "armed by
10818            // an explicit recipe" from "rolled back by the seam" from "armed because EP2". A
10819            // default flip whose receipt cannot say which of those happened cannot prove the
10820            // DEFAULT was what got measured.
10821            if ep2 {
10822                "ep2-always"
10823            } else {
10824                bank_slot_major_source().1
10825            },
10826            gate.expert_count,
10827            gate.in_features,
10828            gate.out_features
10829        );
10830        let mut gate_ranks = Vec::with_capacity(tp);
10831        let mut up_ranks = Vec::with_capacity(tp);
10832        let mut macros_gate_dev = Vec::with_capacity(tp);
10833        let mut macros_up_dev = Vec::with_capacity(tp);
10834        let mut macros_down_dev = Vec::with_capacity(tp);
10835        for (rank_index, engine) in self.ranks.iter().enumerate() {
10836            let _main = engine.gpu.enter_main()?;
10837            // Contiguous per-rank banks: repack every expert shard into one host buffer, one
10838            // upload. Contiguity feeds the batched selected-experts launch; per-expert bytes
10839            // are unchanged (same repack).
10840            // EP2: this rank holds the FULL matrices of the experts it owns (id & 1 ==
10841            // rank_index), stacked at slot id >> 1 — same total bytes as the shard bank.
10842            let mut gate_host: Vec<u8> = Vec::new();
10843            let mut up_host: Vec<u8> = Vec::new();
10844            let mut owned = 0usize;
10845            for expert in 0..gate.expert_count {
10846                if ep2 {
10847                    if expert % 2 != rank_index {
10848                        continue;
10849                    }
10850                    owned += 1;
10851                    gate_host.extend_from_slice(&nvfp4_repack_bank_matrix(
10852                        gate.expert(expert)?,
10853                        slot_major,
10854                    ));
10855                    up_host.extend_from_slice(&nvfp4_repack_bank_matrix(
10856                        up.expert(expert)?,
10857                        slot_major,
10858                    ));
10859                } else {
10860                    let gate_shard = nvfp4_column_shard(gate.expert(expert)?, tp, rank_index)?;
10861                    gate_host.extend_from_slice(&nvfp4_repack_bank_matrix(gate_shard, slot_major));
10862                    let up_shard = nvfp4_column_shard(up.expert(expert)?, tp, rank_index)?;
10863                    up_host.extend_from_slice(&nvfp4_repack_bank_matrix(up_shard, slot_major));
10864                }
10865            }
10866            let bank_experts = if ep2 { owned } else { gate.expert_count };
10867            let gate_expert_bytes = gate_host.len() / bank_experts.max(1);
10868            let up_expert_bytes = up_host.len() / bank_experts.max(1);
10869            let local_out = if ep2 {
10870                gate.out_features
10871            } else {
10872                gate.out_features / tp
10873            };
10874            gate_ranks.push(ResidentNvfp4ColumnBankRank {
10875                bank: engine.htod_bytes(&gate_host)?,
10876                expert_bytes: gate_expert_bytes,
10877                local_out,
10878                in_features: gate.in_features,
10879                row_bytes: nvfp4_row_bytes(gate.in_features),
10880                slot_major,
10881            });
10882            up_ranks.push(ResidentNvfp4ColumnBankRank {
10883                bank: engine.htod_bytes(&up_host)?,
10884                expert_bytes: up_expert_bytes,
10885                local_out,
10886                in_features: up.in_features,
10887                row_bytes: nvfp4_row_bytes(up.in_features),
10888                slot_major,
10889            });
10890            macros_gate_dev.push(engine.htod(gate.macros)?);
10891            macros_up_dev.push(engine.htod(up.macros)?);
10892            macros_down_dev.push(engine.htod(down.macros)?);
10893        }
10894        // Down: canonical shard grid, NOT the world size (see NVFP4_CANONICAL_ROW_SHARDS).
10895        // Shard s lives on rank s % world, so TP1 holds both shards and TP2 one each, while the
10896        // execution and reduction order stay identical.
10897        let mut down_ranks = Vec::with_capacity(NVFP4_CANONICAL_ROW_SHARDS);
10898        for shard_index in 0..NVFP4_CANONICAL_ROW_SHARDS {
10899            let device_rank = shard_index % tp;
10900            let engine = &self.ranks[device_rank];
10901            let _main = engine.gpu.enter_main()?;
10902            let mut down_host: Vec<u8> = Vec::new();
10903            let mut owned = 0usize;
10904            for expert in 0..down.expert_count {
10905                let down_matrix = down.expert(expert)?;
10906                if ep2 {
10907                    // EP2: shard_index doubles as the owner rank; full-width down matrices
10908                    // of the owned experts, stacked at slot id >> 1.
10909                    if expert % 2 != device_rank {
10910                        continue;
10911                    }
10912                    owned += 1;
10913                    down_host.extend_from_slice(&nvfp4_repack_bank_matrix(down_matrix, slot_major));
10914                } else {
10915                    let (codes, scales, local_in) =
10916                        nvfp4_row_shard(down_matrix, NVFP4_CANONICAL_ROW_SHARDS, shard_index)?;
10917                    down_host.extend_from_slice(&nvfp4_repack_bank_matrix(
10918                        Nvfp4BlockMatrix {
10919                            codes: &codes,
10920                            scales: &scales,
10921                            macro_scale: down_matrix.macro_scale,
10922                            out_features: down_matrix.out_features,
10923                            in_features: local_in,
10924                        },
10925                        slot_major,
10926                    ));
10927                }
10928            }
10929            let bank_experts = if ep2 { owned } else { down.expert_count };
10930            let down_expert_bytes = down_host.len() / bank_experts.max(1);
10931            let local_in = if ep2 {
10932                down.in_features
10933            } else {
10934                down.in_features / NVFP4_CANONICAL_ROW_SHARDS
10935            };
10936            down_ranks.push(ResidentNvfp4RowBankRank {
10937                bank: engine.htod_bytes(&down_host)?,
10938                expert_bytes: down_expert_bytes,
10939                device_rank,
10940                out_features: down.out_features,
10941                local_in,
10942                row_bytes: nvfp4_row_bytes(local_in),
10943                slot_major,
10944            });
10945        }
10946        Ok(ResidentNvfp4TensorParallel {
10947            gate: gate_ranks,
10948            up: up_ranks,
10949            down: down_ranks,
10950            macros_gate: gate.macros.to_vec(),
10951            macros_up: up.macros.to_vec(),
10952            macros_down: down.macros.to_vec(),
10953            macros_gate_dev,
10954            macros_up_dev,
10955            macros_down_dev,
10956            expert_count: gate.expert_count,
10957            input_width: gate.in_features,
10958            expert_width: gate.out_features,
10959            device_workspace: std::sync::Mutex::new(None),
10960            prime_tables: std::sync::Mutex::new(Vec::new()),
10961            ep2,
10962        })
10963    }
10964
10965    /// EP2 host-canonical: the whole expert executes on its owning rank at full width
10966    /// (owner = expert & 1, bank slot = expert >> 1). Per-row program == the column-bank
10967    /// path's kernel, so gate/up are bit-equal to the TP layout.
10968    fn run_full_bank_expert_nvfp4(
10969        &self,
10970        ranks: &[ResidentNvfp4ColumnBankRank],
10971        macros: &[f32],
10972        expert: usize,
10973        input: &[f32],
10974    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10975        let owner = expert & 1;
10976        let slot = expert >> 1;
10977        let bank = ranks
10978            .get(owner)
10979            .ok_or("NVFP4 EP2 column bank missing owner rank")?;
10980        let engine = &self.ranks[owner];
10981        let _main = engine.gpu.enter_main()?;
10982        let activations = engine.htod(input)?;
10983        let output = bank.host_canonical_expert(engine, slot, &activations)?;
10984        let mut out = engine.dtoh(&output)?;
10985        apply_macro(&mut out, macros[expert]);
10986        Ok(out)
10987    }
10988
10989    /// EP2 host-canonical down: one full-width dot on the owner (NUMERIC-CLASS vs the
10990    /// canonical 2-shard sum — the parenthesization this door declares).
10991    fn run_full_down_expert_nvfp4(
10992        &self,
10993        shards: &[ResidentNvfp4RowBankRank],
10994        macros: &[f32],
10995        expert: usize,
10996        input: &[f32],
10997    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10998        let owner = expert & 1;
10999        let slot = expert >> 1;
11000        let shard = shards
11001            .get(owner)
11002            .ok_or("NVFP4 EP2 down bank missing owner rank")?;
11003        let engine = &self.ranks[owner];
11004        let _main = engine.gpu.enter_main()?;
11005        let activations = engine.htod(input)?;
11006        let output = shard.host_canonical_expert(engine, slot, &activations)?;
11007        let mut out = engine.dtoh(&output)?;
11008        apply_macro(&mut out, macros[expert]);
11009        Ok(out)
11010    }
11011
11012    fn run_column_bank_expert_nvfp4(
11013        &self,
11014        ranks: &[ResidentNvfp4ColumnBankRank],
11015        macros: &[f32],
11016        expert: usize,
11017        input: &[f32],
11018    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
11019        let local_out = ranks
11020            .first()
11021            .ok_or("NVFP4 TP column bank has no ranks")?
11022            .local_out;
11023        let mut gathered = vec![0.0f32; local_out * ranks.len()];
11024        for (rank_index, (engine, bank)) in self.ranks.iter().zip(ranks).enumerate() {
11025            let _main = engine.gpu.enter_main()?;
11026            let activations = engine.htod(input)?;
11027            let output = bank.host_canonical_expert(engine, expert, &activations)?;
11028            let output = engine.dtoh(&output)?;
11029            gathered[rank_index * local_out..(rank_index + 1) * local_out].copy_from_slice(&output);
11030        }
11031        apply_macro(&mut gathered, macros[expert]);
11032        Ok(gathered)
11033    }
11034
11035    /// Canonical-shard row reduction: iterate the FIXED shard grid in shard order (each shard
11036    /// executes on its owning rank engine), so the reduction parenthesization is identical at
11037    /// every world size — that identity is what the TP1-oracle-vs-TP2 bit gate proves.
11038    fn run_row_bank_expert_nvfp4(
11039        &self,
11040        shards: &[ResidentNvfp4RowBankRank],
11041        macros: &[f32],
11042        expert: usize,
11043        input: &[f32],
11044    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
11045        let out_features = shards
11046            .first()
11047            .ok_or("NVFP4 TP row bank has no canonical shards")?
11048            .out_features;
11049        let in_features = shards.iter().map(|shard| shard.local_in).sum::<usize>();
11050        let mut reduced = vec![0.0f32; out_features];
11051        for (shard_index, shard) in shards.iter().enumerate() {
11052            let engine = self
11053                .ranks
11054                .get(shard.device_rank)
11055                .ok_or("NVFP4 canonical shard names a rank outside this runtime")?;
11056            let _main = engine.gpu.enter_main()?;
11057            let local_activations =
11058                activation_shard(input, 1, in_features, shards.len(), shard_index);
11059            let activations = engine.htod(&local_activations)?;
11060            let output = shard.host_canonical_expert(engine, expert, &activations)?;
11061            let partial = engine.dtoh(&output)?;
11062            for (sum, value) in reduced.iter_mut().zip(&partial) {
11063                *sum += *value;
11064            }
11065        }
11066        apply_macro(&mut reduced, macros[expert]);
11067        Ok(reduced)
11068    }
11069
11070    /// Upload whole experts per owning rank (NVFP4 expert-parallel: the layout the clamped tail
11071    /// layers require — clamp semantics do not distribute across a tensor shard). Each owned
11072    /// expert keeps its full gate/up/down as one repacked block buffer on its owner.
11073    #[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
11074    pub fn upload_expert_parallel_nvfp4(
11075        &self,
11076        gate: Nvfp4ExpertBank<'_>,
11077        up: Nvfp4ExpertBank<'_>,
11078        down: Nvfp4ExpertBank<'_>,
11079    ) -> Result<ResidentNvfp4ExpertParallel, Box<dyn std::error::Error>> {
11080        gate.validate()?;
11081        up.validate()?;
11082        down.validate()?;
11083        if gate.expert_count != up.expert_count || gate.expert_count != down.expert_count {
11084            return Err("NVFP4 EP gate/up/down expert counts differ".into());
11085        }
11086        if gate.in_features != up.in_features || gate.out_features != up.out_features {
11087            return Err("NVFP4 EP gate/up dimensions differ".into());
11088        }
11089        if down.in_features != gate.out_features || down.out_features != gate.in_features {
11090            return Err(format!(
11091                "NVFP4 EP down {}x{} does not invert gate/up {}x{}",
11092                down.out_features, down.in_features, gate.out_features, gate.in_features
11093            )
11094            .into());
11095        }
11096        let world = self.ranks.len();
11097        if gate.expert_count % world != 0 {
11098            return Err(format!(
11099                "NVFP4 EP expert count {} is not divisible by {world} ranks",
11100                gate.expert_count
11101            )
11102            .into());
11103        }
11104        let experts_per_rank = gate.expert_count / world;
11105        let mut ranks = Vec::with_capacity(world);
11106        for (rank_index, engine) in self.ranks.iter().enumerate() {
11107            let _main = engine.gpu.enter_main()?;
11108            let expert_range = rank_index * experts_per_rank..(rank_index + 1) * experts_per_rank;
11109            let mut gate_host = Vec::new();
11110            let mut up_host = Vec::new();
11111            let mut down_host = Vec::new();
11112            for expert in expert_range.clone() {
11113                gate_host.extend_from_slice(&nvfp4_repack_matrix(gate.expert(expert)?));
11114                up_host.extend_from_slice(&nvfp4_repack_matrix(up.expert(expert)?));
11115                down_host.extend_from_slice(&nvfp4_repack_matrix(down.expert(expert)?));
11116            }
11117            let gate_expert_bytes = gate_host.len() / experts_per_rank;
11118            let up_expert_bytes = up_host.len() / experts_per_rank;
11119            if gate_expert_bytes != up_expert_bytes {
11120                return Err("NVFP4 EP gate/up packed expert bytes differ".into());
11121            }
11122            let down_expert_bytes = down_host.len() / experts_per_rank;
11123            ranks.push(ResidentNvfp4EpRank {
11124                gate: engine.htod_bytes(&gate_host)?,
11125                up: engine.htod_bytes(&up_host)?,
11126                down: engine.htod_bytes(&down_host)?,
11127                gate_expert_bytes,
11128                down_expert_bytes,
11129                macros_gate: engine.htod(&gate.macros[expert_range.clone()])?,
11130                macros_up: engine.htod(&up.macros[expert_range.clone()])?,
11131                macros_down: engine.htod(&down.macros[expert_range.clone()])?,
11132                expert_range,
11133            });
11134        }
11135        Ok(ResidentNvfp4ExpertParallel {
11136            ranks,
11137            macros_gate: gate.macros.to_vec(),
11138            macros_up: up.macros.to_vec(),
11139            macros_down: down.macros.to_vec(),
11140            expert_count: gate.expert_count,
11141            input_width: gate.in_features,
11142            expert_width: gate.out_features,
11143            gate_row_bytes: nvfp4_row_bytes(gate.in_features),
11144            down_row_bytes: nvfp4_row_bytes(down.in_features),
11145            device_workspace: std::sync::Mutex::new(None),
11146        })
11147    }
11148
11149    /// Upload an already-normalized NVFP4 expert bank.
11150    ///
11151    /// `HostExps` is the physical-format boundary: stacked checkpoint tensors, gathered
11152    /// per-expert tensors, and manifest-backed overlays all become the same contiguous
11153    /// block_nvfp4 expert representation before the parallel backend sees them.
11154    pub fn upload_expert_parallel_nvfp4_normalized(
11155        &self,
11156        gate: &crate::model::HostExps,
11157        up: &crate::model::HostExps,
11158        down: &crate::model::HostExps,
11159    ) -> Result<ResidentNvfp4ExpertParallel, Box<dyn std::error::Error>> {
11160        for (label, bank) in [("gate", gate), ("up", up), ("down", down)] {
11161            if bank.qtype != crate::QT_NVFP4 || !bank.is_uniform_layout() {
11162                return Err(format!(
11163                    "NVFP4 EP normalized {label} bank requires one uniform NVFP4 layout, \
11164                     got qtype={} uniform={}",
11165                    bank.qtype,
11166                    bank.is_uniform_layout()
11167                )
11168                .into());
11169            }
11170            if bank.n_expert == 0
11171                || bank.expert_stride != bank.out_f * bank.row_bytes
11172                || (0..bank.n_expert)
11173                    .any(|expert| bank.expert_bytes(expert).len() != bank.expert_stride)
11174            {
11175                return Err(format!("NVFP4 EP normalized {label} bank geometry is invalid").into());
11176            }
11177        }
11178        if gate.n_expert != up.n_expert || gate.n_expert != down.n_expert {
11179            return Err("NVFP4 EP normalized gate/up/down expert counts differ".into());
11180        }
11181        if gate.in_f != up.in_f || gate.out_f != up.out_f {
11182            return Err("NVFP4 EP normalized gate/up dimensions differ".into());
11183        }
11184        if down.in_f != gate.out_f || down.out_f != gate.in_f {
11185            return Err(format!(
11186                "NVFP4 EP normalized down {}x{} does not invert gate/up {}x{}",
11187                down.out_f, down.in_f, gate.out_f, gate.in_f
11188            )
11189            .into());
11190        }
11191        let macros = |bank: &crate::model::HostExps| -> Result<Vec<f32>, String> {
11192            let values = bank
11193                .macros
11194                .clone()
11195                .unwrap_or_else(|| vec![1.0; bank.n_expert]);
11196            if values.len() != bank.n_expert
11197                || !values.iter().all(|value| value.is_finite() && *value > 0.0)
11198            {
11199                return Err("NVFP4 EP normalized macro row is not finite-positive".to_string());
11200            }
11201            Ok(values)
11202        };
11203        let macros_gate = macros(gate)?;
11204        let macros_up = macros(up)?;
11205        let macros_down = macros(down)?;
11206        let world = self.ranks.len();
11207        if !gate.n_expert.is_multiple_of(world) {
11208            return Err(format!(
11209                "NVFP4 EP normalized expert count {} is not divisible by {world} ranks",
11210                gate.n_expert
11211            )
11212            .into());
11213        }
11214        let experts_per_rank = gate.n_expert / world;
11215        let mut ranks = Vec::with_capacity(world);
11216        for (rank_index, engine) in self.ranks.iter().enumerate() {
11217            let _main = engine.gpu.enter_main()?;
11218            let expert_range = rank_index * experts_per_rank..(rank_index + 1) * experts_per_rank;
11219            let mut gate_host = Vec::with_capacity(experts_per_rank * gate.expert_stride);
11220            let mut up_host = Vec::with_capacity(experts_per_rank * up.expert_stride);
11221            let mut down_host = Vec::with_capacity(experts_per_rank * down.expert_stride);
11222            for expert in expert_range.clone() {
11223                gate_host.extend_from_slice(gate.expert_bytes(expert));
11224                up_host.extend_from_slice(up.expert_bytes(expert));
11225                down_host.extend_from_slice(down.expert_bytes(expert));
11226            }
11227            ranks.push(ResidentNvfp4EpRank {
11228                gate: engine.htod_bytes(&gate_host)?,
11229                up: engine.htod_bytes(&up_host)?,
11230                down: engine.htod_bytes(&down_host)?,
11231                gate_expert_bytes: gate.expert_stride,
11232                down_expert_bytes: down.expert_stride,
11233                macros_gate: engine.htod(&macros_gate[expert_range.clone()])?,
11234                macros_up: engine.htod(&macros_up[expert_range.clone()])?,
11235                macros_down: engine.htod(&macros_down[expert_range.clone()])?,
11236                expert_range,
11237            });
11238        }
11239        Ok(ResidentNvfp4ExpertParallel {
11240            ranks,
11241            macros_gate,
11242            macros_up,
11243            macros_down,
11244            expert_count: gate.n_expert,
11245            input_width: gate.in_f,
11246            expert_width: gate.out_f,
11247            gate_row_bytes: gate.row_bytes,
11248            down_row_bytes: down.row_bytes,
11249            device_workspace: std::sync::Mutex::new(None),
11250        })
11251    }
11252
11253    /// Routed NVFP4 expert-parallel program, host-canonical: every selected expert executes WHOLE
11254    /// on its owning rank (gate -> up -> clamped-or-plain SwiGLU on host -> down), each projection
11255    /// macro applied once post-kernel, route-weighted accumulate on the host in slot order. The
11256    /// activation uses `step_expert_activation_host`, so the clamped tail layers keep the official
11257    /// contract. Exactness-first; no throughput claim.
11258    #[allow(clippy::too_many_arguments)]
11259    pub fn run_routed_experts_nvfp4(
11260        &self,
11261        experts: &ResidentNvfp4ExpertParallel,
11262        input: &[f32],
11263        tokens: usize,
11264        selected: &[usize],
11265        route_weights: &[f32],
11266        experts_per_token: usize,
11267        activation_limit: Option<f32>,
11268    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
11269        validate_activations(input, tokens, experts.input_width)?;
11270        let pairs = tokens
11271            .checked_mul(experts_per_token)
11272            .ok_or("NVFP4 EP route count overflow")?;
11273        if selected.len() != pairs || route_weights.len() != pairs {
11274            return Err(format!(
11275                "NVFP4 EP routes selected={} weights={} != tokens {tokens} x experts/token \
11276                 {experts_per_token} ({pairs})",
11277                selected.len(),
11278                route_weights.len(),
11279            )
11280            .into());
11281        }
11282        if !route_weights.iter().all(|weight| weight.is_finite()) {
11283            return Err("NVFP4 EP route weights contain a non-finite value".into());
11284        }
11285        let experts_per_rank = experts.expert_count / experts.ranks.len();
11286        let mut output = vec![0.0f32; tokens * experts.input_width];
11287        for token in 0..tokens {
11288            let input_row = &input[token * experts.input_width..(token + 1) * experts.input_width];
11289            for slot in 0..experts_per_token {
11290                let pair = token * experts_per_token + slot;
11291                let expert = selected[pair];
11292                if expert >= experts.expert_count {
11293                    return Err(format!(
11294                        "NVFP4 EP selected expert {expert} outside 0..{}",
11295                        experts.expert_count
11296                    )
11297                    .into());
11298                }
11299                let owner = expert / experts_per_rank;
11300                let local = expert - owner * experts_per_rank;
11301                let rank = &experts.ranks[owner];
11302                let engine = &self.ranks[owner];
11303                let _main = engine.gpu.enter_main()?;
11304                let device_input = engine.htod(input_row)?;
11305                let gate_out = engine.qmatvec_nvfp4_fast(
11306                    &rank.gate.slice(
11307                        local * rank.gate_expert_bytes..(local + 1) * rank.gate_expert_bytes,
11308                    ),
11309                    &device_input,
11310                    1,
11311                    experts.input_width,
11312                    experts.expert_width,
11313                    experts.gate_row_bytes,
11314                )?;
11315                let up_out = engine.qmatvec_nvfp4_fast(
11316                    &rank.up.slice(
11317                        local * rank.gate_expert_bytes..(local + 1) * rank.gate_expert_bytes,
11318                    ),
11319                    &device_input,
11320                    1,
11321                    experts.input_width,
11322                    experts.expert_width,
11323                    experts.gate_row_bytes,
11324                )?;
11325                let mut gate_host = engine.dtoh(&gate_out)?;
11326                let mut up_host = engine.dtoh(&up_out)?;
11327                apply_macro(&mut gate_host, experts.macros_gate[expert]);
11328                apply_macro(&mut up_host, experts.macros_up[expert]);
11329                let activated: Vec<f32> = gate_host
11330                    .iter()
11331                    .zip(&up_host)
11332                    .map(|(&gate, &up)| step_expert_activation_host(gate, up, activation_limit))
11333                    .collect();
11334                let device_activated = engine.htod(&activated)?;
11335                let down_out = engine.qmatvec_nvfp4_fast(
11336                    &rank.down.slice(
11337                        local * rank.down_expert_bytes..(local + 1) * rank.down_expert_bytes,
11338                    ),
11339                    &device_activated,
11340                    1,
11341                    experts.expert_width,
11342                    experts.input_width,
11343                    experts.down_row_bytes,
11344                )?;
11345                let mut down_host = engine.dtoh(&down_out)?;
11346                apply_macro(&mut down_host, experts.macros_down[expert]);
11347                let weight = route_weights[pair];
11348                for (sum, value) in output
11349                    [token * experts.input_width..(token + 1) * experts.input_width]
11350                    .iter_mut()
11351                    .zip(down_host)
11352                {
11353                    *sum += weight * value;
11354                }
11355            }
11356        }
11357        Ok(output)
11358    }
11359
11360    /// Device-resident W4A16 expert parallelism for one scheduler/prefill batch (1..=128 rows).
11361    ///
11362    /// The host router partitions token/slot pairs by contiguous expert owner. Each rank
11363    /// peer-reads the whole batch input once, rounds it to BF16, and executes its owner-local
11364    /// selected gate/up -> host-expf SwiGLU -> BF16 -> down program. Down rows scatter directly
11365    /// into canonical token-major pair positions in the model engine's peer-accessible pool at
11366    /// every batch width; the root reduces each token's slots in original order. Thus batching
11367    /// and owner assignment do not change route-reduction parenthesization.
11368    #[allow(clippy::too_many_arguments)]
11369    pub fn run_routed_experts_nvfp4_w4a16_device_io(
11370        &self,
11371        experts: &ResidentNvfp4ExpertParallel,
11372        e: &Engine,
11373        input_dev: &crate::CudaSlice<f32>,
11374        tokens: usize,
11375        selected: &[usize],
11376        route_weights: &[f32],
11377        experts_per_token: usize,
11378        activation_limit: Option<f32>,
11379    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
11380        // Diagnostic attribution only: force the returned root event chain to completion so the
11381        // caller's shared-expert timer does not absorb routed-EP work. The normal path remains
11382        // fully asynchronous.
11383        static TIMING_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11384        static TIMING_CALLS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11385        let timing = std::env::var("MEMRA_STEP_TP_TIMING").as_deref() == Ok("1");
11386        let started = timing.then(std::time::Instant::now);
11387        if !self.native_p2p {
11388            return Err("W4A16 NVFP4 device EP requires native P2P".into());
11389        }
11390        if self.devices.first().copied() != Some(e.ctx().ordinal()) {
11391            return Err(format!(
11392                "W4A16 NVFP4 device EP root device {:?} != model engine device {}",
11393                self.devices.first(),
11394                e.ctx().ordinal()
11395            )
11396            .into());
11397        }
11398        // Prime/cache scratch buffers are grow-only: a 160-token host-oracle chunk can be
11399        // followed by a 44-token device-EP tail using the same 160-row allocation. Consume the
11400        // active prefix rather than requiring allocation length == active length.
11401        let active_input_values =
11402            nvfp4_ep_active_input_values(input_dev.len(), tokens, experts.input_width)?;
11403        let pairs = tokens
11404            .checked_mul(experts_per_token)
11405            .ok_or("W4A16 NVFP4 device EP route count overflow")?;
11406        if selected.len() != pairs || route_weights.len() != pairs {
11407            return Err(format!(
11408                "W4A16 NVFP4 device EP routes selected={} weights={} != tokens {tokens} x \
11409                 experts/token {experts_per_token} ({pairs})",
11410                selected.len(),
11411                route_weights.len(),
11412            )
11413            .into());
11414        }
11415        if !route_weights.iter().all(|weight| weight.is_finite()) {
11416            return Err("W4A16 NVFP4 device EP route weights contain a non-finite value".into());
11417        }
11418        let world = self.ranks.len();
11419        if world != experts.ranks.len() || !(2..=PRODUCT_MAX_CARDS).contains(&world) {
11420            return Err(format!(
11421                "W4A16 NVFP4 device EP runtime ranks {world} != bank ranks {}",
11422                experts.ranks.len()
11423            )
11424            .into());
11425        }
11426        let owner_routes = partition_expert_owner_routes(
11427            experts.expert_count,
11428            world,
11429            tokens,
11430            experts_per_token,
11431            selected,
11432        )?;
11433
11434        let mut workspace_guard = experts
11435            .device_workspace
11436            .lock()
11437            .map_err(|_| "W4A16 NVFP4 device EP workspace lock is poisoned")?;
11438        if workspace_guard.is_none() {
11439            let capacity_tokens = NVFP4_EP_DEVICE_BATCH_CAP;
11440            let capacity_pairs = capacity_tokens * experts_per_token;
11441            let mut input = Vec::with_capacity(world);
11442            let mut input_bf16 = Vec::with_capacity(world);
11443            let mut input_q8 = Vec::with_capacity(world);
11444            let mut input_q8_scales = Vec::with_capacity(world);
11445            let mut sel = Vec::with_capacity(world);
11446            let mut token_rows = Vec::with_capacity(world);
11447            let mut global_pairs = Vec::with_capacity(world);
11448            let mut route_w = Vec::with_capacity(world);
11449            let mut gate_out = Vec::with_capacity(world);
11450            let mut up_out = Vec::with_capacity(world);
11451            let mut activation_bf16 = Vec::with_capacity(world);
11452            let mut activation_q8 = Vec::with_capacity(world);
11453            let mut activation_q8_scales = Vec::with_capacity(world);
11454            let mut ev_rank = Vec::with_capacity(world);
11455            for engine in &self.ranks {
11456                let _main = engine.gpu.enter_main()?;
11457                input.push(engine.uninit(capacity_tokens * experts.input_width)?);
11458                input_bf16.push(engine.alloc_u8_uninit(2 * capacity_tokens * experts.input_width)?);
11459                input_q8.push(engine.alloc_i8_uninit(capacity_tokens * experts.input_width)?);
11460                input_q8_scales
11461                    .push(engine.uninit(capacity_tokens * experts.input_width.div_ceil(32))?);
11462                sel.push(engine.htod_i32(&vec![0i32; capacity_pairs])?);
11463                token_rows.push(engine.htod_i32(&vec![0i32; capacity_pairs])?);
11464                global_pairs.push(engine.htod_i32(&vec![0i32; capacity_pairs])?);
11465                route_w.push(engine.htod(&vec![0.0f32; capacity_pairs])?);
11466                gate_out.push(engine.uninit(capacity_pairs * experts.expert_width)?);
11467                up_out.push(engine.uninit(capacity_pairs * experts.expert_width)?);
11468                activation_bf16
11469                    .push(engine.alloc_u8_uninit(2 * capacity_pairs * experts.expert_width)?);
11470                activation_q8.push(engine.alloc_i8_uninit(capacity_pairs * experts.expert_width)?);
11471                activation_q8_scales
11472                    .push(engine.uninit(capacity_pairs * experts.expert_width.div_ceil(32))?);
11473                ev_rank.push(engine.ctx().new_event(None)?);
11474            }
11475            let _main = e.gpu.enter_main()?;
11476            let slot_rows = e.uninit(capacity_pairs * experts.input_width)?;
11477            let slot_rows_raw = {
11478                use cudarc::driver::DevicePtr;
11479                let stream = e.stream();
11480                let (pointer, _guard) = slot_rows.device_ptr(&stream);
11481                pointer
11482            };
11483            *workspace_guard = Some(Nvfp4EpDeviceWorkspace {
11484                input,
11485                input_bf16,
11486                input_q8,
11487                input_q8_scales,
11488                sel,
11489                token_rows,
11490                global_pairs,
11491                route_w,
11492                gate_out,
11493                up_out,
11494                activation_bf16,
11495                activation_q8,
11496                activation_q8_scales,
11497                slot_rows,
11498                slot_rows_raw,
11499                route_weights: e.htod(&vec![0.0f32; capacity_pairs])?,
11500                graph_input: e.uninit(NVFP4_EP_GRAPH_BATCH_CAP * experts.input_width)?,
11501                graph_output: e.uninit(NVFP4_EP_GRAPH_BATCH_CAP * experts.input_width)?,
11502                graph_routes: None,
11503                graphs: std::iter::repeat_with(|| None)
11504                    .take(NVFP4_EP_GRAPH_BATCH_CAP + 1)
11505                    .collect(),
11506                ev_entry: e.ctx().new_event(None)?,
11507                ev_entry_device: e.ctx().ordinal(),
11508                ev_rank,
11509                phase_events: None,
11510                capacity_tokens,
11511                experts_per_token,
11512            });
11513        }
11514        let workspace = workspace_guard
11515            .as_mut()
11516            .expect("W4A16 NVFP4 device EP workspace initialized above");
11517        if workspace.experts_per_token != experts_per_token || tokens > workspace.capacity_tokens {
11518            return Err(format!(
11519                "W4A16 NVFP4 device EP workspace tokens={} experts/token={} cannot serve \
11520                 tokens={tokens} experts/token={experts_per_token}",
11521                workspace.capacity_tokens, workspace.experts_per_token,
11522            )
11523            .into());
11524        }
11525        if workspace.ev_entry_device != e.ctx().ordinal() {
11526            return Err("W4A16 NVFP4 device EP model engine changed".into());
11527        }
11528
11529        {
11530            let _main = e.gpu.enter_main()?;
11531            let mut destination = workspace.route_weights.slice_mut(0..pairs);
11532            e.stream()
11533                .memcpy_htod(&route_weights[..pairs], &mut destination)?;
11534            workspace.ev_entry.record(&e.stream())?;
11535        }
11536        for (rank_index, engine) in self.ranks.iter().enumerate() {
11537            let _main = engine.gpu.enter_main()?;
11538            engine.stream().wait(&workspace.ev_entry)?;
11539            {
11540                let mut destination = workspace.input[rank_index].slice_mut(0..active_input_values);
11541                engine
11542                    .stream()
11543                    .memcpy_dtod(&input_dev.slice(0..active_input_values), &mut destination)?;
11544            }
11545            engine.f32_to_bf16_into(
11546                &workspace.input[rank_index],
11547                &mut workspace.input_bf16[rank_index],
11548                tokens * experts.input_width,
11549            )?;
11550            let owner = &owner_routes[rank_index];
11551            debug_assert_eq!(owner.rank, rank_index);
11552            let local_count = owner.selected.len();
11553            if local_count > 0 {
11554                let local_selected = owner
11555                    .selected
11556                    .iter()
11557                    .map(|&expert| expert as i32)
11558                    .collect::<Vec<_>>();
11559                let local_token_rows = owner
11560                    .token_rows
11561                    .iter()
11562                    .map(|&token| token as i32)
11563                    .collect::<Vec<_>>();
11564                let local_global_pairs = owner
11565                    .global_pairs
11566                    .iter()
11567                    .map(|&pair| pair as i32)
11568                    .collect::<Vec<_>>();
11569                {
11570                    let mut destination = workspace.sel[rank_index].slice_mut(0..local_count);
11571                    engine
11572                        .stream()
11573                        .memcpy_htod(&local_selected, &mut destination)?;
11574                }
11575                {
11576                    let mut destination =
11577                        workspace.token_rows[rank_index].slice_mut(0..local_count);
11578                    engine
11579                        .stream()
11580                        .memcpy_htod(&local_token_rows, &mut destination)?;
11581                }
11582                {
11583                    let mut destination =
11584                        workspace.global_pairs[rank_index].slice_mut(0..local_count);
11585                    engine
11586                        .stream()
11587                        .memcpy_htod(&local_global_pairs, &mut destination)?;
11588                }
11589                let rank = &experts.ranks[rank_index];
11590                engine.qmatvec_nvfp4_bf16_sel_dual_rows_into(
11591                    &rank.gate,
11592                    &rank.up,
11593                    &workspace.sel[rank_index],
11594                    &workspace.token_rows[rank_index],
11595                    &workspace.input_bf16[rank_index],
11596                    &mut workspace.gate_out[rank_index],
11597                    &mut workspace.up_out[rank_index],
11598                    local_count,
11599                    experts.input_width,
11600                    experts.expert_width,
11601                    experts.gate_row_bytes,
11602                    rank.gate_expert_bytes,
11603                    tokens,
11604                )?;
11605                engine.silu_mul_scaled_host_expf_bf16_sel_into(
11606                    &workspace.gate_out[rank_index],
11607                    &workspace.up_out[rank_index],
11608                    &rank.macros_gate,
11609                    &rank.macros_up,
11610                    &workspace.sel[rank_index],
11611                    activation_limit,
11612                    &mut workspace.activation_bf16[rank_index],
11613                    experts.expert_width,
11614                    local_count,
11615                )?;
11616                engine.qmatvec_nvfp4_bf16_sel_down_rows_raw(
11617                    &rank.down,
11618                    &workspace.sel[rank_index],
11619                    &workspace.global_pairs[rank_index],
11620                    &workspace.activation_bf16[rank_index],
11621                    &rank.macros_down,
11622                    workspace.slot_rows_raw,
11623                    local_count,
11624                    experts.expert_width,
11625                    experts.input_width,
11626                    experts.down_row_bytes,
11627                    rank.down_expert_bytes,
11628                    pairs,
11629                )?;
11630            }
11631            workspace.ev_rank[rank_index].record(&engine.stream())?;
11632        }
11633
11634        let output = {
11635            let _main = e.gpu.enter_main()?;
11636            for event in &workspace.ev_rank {
11637                e.stream().wait(event)?;
11638            }
11639            let mut output = e.uninit(tokens * experts.input_width)?;
11640            e.axpy_rows_seq_tokens_into(
11641                &workspace.slot_rows,
11642                &workspace.route_weights,
11643                &mut output,
11644                experts.input_width,
11645                experts_per_token,
11646                tokens,
11647            )?;
11648            output
11649        };
11650        if let Some(started) = started {
11651            use std::sync::atomic::Ordering;
11652            e.stream().synchronize()?;
11653            let elapsed = started.elapsed().as_nanos() as u64;
11654            let ns = TIMING_NS.fetch_add(elapsed, Ordering::Relaxed) + elapsed;
11655            let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
11656            if calls.is_multiple_of(430) {
11657                eprintln!(
11658                    "[nvfp4-ep-w4a16-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
11659                    ns as f64 / 1.0e6,
11660                    ns as f64 / calls as f64 / 1.0e3,
11661                );
11662            }
11663        }
11664        Ok(output)
11665    }
11666
11667    /// Fully device-routed W4A16 expert parallelism. Router ids/weights stay on the model GPU;
11668    /// each rank receives the fixed token/slot metadata, rejects non-owned experts in-kernel, and
11669    /// writes canonical token-major slot rows back to the root at every batch width. Preserving
11670    /// that one accumulation program is required by speculative verification: the former t=1
11671    /// owner-grouped FMA was a distinct numeric class and failed real HY3 MTP self-consistency.
11672    #[allow(clippy::too_many_arguments)]
11673    pub fn run_routed_experts_nvfp4_w4a16_device_routed(
11674        &self,
11675        experts: &ResidentNvfp4ExpertParallel,
11676        e: &Engine,
11677        input_dev: &crate::CudaSlice<f32>,
11678        selected_dev: &crate::CudaSlice<i32>,
11679        route_weights_dev: &crate::CudaSlice<f32>,
11680        tokens: usize,
11681        experts_per_token: usize,
11682        activation_limit: Option<f32>,
11683    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
11684        self.run_routed_experts_nvfp4_w4a16_device_routed_inner(
11685            experts,
11686            e,
11687            input_dev,
11688            selected_dev,
11689            route_weights_dev,
11690            tokens,
11691            experts_per_token,
11692            activation_limit,
11693            None,
11694        )
11695    }
11696
11697    /// Automatic whole-expert EP with a PREJOIN hook. The hook runs after every rank's routed
11698    /// chain has been issued and before the root waits for rank completion, so independent
11699    /// root-device work can fill the peer drain without changing the routed accumulation order.
11700    #[allow(clippy::too_many_arguments)]
11701    pub fn run_routed_experts_nvfp4_w4a16_device_routed_prejoin(
11702        &self,
11703        experts: &ResidentNvfp4ExpertParallel,
11704        e: &Engine,
11705        input_dev: &crate::CudaSlice<f32>,
11706        selected_dev: &crate::CudaSlice<i32>,
11707        route_weights_dev: &crate::CudaSlice<f32>,
11708        tokens: usize,
11709        experts_per_token: usize,
11710        activation_limit: Option<f32>,
11711        mut pre_join: impl FnMut() -> Result<(), Box<dyn std::error::Error>>,
11712    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
11713        self.run_routed_experts_nvfp4_w4a16_device_routed_inner(
11714            experts,
11715            e,
11716            input_dev,
11717            selected_dev,
11718            route_weights_dev,
11719            tokens,
11720            experts_per_token,
11721            activation_limit,
11722            Some(&mut pre_join),
11723        )
11724    }
11725
11726    #[allow(clippy::too_many_arguments)]
11727    fn run_routed_experts_nvfp4_w4a16_device_routed_inner(
11728        &self,
11729        experts: &ResidentNvfp4ExpertParallel,
11730        e: &Engine,
11731        input_dev: &crate::CudaSlice<f32>,
11732        selected_dev: &crate::CudaSlice<i32>,
11733        route_weights_dev: &crate::CudaSlice<f32>,
11734        tokens: usize,
11735        experts_per_token: usize,
11736        activation_limit: Option<f32>,
11737        mut pre_join: Option<&mut dyn FnMut() -> Result<(), Box<dyn std::error::Error>>>,
11738    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
11739        if !self.native_p2p {
11740            return Err("W4A16 device-routed EP requires native P2P".into());
11741        }
11742        if self.devices.first().copied() != Some(e.ctx().ordinal()) {
11743            return Err(format!(
11744                "W4A16 device-routed EP root device {:?} != model engine device {}",
11745                self.devices.first(),
11746                e.ctx().ordinal()
11747            )
11748            .into());
11749        }
11750        let active_input_values =
11751            nvfp4_ep_active_input_values(input_dev.len(), tokens, experts.input_width)?;
11752        let pairs = tokens
11753            .checked_mul(experts_per_token)
11754            .ok_or("W4A16 device-routed EP route count overflow")?;
11755        if selected_dev.len() < pairs || route_weights_dev.len() < pairs {
11756            return Err(format!(
11757                "W4A16 device-routed EP metadata selected={} weights={} < pairs={pairs}",
11758                selected_dev.len(),
11759                route_weights_dev.len(),
11760            )
11761            .into());
11762        }
11763        let world = self.ranks.len();
11764        if world != experts.ranks.len() || !(2..=PRODUCT_MAX_CARDS).contains(&world) {
11765            return Err(format!(
11766                "W4A16 device-routed EP runtime ranks {world} != bank ranks {}",
11767                experts.ranks.len()
11768            )
11769            .into());
11770        }
11771
11772        static TIMING_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11773        static TIMING_CALLS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11774        static ISSUE_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11775        static JOIN_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11776        static COPY_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11777        static GATE_UP_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11778        static ACTIVATION_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11779        static DOWN_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11780        static RANK_SPAN_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11781        let timing = std::env::var("MEMRA_STEP_TP_TIMING").as_deref() == Ok("1");
11782        let started = timing.then(std::time::Instant::now);
11783        let graph_enabled = parallel_ep_graph_enabled()?;
11784        let pair_down_enabled = parallel_ep_pair_down_enabled()?;
11785
11786        let mut workspace_guard = experts
11787            .device_workspace
11788            .lock()
11789            .map_err(|_| "W4A16 device-routed EP workspace lock is poisoned")?;
11790        if workspace_guard.is_none() {
11791            let capacity_tokens = NVFP4_EP_DEVICE_BATCH_CAP;
11792            let capacity_pairs = capacity_tokens * experts_per_token;
11793            let mut input = Vec::with_capacity(world);
11794            let mut input_bf16 = Vec::with_capacity(world);
11795            let mut input_q8 = Vec::with_capacity(world);
11796            let mut input_q8_scales = Vec::with_capacity(world);
11797            let mut sel = Vec::with_capacity(world);
11798            let mut token_rows = Vec::with_capacity(world);
11799            let mut global_pairs = Vec::with_capacity(world);
11800            let mut route_w = Vec::with_capacity(world);
11801            let mut gate_out = Vec::with_capacity(world);
11802            let mut up_out = Vec::with_capacity(world);
11803            let mut activation_bf16 = Vec::with_capacity(world);
11804            let mut activation_q8 = Vec::with_capacity(world);
11805            let mut activation_q8_scales = Vec::with_capacity(world);
11806            let mut ev_rank = Vec::with_capacity(world);
11807            let mut phase_head = Vec::with_capacity(world);
11808            let mut phase_copy_done = Vec::with_capacity(world);
11809            let mut phase_gate_up_done = Vec::with_capacity(world);
11810            let mut phase_activation_done = Vec::with_capacity(world);
11811            let mut phase_down_done = Vec::with_capacity(world);
11812            for engine in &self.ranks {
11813                let _main = engine.gpu.enter_main()?;
11814                input.push(engine.uninit(capacity_tokens * experts.input_width)?);
11815                input_bf16.push(engine.alloc_u8_uninit(2 * capacity_tokens * experts.input_width)?);
11816                input_q8.push(engine.alloc_i8_uninit(capacity_tokens * experts.input_width)?);
11817                input_q8_scales
11818                    .push(engine.uninit(capacity_tokens * experts.input_width.div_ceil(32))?);
11819                sel.push(engine.htod_i32(&vec![0i32; capacity_pairs])?);
11820                token_rows.push(engine.htod_i32(&vec![0i32; capacity_pairs])?);
11821                global_pairs.push(engine.htod_i32(&vec![0i32; capacity_pairs])?);
11822                route_w.push(engine.htod(&vec![0.0f32; capacity_pairs])?);
11823                gate_out.push(engine.uninit(capacity_pairs * experts.expert_width)?);
11824                up_out.push(engine.uninit(capacity_pairs * experts.expert_width)?);
11825                activation_bf16
11826                    .push(engine.alloc_u8_uninit(2 * capacity_pairs * experts.expert_width)?);
11827                activation_q8.push(engine.alloc_i8_uninit(capacity_pairs * experts.expert_width)?);
11828                activation_q8_scales
11829                    .push(engine.uninit(capacity_pairs * experts.expert_width.div_ceil(32))?);
11830                ev_rank.push(engine.ctx().new_event(None)?);
11831                if timing {
11832                    phase_head.push(
11833                        engine.ctx().new_event(Some(
11834                            cudarc::driver::sys::CUevent_flags::CU_EVENT_DEFAULT,
11835                        ))?,
11836                    );
11837                    phase_copy_done.push(
11838                        engine.ctx().new_event(Some(
11839                            cudarc::driver::sys::CUevent_flags::CU_EVENT_DEFAULT,
11840                        ))?,
11841                    );
11842                    phase_gate_up_done.push(
11843                        engine.ctx().new_event(Some(
11844                            cudarc::driver::sys::CUevent_flags::CU_EVENT_DEFAULT,
11845                        ))?,
11846                    );
11847                    phase_activation_done.push(
11848                        engine.ctx().new_event(Some(
11849                            cudarc::driver::sys::CUevent_flags::CU_EVENT_DEFAULT,
11850                        ))?,
11851                    );
11852                    phase_down_done.push(
11853                        engine.ctx().new_event(Some(
11854                            cudarc::driver::sys::CUevent_flags::CU_EVENT_DEFAULT,
11855                        ))?,
11856                    );
11857                }
11858            }
11859            let _main = e.gpu.enter_main()?;
11860            let slot_rows = e.uninit(capacity_pairs * experts.input_width)?;
11861            let slot_rows_raw = {
11862                use cudarc::driver::DevicePtr;
11863                let stream = e.stream();
11864                let (pointer, _guard) = slot_rows.device_ptr(&stream);
11865                pointer
11866            };
11867            *workspace_guard = Some(Nvfp4EpDeviceWorkspace {
11868                input,
11869                input_bf16,
11870                input_q8,
11871                input_q8_scales,
11872                sel,
11873                token_rows,
11874                global_pairs,
11875                route_w,
11876                gate_out,
11877                up_out,
11878                activation_bf16,
11879                activation_q8,
11880                activation_q8_scales,
11881                slot_rows,
11882                slot_rows_raw,
11883                route_weights: e.htod(&vec![0.0f32; capacity_pairs])?,
11884                graph_input: e.uninit(NVFP4_EP_GRAPH_BATCH_CAP * experts.input_width)?,
11885                graph_output: e.uninit(NVFP4_EP_GRAPH_BATCH_CAP * experts.input_width)?,
11886                graph_routes: None,
11887                graphs: std::iter::repeat_with(|| None)
11888                    .take(NVFP4_EP_GRAPH_BATCH_CAP + 1)
11889                    .collect(),
11890                ev_entry: e.ctx().new_event(None)?,
11891                ev_entry_device: e.ctx().ordinal(),
11892                ev_rank,
11893                phase_events: timing.then_some(Nvfp4EpPhaseEvents {
11894                    head: phase_head,
11895                    copy_done: phase_copy_done,
11896                    gate_up_done: phase_gate_up_done,
11897                    activation_done: phase_activation_done,
11898                    down_done: phase_down_done,
11899                }),
11900                capacity_tokens,
11901                experts_per_token,
11902            });
11903        }
11904        let workspace = workspace_guard
11905            .as_mut()
11906            .expect("W4A16 device-routed EP workspace initialized above");
11907        if workspace.experts_per_token != experts_per_token || tokens > workspace.capacity_tokens {
11908            return Err(format!(
11909                "W4A16 device-routed EP workspace tokens={} experts/token={} cannot serve \
11910                 tokens={tokens} experts/token={experts_per_token}",
11911                workspace.capacity_tokens, workspace.experts_per_token,
11912            )
11913            .into());
11914        }
11915
11916        if tokens <= NVFP4_EP_Q8_BATCH_CAP && parallel_ep_q8_act_enabled()? {
11917            if graph_enabled {
11918                return Err("MEMRA_PARALLEL_EP_GRAPH=1 is exact W4A16-only; disable \
11919                     MEMRA_PARALLEL_EP_Q8_ACT or the graph door"
11920                    .into());
11921            }
11922            return self.run_routed_experts_nvfp4_w4a8_device_routed(
11923                experts,
11924                e,
11925                input_dev,
11926                selected_dev,
11927                route_weights_dev,
11928                workspace,
11929                tokens,
11930                experts_per_token,
11931                activation_limit,
11932                pre_join,
11933            );
11934        }
11935
11936        if graph_enabled && !timing && pre_join.is_none() && tokens <= NVFP4_EP_GRAPH_BATCH_CAP {
11937            use cudarc::driver::DevicePtr;
11938            let route_ptrs = {
11939                let stream = e.stream();
11940                let (sel_ptr, _sel_guard) = selected_dev.device_ptr(&stream);
11941                let (weight_ptr, _weight_guard) = route_weights_dev.device_ptr(&stream);
11942                (sel_ptr, weight_ptr)
11943            };
11944            if let Some(graph_exec) = workspace.graphs[tokens].as_ref().map(|graph| graph.exec) {
11945                if workspace.graph_routes != Some(route_ptrs) {
11946                    return Err(format!(
11947                        "W4A16 EP graph route buffers moved: built={:?} current={route_ptrs:?}",
11948                        workspace.graph_routes,
11949                    )
11950                    .into());
11951                }
11952                let _main = e.gpu.enter_main()?;
11953                e.stream().memcpy_dtod(
11954                    &input_dev.slice(0..active_input_values),
11955                    &mut workspace.graph_input.slice_mut(0..active_input_values),
11956                )?;
11957                e.memset_zeros_view(
11958                    &mut workspace
11959                        .slot_rows
11960                        .slice_mut(0..pairs * experts.input_width),
11961                )?;
11962                unsafe {
11963                    let result = cudarc::driver::sys::cuGraphLaunch(
11964                        graph_exec,
11965                        e.stream().cu_stream() as cudarc::driver::sys::CUstream,
11966                    );
11967                    if result != cudarc::driver::sys::CUresult::CUDA_SUCCESS {
11968                        return Err(format!("W4A16 EP graph launch: {result:?}").into());
11969                    }
11970                }
11971                let mut output = e.uninit(active_input_values)?;
11972                e.stream().memcpy_dtod(
11973                    &workspace.graph_output.slice(0..active_input_values),
11974                    &mut output.slice_mut(0..active_input_values),
11975                )?;
11976                return Ok(output);
11977            }
11978        }
11979
11980        {
11981            let _main = e.gpu.enter_main()?;
11982            e.memset_zeros_view(
11983                &mut workspace
11984                    .slot_rows
11985                    .slice_mut(0..pairs * experts.input_width),
11986            )?;
11987            workspace.ev_entry.record(&e.stream())?;
11988        }
11989
11990        for (rank_index, engine) in self.ranks.iter().enumerate() {
11991            let _main = engine.gpu.enter_main()?;
11992            if let Some(events) = workspace.phase_events.as_ref() {
11993                events.head[rank_index].record(&engine.stream())?;
11994            }
11995            engine.stream().wait(&workspace.ev_entry)?;
11996            let Nvfp4EpDeviceWorkspace {
11997                input_bf16,
11998                sel,
11999                route_w,
12000                ..
12001            } = &mut *workspace;
12002            engine.nvfp4_ep_stage_inputs(
12003                input_dev,
12004                selected_dev,
12005                route_weights_dev,
12006                &mut input_bf16[rank_index],
12007                &mut sel[rank_index],
12008                &mut route_w[rank_index],
12009                active_input_values,
12010                pairs,
12011                false,
12012            )?;
12013            if let Some(events) = workspace.phase_events.as_ref() {
12014                events.copy_done[rank_index].record(&engine.stream())?;
12015            }
12016            let rank = &experts.ranks[rank_index];
12017            let owner_start = rank.expert_range.start;
12018            let owner_end = rank.expert_range.end;
12019            engine.qmatvec_nvfp4_bf16_ep_dual_slots_into(
12020                &rank.gate,
12021                &rank.up,
12022                &workspace.sel[rank_index],
12023                &workspace.input_bf16[rank_index],
12024                &mut workspace.gate_out[rank_index],
12025                &mut workspace.up_out[rank_index],
12026                pairs,
12027                experts_per_token,
12028                experts.input_width,
12029                experts.expert_width,
12030                owner_start,
12031                owner_end,
12032                experts.gate_row_bytes,
12033                rank.gate_expert_bytes,
12034            )?;
12035            if let Some(events) = workspace.phase_events.as_ref() {
12036                events.gate_up_done[rank_index].record(&engine.stream())?;
12037            }
12038            engine.silu_mul_scaled_host_expf_bf16_ep_slots_into(
12039                &workspace.gate_out[rank_index],
12040                &workspace.up_out[rank_index],
12041                &rank.macros_gate,
12042                &rank.macros_up,
12043                &workspace.sel[rank_index],
12044                owner_start,
12045                owner_end,
12046                activation_limit,
12047                &mut workspace.activation_bf16[rank_index],
12048                experts.expert_width,
12049                pairs,
12050            )?;
12051            if let Some(events) = workspace.phase_events.as_ref() {
12052                events.activation_done[rank_index].record(&engine.stream())?;
12053            }
12054            if tokens > 1 && pair_down_enabled {
12055                engine.qmatvec_nvfp4_bf16_ep_down_pairs_raw(
12056                    &rank.down,
12057                    &workspace.sel[rank_index],
12058                    &workspace.activation_bf16[rank_index],
12059                    &rank.macros_down,
12060                    workspace.slot_rows_raw,
12061                    pairs,
12062                    experts.expert_width,
12063                    experts.input_width,
12064                    owner_start,
12065                    owner_end,
12066                    experts.down_row_bytes,
12067                    rank.down_expert_bytes,
12068                )?;
12069            } else {
12070                engine.qmatvec_nvfp4_bf16_ep_down_slots_raw(
12071                    &rank.down,
12072                    &workspace.sel[rank_index],
12073                    &workspace.activation_bf16[rank_index],
12074                    &rank.macros_down,
12075                    workspace.slot_rows_raw,
12076                    pairs,
12077                    experts.expert_width,
12078                    experts.input_width,
12079                    owner_start,
12080                    owner_end,
12081                    experts.down_row_bytes,
12082                    rank.down_expert_bytes,
12083                )?;
12084            }
12085            if let Some(events) = workspace.phase_events.as_ref() {
12086                events.down_done[rank_index].record(&engine.stream())?;
12087            }
12088            workspace.ev_rank[rank_index].record(&engine.stream())?;
12089        }
12090
12091        if let Some(pre_join) = pre_join.as_mut() {
12092            pre_join()?;
12093        }
12094        let issue_ns_this = started
12095            .as_ref()
12096            .map(|started| started.elapsed().as_nanos() as u64);
12097        let join_started = timing.then(std::time::Instant::now);
12098        let output = {
12099            let _main = e.gpu.enter_main()?;
12100            for event in &workspace.ev_rank {
12101                e.stream().wait(event)?;
12102            }
12103            let mut output = e.uninit(tokens * experts.input_width)?;
12104            e.axpy_rows_seq_tokens_into(
12105                &workspace.slot_rows,
12106                route_weights_dev,
12107                &mut output,
12108                experts.input_width,
12109                experts_per_token,
12110                tokens,
12111            )?;
12112            output
12113        };
12114
12115        if let Some(started) = started {
12116            use std::sync::atomic::Ordering;
12117            e.stream().synchronize()?;
12118            let elapsed = started.elapsed().as_nanos() as u64;
12119            let join_ns_this = join_started
12120                .expect("timing join starts with total timing")
12121                .elapsed()
12122                .as_nanos() as u64;
12123            let mut phase_max_ms = [0.0f32; 5];
12124            if let Some(events) = workspace.phase_events.as_ref() {
12125                for rank_index in 0..world {
12126                    let engine = &self.ranks[rank_index];
12127                    let _main = engine.gpu.enter_main()?;
12128                    phase_max_ms[0] = phase_max_ms[0]
12129                        .max(events.head[rank_index].elapsed_ms(&events.copy_done[rank_index])?);
12130                    phase_max_ms[1] = phase_max_ms[1].max(
12131                        events.copy_done[rank_index]
12132                            .elapsed_ms(&events.gate_up_done[rank_index])?,
12133                    );
12134                    phase_max_ms[2] = phase_max_ms[2].max(
12135                        events.gate_up_done[rank_index]
12136                            .elapsed_ms(&events.activation_done[rank_index])?,
12137                    );
12138                    phase_max_ms[3] = phase_max_ms[3].max(
12139                        events.activation_done[rank_index]
12140                            .elapsed_ms(&events.down_done[rank_index])?,
12141                    );
12142                    phase_max_ms[4] = phase_max_ms[4]
12143                        .max(events.head[rank_index].elapsed_ms(&events.down_done[rank_index])?);
12144                }
12145            }
12146            let phase_ns = phase_max_ms.map(|ms| (ms as f64 * 1.0e6) as u64);
12147            let ns = TIMING_NS.fetch_add(elapsed, Ordering::Relaxed) + elapsed;
12148            let issue_ns = ISSUE_NS.fetch_add(
12149                issue_ns_this.expect("timing issue starts with total timing"),
12150                Ordering::Relaxed,
12151            ) + issue_ns_this.expect("timing issue starts with total timing");
12152            let join_ns = JOIN_NS.fetch_add(join_ns_this, Ordering::Relaxed) + join_ns_this;
12153            let copy_ns = COPY_NS.fetch_add(phase_ns[0], Ordering::Relaxed) + phase_ns[0];
12154            let gate_up_ns = GATE_UP_NS.fetch_add(phase_ns[1], Ordering::Relaxed) + phase_ns[1];
12155            let activation_ns =
12156                ACTIVATION_NS.fetch_add(phase_ns[2], Ordering::Relaxed) + phase_ns[2];
12157            let down_ns = DOWN_NS.fetch_add(phase_ns[3], Ordering::Relaxed) + phase_ns[3];
12158            let rank_span_ns = RANK_SPAN_NS.fetch_add(phase_ns[4], Ordering::Relaxed) + phase_ns[4];
12159            let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
12160            if calls.is_multiple_of(430) {
12161                eprintln!(
12162                    "[nvfp4-ep-device-router-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
12163                    ns as f64 / 1.0e6,
12164                    ns as f64 / calls as f64 / 1.0e3,
12165                );
12166                eprintln!(
12167                    "[nvfp4-ep-device-router-phases] calls={calls} issue_us={:.1} \
12168                     join_us={:.1} rank_span_us={:.1} copy_us={:.1} gate_up_us={:.1} \
12169                     activation_us={:.1} down_us={:.1}",
12170                    issue_ns as f64 / calls as f64 / 1.0e3,
12171                    join_ns as f64 / calls as f64 / 1.0e3,
12172                    rank_span_ns as f64 / calls as f64 / 1.0e3,
12173                    copy_ns as f64 / calls as f64 / 1.0e3,
12174                    gate_up_ns as f64 / calls as f64 / 1.0e3,
12175                    activation_ns as f64 / calls as f64 / 1.0e3,
12176                    down_ns as f64 / calls as f64 / 1.0e3,
12177                );
12178            }
12179        }
12180        if graph_enabled
12181            && !timing
12182            && pre_join.is_none()
12183            && tokens <= NVFP4_EP_GRAPH_BATCH_CAP
12184            && workspace.graphs[tokens].is_none()
12185        {
12186            e.stream().synchronize()?;
12187            let graph = self.build_nvfp4_ep_routes_graph(
12188                experts,
12189                e,
12190                workspace,
12191                selected_dev,
12192                route_weights_dev,
12193                tokens,
12194                experts_per_token,
12195                activation_limit,
12196            )?;
12197            workspace.graphs[tokens] = Some(graph);
12198            eprintln!(
12199                "[parallel-ep-graph] captured devices={:?} tokens={tokens} \
12200                 experts/token={experts_per_token} input=staged routes=fixed \
12201                 device_arithmetic=unchanged performance_claim=false",
12202                self.devices,
12203            );
12204        }
12205        Ok(output)
12206    }
12207
12208    #[allow(clippy::too_many_arguments)]
12209    fn run_routed_experts_nvfp4_w4a8_device_routed(
12210        &self,
12211        experts: &ResidentNvfp4ExpertParallel,
12212        e: &Engine,
12213        input_dev: &crate::CudaSlice<f32>,
12214        selected_dev: &crate::CudaSlice<i32>,
12215        route_weights_dev: &crate::CudaSlice<f32>,
12216        workspace: &mut Nvfp4EpDeviceWorkspace,
12217        tokens: usize,
12218        experts_per_token: usize,
12219        activation_limit: Option<f32>,
12220        mut pre_join: Option<&mut dyn FnMut() -> Result<(), Box<dyn std::error::Error>>>,
12221    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
12222        static TIMING_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
12223        static TIMING_CALLS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
12224        static ISSUE_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
12225        static JOIN_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
12226        static COPY_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
12227        static GATE_UP_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
12228        static ACTIVATION_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
12229        static DOWN_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
12230        static RANK_SPAN_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
12231        let timing = std::env::var("MEMRA_STEP_TP_TIMING").as_deref() == Ok("1");
12232        let started = timing.then(std::time::Instant::now);
12233        let pairs = tokens
12234            .checked_mul(experts_per_token)
12235            .ok_or("W4A8 device-routed EP route count overflow")?;
12236        let input_values = tokens
12237            .checked_mul(experts.input_width)
12238            .ok_or("W4A8 device-routed EP input size overflow")?;
12239        let scope = parallel_ep_q8_scope()?.unwrap_or(ParallelEpQ8Scope::All);
12240        let gate_up_paired = parallel_ep_q8_gu_paired_enabled(true, Some(scope))?;
12241
12242        {
12243            let _main = e.gpu.enter_main()?;
12244            e.memset_zeros_view(
12245                &mut workspace
12246                    .slot_rows
12247                    .slice_mut(0..pairs * experts.input_width),
12248            )?;
12249            workspace.ev_entry.record(&e.stream())?;
12250        }
12251        for (rank_index, engine) in self.ranks.iter().enumerate() {
12252            let _main = engine.gpu.enter_main()?;
12253            if let Some(events) = workspace.phase_events.as_ref() {
12254                events.head[rank_index].record(&engine.stream())?;
12255            }
12256            engine.stream().wait(&workspace.ev_entry)?;
12257            let rank = &experts.ranks[rank_index];
12258            let owner_start = rank.expert_range.start;
12259            let owner_end = rank.expert_range.end;
12260            match scope {
12261                ParallelEpQ8Scope::All | ParallelEpQ8Scope::GateUp => {
12262                    engine.quantize_q8_1_into(
12263                        input_dev,
12264                        tokens,
12265                        experts.input_width,
12266                        &mut workspace.input_q8[rank_index],
12267                        &mut workspace.input_q8_scales[rank_index],
12268                    )?;
12269                    engine.moe_sel_w_mirror(
12270                        selected_dev,
12271                        route_weights_dev,
12272                        &mut workspace.sel[rank_index],
12273                        &mut workspace.route_w[rank_index],
12274                        pairs,
12275                    )?;
12276                    if let Some(events) = workspace.phase_events.as_ref() {
12277                        events.copy_done[rank_index].record(&engine.stream())?;
12278                    }
12279                    if gate_up_paired {
12280                        engine.qmatvec_nvfp4_q8_ep_paired_slots_into(
12281                            &rank.gate,
12282                            &rank.up,
12283                            &workspace.sel[rank_index],
12284                            &workspace.input_q8[rank_index],
12285                            &workspace.input_q8_scales[rank_index],
12286                            &mut workspace.gate_out[rank_index],
12287                            &mut workspace.up_out[rank_index],
12288                            pairs,
12289                            experts_per_token,
12290                            experts.input_width,
12291                            experts.expert_width,
12292                            owner_start,
12293                            owner_end,
12294                            experts.gate_row_bytes,
12295                            rank.gate_expert_bytes,
12296                        )?;
12297                    } else {
12298                        engine.qmatvec_nvfp4_q8_ep_dual_slots_into(
12299                            &rank.gate,
12300                            &rank.up,
12301                            &workspace.sel[rank_index],
12302                            &workspace.input_q8[rank_index],
12303                            &workspace.input_q8_scales[rank_index],
12304                            &mut workspace.gate_out[rank_index],
12305                            &mut workspace.up_out[rank_index],
12306                            pairs,
12307                            experts_per_token,
12308                            experts.input_width,
12309                            experts.expert_width,
12310                            owner_start,
12311                            owner_end,
12312                            experts.gate_row_bytes,
12313                            rank.gate_expert_bytes,
12314                        )?;
12315                    }
12316                }
12317                ParallelEpQ8Scope::Down => {
12318                    engine.nvfp4_ep_stage_inputs(
12319                        input_dev,
12320                        selected_dev,
12321                        route_weights_dev,
12322                        &mut workspace.input_bf16[rank_index],
12323                        &mut workspace.sel[rank_index],
12324                        &mut workspace.route_w[rank_index],
12325                        input_values,
12326                        pairs,
12327                        false,
12328                    )?;
12329                    if let Some(events) = workspace.phase_events.as_ref() {
12330                        events.copy_done[rank_index].record(&engine.stream())?;
12331                    }
12332                    engine.qmatvec_nvfp4_bf16_ep_dual_slots_into(
12333                        &rank.gate,
12334                        &rank.up,
12335                        &workspace.sel[rank_index],
12336                        &workspace.input_bf16[rank_index],
12337                        &mut workspace.gate_out[rank_index],
12338                        &mut workspace.up_out[rank_index],
12339                        pairs,
12340                        experts_per_token,
12341                        experts.input_width,
12342                        experts.expert_width,
12343                        owner_start,
12344                        owner_end,
12345                        experts.gate_row_bytes,
12346                        rank.gate_expert_bytes,
12347                    )?;
12348                }
12349            }
12350            if let Some(events) = workspace.phase_events.as_ref() {
12351                events.gate_up_done[rank_index].record(&engine.stream())?;
12352            }
12353            match scope {
12354                ParallelEpQ8Scope::All | ParallelEpQ8Scope::Down => {
12355                    engine.silu_mul_scaled_host_expf_q8_ep_slots_into(
12356                        &workspace.gate_out[rank_index],
12357                        &workspace.up_out[rank_index],
12358                        &rank.macros_gate,
12359                        &rank.macros_up,
12360                        &workspace.sel[rank_index],
12361                        owner_start,
12362                        owner_end,
12363                        activation_limit,
12364                        &mut workspace.activation_q8[rank_index],
12365                        &mut workspace.activation_q8_scales[rank_index],
12366                        experts.expert_width,
12367                        pairs,
12368                    )?;
12369                    if let Some(events) = workspace.phase_events.as_ref() {
12370                        events.activation_done[rank_index].record(&engine.stream())?;
12371                    }
12372                    engine.qmatvec_nvfp4_q8_ep_down_slots_raw(
12373                        &rank.down,
12374                        &workspace.sel[rank_index],
12375                        &workspace.activation_q8[rank_index],
12376                        &workspace.activation_q8_scales[rank_index],
12377                        &rank.macros_down,
12378                        workspace.slot_rows_raw,
12379                        pairs,
12380                        experts.expert_width,
12381                        experts.input_width,
12382                        owner_start,
12383                        owner_end,
12384                        experts.down_row_bytes,
12385                        rank.down_expert_bytes,
12386                    )?;
12387                }
12388                ParallelEpQ8Scope::GateUp => {
12389                    engine.silu_mul_scaled_host_expf_bf16_ep_slots_into(
12390                        &workspace.gate_out[rank_index],
12391                        &workspace.up_out[rank_index],
12392                        &rank.macros_gate,
12393                        &rank.macros_up,
12394                        &workspace.sel[rank_index],
12395                        owner_start,
12396                        owner_end,
12397                        activation_limit,
12398                        &mut workspace.activation_bf16[rank_index],
12399                        experts.expert_width,
12400                        pairs,
12401                    )?;
12402                    if let Some(events) = workspace.phase_events.as_ref() {
12403                        events.activation_done[rank_index].record(&engine.stream())?;
12404                    }
12405                    engine.qmatvec_nvfp4_bf16_ep_down_slots_raw(
12406                        &rank.down,
12407                        &workspace.sel[rank_index],
12408                        &workspace.activation_bf16[rank_index],
12409                        &rank.macros_down,
12410                        workspace.slot_rows_raw,
12411                        pairs,
12412                        experts.expert_width,
12413                        experts.input_width,
12414                        owner_start,
12415                        owner_end,
12416                        experts.down_row_bytes,
12417                        rank.down_expert_bytes,
12418                    )?;
12419                }
12420            }
12421            if let Some(events) = workspace.phase_events.as_ref() {
12422                events.down_done[rank_index].record(&engine.stream())?;
12423            }
12424            workspace.ev_rank[rank_index].record(&engine.stream())?;
12425        }
12426
12427        if let Some(pre_join) = pre_join.as_mut() {
12428            pre_join()?;
12429        }
12430        let issue_ns_this = started
12431            .as_ref()
12432            .map(|started| started.elapsed().as_nanos() as u64);
12433        let join_started = timing.then(std::time::Instant::now);
12434        let output = {
12435            let _main = e.gpu.enter_main()?;
12436            for event in &workspace.ev_rank {
12437                e.stream().wait(event)?;
12438            }
12439            let mut output = e.uninit(input_values)?;
12440            e.axpy_rows_seq_tokens_into(
12441                &workspace.slot_rows,
12442                route_weights_dev,
12443                &mut output,
12444                experts.input_width,
12445                experts_per_token,
12446                tokens,
12447            )?;
12448            output
12449        };
12450        if let Some(started) = started {
12451            use std::sync::atomic::Ordering;
12452            e.stream().synchronize()?;
12453            let elapsed = started.elapsed().as_nanos() as u64;
12454            let join_ns_this = join_started
12455                .expect("timing join starts with total timing")
12456                .elapsed()
12457                .as_nanos() as u64;
12458            let mut phase_max_ms = [0.0f32; 5];
12459            if let Some(events) = workspace.phase_events.as_ref() {
12460                for rank_index in 0..self.ranks.len() {
12461                    let engine = &self.ranks[rank_index];
12462                    let _main = engine.gpu.enter_main()?;
12463                    phase_max_ms[0] = phase_max_ms[0]
12464                        .max(events.head[rank_index].elapsed_ms(&events.copy_done[rank_index])?);
12465                    phase_max_ms[1] = phase_max_ms[1].max(
12466                        events.copy_done[rank_index]
12467                            .elapsed_ms(&events.gate_up_done[rank_index])?,
12468                    );
12469                    phase_max_ms[2] = phase_max_ms[2].max(
12470                        events.gate_up_done[rank_index]
12471                            .elapsed_ms(&events.activation_done[rank_index])?,
12472                    );
12473                    phase_max_ms[3] = phase_max_ms[3].max(
12474                        events.activation_done[rank_index]
12475                            .elapsed_ms(&events.down_done[rank_index])?,
12476                    );
12477                    phase_max_ms[4] = phase_max_ms[4]
12478                        .max(events.head[rank_index].elapsed_ms(&events.down_done[rank_index])?);
12479                }
12480            }
12481            let phase_ns = phase_max_ms.map(|ms| (ms as f64 * 1.0e6) as u64);
12482            let ns = TIMING_NS.fetch_add(elapsed, Ordering::Relaxed) + elapsed;
12483            let issue_ns = ISSUE_NS.fetch_add(
12484                issue_ns_this.expect("timing issue starts with total timing"),
12485                Ordering::Relaxed,
12486            ) + issue_ns_this.expect("timing issue starts with total timing");
12487            let join_ns = JOIN_NS.fetch_add(join_ns_this, Ordering::Relaxed) + join_ns_this;
12488            let copy_ns = COPY_NS.fetch_add(phase_ns[0], Ordering::Relaxed) + phase_ns[0];
12489            let gate_up_ns = GATE_UP_NS.fetch_add(phase_ns[1], Ordering::Relaxed) + phase_ns[1];
12490            let activation_ns =
12491                ACTIVATION_NS.fetch_add(phase_ns[2], Ordering::Relaxed) + phase_ns[2];
12492            let down_ns = DOWN_NS.fetch_add(phase_ns[3], Ordering::Relaxed) + phase_ns[3];
12493            let rank_span_ns = RANK_SPAN_NS.fetch_add(phase_ns[4], Ordering::Relaxed) + phase_ns[4];
12494            let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
12495            if calls.is_multiple_of(430) {
12496                eprintln!(
12497                    "[nvfp4-ep-q8-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
12498                    ns as f64 / 1.0e6,
12499                    ns as f64 / calls as f64 / 1.0e3,
12500                );
12501                eprintln!(
12502                    "[nvfp4-ep-q8-phases] calls={calls} issue_us={:.1} join_us={:.1} \
12503                     rank_span_us={:.1} copy_us={:.1} gate_up_us={:.1} \
12504                     activation_us={:.1} down_us={:.1}",
12505                    issue_ns as f64 / calls as f64 / 1.0e3,
12506                    join_ns as f64 / calls as f64 / 1.0e3,
12507                    rank_span_ns as f64 / calls as f64 / 1.0e3,
12508                    copy_ns as f64 / calls as f64 / 1.0e3,
12509                    gate_up_ns as f64 / calls as f64 / 1.0e3,
12510                    activation_ns as f64 / calls as f64 / 1.0e3,
12511                    down_ns as f64 / calls as f64 / 1.0e3,
12512                );
12513            }
12514        }
12515        static LOGGED: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
12516        if !LOGGED.swap(true, std::sync::atomic::Ordering::Relaxed) {
12517            let (expert_input, post_activation, numeric_class) = match scope {
12518                ParallelEpQ8Scope::All => ("q8_1", "q8_1", "w4a8-internal"),
12519                ParallelEpQ8Scope::GateUp => ("q8_1", "bf16", "w4a8-gate-up-internal"),
12520                ParallelEpQ8Scope::Down => ("bf16", "q8_1", "w4a8-down-internal"),
12521            };
12522            eprintln!(
12523                "[parallel-ep-q8] devices={:?} tokens={tokens} scope={} \
12524                 expert_input={expert_input} post_activation={post_activation} \
12525                 gate_up_schedule={} \
12526                 external_boundary=bf16 numeric_class={numeric_class} \
12527                 host_expf=true accumulation=token-slot-order performance_claim=false",
12528                self.devices,
12529                scope.label(),
12530                if gate_up_paired {
12531                    "paired-cta"
12532                } else {
12533                    "separate-cta"
12534                },
12535            );
12536        }
12537        Ok(output)
12538    }
12539
12540    #[allow(clippy::too_many_arguments)]
12541    fn build_nvfp4_ep_routes_graph(
12542        &self,
12543        experts: &ResidentNvfp4ExpertParallel,
12544        e: &Engine,
12545        workspace: &mut Nvfp4EpDeviceWorkspace,
12546        selected_dev: &crate::CudaSlice<i32>,
12547        route_weights_dev: &crate::CudaSlice<f32>,
12548        tokens: usize,
12549        experts_per_token: usize,
12550        activation_limit: Option<f32>,
12551    ) -> Result<RoutesGraph, Box<dyn std::error::Error>> {
12552        use cudarc::driver::DevicePtr;
12553        use cudarc::driver::sys;
12554
12555        fn cu_try(result: sys::CUresult, context: &str) -> Result<(), Box<dyn std::error::Error>> {
12556            if result == sys::CUresult::CUDA_SUCCESS {
12557                Ok(())
12558            } else {
12559                Err(format!("{context}: {result:?}").into())
12560            }
12561        }
12562
12563        let world = self.ranks.len();
12564        if world != experts.ranks.len() || !(2..=PRODUCT_MAX_CARDS).contains(&world) {
12565            return Err(format!(
12566                "W4A16 EP graph world {world} != expert ranks {}",
12567                experts.ranks.len()
12568            )
12569            .into());
12570        }
12571        let width = experts.input_width;
12572        if !(1..=NVFP4_EP_GRAPH_BATCH_CAP).contains(&tokens) {
12573            return Err(format!(
12574                "W4A16 EP graph tokens {tokens} outside 1..={NVFP4_EP_GRAPH_BATCH_CAP}"
12575            )
12576            .into());
12577        }
12578        let pairs = tokens
12579            .checked_mul(experts_per_token)
12580            .ok_or("W4A16 EP graph pair count overflow")?;
12581        let input_values = tokens
12582            .checked_mul(width)
12583            .ok_or("W4A16 EP graph input size overflow")?;
12584        let root_stream = e.stream();
12585        let (input_ptr, _input_guard) = workspace.graph_input.device_ptr(&root_stream);
12586        let (selected_ptr, _selected_guard) = selected_dev.device_ptr(&root_stream);
12587        let (weights_ptr, _weights_guard) = route_weights_dev.device_ptr(&root_stream);
12588        let route_ptrs = (selected_ptr, weights_ptr);
12589
12590        let mut children = Vec::with_capacity(world + 1);
12591        for rank_index in 0..world {
12592            let engine = &self.ranks[rank_index];
12593            let rank = &experts.ranks[rank_index];
12594            let owner_start = rank.expert_range.start;
12595            let owner_end = rank.expert_range.end;
12596            let _main = engine.gpu.enter_main()?;
12597            let (child, _retained) = engine.capture_graph_retained(|_| {
12598                engine.nvfp4_ep_stage_inputs_raw(
12599                    input_ptr,
12600                    selected_ptr,
12601                    weights_ptr,
12602                    &mut workspace.input_bf16[rank_index],
12603                    &mut workspace.sel[rank_index],
12604                    &mut workspace.route_w[rank_index],
12605                    input_values,
12606                    pairs,
12607                    false,
12608                )?;
12609                engine.qmatvec_nvfp4_bf16_ep_dual_slots_into(
12610                    &rank.gate,
12611                    &rank.up,
12612                    &workspace.sel[rank_index],
12613                    &workspace.input_bf16[rank_index],
12614                    &mut workspace.gate_out[rank_index],
12615                    &mut workspace.up_out[rank_index],
12616                    pairs,
12617                    experts_per_token,
12618                    width,
12619                    experts.expert_width,
12620                    owner_start,
12621                    owner_end,
12622                    experts.gate_row_bytes,
12623                    rank.gate_expert_bytes,
12624                )?;
12625                engine.silu_mul_scaled_host_expf_bf16_ep_slots_into(
12626                    &workspace.gate_out[rank_index],
12627                    &workspace.up_out[rank_index],
12628                    &rank.macros_gate,
12629                    &rank.macros_up,
12630                    &workspace.sel[rank_index],
12631                    owner_start,
12632                    owner_end,
12633                    activation_limit,
12634                    &mut workspace.activation_bf16[rank_index],
12635                    experts.expert_width,
12636                    pairs,
12637                )?;
12638                engine.qmatvec_nvfp4_bf16_ep_down_slots_raw(
12639                    &rank.down,
12640                    &workspace.sel[rank_index],
12641                    &workspace.activation_bf16[rank_index],
12642                    &rank.macros_down,
12643                    workspace.slot_rows_raw,
12644                    pairs,
12645                    experts.expert_width,
12646                    width,
12647                    owner_start,
12648                    owner_end,
12649                    experts.down_row_bytes,
12650                    rank.down_expert_bytes,
12651                )?;
12652                Ok(())
12653            })?;
12654            children.push(child);
12655        }
12656
12657        {
12658            let _main = e.gpu.enter_main()?;
12659            let (child, _retained) = e.capture_graph_retained(|_| {
12660                e.axpy_rows_seq_tokens_into(
12661                    &workspace.slot_rows,
12662                    route_weights_dev,
12663                    &mut workspace.graph_output,
12664                    width,
12665                    experts_per_token,
12666                    tokens,
12667                )
12668            })?;
12669            children.push(child);
12670        }
12671
12672        let mut parent: sys::CUgraph = std::ptr::null_mut();
12673        unsafe {
12674            cu_try(sys::cuGraphCreate(&mut parent, 0), "W4A16 EP cuGraphCreate")?;
12675        }
12676        let mut rank_nodes = Vec::with_capacity(world);
12677        for (rank_index, child) in children.iter().take(world).enumerate() {
12678            let mut node: sys::CUgraphNode = std::ptr::null_mut();
12679            unsafe {
12680                cu_try(
12681                    sys::cuGraphAddChildGraphNode(
12682                        &mut node,
12683                        parent,
12684                        std::ptr::null(),
12685                        0,
12686                        child.cu_graph(),
12687                    ),
12688                    &format!("W4A16 EP graph rank {rank_index}"),
12689                )?;
12690            }
12691            rank_nodes.push(node);
12692        }
12693        let mut combine_node: sys::CUgraphNode = std::ptr::null_mut();
12694        unsafe {
12695            cu_try(
12696                sys::cuGraphAddChildGraphNode(
12697                    &mut combine_node,
12698                    parent,
12699                    rank_nodes.as_ptr(),
12700                    rank_nodes.len(),
12701                    children[world].cu_graph(),
12702                ),
12703                "W4A16 EP graph combine",
12704            )?;
12705        }
12706        let mut exec: sys::CUgraphExec = std::ptr::null_mut();
12707        unsafe {
12708            cu_try(
12709                sys::cuGraphInstantiateWithFlags(&mut exec, parent, 0),
12710                "W4A16 EP graph instantiate",
12711            )?;
12712        }
12713        workspace.graph_routes = Some(route_ptrs);
12714        Ok(RoutesGraph {
12715            exec,
12716            parent,
12717            _children: children,
12718        })
12719    }
12720
12721    /// Device-resident routed NVFP4 expert program (decode shape, t=1 rows). The geometry gift
12722    /// this exploits: gate/up column halves land on the SAME rank that owns the matching down
12723    /// canonical shard (act[rank r] is exactly down-shard r's input-column window), so the whole
12724    /// expert interior — gate, up, macro-scaled SwiGLU, down partial, route-weighted accumulate —
12725    /// runs rank-local with ZERO cross-rank transfer. Per (token, layer): one input upload per
12726    /// rank, one fenced peer copy of the remote accumulator, one root add, one readback.
12727    ///
12728    /// Numeric class: device silu (silu_mul_scaled) with gate/up macros folded as gs/us and the
12729    /// down macro folded into the accumulate scalar (weight * macro_down — exact, both are
12730    /// per-expert constants). This matches the owning-stage MoE dev-path semantics, NOT the
12731    /// host-canonical program bit-for-bit; gate it with argmax + relative bounds against the
12732    /// host-canonical oracle, and with repeat determinism against itself.
12733    /// Clamped layers refuse (they stay on the EP program).
12734    pub fn run_tensor_parallel_routes_nvfp4_device(
12735        &self,
12736        experts: &ResidentNvfp4TensorParallel,
12737        input: &[f32],
12738        selected: &[usize],
12739        route_weights: &[f32],
12740        experts_per_token: usize,
12741        activation_limit: Option<f32>,
12742    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
12743        validate_activations(input, 1, experts.input_width)?;
12744        if selected.len() != experts_per_token || route_weights.len() != experts_per_token {
12745            return Err(format!(
12746                "NVFP4 device routes selected={} weights={} != experts/token {experts_per_token}",
12747                selected.len(),
12748                route_weights.len(),
12749            )
12750            .into());
12751        }
12752        if !route_weights.iter().all(|weight| weight.is_finite()) {
12753            return Err("NVFP4 device route weights contain a non-finite value".into());
12754        }
12755        let world = self.ranks.len();
12756        if world != NVFP4_CANONICAL_ROW_SHARDS {
12757            return Err(format!(
12758                "NVFP4 device routes require world == canonical shard grid \
12759                 ({NVFP4_CANONICAL_ROW_SHARDS}), got {world}"
12760            )
12761            .into());
12762        }
12763        let local_out = if experts.ep2 {
12764            experts.expert_width
12765        } else {
12766            experts.expert_width / world
12767        };
12768
12769        // MEMRA_STEP_TP_TIMING=1: cumulative wall-clock of this program, printed every 430 calls
12770        // (~one 43-layer decode step's worth) so a bench run decomposes expert-program time vs
12771        // everything else without Nsight.
12772        static TIMING_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
12773        static TIMING_CALLS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
12774        let timing = std::env::var("MEMRA_STEP_TP_TIMING").as_deref() == Ok("1");
12775        let started = timing.then(std::time::Instant::now);
12776
12777        let n_sel = experts_per_token;
12778        let mut workspace_guard = experts
12779            .device_workspace
12780            .lock()
12781            .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
12782        if workspace_guard.is_none() {
12783            let mut gate_out = Vec::with_capacity(world);
12784            let mut up_out = Vec::with_capacity(world);
12785            let mut act_q = Vec::with_capacity(world);
12786            let mut act_d = Vec::with_capacity(world);
12787            let mut sel = Vec::with_capacity(world);
12788            let mut partial = Vec::with_capacity(world);
12789            let mut accumulator = Vec::with_capacity(world);
12790            let mut combine_w = Vec::with_capacity(world);
12791            let mut route_w = Vec::with_capacity(world);
12792            let mut in_q = Vec::with_capacity(world);
12793            let mut in_d = Vec::with_capacity(world);
12794            let mut input = Vec::with_capacity(world);
12795            let mut ev_rank = Vec::with_capacity(world);
12796            let moe_direct = moe_direct_on();
12797            for (rank, engine) in self.ranks.iter().enumerate() {
12798                let _main = engine.gpu.enter_main()?;
12799                gate_out.push(engine.uninit(n_sel * local_out)?);
12800                up_out.push(engine.uninit(n_sel * local_out)?);
12801                act_q.push(engine.uninit_i8(n_sel * local_out)?);
12802                act_d.push(engine.uninit(n_sel * local_out / 32)?);
12803                sel.push(engine.htod_i32(&vec![0i32; n_sel])?);
12804                partial.push(engine.uninit(n_sel * experts.input_width)?);
12805                // Direct join: peer accumulators live on ROOT (single P2P store pass).
12806                if moe_direct && rank != 0 {
12807                    let root = &self.ranks[0];
12808                    let _root_main = root.gpu.enter_main()?;
12809                    accumulator.push(root.zeros(experts.input_width)?);
12810                } else {
12811                    accumulator.push(engine.zeros(experts.input_width)?);
12812                }
12813                combine_w.push(engine.htod(&vec![0.0f32; n_sel])?);
12814                route_w.push(engine.htod(&vec![0.0f32; n_sel])?);
12815                in_q.push(engine.uninit_i8(experts.input_width)?);
12816                in_d.push(engine.uninit(experts.input_width / 32)?);
12817                input.push(engine.uninit(experts.input_width)?);
12818                ev_rank.push(engine.ctx().new_event(None)?);
12819            }
12820            let root = &self.ranks[0];
12821            let _main = root.gpu.enter_main()?;
12822            *workspace_guard = Some(Nvfp4DeviceRoutesWorkspace {
12823                prestaged: false,
12824                rank1_routed: false,
12825                ev_input: None,
12826                fence_flags_raw: 0,
12827                fence_ticket: 0,
12828                gate_out,
12829                up_out,
12830                act_q,
12831                act_d,
12832                sel,
12833                partial,
12834                accumulator,
12835                combine_w,
12836                route_w,
12837                in_q,
12838                in_d,
12839                dev_route_e: None,
12840                in_stage_e: None,
12841                out_stage_e: None,
12842                routes_graph: None,
12843                raw_dev_route_e: None,
12844                raw_combine: None,
12845                raw_input: Vec::new(),
12846                raw_sel: Vec::new(),
12847                raw_route_w: Vec::new(),
12848                remote: root.uninit(experts.input_width)?,
12849                combined: root.uninit(experts.input_width)?,
12850                n_sel,
12851                input,
12852                ev_rank,
12853                ev_done: Some(root.ctx().new_event(None)?),
12854                ev_entry: None,
12855            });
12856        }
12857        let workspace = workspace_guard
12858            .as_mut()
12859            .expect("NVFP4 device routes workspace initialized above");
12860        // EP2 uses this call only as the workspace-arming warmup (the prejoin path drives
12861        // decode); its host-routed sweep semantics do not apply to whole-expert banks.
12862        if experts.ep2 {
12863            return Ok(vec![0.0f32; experts.input_width]);
12864        }
12865        if workspace.n_sel != n_sel {
12866            return Err(format!(
12867                "NVFP4 device routes experts/token changed: workspace {} != call {n_sel}",
12868                workspace.n_sel
12869            )
12870            .into());
12871        }
12872        for &expert in selected {
12873            if expert >= experts.expert_count {
12874                return Err(format!(
12875                    "NVFP4 device selected expert {expert} outside 0..{}",
12876                    experts.expert_count
12877                )
12878                .into());
12879            }
12880        }
12881        let sel_i32 = selected
12882            .iter()
12883            .map(|&expert| expert as i32)
12884            .collect::<Vec<_>>();
12885
12886        // BATCHED program (2026-08-20): per rank, ONE launch per sweep (gate, up, SwiGLU,
12887        // down) covers every selected expert via the selection array and the contiguous bank —
12888        // the per-expert launch loop was pure host latency (~100 sequential launches/layer,
12889        // 291us wall for ~35us of arithmetic). Per (expert, row) the kernels are bit-identical
12890        // to the per-expert forms, and the route-weight axpy chain keeps its exact sequential
12891        // accumulation order — the program's values are unchanged.
12892        for (rank_index, engine) in self.ranks.iter().enumerate() {
12893            let _main = engine.gpu.enter_main()?;
12894            let device_input = engine.htod(input)?;
12895            let Nvfp4DeviceRoutesWorkspace { in_q, in_d, .. } = &mut *workspace;
12896            engine.quantize_q8_1_into(
12897                &device_input,
12898                1,
12899                experts.input_width,
12900                &mut in_q[rank_index],
12901                &mut in_d[rank_index],
12902            )?;
12903            // device_input frees on this rank's stream after the quantize — same-stream order.
12904        }
12905        self.nvfp4_routes_batched_sweeps(
12906            experts,
12907            workspace,
12908            selected,
12909            route_weights,
12910            &sel_i32,
12911            local_out,
12912            n_sel,
12913            activation_limit,
12914            false,
12915        )?;
12916
12917        // Combine: fence the remote shard's producer stream, peer-copy its accumulator to root,
12918        // reduce in canonical shard order, read back once.
12919        let root = &self.ranks[0];
12920        for engine in &self.ranks[1..] {
12921            let _main = engine.gpu.enter_main()?;
12922            engine.stream().synchronize()?;
12923        }
12924        let _main = root.gpu.enter_main()?;
12925        root.stream()
12926            .memcpy_dtod(&workspace.accumulator[1], &mut workspace.remote)?;
12927        root.add(
12928            &workspace.accumulator[0],
12929            &workspace.remote,
12930            &mut workspace.combined,
12931            experts.input_width,
12932        )?;
12933        let output = root.dtoh(&workspace.combined)?;
12934        if let Some(started) = started {
12935            use std::sync::atomic::Ordering;
12936            let ns = TIMING_NS.fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
12937                + started.elapsed().as_nanos() as u64;
12938            let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
12939            if calls.is_multiple_of(430) {
12940                eprintln!(
12941                    "[nvfp4-dev-routes-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
12942                    ns as f64 / 1.0e6,
12943                    ns as f64 / calls as f64 / 1.0e3,
12944                );
12945            }
12946        }
12947        Ok(output)
12948    }
12949
12950    /// The shared batched sweeps of the device routes program: per rank, upload the selection,
12951    /// reset the accumulator, run the gate/up/SwiGLU/down batched launches, then the
12952    /// route-weight axpy chain in exact sequential per-pair order. Every op queues on the
12953    /// owning rank's stream; callers own input acquisition and the combine.
12954    #[allow(clippy::too_many_arguments)]
12955    fn nvfp4_routes_batched_sweeps(
12956        &self,
12957        experts: &ResidentNvfp4TensorParallel,
12958        workspace: &mut Nvfp4DeviceRoutesWorkspace,
12959        selected: &[usize],
12960        route_weights: &[f32],
12961        sel_i32: &[i32],
12962        local_out: usize,
12963        n_sel: usize,
12964        activation_limit: Option<f32>,
12965        device_routed: bool,
12966    ) -> Result<(), Box<dyn std::error::Error>> {
12967        for rank_index in 0..self.ranks.len() {
12968            self.nvfp4_routes_batched_sweeps_rank(
12969                experts,
12970                workspace,
12971                selected,
12972                route_weights,
12973                sel_i32,
12974                local_out,
12975                n_sel,
12976                activation_limit,
12977                device_routed,
12978                rank_index,
12979            )?;
12980        }
12981        Ok(())
12982    }
12983
12984    /// One rank's sweeps (the per-rank body of `nvfp4_routes_batched_sweeps`) — separated so
12985    /// the graph door can capture each rank's segment on its own stream.
12986    #[allow(clippy::too_many_arguments)]
12987    fn nvfp4_routes_batched_sweeps_rank(
12988        &self,
12989        experts: &ResidentNvfp4TensorParallel,
12990        workspace: &mut Nvfp4DeviceRoutesWorkspace,
12991        selected: &[usize],
12992        route_weights: &[f32],
12993        sel_i32: &[i32],
12994        local_out: usize,
12995        n_sel: usize,
12996        activation_limit: Option<f32>,
12997        device_routed: bool,
12998        rank_index: usize,
12999    ) -> Result<(), Box<dyn std::error::Error>> {
13000        {
13001            let engine = &self.ranks[rank_index];
13002            let _main = engine.gpu.enter_main()?;
13003            // EP2: whole-expert full-width sweep, owner-guarded; down+combine fused writes
13004            // this rank's slot-ordered partial straight into its accumulator (the join is
13005            // unchanged). Device-routed only — the host-routed arm and the graph door refuse
13006            // at the caller.
13007            if experts.ep2 {
13008                if !device_routed {
13009                    return Err("NVFP4 EP2 banks support the device-routed decode arm only".into());
13010                }
13011                let gate_bank = &experts.gate[rank_index];
13012                let up_bank = &experts.up[rank_index];
13013                if gate_bank.local_out != experts.expert_width
13014                    || gate_bank.expert_bytes != up_bank.expert_bytes
13015                {
13016                    return Err("NVFP4 EP2 bank geometry drifted".into());
13017                }
13018                {
13019                    let Nvfp4DeviceRoutesWorkspace {
13020                        sel,
13021                        gate_out,
13022                        up_out,
13023                        in_q,
13024                        in_d,
13025                        ..
13026                    } = &mut *workspace;
13027                    engine.qmatvec_nvfp4_sel_gu_ep_into(
13028                        &gate_bank.bank,
13029                        &up_bank.bank,
13030                        &sel[rank_index],
13031                        &in_q[rank_index],
13032                        &in_d[rank_index],
13033                        &mut gate_out[rank_index],
13034                        &mut up_out[rank_index],
13035                        n_sel,
13036                        gate_bank.in_features,
13037                        gate_bank.local_out,
13038                        gate_bank.row_bytes,
13039                        gate_bank.expert_bytes,
13040                        rank_index,
13041                    )?;
13042                }
13043                {
13044                    let Nvfp4DeviceRoutesWorkspace {
13045                        gate_out,
13046                        up_out,
13047                        sel,
13048                        act_q,
13049                        act_d,
13050                        ..
13051                    } = &mut *workspace;
13052                    engine.silu_mul_scaled_q8_1_sel_ep_into(
13053                        &gate_out[rank_index],
13054                        &up_out[rank_index],
13055                        &experts.macros_gate_dev[rank_index],
13056                        &experts.macros_up_dev[rank_index],
13057                        &sel[rank_index],
13058                        activation_limit,
13059                        &mut act_q[rank_index],
13060                        &mut act_d[rank_index],
13061                        local_out,
13062                        n_sel,
13063                        rank_index,
13064                    )?;
13065                }
13066                let shard = &experts.down[rank_index];
13067                if shard.device_rank != rank_index || shard.local_in != local_out {
13068                    return Err("NVFP4 EP2 down bank placement drifted".into());
13069                }
13070                {
13071                    let Nvfp4DeviceRoutesWorkspace {
13072                        sel,
13073                        act_q,
13074                        act_d,
13075                        route_w,
13076                        accumulator,
13077                        ..
13078                    } = &mut *workspace;
13079                    engine.qmatvec_nvfp4_sel_down8_ep_into(
13080                        &shard.bank,
13081                        &sel[rank_index],
13082                        &act_q[rank_index],
13083                        &act_d[rank_index],
13084                        &route_w[rank_index],
13085                        &experts.macros_down_dev[rank_index],
13086                        &mut accumulator[rank_index],
13087                        n_sel,
13088                        shard.local_in,
13089                        shard.out_features,
13090                        shard.row_bytes,
13091                        shard.expert_bytes,
13092                        local_out,
13093                        local_out / 32,
13094                        rank_index,
13095                    )?;
13096                }
13097                return Ok(());
13098            }
13099            if !device_routed {
13100                engine.htod_i32_into(&mut workspace.sel[rank_index], sel_i32)?;
13101                // Folded combine weights (route_weight x down macro) — one 40-byte upload
13102                // replaces the accumulator reset + n_sel sequential axpy launches below.
13103                let folded = (0..n_sel)
13104                    .map(|pair| route_weights[pair] * experts.macros_down[selected[pair]])
13105                    .collect::<Vec<_>>();
13106                let mut view = workspace.combine_w[rank_index].slice_mut(0..n_sel);
13107                engine.stream().memcpy_htod(&folded, &mut view)?;
13108            }
13109            let gate_bank = &experts.gate[rank_index];
13110            let up_bank = &experts.up[rank_index];
13111            let (aq, ad) = (&workspace.in_q[rank_index], &workspace.in_d[rank_index]);
13112            // PROGRAM 2 (`MEMRA_NVFP4_SEL_GU`): the two sweeps share sel/aq/ad and, when the
13113            // geometry matches exactly, one launch covers both — per-row bit-identical, double
13114            // the grid fill. Armed by ITS OWN door, and additionally guarded on both banks
13115            // reporting slot-major, because the fused kernel reads only that byte map. Its door
13116            // is separate from PROGRAM 1's on purpose: in the removed implementation it armed
13117            // silently on the bank predicate, so the bank layout and this fusion could never be
13118            // priced apart (DIAGNOSIS.md, "the bisect could not name the mechanism").
13119            let gu_fused = sel_gu_fused_on()
13120                && gate_bank.slot_major
13121                && up_bank.slot_major
13122                && gate_bank.in_features == up_bank.in_features
13123                && gate_bank.local_out == up_bank.local_out
13124                && gate_bank.row_bytes == up_bank.row_bytes
13125                && gate_bank.expert_bytes == up_bank.expert_bytes;
13126            // ENGAGEMENT RECEIPT for PROGRAM 2, one line per DISTINCT decision combo. The
13127            // removed implementation had this behind MEMRA_SWEEP_TRACE and its own comment said
13128            // why it existed: "a silently-dead fusion reads as roofline physics without it".
13129            // It is unconditional here, because a perf row whose fusion never armed is worse
13130            // than no row -- it is a number that looks like evidence.
13131            {
13132                static SEEN_GU: std::sync::Mutex<Vec<(bool, bool, bool)>> =
13133                    std::sync::Mutex::new(Vec::new());
13134                let combo = (gu_fused, sel_gu_fused_on(), gate_bank.slot_major);
13135                let mut seen = SEEN_GU.lock().unwrap();
13136                if !seen.contains(&combo) {
13137                    seen.push(combo);
13138                    eprintln!(
13139                        "[nvfp4-sweep] gu_fused={} door={} slot_major={} geometry_match={} \
13140                         in_f={} out_f={} n_sel={n_sel}",
13141                        gu_fused,
13142                        sel_gu_fused_on(),
13143                        gate_bank.slot_major,
13144                        gate_bank.in_features == up_bank.in_features
13145                            && gate_bank.local_out == up_bank.local_out
13146                            && gate_bank.row_bytes == up_bank.row_bytes
13147                            && gate_bank.expert_bytes == up_bank.expert_bytes,
13148                        gate_bank.in_features,
13149                        gate_bank.local_out
13150                    );
13151                }
13152            }
13153            if gu_fused {
13154                let Nvfp4DeviceRoutesWorkspace {
13155                    sel,
13156                    gate_out,
13157                    up_out,
13158                    in_q,
13159                    in_d,
13160                    ..
13161                } = &mut *workspace;
13162                engine.qmatvec_nvfp4_sel_gu_into(
13163                    &gate_bank.bank,
13164                    &up_bank.bank,
13165                    &sel[rank_index],
13166                    &in_q[rank_index],
13167                    &in_d[rank_index],
13168                    &mut gate_out[rank_index],
13169                    &mut up_out[rank_index],
13170                    n_sel,
13171                    gate_bank.in_features,
13172                    gate_bank.local_out,
13173                    gate_bank.row_bytes,
13174                    gate_bank.expert_bytes,
13175                    gate_bank.slot_major,
13176                )?;
13177            } else {
13178                engine.qmatvec_nvfp4_sel_into(
13179                    &gate_bank.bank,
13180                    &workspace.sel[rank_index],
13181                    aq,
13182                    ad,
13183                    &mut workspace.gate_out[rank_index],
13184                    n_sel,
13185                    gate_bank.in_features,
13186                    gate_bank.local_out,
13187                    gate_bank.row_bytes,
13188                    gate_bank.expert_bytes,
13189                    0,
13190                    0,
13191                    gate_bank.slot_major,
13192                )?;
13193                engine.qmatvec_nvfp4_sel_into(
13194                    &up_bank.bank,
13195                    &workspace.sel[rank_index],
13196                    aq,
13197                    ad,
13198                    &mut workspace.up_out[rank_index],
13199                    n_sel,
13200                    up_bank.in_features,
13201                    up_bank.local_out,
13202                    up_bank.row_bytes,
13203                    up_bank.expert_bytes,
13204                    0,
13205                    0,
13206                    up_bank.slot_major,
13207                )?;
13208            }
13209            // Fused macro-scaled SwiGLU that EMITS q8_1 directly — down consumes it with no
13210            // separate quantize launch. act[rank] IS down canonical shard `rank_index`'s
13211            // input-column window (the geometry gift; see the method doc).
13212            {
13213                let Nvfp4DeviceRoutesWorkspace {
13214                    gate_out,
13215                    up_out,
13216                    sel,
13217                    act_q,
13218                    act_d,
13219                    ..
13220                } = &mut *workspace;
13221                engine.silu_mul_scaled_q8_1_sel_into(
13222                    &gate_out[rank_index],
13223                    &up_out[rank_index],
13224                    &experts.macros_gate_dev[rank_index],
13225                    &experts.macros_up_dev[rank_index],
13226                    &sel[rank_index],
13227                    activation_limit,
13228                    &mut act_q[rank_index],
13229                    &mut act_d[rank_index],
13230                    local_out,
13231                    n_sel,
13232                )?;
13233            }
13234            let shard = &experts.down[rank_index];
13235            if shard.device_rank != rank_index || shard.local_in != local_out {
13236                return Err(
13237                    "NVFP4 device routes: down canonical shard placement drifted from \
13238                     the gate/up column split"
13239                        .into(),
13240                );
13241            }
13242            // PROGRAM 3 (`MEMRA_NVFP4_SEL_DOWN8`): the down sweep and the route-weight combine
13243            // in ONE launch, one warp per SLOT instead of one warp per (row, slot), and the
13244            // `n_sel x out_f` partial round trip gone. Device-routed only — the host-routed arm
13245            // folds the macro into `combine_w` instead of reading `md` on device — and
13246            // slot-major only, read off the shard. `nsb <= 32` is the fit-block class the reduce
13247            // identity is argued at. Its own door, priced LAST and only on green gates for the
13248            // programs beneath it (lane mandate, milestone 5).
13249            let down8 =
13250                device_routed && sel_down8_on() && shard.slot_major && (shard.local_in >> 5) <= 32;
13251            // ENGAGEMENT RECEIPT for PROGRAM 3, one line per distinct combo. `device_routed`
13252            // and `nsb <= 32` are printed because they are the two eligibility conditions that
13253            // can silently disqualify the arm on a geometry or a route the operator did not
13254            // expect -- exactly the case where a flat perf row would be misread as "no win".
13255            {
13256                static SEEN_D8: std::sync::Mutex<Vec<(bool, bool, bool, bool)>> =
13257                    std::sync::Mutex::new(Vec::new());
13258                let combo = (down8, sel_down8_on(), device_routed, shard.slot_major);
13259                let mut seen = SEEN_D8.lock().unwrap();
13260                if !seen.contains(&combo) {
13261                    seen.push(combo);
13262                    // `door_source` is what makes this line a DEFAULT-flip receipt rather than
13263                    // only an engagement receipt: `door=true door_source=default-on` is the
13264                    // flip doing the work, `env=1` is a recipe doing it, and
13265                    // `down8=false door=true` is the silent-no-op shape that PROGRAM 1's
13266                    // default exists to prevent.
13267                    eprintln!(
13268                        "[nvfp4-sweep] down8={} door={} door_source={} device_routed={} \
13269                         slot_major={} nsb={} in_class={} n_sel={n_sel}",
13270                        down8,
13271                        sel_down8_on(),
13272                        sel_down8_source().1,
13273                        device_routed,
13274                        shard.slot_major,
13275                        shard.local_in >> 5,
13276                        (shard.local_in >> 5) <= 32
13277                    );
13278                }
13279            }
13280            if down8 {
13281                let Nvfp4DeviceRoutesWorkspace {
13282                    sel,
13283                    act_q,
13284                    act_d,
13285                    route_w,
13286                    accumulator,
13287                    ..
13288                } = &mut *workspace;
13289                engine.qmatvec_nvfp4_sel_down8_into(
13290                    &shard.bank,
13291                    &sel[rank_index],
13292                    &act_q[rank_index],
13293                    &act_d[rank_index],
13294                    &route_w[rank_index],
13295                    &experts.macros_down_dev[rank_index],
13296                    &mut accumulator[rank_index],
13297                    n_sel,
13298                    shard.local_in,
13299                    shard.out_features,
13300                    shard.row_bytes,
13301                    shard.expert_bytes,
13302                    local_out,
13303                    local_out / 32,
13304                    shard.slot_major,
13305                )?;
13306            } else {
13307                let Nvfp4DeviceRoutesWorkspace {
13308                    sel,
13309                    act_q,
13310                    act_d,
13311                    partial,
13312                    ..
13313                } = &mut *workspace;
13314                engine.qmatvec_nvfp4_sel_into(
13315                    &shard.bank,
13316                    &sel[rank_index],
13317                    &act_q[rank_index],
13318                    &act_d[rank_index],
13319                    &mut partial[rank_index],
13320                    n_sel,
13321                    shard.local_in,
13322                    shard.out_features,
13323                    shard.row_bytes,
13324                    shard.expert_bytes,
13325                    local_out,
13326                    local_out / 32,
13327                    shard.slot_major,
13328                )?;
13329            }
13330            // Route-weight accumulation: axpy_rows_seq keeps the exact sequential per-pair
13331            // FP chain of the reset + n_sel axpy launches in ONE launch. Device-routed calls
13332            // fold the down macro in-kernel from the device selection. (down8 already produced
13333            // the accumulator inside the sweep.)
13334            if !down8 {
13335                let Nvfp4DeviceRoutesWorkspace {
13336                    partial,
13337                    combine_w,
13338                    route_w,
13339                    sel,
13340                    accumulator,
13341                    ..
13342                } = &mut *workspace;
13343                if device_routed {
13344                    engine.axpy_rows_seq_md_into(
13345                        &partial[rank_index],
13346                        &route_w[rank_index],
13347                        &experts.macros_down_dev[rank_index],
13348                        &sel[rank_index],
13349                        &mut accumulator[rank_index],
13350                        experts.input_width,
13351                        n_sel,
13352                    )?;
13353                } else {
13354                    engine.axpy_rows_seq_into(
13355                        &partial[rank_index],
13356                        &combine_w[rank_index],
13357                        &mut accumulator[rank_index],
13358                        experts.input_width,
13359                        n_sel,
13360                    )?;
13361                }
13362            }
13363        }
13364        Ok(())
13365    }
13366
13367    /// Device-IO twin of `run_tensor_parallel_routes_nvfp4_device`: the layer input arrives as
13368    /// a device row on the model engine `e` and the combined output returns as a fresh
13369    /// `e`-context row — no host round-trip, no host stream sync. Ordering is evented (the v2
13370    /// attention discipline): `ev_entry` is recorded on `e`'s stream AFTER the caller queued
13371    /// the input's producer; each rank waits it before its peer read; the root reduce waits
13372    /// every rank's done event; `e` waits the root's done event before copying out. The
13373    /// program bytes are identical to the host-IO twin — dtoh/htod and dtod preserve f32 bits.
13374    #[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
13375    pub fn run_tensor_parallel_routes_nvfp4_device_io(
13376        &self,
13377        experts: &ResidentNvfp4TensorParallel,
13378        e: &Engine,
13379        input_dev: &crate::CudaSlice<f32>,
13380        selected: &[usize],
13381        route_weights: &[f32],
13382        experts_per_token: usize,
13383        activation_limit: Option<f32>,
13384    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
13385        if input_dev.len() != experts.input_width {
13386            return Err(format!(
13387                "NVFP4 device-io routes input {} != width {}",
13388                input_dev.len(),
13389                experts.input_width
13390            )
13391            .into());
13392        }
13393        if selected.len() != experts_per_token || route_weights.len() != experts_per_token {
13394            return Err(format!(
13395                "NVFP4 device-io routes selected={} weights={} != experts/token {experts_per_token}",
13396                selected.len(),
13397                route_weights.len(),
13398            )
13399            .into());
13400        }
13401        if !route_weights.iter().all(|weight| weight.is_finite()) {
13402            return Err("NVFP4 device route weights contain a non-finite value".into());
13403        }
13404        let world = self.ranks.len();
13405        if world != NVFP4_CANONICAL_ROW_SHARDS {
13406            return Err(format!(
13407                "NVFP4 device routes require world == canonical shard grid \
13408                 ({NVFP4_CANONICAL_ROW_SHARDS}), got {world}"
13409            )
13410            .into());
13411        }
13412        let local_out = experts.expert_width / world;
13413        let n_sel = experts_per_token;
13414
13415        static TIMING_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
13416        static TIMING_CALLS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
13417        let timing = std::env::var("MEMRA_STEP_TP_TIMING").as_deref() == Ok("1");
13418        let started = timing.then(std::time::Instant::now);
13419
13420        let mut workspace_guard = experts
13421            .device_workspace
13422            .lock()
13423            .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
13424        if workspace_guard.is_none() {
13425            drop(workspace_guard);
13426            // Build through the host-IO ensure path exactly once: run it with a zero input.
13427            // Cheaper than duplicating the init; the first real call overwrites everything.
13428            let zero = vec![0.0f32; experts.input_width];
13429            let zero_sel = vec![0usize; n_sel];
13430            let zero_w = vec![0.0f32; n_sel];
13431            let _ = self.run_tensor_parallel_routes_nvfp4_device(
13432                experts,
13433                &zero,
13434                &zero_sel,
13435                &zero_w,
13436                n_sel,
13437                activation_limit,
13438            )?;
13439            workspace_guard = experts
13440                .device_workspace
13441                .lock()
13442                .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
13443        }
13444        let workspace = workspace_guard
13445            .as_mut()
13446            .expect("NVFP4 device routes workspace initialized above");
13447        if workspace.n_sel != n_sel {
13448            return Err(format!(
13449                "NVFP4 device routes experts/token changed: workspace {} != call {n_sel}",
13450                workspace.n_sel
13451            )
13452            .into());
13453        }
13454        for &expert in selected {
13455            if expert >= experts.expert_count {
13456                return Err(format!(
13457                    "NVFP4 device selected expert {expert} outside 0..{}",
13458                    experts.expert_count
13459                )
13460                .into());
13461            }
13462        }
13463        let sel_i32 = selected
13464            .iter()
13465            .map(|&expert| expert as i32)
13466            .collect::<Vec<_>>();
13467
13468        // Entry fence: e's stream position covers the input's producer AND every consumer of
13469        // the previous layer's output (queued on e's stream before this call), guarding the
13470        // workspace reuse exactly like the v2 attention driver.
13471        if let Some((_, device)) = workspace.ev_entry.as_ref() {
13472            if *device != e.ctx().ordinal() {
13473                return Err("NVFP4 device-io routes engine changed".into());
13474            }
13475        } else {
13476            let _main = e.gpu.enter_main()?;
13477            workspace.ev_entry = Some((e.ctx().new_event(None)?, e.ctx().ordinal()));
13478        }
13479        {
13480            let _main = e.gpu.enter_main()?;
13481            let (ev_entry, _) = workspace.ev_entry.as_ref().expect("entry event set above");
13482            ev_entry.record(&e.stream())?;
13483        }
13484        for (rank_index, engine) in self.ranks.iter().enumerate() {
13485            let _main = engine.gpu.enter_main()?;
13486            let (ev_entry, _) = workspace.ev_entry.as_ref().expect("entry event set above");
13487            engine.stream().wait(ev_entry)?;
13488            {
13489                let mut destination = workspace.input[rank_index].slice_mut(0..experts.input_width);
13490                engine
13491                    .stream()
13492                    .memcpy_dtod(&input_dev.slice(0..experts.input_width), &mut destination)?;
13493            }
13494            {
13495                let Nvfp4DeviceRoutesWorkspace {
13496                    input, in_q, in_d, ..
13497                } = &mut *workspace;
13498                engine.quantize_q8_1_into(
13499                    &input[rank_index],
13500                    1,
13501                    experts.input_width,
13502                    &mut in_q[rank_index],
13503                    &mut in_d[rank_index],
13504                )?;
13505            }
13506        }
13507        self.nvfp4_routes_batched_sweeps(
13508            experts,
13509            workspace,
13510            selected,
13511            route_weights,
13512            &sel_i32,
13513            local_out,
13514            n_sel,
13515            activation_limit,
13516            false,
13517        )?;
13518
13519        // Evented combine: rank done events replace the host stream syncs, the reduce runs on
13520        // the root stream in canonical shard order, and e copies the combined row out behind
13521        // the root's done event.
13522        // rank0 == root: its own stream order already covers its sweep; only the PEER
13523        // ranks need the record/wait pair (host-op diet at the #1 eager seam, 2026-08-21).
13524        for (rank_index, engine) in self.ranks.iter().enumerate().skip(1) {
13525            let _main = engine.gpu.enter_main()?;
13526            workspace.ev_rank[rank_index].record(&engine.stream())?;
13527        }
13528        if moe_direct_on() && self.ranks.len() == 2 {
13529            // DIRECT JOIN: rank1's accumulator is root-resident (P2P single-store pass);
13530            // rank0's is root-stream-ordered. One root event + rank1's own event order
13531            // the model engine's single add — same operand order as root's add
13532            // (accumulator[0] + accumulator[1]): BIT-IDENTICAL. Output is a FRESH
13533            // e-context row (NOT an alias of ws state — the reverted zero-copy handoff's
13534            // hazard class does not apply).
13535            {
13536                let root = &self.ranks[0];
13537                let _main = root.gpu.enter_main()?;
13538                workspace
13539                    .ev_done
13540                    .as_ref()
13541                    .expect("device routes done event")
13542                    .record(&root.stream())?;
13543            }
13544            let _main = e.gpu.enter_main()?;
13545            e.stream().wait(
13546                workspace
13547                    .ev_done
13548                    .as_ref()
13549                    .expect("device routes done event"),
13550            )?;
13551            for ev in workspace.ev_rank.iter().skip(1) {
13552                e.stream().wait(ev)?;
13553            }
13554            let mut output = e.uninit(experts.input_width)?;
13555            e.add(
13556                &workspace.accumulator[0],
13557                &workspace.accumulator[1],
13558                &mut output,
13559                experts.input_width,
13560            )?;
13561            let output = output;
13562            if let Some(started) = started {
13563                use std::sync::atomic::Ordering;
13564                let ns = TIMING_NS
13565                    .fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
13566                    + started.elapsed().as_nanos() as u64;
13567                let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
13568                if calls.is_multiple_of(430) {
13569                    eprintln!(
13570                        "[nvfp4-dev-routes-direct-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
13571                        ns as f64 / 1.0e6,
13572                        ns as f64 / calls as f64 / 1.0e3,
13573                    );
13574                }
13575            }
13576            return Ok(output);
13577        }
13578        {
13579            let root = &self.ranks[0];
13580            let _main = root.gpu.enter_main()?;
13581            for ev in workspace.ev_rank.iter().skip(1) {
13582                root.stream().wait(ev)?;
13583            }
13584            root.stream()
13585                .memcpy_dtod(&workspace.accumulator[1], &mut workspace.remote)?;
13586            {
13587                let Nvfp4DeviceRoutesWorkspace {
13588                    accumulator,
13589                    remote,
13590                    combined,
13591                    ..
13592                } = &mut *workspace;
13593                root.add(&accumulator[0], remote, combined, experts.input_width)?;
13594            }
13595            workspace
13596                .ev_done
13597                .as_ref()
13598                .expect("device routes done event")
13599                .record(&root.stream())?;
13600        }
13601        let output = {
13602            let _main = e.gpu.enter_main()?;
13603            e.stream().wait(
13604                workspace
13605                    .ev_done
13606                    .as_ref()
13607                    .expect("device routes done event"),
13608            )?;
13609            // (Zero-copy clone handoff REVERTED 2026-08-21: identity mismatch in the
13610            // routes-diet bisect. The alloc+copy stays until the hazard is understood.)
13611            let mut output = e.uninit(experts.input_width)?;
13612            e.stream().memcpy_dtod(
13613                &workspace.combined.slice(0..experts.input_width),
13614                &mut output.slice_mut(0..experts.input_width),
13615            )?;
13616            output
13617        };
13618        if let Some(started) = started {
13619            use std::sync::atomic::Ordering;
13620            let ns = TIMING_NS.fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
13621                + started.elapsed().as_nanos() as u64;
13622            let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
13623            if calls.is_multiple_of(430) {
13624                eprintln!(
13625                    "[nvfp4-dev-routes-io-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
13626                    ns as f64 / 1.0e6,
13627                    ns as f64 / calls as f64 / 1.0e3,
13628                );
13629            }
13630        }
13631        Ok(output)
13632    }
13633
13634    /// Device-routed twin of `run_tensor_parallel_routes_nvfp4_device_io`: the selection and
13635    /// route weights arrive as the device router's e-context outputs — the per-layer host
13636    /// logits readback disappears. The fresh router outputs are staged into persistent
13637    /// e-context buffers on e's stream (never-free discipline) before the entry event; each
13638    /// rank peer-reads them behind it. The down-macro fold happens in-kernel.
13639    #[allow(clippy::too_many_arguments)]
13640    /// Prestage the routed-expert input: pull the shared row to every rank and quantize it
13641    /// there, WITHOUT the selection — callable before the router so the rank chains overlap
13642    /// it. No-op (returns false) when the workspace is not built yet or the door is off;
13643    /// the routed run then does its own staging as before.
13644    pub fn nvfp4_routes_prestage(
13645        &self,
13646        experts: &ResidentNvfp4TensorParallel,
13647        e: &Engine,
13648        input_dev: &crate::CudaSlice<f32>,
13649    ) -> Result<bool, Box<dyn std::error::Error>> {
13650        self.nvfp4_routes_prestage_with(experts, e, input_dev, |_, _, _, _| Ok(false))
13651    }
13652
13653    /// `nvfp4_routes_prestage` with a PEER-ROUTER hook: after rank1's input pull +
13654    /// quantize, the hook may compute rank1's route selection LOCALLY (replicated router —
13655    /// deterministic kernels on identical input bits produce identical sel/w, so the
13656    /// selection is bit-equal to the root's). Returns true when it wrote sel/route_w; the
13657    /// routed run then skips rank1's sel pull.
13658    pub fn nvfp4_routes_prestage_with(
13659        &self,
13660        experts: &ResidentNvfp4TensorParallel,
13661        e: &Engine,
13662        input_dev: &crate::CudaSlice<f32>,
13663        rank1_router: impl FnOnce(
13664            &Engine,
13665            &crate::CudaSlice<f32>,
13666            &mut crate::CudaSlice<i32>,
13667            &mut crate::CudaSlice<f32>,
13668        ) -> Result<bool, Box<dyn std::error::Error>>,
13669    ) -> Result<bool, Box<dyn std::error::Error>> {
13670        if !routes_prestage_on() || step_tp_graph_enabled()? {
13671            return Ok(false);
13672        }
13673        if input_dev.len() != experts.input_width {
13674            return Err("NVFP4 prestage input width mismatch".into());
13675        }
13676        let mut workspace_guard = experts
13677            .device_workspace
13678            .lock()
13679            .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
13680        let Some(workspace) = workspace_guard.as_mut() else {
13681            return Ok(false);
13682        };
13683        if workspace.ev_input.is_none() {
13684            let _main = e.gpu.enter_main()?;
13685            workspace.ev_input = Some((e.ctx().new_event(None)?, e.ctx().ordinal()));
13686        } else if workspace.ev_input.as_ref().map(|(_, d)| *d) != Some(e.ctx().ordinal()) {
13687            return Err("NVFP4 prestage engine changed".into());
13688        }
13689        {
13690            let _main = e.gpu.enter_main()?;
13691            let (ev, _) = workspace.ev_input.as_ref().expect("armed above");
13692            ev.record(&e.stream())?;
13693        }
13694        for (rank_index, engine) in self.ranks.iter().enumerate() {
13695            let _main = engine.gpu.enter_main()?;
13696            let (ev, _) = workspace.ev_input.as_ref().expect("armed above");
13697            engine.stream().wait(ev)?;
13698            {
13699                let mut destination = workspace.input[rank_index].slice_mut(0..experts.input_width);
13700                engine
13701                    .stream()
13702                    .memcpy_dtod(&input_dev.slice(0..experts.input_width), &mut destination)?;
13703            }
13704            {
13705                let Nvfp4DeviceRoutesWorkspace {
13706                    input, in_q, in_d, ..
13707                } = &mut *workspace;
13708                engine.quantize_q8_1_into(
13709                    &input[rank_index],
13710                    1,
13711                    experts.input_width,
13712                    &mut in_q[rank_index],
13713                    &mut in_d[rank_index],
13714                )?;
13715            }
13716        }
13717        if self.ranks.len() == 2 {
13718            let rank1 = &self.ranks[1];
13719            let _r1 = rank1.gpu.enter_main()?;
13720            let Nvfp4DeviceRoutesWorkspace {
13721                input,
13722                sel,
13723                route_w,
13724                ..
13725            } = &mut *workspace;
13726            let (in1, rest_sel) = (&input[1], &mut sel[1]);
13727            if rank1_router(rank1, in1, rest_sel, &mut route_w[1])? {
13728                workspace.rank1_routed = true;
13729            }
13730        }
13731        workspace.prestaged = true;
13732        Ok(true)
13733    }
13734
13735    /// STEP TP2 GEMM PRIME (`MEMRA_STEP_GEMM_PRIME`, 2026-08-27, TTFT lane): one grouped
13736    /// f16 GEMM per projection over the RESIDENT NVFP4 banks for a prime chunk of `t` tokens.
13737    ///
13738    /// WHY: the t-row walk primes a 4,092-token prompt in 19.8 s at its widest (GEMV-bound) and
13739    /// the generic batch prime's decode-class MoE takes 240 s; the CUTLASS sizing rows put
13740    /// GEMM-class expert math at 170-270 TFLOP/s on this silicon, i.e. a sub-second cold prime.
13741    /// This reuses the grouped f16 lane end to end (`moe_f16g_act` -> `moe_f16_grouped`
13742    /// direct-from-NVFP4 -> silu pairs -> grouped down) once per RANK against that rank's bank
13743    /// half: gate/up are column-halves (silu runs on matching halves), down is the canonical
13744    /// row-shard pair producing partials joined in the pinned shard order, and the final
13745    /// weighted scatter runs a fixed slot-0..n_used-1 sum per token - no atomics anywhere.
13746    /// Per-expert NVFP4 macro scales land where they must: gate/up BEFORE silu (nonlinear),
13747    /// down folded into the scatter weight.
13748    ///
13749    /// NUMERIC CLASS: the f16-mirror grouped-prefill class other families already serve -
13750    /// admission is the prefill-KV acceptance gate plus the ship-shape tape, not byte identity.
13751    #[allow(clippy::too_many_arguments)]
13752    /// MEMRA_MOE_DETERM_STAGE=1: checksum a stage's device buffer so two back-to-back calls of the
13753    /// grouped routine can be compared STAGE BY STAGE. The routine's OUTPUT is nondeterministic above
13754    /// ~400 tokens on the direct lane (1.9e-7 / 99% of elements at t=4096) while its GEMM kernels are
13755    /// bit-exact in isolation, so the divergence enters somewhere between. The first stage whose
13756    /// checksum differs across the two calls is where.
13757    ///
13758    /// Sum-of-bits, not sum-of-floats: float addition would itself reorder and could mask exactly the
13759    /// class of difference being hunted.
13760    fn determ_stage_bytes(v: &[u8]) -> u64 {
13761        v.iter().fold(0u64, |a, b| {
13762            a.wrapping_mul(1_000_003).wrapping_add(*b as u64)
13763        })
13764    }
13765
13766    /// Checksum an i32 index/offset buffer. The CSR, the active-expert ids and the group
13767    /// offsets are inputs the gate kernel dereferences just as much as the activations are;
13768    /// leaving them unchecksummed is what let "identical inputs, different output" stand on a
13769    /// SUBSET of the inputs for six rounds of this investigation.
13770    fn determ_stage_i32(v: &[i32]) -> u64 {
13771        v.iter().fold(0u64, |a, b| {
13772            a.wrapping_mul(1_000_003).wrapping_add(*b as u32 as u64)
13773        })
13774    }
13775
13776    fn determ_stage_sum(v: &[f32]) -> u64 {
13777        v.iter().fold(0u64, |a, x| {
13778            a.wrapping_mul(1_000_003).wrapping_add(x.to_bits() as u64)
13779        })
13780    }
13781
13782    #[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
13783    pub fn run_tensor_parallel_routes_nvfp4_prime_grouped(
13784        &self,
13785        experts: &ResidentNvfp4TensorParallel,
13786        e: &Engine,
13787        z_t: &crate::CudaSlice<f32>,
13788        t: usize,
13789        sel: &[i32],
13790        w: &[f32],
13791        n_used: usize,
13792        activation_limit: Option<f32>,
13793    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
13794        let world = self.ranks.len();
13795        if world != NVFP4_CANONICAL_ROW_SHARDS {
13796            return Err("NVFP4 grouped prime requires the canonical 2-shard grid".into());
13797        }
13798        // The dequant must read the layout the bank was BUILT in (feeding slot-major bytes to
13799        // the v1 kernel was a garbage-output bug this line exists for). Taken from the BANK,
13800        // never from the environment: EP2 banks are always slot-major, TP shard banks are
13801        // slot-major only under PROGRAM 1 (`MEMRA_NVFP4_BANK_SM`). All three banks share one
13802        // decision at build (`nvfp4_repack_bank_matrix`), and the assert below refuses to run a
13803        // prime over banks that disagree instead of silently priming one of them wrong.
13804        //
13805        // THIS IS THE LINE THE 2026-08-29 CORRUPTION WENT THROUGH. `QT_NVFP4_V2` selects the
13806        // `kq_fetch` branch whose two prefetch callers omitted `in_f`; the codes stayed right
13807        // and the per-16 scale came from inside the packed-codes region, so the prime produced
13808        // fluent WRONG text. No v2 gate had ever run this GEMM. It is now covered device-side by
13809        // `nvfp4-bank-oracle` (both step37 layer geometries, all four tile forms) and end-to-end
13810        // by a prefill-heavy byte gate. Keep both: a decode-only byte gate proved nothing here.
13811        let slot_major = experts.gate.iter().all(|b| b.slot_major)
13812            && experts.up.iter().all(|b| b.slot_major)
13813            && experts.down.iter().all(|b| b.slot_major);
13814        let any_slot_major = experts.gate.iter().any(|b| b.slot_major)
13815            || experts.up.iter().any(|b| b.slot_major)
13816            || experts.down.iter().any(|b| b.slot_major);
13817        if any_slot_major != slot_major {
13818            return Err(
13819                "NVFP4 grouped prime: gate/up/down banks disagree on the row layout — \
13820                        one grouped GEMM cannot serve two byte maps"
13821                    .into(),
13822            );
13823        }
13824        let bank_qt = if slot_major {
13825            crate::QT_NVFP4_V2
13826        } else {
13827            crate::QT_NVFP4
13828        };
13829        let width = experts.input_width;
13830        let n_expert = experts.expert_count;
13831        let n_pairs = t * n_used;
13832        if sel.len() < n_pairs || w.len() < n_pairs || z_t.len() < t * width {
13833            return Err("NVFP4 grouped prime geometry".into());
13834        }
13835        // MEMRA_PRIME_PROF=1 sub-split of the grouped prime (2026-08-28). The [moe-prof] mark
13836        // around this whole call reads 90% of the MoE bucket, but the call is not just GEMMs:
13837        // it host-builds the CSR, allocates ~6 large device buffers per rank per layer (z_r is
13838        // 67 MB, act is 84 MB at t=4096), and does 5 H2D copies per rank. Tile form, occupancy,
13839        // padding, B double-buffering and register pressure have ALL come back null, which is
13840        // the signature of time that is not in the kernel. So measure HOST wall with no syncs
13841        // for the build and the issue, and let the join wait absorb the GPU time: host-bound and
13842        // GPU-bound then read differently instead of summing into one opaque number.
13843        let gprof = std::env::var("MEMRA_PRIME_PROF").as_deref() == Ok("1") && t >= 16;
13844        let g_t0 = std::time::Instant::now();
13845        // CSR: expert-major pair lists. Host-built - prime is chunk-granular, and the router
13846        // selections arrive host-side from the sigmoid router oracle.
13847        let mut buckets: Vec<Vec<i32>> = vec![Vec::new(); n_expert];
13848        for (p, &s_id) in sel.iter().take(n_pairs).enumerate() {
13849            let s_id = s_id as usize;
13850            if s_id >= n_expert {
13851                return Err(format!("grouped prime selection {s_id} >= {n_expert}").into());
13852            }
13853            buckets[s_id].push(p as i32);
13854        }
13855        let mut ex_ids: Vec<i32> = Vec::new();
13856        let mut ex_off: Vec<i32> = vec![0];
13857        let mut ex_pairs: Vec<i32> = Vec::new();
13858        for (e_id, b) in buckets.iter().enumerate() {
13859            if !b.is_empty() {
13860                ex_ids.push(e_id as i32);
13861                ex_pairs.extend_from_slice(b);
13862                ex_off.push(ex_pairs.len() as i32);
13863            }
13864        }
13865        let n_active = ex_ids.len();
13866        if n_active == 0 {
13867            return e.zeros(t * width);
13868        }
13869        if n_active > 512 {
13870            return Err("grouped prime n_active > 512 (direct lane cap)".into());
13871        }
13872        let csr_tok: Vec<i32> = ex_pairs.iter().map(|&p| p / n_used as i32).collect();
13873        // pair-id -> CSR row: lets the fused tail read the partials in place, so the prime skips
13874        // a whole [n_pairs, width] permute (532 MB read + write per rank per layer at 4k).
13875        let mut inv = vec![0i32; n_pairs];
13876        for (row, &pair) in ex_pairs.iter().enumerate() {
13877            inv[pair as usize] = row as i32;
13878        }
13879        // Per-CSR-row gate/up macro scales (before silu); down macro folds into the scatter w.
13880        let mg: Vec<f32> = ex_pairs
13881            .iter()
13882            .map(|&p| experts.macros_gate[sel[p as usize] as usize])
13883            .collect();
13884        let mu: Vec<f32> = ex_pairs
13885            .iter()
13886            .map(|&p| experts.macros_up[sel[p as usize] as usize])
13887            .collect();
13888        let wd: Vec<f32> = (0..n_pairs)
13889            .map(|p| w[p] * experts.macros_down[sel[p] as usize])
13890            .collect();
13891        // Pointer tables: built on first use and kept on the bank. Resident banks never move,
13892        // so the old per-rank-per-LAYER rebuild+upload of 3*n_expert u64s was pure prime-path
13893        // host churn (45 layers x 2 ranks x 864 entries per prime).
13894        {
13895            let mut tabs = experts
13896                .prime_tables
13897                .lock()
13898                .map_err(|_| "grouped prime table cache is poisoned")?;
13899            if tabs.len() != world {
13900                tabs.clear();
13901                for rank in 0..world {
13902                    let engine = &self.ranks[rank];
13903                    let _main = engine.gpu.enter_main()?;
13904                    let (gb, ub, db) =
13905                        (&experts.gate[rank], &experts.up[rank], &experts.down[rank]);
13906                    let mut tab = vec![0u64; 3 * n_expert];
13907                    {
13908                        use cudarc::driver::DevicePtr;
13909                        let stream = engine.stream();
13910                        let (pg, _g0) = gb.bank.device_ptr(&stream);
13911                        let (pu, _g1) = ub.bank.device_ptr(&stream);
13912                        let (pd, _g2) = db.bank.device_ptr(&stream);
13913                        for ex in 0..n_expert {
13914                            tab[ex] = pg + (ex * gb.expert_bytes) as u64;
13915                            tab[n_expert + ex] = pu + (ex * ub.expert_bytes) as u64;
13916                            tab[2 * n_expert + ex] = pd + (ex * db.expert_bytes) as u64;
13917                        }
13918                    }
13919                    tabs.push(engine.htod_u64(&tab)?);
13920                }
13921            }
13922        }
13923        let g_csr = g_t0.elapsed().as_secs_f64() * 1e3;
13924        let g_t1 = std::time::Instant::now();
13925        // WHAT ARE THESE RANKS, ACTUALLY (2026-08-28)? The grouped MoE measures join ~ span_sum
13926        // (strictly serialized) at t=4096 while the same kernel hits 40 TFLOP/s standalone, and
13927        // one intervention based on cudarc's peer-copy event was refuted. Before proposing an
13928        // eleventh mechanism, verify the premise the whole question rests on: that the two ranks
13929        // are on DISTINCT devices, contexts and streams. If they share any of those, the
13930        // serialization needs no further explanation. One line per process.
13931        {
13932            static SAID: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
13933            if gprof && !SAID.swap(true, std::sync::atomic::Ordering::Relaxed) {
13934                for rank in 0..world {
13935                    let e_r = &self.ranks[rank];
13936                    let _m = e_r.gpu.enter_main();
13937                    eprintln!(
13938                        "[rank-id] rank={rank} ordinal={} ctx={:?} stream={:?} root_ordinal={} \
13939                         root_stream={:?}",
13940                        e_r.ctx().ordinal(),
13941                        std::sync::Arc::as_ptr(e_r.ctx()),
13942                        e_r.stream().cu_stream(),
13943                        e.ctx().ordinal(),
13944                        e.stream().cu_stream(),
13945                    );
13946                }
13947            }
13948        }
13949
13950        let mut partials: Vec<crate::CudaSlice<f32>> = Vec::with_capacity(world);
13951        let mut ev_rank: Vec<CudaEvent> = Vec::with_capacity(world);
13952        let mut ev_head: Vec<CudaEvent> = Vec::with_capacity(world);
13953        let mut ev_tail_prof: Vec<CudaEvent> = Vec::with_capacity(world);
13954        for rank in 0..world {
13955            let engine = &self.ranks[rank];
13956            let _main = engine.gpu.enter_main()?;
13957            if gprof {
13958                // CU_EVENT_DEFAULT, not None: cudarc's new_event(None) creates the event with
13959                // CU_EVENT_DISABLE_TIMING, and cuEventElapsedTime then returns INVALID_HANDLE.
13960                // That is what failed every span query for two build cycles — the ordering
13961                // events below correctly keep the default, since they are never timed.
13962                let h = engine
13963                    .ctx()
13964                    .new_event(Some(cudarc::driver::sys::CUevent_flags::CU_EVENT_DEFAULT))?;
13965                h.record(&engine.stream())?;
13966                ev_head.push(h);
13967            }
13968            // The grouped-MoE FFI's raw launches follow the RUNTIME API's current device, not
13969            // the pushed driver context — bind it per rank or rank-1 calls die InvalidValue.
13970            engine.bind_runtime_device(engine.ctx().ordinal() as i32)?;
13971            let gb = &experts.gate[rank];
13972            let ub = &experts.up[rank];
13973            let db = &experts.down[rank];
13974            if db.device_rank != rank {
13975                return Err("grouped prime: down shard placement drifted".into());
13976            }
13977            let local_ff = gb.local_out;
13978            if ub.local_out != local_ff || db.local_in != local_ff || db.out_features != width {
13979                return Err("grouped prime: bank width mismatch".into());
13980            }
13981            // All of the rank's host-side staging lands before its first kernel, so the
13982            // launch chain below issues without host copies interleaved.
13983            let csr_tok_d = engine.htod_i32(&csr_tok)?;
13984            let exi_d = engine.htod_i32(&ex_ids)?;
13985            let exoff_d = engine.htod_i32(&ex_off)?;
13986            let mg_d = engine.htod(&mg)?;
13987            let mu_d = engine.htod(&mu)?;
13988            // Per-rank pointer table into the bank shards, slot-major like DevExps::ptr_row.
13989            let tabs_guard = experts
13990                .prime_tables
13991                .lock()
13992                .map_err(|_| "grouped prime table cache is poisoned")?;
13993            let tab_d = &tabs_guard[rank];
13994            let mut z_r = engine.uninit(t * width)?;
13995            {
13996                let mut dst = z_r.slice_mut(0..t * width);
13997                engine
13998                    .stream()
13999                    .memcpy_dtod(&z_t.slice(0..t * width), &mut dst)?;
14000            }
14001            let dstage = std::env::var("MEMRA_MOE_DETERM_STAGE").as_deref() == Ok("1") && t >= 16;
14002            let (z16, zs) = engine.moe_f16g_act(&z_r, Some(&csr_tok_d), width, n_pairs)?;
14003            if dstage {
14004                // z16 is the GEMM's actual DATA input and is a byte buffer; checksumming only
14005                // z_r and zs left "identical inputs" unestablished and produced a localization
14006                // that outran the measurement. Checksum it as bytes.
14007                let zr = engine.dtoh(&z_r)?;
14008                let zsv = engine.dtoh(&zs)?;
14009                let z16v = engine.dtoh_u8(&z16)?;
14010                eprintln!(
14011                    "[determ-stage] rank={rank} t={t} z_r={:016x} zs={:016x} z16={:016x}",
14012                    Self::determ_stage_sum(&zr),
14013                    Self::determ_stage_sum(&zsv),
14014                    Self::determ_stage_bytes(&z16v)
14015                );
14016            }
14017            if dstage {
14018                // INPUT CLOSURE. Everything the gate kernel dereferences, plus the launch
14019                // geometry that decides how it is summed, checksummed in ONE place. A kernel
14020                // proven bit-deterministic on live data, with no atomics, can only diverge if
14021                // (A) some byte it reads differs, (B) the launch differs, or (C) it reads
14022                // outside its declared inputs. This closes A and B; C is what compute-sanitizer
14023                // is for. Partial input sets are how the divergence kept retreating into the
14024                // part that was never measured.
14025                engine.stream().synchronize()?;
14026                let csr_v = engine.dtoh_i32(&csr_tok_d)?;
14027                let exi_v = engine.dtoh_i32(&exi_d)?;
14028                let exo_v = engine.dtoh_i32(&exoff_d)?;
14029                let mg_v = engine.dtoh(&mg_d)?;
14030                let mu_v = engine.dtoh(&mu_d)?;
14031                let tab_v = engine.dtoh_u64(tab_d)?;
14032                eprintln!(
14033                    "[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={}",
14034                    Self::determ_stage_i32(&csr_v),
14035                    Self::determ_stage_i32(&exi_v),
14036                    Self::determ_stage_i32(&exo_v),
14037                    Self::determ_stage_i32(&ex_off),
14038                    Self::determ_stage_sum(&mg_v),
14039                    Self::determ_stage_sum(&mu_v),
14040                    tab_v
14041                        .iter()
14042                        .fold(0u64, |a, b| a.wrapping_mul(1_000_003).wrapping_add(*b)),
14043                    gb.row_bytes
14044                );
14045                // The resident weight bank is the GEMM's OTHER operand and was never checked.
14046                // Opt-in because it is a ~424 MB dtoh per rank per layer.
14047                if std::env::var("MEMRA_MOE_DETERM_BANK").as_deref() == Ok("1") {
14048                    let bank_v = engine.dtoh_u8(&gb.bank)?;
14049                    eprintln!(
14050                        "[determ-closure] rank={rank} t={t} gate_bank={:016x} bytes={}",
14051                        Self::determ_stage_bytes(&bank_v),
14052                        bank_v.len()
14053                    );
14054                }
14055            }
14056            let mut g = engine.moe_f16_grouped(
14057                tab_d,
14058                0,
14059                n_expert,
14060                &exi_d,
14061                &ex_off,
14062                &exoff_d,
14063                &z16,
14064                &zs,
14065                width,
14066                local_ff,
14067                n_active,
14068                n_pairs,
14069                bank_qt,
14070                gb.row_bytes,
14071            )?;
14072            engine.scale_rows(&mut g, &mg_d, local_ff, n_pairs)?;
14073            let mut u = engine.moe_f16_grouped(
14074                tab_d,
14075                1,
14076                n_expert,
14077                &exi_d,
14078                &ex_off,
14079                &exoff_d,
14080                &z16,
14081                &zs,
14082                width,
14083                local_ff,
14084                n_active,
14085                n_pairs,
14086                bank_qt,
14087                ub.row_bytes,
14088            )?;
14089            engine.scale_rows(&mut u, &mu_d, local_ff, n_pairs)?;
14090            // step35 routed SwiGLU clamp (per-layer; live only on layers 43/44 for this
14091            // family): min(silu(g), lim) * clamp(u, +-lim). Dropping it was the second
14092            // correctness bug of the first engaged run.
14093            let act = match activation_limit.filter(|l| *l > 1e-6) {
14094                Some(lim) => {
14095                    let mut a = engine.uninit(n_pairs * local_ff)?;
14096                    engine.swiglu_clamped_mul_scaled(
14097                        &g,
14098                        &u,
14099                        1.0,
14100                        1.0,
14101                        lim,
14102                        &mut a,
14103                        n_pairs * local_ff,
14104                    )?;
14105                    a
14106                }
14107                None => engine.moe_pairs_silu_mul(&g, &u, n_pairs * local_ff)?,
14108            };
14109            if dstage {
14110                let gv = engine.dtoh(&g)?;
14111                let uv = engine.dtoh(&u)?;
14112                let av = engine.dtoh(&act)?;
14113                // A SUM tells you THAT gate differs; it does not tell you HOW. ULP-dense diffs
14114                // (nearly every element, ~1e-8) are an ordering/precision class; a handful of
14115                // huge ones are a corruption class. They need different hunts, so measure the
14116                // shape here instead of inferring it later.
14117                let key = (rank, t);
14118                let mut prev_map = DETERM_PREV
14119                    .get_or_init(|| std::sync::Mutex::new(std::collections::HashMap::new()))
14120                    .lock()
14121                    .map_err(|_| "determ prev map poisoned")?;
14122                let shape = match prev_map.get(&key) {
14123                    Some(prev) if prev.len() == gv.len() => {
14124                        let mut md = 0.0f32;
14125                        let mut n_diff = 0usize;
14126                        let mut n_big = 0usize;
14127                        for (a, b) in prev.iter().zip(gv.iter()) {
14128                            let d = (a - b).abs();
14129                            if d > 0.0 {
14130                                n_diff += 1;
14131                            }
14132                            if d > 1e-3 {
14133                                n_big += 1;
14134                            }
14135                            if d > md {
14136                                md = d;
14137                            }
14138                        }
14139                        format!(
14140                            " | vs_prev maxdiff={md:.3e} differing={n_diff}/{} big(>1e-3)={n_big}",
14141                            gv.len()
14142                        )
14143                    }
14144                    _ => String::new(),
14145                };
14146                prev_map.insert(key, gv.clone());
14147                drop(prev_map);
14148                eprintln!(
14149                    "[determ-stage] rank={rank} t={t} gate={:016x} up={:016x} silu={:016x}{shape}",
14150                    Self::determ_stage_sum(&gv),
14151                    Self::determ_stage_sum(&uv),
14152                    Self::determ_stage_sum(&av)
14153                );
14154            }
14155            let (a16, a_s) = engine.moe_f16g_act(&act, None, local_ff, n_pairs)?;
14156            let d_csr = engine.moe_f16_grouped(
14157                tab_d,
14158                2,
14159                n_expert,
14160                &exi_d,
14161                &ex_off,
14162                &exoff_d,
14163                &a16,
14164                &a_s,
14165                local_ff,
14166                width,
14167                n_active,
14168                n_pairs,
14169                bank_qt,
14170                db.row_bytes,
14171            )?;
14172
14173            // No host sync: both ranks' chains must be in flight before anything waits.
14174            // The rank's tail event orders the root's cross-device pulls below.
14175            if dstage {
14176                engine.stream().synchronize()?;
14177                let a16v = engine.dtoh_u8(&a16)?;
14178                let dv = engine.dtoh(&d_csr)?;
14179                eprintln!(
14180                    "[determ-stage] rank={rank} t={t} a16={:016x} down_partial={:016x}",
14181                    Self::determ_stage_bytes(&a16v),
14182                    Self::determ_stage_sum(&dv)
14183                );
14184            }
14185            let ev = engine.ctx().new_event(None)?;
14186            ev.record(&engine.stream())?;
14187            if gprof {
14188                // Per-rank GPU SPAN (2026-08-28). Keep the tail event; the elapsed time is read
14189                // AFTER the join sync below. Reading it here returns NOT_READY (the work has only
14190                // been queued) and cudarc's elapsed_ms synchronizes, which serialized the very
14191                // ranks this is meant to test: host issue jumped 1.9 ms -> 34-47 ms per call and
14192                // the join wall fell to match. A probe that changes the schedule measures its own
14193                // perturbation.
14194                // CudaEvent is not Clone, so record a second tail event on the same stream —
14195                // adjacent to `ev`, so it carries the same completion timestamp for timing.
14196                let tp = engine
14197                    .ctx()
14198                    .new_event(Some(cudarc::driver::sys::CUevent_flags::CU_EVENT_DEFAULT))?;
14199                tp.record(&engine.stream())?;
14200                ev_tail_prof.push(tp);
14201            }
14202            ev_rank.push(ev);
14203            partials.push(d_csr);
14204        }
14205        let _main = e.gpu.enter_main()?;
14206        e.bind_runtime_device(e.ctx().ordinal() as i32)?;
14207        // Host-only: every rank's chain is queued, nothing has been waited on yet.
14208        let g_issue = g_t1.elapsed().as_secs_f64() * 1e3;
14209        let g_t2 = std::time::Instant::now();
14210        for ev in &ev_rank {
14211            e.stream().wait(ev)?;
14212        }
14213        // Both partials land on the root (rank 1's crosses the link once), then ONE fused pass
14214        // does join + CSR permute + weight + scatter. Shard order stays pinned as (y0 + y1).
14215        let mut y0 = e.uninit(n_pairs * width)?;
14216        {
14217            let mut dst = y0.slice_mut(0..n_pairs * width);
14218            e.stream()
14219                .memcpy_dtod(&partials[0].slice(0..n_pairs * width), &mut dst)?;
14220        }
14221        let mut y1 = e.uninit(n_pairs * width)?;
14222        {
14223            let mut dst = y1.slice_mut(0..n_pairs * width);
14224            e.stream()
14225                .memcpy_dtod(&partials[1].slice(0..n_pairs * width), &mut dst)?;
14226        }
14227        let inv_d = e.htod_i32(&inv)?;
14228        let wd_d = e.htod(&wd)?;
14229        let mut out = e.uninit(t * width)?;
14230        e.moe_prime_join_scatter(&y0, &y1, &inv_d, &wd_d, &mut out, width, n_used, t)?;
14231        if gprof {
14232            let _ = e.stream().synchronize();
14233            let g_join = g_t2.elapsed().as_secs_f64() * 1e3;
14234            // Everything has completed, so both events of every pair are ready and elapsed_ms
14235            // cannot block. A negative entry means the query itself failed and the row must be
14236            // read as missing data, never as a zero-length span.
14237            // cuEventElapsedTime needs the events' OWN context current — computing it under the
14238            // root's pushed context returned an error for every pair, and the first version
14239            // swallowed that into -1.0 with no reason attached. Enter each rank's context, and
14240            // print the failure once so a dead probe can never again look like a zero-length span.
14241            let mut span_ms: Vec<f32> = Vec::with_capacity(world);
14242            for (rank, (h, tp)) in ev_head.iter().zip(ev_tail_prof.iter()).enumerate() {
14243                let guard = self.ranks[rank].gpu.enter_main();
14244                match guard.and_then(|_g| h.elapsed_ms(tp).map_err(|e| e.into())) {
14245                    Ok(v) => span_ms.push(v),
14246                    Err(err) => {
14247                        static SAID: std::sync::atomic::AtomicBool =
14248                            std::sync::atomic::AtomicBool::new(false);
14249                        if !SAID.swap(true, std::sync::atomic::Ordering::Relaxed) {
14250                            eprintln!("[grp-prof] span query failed on rank {rank}: {err}");
14251                        }
14252                        span_ms.push(-1.0);
14253                    }
14254                }
14255            }
14256            eprintln!(
14257                "[grp-prof] t={t} n_active={n_active} csr={g_csr:.1}ms issue={g_issue:.1}ms \
14258                 join={g_join:.1}ms spans={span_ms:?} span_sum={:.1}ms span_max={:.1}ms",
14259                span_ms.iter().sum::<f32>(),
14260                span_ms.iter().cloned().fold(0.0f32, f32::max)
14261            );
14262        }
14263        Ok(out)
14264    }
14265
14266    #[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
14267    pub fn run_tensor_parallel_routes_nvfp4_device_routed(
14268        &self,
14269        experts: &ResidentNvfp4TensorParallel,
14270        e: &Engine,
14271        input_dev: &crate::CudaSlice<f32>,
14272        sel_d: &crate::CudaSlice<i32>,
14273        w_d: &crate::CudaSlice<f32>,
14274        experts_per_token: usize,
14275        activation_limit: Option<f32>,
14276    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
14277        self.run_tensor_parallel_routes_nvfp4_device_routed_prejoin(
14278            experts,
14279            e,
14280            input_dev,
14281            sel_d,
14282            w_d,
14283            experts_per_token,
14284            activation_limit,
14285            || Ok(()),
14286        )
14287    }
14288
14289    /// `run_tensor_parallel_routes_nvfp4_device_routed` with a PREJOIN hook: `pre_join`
14290    /// runs on the host right before the join wait is enqueued on e's stream — work it
14291    /// issues there (e.g. the shexp overlap) executes WHILE the peer rank finishes its
14292    /// sweep, instead of after the join. Value-neutral by construction (the hook only
14293    /// reorders independent host issue).
14294    #[allow(clippy::too_many_arguments)]
14295    pub fn run_tensor_parallel_routes_nvfp4_device_routed_prejoin(
14296        &self,
14297        experts: &ResidentNvfp4TensorParallel,
14298        e: &Engine,
14299        input_dev: &crate::CudaSlice<f32>,
14300        sel_d: &crate::CudaSlice<i32>,
14301        w_d: &crate::CudaSlice<f32>,
14302        experts_per_token: usize,
14303        activation_limit: Option<f32>,
14304        pre_join: impl FnOnce() -> Result<(), Box<dyn std::error::Error>>,
14305    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
14306        self.run_tensor_parallel_routes_nvfp4_device_routed_prejoin_add3(
14307            experts,
14308            e,
14309            input_dev,
14310            sel_d,
14311            w_d,
14312            experts_per_token,
14313            activation_limit,
14314            pre_join,
14315            None,
14316        )
14317    }
14318
14319    /// The prejoin variant with MOE TAIL FUSION M1: when `post_add = Some((sh_raw,
14320    /// scale_raw))`, the direct-join arm folds the shexp apply into the join add
14321    /// (`dst = (acc0+acc1) + sh*scale[0]`, exact split-pair sequence) — the caller skips
14322    /// its apply launch. Raw UVA pointers so no lock is held across the call.
14323    #[allow(clippy::too_many_arguments)]
14324    pub fn run_tensor_parallel_routes_nvfp4_device_routed_prejoin_add3(
14325        &self,
14326        experts: &ResidentNvfp4TensorParallel,
14327        e: &Engine,
14328        input_dev: &crate::CudaSlice<f32>,
14329        sel_d: &crate::CudaSlice<i32>,
14330        w_d: &crate::CudaSlice<f32>,
14331        experts_per_token: usize,
14332        activation_limit: Option<f32>,
14333        pre_join: impl FnOnce() -> Result<(), Box<dyn std::error::Error>>,
14334        post_add: Option<(u64, u64)>,
14335    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
14336        if input_dev.len() != experts.input_width {
14337            return Err(format!(
14338                "NVFP4 device-routed input {} != width {}",
14339                input_dev.len(),
14340                experts.input_width
14341            )
14342            .into());
14343        }
14344        let n_sel = experts_per_token;
14345        if sel_d.len() < n_sel || w_d.len() < n_sel {
14346            return Err(format!(
14347                "NVFP4 device-routed routes sel={} w={} < experts/token {n_sel}",
14348                sel_d.len(),
14349                w_d.len()
14350            )
14351            .into());
14352        }
14353        let world = self.ranks.len();
14354        if world != NVFP4_CANONICAL_ROW_SHARDS {
14355            return Err(format!(
14356                "NVFP4 device routes require world == canonical shard grid \
14357                 ({NVFP4_CANONICAL_ROW_SHARDS}), got {world}"
14358            )
14359            .into());
14360        }
14361        let local_out = if experts.ep2 {
14362            experts.expert_width
14363        } else {
14364            experts.expert_width / world
14365        };
14366
14367        static TIMING_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
14368        static TIMING_CALLS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
14369        let timing = std::env::var("MEMRA_STEP_TP_TIMING").as_deref() == Ok("1");
14370        let started = timing.then(std::time::Instant::now);
14371
14372        let mut workspace_guard = experts
14373            .device_workspace
14374            .lock()
14375            .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
14376        if workspace_guard.is_none() {
14377            drop(workspace_guard);
14378            let zero = vec![0.0f32; experts.input_width];
14379            let zero_sel = vec![0usize; n_sel];
14380            let zero_w = vec![0.0f32; n_sel];
14381            let _ = self.run_tensor_parallel_routes_nvfp4_device(
14382                experts,
14383                &zero,
14384                &zero_sel,
14385                &zero_w,
14386                n_sel,
14387                activation_limit,
14388            )?;
14389            workspace_guard = experts
14390                .device_workspace
14391                .lock()
14392                .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
14393        }
14394        let workspace = workspace_guard
14395            .as_mut()
14396            .expect("NVFP4 device routes workspace initialized above");
14397        if workspace.n_sel != n_sel {
14398            return Err(format!(
14399                "NVFP4 device routes experts/token changed: workspace {} != call {n_sel}",
14400                workspace.n_sel
14401            )
14402            .into());
14403        }
14404
14405        // GRAPH DOOR (MEMRA_STEP_TP_GRAPH=1): the whole rank+root segment replays as one
14406        // stitched multi-device parent launched on e's stream — no events, no per-token node
14407        // updates (every address is persistent staging). VALUE-IDENTICAL to the eager path:
14408        // the children replay exactly the same kernel/copy sequence.
14409        //
14410        // GRAPH-LAUNCH HEADROOM GUARD (see spec::GRAPH_LAUNCH_MIN_FREE): below the
14411        // driver-free floor on the launching device this call falls through to the
14412        // eager routes path below — the exact body the graph captures, stateless per
14413        // call — instead of feeding cuGraphLaunch an exhausted card
14414        // (lane/graph-launch-guard-sweep-20260831).
14415        if step_tp_graph_enabled()? && step_tp_graph_headroom_ok(e) {
14416            if experts.ep2 {
14417                return Err(
14418                    "MEMRA_STEP_TP_GRAPH=1 with MEMRA_STEP_NVFP4_EP2=1 has never been \
14419                     co-gated; unset one"
14420                        .into(),
14421                );
14422            }
14423            if workspace.dev_route_e.is_none() {
14424                let _main = e.gpu.enter_main()?;
14425                workspace.dev_route_e = Some((
14426                    e.htod_i32(&vec![0i32; n_sel])?,
14427                    e.htod(&vec![0.0f32; n_sel])?,
14428                ));
14429            }
14430            if workspace.in_stage_e.is_none() {
14431                let _main = e.gpu.enter_main()?;
14432                workspace.in_stage_e = Some(e.htod(&vec![0.0f32; experts.input_width])?);
14433                workspace.out_stage_e = Some(e.htod(&vec![0.0f32; experts.input_width])?);
14434            }
14435            if workspace.routes_graph.is_none() {
14436                let graph = self.nvfp4_routes_build_graph(
14437                    experts,
14438                    workspace,
14439                    local_out,
14440                    n_sel,
14441                    activation_limit,
14442                )?;
14443                workspace.routes_graph = Some(graph);
14444                eprintln!(
14445                    "[step-tp-graph] routes segment captured: ranks={world} n_sel={n_sel} \
14446                     children=3 updates=none performance_claim=false"
14447                );
14448            }
14449            let output = {
14450                let _main = e.gpu.enter_main()?;
14451                {
14452                    let (sel_e, w_e) = workspace
14453                        .dev_route_e
14454                        .as_mut()
14455                        .expect("device route staging set above");
14456                    {
14457                        let mut dst = sel_e.slice_mut(0..n_sel);
14458                        e.stream().memcpy_dtod(&sel_d.slice(0..n_sel), &mut dst)?;
14459                    }
14460                    {
14461                        let mut dst = w_e.slice_mut(0..n_sel);
14462                        e.stream().memcpy_dtod(&w_d.slice(0..n_sel), &mut dst)?;
14463                    }
14464                }
14465                {
14466                    let in_stage = workspace
14467                        .in_stage_e
14468                        .as_mut()
14469                        .expect("graph staging set above");
14470                    let mut dst = in_stage.slice_mut(0..experts.input_width);
14471                    e.stream()
14472                        .memcpy_dtod(&input_dev.slice(0..experts.input_width), &mut dst)?;
14473                }
14474                unsafe {
14475                    let r = cudarc::driver::sys::cuGraphLaunch(
14476                        workspace
14477                            .routes_graph
14478                            .as_ref()
14479                            .expect("routes graph built above")
14480                            .exec,
14481                        e.stream().cu_stream() as cudarc::driver::sys::CUstream,
14482                    );
14483                    if r != cudarc::driver::sys::CUresult::CUDA_SUCCESS {
14484                        return Err(format!("routes graph launch: {r:?}").into());
14485                    }
14486                }
14487                let mut output = e.uninit(experts.input_width)?;
14488                {
14489                    let out_stage = workspace
14490                        .out_stage_e
14491                        .as_ref()
14492                        .expect("graph staging set above");
14493                    e.stream().memcpy_dtod(
14494                        &out_stage.slice(0..experts.input_width),
14495                        &mut output.slice_mut(0..experts.input_width),
14496                    )?;
14497                }
14498                output
14499            };
14500            if let Some(started) = started {
14501                use std::sync::atomic::Ordering;
14502                let ns = TIMING_NS
14503                    .fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
14504                    + started.elapsed().as_nanos() as u64;
14505                let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
14506                if calls.is_multiple_of(430) {
14507                    eprintln!(
14508                        "[nvfp4-dev-routed-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
14509                        ns as f64 / 1.0e6,
14510                        ns as f64 / calls as f64 / 1.0e3,
14511                    );
14512                }
14513            }
14514            return Ok(output);
14515        }
14516
14517        // Entry fence + router-output staging, all on e's stream: the fresh sel/w slices are
14518        // copied into the persistent e-context pair, then the event is recorded — the caller's
14519        // sel_d/w_d can free on e's stream with no cross-stream reader.
14520        if let Some((_, device)) = workspace.ev_entry.as_ref() {
14521            if *device != e.ctx().ordinal() {
14522                return Err("NVFP4 device-routed routes engine changed".into());
14523            }
14524        } else {
14525            let _main = e.gpu.enter_main()?;
14526            workspace.ev_entry = Some((e.ctx().new_event(None)?, e.ctx().ordinal()));
14527        }
14528        if workspace.dev_route_e.is_none() {
14529            let _main = e.gpu.enter_main()?;
14530            workspace.dev_route_e = Some((
14531                e.htod_i32(&vec![0i32; n_sel])?,
14532                e.htod(&vec![0.0f32; n_sel])?,
14533            ));
14534        }
14535        // MEMRA_SEL_MIRROR: the staging pair exists so the rank streams read a persistent
14536        // e-context address. The caller's sel_d/w_d ARE persistent (the process-static
14537        // selection rows), so when every consuming rank shares e's device the ranks can read
14538        // them directly and this hop disappears. The graph door keeps the staging (its
14539        // captured copies read the fixed addresses).
14540        let mirror = sel_mirror_on() && !step_tp_graph_enabled()?;
14541        let e_device = e.ctx().ordinal();
14542        // rank1_routed is consumed (taken) below; peek it here for the staging decision.
14543        let rank1_routed_peek = workspace.rank1_routed;
14544        let stage_needed = !mirror
14545            || self.ranks.iter().enumerate().any(|(rank_index, engine)| {
14546                !(rank1_routed_peek && rank_index == 1) && engine.ctx().ordinal() != e_device
14547            });
14548        {
14549            let _main = e.gpu.enter_main()?;
14550            if stage_needed {
14551                let (sel_e, w_e) = workspace
14552                    .dev_route_e
14553                    .as_mut()
14554                    .expect("device route staging set above");
14555                {
14556                    let mut dst = sel_e.slice_mut(0..n_sel);
14557                    e.stream().memcpy_dtod(&sel_d.slice(0..n_sel), &mut dst)?;
14558                }
14559                {
14560                    let mut dst = w_e.slice_mut(0..n_sel);
14561                    e.stream().memcpy_dtod(&w_d.slice(0..n_sel), &mut dst)?;
14562                }
14563            }
14564            let (ev_entry, _) = workspace.ev_entry.as_ref().expect("entry event set above");
14565            ev_entry.record(&e.stream())?;
14566        }
14567        // Prestage door: input pull + quantize were already issued on the rank streams
14568        // (before the router) — the rank stream order suffices, skip them here.
14569        let prestaged = std::mem::take(&mut workspace.prestaged);
14570        let rank1_routed = std::mem::take(&mut workspace.rank1_routed);
14571        for (rank_index, engine) in self.ranks.iter().enumerate() {
14572            let _main = engine.gpu.enter_main()?;
14573            let (ev_entry, _) = workspace.ev_entry.as_ref().expect("entry event set above");
14574            engine.stream().wait(ev_entry)?;
14575            if !prestaged {
14576                let mut destination = workspace.input[rank_index].slice_mut(0..experts.input_width);
14577                engine
14578                    .stream()
14579                    .memcpy_dtod(&input_dev.slice(0..experts.input_width), &mut destination)?;
14580            }
14581            if !(rank1_routed && rank_index == 1) {
14582                // ONE mirror launch instead of two 32-byte copy-engine dispatches; source is
14583                // the caller's persistent rows when this rank shares e's device (UVA, ordered
14584                // by ev_entry), else the staged e-context pair.
14585                let same_dev = engine.ctx().ordinal() == e_device;
14586                if mirror {
14587                    // Split the workspace borrow so the source (the staged pair, when this
14588                    // rank is off-device) and the destination rows coexist.
14589                    let Nvfp4DeviceRoutesWorkspace {
14590                        sel,
14591                        route_w,
14592                        dev_route_e,
14593                        ..
14594                    } = &mut *workspace;
14595                    let (src_sel, src_w): (&crate::CudaSlice<i32>, &crate::CudaSlice<f32>) =
14596                        if same_dev {
14597                            (sel_d, w_d)
14598                        } else {
14599                            let (sel_e, w_e) = dev_route_e
14600                                .as_ref()
14601                                .expect("device route staging set above");
14602                            (sel_e, w_e)
14603                        };
14604                    engine.moe_sel_w_mirror(
14605                        src_sel,
14606                        src_w,
14607                        &mut sel[rank_index],
14608                        &mut route_w[rank_index],
14609                        n_sel,
14610                    )?;
14611                } else {
14612                    let (sel_e, w_e) = workspace
14613                        .dev_route_e
14614                        .as_ref()
14615                        .expect("device route staging set above");
14616                    {
14617                        let mut dst = workspace.sel[rank_index].slice_mut(0..n_sel);
14618                        engine
14619                            .stream()
14620                            .memcpy_dtod(&sel_e.slice(0..n_sel), &mut dst)?;
14621                    }
14622                    {
14623                        let mut dst = workspace.route_w[rank_index].slice_mut(0..n_sel);
14624                        engine
14625                            .stream()
14626                            .memcpy_dtod(&w_e.slice(0..n_sel), &mut dst)?;
14627                    }
14628                }
14629            }
14630            if !prestaged {
14631                let Nvfp4DeviceRoutesWorkspace {
14632                    input, in_q, in_d, ..
14633                } = &mut *workspace;
14634                engine.quantize_q8_1_into(
14635                    &input[rank_index],
14636                    1,
14637                    experts.input_width,
14638                    &mut in_q[rank_index],
14639                    &mut in_d[rank_index],
14640                )?;
14641            }
14642        }
14643        self.nvfp4_routes_batched_sweeps(
14644            experts,
14645            workspace,
14646            &[],
14647            &[],
14648            &[],
14649            local_out,
14650            n_sel,
14651            activation_limit,
14652            true,
14653        )?;
14654
14655        // rank0 == root: its own stream order already covers its sweep; only the PEER
14656        // ranks need the record/wait pair (host-op diet at the #1 eager seam, 2026-08-21).
14657        for (rank_index, engine) in self.ranks.iter().enumerate().skip(1) {
14658            let _main = engine.gpu.enter_main()?;
14659            workspace.ev_rank[rank_index].record(&engine.stream())?;
14660        }
14661        // Doorbell fences (MEMRA_FENCE_MEMOPS=1): rank1 + root ring their flags; e waits
14662        // the tickets instead of the two events. Arm lazily; 0-len = unsupported.
14663        let memops = fence_memops_on() && moe_direct_on() && self.ranks.len() == 2;
14664        let mut ticket = 0u32;
14665        if memops {
14666            use cudarc::driver::sys;
14667            if workspace.fence_flags_raw == 0 {
14668                let root = &self.ranks[0];
14669                let _main = root.gpu.enter_main()?;
14670                let mut ptr: sys::CUdeviceptr = 0;
14671                let r = unsafe { sys::cuMemAlloc_v2(&mut ptr, 8) };
14672                if r != sys::CUresult::CUDA_SUCCESS {
14673                    return Err(format!("fence flag alloc: {r:?}").into());
14674                }
14675                let r = unsafe { sys::cuMemsetD8_v2(ptr, 0, 8) };
14676                if r != sys::CUresult::CUDA_SUCCESS {
14677                    return Err(format!("fence flag memset: {r:?}").into());
14678                }
14679                workspace.fence_flags_raw = ptr as u64;
14680            }
14681            workspace.fence_ticket = workspace.fence_ticket.wrapping_add(1).max(1);
14682            ticket = workspace.fence_ticket;
14683            let base = workspace.fence_flags_raw;
14684            // rank1's fence: a peer stream MEMOP is rejected over PCIe P2P
14685            // (CUDA_ERROR_INVALID_VALUE, receipted 2026-08-23), but a peer KERNEL STORE into
14686            // root memory is legal — the direct join already relies on it. Under
14687            // MEMRA_FENCE_RANK1 rank1 rings flag[0] that way and e waits it same-device,
14688            // replacing the cross-device event wait below.
14689            if fence_rank1_on() {
14690                let peer = &self.ranks[1];
14691                let _pmain = peer.gpu.enter_main()?;
14692                peer.ring_flag_raw(base, ticket)?;
14693            }
14694            {
14695                let root = &self.ranks[0];
14696                let _main = root.gpu.enter_main()?;
14697                let r = unsafe {
14698                    sys::cuStreamWriteValue32_v2(
14699                        root.stream().cu_stream() as sys::CUstream,
14700                        (base + 4) as sys::CUdeviceptr,
14701                        ticket,
14702                        0,
14703                    )
14704                };
14705                if r != sys::CUresult::CUDA_SUCCESS {
14706                    return Err(format!("fence write root: {r:?}").into());
14707                }
14708            }
14709        }
14710        // PREJOIN hook: rank work is fully issued (dev1 running); independent e-stream
14711        // kernels queued here execute while the peer rank drains its sweep.
14712        pre_join()?;
14713
14714        if moe_direct_on() && self.ranks.len() == 2 {
14715            // DIRECT JOIN: rank1's accumulator is root-resident (P2P single-store pass);
14716            // rank0's is root-stream-ordered. One root event + rank1's own event order
14717            // the model engine's single add — same operand order as root's add
14718            // (accumulator[0] + accumulator[1]): BIT-IDENTICAL. Output is a FRESH
14719            // e-context row (NOT an alias of ws state — the reverted zero-copy handoff's
14720            // hazard class does not apply).
14721            let _main = e.gpu.enter_main()?;
14722            if memops {
14723                use cudarc::driver::sys;
14724                let base = workspace.fence_flags_raw;
14725                let r = unsafe {
14726                    sys::cuStreamWaitValue32_v2(
14727                        e.stream().cu_stream() as sys::CUstream,
14728                        (base + 4) as sys::CUdeviceptr,
14729                        ticket,
14730                        sys::CUstreamWaitValue_flags::CU_STREAM_WAIT_VALUE_GEQ as u32,
14731                    )
14732                };
14733                if r != sys::CUresult::CUDA_SUCCESS {
14734                    return Err(format!("fence wait: {r:?}").into());
14735                }
14736                if fence_rank1_on() {
14737                    // Same-device wait on the flag rank1 rang over P2P.
14738                    let r = unsafe {
14739                        sys::cuStreamWaitValue32_v2(
14740                            e.stream().cu_stream() as sys::CUstream,
14741                            base as sys::CUdeviceptr,
14742                            ticket,
14743                            sys::CUstreamWaitValue_flags::CU_STREAM_WAIT_VALUE_GEQ as u32,
14744                        )
14745                    };
14746                    if r != sys::CUresult::CUDA_SUCCESS {
14747                        return Err(format!("fence wait rank1: {r:?}").into());
14748                    }
14749                } else {
14750                    for ev in workspace.ev_rank.iter().skip(1) {
14751                        e.stream().wait(ev)?;
14752                    }
14753                }
14754            } else {
14755                {
14756                    let root = &self.ranks[0];
14757                    let _rmain = root.gpu.enter_main()?;
14758                    workspace
14759                        .ev_done
14760                        .as_ref()
14761                        .expect("device routes done event")
14762                        .record(&root.stream())?;
14763                }
14764                e.stream().wait(
14765                    workspace
14766                        .ev_done
14767                        .as_ref()
14768                        .expect("device routes done event"),
14769                )?;
14770                for ev in workspace.ev_rank.iter().skip(1) {
14771                    e.stream().wait(ev)?;
14772                }
14773            }
14774            let mut output = e.uninit(experts.input_width)?;
14775            if let Some((sh_raw, scale_raw)) = post_add {
14776                // MOE TAIL FUSION M1: fold the shexp apply into the join add —
14777                // dst = (acc0 + acc1) + sh*scale[0], the exact split-pair sequence.
14778                e.add3_raw(
14779                    &workspace.accumulator[0],
14780                    &workspace.accumulator[1],
14781                    sh_raw,
14782                    scale_raw,
14783                    &mut output,
14784                    experts.input_width,
14785                )?;
14786            } else {
14787                e.add(
14788                    &workspace.accumulator[0],
14789                    &workspace.accumulator[1],
14790                    &mut output,
14791                    experts.input_width,
14792                )?;
14793            }
14794            let output = output;
14795            if let Some(started) = started {
14796                use std::sync::atomic::Ordering;
14797                let ns = TIMING_NS
14798                    .fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
14799                    + started.elapsed().as_nanos() as u64;
14800                let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
14801                if calls.is_multiple_of(430) {
14802                    eprintln!(
14803                        "[nvfp4-dev-routes-direct-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
14804                        ns as f64 / 1.0e6,
14805                        ns as f64 / calls as f64 / 1.0e3,
14806                    );
14807                }
14808            }
14809            return Ok(output);
14810        }
14811        {
14812            let root = &self.ranks[0];
14813            let _main = root.gpu.enter_main()?;
14814            for ev in workspace.ev_rank.iter().skip(1) {
14815                root.stream().wait(ev)?;
14816            }
14817            root.stream()
14818                .memcpy_dtod(&workspace.accumulator[1], &mut workspace.remote)?;
14819            {
14820                let Nvfp4DeviceRoutesWorkspace {
14821                    accumulator,
14822                    remote,
14823                    combined,
14824                    ..
14825                } = &mut *workspace;
14826                root.add(&accumulator[0], remote, combined, experts.input_width)?;
14827            }
14828            workspace
14829                .ev_done
14830                .as_ref()
14831                .expect("device routes done event")
14832                .record(&root.stream())?;
14833        }
14834        let output = {
14835            let _main = e.gpu.enter_main()?;
14836            e.stream().wait(
14837                workspace
14838                    .ev_done
14839                    .as_ref()
14840                    .expect("device routes done event"),
14841            )?;
14842            // (Zero-copy clone handoff REVERTED 2026-08-21: identity mismatch in the
14843            // routes-diet bisect. The alloc+copy stays until the hazard is understood.)
14844            let mut output = e.uninit(experts.input_width)?;
14845            e.stream().memcpy_dtod(
14846                &workspace.combined.slice(0..experts.input_width),
14847                &mut output.slice_mut(0..experts.input_width),
14848            )?;
14849            output
14850        };
14851        if let Some(started) = started {
14852            use std::sync::atomic::Ordering;
14853            let ns = TIMING_NS.fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
14854                + started.elapsed().as_nanos() as u64;
14855            let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
14856            if calls.is_multiple_of(430) {
14857                eprintln!(
14858                    "[nvfp4-dev-routed-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
14859                    ns as f64 / 1.0e6,
14860                    ns as f64 / calls as f64 / 1.0e3,
14861                );
14862            }
14863        }
14864        Ok(output)
14865    }
14866
14867    /// The fused finish's ROOT section (combine + shadow gathers), event-free: the eager
14868    /// caller wraps it with rank-event waits + the done record; the token graph captures it
14869    /// verbatim (parent edges provide the ordering).
14870    pub(crate) fn decode_v2_finish_root_fused(
14871        &self,
14872        ws: &mut StepTpDecodeV2Ws,
14873    ) -> Result<(), Box<dyn std::error::Error>> {
14874        let root = &self.ranks[0];
14875        let _main = root.gpu.enter_main()?;
14876        if ws.raw_peer_partial != 0 {
14877            // Capture-safe raw seams (arming happened in the stage flow).
14878            raw_copy_bytes(ws.raw_peer_partial, ws.raw_o_partial1, ws.o_out * 4, root)?;
14879        } else {
14880            root.stream()
14881                .memcpy_dtod(&ws.o_partials[1][0], &mut ws.peer_partial)?;
14882        }
14883        {
14884            let StepTpDecodeV2Ws {
14885                o_partials,
14886                peer_partial,
14887                reduce_a,
14888                o_out,
14889                ..
14890            } = &mut *ws;
14891            root.add(&o_partials[0][0], peer_partial, reduce_a, *o_out)?;
14892        }
14893        let shadows = !no_local_shadow_on() || ws.raw_mixed_stage_e != 0;
14894        if shadows {
14895            // rank0's shadows are same-context (root) copies; rank1's cross-context reads go
14896            // raw when armed.
14897            let mut k_dst = ws.k_shadow.slice_mut(0..ws.local_kv_dim);
14898            root.stream().memcpy_dtod(&ws.k[0], &mut k_dst)?;
14899            let mut v_dst = ws.v_shadow.slice_mut(0..ws.local_kv_dim);
14900            root.stream().memcpy_dtod(&ws.v_raw[0], &mut v_dst)?;
14901        }
14902        if shadows && ws.raw_peer_partial != 0 {
14903            raw_copy_bytes(
14904                ws.raw_k_shadow + (ws.local_kv_dim * 4) as u64,
14905                ws.raw_k1,
14906                ws.local_kv_dim * 4,
14907                root,
14908            )?;
14909            raw_copy_bytes(
14910                ws.raw_v_shadow + (ws.local_kv_dim * 4) as u64,
14911                ws.raw_v1,
14912                ws.local_kv_dim * 4,
14913                root,
14914            )?;
14915        } else if shadows {
14916            let start = ws.local_kv_dim;
14917            let mut k_dst = ws.k_shadow.slice_mut(start..start + ws.local_kv_dim);
14918            root.stream().memcpy_dtod(&ws.k[1], &mut k_dst)?;
14919            let mut v_dst = ws.v_shadow.slice_mut(start..start + ws.local_kv_dim);
14920            root.stream().memcpy_dtod(&ws.v_raw[1], &mut v_dst)?;
14921        }
14922        if ws.raw_mixed_stage_e != 0 {
14923            // Token-graph mirrors: the e-glue children read same-context copies of the
14924            // root-produced rows.
14925            raw_copy_bytes(ws.raw_mixed_stage_e, ws.raw_reduce_a, ws.o_out * 4, root)?;
14926            let (k_stage, v_stage) = ws.raw_shadow_stage_e;
14927            raw_copy_bytes(k_stage, ws.raw_k_shadow, 2 * ws.local_kv_dim * 4, root)?;
14928            raw_copy_bytes(v_stage, ws.raw_v_shadow, 2 * ws.local_kv_dim * 4, root)?;
14929        }
14930        Ok(())
14931    }
14932
14933    /// Arm the token-graph e-context mirrors (orchestrator-supplied fixed addresses) plus
14934    /// reduce_a's own pointer.
14935    pub(crate) fn decode_v2_arm_token_mirrors(
14936        &self,
14937        ws: &mut StepTpDecodeV2Ws,
14938        mixed_stage_e: u64,
14939        shadow_stage_e: (u64, u64),
14940    ) -> Result<(), Box<dyn std::error::Error>> {
14941        use cudarc::driver::DevicePtr;
14942        let root = &self.ranks[0];
14943        let _main = root.gpu.enter_main()?;
14944        let stream = root.stream();
14945        let (a, _g) = ws.reduce_a.device_ptr(&stream);
14946        ws.raw_reduce_a = a;
14947        ws.raw_mixed_stage_e = mixed_stage_e;
14948        ws.raw_shadow_stage_e = shadow_stage_e;
14949        Ok(())
14950    }
14951
14952    /// Build one layer's stitched routes graph: per-rank children captured on their own
14953    /// streams (raw cuMemcpyAsync at every cross-context seam — cudarc's slice tracking is
14954    /// capture-illegal there), a root combine child, and a multi-device parent with
14955    /// {rank0, rank1} -> root dependency edges. Zero per-token updates: every address the
14956    /// nodes touch is persistent workspace/staging.
14957    fn nvfp4_routes_build_graph(
14958        &self,
14959        experts: &ResidentNvfp4TensorParallel,
14960        workspace: &mut Nvfp4DeviceRoutesWorkspace,
14961        local_out: usize,
14962        n_sel: usize,
14963        activation_limit: Option<f32>,
14964    ) -> Result<RoutesGraph, Box<dyn std::error::Error>> {
14965        use cudarc::driver::DevicePtr;
14966        use cudarc::driver::sys;
14967        fn cu_try(r: sys::CUresult, what: &str) -> Result<(), Box<dyn std::error::Error>> {
14968            if r == sys::CUresult::CUDA_SUCCESS {
14969                Ok(())
14970            } else {
14971                Err(format!("{what}: {r:?}").into())
14972            }
14973        }
14974        let world = self.ranks.len();
14975        if world != 2 {
14976            return Err("routes graph door is built for the TP2 pair".into());
14977        }
14978        let width = experts.input_width;
14979
14980        // Raw pointers cached before capture (each read with its owner's stream).
14981        let ptr_f32 = |buf: &crate::CudaSlice<f32>, engine: &Engine| -> u64 {
14982            let stream = engine.stream();
14983            let (ptr, _g) = buf.device_ptr(&stream);
14984            ptr
14985        };
14986        let ptr_i32 = |buf: &crate::CudaSlice<i32>, engine: &Engine| -> u64 {
14987            let stream = engine.stream();
14988            let (ptr, _g) = buf.device_ptr(&stream);
14989            ptr
14990        };
14991        let (sel_e, w_e) = workspace
14992            .dev_route_e
14993            .as_ref()
14994            .expect("device route staging set before graph build");
14995        let root_engine = &self.ranks[0];
14996        let p_in_stage = ptr_f32(
14997            workspace.in_stage_e.as_ref().expect("graph staging"),
14998            root_engine,
14999        );
15000        let p_out_stage = ptr_f32(
15001            workspace.out_stage_e.as_ref().expect("graph staging"),
15002            root_engine,
15003        );
15004        let p_sel_e = ptr_i32(sel_e, root_engine);
15005        let p_w_e = ptr_f32(w_e, root_engine);
15006        let p_input: Vec<u64> = (0..world)
15007            .map(|r| ptr_f32(&workspace.input[r], &self.ranks[r]))
15008            .collect();
15009        let p_sel: Vec<u64> = (0..world)
15010            .map(|r| ptr_i32(&workspace.sel[r], &self.ranks[r]))
15011            .collect();
15012        let p_route_w: Vec<u64> = (0..world)
15013            .map(|r| ptr_f32(&workspace.route_w[r], &self.ranks[r]))
15014            .collect();
15015        let p_acc1 = ptr_f32(&workspace.accumulator[1], &self.ranks[1]);
15016        let p_remote = ptr_f32(&workspace.remote, root_engine);
15017        let p_combined = ptr_f32(&workspace.combined, root_engine);
15018
15019        let raw_copy = |dst: u64,
15020                        src: u64,
15021                        bytes: usize,
15022                        engine: &Engine|
15023         -> Result<(), Box<dyn std::error::Error>> {
15024            unsafe {
15025                cu_try(
15026                    sys::cuMemcpyAsync(
15027                        dst as sys::CUdeviceptr,
15028                        src as sys::CUdeviceptr,
15029                        bytes,
15030                        engine.stream().cu_stream() as sys::CUstream,
15031                    ),
15032                    "routes graph cuMemcpyAsync",
15033                )
15034            }
15035        };
15036
15037        let mut children = Vec::with_capacity(3);
15038        for rank in 0..world {
15039            let engine = &self.ranks[rank];
15040            let _main = engine.gpu.enter_main()?;
15041            let (child, _retained) = engine.capture_graph_retained(|_| {
15042                raw_copy(p_input[rank], p_in_stage, width * 4, engine)?;
15043                raw_copy(p_sel[rank], p_sel_e, n_sel * 4, engine)?;
15044                raw_copy(p_route_w[rank], p_w_e, n_sel * 4, engine)?;
15045                {
15046                    let Nvfp4DeviceRoutesWorkspace {
15047                        input, in_q, in_d, ..
15048                    } = &mut *workspace;
15049                    engine.quantize_q8_1_into(
15050                        &input[rank],
15051                        1,
15052                        width,
15053                        &mut in_q[rank],
15054                        &mut in_d[rank],
15055                    )?;
15056                }
15057                self.nvfp4_routes_batched_sweeps_rank(
15058                    experts,
15059                    workspace,
15060                    &[],
15061                    &[],
15062                    &[],
15063                    local_out,
15064                    n_sel,
15065                    activation_limit,
15066                    true,
15067                    rank,
15068                )?;
15069                Ok(())
15070            })?;
15071            children.push(child);
15072        }
15073        {
15074            let root = &self.ranks[0];
15075            let _main = root.gpu.enter_main()?;
15076            let (child, _retained) = root.capture_graph_retained(|_| {
15077                raw_copy(p_remote, p_acc1, width * 4, root)?;
15078                {
15079                    let Nvfp4DeviceRoutesWorkspace {
15080                        accumulator,
15081                        remote,
15082                        combined,
15083                        ..
15084                    } = &mut *workspace;
15085                    root.add(&accumulator[0], remote, combined, width)?;
15086                }
15087                raw_copy(p_out_stage, p_combined, width * 4, root)?;
15088                Ok(())
15089            })?;
15090            children.push(child);
15091        }
15092
15093        let mut parent: sys::CUgraph = std::ptr::null_mut();
15094        unsafe {
15095            cu_try(sys::cuGraphCreate(&mut parent, 0), "routes cuGraphCreate")?;
15096        }
15097        let mut n0: sys::CUgraphNode = std::ptr::null_mut();
15098        let mut n1: sys::CUgraphNode = std::ptr::null_mut();
15099        let mut n2: sys::CUgraphNode = std::ptr::null_mut();
15100        unsafe {
15101            cu_try(
15102                sys::cuGraphAddChildGraphNode(
15103                    &mut n0,
15104                    parent,
15105                    std::ptr::null(),
15106                    0,
15107                    children[0].cu_graph(),
15108                ),
15109                "routes child r0",
15110            )?;
15111            cu_try(
15112                sys::cuGraphAddChildGraphNode(
15113                    &mut n1,
15114                    parent,
15115                    std::ptr::null(),
15116                    0,
15117                    children[1].cu_graph(),
15118                ),
15119                "routes child r1",
15120            )?;
15121            let deps = [n0, n1];
15122            cu_try(
15123                sys::cuGraphAddChildGraphNode(
15124                    &mut n2,
15125                    parent,
15126                    deps.as_ptr(),
15127                    2,
15128                    children[2].cu_graph(),
15129                ),
15130                "routes child root",
15131            )?;
15132        }
15133        let mut exec: sys::CUgraphExec = std::ptr::null_mut();
15134        unsafe {
15135            cu_try(
15136                sys::cuGraphInstantiateWithFlags(&mut exec, parent, 0),
15137                "routes instantiate",
15138            )?;
15139        }
15140        Ok(RoutesGraph {
15141            exec,
15142            parent,
15143            _children: children,
15144        })
15145    }
15146
15147    /// One rank's routes section for the token graph (event-free): staged input copy (raw
15148    /// when the caller supplies the source pointer), quantize, and the batched sweeps.
15149    /// Eager device_routed wraps it with the entry-event wait.
15150    #[allow(clippy::too_many_arguments)]
15151    pub(crate) fn routes_rank_section(
15152        &self,
15153        experts: &ResidentNvfp4TensorParallel,
15154        workspace: &mut Nvfp4DeviceRoutesWorkspace,
15155        raw_input_src: u64,
15156        local_out: usize,
15157        n_sel: usize,
15158        activation_limit: Option<f32>,
15159        rank_index: usize,
15160    ) -> Result<(), Box<dyn std::error::Error>> {
15161        let engine = &self.ranks[rank_index];
15162        {
15163            let _main = engine.gpu.enter_main()?;
15164            // sel/route_w land via raw copies from the e staging (fixed addresses).
15165            let (sel_e_ptr, w_e_ptr) = workspace
15166                .raw_dev_route_e
15167                .ok_or("routes rank section requires armed staging pointers")?;
15168            raw_copy_bytes(
15169                workspace.raw_input[rank_index],
15170                raw_input_src,
15171                experts.input_width * 4,
15172                engine,
15173            )?;
15174            raw_copy_bytes(workspace.raw_sel[rank_index], sel_e_ptr, n_sel * 4, engine)?;
15175            raw_copy_bytes(
15176                workspace.raw_route_w[rank_index],
15177                w_e_ptr,
15178                n_sel * 4,
15179                engine,
15180            )?;
15181            {
15182                let Nvfp4DeviceRoutesWorkspace {
15183                    input, in_q, in_d, ..
15184                } = &mut *workspace;
15185                engine.quantize_q8_1_into(
15186                    &input[rank_index],
15187                    1,
15188                    experts.input_width,
15189                    &mut in_q[rank_index],
15190                    &mut in_d[rank_index],
15191                )?;
15192            }
15193        }
15194        self.nvfp4_routes_batched_sweeps_rank(
15195            experts,
15196            workspace,
15197            &[],
15198            &[],
15199            &[],
15200            local_out,
15201            n_sel,
15202            activation_limit,
15203            true,
15204            rank_index,
15205        )
15206    }
15207
15208    /// The routes ROOT combine section (event-free): peer accumulator read (raw), canonical
15209    /// add, combined row raw-copied into the fixed e-context out stage.
15210    pub(crate) fn routes_root_section(
15211        &self,
15212        experts: &ResidentNvfp4TensorParallel,
15213        workspace: &mut Nvfp4DeviceRoutesWorkspace,
15214    ) -> Result<(), Box<dyn std::error::Error>> {
15215        let root = &self.ranks[0];
15216        let _main = root.gpu.enter_main()?;
15217        let (acc1_ptr, remote_ptr, combined_ptr, out_stage_ptr) = workspace
15218            .raw_combine
15219            .ok_or("routes root section requires armed combine pointers")?;
15220        raw_copy_bytes(remote_ptr, acc1_ptr, experts.input_width * 4, root)?;
15221        {
15222            let Nvfp4DeviceRoutesWorkspace {
15223                accumulator,
15224                remote,
15225                combined,
15226                ..
15227            } = &mut *workspace;
15228            root.add(&accumulator[0], remote, combined, experts.input_width)?;
15229        }
15230        raw_copy_bytes(out_stage_ptr, combined_ptr, experts.input_width * 4, root)?;
15231        Ok(())
15232    }
15233
15234    /// Arm the routes raw pointers (once): staging pair, per-rank input/sel/route_w, and the
15235    /// combine set. Requires dev_route_e + in/out stages already allocated.
15236    pub(crate) fn routes_arm_raw(
15237        &self,
15238        experts: &ResidentNvfp4TensorParallel,
15239        workspace: &mut Nvfp4DeviceRoutesWorkspace,
15240    ) -> Result<(), Box<dyn std::error::Error>> {
15241        use cudarc::driver::DevicePtr;
15242        if workspace.raw_dev_route_e.is_some() {
15243            return Ok(());
15244        }
15245        let _ = experts;
15246        let (sel_e, w_e) = workspace
15247            .dev_route_e
15248            .as_ref()
15249            .ok_or("routes staging not armed")?;
15250        let root = &self.ranks[0];
15251        {
15252            let _main = root.gpu.enter_main()?;
15253            let stream = root.stream();
15254            let (a, _g) = sel_e.device_ptr(&stream);
15255            let (b, _g) = w_e.device_ptr(&stream);
15256            workspace.raw_dev_route_e = Some((a, b));
15257            let (c, _g) = workspace.accumulator[1].device_ptr(&stream);
15258            let (d, _g) = workspace.remote.device_ptr(&stream);
15259            let (f, _g) = workspace.combined.device_ptr(&stream);
15260            let out_stage = workspace
15261                .out_stage_e
15262                .as_ref()
15263                .ok_or("routes out stage not armed")?;
15264            let (g_, _g) = out_stage.device_ptr(&stream);
15265            workspace.raw_combine = Some((c, d, f, g_));
15266        }
15267        for rank in 0..self.ranks.len() {
15268            let engine = &self.ranks[rank];
15269            let _main = engine.gpu.enter_main()?;
15270            let stream = engine.stream();
15271            let (a, _g) = workspace.input[rank].device_ptr(&stream);
15272            let (b, _g) = workspace.sel[rank].device_ptr(&stream);
15273            let (c, _g) = workspace.route_w[rank].device_ptr(&stream);
15274            workspace.raw_input.push(a);
15275            workspace.raw_sel.push(b);
15276            workspace.raw_route_w.push(c);
15277        }
15278        Ok(())
15279    }
15280
15281    /// Routed NVFP4 expert program, host-canonical transport. Native/bulk P2P transport for the
15282    /// NVFP4 bank is a separate increment; this entry point is exactness-first and reports no
15283    /// throughput claim.
15284    #[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
15285    pub fn run_tensor_parallel_routes_nvfp4(
15286        &self,
15287        experts: &ResidentNvfp4TensorParallel,
15288        input: &[f32],
15289        tokens: usize,
15290        selected: &[usize],
15291        route_weights: &[f32],
15292        experts_per_token: usize,
15293        activation_limit: Option<f32>,
15294    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
15295        validate_activations(input, tokens, experts.input_width)?;
15296        let pairs = tokens
15297            .checked_mul(experts_per_token)
15298            .ok_or("NVFP4 TP route count overflow")?;
15299        if selected.len() != pairs || route_weights.len() != pairs {
15300            return Err(format!(
15301                "NVFP4 TP routes selected={} weights={} != tokens {tokens} x experts/token \
15302                 {experts_per_token} ({pairs})",
15303                selected.len(),
15304                route_weights.len(),
15305            )
15306            .into());
15307        }
15308        if !route_weights.iter().all(|weight| weight.is_finite()) {
15309            return Err("NVFP4 TP route weights contain a non-finite value".into());
15310        }
15311
15312        let mut output = vec![0.0f32; tokens * experts.input_width];
15313        for token in 0..tokens {
15314            let input_row = &input[token * experts.input_width..(token + 1) * experts.input_width];
15315            for slot in 0..experts_per_token {
15316                let pair = token * experts_per_token + slot;
15317                let expert = selected[pair];
15318                if expert >= experts.expert_count {
15319                    return Err(format!(
15320                        "NVFP4 TP selected expert {expert} outside 0..{}",
15321                        experts.expert_count
15322                    )
15323                    .into());
15324                }
15325                // EP2 banks hold the WHOLE expert on rank (expert & 1) at slot (expert >> 1);
15326                // per-row dots are the same full-width program either way (a column shard
15327                // splits ROWS, not the dot), so gate/up are bit-equal across layouts. Only
15328                // down's parenthesization moves (full-width dot vs canonical 2-shard sum) —
15329                // the numeric-class this door declares.
15330                let gate = if experts.ep2 {
15331                    self.run_full_bank_expert_nvfp4(
15332                        &experts.gate,
15333                        &experts.macros_gate,
15334                        expert,
15335                        input_row,
15336                    )?
15337                } else {
15338                    self.run_column_bank_expert_nvfp4(
15339                        &experts.gate,
15340                        &experts.macros_gate,
15341                        expert,
15342                        input_row,
15343                    )?
15344                };
15345                let up = if experts.ep2 {
15346                    self.run_full_bank_expert_nvfp4(
15347                        &experts.up,
15348                        &experts.macros_up,
15349                        expert,
15350                        input_row,
15351                    )?
15352                } else {
15353                    self.run_column_bank_expert_nvfp4(
15354                        &experts.up,
15355                        &experts.macros_up,
15356                        expert,
15357                        input_row,
15358                    )?
15359                };
15360                let activated: Vec<f32> = gate
15361                    .iter()
15362                    .zip(&up)
15363                    .map(|(&gate, &up)| step_expert_activation_host(gate, up, activation_limit))
15364                    .collect();
15365                debug_assert_eq!(activated.len(), experts.expert_width);
15366                let down = if experts.ep2 {
15367                    self.run_full_down_expert_nvfp4(
15368                        &experts.down,
15369                        &experts.macros_down,
15370                        expert,
15371                        &activated,
15372                    )?
15373                } else {
15374                    self.run_row_bank_expert_nvfp4(
15375                        &experts.down,
15376                        &experts.macros_down,
15377                        expert,
15378                        &activated,
15379                    )?
15380                };
15381                let weight = route_weights[pair];
15382                for (sum, value) in output
15383                    [token * experts.input_width..(token + 1) * experts.input_width]
15384                    .iter_mut()
15385                    .zip(down)
15386                {
15387                    *sum += weight * value;
15388                }
15389            }
15390        }
15391        Ok(output)
15392    }
15393}
15394
15395#[cfg(test)]
15396mod default_on_door_tests {
15397    use super::door_default_on_value;
15398
15399    /// The DEFAULT-ON parse, pinned in every state — including the two that only matter because
15400    /// the default is ON.
15401    ///
15402    /// While these doors were default OFF the parse was `== Ok("1")` and its failure mode was
15403    /// benign: any typo read as the default, which was OFF, which was the safe program. Flipping
15404    /// the default INVERTS that. Under a naive `!= Ok("0")` rule, `MEMRA_NVFP4_BANK_SM=false`
15405    /// (or `=off`, or `=no`) would leave the program ARMED while the operator believed they had
15406    /// rolled it back — a rollback seam that silently does nothing, on the exact door whose
15407    /// predecessor shipped fluent wrong text. So the unrecognized-value case is a named,
15408    /// tested branch that keeps the default AND warns, rather than an accident of `!=`.
15409    #[test]
15410    fn the_default_on_door_parses_every_state_and_names_its_source() {
15411        // unset: the flip is what arms it, and the source string says so — this is the string a
15412        // default-flip receipt needs, because in the flip arms there is no env var to point at.
15413        assert_eq!(
15414            door_default_on_value("MEMRA_TEST_DOOR", None),
15415            (true, "default-on")
15416        );
15417        // explicit 1: armed by a RECIPE, not by the default. Different fact, different label.
15418        assert_eq!(
15419            door_default_on_value("MEMRA_TEST_DOOR", Some("1")),
15420            (true, "env=1")
15421        );
15422        // THE ROLLBACK SEAM. This is the assertion the flip's safety rests on.
15423        assert_eq!(
15424            door_default_on_value("MEMRA_TEST_DOOR", Some("0")),
15425            (false, "env=0 (rollback seam)")
15426        );
15427        // Unrecognized values keep the DEFAULT (ON) and are flagged as such, for every shape an
15428        // operator plausibly types when they mean "off". Every one of these MUST still read ON:
15429        // a parse that guessed "off" from `false` would be a second, undocumented seam, and a
15430        // parse that guessed "off" from `2` would make a typo a silent program change.
15431        for bad in [
15432            "false", "off", "no", "", " 0", "0 ", "00", "true", "2", "-1",
15433        ] {
15434            let (on, source) = door_default_on_value("MEMRA_TEST_DOOR", Some(bad));
15435            assert!(on, "value {bad:?} must NOT disarm a default-ON door");
15436            assert!(
15437                source.contains("default-on") && source.contains("unrecognized"),
15438                "value {bad:?} gave source {source:?}, which does not announce itself as an \
15439                 ignored value — a receipt reader would take it for a clean default"
15440            );
15441        }
15442    }
15443}
15444
15445#[cfg(test)]
15446mod bank_v2_layout_tests {
15447    use super::{nvfp4_matrix_v2_permute, nvfp4_row_bytes};
15448
15449    /// The slot-major permutation had NO test at all until 2026-08-29, while its (since
15450    /// removed) `MEMRA_NVFP4_BANK_V2` FLAGS row carried a bit-identity claim and the live
15451    /// serving env pinned it on. This pins the DOCUMENTED mapping so a reader can be checked
15452    /// against something: per row, slot g's 16 qs bytes land contiguously at `g*16`, and its
15453    /// two UE4M3 scale bytes at `nslots*16 + g*2`. Source layout is memra `block_nvfp4`:
15454    /// 36-byte superblocks of [4 scale bytes | 32 packed e2m1], two 32-value slots per
15455    /// superblock. Since the 2026-08-29 door removal the permutation's ONLY consumer is the
15456    /// EP2 whole-expert bank build (`nvfp4_repack_bank_matrix(_, true)`), whose `*_ep`
15457    /// kernels and `qmatvec_nvfp4_fast_v2` oracle read this exact mapping.
15458    #[test]
15459    fn the_v2_bank_row_is_the_documented_slot_major_permutation() {
15460        // two rows, in_features 128 => 2 superblocks/row, 4 slots/row, 72 bytes/row.
15461        let (out_f, in_f) = (2usize, 128usize);
15462        let row_bytes = nvfp4_row_bytes(in_f);
15463        assert_eq!(row_bytes, 72);
15464        let v1: Vec<u8> = (0..out_f * row_bytes).map(|i| (i % 251) as u8).collect();
15465        let v2 = nvfp4_matrix_v2_permute(&v1, out_f, in_f);
15466        assert_eq!(v2.len(), v1.len(), "a permutation cannot change the size");
15467        let n_slots = in_f / 32;
15468        for row in 0..out_f {
15469            let src = &v1[row * row_bytes..(row + 1) * row_bytes];
15470            let dst = &v2[row * row_bytes..(row + 1) * row_bytes];
15471            for g in 0..n_slots {
15472                let (sblk, h) = (g / 2, g % 2);
15473                let sb = &src[sblk * 36..sblk * 36 + 36];
15474                assert_eq!(
15475                    &dst[g * 16..g * 16 + 16],
15476                    &sb[4 + 16 * h..4 + 16 * h + 16],
15477                    "row {row} slot {g} codes"
15478                );
15479                assert_eq!(
15480                    &dst[n_slots * 16 + g * 2..n_slots * 16 + g * 2 + 2],
15481                    &sb[2 * h..2 * h + 2],
15482                    "row {row} slot {g} scales"
15483                );
15484            }
15485            // and it moves bytes only: same multiset per row, rows never cross.
15486            let (mut a, mut b) = (src.to_vec(), dst.to_vec());
15487            a.sort_unstable();
15488            b.sort_unstable();
15489            assert_eq!(a, b, "row {row} is not a byte permutation");
15490        }
15491    }
15492}
15493
15494#[cfg(test)]
15495mod tests {
15496
15497    #[test]
15498    fn replicated_row_join_is_strictly_tp2_native_and_nonempty() {
15499        assert!(super::validate_tp2_replicated_row_join(2, true, 4096).is_ok());
15500        assert!(
15501            super::validate_tp2_replicated_row_join(1, true, 4096)
15502                .unwrap_err()
15503                .contains("exactly two ranks")
15504        );
15505        assert!(
15506            super::validate_tp2_replicated_row_join(4, true, 4096)
15507                .unwrap_err()
15508                .contains("exactly two ranks")
15509        );
15510        assert!(
15511            super::validate_tp2_replicated_row_join(2, false, 4096)
15512                .unwrap_err()
15513                .contains("native P2P")
15514        );
15515        assert!(super::validate_tp2_replicated_row_join(2, true, 0).is_err());
15516    }
15517
15518    #[test]
15519    fn door_composition_refuses_first_armed_flag_by_name() {
15520        let table: [(&str, &str); 2] = [
15521            ("MEMRA_DOOR_A", "gated on the unsharded walk only"),
15522            ("MEMRA_DOOR_B", "no sharded branches"),
15523        ];
15524        // cold doors pass
15525        super::refuse_door_composition("MEMRA_X_TP", &table, |_| false).expect("cold doors pass");
15526        // an armed door refuses with the exact byte format the glm5 gate asserts on
15527        let err = super::refuse_door_composition("MEMRA_X_TP", &table, |f| f == "MEMRA_DOOR_B")
15528            .expect_err("armed door must refuse");
15529        assert_eq!(
15530            err,
15531            "MEMRA_X_TP + MEMRA_DOOR_B: unproven composition, refused (no sharded branches)"
15532        );
15533        // a flag outside the table never trips it
15534        super::refuse_door_composition("MEMRA_X_TP", &table, |f| f == "MEMRA_DOOR_C")
15535            .expect("foreign flags are not the matrix");
15536    }
15537
15538    /// THE DEFECT, ASSERTED SO IT CANNOT COME BACK. The retired memo key hashed only the K
15539    /// pointer, the base pointer, the layer and t, while the table it returned ALSO carried
15540    /// the V and LEN pointers. Two different allocation generations that happen to share a K
15541    /// address therefore collide, and the entry the map hands back sends a live launch at
15542    /// another allocation's V and len. This test does not assert the key is fine; it asserts
15543    /// the key is BLIND, which is why `rows_tab_restage_on` exists and defaults ON.
15544    #[test]
15545    fn the_retired_rows_tab_key_cannot_see_the_v_and_len_pointers_it_hands_back() {
15546        let (kp, bp) = (0xdead_0000u64, 0u64);
15547        let live = [[kp, 0x00b1_0000u64, 0x00c1_0000u64, bp]];
15548        let recycled = [[kp, 0x00b2_0000u64, 0x00c2_0000u64, bp]];
15549        assert_eq!(
15550            super::retired_rows_tab_key(kp, bp, 20, 2),
15551            super::retired_rows_tab_key(kp, bp, 20, 2),
15552            "same layer and t must hash the same, or the test proves nothing"
15553        );
15554        let a = super::rows_tab_host(&live, 0x9000, true, 1);
15555        let b = super::rows_tab_host(&recycled, 0x9000, true, 1);
15556        assert_ne!(a, b, "the two generations write DIFFERENT tables");
15557        // ... yet one key covers both, which is exactly the use-after-free.
15558        assert_eq!(
15559            super::retired_rows_tab_key(live[0][0], live[0][3], 20, 1),
15560            super::retired_rows_tab_key(recycled[0][0], recycled[0][3], 20, 1),
15561            "the retired key collides across allocation generations"
15562        );
15563    }
15564
15565    /// The restage must be VALUE-NEUTRAL: on a fresh lookup the memo and the restage produce
15566    /// identical bytes, which is what makes spec-on output byte-identical to spec-off.
15567    #[test]
15568    fn rows_tab_layout_is_the_same_bytes_the_memo_would_have_cached() {
15569        let parts = [
15570            [0x00a0u64, 0x00b0u64, 0x00c0u64, 0x00d0u64],
15571            [0x00a1u64, 0x00b1u64, 0x00c1u64, 0x00d1u64],
15572        ];
15573        let same = super::rows_tab_host(&parts, 0x7000, true, 2);
15574        assert_eq!(
15575            same,
15576            vec![
15577                0x00a0u64, 0x00b0u64, 0x00c0u64, 0x00d0u64, 0x7000,
15578                1, // row 0: back = t-1-r = 1
15579                0x00a1u64, 0x00b1u64, 0x00c1u64, 0x00d1u64, 0x7000, 0, // row 1: back = 0
15580            ],
15581            "same-session rows share one counter cell and step back t-1-r"
15582        );
15583        let cross = super::rows_tab_host(&parts, 0x7000, false, 2);
15584        assert_eq!(
15585            cross,
15586            vec![
15587                0x00a0u64, 0x00b0u64, 0x00c0u64, 0x00d0u64, 0x7000, 0, 0x00a1u64, 0x00b1u64,
15588                0x00c1u64, 0x00d1u64, 0x7004, 0,
15589            ],
15590            "cross-session rows get their own counter cell and no step back"
15591        );
15592    }
15593    use super::*;
15594
15595    #[test]
15596    fn step_expert_activation_clamps_each_arm_by_the_official_contract() {
15597        let limit = Some(7.0);
15598        assert_eq!(step_expert_activation_host(20.0, 9.0, limit), 49.0);
15599        assert_eq!(step_expert_activation_host(20.0, -9.0, limit), -49.0);
15600        assert!(
15601            step_expert_activation_host(-20.0, 9.0, limit).abs()
15602                < step_expert_activation_host(-20.0, 9.0, None).abs()
15603        );
15604        assert!(validate_step_expert_activation_limit(Some(f32::NAN)).is_err());
15605        assert!(validate_step_expert_activation_limit(Some(0.0)).is_err());
15606        assert!(validate_step_expert_activation_limit(limit).is_ok());
15607    }
15608
15609    #[test]
15610    fn moe_residual_host_preserves_official_add_order() {
15611        let output = moe_residual_host(&[1.0e20], &[-1.0e20], &[1.0]).unwrap();
15612        assert_eq!(output, [0.0]);
15613        assert_eq!(
15614            moe_residual_host(&[0.0], &[0.0, 1.0], &[0.0]).unwrap_err(),
15615            "MoE residual lengths residual=1 routed=2 shared=1"
15616        );
15617    }
15618
15619    #[test]
15620    fn expert_owner_routes_preserve_global_pair_order_with_local_expert_ids() {
15621        let selected = [0, 36, 72, 108, 144, 180, 216, 252];
15622        let owners = partition_expert_owner_routes(288, 4, 1, 8, &selected).unwrap();
15623        assert_eq!(owners.len(), 4);
15624        for (rank, owner) in owners.iter().enumerate() {
15625            assert_eq!(owner.rank, rank);
15626            assert_eq!(owner.selected, vec![0, 36]);
15627            assert_eq!(owner.token_rows, vec![0, 0]);
15628            assert_eq!(owner.global_pairs, vec![rank * 2, rank * 2 + 1]);
15629        }
15630    }
15631
15632    #[test]
15633    fn expert_owner_routes_validate_geometry_and_selected_experts() {
15634        assert!(partition_expert_owner_routes(288, 5, 1, 8, &[0; 8]).is_err());
15635        assert!(partition_expert_owner_routes(288, 4, 2, 8, &[0; 8]).is_err());
15636        let error = partition_expert_owner_routes(288, 4, 1, 8, &[288; 8]).unwrap_err();
15637        assert!(error.contains("outside 0..288"));
15638    }
15639
15640    #[test]
15641    fn step_grouped_owner_routes_validate_dynamic_top8_shapes() {
15642        let selected = [
15643            1, 73, 80, 145, 152, 159, 217, 224, 12, 84, 91, 156, 163, 170, 228, 235,
15644        ];
15645        assert_eq!(
15646            validate_step_grouped_owner_routes(288, 2, &selected).unwrap(),
15647            16
15648        );
15649        let owners = partition_expert_owner_routes(288, 4, 2, 8, &selected).unwrap();
15650        assert_eq!(
15651            owners
15652                .iter()
15653                .map(|owner| owner.selected.len())
15654                .collect::<Vec<_>>(),
15655            vec![2, 4, 6, 4]
15656        );
15657        assert!(validate_step_grouped_owner_routes(288, 2, &selected[..8]).is_err());
15658        assert!(validate_step_grouped_owner_routes(288, 1, &[0; 8]).is_err());
15659        assert!(validate_step_grouped_owner_routes(287, 2, &selected).is_err());
15660    }
15661
15662    #[test]
15663    fn weighted_route_combine_requires_a_canonical_pair_permutation() {
15664        let owner0 = [0usize, 3];
15665        let owner1 = [1usize, 2];
15666        let owners = [owner0.as_slice(), owner1.as_slice()];
15667        assert_eq!(
15668            validate_weighted_route_combine(4096, 4, 3, 1, &owners, &[0.1, 0.2, 0.3, 0.4],)
15669                .unwrap(),
15670            WeightedRouteCombineShape {
15671                pairs: 4,
15672                max_pairs: 12,
15673            }
15674        );
15675        let duplicate = [owner0.as_slice(), &[1usize, 1][..]];
15676        assert!(
15677            validate_weighted_route_combine(4096, 4, 3, 1, &duplicate, &[0.1, 0.2, 0.3, 0.4],)
15678                .is_err()
15679        );
15680        assert!(
15681            validate_weighted_route_combine(4096, 4, 3, 1, &owners, &[0.1, f32::NAN, 0.3, 0.4],)
15682                .is_err()
15683        );
15684        assert!(
15685            validate_weighted_route_combine(4096, 4, 1, 2, &owners, &[0.1, 0.2, 0.3, 0.4],)
15686                .is_err()
15687        );
15688    }
15689
15690    #[test]
15691    fn native_p2p_door_is_strict_and_default_off() {
15692        assert!(!parse_step_tp_native_p2p(None).unwrap());
15693        assert!(!parse_step_tp_native_p2p(Some("")).unwrap());
15694        assert!(!parse_step_tp_native_p2p(Some("0")).unwrap());
15695        assert!(parse_step_tp_native_p2p(Some("1")).unwrap());
15696        assert!(parse_step_tp_native_p2p(Some("true")).is_err());
15697        assert!(parse_step_tp_native_p2p(Some("2")).is_err());
15698    }
15699
15700    #[test]
15701    fn bulk_p2p_door_is_strict_and_default_off() {
15702        assert!(!parse_step_tp_bulk_p2p(None).unwrap());
15703        assert!(!parse_step_tp_bulk_p2p(Some("")).unwrap());
15704        assert!(!parse_step_tp_bulk_p2p(Some("0")).unwrap());
15705        assert!(parse_step_tp_bulk_p2p(Some("1")).unwrap());
15706        assert!(parse_step_tp_bulk_p2p(Some("true")).is_err());
15707        assert!(parse_step_tp_bulk_p2p(Some("2")).is_err());
15708    }
15709
15710    #[test]
15711    fn ep_device_arithmetic_door_is_strict_and_default_off() {
15712        assert!(!parse_step_ep_device_arithmetic(None).unwrap());
15713        assert!(!parse_step_ep_device_arithmetic(Some("")).unwrap());
15714        assert!(!parse_step_ep_device_arithmetic(Some("0")).unwrap());
15715        assert!(parse_step_ep_device_arithmetic(Some("1")).unwrap());
15716        assert!(parse_step_ep_device_arithmetic(Some("true")).is_err());
15717        assert!(parse_step_ep_device_arithmetic(Some("2")).is_err());
15718    }
15719
15720    #[test]
15721    fn f32_mirror_door_is_strict_and_default_off() {
15722        assert!(!parse_step_tp_f32_mirror(None).unwrap());
15723        assert!(!parse_step_tp_f32_mirror(Some("")).unwrap());
15724        assert!(!parse_step_tp_f32_mirror(Some("0")).unwrap());
15725        assert!(parse_step_tp_f32_mirror(Some("1")).unwrap());
15726        assert!(parse_step_tp_f32_mirror(Some("true")).is_err());
15727        assert!(parse_step_tp_f32_mirror(Some("2")).is_err());
15728    }
15729
15730    fn matrix(out_features: usize, in_features: usize) -> (Vec<u8>, Vec<f32>) {
15731        let codes = (0..out_features * in_features)
15732            .map(|index| (index % 251) as u8)
15733            .collect();
15734        let scales = (0..out_features.div_ceil(FP8_BLOCK) * in_features.div_ceil(FP8_BLOCK))
15735            .map(|index| index as f32 + 1.0)
15736            .collect();
15737        (codes, scales)
15738    }
15739
15740    fn bf16_matrix_bytes(out_features: usize, in_features: usize) -> Vec<u8> {
15741        (0..out_features * in_features)
15742            .flat_map(|value| (value as u16).to_le_bytes())
15743            .collect()
15744    }
15745
15746    fn decode_u16(bytes: &[u8]) -> Vec<u16> {
15747        bytes
15748            .chunks_exact(2)
15749            .map(|bytes| u16::from_le_bytes([bytes[0], bytes[1]]))
15750            .collect()
15751    }
15752
15753    #[test]
15754    fn bf16_matrix_rejects_wrong_byte_count() {
15755        let bytes = vec![0u8; 4 * 4 * 2 - 1];
15756        let matrix = Bf16Matrix {
15757            bytes: &bytes,
15758            out_features: 4,
15759            in_features: 4,
15760        };
15761        assert!(matrix.validate().unwrap_err().contains("4x4x2"));
15762    }
15763
15764    #[test]
15765    fn replicated_device_rows_require_exact_rank_local_shapes() {
15766        assert_eq!(
15767            replicated_device_row_values(3, 4096, 4, &[12_288; 4]).unwrap(),
15768            12_288
15769        );
15770        assert!(replicated_device_row_values(0, 4096, 4, &[0; 4]).is_err());
15771        assert!(replicated_device_row_values(3, 0, 4, &[0; 4]).is_err());
15772        assert!(replicated_device_row_values(3, 4096, 4, &[12_288; 3]).is_err());
15773        assert!(
15774            replicated_device_row_values(3, 4096, 4, &[12_288, 12_288, 12_287, 12_288]).is_err()
15775        );
15776        assert!(replicated_device_row_values(usize::MAX, 2, 1, &[0]).is_err());
15777    }
15778
15779    #[test]
15780    fn replicated_device_row_refresh_requires_exact_root_source() {
15781        assert_eq!(
15782            replicated_device_row_source_values(1, 12_288, 12_288, 3, 3).unwrap(),
15783            12_288
15784        );
15785        assert!(replicated_device_row_source_values(0, 12_288, 0, 3, 3).is_err());
15786        assert!(replicated_device_row_source_values(1, 0, 0, 3, 3).is_err());
15787        assert!(replicated_device_row_source_values(1, 12_288, 12_287, 3, 3).is_err());
15788        assert!(replicated_device_row_source_values(1, 12_288, 12_288, 2, 3).is_err());
15789        assert!(replicated_device_row_source_values(usize::MAX, 2, 0, 3, 3).is_err());
15790    }
15791
15792    #[test]
15793    fn step_bf16_canonical_rows_are_topology_invariant_through_tp8() {
15794        for tp in [1, 2, 4, 8] {
15795            assert_eq!(step_bf16_canonical_chunk_rows(8_192, tp).unwrap(), 1_024);
15796            assert_eq!(step_bf16_canonical_chunk_rows(12_288, tp).unwrap(), 1_536);
15797            assert_eq!(step_bf16_canonical_chunk_rows(1_024, tp).unwrap(), 128);
15798            assert_eq!(step_bf16_canonical_chunk_cols(8_192, tp).unwrap(), 1_024);
15799            assert_eq!(step_bf16_canonical_chunk_cols(12_288, tp).unwrap(), 1_536);
15800        }
15801        assert!(step_bf16_canonical_chunk_rows(12_288, 3).is_err());
15802        assert!(step_bf16_canonical_chunk_rows(1_001, 2).is_err());
15803        assert!(step_bf16_canonical_chunk_cols(12_288, 3).is_err());
15804        assert!(step_bf16_canonical_chunk_cols(1_001, 2).is_err());
15805    }
15806
15807    #[test]
15808    fn cache_rows_split_by_token_then_rank() {
15809        let rows = (0u8..24).collect::<Vec<_>>();
15810        assert_eq!(
15811            cache_rank_rows(&rows, 3, 4, 2, 0).unwrap(),
15812            vec![0, 1, 2, 3, 8, 9, 10, 11, 16, 17, 18, 19]
15813        );
15814        assert_eq!(
15815            cache_rank_rows(&rows, 3, 4, 2, 1).unwrap(),
15816            vec![4, 5, 6, 7, 12, 13, 14, 15, 20, 21, 22, 23]
15817        );
15818        assert!(cache_rank_rows(&rows[..23], 3, 4, 2, 0).is_err());
15819        assert!(cache_rank_rows(&rows, 3, 4, 2, 2).is_err());
15820    }
15821
15822    #[test]
15823    fn bf16_column_shard_preserves_contiguous_output_rows() {
15824        let bytes = bf16_matrix_bytes(4, 4);
15825        let matrix = Bf16Matrix {
15826            bytes: &bytes,
15827            out_features: 4,
15828            in_features: 4,
15829        };
15830        let shard = bf16_column_shard(matrix, 2, 1).unwrap();
15831        assert_eq!(shard.out_features, 2);
15832        assert_eq!(shard.in_features, 4);
15833        assert_eq!(decode_u16(shard.bytes), (8..16).collect::<Vec<_>>());
15834    }
15835
15836    #[test]
15837    fn bf16_row_shard_preserves_each_input_column_window() {
15838        let bytes = bf16_matrix_bytes(3, 4);
15839        let matrix = Bf16Matrix {
15840            bytes: &bytes,
15841            out_features: 3,
15842            in_features: 4,
15843        };
15844        let shard = bf16_row_shard(matrix, 2, 1).unwrap();
15845        assert_eq!(decode_u16(&shard), vec![2, 3, 6, 7, 10, 11]);
15846    }
15847
15848    #[test]
15849    fn bf16_row_block_preserves_global_column_order() {
15850        let bytes = bf16_matrix_bytes(3, 8);
15851        let matrix = Bf16Matrix {
15852            bytes: &bytes,
15853            out_features: 3,
15854            in_features: 8,
15855        };
15856        let block = bf16_row_block(matrix, 2, 3).unwrap();
15857        assert_eq!(decode_u16(&block), vec![2, 3, 4, 10, 11, 12, 18, 19, 20]);
15858    }
15859
15860    #[test]
15861    fn column_shard_preserves_contiguous_weight_and_scale_rows() {
15862        let (codes, scales) = matrix(1280, 4096);
15863        let matrix = E4m3BlockMatrix {
15864            codes: &codes,
15865            scales: &scales,
15866            out_features: 1280,
15867            in_features: 4096,
15868        };
15869        let shard = column_shard(matrix, 2, 1).unwrap();
15870        assert_eq!(shard.out_features, 640);
15871        assert_eq!(shard.codes, &codes[640 * 4096..]);
15872        assert_eq!(shard.scales, &scales[5 * 32..]);
15873    }
15874
15875    #[test]
15876    fn row_shard_preserves_each_weight_and_scale_column_window() {
15877        let (codes, scales) = matrix(4096, 1280);
15878        let matrix = E4m3BlockMatrix {
15879            codes: &codes,
15880            scales: &scales,
15881            out_features: 4096,
15882            in_features: 1280,
15883        };
15884        let (shard_codes, shard_scales) = row_shard(matrix, 2, 1).unwrap();
15885        assert_eq!(shard_codes.len(), 4096 * 640);
15886        assert_eq!(&shard_codes[..640], &codes[640..1280]);
15887        assert_eq!(&shard_codes[640..1280], &codes[1280 + 640..2560]);
15888        assert_eq!(shard_scales.len(), 32 * 5);
15889        assert_eq!(&shard_scales[..5], &scales[5..10]);
15890        assert_eq!(&shard_scales[5..10], &scales[15..20]);
15891    }
15892
15893    #[test]
15894    fn activation_shards_keep_token_rows_separate() {
15895        let activations: Vec<f32> = (0..2 * 8).map(|value| value as f32).collect();
15896        assert_eq!(
15897            activation_shard(&activations, 2, 8, 2, 1),
15898            vec![4.0, 5.0, 6.0, 7.0, 12.0, 13.0, 14.0, 15.0],
15899        );
15900    }
15901
15902    #[test]
15903    fn expert_bank_selects_expert_major_code_and_scale_planes() {
15904        let expert_count = 2;
15905        let out_features = 128;
15906        let in_features = 128;
15907        let code_stride = out_features * in_features;
15908        let codes: Vec<u8> = (0..expert_count * code_stride)
15909            .map(|index| (index % 251) as u8)
15910            .collect();
15911        let scales = vec![1.0f32, 2.0];
15912        let bank = E4m3ExpertBank {
15913            codes: &codes,
15914            scales: &scales,
15915            expert_count,
15916            out_features,
15917            in_features,
15918        };
15919        bank.validate().unwrap();
15920        let expert = bank.expert(1).unwrap();
15921        assert_eq!(expert.codes, &codes[code_stride..]);
15922        assert_eq!(expert.scales, &[2.0]);
15923    }
15924
15925    #[test]
15926    fn expert_bank_rejects_non_positive_scale() {
15927        let codes = vec![0u8; 128 * 128];
15928        let scales = vec![0.0f32];
15929        let bank = E4m3ExpertBank {
15930            codes: &codes,
15931            scales: &scales,
15932            expert_count: 1,
15933            out_features: 128,
15934            in_features: 128,
15935        };
15936        assert!(bank.validate().unwrap_err().contains("non-positive"));
15937    }
15938
15939    #[test]
15940    fn tensor_parallel_column_bank_keeps_each_expert_scale_plane_separate() {
15941        let expert_count = 2;
15942        let out_features = 256;
15943        let in_features = 128;
15944        let code_stride = out_features * in_features;
15945        let scale_stride = 2;
15946        let codes = (0..expert_count * code_stride)
15947            .map(|index| (index % 251) as u8)
15948            .collect::<Vec<_>>();
15949        let scales = vec![10.0f32, 11.0, 20.0, 21.0];
15950        let bank = E4m3ExpertBank {
15951            codes: &codes,
15952            scales: &scales,
15953            expert_count,
15954            out_features,
15955            in_features,
15956        };
15957
15958        let rank = pack_column_bank_rank(bank, 2, 1).unwrap();
15959        assert_eq!(rank.out_features, 128);
15960        assert_eq!(rank.in_features, 128);
15961        assert_eq!(rank.codes.len(), expert_count * 128 * 128);
15962        assert_eq!(rank.scales, vec![11.0, 21.0]);
15963        assert_eq!(&rank.codes[..128 * 128], &codes[128 * 128..256 * 128]);
15964        assert_eq!(
15965            &rank.codes[128 * 128..],
15966            &codes[code_stride + 128 * 128..2 * code_stride]
15967        );
15968        assert_eq!(scale_stride, scales.len() / expert_count);
15969    }
15970
15971    #[test]
15972    fn tensor_parallel_row_bank_keeps_each_expert_scale_plane_separate() {
15973        let expert_count = 2;
15974        let out_features = 128;
15975        let in_features = 256;
15976        let code_stride = out_features * in_features;
15977        let codes = (0..expert_count * code_stride)
15978            .map(|index| (index % 251) as u8)
15979            .collect::<Vec<_>>();
15980        let scales = vec![10.0f32, 11.0, 20.0, 21.0];
15981        let bank = E4m3ExpertBank {
15982            codes: &codes,
15983            scales: &scales,
15984            expert_count,
15985            out_features,
15986            in_features,
15987        };
15988
15989        let rank = pack_row_bank_rank(bank, 2, 1).unwrap();
15990        assert_eq!(rank.out_features, 128);
15991        assert_eq!(rank.in_features, 128);
15992        assert_eq!(rank.k_blocks, Some(1));
15993        assert_eq!(rank.codes.len(), expert_count * 128 * 128);
15994        assert_eq!(rank.scales, vec![11.0, 21.0]);
15995        assert_eq!(&rank.codes[..128], &codes[128..256]);
15996        assert_eq!(
15997            &rank.codes[128 * 128..128 * 128 + 128],
15998            &codes[code_stride + 128..code_stride + 256]
15999        );
16000    }
16001
16002    #[test]
16003    fn tensor_parallel_row_bank_preserves_global_k_block_order() {
16004        let expert_count = 2;
16005        let out_features = 256;
16006        let in_features = 512;
16007        let code_stride = out_features * in_features;
16008        let mut codes = vec![0u8; expert_count * code_stride];
16009        for expert in 0..expert_count {
16010            for row in 0..out_features {
16011                for block in 0..4 {
16012                    let value = (expert * 80 + block * 16 + row % 16) as u8;
16013                    let start = expert * code_stride + row * in_features + block * FP8_BLOCK;
16014                    codes[start..start + FP8_BLOCK].fill(value);
16015                }
16016            }
16017        }
16018        let scales = vec![
16019            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,
16020            112.0, 113.0, 114.0,
16021        ];
16022        let bank = E4m3ExpertBank {
16023            codes: &codes,
16024            scales: &scales,
16025            expert_count,
16026            out_features,
16027            in_features,
16028        };
16029
16030        let rank = pack_row_bank_rank(bank, 2, 1).unwrap();
16031        assert_eq!(rank.out_features, out_features);
16032        assert_eq!(rank.in_features, 256);
16033        assert_eq!(rank.k_blocks, Some(2));
16034        assert_eq!(rank.code_stride, out_features * 256);
16035        assert_eq!(rank.scale_stride, 4);
16036        assert_eq!(&rank.scales[..4], &[3.0, 13.0, 4.0, 14.0]);
16037        assert_eq!(&rank.scales[4..], &[103.0, 113.0, 104.0, 114.0]);
16038
16039        let block_stride = out_features * FP8_BLOCK;
16040        assert!(rank.codes[..FP8_BLOCK].iter().all(|&code| code == 32));
16041        assert!(
16042            rank.codes[block_stride..block_stride + FP8_BLOCK]
16043                .iter()
16044                .all(|&code| code == 48)
16045        );
16046        assert!(
16047            rank.codes[rank.code_stride..rank.code_stride + FP8_BLOCK]
16048                .iter()
16049                .all(|&code| code == 112)
16050        );
16051        assert!(
16052            rank.codes
16053                [rank.code_stride + block_stride..rank.code_stride + block_stride + FP8_BLOCK]
16054                .iter()
16055                .all(|&code| code == 128)
16056        );
16057    }
16058
16059    #[test]
16060    fn automatic_parallel_policy_needs_only_one_device_set_not_layer_recipes() {
16061        assert_eq!(parse_auto_parallel_devices(None, None).unwrap(), None);
16062        assert_eq!(
16063            parse_auto_parallel_devices(Some("auto"), Some("0,1,2,3")).unwrap(),
16064            Some(vec![0, 1, 2, 3])
16065        );
16066        assert!(parse_auto_parallel_devices(Some("auto"), None).is_err());
16067        assert!(parse_auto_parallel_devices(Some("auto"), Some("0,1,1")).is_err());
16068        assert!(parse_auto_parallel_devices(Some("auto"), Some("0,1,2,3,4")).is_err());
16069        assert!(parse_auto_parallel_devices(Some("ep"), Some("0,1")).is_err());
16070    }
16071
16072    #[test]
16073    fn automatic_ep_device_router_flag_is_strict() {
16074        assert!(!parse_parallel_ep_device_router(None).unwrap());
16075        assert!(!parse_parallel_ep_device_router(Some("0")).unwrap());
16076        assert!(parse_parallel_ep_device_router(Some("1")).unwrap());
16077        assert!(parse_parallel_ep_device_router(Some("true")).is_err());
16078    }
16079
16080    #[test]
16081    fn automatic_ep_graph_flag_is_strict_and_defaults_off() {
16082        assert!(!parse_parallel_ep_graph(None).unwrap());
16083        assert!(!parse_parallel_ep_graph(Some("0")).unwrap());
16084        assert!(parse_parallel_ep_graph(Some("1")).unwrap());
16085        assert!(parse_parallel_ep_graph(Some("true")).is_err());
16086    }
16087
16088    #[test]
16089    fn automatic_ep_pair_down_flag_is_strict_and_defaults_off() {
16090        assert!(!parse_parallel_ep_pair_down(None).unwrap());
16091        assert!(!parse_parallel_ep_pair_down(Some("0")).unwrap());
16092        assert!(parse_parallel_ep_pair_down(Some("1")).unwrap());
16093        assert!(parse_parallel_ep_pair_down(Some("true")).is_err());
16094    }
16095
16096    #[test]
16097    fn automatic_ep_q8_activation_flag_is_strict() {
16098        assert!(!parse_parallel_ep_q8_act(None).unwrap());
16099        assert!(!parse_parallel_ep_q8_act(Some("0")).unwrap());
16100        assert!(parse_parallel_ep_q8_act(Some("1")).unwrap());
16101        assert!(parse_parallel_ep_q8_act(Some("true")).is_err());
16102    }
16103
16104    #[test]
16105    fn automatic_ep_q8_scope_is_explicit_and_strict() {
16106        assert_eq!(parse_parallel_ep_q8_scope(None).unwrap(), None);
16107        assert_eq!(
16108            parse_parallel_ep_q8_scope(Some("all")).unwrap(),
16109            Some(ParallelEpQ8Scope::All)
16110        );
16111        assert_eq!(
16112            parse_parallel_ep_q8_scope(Some("gate-up")).unwrap(),
16113            Some(ParallelEpQ8Scope::GateUp)
16114        );
16115        assert_eq!(
16116            parse_parallel_ep_q8_scope(Some("down")).unwrap(),
16117            Some(ParallelEpQ8Scope::Down)
16118        );
16119        assert!(parse_parallel_ep_q8_scope(Some("input")).is_err());
16120    }
16121
16122    #[test]
16123    fn automatic_ep_q8_gate_up_paired_is_parent_scoped_and_strict() {
16124        assert_eq!(parse_parallel_ep_q8_gu_paired(None).unwrap(), None);
16125        assert_eq!(parse_parallel_ep_q8_gu_paired(Some("")).unwrap(), None);
16126        assert_eq!(
16127            parse_parallel_ep_q8_gu_paired(Some("0")).unwrap(),
16128            Some(false)
16129        );
16130        assert_eq!(
16131            parse_parallel_ep_q8_gu_paired(Some("1")).unwrap(),
16132            Some(true)
16133        );
16134        assert!(parse_parallel_ep_q8_gu_paired(Some("paired")).is_err());
16135        assert!(parse_parallel_ep_q8_gu_paired(Some("true")).is_err());
16136
16137        assert!(!resolve_parallel_ep_q8_gu_paired(None, false, None).unwrap());
16138        assert!(resolve_parallel_ep_q8_gu_paired(None, true, None).unwrap());
16139        assert!(
16140            resolve_parallel_ep_q8_gu_paired(None, true, Some(ParallelEpQ8Scope::GateUp)).unwrap()
16141        );
16142        assert!(
16143            !resolve_parallel_ep_q8_gu_paired(None, true, Some(ParallelEpQ8Scope::Down)).unwrap()
16144        );
16145        assert!(!resolve_parallel_ep_q8_gu_paired(Some("0"), false, None).unwrap());
16146        assert!(!resolve_parallel_ep_q8_gu_paired(Some("0"), true, None).unwrap());
16147        assert!(resolve_parallel_ep_q8_gu_paired(Some("1"), false, None).is_err());
16148        assert!(
16149            resolve_parallel_ep_q8_gu_paired(Some("1"), true, Some(ParallelEpQ8Scope::Down))
16150                .is_err()
16151        );
16152    }
16153
16154    #[test]
16155    fn w4a16_device_ep_accepts_a_capacity_backed_active_prefix() {
16156        let width = 4096;
16157        assert_eq!(
16158            nvfp4_ep_active_input_values(160 * width, 44, width).unwrap(),
16159            44 * width
16160        );
16161        assert_eq!(
16162            nvfp4_ep_active_input_values(44 * width, 44, width).unwrap(),
16163            44 * width
16164        );
16165        assert!(nvfp4_ep_active_input_values(43 * width, 44, width).is_err());
16166        assert!(
16167            nvfp4_ep_active_input_values(160 * width, NVFP4_EP_DEVICE_BATCH_CAP + 1, width)
16168                .is_err()
16169        );
16170    }
16171
16172    #[test]
16173    fn step_ep_layer_specs_are_literal_and_fail_closed() {
16174        assert!(parse_step_ep_layer_specs(None).unwrap().is_empty());
16175        assert!(parse_step_ep_layer_specs(Some("0")).unwrap().is_empty());
16176        assert_eq!(
16177            parse_step_ep_layer_specs(Some("24@1,2")).unwrap(),
16178            vec![StepEpLayerSpec {
16179                layer: 24,
16180                devices: vec![1, 2],
16181            }]
16182        );
16183        assert_eq!(
16184            parse_step_ep_layer_specs(Some("24-25@1,2;31@0,2")).unwrap(),
16185            vec![
16186                StepEpLayerSpec {
16187                    layer: 24,
16188                    devices: vec![1, 2],
16189                },
16190                StepEpLayerSpec {
16191                    layer: 25,
16192                    devices: vec![1, 2],
16193                },
16194                StepEpLayerSpec {
16195                    layer: 31,
16196                    devices: vec![0, 2],
16197                },
16198            ]
16199        );
16200        assert!(parse_step_ep_layer_specs(Some("24@1")).is_err());
16201        assert!(parse_step_ep_layer_specs(Some("24@1,1")).is_err());
16202        assert!(parse_step_ep_layer_specs(Some("layer@1,2")).is_err());
16203        assert!(parse_step_ep_layer_specs(Some("25-24@1,2")).is_err());
16204        assert!(parse_step_ep_layer_specs(Some("0-128@1,2")).is_err());
16205        assert!(parse_step_ep_layer_specs(Some("24-25@1,2;25@0,2")).is_err());
16206        assert!(parse_step_ep_layer_specs(Some("all@0,1")).is_err());
16207    }
16208
16209    #[test]
16210    fn step_tp_layer_specs_share_the_fail_closed_layer_contract() {
16211        assert!(parse_step_tp_layer_specs(None).unwrap().is_empty());
16212        assert!(parse_step_tp_layer_specs(Some("0")).unwrap().is_empty());
16213        assert_eq!(
16214            parse_step_tp_layer_specs(Some("24-25@1,2")).unwrap(),
16215            vec![
16216                StepTpLayerSpec {
16217                    layer: 24,
16218                    devices: vec![1, 2],
16219                },
16220                StepTpLayerSpec {
16221                    layer: 25,
16222                    devices: vec![1, 2],
16223                },
16224            ]
16225        );
16226        let error = parse_step_tp_layer_specs(Some("24@1")).unwrap_err();
16227        assert!(error.contains("MEMRA_STEP_TP"));
16228        assert!(parse_step_tp_layer_specs(Some("24@1,1")).is_err());
16229        assert!(parse_step_tp_layer_specs(Some("24-25@1,2;25@0,2")).is_err());
16230
16231        let all = parse_step_tp_layer_specs(Some("all@0,1,2,3,4,5,6,7")).unwrap();
16232        assert_eq!(all.len(), STEP37_TRUNK_LAYERS);
16233        assert_eq!(all.first().unwrap().layer, 0);
16234        assert_eq!(all.last().unwrap().layer, STEP37_TRUNK_LAYERS - 1);
16235        let devices = (0..8).collect::<Vec<_>>();
16236        assert!(all.iter().all(|spec| spec.devices == devices));
16237        assert!(parse_step_tp_layer_specs(Some("all@0,1;44@0,1")).is_err());
16238    }
16239}
16240
16241// ===== Whole-token graph builder (increment B) ==================================================
16242//
16243// The decode fns are already sectioned at every e/rank/root seam (the stage flow, sweeps_rank,
16244// finish splits, the dcw arm). `graph_section` is the one annotation those seams call: eager
16245// mode runs the closure verbatim; build mode wraps it in a stream capture on the section's
16246// device and records a child + its dependency edges. A token then assembles as ONE multi-device
16247// parent (children per section per layer), launched once per token — the launch-collapse the
16248// per-layer minis could not reach (routes-mini negative, 2026-08-21).
16249
16250/// One captured section: the child graph plus which parent node it became, and the CUDA
16251/// context it was captured under (exec memset updates need it).
16252struct TokenGraphChild {
16253    #[allow(dead_code)]
16254    // allow: keep-alive: the child graph must outlive the exec instantiated from it
16255    graph: cudarc::driver::CudaGraph,
16256    node: cudarc::driver::sys::CUgraphNode,
16257    ctx: cudarc::driver::sys::CUcontext,
16258}
16259
16260/// Exec-updatable fa geometry discovered in one attention rank child: the three partial-pool
16261/// memsets, the dcw fa kernel, and its combine — everything a bucket change touches. Node
16262/// handles address the parent's CLONED child graphs (the M1-probed update path).
16263struct TokenGraphFaSite {
16264    ctx: cudarc::driver::sys::CUcontext,
16265    memset_o: cudarc::driver::sys::CUgraphNode,
16266    memset_m: [cudarc::driver::sys::CUgraphNode; 2],
16267    fa: cudarc::driver::sys::CUgraphNode,
16268    combine: cudarc::driver::sys::CUgraphNode,
16269    window: usize,
16270    n_head: usize,
16271    n_head_kv: usize,
16272    head_dim: usize,
16273}
16274
16275pub struct TokenGraphBuilder {
16276    parent: cudarc::driver::sys::CUgraph,
16277    children: Vec<TokenGraphChild>,
16278    /// Nodes every NEXT section must depend on (the frontier): one node for serial flow,
16279    /// several while a parallel group is open.
16280    frontier: Vec<cudarc::driver::sys::CUgraphNode>,
16281    /// Detached sections: forked from the frontier at issue time, joined ONLY by the next
16282    /// non-group section (they never gate a parallel group merge — the SH1 shape).
16283    pending_detached: Vec<cudarc::driver::sys::CUgraphNode>,
16284    /// Open parallel group: sections issued under the same group id fork from the SAME
16285    /// predecessor set and merge into the frontier together when the group closes.
16286    group: Option<(
16287        u32,
16288        Vec<cudarc::driver::sys::CUgraphNode>,
16289        Vec<cudarc::driver::sys::CUgraphNode>,
16290    )>,
16291}
16292
16293// SAFETY: single decode thread; graph handles are process handles.
16294unsafe impl Send for TokenGraphBuilder {}
16295
16296impl TokenGraphBuilder {
16297    pub fn new() -> Result<Self, Box<dyn std::error::Error>> {
16298        use cudarc::driver::sys;
16299        let mut parent: sys::CUgraph = std::ptr::null_mut();
16300        let r = unsafe { sys::cuGraphCreate(&mut parent, 0) };
16301        if r != sys::CUresult::CUDA_SUCCESS {
16302            return Err(format!("token graph create: {r:?}").into());
16303        }
16304        Ok(Self {
16305            parent,
16306            children: Vec::new(),
16307            frontier: Vec::new(),
16308            pending_detached: Vec::new(),
16309            group: None,
16310        })
16311    }
16312
16313    fn push_child(
16314        &mut self,
16315        graph: cudarc::driver::CudaGraph,
16316        parallel_group: Option<u32>,
16317        detached: bool,
16318        absorb: bool,
16319        ctx: cudarc::driver::sys::CUcontext,
16320    ) -> Result<(), Box<dyn std::error::Error>> {
16321        use cudarc::driver::sys;
16322        // Resolve the dependency set: serial sections depend on the current frontier; a
16323        // parallel-group section depends on the frontier AS OF the group opening; a
16324        // DETACHED section forks like a group member but joins only the next serial section.
16325        let deps: Vec<sys::CUgraphNode> = match (&mut self.group, parallel_group) {
16326            (Some((open, base, _)), Some(group)) if *open == group => base.clone(),
16327            (state, Some(group)) => {
16328                // opening a new group (closing any previous one first)
16329                if let Some((_, _, members)) = state.take() {
16330                    self.frontier = members;
16331                }
16332                let base = self.frontier.clone();
16333                *state = Some((group, base.clone(), Vec::new()));
16334                base
16335            }
16336            (state, None) if detached => match state.as_ref() {
16337                Some((_, base, _)) => base.clone(),
16338                None => self.frontier.clone(),
16339            },
16340            (state, None) => {
16341                if let Some((_, _, members)) = state.take() {
16342                    self.frontier = members;
16343                }
16344                let mut deps = self.frontier.clone();
16345                if absorb {
16346                    deps.append(&mut self.pending_detached);
16347                }
16348                deps
16349            }
16350        };
16351        let mut node: sys::CUgraphNode = std::ptr::null_mut();
16352        let r = unsafe {
16353            sys::cuGraphAddChildGraphNode(
16354                &mut node,
16355                self.parent,
16356                if deps.is_empty() {
16357                    std::ptr::null()
16358                } else {
16359                    deps.as_ptr()
16360                },
16361                deps.len(),
16362                graph.cu_graph(),
16363            )
16364        };
16365        if r != sys::CUresult::CUDA_SUCCESS {
16366            return Err(format!("token graph child: {r:?}").into());
16367        }
16368        match (&mut self.group, parallel_group, detached) {
16369            (_, None, true) => self.pending_detached.push(node),
16370            (Some((_, _, members)), Some(_), _) => members.push(node),
16371            _ => self.frontier = vec![node],
16372        }
16373        self.children.push(TokenGraphChild { graph, node, ctx });
16374        Ok(())
16375    }
16376
16377    pub fn finish(mut self) -> Result<TokenGraph, Box<dyn std::error::Error>> {
16378        use cudarc::driver::sys;
16379        if let Some((_, _, members)) = self.group.take() {
16380            self.frontier = members;
16381        }
16382        // Discover the fa sites BEFORE instantiate: the parent's cloned child graphs hold
16383        // the node handles the exec update path (M1) addresses.
16384        let mut fa_sites = Vec::new();
16385        for child in &self.children {
16386            if let Some(site) = discover_fa_site(child.node, child.ctx)? {
16387                fa_sites.push(site);
16388            }
16389        }
16390        let mut exec: sys::CUgraphExec = std::ptr::null_mut();
16391        let r = unsafe { sys::cuGraphInstantiateWithFlags(&mut exec, self.parent, 0) };
16392        if r != sys::CUresult::CUDA_SUCCESS {
16393            return Err(format!("token graph instantiate: {r:?}").into());
16394        }
16395        Ok(TokenGraph {
16396            exec,
16397            parent: self.parent,
16398            _children: self.children,
16399            fa_sites,
16400        })
16401    }
16402}
16403
16404/// Walk one child graph; if it carries the attention-section signature (exactly three MEMSET
16405/// nodes chained memset->memset->memset->fa_kernel->combine_kernel), return its update site.
16406fn discover_fa_site(
16407    child_node: cudarc::driver::sys::CUgraphNode,
16408    ctx: cudarc::driver::sys::CUcontext,
16409) -> Result<Option<TokenGraphFaSite>, Box<dyn std::error::Error>> {
16410    use cudarc::driver::sys;
16411    fn cu_try(r: sys::CUresult, what: &str) -> Result<(), Box<dyn std::error::Error>> {
16412        if r == sys::CUresult::CUDA_SUCCESS {
16413            Ok(())
16414        } else {
16415            Err(format!("{what}: {r:?}").into())
16416        }
16417    }
16418    let mut graph: sys::CUgraph = std::ptr::null_mut();
16419    unsafe {
16420        cu_try(
16421            sys::cuGraphChildGraphNodeGetGraph(child_node, &mut graph),
16422            "fa-site child GetGraph",
16423        )?;
16424    }
16425    let mut count: usize = 0;
16426    unsafe {
16427        cu_try(
16428            sys::cuGraphGetNodes(graph, std::ptr::null_mut(), &mut count),
16429            "fa-site GetNodes(count)",
16430        )?;
16431    }
16432    let mut nodes: Vec<sys::CUgraphNode> = vec![std::ptr::null_mut(); count];
16433    unsafe {
16434        cu_try(
16435            sys::cuGraphGetNodes(graph, nodes.as_mut_ptr(), &mut count),
16436            "fa-site GetNodes",
16437        )?;
16438    }
16439    nodes.truncate(count);
16440    let node_type =
16441        |node: sys::CUgraphNode| -> Result<sys::CUgraphNodeType, Box<dyn std::error::Error>> {
16442            let mut ty = sys::CUgraphNodeType::CU_GRAPH_NODE_TYPE_EMPTY;
16443            unsafe {
16444                cu_try(
16445                    sys::cuGraphNodeGetType(node, &mut ty),
16446                    "fa-site NodeGetType",
16447                )?;
16448            }
16449            Ok(ty)
16450        };
16451    let memsets: Vec<sys::CUgraphNode> = {
16452        let mut v = Vec::new();
16453        for &node in &nodes {
16454            if node_type(node)? == sys::CUgraphNodeType::CU_GRAPH_NODE_TYPE_MEMSET {
16455                v.push(node);
16456            }
16457        }
16458        v
16459    };
16460    if memsets.len() != 3 {
16461        return Ok(None);
16462    }
16463    // Single-stream capture makes the chain linear: follow dependent edges from each memset.
16464    let dependents =
16465        |node: sys::CUgraphNode| -> Result<Vec<sys::CUgraphNode>, Box<dyn std::error::Error>> {
16466            let mut n: usize = 0;
16467            unsafe {
16468                cu_try(
16469                    sys::cuGraphNodeGetDependentNodes_v2(
16470                        node,
16471                        std::ptr::null_mut(),
16472                        std::ptr::null_mut(),
16473                        &mut n,
16474                    ),
16475                    "fa-site GetDependentNodes(count)",
16476                )?;
16477            }
16478            let mut v: Vec<sys::CUgraphNode> = vec![std::ptr::null_mut(); n];
16479            unsafe {
16480                cu_try(
16481                    sys::cuGraphNodeGetDependentNodes_v2(
16482                        node,
16483                        v.as_mut_ptr(),
16484                        std::ptr::null_mut(),
16485                        &mut n,
16486                    ),
16487                    "fa-site GetDependentNodes",
16488                )?;
16489            }
16490            v.truncate(n);
16491            Ok(v)
16492        };
16493    // The LAST memset is the one whose direct dependent is a kernel (fa); the other two are
16494    // ordered among themselves but interchangeable for width updates.
16495    let mut fa: Option<sys::CUgraphNode> = None;
16496    let mut last_memset: Option<sys::CUgraphNode> = None;
16497    for &ms in &memsets {
16498        for dep in dependents(ms)? {
16499            if node_type(dep)? == sys::CUgraphNodeType::CU_GRAPH_NODE_TYPE_KERNEL {
16500                fa = Some(dep);
16501                last_memset = Some(ms);
16502            }
16503        }
16504    }
16505    let (Some(fa), Some(_last)) = (fa, last_memset) else {
16506        return Ok(None);
16507    };
16508    let mut combine: Option<sys::CUgraphNode> = None;
16509    for dep in dependents(fa)? {
16510        if node_type(dep)? == sys::CUgraphNodeType::CU_GRAPH_NODE_TYPE_KERNEL {
16511            combine = Some(dep);
16512        }
16513    }
16514    let Some(combine) = combine else {
16515        return Ok(None);
16516    };
16517    // Read the fa launch geometry from its baked args (arg order pinned by fa_decode_dcw):
16518    // 6=hd 7=nh 8=nhkv 11=win 13=nsp 14=ski.
16519    let mut params: sys::CUDA_KERNEL_NODE_PARAMS = unsafe { std::mem::zeroed() };
16520    unsafe {
16521        cu_try(
16522            sys::cuGraphKernelNodeGetParams_v2(fa, &mut params),
16523            "fa-site KernelNodeGetParams",
16524        )?;
16525    }
16526    let arg_i32 =
16527        |slot: usize| -> i32 { unsafe { *(*params.kernelParams.add(slot) as *const i32) } };
16528    let (hd, nh, nhkv, win) = (arg_i32(6), arg_i32(7), arg_i32(8), arg_i32(11));
16529    // Identify the o-partial memset (hd x wider than the m/l pair).
16530    let width_of = |node: sys::CUgraphNode| -> Result<usize, Box<dyn std::error::Error>> {
16531        let mut mp: sys::CUDA_MEMSET_NODE_PARAMS = unsafe { std::mem::zeroed() };
16532        unsafe {
16533            cu_try(
16534                sys::cuGraphMemsetNodeGetParams(node, &mut mp),
16535                "fa-site MemsetNodeGetParams",
16536            )?;
16537        }
16538        Ok(mp.width)
16539    };
16540    let mut widest = memsets[0];
16541    for &ms in &memsets[1..] {
16542        if width_of(ms)? > width_of(widest)? {
16543            widest = ms;
16544        }
16545    }
16546    let memset_m: Vec<sys::CUgraphNode> =
16547        memsets.iter().copied().filter(|&m| m != widest).collect();
16548    Ok(Some(TokenGraphFaSite {
16549        ctx,
16550        memset_o: widest,
16551        memset_m: [memset_m[0], memset_m[1]],
16552        fa,
16553        combine,
16554        window: win as usize,
16555        n_head: nh as usize,
16556        n_head_kv: nhkv as usize,
16557        head_dim: hd as usize,
16558    }))
16559}
16560
16561pub struct TokenGraph {
16562    exec: cudarc::driver::sys::CUgraphExec,
16563    parent: cudarc::driver::sys::CUgraph,
16564    _children: Vec<TokenGraphChild>,
16565    fa_sites: Vec<TokenGraphFaSite>,
16566}
16567
16568unsafe impl Send for TokenGraph {}
16569
16570impl TokenGraph {
16571    /// Retarget every fa site to a new bucket via exec param updates (M1 path) — replaces the
16572    /// per-bucket whole-graph rebuild (~55ms) with ~450 node updates (~1ms). Per site the
16573    /// bucket caps at the layer window; nsp/ski/gridDimY and the partial-pool memset widths
16574    /// move together so the exec always matches what a fresh build at `bucket` would bake.
16575    pub fn retarget_bucket(&mut self, bucket: usize) -> Result<(), Box<dyn std::error::Error>> {
16576        use cudarc::driver::sys;
16577        fn cu_try(r: sys::CUresult, what: &str) -> Result<(), Box<dyn std::error::Error>> {
16578            if r == sys::CUresult::CUDA_SUCCESS {
16579                Ok(())
16580            } else {
16581                Err(format!("{what}: {r:?}").into())
16582            }
16583        }
16584        for site in &self.fa_sites {
16585            let layer_bucket = if site.window > 0 {
16586                bucket.min(site.window)
16587            } else {
16588                bucket
16589            };
16590            let sp = crate::fa_split_keys(layer_bucket, site.n_head_kv);
16591            let nsp = layer_bucket.div_ceil(sp).max(1);
16592            // fa kernel: nsp (slot 13), ski (slot 14), gridDimY = nsp.
16593            let mut params: sys::CUDA_KERNEL_NODE_PARAMS = unsafe { std::mem::zeroed() };
16594            unsafe {
16595                cu_try(
16596                    sys::cuGraphKernelNodeGetParams_v2(site.fa, &mut params),
16597                    "retarget fa GetParams",
16598                )?;
16599                *(*params.kernelParams.add(13) as *mut i32) = nsp as i32;
16600                *(*params.kernelParams.add(14) as *mut i32) = sp as i32;
16601                params.gridDimY = nsp as u32;
16602                cu_try(
16603                    sys::cuGraphExecKernelNodeSetParams_v2(self.exec, site.fa, &params),
16604                    "retarget fa SetParams",
16605                )?;
16606            }
16607            // combine: nsp (slot 6).
16608            let mut cparams: sys::CUDA_KERNEL_NODE_PARAMS = unsafe { std::mem::zeroed() };
16609            unsafe {
16610                cu_try(
16611                    sys::cuGraphKernelNodeGetParams_v2(site.combine, &mut cparams),
16612                    "retarget combine GetParams",
16613                )?;
16614                *(*cparams.kernelParams.add(6) as *mut i32) = nsp as i32;
16615                cu_try(
16616                    sys::cuGraphExecKernelNodeSetParams_v2(self.exec, site.combine, &cparams),
16617                    "retarget combine SetParams",
16618                )?;
16619            }
16620            // partial-pool memsets: o = nh*nsp*hd elements, m/l = nh*nsp.
16621            let set_width =
16622                |node: sys::CUgraphNode, width: usize| -> Result<(), Box<dyn std::error::Error>> {
16623                    let mut mp: sys::CUDA_MEMSET_NODE_PARAMS = unsafe { std::mem::zeroed() };
16624                    unsafe {
16625                        cu_try(
16626                            sys::cuGraphMemsetNodeGetParams(node, &mut mp),
16627                            "retarget memset GetParams",
16628                        )?;
16629                    }
16630                    mp.width = width;
16631                    unsafe {
16632                        cu_try(
16633                            sys::cuGraphExecMemsetNodeSetParams(self.exec, node, &mp, site.ctx),
16634                            "retarget memset SetParams",
16635                        )?;
16636                    }
16637                    Ok(())
16638                };
16639            set_width(site.memset_o, site.n_head * nsp * site.head_dim)?;
16640            set_width(site.memset_m[0], site.n_head * nsp)?;
16641            set_width(site.memset_m[1], site.n_head * nsp)?;
16642        }
16643        Ok(())
16644    }
16645
16646    pub fn launch(&self, e: &Engine) -> Result<(), Box<dyn std::error::Error>> {
16647        use cudarc::driver::sys;
16648        let _main = e.gpu.enter_main()?;
16649        let r = unsafe { sys::cuGraphLaunch(self.exec, e.stream().cu_stream() as sys::CUstream) };
16650        if r != sys::CUresult::CUDA_SUCCESS {
16651            return Err(format!("token graph launch: {r:?}").into());
16652        }
16653        Ok(())
16654    }
16655}
16656
16657impl Drop for TokenGraph {
16658    fn drop(&mut self) {
16659        unsafe {
16660            let _ = cudarc::driver::sys::cuGraphExecDestroy(self.exec);
16661            let _ = cudarc::driver::sys::cuGraphDestroy(self.parent);
16662        }
16663    }
16664}
16665
16666std::thread_local! {
16667    static TOKEN_GRAPH_BUILDER: std::cell::RefCell<Option<TokenGraphBuilder>> =
16668        const { std::cell::RefCell::new(None) };
16669}
16670
16671/// Arm the thread-local builder (build mode) — the next `graph_section` calls capture.
16672pub fn token_graph_build_begin() -> Result<(), Box<dyn std::error::Error>> {
16673    let builder = TokenGraphBuilder::new()?;
16674    TOKEN_GRAPH_BUILDER.with(|cell| *cell.borrow_mut() = Some(builder));
16675    Ok(())
16676}
16677
16678/// Take the finished parent (ends build mode).
16679pub fn token_graph_build_finish() -> Result<TokenGraph, Box<dyn std::error::Error>> {
16680    let builder = TOKEN_GRAPH_BUILDER
16681        .with(|cell| cell.borrow_mut().take())
16682        .ok_or("token graph build was not begun")?;
16683    builder.finish()
16684}
16685
16686/// True while the thread-local builder is armed.
16687pub fn token_graph_building() -> bool {
16688    TOKEN_GRAPH_BUILDER.with(|cell| cell.borrow().is_some())
16689}
16690
16691/// The section annotation: eager mode runs the closure verbatim; build mode wraps it in a
16692/// stream capture on `engine`'s stream and records the child. Sections sharing a
16693/// `parallel_group` id fork from the same predecessor set and merge together. The closure
16694/// must be capture-safe (raw copies at cross-context seams, no host syncs, no events).
16695pub fn graph_section<F>(
16696    engine: &Engine,
16697    parallel_group: Option<u32>,
16698    f: F,
16699) -> Result<(), Box<dyn std::error::Error>>
16700where
16701    F: FnMut() -> Result<(), Box<dyn std::error::Error>>,
16702{
16703    graph_section_opts(engine, parallel_group, false, false, f)
16704}
16705
16706/// Serial section that ALSO joins every pending detached section (the SH1 consumer shape).
16707pub fn graph_section_absorbing<F>(engine: &Engine, f: F) -> Result<(), Box<dyn std::error::Error>>
16708where
16709    F: FnMut() -> Result<(), Box<dyn std::error::Error>>,
16710{
16711    graph_section_opts(engine, None, false, true, f)
16712}
16713
16714/// `graph_section` with the DETACHED shape: forks from the current frontier (or the open
16715/// group base) and is joined only by the next serial section — never gates a group merge.
16716pub fn graph_section_detached<F>(engine: &Engine, f: F) -> Result<(), Box<dyn std::error::Error>>
16717where
16718    F: FnMut() -> Result<(), Box<dyn std::error::Error>>,
16719{
16720    graph_section_opts(engine, None, true, false, f)
16721}
16722
16723pub fn graph_section_opts<F>(
16724    engine: &Engine,
16725    parallel_group: Option<u32>,
16726    detached: bool,
16727    absorb: bool,
16728    f: F,
16729) -> Result<(), Box<dyn std::error::Error>>
16730where
16731    F: FnMut() -> Result<(), Box<dyn std::error::Error>>,
16732{
16733    let building = token_graph_building();
16734    if !building {
16735        let mut f = f;
16736        return f();
16737    }
16738    let (child, ctx) = {
16739        let _main = engine.gpu.enter_main()?;
16740        let mut ctx: cudarc::driver::sys::CUcontext = std::ptr::null_mut();
16741        let r = unsafe { cudarc::driver::sys::cuCtxGetCurrent(&mut ctx) };
16742        if r != cudarc::driver::sys::CUresult::CUDA_SUCCESS {
16743            return Err(format!("graph section ctx query: {r:?}").into());
16744        }
16745        let mut f = f;
16746        // NO WARMUP RUNS: section bodies carry device side effects (dcw appends, counter
16747        // incs) that a warmup would really execute — the len_d-drift crash of 2026-08-21.
16748        let (child, _retained) = engine.capture_graph_retained_nowarm(|_| f())?;
16749        (child, ctx)
16750    };
16751    TOKEN_GRAPH_BUILDER.with(|cell| {
16752        cell.borrow_mut()
16753            .as_mut()
16754            .expect("builder checked above")
16755            .push_child(child, parallel_group, detached, absorb, ctx)
16756    })
16757}