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_SPEC_FA2=1 (the DSpark verify lesson): the verify walk defers each column's
189/// ATTENTION CORE — the dcw arm appends the column's K/V and stashes its post-rope q and
190/// gate rows, then ONE fa_decode_vec_q_v3_dcw_rows per rank attends every stashed row
191/// (each row runs its own t=1 dcw program, bit-identical per row), the per-row combine
192/// writes the gated rows, and the o_proj join runs on the TCOL slabs.
193/// ROW-TABLE RESTAGE (`MEMRA_ROWS_TAB_RESTAGE`, DEFAULT ON since this lane).
194///
195/// ON: `decode_v2_rope_fa_rows` builds the 6-word-per-row pointer table from the caller's
196/// freshly-read live cache pointers and stages it into a persistent per-rank slab before
197/// every launch. OFF (`=0`): the retired process-lifetime `rows_tabs` memo, keyed by a hash
198/// of (k pointer, base pointer, layer, t) that could not see the V or LEN pointers the
199/// entry also carried, and that nothing invalidated when a session's KV cache was dropped.
200///
201/// Default ON because the OFF arm is a proven use-after-free, not a slower correct path:
202/// on step37-flash with MEMRA_FUSE_ROPE_APPEND=1 it made speculative decoding unservable
203/// (whole non-finite verify rows, then CUDA_ERROR_ILLEGAL_ADDRESS). ON is value-neutral on
204/// every fresh lookup by construction: identical bytes reach the same kernels. Rollback
205/// seam: `MEMRA_ROWS_TAB_RESTAGE=0`.
206/// The 6-word-per-row launch table `{k, v, len, base, ctr, back}` the fused rope/append/fa
207/// kernels dereference. Pure so it can be tested: the words come from the caller's live
208/// per-row `[k, v, len, base]` pointers, `ctr` is this rank's counter slab (one shared cell
209/// for same-session rows, one cell per row otherwise) and `back` is the same-session causal
210/// step-back `t-1-r` (0 across sessions, where each row owns its own len).
211pub(crate) fn rows_tab_host(
212    parts_rank: &[[u64; 4]],
213    ctr_base: u64,
214    same_session: bool,
215    t: usize,
216) -> Vec<u64> {
217    let mut host = Vec::with_capacity(t * 6);
218    for (r, parts) in parts_rank.iter().enumerate().take(t) {
219        host.extend_from_slice(&[
220            parts[0],
221            parts[1],
222            parts[2],
223            parts[3],
224            if same_session {
225                ctr_base
226            } else {
227                ctr_base + (r as u64) * 4
228            },
229            if same_session {
230                (t - 1 - r) as u64
231            } else {
232                0u64
233            },
234        ]);
235    }
236    host
237}
238
239/// The RETIRED memo key, kept ONLY so a test can assert what it cannot see. Both historical
240/// call sites hashed a SUBSET of the pointers the table carries; this reproduces the verify
241/// site's formula verbatim.
242#[cfg(test)]
243pub(crate) fn retired_rows_tab_key(kp: u64, bp: u64, il: usize, t: usize) -> u64 {
244    kp.rotate_left(17)
245        .wrapping_add(bp)
246        .wrapping_add((il as u64) << 32)
247        .wrapping_add(t as u64)
248        .wrapping_add(1 << 63)
249}
250
251pub(crate) fn rows_tab_restage_on() -> bool {
252    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
253    *ON.get_or_init(|| std::env::var("MEMRA_ROWS_TAB_RESTAGE").as_deref() != Ok("0"))
254}
255
256/// STALE-HIT RECEIPT (`MEMRA_ROWS_TAB_STALE_SCAN`, DEFAULT OFF, diagnostic only).
257///
258/// Keeps a HOST shadow of the last table staged under each retired memo key and prints one
259/// line whenever the key repeats with different contents, naming the words that moved. It
260/// costs a host hash lookup and a small clone per rank per layer per verify round, so it is
261/// off in serving. `[rows-tab] engaged=` on the counter proves the path executes at all,
262/// which is what separates "the memo was innocent" from "the memo never ran".
263/// Rollback seam: unset it (or `=0`).
264pub(crate) fn rows_tab_stale_scan() -> bool {
265    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
266    *ON.get_or_init(|| std::env::var("MEMRA_ROWS_TAB_STALE_SCAN").as_deref() == Ok("1"))
267}
268
269pub(crate) static ROWS_TAB_ENGAGED: std::sync::atomic::AtomicU64 =
270    std::sync::atomic::AtomicU64::new(0);
271pub(crate) static ROWS_TAB_STALE: std::sync::atomic::AtomicU64 =
272    std::sync::atomic::AtomicU64::new(0);
273
274pub(crate) fn spec_fa2_on() -> bool {
275    static ENV: std::sync::OnceLock<Option<bool>> = std::sync::OnceLock::new();
276    crate::step37_door(&ENV, "MEMRA_SPEC_FA2")
277}
278thread_local! {
279    /// The verify driver arms the column before each per-column attention call; the dcw
280    /// arm takes it (once) and stashes q/gate instead of running fa+finish.
281    static SPEC_FA2_DEFER: std::cell::Cell<Option<usize>> = const { std::cell::Cell::new(None) };
282    static SPEC_FA2_STASHED: std::cell::Cell<bool> = const { std::cell::Cell::new(false) };
283}
284pub(crate) fn set_spec_fa2_defer(c: Option<usize>) {
285    SPEC_FA2_DEFER.with(|x| x.set(c));
286}
287pub(crate) fn take_spec_fa2_defer() -> Option<usize> {
288    SPEC_FA2_DEFER.with(|x| x.take())
289}
290pub(crate) fn set_spec_fa2_stashed() {
291    SPEC_FA2_STASHED.with(|x| x.set(true));
292}
293pub(crate) fn take_spec_fa2_stashed() -> bool {
294    SPEC_FA2_STASHED.with(|x| x.replace(false))
295}
296
297pub(crate) fn sel_mirror_on() -> bool {
298    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
299    *ON.get_or_init(|| std::env::var("MEMRA_SEL_MIRROR").as_deref() == Ok("1"))
300}
301
302pub(crate) fn oproj_direct_on() -> bool {
303    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
304    *ON.get_or_init(|| std::env::var("MEMRA_OPROJ_DIRECT").as_deref() == Ok("1"))
305}
306
307// ─── Slot-major NVFP4 expert-bank programs: THREE independent doors ───────────────────────────
308//
309// These restore, under separate flags, the three programs that the 2026-08-29 removal
310// (`fd0a175ab`) deleted behind ONE env var (`MEMRA_NVFP4_BANK_V2`). That coupling is why the
311// incident's bisect could not name a mechanism: toggling one var moved the bank layout, the
312// gate+up fusion (which auto-armed on the same predicate with no door of its own) and the fused
313// down+combine (which hard-refused without the layout) all at once, so the priced -21.5% wall /
314// -23.7% decode (research/perf-chain-20260831 cell 1) was an unattributable bundle.
315//
316// The corruption they were removed for was NOT any of them: it was a defaulted `in_f = 0`
317// argument at two `kq_fetch` call sites in the PREFILL grouped-GEMM tail
318// (research/step37-bankv3-20260901/DIAGNOSIS.md), fixed compiler-enforced at `1b18a61e8` and
319// gated device-side by the `nvfp4-bank-oracle` bin. Each door below is strict `0`/`1` and
320// admitted separately so its contribution is a number; BANK_SM and SEL_DOWN8 default ON since
321// 2026-09-01 (one coupled decision, PR #76 battery), SEL_GU and the sub-doors default OFF.
322//
323// LAYOUT IS A PROPERTY OF THE BANK. `bank_slot_major_on()` is read ONCE, at bank BUILD, and
324// recorded on the resident bank (`ResidentNvfp4{Column,Row}BankRank::slot_major`). Every reader
325// branches on that stored field, never on the env door. The removed implementation read
326// `nvfp4_bank_v2_on()` at each reader site instead, which is the same class of hole as the
327// defaulted `in_f`: a piece of layout geometry that a caller can fail to supply or can supply
328// inconsistently with the bytes actually resident.
329
330/// Read a DEFAULT-ON door strictly, and report the SOURCE of the answer rather than only the
331/// answer. `0` disables (the rollback seam), `1` re-states the default, unset takes the default.
332///
333/// Two properties this buys, both learned the hard way in this lane's own archaeology:
334///
335/// * **A typo cannot silently disarm a rollback seam.** The default-OFF doors here parse as
336///   `== Ok("1")`, which is safe when the default is OFF (a typo reads as the default) and
337///   DANGEROUS when the default is ON: `MEMRA_NVFP4_BANK_SM=false` under a `!= Ok("0")` rule
338///   would keep the program armed while the operator believed it was rolled back. So an
339///   unrecognized value is reported as such and the default is kept, loudly.
340/// * **The engagement receipt can name the source.** `default-on` and `MEMRA_..=1` are
341///   different facts about the same boot: one says the flip is doing the work, the other says
342///   a recipe is. A pricing or post-deploy receipt that cannot tell them apart cannot prove a
343///   DEFAULT was measured (TRAP:corrupt-arm-inflates-its-own-perf-price's sibling: an arm that
344///   cannot name what armed it is not an arm).
345fn door_default_on(name: &'static str) -> (bool, &'static str) {
346    let raw = std::env::var(name).ok();
347    door_default_on_value(name, raw.as_deref())
348}
349
350/// The parse, separated from the environment so it can be TESTED. `std::env` is process-global
351/// state and these doors are `OnceLock`-cached, so an env-var test would be both racy under
352/// `cargo test`'s thread pool and unrepeatable within one process — i.e. exactly the kind of
353/// gate that passes because it never really ran.
354fn door_default_on_value(name: &str, value: Option<&str>) -> (bool, &'static str) {
355    match value {
356        Some("0") => (false, "env=0 (rollback seam)"),
357        Some("1") => (true, "env=1"),
358        None => (true, "default-on"),
359        Some(_) => {
360            eprintln!(
361                "[nvfp4-door] WARN {name} has an unrecognized value; only `0` and `1` are \
362                 accepted and the DEFAULT-ON answer is kept. To roll back, set {name}=0."
363            );
364            (true, "default-on (unrecognized value ignored)")
365        }
366    }
367}
368
369/// MEMRA_NVFP4_BANK_SM (PROGRAM 1, **default ON since 2026-09-01**): build the step TP
370/// contiguous NVFP4 expert banks (gate/up/down) in the SLOT-MAJOR row layout — slot g's 16 qs
371/// bytes contiguous at `g*16` (one coalesced 512B warp wave) and the two UE4M3 scale bytes at
372/// `nslots*16 + g*2` — and dispatch the `_sel_v2` decode readers over them. Pure byte
373/// permutation, so BIT-IDENTICAL per row; the claim is gated by `nvfp4-bank-oracle`
374/// (device-side, prefill GEMM included) and by end-to-end greedy byte identity, never by a
375/// comment.
376///
377/// **WHY A BIT-IDENTICAL, MEASURABLY-FREE PROGRAM DEFAULTS ON.** On its own this layout earns
378/// nothing: x5 interleaved, 105.35 vs 106.78 decode tok/s, per-boot range `[104.66, 107.95]`
379/// overlapping the OFF arm's `[105.11, 107.09]`. It defaults ON for exactly one reason —
380/// `MEMRA_NVFP4_SEL_DOWN8` (PROGRAM 3), the one program that DOES separate (+5.48% decode), is
381/// gated at its call site on `shard.slot_major`, so with this door off PROGRAM 3's default-ON
382/// is a SILENT NO-OP: `down8=false door=true`, no refusal, no warning, and the win simply does
383/// not happen. The deployable unit is the two together, which makes this one coupled default
384/// decision and not two independent ones. Receipts:
385/// `research/step37-bankv3-20260901/RESULTS.md` (the down8 default-ON qualification battery).
386///
387/// ROLLBACK SEAM: `MEMRA_NVFP4_BANK_SM=0`, which also disarms PROGRAM 3 by construction.
388pub(crate) fn bank_slot_major_on() -> bool {
389    bank_slot_major_source().0
390}
391
392/// `bank_slot_major_on()` plus the SOURCE of the answer, for the engagement receipt.
393pub(crate) fn bank_slot_major_source() -> (bool, &'static str) {
394    static ON: std::sync::OnceLock<(bool, &'static str)> = std::sync::OnceLock::new();
395    *ON.get_or_init(|| door_default_on("MEMRA_NVFP4_BANK_SM"))
396}
397
398/// MEMRA_NVFP4_SEL_DOWN8 (PROGRAM 3, default ON since 2026-09-01; `=0` is the rollback seam): fuse the routed DOWN sweep with the
399/// route-weight combine into one launch (`qmatvec_nvfp4_dp4a_sel_v2_down8`, the q8 `down8 w8`
400/// occupancy arm ported to the NVFP4 banks) — one warp per routed slot instead of one warp per
401/// (row, slot), and the `n_sel x out_f` partial-buffer round trip disappears. Bit-identical
402/// (same dot program, same reduce tree, same slot-ordered combine chain). Also subordinate to
403/// PROGRAM 1: the caller arms it only when the down shard reports `slot_major`, and only on the
404/// device-routed arm at `nsb <= 32` (the fit-block class the reduce identity is argued at).
405/// Rides LAST per the lane mandate: it is priced only on green gates for the layers beneath it.
406///
407/// **DEFAULT ON since 2026-09-01**, and it is the reason PROGRAM 1 defaults ON too. This is the
408/// only one of the three restored programs that separates from noise: +5.48% decode / +5.09%
409/// wall, x5 interleaved vendor-default sampled, per-boot range `[112.59, 114.82]` with NO
410/// overlap against either the OFF arm or the arm directly beneath it, re-qualified at deploy
411/// grade in `research/step37-bankv3-20260901/RESULTS.md`.
412///
413/// ELIGIBILITY IS NARROWER THAN THE DEFAULT, and the engagement receipt below prints every
414/// condition: the arm needs `device_routed`, `shard.slot_major` (i.e. PROGRAM 1) and
415/// `nsb <= 32`. On any other geometry or route the default is INERT, which is correct-by-
416/// refusal and NOT a regression — but it does mean "default ON" and "engaged" are two facts,
417/// and only the `[nvfp4-sweep]` line settles the second.
418///
419/// ROLLBACK SEAM: `MEMRA_NVFP4_SEL_DOWN8=0` (or `MEMRA_NVFP4_BANK_SM=0`, which disarms it by
420/// construction).
421pub(crate) fn sel_down8_on() -> bool {
422    sel_down8_source().0
423}
424
425/// `sel_down8_on()` plus the SOURCE of the answer, for the engagement receipt.
426pub(crate) fn sel_down8_source() -> (bool, &'static str) {
427    static ON: std::sync::OnceLock<(bool, &'static str)> = std::sync::OnceLock::new();
428    *ON.get_or_init(|| door_default_on("MEMRA_NVFP4_SEL_DOWN8"))
429}
430
431pub(crate) fn raw_copy_bytes(
432    dst: u64,
433    src: u64,
434    bytes: usize,
435    engine: &Engine,
436) -> Result<(), Box<dyn std::error::Error>> {
437    use cudarc::driver::sys;
438    let r = unsafe {
439        sys::cuMemcpyAsync(
440            dst as sys::CUdeviceptr,
441            src as sys::CUdeviceptr,
442            bytes,
443            engine.stream().cu_stream() as sys::CUstream,
444        )
445    };
446    if r == sys::CUresult::CUDA_SUCCESS {
447        Ok(())
448    } else {
449        // MEMRA_RAW_COPY_TRACE=1: a raw D2D failure carries no call site by itself, and
450        // every slab-width bug in the t-row family surfaces here. Operands + backtrace.
451        if std::env::var("MEMRA_RAW_COPY_TRACE").as_deref() == Ok("1") {
452            eprintln!(
453                "[raw-copy-fail] dst={dst:#x} src={src:#x} bytes={bytes} {r:?}\n{}",
454                std::backtrace::Backtrace::force_capture()
455            );
456        }
457        Err(format!("raw_copy_bytes: {r:?} bytes={bytes} dst={dst:#x} src={src:#x}").into())
458    }
459}
460
461pub fn step_expert_activation_host(gate: f32, up: f32, limit: Option<f32>) -> f32 {
462    let silu = gate / (1.0 + (-gate).exp());
463    match limit {
464        Some(limit) => silu.min(limit) * up.clamp(-limit, limit),
465        None => silu * up,
466    }
467}
468
469#[derive(Debug, Clone, PartialEq, Eq)]
470struct ExpertOwnerRoutes {
471    rank: usize,
472    selected: Vec<usize>,
473    token_rows: Vec<usize>,
474    global_pairs: Vec<usize>,
475}
476
477#[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
478fn partition_expert_owner_routes(
479    expert_count: usize,
480    ranks: usize,
481    tokens: usize,
482    experts_per_token: usize,
483    selected: &[usize],
484) -> Result<Vec<ExpertOwnerRoutes>, String> {
485    if expert_count == 0
486        || ranks == 0
487        || tokens == 0
488        || experts_per_token == 0
489        || expert_count % ranks != 0
490    {
491        return Err(format!(
492            "invalid expert-owner route geometry experts={expert_count} ranks={ranks} \
493             tokens={tokens} experts_per_token={experts_per_token}"
494        ));
495    }
496    let pairs = tokens
497        .checked_mul(experts_per_token)
498        .ok_or("expert-owner route count overflow")?;
499    if selected.len() != pairs {
500        return Err(format!(
501            "expert-owner routes {} != {tokens}x{experts_per_token} ({pairs})",
502            selected.len()
503        ));
504    }
505    let per_rank = expert_count / ranks;
506    let mut owners = (0..ranks)
507        .map(|rank| ExpertOwnerRoutes {
508            rank,
509            selected: Vec::new(),
510            token_rows: Vec::new(),
511            global_pairs: Vec::new(),
512        })
513        .collect::<Vec<_>>();
514    for (pair, &expert) in selected.iter().enumerate() {
515        if expert >= expert_count {
516            return Err(format!(
517                "expert-owner route {pair} selects expert {expert} outside 0..{expert_count}"
518            ));
519        }
520        let rank = expert / per_rank;
521        owners[rank].selected.push(expert - rank * per_rank);
522        owners[rank].token_rows.push(pair / experts_per_token);
523        owners[rank].global_pairs.push(pair);
524    }
525    Ok(owners)
526}
527
528fn validate_step_grouped_owner_routes(
529    expert_count: usize,
530    tokens: usize,
531    selected: &[usize],
532) -> Result<usize, String> {
533    if expert_count != STEP_GROUPED_FP8_EXPERTS || tokens == 0 {
534        return Err(format!(
535            "official Step owner-grouped FP8 requires {} experts and nonzero tokens, got \
536             experts={expert_count} tokens={tokens}",
537            STEP_GROUPED_FP8_EXPERTS
538        ));
539    }
540    let pairs = tokens
541        .checked_mul(STEP_GROUPED_FP8_TOP_K)
542        .ok_or("official Step owner-grouped FP8 route count overflow")?;
543    if selected.len() != pairs {
544        return Err(format!(
545            "official Step owner-grouped FP8 routes {} != {tokens}x{} ({pairs})",
546            selected.len(),
547            STEP_GROUPED_FP8_TOP_K,
548        ));
549    }
550    for (token, routes) in selected.chunks_exact(STEP_GROUPED_FP8_TOP_K).enumerate() {
551        let mut unique = routes.to_vec();
552        unique.sort_unstable();
553        unique.dedup();
554        if unique.len() != STEP_GROUPED_FP8_TOP_K {
555            return Err(format!(
556                "official Step owner-grouped FP8 token {token} routes are not top-8 unique: \
557                 {routes:?}"
558            ));
559        }
560    }
561    Ok(pairs)
562}
563
564#[derive(Debug, Clone, Copy, PartialEq, Eq)]
565struct WeightedRouteCombineShape {
566    pairs: usize,
567    max_pairs: usize,
568}
569
570fn validate_weighted_route_combine(
571    width: usize,
572    experts_per_token: usize,
573    max_tokens: usize,
574    tokens: usize,
575    owner_global_pairs: &[&[usize]],
576    route_weights: &[f32],
577) -> Result<WeightedRouteCombineShape, String> {
578    if width == 0
579        || experts_per_token == 0
580        || max_tokens == 0
581        || tokens == 0
582        || tokens > max_tokens
583        || width > i32::MAX as usize
584        || experts_per_token > i32::MAX as usize
585        || tokens > i32::MAX as usize
586    {
587        return Err(format!(
588            "invalid weighted route combine geometry width={width} experts_per_token=\
589             {experts_per_token} tokens={tokens}/{max_tokens}"
590        ));
591    }
592    let pairs = tokens
593        .checked_mul(experts_per_token)
594        .ok_or("weighted route combine pair count overflow")?;
595    let max_pairs = max_tokens
596        .checked_mul(experts_per_token)
597        .ok_or("weighted route combine capacity overflow")?;
598    if route_weights.len() != pairs || !route_weights.iter().all(|weight| weight.is_finite()) {
599        return Err(format!(
600            "weighted route combine weights {} != pairs {pairs} or contain a non-finite value",
601            route_weights.len()
602        ));
603    }
604    let mut seen = vec![false; pairs];
605    let mut observed = 0usize;
606    for pairs_for_owner in owner_global_pairs {
607        observed = observed
608            .checked_add(pairs_for_owner.len())
609            .ok_or("weighted route combine observed pair count overflow")?;
610        for &pair in *pairs_for_owner {
611            if pair >= pairs || std::mem::replace(&mut seen[pair], true) {
612                return Err(format!(
613                    "weighted route combine pair {pair} is outside 0..{pairs} or duplicated"
614                ));
615            }
616        }
617    }
618    if observed != pairs || seen.iter().any(|present| !present) {
619        return Err(format!(
620            "weighted route combine owner schedules cover {observed} of {pairs} canonical pairs"
621        ));
622    }
623    Ok(WeightedRouteCombineShape { pairs, max_pairs })
624}
625
626fn cache_rank_rows(
627    rows: &[u8],
628    tokens: usize,
629    local_token_bytes: usize,
630    ranks: usize,
631    rank: usize,
632) -> Result<Vec<u8>, String> {
633    if ranks == 0 || rank >= ranks {
634        return Err(format!(
635            "TP cache rank {rank} is outside a {ranks}-rank layout"
636        ));
637    }
638    let global_token_bytes = local_token_bytes
639        .checked_mul(ranks)
640        .ok_or("TP cache global token-byte overflow")?;
641    let expected = tokens
642        .checked_mul(global_token_bytes)
643        .ok_or("TP cache row-byte overflow")?;
644    if rows.len() != expected {
645        return Err(format!(
646            "TP cache rows contain {} bytes, expected {tokens}x{global_token_bytes}={expected}",
647            rows.len()
648        ));
649    }
650    let mut shard = Vec::with_capacity(tokens * local_token_bytes);
651    for token in 0..tokens {
652        let start = token * global_token_bytes + rank * local_token_bytes;
653        shard.extend_from_slice(&rows[start..start + local_token_bytes]);
654    }
655    Ok(shard)
656}
657
658fn parse_step_tp_native_p2p(value: Option<&str>) -> Result<bool, String> {
659    match value {
660        None | Some("") | Some("0") => Ok(false),
661        Some("1") => Ok(true),
662        Some(value) => Err(format!(
663            "MEMRA_STEP_TP_NATIVE_P2P={value:?} is invalid; expected 0 or 1"
664        )),
665    }
666}
667
668pub fn step_tp_native_p2p_enabled() -> Result<bool, String> {
669    parse_step_tp_native_p2p(std::env::var("MEMRA_STEP_TP_NATIVE_P2P").ok().as_deref())
670}
671
672fn parse_step_tp_bulk_p2p(value: Option<&str>) -> Result<bool, String> {
673    match value {
674        None | Some("") | Some("0") => Ok(false),
675        Some("1") => Ok(true),
676        Some(value) => Err(format!(
677            "MEMRA_STEP_TP_BULK_P2P={value:?} is invalid; expected 0 or 1"
678        )),
679    }
680}
681
682pub fn step_tp_bulk_p2p_enabled() -> Result<bool, String> {
683    parse_step_tp_bulk_p2p(std::env::var("MEMRA_STEP_TP_BULK_P2P").ok().as_deref())
684}
685
686fn parse_step_ep_device_arithmetic(value: Option<&str>) -> Result<bool, String> {
687    match value {
688        None | Some("") | Some("0") => Ok(false),
689        Some("1") => Ok(true),
690        Some(value) => Err(format!(
691            "MEMRA_STEP_EP_DEVICE_ARITHMETIC={value:?} is invalid; expected 0 or 1"
692        )),
693    }
694}
695
696fn parse_step_nvfp4_dev_routes(value: Option<&str>) -> Result<bool, String> {
697    match value {
698        None | Some("") | Some("0") => Ok(false),
699        Some("1") => Ok(true),
700        Some(value) => Err(format!(
701            "MEMRA_STEP_NVFP4_DEV_ROUTES={value:?} is invalid; expected 0 or 1"
702        )),
703    }
704}
705
706/// Opt-in door for the device-resident NVFP4 TP routed-expert decode program. Default OFF; the
707/// host-canonical program remains the oracle until the device path carries its own gates.
708pub fn step_nvfp4_dev_routes_enabled() -> Result<bool, String> {
709    parse_step_nvfp4_dev_routes(std::env::var("MEMRA_STEP_NVFP4_DEV_ROUTES").ok().as_deref())
710}
711
712pub fn step_ep_device_arithmetic_enabled() -> Result<bool, String> {
713    parse_step_ep_device_arithmetic(
714        std::env::var("MEMRA_STEP_EP_DEVICE_ARITHMETIC")
715            .ok()
716            .as_deref(),
717    )
718}
719
720fn parse_step_tp_f32_mirror(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_TP_F32_MIRROR={value:?} is invalid; expected 0 or 1"
726        )),
727    }
728}
729
730pub fn step_tp_f32_mirror_enabled() -> Result<bool, String> {
731    parse_step_tp_f32_mirror(std::env::var("MEMRA_STEP_TP_F32_MIRROR").ok().as_deref())
732}
733
734fn parse_step_tp_decode_v2(value: Option<&str>) -> Result<bool, String> {
735    match value {
736        None | Some("") | Some("0") => Ok(false),
737        Some("1") => Ok(true),
738        Some(value) => Err(format!(
739            "MEMRA_STEP_TP_DECODE_V2={value:?} is invalid; expected 0 or 1"
740        )),
741    }
742}
743
744/// The v2 rank-local Step decode-attention driver: persistent workspaces, evented cross-stream
745/// ordering, and a root-device O reduction — same kernels, values, and canonical reduction order
746/// as the v1 driver (it requires the F32 mirror so no per-call weight expansion exists on either
747/// side of the comparison).
748pub fn step_tp_decode_v2_enabled() -> Result<bool, String> {
749    parse_step_tp_decode_v2(std::env::var("MEMRA_STEP_TP_DECODE_V2").ok().as_deref())
750}
751
752fn parse_step_tp_qkv_fused(value: Option<&str>) -> Result<bool, String> {
753    match value {
754        None | Some("") | Some("0") => Ok(false),
755        Some("1") => Ok(true),
756        Some(value) => Err(format!(
757            "MEMRA_STEP_TP_QKV_FUSED={value:?} is invalid; expected 0 or 1"
758        )),
759    }
760}
761
762fn parse_step_tp_dev_router(value: Option<&str>) -> Result<bool, String> {
763    match value {
764        None | Some("") | Some("0") => Ok(false),
765        Some("1") => Ok(true),
766        Some(value) => Err(format!(
767            "MEMRA_STEP_TP_DEV_ROUTER={value:?} is invalid; expected 0 or 1"
768        )),
769    }
770}
771
772/// Device-side sigmoid top-k routing for the TP device-IO expert program: the per-layer host
773/// logits readback (the last per-layer host sync) disappears. Selection tie-breaking may
774/// differ from the host router — NUMERIC-CLASS door, run-gen argmax gate + boot battery.
775pub fn step_tp_dev_router_enabled() -> Result<bool, String> {
776    parse_step_tp_dev_router(std::env::var("MEMRA_STEP_TP_DEV_ROUTER").ok().as_deref())
777}
778
779fn parse_step_tp_graph(value: Option<&str>) -> Result<bool, String> {
780    match value {
781        None | Some("") | Some("0") => Ok(false),
782        Some("1") => Ok(true),
783        Some(value) => Err(format!(
784            "MEMRA_STEP_TP_GRAPH={value:?} is invalid; expected 0 or 1"
785        )),
786    }
787}
788
789fn parse_step_tp_dcw(value: Option<&str>) -> Result<bool, String> {
790    match value {
791        None | Some("") | Some("0") => Ok(false),
792        Some("1") => Ok(true),
793        Some(value) => Err(format!(
794            "MEMRA_STEP_TP_DCW={value:?} is invalid; expected 0 or 1"
795        )),
796    }
797}
798
799/// Device-counter attention path (graph increment A run EAGERLY): append at len_d - base_d,
800/// inc_i32, fa over the counter-derived window — with bucket = the effective t_kv this is
801/// bit-identical to the host-row + kvmod path (the one-partition law), and it is the exact
802/// child content the capture wraps. Rebase tokens and sub-vec-floor contexts fall back.
803pub fn step_tp_dcw_enabled() -> Result<bool, String> {
804    parse_step_tp_dcw(std::env::var("MEMRA_STEP_TP_DCW").ok().as_deref())
805}
806
807/// CUDA-graph door for the shape-stable TP segments (first increment: the device-routed
808/// expert program — per-layer multi-device parents built from per-rank children, launched on
809/// the model engine's stream; zero per-token node updates). Mechanism proven by
810/// tp_graph_probe. VALUE-IDENTICAL: the graphs replay exactly the eager kernel/copy sequence.
811pub fn step_tp_graph_enabled() -> Result<bool, String> {
812    parse_step_tp_graph(std::env::var("MEMRA_STEP_TP_GRAPH").ok().as_deref())
813}
814
815/// GRAPH-LAUNCH HEADROOM GUARD for the routed-prejoin graph door (see
816/// `spec::GRAPH_LAUNCH_MIN_FREE`): checked on the launching engine only when the door
817/// is armed (short-circuit after `step_tp_graph_enabled`), noting once per process with
818/// the sweep's grep-stable `graph replay suspended:` key.
819fn step_tp_graph_headroom_ok(e: &Engine) -> bool {
820    let ok = crate::spec::graph_launch_headroom_ok(e);
821    if !ok {
822        static NOTED: std::sync::Once = std::sync::Once::new();
823        NOTED.call_once(|| crate::spec::graph_replay_suspended_note("step-tp-routes"));
824    }
825    ok
826}
827
828/// Fused single-launch QKV projection inside the v2 decode driver — a NUMERIC-CLASS door
829/// (per-row deterministic tree reduce instead of the chunked cuBLASLt program), default OFF,
830/// gated by the run-gen argmax gate + boot battery like MEMRA_STEP_NVFP4_DEV_ROUTES.
831pub fn step_tp_qkv_fused_enabled() -> Result<bool, String> {
832    parse_step_tp_qkv_fused(std::env::var("MEMRA_STEP_TP_QKV_FUSED").ok().as_deref())
833}
834
835#[derive(Debug, Clone, PartialEq, Eq)]
836pub struct StepEpLayerSpec {
837    pub layer: usize,
838    pub devices: Vec<usize>,
839}
840
841pub type StepTpLayerSpec = StepEpLayerSpec;
842
843/// ModelPlan-driven whole-model parallel policy. `auto` removes per-layer family recipes; the
844/// loader derives its scope from dense/MoE operations and selects a registered numeric backend
845/// from the artifact tensor/activation contract.
846fn parse_auto_parallel_devices(
847    mode: Option<&str>,
848    raw_devices: Option<&str>,
849) -> Result<Option<Vec<usize>>, String> {
850    let mode = match mode {
851        None | Some("") | Some("0") | Some("off") => return Ok(None),
852        Some("auto") => "auto",
853        Some(value) => {
854            return Err(format!(
855                "MEMRA_PARALLEL={value:?} is invalid; expected off or auto"
856            ));
857        }
858    };
859    let raw = raw_devices.ok_or_else(|| {
860        format!("{mode} parallel placement requires MEMRA_PARALLEL_DEVICES=DEVICE,DEVICE[...]")
861    })?;
862    let devices =
863        raw.split(',')
864            .map(|device| {
865                device.trim().parse::<usize>().map_err(|_| {
866                    format!("MEMRA_PARALLEL_DEVICES entry {device:?} is not an integer")
867                })
868            })
869            .collect::<Result<Vec<_>, _>>()?;
870    if !(2..=crate::parallel::AUTO_PARALLEL_MAX_CARDS).contains(&devices.len()) {
871        return Err(format!(
872            "MEMRA_PARALLEL=auto requires 2..={} devices, got {}",
873            crate::parallel::AUTO_PARALLEL_MAX_CARDS,
874            devices.len()
875        ));
876    }
877    let mut unique = devices.clone();
878    unique.sort_unstable();
879    unique.dedup();
880    if unique.len() != devices.len() {
881        return Err(format!(
882            "MEMRA_PARALLEL_DEVICES must be distinct, got {devices:?}"
883        ));
884    }
885    Ok(Some(devices))
886}
887
888pub fn auto_parallel_devices() -> Result<Option<Vec<usize>>, String> {
889    parse_auto_parallel_devices(
890        std::env::var("MEMRA_PARALLEL").ok().as_deref(),
891        std::env::var("MEMRA_PARALLEL_DEVICES").ok().as_deref(),
892    )
893}
894
895fn parse_parallel_ep_device_router(value: Option<&str>) -> Result<bool, String> {
896    match value {
897        None | Some("") | Some("0") => Ok(false),
898        Some("1") => Ok(true),
899        Some(value) => Err(format!(
900            "MEMRA_PARALLEL_EP_DEVICE_ROUTER={value:?} is invalid; expected 0 or 1"
901        )),
902    }
903}
904
905pub fn parallel_ep_device_router_enabled() -> Result<bool, String> {
906    parse_parallel_ep_device_router(
907        std::env::var("MEMRA_PARALLEL_EP_DEVICE_ROUTER")
908            .ok()
909            .as_deref(),
910    )
911}
912
913fn parse_parallel_ep_pair_down(value: Option<&str>) -> Result<bool, String> {
914    match value {
915        None | Some("") | Some("0") => Ok(false),
916        Some("1") => Ok(true),
917        Some(value) => Err(format!(
918            "MEMRA_PARALLEL_EP_PAIR_DOWN={value:?} is invalid; expected 0 or 1"
919        )),
920    }
921}
922
923pub fn parallel_ep_pair_down_enabled() -> Result<bool, String> {
924    parse_parallel_ep_pair_down(std::env::var("MEMRA_PARALLEL_EP_PAIR_DOWN").ok().as_deref())
925}
926
927fn parse_parallel_ep_q8_act(value: Option<&str>) -> Result<bool, String> {
928    match value {
929        None | Some("") | Some("0") => Ok(false),
930        Some("1") => Ok(true),
931        Some(value) => Err(format!(
932            "MEMRA_PARALLEL_EP_Q8_ACT={value:?} is invalid; expected 0 or 1"
933        )),
934    }
935}
936
937pub fn parallel_ep_q8_act_enabled() -> Result<bool, String> {
938    parse_parallel_ep_q8_act(std::env::var("MEMRA_PARALLEL_EP_Q8_ACT").ok().as_deref())
939}
940
941#[derive(Clone, Copy, Debug, PartialEq, Eq)]
942pub(crate) enum ParallelEpQ8Scope {
943    All,
944    GateUp,
945    Down,
946}
947
948impl ParallelEpQ8Scope {
949    fn label(self) -> &'static str {
950        match self {
951            Self::All => "all",
952            Self::GateUp => "gate-up",
953            Self::Down => "down",
954        }
955    }
956}
957
958fn parse_parallel_ep_q8_scope(value: Option<&str>) -> Result<Option<ParallelEpQ8Scope>, String> {
959    match value {
960        None | Some("") => Ok(None),
961        Some("all") => Ok(Some(ParallelEpQ8Scope::All)),
962        Some("gate-up") => Ok(Some(ParallelEpQ8Scope::GateUp)),
963        Some("down") => Ok(Some(ParallelEpQ8Scope::Down)),
964        Some(value) => Err(format!(
965            "MEMRA_PARALLEL_EP_Q8_SCOPE={value:?} is invalid; expected all, gate-up, or down"
966        )),
967    }
968}
969
970pub(crate) fn parallel_ep_q8_scope() -> Result<Option<ParallelEpQ8Scope>, String> {
971    parse_parallel_ep_q8_scope(std::env::var("MEMRA_PARALLEL_EP_Q8_SCOPE").ok().as_deref())
972}
973
974/// The paired-CTA Q8 gate/up program: one CTA computes the same output row for gate and up and
975/// shares the q8_1 activation loads. Always on where Q8 gate/up arithmetic runs.
976pub(crate) fn parallel_ep_q8_gu_paired_enabled(
977    q8_active: bool,
978    scope: Option<ParallelEpQ8Scope>,
979) -> bool {
980    q8_active && scope != Some(ParallelEpQ8Scope::Down)
981}
982
983fn parse_step_layer_specs(
984    flag: &str,
985    value: Option<&str>,
986    allow_full_model: bool,
987) -> Result<Vec<StepEpLayerSpec>, String> {
988    let trunk = allow_full_model.then_some(STEP37_TRUNK_LAYERS);
989    parse_layer_specs_for_trunk(flag, value, trunk)
990}
991
992/// The pure composition-refusal law behind every parallel door's UNPROVEN-pair matrix
993/// (hoisted from the glm5 TP door, lane/glm5-extract-general): the first armed flag in
994/// `table` refuses by name, BEFORE any parallel CUDA state exists. Each family owns its
995/// own TABLE of `(flag, why)` rows — the reasons are gate receipts, part of the law; a
996/// pair unlocks only with its own composition gate (the primary flag's FLAGS.md row
997/// carries the matrix). `armed` reports whether a flag is set to `"1"` (env in
998/// production; a plain set in unit tests — the pattern keeps tests env-mutation-free).
999pub(crate) fn refuse_door_composition(
1000    primary: &str,
1001    table: &[(&str, &str)],
1002    armed: impl Fn(&str) -> bool,
1003) -> Result<(), String> {
1004    for (flag, why) in table {
1005        if armed(flag) {
1006            return Err(format!(
1007                "{primary} + {flag}: unproven composition, refused ({why})"
1008            ));
1009        }
1010    }
1011    Ok(())
1012}
1013
1014/// The shared `LAYER[-LAYER]@DEVICE,DEVICE[;...]` grammar behind every per-layer parallel
1015/// door. `full_model_trunk` enables the `all` shorthand and names the trunk it expands to —
1016/// the caller's model contract owns that constant, never this parser (the step door passes
1017/// `STEP37_TRUNK_LAYERS`; the glm5 door passes its own trunk length at load time).
1018pub(crate) fn parse_layer_specs_for_trunk(
1019    flag: &str,
1020    value: Option<&str>,
1021    full_model_trunk: Option<usize>,
1022) -> Result<Vec<StepEpLayerSpec>, String> {
1023    let Some(value) = value else {
1024        return Ok(Vec::new());
1025    };
1026    if value.is_empty() || value == "0" {
1027        return Ok(Vec::new());
1028    }
1029
1030    let mut specs = Vec::new();
1031    for item in value.split(';') {
1032        let (layers, devices) = item.split_once('@').ok_or_else(|| {
1033            let layers = if full_model_trunk.is_some() {
1034                "LAYER[-LAYER] or all"
1035            } else {
1036                "LAYER[-LAYER]"
1037            };
1038            format!("{flag} must be {layers}@DEVICE,DEVICE[;...]")
1039        })?;
1040        let (first, last) = if layers == "all" {
1041            let Some(trunk) = full_model_trunk else {
1042                return Err(format!(
1043                    "{flag} does not support the full-model shorthand; assign routed layers \
1044                     explicitly"
1045                ));
1046            };
1047            (0, trunk - 1)
1048        } else {
1049            match layers.split_once('-') {
1050                Some((first, last)) => {
1051                    let first = first
1052                        .parse::<usize>()
1053                        .map_err(|_| format!("{flag} layer {first:?} is not an integer"))?;
1054                    let last = last
1055                        .parse::<usize>()
1056                        .map_err(|_| format!("{flag} layer {last:?} is not an integer"))?;
1057                    if first > last {
1058                        return Err(format!("{flag} layer range {first}-{last} is reversed"));
1059                    }
1060                    if last - first + 1 > 128 {
1061                        return Err(format!(
1062                            "{flag} layer range {first}-{last} exceeds the 128-layer parser cap"
1063                        ));
1064                    }
1065                    (first, last)
1066                }
1067                None => {
1068                    let layer = layers
1069                        .parse::<usize>()
1070                        .map_err(|_| format!("{flag} layer {layers:?} is not an integer"))?;
1071                    (layer, layer)
1072                }
1073            }
1074        };
1075        let devices = devices
1076            .split(',')
1077            .map(|device| {
1078                device
1079                    .parse::<usize>()
1080                    .map_err(|_| format!("{flag} device {device:?} is not an integer"))
1081            })
1082            .collect::<Result<Vec<_>, _>>()?;
1083        if !(2..=8).contains(&devices.len()) {
1084            return Err(format!(
1085                "{flag} requires 2..=8 devices, got {}",
1086                devices.len()
1087            ));
1088        }
1089        let mut unique = devices.clone();
1090        unique.sort_unstable();
1091        unique.dedup();
1092        if unique.len() != devices.len() {
1093            return Err(format!("{flag} devices must be distinct, got {devices:?}"));
1094        }
1095        for layer in first..=last {
1096            if specs
1097                .iter()
1098                .any(|existing: &StepEpLayerSpec| existing.layer == layer)
1099            {
1100                return Err(format!("{flag} assigns layer {layer} more than once"));
1101            }
1102            specs.push(StepEpLayerSpec {
1103                layer,
1104                devices: devices.clone(),
1105            });
1106        }
1107    }
1108    Ok(specs)
1109}
1110
1111pub fn parse_step_ep_layer_specs(value: Option<&str>) -> Result<Vec<StepEpLayerSpec>, String> {
1112    parse_step_layer_specs("MEMRA_STEP_EP", value, false)
1113}
1114
1115pub fn step_ep_layer_specs() -> Result<Vec<StepEpLayerSpec>, String> {
1116    parse_step_ep_layer_specs(std::env::var("MEMRA_STEP_EP").ok().as_deref())
1117}
1118
1119pub fn parse_step_tp_layer_specs(value: Option<&str>) -> Result<Vec<StepTpLayerSpec>, String> {
1120    parse_step_layer_specs("MEMRA_STEP_TP", value, true)
1121}
1122
1123pub fn step_tp_layer_specs() -> Result<Vec<StepTpLayerSpec>, String> {
1124    parse_step_tp_layer_specs(std::env::var("MEMRA_STEP_TP").ok().as_deref())
1125}
1126
1127#[derive(Clone, Copy)]
1128pub struct E4m3BlockMatrix<'a> {
1129    pub codes: &'a [u8],
1130    pub scales: &'a [f32],
1131    pub out_features: usize,
1132    pub in_features: usize,
1133}
1134
1135impl E4m3BlockMatrix<'_> {
1136    fn validate(&self) -> Result<(), String> {
1137        let code_count = self
1138            .out_features
1139            .checked_mul(self.in_features)
1140            .ok_or_else(|| "E4M3 matrix size overflow".to_string())?;
1141        if self.codes.len() != code_count {
1142            return Err(format!(
1143                "E4M3 code count {} != {}x{} ({code_count})",
1144                self.codes.len(),
1145                self.out_features,
1146                self.in_features,
1147            ));
1148        }
1149        let scale_count =
1150            self.out_features.div_ceil(FP8_BLOCK) * self.in_features.div_ceil(FP8_BLOCK);
1151        if self.scales.len() != scale_count {
1152            return Err(format!(
1153                "E4M3 scale count {} != {scale_count} for {}x{}",
1154                self.scales.len(),
1155                self.out_features,
1156                self.in_features,
1157            ));
1158        }
1159        if !self
1160            .scales
1161            .iter()
1162            .all(|scale| scale.is_finite() && *scale > 0.0)
1163        {
1164            return Err("E4M3 scale grid contains a non-finite or non-positive value".to_string());
1165        }
1166        Ok(())
1167    }
1168}
1169
1170#[derive(Clone, Copy)]
1171pub struct E4m3ExpertBank<'a> {
1172    pub codes: &'a [u8],
1173    pub scales: &'a [f32],
1174    pub expert_count: usize,
1175    pub out_features: usize,
1176    pub in_features: usize,
1177}
1178
1179impl E4m3ExpertBank<'_> {
1180    fn validate(&self) -> Result<(), String> {
1181        if self.expert_count == 0 {
1182            return Err("E4M3 expert bank is empty".to_string());
1183        }
1184        let code_stride = self
1185            .out_features
1186            .checked_mul(self.in_features)
1187            .ok_or_else(|| "E4M3 expert code stride overflow".to_string())?;
1188        let code_count = self
1189            .expert_count
1190            .checked_mul(code_stride)
1191            .ok_or_else(|| "E4M3 expert code count overflow".to_string())?;
1192        if self.codes.len() != code_count {
1193            return Err(format!(
1194                "E4M3 expert code count {} != {}x{} ({code_count})",
1195                self.codes.len(),
1196                self.expert_count,
1197                code_stride,
1198            ));
1199        }
1200        let scale_stride =
1201            self.out_features.div_ceil(FP8_BLOCK) * self.in_features.div_ceil(FP8_BLOCK);
1202        let scale_count = self
1203            .expert_count
1204            .checked_mul(scale_stride)
1205            .ok_or_else(|| "E4M3 expert scale count overflow".to_string())?;
1206        if self.scales.len() != scale_count {
1207            return Err(format!(
1208                "E4M3 expert scale count {} != {}x{} ({scale_count})",
1209                self.scales.len(),
1210                self.expert_count,
1211                scale_stride,
1212            ));
1213        }
1214        if !self
1215            .scales
1216            .iter()
1217            .all(|scale| scale.is_finite() && *scale > 0.0)
1218        {
1219            return Err(
1220                "E4M3 expert scale grid contains a non-finite or non-positive value".to_string(),
1221            );
1222        }
1223        Ok(())
1224    }
1225
1226    pub fn expert(&self, expert: usize) -> Result<E4m3BlockMatrix<'_>, String> {
1227        if expert >= self.expert_count {
1228            return Err(format!("expert {expert} outside 0..{}", self.expert_count));
1229        }
1230        let code_stride = self.out_features * self.in_features;
1231        let scale_stride =
1232            self.out_features.div_ceil(FP8_BLOCK) * self.in_features.div_ceil(FP8_BLOCK);
1233        Ok(E4m3BlockMatrix {
1234            codes: &self.codes[expert * code_stride..(expert + 1) * code_stride],
1235            scales: &self.scales[expert * scale_stride..(expert + 1) * scale_stride],
1236            out_features: self.out_features,
1237            in_features: self.in_features,
1238        })
1239    }
1240}
1241
1242pub struct ColumnParallelResult {
1243    pub gathered: Vec<f32>,
1244    pub rank_outputs: Vec<Vec<f32>>,
1245}
1246
1247pub struct RowParallelResult {
1248    pub reduced: Vec<f32>,
1249    pub rank_partials: Vec<Vec<f32>>,
1250}
1251
1252#[derive(Clone, Copy)]
1253pub struct Bf16Matrix<'a> {
1254    pub bytes: &'a [u8],
1255    pub out_features: usize,
1256    pub in_features: usize,
1257}
1258
1259impl Bf16Matrix<'_> {
1260    pub fn validate(&self) -> Result<(), String> {
1261        if self.out_features == 0 || self.in_features == 0 {
1262            return Err("BF16 matrix dimensions must be nonzero".into());
1263        }
1264        let expected = self
1265            .out_features
1266            .checked_mul(self.in_features)
1267            .and_then(|values| values.checked_mul(2))
1268            .ok_or("BF16 matrix byte count overflow")?;
1269        if self.bytes.len() != expected {
1270            return Err(format!(
1271                "BF16 matrix bytes {} != {}x{}x2 ({expected})",
1272                self.bytes.len(),
1273                self.out_features,
1274                self.in_features,
1275            ));
1276        }
1277        Ok(())
1278    }
1279}
1280
1281struct ResidentE4m3Rank {
1282    codes: CudaSlice<u8>,
1283    scales: CudaSlice<f32>,
1284    out_features: usize,
1285    in_features: usize,
1286}
1287
1288enum ResidentBf16Weight {
1289    Bf16(CudaSlice<u8>),
1290    F32(CudaSlice<f32>),
1291}
1292
1293impl ResidentBf16Weight {
1294    fn ordinal(&self) -> usize {
1295        match self {
1296            Self::Bf16(bytes) => bytes.ordinal(),
1297            Self::F32(values) => values.ordinal(),
1298        }
1299    }
1300}
1301
1302struct ResidentBf16Rank {
1303    weight: ResidentBf16Weight,
1304    out_features: usize,
1305    in_features: usize,
1306    /// q8_0 mirror built at load under MEMRA_STEP_TP_W8 (numeric-class door; the bf16 slab
1307    /// stays resident because every prefill/verify path is qualified against it).
1308    q8: Option<CudaSlice<u8>>,
1309}
1310
1311pub struct ResidentColumnParallel {
1312    ranks: Vec<ResidentE4m3Rank>,
1313    out_features: usize,
1314    in_features: usize,
1315}
1316
1317pub struct ResidentRowParallel {
1318    ranks: Vec<ResidentE4m3Rank>,
1319    out_features: usize,
1320    in_features: usize,
1321}
1322
1323pub struct ResidentBf16ColumnParallel {
1324    ranks: Vec<ResidentBf16Rank>,
1325    out_features: usize,
1326    in_features: usize,
1327    canonical_chunk_rows: Option<usize>,
1328}
1329
1330pub struct ResidentBf16RowParallel {
1331    ranks: Vec<ResidentBf16Rank>,
1332    out_features: usize,
1333    in_features: usize,
1334}
1335
1336pub struct ResidentStepBf16RowParallel {
1337    ranks: Vec<Vec<ResidentBf16Rank>>,
1338    out_features: usize,
1339    in_features: usize,
1340    canonical_chunk_cols: usize,
1341}
1342
1343/// Root-owned BF16 sigmoid router with persistent F32 weight, bias, and active mask.
1344pub struct ResidentSigmoidTopKRouter {
1345    weight: CudaSlice<f32>,
1346    correction_bias: CudaSlice<f32>,
1347    active: CudaSlice<u8>,
1348    root_device: usize,
1349    input_width: usize,
1350    expert_count: usize,
1351    experts_per_token: usize,
1352    active_count: usize,
1353    scaling_factor: f32,
1354    route_norm: bool,
1355}
1356
1357pub struct SigmoidTopKHostOutput {
1358    pub logits: Vec<f32>,
1359    pub selected: Vec<u32>,
1360    pub weights: Vec<f32>,
1361}
1362
1363/// Full BF16 SwiGLU weights replicated independently on every runtime rank.
1364pub struct ResidentReplicatedBf16SwiGlu {
1365    gate: Vec<ResidentBf16Rank>,
1366    up: Vec<ResidentBf16Rank>,
1367    down: Vec<ResidentBf16Rank>,
1368    input_width: usize,
1369    intermediate_width: usize,
1370}
1371
1372/// One token-major F32 batch replicated across a native-P2P rank group.
1373///
1374/// Every allocation is owned by its matching rank CUDA context. This is the generic handoff
1375/// substrate between independently sharded operators; it carries no model or topology claim.
1376pub struct ResidentReplicatedDeviceRows {
1377    ranks: Vec<CudaSlice<f32>>,
1378    tokens: usize,
1379    width: usize,
1380}
1381
1382impl ResidentReplicatedDeviceRows {
1383    pub fn tokens(&self) -> usize {
1384        self.tokens
1385    }
1386
1387    pub fn width(&self) -> usize {
1388        self.width
1389    }
1390
1391    pub fn ranks(&self) -> usize {
1392        self.ranks.len()
1393    }
1394}
1395
1396/// Canonical MoE output order: routed plus shared, then add the layer residual.
1397pub fn moe_residual_host(
1398    residual: &[f32],
1399    routed: &[f32],
1400    shared: &[f32],
1401) -> Result<Vec<f32>, String> {
1402    if residual.len() != routed.len() || residual.len() != shared.len() {
1403        return Err(format!(
1404            "MoE residual lengths residual={} routed={} shared={}",
1405            residual.len(),
1406            routed.len(),
1407            shared.len()
1408        ));
1409    }
1410    let ffn = routed
1411        .iter()
1412        .zip(shared)
1413        .map(|(&routed, &shared)| routed + shared)
1414        .collect::<Vec<_>>();
1415    Ok(residual
1416        .iter()
1417        .zip(ffn)
1418        .map(|(&residual, ffn)| residual + ffn)
1419        .collect())
1420}
1421
1422pub use memra_kv::{
1423    KvRingAppend, ResidentTpKvCache, ResidentTpKvCacheRank, TpKvAppendPlan, TpKvTransaction,
1424};
1425
1426/// Persistent TP2/TP4/TP8 routed-expert reference.
1427///
1428/// Rank-local checkpoint shards are uploaded once and remain tied to their owning CUDA context.
1429/// Activations and deterministic host-staged collectives remain per invocation. This is the
1430/// correctness substrate for serving TP/EP, not product-throughput evidence.
1431pub struct ResidentTpExpert {
1432    gate: ResidentColumnParallel,
1433    up: ResidentColumnParallel,
1434    down: ResidentRowParallel,
1435    input_width: usize,
1436    expert_width: usize,
1437}
1438
1439struct ResidentE4m3ExpertBankRank {
1440    codes: CudaSlice<u8>,
1441    scales: CudaSlice<f32>,
1442    expert_range: Range<usize>,
1443    out_features: usize,
1444    in_features: usize,
1445    code_stride: usize,
1446    scale_stride: usize,
1447    /// TP row banks are packed by native 128-wide K block so reduction can replay the
1448    /// checkpoint's global block order exactly. Other banks remain row-major.
1449    k_blocks: Option<usize>,
1450}
1451
1452struct PackedE4m3ExpertBankRank {
1453    codes: Vec<u8>,
1454    scales: Vec<f32>,
1455    expert_range: Range<usize>,
1456    out_features: usize,
1457    in_features: usize,
1458    code_stride: usize,
1459    scale_stride: usize,
1460    k_blocks: Option<usize>,
1461}
1462
1463struct ResidentEpRank {
1464    gate: ResidentE4m3ExpertBankRank,
1465    up: ResidentE4m3ExpertBankRank,
1466    down: ResidentE4m3ExpertBankRank,
1467}
1468
1469/// Persistent expert-parallel reference.
1470///
1471/// Every routed expert has exactly one owner rank. Shared experts are deliberately absent from
1472/// this object because Step replicates them per rank. Routes execute on the owner CUDA context.
1473/// The default oracle stages through host memory; the native path peer-dispatches inputs and
1474/// peer-returns owner outputs while preserving host-canonical activation and accumulation.
1475pub struct ResidentExpertParallel {
1476    ranks: Vec<ResidentEpRank>,
1477    expert_count: usize,
1478    input_width: usize,
1479    expert_width: usize,
1480}
1481
1482/// Projection-level output from the opt-in official Step grouped-FP8 gate.
1483///
1484/// Rows remain pair-major. Routing, weighted combine, and production integration are deliberately
1485/// outside this gate-only adapter.
1486pub struct StepGroupedFp8ProjectionOutput {
1487    pub gate: Vec<f32>,
1488    pub up: Vec<f32>,
1489    pub down: Vec<f32>,
1490}
1491
1492/// Prepared official Step grouped-FP8 projection gate.
1493///
1494/// The complete tensor banks, both CSR schedules, input, activation buffer, and three projection
1495/// workspaces are uploaded or allocated once. Repeated execution performs no device allocation.
1496pub struct PreparedStepGroupedFp8Gate {
1497    device: usize,
1498    gate: ResidentE4m3ExpertBankRank,
1499    up: ResidentE4m3ExpertBankRank,
1500    down: ResidentE4m3ExpertBankRank,
1501    input: CudaSlice<f32>,
1502    route_csr: DeviceExpertCsr,
1503    down_csr: DeviceExpertCsr,
1504    gate_workspace: Fp8GroupedWorkspace,
1505    up_workspace: Fp8GroupedWorkspace,
1506    down_workspace: Fp8GroupedWorkspace,
1507    activation: CudaSlice<f32>,
1508    activation_limit: Option<f32>,
1509    tokens: usize,
1510    pairs: usize,
1511}
1512
1513impl PreparedStepGroupedFp8Gate {
1514    pub fn tokens(&self) -> usize {
1515        self.tokens
1516    }
1517
1518    pub fn pairs(&self) -> usize {
1519        self.pairs
1520    }
1521}
1522
1523struct PreparedStepGroupedExpertOwner {
1524    rank: usize,
1525    global_pairs: Vec<usize>,
1526    route_csr: DeviceExpertCsr,
1527    down_csr: DeviceExpertCsr,
1528    gate_workspace: Fp8GroupedWorkspace,
1529    up_workspace: Fp8GroupedWorkspace,
1530    down_workspace: Fp8GroupedWorkspace,
1531    activation: CudaSlice<f32>,
1532}
1533
1534struct StepGroupedExpertOwnerSchedule {
1535    global_pairs: Vec<usize>,
1536    route_csr: ExpertCsr,
1537    down_csr: ExpertCsr,
1538}
1539
1540/// Prepared official Step expert-owner grouped-FP8 projection gate.
1541///
1542/// Route partitioning, owner-local CSR uploads, input dispatch, activation buffers, and grouped
1543/// workspaces are persistent. Projection rows are scattered back to canonical pair order only
1544/// after every owner has completed its rank-local program.
1545pub struct PreparedStepGroupedExpertParallelGate {
1546    rank_inputs: Vec<CudaSlice<f32>>,
1547    owners: Vec<PreparedStepGroupedExpertOwner>,
1548    activation_limit: Option<f32>,
1549    tokens: usize,
1550    pairs: usize,
1551    max_tokens: usize,
1552    max_pairs: usize,
1553    input_width: usize,
1554    expert_width: usize,
1555    generation: u64,
1556    executed_generation: Option<u64>,
1557    ready: bool,
1558}
1559
1560impl PreparedStepGroupedExpertParallelGate {
1561    pub fn tokens(&self) -> usize {
1562        self.tokens
1563    }
1564
1565    pub fn pairs(&self) -> usize {
1566        self.pairs
1567    }
1568
1569    pub fn max_tokens(&self) -> usize {
1570        self.max_tokens
1571    }
1572
1573    pub fn input_width(&self) -> usize {
1574        self.input_width
1575    }
1576
1577    pub fn expert_width(&self) -> usize {
1578        self.expert_width
1579    }
1580
1581    pub fn set_activation_limit(&mut self, limit: Option<f32>) -> Result<(), String> {
1582        validate_step_expert_activation_limit(limit)?;
1583        self.activation_limit = limit;
1584        self.executed_generation = None;
1585        Ok(())
1586    }
1587
1588    pub fn active_owners(&self) -> usize {
1589        self.owners
1590            .iter()
1591            .filter(|owner| !owner.global_pairs.is_empty())
1592            .count()
1593    }
1594
1595    pub fn owner_pair_counts(&self) -> Vec<usize> {
1596        self.owners
1597            .iter()
1598            .map(|owner| owner.global_pairs.len())
1599            .collect()
1600    }
1601
1602    pub fn generation(&self) -> u64 {
1603        self.generation
1604    }
1605}
1606
1607struct PreparedPeerWeightedRouteOwner {
1608    token_rows: CudaSlice<i32>,
1609    slots: CudaSlice<i32>,
1610    weights: CudaSlice<f32>,
1611    active_pairs: usize,
1612}
1613
1614/// Persistent root-side weighted combine for peer-owned canonical route rows.
1615///
1616/// Owner metadata, one reusable peer staging buffer, the canonical slot bank, weight bank, and
1617/// output are allocated once. Refreshes update metadata prefixes; execution peer-copies active
1618/// rows, scatters them by canonical token/slot, and reduces in the requested numeric order.
1619pub struct PreparedPeerWeightedRouteCombine {
1620    root_device: usize,
1621    owners: Vec<PreparedPeerWeightedRouteOwner>,
1622    peer_staging: CudaSlice<f32>,
1623    slots: CudaSlice<f32>,
1624    weights: CudaSlice<f32>,
1625    output: CudaSlice<f32>,
1626    peer_devices: Vec<usize>,
1627    peer_outputs: Vec<CudaSlice<f32>>,
1628    width: usize,
1629    experts_per_token: usize,
1630    max_tokens: usize,
1631    max_pairs: usize,
1632    tokens: usize,
1633    pairs: usize,
1634    projection_generation: u64,
1635    output_generation: Option<u64>,
1636    broadcast_generation: Option<u64>,
1637    ready: bool,
1638}
1639
1640impl PreparedPeerWeightedRouteCombine {
1641    pub fn tokens(&self) -> usize {
1642        self.tokens
1643    }
1644
1645    pub fn pairs(&self) -> usize {
1646        self.pairs
1647    }
1648
1649    pub fn owner_pair_counts(&self) -> Vec<usize> {
1650        self.owners.iter().map(|owner| owner.active_pairs).collect()
1651    }
1652
1653    pub fn distributed_ranks(&self) -> usize {
1654        1 + self.peer_outputs.len()
1655    }
1656}
1657
1658struct ResidentTpExpertBank {
1659    gate: Vec<ResidentE4m3ExpertBankRank>,
1660    up: Vec<ResidentE4m3ExpertBankRank>,
1661    down: Vec<ResidentE4m3ExpertBankRank>,
1662    expert_count: usize,
1663    input_width: usize,
1664    expert_width: usize,
1665}
1666
1667/// Persistent tensor-parallel expert bank.
1668///
1669/// Every rank owns a checkpoint-aligned output-row shard of every gate/up projection and an
1670/// input-column shard of every down projection. Activations cross deterministic host-staged
1671/// collectives on hosts where native peer copies are unavailable or corrupt.
1672pub struct ResidentTensorParallel {
1673    bank: ResidentTpExpertBank,
1674}
1675
1676/// Multi-context TP correctness runtime. Each rank owns an independent `Engine` and CUDA context.
1677///
1678/// Host bounce is the default oracle. Native P2P is opt-in and preserves the oracle's global
1679/// checkpoint-block reduction order; it remains a correctness path until serving gates and
1680/// repeated performance evidence qualify it.
1681pub struct TpE4m3HostBounce {
1682    devices: Vec<usize>,
1683    ranks: Vec<Engine>,
1684    native_p2p: bool,
1685    ep_device_arithmetic: bool,
1686    bulk_p2p: bool,
1687    /// v2 decode-attention workspace (MEMRA_STEP_TP_DECODE_V2). One per runtime, shared by
1688    /// every TP attention layer — the buffer shapes are geometry-constant across the trunk.
1689    decode_v2: std::sync::Mutex<Vec<StepTpDecodeV2Ws>>,
1690}
1691
1692pub struct TpKvVerifiedLayer<'a> {
1693    pub cache: &'a mut ResidentTpKvCache,
1694    pub start: usize,
1695    pub logical_len: usize,
1696    pub source_k_raw: u64,
1697    pub source_v_raw: u64,
1698    pub source_k_tok_bytes: usize,
1699    pub source_v_tok_bytes: usize,
1700}
1701
1702/// Persistent two-rank all-reduce for one replicated f32 row.
1703///
1704/// Each rank pushes its local partial directly into a peer-resident staging row, records one
1705/// reusable event, waits for the peer's corresponding event, then adds `(rank0, rank1)` in that
1706/// same operand order on both devices. Two staging rows per direction are enough because join
1707/// `j + 1` is ordered after each rank's add at join `j`, so overwriting parity `j` cannot race its
1708/// peer consumer. The collective allocates nothing and performs no host synchronization per call.
1709pub struct Tp2ReplicatedRowJoin {
1710    width: usize,
1711    parity: usize,
1712    stage0: [CudaSlice<f32>; 2],
1713    stage1: [CudaSlice<f32>; 2],
1714    stage0_raw: [u64; 2],
1715    stage1_raw: [u64; 2],
1716    event0: [CudaEvent; 2],
1717    event1: [CudaEvent; 2],
1718}
1719
1720fn validate_tp2_replicated_row_join(
1721    ranks: usize,
1722    native_p2p: bool,
1723    width: usize,
1724) -> Result<(), String> {
1725    if ranks != 2 {
1726        return Err(format!(
1727            "replicated-row join requires exactly two ranks, got {ranks}"
1728        ));
1729    }
1730    if !native_p2p {
1731        return Err("replicated-row join requires native P2P".into());
1732    }
1733    if width == 0 || width > i32::MAX as usize {
1734        return Err(format!(
1735            "replicated-row join width must be in 1..={}, got {width}",
1736            i32::MAX
1737        ));
1738    }
1739    Ok(())
1740}
1741
1742fn launch_tp2_peer_push(
1743    engine: &Engine,
1744    source: &CudaSlice<f32>,
1745    destination: u64,
1746    width: usize,
1747) -> Result<(), Box<dyn std::error::Error>> {
1748    let function = engine.func("q4e_push_f32");
1749    let config = LaunchConfig::for_num_elems(width as u32);
1750    let width = width as i64;
1751    let stream = engine.gpu.stream();
1752    let mut launch = stream.launch_builder(&function);
1753    launch.arg(source).arg(&destination).arg(&width);
1754    unsafe {
1755        launch.launch(config)?;
1756    }
1757    Ok(())
1758}
1759
1760/// Persistent workspace of the v2 rank-local decode-attention driver.
1761///
1762/// Buffers live in their producing rank's CUDA context, are never freed, and events are
1763/// re-recorded per call — the pp.rs `BoundarySlot` discipline — so the per-token path has no
1764/// cuMemAlloc, no cross-stream free, and no host round-trip. Every buffer is fully overwritten
1765/// before its consumers run in the same call; nothing carries state between tokens.
1766/// Per-rank attn_gate row shards for the fused QKV+gate kernel, in the weight class the
1767/// fused kernels read (F32 mirror or raw checkpoint bf16).
1768pub enum StepTpGateShards<'a> {
1769    F32(&'a [crate::CudaSlice<f32>]),
1770    Bf16(&'a [crate::CudaSlice<u8>]),
1771}
1772
1773pub struct StepTpDecodeV2Ws {
1774    /// T-COLUMN verify slabs (spec MTP): per-rank [t, local_dim] projections computed by
1775    /// the weight-amortized qkvg_tcol kernel; the col-select door copies one column into
1776    /// the single-row buffers and everything downstream runs the unmodified t=1 program.
1777    pub(crate) tcol_q: Vec<CudaSlice<f32>>,
1778    pub(crate) tcol_k: Vec<CudaSlice<f32>>,
1779    pub(crate) tcol_v: Vec<CudaSlice<f32>>,
1780    pub(crate) tcol_g: Vec<CudaSlice<f32>>,
1781    pub(crate) tcol_in: Vec<CudaSlice<f32>>,
1782    pub(crate) tcol_cap: usize,
1783    /// MEMRA_STEP_TP_W8 activation scratch: per-rank q8_1 quantized attention input
1784    /// ([in_f] i8 + one f32 scale pair per 32). Persistent because the alternative is an
1785    /// allocation per rank per layer per token.
1786    w8_aq: Vec<CudaSlice<i8>>,
1787    w8_ad: Vec<CudaSlice<f32>>,
1788    w8_in: usize,
1789    /// o_proj-side twin of the same scratch (its activation is the gated attention output,
1790    /// a different vector from the QKV input, so it needs its own buffers).
1791    w8o_aq: Vec<CudaSlice<i8>>,
1792    w8o_ad: Vec<CudaSlice<f32>>,
1793    w8o_in: usize,
1794    /// VERIFY-WALK q8_1 activation scratch, t columns wide (the decode scratch above is one
1795    /// row). Two sets because the QKV input and the gated attention output are different
1796    /// vectors of different widths.
1797    w8t_aq: Vec<CudaSlice<i8>>,
1798    w8t_ad: Vec<CudaSlice<f32>>,
1799    w8t_in: usize,
1800    w8t_oaq: Vec<CudaSlice<i8>>,
1801    w8t_oad: Vec<CudaSlice<f32>>,
1802    w8t_oin: usize,
1803    w8t_cap: usize,
1804    /// MEMRA_TCOL_OPROJ slabs: per-rank stashed `gated` rows ([8, local_q_dim]), per-rank
1805    /// b4_tcol partials ([8, o_out]), a root-side peer pull of rank1's partial slab, and
1806    /// the root-side joined `mixed` slab. Armed lazily by the first stash.
1807    /// MEMRA_SPEC_FA2 slabs: per-rank stashed post-rope q rows ([2, local_q_dim]), gate
1808    /// rows ([2, heads/ranks]) and the two gated outputs the per-row combine writes
1809    /// ([2, local_q_dim]). Armed lazily by the first stash.
1810    pub(crate) fa2_q: Vec<CudaSlice<f32>>,
1811    pub(crate) fa2_gate: Vec<CudaSlice<f32>>,
1812    pub(crate) fa2_gated: Vec<CudaSlice<f32>>,
1813    pub(crate) fa2_cap: usize,
1814    /// T-ROW rope/append twin scratch: per-rank roped-k rows ([8, local_kv]), per-row
1815    /// last-block counters ([8]) and the per-tick position slab ([8]). Armed with the
1816    /// fa2 slabs.
1817    rope_k_t: Vec<CudaSlice<f32>>,
1818    rope_ctr_t: Vec<CudaSlice<u32>>,
1819    rope_pos_t: Vec<CudaSlice<i32>>,
1820    /// Per-rank combined 6-word row tables, keyed by the caller's (layer, session-set,
1821    /// base-arming) signature. LEGACY: only the `MEMRA_ROWS_TAB_RESTAGE=0` rollback arm
1822    /// reads this. See `rows_tab_t` for why the key cannot be made safe.
1823    rows_tabs: Vec<std::collections::HashMap<u64, CudaSlice<u64>>>,
1824    /// Per-rank PERSISTENT 6-word row-table slab ([32, 6] u64), RESTAGED from the live
1825    /// distributed cache before every launch. Replaces the `rows_tabs` memo, whose key was
1826    /// a hash of (k pointer, base pointer, layer, t) while the table it returned also
1827    /// carried the V and LEN pointers: a session whose K buffer address was recycled hit
1828    /// another session's table and the append kernel wrote its K/V through the FREED
1829    /// pointers the entry still held. Same defect and same cure as the row-table twin in
1830    /// `step35_verify_fa_rows_join` (8c8397e0b2, Hermes `11339f5cd3c132a3`), which this
1831    /// path was left out of. One 32-word htod per rank per layer replaces the map lookup;
1832    /// no allocation, and the staging is stream-ordered exactly like `rope_pos_t`.
1833    rows_tab_t: Vec<CudaSlice<u64>>,
1834    /// HOST shadow of the last table staged under each retired memo key, used ONLY by
1835    /// `MEMRA_ROWS_TAB_STALE_SCAN=1` to prove that the retired key would have handed a live
1836    /// launch another allocation's pointers. Never read by a kernel.
1837    rows_tab_shadow: Vec<std::collections::HashMap<u64, Vec<u64>>>,
1838    tcol_gated: Vec<CudaSlice<f32>>,
1839    tcol_opart: Vec<CudaSlice<f32>>,
1840    tcol_opeer: Option<CudaSlice<f32>>,
1841    tcol_omix: Option<CudaSlice<f32>>,
1842    tcol_ocap: usize,
1843    // rank-context buffers, indexed by rank (pub(crate): the v2 driver in hybrid_forward
1844    // feeds them to the KV transaction and attention kernels between the two v2 phases)
1845    pub(crate) q_raw: Vec<CudaSlice<f32>>,
1846    pub(crate) k_raw: Vec<CudaSlice<f32>>,
1847    pub(crate) v_raw: Vec<CudaSlice<f32>>,
1848    pub(crate) q: Vec<CudaSlice<f32>>,
1849    pub(crate) k: Vec<CudaSlice<f32>>,
1850    pub(crate) pos: Vec<CudaSlice<i32>>,
1851    /// FUSION #1 last-block counters (one per rank; atomicInc auto-resets per launch).
1852    pub(crate) fuse_ctr: Vec<CudaSlice<u32>>,
1853    pub(crate) gate: Vec<CudaSlice<f32>>,
1854    pub(crate) attn_out: Vec<CudaSlice<f32>>,
1855    pub(crate) gated: Vec<CudaSlice<f32>>,
1856    /// [rank][block] O partials, each `o_out` wide, in the owning rank's context.
1857    o_partials: Vec<Vec<CudaSlice<f32>>>,
1858    /// Stable workspace pointers for the rank-done-fenced raw P2P gather. Safe
1859    /// `memcpy_dtod` creates a fresh source event for every cross-context copy; the v2
1860    /// driver already records one persistent `ev_rank` after all three source families.
1861    raw_o_partials: Vec<Vec<u64>>,
1862    raw_k: Vec<u64>,
1863    raw_v_raw: Vec<u64>,
1864    /// Recorded on each rank's stream after its per-call work; root waits before peer reads.
1865    ev_rank: Vec<CudaEvent>,
1866    // root-context buffers
1867    peer_partial: CudaSlice<f32>,
1868    reduce_a: CudaSlice<f32>,
1869    reduce_b: CudaSlice<f32>,
1870    /// Never written; the canonical zero start of the v1 add chain.
1871    zeros: CudaSlice<f32>,
1872    pub(crate) k_shadow: CudaSlice<f32>,
1873    pub(crate) v_shadow: CudaSlice<f32>,
1874    ev_refresh: CudaEvent,
1875    ev_oproj: CudaEvent,
1876    // model-engine (e) context
1877    gate_e: CudaSlice<f32>,
1878    /// Per-token stages (e-ctx, fixed addresses): one eager e-stream copy each per layer; the
1879    /// rank flows raw-copy FROM them, which is exactly the shape graph capture needs.
1880    pub(crate) h_stage: Option<CudaSlice<f32>>,
1881    pub(crate) pos_stage: Option<CudaSlice<i32>>,
1882    /// Workspace-owned per-rank attention input rows (the stage flow copies into THESE, not
1883    /// the per-layer decode_input buffers — the workspace is shared across layers, so every
1884    /// captured/raw address it uses must be layer-invariant).
1885    attn_in: Vec<CudaSlice<f32>>,
1886    /// Cached raw pointers of the stage-flow operands (set when the stages arm).
1887    raw_h_stage: u64,
1888    raw_pos_stage: u64,
1889    raw_attn_in: Vec<u64>,
1890    raw_pos: Vec<u64>,
1891    raw_o_partial1: u64,
1892    raw_peer_partial: u64,
1893    raw_k1: u64,
1894    raw_v1: u64,
1895    raw_k_shadow: u64,
1896    raw_v_shadow: u64,
1897    /// Token-graph e-context mirrors (armed by the orchestrator): the root section
1898    /// raw-copies the reduced attention output and the shadow rows here so the e-glue
1899    /// children read same-context memory (cross-context kernel args are capture-illegal).
1900    raw_mixed_stage_e: u64,
1901    raw_reduce_a: u64,
1902    raw_shadow_stage_e: (u64, u64),
1903    ev_entry: CudaEvent,
1904    e_device: usize,
1905    // geometry pins
1906    local_q_dim: usize,
1907    local_kv_dim: usize,
1908    heads: usize,
1909    pub(crate) o_out: usize,
1910    o_block_cols: usize,
1911    blocks_per_rank: usize,
1912}
1913
1914impl TpE4m3HostBounce {
1915    pub fn new(devices: &[usize]) -> Result<Self, Box<dyn std::error::Error>> {
1916        Self::new_inner(devices, false, false, false, false)
1917    }
1918
1919    pub fn new_native_p2p(devices: &[usize]) -> Result<Self, Box<dyn std::error::Error>> {
1920        Self::new_inner(devices, false, true, false, false)
1921    }
1922
1923    pub fn new_native_p2p_device_arithmetic(
1924        devices: &[usize],
1925    ) -> Result<Self, Box<dyn std::error::Error>> {
1926        Self::new_inner(devices, false, true, true, false)
1927    }
1928
1929    pub(crate) fn new_configured(
1930        devices: &[usize],
1931        native_p2p: bool,
1932        ep_device_arithmetic: bool,
1933        bulk_p2p: bool,
1934    ) -> Result<Self, Box<dyn std::error::Error>> {
1935        Self::new_inner(devices, false, native_p2p, ep_device_arithmetic, bulk_p2p)
1936    }
1937
1938    /// Single-rank execution of the canonical checkpoint-block TP program.
1939    ///
1940    /// This is an oracle for distributed exactness, not a serving topology. It lets gates compare
1941    /// TP=1 and TP>1 with the same packing, kernel launches, and deterministic reduction order.
1942    pub fn new_single_rank_oracle(device: usize) -> Result<Self, Box<dyn std::error::Error>> {
1943        Self::new_inner(&[device], true, false, false, false)
1944    }
1945
1946    fn new_inner(
1947        devices: &[usize],
1948        allow_single_rank: bool,
1949        native_p2p: bool,
1950        ep_device_arithmetic: bool,
1951        bulk_p2p: bool,
1952    ) -> Result<Self, Box<dyn std::error::Error>> {
1953        if ep_device_arithmetic && !native_p2p {
1954            return Err("device-resident EP arithmetic requires native P2P".into());
1955        }
1956        if bulk_p2p && !native_p2p {
1957            return Err("bulk TP transport requires native P2P".into());
1958        }
1959        let minimum = if allow_single_rank { 1 } else { 2 };
1960        if !(minimum..=8).contains(&devices.len()) {
1961            return Err(format!(
1962                "TP reference requires {minimum}..=8 devices, got {}",
1963                devices.len()
1964            )
1965            .into());
1966        }
1967        let mut unique = devices.to_vec();
1968        unique.sort_unstable();
1969        unique.dedup();
1970        if unique.len() != devices.len() {
1971            return Err(format!("TP devices must be distinct, got {devices:?}").into());
1972        }
1973        let ranks = devices
1974            .iter()
1975            .map(|&device| Engine::new(device))
1976            .collect::<Result<Vec<_>, _>>()?;
1977        if native_p2p {
1978            configure_native_p2p(&ranks, devices)?;
1979        }
1980        if allow_single_rank {
1981            eprintln!(
1982                "[tp] canonical oracle transport=local device={} performance_claim=false",
1983                devices[0]
1984            );
1985        } else if native_p2p {
1986            if ep_device_arithmetic {
1987                eprintln!(
1988                    "[tp] correctness transport=native-p2p devices={devices:?} \
1989                     native_p2p=true activation=device-host-exact \
1990                     accumulation=device-host-exact output=root-readback \
1991                     bulk_p2p={bulk_p2p} performance_claim=false"
1992                );
1993            } else {
1994                eprintln!(
1995                    "[tp] correctness transport=native-p2p devices={devices:?} \
1996                     native_p2p=true activation=host-canonical bulk_p2p={bulk_p2p} \
1997                     performance_claim=false"
1998                );
1999            }
2000        } else {
2001            eprintln!(
2002                "[tp] correctness transport=host-bounce devices={devices:?} \
2003                 native_p2p=false performance_claim=false"
2004            );
2005        }
2006        Ok(Self {
2007            devices: devices.to_vec(),
2008            ranks,
2009            native_p2p,
2010            ep_device_arithmetic,
2011            bulk_p2p,
2012            decode_v2: std::sync::Mutex::new(Vec::new()),
2013        })
2014    }
2015
2016    pub fn devices(&self) -> &[usize] {
2017        &self.devices
2018    }
2019
2020    pub fn native_p2p(&self) -> bool {
2021        self.native_p2p
2022    }
2023
2024    pub fn bulk_p2p(&self) -> bool {
2025        self.bulk_p2p
2026    }
2027
2028    pub fn expert_activation_label(&self) -> &'static str {
2029        if self.ep_device_arithmetic {
2030            "device-host-exact"
2031        } else {
2032            "host-canonical"
2033        }
2034    }
2035
2036    pub fn expert_accumulation_label(&self) -> &'static str {
2037        self.expert_activation_label()
2038    }
2039
2040    pub fn expert_output_label(&self) -> &'static str {
2041        if self.ep_device_arithmetic {
2042            "root-readback"
2043        } else {
2044            "host-accumulated"
2045        }
2046    }
2047
2048    pub fn transport_label(&self) -> &'static str {
2049        if self.devices.len() == 1 {
2050            "local"
2051        } else if self.native_p2p {
2052            "native-p2p"
2053        } else {
2054            "host-bounce"
2055        }
2056    }
2057
2058    pub fn device_names(&self) -> Result<Vec<String>, Box<dyn std::error::Error>> {
2059        self.ranks
2060            .iter()
2061            .map(|rank| rank.ctx().name().map_err(Into::into))
2062            .collect()
2063    }
2064
2065    /// Correctness-gate access to the engine that owns one TP rank.
2066    ///
2067    /// Model execution should prefer collective methods on this runtime. This accessor exists so
2068    /// focused gates can prove that the rank-local projection outputs remain device-resident
2069    /// through the next ownership boundary before that boundary is wired into serving.
2070    pub fn rank_engine(&self, rank: usize) -> Option<&Engine> {
2071        self.ranks.get(rank)
2072    }
2073
2074    /// Allocate the persistent ping-pong staging and event state for a two-rank replicated-row
2075    /// all-reduce. The caller owns one instance per concurrently live collective sequence.
2076    pub fn prepare_tp2_replicated_row_join(
2077        &self,
2078        width: usize,
2079    ) -> Result<Tp2ReplicatedRowJoin, Box<dyn std::error::Error>> {
2080        validate_tp2_replicated_row_join(self.ranks.len(), self.native_p2p, width)?;
2081        let rank0 = &self.ranks[0];
2082        let rank1 = &self.ranks[1];
2083
2084        let (stage0, stage0_raw, event0) = {
2085            let _main = rank0.gpu.enter_main()?;
2086            let stage = [rank0.zeros(width)?, rank0.zeros(width)?];
2087            let stream = rank0.gpu.stream();
2088            let raw = [
2089                stage[0].device_ptr(&stream).0,
2090                stage[1].device_ptr(&stream).0,
2091            ];
2092            let events = [rank0.ctx().new_event(None)?, rank0.ctx().new_event(None)?];
2093            (stage, raw, events)
2094        };
2095        let (stage1, stage1_raw, event1) = {
2096            let _main = rank1.gpu.enter_main()?;
2097            let stage = [rank1.zeros(width)?, rank1.zeros(width)?];
2098            let stream = rank1.gpu.stream();
2099            let raw = [
2100                stage[0].device_ptr(&stream).0,
2101                stage[1].device_ptr(&stream).0,
2102            ];
2103            let events = [rank1.ctx().new_event(None)?, rank1.ctx().new_event(None)?];
2104            (stage, raw, events)
2105        };
2106        Ok(Tp2ReplicatedRowJoin {
2107            width,
2108            parity: 0,
2109            stage0,
2110            stage1,
2111            stage0_raw,
2112            stage1_raw,
2113            event0,
2114            event1,
2115        })
2116    }
2117
2118    /// Sum one rank-local partial from each of two ranks and publish the same canonical
2119    /// `(rank0 + rank1)` row on both devices. The method only enqueues work; subsequent work on
2120    /// each rank's stream consumes its corresponding output without a host fence.
2121    pub fn tp2_replicated_row_join(
2122        &self,
2123        join: &mut Tp2ReplicatedRowJoin,
2124        partial0: &CudaSlice<f32>,
2125        partial1: &CudaSlice<f32>,
2126        output0: &mut CudaSlice<f32>,
2127        output1: &mut CudaSlice<f32>,
2128    ) -> Result<(), Box<dyn std::error::Error>> {
2129        validate_tp2_replicated_row_join(self.ranks.len(), self.native_p2p, join.width)?;
2130        let rank0 = &self.ranks[0];
2131        let rank1 = &self.ranks[1];
2132        let width = join.width;
2133        if partial0.len() < width
2134            || partial1.len() < width
2135            || output0.len() < width
2136            || output1.len() < width
2137            || partial0.ordinal() != rank0.ctx().ordinal()
2138            || output0.ordinal() != rank0.ctx().ordinal()
2139            || partial1.ordinal() != rank1.ctx().ordinal()
2140            || output1.ordinal() != rank1.ctx().ordinal()
2141        {
2142            return Err("replicated-row join buffer geometry or ownership mismatch".into());
2143        }
2144
2145        let parity = join.parity;
2146        {
2147            let _main = rank0.gpu.enter_main()?;
2148            launch_tp2_peer_push(rank0, partial0, join.stage1_raw[parity], width)?;
2149            join.event0[parity].record(&rank0.gpu.stream())?;
2150        }
2151        {
2152            let _main = rank1.gpu.enter_main()?;
2153            launch_tp2_peer_push(rank1, partial1, join.stage0_raw[parity], width)?;
2154            join.event1[parity].record(&rank1.gpu.stream())?;
2155        }
2156        {
2157            let _main = rank0.gpu.enter_main()?;
2158            rank0.gpu.stream().wait(&join.event1[parity])?;
2159            rank0.add(partial0, &join.stage0[parity], output0, width)?;
2160        }
2161        {
2162            let _main = rank1.gpu.enter_main()?;
2163            rank1.gpu.stream().wait(&join.event0[parity])?;
2164            rank1.add(&join.stage1[parity], partial1, output1, width)?;
2165        }
2166        join.parity ^= 1;
2167        Ok(())
2168    }
2169
2170    pub fn allocate_tp_kv_cache(
2171        &self,
2172        kv_dim_k: usize,
2173        kv_dim_v: usize,
2174        capacity: usize,
2175    ) -> Result<ResidentTpKvCache, Box<dyn std::error::Error>> {
2176        self.allocate_tp_kv_cache_inner(kv_dim_k, kv_dim_v, capacity, None)
2177    }
2178
2179    pub fn allocate_tp_swa_kv_cache(
2180        &self,
2181        kv_dim_k: usize,
2182        kv_dim_v: usize,
2183        capacity: usize,
2184        window: usize,
2185    ) -> Result<ResidentTpKvCache, Box<dyn std::error::Error>> {
2186        if window == 0 {
2187            return Err("TP SWA KV window must be nonzero".into());
2188        }
2189        self.allocate_tp_kv_cache_inner(kv_dim_k, kv_dim_v, capacity, Some(window))
2190    }
2191
2192    fn allocate_tp_kv_cache_inner(
2193        &self,
2194        kv_dim_k: usize,
2195        kv_dim_v: usize,
2196        capacity: usize,
2197        window: Option<usize>,
2198    ) -> Result<ResidentTpKvCache, Box<dyn std::error::Error>> {
2199        if capacity == 0 || capacity > i32::MAX as usize {
2200            return Err(
2201                format!("TP KV capacity must be in 1..={}, got {capacity}", i32::MAX).into(),
2202            );
2203        }
2204        let tp = self.ranks.len();
2205        let shape = crate::cache::tp_kv_rank_allocation_shape(kv_dim_k, kv_dim_v, tp)?;
2206        let physical_rows = window
2207            .map(|window| crate::cache::swa_ring_rows(window, capacity))
2208            .unwrap_or(capacity);
2209        let k_plane_bytes = physical_rows
2210            .checked_mul(shape.k_token_bytes)
2211            .and_then(|bytes| bytes.checked_add(8))
2212            .ok_or("TP KV K plane-byte overflow")?;
2213        let v_plane_bytes = physical_rows
2214            .checked_mul(shape.v_token_bytes)
2215            .and_then(|bytes| bytes.checked_add(8))
2216            .ok_or("TP KV V plane-byte overflow")?;
2217        let mut ranks = Vec::with_capacity(tp);
2218        for engine in &self.ranks {
2219            let _main = engine.gpu.enter_main()?;
2220            ranks.push(ResidentTpKvCacheRank::new(
2221                engine.alloc_u8(k_plane_bytes)?,
2222                engine.alloc_u8(v_plane_bytes)?,
2223                engine.htod_i32(&[0])?,
2224            ));
2225        }
2226        Ok(match window {
2227            Some(window) => ResidentTpKvCache::new_swa(
2228                ranks,
2229                shape.kv_dim_k,
2230                shape.kv_dim_v,
2231                shape.k_token_bytes,
2232                shape.v_token_bytes,
2233                capacity,
2234                window,
2235            ),
2236            None => ResidentTpKvCache::new(
2237                ranks,
2238                shape.kv_dim_k,
2239                shape.kv_dim_v,
2240                shape.k_token_bytes,
2241                shape.v_token_bytes,
2242                capacity,
2243            ),
2244        })
2245    }
2246
2247    pub fn grow_tp_kv_cache(
2248        &self,
2249        source: &ResidentTpKvCache,
2250        target_capacity: usize,
2251        rows: usize,
2252    ) -> Result<ResidentTpKvCache, Box<dyn std::error::Error>> {
2253        self.validate_tp_kv_cache(source)?;
2254        let plan = source.prepare_grow(target_capacity, rows)?;
2255        let ranks = self.ranks.len();
2256        let global_k = source
2257            .kv_dim_k()
2258            .checked_mul(ranks)
2259            .ok_or("TP KV grow global K dimension overflow")?;
2260        let global_v = source
2261            .kv_dim_v()
2262            .checked_mul(ranks)
2263            .ok_or("TP KV grow global V dimension overflow")?;
2264        let mut target = match source.ring_window() {
2265            Some(window) => {
2266                self.allocate_tp_swa_kv_cache(global_k, global_v, target_capacity, window)?
2267            }
2268            None => self.allocate_tp_kv_cache(global_k, global_v, target_capacity)?,
2269        };
2270        self.validate_tp_kv_cache(&target)?;
2271
2272        for (rank, engine) in self.ranks.iter().enumerate() {
2273            let _main = engine.gpu.enter_main()?;
2274            let src = source
2275                .rank(rank)
2276                .ok_or_else(|| format!("TP KV grow source has no rank {rank}"))?;
2277            let dst = target
2278                .rank_mut(rank)
2279                .ok_or_else(|| format!("TP KV grow target has no rank {rank}"))?;
2280            if plan.k_bytes() > 0 {
2281                engine.copy_u8_range_into(
2282                    dst.k_mut(),
2283                    0,
2284                    src.k(),
2285                    plan.source_row() * source.k_tok_bytes(),
2286                    plan.k_bytes(),
2287                )?;
2288            }
2289            if plan.v_bytes() > 0 {
2290                engine.copy_u8_range_into(
2291                    dst.v_mut(),
2292                    0,
2293                    src.v(),
2294                    plan.source_row() * source.v_tok_bytes(),
2295                    plan.v_bytes(),
2296                )?;
2297            }
2298        }
2299        self.set_tp_kv_len_mirrors(&mut target, plan.rows())?;
2300
2301        // The caller publishes `target` and immediately drops `source`. Drain every rank's
2302        // stream so an async-pool free cannot recycle a source plane under an in-flight D2D copy.
2303        for engine in &self.ranks {
2304            let _main = engine.gpu.enter_main()?;
2305            engine.stream().synchronize()?;
2306        }
2307        let physical_copy_rows = plan.copy_rows();
2308        target.publish_grow(plan)?;
2309        eprintln!(
2310            "[step-tp-kv-grow] rows={} source_capacity={} target_capacity={} ranks={} \
2311             physical_copy_rows={} ring_window={:?} copy=rank-local-dtod \
2312             rank_streams_synchronized=true generation_preserved=true",
2313            rows,
2314            source.capacity(),
2315            target_capacity,
2316            ranks,
2317            physical_copy_rows,
2318            source.ring_window(),
2319        );
2320        Ok(target)
2321    }
2322
2323    pub fn hydrate_tp_kv_cache(
2324        &self,
2325        cache: &mut ResidentTpKvCache,
2326        rows: usize,
2327        k_rows: &[u8],
2328        v_rows: &[u8],
2329    ) -> Result<(), Box<dyn std::error::Error>> {
2330        self.hydrate_tp_kv_cache_from(cache, rows, 0, k_rows, v_rows)
2331    }
2332
2333    pub fn hydrate_tp_kv_cache_from(
2334        &self,
2335        cache: &mut ResidentTpKvCache,
2336        logical_len: usize,
2337        resident_start: usize,
2338        k_rows: &[u8],
2339        v_rows: &[u8],
2340    ) -> Result<(), Box<dyn std::error::Error>> {
2341        self.validate_tp_kv_cache(cache)?;
2342        if cache.committed_len() != 0 || cache.staged_len() != 0 {
2343            return Err(format!(
2344                "TP KV hydration requires an empty cache, got committed/staged={}/{}",
2345                cache.committed_len(),
2346                cache.staged_len()
2347            )
2348            .into());
2349        }
2350        if resident_start > logical_len || logical_len > cache.capacity() {
2351            return Err(format!(
2352                "TP KV hydration range [{resident_start},{logical_len}) exceeds capacity {}",
2353                cache.capacity(),
2354            )
2355            .into());
2356        }
2357        let rows = logical_len - resident_start;
2358        if rows > cache.physical_capacity() {
2359            return Err(format!(
2360                "TP KV hydration rows {rows} exceed physical capacity {}",
2361                cache.physical_capacity()
2362            )
2363            .into());
2364        }
2365        for rank in 0..self.ranks.len() {
2366            let k_rank =
2367                cache_rank_rows(k_rows, rows, cache.k_tok_bytes(), self.ranks.len(), rank)?;
2368            let v_rank =
2369                cache_rank_rows(v_rows, rows, cache.v_tok_bytes(), self.ranks.len(), rank)?;
2370            let engine = &self.ranks[rank];
2371            let _main = engine.gpu.enter_main()?;
2372            let rank_cache = cache
2373                .rank_mut(rank)
2374                .ok_or_else(|| format!("TP KV cache has no rank {rank}"))?;
2375            engine.htod_u8_into(rank_cache.k_mut(), 0, &k_rank)?;
2376            engine.htod_u8_into(rank_cache.v_mut(), 0, &v_rank)?;
2377        }
2378        cache.publish_hydration(logical_len, resident_start)?;
2379        Ok(())
2380    }
2381
2382    /// Restore rows retained from a speculative verify walk into an already-live distributed
2383    /// cache. The verify oracle appends canonical full-width quantized K/V rows on the model
2384    /// device. Each destination rank pulls its own contiguous KV-head slice over native P2P; its
2385    /// length mirror is published on that same rank stream after every row copy.
2386    #[allow(clippy::too_many_arguments)]
2387    pub fn restore_tp_kv_rows_from_device(
2388        &self,
2389        cache: &mut ResidentTpKvCache,
2390        start: usize,
2391        logical_len: usize,
2392        source_k_raw: u64,
2393        source_v_raw: u64,
2394        source_k_tok_bytes: usize,
2395        source_v_tok_bytes: usize,
2396    ) -> Result<(), Box<dyn std::error::Error>> {
2397        self.validate_tp_kv_cache(cache)?;
2398        if cache.committed_len() != cache.staged_len() {
2399            return Err(format!(
2400                "TP KV verify restore requires quiescent state, got committed/staged={}/{}",
2401                cache.committed_len(),
2402                cache.staged_len()
2403            )
2404            .into());
2405        }
2406        if start > logical_len || logical_len > cache.capacity() {
2407            return Err(format!(
2408                "TP KV verify restore range [{start},{logical_len}) exceeds capacity {}",
2409                cache.capacity()
2410            )
2411            .into());
2412        }
2413        let rows = logical_len - start;
2414        let physical = cache.physical_range(start, logical_len)?;
2415        if physical.len() != rows {
2416            return Err(format!(
2417                "TP KV verify restore range [{start},{logical_len}) is not physically contiguous"
2418            )
2419            .into());
2420        }
2421        let ranks = self.ranks.len();
2422        let k_tok_bytes = cache.k_tok_bytes();
2423        let v_tok_bytes = cache.v_tok_bytes();
2424        if source_k_tok_bytes != k_tok_bytes * ranks || source_v_tok_bytes != v_tok_bytes * ranks {
2425            return Err(format!(
2426                "TP KV verify source token bytes k={source_k_tok_bytes} v={source_v_tok_bytes} \
2427                 do not match distributed k={}x{ranks} v={}x{ranks}",
2428                k_tok_bytes, v_tok_bytes
2429            )
2430            .into());
2431        }
2432        for rank in 0..self.ranks.len() {
2433            let engine = &self.ranks[rank];
2434            let _main = engine.gpu.enter_main()?;
2435            use cudarc::driver::DevicePtr;
2436            let stream = engine.stream();
2437            let k_offset = physical
2438                .start
2439                .checked_mul(k_tok_bytes)
2440                .ok_or("TP KV verify K offset overflow")?;
2441            let v_offset = physical
2442                .start
2443                .checked_mul(v_tok_bytes)
2444                .ok_or("TP KV verify V offset overflow")?;
2445            let rank_cache = cache
2446                .rank_mut(rank)
2447                .ok_or_else(|| format!("TP KV cache has no rank {rank}"))?;
2448            let k_dst = {
2449                let (pointer, _guard) = rank_cache.k_mut().device_ptr(&stream);
2450                pointer
2451            };
2452            let v_dst = {
2453                let (pointer, _guard) = rank_cache.v_mut().device_ptr(&stream);
2454                pointer
2455            };
2456            for row in 0..rows {
2457                let k_src = source_k_raw + (row * source_k_tok_bytes + rank * k_tok_bytes) as u64;
2458                let v_src = source_v_raw + (row * source_v_tok_bytes + rank * v_tok_bytes) as u64;
2459                let k_out = k_dst + (k_offset + row * k_tok_bytes) as u64;
2460                let v_out = v_dst + (v_offset + row * v_tok_bytes) as u64;
2461                raw_copy_bytes(k_out, k_src, k_tok_bytes, engine)?;
2462                raw_copy_bytes(v_out, v_src, v_tok_bytes, engine)?;
2463            }
2464        }
2465        cache.rewind_to(logical_len)?;
2466        Ok(())
2467    }
2468
2469    /// Batch the accepted verify rows of every uniform TP-attention layer into one kernel per
2470    /// rank. Returns `false` before enqueueing anything when the layer group is not uniform, so
2471    /// the caller can use the existing per-layer repair without splitting semantics.
2472    pub fn restore_tp_kv_layers_from_device(
2473        &self,
2474        layers: &mut [TpKvVerifiedLayer<'_>],
2475    ) -> Result<bool, Box<dyn std::error::Error>> {
2476        let Some(first) = layers.first() else {
2477            return Ok(false);
2478        };
2479        if !self.native_p2p || first.start >= first.logical_len {
2480            return Ok(false);
2481        }
2482        let ranks = self.ranks.len();
2483        let rows = first.logical_len - first.start;
2484        let logical_len = first.logical_len;
2485        let k_row_bytes = first.cache.k_tok_bytes();
2486        let v_row_bytes = first.cache.v_tok_bytes();
2487        let k_src_stride = first.source_k_tok_bytes;
2488        let v_src_stride = first.source_v_tok_bytes;
2489        let Some(expected_k_stride) = k_row_bytes.checked_mul(ranks) else {
2490            return Ok(false);
2491        };
2492        let Some(expected_v_stride) = v_row_bytes.checked_mul(ranks) else {
2493            return Ok(false);
2494        };
2495        if k_src_stride != expected_k_stride || v_src_stride != expected_v_stride {
2496            return Ok(false);
2497        }
2498
2499        for layer in layers.iter() {
2500            self.validate_tp_kv_cache(layer.cache)?;
2501            if layer.cache.committed_len() != layer.cache.staged_len()
2502                || layer.start > layer.logical_len
2503                || layer.logical_len != logical_len
2504                || layer.logical_len - layer.start != rows
2505                || layer.cache.k_tok_bytes() != k_row_bytes
2506                || layer.cache.v_tok_bytes() != v_row_bytes
2507                || layer.source_k_tok_bytes != k_src_stride
2508                || layer.source_v_tok_bytes != v_src_stride
2509            {
2510                return Ok(false);
2511            }
2512            let physical = layer.cache.physical_range(layer.start, layer.logical_len)?;
2513            if physical.len() != rows {
2514                return Ok(false);
2515            }
2516        }
2517
2518        for rank in 0..ranks {
2519            let engine = &self.ranks[rank];
2520            let _main = engine.gpu.enter_main()?;
2521            let stream = engine.stream();
2522            let n = layers.len();
2523            let mut table = vec![0u64; 5 * n];
2524            for (index, layer) in layers.iter_mut().enumerate() {
2525                let physical = layer.cache.physical_range(layer.start, layer.logical_len)?;
2526                let rank_cache = layer
2527                    .cache
2528                    .rank_mut(rank)
2529                    .ok_or_else(|| format!("TP KV cache has no rank {rank}"))?;
2530                table[index] = layer.source_k_raw + (rank * k_row_bytes) as u64;
2531                table[n + index] = layer.source_v_raw + (rank * v_row_bytes) as u64;
2532                table[2 * n + index] = rank_cache.k_mut().device_ptr(&stream).0
2533                    + (physical.start * k_row_bytes) as u64;
2534                table[3 * n + index] = rank_cache.v_mut().device_ptr(&stream).0
2535                    + (physical.start * v_row_bytes) as u64;
2536                table[4 * n + index] = rank_cache.len_d_mut().device_ptr(&stream).0;
2537            }
2538            let table = engine.htod_u64(&table)?;
2539            engine.copy_batch_uniform_kv_u8_set_len(
2540                &table,
2541                n,
2542                rows,
2543                k_row_bytes,
2544                v_row_bytes,
2545                k_src_stride,
2546                v_src_stride,
2547                logical_len,
2548            )?;
2549        }
2550        let layer_count = layers.len();
2551        for layer in layers.iter_mut() {
2552            layer.cache.publish_device_rewind(logical_len)?;
2553        }
2554        static ANNOUNCED: std::sync::Once = std::sync::Once::new();
2555        ANNOUNCED.call_once(|| {
2556            eprintln!(
2557                "[tp-kv-verify-batch] engaged: layers={} ranks={ranks} rows={rows} \
2558                 k_row_bytes={k_row_bytes} v_row_bytes={v_row_bytes}",
2559                layer_count
2560            );
2561        });
2562        Ok(true)
2563    }
2564
2565    pub fn append_tp_kv_transaction(
2566        &self,
2567        cache: &mut ResidentTpKvCache,
2568        transaction: TpKvTransaction,
2569        k_shards: &[CudaSlice<f32>],
2570        v_shards: &[CudaSlice<f32>],
2571        rows: usize,
2572    ) -> Result<(), Box<dyn std::error::Error>> {
2573        self.append_tp_kv_transaction_inner(cache, transaction, k_shards, v_shards, rows, false)
2574    }
2575
2576    /// `external_rank_appends`: the dcw path already wrote the rank rows (device-counter
2577    /// append) — run everything EXCEPT the per-rank quantize/append loop (plan validation,
2578    /// rebase arm — unreachable when the caller peeked — and the absolute len-mirror sets,
2579    /// which land the same value the in-stream inc produced).
2580    #[allow(clippy::too_many_arguments)]
2581    pub fn append_tp_kv_transaction_inner(
2582        &self,
2583        cache: &mut ResidentTpKvCache,
2584        transaction: TpKvTransaction,
2585        k_shards: &[CudaSlice<f32>],
2586        v_shards: &[CudaSlice<f32>],
2587        rows: usize,
2588        external_rank_appends: bool,
2589    ) -> Result<(), Box<dyn std::error::Error>> {
2590        self.validate_tp_kv_cache(cache)?;
2591        let plan = cache.prepare_append(transaction, rows)?;
2592        let target = plan.target();
2593        let expected_k = rows
2594            .checked_mul(cache.kv_dim_k())
2595            .ok_or("TP KV K append size overflow")?;
2596        let expected_v = rows
2597            .checked_mul(cache.kv_dim_v())
2598            .ok_or("TP KV V append size overflow")?;
2599        // external_rank_appends passes no shards — the graph's dcw appends already wrote
2600        // the rank rows, so this call is bookkeeping-only and the shard slices are unused.
2601        if !external_rank_appends
2602            && (k_shards.len() != self.ranks.len() || v_shards.len() != self.ranks.len())
2603        {
2604            return Err(format!(
2605                "TP KV append shard counts k={} v={} != ranks {}",
2606                k_shards.len(),
2607                v_shards.len(),
2608                self.ranks.len()
2609            )
2610            .into());
2611        }
2612        let kv_dim_k = cache.kv_dim_k();
2613        let kv_dim_v = cache.kv_dim_v();
2614        let k_tok_bytes = cache.k_tok_bytes();
2615        let v_tok_bytes = cache.v_tok_bytes();
2616        if let Some(ring_base) = cache.ring_base() {
2617            let base_val = ring_base as i32;
2618            for rank in 0..self.ranks.len() {
2619                let engine = &self.ranks[rank];
2620                let _main = engine.gpu.enter_main()?;
2621                let rank_cache = cache
2622                    .rank_mut(rank)
2623                    .ok_or_else(|| format!("TP KV cache has no rank {rank}"))?;
2624                if rank_cache.base_d().is_none() {
2625                    rank_cache.arm_base_d(engine.htod_i32(&[base_val])?);
2626                }
2627            }
2628        }
2629        if let Some(KvRingAppend::Rebase {
2630            src_row,
2631            keep_rows,
2632            new_base,
2633            ..
2634        }) = plan.ring_append()
2635        {
2636            for rank in 0..self.ranks.len() {
2637                let engine = &self.ranks[rank];
2638                let _main = engine.gpu.enter_main()?;
2639                let rank_cache = cache
2640                    .rank_mut(rank)
2641                    .ok_or_else(|| format!("TP KV cache has no rank {rank}"))?;
2642                if keep_rows > 0 {
2643                    let k_len = keep_rows
2644                        .checked_mul(k_tok_bytes)
2645                        .ok_or("TP KV K rebase-byte overflow")?;
2646                    let v_len = keep_rows
2647                        .checked_mul(v_tok_bytes)
2648                        .ok_or("TP KV V rebase-byte overflow")?;
2649                    let mut k_tmp = engine.alloc_u8_uninit(k_len)?;
2650                    let mut v_tmp = engine.alloc_u8_uninit(v_len)?;
2651                    engine.copy_u8_range_into(
2652                        &mut k_tmp,
2653                        0,
2654                        rank_cache.k(),
2655                        src_row * k_tok_bytes,
2656                        k_len,
2657                    )?;
2658                    engine.copy_u8_range_into(
2659                        &mut v_tmp,
2660                        0,
2661                        rank_cache.v(),
2662                        src_row * v_tok_bytes,
2663                        v_len,
2664                    )?;
2665                    engine.copy_u8_into(rank_cache.k_mut(), 0, &k_tmp, k_len)?;
2666                    engine.copy_u8_into(rank_cache.v_mut(), 0, &v_tmp, v_len)?;
2667                }
2668                // dcw base mirror (graph increment A): physical row 0 now holds logical
2669                // row `new_base`; armed device mirrors track it (rebases are rare host
2670                // events, so a host set here is the whole maintenance cost).
2671                let value = new_base as i32;
2672                if let Some(base_d) = rank_cache.base_d_mut() {
2673                    engine.set_i32_one(base_d, value)?;
2674                } else {
2675                    rank_cache.arm_base_d(engine.htod_i32(&[value])?);
2676                }
2677            }
2678        }
2679        cache.publish_append_rebase(plan)?;
2680        let write_row = plan.write_row();
2681        for rank in 0..self.ranks.len() {
2682            if external_rank_appends {
2683                break;
2684            }
2685            let engine = &self.ranks[rank];
2686            let _main = engine.gpu.enter_main()?;
2687            if k_shards[rank].len() != expected_k
2688                || v_shards[rank].len() != expected_v
2689                || k_shards[rank].ordinal() != engine.ctx().ordinal()
2690                || v_shards[rank].ordinal() != engine.ctx().ordinal()
2691            {
2692                return Err(format!(
2693                    "TP KV rank {rank} shard geometry/device k={}/{} v={}/{} \
2694                     != expected {expected_k}/{expected_v} on device {}",
2695                    k_shards[rank].len(),
2696                    k_shards[rank].ordinal(),
2697                    v_shards[rank].len(),
2698                    v_shards[rank].ordinal(),
2699                    engine.ctx().ordinal(),
2700                )
2701                .into());
2702            }
2703            let rank_cache = cache
2704                .rank_mut(rank)
2705                .ok_or_else(|| format!("TP KV cache has no rank {rank}"))?;
2706            let (rank_k, rank_v) = rank_cache.planes_mut();
2707            engine.append_kv_quantized_rows(
2708                &k_shards[rank],
2709                &v_shards[rank],
2710                rank_k,
2711                rank_v,
2712                write_row,
2713                rows,
2714                kv_dim_k,
2715                kv_dim_v,
2716                k_tok_bytes,
2717                v_tok_bytes,
2718                false,
2719            )?;
2720        }
2721        if !external_rank_appends {
2722            // dcw appends advance the device counters with in-stream inc_i32; an absolute set
2723            // here would race the merged per-rank append (it reads len_d for its write row).
2724            self.set_tp_kv_len_mirrors(cache, target)?;
2725        }
2726        cache.publish_append_plan(plan)?;
2727        Ok(())
2728    }
2729
2730    pub fn commit_tp_kv_transaction(
2731        &self,
2732        cache: &mut ResidentTpKvCache,
2733        transaction: TpKvTransaction,
2734        accepted_rows: usize,
2735    ) -> Result<(), Box<dyn std::error::Error>> {
2736        self.validate_tp_kv_cache(cache)?;
2737        let target = cache.commit_target(transaction, accepted_rows)?;
2738        self.set_tp_kv_len_mirrors(cache, target)?;
2739        cache.publish_finalize(transaction, target)?;
2740        // This path derived the rank rows from the canonical rows, so a later restore from
2741        // the canonical cache is at worst redundant. See `rows_external`.
2742        cache.mark_rows_external(false);
2743        Ok(())
2744    }
2745
2746    /// Commit for the external-appends (token graph) path: host bookkeeping only, NO absolute
2747    /// len-mirror sets. The graph's in-stream inc_i32 owns the device counters; a rank-stream
2748    /// set here has no ordering edge against the NEXT token's graph launch (graph children do
2749    /// not wait on the rank streams), so it can land AFTER that graph's inc and drag the
2750    /// counter backward mid-token.
2751    pub fn commit_tp_kv_transaction_external(
2752        &self,
2753        cache: &mut ResidentTpKvCache,
2754        transaction: TpKvTransaction,
2755        accepted_rows: usize,
2756    ) -> Result<(), Box<dyn std::error::Error>> {
2757        self.validate_tp_kv_cache(cache)?;
2758        let target = cache.commit_target(transaction, accepted_rows)?;
2759        cache.publish_finalize(transaction, target)?;
2760        // The rank rows were written on-device by the caller (dcw / fa2 verify); the
2761        // canonical model-device cache only had its length advanced and holds stale content
2762        // for these rows. A verified-prefix restore must skip this layer (memra#128).
2763        cache.mark_rows_external(true);
2764        Ok(())
2765    }
2766
2767    pub fn rollback_tp_kv_transaction(
2768        &self,
2769        cache: &mut ResidentTpKvCache,
2770        transaction: TpKvTransaction,
2771    ) -> Result<(), Box<dyn std::error::Error>> {
2772        self.validate_tp_kv_cache(cache)?;
2773        cache.validate_transaction(transaction)?;
2774        let target = transaction.base_len();
2775        self.set_tp_kv_len_mirrors(cache, target)?;
2776        cache.publish_finalize(transaction, target)?;
2777        Ok(())
2778    }
2779
2780    pub fn tp_kv_device_lengths(
2781        &self,
2782        cache: &ResidentTpKvCache,
2783    ) -> Result<Vec<i32>, Box<dyn std::error::Error>> {
2784        self.validate_tp_kv_cache(cache)?;
2785        let mut lengths = Vec::with_capacity(self.ranks.len());
2786        for (engine, rank_cache) in self.ranks.iter().zip(cache.ranks()) {
2787            let _main = engine.gpu.enter_main()?;
2788            lengths.push(engine.dtoh_i32_one(rank_cache.len_d())?);
2789        }
2790        Ok(lengths)
2791    }
2792
2793    fn set_tp_kv_len_mirrors(
2794        &self,
2795        cache: &mut ResidentTpKvCache,
2796        len: usize,
2797    ) -> Result<(), Box<dyn std::error::Error>> {
2798        let len = i32::try_from(len).map_err(|_| "TP KV length exceeds i32 device mirror")?;
2799        for (engine, rank_cache) in self.ranks.iter().zip(cache.ranks_mut()) {
2800            let _main = engine.gpu.enter_main()?;
2801            engine.set_i32_one(rank_cache.len_d_mut(), len)?;
2802        }
2803        Ok(())
2804    }
2805
2806    fn validate_tp_kv_cache(
2807        &self,
2808        cache: &ResidentTpKvCache,
2809    ) -> Result<(), Box<dyn std::error::Error>> {
2810        if cache.ranks_len() != self.ranks.len() {
2811            return Err(format!(
2812                "TP KV cache ranks {} != runtime ranks {}",
2813                cache.ranks_len(),
2814                self.ranks.len()
2815            )
2816            .into());
2817        }
2818        let expected_k = cache
2819            .physical_capacity()
2820            .checked_mul(cache.k_tok_bytes())
2821            .and_then(|bytes| bytes.checked_add(8))
2822            .ok_or("TP KV K plane validation overflow")?;
2823        let expected_v = cache
2824            .physical_capacity()
2825            .checked_mul(cache.v_tok_bytes())
2826            .and_then(|bytes| bytes.checked_add(8))
2827            .ok_or("TP KV V plane validation overflow")?;
2828        for (rank, (engine, rank_cache)) in self.ranks.iter().zip(cache.ranks()).enumerate() {
2829            let device = engine.ctx().ordinal();
2830            if rank_cache.k().len() != expected_k
2831                || rank_cache.v().len() != expected_v
2832                || rank_cache.len_d().len() != 1
2833                || rank_cache.k().ordinal() != device
2834                || rank_cache.v().ordinal() != device
2835                || rank_cache.len_d().ordinal() != device
2836            {
2837                return Err(format!(
2838                    "TP KV rank {rank} residency does not match device {device} or plane geometry"
2839                )
2840                .into());
2841            }
2842        }
2843        Ok(())
2844    }
2845
2846    pub fn full(
2847        &self,
2848        matrix: E4m3BlockMatrix<'_>,
2849        activations: &[f32],
2850        tokens: usize,
2851    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
2852        matrix.validate()?;
2853        validate_activations(activations, tokens, matrix.in_features)?;
2854        run_rank(&self.ranks[0], matrix, activations, tokens)
2855    }
2856
2857    /// Column-parallel projection. Weight output rows and their scale rows are partitioned across
2858    /// ranks. The input is host-broadcast, rank-local projections execute independently, and the
2859    /// output is host-gathered in rank order.
2860    #[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
2861    pub fn column_parallel(
2862        &self,
2863        matrix: E4m3BlockMatrix<'_>,
2864        activations: &[f32],
2865        tokens: usize,
2866    ) -> Result<ColumnParallelResult, Box<dyn std::error::Error>> {
2867        matrix.validate()?;
2868        validate_activations(activations, tokens, matrix.in_features)?;
2869        let tp = self.ranks.len();
2870        if matrix.out_features % tp != 0 {
2871            return Err(format!(
2872                "column-parallel out_features {} is not divisible by TP={tp}",
2873                matrix.out_features
2874            )
2875            .into());
2876        }
2877        let local_out = matrix.out_features / tp;
2878        if !local_out.is_multiple_of(FP8_BLOCK) {
2879            return Err(format!(
2880                "column-parallel output shard {local_out} cuts through a {FP8_BLOCK}-row \
2881                 E4M3 scale block"
2882            )
2883            .into());
2884        }
2885
2886        let mut gathered = vec![0.0f32; tokens * matrix.out_features];
2887        let mut rank_outputs = Vec::with_capacity(tp);
2888        for (rank_index, rank) in self.ranks.iter().enumerate() {
2889            let shard = column_shard(matrix, tp, rank_index)?;
2890            let output = run_rank(rank, shard, activations, tokens)?;
2891            let row_start = rank_index * local_out;
2892            for token in 0..tokens {
2893                gathered[token * matrix.out_features + row_start
2894                    ..token * matrix.out_features + row_start + local_out]
2895                    .copy_from_slice(&output[token * local_out..(token + 1) * local_out]);
2896            }
2897            rank_outputs.push(output);
2898        }
2899        Ok(ColumnParallelResult {
2900            gathered,
2901            rank_outputs,
2902        })
2903    }
2904
2905    pub fn upload_column_parallel(
2906        &self,
2907        matrix: E4m3BlockMatrix<'_>,
2908    ) -> Result<ResidentColumnParallel, Box<dyn std::error::Error>> {
2909        matrix.validate()?;
2910        let tp = self.ranks.len();
2911        validate_column_shape(matrix, tp)?;
2912        let mut ranks = Vec::with_capacity(tp);
2913        for (rank_index, engine) in self.ranks.iter().enumerate() {
2914            ranks.push(upload_rank(engine, column_shard(matrix, tp, rank_index)?)?);
2915        }
2916        Ok(ResidentColumnParallel {
2917            ranks,
2918            out_features: matrix.out_features,
2919            in_features: matrix.in_features,
2920        })
2921    }
2922
2923    pub fn column_parallel_resident(
2924        &self,
2925        matrix: &ResidentColumnParallel,
2926        activations: &[f32],
2927        tokens: usize,
2928    ) -> Result<ColumnParallelResult, Box<dyn std::error::Error>> {
2929        validate_resident_ranks(&self.ranks, &matrix.ranks)?;
2930        validate_activations(activations, tokens, matrix.in_features)?;
2931        let local_out = matrix.out_features / self.ranks.len();
2932        let mut gathered = vec![0.0f32; tokens * matrix.out_features];
2933        let mut rank_outputs = Vec::with_capacity(self.ranks.len());
2934        for (rank_index, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
2935            let output = run_resident_rank(engine, shard, activations, tokens)?;
2936            let row_start = rank_index * local_out;
2937            for token in 0..tokens {
2938                gathered[token * matrix.out_features + row_start
2939                    ..token * matrix.out_features + row_start + local_out]
2940                    .copy_from_slice(&output[token * local_out..(token + 1) * local_out]);
2941            }
2942            rank_outputs.push(output);
2943        }
2944        Ok(ColumnParallelResult {
2945            gathered,
2946            rank_outputs,
2947        })
2948    }
2949
2950    /// Row-parallel projection. Weight/input columns and their scale columns are partitioned
2951    /// across ranks. Rank-local partials return through host memory and are reduced in stable
2952    /// rank order.
2953    #[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
2954    pub fn row_parallel(
2955        &self,
2956        matrix: E4m3BlockMatrix<'_>,
2957        activations: &[f32],
2958        tokens: usize,
2959    ) -> Result<RowParallelResult, Box<dyn std::error::Error>> {
2960        matrix.validate()?;
2961        validate_activations(activations, tokens, matrix.in_features)?;
2962        let tp = self.ranks.len();
2963        if matrix.in_features % tp != 0 {
2964            return Err(format!(
2965                "row-parallel in_features {} is not divisible by TP={tp}",
2966                matrix.in_features
2967            )
2968            .into());
2969        }
2970        let local_in = matrix.in_features / tp;
2971        if !local_in.is_multiple_of(FP8_BLOCK) {
2972            return Err(format!(
2973                "row-parallel input shard {local_in} cuts through a {FP8_BLOCK}-column \
2974                 E4M3 scale block"
2975            )
2976            .into());
2977        }
2978
2979        let mut reduced = vec![0.0f32; tokens * matrix.out_features];
2980        let mut rank_partials = Vec::with_capacity(tp);
2981        for (rank_index, rank) in self.ranks.iter().enumerate() {
2982            let (codes, scales) = row_shard(matrix, tp, rank_index)?;
2983            let local_activations =
2984                activation_shard(activations, tokens, matrix.in_features, tp, rank_index);
2985            let shard = E4m3BlockMatrix {
2986                codes: &codes,
2987                scales: &scales,
2988                out_features: matrix.out_features,
2989                in_features: local_in,
2990            };
2991            let partial = run_rank(rank, shard, &local_activations, tokens)?;
2992            for (sum, value) in reduced.iter_mut().zip(&partial) {
2993                *sum += *value;
2994            }
2995            rank_partials.push(partial);
2996        }
2997        Ok(RowParallelResult {
2998            reduced,
2999            rank_partials,
3000        })
3001    }
3002
3003    pub fn upload_row_parallel(
3004        &self,
3005        matrix: E4m3BlockMatrix<'_>,
3006    ) -> Result<ResidentRowParallel, Box<dyn std::error::Error>> {
3007        matrix.validate()?;
3008        let tp = self.ranks.len();
3009        validate_row_shape(matrix, tp)?;
3010        let local_in = matrix.in_features / tp;
3011        let mut ranks = Vec::with_capacity(tp);
3012        for (rank_index, engine) in self.ranks.iter().enumerate() {
3013            let (codes, scales) = row_shard(matrix, tp, rank_index)?;
3014            ranks.push(upload_rank(
3015                engine,
3016                E4m3BlockMatrix {
3017                    codes: &codes,
3018                    scales: &scales,
3019                    out_features: matrix.out_features,
3020                    in_features: local_in,
3021                },
3022            )?);
3023        }
3024        Ok(ResidentRowParallel {
3025            ranks,
3026            out_features: matrix.out_features,
3027            in_features: matrix.in_features,
3028        })
3029    }
3030
3031    pub fn row_parallel_resident(
3032        &self,
3033        matrix: &ResidentRowParallel,
3034        activations: &[f32],
3035        tokens: usize,
3036    ) -> Result<RowParallelResult, Box<dyn std::error::Error>> {
3037        validate_resident_ranks(&self.ranks, &matrix.ranks)?;
3038        validate_activations(activations, tokens, matrix.in_features)?;
3039        let tp = self.ranks.len();
3040        let mut reduced = vec![0.0f32; tokens * matrix.out_features];
3041        let mut rank_partials = Vec::with_capacity(tp);
3042        for (rank_index, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
3043            let local_activations =
3044                activation_shard(activations, tokens, matrix.in_features, tp, rank_index);
3045            let partial = run_resident_rank(engine, shard, &local_activations, tokens)?;
3046            for (sum, value) in reduced.iter_mut().zip(&partial) {
3047                *sum += *value;
3048            }
3049            rank_partials.push(partial);
3050        }
3051        Ok(RowParallelResult {
3052            reduced,
3053            rank_partials,
3054        })
3055    }
3056
3057    pub fn upload_bf16_column_parallel(
3058        &self,
3059        matrix: Bf16Matrix<'_>,
3060    ) -> Result<ResidentBf16ColumnParallel, Box<dyn std::error::Error>> {
3061        self.upload_bf16_column_parallel_inner(matrix, None, false)
3062    }
3063
3064    /// Step-3.7 column projection with one numerical program across TP1/TP2/TP4/TP8.
3065    pub fn upload_step_bf16_column_parallel(
3066        &self,
3067        matrix: Bf16Matrix<'_>,
3068    ) -> Result<ResidentBf16ColumnParallel, Box<dyn std::error::Error>> {
3069        self.upload_step_bf16_column_parallel_inner(matrix, false)
3070    }
3071
3072    /// Load-time exact F32 expansion of a Step BF16 shard.
3073    ///
3074    /// The original BF16 allocation is released after the stream-ordered conversion. Decode then
3075    /// reuses the resident F32 values with the same topology-invariant output-row chunks.
3076    pub fn upload_step_bf16_column_parallel_f32_mirror(
3077        &self,
3078        matrix: Bf16Matrix<'_>,
3079    ) -> Result<ResidentBf16ColumnParallel, Box<dyn std::error::Error>> {
3080        self.upload_step_bf16_column_parallel_inner(matrix, true)
3081    }
3082
3083    fn upload_step_bf16_column_parallel_inner(
3084        &self,
3085        matrix: Bf16Matrix<'_>,
3086        f32_mirror: bool,
3087    ) -> Result<ResidentBf16ColumnParallel, Box<dyn std::error::Error>> {
3088        let canonical_chunk_rows =
3089            step_bf16_canonical_chunk_rows(matrix.out_features, self.ranks.len())?;
3090        self.upload_bf16_column_parallel_inner(matrix, Some(canonical_chunk_rows), f32_mirror)
3091    }
3092
3093    #[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
3094    fn upload_bf16_column_parallel_inner(
3095        &self,
3096        matrix: Bf16Matrix<'_>,
3097        canonical_chunk_rows: Option<usize>,
3098        f32_mirror: bool,
3099    ) -> Result<ResidentBf16ColumnParallel, Box<dyn std::error::Error>> {
3100        matrix.validate()?;
3101        let tp = self.ranks.len();
3102        if matrix.out_features % tp != 0 {
3103            return Err(format!(
3104                "BF16 column-parallel out_features {} is not divisible by TP={tp}",
3105                matrix.out_features
3106            )
3107            .into());
3108        }
3109        let mut ranks = Vec::with_capacity(tp);
3110        for (rank, engine) in self.ranks.iter().enumerate() {
3111            ranks.push(upload_bf16_rank(
3112                engine,
3113                bf16_column_shard(matrix, tp, rank)?,
3114                f32_mirror,
3115            )?);
3116        }
3117        Ok(ResidentBf16ColumnParallel {
3118            ranks,
3119            out_features: matrix.out_features,
3120            in_features: matrix.in_features,
3121            canonical_chunk_rows,
3122        })
3123    }
3124
3125    pub fn bf16_column_parallel_resident(
3126        &self,
3127        matrix: &ResidentBf16ColumnParallel,
3128        activations: &[f32],
3129        tokens: usize,
3130    ) -> Result<ColumnParallelResult, Box<dyn std::error::Error>> {
3131        validate_resident_bf16_ranks(&self.ranks, &matrix.ranks)?;
3132        validate_activations(activations, tokens, matrix.in_features)?;
3133        let local_out = matrix.out_features / self.ranks.len();
3134        let mut gathered = vec![0.0f32; tokens * matrix.out_features];
3135        let mut rank_outputs = Vec::with_capacity(self.ranks.len());
3136        for (rank, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
3137            let output = run_resident_bf16_rank(
3138                engine,
3139                shard,
3140                activations,
3141                tokens,
3142                matrix.canonical_chunk_rows,
3143            )?;
3144            for token in 0..tokens {
3145                let src = &output[token * local_out..(token + 1) * local_out];
3146                let dst_start = token * matrix.out_features + rank * local_out;
3147                gathered[dst_start..dst_start + local_out].copy_from_slice(src);
3148            }
3149            rank_outputs.push(output);
3150        }
3151        Ok(ColumnParallelResult {
3152            gathered,
3153            rank_outputs,
3154        })
3155    }
3156
3157    /// Native-P2P twin of [`Self::bf16_column_parallel_resident`].
3158    ///
3159    /// The host-canonical activation is uploaded once on rank zero and peer-broadcast to the
3160    /// remaining ranks. Rank-local outputs are peer-gathered in token-major order before one root
3161    /// readback. This removes per-rank host staging but deliberately still returns a host oracle;
3162    /// attention and KV ownership are separate milestones.
3163    pub fn bf16_column_parallel_resident_native(
3164        &self,
3165        matrix: &ResidentBf16ColumnParallel,
3166        activations: &[f32],
3167        tokens: usize,
3168    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
3169        let rank_outputs =
3170            self.bf16_column_parallel_resident_device_shards(matrix, activations, tokens)?;
3171        let local_out = matrix.out_features / self.ranks.len();
3172        self.gather_native_column_shards(&rank_outputs, tokens, local_out)
3173    }
3174
3175    /// Does the serving engine live in the SAME CUDA context as this runtime's root rank?
3176    /// The device-resident input/output seams below hand raw device buffers across the
3177    /// Engine boundary, which is only addressable when both sides share the root device's
3178    /// primary context — the generic full-attention TP seam keys its residency dispatch on.
3179    pub fn root_shares_ctx(&self, e: &Engine) -> bool {
3180        self.ranks
3181            .first()
3182            .is_some_and(|root| root.ctx().cu_ctx() == e.ctx().cu_ctx())
3183    }
3184
3185    /// Device-input twin of [`Self::bf16_column_parallel_resident_native`] (lane/
3186    /// hermes-perf-fixes, 2026-08-23 — the step QKV TP host-bounce finding). The activation
3187    /// arrives as a ROOT-DEVICE buffer (first `tokens * in_features` values) instead of a
3188    /// host slice, and the gathered output stays root-resident: no DtoH of the hidden state,
3189    /// no host q/k/v staging, no re-upload. BYTE-IDENTICAL to the host-canonical native arm
3190    /// by construction — the root input bytes are dtod-copied where the host arm htod'd the
3191    /// same bytes, and every kernel, peer copy, and gather order is shared.
3192    ///
3193    /// FENCES: caller must have synchronized the producer stream that wrote
3194    /// `root_activation` (the serving engine's — a DIFFERENT stream in the same context);
3195    /// this method synchronizes the root stream before returning so the caller's stream can
3196    /// consume the gathered output immediately.
3197    pub fn bf16_column_parallel_resident_native_device(
3198        &self,
3199        matrix: &ResidentBf16ColumnParallel,
3200        root_activation: &CudaSlice<f32>,
3201        tokens: usize,
3202    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
3203        let rank_outputs = self.bf16_column_parallel_resident_device_shards_from_root(
3204            matrix,
3205            root_activation,
3206            tokens,
3207        )?;
3208        let local_out = matrix.out_features / self.ranks.len();
3209        let gathered = self.gather_native_column_shards_device(&rank_outputs, tokens, local_out)?;
3210        let root = &self.ranks[0];
3211        let _main = root.gpu.enter_main()?;
3212        root.stream().synchronize()?;
3213        Ok(gathered)
3214    }
3215
3216    /// Root-device-input twin of [`Self::bf16_column_parallel_resident_device_shards`]:
3217    /// the canonical activation is already resident on the root device (len >=
3218    /// `tokens * in_features`; extra tail values beyond the active prefix are ignored,
3219    /// the reused-prime-slab contract of `active_matrix_values`).
3220    pub fn bf16_column_parallel_resident_device_shards_from_root(
3221        &self,
3222        matrix: &ResidentBf16ColumnParallel,
3223        root_activation: &CudaSlice<f32>,
3224        tokens: usize,
3225    ) -> Result<Vec<CudaSlice<f32>>, Box<dyn std::error::Error>> {
3226        if self.ranks.len() > 1 && !self.native_p2p {
3227            return Err("device-resident BF16 column parallelism requires native P2P ranks".into());
3228        }
3229        validate_resident_bf16_ranks(&self.ranks, &matrix.ranks)?;
3230        let values = tokens
3231            .checked_mul(matrix.in_features)
3232            .ok_or("device BF16 column activation size overflow")?;
3233        let root = &self.ranks[0];
3234        if tokens == 0
3235            || root_activation.len() < values
3236            || root_activation.ordinal() != root.ctx().ordinal()
3237        {
3238            return Err("device BF16 column root activation geometry mismatch".into());
3239        }
3240
3241        let mut rank_inputs = Vec::with_capacity(self.ranks.len());
3242        let root_input = {
3243            let _main = root.gpu.enter_main()?;
3244            let mut root_input = root.uninit(values)?;
3245            root.stream()
3246                .memcpy_dtod(&root_activation.slice(0..values), &mut root_input)?;
3247            root_input
3248        };
3249        // PRODUCER FENCE (same discipline as the host-input twin): the peer broadcast
3250        // below reads this buffer from the OTHER ranks' streams while the root dtod may
3251        // still be in flight.
3252        {
3253            let _main = root.gpu.enter_main()?;
3254            root.stream().synchronize()?;
3255        }
3256        rank_inputs.push(root_input);
3257        for engine in &self.ranks[1..] {
3258            let peer_input = {
3259                let _main = engine.gpu.enter_main()?;
3260                let mut peer_input = engine.uninit(values)?;
3261                engine
3262                    .stream()
3263                    .memcpy_dtod(&rank_inputs[0], &mut peer_input)?;
3264                peer_input
3265            };
3266            rank_inputs.push(peer_input);
3267        }
3268
3269        let mut rank_outputs = Vec::with_capacity(self.ranks.len());
3270        #[allow(clippy::needless_range_loop)]
3271        // allow: the explicit index loop keeps the offset arithmetic visible and aligned with the device-side indexing
3272        for rank in 0..self.ranks.len() {
3273            rank_outputs.push(run_resident_bf16_rank_device(
3274                &self.ranks[rank],
3275                &matrix.ranks[rank],
3276                &rank_inputs[rank],
3277                tokens,
3278                matrix.canonical_chunk_rows,
3279                self.bulk_p2p,
3280            )?);
3281        }
3282        Ok(rank_outputs)
3283    }
3284
3285    /// Keep Step BF16 column outputs resident on their owning TP ranks.
3286    ///
3287    /// Rank zero receives the host-canonical activation once and peer-broadcasts it when TP>1.
3288    /// Unlike [`Self::bf16_column_parallel_resident_native`], this method performs no output
3289    /// gather or readback. It is the correctness substrate for rank-local norm, RoPE, attention,
3290    /// and cache ownership; callers must not treat its existence as serving qualification.
3291    pub fn bf16_column_parallel_resident_device_shards(
3292        &self,
3293        matrix: &ResidentBf16ColumnParallel,
3294        activations: &[f32],
3295        tokens: usize,
3296    ) -> Result<Vec<CudaSlice<f32>>, Box<dyn std::error::Error>> {
3297        if self.ranks.len() > 1 && !self.native_p2p {
3298            return Err("device-resident BF16 column parallelism requires native P2P ranks".into());
3299        }
3300        validate_resident_bf16_ranks(&self.ranks, &matrix.ranks)?;
3301        validate_activations(activations, tokens, matrix.in_features)?;
3302
3303        let mut rank_inputs = Vec::with_capacity(self.ranks.len());
3304        let root_input = {
3305            let root = &self.ranks[0];
3306            let _main = root.gpu.enter_main()?;
3307            root.htod(activations)?
3308        };
3309        // PRODUCER FENCE (2026-08-20 flake fix): the peer broadcast below reads this buffer from
3310        // the OTHER ranks' streams, and clone_htod is asynchronous on the root stream. Without
3311        // this fence a peer copy can overtake the in-flight H2D and replicate stale bytes — the
3312        // measured ~30%-of-boots prefill/decode argmax flake. Same discipline as
3313        // `upload_replicated_device_rows`.
3314        {
3315            let root = &self.ranks[0];
3316            let _main = root.gpu.enter_main()?;
3317            root.stream().synchronize()?;
3318        }
3319        rank_inputs.push(root_input);
3320        for engine in &self.ranks[1..] {
3321            let peer_input = {
3322                let _main = engine.gpu.enter_main()?;
3323                let mut peer_input = engine.uninit(activations.len())?;
3324                engine
3325                    .stream()
3326                    .memcpy_dtod(&rank_inputs[0], &mut peer_input)?;
3327                peer_input
3328            };
3329            rank_inputs.push(peer_input);
3330        }
3331
3332        let mut rank_outputs = Vec::with_capacity(self.ranks.len());
3333        #[allow(clippy::needless_range_loop)]
3334        // allow: the explicit index loop keeps the offset arithmetic visible and aligned with the device-side indexing
3335        for rank in 0..self.ranks.len() {
3336            rank_outputs.push(run_resident_bf16_rank_device(
3337                &self.ranks[rank],
3338                &matrix.ranks[rank],
3339                &rank_inputs[rank],
3340                tokens,
3341                matrix.canonical_chunk_rows,
3342                self.bulk_p2p,
3343            )?);
3344        }
3345        Ok(rank_outputs)
3346    }
3347
3348    /// Allocate one fixed-shape replicated batch without initializing its contents.
3349    ///
3350    /// Callers must refresh every rank before passing the batch to an operator.
3351    pub fn allocate_replicated_device_rows(
3352        &self,
3353        tokens: usize,
3354        width: usize,
3355    ) -> Result<ResidentReplicatedDeviceRows, Box<dyn std::error::Error>> {
3356        if self.ranks.len() > 1 && !self.native_p2p {
3357            return Err("replicated device rows require native P2P ranks".into());
3358        }
3359        let values = tokens
3360            .checked_mul(width)
3361            .ok_or("replicated device row size overflow")?;
3362        let rank_lengths = vec![values; self.ranks.len()];
3363        replicated_device_row_values(tokens, width, self.ranks.len(), &rank_lengths)?;
3364        let mut ranks = Vec::with_capacity(self.ranks.len());
3365        for engine in &self.ranks {
3366            let _main = engine.gpu.enter_main()?;
3367            ranks.push(engine.uninit(values)?);
3368        }
3369        Ok(ResidentReplicatedDeviceRows {
3370            ranks,
3371            tokens,
3372            width,
3373        })
3374    }
3375
3376    /// Replace a fixed-shape replicated batch from a root-device source.
3377    pub fn refresh_replicated_device_rows_from_root(
3378        &self,
3379        rows: &mut ResidentReplicatedDeviceRows,
3380        source: &CudaSlice<f32>,
3381    ) -> Result<(), Box<dyn std::error::Error>> {
3382        if self.ranks.len() > 1 && !self.native_p2p {
3383            return Err("replicated device rows require native P2P ranks".into());
3384        }
3385        validate_replicated_device_rows(&self.ranks, rows)?;
3386        let root = self
3387            .ranks
3388            .first()
3389            .ok_or("replicated rows have no root rank")?;
3390        let values = replicated_device_row_source_values(
3391            rows.tokens,
3392            rows.width,
3393            source.len(),
3394            source.ordinal(),
3395            root.ctx().ordinal(),
3396        )?;
3397        let (root_rows, peer_rows) = rows
3398            .ranks
3399            .split_first_mut()
3400            .ok_or("replicated rows have no root allocation")?;
3401        {
3402            let _main = root.gpu.enter_main()?;
3403            let mut destination = root_rows.slice_mut(0..values);
3404            root.stream()
3405                .memcpy_dtod(&source.slice(0..values), &mut destination)?;
3406            root.stream().synchronize()?;
3407        }
3408        for (engine, peer_rows) in self.ranks.iter().skip(1).zip(peer_rows) {
3409            let _main = engine.gpu.enter_main()?;
3410            let mut destination = peer_rows.slice_mut(0..values);
3411            engine
3412                .stream()
3413                .memcpy_dtod(&root_rows.slice(0..values), &mut destination)?;
3414        }
3415        Ok(())
3416    }
3417
3418    /// Upload one canonical batch on rank zero and replicate it over native P2P.
3419    pub fn upload_replicated_device_rows(
3420        &self,
3421        rows: &[f32],
3422        tokens: usize,
3423        width: usize,
3424    ) -> Result<ResidentReplicatedDeviceRows, Box<dyn std::error::Error>> {
3425        if self.ranks.len() > 1 && !self.native_p2p {
3426            return Err("replicated device rows require native P2P ranks".into());
3427        }
3428        validate_activations(rows, tokens, width)?;
3429        let root = self
3430            .ranks
3431            .first()
3432            .ok_or("replicated rows have no root rank")?;
3433        let root_rows = {
3434            let _main = root.gpu.enter_main()?;
3435            root.htod(rows)?
3436        };
3437        {
3438            let _main = root.gpu.enter_main()?;
3439            root.stream().synchronize()?;
3440        }
3441        let mut ranks = Vec::with_capacity(self.ranks.len());
3442        ranks.push(root_rows);
3443        for engine in self.ranks.iter().skip(1) {
3444            let _main = engine.gpu.enter_main()?;
3445            let mut peer_rows = engine.uninit(rows.len())?;
3446            engine.stream().memcpy_dtod(&ranks[0], &mut peer_rows)?;
3447            ranks.push(peer_rows);
3448        }
3449        Ok(ResidentReplicatedDeviceRows {
3450            ranks,
3451            tokens,
3452            width,
3453        })
3454    }
3455
3456    /// Execute a column-parallel BF16 matrix directly from rank-local replicated inputs.
3457    pub fn bf16_column_parallel_resident_replicated_device_shards(
3458        &self,
3459        matrix: &ResidentBf16ColumnParallel,
3460        activations: &ResidentReplicatedDeviceRows,
3461    ) -> Result<Vec<CudaSlice<f32>>, Box<dyn std::error::Error>> {
3462        validate_resident_bf16_ranks(&self.ranks, &matrix.ranks)?;
3463        validate_replicated_device_rows(&self.ranks, activations)?;
3464        if activations.width != matrix.in_features {
3465            return Err(format!(
3466                "replicated BF16 column input width {} != matrix width {}",
3467                activations.width, matrix.in_features
3468            )
3469            .into());
3470        }
3471        let mut outputs = Vec::with_capacity(self.ranks.len());
3472        for rank in 0..self.ranks.len() {
3473            outputs.push(run_resident_bf16_rank_device(
3474                &self.ranks[rank],
3475                &matrix.ranks[rank],
3476                &activations.ranks[rank],
3477                activations.tokens,
3478                matrix.canonical_chunk_rows,
3479                self.bulk_p2p,
3480            )?);
3481        }
3482        Ok(outputs)
3483    }
3484
3485    /// Upload a BF16 router once on rank zero and retain its exact F32 expansion.
3486    #[allow(clippy::too_many_arguments)]
3487    pub fn upload_sigmoid_topk_router(
3488        &self,
3489        weight: Bf16Matrix<'_>,
3490        correction_bias: &[f32],
3491        active: Option<&[bool]>,
3492        experts_per_token: usize,
3493        scaling_factor: f32,
3494        route_norm: bool,
3495    ) -> Result<ResidentSigmoidTopKRouter, Box<dyn std::error::Error>> {
3496        weight.validate()?;
3497        if correction_bias.len() != weight.out_features
3498            || experts_per_token == 0
3499            || experts_per_token > weight.out_features
3500            || !correction_bias.iter().all(|value| value.is_finite())
3501            || !scaling_factor.is_finite()
3502            || scaling_factor <= 0.0
3503        {
3504            return Err(format!(
3505                "sigmoid router geometry weight={}x{} bias={} top_k={} scale={scaling_factor}",
3506                weight.out_features,
3507                weight.in_features,
3508                correction_bias.len(),
3509                experts_per_token,
3510            )
3511            .into());
3512        }
3513        let active_row = active
3514            .map(|mask| {
3515                if mask.len() != weight.out_features {
3516                    return Err(format!(
3517                        "sigmoid router active mask {} != experts {}",
3518                        mask.len(),
3519                        weight.out_features
3520                    ));
3521                }
3522                Ok(mask
3523                    .iter()
3524                    .map(|&enabled| u8::from(enabled))
3525                    .collect::<Vec<_>>())
3526            })
3527            .transpose()?
3528            .unwrap_or_else(|| vec![1; weight.out_features]);
3529        let active_count = active_row.iter().filter(|&&enabled| enabled != 0).count();
3530        crate::sigrouter_contract::validate_active_count(experts_per_token, active_count)?;
3531
3532        let root = self
3533            .ranks
3534            .first()
3535            .ok_or("sigmoid router runtime has no root rank")?;
3536        let _main = root.gpu.enter_main()?;
3537        let bf16 = root.htod_bytes(weight.bytes)?;
3538        let weight_f32 = root.bf16_to_f32(
3539            &bf16.slice(0..bf16.len()),
3540            weight.out_features * weight.in_features,
3541        )?;
3542        Ok(ResidentSigmoidTopKRouter {
3543            weight: weight_f32,
3544            correction_bias: root.htod(correction_bias)?,
3545            active: root.htod_bytes(&active_row)?,
3546            root_device: root.ctx().ordinal(),
3547            input_width: weight.in_features,
3548            expert_count: weight.out_features,
3549            experts_per_token,
3550            active_count,
3551            scaling_factor,
3552            route_norm,
3553        })
3554    }
3555
3556    /// Route rank-zero replicated rows and return the narrow host control result plus logits.
3557    ///
3558    /// The logits readback exists for independent oracle comparison. This method is a correctness
3559    /// surface; a serving scheduler may retain logits and selected routes on device.
3560    pub fn sigmoid_topk_replicated_device_rows_host(
3561        &self,
3562        router: &ResidentSigmoidTopKRouter,
3563        input: &ResidentReplicatedDeviceRows,
3564    ) -> Result<SigmoidTopKHostOutput, Box<dyn std::error::Error>> {
3565        validate_replicated_device_rows(&self.ranks, input)?;
3566        if input.width != router.input_width {
3567            return Err(format!(
3568                "sigmoid router input width {} != resident width {}",
3569                input.width, router.input_width
3570            )
3571            .into());
3572        }
3573        let root = self
3574            .ranks
3575            .first()
3576            .ok_or("sigmoid router runtime has no root rank")?;
3577        let _main = root.gpu.enter_main()?;
3578        if root.ctx().ordinal() != router.root_device
3579            || router.weight.ordinal() != router.root_device
3580            || router.correction_bias.ordinal() != router.root_device
3581            || router.active.ordinal() != router.root_device
3582        {
3583            return Err("sigmoid router root residency changed".into());
3584        }
3585        let logits = root.router_gemv(
3586            &router.weight,
3587            &input.ranks[0],
3588            router.input_width,
3589            router.expert_count,
3590            input.tokens,
3591        )?;
3592        let (selected, weights) = root.moe_router_sigmoid_topk_host(
3593            &logits,
3594            input.tokens,
3595            router.expert_count,
3596            router.experts_per_token,
3597            router.active_count,
3598            &router.correction_bias,
3599            &router.active,
3600            router.scaling_factor,
3601            router.route_norm,
3602        )?;
3603        Ok(SigmoidTopKHostOutput {
3604            logits: root.dtoh(&logits)?,
3605            selected,
3606            weights,
3607        })
3608    }
3609
3610    /// Replicate a full BF16 SwiGLU bank on every rank.
3611    pub fn upload_replicated_bf16_swiglu(
3612        &self,
3613        gate: Bf16Matrix<'_>,
3614        up: Bf16Matrix<'_>,
3615        down: Bf16Matrix<'_>,
3616    ) -> Result<ResidentReplicatedBf16SwiGlu, Box<dyn std::error::Error>> {
3617        gate.validate()?;
3618        up.validate()?;
3619        down.validate()?;
3620        if gate.in_features != up.in_features
3621            || gate.out_features != up.out_features
3622            || down.in_features != gate.out_features
3623            || down.out_features != gate.in_features
3624        {
3625            return Err(format!(
3626                "replicated BF16 SwiGLU geometry gate={}x{} up={}x{} down={}x{}",
3627                gate.out_features,
3628                gate.in_features,
3629                up.out_features,
3630                up.in_features,
3631                down.out_features,
3632                down.in_features,
3633            )
3634            .into());
3635        }
3636        let mut gate_ranks = Vec::with_capacity(self.ranks.len());
3637        let mut up_ranks = Vec::with_capacity(self.ranks.len());
3638        let mut down_ranks = Vec::with_capacity(self.ranks.len());
3639        for engine in &self.ranks {
3640            gate_ranks.push(upload_bf16_rank(engine, gate, false)?);
3641            up_ranks.push(upload_bf16_rank(engine, up, false)?);
3642            down_ranks.push(upload_bf16_rank(engine, down, false)?);
3643        }
3644        Ok(ResidentReplicatedBf16SwiGlu {
3645            gate: gate_ranks,
3646            up: up_ranks,
3647            down: down_ranks,
3648            input_width: gate.in_features,
3649            intermediate_width: gate.out_features,
3650        })
3651    }
3652
3653    /// Execute a fully replicated BF16 SwiGLU directly from replicated device rows.
3654    pub fn replicated_bf16_swiglu_resident_device(
3655        &self,
3656        mlp: &ResidentReplicatedBf16SwiGlu,
3657        input: &ResidentReplicatedDeviceRows,
3658        activation_limit: Option<f32>,
3659    ) -> Result<ResidentReplicatedDeviceRows, Box<dyn std::error::Error>> {
3660        validate_step_expert_activation_limit(activation_limit)?;
3661        validate_replicated_device_rows(&self.ranks, input)?;
3662        validate_resident_bf16_ranks(&self.ranks, &mlp.gate)?;
3663        validate_resident_bf16_ranks(&self.ranks, &mlp.up)?;
3664        validate_resident_bf16_ranks(&self.ranks, &mlp.down)?;
3665        if input.width != mlp.input_width
3666            || mlp.gate.len() != self.ranks.len()
3667            || mlp.up.len() != self.ranks.len()
3668            || mlp.down.len() != self.ranks.len()
3669        {
3670            return Err("replicated BF16 SwiGLU residency or input width changed".into());
3671        }
3672
3673        let mut outputs = Vec::with_capacity(self.ranks.len());
3674        for rank in 0..self.ranks.len() {
3675            let engine = &self.ranks[rank];
3676            let gate = run_resident_bf16_rank_device(
3677                engine,
3678                &mlp.gate[rank],
3679                &input.ranks[rank],
3680                input.tokens,
3681                None,
3682                self.bulk_p2p,
3683            )?;
3684            let up = run_resident_bf16_rank_device(
3685                engine,
3686                &mlp.up[rank],
3687                &input.ranks[rank],
3688                input.tokens,
3689                None,
3690                self.bulk_p2p,
3691            )?;
3692            let _main = engine.gpu.enter_main()?;
3693            let values = input
3694                .tokens
3695                .checked_mul(mlp.intermediate_width)
3696                .ok_or("replicated BF16 SwiGLU activation size overflow")?;
3697            let mut activation = engine.uninit(values)?;
3698            if let Some(limit) = activation_limit {
3699                engine.silu_clamped_mul_host_expf(&gate, &up, limit, &mut activation, values)?;
3700            } else {
3701                engine.silu_mul_host_expf(&gate, &up, &mut activation, values)?;
3702            }
3703            outputs.push(run_resident_bf16_rank_device(
3704                engine,
3705                &mlp.down[rank],
3706                &activation,
3707                input.tokens,
3708                None,
3709                self.bulk_p2p,
3710            )?);
3711        }
3712        Ok(ResidentReplicatedDeviceRows {
3713            ranks: outputs,
3714            tokens: input.tokens,
3715            width: mlp.input_width,
3716        })
3717    }
3718
3719    /// Apply the same RMS-norm row program independently on every replicated rank.
3720    pub fn rms_norm_replicated_device_rows(
3721        &self,
3722        input: &ResidentReplicatedDeviceRows,
3723        weight: &[f32],
3724        eps: f32,
3725    ) -> Result<ResidentReplicatedDeviceRows, Box<dyn std::error::Error>> {
3726        validate_replicated_device_rows(&self.ranks, input)?;
3727        if weight.len() != input.width || !eps.is_finite() || eps <= 0.0 {
3728            return Err(format!(
3729                "replicated RMS norm weight/eps {}/{} != width {}",
3730                weight.len(),
3731                eps,
3732                input.width
3733            )
3734            .into());
3735        }
3736        let mut ranks = Vec::with_capacity(self.ranks.len());
3737        for (rank, engine) in self.ranks.iter().enumerate() {
3738            let _main = engine.gpu.enter_main()?;
3739            let weight = engine.htod(weight)?;
3740            let mut output = engine.uninit(input.tokens * input.width)?;
3741            engine.rms_norm(
3742                &input.ranks[rank],
3743                &weight,
3744                &mut output,
3745                input.width,
3746                input.tokens,
3747                eps,
3748            )?;
3749            ranks.push(output);
3750        }
3751        Ok(ResidentReplicatedDeviceRows {
3752            ranks,
3753            tokens: input.tokens,
3754            width: input.width,
3755        })
3756    }
3757
3758    /// Add two replicated batches and RMS-normalize the exact residual on every rank.
3759    pub fn add_rms_norm_replicated_device_rows(
3760        &self,
3761        input: &ResidentReplicatedDeviceRows,
3762        update: &ResidentReplicatedDeviceRows,
3763        weight: &[f32],
3764        eps: f32,
3765    ) -> Result<
3766        (ResidentReplicatedDeviceRows, ResidentReplicatedDeviceRows),
3767        Box<dyn std::error::Error>,
3768    > {
3769        validate_replicated_device_rows(&self.ranks, input)?;
3770        validate_replicated_device_rows(&self.ranks, update)?;
3771        if input.tokens != update.tokens
3772            || input.width != update.width
3773            || weight.len() != input.width
3774            || !eps.is_finite()
3775            || eps <= 0.0
3776        {
3777            return Err(format!(
3778                "replicated add/RMS geometry input={}x{} update={}x{} weight={} eps={eps}",
3779                input.tokens,
3780                input.width,
3781                update.tokens,
3782                update.width,
3783                weight.len(),
3784            )
3785            .into());
3786        }
3787        let values = input.tokens * input.width;
3788        let mut residual_ranks = Vec::with_capacity(self.ranks.len());
3789        let mut normalized_ranks = Vec::with_capacity(self.ranks.len());
3790        for (rank, engine) in self.ranks.iter().enumerate() {
3791            let _main = engine.gpu.enter_main()?;
3792            let weight = engine.htod(weight)?;
3793            let mut residual = engine.uninit(values)?;
3794            let mut normalized = engine.uninit(values)?;
3795            engine.add_rms_norm(
3796                &input.ranks[rank],
3797                &update.ranks[rank],
3798                &weight,
3799                &mut residual,
3800                &mut normalized,
3801                input.width,
3802                input.tokens,
3803                eps,
3804            )?;
3805            residual_ranks.push(residual);
3806            normalized_ranks.push(normalized);
3807        }
3808        Ok((
3809            ResidentReplicatedDeviceRows {
3810                ranks: residual_ranks,
3811                tokens: input.tokens,
3812                width: input.width,
3813            },
3814            ResidentReplicatedDeviceRows {
3815                ranks: normalized_ranks,
3816                tokens: input.tokens,
3817                width: input.width,
3818            },
3819        ))
3820    }
3821
3822    pub fn collect_replicated_device_rows(
3823        &self,
3824        rows: &ResidentReplicatedDeviceRows,
3825    ) -> Result<Vec<Vec<f32>>, Box<dyn std::error::Error>> {
3826        validate_replicated_device_rows(&self.ranks, rows)?;
3827        let mut outputs = Vec::with_capacity(self.ranks.len());
3828        for (rank, engine) in self.ranks.iter().enumerate() {
3829            let _main = engine.gpu.enter_main()?;
3830            outputs.push(engine.dtoh(&rows.ranks[rank])?);
3831        }
3832        Ok(outputs)
3833    }
3834
3835    #[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
3836    pub fn upload_bf16_row_parallel(
3837        &self,
3838        matrix: Bf16Matrix<'_>,
3839    ) -> Result<ResidentBf16RowParallel, Box<dyn std::error::Error>> {
3840        matrix.validate()?;
3841        let tp = self.ranks.len();
3842        if matrix.in_features % tp != 0 {
3843            return Err(format!(
3844                "BF16 row-parallel in_features {} is not divisible by TP={tp}",
3845                matrix.in_features
3846            )
3847            .into());
3848        }
3849        let mut ranks = Vec::with_capacity(tp);
3850        for (rank, engine) in self.ranks.iter().enumerate() {
3851            let shard = bf16_row_shard(matrix, tp, rank)?;
3852            ranks.push(upload_bf16_rank(
3853                engine,
3854                Bf16Matrix {
3855                    bytes: &shard,
3856                    out_features: matrix.out_features,
3857                    in_features: matrix.in_features / tp,
3858                },
3859                false,
3860            )?);
3861        }
3862        Ok(ResidentBf16RowParallel {
3863            ranks,
3864            out_features: matrix.out_features,
3865            in_features: matrix.in_features,
3866        })
3867    }
3868
3869    pub fn bf16_row_parallel_resident(
3870        &self,
3871        matrix: &ResidentBf16RowParallel,
3872        activations: &[f32],
3873        tokens: usize,
3874    ) -> Result<RowParallelResult, Box<dyn std::error::Error>> {
3875        validate_resident_bf16_ranks(&self.ranks, &matrix.ranks)?;
3876        validate_activations(activations, tokens, matrix.in_features)?;
3877        let tp = self.ranks.len();
3878        let mut reduced = vec![0.0f32; tokens * matrix.out_features];
3879        let mut rank_partials = Vec::with_capacity(tp);
3880        for (rank, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
3881            let local_activations =
3882                activation_shard(activations, tokens, matrix.in_features, tp, rank);
3883            let partial = run_resident_bf16_rank(engine, shard, &local_activations, tokens, None)?;
3884            for (sum, value) in reduced.iter_mut().zip(&partial) {
3885                *sum += value;
3886            }
3887            rank_partials.push(partial);
3888        }
3889        Ok(RowParallelResult {
3890            reduced,
3891            rank_partials,
3892        })
3893    }
3894
3895    /// Step-3.7 row projection split into the same eight global K blocks for TP1/TP2/TP4/TP8.
3896    pub fn upload_step_bf16_row_parallel(
3897        &self,
3898        matrix: Bf16Matrix<'_>,
3899    ) -> Result<ResidentStepBf16RowParallel, Box<dyn std::error::Error>> {
3900        self.upload_step_bf16_row_parallel_inner(matrix, false)
3901    }
3902
3903    pub fn upload_step_bf16_row_parallel_f32_mirror(
3904        &self,
3905        matrix: Bf16Matrix<'_>,
3906    ) -> Result<ResidentStepBf16RowParallel, Box<dyn std::error::Error>> {
3907        self.upload_step_bf16_row_parallel_inner(matrix, true)
3908    }
3909
3910    fn upload_step_bf16_row_parallel_inner(
3911        &self,
3912        matrix: Bf16Matrix<'_>,
3913        f32_mirror: bool,
3914    ) -> Result<ResidentStepBf16RowParallel, Box<dyn std::error::Error>> {
3915        matrix.validate()?;
3916        let tp = self.ranks.len();
3917        let canonical_chunk_cols = step_bf16_canonical_chunk_cols(matrix.in_features, tp)?;
3918        let local_in = matrix.in_features / tp;
3919        let blocks_per_rank = local_in / canonical_chunk_cols;
3920        let mut ranks = Vec::with_capacity(tp);
3921        for (rank, engine) in self.ranks.iter().enumerate() {
3922            let mut blocks = Vec::with_capacity(blocks_per_rank);
3923            for block in 0..blocks_per_rank {
3924                let global_block = rank * blocks_per_rank + block;
3925                let col_start = global_block * canonical_chunk_cols;
3926                let bytes = bf16_row_block(matrix, col_start, canonical_chunk_cols)?;
3927                blocks.push(upload_bf16_rank(
3928                    engine,
3929                    Bf16Matrix {
3930                        bytes: &bytes,
3931                        out_features: matrix.out_features,
3932                        in_features: canonical_chunk_cols,
3933                    },
3934                    f32_mirror,
3935                )?);
3936            }
3937            ranks.push(blocks);
3938        }
3939        Ok(ResidentStepBf16RowParallel {
3940            ranks,
3941            out_features: matrix.out_features,
3942            in_features: matrix.in_features,
3943            canonical_chunk_cols,
3944        })
3945    }
3946
3947    /// Host-staged exactness twin of [`Self::step_bf16_row_parallel_resident_native`].
3948    ///
3949    /// Block inputs and partials cross host memory, but every partial is added on the root device
3950    /// in global checkpoint-column order. Native transport must reproduce this result bitwise.
3951    pub fn step_bf16_row_parallel_resident(
3952        &self,
3953        matrix: &ResidentStepBf16RowParallel,
3954        activations: &[f32],
3955        tokens: usize,
3956    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
3957        validate_step_bf16_row_residency(&self.ranks, matrix)?;
3958        validate_activations(activations, tokens, matrix.in_features)?;
3959        let root = &self.ranks[0];
3960        let output_len = tokens
3961            .checked_mul(matrix.out_features)
3962            .ok_or("Step BF16 row output size overflow")?;
3963        let mut reduced = {
3964            let _main = root.gpu.enter_main()?;
3965            root.htod(&vec![0.0f32; output_len])?
3966        };
3967        let blocks_per_rank = PRODUCT_MAX_CARDS / self.ranks.len();
3968        for (rank, blocks) in matrix.ranks.iter().enumerate() {
3969            for (block, resident) in blocks.iter().enumerate() {
3970                let global_block = rank * blocks_per_rank + block;
3971                let input = activation_shard(
3972                    activations,
3973                    tokens,
3974                    matrix.in_features,
3975                    PRODUCT_MAX_CARDS,
3976                    global_block,
3977                );
3978                let partial =
3979                    run_resident_bf16_rank(&self.ranks[rank], resident, &input, tokens, None)?;
3980                let next = {
3981                    let _main = root.gpu.enter_main()?;
3982                    let partial = root.htod(&partial)?;
3983                    let mut next = root.uninit(output_len)?;
3984                    root.add(&reduced, &partial, &mut next, output_len)?;
3985                    next
3986                };
3987                reduced = next;
3988            }
3989        }
3990        let _main = root.gpu.enter_main()?;
3991        root.dtoh(&reduced)
3992    }
3993
3994    /// Native-P2P Step row projection with canonical global K-block reduction.
3995    ///
3996    /// The full activation is uploaded once on the root. Each TP8-sized block is peer-scattered
3997    /// to its owning rank, its BF16 partial is peer-returned to the root, and root-device adds
3998    /// replay the same eight-block order as TP1 and the host-staged oracle.
3999    pub fn step_bf16_row_parallel_resident_native(
4000        &self,
4001        matrix: &ResidentStepBf16RowParallel,
4002        activations: &[f32],
4003        tokens: usize,
4004    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
4005        if self.ranks.len() > 1 && !self.native_p2p {
4006            return Err("native Step BF16 row parallelism requires P2P ranks".into());
4007        }
4008        validate_step_bf16_row_residency(&self.ranks, matrix)?;
4009        validate_activations(activations, tokens, matrix.in_features)?;
4010        let root = &self.ranks[0];
4011        let root_input = {
4012            let _main = root.gpu.enter_main()?;
4013            root.htod(activations)?
4014        };
4015        // PRODUCER FENCE (2026-08-20 flake fix): the non-bulk arm below peer-reads root_input
4016        // from the other ranks' streams while root's clone_htod may still be in flight.
4017        {
4018            let _main = root.gpu.enter_main()?;
4019            root.stream().synchronize()?;
4020        }
4021        let reduced = self.step_bf16_row_native_reduce_from_root(matrix, &root_input, tokens)?;
4022        let _main = root.gpu.enter_main()?;
4023        root.dtoh(&reduced)
4024    }
4025
4026    /// Device-input twin of [`Self::step_bf16_row_parallel_resident_native`] (lane/
4027    /// hermes-perf-fixes, 2026-08-23): the full activation arrives as a ROOT-DEVICE buffer
4028    /// and the reduced output stays root-resident — no DtoH of the attention output, no
4029    /// host O staging, no re-upload. Byte-identical to the host-canonical arm by
4030    /// construction (same block scatter, kernels, and global TP8 reduction order; the root
4031    /// bytes are dtod-copied where the host arm htod'd the same bytes). Caller must have
4032    /// synchronized the producer stream; the root stream is synchronized before returning.
4033    pub fn step_bf16_row_parallel_resident_native_device(
4034        &self,
4035        matrix: &ResidentStepBf16RowParallel,
4036        root_activation: &CudaSlice<f32>,
4037        tokens: usize,
4038    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
4039        if self.ranks.len() > 1 && !self.native_p2p {
4040            return Err("native Step BF16 row parallelism requires P2P ranks".into());
4041        }
4042        validate_step_bf16_row_residency(&self.ranks, matrix)?;
4043        let values = tokens
4044            .checked_mul(matrix.in_features)
4045            .ok_or("device Step BF16 row activation size overflow")?;
4046        let root = &self.ranks[0];
4047        if tokens == 0
4048            || root_activation.len() < values
4049            || root_activation.ordinal() != root.ctx().ordinal()
4050        {
4051            return Err("device Step BF16 row root activation geometry mismatch".into());
4052        }
4053        let root_input = {
4054            let _main = root.gpu.enter_main()?;
4055            let mut root_input = root.uninit(values)?;
4056            root.stream()
4057                .memcpy_dtod(&root_activation.slice(0..values), &mut root_input)?;
4058            root.stream().synchronize()?; // producer fence, as the host-input twin
4059            root_input
4060        };
4061        let reduced = self.step_bf16_row_native_reduce_from_root(matrix, &root_input, tokens)?;
4062        let _main = root.gpu.enter_main()?;
4063        root.stream().synchronize()?;
4064        Ok(reduced)
4065    }
4066
4067    /// Shared core of the two native Step row arms above: block scatter + rank GEMMs +
4068    /// canonical global TP8-order root reduction, from a root-resident input, returning the
4069    /// root-resident reduced output. Extracted verbatim so the host and device twins cannot
4070    /// drift numerically.
4071    fn step_bf16_row_native_reduce_from_root(
4072        &self,
4073        matrix: &ResidentStepBf16RowParallel,
4074        root_input: &CudaSlice<f32>,
4075        tokens: usize,
4076    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
4077        let root = &self.ranks[0];
4078        let output_len = tokens
4079            .checked_mul(matrix.out_features)
4080            .ok_or("native Step BF16 row output size overflow")?;
4081        let mut reduced = {
4082            let _main = root.gpu.enter_main()?;
4083            root.htod(&vec![0.0f32; output_len])?
4084        };
4085        let blocks_per_rank = PRODUCT_MAX_CARDS / self.ranks.len();
4086        let mut block_input_keepalive = Vec::with_capacity(PRODUCT_MAX_CARDS);
4087        let mut root_packed_keepalive = Vec::with_capacity(PRODUCT_MAX_CARDS);
4088        let mut remote_partial_keepalive = Vec::new();
4089        for (rank, blocks) in matrix.ranks.iter().enumerate() {
4090            for (block, resident) in blocks.iter().enumerate() {
4091                let global_block = rank * blocks_per_rank + block;
4092                let col_start = global_block * matrix.canonical_chunk_cols;
4093                let block_len = tokens
4094                    .checked_mul(matrix.canonical_chunk_cols)
4095                    .ok_or("native Step BF16 row block size overflow")?;
4096                let block_input = if self.bulk_p2p {
4097                    let root_packed = {
4098                        let _main = root.gpu.enter_main()?;
4099                        let mut root_packed = root.uninit(block_len)?;
4100                        root.copy_rows_strided(
4101                            root_input,
4102                            &mut root_packed,
4103                            matrix.canonical_chunk_cols,
4104                            tokens,
4105                            matrix.in_features,
4106                            col_start,
4107                        )?;
4108                        root_packed
4109                    };
4110                    if rank == 0 {
4111                        root_packed
4112                    } else {
4113                        // PRODUCER FENCE (2026-08-20 flake fix): the pack kernel runs on the
4114                        // root stream; this rank's peer read must not overtake it.
4115                        {
4116                            let _main = root.gpu.enter_main()?;
4117                            root.stream().synchronize()?;
4118                        }
4119                        let engine = &self.ranks[rank];
4120                        let _main = engine.gpu.enter_main()?;
4121                        let mut block_input = engine.uninit(block_len)?;
4122                        engine
4123                            .stream()
4124                            .memcpy_dtod(&root_packed, &mut block_input)?;
4125                        root_packed_keepalive.push(root_packed);
4126                        block_input
4127                    }
4128                } else {
4129                    let engine = &self.ranks[rank];
4130                    let _main = engine.gpu.enter_main()?;
4131                    let mut block_input = engine.uninit(block_len)?;
4132                    for token in 0..tokens {
4133                        let source_start = token * matrix.in_features + col_start;
4134                        let source = root_input
4135                            .slice(source_start..source_start + matrix.canonical_chunk_cols);
4136                        let destination_start = token * matrix.canonical_chunk_cols;
4137                        let mut destination = block_input.slice_mut(
4138                            destination_start..destination_start + matrix.canonical_chunk_cols,
4139                        );
4140                        engine.stream().memcpy_dtod(&source, &mut destination)?;
4141                    }
4142                    block_input
4143                };
4144                let partial = run_resident_bf16_rank_device(
4145                    &self.ranks[rank],
4146                    resident,
4147                    &block_input,
4148                    tokens,
4149                    None,
4150                    self.bulk_p2p,
4151                )?;
4152                block_input_keepalive.push(block_input);
4153                let root_partial = if rank == 0 {
4154                    partial
4155                } else {
4156                    // PRODUCER FENCE (2026-08-20 flake fix): the partial was produced by this
4157                    // rank's kernel on its own stream; root's peer read must not overtake it.
4158                    {
4159                        let engine = &self.ranks[rank];
4160                        let _main = engine.gpu.enter_main()?;
4161                        engine.stream().synchronize()?;
4162                    }
4163                    let _main = root.gpu.enter_main()?;
4164                    let mut peer_partial = root.uninit(output_len)?;
4165                    root.stream().memcpy_dtod(&partial, &mut peer_partial)?;
4166                    remote_partial_keepalive.push(partial);
4167                    peer_partial
4168                };
4169                let next = {
4170                    let _main = root.gpu.enter_main()?;
4171                    let mut next = root.uninit(output_len)?;
4172                    root.add(&reduced, &root_partial, &mut next, output_len)?;
4173                    next
4174                };
4175                reduced = next;
4176            }
4177        }
4178        {
4179            let _main = root.gpu.enter_main()?;
4180            root.stream().synchronize()?;
4181        }
4182        drop(remote_partial_keepalive);
4183        drop(root_packed_keepalive);
4184        drop(block_input_keepalive);
4185        Ok(reduced)
4186    }
4187
4188    /// Reduce rank-local Step attention shards in canonical TP8 K-block order and keep the result
4189    /// on the root device.
4190    pub fn step_bf16_row_parallel_resident_root_device(
4191        &self,
4192        matrix: &ResidentStepBf16RowParallel,
4193        rank_activations: &[CudaSlice<f32>],
4194        tokens: usize,
4195    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
4196        if self.ranks.len() > 1 && !self.native_p2p {
4197            return Err(
4198                "device-resident Step BF16 row parallelism requires native P2P ranks".into(),
4199            );
4200        }
4201        validate_step_bf16_row_residency(&self.ranks, matrix)?;
4202        let local_width = matrix.in_features / self.ranks.len();
4203        let shard_len = tokens
4204            .checked_mul(local_width)
4205            .ok_or("device Step BF16 row shard size overflow")?;
4206        if tokens == 0
4207            || rank_activations.len() != self.ranks.len()
4208            || rank_activations
4209                .iter()
4210                .zip(&self.ranks)
4211                .any(|(rows, engine)| {
4212                    rows.len() != shard_len || rows.ordinal() != engine.ctx().ordinal()
4213                })
4214        {
4215            return Err("device Step BF16 row activation shard geometry changed".into());
4216        }
4217
4218        let blocks_per_rank = PRODUCT_MAX_CARDS / self.ranks.len();
4219        let mut block_inputs = Vec::with_capacity(self.ranks.len());
4220        let mut partials = Vec::with_capacity(self.ranks.len());
4221        for (rank, blocks) in matrix.ranks.iter().enumerate() {
4222            if blocks.len() != blocks_per_rank {
4223                return Err(format!(
4224                    "device Step BF16 row rank {rank} blocks {} != {blocks_per_rank}",
4225                    blocks.len()
4226                )
4227                .into());
4228            }
4229            let engine = &self.ranks[rank];
4230            let _main = engine.gpu.enter_main()?;
4231            let mut rank_inputs = Vec::with_capacity(blocks_per_rank);
4232            let mut rank_partials = Vec::with_capacity(blocks_per_rank);
4233            for (block, resident) in blocks.iter().enumerate() {
4234                let block_len = tokens
4235                    .checked_mul(matrix.canonical_chunk_cols)
4236                    .ok_or("device Step BF16 row block size overflow")?;
4237                let mut block_input = engine.uninit(block_len)?;
4238                let local_col_start = block * matrix.canonical_chunk_cols;
4239                if self.bulk_p2p {
4240                    engine.copy_rows_strided(
4241                        &rank_activations[rank],
4242                        &mut block_input,
4243                        matrix.canonical_chunk_cols,
4244                        tokens,
4245                        local_width,
4246                        local_col_start,
4247                    )?;
4248                } else {
4249                    for token in 0..tokens {
4250                        let source_start = token * local_width + local_col_start;
4251                        let source = rank_activations[rank]
4252                            .slice(source_start..source_start + matrix.canonical_chunk_cols);
4253                        let destination_start = token * matrix.canonical_chunk_cols;
4254                        let mut destination = block_input.slice_mut(
4255                            destination_start..destination_start + matrix.canonical_chunk_cols,
4256                        );
4257                        engine.stream().memcpy_dtod(&source, &mut destination)?;
4258                    }
4259                }
4260                let partial = run_resident_bf16_rank_device(
4261                    engine,
4262                    resident,
4263                    &block_input,
4264                    tokens,
4265                    None,
4266                    self.bulk_p2p,
4267                )?;
4268                rank_inputs.push(block_input);
4269                rank_partials.push(partial);
4270            }
4271            block_inputs.push(rank_inputs);
4272            partials.push(rank_partials);
4273        }
4274        for engine in self.ranks.iter().skip(1) {
4275            let _main = engine.gpu.enter_main()?;
4276            engine.stream().synchronize()?;
4277        }
4278
4279        let output_len = tokens
4280            .checked_mul(matrix.out_features)
4281            .ok_or("device Step BF16 row output size overflow")?;
4282        let root = &self.ranks[0];
4283        let _main = root.gpu.enter_main()?;
4284        let mut reduced = root.htod(&vec![0.0f32; output_len])?;
4285        let mut remote_partials = Vec::new();
4286        for (rank, rank_partials) in partials.into_iter().enumerate() {
4287            for partial in rank_partials {
4288                let root_partial = if rank == 0 {
4289                    partial
4290                } else {
4291                    let mut peer_partial = root.uninit(output_len)?;
4292                    root.stream().memcpy_dtod(&partial, &mut peer_partial)?;
4293                    remote_partials.push(partial);
4294                    peer_partial
4295                };
4296                let mut next = root.uninit(output_len)?;
4297                root.add(&reduced, &root_partial, &mut next, output_len)?;
4298                reduced = next;
4299            }
4300        }
4301        root.stream().synchronize()?;
4302        drop(remote_partials);
4303        drop(block_inputs);
4304        Ok(reduced)
4305    }
4306
4307    /// Reduce rank-local Step attention shards, then replicate the canonical root result.
4308    pub fn step_bf16_row_parallel_resident_replicated_device(
4309        &self,
4310        matrix: &ResidentStepBf16RowParallel,
4311        rank_activations: &[CudaSlice<f32>],
4312        tokens: usize,
4313    ) -> Result<ResidentReplicatedDeviceRows, Box<dyn std::error::Error>> {
4314        let reduced =
4315            self.step_bf16_row_parallel_resident_root_device(matrix, rank_activations, tokens)?;
4316        let output_len = tokens
4317            .checked_mul(matrix.out_features)
4318            .ok_or("device Step BF16 row output size overflow")?;
4319        let mut ranks = Vec::with_capacity(self.ranks.len());
4320        ranks.push(reduced);
4321        for engine in self.ranks.iter().skip(1) {
4322            let _main = engine.gpu.enter_main()?;
4323            let mut peer_output = engine.uninit(output_len)?;
4324            engine.stream().memcpy_dtod(&ranks[0], &mut peer_output)?;
4325            ranks.push(peer_output);
4326        }
4327        Ok(ResidentReplicatedDeviceRows {
4328            ranks,
4329            tokens,
4330            width: matrix.out_features,
4331        })
4332    }
4333
4334    pub fn upload_expert(
4335        &self,
4336        gate: E4m3BlockMatrix<'_>,
4337        up: E4m3BlockMatrix<'_>,
4338        down: E4m3BlockMatrix<'_>,
4339    ) -> Result<ResidentTpExpert, Box<dyn std::error::Error>> {
4340        if gate.in_features != up.in_features || gate.out_features != up.out_features {
4341            return Err("TP expert gate/up dimensions differ".into());
4342        }
4343        if down.in_features != gate.out_features || down.out_features != gate.in_features {
4344            return Err(format!(
4345                "TP expert down {}x{} does not invert gate/up {}x{}",
4346                down.out_features, down.in_features, gate.out_features, gate.in_features
4347            )
4348            .into());
4349        }
4350        Ok(ResidentTpExpert {
4351            gate: self.upload_column_parallel(gate)?,
4352            up: self.upload_column_parallel(up)?,
4353            down: self.upload_row_parallel(down)?,
4354            input_width: gate.in_features,
4355            expert_width: gate.out_features,
4356        })
4357    }
4358
4359    pub fn run_expert(
4360        &self,
4361        expert: &ResidentTpExpert,
4362        input: &[f32],
4363        tokens: usize,
4364    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
4365        validate_activations(input, tokens, expert.input_width)?;
4366        let gate = self.column_parallel_resident(&expert.gate, input, tokens)?;
4367        let up = self.column_parallel_resident(&expert.up, input, tokens)?;
4368        let activated: Vec<f32> = gate
4369            .gathered
4370            .iter()
4371            .zip(&up.gathered)
4372            .map(|(&gate, &up)| gate / (1.0 + (-gate).exp()) * up)
4373            .collect();
4374        debug_assert_eq!(activated.len(), tokens * expert.expert_width);
4375        Ok(self
4376            .row_parallel_resident(&expert.down, &activated, tokens)?
4377            .reduced)
4378    }
4379
4380    #[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
4381    pub fn upload_expert_parallel(
4382        &self,
4383        gate: E4m3ExpertBank<'_>,
4384        up: E4m3ExpertBank<'_>,
4385        down: E4m3ExpertBank<'_>,
4386    ) -> Result<ResidentExpertParallel, Box<dyn std::error::Error>> {
4387        gate.validate()?;
4388        up.validate()?;
4389        down.validate()?;
4390        if gate.expert_count != up.expert_count || gate.expert_count != down.expert_count {
4391            return Err("EP gate/up/down expert counts differ".into());
4392        }
4393        if gate.in_features != up.in_features || gate.out_features != up.out_features {
4394            return Err("EP gate/up dimensions differ".into());
4395        }
4396        if down.in_features != gate.out_features || down.out_features != gate.in_features {
4397            return Err(format!(
4398                "EP down {}x{} does not invert gate/up {}x{}",
4399                down.out_features, down.in_features, gate.out_features, gate.in_features
4400            )
4401            .into());
4402        }
4403        if gate.expert_count % self.ranks.len() != 0 {
4404            return Err(format!(
4405                "EP expert count {} is not divisible by {} ranks",
4406                gate.expert_count,
4407                self.ranks.len()
4408            )
4409            .into());
4410        }
4411
4412        let per_rank = gate.expert_count / self.ranks.len();
4413        let mut ranks = Vec::with_capacity(self.ranks.len());
4414        for (rank, engine) in self.ranks.iter().enumerate() {
4415            let expert_range = rank * per_rank..(rank + 1) * per_rank;
4416            ranks.push(ResidentEpRank {
4417                gate: upload_expert_bank_rank(engine, gate, expert_range.clone())?,
4418                up: upload_expert_bank_rank(engine, up, expert_range.clone())?,
4419                down: upload_expert_bank_rank(engine, down, expert_range)?,
4420            });
4421        }
4422        Ok(ResidentExpertParallel {
4423            ranks,
4424            expert_count: gate.expert_count,
4425            input_width: gate.in_features,
4426            expert_width: gate.out_features,
4427        })
4428    }
4429
4430    /// Prepare the official Step gate-only grouped-FP8 projection oracle on rank zero.
4431    ///
4432    /// This intentionally does not alter the resident EP path. It owns a full rank-local tensor
4433    /// bank solely so the grouped projection can be compared with the existing per-route oracle
4434    /// without routing, transport, or combine changing underneath it.
4435    #[allow(clippy::too_many_arguments)]
4436    pub fn prepare_step_grouped_fp8_gate(
4437        &self,
4438        gate: E4m3ExpertBank<'_>,
4439        up: E4m3ExpertBank<'_>,
4440        down: E4m3ExpertBank<'_>,
4441        input: &[f32],
4442        tokens: usize,
4443        selected: &[usize],
4444        activation_limit: Option<f32>,
4445    ) -> Result<PreparedStepGroupedFp8Gate, Box<dyn std::error::Error>> {
4446        gate.validate()?;
4447        up.validate()?;
4448        down.validate()?;
4449        validate_step_expert_activation_limit(activation_limit)?;
4450        if gate.expert_count != STEP_GROUPED_FP8_EXPERTS
4451            || up.expert_count != STEP_GROUPED_FP8_EXPERTS
4452            || down.expert_count != STEP_GROUPED_FP8_EXPERTS
4453        {
4454            return Err(format!(
4455                "official Step grouped FP8 gate requires {STEP_GROUPED_FP8_EXPERTS} experts, \
4456                 got gate/up/down={}/{}/{}",
4457                gate.expert_count, up.expert_count, down.expert_count,
4458            )
4459            .into());
4460        }
4461        if gate.in_features != up.in_features
4462            || gate.out_features != STEP_GROUPED_FP8_WIDTH
4463            || up.out_features != STEP_GROUPED_FP8_WIDTH
4464            || down.in_features != STEP_GROUPED_FP8_WIDTH
4465            || down.out_features != gate.in_features
4466        {
4467            return Err(format!(
4468                "official Step grouped FP8 geometry gate={}x{} up={}x{} down={}x{}",
4469                gate.out_features,
4470                gate.in_features,
4471                up.out_features,
4472                up.in_features,
4473                down.out_features,
4474                down.in_features,
4475            )
4476            .into());
4477        }
4478        validate_activations(input, tokens, gate.in_features)?;
4479        let pairs = tokens
4480            .checked_mul(STEP_GROUPED_FP8_TOP_K)
4481            .ok_or("official Step grouped FP8 route count overflow")?;
4482        if selected.len() != pairs {
4483            return Err(format!(
4484                "official Step grouped FP8 routes {} != {tokens}x{STEP_GROUPED_FP8_TOP_K} \
4485                 ({pairs})",
4486                selected.len()
4487            )
4488            .into());
4489        }
4490        for (token, routes) in selected.chunks_exact(STEP_GROUPED_FP8_TOP_K).enumerate() {
4491            let mut unique = routes.to_vec();
4492            unique.sort_unstable();
4493            unique.dedup();
4494            if unique.len() != STEP_GROUPED_FP8_TOP_K {
4495                return Err(format!(
4496                    "official Step grouped FP8 token {token} routes are not top-8 unique: \
4497                     {routes:?}"
4498                )
4499                .into());
4500            }
4501        }
4502
4503        let engine = self
4504            .ranks
4505            .first()
4506            .ok_or("official Step grouped FP8 gate has no rank-zero engine")?;
4507        let _main = engine.gpu.enter_main()?;
4508        let expert_range = 0..STEP_GROUPED_FP8_EXPERTS;
4509        let gate = upload_expert_bank_rank(engine, gate, expert_range.clone())?;
4510        let up = upload_expert_bank_rank(engine, up, expert_range.clone())?;
4511        let down = upload_expert_bank_rank(engine, down, expert_range)?;
4512        let input = engine.htod(input)?;
4513        let route_csr = ExpertCsr::from_token_routes(
4514            STEP_GROUPED_FP8_EXPERTS,
4515            tokens,
4516            STEP_GROUPED_FP8_TOP_K,
4517            selected,
4518        )?
4519        .upload(engine)?;
4520        let pair_rows = (0..pairs).collect::<Vec<_>>();
4521        let down_csr =
4522            ExpertCsr::from_pair_rows(STEP_GROUPED_FP8_EXPERTS, pairs, selected, &pair_rows)?
4523                .upload(engine)?;
4524        let gate_workspace =
4525            Fp8GroupedWorkspace::new(engine, gate.in_features, gate.out_features, tokens, pairs)?;
4526        let up_workspace =
4527            Fp8GroupedWorkspace::new(engine, up.in_features, up.out_features, tokens, pairs)?;
4528        let down_workspace =
4529            Fp8GroupedWorkspace::new(engine, down.in_features, down.out_features, pairs, pairs)?;
4530        let activation = engine.uninit(pairs * STEP_GROUPED_FP8_WIDTH)?;
4531        Ok(PreparedStepGroupedFp8Gate {
4532            device: engine.ctx().ordinal(),
4533            gate,
4534            up,
4535            down,
4536            input,
4537            route_csr,
4538            down_csr,
4539            gate_workspace,
4540            up_workspace,
4541            down_workspace,
4542            activation,
4543            activation_limit,
4544            tokens,
4545            pairs,
4546        })
4547    }
4548
4549    /// Execute one prepared gate/up/activation/down projection sequence on rank zero.
4550    pub fn run_step_grouped_fp8_gate(
4551        &self,
4552        plan: &mut PreparedStepGroupedFp8Gate,
4553    ) -> Result<StepGroupedFp8ProjectionOutput, Box<dyn std::error::Error>> {
4554        let engine = self
4555            .ranks
4556            .first()
4557            .ok_or("official Step grouped FP8 gate has no rank-zero engine")?;
4558        if engine.ctx().ordinal() != plan.device {
4559            return Err(format!(
4560                "official Step grouped FP8 plan device {} != rank-zero device {}",
4561                plan.device,
4562                engine.ctx().ordinal()
4563            )
4564            .into());
4565        }
4566        let _main = engine.gpu.enter_main()?;
4567
4568        plan.gate_workspace.quantize(engine, &plan.input)?;
4569        plan.gate_workspace.project(
4570            engine,
4571            &plan.gate.codes,
4572            &plan.gate.scales,
4573            &plan.route_csr,
4574            plan.gate.code_stride,
4575            plan.gate.scale_stride,
4576            1.0,
4577        )?;
4578        plan.up_workspace.quantize(engine, &plan.input)?;
4579        plan.up_workspace.project(
4580            engine,
4581            &plan.up.codes,
4582            &plan.up.scales,
4583            &plan.route_csr,
4584            plan.up.code_stride,
4585            plan.up.scale_stride,
4586            1.0,
4587        )?;
4588        if let Some(limit) = plan.activation_limit {
4589            engine.silu_clamped_mul_host_expf(
4590                plan.gate_workspace.output(),
4591                plan.up_workspace.output(),
4592                limit,
4593                &mut plan.activation,
4594                plan.pairs * STEP_GROUPED_FP8_WIDTH,
4595            )?;
4596        } else {
4597            engine.silu_mul_host_expf(
4598                plan.gate_workspace.output(),
4599                plan.up_workspace.output(),
4600                &mut plan.activation,
4601                plan.pairs * STEP_GROUPED_FP8_WIDTH,
4602            )?;
4603        }
4604        plan.down_workspace.quantize(engine, &plan.activation)?;
4605        plan.down_workspace.project(
4606            engine,
4607            &plan.down.codes,
4608            &plan.down.scales,
4609            &plan.down_csr,
4610            plan.down.code_stride,
4611            plan.down.scale_stride,
4612            1.0,
4613        )?;
4614
4615        Ok(StepGroupedFp8ProjectionOutput {
4616            gate: engine.dtoh(plan.gate_workspace.output())?,
4617            up: engine.dtoh(plan.up_workspace.output())?,
4618            down: engine.dtoh(plan.down_workspace.output())?,
4619        })
4620    }
4621
4622    pub fn prepare_step_grouped_expert_parallel_gate(
4623        &self,
4624        experts: &ResidentExpertParallel,
4625        input: &[f32],
4626        tokens: usize,
4627        selected: &[usize],
4628        activation_limit: Option<f32>,
4629    ) -> Result<PreparedStepGroupedExpertParallelGate, Box<dyn std::error::Error>> {
4630        self.prepare_step_grouped_expert_parallel_gate_with_capacity(
4631            experts,
4632            input,
4633            tokens,
4634            selected,
4635            activation_limit,
4636            tokens,
4637        )
4638    }
4639
4640    #[allow(clippy::too_many_arguments)]
4641    pub fn prepare_step_grouped_expert_parallel_gate_with_capacity(
4642        &self,
4643        experts: &ResidentExpertParallel,
4644        input: &[f32],
4645        tokens: usize,
4646        selected: &[usize],
4647        activation_limit: Option<f32>,
4648        max_tokens: usize,
4649    ) -> Result<PreparedStepGroupedExpertParallelGate, Box<dyn std::error::Error>> {
4650        if !self.native_p2p || !self.ep_device_arithmetic {
4651            return Err(
4652                "Step owner-grouped FP8 requires native P2P and device-resident arithmetic".into(),
4653            );
4654        }
4655        validate_step_expert_activation_limit(activation_limit)?;
4656        validate_ep_residency(&self.ranks, experts)?;
4657        validate_activations(input, tokens, experts.input_width)?;
4658        if max_tokens < tokens || max_tokens > i32::MAX as usize {
4659            return Err(format!(
4660                "official Step owner-grouped FP8 tokens {tokens} exceed capacity {max_tokens}"
4661            )
4662            .into());
4663        }
4664        if experts.expert_count != STEP_GROUPED_FP8_EXPERTS
4665            || experts.expert_width != STEP_GROUPED_FP8_WIDTH
4666        {
4667            return Err(format!(
4668                "official Step owner-grouped FP8 requires {} experts at width {}, got {} at {}",
4669                STEP_GROUPED_FP8_EXPERTS,
4670                STEP_GROUPED_FP8_WIDTH,
4671                experts.expert_count,
4672                experts.expert_width,
4673            )
4674            .into());
4675        }
4676        validate_step_grouped_owner_routes(experts.expert_count, tokens, selected)?;
4677        let max_pairs = max_tokens
4678            .checked_mul(STEP_GROUPED_FP8_TOP_K)
4679            .ok_or("official Step owner-grouped FP8 capacity route count overflow")?;
4680        let input_capacity = max_tokens
4681            .checked_mul(experts.input_width)
4682            .ok_or("official Step owner-grouped FP8 input capacity overflow")?;
4683
4684        let mut rank_inputs = Vec::with_capacity(self.ranks.len());
4685        for engine in &self.ranks {
4686            let _main = engine.gpu.enter_main()?;
4687            rank_inputs.push(engine.uninit(input_capacity)?);
4688        }
4689
4690        let mut owners = Vec::with_capacity(self.ranks.len());
4691        for (owner_rank, rank) in experts.ranks.iter().enumerate() {
4692            if rank.gate.expert_range != rank.up.expert_range
4693                || rank.gate.expert_range != rank.down.expert_range
4694            {
4695                return Err(format!(
4696                    "owner-grouped FP8 rank {} gate/up/down expert ranges differ",
4697                    owner_rank
4698                )
4699                .into());
4700            }
4701            let local_experts = rank.gate.expert_range.len();
4702            let engine = &self.ranks[owner_rank];
4703            let _main = engine.gpu.enter_main()?;
4704            let route_csr =
4705                DeviceExpertCsr::with_capacity(engine, local_experts, max_tokens, max_pairs)?;
4706            let down_csr =
4707                DeviceExpertCsr::with_capacity(engine, local_experts, max_pairs, max_pairs)?;
4708            let gate_workspace = Fp8GroupedWorkspace::new(
4709                engine,
4710                experts.input_width,
4711                experts.expert_width,
4712                max_tokens,
4713                max_pairs,
4714            )?;
4715            let up_workspace = Fp8GroupedWorkspace::new(
4716                engine,
4717                experts.input_width,
4718                experts.expert_width,
4719                max_tokens,
4720                max_pairs,
4721            )?;
4722            let down_workspace = Fp8GroupedWorkspace::new(
4723                engine,
4724                experts.expert_width,
4725                experts.input_width,
4726                max_pairs,
4727                max_pairs,
4728            )?;
4729            let activation = engine.uninit(
4730                max_pairs
4731                    .checked_mul(experts.expert_width)
4732                    .ok_or("official Step owner-grouped FP8 activation capacity overflow")?,
4733            )?;
4734            owners.push(PreparedStepGroupedExpertOwner {
4735                rank: owner_rank,
4736                global_pairs: Vec::new(),
4737                route_csr,
4738                down_csr,
4739                gate_workspace,
4740                up_workspace,
4741                down_workspace,
4742                activation,
4743            });
4744        }
4745
4746        let mut plan = PreparedStepGroupedExpertParallelGate {
4747            rank_inputs,
4748            owners,
4749            activation_limit,
4750            tokens: 0,
4751            pairs: 0,
4752            max_tokens,
4753            max_pairs,
4754            input_width: experts.input_width,
4755            expert_width: experts.expert_width,
4756            generation: 0,
4757            executed_generation: None,
4758            ready: false,
4759        };
4760        self.refresh_step_grouped_expert_parallel_gate(
4761            experts, &mut plan, input, tokens, selected,
4762        )?;
4763        Ok(plan)
4764    }
4765
4766    #[allow(clippy::type_complexity)] // allow: one-shot composite type; naming it would hide the shape that matters at the call site
4767    fn prepare_step_grouped_expert_parallel_refresh(
4768        &self,
4769        experts: &ResidentExpertParallel,
4770        plan: &PreparedStepGroupedExpertParallelGate,
4771        tokens: usize,
4772        selected: &[usize],
4773    ) -> Result<(usize, u64, Vec<Option<StepGroupedExpertOwnerSchedule>>), Box<dyn std::error::Error>>
4774    {
4775        validate_ep_residency(&self.ranks, experts)?;
4776        if plan.rank_inputs.len() != self.ranks.len()
4777            || plan.owners.len() != self.ranks.len()
4778            || plan.input_width != experts.input_width
4779            || plan.expert_width != experts.expert_width
4780            || tokens > plan.max_tokens
4781        {
4782            return Err(format!(
4783                "Step owner-grouped FP8 refresh geometry changed ranks={}/{} owners={}/{} \
4784                 input={}/{} expert={}/{} tokens={}/{}",
4785                plan.rank_inputs.len(),
4786                self.ranks.len(),
4787                plan.owners.len(),
4788                self.ranks.len(),
4789                plan.input_width,
4790                experts.input_width,
4791                plan.expert_width,
4792                experts.expert_width,
4793                tokens,
4794                plan.max_tokens,
4795            )
4796            .into());
4797        }
4798        let pairs = validate_step_grouped_owner_routes(experts.expert_count, tokens, selected)?;
4799        if pairs > plan.max_pairs {
4800            return Err(format!(
4801                "Step owner-grouped FP8 route count {pairs} exceeds capacity {}",
4802                plan.max_pairs
4803            )
4804            .into());
4805        }
4806        let next_generation = plan
4807            .generation
4808            .checked_add(1)
4809            .ok_or("Step owner-grouped FP8 plan generation overflow")?;
4810        let owner_routes = partition_expert_owner_routes(
4811            experts.expert_count,
4812            self.ranks.len(),
4813            tokens,
4814            STEP_GROUPED_FP8_TOP_K,
4815            selected,
4816        )?;
4817        let mut schedules = Vec::with_capacity(self.ranks.len());
4818        for routes in owner_routes {
4819            if routes.selected.is_empty() {
4820                schedules.push(None);
4821                continue;
4822            }
4823            let local_experts = experts.ranks[routes.rank].gate.expert_range.len();
4824            let local_pairs = routes.selected.len();
4825            let route_csr = ExpertCsr::from_pair_rows(
4826                local_experts,
4827                tokens,
4828                &routes.selected,
4829                &routes.token_rows,
4830            )?;
4831            let down_rows = (0..local_pairs).collect::<Vec<_>>();
4832            let down_csr = ExpertCsr::from_pair_rows(
4833                local_experts,
4834                local_pairs,
4835                &routes.selected,
4836                &down_rows,
4837            )?;
4838            schedules.push(Some(StepGroupedExpertOwnerSchedule {
4839                global_pairs: routes.global_pairs,
4840                route_csr,
4841                down_csr,
4842            }));
4843        }
4844        Ok((pairs, next_generation, schedules))
4845    }
4846
4847    fn commit_step_grouped_expert_parallel_refresh(
4848        &self,
4849        plan: &mut PreparedStepGroupedExpertParallelGate,
4850        tokens: usize,
4851        pairs: usize,
4852        next_generation: u64,
4853        schedules: Vec<Option<StepGroupedExpertOwnerSchedule>>,
4854    ) -> Result<(), Box<dyn std::error::Error>> {
4855        for (owner, schedule) in plan.owners.iter_mut().zip(schedules) {
4856            let engine = &self.ranks[owner.rank];
4857            let _main = engine.gpu.enter_main()?;
4858            if let Some(schedule) = schedule {
4859                owner.route_csr.refresh(engine, &schedule.route_csr)?;
4860                owner.down_csr.refresh(engine, &schedule.down_csr)?;
4861                owner.global_pairs = schedule.global_pairs;
4862            } else {
4863                owner.route_csr.clear();
4864                owner.down_csr.clear();
4865                owner.global_pairs.clear();
4866            }
4867        }
4868        plan.tokens = tokens;
4869        plan.pairs = pairs;
4870        plan.generation = next_generation;
4871        plan.ready = true;
4872        Ok(())
4873    }
4874
4875    pub fn refresh_step_grouped_expert_parallel_gate(
4876        &self,
4877        experts: &ResidentExpertParallel,
4878        plan: &mut PreparedStepGroupedExpertParallelGate,
4879        input: &[f32],
4880        tokens: usize,
4881        selected: &[usize],
4882    ) -> Result<(), Box<dyn std::error::Error>> {
4883        validate_activations(input, tokens, experts.input_width)?;
4884        let (pairs, next_generation, schedules) =
4885            self.prepare_step_grouped_expert_parallel_refresh(experts, plan, tokens, selected)?;
4886
4887        plan.ready = false;
4888        plan.executed_generation = None;
4889        {
4890            let root = &self.ranks[0];
4891            let _main = root.gpu.enter_main()?;
4892            let mut destination = plan.rank_inputs[0].slice_mut(0..input.len());
4893            root.stream().memcpy_htod(input, &mut destination)?;
4894            root.stream().synchronize()?;
4895        }
4896        let (root_inputs, peer_inputs) = plan.rank_inputs.split_at_mut(1);
4897        let root_input = &root_inputs[0];
4898        for (rank, peer_input) in peer_inputs.iter_mut().enumerate() {
4899            let engine = &self.ranks[rank + 1];
4900            let _main = engine.gpu.enter_main()?;
4901            let mut destination = peer_input.slice_mut(0..input.len());
4902            engine
4903                .stream()
4904                .memcpy_dtod(&root_input.slice(0..input.len()), &mut destination)?;
4905        }
4906        self.commit_step_grouped_expert_parallel_refresh(
4907            plan,
4908            tokens,
4909            pairs,
4910            next_generation,
4911            schedules,
4912        )
4913    }
4914
4915    /// Refresh routes and inputs from an already-resident rank-zero activation.
4916    ///
4917    /// The caller must order the source producer before this call. The root copy is completed
4918    /// before peer dispatch, while CSR and workspace allocations retain their stable addresses.
4919    pub fn refresh_step_grouped_expert_parallel_gate_from_root_device(
4920        &self,
4921        experts: &ResidentExpertParallel,
4922        plan: &mut PreparedStepGroupedExpertParallelGate,
4923        input: &CudaSlice<f32>,
4924        tokens: usize,
4925        selected: &[usize],
4926    ) -> Result<(), Box<dyn std::error::Error>> {
4927        let input_values = tokens
4928            .checked_mul(experts.input_width)
4929            .ok_or("Step owner-grouped FP8 input size overflow")?;
4930        let root = self
4931            .ranks
4932            .first()
4933            .ok_or("Step owner-grouped FP8 runtime has no root rank")?;
4934        if input.len() < input_values || input.ordinal() != root.ctx().ordinal() {
4935            return Err(format!(
4936                "Step owner-grouped FP8 root input len/device {}/{} does not cover {} values on \
4937                 device {}",
4938                input.len(),
4939                input.ordinal(),
4940                input_values,
4941                root.ctx().ordinal(),
4942            )
4943            .into());
4944        }
4945        let (pairs, next_generation, schedules) =
4946            self.prepare_step_grouped_expert_parallel_refresh(experts, plan, tokens, selected)?;
4947
4948        plan.ready = false;
4949        plan.executed_generation = None;
4950        {
4951            let _main = root.gpu.enter_main()?;
4952            let mut destination = plan.rank_inputs[0].slice_mut(0..input_values);
4953            root.stream()
4954                .memcpy_dtod(&input.slice(0..input_values), &mut destination)?;
4955            root.stream().synchronize()?;
4956        }
4957        let (root_inputs, peer_inputs) = plan.rank_inputs.split_at_mut(1);
4958        let root_input = &root_inputs[0];
4959        for (rank, peer_input) in peer_inputs.iter_mut().enumerate() {
4960            let engine = &self.ranks[rank + 1];
4961            let _main = engine.gpu.enter_main()?;
4962            let mut destination = peer_input.slice_mut(0..input_values);
4963            engine
4964                .stream()
4965                .memcpy_dtod(&root_input.slice(0..input_values), &mut destination)?;
4966        }
4967        self.commit_step_grouped_expert_parallel_refresh(
4968            plan,
4969            tokens,
4970            pairs,
4971            next_generation,
4972            schedules,
4973        )
4974    }
4975
4976    /// Replace a fixed route plan's rank inputs from an already replicated device batch.
4977    ///
4978    /// Route CSR remains unchanged. Advancing the generation invalidates every prior projection
4979    /// and combine result, so callers must refresh combine metadata before executing again.
4980    pub fn refresh_step_grouped_expert_parallel_inputs_from_replicated(
4981        &self,
4982        experts: &ResidentExpertParallel,
4983        plan: &mut PreparedStepGroupedExpertParallelGate,
4984        input: &ResidentReplicatedDeviceRows,
4985    ) -> Result<(), Box<dyn std::error::Error>> {
4986        validate_ep_residency(&self.ranks, experts)?;
4987        validate_replicated_device_rows(&self.ranks, input)?;
4988        if !plan.ready
4989            || input.tokens != plan.tokens
4990            || input.width != plan.input_width
4991            || input.tokens > plan.max_tokens
4992            || plan.rank_inputs.len() != self.ranks.len()
4993            || plan.owners.len() != self.ranks.len()
4994            || plan.input_width != experts.input_width
4995            || plan.expert_width != experts.expert_width
4996        {
4997            return Err("Step owner-grouped replicated input geometry changed".into());
4998        }
4999        let values = input
5000            .tokens
5001            .checked_mul(input.width)
5002            .ok_or("Step owner-grouped replicated input size overflow")?;
5003        let next_generation = plan
5004            .generation
5005            .checked_add(1)
5006            .ok_or("Step owner-grouped FP8 plan generation overflow")?;
5007        plan.ready = false;
5008        plan.executed_generation = None;
5009        for (rank, engine) in self.ranks.iter().enumerate() {
5010            let _main = engine.gpu.enter_main()?;
5011            let mut destination = plan.rank_inputs[rank].slice_mut(0..values);
5012            engine
5013                .stream()
5014                .memcpy_dtod(&input.ranks[rank], &mut destination)?;
5015        }
5016        plan.generation = next_generation;
5017        plan.ready = true;
5018        Ok(())
5019    }
5020
5021    pub fn execute_step_grouped_expert_parallel_gate(
5022        &self,
5023        experts: &ResidentExpertParallel,
5024        plan: &mut PreparedStepGroupedExpertParallelGate,
5025    ) -> Result<(), Box<dyn std::error::Error>> {
5026        validate_ep_residency(&self.ranks, experts)?;
5027        if !plan.ready
5028            || plan.rank_inputs.len() != self.ranks.len()
5029            || plan.owners.len() != self.ranks.len()
5030            || plan.input_width != experts.input_width
5031            || plan.expert_width != experts.expert_width
5032        {
5033            return Err("Step owner-grouped FP8 plan is not ready or its geometry changed".into());
5034        }
5035        plan.executed_generation = None;
5036
5037        for owner in &mut plan.owners {
5038            if owner.global_pairs.is_empty() {
5039                continue;
5040            }
5041            let engine = &self.ranks[owner.rank];
5042            let bank = &experts.ranks[owner.rank];
5043            let _main = engine.gpu.enter_main()?;
5044            let local_pairs = owner.global_pairs.len();
5045            owner.gate_workspace.quantize_for_shape(
5046                engine,
5047                &plan.rank_inputs[owner.rank],
5048                plan.tokens,
5049                local_pairs,
5050            )?;
5051            owner.gate_workspace.project(
5052                engine,
5053                &bank.gate.codes,
5054                &bank.gate.scales,
5055                &owner.route_csr,
5056                bank.gate.code_stride,
5057                bank.gate.scale_stride,
5058                1.0,
5059            )?;
5060            owner.up_workspace.quantize_for_shape(
5061                engine,
5062                &plan.rank_inputs[owner.rank],
5063                plan.tokens,
5064                local_pairs,
5065            )?;
5066            owner.up_workspace.project(
5067                engine,
5068                &bank.up.codes,
5069                &bank.up.scales,
5070                &owner.route_csr,
5071                bank.up.code_stride,
5072                bank.up.scale_stride,
5073                1.0,
5074            )?;
5075        }
5076        for owner in &mut plan.owners {
5077            if owner.global_pairs.is_empty() {
5078                continue;
5079            }
5080            let engine = &self.ranks[owner.rank];
5081            let _main = engine.gpu.enter_main()?;
5082            let values = owner.global_pairs.len() * plan.expert_width;
5083            if let Some(limit) = plan.activation_limit {
5084                engine.silu_clamped_mul_host_expf(
5085                    owner.gate_workspace.output(),
5086                    owner.up_workspace.output(),
5087                    limit,
5088                    &mut owner.activation,
5089                    values,
5090                )?;
5091            } else {
5092                engine.silu_mul_host_expf(
5093                    owner.gate_workspace.output(),
5094                    owner.up_workspace.output(),
5095                    &mut owner.activation,
5096                    values,
5097                )?;
5098            }
5099        }
5100        for owner in &mut plan.owners {
5101            if owner.global_pairs.is_empty() {
5102                continue;
5103            }
5104            let engine = &self.ranks[owner.rank];
5105            let bank = &experts.ranks[owner.rank];
5106            let _main = engine.gpu.enter_main()?;
5107            let local_pairs = owner.global_pairs.len();
5108            owner.down_workspace.quantize_for_shape(
5109                engine,
5110                &owner.activation,
5111                local_pairs,
5112                local_pairs,
5113            )?;
5114            owner.down_workspace.project(
5115                engine,
5116                &bank.down.codes,
5117                &bank.down.scales,
5118                &owner.down_csr,
5119                bank.down.code_stride,
5120                bank.down.scale_stride,
5121                1.0,
5122            )?;
5123        }
5124        plan.executed_generation = Some(plan.generation);
5125        Ok(())
5126    }
5127
5128    pub fn collect_step_grouped_expert_parallel_gate(
5129        &self,
5130        plan: &PreparedStepGroupedExpertParallelGate,
5131    ) -> Result<StepGroupedFp8ProjectionOutput, Box<dyn std::error::Error>> {
5132        if !plan.ready || plan.executed_generation != Some(plan.generation) {
5133            return Err("Step owner-grouped FP8 projection is stale or has not executed".into());
5134        }
5135        let mut gate = vec![0.0f32; plan.pairs * plan.expert_width];
5136        let mut up = vec![0.0f32; plan.pairs * plan.expert_width];
5137        let mut down = vec![0.0f32; plan.pairs * plan.input_width];
5138        for owner in &plan.owners {
5139            if owner.global_pairs.is_empty() {
5140                continue;
5141            }
5142            let engine = &self.ranks[owner.rank];
5143            let _main = engine.gpu.enter_main()?;
5144            let owner_gate = engine.dtoh_view(
5145                &owner
5146                    .gate_workspace
5147                    .output()
5148                    .slice(0..owner.gate_workspace.output_len()),
5149            )?;
5150            let owner_up = engine.dtoh_view(
5151                &owner
5152                    .up_workspace
5153                    .output()
5154                    .slice(0..owner.up_workspace.output_len()),
5155            )?;
5156            let owner_down = engine.dtoh_view(
5157                &owner
5158                    .down_workspace
5159                    .output()
5160                    .slice(0..owner.down_workspace.output_len()),
5161            )?;
5162            for (local_pair, &global_pair) in owner.global_pairs.iter().enumerate() {
5163                let local_expert = local_pair * plan.expert_width;
5164                let global_expert = global_pair * plan.expert_width;
5165                gate[global_expert..global_expert + plan.expert_width]
5166                    .copy_from_slice(&owner_gate[local_expert..local_expert + plan.expert_width]);
5167                up[global_expert..global_expert + plan.expert_width]
5168                    .copy_from_slice(&owner_up[local_expert..local_expert + plan.expert_width]);
5169
5170                let local_hidden = local_pair * plan.input_width;
5171                let global_hidden = global_pair * plan.input_width;
5172                down[global_hidden..global_hidden + plan.input_width]
5173                    .copy_from_slice(&owner_down[local_hidden..local_hidden + plan.input_width]);
5174            }
5175        }
5176        Ok(StepGroupedFp8ProjectionOutput { gate, up, down })
5177    }
5178
5179    pub fn run_step_grouped_expert_parallel_gate(
5180        &self,
5181        experts: &ResidentExpertParallel,
5182        plan: &mut PreparedStepGroupedExpertParallelGate,
5183    ) -> Result<StepGroupedFp8ProjectionOutput, Box<dyn std::error::Error>> {
5184        self.execute_step_grouped_expert_parallel_gate(experts, plan)?;
5185        self.collect_step_grouped_expert_parallel_gate(plan)
5186    }
5187
5188    pub fn prepare_step_grouped_expert_parallel_combine(
5189        &self,
5190        plan: &PreparedStepGroupedExpertParallelGate,
5191        route_weights: &[f32],
5192    ) -> Result<PreparedPeerWeightedRouteCombine, Box<dyn std::error::Error>> {
5193        if !self.native_p2p || !self.ep_device_arithmetic || !plan.ready {
5194            return Err(
5195                "Step owner-grouped combine requires a ready native-P2P device plan".into(),
5196            );
5197        }
5198        let owner_pairs = plan
5199            .owners
5200            .iter()
5201            .map(|owner| owner.global_pairs.as_slice())
5202            .collect::<Vec<_>>();
5203        let shape = validate_weighted_route_combine(
5204            plan.input_width,
5205            STEP_GROUPED_FP8_TOP_K,
5206            plan.max_tokens,
5207            plan.tokens,
5208            &owner_pairs,
5209            route_weights,
5210        )?;
5211        if shape.max_pairs != plan.max_pairs {
5212            return Err(format!(
5213                "Step owner-grouped combine capacity {} != projection capacity {}",
5214                shape.max_pairs, plan.max_pairs
5215            )
5216            .into());
5217        }
5218        let root = self
5219            .ranks
5220            .first()
5221            .ok_or("Step owner-grouped combine has no root rank")?;
5222        let slot_values = shape
5223            .max_pairs
5224            .checked_mul(plan.input_width)
5225            .ok_or("Step owner-grouped combine slot capacity overflow")?;
5226        let output_values = plan
5227            .max_tokens
5228            .checked_mul(plan.input_width)
5229            .ok_or("Step owner-grouped combine output capacity overflow")?;
5230        let (root_device, owners, peer_staging, slots, weights, output) = {
5231            let _main = root.gpu.enter_main()?;
5232            let mut owners = Vec::with_capacity(plan.owners.len());
5233            for _ in &plan.owners {
5234                owners.push(PreparedPeerWeightedRouteOwner {
5235                    token_rows: root.htod_i32(&vec![0; shape.max_pairs])?,
5236                    slots: root.htod_i32(&vec![0; shape.max_pairs])?,
5237                    weights: root.htod(&vec![0.0; shape.max_pairs])?,
5238                    active_pairs: 0,
5239                });
5240            }
5241            (
5242                root.ctx().ordinal(),
5243                owners,
5244                root.uninit(slot_values)?,
5245                root.uninit(slot_values)?,
5246                root.uninit(shape.max_pairs)?,
5247                root.uninit(output_values)?,
5248            )
5249        };
5250        let mut peer_devices = Vec::with_capacity(self.ranks.len().saturating_sub(1));
5251        let mut peer_outputs = Vec::with_capacity(self.ranks.len().saturating_sub(1));
5252        for engine in self.ranks.iter().skip(1) {
5253            let _main = engine.gpu.enter_main()?;
5254            peer_devices.push(engine.ctx().ordinal());
5255            peer_outputs.push(engine.uninit(output_values)?);
5256        }
5257        let mut combine = PreparedPeerWeightedRouteCombine {
5258            root_device,
5259            owners,
5260            peer_staging,
5261            slots,
5262            weights,
5263            output,
5264            peer_devices,
5265            peer_outputs,
5266            width: plan.input_width,
5267            experts_per_token: STEP_GROUPED_FP8_TOP_K,
5268            max_tokens: plan.max_tokens,
5269            max_pairs: shape.max_pairs,
5270            tokens: 0,
5271            pairs: 0,
5272            projection_generation: 0,
5273            output_generation: None,
5274            broadcast_generation: None,
5275            ready: false,
5276        };
5277        self.refresh_step_grouped_expert_parallel_combine(plan, &mut combine, route_weights)?;
5278        Ok(combine)
5279    }
5280
5281    pub fn refresh_step_grouped_expert_parallel_combine(
5282        &self,
5283        plan: &PreparedStepGroupedExpertParallelGate,
5284        combine: &mut PreparedPeerWeightedRouteCombine,
5285        route_weights: &[f32],
5286    ) -> Result<(), Box<dyn std::error::Error>> {
5287        let output_capacity = combine
5288            .max_tokens
5289            .checked_mul(combine.width)
5290            .ok_or("Step owner-grouped combine output capacity overflow")?;
5291        if !plan.ready
5292            || combine.owners.len() != plan.owners.len()
5293            || combine.peer_devices.len() + 1 != self.ranks.len()
5294            || combine.peer_outputs.len() + 1 != self.ranks.len()
5295            || combine.width != plan.input_width
5296            || combine.experts_per_token != STEP_GROUPED_FP8_TOP_K
5297            || combine.max_tokens != plan.max_tokens
5298            || combine.max_pairs != plan.max_pairs
5299            || combine.output.len() < output_capacity
5300            || combine
5301                .peer_outputs
5302                .iter()
5303                .any(|output| output.len() < output_capacity)
5304        {
5305            return Err("Step owner-grouped combine/projection geometry changed".into());
5306        }
5307        if self
5308            .ranks
5309            .iter()
5310            .skip(1)
5311            .zip(&combine.peer_devices)
5312            .any(|(engine, &device)| engine.ctx().ordinal() != device)
5313        {
5314            return Err("Step owner-grouped combine peer devices changed".into());
5315        }
5316        let owner_pairs = plan
5317            .owners
5318            .iter()
5319            .map(|owner| owner.global_pairs.as_slice())
5320            .collect::<Vec<_>>();
5321        let shape = validate_weighted_route_combine(
5322            combine.width,
5323            combine.experts_per_token,
5324            combine.max_tokens,
5325            plan.tokens,
5326            &owner_pairs,
5327            route_weights,
5328        )?;
5329        if shape.max_pairs != combine.max_pairs {
5330            return Err("Step owner-grouped combine capacity changed during refresh".into());
5331        }
5332        let metadata = owner_pairs
5333            .iter()
5334            .map(|pairs| {
5335                let token_rows = pairs
5336                    .iter()
5337                    .map(|&pair| (pair / combine.experts_per_token) as i32)
5338                    .collect::<Vec<_>>();
5339                let slots = pairs
5340                    .iter()
5341                    .map(|&pair| (pair % combine.experts_per_token) as i32)
5342                    .collect::<Vec<_>>();
5343                let weights = pairs
5344                    .iter()
5345                    .map(|&pair| route_weights[pair])
5346                    .collect::<Vec<_>>();
5347                (token_rows, slots, weights)
5348            })
5349            .collect::<Vec<_>>();
5350
5351        combine.ready = false;
5352        combine.output_generation = None;
5353        combine.broadcast_generation = None;
5354        let root = self
5355            .ranks
5356            .first()
5357            .ok_or("Step owner-grouped combine has no root rank")?;
5358        let _main = root.gpu.enter_main()?;
5359        if root.ctx().ordinal() != combine.root_device {
5360            return Err(format!(
5361                "Step owner-grouped combine root device changed {} != {}",
5362                root.ctx().ordinal(),
5363                combine.root_device
5364            )
5365            .into());
5366        }
5367        for (owner, (token_rows, slots, weights)) in combine.owners.iter_mut().zip(metadata) {
5368            if token_rows.is_empty() {
5369                owner.active_pairs = 0;
5370                continue;
5371            }
5372            root.htod_i32_into(&mut owner.token_rows, &token_rows)?;
5373            root.htod_i32_into(&mut owner.slots, &slots)?;
5374            let mut weight_prefix = owner.weights.slice_mut(0..weights.len());
5375            root.stream().memcpy_htod(&weights, &mut weight_prefix)?;
5376            owner.active_pairs = token_rows.len();
5377        }
5378        combine.tokens = plan.tokens;
5379        combine.pairs = shape.pairs;
5380        combine.projection_generation = plan.generation;
5381        combine.ready = true;
5382        Ok(())
5383    }
5384
5385    pub fn execute_step_grouped_expert_parallel_combine(
5386        &self,
5387        plan: &PreparedStepGroupedExpertParallelGate,
5388        combine: &mut PreparedPeerWeightedRouteCombine,
5389    ) -> Result<(), Box<dyn std::error::Error>> {
5390        if !plan.ready
5391            || plan.executed_generation != Some(plan.generation)
5392            || !combine.ready
5393            || combine.tokens != plan.tokens
5394            || combine.pairs != plan.pairs
5395            || combine.width != plan.input_width
5396            || combine.owners.len() != plan.owners.len()
5397            || combine.projection_generation != plan.generation
5398        {
5399            return Err("Step owner-grouped combine is stale or its geometry changed".into());
5400        }
5401        combine.output_generation = None;
5402        combine.broadcast_generation = None;
5403        for owner in &plan.owners {
5404            if owner.rank == 0 || owner.global_pairs.is_empty() {
5405                continue;
5406            }
5407            let engine = &self.ranks[owner.rank];
5408            let _main = engine.gpu.enter_main()?;
5409            engine.stream().synchronize()?;
5410        }
5411        let root = self
5412            .ranks
5413            .first()
5414            .ok_or("Step owner-grouped combine has no root rank")?;
5415        let _main = root.gpu.enter_main()?;
5416        if root.ctx().ordinal() != combine.root_device {
5417            return Err("Step owner-grouped combine is not resident on the root device".into());
5418        }
5419        for (index, owner) in plan.owners.iter().enumerate() {
5420            let metadata = &combine.owners[index];
5421            if owner.global_pairs.len() != metadata.active_pairs {
5422                return Err(format!(
5423                    "Step owner-grouped combine owner {index} rows {} != metadata {}",
5424                    owner.global_pairs.len(),
5425                    metadata.active_pairs
5426                )
5427                .into());
5428            }
5429            if metadata.active_pairs == 0 {
5430                continue;
5431            }
5432            let values = metadata
5433                .active_pairs
5434                .checked_mul(combine.width)
5435                .ok_or("Step owner-grouped combine peer value count overflow")?;
5436            if owner.rank == 0 {
5437                root.scatter_slot(
5438                    owner.down_workspace.output(),
5439                    &metadata.token_rows,
5440                    &metadata.slots,
5441                    &metadata.weights,
5442                    &mut combine.slots,
5443                    &mut combine.weights,
5444                    combine.width,
5445                    combine.experts_per_token,
5446                    metadata.active_pairs,
5447                )?;
5448            } else {
5449                let source = owner.down_workspace.output().slice(0..values);
5450                let mut destination = combine.peer_staging.slice_mut(0..values);
5451                root.stream().memcpy_dtod(&source, &mut destination)?;
5452                root.scatter_slot(
5453                    &combine.peer_staging,
5454                    &metadata.token_rows,
5455                    &metadata.slots,
5456                    &metadata.weights,
5457                    &mut combine.slots,
5458                    &mut combine.weights,
5459                    combine.width,
5460                    combine.experts_per_token,
5461                    metadata.active_pairs,
5462                )?;
5463            }
5464        }
5465        root.reduce_slots_host(
5466            &combine.slots,
5467            &combine.weights,
5468            &mut combine.output,
5469            combine.width,
5470            combine.experts_per_token,
5471            combine.tokens,
5472        )?;
5473        combine.output_generation = Some(plan.generation);
5474        Ok(())
5475    }
5476
5477    pub fn collect_step_grouped_expert_parallel_combine(
5478        &self,
5479        plan: &PreparedStepGroupedExpertParallelGate,
5480        combine: &PreparedPeerWeightedRouteCombine,
5481    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
5482        if !plan.ready
5483            || combine.output_generation != Some(plan.generation)
5484            || combine.projection_generation != plan.generation
5485        {
5486            return Err("Step owner-grouped combine output is stale or has not executed".into());
5487        }
5488        let root = self
5489            .ranks
5490            .first()
5491            .ok_or("Step owner-grouped combine has no root rank")?;
5492        let _main = root.gpu.enter_main()?;
5493        if root.ctx().ordinal() != combine.root_device {
5494            return Err("Step owner-grouped combine is not resident on the root device".into());
5495        }
5496        root.dtoh_view(&combine.output.slice(0..combine.tokens * combine.width))
5497    }
5498
5499    /// Copy the active root combine result into a caller-owned engine on the same CUDA device.
5500    ///
5501    /// The persistent combine buffer remains reusable by the next route generation; the returned
5502    /// allocation follows the serving runtime's ordinary transient-output ownership.
5503    pub fn copy_step_grouped_expert_parallel_combine_root(
5504        &self,
5505        plan: &PreparedStepGroupedExpertParallelGate,
5506        combine: &PreparedPeerWeightedRouteCombine,
5507        destination: &Engine,
5508    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
5509        if !plan.ready
5510            || combine.output_generation != Some(plan.generation)
5511            || combine.projection_generation != plan.generation
5512        {
5513            return Err("Step owner-grouped combine output is stale or has not executed".into());
5514        }
5515        let root = self
5516            .ranks
5517            .first()
5518            .ok_or("Step owner-grouped combine has no root rank")?;
5519        if root.ctx().ordinal() != combine.root_device
5520            || destination.ctx().ordinal() != combine.root_device
5521        {
5522            return Err(format!(
5523                "Step owner-grouped combine root/destination devices {}/{} != {}",
5524                root.ctx().ordinal(),
5525                destination.ctx().ordinal(),
5526                combine.root_device,
5527            )
5528            .into());
5529        }
5530        let values = combine
5531            .tokens
5532            .checked_mul(combine.width)
5533            .ok_or("Step owner-grouped combine copy size overflow")?;
5534        {
5535            let _main = root.gpu.enter_main()?;
5536            root.stream().synchronize()?;
5537        }
5538        let _main = destination.gpu.enter_main()?;
5539        let mut output = destination.uninit(values)?;
5540        destination
5541            .stream()
5542            .memcpy_dtod(&combine.output.slice(0..values), &mut output)?;
5543        Ok(output)
5544    }
5545
5546    pub fn broadcast_step_grouped_expert_parallel_combine(
5547        &self,
5548        plan: &PreparedStepGroupedExpertParallelGate,
5549        combine: &mut PreparedPeerWeightedRouteCombine,
5550    ) -> Result<(), Box<dyn std::error::Error>> {
5551        if !plan.ready
5552            || combine.output_generation != Some(plan.generation)
5553            || combine.projection_generation != plan.generation
5554            || combine.peer_devices.len() + 1 != self.ranks.len()
5555            || combine.peer_outputs.len() + 1 != self.ranks.len()
5556        {
5557            return Err("Step owner-grouped combine output cannot be broadcast".into());
5558        }
5559        combine.broadcast_generation = None;
5560        let values = combine
5561            .tokens
5562            .checked_mul(combine.width)
5563            .ok_or("Step owner-grouped combine broadcast size overflow")?;
5564        {
5565            let root = self
5566                .ranks
5567                .first()
5568                .ok_or("Step owner-grouped combine has no root rank")?;
5569            let _main = root.gpu.enter_main()?;
5570            if root.ctx().ordinal() != combine.root_device {
5571                return Err("Step owner-grouped combine root device changed".into());
5572            }
5573            root.stream().synchronize()?;
5574        }
5575        let source = &combine.output;
5576        for (index, destination_buffer) in combine.peer_outputs.iter_mut().enumerate() {
5577            let engine = &self.ranks[index + 1];
5578            let _main = engine.gpu.enter_main()?;
5579            if engine.ctx().ordinal() != combine.peer_devices[index] {
5580                return Err(format!(
5581                    "Step owner-grouped combine peer {} device changed",
5582                    index + 1
5583                )
5584                .into());
5585            }
5586            let mut destination = destination_buffer.slice_mut(0..values);
5587            engine
5588                .stream()
5589                .memcpy_dtod(&source.slice(0..values), &mut destination)?;
5590        }
5591        combine.broadcast_generation = Some(plan.generation);
5592        Ok(())
5593    }
5594
5595    pub fn collect_step_grouped_expert_parallel_broadcast(
5596        &self,
5597        plan: &PreparedStepGroupedExpertParallelGate,
5598        combine: &PreparedPeerWeightedRouteCombine,
5599    ) -> Result<Vec<Vec<f32>>, Box<dyn std::error::Error>> {
5600        if !plan.ready
5601            || combine.output_generation != Some(plan.generation)
5602            || combine.broadcast_generation != Some(plan.generation)
5603            || combine.peer_outputs.len() + 1 != self.ranks.len()
5604        {
5605            return Err("Step owner-grouped combine broadcast is stale or incomplete".into());
5606        }
5607        let values = combine
5608            .tokens
5609            .checked_mul(combine.width)
5610            .ok_or("Step owner-grouped combine collection size overflow")?;
5611        let mut outputs = Vec::with_capacity(self.ranks.len());
5612        {
5613            let root = &self.ranks[0];
5614            let _main = root.gpu.enter_main()?;
5615            outputs.push(root.dtoh_view(&combine.output.slice(0..values))?);
5616        }
5617        for (index, output) in combine.peer_outputs.iter().enumerate() {
5618            let engine = &self.ranks[index + 1];
5619            let _main = engine.gpu.enter_main()?;
5620            outputs.push(engine.dtoh_view(&output.slice(0..values))?);
5621        }
5622        Ok(outputs)
5623    }
5624
5625    /// Add routed and replicated shared-expert outputs, then add the attention residual.
5626    pub fn finish_step_grouped_expert_parallel_layer(
5627        &self,
5628        plan: &PreparedStepGroupedExpertParallelGate,
5629        combine: &PreparedPeerWeightedRouteCombine,
5630        shared: &ResidentReplicatedDeviceRows,
5631        residual: &ResidentReplicatedDeviceRows,
5632    ) -> Result<ResidentReplicatedDeviceRows, Box<dyn std::error::Error>> {
5633        validate_replicated_device_rows(&self.ranks, shared)?;
5634        validate_replicated_device_rows(&self.ranks, residual)?;
5635        if !plan.ready
5636            || plan.executed_generation != Some(plan.generation)
5637            || combine.output_generation != Some(plan.generation)
5638            || combine.broadcast_generation != Some(plan.generation)
5639            || combine.projection_generation != plan.generation
5640            || combine.peer_outputs.len() + 1 != self.ranks.len()
5641            || shared.tokens != combine.tokens
5642            || residual.tokens != combine.tokens
5643            || shared.width != combine.width
5644            || residual.width != combine.width
5645        {
5646            return Err("Step full-layer finish inputs are stale or their geometry changed".into());
5647        }
5648        let values = combine
5649            .tokens
5650            .checked_mul(combine.width)
5651            .ok_or("Step full-layer output size overflow")?;
5652        let mut ranks = Vec::with_capacity(self.ranks.len());
5653        for rank in 0..self.ranks.len() {
5654            let engine = &self.ranks[rank];
5655            let _main = engine.gpu.enter_main()?;
5656            let routed = if rank == 0 {
5657                &combine.output
5658            } else {
5659                &combine.peer_outputs[rank - 1]
5660            };
5661            let mut ffn = engine.uninit(values)?;
5662            engine.add(routed, &shared.ranks[rank], &mut ffn, values)?;
5663            let mut output = engine.uninit(values)?;
5664            engine.add(&residual.ranks[rank], &ffn, &mut output, values)?;
5665            ranks.push(output);
5666        }
5667        Ok(ResidentReplicatedDeviceRows {
5668            ranks,
5669            tokens: combine.tokens,
5670            width: combine.width,
5671        })
5672    }
5673
5674    pub fn run_step_grouped_expert_parallel_combine(
5675        &self,
5676        plan: &PreparedStepGroupedExpertParallelGate,
5677        combine: &mut PreparedPeerWeightedRouteCombine,
5678    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
5679        self.execute_step_grouped_expert_parallel_combine(plan, combine)?;
5680        self.collect_step_grouped_expert_parallel_combine(plan, combine)
5681    }
5682
5683    pub fn upload_tensor_parallel(
5684        &self,
5685        gate: E4m3ExpertBank<'_>,
5686        up: E4m3ExpertBank<'_>,
5687        down: E4m3ExpertBank<'_>,
5688    ) -> Result<ResidentTensorParallel, Box<dyn std::error::Error>> {
5689        gate.validate()?;
5690        up.validate()?;
5691        down.validate()?;
5692        if gate.expert_count != up.expert_count || gate.expert_count != down.expert_count {
5693            return Err("TP gate/up/down expert counts differ".into());
5694        }
5695        if gate.in_features != up.in_features || gate.out_features != up.out_features {
5696            return Err("TP gate/up dimensions differ".into());
5697        }
5698        if down.in_features != gate.out_features || down.out_features != gate.in_features {
5699            return Err(format!(
5700                "TP down {}x{} does not invert gate/up {}x{}",
5701                down.out_features, down.in_features, gate.out_features, gate.in_features
5702            )
5703            .into());
5704        }
5705        let tp = self.ranks.len();
5706        validate_column_bank_shape(gate, tp)?;
5707        validate_column_bank_shape(up, tp)?;
5708        validate_row_bank_shape(down, tp)?;
5709
5710        let mut gate_ranks = Vec::with_capacity(tp);
5711        let mut up_ranks = Vec::with_capacity(tp);
5712        let mut down_ranks = Vec::with_capacity(tp);
5713        for (rank, engine) in self.ranks.iter().enumerate() {
5714            gate_ranks.push(upload_column_bank_rank(engine, gate, tp, rank)?);
5715            up_ranks.push(upload_column_bank_rank(engine, up, tp, rank)?);
5716            down_ranks.push(upload_row_bank_rank(engine, down, tp, rank)?);
5717        }
5718        Ok(ResidentTensorParallel {
5719            bank: ResidentTpExpertBank {
5720                gate: gate_ranks,
5721                up: up_ranks,
5722                down: down_ranks,
5723                expert_count: gate.expert_count,
5724                input_width: gate.in_features,
5725                expert_width: gate.out_features,
5726            },
5727        })
5728    }
5729
5730    pub fn run_tensor_parallel_routes(
5731        &self,
5732        experts: &ResidentTensorParallel,
5733        input: &[f32],
5734        tokens: usize,
5735        selected: &[usize],
5736        route_weights: &[f32],
5737        experts_per_token: usize,
5738    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
5739        validate_tp_bank_residency(&self.ranks, &experts.bank)?;
5740        validate_activations(input, tokens, experts.bank.input_width)?;
5741        let pairs = tokens
5742            .checked_mul(experts_per_token)
5743            .ok_or("TP route count overflow")?;
5744        if selected.len() != pairs || route_weights.len() != pairs {
5745            return Err(format!(
5746                "TP routes selected={} weights={} != tokens {tokens} x experts/token \
5747                 {experts_per_token} ({pairs})",
5748                selected.len(),
5749                route_weights.len(),
5750            )
5751            .into());
5752        }
5753        if !route_weights.iter().all(|weight| weight.is_finite()) {
5754            return Err("TP route weights contain a non-finite value".into());
5755        }
5756
5757        let mut output = vec![0.0f32; tokens * experts.bank.input_width];
5758        for token in 0..tokens {
5759            let input_row =
5760                &input[token * experts.bank.input_width..(token + 1) * experts.bank.input_width];
5761            for slot in 0..experts_per_token {
5762                let pair = token * experts_per_token + slot;
5763                let expert = selected[pair];
5764                if expert >= experts.bank.expert_count {
5765                    return Err(format!(
5766                        "TP selected expert {expert} outside 0..{}",
5767                        experts.bank.expert_count
5768                    )
5769                    .into());
5770                }
5771                let down = if self.native_p2p {
5772                    self.run_tensor_parallel_expert_native(&experts.bank, expert, input_row)?
5773                } else {
5774                    let gate =
5775                        self.run_column_bank_expert(&experts.bank.gate, expert, input_row)?;
5776                    let up = self.run_column_bank_expert(&experts.bank.up, expert, input_row)?;
5777                    let activated: Vec<f32> = gate
5778                        .iter()
5779                        .zip(&up)
5780                        .map(|(&gate, &up)| gate / (1.0 + (-gate).exp()) * up)
5781                        .collect();
5782                    debug_assert_eq!(activated.len(), experts.bank.expert_width);
5783                    self.run_row_bank_expert(&experts.bank.down, expert, &activated)?
5784                };
5785                let weight = route_weights[pair];
5786                for (sum, value) in output
5787                    [token * experts.bank.input_width..(token + 1) * experts.bank.input_width]
5788                    .iter_mut()
5789                    .zip(down)
5790                {
5791                    *sum += weight * value;
5792                }
5793            }
5794        }
5795        Ok(output)
5796    }
5797
5798    fn run_column_bank_expert(
5799        &self,
5800        ranks: &[ResidentE4m3ExpertBankRank],
5801        expert: usize,
5802        input: &[f32],
5803    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
5804        let local_out = ranks
5805            .first()
5806            .ok_or("TP column bank has no ranks")?
5807            .out_features;
5808        let mut gathered = vec![0.0f32; local_out * ranks.len()];
5809        for (rank, (engine, bank)) in self.ranks.iter().zip(ranks).enumerate() {
5810            let shard = run_resident_bank_expert(engine, bank, expert, input, 1)?;
5811            gathered[rank * local_out..(rank + 1) * local_out].copy_from_slice(&shard);
5812        }
5813        Ok(gathered)
5814    }
5815
5816    fn run_row_bank_expert(
5817        &self,
5818        ranks: &[ResidentE4m3ExpertBankRank],
5819        expert: usize,
5820        input: &[f32],
5821    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
5822        let local_in = ranks.first().ok_or("TP row bank has no ranks")?.in_features;
5823        if input.len() != local_in * ranks.len() {
5824            return Err(format!(
5825                "TP row input {} != {} ranks x {local_in}",
5826                input.len(),
5827                ranks.len()
5828            )
5829            .into());
5830        }
5831        let out_features = ranks[0].out_features;
5832        let mut reduced = vec![0.0f32; out_features];
5833        for (rank, (engine, bank)) in self.ranks.iter().zip(ranks).enumerate() {
5834            let blocks = bank
5835                .k_blocks
5836                .ok_or("TP row bank is not packed in native K-block order")?;
5837            if blocks * FP8_BLOCK != local_in {
5838                return Err(format!(
5839                    "TP row bank has {blocks} blocks but local input width is {local_in}"
5840                )
5841                .into());
5842            }
5843            for block in 0..blocks {
5844                let global_start = rank * local_in + block * FP8_BLOCK;
5845                let partial = run_resident_bank_expert_block(
5846                    engine,
5847                    bank,
5848                    expert,
5849                    block,
5850                    &input[global_start..global_start + FP8_BLOCK],
5851                )?;
5852                for (sum, value) in reduced.iter_mut().zip(partial) {
5853                    *sum += value;
5854                }
5855            }
5856        }
5857        Ok(reduced)
5858    }
5859
5860    fn run_tensor_parallel_expert_native(
5861        &self,
5862        bank: &ResidentTpExpertBank,
5863        expert: usize,
5864        input: &[f32],
5865    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
5866        if !self.native_p2p || self.ranks.len() < 2 {
5867            return Err("native TP expert execution requires at least two P2P ranks".into());
5868        }
5869        let local_out = bank
5870            .gate
5871            .first()
5872            .ok_or("native TP gate bank has no ranks")?
5873            .out_features;
5874        if local_out * self.ranks.len() != bank.expert_width {
5875            return Err(format!(
5876                "native TP gate shards {}x{local_out} != expert width {}",
5877                self.ranks.len(),
5878                bank.expert_width
5879            )
5880            .into());
5881        }
5882
5883        // The caller's routed input is already host-canonical. Upload once on rank zero, then
5884        // broadcast over peer copies so no other rank receives a host-staged duplicate.
5885        let mut rank_inputs = Vec::with_capacity(self.ranks.len());
5886        let root_input = {
5887            let root = &self.ranks[0];
5888            let _main = root.gpu.enter_main()?;
5889            root.htod(input)?
5890        };
5891        rank_inputs.push(root_input);
5892        for engine in &self.ranks[1..] {
5893            let peer_input = {
5894                let _main = engine.gpu.enter_main()?;
5895                let mut peer_input = engine.uninit(input.len())?;
5896                engine
5897                    .stream()
5898                    .memcpy_dtod(&rank_inputs[0], &mut peer_input)?;
5899                peer_input
5900            };
5901            rank_inputs.push(peer_input);
5902        }
5903
5904        let mut gate_shards = Vec::with_capacity(self.ranks.len());
5905        let mut up_shards = Vec::with_capacity(self.ranks.len());
5906        #[allow(clippy::needless_range_loop)]
5907        // allow: the explicit index loop keeps the offset arithmetic visible and aligned with the device-side indexing
5908        for rank in 0..self.ranks.len() {
5909            gate_shards.push(run_resident_bank_expert_device(
5910                &self.ranks[rank],
5911                &bank.gate[rank],
5912                expert,
5913                &rank_inputs[rank],
5914                1,
5915            )?);
5916            up_shards.push(run_resident_bank_expert_device(
5917                &self.ranks[rank],
5918                &bank.up[rank],
5919                expert,
5920                &rank_inputs[rank],
5921                1,
5922            )?);
5923        }
5924
5925        // Preserve the established canonical activation program for the first native transport
5926        // milestone. The shards move to rank zero over P2P; only the scalar activation expression
5927        // executes on host. A later device-activation increment must earn its own exactness gate.
5928        let gate = self.gather_native_column_shards(&gate_shards, 1, local_out)?;
5929        let up = self.gather_native_column_shards(&up_shards, 1, local_out)?;
5930        let activated = gate
5931            .iter()
5932            .zip(&up)
5933            .map(|(&gate, &up)| gate / (1.0 + (-gate).exp()) * up)
5934            .collect::<Vec<_>>();
5935        debug_assert_eq!(activated.len(), bank.expert_width);
5936
5937        let root_activated = {
5938            let root = &self.ranks[0];
5939            let _main = root.gpu.enter_main()?;
5940            root.htod(&activated)?
5941        };
5942        let mut rank_activated = Vec::with_capacity(self.ranks.len());
5943        for (rank, engine) in self.ranks.iter().enumerate() {
5944            let start = rank * local_out;
5945            let source = root_activated.slice(start..start + local_out);
5946            let local = {
5947                let _main = engine.gpu.enter_main()?;
5948                let mut local = engine.uninit(local_out)?;
5949                engine.stream().memcpy_dtod(&source, &mut local)?;
5950                local
5951            };
5952            rank_activated.push(local);
5953        }
5954
5955        let out_features = bank
5956            .down
5957            .first()
5958            .ok_or("native TP down bank has no ranks")?
5959            .out_features;
5960        let mut reduced = {
5961            let root = &self.ranks[0];
5962            let _main = root.gpu.enter_main()?;
5963            root.htod(&vec![0.0f32; out_features])?
5964        };
5965        let mut remote_partial_keepalive = Vec::new();
5966        #[allow(clippy::needless_range_loop)]
5967        // allow: the explicit index loop keeps the offset arithmetic visible and aligned with the device-side indexing
5968        for rank in 0..self.ranks.len() {
5969            let down = &bank.down[rank];
5970            let blocks = down
5971                .k_blocks
5972                .ok_or("native TP row bank is not packed in checkpoint-block order")?;
5973            if blocks * FP8_BLOCK != local_out {
5974                return Err(format!(
5975                    "native TP rank {rank} has {blocks} blocks but local activation width is \
5976                     {local_out}"
5977                )
5978                .into());
5979            }
5980            for block in 0..blocks {
5981                let start = block * FP8_BLOCK;
5982                let input_block = rank_activated[rank].slice(start..start + FP8_BLOCK);
5983                let partial = run_resident_bank_expert_block_device(
5984                    &self.ranks[rank],
5985                    down,
5986                    expert,
5987                    block,
5988                    &input_block,
5989                )?;
5990                let root_partial = if rank == 0 {
5991                    partial
5992                } else {
5993                    let root = &self.ranks[0];
5994                    let _main = root.gpu.enter_main()?;
5995                    let mut peer_partial = root.uninit(out_features)?;
5996                    root.stream().memcpy_dtod(&partial, &mut peer_partial)?;
5997                    remote_partial_keepalive.push(partial);
5998                    peer_partial
5999                };
6000                let next = {
6001                    let root = &self.ranks[0];
6002                    let _main = root.gpu.enter_main()?;
6003                    let mut next = root.uninit(out_features)?;
6004                    root.add(&reduced, &root_partial, &mut next, out_features)?;
6005                    next
6006                };
6007                reduced = next;
6008            }
6009        }
6010        let output = {
6011            let root = &self.ranks[0];
6012            let _main = root.gpu.enter_main()?;
6013            root.dtoh(&reduced)?
6014        };
6015        drop(remote_partial_keepalive);
6016        Ok(output)
6017    }
6018
6019    /// Gather token-major rank-local columns into one canonical root-device matrix.
6020    pub fn gather_native_column_shards_device(
6021        &self,
6022        shards: &[CudaSlice<f32>],
6023        tokens: usize,
6024        local_out: usize,
6025    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
6026        let shard_len = tokens
6027            .checked_mul(local_out)
6028            .ok_or("native TP gather shard size overflow")?;
6029        if shards.len() != self.ranks.len() || shards.iter().any(|shard| shard.len() != shard_len) {
6030            return Err("native TP gather shard geometry mismatch".into());
6031        }
6032        // PRODUCER FENCE (2026-08-20 flake fix): the root stream peer-reads shards produced on
6033        // the other ranks' streams; without fencing those producers the copy can read a partial
6034        // kernel output.
6035        for engine in &self.ranks[1..] {
6036            let _main = engine.gpu.enter_main()?;
6037            engine.stream().synchronize()?;
6038        }
6039        let root = &self.ranks[0];
6040        let _main = root.gpu.enter_main()?;
6041        let global_out = shards
6042            .len()
6043            .checked_mul(local_out)
6044            .ok_or("native TP gather output width overflow")?;
6045        let gathered_len = tokens
6046            .checked_mul(global_out)
6047            .ok_or("native TP gather output size overflow")?;
6048        let mut gathered = root.uninit(gathered_len)?;
6049        if self.bulk_p2p {
6050            root.place_rows_strided(&shards[0], &mut gathered, local_out, tokens, global_out, 0)?;
6051            if shards.len() > 1 {
6052                let mut staging = root.uninit(shard_len)?;
6053                for (rank, shard) in shards.iter().enumerate().skip(1) {
6054                    root.stream().memcpy_dtod(shard, &mut staging)?;
6055                    root.place_rows_strided(
6056                        &staging,
6057                        &mut gathered,
6058                        local_out,
6059                        tokens,
6060                        global_out,
6061                        rank * local_out,
6062                    )?;
6063                }
6064            }
6065        } else {
6066            for token in 0..tokens {
6067                for (rank, shard) in shards.iter().enumerate() {
6068                    let source = shard.slice(token * local_out..(token + 1) * local_out);
6069                    let start = token * global_out + rank * local_out;
6070                    let mut destination = gathered.slice_mut(start..start + local_out);
6071                    root.stream().memcpy_dtod(&source, &mut destination)?;
6072                }
6073            }
6074        }
6075        Ok(gathered)
6076    }
6077
6078    pub fn gather_native_column_shards(
6079        &self,
6080        shards: &[CudaSlice<f32>],
6081        tokens: usize,
6082        local_out: usize,
6083    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
6084        let gathered = self.gather_native_column_shards_device(shards, tokens, local_out)?;
6085        let root = &self.ranks[0];
6086        let _main = root.gpu.enter_main()?;
6087        root.dtoh(&gathered)
6088    }
6089
6090    pub(crate) fn decode_v2_workspace(&self) -> &std::sync::Mutex<Vec<StepTpDecodeV2Ws>> {
6091        &self.decode_v2
6092    }
6093
6094    /// Build the v2 decode-attention workspace for this layer's geometry on first use, or
6095    /// return the index of the matching one. Attention geometry varies across the trunk
6096    /// (per-layer query-head counts), so workspaces are keyed by their geometry pins — a
6097    /// handful exist per model, never one per layer.
6098    ///
6099    /// Refuses non-F32-resident projections: the v2 driver's bit-exactness claim against v1
6100    /// holds per residency class, and only the mirror class has no per-call weight expansion
6101    /// to hide allocation churn behind.
6102    #[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
6103    pub(crate) fn decode_v2_ensure(
6104        &self,
6105        e: &Engine,
6106        q_m: &ResidentBf16ColumnParallel,
6107        k_m: &ResidentBf16ColumnParallel,
6108        v_m: &ResidentBf16ColumnParallel,
6109        o_m: &ResidentStepBf16RowParallel,
6110        heads: usize,
6111    ) -> Result<usize, Box<dyn std::error::Error>> {
6112        if self.ranks.len() > 1 && !self.native_p2p {
6113            return Err("step TP decode v2 requires native P2P ranks".into());
6114        }
6115        let ranks = self.ranks.len();
6116        // Residency contract: the canonical-chunk (non-fused) program needs the F32 mirror;
6117        // the fused-kernel door also reads raw checkpoint bf16 directly (halving the weight
6118        // traffic), so bf16 residency is accepted when that door is on.
6119        let fused_door = step_tp_qkv_fused_enabled()?;
6120        let arm_ok = |weight: &ResidentBf16Weight| match weight {
6121            ResidentBf16Weight::F32(_) => true,
6122            ResidentBf16Weight::Bf16(_) => fused_door,
6123        };
6124        for matrix in [q_m, k_m, v_m] {
6125            validate_resident_bf16_ranks(&self.ranks, &matrix.ranks)?;
6126            if matrix.out_features % ranks != 0 || matrix.in_features != q_m.in_features {
6127                return Err("step TP decode v2 QKV geometry mismatch".into());
6128            }
6129            for rank in &matrix.ranks {
6130                if !arm_ok(&rank.weight) {
6131                    return Err("step TP decode v2 requires MEMRA_STEP_TP_F32_MIRROR=1 or \
6132                                MEMRA_STEP_TP_QKV_FUSED=1 (bf16-resident fused kernels)"
6133                        .into());
6134                }
6135            }
6136        }
6137        validate_step_bf16_row_residency(&self.ranks, o_m)?;
6138        for blocks in &o_m.ranks {
6139            for block in blocks {
6140                if !arm_ok(&block.weight) {
6141                    return Err("step TP decode v2 requires MEMRA_STEP_TP_F32_MIRROR=1 or \
6142                                MEMRA_STEP_TP_QKV_FUSED=1 (bf16-resident fused kernels)"
6143                        .into());
6144                }
6145            }
6146        }
6147        if v_m.out_features != k_m.out_features
6148            || o_m.in_features != q_m.out_features
6149            || heads == 0
6150            || heads % ranks != 0
6151        {
6152            return Err("step TP decode v2 K/V/O geometry mismatch".into());
6153        }
6154        let local_q_dim = q_m.out_features / ranks;
6155        let local_kv_dim = k_m.out_features / ranks;
6156        let o_out = o_m.out_features;
6157        let o_block_cols = o_m.canonical_chunk_cols;
6158        let blocks_per_rank = o_m.ranks.first().map(Vec::len).unwrap_or(0);
6159        if blocks_per_rank == 0
6160            || o_m
6161                .ranks
6162                .iter()
6163                .any(|blocks| blocks.len() != blocks_per_rank)
6164            || blocks_per_rank * o_block_cols * ranks != o_m.in_features
6165        {
6166            return Err("step TP decode v2 O canonical block grid mismatch".into());
6167        }
6168
6169        let mut guard = self
6170            .decode_v2
6171            .lock()
6172            .map_err(|_| "step TP decode v2 workspace lock is poisoned")?;
6173        if let Some(index) = guard.iter().position(|ws| {
6174            ws.local_q_dim == local_q_dim
6175                && ws.local_kv_dim == local_kv_dim
6176                && ws.heads == heads
6177                && ws.o_out == o_out
6178                && ws.o_block_cols == o_block_cols
6179                && ws.blocks_per_rank == blocks_per_rank
6180                && ws.e_device == e.ctx().ordinal()
6181                && ws.q.len() == ranks
6182        }) {
6183            return Ok(index);
6184        }
6185
6186        let mut q_raw = Vec::with_capacity(ranks);
6187        let mut k_raw = Vec::with_capacity(ranks);
6188        let mut v_raw = Vec::with_capacity(ranks);
6189        let mut q = Vec::with_capacity(ranks);
6190        let mut k = Vec::with_capacity(ranks);
6191        let mut pos = Vec::with_capacity(ranks);
6192        let mut gate = Vec::with_capacity(ranks);
6193        let mut attn_out = Vec::with_capacity(ranks);
6194        let mut gated = Vec::with_capacity(ranks);
6195        let mut fuse_ctr = Vec::with_capacity(ranks);
6196        let mut o_partials = Vec::with_capacity(ranks);
6197        let mut ev_rank = Vec::with_capacity(ranks);
6198        let direct_join = oproj_direct_on();
6199        for (rank, engine) in self.ranks.iter().enumerate() {
6200            let _main = engine.gpu.enter_main()?;
6201            q_raw.push(engine.uninit(local_q_dim)?);
6202            k_raw.push(engine.uninit(local_kv_dim)?);
6203            v_raw.push(engine.uninit(local_kv_dim)?);
6204            q.push(engine.uninit(local_q_dim)?);
6205            k.push(engine.uninit(local_kv_dim)?);
6206            pos.push(engine.htod_i32(&[0])?);
6207            fuse_ctr.push(engine.stream().clone_htod(&[0u32])?);
6208            gate.push(engine.uninit(heads / ranks)?);
6209            attn_out.push(engine.uninit(local_q_dim)?);
6210            gated.push(engine.uninit(local_q_dim)?);
6211            let mut rank_partials = Vec::with_capacity(blocks_per_rank);
6212            for _ in 0..blocks_per_rank {
6213                // Direct join: peer ranks' partials live on ROOT so the b4 kernel's
6214                // stores land there over P2P (UVA) and no pull copy is needed.
6215                if direct_join && rank != 0 {
6216                    let root = &self.ranks[0];
6217                    let _root_main = root.gpu.enter_main()?;
6218                    rank_partials.push(root.uninit(o_out)?);
6219                } else {
6220                    rank_partials.push(engine.uninit(o_out)?);
6221                }
6222            }
6223            o_partials.push(rank_partials);
6224            ev_rank.push(engine.ctx().new_event(None)?);
6225        }
6226        use cudarc::driver::DevicePtr;
6227        let mut raw_o_partials = Vec::with_capacity(ranks);
6228        let mut raw_k = Vec::with_capacity(ranks);
6229        let mut raw_v_raw = Vec::with_capacity(ranks);
6230        for rank in 0..ranks {
6231            let engine = &self.ranks[rank];
6232            {
6233                let _main = engine.gpu.enter_main()?;
6234                let stream = engine.stream();
6235                let (k_ptr, _k_guard) = k[rank].device_ptr(&stream);
6236                let (v_ptr, _v_guard) = v_raw[rank].device_ptr(&stream);
6237                raw_k.push(k_ptr);
6238                raw_v_raw.push(v_ptr);
6239            }
6240            let partial_engine = if direct_join && rank != 0 {
6241                &self.ranks[0]
6242            } else {
6243                engine
6244            };
6245            let _main = partial_engine.gpu.enter_main()?;
6246            let stream = partial_engine.stream();
6247            let mut rank_raw = Vec::with_capacity(blocks_per_rank);
6248            for partial in &o_partials[rank] {
6249                let (ptr, _guard) = partial.device_ptr(&stream);
6250                rank_raw.push(ptr);
6251            }
6252            raw_o_partials.push(rank_raw);
6253        }
6254        let root = &self.ranks[0];
6255        let (peer_partial, reduce_a, reduce_b, zeros, k_shadow, v_shadow, ev_refresh, ev_oproj) = {
6256            let _main = root.gpu.enter_main()?;
6257            (
6258                root.uninit(o_out)?,
6259                root.uninit(o_out)?,
6260                root.uninit(o_out)?,
6261                root.htod(&vec![0.0f32; o_out])?,
6262                root.uninit(ranks * local_kv_dim)?,
6263                root.uninit(ranks * local_kv_dim)?,
6264                root.ctx().new_event(None)?,
6265                root.ctx().new_event(None)?,
6266            )
6267        };
6268        let (raw_peer_partial, raw_k_shadow, raw_v_shadow) = {
6269            let _main = root.gpu.enter_main()?;
6270            let stream = root.stream();
6271            let (peer, _peer_guard) = peer_partial.device_ptr(&stream);
6272            let (k, _k_guard) = k_shadow.device_ptr(&stream);
6273            let (v, _v_guard) = v_shadow.device_ptr(&stream);
6274            (peer, k, v)
6275        };
6276        let (gate_e, ev_entry) = {
6277            let _main = e.gpu.enter_main()?;
6278            (e.uninit(heads)?, e.ctx().new_event(None)?)
6279        };
6280        let raw_attn_in = Vec::new();
6281        let raw_pos = Vec::new();
6282        guard.push(StepTpDecodeV2Ws {
6283            tcol_q: Vec::new(),
6284            tcol_k: Vec::new(),
6285            tcol_v: Vec::new(),
6286            tcol_g: Vec::new(),
6287            tcol_in: Vec::new(),
6288            tcol_cap: 0,
6289            w8_aq: Vec::new(),
6290            w8_ad: Vec::new(),
6291            w8_in: 0,
6292            w8o_aq: Vec::new(),
6293            w8o_ad: Vec::new(),
6294            w8o_in: 0,
6295            w8t_aq: Vec::new(),
6296            w8t_ad: Vec::new(),
6297            w8t_in: 0,
6298            w8t_oaq: Vec::new(),
6299            w8t_oad: Vec::new(),
6300            w8t_oin: 0,
6301            w8t_cap: 0,
6302            fa2_q: Vec::new(),
6303            fa2_gate: Vec::new(),
6304            fa2_gated: Vec::new(),
6305            fa2_cap: 0,
6306            rope_k_t: Vec::new(),
6307            rope_ctr_t: Vec::new(),
6308            rope_pos_t: Vec::new(),
6309            rows_tabs: Vec::new(),
6310            rows_tab_t: Vec::new(),
6311            rows_tab_shadow: Vec::new(),
6312            tcol_gated: Vec::new(),
6313            tcol_opart: Vec::new(),
6314            tcol_opeer: None,
6315            tcol_omix: None,
6316            tcol_ocap: 0,
6317            q_raw,
6318            k_raw,
6319            v_raw,
6320            q,
6321            k,
6322            pos,
6323            fuse_ctr,
6324            gate,
6325            attn_out,
6326            gated,
6327            o_partials,
6328            raw_o_partials,
6329            raw_k,
6330            raw_v_raw,
6331            ev_rank,
6332            peer_partial,
6333            reduce_a,
6334            reduce_b,
6335            zeros,
6336            k_shadow,
6337            v_shadow,
6338            ev_refresh,
6339            ev_oproj,
6340            gate_e,
6341            attn_in: Vec::new(),
6342            h_stage: None,
6343            pos_stage: None,
6344            raw_h_stage: 0,
6345            raw_pos_stage: 0,
6346            raw_attn_in,
6347            raw_pos,
6348            raw_o_partial1: 0,
6349            raw_peer_partial,
6350            raw_k1: 0,
6351            raw_v1: 0,
6352            raw_k_shadow,
6353            raw_v_shadow,
6354            raw_mixed_stage_e: 0,
6355            raw_reduce_a: 0,
6356            raw_shadow_stage_e: (0, 0),
6357            ev_entry,
6358            e_device: e.ctx().ordinal(),
6359            local_q_dim,
6360            local_kv_dim,
6361            heads,
6362            o_out,
6363            o_block_cols,
6364            blocks_per_rank,
6365        });
6366        eprintln!(
6367            "[step-tp-decode-v2] workspace ranks={ranks} local_q={local_q_dim} \
6368             local_kv={local_kv_dim} heads={heads} o_blocks={blocks_per_rank}x{o_block_cols} \
6369             residency=persistent ordering=evented performance_claim=false"
6370        );
6371        Ok(guard.len() - 1)
6372    }
6373
6374    /// v2 phase 1: replicate the layer input, project QKV, norm, rope, and stage the gate —
6375    /// all into the persistent workspace, ordered by events instead of host syncs.
6376    ///
6377    /// The caller must have queued every producer of `h`, `pos_d`, and `gate_raw` on `e`'s
6378    /// stream BEFORE this call: `ev_entry` is recorded once here and every rank stream waits
6379    /// on it (the entry fence also guards workspace reuse across layers — any consumer of the
6380    /// previous layer's outputs was queued on `e`'s stream before this record).
6381    #[allow(clippy::too_many_arguments)]
6382    /// T-COLUMN verify precompute (spec MTP): stage T input rows to every rank and run the
6383    /// weight-amortized qkvg_tcol per rank into the ws slabs. Rope/norm/append stay per
6384    /// column in the unmodified t=1 program (defer_norm_rope contract). Bit-exact per
6385    /// column vs the t=1 kernel by construction.
6386    #[allow(clippy::too_many_arguments)]
6387    pub fn decode_v2_input_qkv_tcol(
6388        &self,
6389        ws_index: usize,
6390        e: &Engine,
6391        h_t: &CudaSlice<f32>,
6392        t: usize,
6393        q_m: &ResidentBf16ColumnParallel,
6394        k_m: &ResidentBf16ColumnParallel,
6395        v_m: &ResidentBf16ColumnParallel,
6396        gate_shards: Option<StepTpGateShards<'_>>,
6397    ) -> Result<(), Box<dyn std::error::Error>> {
6398        let ranks = self.ranks.len();
6399        let mut guard = self
6400            .decode_v2
6401            .lock()
6402            .map_err(|_| "step TP decode v2 workspace lock is poisoned")?;
6403        let ws = guard
6404            .get_mut(ws_index)
6405            .ok_or("step TP decode v2 workspace index out of range")?;
6406        let in_f = q_m.in_features;
6407        if h_t.len() < t * in_f || t == 0 || t > 32 {
6408            return Err("decode_v2_input_qkv_tcol geometry".into());
6409        }
6410        // Lazily arm the slabs to capacity.
6411        if ws.tcol_cap < t || ws.tcol_q.len() != ranks {
6412            ws.tcol_q.clear();
6413            ws.tcol_k.clear();
6414            ws.tcol_v.clear();
6415            ws.tcol_g.clear();
6416            ws.tcol_in.clear();
6417            for engine in &self.ranks {
6418                let _m = engine.gpu.enter_main()?;
6419                ws.tcol_q.push(engine.uninit(32 * ws.local_q_dim)?);
6420                ws.tcol_k.push(engine.uninit(32 * ws.local_kv_dim)?);
6421                ws.tcol_v.push(engine.uninit(32 * ws.local_kv_dim)?);
6422                ws.tcol_g
6423                    .push(engine.uninit(32 * (ws.heads / ranks).max(1))?);
6424                ws.tcol_in.push(engine.uninit(32 * in_f)?);
6425            }
6426            ws.tcol_cap = 32;
6427        }
6428        // Stage the T input rows on e, fence, per-rank pull + tcol launch.
6429        use cudarc::driver::DevicePtr;
6430        let raw_src = {
6431            let _main = e.gpu.enter_main()?;
6432            let stream = e.stream();
6433            let (p, _g) = h_t.device_ptr(&stream);
6434            ws.ev_entry.record(&stream)?;
6435            p
6436        };
6437        for rank in 0..ranks {
6438            let engine = &self.ranks[rank];
6439            let _main = engine.gpu.enter_main()?;
6440            engine.stream().wait(&ws.ev_entry)?;
6441            let raw_dst = {
6442                let stream = engine.stream();
6443                let (p, _g) = ws.tcol_in[rank].device_ptr(&stream);
6444                p
6445            };
6446            raw_copy_bytes(raw_dst, raw_src, t * in_f * 4, engine)?;
6447            let out_g = match &gate_shards {
6448                Some(_) => ws.heads / ranks,
6449                None => 0,
6450            };
6451            match (
6452                &q_m.ranks[rank].weight,
6453                &k_m.ranks[rank].weight,
6454                &v_m.ranks[rank].weight,
6455            ) {
6456                (
6457                    ResidentBf16Weight::Bf16(wq),
6458                    ResidentBf16Weight::Bf16(wk),
6459                    ResidentBf16Weight::Bf16(wv),
6460                ) => {
6461                    let wg = match &gate_shards {
6462                        Some(StepTpGateShards::Bf16(shards)) => &shards[rank],
6463                        Some(StepTpGateShards::F32(_)) => {
6464                            return Err(
6465                                "tcol verify: gate shard class does not match bf16 QKV".into()
6466                            );
6467                        }
6468                        None => wq,
6469                    };
6470                    let StepTpDecodeV2Ws {
6471                        tcol_q,
6472                        tcol_k,
6473                        tcol_v,
6474                        tcol_g,
6475                        tcol_in,
6476                        local_q_dim,
6477                        local_kv_dim,
6478                        w8t_aq,
6479                        w8t_ad,
6480                        w8t_in,
6481                        w8t_cap,
6482                        ..
6483                    } = &mut *ws;
6484                    // MEMRA_TCOL_REFKERN=1 (bisect): fill the slabs via the t=1 kernel per
6485                    // column — separates driver bugs from tcol-kernel bugs.
6486                    static REFK: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
6487                    let refk = *REFK
6488                        .get_or_init(|| std::env::var("MEMRA_TCOL_REFKERN").as_deref() == Ok("1"));
6489                    if refk {
6490                        let lq = *local_q_dim;
6491                        let lkv = *local_kv_dim;
6492                        let mut hrow = engine.uninit(in_f)?;
6493                        let mut qr = engine.uninit(lq)?;
6494                        let mut kr = engine.uninit(lkv)?;
6495                        let mut vr = engine.uninit(lkv)?;
6496                        let mut gr = engine.uninit(out_g.max(1))?;
6497                        for c in 0..t {
6498                            {
6499                                let mut dst = hrow.slice_mut(0..in_f);
6500                                engine.stream().memcpy_dtod(
6501                                    &tcol_in[rank].slice(c * in_f..(c + 1) * in_f),
6502                                    &mut dst,
6503                                )?;
6504                            }
6505                            engine.matvec_bf16_qkvg_into(
6506                                wq, wk, wv, wg, &hrow, &mut qr, &mut kr, &mut vr, &mut gr, in_f,
6507                                lq, lkv, out_g,
6508                            )?;
6509                            let stream = engine.stream();
6510                            {
6511                                let mut dst = tcol_q[rank].slice_mut(c * lq..(c + 1) * lq);
6512                                stream.memcpy_dtod(&qr.slice(0..lq), &mut dst)?;
6513                            }
6514                            {
6515                                let mut dst = tcol_k[rank].slice_mut(c * lkv..(c + 1) * lkv);
6516                                stream.memcpy_dtod(&kr.slice(0..lkv), &mut dst)?;
6517                            }
6518                            {
6519                                let mut dst = tcol_v[rank].slice_mut(c * lkv..(c + 1) * lkv);
6520                                stream.memcpy_dtod(&vr.slice(0..lkv), &mut dst)?;
6521                            }
6522                            if out_g > 0 {
6523                                let mut dst = tcol_g[rank].slice_mut(c * out_g..(c + 1) * out_g);
6524                                stream.memcpy_dtod(&gr.slice(0..out_g), &mut dst)?;
6525                            }
6526                        }
6527                    } else if crate::step_tp_w8_on()
6528                        && q_m.ranks[rank].q8.is_some()
6529                        && k_m.ranks[rank].q8.is_some()
6530                        && v_m.ranks[rank].q8.is_some()
6531                        && in_f.is_multiple_of(32)
6532                    {
6533                        // MEMRA_STEP_TP_W8 on the VERIFY walk. nsys put the bf16 tcol QKV at
6534                        // 12.3% of spec GPU time and the bf16 tcol o_proj at 24.8% — the door
6535                        // had only ever replaced the DECODE kernels, so 37% of the verify still
6536                        // streamed bf16 weights. One q8 launch over all t columns; the gate rows
6537                        // stay bf16 as on the decode side.
6538                        if *w8t_in != in_f || *w8t_cap < t || w8t_aq.len() != ranks {
6539                            w8t_aq.clear();
6540                            w8t_ad.clear();
6541                            for e_rank in &self.ranks {
6542                                let _m = e_rank.gpu.enter_main()?;
6543                                w8t_aq.push(e_rank.alloc_i8_uninit(32 * in_f)?);
6544                                w8t_ad.push(e_rank.alloc_uninit::<f32>(32 * (in_f / 32))?);
6545                            }
6546                            *w8t_in = in_f;
6547                            *w8t_cap = 32;
6548                        }
6549                        engine.quantize_q8_1_into(
6550                            &tcol_in[rank],
6551                            t,
6552                            in_f,
6553                            &mut w8t_aq[rank],
6554                            &mut w8t_ad[rank],
6555                        )?;
6556                        engine.qmatvec_q8_0_qkv_rp_t_into(
6557                            q_m.ranks[rank].q8.as_ref().unwrap(),
6558                            k_m.ranks[rank].q8.as_ref().unwrap(),
6559                            v_m.ranks[rank].q8.as_ref().unwrap(),
6560                            &w8t_aq[rank],
6561                            &w8t_ad[rank],
6562                            &mut tcol_q[rank],
6563                            &mut tcol_k[rank],
6564                            &mut tcol_v[rank],
6565                            in_f,
6566                            *local_q_dim,
6567                            *local_kv_dim,
6568                            t,
6569                        )?;
6570                        if out_g > 0 {
6571                            engine.matvec_bf16_rows_into(
6572                                wg,
6573                                &tcol_in[rank],
6574                                &mut tcol_g[rank],
6575                                in_f,
6576                                out_g,
6577                                t,
6578                            )?;
6579                        }
6580                    } else {
6581                        engine.matvec_bf16_qkvg_tcol_into(
6582                            wq,
6583                            wk,
6584                            wv,
6585                            wg,
6586                            &tcol_in[rank],
6587                            &mut tcol_q[rank],
6588                            &mut tcol_k[rank],
6589                            &mut tcol_v[rank],
6590                            &mut tcol_g[rank],
6591                            in_f,
6592                            *local_q_dim,
6593                            *local_kv_dim,
6594                            out_g,
6595                            t,
6596                        )?;
6597                    }
6598                }
6599                _ => return Err("tcol verify requires bf16-resident fused QKV".into()),
6600            }
6601        }
6602        Ok(())
6603    }
6604
6605    /// MEMRA_TCOL_OPROJ eligibility: the defer replaces exactly the o_fused direct-join
6606    /// finish (bf16 b4 kernel, 2 ranks, 4 canonical blocks) with the shadow gathers
6607    /// skipped — so it requires the same doors that arm dictate that finish shape.
6608    pub(crate) fn decode_v2_oproj_tcol_eligible(
6609        &self,
6610        ws: &StepTpDecodeV2Ws,
6611        o_m: &ResidentStepBf16RowParallel,
6612    ) -> bool {
6613        self.ranks.len() == 2
6614            && ws.blocks_per_rank == 4
6615            && step_tp_qkv_fused_enabled().unwrap_or(false)
6616            && no_local_shadow_on()
6617            && o_m
6618                .ranks
6619                .iter()
6620                .flatten()
6621                .all(|block| matches!(block.weight, ResidentBf16Weight::Bf16(_)))
6622    }
6623
6624    /// MEMRA_SPEC_FA2 stash: copy this column's per-rank post-rope q and gate rows into
6625    /// the fa2 slabs (rank-stream ordered behind the rope/append that produced them), and
6626    /// give `e` the same anti-dependency wait the skipped finish provided (next column's
6627    /// h/pos re-staging must not overtake this column's rank pulls).
6628    pub(crate) fn decode_v2_stash_fa2(
6629        &self,
6630        ws: &mut StepTpDecodeV2Ws,
6631        e: &Engine,
6632        col: usize,
6633    ) -> Result<(), Box<dyn std::error::Error>> {
6634        let ranks = self.ranks.len();
6635        if col >= 32 {
6636            return Err("decode_v2_stash_fa2 column out of range".into());
6637        }
6638        let lq = ws.local_q_dim;
6639        let lg = (ws.heads / ranks).max(1);
6640        if ws.fa2_cap < 32 || ws.fa2_q.len() != ranks || ws.rows_tab_t.len() != ranks {
6641            ws.fa2_q.clear();
6642            ws.fa2_gate.clear();
6643            ws.fa2_gated.clear();
6644            ws.rope_k_t.clear();
6645            ws.rope_ctr_t.clear();
6646            ws.rope_pos_t.clear();
6647            ws.rows_tab_t.clear();
6648            for engine in &self.ranks {
6649                let _m = engine.gpu.enter_main()?;
6650                ws.fa2_q.push(engine.uninit(32 * lq)?);
6651                ws.fa2_gate.push(engine.uninit(32 * lg)?);
6652                ws.fa2_gated.push(engine.uninit(32 * lq)?);
6653                ws.rope_k_t.push(engine.uninit(32 * ws.local_kv_dim)?);
6654                ws.rope_ctr_t.push(engine.stream().clone_htod(&[0u32; 32])?);
6655                ws.rope_pos_t.push(engine.htod_i32(&[0i32; 32])?);
6656                ws.rows_tab_t
6657                    .push(engine.stream().clone_htod(&[0u64; 32 * 6])?);
6658            }
6659            ws.rows_tabs = (0..ranks).map(|_| Default::default()).collect();
6660            ws.fa2_cap = 32;
6661        }
6662        for rank in 0..ranks {
6663            let engine = &self.ranks[rank];
6664            let _main = engine.gpu.enter_main()?;
6665            {
6666                let mut dst = ws.fa2_q[rank].slice_mut(col * lq..(col + 1) * lq);
6667                engine
6668                    .stream()
6669                    .memcpy_dtod(&ws.q[rank].slice(0..lq), &mut dst)?;
6670            }
6671            {
6672                let mut dst = ws.fa2_gate[rank].slice_mut(col * lg..(col + 1) * lg);
6673                engine
6674                    .stream()
6675                    .memcpy_dtod(&ws.gate[rank].slice(0..lg), &mut dst)?;
6676            }
6677            ws.ev_rank[rank].record(&engine.stream())?;
6678        }
6679        {
6680            let _main = e.gpu.enter_main()?;
6681            for ev in ws.ev_rank.iter() {
6682                e.stream().wait(ev)?;
6683            }
6684        }
6685        Ok(())
6686    }
6687
6688    /// FULL T-ROW ATTENTION PASS over per-row session tables (batched serving): reads
6689    /// the tcol raw-projection slabs, runs ONE rope/append rows launch + ONE fa rows
6690    /// launch + ONE combine per rank (gate straight from the tcol gate slab), then the
6691    /// o_proj tcol join — the whole per-row attention loop in 3 launches/rank/layer.
6692    /// Per-(row, head) programs are the t=1 kernels verbatim; each row appends to and
6693    /// attends its OWN session. `session_parts[rank][row]` = {k_plane, v_plane, len_ptr,
6694    /// base_ptr}; `tab_keys[rank]` keys the per-rank combined-table cache (caller folds
6695    /// layer + session-set + base-arming into it); `stage_pos` stages the position slab
6696    /// (positions are constant across layers within a tick — stage on the first layer).
6697    #[allow(clippy::too_many_arguments)]
6698    pub(crate) fn decode_v2_rope_fa_rows(
6699        &self,
6700        ws_index: usize,
6701        e: &Engine,
6702        o_m: &ResidentStepBf16RowParallel,
6703        session_parts: &[Vec<[u64; 4]>],
6704        tab_keys: &[u64],
6705        positions: &[i32],
6706        stage_pos: bool,
6707        same_session: bool,
6708        q_norms: &[CudaSlice<f32>],
6709        k_norms: &[CudaSlice<f32>],
6710        rope_freqs: &[Option<&crate::CudaSlice<f32>>],
6711        t: usize,
6712        head_dim: usize,
6713        n_rot: usize,
6714        window: usize,
6715        max_ns: usize,
6716        scale: f32,
6717        k_tok_bytes: usize,
6718        v_tok_bytes: usize,
6719        eps: f32,
6720        rope_base: f32,
6721    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
6722        use cudarc::driver::DevicePtr;
6723        let ranks = self.ranks.len();
6724        if session_parts.len() != ranks || tab_keys.len() != ranks || positions.len() < t {
6725            return Err("rope fa rows geometry".into());
6726        }
6727        {
6728            let mut guard = self
6729                .decode_v2
6730                .lock()
6731                .map_err(|_| "step TP decode v2 workspace lock is poisoned")?;
6732            let ws = guard
6733                .get_mut(ws_index)
6734                .ok_or("step TP decode v2 workspace index out of range")?;
6735            if ws.tcol_cap < t || ws.tcol_q.len() != ranks {
6736                return Err("rope fa rows without tcol slabs".into());
6737            }
6738            let lq = ws.local_q_dim;
6739            let lkv = ws.local_kv_dim;
6740            let lg = (ws.heads / ranks).max(1);
6741            let local_heads = (ws.heads / ranks).max(1);
6742            let local_kv_heads = (lkv / head_dim).max(1);
6743            // Arm the fa2/rope slabs (shared with the stash path).
6744            if ws.fa2_cap < 32 || ws.fa2_q.len() != ranks || ws.rows_tab_t.len() != ranks {
6745                ws.fa2_q.clear();
6746                ws.fa2_gate.clear();
6747                ws.fa2_gated.clear();
6748                ws.rope_k_t.clear();
6749                ws.rope_ctr_t.clear();
6750                ws.rope_pos_t.clear();
6751                ws.rows_tab_t.clear();
6752                for engine in &self.ranks {
6753                    let _m = engine.gpu.enter_main()?;
6754                    ws.fa2_q.push(engine.uninit(32 * lq)?);
6755                    ws.fa2_gate.push(engine.uninit(32 * lg)?);
6756                    ws.fa2_gated.push(engine.uninit(32 * lq)?);
6757                    ws.rope_k_t.push(engine.uninit(32 * lkv)?);
6758                    ws.rope_ctr_t.push(engine.stream().clone_htod(&[0u32; 32])?);
6759                    ws.rope_pos_t.push(engine.htod_i32(&[0i32; 32])?);
6760                    ws.rows_tab_t
6761                        .push(engine.stream().clone_htod(&[0u64; 32 * 6])?);
6762                }
6763                ws.rows_tabs = (0..ranks).map(|_| Default::default()).collect();
6764                ws.fa2_cap = 32;
6765            }
6766            if ws.tcol_ocap < t || ws.tcol_gated.len() != ranks {
6767                ws.tcol_gated.clear();
6768                ws.tcol_opart.clear();
6769                for engine in &self.ranks {
6770                    let _m = engine.gpu.enter_main()?;
6771                    ws.tcol_gated.push(engine.uninit(32 * lq)?);
6772                    ws.tcol_opart.push(engine.uninit(32 * ws.o_out)?);
6773                }
6774                let root = &self.ranks[0];
6775                let _m = root.gpu.enter_main()?;
6776                ws.tcol_opeer = Some(root.uninit(32 * ws.o_out)?);
6777                ws.tcol_omix = Some(root.uninit(32 * ws.o_out)?);
6778                ws.tcol_ocap = 32;
6779            }
6780            for rank in 0..ranks {
6781                let engine = &self.ranks[rank];
6782                let _main = engine.gpu.enter_main()?;
6783                if stage_pos {
6784                    let host: Vec<i32> = positions[..t].to_vec();
6785                    let mut view = ws.rope_pos_t[rank].slice_mut(0..t);
6786                    engine.stream().memcpy_htod(&host, &mut view)?;
6787                }
6788                // Combined 6-word table {k, v, len, base, ctr, back}; ctr = this rank's
6789                // per-row counter slab. Built from the pointers the CALLER just read off
6790                // the live distributed cache, and RESTAGED into a persistent slab before
6791                // every launch (MEMRA_ROWS_TAB_RESTAGE, default ON).
6792                //
6793                // The `rows_tabs` memo this replaces was keyed by a hash of
6794                // (k pointer, base pointer, layer, t) but the table it handed back ALSO
6795                // carried the V and LEN pointers, and nothing invalidated it when a
6796                // session's KV cache was dropped. A later session whose K buffer landed on
6797                // a recycled address therefore hit a dead entry, and
6798                // `qk_norm_rope_append_inc_dcw_rows` WROTE this session's K/V rows through
6799                // the freed V/len pointers it still held while `fa_decode_dcw_rows` read
6800                // them back: a whole non-finite row when the freed pages were re-mapped,
6801                // CUDA_ERROR_ILLEGAL_ADDRESS when they were not. The row-table twin in
6802                // `step35_verify_fa_rows_join` was cured of exactly this in 8c8397e0b2
6803                // ("a process-lifetime map cannot prove allocation generation", Hermes
6804                // `11339f5cd3c132a3`); this fused rope+append+fa path was left out of it,
6805                // and MEMRA_FUSE_ROPE_APPEND=1 makes it the arm that actually runs.
6806                let ctr_base = {
6807                    let s = engine.stream();
6808                    let (p, _g) = ws.rope_ctr_t[rank].device_ptr(&s);
6809                    p
6810                };
6811                let host = rows_tab_host(&session_parts[rank], ctr_base, same_session, t);
6812                // STALE-HIT RECEIPT (MEMRA_ROWS_TAB_STALE_SCAN=1, default OFF): replay the
6813                // retired key against the contents we are about to stage. `engaged` proves
6814                // this path executes at all; `STALE` proves the retired memo would have
6815                // handed a live launch another allocation's pointers, and names which word
6816                // moved. Diagnostic only: it never feeds a kernel.
6817                if rows_tab_stale_scan() {
6818                    if ws.rows_tab_shadow.len() != ranks {
6819                        ws.rows_tab_shadow = (0..ranks).map(|_| Default::default()).collect();
6820                    }
6821                    let n = ROWS_TAB_ENGAGED.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
6822                    if let Some(prev) = ws.rows_tab_shadow[rank].get(&tab_keys[rank])
6823                        && prev != &host
6824                    {
6825                        let words = ["k", "v", "len", "base", "ctr", "back"];
6826                        let moved: Vec<String> = (0..host.len())
6827                            .filter(|&i| prev.get(i) != Some(&host[i]))
6828                            .map(|i| format!("{}[row{}]", words[i % 6], i / 6))
6829                            .collect();
6830                        let stale =
6831                            ROWS_TAB_STALE.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
6832                        eprintln!(
6833                            "[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",
6834                            tab_keys[rank],
6835                            moved.join(",")
6836                        );
6837                    }
6838                    ws.rows_tab_shadow[rank].insert(tab_keys[rank], host.clone());
6839                }
6840                let legacy_memo = !rows_tab_restage_on();
6841                if legacy_memo && !ws.rows_tabs[rank].contains_key(&tab_keys[rank]) {
6842                    let tab = engine.stream().clone_htod(&host)?;
6843                    ws.rows_tabs[rank].insert(tab_keys[rank], tab);
6844                }
6845                if !legacy_memo {
6846                    let mut view = ws.rows_tab_t[rank].slice_mut(0..t * 6);
6847                    engine.stream().memcpy_htod(&host, &mut view)?;
6848                }
6849                let StepTpDecodeV2Ws {
6850                    tcol_q,
6851                    tcol_k,
6852                    tcol_v,
6853                    tcol_g,
6854                    fa2_q,
6855                    fa2_gated,
6856                    rope_k_t,
6857                    rope_pos_t,
6858                    rows_tabs,
6859                    rows_tab_t,
6860                    ..
6861                } = &mut *ws;
6862                let tab = if legacy_memo {
6863                    rows_tabs[rank]
6864                        .get(&tab_keys[rank])
6865                        .ok_or("rows tab memo lost its entry")?
6866                } else {
6867                    &rows_tab_t[rank]
6868                };
6869                engine.qk_norm_rope_append_inc_dcw_rows(
6870                    &tcol_q[rank],
6871                    &tcol_k[rank],
6872                    &tcol_v[rank],
6873                    &q_norms[rank],
6874                    &k_norms[rank],
6875                    &mut fa2_q[rank],
6876                    &mut rope_k_t[rank],
6877                    tab,
6878                    &rope_pos_t[rank],
6879                    same_session,
6880                    t,
6881                    lkv,
6882                    lkv,
6883                    k_tok_bytes,
6884                    v_tok_bytes,
6885                    head_dim,
6886                    n_rot,
6887                    local_heads,
6888                    local_kv_heads,
6889                    eps,
6890                    rope_base,
6891                    1.0,
6892                    rope_freqs[rank],
6893                )?;
6894                engine.fa_decode_dcw_rows(
6895                    &fa2_q[rank],
6896                    tab,
6897                    &mut fa2_gated[rank],
6898                    t,
6899                    head_dim,
6900                    local_heads,
6901                    local_kv_heads,
6902                    window,
6903                    max_ns,
6904                    scale,
6905                    k_tok_bytes,
6906                    v_tok_bytes,
6907                    &tcol_g[rank],
6908                )?;
6909                let StepTpDecodeV2Ws {
6910                    fa2_gated,
6911                    tcol_gated,
6912                    ..
6913                } = &mut *ws;
6914                let mut dst = tcol_gated[rank].slice_mut(0..t * lq);
6915                engine
6916                    .stream()
6917                    .memcpy_dtod(&fa2_gated[rank].slice(0..t * lq), &mut dst)?;
6918            }
6919        }
6920        self.decode_v2_oproj_tcol(ws_index, e, o_m, t)
6921    }
6922
6923    /// T-ROW fa join over per-row session tables (the per-session distributed-KV
6924    /// primitive): after all t rows stashed q+gate (their appends landed in rank-stream
6925    /// order), ONE fa_decode_dcw_rows per rank walks every row's own ring with its own
6926    /// geometry — bit-identical per row to its per-row launch — then the o_proj tcol
6927    /// join lands the [t, o_out] `mixed` slab on `e`. `tabs[rank]` is the pre-staged
6928    /// device table on that rank.
6929    #[allow(clippy::too_many_arguments)]
6930    pub(crate) fn decode_v2_fa_rows_join(
6931        &self,
6932        ws_index: usize,
6933        e: &Engine,
6934        o_m: &ResidentStepBf16RowParallel,
6935        tabs: &[&crate::CudaSlice<u64>],
6936        t: usize,
6937        head_dim: usize,
6938        window: usize,
6939        max_ns: usize,
6940        scale: f32,
6941        k_tok_bytes: usize,
6942        v_tok_bytes: usize,
6943    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
6944        let ranks = self.ranks.len();
6945        if tabs.len() != ranks {
6946            return Err("fa rows join needs one table per rank".into());
6947        }
6948        {
6949            let mut guard = self
6950                .decode_v2
6951                .lock()
6952                .map_err(|_| "step TP decode v2 workspace lock is poisoned")?;
6953            let ws = guard
6954                .get_mut(ws_index)
6955                .ok_or("step TP decode v2 workspace index out of range")?;
6956            if ws.fa2_cap < t || ws.fa2_q.len() != ranks {
6957                return Err("fa rows join without stashed rows".into());
6958            }
6959            let lq = ws.local_q_dim;
6960            let local_heads = (ws.heads / ranks).max(1);
6961            let local_kv_heads = (ws.local_kv_dim / head_dim).max(1);
6962            if ws.tcol_ocap < t || ws.tcol_gated.len() != ranks {
6963                ws.tcol_gated.clear();
6964                ws.tcol_opart.clear();
6965                for engine in &self.ranks {
6966                    let _m = engine.gpu.enter_main()?;
6967                    ws.tcol_gated.push(engine.uninit(32 * lq)?);
6968                    ws.tcol_opart.push(engine.uninit(32 * ws.o_out)?);
6969                }
6970                let root = &self.ranks[0];
6971                let _m = root.gpu.enter_main()?;
6972                ws.tcol_opeer = Some(root.uninit(32 * ws.o_out)?);
6973                ws.tcol_omix = Some(root.uninit(32 * ws.o_out)?);
6974                ws.tcol_ocap = 32;
6975            }
6976            for rank in 0..ranks {
6977                let engine = &self.ranks[rank];
6978                let _main = engine.gpu.enter_main()?;
6979                {
6980                    let StepTpDecodeV2Ws {
6981                        fa2_q,
6982                        fa2_gate,
6983                        fa2_gated,
6984                        ..
6985                    } = &mut *ws;
6986                    engine.fa_decode_dcw_rows(
6987                        &fa2_q[rank],
6988                        tabs[rank],
6989                        &mut fa2_gated[rank],
6990                        t,
6991                        head_dim,
6992                        local_heads,
6993                        local_kv_heads,
6994                        window,
6995                        max_ns,
6996                        scale,
6997                        k_tok_bytes,
6998                        v_tok_bytes,
6999                        &fa2_gate[rank],
7000                    )?;
7001                }
7002                let StepTpDecodeV2Ws {
7003                    fa2_gated,
7004                    tcol_gated,
7005                    ..
7006                } = &mut *ws;
7007                let mut dst = tcol_gated[rank].slice_mut(0..t * lq);
7008                engine
7009                    .stream()
7010                    .memcpy_dtod(&fa2_gated[rank].slice(0..t * lq), &mut dst)?;
7011            }
7012        }
7013        self.decode_v2_oproj_tcol(ws_index, e, o_m, t)
7014    }
7015
7016    /// MEMRA_TCOL_OPROJ stash: copy this column's per-rank `gated` rows into the o-tcol
7017    /// slabs (rank-stream ordered behind the attention kernels that produced them). The
7018    /// per-column finish choreography is skipped entirely; `decode_v2_oproj_tcol` joins
7019    /// every column afterwards.
7020    pub(crate) fn decode_v2_stash_gated(
7021        &self,
7022        ws: &mut StepTpDecodeV2Ws,
7023        e: &Engine,
7024        col: usize,
7025    ) -> Result<(), Box<dyn std::error::Error>> {
7026        let ranks = self.ranks.len();
7027        // 32, not 8: the slabs below have been 32 rows since the slab-width fix, and the walk now
7028        // runs chunks up to t=32 (the w=16 arm died here on a guard three widths staler than its
7029        // own allocation, 2026-08-27).
7030        if col >= 32 {
7031            return Err("decode_v2_stash_gated column out of range".into());
7032        }
7033        let lq = ws.local_q_dim;
7034        if ws.tcol_ocap == 0 || ws.tcol_gated.len() != ranks {
7035            ws.tcol_gated.clear();
7036            ws.tcol_opart.clear();
7037            for engine in &self.ranks {
7038                let _m = engine.gpu.enter_main()?;
7039                ws.tcol_gated.push(engine.uninit(32 * lq)?);
7040                ws.tcol_opart.push(engine.uninit(32 * ws.o_out)?);
7041            }
7042            let root = &self.ranks[0];
7043            let _m = root.gpu.enter_main()?;
7044            ws.tcol_opeer = Some(root.uninit(32 * ws.o_out)?);
7045            ws.tcol_omix = Some(root.uninit(32 * ws.o_out)?);
7046            ws.tcol_ocap = 32;
7047        }
7048        for rank in 0..ranks {
7049            let engine = &self.ranks[rank];
7050            let _main = engine.gpu.enter_main()?;
7051            let mut dst = ws.tcol_gated[rank].slice_mut(col * lq..(col + 1) * lq);
7052            engine
7053                .stream()
7054                .memcpy_dtod(&ws.gated[rank].slice(0..lq), &mut dst)?;
7055            // The skipped finish's e-wait was ALSO the anti-dependency guard: it ordered
7056            // e's NEXT column's h/pos re-staging behind this column's rank-side raw pulls.
7057            // Record each rank here and make e wait — same protection, no o_proj work.
7058            ws.ev_rank[rank].record(&engine.stream())?;
7059        }
7060        {
7061            let _main = e.gpu.enter_main()?;
7062            for ev in ws.ev_rank.iter() {
7063                e.stream().wait(ev)?;
7064            }
7065        }
7066        Ok(())
7067    }
7068
7069    /// MEMRA_TCOL_OPROJ join: one weight-amortized b4_tcol per rank over the stashed
7070    /// `gated` slabs (per-column FP order == the t=1 b4 kernel), one peer pull of rank1's
7071    /// partial slab, one elementwise slab add on the root (independent elements — each
7072    /// column's add is the exact direct-join `add(p0, p1)`), then the joined `mixed` slab
7073    /// lands on `e`. Returns [t, o_out] on the model engine.
7074    pub(crate) fn decode_v2_oproj_tcol(
7075        &self,
7076        ws_index: usize,
7077        e: &Engine,
7078        o_m: &ResidentStepBf16RowParallel,
7079        t: usize,
7080    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
7081        let ranks = self.ranks.len();
7082        let mut guard = self
7083            .decode_v2
7084            .lock()
7085            .map_err(|_| "step TP decode v2 workspace lock is poisoned")?;
7086        let ws = guard
7087            .get_mut(ws_index)
7088            .ok_or("step TP decode v2 workspace index out of range")?;
7089        if ranks != 2 || ws.blocks_per_rank != 4 || t == 0 || t > 32 || ws.tcol_ocap < t {
7090            return Err("decode_v2_oproj_tcol geometry".into());
7091        }
7092        for rank in 0..ranks {
7093            let engine = &self.ranks[rank];
7094            let _main = engine.gpu.enter_main()?;
7095            let mut weights = Vec::with_capacity(4);
7096            for block in 0..4 {
7097                let ResidentBf16Weight::Bf16(weight) = &o_m.ranks[rank][block].weight else {
7098                    return Err("tcol o_proj requires bf16-resident O blocks".into());
7099                };
7100                weights.push(weight);
7101            }
7102            {
7103                let StepTpDecodeV2Ws {
7104                    tcol_gated,
7105                    tcol_opart,
7106                    local_q_dim,
7107                    o_block_cols,
7108                    o_out,
7109                    w8t_oaq,
7110                    w8t_oad,
7111                    w8t_oin,
7112                    w8t_cap,
7113                    ..
7114                } = &mut *ws;
7115                // MEMRA_TCOL_OPROJ_REF=1 (bisect): fill the partial slab via the t=1 b4
7116                // kernel per column — separates choreography bugs from tcol-kernel bugs.
7117                static REFK: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
7118                let refk = *REFK
7119                    .get_or_init(|| std::env::var("MEMRA_TCOL_OPROJ_REF").as_deref() == Ok("1"));
7120                if refk {
7121                    let lq = *local_q_dim;
7122                    let mut xr = engine.uninit(lq)?;
7123                    let mut yr = engine.uninit(*o_out)?;
7124                    for c in 0..t {
7125                        {
7126                            let mut dst = xr.slice_mut(0..lq);
7127                            engine.stream().memcpy_dtod(
7128                                &tcol_gated[rank].slice(c * lq..(c + 1) * lq),
7129                                &mut dst,
7130                            )?;
7131                        }
7132                        engine.matvec_bf16_b4_into(
7133                            [weights[0], weights[1], weights[2], weights[3]],
7134                            &xr,
7135                            &mut yr,
7136                            *o_block_cols,
7137                            *o_out,
7138                        )?;
7139                        let mut dst = tcol_opart[rank].slice_mut(c * *o_out..(c + 1) * *o_out);
7140                        engine
7141                            .stream()
7142                            .memcpy_dtod(&yr.slice(0..*o_out), &mut dst)?;
7143                    }
7144                } else if crate::step_tp_w8_on()
7145                    && (0..4).all(|b| o_m.ranks[rank][b].q8.is_some())
7146                    && (4 * *o_block_cols) % 32 == 0
7147                {
7148                    // The verify walk's biggest single kernel: bf16 tcol o_proj was 24.8% of
7149                    // spec GPU time. Same planar q8_0 mirrors the decode arm uses, one launch
7150                    // over all t columns.
7151                    let in_f = 4 * *o_block_cols;
7152                    if *w8t_oin != in_f || *w8t_cap < t || w8t_oaq.len() != ranks {
7153                        w8t_oaq.clear();
7154                        w8t_oad.clear();
7155                        for e_rank in &self.ranks {
7156                            let _m = e_rank.gpu.enter_main()?;
7157                            w8t_oaq.push(e_rank.alloc_i8_uninit(32 * in_f)?);
7158                            w8t_oad.push(e_rank.alloc_uninit::<f32>(32 * (in_f / 32))?);
7159                        }
7160                        *w8t_oin = in_f;
7161                        *w8t_cap = (*w8t_cap).max(32);
7162                    }
7163                    engine.quantize_q8_1_into(
7164                        &tcol_gated[rank],
7165                        t,
7166                        in_f,
7167                        &mut w8t_oaq[rank],
7168                        &mut w8t_oad[rank],
7169                    )?;
7170                    engine.qmatvec_q8_0_b4_rp_t_into(
7171                        [
7172                            o_m.ranks[rank][0].q8.as_ref().unwrap(),
7173                            o_m.ranks[rank][1].q8.as_ref().unwrap(),
7174                            o_m.ranks[rank][2].q8.as_ref().unwrap(),
7175                            o_m.ranks[rank][3].q8.as_ref().unwrap(),
7176                        ],
7177                        &w8t_oaq[rank],
7178                        &w8t_oad[rank],
7179                        &mut tcol_opart[rank],
7180                        *o_block_cols,
7181                        *o_out,
7182                        t,
7183                    )?;
7184                } else {
7185                    engine.matvec_bf16_b4_tcol_into(
7186                        [weights[0], weights[1], weights[2], weights[3]],
7187                        &tcol_gated[rank],
7188                        &mut tcol_opart[rank],
7189                        *o_block_cols,
7190                        *o_out,
7191                        t,
7192                    )?;
7193                }
7194            }
7195            if rank != 0 {
7196                ws.ev_rank[rank].record(&engine.stream())?;
7197            }
7198        }
7199        let root = &self.ranks[0];
7200        {
7201            let _main = root.gpu.enter_main()?;
7202            for ev in ws.ev_rank.iter().skip(1) {
7203                root.stream().wait(ev)?;
7204            }
7205            {
7206                let StepTpDecodeV2Ws {
7207                    tcol_opart,
7208                    tcol_opeer,
7209                    tcol_omix,
7210                    o_out,
7211                    ..
7212                } = &mut *ws;
7213                let opeer = tcol_opeer.as_mut().ok_or("tcol o_proj slabs not armed")?;
7214                let omix = tcol_omix.as_mut().ok_or("tcol o_proj slabs not armed")?;
7215                {
7216                    let mut dst = opeer.slice_mut(0..t * *o_out);
7217                    root.stream()
7218                        .memcpy_dtod(&tcol_opart[1].slice(0..t * *o_out), &mut dst)?;
7219                }
7220                // Elementwise over the whole slab: per element identical to the per-column
7221                // direct-join add (independent lanes, same operand values).
7222                root.add(&tcol_opart[0], opeer, omix, t * *o_out)?;
7223            }
7224            ws.ev_oproj.record(&root.stream())?;
7225        }
7226        let _main = e.gpu.enter_main()?;
7227        e.stream().wait(&ws.ev_oproj)?;
7228        let mut out = e.uninit(t * ws.o_out)?;
7229        let omix = ws.tcol_omix.as_ref().ok_or("tcol o_proj slabs not armed")?;
7230        e.stream().memcpy_dtod(
7231            &omix.slice(0..t * ws.o_out),
7232            &mut out.slice_mut(0..t * ws.o_out),
7233        )?;
7234        Ok(out)
7235    }
7236
7237    #[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
7238    pub(crate) fn decode_v2_input_qkv(
7239        &self,
7240        ws: &mut StepTpDecodeV2Ws,
7241        e: &Engine,
7242        h: &CudaSlice<f32>,
7243        pos_d: &CudaSlice<i32>,
7244        gate_raw: Option<&CudaSlice<f32>>,
7245        gate_shards: Option<StepTpGateShards<'_>>,
7246        decode_input: &mut ResidentReplicatedDeviceRows,
7247        q_m: &ResidentBf16ColumnParallel,
7248        k_m: &ResidentBf16ColumnParallel,
7249        v_m: &ResidentBf16ColumnParallel,
7250        q_norm: &[CudaSlice<f32>],
7251        k_norm: &[CudaSlice<f32>],
7252        head_dim: usize,
7253        n_rot: usize,
7254        rope_base: f32,
7255        rope_freqs: &[Option<&CudaSlice<f32>>],
7256        rms_eps: f32,
7257        has_gate: bool,
7258        defer_norm_rope: bool,
7259        tcol_col: Option<usize>,
7260    ) -> Result<(), Box<dyn std::error::Error>> {
7261        let ranks = self.ranks.len();
7262        validate_replicated_device_rows(&self.ranks, decode_input)?;
7263        let gate_sources = usize::from(gate_raw.is_some()) + usize::from(gate_shards.is_some());
7264        if decode_input.tokens != 1
7265            || decode_input.width != q_m.in_features
7266            || pos_d.len() != 1
7267            || gate_raw.is_some_and(|gate| gate.len() != ws.heads)
7268            || (has_gate && gate_sources != 1)
7269            || (!has_gate && gate_sources != 0)
7270            || gate_shards.as_ref().is_some_and(|shards| match shards {
7271                StepTpGateShards::F32(shards) => shards.len() != ranks,
7272                StepTpGateShards::Bf16(shards) => shards.len() != ranks,
7273            })
7274            || q_norm.len() != ranks
7275            || k_norm.len() != ranks
7276            || rope_freqs.len() != ranks
7277            || e.ctx().ordinal() != ws.e_device
7278        {
7279            return Err("step TP decode v2 input geometry mismatch".into());
7280        }
7281
7282        let qkv_fused = step_tp_qkv_fused_enabled()?;
7283        if gate_shards.is_some() && !qkv_fused {
7284            return Err("step TP decode v2 gate shards require MEMRA_STEP_TP_QKV_FUSED=1".into());
7285        }
7286        let values = decode_input.width;
7287        if h.len() != values {
7288            return Err(format!(
7289                "step TP decode v2 hidden width {} != replicated width {values}",
7290                h.len()
7291            )
7292            .into());
7293        }
7294
7295        if qkv_fused {
7296            // STAGE-BASED flow (graph increment A): h and pos land in fixed e-context stages
7297            // (one e-stream copy each), the entry event covers them, and every rank raw-copies
7298            // from the stages on its own stream — exactly the shape graph capture wraps.
7299            if ws.h_stage.is_none() {
7300                use cudarc::driver::DevicePtr;
7301                let _main = e.gpu.enter_main()?;
7302                let h_stage = e.uninit(values)?;
7303                let pos_stage = e.htod_i32(&[0])?;
7304                {
7305                    let stream = e.stream();
7306                    let (hp, _g0) = h_stage.device_ptr(&stream);
7307                    let (pp, _g1) = pos_stage.device_ptr(&stream);
7308                    ws.raw_h_stage = hp;
7309                    ws.raw_pos_stage = pp;
7310                }
7311                ws.h_stage = Some(h_stage);
7312                ws.pos_stage = Some(pos_stage);
7313                for rank in 0..ranks {
7314                    use cudarc::driver::DevicePtr;
7315                    let engine = &self.ranks[rank];
7316                    let _rmain = engine.gpu.enter_main()?;
7317                    let attn_in = engine.uninit(values)?;
7318                    let (dp, pp) = {
7319                        let stream = engine.stream();
7320                        let (dp, _g2) = attn_in.device_ptr(&stream);
7321                        let (pp, _g3) = ws.pos[rank].device_ptr(&stream);
7322                        (dp, pp)
7323                    };
7324                    ws.raw_attn_in.push(dp);
7325                    ws.raw_pos.push(pp);
7326                    ws.attn_in.push(attn_in);
7327                }
7328                {
7329                    use cudarc::driver::DevicePtr;
7330                    let root = &self.ranks[0];
7331                    let _rmain = root.gpu.enter_main()?;
7332                    let stream = root.stream();
7333                    let (a, _g) = ws.peer_partial.device_ptr(&stream);
7334                    let (b, _g) = ws.k_shadow.device_ptr(&stream);
7335                    let (c, _g) = ws.v_shadow.device_ptr(&stream);
7336                    ws.raw_peer_partial = a;
7337                    ws.raw_k_shadow = b;
7338                    ws.raw_v_shadow = c;
7339                }
7340                {
7341                    use cudarc::driver::DevicePtr;
7342                    let rank1 = &self.ranks[1];
7343                    let _rmain = rank1.gpu.enter_main()?;
7344                    let stream = rank1.stream();
7345                    let (a, _g) = ws.o_partials[1][0].device_ptr(&stream);
7346                    let (b, _g) = ws.k[1].device_ptr(&stream);
7347                    let (c, _g) = ws.v_raw[1].device_ptr(&stream);
7348                    ws.raw_o_partial1 = a;
7349                    ws.raw_k1 = b;
7350                    ws.raw_v1 = c;
7351                }
7352            }
7353            {
7354                let _main = e.gpu.enter_main()?;
7355                {
7356                    // (Always staged: a tcol column below the dcw floor falls back to the
7357                    // normal fused arm, which reads h through this stage.)
7358                    let h_stage = ws.h_stage.as_mut().expect("stage armed above");
7359                    let mut dst = h_stage.slice_mut(0..values);
7360                    e.stream().memcpy_dtod(&h.slice(0..values), &mut dst)?;
7361                }
7362                {
7363                    let pos_stage = ws.pos_stage.as_mut().expect("stage armed above");
7364                    let mut dst = pos_stage.slice_mut(0..1);
7365                    e.stream().memcpy_dtod(&pos_d.slice(0..1), &mut dst)?;
7366                }
7367                ws.ev_entry.record(&e.stream())?;
7368            }
7369            for rank in 0..ranks {
7370                let engine = &self.ranks[rank];
7371                let _main = engine.gpu.enter_main()?;
7372                engine.stream().wait(&ws.ev_entry)?;
7373            }
7374        } else {
7375            // Evented replicate flow (the pre-stage shape, kept for the non-fused class).
7376            {
7377                let _main = e.gpu.enter_main()?;
7378                if let Some(gate_raw) = gate_raw {
7379                    let mut gate_dst = ws.gate_e.slice_mut(0..ws.heads);
7380                    e.stream()
7381                        .memcpy_dtod(&gate_raw.slice(0..ws.heads), &mut gate_dst)?;
7382                }
7383                ws.ev_entry.record(&e.stream())?;
7384            }
7385            {
7386                let root = &self.ranks[0];
7387                let _main = root.gpu.enter_main()?;
7388                root.stream().wait(&ws.ev_entry)?;
7389                let mut destination = decode_input.ranks[0].slice_mut(0..values);
7390                root.stream()
7391                    .memcpy_dtod(&h.slice(0..values), &mut destination)?;
7392                ws.ev_refresh.record(&root.stream())?;
7393            }
7394            for rank in 1..ranks {
7395                let engine = &self.ranks[rank];
7396                let _main = engine.gpu.enter_main()?;
7397                engine.stream().wait(&ws.ev_refresh)?;
7398                let (root_rows, peer_rows) = decode_input.ranks.split_at_mut(rank);
7399                let mut destination = peer_rows[0].slice_mut(0..values);
7400                engine
7401                    .stream()
7402                    .memcpy_dtod(&root_rows[0].slice(0..values), &mut destination)?;
7403            }
7404        }
7405        for rank in 0..ranks {
7406            self.decode_v2_input_qkv_rank(
7407                ws,
7408                pos_d,
7409                decode_input,
7410                q_m,
7411                k_m,
7412                v_m,
7413                q_norm,
7414                k_norm,
7415                head_dim,
7416                n_rot,
7417                rope_base,
7418                rope_freqs,
7419                rms_eps,
7420                gate_shards.as_ref(),
7421                has_gate,
7422                qkv_fused,
7423                defer_norm_rope,
7424                rank,
7425                tcol_col,
7426            )?;
7427        }
7428        Ok(())
7429    }
7430
7431    /// One rank's slice of `decode_v2_input_qkv` (projection, norm+rope, gate staging) — the
7432    /// per-device issue unit the whole-token graph captures on that rank's stream.
7433    #[allow(clippy::too_many_arguments)]
7434    pub(crate) fn decode_v2_input_qkv_rank(
7435        &self,
7436        ws: &mut StepTpDecodeV2Ws,
7437        pos_d: &CudaSlice<i32>,
7438        decode_input: &mut ResidentReplicatedDeviceRows,
7439        q_m: &ResidentBf16ColumnParallel,
7440        k_m: &ResidentBf16ColumnParallel,
7441        v_m: &ResidentBf16ColumnParallel,
7442        q_norm: &[CudaSlice<f32>],
7443        k_norm: &[CudaSlice<f32>],
7444        head_dim: usize,
7445        n_rot: usize,
7446        rope_base: f32,
7447        rope_freqs: &[Option<&CudaSlice<f32>>],
7448        rms_eps: f32,
7449        gate_shards: Option<&StepTpGateShards<'_>>,
7450        has_gate: bool,
7451        qkv_fused: bool,
7452        defer_norm_rope: bool,
7453        rank: usize,
7454        tcol_col: Option<usize>,
7455    ) -> Result<(), Box<dyn std::error::Error>> {
7456        let ranks = self.ranks.len();
7457        let local_heads = ws.local_q_dim / head_dim;
7458        let local_kv_heads = ws.local_kv_dim / head_dim;
7459        let engine = &self.ranks[rank];
7460        let _main = engine.gpu.enter_main()?;
7461        let ws_e_device = ws.e_device;
7462        // T-COLUMN SELECT (spec verify): the projections for this column were precomputed
7463        // by the weight-amortized tcol kernel — copy the column into the single-row buffers
7464        // (pure f32 moves, bit-exact) and skip the per-column matvec. Rope/norm/append run
7465        // below exactly as in the t=1 program.
7466        if qkv_fused && tcol_col.is_some() {
7467            #[allow(clippy::unnecessary_unwrap)]
7468            // allow: the Some-guard sits in a multi-clause regime gate; if-let would reshape the arm structure
7469            let c = tcol_col.expect("checked");
7470            if ws.tcol_cap == 0 || ws.tcol_q.len() != ranks {
7471                return Err("tcol select without precompute".into());
7472            }
7473            // The select skips the matvec but NOT the position: rope/append below still
7474            // read this rank's pos buffer, which only the (skipped) stage path fills for
7475            // peer-device ranks. Stage it here or rank1 ropes at the previous position.
7476            if engine.ctx().ordinal() != ws_e_device {
7477                raw_copy_bytes(ws.raw_pos[rank], ws.raw_pos_stage, 4, engine)?;
7478            }
7479            let StepTpDecodeV2Ws {
7480                tcol_q,
7481                tcol_k,
7482                tcol_v,
7483                tcol_g,
7484                q_raw,
7485                k_raw,
7486                v_raw,
7487                gate,
7488                local_q_dim,
7489                local_kv_dim,
7490                heads,
7491                ..
7492            } = &mut *ws;
7493            let lg = *heads / ranks;
7494            let stream = engine.stream();
7495            {
7496                let mut dst = q_raw[rank].slice_mut(0..*local_q_dim);
7497                stream.memcpy_dtod(
7498                    &tcol_q[rank].slice(c * *local_q_dim..(c + 1) * *local_q_dim),
7499                    &mut dst,
7500                )?;
7501            }
7502            {
7503                let mut dst = k_raw[rank].slice_mut(0..*local_kv_dim);
7504                stream.memcpy_dtod(
7505                    &tcol_k[rank].slice(c * *local_kv_dim..(c + 1) * *local_kv_dim),
7506                    &mut dst,
7507                )?;
7508            }
7509            {
7510                let mut dst = v_raw[rank].slice_mut(0..*local_kv_dim);
7511                stream.memcpy_dtod(
7512                    &tcol_v[rank].slice(c * *local_kv_dim..(c + 1) * *local_kv_dim),
7513                    &mut dst,
7514                )?;
7515            }
7516            if has_gate && lg > 0 {
7517                let mut dst = gate[rank].slice_mut(0..lg);
7518                stream.memcpy_dtod(&tcol_g[rank].slice(c * lg..(c + 1) * lg), &mut dst)?;
7519            }
7520            if !defer_norm_rope {
7521                // Below the dcw floor (or a non-defer shape) the col-select cannot apply:
7522                // fall through and recompute this column's QKV from the REAL h row — the
7523                // caller always passes it. The slab copies above are dead stores.
7524            } else {
7525                return Ok(());
7526            }
7527        }
7528        if qkv_fused {
7529            // Stage-based input: raw copies from the fixed e-context stages (capture-safe;
7530            // eager ordering comes from the caller's ev_entry wait on this stream). The rank
7531            // SHARING e's device reads the stages directly — same context (probed), ordering
7532            // identical (ev_entry / graph edge), bytes identical: the copies are pure waste.
7533            let same_dev = engine.ctx().ordinal() == ws.e_device;
7534            if !same_dev {
7535                raw_copy_bytes(
7536                    ws.raw_attn_in[rank],
7537                    ws.raw_h_stage,
7538                    q_m.in_features * 4,
7539                    engine,
7540                )?;
7541                raw_copy_bytes(ws.raw_pos[rank], ws.raw_pos_stage, 4, engine)?;
7542            }
7543            let StepTpDecodeV2Ws {
7544                q_raw,
7545                k_raw,
7546                v_raw,
7547                gate,
7548                gate_e,
7549                attn_in,
7550                h_stage,
7551                heads,
7552                local_q_dim,
7553                local_kv_dim,
7554                w8_aq,
7555                w8_ad,
7556                w8_in,
7557                ..
7558            } = &mut *ws;
7559            let input_ref: &CudaSlice<f32> = if same_dev {
7560                h_stage
7561                    .as_ref()
7562                    .ok_or("step TP decode v2 stage not armed")?
7563            } else {
7564                &attn_in[rank]
7565            };
7566            match (
7567                &q_m.ranks[rank].weight,
7568                &k_m.ranks[rank].weight,
7569                &v_m.ranks[rank].weight,
7570            ) {
7571                (
7572                    ResidentBf16Weight::F32(wq),
7573                    ResidentBf16Weight::F32(wk),
7574                    ResidentBf16Weight::F32(wv),
7575                ) => {
7576                    let (wg, out_g) = match &gate_shards {
7577                        Some(StepTpGateShards::F32(shards)) => (&shards[rank], *heads / ranks),
7578                        Some(StepTpGateShards::Bf16(_)) => {
7579                            return Err("step TP decode v2 gate shard class does not \
7580                                            match the F32 projections"
7581                                .into());
7582                        }
7583                        // out_g = 0: the kernel never reads wg; any resident buffer works.
7584                        None => (&*gate_e, 0),
7585                    };
7586                    engine.matvec_f32_qkv_into(
7587                        wq,
7588                        wk,
7589                        wv,
7590                        wg,
7591                        input_ref,
7592                        &mut q_raw[rank],
7593                        &mut k_raw[rank],
7594                        &mut v_raw[rank],
7595                        &mut gate[rank],
7596                        q_m.in_features,
7597                        *local_q_dim,
7598                        *local_kv_dim,
7599                        out_g,
7600                    )?;
7601                }
7602                (
7603                    ResidentBf16Weight::Bf16(wq),
7604                    ResidentBf16Weight::Bf16(wk),
7605                    ResidentBf16Weight::Bf16(wv),
7606                ) => {
7607                    let (wg, out_g) = match &gate_shards {
7608                        Some(StepTpGateShards::Bf16(shards)) => (&shards[rank], *heads / ranks),
7609                        Some(StepTpGateShards::F32(_)) => {
7610                            return Err("step TP decode v2 gate shard class does not \
7611                                            match the bf16 projections"
7612                                .into());
7613                        }
7614                        None => (wq, 0),
7615                    };
7616                    // MEMRA_STEP_TP_W8: q8_0 weights + q8_1 activation through mmvq instead of
7617                    // the fused bf16 qkvg. NUMERIC CLASS (int8 dp4a with per-32 scales, not a
7618                    // bf16 fma chain) — argmax-gated, never a bit-tape flip. Q, K and V each
7619                    // get their own launch because the fused kernel has no q8 twin; the gate
7620                    // rows stay bf16 (32 rows, ~0.3 MB, nothing to win and one less class to
7621                    // qualify). Measured motive: 23.0 us bf16 -> 14.0 us q8 at this shape.
7622                    let in_f = q_m.in_features;
7623                    let q8_ready = crate::step_tp_w8_on()
7624                        && q_m.ranks[rank].q8.is_some()
7625                        && k_m.ranks[rank].q8.is_some()
7626                        && v_m.ranks[rank].q8.is_some();
7627                    if q8_ready {
7628                        if *w8_in != in_f || w8_aq.len() != ranks {
7629                            w8_aq.clear();
7630                            w8_ad.clear();
7631                            for e_rank in &self.ranks {
7632                                let _m = e_rank.gpu.enter_main()?;
7633                                w8_aq.push(e_rank.alloc_uninit::<i8>(in_f)?);
7634                                w8_ad.push(e_rank.alloc_uninit::<f32>(in_f / 32)?);
7635                            }
7636                            *w8_in = in_f;
7637                        }
7638                        engine.quantize_q8_1_into(
7639                            input_ref,
7640                            1,
7641                            in_f,
7642                            &mut w8_aq[rank],
7643                            &mut w8_ad[rank],
7644                        )?;
7645                        // ONE launch over the stacked q/k/v rows. The three-call version
7646                        // measured 79.52 vs 80.72 tok/s — SLOWER than the bf16 fused kernel —
7647                        // because three launches plus the activation quantize cost more than
7648                        // the halved weight bytes save. Bit-identical to those three calls.
7649                        engine.qmatvec_q8_0_qkv_rp_into(
7650                            q_m.ranks[rank].q8.as_ref().unwrap(),
7651                            k_m.ranks[rank].q8.as_ref().unwrap(),
7652                            v_m.ranks[rank].q8.as_ref().unwrap(),
7653                            &w8_aq[rank],
7654                            &w8_ad[rank],
7655                            &mut q_raw[rank],
7656                            &mut k_raw[rank],
7657                            &mut v_raw[rank],
7658                            in_f,
7659                            *local_q_dim,
7660                            *local_kv_dim,
7661                        )?;
7662                        if out_g > 0 {
7663                            engine.matvec_bf16_into(wg, input_ref, &mut gate[rank], in_f, out_g)?;
7664                        }
7665                    } else {
7666                        engine.matvec_bf16_qkvg_into(
7667                            wq,
7668                            wk,
7669                            wv,
7670                            wg,
7671                            input_ref,
7672                            &mut q_raw[rank],
7673                            &mut k_raw[rank],
7674                            &mut v_raw[rank],
7675                            &mut gate[rank],
7676                            q_m.in_features,
7677                            *local_q_dim,
7678                            *local_kv_dim,
7679                            out_g,
7680                        )?;
7681                    }
7682                }
7683                _ => {
7684                    return Err("step TP decode v2 QKV projections mix residency classes".into());
7685                }
7686            }
7687        } else {
7688            for (matrix, local_out, raw) in [
7689                (q_m, ws.local_q_dim, &mut ws.q_raw),
7690                (k_m, ws.local_kv_dim, &mut ws.k_raw),
7691                (v_m, ws.local_kv_dim, &mut ws.v_raw),
7692            ] {
7693                let ResidentBf16Weight::F32(values_w) = &matrix.ranks[rank].weight else {
7694                    return Err("step TP decode v2 lost its F32 projection residency".into());
7695                };
7696                let chunk_rows = matrix.canonical_chunk_rows.unwrap_or(local_out);
7697                engine.linear_f32_resident_canonical_rows_t1_into(
7698                    &decode_input.ranks[rank],
7699                    values_w,
7700                    &mut raw[rank],
7701                    matrix.in_features,
7702                    local_out,
7703                    chunk_rows,
7704                )?;
7705            }
7706        }
7707        if qkv_fused && defer_norm_rope {
7708            // FUSION #1 defers norm+rope to the caller's fused rope+append+inc launch.
7709        } else if qkv_fused {
7710            // Fused norm+rope: one launch; the position comes from the rank-local staged
7711            // copy (raw-copied above from the fixed e-context pos stage — capture-safe).
7712            let StepTpDecodeV2Ws {
7713                q_raw,
7714                k_raw,
7715                q,
7716                k,
7717                pos,
7718                pos_stage,
7719                ..
7720            } = &mut *ws;
7721            let same_dev = engine.ctx().ordinal() == ws_e_device;
7722            let pos_ref: &CudaSlice<i32> = if same_dev {
7723                pos_stage
7724                    .as_ref()
7725                    .ok_or("step TP decode v2 pos stage not armed")?
7726            } else {
7727                &pos[rank]
7728            };
7729            engine.qk_norm_rope_into(
7730                &q_raw[rank],
7731                &k_raw[rank],
7732                &q_norm[rank],
7733                &k_norm[rank],
7734                &mut q[rank],
7735                &mut k[rank],
7736                pos_ref,
7737                head_dim,
7738                n_rot,
7739                local_heads,
7740                local_kv_heads,
7741                rms_eps,
7742                rope_base,
7743                1.0,
7744                rope_freqs[rank],
7745            )?;
7746        } else {
7747            engine.rms_norm(
7748                &ws.q_raw[rank],
7749                &q_norm[rank],
7750                &mut ws.q[rank],
7751                head_dim,
7752                local_heads,
7753                rms_eps,
7754            )?;
7755            engine.rms_norm(
7756                &ws.k_raw[rank],
7757                &k_norm[rank],
7758                &mut ws.k[rank],
7759                head_dim,
7760                local_kv_heads,
7761                rms_eps,
7762            )?;
7763            {
7764                let mut pos_dst = ws.pos[rank].slice_mut(0..1);
7765                engine
7766                    .stream()
7767                    .memcpy_dtod(&pos_d.slice(0..1), &mut pos_dst)?;
7768            }
7769            engine.rope_neox2(
7770                &mut ws.q[rank],
7771                &mut ws.k[rank],
7772                &ws.pos[rank],
7773                head_dim,
7774                n_rot,
7775                local_heads,
7776                local_kv_heads,
7777                1,
7778                rope_base,
7779                1.0,
7780                rope_freqs[rank],
7781            )?;
7782        }
7783        if has_gate && gate_shards.is_none() {
7784            let gate_start = rank * (ws.heads / ranks);
7785            let mut gate_dst = ws.gate[rank].slice_mut(0..ws.heads / ranks);
7786            engine.stream().memcpy_dtod(
7787                &ws.gate_e.slice(gate_start..gate_start + ws.heads / ranks),
7788                &mut gate_dst,
7789            )?;
7790        }
7791        Ok(())
7792    }
7793
7794    /// One rank's O-partial slice of `decode_v2_finish` — the per-device issue unit the
7795    /// whole-token graph captures on that rank's stream (the rank-done event stays with the
7796    /// eager caller; graphs order via parent edges instead).
7797    pub(crate) fn decode_v2_finish_rank_partial(
7798        &self,
7799        ws: &mut StepTpDecodeV2Ws,
7800        o_m: &ResidentStepBf16RowParallel,
7801        o_fused: bool,
7802        rank: usize,
7803    ) -> Result<(), Box<dyn std::error::Error>> {
7804        let engine = &self.ranks[rank];
7805        let _main = engine.gpu.enter_main()?;
7806        if o_fused {
7807            let StepTpDecodeV2Ws {
7808                gated,
7809                o_partials,
7810                o_block_cols,
7811                o_out,
7812                w8o_aq,
7813                w8o_ad,
7814                w8o_in,
7815                ..
7816            } = &mut *ws;
7817            let all_f32 = o_m.ranks[rank]
7818                .iter()
7819                .all(|block| matches!(block.weight, ResidentBf16Weight::F32(_)));
7820            if all_f32 {
7821                let mut weights = Vec::with_capacity(4);
7822                for block in 0..4 {
7823                    let ResidentBf16Weight::F32(weight) = &o_m.ranks[rank][block].weight else {
7824                        unreachable!("all_f32 checked above");
7825                    };
7826                    weights.push(weight);
7827                }
7828                engine.matvec_f32_b4_into(
7829                    [weights[0], weights[1], weights[2], weights[3]],
7830                    &gated[rank],
7831                    &mut o_partials[rank][0],
7832                    *o_block_cols,
7833                    *o_out,
7834                )?;
7835            } else if crate::step_tp_w8_on() && (0..4).all(|b| o_m.ranks[rank][b].q8.is_some()) {
7836                // MEMRA_STEP_TP_W8, o_proj half: quantize the gated attention output once and
7837                // run all four HEAD_SPLIT blocks in one q8 launch. Measured motive: bf16 b4 is
7838                // 24.2 us/layer against 11.7 for the q8 shape — the largest decode line left
7839                // after the QKV arm banked +2.9%.
7840                let in_f = 4 * *o_block_cols;
7841                if *w8o_in != in_f || w8o_aq.len() != self.ranks.len() {
7842                    w8o_aq.clear();
7843                    w8o_ad.clear();
7844                    for e_rank in &self.ranks {
7845                        let _m = e_rank.gpu.enter_main()?;
7846                        w8o_aq.push(e_rank.alloc_uninit::<i8>(in_f)?);
7847                        w8o_ad.push(e_rank.alloc_uninit::<f32>(in_f / 32)?);
7848                    }
7849                    *w8o_in = in_f;
7850                }
7851                engine.quantize_q8_1_into(
7852                    &gated[rank],
7853                    1,
7854                    in_f,
7855                    &mut w8o_aq[rank],
7856                    &mut w8o_ad[rank],
7857                )?;
7858                engine.qmatvec_q8_0_b4_rp_into(
7859                    [
7860                        o_m.ranks[rank][0].q8.as_ref().unwrap(),
7861                        o_m.ranks[rank][1].q8.as_ref().unwrap(),
7862                        o_m.ranks[rank][2].q8.as_ref().unwrap(),
7863                        o_m.ranks[rank][3].q8.as_ref().unwrap(),
7864                    ],
7865                    &w8o_aq[rank],
7866                    &w8o_ad[rank],
7867                    &mut o_partials[rank][0],
7868                    *o_block_cols,
7869                    *o_out,
7870                )?;
7871            } else {
7872                let mut weights = Vec::with_capacity(4);
7873                for block in 0..4 {
7874                    let ResidentBf16Weight::Bf16(weight) = &o_m.ranks[rank][block].weight else {
7875                        return Err("step TP decode v2 O projections mix residency classes".into());
7876                    };
7877                    weights.push(weight);
7878                }
7879                engine.matvec_bf16_b4_into(
7880                    [weights[0], weights[1], weights[2], weights[3]],
7881                    &gated[rank],
7882                    &mut o_partials[rank][0],
7883                    *o_block_cols,
7884                    *o_out,
7885                )?;
7886            }
7887        } else {
7888            for block in 0..ws.blocks_per_rank {
7889                let x =
7890                    ws.gated[rank].slice(block * ws.o_block_cols..(block + 1) * ws.o_block_cols);
7891                let mut y = ws.o_partials[rank][block].slice_mut(0..ws.o_out);
7892                match &o_m.ranks[rank][block].weight {
7893                    ResidentBf16Weight::F32(weight) => {
7894                        let w = weight.slice(0..weight.len());
7895                        engine.linear_t1_into(&x, &w, &mut y, ws.o_block_cols, ws.o_out)?;
7896                    }
7897                    ResidentBf16Weight::Bf16(weight) => {
7898                        engine.matvec_bf16_views_into(
7899                            weight,
7900                            &x,
7901                            &mut y,
7902                            ws.o_block_cols,
7903                            ws.o_out,
7904                        )?;
7905                    }
7906                }
7907            }
7908        }
7909        Ok(())
7910    }
7911
7912    /// v2 phase 2: canonical-block O reduction on the root device plus the K/V shadow gathers,
7913    /// returning a fresh model-engine output ordered behind `ev_oproj` on `e`'s stream.
7914    ///
7915    /// The caller must have queued every rank's attention work (reading `ws.gated`, `ws.k`,
7916    /// `ws.v_raw`) on the rank streams before this call. Reduction order is identical to
7917    /// `step_bf16_row_parallel_resident_native`: zeros, then rank 0's blocks, then each peer
7918    /// rank's blocks, one `add` per block.
7919    pub(crate) fn decode_v2_finish(
7920        &self,
7921        ws: &mut StepTpDecodeV2Ws,
7922        e: &Engine,
7923        o_m: &ResidentStepBf16RowParallel,
7924    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
7925        let ranks = self.ranks.len();
7926        if e.ctx().ordinal() != ws.e_device {
7927            return Err("step TP decode v2 finish engine changed".into());
7928        }
7929        // MEMRA_STEP_TP_QKV_FUSED extends to the O path: one matvec_f32_b4 launch per rank
7930        // (in-order canonical block accumulation per element) and a single peer-copy + add on
7931        // the root, replacing 4 cuBLASLt launches per rank + the 4-copy/8-add chain. Same
7932        // numeric-class door and gate as the fused QKV projection.
7933        let o_fused = step_tp_qkv_fused_enabled()? && ws.blocks_per_rank == 4 && ranks == 2;
7934
7935        // Per-rank O block partials on the owning rank's stream (serial after the attention
7936        // kernels the driver queued there), then the rank-done event for root's peer reads.
7937        for rank in 0..ranks {
7938            self.decode_v2_finish_rank_partial(ws, o_m, o_fused, rank)?;
7939            if rank == 0 {
7940                // root == rank0: its own stream order covers the partial; only peers need
7941                // the record/wait pair (host-op diet, matches the routes-arm skip).
7942                continue;
7943            }
7944            let engine = &self.ranks[rank];
7945            let _main = engine.gpu.enter_main()?;
7946            ws.ev_rank[rank].record(&engine.stream())?;
7947        }
7948
7949        // Root reduce in canonical order + shadow gathers, all on the root stream.
7950        let root = &self.ranks[0];
7951        #[allow(unused_assignments)]
7952        let mut final_in_a = false;
7953        {
7954            let _main = root.gpu.enter_main()?;
7955            for ev in ws.ev_rank.iter().skip(1) {
7956                root.stream().wait(ev)?;
7957            }
7958            if o_fused && oproj_direct_on() && ranks == 2 && no_local_shadow_on() {
7959                // DIRECT JOIN: rank1's partial already sits in root memory (P2P kernel
7960                // stores; visibility guaranteed by the ev_rank[1] wait above), rank0's
7961                // partial is root-stream-ordered — record ONE event and let the model
7962                // engine do the single add itself, straight into its own output row.
7963                // Same operands, same add order as finish_root_fused: BIT-IDENTICAL.
7964                ws.ev_oproj.record(&root.stream())?;
7965                let _main = e.gpu.enter_main()?;
7966                e.stream().wait(&ws.ev_oproj)?;
7967                let mut output = e.uninit(ws.o_out)?;
7968                if oproj_tail_on() && oproj_tail_eligible() {
7969                    // M2: defer the add into the residual+norm consumer (waits stay HERE;
7970                    // only the arithmetic moves). `output` is returned unwritten.
7971                    use cudarc::driver::DevicePtr;
7972                    let stream = e.stream();
7973                    let (p0, _g0) = ws.o_partials[0][0].device_ptr(&stream);
7974                    let (p1, _g1) = ws.o_partials[1][0].device_ptr(&stream);
7975                    set_oproj_tail((p0, p1));
7976                    return Ok(output);
7977                }
7978                e.add(
7979                    &ws.o_partials[0][0],
7980                    &ws.o_partials[1][0],
7981                    &mut output,
7982                    ws.o_out,
7983                )?;
7984                return Ok(output);
7985            }
7986            if o_fused {
7987                self.decode_v2_finish_root_fused(ws)?;
7988                ws.ev_oproj.record(&root.stream())?;
7989                let _main = e.gpu.enter_main()?;
7990                e.stream().wait(&ws.ev_oproj)?;
7991                let mut output = e.uninit(ws.o_out)?;
7992                e.stream().memcpy_dtod(
7993                    &ws.reduce_a.slice(0..ws.o_out),
7994                    &mut output.slice_mut(0..ws.o_out),
7995                )?;
7996                return Ok(output);
7997            }
7998            let mut first = true;
7999            let mut current_is_a = false;
8000            for rank in 0..ranks {
8001                for block in 0..ws.blocks_per_rank {
8002                    let use_peer = rank != 0;
8003                    if use_peer {
8004                        raw_copy_bytes(
8005                            ws.raw_peer_partial,
8006                            ws.raw_o_partials[rank][block],
8007                            ws.o_out * std::mem::size_of::<f32>(),
8008                            root,
8009                        )?;
8010                    }
8011                    // add(prev, partial) -> the other reduce buffer, exactly one add per block
8012                    match (first, current_is_a, use_peer) {
8013                        (true, _, true) => {
8014                            root.add(&ws.zeros, &ws.peer_partial, &mut ws.reduce_a, ws.o_out)?
8015                        }
8016                        (true, _, false) => root.add(
8017                            &ws.zeros,
8018                            &ws.o_partials[0][block],
8019                            &mut ws.reduce_a,
8020                            ws.o_out,
8021                        )?,
8022                        (false, true, true) => {
8023                            root.add(&ws.reduce_a, &ws.peer_partial, &mut ws.reduce_b, ws.o_out)?
8024                        }
8025                        (false, true, false) => root.add(
8026                            &ws.reduce_a,
8027                            &ws.o_partials[0][block],
8028                            &mut ws.reduce_b,
8029                            ws.o_out,
8030                        )?,
8031                        (false, false, true) => {
8032                            root.add(&ws.reduce_b, &ws.peer_partial, &mut ws.reduce_a, ws.o_out)?
8033                        }
8034                        (false, false, false) => root.add(
8035                            &ws.reduce_b,
8036                            &ws.o_partials[0][block],
8037                            &mut ws.reduce_a,
8038                            ws.o_out,
8039                        )?,
8040                    }
8041                    current_is_a = first || !current_is_a;
8042                    first = false;
8043                }
8044            }
8045            final_in_a = current_is_a;
8046
8047            if !no_local_shadow_on() {
8048                let bytes = ws.local_kv_dim * std::mem::size_of::<f32>();
8049                for rank in 0..ranks {
8050                    let offset = rank * bytes;
8051                    raw_copy_bytes(ws.raw_k_shadow + offset as u64, ws.raw_k[rank], bytes, root)?;
8052                    raw_copy_bytes(
8053                        ws.raw_v_shadow + offset as u64,
8054                        ws.raw_v_raw[rank],
8055                        bytes,
8056                        root,
8057                    )?;
8058                }
8059            }
8060            ws.ev_oproj.record(&root.stream())?;
8061        }
8062
8063        // Model-engine output: e waits the root event, then copies the reduced row into a
8064        // fresh e-context buffer (same ownership contract as v1's `e.htod`). The same wait
8065        // orders the driver's shadow append (it reads ws.k_shadow/ws.v_shadow on e's stream).
8066        let _main = e.gpu.enter_main()?;
8067        e.stream().wait(&ws.ev_oproj)?;
8068        let mut output = e.uninit(ws.o_out)?;
8069        let source = if final_in_a {
8070            &ws.reduce_a
8071        } else {
8072            &ws.reduce_b
8073        };
8074        e.stream().memcpy_dtod(
8075            &source.slice(0..ws.o_out),
8076            &mut output.slice_mut(0..ws.o_out),
8077        )?;
8078        Ok(output)
8079    }
8080
8081    #[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
8082    pub fn run_routed_experts(
8083        &self,
8084        experts: &ResidentExpertParallel,
8085        input: &[f32],
8086        tokens: usize,
8087        selected: &[usize],
8088        route_weights: &[f32],
8089        experts_per_token: usize,
8090        activation_limit: Option<f32>,
8091    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
8092        validate_step_expert_activation_limit(activation_limit)?;
8093        validate_ep_residency(&self.ranks, experts)?;
8094        validate_activations(input, tokens, experts.input_width)?;
8095        let pairs = tokens
8096            .checked_mul(experts_per_token)
8097            .ok_or("EP route count overflow")?;
8098        if selected.len() != pairs || route_weights.len() != pairs {
8099            return Err(format!(
8100                "EP routes selected={} weights={} != tokens {tokens} x experts/token \
8101                 {experts_per_token} ({pairs})",
8102                selected.len(),
8103                route_weights.len(),
8104            )
8105            .into());
8106        }
8107        if !route_weights.iter().all(|weight| weight.is_finite()) {
8108            return Err("EP route weights contain a non-finite value".into());
8109        }
8110        if self.native_p2p {
8111            return self.run_routed_experts_native(
8112                experts,
8113                input,
8114                tokens,
8115                selected,
8116                route_weights,
8117                experts_per_token,
8118                activation_limit,
8119            );
8120        }
8121
8122        let mut output = vec![0.0f32; tokens * experts.input_width];
8123        let per_rank = experts.expert_count / experts.ranks.len();
8124        for token in 0..tokens {
8125            let input_row = &input[token * experts.input_width..(token + 1) * experts.input_width];
8126            for slot in 0..experts_per_token {
8127                let pair = token * experts_per_token + slot;
8128                let expert = selected[pair];
8129                if expert >= experts.expert_count {
8130                    return Err(format!(
8131                        "EP selected expert {expert} outside 0..{}",
8132                        experts.expert_count
8133                    )
8134                    .into());
8135                }
8136                let owner = expert / per_rank;
8137                let local_expert = expert - experts.ranks[owner].gate.expert_range.start;
8138                let rank = &experts.ranks[owner];
8139                let engine = &self.ranks[owner];
8140                let gate =
8141                    run_resident_bank_expert(engine, &rank.gate, local_expert, input_row, 1)?;
8142                let up = run_resident_bank_expert(engine, &rank.up, local_expert, input_row, 1)?;
8143                let activated: Vec<f32> = gate
8144                    .iter()
8145                    .zip(&up)
8146                    .map(|(&gate, &up)| step_expert_activation_host(gate, up, activation_limit))
8147                    .collect();
8148                debug_assert_eq!(activated.len(), experts.expert_width);
8149                let down =
8150                    run_resident_bank_expert(engine, &rank.down, local_expert, &activated, 1)?;
8151                let weight = route_weights[pair];
8152                for (sum, value) in output
8153                    [token * experts.input_width..(token + 1) * experts.input_width]
8154                    .iter_mut()
8155                    .zip(down)
8156                {
8157                    *sum += weight * value;
8158                }
8159            }
8160        }
8161        Ok(output)
8162    }
8163
8164    #[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
8165    fn run_routed_experts_native(
8166        &self,
8167        experts: &ResidentExpertParallel,
8168        input: &[f32],
8169        tokens: usize,
8170        selected: &[usize],
8171        route_weights: &[f32],
8172        experts_per_token: usize,
8173        activation_limit: Option<f32>,
8174    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
8175        if !self.native_p2p || self.ranks.len() < 2 {
8176            return Err("native EP execution requires at least two P2P ranks".into());
8177        }
8178        if self.ep_device_arithmetic {
8179            return self.run_routed_experts_native_device(
8180                experts,
8181                input,
8182                tokens,
8183                selected,
8184                route_weights,
8185                experts_per_token,
8186                activation_limit,
8187            );
8188        }
8189        let mut output = vec![0.0f32; tokens * experts.input_width];
8190        let per_rank = experts.expert_count / experts.ranks.len();
8191        for token in 0..tokens {
8192            let input_row = &input[token * experts.input_width..(token + 1) * experts.input_width];
8193            let mut rank_inputs = (0..self.ranks.len())
8194                .map(|_| None)
8195                .collect::<Vec<Option<CudaSlice<f32>>>>();
8196            rank_inputs[0] = Some({
8197                let root = &self.ranks[0];
8198                let _main = root.gpu.enter_main()?;
8199                root.htod(input_row)?
8200            });
8201
8202            for slot in 0..experts_per_token {
8203                let pair = token * experts_per_token + slot;
8204                let expert = selected[pair];
8205                if expert >= experts.expert_count {
8206                    return Err(format!(
8207                        "EP selected expert {expert} outside 0..{}",
8208                        experts.expert_count
8209                    )
8210                    .into());
8211                }
8212                let owner = expert / per_rank;
8213                let local_expert = expert - experts.ranks[owner].gate.expert_range.start;
8214                if rank_inputs[owner].is_none() {
8215                    let peer_input = {
8216                        let root_input = rank_inputs[0]
8217                            .as_ref()
8218                            .ok_or("native EP lost its root input")?;
8219                        let engine = &self.ranks[owner];
8220                        let _main = engine.gpu.enter_main()?;
8221                        let mut peer_input = engine.uninit(experts.input_width)?;
8222                        engine.stream().memcpy_dtod(root_input, &mut peer_input)?;
8223                        peer_input
8224                    };
8225                    rank_inputs[owner] = Some(peer_input);
8226                }
8227
8228                let rank = &experts.ranks[owner];
8229                let engine = &self.ranks[owner];
8230                let owner_input = rank_inputs[owner]
8231                    .as_ref()
8232                    .ok_or("native EP owner input is absent after dispatch")?;
8233                let gate = run_resident_bank_expert_device(
8234                    engine,
8235                    &rank.gate,
8236                    local_expert,
8237                    owner_input,
8238                    1,
8239                )?;
8240                let up = run_resident_bank_expert_device(
8241                    engine,
8242                    &rank.up,
8243                    local_expert,
8244                    owner_input,
8245                    1,
8246                )?;
8247                let (gate, up) = {
8248                    let _main = engine.gpu.enter_main()?;
8249                    (engine.dtoh(&gate)?, engine.dtoh(&up)?)
8250                };
8251                let activated = gate
8252                    .iter()
8253                    .zip(&up)
8254                    .map(|(&gate, &up)| step_expert_activation_host(gate, up, activation_limit))
8255                    .collect::<Vec<_>>();
8256                debug_assert_eq!(activated.len(), experts.expert_width);
8257                let activated = {
8258                    let _main = engine.gpu.enter_main()?;
8259                    engine.htod(&activated)?
8260                };
8261                let down = run_resident_bank_expert_device(
8262                    engine,
8263                    &rank.down,
8264                    local_expert,
8265                    &activated,
8266                    1,
8267                )?;
8268                let down = if owner == 0 {
8269                    let _main = engine.gpu.enter_main()?;
8270                    engine.dtoh(&down)?
8271                } else {
8272                    let root = &self.ranks[0];
8273                    let _main = root.gpu.enter_main()?;
8274                    let mut root_down = root.uninit(experts.input_width)?;
8275                    root.stream().memcpy_dtod(&down, &mut root_down)?;
8276                    root.dtoh(&root_down)?
8277                };
8278                let weight = route_weights[pair];
8279                for (sum, value) in output
8280                    [token * experts.input_width..(token + 1) * experts.input_width]
8281                    .iter_mut()
8282                    .zip(down)
8283                {
8284                    *sum += weight * value;
8285                }
8286            }
8287        }
8288        Ok(output)
8289    }
8290
8291    #[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
8292    fn run_routed_experts_native_device(
8293        &self,
8294        experts: &ResidentExpertParallel,
8295        input: &[f32],
8296        tokens: usize,
8297        selected: &[usize],
8298        route_weights: &[f32],
8299        experts_per_token: usize,
8300        activation_limit: Option<f32>,
8301    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
8302        if !self.native_p2p || !self.ep_device_arithmetic || self.ranks.len() < 2 {
8303            return Err(
8304                "device-resident EP arithmetic requires at least two native P2P ranks".into(),
8305            );
8306        }
8307        let mut output = Vec::with_capacity(tokens * experts.input_width);
8308        let per_rank = experts.expert_count / experts.ranks.len();
8309        let root = &self.ranks[0];
8310        for token in 0..tokens {
8311            let input_row = &input[token * experts.input_width..(token + 1) * experts.input_width];
8312            let mut rank_inputs = (0..self.ranks.len())
8313                .map(|_| None)
8314                .collect::<Vec<Option<CudaSlice<f32>>>>();
8315            rank_inputs[0] = Some({
8316                let _main = root.gpu.enter_main()?;
8317                root.htod(input_row)?
8318            });
8319            let mut root_output = {
8320                let _main = root.gpu.enter_main()?;
8321                root.zeros(experts.input_width)?
8322            };
8323            let mut remote_down_keepalive = Vec::new();
8324
8325            for slot in 0..experts_per_token {
8326                let pair = token * experts_per_token + slot;
8327                let expert = selected[pair];
8328                if expert >= experts.expert_count {
8329                    return Err(format!(
8330                        "EP selected expert {expert} outside 0..{}",
8331                        experts.expert_count
8332                    )
8333                    .into());
8334                }
8335                let owner = expert / per_rank;
8336                let local_expert = expert - experts.ranks[owner].gate.expert_range.start;
8337                if rank_inputs[owner].is_none() {
8338                    let peer_input = {
8339                        let root_input = rank_inputs[0]
8340                            .as_ref()
8341                            .ok_or("native EP lost its root input")?;
8342                        let engine = &self.ranks[owner];
8343                        let _main = engine.gpu.enter_main()?;
8344                        let mut peer_input = engine.uninit(experts.input_width)?;
8345                        engine.stream().memcpy_dtod(root_input, &mut peer_input)?;
8346                        peer_input
8347                    };
8348                    rank_inputs[owner] = Some(peer_input);
8349                }
8350
8351                let rank = &experts.ranks[owner];
8352                let engine = &self.ranks[owner];
8353                let owner_input = rank_inputs[owner]
8354                    .as_ref()
8355                    .ok_or("native EP owner input is absent after dispatch")?;
8356                let gate = run_resident_bank_expert_device(
8357                    engine,
8358                    &rank.gate,
8359                    local_expert,
8360                    owner_input,
8361                    1,
8362                )?;
8363                let up = run_resident_bank_expert_device(
8364                    engine,
8365                    &rank.up,
8366                    local_expert,
8367                    owner_input,
8368                    1,
8369                )?;
8370                let activated = {
8371                    let _main = engine.gpu.enter_main()?;
8372                    let mut activated = engine.uninit(experts.expert_width)?;
8373                    if let Some(limit) = activation_limit {
8374                        engine.silu_clamped_mul_host_expf(
8375                            &gate,
8376                            &up,
8377                            limit,
8378                            &mut activated,
8379                            experts.expert_width,
8380                        )?;
8381                    } else {
8382                        engine.silu_mul_host_expf(
8383                            &gate,
8384                            &up,
8385                            &mut activated,
8386                            experts.expert_width,
8387                        )?;
8388                    }
8389                    activated
8390                };
8391                let down = run_resident_bank_expert_device(
8392                    engine,
8393                    &rank.down,
8394                    local_expert,
8395                    &activated,
8396                    1,
8397                )?;
8398                let root_down = if owner == 0 {
8399                    down
8400                } else {
8401                    let _main = root.gpu.enter_main()?;
8402                    let mut root_down = root.uninit(experts.input_width)?;
8403                    root.stream().memcpy_dtod(&down, &mut root_down)?;
8404                    // The peer copy runs on the root stream. Keep its remote source alive until
8405                    // the final root readback synchronizes that stream; otherwise async free can
8406                    // recycle the owner's allocation while cuMemcpyPeerAsync is still reading it.
8407                    remote_down_keepalive.push(down);
8408                    root_down
8409                };
8410                let _main = root.gpu.enter_main()?;
8411                let mut destination = root_output.slice_mut(0..experts.input_width);
8412                root.axpy_host_into(
8413                    &root_down.slice(0..root_down.len()),
8414                    route_weights[pair],
8415                    &mut destination,
8416                    experts.input_width,
8417                )?;
8418            }
8419
8420            let _main = root.gpu.enter_main()?;
8421            let root_output = root.dtoh(&root_output)?;
8422            drop(remote_down_keepalive);
8423            output.extend(root_output);
8424        }
8425        Ok(output)
8426    }
8427}
8428
8429#[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
8430fn validate_column_shape(matrix: E4m3BlockMatrix<'_>, tp: usize) -> Result<(), String> {
8431    if matrix.out_features % tp != 0 {
8432        return Err(format!(
8433            "column-parallel out_features {} is not divisible by TP={tp}",
8434            matrix.out_features
8435        ));
8436    }
8437    let local_out = matrix.out_features / tp;
8438    if !local_out.is_multiple_of(FP8_BLOCK) {
8439        return Err(format!(
8440            "column-parallel output shard {local_out} cuts through a {FP8_BLOCK}-row \
8441             E4M3 scale block"
8442        ));
8443    }
8444    Ok(())
8445}
8446
8447#[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
8448fn step_bf16_canonical_chunk_rows(out_features: usize, tp: usize) -> Result<usize, String> {
8449    if !matches!(tp, 1 | 2 | 4 | 8) {
8450        return Err(format!(
8451            "Step BF16 canonical projection requires TP1/TP2/TP4/TP8, got TP={tp}"
8452        ));
8453    }
8454    if out_features == 0 || !out_features.is_multiple_of(PRODUCT_MAX_CARDS) {
8455        return Err(format!(
8456            "Step BF16 output width {out_features} is not divisible by the TP8 product envelope"
8457        ));
8458    }
8459    let canonical_rows = out_features / PRODUCT_MAX_CARDS;
8460    let local_out = out_features / tp;
8461    if local_out % canonical_rows != 0 {
8462        return Err(format!(
8463            "Step BF16 TP={tp} output shard {local_out} is not divisible by canonical \
8464             {canonical_rows}-row chunks"
8465        ));
8466    }
8467    Ok(canonical_rows)
8468}
8469
8470#[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
8471fn step_bf16_canonical_chunk_cols(in_features: usize, tp: usize) -> Result<usize, String> {
8472    if !matches!(tp, 1 | 2 | 4 | 8) {
8473        return Err(format!(
8474            "Step BF16 canonical row projection requires TP1/TP2/TP4/TP8, got TP={tp}"
8475        ));
8476    }
8477    if in_features == 0 || !in_features.is_multiple_of(PRODUCT_MAX_CARDS) {
8478        return Err(format!(
8479            "Step BF16 input width {in_features} is not divisible by the TP8 product envelope"
8480        ));
8481    }
8482    let canonical_cols = in_features / PRODUCT_MAX_CARDS;
8483    let local_in = in_features / tp;
8484    if local_in % canonical_cols != 0 {
8485        return Err(format!(
8486            "Step BF16 TP={tp} input shard {local_in} is not divisible by canonical \
8487             {canonical_cols}-column chunks"
8488        ));
8489    }
8490    Ok(canonical_cols)
8491}
8492
8493#[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
8494fn validate_row_shape(matrix: E4m3BlockMatrix<'_>, tp: usize) -> Result<(), String> {
8495    if matrix.in_features % tp != 0 {
8496        return Err(format!(
8497            "row-parallel in_features {} is not divisible by TP={tp}",
8498            matrix.in_features
8499        ));
8500    }
8501    let local_in = matrix.in_features / tp;
8502    if !local_in.is_multiple_of(FP8_BLOCK) {
8503        return Err(format!(
8504            "row-parallel input shard {local_in} cuts through a {FP8_BLOCK}-column \
8505             E4M3 scale block"
8506        ));
8507    }
8508    Ok(())
8509}
8510
8511fn upload_rank(
8512    engine: &Engine,
8513    matrix: E4m3BlockMatrix<'_>,
8514) -> Result<ResidentE4m3Rank, Box<dyn std::error::Error>> {
8515    let _main = engine.gpu.enter_main()?;
8516    matrix.validate()?;
8517    Ok(ResidentE4m3Rank {
8518        codes: engine.htod_bytes(matrix.codes)?,
8519        scales: engine.htod(matrix.scales)?,
8520        out_features: matrix.out_features,
8521        in_features: matrix.in_features,
8522    })
8523}
8524
8525fn upload_bf16_rank(
8526    engine: &Engine,
8527    matrix: Bf16Matrix<'_>,
8528    f32_mirror: bool,
8529) -> Result<ResidentBf16Rank, Box<dyn std::error::Error>> {
8530    let _main = engine.gpu.enter_main()?;
8531    matrix.validate()?;
8532    let bytes = engine.htod_bytes(matrix.bytes)?;
8533    let weight = if f32_mirror {
8534        let values = matrix
8535            .out_features
8536            .checked_mul(matrix.in_features)
8537            .ok_or("resident BF16 mirror element count overflow")?;
8538        ResidentBf16Weight::F32(engine.bf16_to_f32(&bytes.slice(0..bytes.len()), values)?)
8539    } else {
8540        ResidentBf16Weight::Bf16(bytes)
8541    };
8542    // MEMRA_STEP_TP_W8: encode the q8_0 decode mirror once, here, while the bf16 bytes are
8543    // already resident. Rows whose in_features is not a multiple of 32 have no q8_0 form and
8544    // simply keep the bf16 program (the decode arm checks for the mirror, never assumes it).
8545    let q8 = if crate::step_tp_w8_on() && matrix.in_features.is_multiple_of(32) {
8546        if let ResidentBf16Weight::Bf16(bytes) = &weight {
8547            // Two steps, because the mmvq rp kernel does NOT read ggml-interleaved 34-byte
8548            // blocks: it reads a PLANAR mirror (all quants, then all half scales — the
8549            // q4_0/NVFP4 rp convention). The encoder writes the interleaved form and
8550            // `build_q8_rp4_raw` — the same kernel the GGUF loader uses — splits it into
8551            // planes. Skipping the split is what made the first W8 gate return zeros
8552            // (verify-prefill argmax=0, maxdiff=0.000e0).
8553            let row_bytes = Engine::q8_0_row_bytes(matrix.in_features);
8554            let mut interleaved = engine.alloc_u8_uninit(matrix.out_features * row_bytes)?;
8555            engine.encode_q8_0_from_bf16(
8556                bytes,
8557                &mut interleaved,
8558                matrix.in_features,
8559                matrix.out_features,
8560            )?;
8561            let mirror =
8562                engine.build_q8_rp4_raw(&interleaved, matrix.in_features, matrix.out_features)?;
8563            Some(mirror)
8564        } else {
8565            None
8566        }
8567    } else {
8568        None
8569    };
8570    Ok(ResidentBf16Rank {
8571        weight,
8572        out_features: matrix.out_features,
8573        in_features: matrix.in_features,
8574        q8,
8575    })
8576}
8577
8578fn upload_expert_bank_rank(
8579    engine: &Engine,
8580    bank: E4m3ExpertBank<'_>,
8581    expert_range: Range<usize>,
8582) -> Result<ResidentE4m3ExpertBankRank, Box<dyn std::error::Error>> {
8583    let _main = engine.gpu.enter_main()?;
8584    bank.validate()?;
8585    if expert_range.start >= expert_range.end || expert_range.end > bank.expert_count {
8586        return Err(format!(
8587            "invalid EP expert range {expert_range:?} for {} experts",
8588            bank.expert_count
8589        )
8590        .into());
8591    }
8592    let code_stride = bank.out_features * bank.in_features;
8593    let scale_stride = bank.out_features.div_ceil(FP8_BLOCK) * bank.in_features.div_ceil(FP8_BLOCK);
8594    Ok(ResidentE4m3ExpertBankRank {
8595        codes: engine.htod_bytes(
8596            &bank.codes[expert_range.start * code_stride..expert_range.end * code_stride],
8597        )?,
8598        scales: engine.htod(
8599            &bank.scales[expert_range.start * scale_stride..expert_range.end * scale_stride],
8600        )?,
8601        expert_range,
8602        out_features: bank.out_features,
8603        in_features: bank.in_features,
8604        code_stride,
8605        scale_stride,
8606        k_blocks: None,
8607    })
8608}
8609
8610#[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
8611fn validate_column_bank_shape(bank: E4m3ExpertBank<'_>, tp: usize) -> Result<(), String> {
8612    if bank.out_features % tp != 0 {
8613        return Err(format!(
8614            "TP expert output width {} is not divisible by TP={tp}",
8615            bank.out_features
8616        ));
8617    }
8618    let local_out = bank.out_features / tp;
8619    if !local_out.is_multiple_of(FP8_BLOCK) {
8620        return Err(format!(
8621            "TP expert output shard {local_out} cuts through a {FP8_BLOCK}-row E4M3 scale block"
8622        ));
8623    }
8624    Ok(())
8625}
8626
8627#[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
8628fn validate_row_bank_shape(bank: E4m3ExpertBank<'_>, tp: usize) -> Result<(), String> {
8629    if bank.in_features % tp != 0 {
8630        return Err(format!(
8631            "TP expert input width {} is not divisible by TP={tp}",
8632            bank.in_features
8633        ));
8634    }
8635    let local_in = bank.in_features / tp;
8636    if !local_in.is_multiple_of(FP8_BLOCK) {
8637        return Err(format!(
8638            "TP expert input shard {local_in} cuts through a {FP8_BLOCK}-column E4M3 scale block"
8639        ));
8640    }
8641    Ok(())
8642}
8643
8644fn upload_column_bank_rank(
8645    engine: &Engine,
8646    bank: E4m3ExpertBank<'_>,
8647    tp: usize,
8648    rank: usize,
8649) -> Result<ResidentE4m3ExpertBankRank, Box<dyn std::error::Error>> {
8650    let _main = engine.gpu.enter_main()?;
8651    let packed = pack_column_bank_rank(bank, tp, rank)?;
8652    Ok(ResidentE4m3ExpertBankRank {
8653        codes: engine.htod_bytes(&packed.codes)?,
8654        scales: engine.htod(&packed.scales)?,
8655        expert_range: packed.expert_range,
8656        out_features: packed.out_features,
8657        in_features: packed.in_features,
8658        code_stride: packed.code_stride,
8659        scale_stride: packed.scale_stride,
8660        k_blocks: packed.k_blocks,
8661    })
8662}
8663
8664fn pack_column_bank_rank(
8665    bank: E4m3ExpertBank<'_>,
8666    tp: usize,
8667    rank: usize,
8668) -> Result<PackedE4m3ExpertBankRank, String> {
8669    bank.validate()?;
8670    validate_column_bank_shape(bank, tp)?;
8671    if rank >= tp {
8672        return Err(format!("TP rank {rank} outside 0..{tp}"));
8673    }
8674    let local_out = bank.out_features / tp;
8675    let full_code_stride = bank.out_features * bank.in_features;
8676    let local_code_stride = local_out * bank.in_features;
8677    let scale_cols = bank.in_features.div_ceil(FP8_BLOCK);
8678    let full_scale_stride = bank.out_features.div_ceil(FP8_BLOCK) * scale_cols;
8679    let local_scale_rows = local_out / FP8_BLOCK;
8680    let local_scale_stride = local_scale_rows * scale_cols;
8681    let mut codes = Vec::with_capacity(bank.expert_count * local_code_stride);
8682    let mut scales = Vec::with_capacity(bank.expert_count * local_scale_stride);
8683    let row_start = rank * local_out;
8684    let scale_row_start = rank * local_scale_rows;
8685    for expert in 0..bank.expert_count {
8686        let code_start = expert * full_code_stride + row_start * bank.in_features;
8687        codes.extend_from_slice(&bank.codes[code_start..code_start + local_code_stride]);
8688        let scale_start = expert * full_scale_stride + scale_row_start * scale_cols;
8689        scales.extend_from_slice(&bank.scales[scale_start..scale_start + local_scale_stride]);
8690    }
8691    Ok(PackedE4m3ExpertBankRank {
8692        codes,
8693        scales,
8694        expert_range: 0..bank.expert_count,
8695        out_features: local_out,
8696        in_features: bank.in_features,
8697        code_stride: local_code_stride,
8698        scale_stride: local_scale_stride,
8699        k_blocks: None,
8700    })
8701}
8702
8703fn upload_row_bank_rank(
8704    engine: &Engine,
8705    bank: E4m3ExpertBank<'_>,
8706    tp: usize,
8707    rank: usize,
8708) -> Result<ResidentE4m3ExpertBankRank, Box<dyn std::error::Error>> {
8709    let _main = engine.gpu.enter_main()?;
8710    let packed = pack_row_bank_rank(bank, tp, rank)?;
8711    Ok(ResidentE4m3ExpertBankRank {
8712        codes: engine.htod_bytes(&packed.codes)?,
8713        scales: engine.htod(&packed.scales)?,
8714        expert_range: packed.expert_range,
8715        out_features: packed.out_features,
8716        in_features: packed.in_features,
8717        code_stride: packed.code_stride,
8718        scale_stride: packed.scale_stride,
8719        k_blocks: packed.k_blocks,
8720    })
8721}
8722
8723fn pack_row_bank_rank(
8724    bank: E4m3ExpertBank<'_>,
8725    tp: usize,
8726    rank: usize,
8727) -> Result<PackedE4m3ExpertBankRank, String> {
8728    bank.validate()?;
8729    validate_row_bank_shape(bank, tp)?;
8730    if rank >= tp {
8731        return Err(format!("TP rank {rank} outside 0..{tp}"));
8732    }
8733    let local_in = bank.in_features / tp;
8734    let full_code_stride = bank.out_features * bank.in_features;
8735    let local_code_stride = bank.out_features * local_in;
8736    let full_scale_cols = bank.in_features.div_ceil(FP8_BLOCK);
8737    let local_scale_cols = local_in / FP8_BLOCK;
8738    let scale_rows = bank.out_features.div_ceil(FP8_BLOCK);
8739    let full_scale_stride = scale_rows * full_scale_cols;
8740    let local_scale_stride = scale_rows * local_scale_cols;
8741    let global_block_start = rank * local_scale_cols;
8742    let mut codes = Vec::with_capacity(bank.expert_count * local_code_stride);
8743    let mut scales = Vec::with_capacity(bank.expert_count * local_scale_stride);
8744    for expert in 0..bank.expert_count {
8745        let expert_code_start = expert * full_code_stride;
8746        let expert_scale_start = expert * full_scale_stride;
8747        for local_block in 0..local_scale_cols {
8748            let global_block = global_block_start + local_block;
8749            let column_start = global_block * FP8_BLOCK;
8750            for row in 0..bank.out_features {
8751                let start = expert_code_start + row * bank.in_features + column_start;
8752                codes.extend_from_slice(&bank.codes[start..start + FP8_BLOCK]);
8753            }
8754            for row in 0..scale_rows {
8755                scales.push(bank.scales[expert_scale_start + row * full_scale_cols + global_block]);
8756            }
8757        }
8758    }
8759    Ok(PackedE4m3ExpertBankRank {
8760        codes,
8761        scales,
8762        expert_range: 0..bank.expert_count,
8763        out_features: bank.out_features,
8764        in_features: local_in,
8765        code_stride: local_code_stride,
8766        scale_stride: local_scale_stride,
8767        k_blocks: Some(local_scale_cols),
8768    })
8769}
8770
8771fn validate_resident_ranks(engines: &[Engine], ranks: &[ResidentE4m3Rank]) -> Result<(), String> {
8772    if engines.len() != ranks.len() {
8773        return Err(format!(
8774            "resident TP rank count {} != runtime rank count {}",
8775            ranks.len(),
8776            engines.len()
8777        ));
8778    }
8779    for (rank, (engine, matrix)) in engines.iter().zip(ranks).enumerate() {
8780        let device = engine.ctx().ordinal();
8781        if matrix.codes.ordinal() != device || matrix.scales.ordinal() != device {
8782            return Err(format!(
8783                "resident TP rank {rank} is not owned by runtime device {device}"
8784            ));
8785        }
8786    }
8787    Ok(())
8788}
8789
8790fn validate_tp_bank_residency(
8791    engines: &[Engine],
8792    experts: &ResidentTpExpertBank,
8793) -> Result<(), String> {
8794    if engines.len() != experts.gate.len()
8795        || engines.len() != experts.up.len()
8796        || engines.len() != experts.down.len()
8797    {
8798        return Err(format!(
8799            "resident TP expert-bank rank counts gate={} up={} down={} != runtime {}",
8800            experts.gate.len(),
8801            experts.up.len(),
8802            experts.down.len(),
8803            engines.len()
8804        ));
8805    }
8806    for (rank, engine) in engines.iter().enumerate() {
8807        let device = engine.ctx().ordinal();
8808        for (projection, bank) in [
8809            ("gate", &experts.gate[rank]),
8810            ("up", &experts.up[rank]),
8811            ("down", &experts.down[rank]),
8812        ] {
8813            if bank.codes.ordinal() != device || bank.scales.ordinal() != device {
8814                return Err(format!(
8815                    "resident TP rank {rank} {projection} bank is not owned by runtime device \
8816                     {device}"
8817                ));
8818            }
8819        }
8820    }
8821    Ok(())
8822}
8823
8824fn validate_ep_residency(
8825    engines: &[Engine],
8826    experts: &ResidentExpertParallel,
8827) -> Result<(), String> {
8828    if engines.len() != experts.ranks.len() {
8829        return Err(format!(
8830            "resident EP rank count {} != runtime rank count {}",
8831            experts.ranks.len(),
8832            engines.len()
8833        ));
8834    }
8835    for (rank, (engine, resident)) in engines.iter().zip(&experts.ranks).enumerate() {
8836        let device = engine.ctx().ordinal();
8837        for (projection, bank) in [
8838            ("gate", &resident.gate),
8839            ("up", &resident.up),
8840            ("down", &resident.down),
8841        ] {
8842            if bank.codes.ordinal() != device || bank.scales.ordinal() != device {
8843                return Err(format!(
8844                    "resident EP rank {rank} {projection} bank is not owned by runtime device \
8845                     {device}"
8846                ));
8847            }
8848        }
8849    }
8850    Ok(())
8851}
8852
8853fn run_rank(
8854    engine: &Engine,
8855    matrix: E4m3BlockMatrix<'_>,
8856    activations: &[f32],
8857    tokens: usize,
8858) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
8859    let _main = engine.gpu.enter_main()?;
8860    let codes = engine.htod_bytes(matrix.codes)?;
8861    let scales = engine.htod(matrix.scales)?;
8862    let activations = engine.htod(activations)?;
8863    let output = engine.qmatvec_mmq_fp8_blk(
8864        &codes,
8865        &scales,
8866        &activations,
8867        tokens,
8868        matrix.in_features,
8869        matrix.out_features,
8870    )?;
8871    engine.dtoh(&output)
8872}
8873
8874fn run_resident_rank(
8875    engine: &Engine,
8876    matrix: &ResidentE4m3Rank,
8877    activations: &[f32],
8878    tokens: usize,
8879) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
8880    let _main = engine.gpu.enter_main()?;
8881    let activations = engine.htod(activations)?;
8882    let output = engine.qmatvec_mmq_fp8_blk(
8883        &matrix.codes,
8884        &matrix.scales,
8885        &activations,
8886        tokens,
8887        matrix.in_features,
8888        matrix.out_features,
8889    )?;
8890    engine.dtoh(&output)
8891}
8892
8893fn run_resident_bf16_rank(
8894    engine: &Engine,
8895    matrix: &ResidentBf16Rank,
8896    activations: &[f32],
8897    tokens: usize,
8898    canonical_chunk_rows: Option<usize>,
8899) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
8900    let _main = engine.gpu.enter_main()?;
8901    let activations = engine.htod(activations)?;
8902    let output = run_resident_bf16_rank_device(
8903        engine,
8904        matrix,
8905        &activations,
8906        tokens,
8907        canonical_chunk_rows,
8908        false,
8909    )?;
8910    engine.dtoh(&output)
8911}
8912
8913fn run_resident_bf16_rank_device(
8914    engine: &Engine,
8915    matrix: &ResidentBf16Rank,
8916    activations: &CudaSlice<f32>,
8917    tokens: usize,
8918    canonical_chunk_rows: Option<usize>,
8919    strided_chunk_output: bool,
8920) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
8921    let _main = engine.gpu.enter_main()?;
8922    if activations.ordinal() != engine.ctx().ordinal() {
8923        return Err(format!(
8924            "resident BF16 activation device {} != rank device {}",
8925            activations.ordinal(),
8926            engine.ctx().ordinal()
8927        )
8928        .into());
8929    }
8930    if activations.len() != tokens * matrix.in_features {
8931        return Err(format!(
8932            "resident BF16 activation count {} != {tokens}x{}",
8933            activations.len(),
8934            matrix.in_features
8935        )
8936        .into());
8937    }
8938    match (&matrix.weight, canonical_chunk_rows) {
8939        (ResidentBf16Weight::Bf16(bytes), Some(rows)) => engine
8940            .linear_bf16_resident_canonical_rows(
8941                activations,
8942                bytes,
8943                tokens,
8944                matrix.in_features,
8945                matrix.out_features,
8946                rows,
8947            ),
8948        (ResidentBf16Weight::Bf16(bytes), None) => engine.linear_bf16_resident(
8949            activations,
8950            bytes,
8951            tokens,
8952            matrix.in_features,
8953            matrix.out_features,
8954        ),
8955        (ResidentBf16Weight::F32(values), Some(rows)) if strided_chunk_output => engine
8956            .linear_f32_resident_canonical_rows_strided(
8957                activations,
8958                values,
8959                tokens,
8960                matrix.in_features,
8961                matrix.out_features,
8962                rows,
8963            ),
8964        (ResidentBf16Weight::F32(values), Some(rows)) => engine.linear_f32_resident_canonical_rows(
8965            activations,
8966            values,
8967            tokens,
8968            matrix.in_features,
8969            matrix.out_features,
8970            rows,
8971        ),
8972        (ResidentBf16Weight::F32(values), None) => engine.linear(
8973            activations,
8974            values,
8975            tokens,
8976            matrix.in_features,
8977            matrix.out_features,
8978        ),
8979    }
8980}
8981
8982fn validate_resident_bf16_ranks(
8983    engines: &[Engine],
8984    ranks: &[ResidentBf16Rank],
8985) -> Result<(), String> {
8986    if engines.len() != ranks.len() {
8987        return Err(format!(
8988            "resident BF16 TP rank count {} != runtime rank count {}",
8989            ranks.len(),
8990            engines.len(),
8991        ));
8992    }
8993    for (rank, (engine, matrix)) in engines.iter().zip(ranks).enumerate() {
8994        let device = engine.ctx().ordinal();
8995        if matrix.weight.ordinal() != device {
8996            return Err(format!(
8997                "resident BF16 TP rank {rank} is not owned by runtime device {device}"
8998            ));
8999        }
9000    }
9001    Ok(())
9002}
9003
9004fn validate_step_bf16_row_residency(
9005    engines: &[Engine],
9006    matrix: &ResidentStepBf16RowParallel,
9007) -> Result<(), String> {
9008    if engines.len() != matrix.ranks.len() {
9009        return Err(format!(
9010            "resident Step BF16 row rank count {} != runtime rank count {}",
9011            matrix.ranks.len(),
9012            engines.len(),
9013        ));
9014    }
9015    let canonical_cols = step_bf16_canonical_chunk_cols(matrix.in_features, engines.len())?;
9016    if matrix.canonical_chunk_cols != canonical_cols {
9017        return Err(format!(
9018            "resident Step BF16 row canonical columns {} != registered {canonical_cols}",
9019            matrix.canonical_chunk_cols
9020        ));
9021    }
9022    let blocks_per_rank = PRODUCT_MAX_CARDS / engines.len();
9023    for (rank, (engine, blocks)) in engines.iter().zip(&matrix.ranks).enumerate() {
9024        if blocks.len() != blocks_per_rank {
9025            return Err(format!(
9026                "resident Step BF16 row rank {rank} has {} blocks, expected {blocks_per_rank}",
9027                blocks.len()
9028            ));
9029        }
9030        let device = engine.ctx().ordinal();
9031        for (block, resident) in blocks.iter().enumerate() {
9032            if resident.weight.ordinal() != device
9033                || resident.in_features != canonical_cols
9034                || resident.out_features != matrix.out_features
9035            {
9036                return Err(format!(
9037                    "resident Step BF16 row rank {rank} block {block} has inconsistent \
9038                     device or geometry"
9039                ));
9040            }
9041        }
9042    }
9043    Ok(())
9044}
9045
9046fn validate_replicated_device_rows(
9047    engines: &[Engine],
9048    rows: &ResidentReplicatedDeviceRows,
9049) -> Result<(), String> {
9050    let rank_lengths = rows
9051        .ranks
9052        .iter()
9053        .map(|rank_rows| rank_rows.len())
9054        .collect::<Vec<_>>();
9055    replicated_device_row_values(rows.tokens, rows.width, engines.len(), &rank_lengths)?;
9056    if rows
9057        .ranks
9058        .iter()
9059        .zip(engines)
9060        .any(|(rank_rows, engine)| rank_rows.ordinal() != engine.ctx().ordinal())
9061    {
9062        return Err("replicated device rows are owned by the wrong CUDA contexts".into());
9063    }
9064    Ok(())
9065}
9066
9067fn replicated_device_row_values(
9068    tokens: usize,
9069    width: usize,
9070    expected_ranks: usize,
9071    rank_lengths: &[usize],
9072) -> Result<usize, String> {
9073    let values = tokens
9074        .checked_mul(width)
9075        .ok_or("replicated device row size overflow")?;
9076    if tokens == 0
9077        || width == 0
9078        || expected_ranks == 0
9079        || rank_lengths.len() != expected_ranks
9080        || rank_lengths.iter().any(|&rank_len| rank_len != values)
9081    {
9082        return Err(format!(
9083            "replicated device rows have inconsistent geometry tokens={} width={} ranks={}/{}",
9084            tokens,
9085            width,
9086            rank_lengths.len(),
9087            expected_ranks
9088        ));
9089    }
9090    Ok(values)
9091}
9092
9093fn replicated_device_row_source_values(
9094    tokens: usize,
9095    width: usize,
9096    source_len: usize,
9097    source_device: usize,
9098    root_device: usize,
9099) -> Result<usize, String> {
9100    let values = tokens
9101        .checked_mul(width)
9102        .ok_or("replicated device row size overflow")?;
9103    if tokens == 0 || width == 0 || source_len != values || source_device != root_device {
9104        return Err(format!(
9105            "replicated device row source has inconsistent geometry/device \
9106             tokens={tokens} width={width} source={source_len}@{source_device} root={root_device}"
9107        ));
9108    }
9109    Ok(values)
9110}
9111
9112#[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
9113fn bf16_column_shard(
9114    matrix: Bf16Matrix<'_>,
9115    tp: usize,
9116    rank: usize,
9117) -> Result<Bf16Matrix<'_>, String> {
9118    matrix.validate()?;
9119    if tp == 0 || rank >= tp || matrix.out_features % tp != 0 {
9120        return Err(format!(
9121            "invalid BF16 column shard out={} TP={tp} rank={rank}",
9122            matrix.out_features
9123        ));
9124    }
9125    let local_out = matrix.out_features / tp;
9126    let row_bytes = matrix.in_features * 2;
9127    let start = rank * local_out * row_bytes;
9128    Ok(Bf16Matrix {
9129        bytes: &matrix.bytes[start..start + local_out * row_bytes],
9130        out_features: local_out,
9131        in_features: matrix.in_features,
9132    })
9133}
9134
9135#[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
9136fn bf16_row_shard(matrix: Bf16Matrix<'_>, tp: usize, rank: usize) -> Result<Vec<u8>, String> {
9137    matrix.validate()?;
9138    if tp == 0 || rank >= tp || matrix.in_features % tp != 0 {
9139        return Err(format!(
9140            "invalid BF16 row shard in={} TP={tp} rank={rank}",
9141            matrix.in_features
9142        ));
9143    }
9144    let local_in = matrix.in_features / tp;
9145    let mut bytes = Vec::with_capacity(matrix.out_features * local_in * 2);
9146    for row in 0..matrix.out_features {
9147        let start = (row * matrix.in_features + rank * local_in) * 2;
9148        bytes.extend_from_slice(&matrix.bytes[start..start + local_in * 2]);
9149    }
9150    Ok(bytes)
9151}
9152
9153fn bf16_row_block(
9154    matrix: Bf16Matrix<'_>,
9155    col_start: usize,
9156    block_cols: usize,
9157) -> Result<Vec<u8>, String> {
9158    matrix.validate()?;
9159    let col_end = col_start
9160        .checked_add(block_cols)
9161        .ok_or("BF16 row block column overflow")?;
9162    if block_cols == 0 || col_end > matrix.in_features {
9163        return Err(format!(
9164            "invalid BF16 row block columns {col_start}..{col_end} for input width {}",
9165            matrix.in_features
9166        ));
9167    }
9168    let mut bytes = Vec::with_capacity(matrix.out_features * block_cols * 2);
9169    for row in 0..matrix.out_features {
9170        let start = (row * matrix.in_features + col_start) * 2;
9171        bytes.extend_from_slice(&matrix.bytes[start..start + block_cols * 2]);
9172    }
9173    Ok(bytes)
9174}
9175
9176fn run_resident_bank_expert(
9177    engine: &Engine,
9178    bank: &ResidentE4m3ExpertBankRank,
9179    local_expert: usize,
9180    activations: &[f32],
9181    tokens: usize,
9182) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
9183    let _main = engine.gpu.enter_main()?;
9184    if bank.k_blocks.is_some() {
9185        return Err("block-major TP row bank requires canonical block execution".into());
9186    }
9187    let local_count = bank.expert_range.end - bank.expert_range.start;
9188    if local_expert >= local_count {
9189        return Err(format!(
9190            "local EP expert {local_expert} outside 0..{local_count} for range {:?}",
9191            bank.expert_range
9192        )
9193        .into());
9194    }
9195    validate_activations(activations, tokens, bank.in_features)?;
9196    let activations = engine.htod(activations)?;
9197    let weight = bank
9198        .codes
9199        .slice(local_expert * bank.code_stride..(local_expert + 1) * bank.code_stride);
9200    let scales = bank
9201        .scales
9202        .slice(local_expert * bank.scale_stride..(local_expert + 1) * bank.scale_stride);
9203    let input = activations.slice(0..activations.len());
9204    let output = engine.qmatvec_mmq_fp8_blk_view(
9205        &weight,
9206        &scales,
9207        &input,
9208        tokens,
9209        bank.in_features,
9210        bank.out_features,
9211    )?;
9212    engine.dtoh(&output)
9213}
9214
9215fn run_resident_bank_expert_block(
9216    engine: &Engine,
9217    bank: &ResidentE4m3ExpertBankRank,
9218    local_expert: usize,
9219    block: usize,
9220    activations: &[f32],
9221) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
9222    let _main = engine.gpu.enter_main()?;
9223    let local_count = bank.expert_range.end - bank.expert_range.start;
9224    if local_expert >= local_count {
9225        return Err(format!(
9226            "local TP expert {local_expert} outside 0..{local_count} for range {:?}",
9227            bank.expert_range
9228        )
9229        .into());
9230    }
9231    let blocks = bank
9232        .k_blocks
9233        .ok_or("TP row bank is not packed in native K-block order")?;
9234    if block >= blocks {
9235        return Err(format!("TP row block {block} outside 0..{blocks}").into());
9236    }
9237    validate_activations(activations, 1, FP8_BLOCK)?;
9238    let block_code_stride = bank.out_features * FP8_BLOCK;
9239    let block_scale_stride = bank.out_features.div_ceil(FP8_BLOCK);
9240    if bank.in_features != blocks * FP8_BLOCK
9241        || bank.code_stride != blocks * block_code_stride
9242        || bank.scale_stride != blocks * block_scale_stride
9243    {
9244        return Err("TP row bank block-major geometry is inconsistent".into());
9245    }
9246
9247    let expert_code_start = local_expert * bank.code_stride;
9248    let expert_scale_start = local_expert * bank.scale_stride;
9249    let weight = bank.codes.slice(
9250        expert_code_start + block * block_code_stride
9251            ..expert_code_start + (block + 1) * block_code_stride,
9252    );
9253    let scales = bank.scales.slice(
9254        expert_scale_start + block * block_scale_stride
9255            ..expert_scale_start + (block + 1) * block_scale_stride,
9256    );
9257    let activations = engine.htod(activations)?;
9258    let input = activations.slice(0..activations.len());
9259    let output = engine.qmatvec_mmq_fp8_blk_view(
9260        &weight,
9261        &scales,
9262        &input,
9263        1,
9264        FP8_BLOCK,
9265        bank.out_features,
9266    )?;
9267    engine.dtoh(&output)
9268}
9269
9270fn run_resident_bank_expert_device(
9271    engine: &Engine,
9272    bank: &ResidentE4m3ExpertBankRank,
9273    local_expert: usize,
9274    activations: &CudaSlice<f32>,
9275    tokens: usize,
9276) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
9277    let _main = engine.gpu.enter_main()?;
9278    if bank.k_blocks.is_some() {
9279        return Err("block-major TP row bank requires canonical block execution".into());
9280    }
9281    let local_count = bank.expert_range.end - bank.expert_range.start;
9282    if local_expert >= local_count {
9283        return Err(format!(
9284            "local TP expert {local_expert} outside 0..{local_count} for range {:?}",
9285            bank.expert_range
9286        )
9287        .into());
9288    }
9289    let expected = tokens
9290        .checked_mul(bank.in_features)
9291        .ok_or("native TP activation size overflow")?;
9292    if activations.len() != expected || activations.ordinal() != engine.ctx().ordinal() {
9293        return Err(format!(
9294            "native TP activation len/device {}/{} != expected {expected}/{}",
9295            activations.len(),
9296            activations.ordinal(),
9297            engine.ctx().ordinal()
9298        )
9299        .into());
9300    }
9301    let weight = bank
9302        .codes
9303        .slice(local_expert * bank.code_stride..(local_expert + 1) * bank.code_stride);
9304    let scales = bank
9305        .scales
9306        .slice(local_expert * bank.scale_stride..(local_expert + 1) * bank.scale_stride);
9307    let input = activations.slice(0..activations.len());
9308    engine.qmatvec_mmq_fp8_blk_view(
9309        &weight,
9310        &scales,
9311        &input,
9312        tokens,
9313        bank.in_features,
9314        bank.out_features,
9315    )
9316}
9317
9318fn run_resident_bank_expert_block_device(
9319    engine: &Engine,
9320    bank: &ResidentE4m3ExpertBankRank,
9321    local_expert: usize,
9322    block: usize,
9323    activations: &cudarc::driver::CudaView<'_, f32>,
9324) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
9325    let _main = engine.gpu.enter_main()?;
9326    let local_count = bank.expert_range.end - bank.expert_range.start;
9327    if local_expert >= local_count {
9328        return Err(format!(
9329            "local TP expert {local_expert} outside 0..{local_count} for range {:?}",
9330            bank.expert_range
9331        )
9332        .into());
9333    }
9334    let blocks = bank
9335        .k_blocks
9336        .ok_or("native TP row bank is not packed in checkpoint-block order")?;
9337    if block >= blocks {
9338        return Err(format!("native TP row block {block} outside 0..{blocks}").into());
9339    }
9340    let activation_device = activations.stream().context().ordinal();
9341    if activations.len() != FP8_BLOCK || activation_device != engine.ctx().ordinal() {
9342        return Err(format!(
9343            "native TP block activation len/device {}/{} != expected {FP8_BLOCK}/{}",
9344            activations.len(),
9345            activation_device,
9346            engine.ctx().ordinal()
9347        )
9348        .into());
9349    }
9350    let block_code_stride = bank.out_features * FP8_BLOCK;
9351    let block_scale_stride = bank.out_features.div_ceil(FP8_BLOCK);
9352    if bank.in_features != blocks * FP8_BLOCK
9353        || bank.code_stride != blocks * block_code_stride
9354        || bank.scale_stride != blocks * block_scale_stride
9355    {
9356        return Err("native TP row bank block-major geometry is inconsistent".into());
9357    }
9358    let expert_code_start = local_expert * bank.code_stride;
9359    let expert_scale_start = local_expert * bank.scale_stride;
9360    let weight = bank.codes.slice(
9361        expert_code_start + block * block_code_stride
9362            ..expert_code_start + (block + 1) * block_code_stride,
9363    );
9364    let scales = bank.scales.slice(
9365        expert_scale_start + block * block_scale_stride
9366            ..expert_scale_start + (block + 1) * block_scale_stride,
9367    );
9368    engine.qmatvec_mmq_fp8_blk_view(
9369        &weight,
9370        &scales,
9371        activations,
9372        1,
9373        FP8_BLOCK,
9374        bank.out_features,
9375    )
9376}
9377
9378/// Grant `accessor` the right to reach `owner`'s memory — BOTH halves of the grant, which is
9379/// the part every caller gets wrong exactly once:
9380///
9381///   1. `cuCtxEnablePeerAccess`, which covers legacy `cuMemAlloc` allocations, and
9382///   2. `cuMemPoolSetAccess` on `owner`'s DEFAULT MEMORY POOL, because
9383///      `cuCtxEnablePeerAccess` does NOT map STREAM-ORDERED POOL allocations and every
9384///      normal memra buffer is one (the same note `pp.rs:1543`/`pp.rs:1578` carries).
9385///
9386/// Extracted from [`configure_native_p2p`] (which now calls it per ordered pair) so a seam
9387/// holding two `&Engine` rather than a `&[Engine]` — the glm5 TP-2 runtime — reuses the exact
9388/// grant sequence instead of growing a second, drifting copy of it. Directed: call it once
9389/// per direction. Refuses by name when `cuDeviceCanAccessPeer` says the pair has no path,
9390/// which is the only honest answer: this card class is NOT uniformly peer-connected. Some
9391/// 8-GPU host classes present PEER ISLANDS OF TWO — every cross-island cell of a peer-transfer
9392/// matrix reads `N/A` — so a TP group placed across an island boundary has no peer path at all
9393/// and must either stay inside one island or go through host memory. The per-host island map is
9394/// fleet data and lives in the private deployment repo, never here; the engine's job is to
9395/// refuse by name rather than to know which host it is on.
9396pub(crate) fn grant_peer_access(
9397    accessor: &Engine,
9398    owner: &Engine,
9399    label: &str,
9400) -> Result<(), Box<dyn std::error::Error>> {
9401    let (a_dev, o_dev) = (accessor.ctx().ordinal(), owner.ctx().ordinal());
9402    let mut can_access = 0;
9403    unsafe {
9404        cudarc::driver::sys::cuDeviceCanAccessPeer(
9405            &mut can_access,
9406            accessor.ctx().cu_device(),
9407            owner.ctx().cu_device(),
9408        )
9409        .result()?;
9410    }
9411    if can_access == 0 {
9412        return Err(
9413            format!("{label} requires P2P, but dev{a_dev} cannot access dev{o_dev}").into(),
9414        );
9415    }
9416    accessor.ctx().bind_to_thread()?;
9417    let rc = unsafe { cudarc::driver::sys::cuCtxEnablePeerAccess(owner.ctx().cu_ctx(), 0) };
9418    use cudarc::driver::sys::cudaError_enum as E;
9419    if rc != E::CUDA_SUCCESS && rc != E::CUDA_ERROR_PEER_ACCESS_ALREADY_ENABLED {
9420        return Err(format!(
9421            "{label} cuCtxEnablePeerAccess(dev{a_dev} -> dev{o_dev}) failed: {rc:?}"
9422        )
9423        .into());
9424    }
9425    let device = cudarc::driver::result::device::get(o_dev as i32)?;
9426    let mut pool: cudarc::driver::sys::CUmemoryPool = std::ptr::null_mut();
9427    unsafe {
9428        cudarc::driver::sys::cuDeviceGetDefaultMemPool(&mut pool, device).result()?;
9429    }
9430    let desc = cudarc::driver::sys::CUmemAccessDesc {
9431        location: cudarc::driver::sys::CUmemLocation {
9432            type_: cudarc::driver::sys::CUmemLocationType::CU_MEM_LOCATION_TYPE_DEVICE,
9433            id: a_dev as i32,
9434        },
9435        flags: cudarc::driver::sys::CUmemAccess_flags::CU_MEM_ACCESS_FLAGS_PROT_READWRITE,
9436    };
9437    let rc = unsafe { cudarc::driver::sys::cuMemPoolSetAccess(pool, &desc, 1) };
9438    if rc != cudarc::driver::sys::cudaError_enum::CUDA_SUCCESS {
9439        return Err(format!(
9440            "{label} cuMemPoolSetAccess(dev{o_dev} pool -> dev{a_dev}) failed: {rc:?}"
9441        )
9442        .into());
9443    }
9444    Ok(())
9445}
9446
9447fn configure_native_p2p(
9448    ranks: &[Engine],
9449    devices: &[usize],
9450) -> Result<(), Box<dyn std::error::Error>> {
9451    if ranks.len() != devices.len() || ranks.len() < 2 {
9452        return Err("native TP P2P setup requires matching multi-rank devices".into());
9453    }
9454    for (rank, (&device, engine)) in devices.iter().zip(ranks).enumerate() {
9455        if engine.ctx().ordinal() != device {
9456            return Err(format!(
9457                "native TP rank {rank} context device {} != requested device {device}",
9458                engine.ctx().ordinal()
9459            )
9460            .into());
9461        }
9462    }
9463
9464    for src in 0..ranks.len() {
9465        for dst in 0..ranks.len() {
9466            if src == dst {
9467                continue;
9468            }
9469            grant_peer_access(&ranks[src], &ranks[dst], "native TP")?;
9470        }
9471    }
9472
9473    for src in 0..ranks.len() {
9474        for dst in 0..ranks.len() {
9475            if src == dst {
9476                continue;
9477            }
9478            for &words in NATIVE_P2P_PROBE_WORDS {
9479                let expected = (0..words)
9480                    .map(|index| {
9481                        (index as u32)
9482                            .wrapping_mul(0x9e37_79b9)
9483                            .wrapping_add(((src as u32) << 16) | dst as u32)
9484                    })
9485                    .collect::<Vec<_>>();
9486                let poison = expected.iter().map(|value| !value).collect::<Vec<_>>();
9487                let source = ranks[src].htod_u32_v(&expected)?;
9488                let mut destination = ranks[dst].htod_u32_v(&poison)?;
9489                ranks[dst].stream().memcpy_dtod(&source, &mut destination)?;
9490                let actual = ranks[dst].dtoh_u32(&destination)?;
9491                if actual != expected {
9492                    let mismatches = actual
9493                        .iter()
9494                        .zip(&expected)
9495                        .filter(|(actual, expected)| actual != expected)
9496                        .count();
9497                    return Err(format!(
9498                        "native TP peer probe dev{}->dev{} failed at {} bytes: \
9499                         {mismatches}/{} words differ",
9500                        devices[src],
9501                        devices[dst],
9502                        words * std::mem::size_of::<u32>(),
9503                        expected.len()
9504                    )
9505                    .into());
9506                }
9507            }
9508        }
9509    }
9510    ranks[0].ctx().bind_to_thread()?;
9511    eprintln!(
9512        "[tp] native peer byte-integrity probe PASS: devices={devices:?} \
9513         directions={} byte_ladder={:?} mismatches=0",
9514        ranks.len() * (ranks.len() - 1),
9515        NATIVE_P2P_PROBE_WORDS
9516            .iter()
9517            .map(|words| words * std::mem::size_of::<u32>())
9518            .collect::<Vec<_>>(),
9519    );
9520    Ok(())
9521}
9522
9523fn validate_activations(
9524    activations: &[f32],
9525    tokens: usize,
9526    in_features: usize,
9527) -> Result<(), String> {
9528    let expected = tokens
9529        .checked_mul(in_features)
9530        .ok_or_else(|| "activation size overflow".to_string())?;
9531    if activations.len() != expected {
9532        return Err(format!(
9533            "activation count {} != {tokens}x{in_features} ({expected})",
9534            activations.len()
9535        ));
9536    }
9537    if !activations.iter().all(|value| value.is_finite()) {
9538        return Err("activations contain a non-finite value".to_string());
9539    }
9540    Ok(())
9541}
9542
9543fn column_shard(
9544    matrix: E4m3BlockMatrix<'_>,
9545    tp: usize,
9546    rank: usize,
9547) -> Result<E4m3BlockMatrix<'_>, String> {
9548    let local_out = matrix.out_features / tp;
9549    let row_start = rank * local_out;
9550    let code_start = row_start * matrix.in_features;
9551    let code_end = code_start + local_out * matrix.in_features;
9552    let scale_cols = matrix.in_features.div_ceil(FP8_BLOCK);
9553    let local_scale_rows = local_out / FP8_BLOCK;
9554    let scale_start = rank * local_scale_rows * scale_cols;
9555    let scale_end = scale_start + local_scale_rows * scale_cols;
9556    Ok(E4m3BlockMatrix {
9557        codes: &matrix.codes[code_start..code_end],
9558        scales: &matrix.scales[scale_start..scale_end],
9559        out_features: local_out,
9560        in_features: matrix.in_features,
9561    })
9562}
9563
9564fn row_shard(
9565    matrix: E4m3BlockMatrix<'_>,
9566    tp: usize,
9567    rank: usize,
9568) -> Result<(Vec<u8>, Vec<f32>), String> {
9569    let local_in = matrix.in_features / tp;
9570    let col_start = rank * local_in;
9571    let mut codes = Vec::with_capacity(matrix.out_features * local_in);
9572    for row in 0..matrix.out_features {
9573        let start = row * matrix.in_features + col_start;
9574        codes.extend_from_slice(&matrix.codes[start..start + local_in]);
9575    }
9576
9577    let scale_rows = matrix.out_features.div_ceil(FP8_BLOCK);
9578    let scale_cols = matrix.in_features.div_ceil(FP8_BLOCK);
9579    let local_scale_cols = local_in / FP8_BLOCK;
9580    let scale_col_start = rank * local_scale_cols;
9581    let mut scales = Vec::with_capacity(scale_rows * local_scale_cols);
9582    for row in 0..scale_rows {
9583        let start = row * scale_cols + scale_col_start;
9584        scales.extend_from_slice(&matrix.scales[start..start + local_scale_cols]);
9585    }
9586    Ok((codes, scales))
9587}
9588
9589fn activation_shard(
9590    activations: &[f32],
9591    tokens: usize,
9592    in_features: usize,
9593    tp: usize,
9594    rank: usize,
9595) -> Vec<f32> {
9596    let local_in = in_features / tp;
9597    let col_start = rank * local_in;
9598    let mut shard = Vec::with_capacity(tokens * local_in);
9599    for token in 0..tokens {
9600        let start = token * in_features + col_start;
9601        shard.extend_from_slice(&activations[start..start + local_in]);
9602    }
9603    shard
9604}
9605
9606// ─── Step NVFP4 expert TP program (official Step-3.7-Flash-NVFP4 checkpoint class) ─────────────
9607//
9608// The routed experts of the NVFP4 checkpoint are modelopt-packed: e2m1 codes (2/byte), per-16
9609// UE4M3 sub-scales, and a per-EXPERT `weight_scale_2` f32 macro (~1e-5..1e-4, LOAD-BEARING).
9610// Rank compute repacks each shard host-side into memra block_nvfp4 rows (nibble reorder only —
9611// value-exact, see nvfp4_repack.rs) and runs the proven `qmatvec_nvfp4_fast` dp4a kernel; the
9612// activation q8_1 quantization uses per-32 blocks, and every shard cut here is 64-aligned, so a
9613// rank-local partial is bit-identical to the corresponding slice of the unsharded kernel.
9614//
9615// MACRO CANONICAL ORDER: the macro multiplies each assembled f32 output exactly ONCE — after the
9616// column gather (gate/up) and after the FULL row-parallel reduce (down), never per-partial.
9617// `(a + b) * m` and `a * m + b * m` differ in f32, so applying it per-rank would break the
9618// TP1-vs-TP2 bit gate. Every entry point below follows this order.
9619//
9620// TP2 shard legality is NVFP4-native: column parallelism splits whole output rows (scale rows
9621// ride along, nothing cuts), row parallelism splits input columns at 64-element superblock
9622// boundaries (16-element scale groups nest inside). The 128-block E4M3 constraint does not apply.
9623
9624/// One expert's modelopt NVFP4 projection: packed codes + per-16 UE4M3 scale bytes + macro.
9625#[derive(Clone, Copy)]
9626pub struct Nvfp4BlockMatrix<'a> {
9627    pub codes: &'a [u8],  // [out_features, in_features/2] packed e2m1, row-major
9628    pub scales: &'a [u8], // [out_features, in_features/16] UE4M3 bytes, row-major
9629    pub macro_scale: f32, // per-expert weight_scale_2 dequant multiplier
9630    pub out_features: usize,
9631    pub in_features: usize,
9632}
9633
9634impl Nvfp4BlockMatrix<'_> {
9635    pub fn validate(&self) -> Result<(), String> {
9636        if self.in_features == 0 || self.out_features == 0 {
9637            return Err("NVFP4 matrix has a zero dimension".to_string());
9638        }
9639        if !self.in_features.is_multiple_of(64) {
9640            return Err(format!(
9641                "NVFP4 in_features {} is not 64-aligned (memra block_nvfp4 superblock)",
9642                self.in_features
9643            ));
9644        }
9645        if self.codes.len() != self.out_features * self.in_features / 2 {
9646            return Err(format!(
9647                "NVFP4 code bytes {} != {}x{}/2",
9648                self.codes.len(),
9649                self.out_features,
9650                self.in_features
9651            ));
9652        }
9653        if self.scales.len() != self.out_features * self.in_features / 16 {
9654            return Err(format!(
9655                "NVFP4 scale bytes {} != {}x{}/16",
9656                self.scales.len(),
9657                self.out_features,
9658                self.in_features
9659            ));
9660        }
9661        if !self.macro_scale.is_finite() || self.macro_scale <= 0.0 {
9662            return Err(format!(
9663                "NVFP4 macro scale {} is not finite-positive",
9664                self.macro_scale
9665            ));
9666        }
9667        Ok(())
9668    }
9669}
9670
9671/// Stacked modelopt NVFP4 expert bank (host view over the checkpoint bytes).
9672#[derive(Clone, Copy)]
9673pub struct Nvfp4ExpertBank<'a> {
9674    pub codes: &'a [u8],   // [expert_count, out_features, in_features/2]
9675    pub scales: &'a [u8],  // [expert_count, out_features, in_features/16]
9676    pub macros: &'a [f32], // [expert_count] weight_scale_2
9677    pub expert_count: usize,
9678    pub out_features: usize,
9679    pub in_features: usize,
9680}
9681
9682impl Nvfp4ExpertBank<'_> {
9683    pub fn validate(&self) -> Result<(), String> {
9684        if self.expert_count == 0 {
9685            return Err("NVFP4 expert bank is empty".to_string());
9686        }
9687        if self.macros.len() != self.expert_count {
9688            return Err(format!(
9689                "NVFP4 bank macros {} != expert count {}",
9690                self.macros.len(),
9691                self.expert_count
9692            ));
9693        }
9694        self.expert(0).map(|_| ())
9695    }
9696
9697    pub fn expert(&self, expert: usize) -> Result<Nvfp4BlockMatrix<'_>, String> {
9698        if expert >= self.expert_count {
9699            return Err(format!("expert {expert} outside 0..{}", self.expert_count));
9700        }
9701        let code_stride = self.out_features * self.in_features / 2;
9702        let scale_stride = self.out_features * self.in_features / 16;
9703        if self.codes.len() != self.expert_count * code_stride
9704            || self.scales.len() != self.expert_count * scale_stride
9705        {
9706            return Err("NVFP4 bank byte extents do not match the declared geometry".to_string());
9707        }
9708        let matrix = Nvfp4BlockMatrix {
9709            codes: &self.codes[expert * code_stride..(expert + 1) * code_stride],
9710            scales: &self.scales[expert * scale_stride..(expert + 1) * scale_stride],
9711            macro_scale: self.macros[expert],
9712            out_features: self.out_features,
9713            in_features: self.in_features,
9714        };
9715        matrix.validate()?;
9716        Ok(matrix)
9717    }
9718}
9719
9720/// One rank's resident repacked NVFP4 shard: memra block_nvfp4 rows on device.
9721pub struct ResidentNvfp4Rank {
9722    blocks: crate::CudaSlice<u8>,
9723    macro_scale: f32,
9724    out_features: usize,
9725    in_features: usize,
9726    row_bytes: usize,
9727}
9728
9729pub struct ResidentNvfp4ColumnParallel {
9730    ranks: Vec<ResidentNvfp4Rank>,
9731    pub out_features: usize,
9732    pub in_features: usize,
9733}
9734
9735pub struct ResidentNvfp4RowParallel {
9736    ranks: Vec<ResidentNvfp4Rank>,
9737    pub out_features: usize,
9738    pub in_features: usize,
9739}
9740
9741pub struct ResidentTpNvfp4Expert {
9742    gate: ResidentNvfp4ColumnParallel,
9743    up: ResidentNvfp4ColumnParallel,
9744    down: ResidentNvfp4RowParallel,
9745    pub input_width: usize,
9746    pub expert_width: usize,
9747}
9748
9749/// One rank's resident NVFP4 expert bank shard: one repacked block buffer PER expert (per-expert
9750/// device allocations keep this increment off any new strided-kernel API; the strided twin is a
9751/// later perf rung, mirroring the FP8 bank's history).
9752pub struct ResidentNvfp4ColumnBankRank {
9753    /// Contiguous per-rank expert bank: `expert_count` repacked shards of `expert_bytes` each.
9754    /// Contiguity is what lets the device-routes program cover every selected expert with ONE
9755    /// launch (`qmatvec_nvfp4_dp4a_sel` indexes `sel[t] * expert_bytes`).
9756    bank: crate::CudaSlice<u8>,
9757    expert_bytes: usize,
9758    local_out: usize,
9759    in_features: usize,
9760    row_bytes: usize,
9761    /// TRUE when these bytes are the slot-major permutation (`nvfp4_matrix_v2_permute`) and the
9762    /// `_v2` readers must be used; FALSE when they are block_nvfp4 v1. Recorded at BUILD from
9763    /// `bank_slot_major_on()` and never re-derived: the layout travels with the pointer,
9764    /// so no reader can consult an env door that disagrees with the resident bytes. Feeding v1
9765    /// bytes to a `_v2` reader (or the reverse) is a garbage-output bug, and the 2026-08-29
9766    /// step37 incident was its neighbour — a piece of layout geometry a caller failed to supply.
9767    slot_major: bool,
9768}
9769
9770impl ResidentNvfp4ColumnBankRank {
9771    /// THE host-canonical reader for this bank, selected from the layout the bank RECORDS. One
9772    /// place maps layout -> reader for the column banks; every oracle goes through it, so a new
9773    /// producer cannot leave a reader behind (the failure mode that put v1 bytes under a `_v2`
9774    /// reader, called out in the `run_tensor_parallel_routes_nvfp4_prime_grouped` receipt).
9775    fn host_canonical_expert(
9776        &self,
9777        engine: &Engine,
9778        expert: usize,
9779        activations: &crate::CudaSlice<f32>,
9780    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
9781        let w = self.expert(expert);
9782        if self.slot_major {
9783            engine.qmatvec_nvfp4_fast_v2(
9784                &w,
9785                activations,
9786                1,
9787                self.in_features,
9788                self.local_out,
9789                self.row_bytes,
9790            )
9791        } else {
9792            engine.qmatvec_nvfp4_fast(
9793                &w,
9794                activations,
9795                1,
9796                self.in_features,
9797                self.local_out,
9798                self.row_bytes,
9799            )
9800        }
9801    }
9802
9803    fn expert(&self, index: usize) -> cudarc::driver::CudaView<'_, u8> {
9804        self.bank
9805            .slice(index * self.expert_bytes..(index + 1) * self.expert_bytes)
9806    }
9807}
9808
9809/// Canonical row-shard count for the NVFP4 down projection. The down reduction ALWAYS executes
9810/// as exactly this many input-column windows summed in shard order, at every world size: a
9811/// single full-width dot and a two-half-dots-plus-add differ in f32 parenthesization, so pinning
9812/// the shard grid (not the world size) is what makes the TP1-oracle-vs-TP2 bit gate meaningful.
9813/// This is the NVFP4 twin of the FP8 bank's canonical checkpoint-block reduction.
9814pub const NVFP4_CANONICAL_ROW_SHARDS: usize = 2;
9815
9816pub struct ResidentNvfp4RowBankRank {
9817    /// Contiguous per-shard expert bank (see `ResidentNvfp4ColumnBankRank::bank`).
9818    bank: crate::CudaSlice<u8>,
9819    expert_bytes: usize,
9820    device_rank: usize, // index into the runtime's rank engines this canonical shard lives on
9821    out_features: usize,
9822    local_in: usize,
9823    row_bytes: usize,
9824    /// Slot-major layout marker — see `ResidentNvfp4ColumnBankRank::slot_major`.
9825    slot_major: bool,
9826}
9827
9828impl ResidentNvfp4RowBankRank {
9829    /// THE host-canonical reader for this down shard — see
9830    /// `ResidentNvfp4ColumnBankRank::host_canonical_expert`.
9831    fn host_canonical_expert(
9832        &self,
9833        engine: &Engine,
9834        expert: usize,
9835        activations: &crate::CudaSlice<f32>,
9836    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
9837        let w = self.expert(expert);
9838        if self.slot_major {
9839            engine.qmatvec_nvfp4_fast_v2(
9840                &w,
9841                activations,
9842                1,
9843                self.local_in,
9844                self.out_features,
9845                self.row_bytes,
9846            )
9847        } else {
9848            engine.qmatvec_nvfp4_fast(
9849                &w,
9850                activations,
9851                1,
9852                self.local_in,
9853                self.out_features,
9854                self.row_bytes,
9855            )
9856        }
9857    }
9858
9859    fn expert(&self, index: usize) -> cudarc::driver::CudaView<'_, u8> {
9860        self.bank
9861            .slice(index * self.expert_bytes..(index + 1) * self.expert_bytes)
9862    }
9863}
9864
9865impl ResidentNvfp4TensorParallel {
9866    pub(crate) fn device_workspace_handle(
9867        &self,
9868    ) -> &std::sync::Mutex<Option<Nvfp4DeviceRoutesWorkspace>> {
9869        &self.device_workspace
9870    }
9871}
9872
9873pub struct ResidentNvfp4TensorParallel {
9874    gate: Vec<ResidentNvfp4ColumnBankRank>,
9875    up: Vec<ResidentNvfp4ColumnBankRank>,
9876    down: Vec<ResidentNvfp4RowBankRank>,
9877    macros_gate: Vec<f32>,
9878    macros_up: Vec<f32>,
9879    macros_down: Vec<f32>,
9880    /// Per-rank device copies of the gate/up macro-scales (E f32 each), indexed by the
9881    /// batched SwiGLU kernel via the selection array. Down macros stay host-side — they fold
9882    /// into the route-weight axpy scalar.
9883    macros_gate_dev: Vec<crate::CudaSlice<f32>>,
9884    macros_up_dev: Vec<crate::CudaSlice<f32>>,
9885    macros_down_dev: Vec<crate::CudaSlice<f32>>,
9886    pub expert_count: usize,
9887    pub input_width: usize,
9888    pub expert_width: usize,
9889    /// Lazily-built persistent decode workspace (device routes program). Interior mutability
9890    /// mirrors StepEpGroupedDecode: the forward holds the bank behind a shared reference.
9891    device_workspace: std::sync::Mutex<Option<Nvfp4DeviceRoutesWorkspace>>,
9892    /// Grouped-prime per-rank slot-major pointer tables (gate/up/down x n_expert), built once.
9893    /// The banks are resident and never move, so rebuilding + re-uploading 3*n_expert u64s per
9894    /// rank per LAYER was pure per-call host churn on the prime path.
9895    prime_tables: std::sync::Mutex<Vec<crate::CudaSlice<u64>>>,
9896}
9897
9898/// Persistent per-call device buffers for the NVFP4 device routes program: one gate/up output,
9899/// one down partial, and one shard accumulator per rank, plus root combine staging. Reused every
9900/// (token, layer) call so the decode loop performs zero output allocations.
9901/// A stitched multi-device parent graph for one layer's device-routed expert program, plus
9902/// the children it was built from (retained: AddChildGraphNode clones, but the probe retains
9903/// conservatively) and the persistent e-context input staging its copies read.
9904struct RoutesGraph {
9905    exec: cudarc::driver::sys::CUgraphExec,
9906    parent: cudarc::driver::sys::CUgraph,
9907    _children: Vec<cudarc::driver::CudaGraph>,
9908}
9909// SAFETY: the raw handles are only used from the single decode thread; CUDA graph handles are
9910// context-agnostic process handles.
9911unsafe impl Send for RoutesGraph {}
9912
9913impl Drop for RoutesGraph {
9914    fn drop(&mut self) {
9915        unsafe {
9916            let _ = cudarc::driver::sys::cuGraphExecDestroy(self.exec);
9917            let _ = cudarc::driver::sys::cuGraphDestroy(self.parent);
9918        }
9919    }
9920}
9921
9922impl Nvfp4DeviceRoutesWorkspace {
9923    pub(crate) fn in_stage_handle(&self) -> Option<&crate::CudaSlice<f32>> {
9924        self.in_stage_e.as_ref()
9925    }
9926    pub(crate) fn in_stage_mut(&mut self) -> Option<&mut crate::CudaSlice<f32>> {
9927        self.in_stage_e.as_mut()
9928    }
9929    #[allow(dead_code)] // allow: accessor twin of in_stage_mut; kept for the workspace API symmetry
9930    pub(crate) fn out_stage_mut(&mut self) -> Option<&mut crate::CudaSlice<f32>> {
9931        self.out_stage_e.as_mut()
9932    }
9933    /// Arm the e-context stages + router staging pair when absent (token-graph entry).
9934    pub(crate) fn arm_stages(
9935        &mut self,
9936        e: &Engine,
9937        width: usize,
9938        n_sel: usize,
9939    ) -> Result<(), Box<dyn std::error::Error>> {
9940        let _main = e.gpu.enter_main()?;
9941        if self.in_stage_e.is_none() {
9942            self.in_stage_e = Some(e.htod(&vec![0.0f32; width])?);
9943            self.out_stage_e = Some(e.htod(&vec![0.0f32; width])?);
9944        }
9945        if self.dev_route_e.is_none() {
9946            self.dev_route_e = Some((
9947                e.htod_i32(&vec![0i32; n_sel])?,
9948                e.htod(&vec![0.0f32; n_sel])?,
9949            ));
9950        }
9951        Ok(())
9952    }
9953
9954    /// Split-borrow: the routes input (shared) + output (mut) stages together.
9955    pub(crate) fn in_and_out_stages_mut(
9956        &mut self,
9957    ) -> Option<(&crate::CudaSlice<f32>, &mut crate::CudaSlice<f32>)> {
9958        match (self.in_stage_e.as_ref(), self.out_stage_e.as_mut()) {
9959            (Some(input), Some(output)) => Some((input, output)),
9960            _ => None,
9961        }
9962    }
9963    pub(crate) fn dev_route_e_mut(
9964        &mut self,
9965    ) -> Option<(&mut crate::CudaSlice<i32>, &mut crate::CudaSlice<f32>)> {
9966        self.dev_route_e.as_mut().map(|(a, b)| (a, b))
9967    }
9968}
9969
9970pub struct Nvfp4DeviceRoutesWorkspace {
9971    /// [n_sel, local_out] batched gate/up outputs and the SwiGLU q8_1 pair; [n_sel, width]
9972    /// down partials. Sized for `n_sel` selected experts per token (pinned at first call).
9973    gate_out: Vec<crate::CudaSlice<f32>>,
9974    up_out: Vec<crate::CudaSlice<f32>>,
9975    act_q: Vec<crate::CudaSlice<i8>>,
9976    act_d: Vec<crate::CudaSlice<f32>>,
9977    sel: Vec<crate::CudaSlice<i32>>,
9978    partial: Vec<crate::CudaSlice<f32>>,
9979    accumulator: Vec<crate::CudaSlice<f32>>,
9980    /// Per-rank folded combine weights (route_weight x down macro), one htod per call.
9981    combine_w: Vec<crate::CudaSlice<f32>>,
9982    /// Device-routed extension: per-rank raw route weights (the down-macro fold happens
9983    /// in-kernel via sel + macros_down_dev).
9984    route_w: Vec<crate::CudaSlice<f32>>,
9985    /// Persistent q8_1 pair of the shared layer input (one quantize per rank per call, no
9986    /// per-call allocation).
9987    in_q: Vec<crate::CudaSlice<i8>>,
9988    in_d: Vec<crate::CudaSlice<f32>>,
9989    /// e-context staging for the device router outputs (persistent — rank streams peer-read
9990    /// them, so the router's fresh outputs are copied here on e's stream first; the pp.rs
9991    /// never-free discipline).
9992    dev_route_e: Option<(crate::CudaSlice<i32>, crate::CudaSlice<f32>)>,
9993    /// Prestage door state: input pull + quantize already issued for this layer's call
9994    /// (nvfp4_routes_prestage), so the routed run skips them. Reset per call.
9995    prestaged: bool,
9996    /// Peer-router door state: rank1's sel/route_w were computed locally in prestage;
9997    /// the routed run skips rank1's sel pull. Reset per call.
9998    rank1_routed: bool,
9999    /// Doorbell fences (MEMRA_FENCE_MEMOPS): raw cuMemAlloc'd [rank1_flag, root_flag]
10000    /// u32 pair in ROOT memory (async-pool memory is memop-INELIGIBLE — receipted
10001    /// CUDA_ERROR_INVALID_VALUE) + the host-side monotonic ticket. 0 = unarmed.
10002    fence_flags_raw: u64,
10003    fence_ticket: u32,
10004    /// Prestage input fence, recorded on e after the input's producer.
10005    ev_input: Option<(CudaEvent, usize)>,
10006    /// Graph-door staging: persistent e-context input row + output row (fixed addresses the
10007    /// captured copies read/write), and the per-layer stitched parent.
10008    in_stage_e: Option<crate::CudaSlice<f32>>,
10009    out_stage_e: Option<crate::CudaSlice<f32>>,
10010    routes_graph: Option<RoutesGraph>,
10011    /// Token-graph raw pointer sets (armed once by routes_arm_raw).
10012    raw_dev_route_e: Option<(u64, u64)>,
10013    raw_combine: Option<(u64, u64, u64, u64)>,
10014    raw_input: Vec<u64>,
10015    raw_sel: Vec<u64>,
10016    raw_route_w: Vec<u64>,
10017    remote: crate::CudaSlice<f32>,
10018    combined: crate::CudaSlice<f32>,
10019    n_sel: usize,
10020    /// Device-IO extension (lazily built by `run_tensor_parallel_routes_nvfp4_device_io`):
10021    /// persistent per-rank input rows plus the evented ordering pair — the pp.rs
10022    /// BoundarySlot discipline, same as the v2 attention workspace.
10023    input: Vec<crate::CudaSlice<f32>>,
10024    ev_rank: Vec<CudaEvent>,
10025    ev_done: Option<CudaEvent>,
10026    ev_entry: Option<(CudaEvent, usize)>,
10027}
10028
10029/// One rank's whole-expert NVFP4 residency (expert-parallel ownership).
10030struct ResidentNvfp4EpRank {
10031    gate: crate::CudaSlice<u8>,
10032    up: crate::CudaSlice<u8>,
10033    down: crate::CudaSlice<u8>,
10034    gate_expert_bytes: usize,
10035    down_expert_bytes: usize,
10036    macros_gate: crate::CudaSlice<f32>,
10037    macros_up: crate::CudaSlice<f32>,
10038    macros_down: crate::CudaSlice<f32>,
10039    expert_range: Range<usize>,
10040}
10041
10042struct Nvfp4EpDeviceWorkspace {
10043    input: Vec<crate::CudaSlice<f32>>,
10044    input_bf16: Vec<crate::CudaSlice<u8>>,
10045    input_q8: Vec<crate::CudaSlice<i8>>,
10046    input_q8_scales: Vec<crate::CudaSlice<f32>>,
10047    sel: Vec<crate::CudaSlice<i32>>,
10048    token_rows: Vec<crate::CudaSlice<i32>>,
10049    global_pairs: Vec<crate::CudaSlice<i32>>,
10050    route_w: Vec<crate::CudaSlice<f32>>,
10051    gate_out: Vec<crate::CudaSlice<f32>>,
10052    up_out: Vec<crate::CudaSlice<f32>>,
10053    activation_bf16: Vec<crate::CudaSlice<u8>>,
10054    activation_q8: Vec<crate::CudaSlice<i8>>,
10055    activation_q8_scales: Vec<crate::CudaSlice<f32>>,
10056    slot_rows: crate::CudaSlice<f32>,
10057    slot_rows_raw: u64,
10058    route_weights: crate::CudaSlice<f32>,
10059    ev_entry: CudaEvent,
10060    ev_entry_device: usize,
10061    ev_rank: Vec<CudaEvent>,
10062    phase_events: Option<Nvfp4EpPhaseEvents>,
10063    capacity_tokens: usize,
10064    experts_per_token: usize,
10065}
10066
10067struct Nvfp4EpPhaseEvents {
10068    head: Vec<CudaEvent>,
10069    copy_done: Vec<CudaEvent>,
10070    gate_up_done: Vec<CudaEvent>,
10071    activation_done: Vec<CudaEvent>,
10072    down_done: Vec<CudaEvent>,
10073}
10074
10075pub(crate) const NVFP4_EP_DEVICE_BATCH_CAP: usize = 128;
10076pub(crate) const NVFP4_EP_DEVICE_ROUTER_BATCH_CAP: usize = 32;
10077pub(crate) const NVFP4_EP_Q8_BATCH_CAP: usize = 32;
10078
10079fn nvfp4_ep_active_input_values(
10080    input_values: usize,
10081    tokens: usize,
10082    input_width: usize,
10083) -> Result<usize, String> {
10084    if !(1..=NVFP4_EP_DEVICE_BATCH_CAP).contains(&tokens) {
10085        return Err(format!(
10086            "W4A16 NVFP4 device EP batch {tokens} is outside 1..={NVFP4_EP_DEVICE_BATCH_CAP}"
10087        ));
10088    }
10089    let active_values = tokens
10090        .checked_mul(input_width)
10091        .ok_or("W4A16 NVFP4 device EP active input size overflows usize")?;
10092    if input_values < active_values {
10093        return Err(format!(
10094            "W4A16 NVFP4 device EP input {input_values} is smaller than active \
10095             tokens {tokens} x width {input_width} ({active_values})"
10096        ));
10097    }
10098    Ok(active_values)
10099}
10100
10101pub struct ResidentNvfp4ExpertParallel {
10102    ranks: Vec<ResidentNvfp4EpRank>,
10103    macros_gate: Vec<f32>,
10104    macros_up: Vec<f32>,
10105    macros_down: Vec<f32>,
10106    pub expert_count: usize,
10107    pub input_width: usize,
10108    pub expert_width: usize,
10109    gate_row_bytes: usize,
10110    down_row_bytes: usize,
10111    device_workspace: std::sync::Mutex<Option<Nvfp4EpDeviceWorkspace>>,
10112}
10113
10114fn nvfp4_repack_matrix(matrix: Nvfp4BlockMatrix<'_>) -> Vec<u8> {
10115    memra_gguf::nvfp4_repack::repack_modelopt_to_gguf(
10116        matrix.codes,
10117        matrix.scales,
10118        matrix.out_features,
10119        matrix.in_features,
10120    )
10121}
10122
10123fn nvfp4_row_bytes(in_features: usize) -> usize {
10124    in_features / 64 * 36 // memra block_nvfp4: 64 elems -> 36 bytes (4 UE4M3 + 32 packed e2m1)
10125}
10126
10127/// MEMRA_NO_LOCAL_SHADOW=1: skip the per-layer local-KV shadow gathers and appends in the
10128/// eager v2 decode (lengths still advance) — the graph door proved contents-stale local KV
10129/// is decode-identical (12/12). The local contents feed spec/MTP scratch only.
10130/// MEMRA_FUSE_ROPE_APPEND=1: fuse qk norms + rope + dcw KV append + len inc into one
10131/// launch per rank per layer (bit-identical; identity-gated). dcw path only.
10132pub(crate) fn fuse_rope_append_on() -> bool {
10133    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
10134    *ON.get_or_init(|| std::env::var("MEMRA_FUSE_ROPE_APPEND").as_deref() == Ok("1"))
10135}
10136
10137pub(crate) fn no_local_shadow_on() -> bool {
10138    static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
10139    *ON.get_or_init(|| std::env::var("MEMRA_NO_LOCAL_SHADOW").as_deref() == Ok("1"))
10140}
10141
10142/// Permute one repacked block_nvfp4 matrix (out_features rows of `nvfp4_row_bytes(in_f)`)
10143/// into the slot-major row layout the EP2 kernels read: per row, slot g's 16 qs bytes at
10144/// g*16, then the two UE4M3 scale bytes per slot at nslots*16 + g*2. Row byte count
10145/// unchanged. This layout USED to be an env door (`MEMRA_NVFP4_BANK_V2`, removed 2026-08-29
10146/// after its ON arm changed generated text in serving, see
10147/// research/step37-bankv2-removal-20260829); it survives ONLY as the fixed layout of the
10148/// EP2 whole-expert banks, whose `*_ep` kernels read it unconditionally.
10149///
10150/// PUBLIC because it is the SINGLE SOURCE OF TRUTH for this byte map. Every reader — the
10151/// `*_ep` decode kernels, `kq_fetch<QT_NVFP4_V2>` in the grouped GEMM,
10152/// `dequant_nvfp4v2_f16_kernel` — is defined as "reads what this function writes", and the
10153/// `nvfp4-bank-oracle` bin is what proves it, on device, per kernel arm. Do not reimplement
10154/// the map anywhere: the two failures that appeared only on v2 readers were geometry-plumbing
10155/// bugs around a byte map that was itself correct in two separate places. The layout was
10156/// innocent; one live failure was the grouped-prefill sktail call site defaulting `in_f` to zero.
10157pub fn nvfp4_matrix_v2_permute(v1: &[u8], out_features: usize, in_features: usize) -> Vec<u8> {
10158    // The output row is n_slots*18 bytes; the stride every reader uses is
10159    // nvfp4_row_bytes(in_features) = (in_features/64)*36. Those are equal only when
10160    // in_features is a whole number of 64-element superblocks. At in_features % 64 == 32 the
10161    // permute would silently emit a LONGER row than the stride and every row after row 0
10162    // would be read at the wrong offset, so refuse instead of trusting the caller.
10163    assert_eq!(
10164        in_features % 64,
10165        0,
10166        "v2 permute needs whole 64-element superblocks, got in_features={in_features}"
10167    );
10168    let row_bytes = nvfp4_row_bytes(in_features);
10169    assert_eq!(v1.len(), out_features * row_bytes, "v2 permute geometry");
10170    let n_slots = in_features / 32;
10171    let mut out = Vec::with_capacity(v1.len());
10172    for row in 0..out_features {
10173        let r = &v1[row * row_bytes..(row + 1) * row_bytes];
10174        for g in 0..n_slots {
10175            let (sblk, h) = (g / 2, g % 2);
10176            let b = &r[sblk * 36..sblk * 36 + 36];
10177            out.extend_from_slice(&b[4 + 16 * h..4 + 16 * h + 16]);
10178        }
10179        for g in 0..n_slots {
10180            let (sblk, h) = (g / 2, g % 2);
10181            let b = &r[sblk * 36..sblk * 36 + 36];
10182            out.push(b[2 * h]);
10183            out.push(b[2 * h + 1]);
10184        }
10185    }
10186    out
10187}
10188
10189/// Repack one expert shard for the contiguous banks. `slot_major` is true ONLY for the EP2
10190/// whole-expert banks, whose `*_ep` kernels read the slot-major permutation; the TP
10191/// column/row shard banks stay in the block_nvfp4 v1 layout every other kernel reads.
10192fn nvfp4_repack_bank_matrix(matrix: Nvfp4BlockMatrix<'_>, slot_major: bool) -> Vec<u8> {
10193    let (out_features, in_features) = (matrix.out_features, matrix.in_features);
10194    let v1 = nvfp4_repack_matrix(matrix);
10195    if slot_major {
10196        nvfp4_matrix_v2_permute(&v1, out_features, in_features)
10197    } else {
10198        v1
10199    }
10200}
10201
10202/// Column shard: whole output rows per rank (codes and scales are row-major, so both slices are
10203/// contiguous borrows). The macro rides unchanged — it is applied post-gather by the caller.
10204#[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
10205fn nvfp4_column_shard<'a>(
10206    matrix: Nvfp4BlockMatrix<'a>,
10207    tp: usize,
10208    rank: usize,
10209) -> Result<Nvfp4BlockMatrix<'a>, String> {
10210    if matrix.out_features % tp != 0 {
10211        return Err(format!(
10212            "NVFP4 column-parallel out_features {} is not divisible by TP={tp}",
10213            matrix.out_features
10214        ));
10215    }
10216    let local_out = matrix.out_features / tp;
10217    let code_row = matrix.in_features / 2;
10218    let scale_row = matrix.in_features / 16;
10219    Ok(Nvfp4BlockMatrix {
10220        codes: &matrix.codes[rank * local_out * code_row..(rank + 1) * local_out * code_row],
10221        scales: &matrix.scales[rank * local_out * scale_row..(rank + 1) * local_out * scale_row],
10222        macro_scale: matrix.macro_scale,
10223        out_features: local_out,
10224        in_features: matrix.in_features,
10225    })
10226}
10227
10228/// Row shard: input-column windows per rank, 64-superblock aligned. Owned buffers: each output
10229/// row contributes one contiguous byte window, gathered across rows.
10230#[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
10231fn nvfp4_row_shard(
10232    matrix: Nvfp4BlockMatrix<'_>,
10233    tp: usize,
10234    rank: usize,
10235) -> Result<(Vec<u8>, Vec<u8>, usize), String> {
10236    if matrix.in_features % tp != 0 {
10237        return Err(format!(
10238            "NVFP4 row-parallel in_features {} is not divisible by TP={tp}",
10239            matrix.in_features
10240        ));
10241    }
10242    let local_in = matrix.in_features / tp;
10243    if !local_in.is_multiple_of(64) {
10244        return Err(format!(
10245            "NVFP4 row-parallel input shard {local_in} cuts through a 64-element superblock"
10246        ));
10247    }
10248    let code_row = matrix.in_features / 2;
10249    let scale_row = matrix.in_features / 16;
10250    let local_code = local_in / 2;
10251    let local_scale = local_in / 16;
10252    let mut codes = Vec::with_capacity(matrix.out_features * local_code);
10253    let mut scales = Vec::with_capacity(matrix.out_features * local_scale);
10254    for row in 0..matrix.out_features {
10255        let code_start = row * code_row + rank * local_code;
10256        codes.extend_from_slice(&matrix.codes[code_start..code_start + local_code]);
10257        let scale_start = row * scale_row + rank * local_scale;
10258        scales.extend_from_slice(&matrix.scales[scale_start..scale_start + local_scale]);
10259    }
10260    Ok((codes, scales, local_in))
10261}
10262
10263/// Rank compute leaf: repack modelopt -> block_nvfp4, upload, run the proven dp4a kernel. The
10264/// macro is NOT applied here — callers apply it once at the canonical post-gather/post-reduce
10265/// point (see the section header).
10266fn run_rank_nvfp4(
10267    engine: &Engine,
10268    matrix: Nvfp4BlockMatrix<'_>,
10269    activations: &[f32],
10270    tokens: usize,
10271) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10272    matrix.validate()?;
10273    validate_activations(activations, tokens, matrix.in_features)?;
10274    let _main = engine.gpu.enter_main()?;
10275    let blocks = engine.htod_bytes(&nvfp4_repack_matrix(matrix))?;
10276    let activations = engine.htod(activations)?;
10277    let output = engine.qmatvec_nvfp4_fast(
10278        &blocks.slice(0..blocks.len()),
10279        &activations,
10280        tokens,
10281        matrix.in_features,
10282        matrix.out_features,
10283        nvfp4_row_bytes(matrix.in_features),
10284    )?;
10285    engine.dtoh(&output)
10286}
10287
10288fn upload_rank_nvfp4(
10289    engine: &Engine,
10290    matrix: Nvfp4BlockMatrix<'_>,
10291) -> Result<ResidentNvfp4Rank, Box<dyn std::error::Error>> {
10292    matrix.validate()?;
10293    let _main = engine.gpu.enter_main()?;
10294    Ok(ResidentNvfp4Rank {
10295        blocks: engine.htod_bytes(&nvfp4_repack_matrix(matrix))?,
10296        macro_scale: matrix.macro_scale,
10297        out_features: matrix.out_features,
10298        in_features: matrix.in_features,
10299        row_bytes: nvfp4_row_bytes(matrix.in_features),
10300    })
10301}
10302
10303fn run_resident_rank_nvfp4(
10304    engine: &Engine,
10305    rank: &ResidentNvfp4Rank,
10306    activations: &[f32],
10307    tokens: usize,
10308) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10309    validate_activations(activations, tokens, rank.in_features)?;
10310    let _main = engine.gpu.enter_main()?;
10311    let activations = engine.htod(activations)?;
10312    let output = engine.qmatvec_nvfp4_fast(
10313        &rank.blocks.slice(0..rank.blocks.len()),
10314        &activations,
10315        tokens,
10316        rank.in_features,
10317        rank.out_features,
10318        rank.row_bytes,
10319    )?;
10320    engine.dtoh(&output)
10321}
10322
10323fn apply_macro(values: &mut [f32], macro_scale: f32) {
10324    for value in values.iter_mut() {
10325        *value *= macro_scale;
10326    }
10327}
10328
10329impl TpE4m3HostBounce {
10330    /// Unsharded NVFP4 projection on rank 0 (compatibility oracle). Macro applied post-kernel.
10331    pub fn full_nvfp4(
10332        &self,
10333        matrix: Nvfp4BlockMatrix<'_>,
10334        activations: &[f32],
10335        tokens: usize,
10336    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10337        let mut output = run_rank_nvfp4(&self.ranks[0], matrix, activations, tokens)?;
10338        apply_macro(&mut output, matrix.macro_scale);
10339        Ok(output)
10340    }
10341
10342    /// Column-parallel NVFP4 projection: output rows partition across ranks, host gather in rank
10343    /// order, macro applied ONCE post-gather.
10344    pub fn column_parallel_nvfp4(
10345        &self,
10346        matrix: Nvfp4BlockMatrix<'_>,
10347        activations: &[f32],
10348        tokens: usize,
10349    ) -> Result<ColumnParallelResult, Box<dyn std::error::Error>> {
10350        matrix.validate()?;
10351        validate_activations(activations, tokens, matrix.in_features)?;
10352        let tp = self.ranks.len();
10353        let local_out = matrix.out_features / tp;
10354        let mut gathered = vec![0.0f32; tokens * matrix.out_features];
10355        let mut rank_outputs = Vec::with_capacity(tp);
10356        for (rank_index, rank) in self.ranks.iter().enumerate() {
10357            let shard = nvfp4_column_shard(matrix, tp, rank_index)?;
10358            let output = run_rank_nvfp4(rank, shard, activations, tokens)?;
10359            let row_start = rank_index * local_out;
10360            for token in 0..tokens {
10361                gathered[token * matrix.out_features + row_start
10362                    ..token * matrix.out_features + row_start + local_out]
10363                    .copy_from_slice(&output[token * local_out..(token + 1) * local_out]);
10364            }
10365            rank_outputs.push(output);
10366        }
10367        apply_macro(&mut gathered, matrix.macro_scale);
10368        Ok(ColumnParallelResult {
10369            gathered,
10370            rank_outputs,
10371        })
10372    }
10373
10374    /// Row-parallel NVFP4 projection: input columns partition at 64-superblock boundaries,
10375    /// rank-local partials reduce in stable rank order, macro applied ONCE post-reduce.
10376    pub fn row_parallel_nvfp4(
10377        &self,
10378        matrix: Nvfp4BlockMatrix<'_>,
10379        activations: &[f32],
10380        tokens: usize,
10381    ) -> Result<RowParallelResult, Box<dyn std::error::Error>> {
10382        matrix.validate()?;
10383        validate_activations(activations, tokens, matrix.in_features)?;
10384        let tp = self.ranks.len();
10385        let mut reduced = vec![0.0f32; tokens * matrix.out_features];
10386        let mut rank_partials = Vec::with_capacity(tp);
10387        for (rank_index, rank) in self.ranks.iter().enumerate() {
10388            let (codes, scales, local_in) = nvfp4_row_shard(matrix, tp, rank_index)?;
10389            let local_activations =
10390                activation_shard(activations, tokens, matrix.in_features, tp, rank_index);
10391            let shard = Nvfp4BlockMatrix {
10392                codes: &codes,
10393                scales: &scales,
10394                macro_scale: matrix.macro_scale,
10395                out_features: matrix.out_features,
10396                in_features: local_in,
10397            };
10398            let partial = run_rank_nvfp4(rank, shard, &local_activations, tokens)?;
10399            for (sum, value) in reduced.iter_mut().zip(&partial) {
10400                *sum += *value;
10401            }
10402            rank_partials.push(partial);
10403        }
10404        apply_macro(&mut reduced, matrix.macro_scale);
10405        Ok(RowParallelResult {
10406            reduced,
10407            rank_partials,
10408        })
10409    }
10410
10411    pub fn upload_expert_nvfp4(
10412        &self,
10413        gate: Nvfp4BlockMatrix<'_>,
10414        up: Nvfp4BlockMatrix<'_>,
10415        down: Nvfp4BlockMatrix<'_>,
10416    ) -> Result<ResidentTpNvfp4Expert, Box<dyn std::error::Error>> {
10417        if gate.in_features != up.in_features || gate.out_features != up.out_features {
10418            return Err("NVFP4 TP expert gate/up dimensions differ".into());
10419        }
10420        if down.in_features != gate.out_features || down.out_features != gate.in_features {
10421            return Err(format!(
10422                "NVFP4 TP expert down {}x{} does not invert gate/up {}x{}",
10423                down.out_features, down.in_features, gate.out_features, gate.in_features
10424            )
10425            .into());
10426        }
10427        let tp = self.ranks.len();
10428        let mut gate_ranks = Vec::with_capacity(tp);
10429        let mut up_ranks = Vec::with_capacity(tp);
10430        let mut down_ranks = Vec::with_capacity(tp);
10431        for (rank_index, engine) in self.ranks.iter().enumerate() {
10432            gate_ranks.push(upload_rank_nvfp4(
10433                engine,
10434                nvfp4_column_shard(gate, tp, rank_index)?,
10435            )?);
10436            up_ranks.push(upload_rank_nvfp4(
10437                engine,
10438                nvfp4_column_shard(up, tp, rank_index)?,
10439            )?);
10440            let (codes, scales, local_in) = nvfp4_row_shard(down, tp, rank_index)?;
10441            down_ranks.push(upload_rank_nvfp4(
10442                engine,
10443                Nvfp4BlockMatrix {
10444                    codes: &codes,
10445                    scales: &scales,
10446                    macro_scale: down.macro_scale,
10447                    out_features: down.out_features,
10448                    in_features: local_in,
10449                },
10450            )?);
10451        }
10452        Ok(ResidentTpNvfp4Expert {
10453            gate: ResidentNvfp4ColumnParallel {
10454                ranks: gate_ranks,
10455                out_features: gate.out_features,
10456                in_features: gate.in_features,
10457            },
10458            up: ResidentNvfp4ColumnParallel {
10459                ranks: up_ranks,
10460                out_features: up.out_features,
10461                in_features: up.in_features,
10462            },
10463            down: ResidentNvfp4RowParallel {
10464                ranks: down_ranks,
10465                out_features: down.out_features,
10466                in_features: down.in_features,
10467            },
10468            input_width: gate.in_features,
10469            expert_width: gate.out_features,
10470        })
10471    }
10472
10473    fn column_parallel_resident_nvfp4(
10474        &self,
10475        matrix: &ResidentNvfp4ColumnParallel,
10476        activations: &[f32],
10477        tokens: usize,
10478    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10479        validate_activations(activations, tokens, matrix.in_features)?;
10480        let local_out = matrix.out_features / self.ranks.len();
10481        let mut gathered = vec![0.0f32; tokens * matrix.out_features];
10482        let mut macro_scale = None;
10483        for (rank_index, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
10484            let output = run_resident_rank_nvfp4(engine, shard, activations, tokens)?;
10485            let row_start = rank_index * local_out;
10486            for token in 0..tokens {
10487                gathered[token * matrix.out_features + row_start
10488                    ..token * matrix.out_features + row_start + local_out]
10489                    .copy_from_slice(&output[token * local_out..(token + 1) * local_out]);
10490            }
10491            macro_scale = Some(shard.macro_scale);
10492        }
10493        apply_macro(
10494            &mut gathered,
10495            macro_scale.ok_or("NVFP4 column-parallel matrix has no ranks")?,
10496        );
10497        Ok(gathered)
10498    }
10499
10500    fn row_parallel_resident_nvfp4(
10501        &self,
10502        matrix: &ResidentNvfp4RowParallel,
10503        activations: &[f32],
10504        tokens: usize,
10505    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10506        validate_activations(activations, tokens, matrix.in_features)?;
10507        let tp = self.ranks.len();
10508        let local_in = matrix.in_features / tp;
10509        let mut reduced = vec![0.0f32; tokens * matrix.out_features];
10510        let mut macro_scale = None;
10511        for (rank_index, (engine, shard)) in self.ranks.iter().zip(&matrix.ranks).enumerate() {
10512            if shard.in_features != local_in {
10513                return Err(format!(
10514                    "NVFP4 resident row shard in_features {} != expected {local_in}",
10515                    shard.in_features
10516                )
10517                .into());
10518            }
10519            let local_activations =
10520                activation_shard(activations, tokens, matrix.in_features, tp, rank_index);
10521            let partial = run_resident_rank_nvfp4(engine, shard, &local_activations, tokens)?;
10522            for (sum, value) in reduced.iter_mut().zip(&partial) {
10523                *sum += *value;
10524            }
10525            macro_scale = Some(shard.macro_scale);
10526        }
10527        apply_macro(
10528            &mut reduced,
10529            macro_scale.ok_or("NVFP4 row-parallel matrix has no ranks")?,
10530        );
10531        Ok(reduced)
10532    }
10533
10534    pub fn run_expert_nvfp4(
10535        &self,
10536        expert: &ResidentTpNvfp4Expert,
10537        input: &[f32],
10538        tokens: usize,
10539    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10540        validate_activations(input, tokens, expert.input_width)?;
10541        let gate = self.column_parallel_resident_nvfp4(&expert.gate, input, tokens)?;
10542        let up = self.column_parallel_resident_nvfp4(&expert.up, input, tokens)?;
10543        let activated: Vec<f32> = gate
10544            .iter()
10545            .zip(&up)
10546            .map(|(&gate, &up)| gate / (1.0 + (-gate).exp()) * up)
10547            .collect();
10548        debug_assert_eq!(activated.len(), tokens * expert.expert_width);
10549        self.row_parallel_resident_nvfp4(&expert.down, &activated, tokens)
10550    }
10551
10552    /// Upload every expert's TP shards resident (one repacked block buffer per expert per rank).
10553    #[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
10554    pub fn upload_tensor_parallel_nvfp4(
10555        &self,
10556        gate: Nvfp4ExpertBank<'_>,
10557        up: Nvfp4ExpertBank<'_>,
10558        down: Nvfp4ExpertBank<'_>,
10559    ) -> Result<ResidentNvfp4TensorParallel, Box<dyn std::error::Error>> {
10560        gate.validate()?;
10561        up.validate()?;
10562        down.validate()?;
10563        if gate.expert_count != up.expert_count || gate.expert_count != down.expert_count {
10564            return Err("NVFP4 TP gate/up/down expert counts differ".into());
10565        }
10566        if gate.in_features != up.in_features || gate.out_features != up.out_features {
10567            return Err("NVFP4 TP gate/up dimensions differ".into());
10568        }
10569        if down.in_features != gate.out_features || down.out_features != gate.in_features {
10570            return Err(format!(
10571                "NVFP4 TP down {}x{} does not invert gate/up {}x{}",
10572                down.out_features, down.in_features, gate.out_features, gate.in_features
10573            )
10574            .into());
10575        }
10576        let tp = self.ranks.len();
10577        if gate.out_features % tp != 0 {
10578            return Err(format!(
10579                "NVFP4 TP expert output width {} is not divisible by TP={tp}",
10580                gate.out_features
10581            )
10582            .into());
10583        }
10584        if !down.in_features.is_multiple_of(NVFP4_CANONICAL_ROW_SHARDS)
10585            || !(down.in_features / NVFP4_CANONICAL_ROW_SHARDS).is_multiple_of(64)
10586        {
10587            return Err(format!(
10588                "NVFP4 TP expert input width {} does not split into 64-aligned canonical \
10589                 shards ({NVFP4_CANONICAL_ROW_SHARDS})",
10590                down.in_features
10591            )
10592            .into());
10593        }
10594        if tp > NVFP4_CANONICAL_ROW_SHARDS {
10595            return Err(format!(
10596                "NVFP4 TP world {tp} exceeds the canonical row-shard grid \
10597                 ({NVFP4_CANONICAL_ROW_SHARDS})"
10598            )
10599            .into());
10600        }
10601
10602        // LAYOUT DECISION, MADE ONCE PER BANK BUILD. TP shard banks are slot-major under
10603        // PROGRAM 1's door. Every reader below takes this from the bank it is reading, never
10604        // from `bank_slot_major_on()` again.
10605        let slot_major = bank_slot_major_on();
10606        // ENGAGEMENT RECEIPT, not a debug line. A pricing cell that proves only that the env var
10607        // is SET measures nothing: if the door fails to reach the code, the cell reports "the
10608        // program is worth 0%" when the truth is "the program never ran". That exact defect is
10609        // banked -- the MEMRA_BF16_MMV lane's first sweep grepped for engagement, got 0 in BOTH
10610        // arms, and the missing line was mistaken for a no-engagement result until an announce
10611        // was added. So the layout decision announces itself, WITH ITS SOURCE, so a receipt can
10612        // distinguish "armed by the door" from "armed because EP2" from "not armed".
10613        eprintln!(
10614            "[nvfp4-bank] layout={} source={} tp={tp} experts={} in_f={} out_f={}",
10615            if slot_major {
10616                "slot-major"
10617            } else {
10618                "block-nvfp4-v1"
10619            },
10620            // The source string distinguishes "armed by the 2026-09-01 DEFAULT" from "armed by
10621            // an explicit recipe" from "rolled back by the seam" from "armed because EP2". A
10622            // default flip whose receipt cannot say which of those happened cannot prove the
10623            // DEFAULT was what got measured.
10624            bank_slot_major_source().1,
10625            gate.expert_count,
10626            gate.in_features,
10627            gate.out_features
10628        );
10629        let mut gate_ranks = Vec::with_capacity(tp);
10630        let mut up_ranks = Vec::with_capacity(tp);
10631        let mut macros_gate_dev = Vec::with_capacity(tp);
10632        let mut macros_up_dev = Vec::with_capacity(tp);
10633        let mut macros_down_dev = Vec::with_capacity(tp);
10634        for (rank_index, engine) in self.ranks.iter().enumerate() {
10635            let _main = engine.gpu.enter_main()?;
10636            // Contiguous per-rank banks: repack every expert shard into one host buffer, one
10637            // upload. Contiguity feeds the batched selected-experts launch; per-expert bytes
10638            // are unchanged (same repack).
10639            // EP2: this rank holds the FULL matrices of the experts it owns (id & 1 ==
10640            // rank_index), stacked at slot id >> 1 — same total bytes as the shard bank.
10641            let mut gate_host: Vec<u8> = Vec::new();
10642            let mut up_host: Vec<u8> = Vec::new();
10643            for expert in 0..gate.expert_count {
10644                let gate_shard = nvfp4_column_shard(gate.expert(expert)?, tp, rank_index)?;
10645                gate_host.extend_from_slice(&nvfp4_repack_bank_matrix(gate_shard, slot_major));
10646                let up_shard = nvfp4_column_shard(up.expert(expert)?, tp, rank_index)?;
10647                up_host.extend_from_slice(&nvfp4_repack_bank_matrix(up_shard, slot_major));
10648            }
10649            let bank_experts = gate.expert_count;
10650            let gate_expert_bytes = gate_host.len() / bank_experts.max(1);
10651            let up_expert_bytes = up_host.len() / bank_experts.max(1);
10652            let local_out = gate.out_features / tp;
10653            gate_ranks.push(ResidentNvfp4ColumnBankRank {
10654                bank: engine.htod_bytes(&gate_host)?,
10655                expert_bytes: gate_expert_bytes,
10656                local_out,
10657                in_features: gate.in_features,
10658                row_bytes: nvfp4_row_bytes(gate.in_features),
10659                slot_major,
10660            });
10661            up_ranks.push(ResidentNvfp4ColumnBankRank {
10662                bank: engine.htod_bytes(&up_host)?,
10663                expert_bytes: up_expert_bytes,
10664                local_out,
10665                in_features: up.in_features,
10666                row_bytes: nvfp4_row_bytes(up.in_features),
10667                slot_major,
10668            });
10669            macros_gate_dev.push(engine.htod(gate.macros)?);
10670            macros_up_dev.push(engine.htod(up.macros)?);
10671            macros_down_dev.push(engine.htod(down.macros)?);
10672        }
10673        // Down: canonical shard grid, NOT the world size (see NVFP4_CANONICAL_ROW_SHARDS).
10674        // Shard s lives on rank s % world, so TP1 holds both shards and TP2 one each, while the
10675        // execution and reduction order stay identical.
10676        let mut down_ranks = Vec::with_capacity(NVFP4_CANONICAL_ROW_SHARDS);
10677        for shard_index in 0..NVFP4_CANONICAL_ROW_SHARDS {
10678            let device_rank = shard_index % tp;
10679            let engine = &self.ranks[device_rank];
10680            let _main = engine.gpu.enter_main()?;
10681            let mut down_host: Vec<u8> = Vec::new();
10682            for expert in 0..down.expert_count {
10683                let down_matrix = down.expert(expert)?;
10684                let (codes, scales, local_in) =
10685                    nvfp4_row_shard(down_matrix, NVFP4_CANONICAL_ROW_SHARDS, shard_index)?;
10686                down_host.extend_from_slice(&nvfp4_repack_bank_matrix(
10687                    Nvfp4BlockMatrix {
10688                        codes: &codes,
10689                        scales: &scales,
10690                        macro_scale: down_matrix.macro_scale,
10691                        out_features: down_matrix.out_features,
10692                        in_features: local_in,
10693                    },
10694                    slot_major,
10695                ));
10696            }
10697            let bank_experts = down.expert_count;
10698            let down_expert_bytes = down_host.len() / bank_experts.max(1);
10699            let local_in = down.in_features / NVFP4_CANONICAL_ROW_SHARDS;
10700            down_ranks.push(ResidentNvfp4RowBankRank {
10701                bank: engine.htod_bytes(&down_host)?,
10702                expert_bytes: down_expert_bytes,
10703                device_rank,
10704                out_features: down.out_features,
10705                local_in,
10706                row_bytes: nvfp4_row_bytes(local_in),
10707                slot_major,
10708            });
10709        }
10710        Ok(ResidentNvfp4TensorParallel {
10711            gate: gate_ranks,
10712            up: up_ranks,
10713            down: down_ranks,
10714            macros_gate: gate.macros.to_vec(),
10715            macros_up: up.macros.to_vec(),
10716            macros_down: down.macros.to_vec(),
10717            macros_gate_dev,
10718            macros_up_dev,
10719            macros_down_dev,
10720            expert_count: gate.expert_count,
10721            input_width: gate.in_features,
10722            expert_width: gate.out_features,
10723            device_workspace: std::sync::Mutex::new(None),
10724            prime_tables: std::sync::Mutex::new(Vec::new()),
10725        })
10726    }
10727
10728    fn run_column_bank_expert_nvfp4(
10729        &self,
10730        ranks: &[ResidentNvfp4ColumnBankRank],
10731        macros: &[f32],
10732        expert: usize,
10733        input: &[f32],
10734    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10735        let local_out = ranks
10736            .first()
10737            .ok_or("NVFP4 TP column bank has no ranks")?
10738            .local_out;
10739        let mut gathered = vec![0.0f32; local_out * ranks.len()];
10740        for (rank_index, (engine, bank)) in self.ranks.iter().zip(ranks).enumerate() {
10741            let _main = engine.gpu.enter_main()?;
10742            let activations = engine.htod(input)?;
10743            let output = bank.host_canonical_expert(engine, expert, &activations)?;
10744            let output = engine.dtoh(&output)?;
10745            gathered[rank_index * local_out..(rank_index + 1) * local_out].copy_from_slice(&output);
10746        }
10747        apply_macro(&mut gathered, macros[expert]);
10748        Ok(gathered)
10749    }
10750
10751    /// Canonical-shard row reduction: iterate the FIXED shard grid in shard order (each shard
10752    /// executes on its owning rank engine), so the reduction parenthesization is identical at
10753    /// every world size — that identity is what the TP1-oracle-vs-TP2 bit gate proves.
10754    fn run_row_bank_expert_nvfp4(
10755        &self,
10756        shards: &[ResidentNvfp4RowBankRank],
10757        macros: &[f32],
10758        expert: usize,
10759        input: &[f32],
10760    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10761        let out_features = shards
10762            .first()
10763            .ok_or("NVFP4 TP row bank has no canonical shards")?
10764            .out_features;
10765        let in_features = shards.iter().map(|shard| shard.local_in).sum::<usize>();
10766        let mut reduced = vec![0.0f32; out_features];
10767        for (shard_index, shard) in shards.iter().enumerate() {
10768            let engine = self
10769                .ranks
10770                .get(shard.device_rank)
10771                .ok_or("NVFP4 canonical shard names a rank outside this runtime")?;
10772            let _main = engine.gpu.enter_main()?;
10773            let local_activations =
10774                activation_shard(input, 1, in_features, shards.len(), shard_index);
10775            let activations = engine.htod(&local_activations)?;
10776            let output = shard.host_canonical_expert(engine, expert, &activations)?;
10777            let partial = engine.dtoh(&output)?;
10778            for (sum, value) in reduced.iter_mut().zip(&partial) {
10779                *sum += *value;
10780            }
10781        }
10782        apply_macro(&mut reduced, macros[expert]);
10783        Ok(reduced)
10784    }
10785
10786    /// Upload whole experts per owning rank (NVFP4 expert-parallel: the layout the clamped tail
10787    /// layers require — clamp semantics do not distribute across a tensor shard). Each owned
10788    /// expert keeps its full gate/up/down as one repacked block buffer on its owner.
10789    #[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
10790    pub fn upload_expert_parallel_nvfp4(
10791        &self,
10792        gate: Nvfp4ExpertBank<'_>,
10793        up: Nvfp4ExpertBank<'_>,
10794        down: Nvfp4ExpertBank<'_>,
10795    ) -> Result<ResidentNvfp4ExpertParallel, Box<dyn std::error::Error>> {
10796        gate.validate()?;
10797        up.validate()?;
10798        down.validate()?;
10799        if gate.expert_count != up.expert_count || gate.expert_count != down.expert_count {
10800            return Err("NVFP4 EP gate/up/down expert counts differ".into());
10801        }
10802        if gate.in_features != up.in_features || gate.out_features != up.out_features {
10803            return Err("NVFP4 EP gate/up dimensions differ".into());
10804        }
10805        if down.in_features != gate.out_features || down.out_features != gate.in_features {
10806            return Err(format!(
10807                "NVFP4 EP down {}x{} does not invert gate/up {}x{}",
10808                down.out_features, down.in_features, gate.out_features, gate.in_features
10809            )
10810            .into());
10811        }
10812        let world = self.ranks.len();
10813        if gate.expert_count % world != 0 {
10814            return Err(format!(
10815                "NVFP4 EP expert count {} is not divisible by {world} ranks",
10816                gate.expert_count
10817            )
10818            .into());
10819        }
10820        let experts_per_rank = gate.expert_count / world;
10821        let mut ranks = Vec::with_capacity(world);
10822        for (rank_index, engine) in self.ranks.iter().enumerate() {
10823            let _main = engine.gpu.enter_main()?;
10824            let expert_range = rank_index * experts_per_rank..(rank_index + 1) * experts_per_rank;
10825            let mut gate_host = Vec::new();
10826            let mut up_host = Vec::new();
10827            let mut down_host = Vec::new();
10828            for expert in expert_range.clone() {
10829                gate_host.extend_from_slice(&nvfp4_repack_matrix(gate.expert(expert)?));
10830                up_host.extend_from_slice(&nvfp4_repack_matrix(up.expert(expert)?));
10831                down_host.extend_from_slice(&nvfp4_repack_matrix(down.expert(expert)?));
10832            }
10833            let gate_expert_bytes = gate_host.len() / experts_per_rank;
10834            let up_expert_bytes = up_host.len() / experts_per_rank;
10835            if gate_expert_bytes != up_expert_bytes {
10836                return Err("NVFP4 EP gate/up packed expert bytes differ".into());
10837            }
10838            let down_expert_bytes = down_host.len() / experts_per_rank;
10839            ranks.push(ResidentNvfp4EpRank {
10840                gate: engine.htod_bytes(&gate_host)?,
10841                up: engine.htod_bytes(&up_host)?,
10842                down: engine.htod_bytes(&down_host)?,
10843                gate_expert_bytes,
10844                down_expert_bytes,
10845                macros_gate: engine.htod(&gate.macros[expert_range.clone()])?,
10846                macros_up: engine.htod(&up.macros[expert_range.clone()])?,
10847                macros_down: engine.htod(&down.macros[expert_range.clone()])?,
10848                expert_range,
10849            });
10850        }
10851        Ok(ResidentNvfp4ExpertParallel {
10852            ranks,
10853            macros_gate: gate.macros.to_vec(),
10854            macros_up: up.macros.to_vec(),
10855            macros_down: down.macros.to_vec(),
10856            expert_count: gate.expert_count,
10857            input_width: gate.in_features,
10858            expert_width: gate.out_features,
10859            gate_row_bytes: nvfp4_row_bytes(gate.in_features),
10860            down_row_bytes: nvfp4_row_bytes(down.in_features),
10861            device_workspace: std::sync::Mutex::new(None),
10862        })
10863    }
10864
10865    /// Upload an already-normalized NVFP4 expert bank.
10866    ///
10867    /// `HostExps` is the physical-format boundary: stacked checkpoint tensors, gathered
10868    /// per-expert tensors, and manifest-backed overlays all become the same contiguous
10869    /// block_nvfp4 expert representation before the parallel backend sees them.
10870    pub fn upload_expert_parallel_nvfp4_normalized(
10871        &self,
10872        gate: &crate::model::HostExps,
10873        up: &crate::model::HostExps,
10874        down: &crate::model::HostExps,
10875    ) -> Result<ResidentNvfp4ExpertParallel, Box<dyn std::error::Error>> {
10876        for (label, bank) in [("gate", gate), ("up", up), ("down", down)] {
10877            if bank.qtype != crate::QT_NVFP4 || !bank.is_uniform_layout() {
10878                return Err(format!(
10879                    "NVFP4 EP normalized {label} bank requires one uniform NVFP4 layout, \
10880                     got qtype={} uniform={}",
10881                    bank.qtype,
10882                    bank.is_uniform_layout()
10883                )
10884                .into());
10885            }
10886            if bank.n_expert == 0
10887                || bank.expert_stride != bank.out_f * bank.row_bytes
10888                || (0..bank.n_expert)
10889                    .any(|expert| bank.expert_bytes(expert).len() != bank.expert_stride)
10890            {
10891                return Err(format!("NVFP4 EP normalized {label} bank geometry is invalid").into());
10892            }
10893        }
10894        if gate.n_expert != up.n_expert || gate.n_expert != down.n_expert {
10895            return Err("NVFP4 EP normalized gate/up/down expert counts differ".into());
10896        }
10897        if gate.in_f != up.in_f || gate.out_f != up.out_f {
10898            return Err("NVFP4 EP normalized gate/up dimensions differ".into());
10899        }
10900        if down.in_f != gate.out_f || down.out_f != gate.in_f {
10901            return Err(format!(
10902                "NVFP4 EP normalized down {}x{} does not invert gate/up {}x{}",
10903                down.out_f, down.in_f, gate.out_f, gate.in_f
10904            )
10905            .into());
10906        }
10907        let macros = |bank: &crate::model::HostExps| -> Result<Vec<f32>, String> {
10908            let values = bank
10909                .macros
10910                .clone()
10911                .unwrap_or_else(|| vec![1.0; bank.n_expert]);
10912            if values.len() != bank.n_expert
10913                || !values.iter().all(|value| value.is_finite() && *value > 0.0)
10914            {
10915                return Err("NVFP4 EP normalized macro row is not finite-positive".to_string());
10916            }
10917            Ok(values)
10918        };
10919        let macros_gate = macros(gate)?;
10920        let macros_up = macros(up)?;
10921        let macros_down = macros(down)?;
10922        let world = self.ranks.len();
10923        if !gate.n_expert.is_multiple_of(world) {
10924            return Err(format!(
10925                "NVFP4 EP normalized expert count {} is not divisible by {world} ranks",
10926                gate.n_expert
10927            )
10928            .into());
10929        }
10930        let experts_per_rank = gate.n_expert / world;
10931        let mut ranks = Vec::with_capacity(world);
10932        for (rank_index, engine) in self.ranks.iter().enumerate() {
10933            let _main = engine.gpu.enter_main()?;
10934            let expert_range = rank_index * experts_per_rank..(rank_index + 1) * experts_per_rank;
10935            let mut gate_host = Vec::with_capacity(experts_per_rank * gate.expert_stride);
10936            let mut up_host = Vec::with_capacity(experts_per_rank * up.expert_stride);
10937            let mut down_host = Vec::with_capacity(experts_per_rank * down.expert_stride);
10938            for expert in expert_range.clone() {
10939                gate_host.extend_from_slice(gate.expert_bytes(expert));
10940                up_host.extend_from_slice(up.expert_bytes(expert));
10941                down_host.extend_from_slice(down.expert_bytes(expert));
10942            }
10943            ranks.push(ResidentNvfp4EpRank {
10944                gate: engine.htod_bytes(&gate_host)?,
10945                up: engine.htod_bytes(&up_host)?,
10946                down: engine.htod_bytes(&down_host)?,
10947                gate_expert_bytes: gate.expert_stride,
10948                down_expert_bytes: down.expert_stride,
10949                macros_gate: engine.htod(&macros_gate[expert_range.clone()])?,
10950                macros_up: engine.htod(&macros_up[expert_range.clone()])?,
10951                macros_down: engine.htod(&macros_down[expert_range.clone()])?,
10952                expert_range,
10953            });
10954        }
10955        Ok(ResidentNvfp4ExpertParallel {
10956            ranks,
10957            macros_gate,
10958            macros_up,
10959            macros_down,
10960            expert_count: gate.n_expert,
10961            input_width: gate.in_f,
10962            expert_width: gate.out_f,
10963            gate_row_bytes: gate.row_bytes,
10964            down_row_bytes: down.row_bytes,
10965            device_workspace: std::sync::Mutex::new(None),
10966        })
10967    }
10968
10969    /// Routed NVFP4 expert-parallel program, host-canonical: every selected expert executes WHOLE
10970    /// on its owning rank (gate -> up -> clamped-or-plain SwiGLU on host -> down), each projection
10971    /// macro applied once post-kernel, route-weighted accumulate on the host in slot order. The
10972    /// activation uses `step_expert_activation_host`, so the clamped tail layers keep the official
10973    /// contract. Exactness-first; no throughput claim.
10974    #[allow(clippy::too_many_arguments)]
10975    pub fn run_routed_experts_nvfp4(
10976        &self,
10977        experts: &ResidentNvfp4ExpertParallel,
10978        input: &[f32],
10979        tokens: usize,
10980        selected: &[usize],
10981        route_weights: &[f32],
10982        experts_per_token: usize,
10983        activation_limit: Option<f32>,
10984    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
10985        validate_activations(input, tokens, experts.input_width)?;
10986        let pairs = tokens
10987            .checked_mul(experts_per_token)
10988            .ok_or("NVFP4 EP route count overflow")?;
10989        if selected.len() != pairs || route_weights.len() != pairs {
10990            return Err(format!(
10991                "NVFP4 EP routes selected={} weights={} != tokens {tokens} x experts/token \
10992                 {experts_per_token} ({pairs})",
10993                selected.len(),
10994                route_weights.len(),
10995            )
10996            .into());
10997        }
10998        if !route_weights.iter().all(|weight| weight.is_finite()) {
10999            return Err("NVFP4 EP route weights contain a non-finite value".into());
11000        }
11001        let experts_per_rank = experts.expert_count / experts.ranks.len();
11002        let mut output = vec![0.0f32; tokens * experts.input_width];
11003        for token in 0..tokens {
11004            let input_row = &input[token * experts.input_width..(token + 1) * experts.input_width];
11005            for slot in 0..experts_per_token {
11006                let pair = token * experts_per_token + slot;
11007                let expert = selected[pair];
11008                if expert >= experts.expert_count {
11009                    return Err(format!(
11010                        "NVFP4 EP selected expert {expert} outside 0..{}",
11011                        experts.expert_count
11012                    )
11013                    .into());
11014                }
11015                let owner = expert / experts_per_rank;
11016                let local = expert - owner * experts_per_rank;
11017                let rank = &experts.ranks[owner];
11018                let engine = &self.ranks[owner];
11019                let _main = engine.gpu.enter_main()?;
11020                let device_input = engine.htod(input_row)?;
11021                let gate_out = engine.qmatvec_nvfp4_fast(
11022                    &rank.gate.slice(
11023                        local * rank.gate_expert_bytes..(local + 1) * rank.gate_expert_bytes,
11024                    ),
11025                    &device_input,
11026                    1,
11027                    experts.input_width,
11028                    experts.expert_width,
11029                    experts.gate_row_bytes,
11030                )?;
11031                let up_out = engine.qmatvec_nvfp4_fast(
11032                    &rank.up.slice(
11033                        local * rank.gate_expert_bytes..(local + 1) * rank.gate_expert_bytes,
11034                    ),
11035                    &device_input,
11036                    1,
11037                    experts.input_width,
11038                    experts.expert_width,
11039                    experts.gate_row_bytes,
11040                )?;
11041                let mut gate_host = engine.dtoh(&gate_out)?;
11042                let mut up_host = engine.dtoh(&up_out)?;
11043                apply_macro(&mut gate_host, experts.macros_gate[expert]);
11044                apply_macro(&mut up_host, experts.macros_up[expert]);
11045                let activated: Vec<f32> = gate_host
11046                    .iter()
11047                    .zip(&up_host)
11048                    .map(|(&gate, &up)| step_expert_activation_host(gate, up, activation_limit))
11049                    .collect();
11050                let device_activated = engine.htod(&activated)?;
11051                let down_out = engine.qmatvec_nvfp4_fast(
11052                    &rank.down.slice(
11053                        local * rank.down_expert_bytes..(local + 1) * rank.down_expert_bytes,
11054                    ),
11055                    &device_activated,
11056                    1,
11057                    experts.expert_width,
11058                    experts.input_width,
11059                    experts.down_row_bytes,
11060                )?;
11061                let mut down_host = engine.dtoh(&down_out)?;
11062                apply_macro(&mut down_host, experts.macros_down[expert]);
11063                let weight = route_weights[pair];
11064                for (sum, value) in output
11065                    [token * experts.input_width..(token + 1) * experts.input_width]
11066                    .iter_mut()
11067                    .zip(down_host)
11068                {
11069                    *sum += weight * value;
11070                }
11071            }
11072        }
11073        Ok(output)
11074    }
11075
11076    /// Device-resident W4A16 expert parallelism for one scheduler/prefill batch (1..=128 rows).
11077    ///
11078    /// The host router partitions token/slot pairs by contiguous expert owner. Each rank
11079    /// peer-reads the whole batch input once, rounds it to BF16, and executes its owner-local
11080    /// selected gate/up -> host-expf SwiGLU -> BF16 -> down program. Down rows scatter directly
11081    /// into canonical token-major pair positions in the model engine's peer-accessible pool at
11082    /// every batch width; the root reduces each token's slots in original order. Thus batching
11083    /// and owner assignment do not change route-reduction parenthesization.
11084    #[allow(clippy::too_many_arguments)]
11085    pub fn run_routed_experts_nvfp4_w4a16_device_io(
11086        &self,
11087        experts: &ResidentNvfp4ExpertParallel,
11088        e: &Engine,
11089        input_dev: &crate::CudaSlice<f32>,
11090        tokens: usize,
11091        selected: &[usize],
11092        route_weights: &[f32],
11093        experts_per_token: usize,
11094        activation_limit: Option<f32>,
11095    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
11096        // Diagnostic attribution only: force the returned root event chain to completion so the
11097        // caller's shared-expert timer does not absorb routed-EP work. The normal path remains
11098        // fully asynchronous.
11099        static TIMING_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11100        static TIMING_CALLS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11101        let timing = std::env::var("MEMRA_STEP_TP_TIMING").as_deref() == Ok("1");
11102        let started = timing.then(std::time::Instant::now);
11103        if !self.native_p2p {
11104            return Err("W4A16 NVFP4 device EP requires native P2P".into());
11105        }
11106        if self.devices.first().copied() != Some(e.ctx().ordinal()) {
11107            return Err(format!(
11108                "W4A16 NVFP4 device EP root device {:?} != model engine device {}",
11109                self.devices.first(),
11110                e.ctx().ordinal()
11111            )
11112            .into());
11113        }
11114        // Prime/cache scratch buffers are grow-only: a 160-token host-oracle chunk can be
11115        // followed by a 44-token device-EP tail using the same 160-row allocation. Consume the
11116        // active prefix rather than requiring allocation length == active length.
11117        let active_input_values =
11118            nvfp4_ep_active_input_values(input_dev.len(), tokens, experts.input_width)?;
11119        let pairs = tokens
11120            .checked_mul(experts_per_token)
11121            .ok_or("W4A16 NVFP4 device EP route count overflow")?;
11122        if selected.len() != pairs || route_weights.len() != pairs {
11123            return Err(format!(
11124                "W4A16 NVFP4 device EP routes selected={} weights={} != tokens {tokens} x \
11125                 experts/token {experts_per_token} ({pairs})",
11126                selected.len(),
11127                route_weights.len(),
11128            )
11129            .into());
11130        }
11131        if !route_weights.iter().all(|weight| weight.is_finite()) {
11132            return Err("W4A16 NVFP4 device EP route weights contain a non-finite value".into());
11133        }
11134        let world = self.ranks.len();
11135        if world != experts.ranks.len() || !(2..=PRODUCT_MAX_CARDS).contains(&world) {
11136            return Err(format!(
11137                "W4A16 NVFP4 device EP runtime ranks {world} != bank ranks {}",
11138                experts.ranks.len()
11139            )
11140            .into());
11141        }
11142        let owner_routes = partition_expert_owner_routes(
11143            experts.expert_count,
11144            world,
11145            tokens,
11146            experts_per_token,
11147            selected,
11148        )?;
11149
11150        let mut workspace_guard = experts
11151            .device_workspace
11152            .lock()
11153            .map_err(|_| "W4A16 NVFP4 device EP workspace lock is poisoned")?;
11154        if workspace_guard.is_none() {
11155            let capacity_tokens = NVFP4_EP_DEVICE_BATCH_CAP;
11156            let capacity_pairs = capacity_tokens * experts_per_token;
11157            let mut input = Vec::with_capacity(world);
11158            let mut input_bf16 = Vec::with_capacity(world);
11159            let mut input_q8 = Vec::with_capacity(world);
11160            let mut input_q8_scales = Vec::with_capacity(world);
11161            let mut sel = Vec::with_capacity(world);
11162            let mut token_rows = Vec::with_capacity(world);
11163            let mut global_pairs = Vec::with_capacity(world);
11164            let mut route_w = Vec::with_capacity(world);
11165            let mut gate_out = Vec::with_capacity(world);
11166            let mut up_out = Vec::with_capacity(world);
11167            let mut activation_bf16 = Vec::with_capacity(world);
11168            let mut activation_q8 = Vec::with_capacity(world);
11169            let mut activation_q8_scales = Vec::with_capacity(world);
11170            let mut ev_rank = Vec::with_capacity(world);
11171            for engine in &self.ranks {
11172                let _main = engine.gpu.enter_main()?;
11173                input.push(engine.uninit(capacity_tokens * experts.input_width)?);
11174                input_bf16.push(engine.alloc_u8_uninit(2 * capacity_tokens * experts.input_width)?);
11175                input_q8.push(engine.alloc_i8_uninit(capacity_tokens * experts.input_width)?);
11176                input_q8_scales
11177                    .push(engine.uninit(capacity_tokens * experts.input_width.div_ceil(32))?);
11178                sel.push(engine.htod_i32(&vec![0i32; capacity_pairs])?);
11179                token_rows.push(engine.htod_i32(&vec![0i32; capacity_pairs])?);
11180                global_pairs.push(engine.htod_i32(&vec![0i32; capacity_pairs])?);
11181                route_w.push(engine.htod(&vec![0.0f32; capacity_pairs])?);
11182                gate_out.push(engine.uninit(capacity_pairs * experts.expert_width)?);
11183                up_out.push(engine.uninit(capacity_pairs * experts.expert_width)?);
11184                activation_bf16
11185                    .push(engine.alloc_u8_uninit(2 * capacity_pairs * experts.expert_width)?);
11186                activation_q8.push(engine.alloc_i8_uninit(capacity_pairs * experts.expert_width)?);
11187                activation_q8_scales
11188                    .push(engine.uninit(capacity_pairs * experts.expert_width.div_ceil(32))?);
11189                ev_rank.push(engine.ctx().new_event(None)?);
11190            }
11191            let _main = e.gpu.enter_main()?;
11192            let slot_rows = e.uninit(capacity_pairs * experts.input_width)?;
11193            let slot_rows_raw = {
11194                use cudarc::driver::DevicePtr;
11195                let stream = e.stream();
11196                let (pointer, _guard) = slot_rows.device_ptr(&stream);
11197                pointer
11198            };
11199            *workspace_guard = Some(Nvfp4EpDeviceWorkspace {
11200                input,
11201                input_bf16,
11202                input_q8,
11203                input_q8_scales,
11204                sel,
11205                token_rows,
11206                global_pairs,
11207                route_w,
11208                gate_out,
11209                up_out,
11210                activation_bf16,
11211                activation_q8,
11212                activation_q8_scales,
11213                slot_rows,
11214                slot_rows_raw,
11215                route_weights: e.htod(&vec![0.0f32; capacity_pairs])?,
11216                ev_entry: e.ctx().new_event(None)?,
11217                ev_entry_device: e.ctx().ordinal(),
11218                ev_rank,
11219                phase_events: None,
11220                capacity_tokens,
11221                experts_per_token,
11222            });
11223        }
11224        let workspace = workspace_guard
11225            .as_mut()
11226            .expect("W4A16 NVFP4 device EP workspace initialized above");
11227        if workspace.experts_per_token != experts_per_token || tokens > workspace.capacity_tokens {
11228            return Err(format!(
11229                "W4A16 NVFP4 device EP workspace tokens={} experts/token={} cannot serve \
11230                 tokens={tokens} experts/token={experts_per_token}",
11231                workspace.capacity_tokens, workspace.experts_per_token,
11232            )
11233            .into());
11234        }
11235        if workspace.ev_entry_device != e.ctx().ordinal() {
11236            return Err("W4A16 NVFP4 device EP model engine changed".into());
11237        }
11238
11239        {
11240            let _main = e.gpu.enter_main()?;
11241            let mut destination = workspace.route_weights.slice_mut(0..pairs);
11242            e.stream()
11243                .memcpy_htod(&route_weights[..pairs], &mut destination)?;
11244            workspace.ev_entry.record(&e.stream())?;
11245        }
11246        for (rank_index, engine) in self.ranks.iter().enumerate() {
11247            let _main = engine.gpu.enter_main()?;
11248            engine.stream().wait(&workspace.ev_entry)?;
11249            {
11250                let mut destination = workspace.input[rank_index].slice_mut(0..active_input_values);
11251                engine
11252                    .stream()
11253                    .memcpy_dtod(&input_dev.slice(0..active_input_values), &mut destination)?;
11254            }
11255            engine.f32_to_bf16_into(
11256                &workspace.input[rank_index],
11257                &mut workspace.input_bf16[rank_index],
11258                tokens * experts.input_width,
11259            )?;
11260            let owner = &owner_routes[rank_index];
11261            debug_assert_eq!(owner.rank, rank_index);
11262            let local_count = owner.selected.len();
11263            if local_count > 0 {
11264                let local_selected = owner
11265                    .selected
11266                    .iter()
11267                    .map(|&expert| expert as i32)
11268                    .collect::<Vec<_>>();
11269                let local_token_rows = owner
11270                    .token_rows
11271                    .iter()
11272                    .map(|&token| token as i32)
11273                    .collect::<Vec<_>>();
11274                let local_global_pairs = owner
11275                    .global_pairs
11276                    .iter()
11277                    .map(|&pair| pair as i32)
11278                    .collect::<Vec<_>>();
11279                {
11280                    let mut destination = workspace.sel[rank_index].slice_mut(0..local_count);
11281                    engine
11282                        .stream()
11283                        .memcpy_htod(&local_selected, &mut destination)?;
11284                }
11285                {
11286                    let mut destination =
11287                        workspace.token_rows[rank_index].slice_mut(0..local_count);
11288                    engine
11289                        .stream()
11290                        .memcpy_htod(&local_token_rows, &mut destination)?;
11291                }
11292                {
11293                    let mut destination =
11294                        workspace.global_pairs[rank_index].slice_mut(0..local_count);
11295                    engine
11296                        .stream()
11297                        .memcpy_htod(&local_global_pairs, &mut destination)?;
11298                }
11299                let rank = &experts.ranks[rank_index];
11300                engine.qmatvec_nvfp4_bf16_sel_dual_rows_into(
11301                    &rank.gate,
11302                    &rank.up,
11303                    &workspace.sel[rank_index],
11304                    &workspace.token_rows[rank_index],
11305                    &workspace.input_bf16[rank_index],
11306                    &mut workspace.gate_out[rank_index],
11307                    &mut workspace.up_out[rank_index],
11308                    local_count,
11309                    experts.input_width,
11310                    experts.expert_width,
11311                    experts.gate_row_bytes,
11312                    rank.gate_expert_bytes,
11313                    tokens,
11314                )?;
11315                engine.silu_mul_scaled_host_expf_bf16_sel_into(
11316                    &workspace.gate_out[rank_index],
11317                    &workspace.up_out[rank_index],
11318                    &rank.macros_gate,
11319                    &rank.macros_up,
11320                    &workspace.sel[rank_index],
11321                    activation_limit,
11322                    &mut workspace.activation_bf16[rank_index],
11323                    experts.expert_width,
11324                    local_count,
11325                )?;
11326                engine.qmatvec_nvfp4_bf16_sel_down_rows_raw(
11327                    &rank.down,
11328                    &workspace.sel[rank_index],
11329                    &workspace.global_pairs[rank_index],
11330                    &workspace.activation_bf16[rank_index],
11331                    &rank.macros_down,
11332                    workspace.slot_rows_raw,
11333                    local_count,
11334                    experts.expert_width,
11335                    experts.input_width,
11336                    experts.down_row_bytes,
11337                    rank.down_expert_bytes,
11338                    pairs,
11339                )?;
11340            }
11341            workspace.ev_rank[rank_index].record(&engine.stream())?;
11342        }
11343
11344        let output = {
11345            let _main = e.gpu.enter_main()?;
11346            for event in &workspace.ev_rank {
11347                e.stream().wait(event)?;
11348            }
11349            let mut output = e.uninit(tokens * experts.input_width)?;
11350            e.axpy_rows_seq_tokens_into(
11351                &workspace.slot_rows,
11352                &workspace.route_weights,
11353                &mut output,
11354                experts.input_width,
11355                experts_per_token,
11356                tokens,
11357            )?;
11358            output
11359        };
11360        if let Some(started) = started {
11361            use std::sync::atomic::Ordering;
11362            e.stream().synchronize()?;
11363            let elapsed = started.elapsed().as_nanos() as u64;
11364            let ns = TIMING_NS.fetch_add(elapsed, Ordering::Relaxed) + elapsed;
11365            let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
11366            if calls.is_multiple_of(430) {
11367                eprintln!(
11368                    "[nvfp4-ep-w4a16-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
11369                    ns as f64 / 1.0e6,
11370                    ns as f64 / calls as f64 / 1.0e3,
11371                );
11372            }
11373        }
11374        Ok(output)
11375    }
11376
11377    /// Fully device-routed W4A16 expert parallelism. Router ids/weights stay on the model GPU;
11378    /// each rank receives the fixed token/slot metadata, rejects non-owned experts in-kernel, and
11379    /// writes canonical token-major slot rows back to the root at every batch width. Preserving
11380    /// that one accumulation program is required by speculative verification: the former t=1
11381    /// owner-grouped FMA was a distinct numeric class and failed real HY3 MTP self-consistency.
11382    #[allow(clippy::too_many_arguments)]
11383    pub fn run_routed_experts_nvfp4_w4a16_device_routed(
11384        &self,
11385        experts: &ResidentNvfp4ExpertParallel,
11386        e: &Engine,
11387        input_dev: &crate::CudaSlice<f32>,
11388        selected_dev: &crate::CudaSlice<i32>,
11389        route_weights_dev: &crate::CudaSlice<f32>,
11390        tokens: usize,
11391        experts_per_token: usize,
11392        activation_limit: Option<f32>,
11393    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
11394        self.run_routed_experts_nvfp4_w4a16_device_routed_inner(
11395            experts,
11396            e,
11397            input_dev,
11398            selected_dev,
11399            route_weights_dev,
11400            tokens,
11401            experts_per_token,
11402            activation_limit,
11403            None,
11404        )
11405    }
11406
11407    /// Automatic whole-expert EP with a PREJOIN hook. The hook runs after every rank's routed
11408    /// chain has been issued and before the root waits for rank completion, so independent
11409    /// root-device work can fill the peer drain without changing the routed accumulation order.
11410    #[allow(clippy::too_many_arguments)]
11411    pub fn run_routed_experts_nvfp4_w4a16_device_routed_prejoin(
11412        &self,
11413        experts: &ResidentNvfp4ExpertParallel,
11414        e: &Engine,
11415        input_dev: &crate::CudaSlice<f32>,
11416        selected_dev: &crate::CudaSlice<i32>,
11417        route_weights_dev: &crate::CudaSlice<f32>,
11418        tokens: usize,
11419        experts_per_token: usize,
11420        activation_limit: Option<f32>,
11421        mut pre_join: impl FnMut() -> Result<(), Box<dyn std::error::Error>>,
11422    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
11423        self.run_routed_experts_nvfp4_w4a16_device_routed_inner(
11424            experts,
11425            e,
11426            input_dev,
11427            selected_dev,
11428            route_weights_dev,
11429            tokens,
11430            experts_per_token,
11431            activation_limit,
11432            Some(&mut pre_join),
11433        )
11434    }
11435
11436    #[allow(clippy::too_many_arguments)]
11437    fn run_routed_experts_nvfp4_w4a16_device_routed_inner(
11438        &self,
11439        experts: &ResidentNvfp4ExpertParallel,
11440        e: &Engine,
11441        input_dev: &crate::CudaSlice<f32>,
11442        selected_dev: &crate::CudaSlice<i32>,
11443        route_weights_dev: &crate::CudaSlice<f32>,
11444        tokens: usize,
11445        experts_per_token: usize,
11446        activation_limit: Option<f32>,
11447        mut pre_join: Option<&mut dyn FnMut() -> Result<(), Box<dyn std::error::Error>>>,
11448    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
11449        if !self.native_p2p {
11450            return Err("W4A16 device-routed EP requires native P2P".into());
11451        }
11452        if self.devices.first().copied() != Some(e.ctx().ordinal()) {
11453            return Err(format!(
11454                "W4A16 device-routed EP root device {:?} != model engine device {}",
11455                self.devices.first(),
11456                e.ctx().ordinal()
11457            )
11458            .into());
11459        }
11460        let active_input_values =
11461            nvfp4_ep_active_input_values(input_dev.len(), tokens, experts.input_width)?;
11462        let pairs = tokens
11463            .checked_mul(experts_per_token)
11464            .ok_or("W4A16 device-routed EP route count overflow")?;
11465        if selected_dev.len() < pairs || route_weights_dev.len() < pairs {
11466            return Err(format!(
11467                "W4A16 device-routed EP metadata selected={} weights={} < pairs={pairs}",
11468                selected_dev.len(),
11469                route_weights_dev.len(),
11470            )
11471            .into());
11472        }
11473        let world = self.ranks.len();
11474        if world != experts.ranks.len() || !(2..=PRODUCT_MAX_CARDS).contains(&world) {
11475            return Err(format!(
11476                "W4A16 device-routed EP runtime ranks {world} != bank ranks {}",
11477                experts.ranks.len()
11478            )
11479            .into());
11480        }
11481
11482        static TIMING_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11483        static TIMING_CALLS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11484        static ISSUE_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11485        static JOIN_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11486        static COPY_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11487        static GATE_UP_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11488        static ACTIVATION_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11489        static DOWN_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11490        static RANK_SPAN_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11491        let timing = std::env::var("MEMRA_STEP_TP_TIMING").as_deref() == Ok("1");
11492        let started = timing.then(std::time::Instant::now);
11493        let pair_down_enabled = parallel_ep_pair_down_enabled()?;
11494
11495        let mut workspace_guard = experts
11496            .device_workspace
11497            .lock()
11498            .map_err(|_| "W4A16 device-routed EP workspace lock is poisoned")?;
11499        if workspace_guard.is_none() {
11500            let capacity_tokens = NVFP4_EP_DEVICE_BATCH_CAP;
11501            let capacity_pairs = capacity_tokens * experts_per_token;
11502            let mut input = Vec::with_capacity(world);
11503            let mut input_bf16 = Vec::with_capacity(world);
11504            let mut input_q8 = Vec::with_capacity(world);
11505            let mut input_q8_scales = Vec::with_capacity(world);
11506            let mut sel = Vec::with_capacity(world);
11507            let mut token_rows = Vec::with_capacity(world);
11508            let mut global_pairs = Vec::with_capacity(world);
11509            let mut route_w = Vec::with_capacity(world);
11510            let mut gate_out = Vec::with_capacity(world);
11511            let mut up_out = Vec::with_capacity(world);
11512            let mut activation_bf16 = Vec::with_capacity(world);
11513            let mut activation_q8 = Vec::with_capacity(world);
11514            let mut activation_q8_scales = Vec::with_capacity(world);
11515            let mut ev_rank = Vec::with_capacity(world);
11516            let mut phase_head = Vec::with_capacity(world);
11517            let mut phase_copy_done = Vec::with_capacity(world);
11518            let mut phase_gate_up_done = Vec::with_capacity(world);
11519            let mut phase_activation_done = Vec::with_capacity(world);
11520            let mut phase_down_done = Vec::with_capacity(world);
11521            for engine in &self.ranks {
11522                let _main = engine.gpu.enter_main()?;
11523                input.push(engine.uninit(capacity_tokens * experts.input_width)?);
11524                input_bf16.push(engine.alloc_u8_uninit(2 * capacity_tokens * experts.input_width)?);
11525                input_q8.push(engine.alloc_i8_uninit(capacity_tokens * experts.input_width)?);
11526                input_q8_scales
11527                    .push(engine.uninit(capacity_tokens * experts.input_width.div_ceil(32))?);
11528                sel.push(engine.htod_i32(&vec![0i32; capacity_pairs])?);
11529                token_rows.push(engine.htod_i32(&vec![0i32; capacity_pairs])?);
11530                global_pairs.push(engine.htod_i32(&vec![0i32; capacity_pairs])?);
11531                route_w.push(engine.htod(&vec![0.0f32; capacity_pairs])?);
11532                gate_out.push(engine.uninit(capacity_pairs * experts.expert_width)?);
11533                up_out.push(engine.uninit(capacity_pairs * experts.expert_width)?);
11534                activation_bf16
11535                    .push(engine.alloc_u8_uninit(2 * capacity_pairs * experts.expert_width)?);
11536                activation_q8.push(engine.alloc_i8_uninit(capacity_pairs * experts.expert_width)?);
11537                activation_q8_scales
11538                    .push(engine.uninit(capacity_pairs * experts.expert_width.div_ceil(32))?);
11539                ev_rank.push(engine.ctx().new_event(None)?);
11540                if timing {
11541                    phase_head.push(
11542                        engine.ctx().new_event(Some(
11543                            cudarc::driver::sys::CUevent_flags::CU_EVENT_DEFAULT,
11544                        ))?,
11545                    );
11546                    phase_copy_done.push(
11547                        engine.ctx().new_event(Some(
11548                            cudarc::driver::sys::CUevent_flags::CU_EVENT_DEFAULT,
11549                        ))?,
11550                    );
11551                    phase_gate_up_done.push(
11552                        engine.ctx().new_event(Some(
11553                            cudarc::driver::sys::CUevent_flags::CU_EVENT_DEFAULT,
11554                        ))?,
11555                    );
11556                    phase_activation_done.push(
11557                        engine.ctx().new_event(Some(
11558                            cudarc::driver::sys::CUevent_flags::CU_EVENT_DEFAULT,
11559                        ))?,
11560                    );
11561                    phase_down_done.push(
11562                        engine.ctx().new_event(Some(
11563                            cudarc::driver::sys::CUevent_flags::CU_EVENT_DEFAULT,
11564                        ))?,
11565                    );
11566                }
11567            }
11568            let _main = e.gpu.enter_main()?;
11569            let slot_rows = e.uninit(capacity_pairs * experts.input_width)?;
11570            let slot_rows_raw = {
11571                use cudarc::driver::DevicePtr;
11572                let stream = e.stream();
11573                let (pointer, _guard) = slot_rows.device_ptr(&stream);
11574                pointer
11575            };
11576            *workspace_guard = Some(Nvfp4EpDeviceWorkspace {
11577                input,
11578                input_bf16,
11579                input_q8,
11580                input_q8_scales,
11581                sel,
11582                token_rows,
11583                global_pairs,
11584                route_w,
11585                gate_out,
11586                up_out,
11587                activation_bf16,
11588                activation_q8,
11589                activation_q8_scales,
11590                slot_rows,
11591                slot_rows_raw,
11592                route_weights: e.htod(&vec![0.0f32; capacity_pairs])?,
11593                ev_entry: e.ctx().new_event(None)?,
11594                ev_entry_device: e.ctx().ordinal(),
11595                ev_rank,
11596                phase_events: timing.then_some(Nvfp4EpPhaseEvents {
11597                    head: phase_head,
11598                    copy_done: phase_copy_done,
11599                    gate_up_done: phase_gate_up_done,
11600                    activation_done: phase_activation_done,
11601                    down_done: phase_down_done,
11602                }),
11603                capacity_tokens,
11604                experts_per_token,
11605            });
11606        }
11607        let workspace = workspace_guard
11608            .as_mut()
11609            .expect("W4A16 device-routed EP workspace initialized above");
11610        if workspace.experts_per_token != experts_per_token || tokens > workspace.capacity_tokens {
11611            return Err(format!(
11612                "W4A16 device-routed EP workspace tokens={} experts/token={} cannot serve \
11613                 tokens={tokens} experts/token={experts_per_token}",
11614                workspace.capacity_tokens, workspace.experts_per_token,
11615            )
11616            .into());
11617        }
11618
11619        if tokens <= NVFP4_EP_Q8_BATCH_CAP && parallel_ep_q8_act_enabled()? {
11620            return self.run_routed_experts_nvfp4_w4a8_device_routed(
11621                experts,
11622                e,
11623                input_dev,
11624                selected_dev,
11625                route_weights_dev,
11626                workspace,
11627                tokens,
11628                experts_per_token,
11629                activation_limit,
11630                pre_join,
11631            );
11632        }
11633
11634        {
11635            let _main = e.gpu.enter_main()?;
11636            e.memset_zeros_view(
11637                &mut workspace
11638                    .slot_rows
11639                    .slice_mut(0..pairs * experts.input_width),
11640            )?;
11641            workspace.ev_entry.record(&e.stream())?;
11642        }
11643
11644        for (rank_index, engine) in self.ranks.iter().enumerate() {
11645            let _main = engine.gpu.enter_main()?;
11646            if let Some(events) = workspace.phase_events.as_ref() {
11647                events.head[rank_index].record(&engine.stream())?;
11648            }
11649            engine.stream().wait(&workspace.ev_entry)?;
11650            let Nvfp4EpDeviceWorkspace {
11651                input_bf16,
11652                sel,
11653                route_w,
11654                ..
11655            } = &mut *workspace;
11656            engine.nvfp4_ep_stage_inputs(
11657                input_dev,
11658                selected_dev,
11659                route_weights_dev,
11660                &mut input_bf16[rank_index],
11661                &mut sel[rank_index],
11662                &mut route_w[rank_index],
11663                active_input_values,
11664                pairs,
11665                false,
11666            )?;
11667            if let Some(events) = workspace.phase_events.as_ref() {
11668                events.copy_done[rank_index].record(&engine.stream())?;
11669            }
11670            let rank = &experts.ranks[rank_index];
11671            let owner_start = rank.expert_range.start;
11672            let owner_end = rank.expert_range.end;
11673            engine.qmatvec_nvfp4_bf16_ep_dual_slots_into(
11674                &rank.gate,
11675                &rank.up,
11676                &workspace.sel[rank_index],
11677                &workspace.input_bf16[rank_index],
11678                &mut workspace.gate_out[rank_index],
11679                &mut workspace.up_out[rank_index],
11680                pairs,
11681                experts_per_token,
11682                experts.input_width,
11683                experts.expert_width,
11684                owner_start,
11685                owner_end,
11686                experts.gate_row_bytes,
11687                rank.gate_expert_bytes,
11688            )?;
11689            if let Some(events) = workspace.phase_events.as_ref() {
11690                events.gate_up_done[rank_index].record(&engine.stream())?;
11691            }
11692            engine.silu_mul_scaled_host_expf_bf16_ep_slots_into(
11693                &workspace.gate_out[rank_index],
11694                &workspace.up_out[rank_index],
11695                &rank.macros_gate,
11696                &rank.macros_up,
11697                &workspace.sel[rank_index],
11698                owner_start,
11699                owner_end,
11700                activation_limit,
11701                &mut workspace.activation_bf16[rank_index],
11702                experts.expert_width,
11703                pairs,
11704            )?;
11705            if let Some(events) = workspace.phase_events.as_ref() {
11706                events.activation_done[rank_index].record(&engine.stream())?;
11707            }
11708            if tokens > 1 && pair_down_enabled {
11709                engine.qmatvec_nvfp4_bf16_ep_down_pairs_raw(
11710                    &rank.down,
11711                    &workspace.sel[rank_index],
11712                    &workspace.activation_bf16[rank_index],
11713                    &rank.macros_down,
11714                    workspace.slot_rows_raw,
11715                    pairs,
11716                    experts.expert_width,
11717                    experts.input_width,
11718                    owner_start,
11719                    owner_end,
11720                    experts.down_row_bytes,
11721                    rank.down_expert_bytes,
11722                )?;
11723            } else {
11724                engine.qmatvec_nvfp4_bf16_ep_down_slots_raw(
11725                    &rank.down,
11726                    &workspace.sel[rank_index],
11727                    &workspace.activation_bf16[rank_index],
11728                    &rank.macros_down,
11729                    workspace.slot_rows_raw,
11730                    pairs,
11731                    experts.expert_width,
11732                    experts.input_width,
11733                    owner_start,
11734                    owner_end,
11735                    experts.down_row_bytes,
11736                    rank.down_expert_bytes,
11737                )?;
11738            }
11739            if let Some(events) = workspace.phase_events.as_ref() {
11740                events.down_done[rank_index].record(&engine.stream())?;
11741            }
11742            workspace.ev_rank[rank_index].record(&engine.stream())?;
11743        }
11744
11745        if let Some(pre_join) = pre_join.as_mut() {
11746            pre_join()?;
11747        }
11748        let issue_ns_this = started
11749            .as_ref()
11750            .map(|started| started.elapsed().as_nanos() as u64);
11751        let join_started = timing.then(std::time::Instant::now);
11752        let output = {
11753            let _main = e.gpu.enter_main()?;
11754            for event in &workspace.ev_rank {
11755                e.stream().wait(event)?;
11756            }
11757            let mut output = e.uninit(tokens * experts.input_width)?;
11758            e.axpy_rows_seq_tokens_into(
11759                &workspace.slot_rows,
11760                route_weights_dev,
11761                &mut output,
11762                experts.input_width,
11763                experts_per_token,
11764                tokens,
11765            )?;
11766            output
11767        };
11768
11769        if let Some(started) = started {
11770            use std::sync::atomic::Ordering;
11771            e.stream().synchronize()?;
11772            let elapsed = started.elapsed().as_nanos() as u64;
11773            let join_ns_this = join_started
11774                .expect("timing join starts with total timing")
11775                .elapsed()
11776                .as_nanos() as u64;
11777            let mut phase_max_ms = [0.0f32; 5];
11778            if let Some(events) = workspace.phase_events.as_ref() {
11779                for rank_index in 0..world {
11780                    let engine = &self.ranks[rank_index];
11781                    let _main = engine.gpu.enter_main()?;
11782                    phase_max_ms[0] = phase_max_ms[0]
11783                        .max(events.head[rank_index].elapsed_ms(&events.copy_done[rank_index])?);
11784                    phase_max_ms[1] = phase_max_ms[1].max(
11785                        events.copy_done[rank_index]
11786                            .elapsed_ms(&events.gate_up_done[rank_index])?,
11787                    );
11788                    phase_max_ms[2] = phase_max_ms[2].max(
11789                        events.gate_up_done[rank_index]
11790                            .elapsed_ms(&events.activation_done[rank_index])?,
11791                    );
11792                    phase_max_ms[3] = phase_max_ms[3].max(
11793                        events.activation_done[rank_index]
11794                            .elapsed_ms(&events.down_done[rank_index])?,
11795                    );
11796                    phase_max_ms[4] = phase_max_ms[4]
11797                        .max(events.head[rank_index].elapsed_ms(&events.down_done[rank_index])?);
11798                }
11799            }
11800            let phase_ns = phase_max_ms.map(|ms| (ms as f64 * 1.0e6) as u64);
11801            let ns = TIMING_NS.fetch_add(elapsed, Ordering::Relaxed) + elapsed;
11802            let issue_ns = ISSUE_NS.fetch_add(
11803                issue_ns_this.expect("timing issue starts with total timing"),
11804                Ordering::Relaxed,
11805            ) + issue_ns_this.expect("timing issue starts with total timing");
11806            let join_ns = JOIN_NS.fetch_add(join_ns_this, Ordering::Relaxed) + join_ns_this;
11807            let copy_ns = COPY_NS.fetch_add(phase_ns[0], Ordering::Relaxed) + phase_ns[0];
11808            let gate_up_ns = GATE_UP_NS.fetch_add(phase_ns[1], Ordering::Relaxed) + phase_ns[1];
11809            let activation_ns =
11810                ACTIVATION_NS.fetch_add(phase_ns[2], Ordering::Relaxed) + phase_ns[2];
11811            let down_ns = DOWN_NS.fetch_add(phase_ns[3], Ordering::Relaxed) + phase_ns[3];
11812            let rank_span_ns = RANK_SPAN_NS.fetch_add(phase_ns[4], Ordering::Relaxed) + phase_ns[4];
11813            let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
11814            if calls.is_multiple_of(430) {
11815                eprintln!(
11816                    "[nvfp4-ep-device-router-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
11817                    ns as f64 / 1.0e6,
11818                    ns as f64 / calls as f64 / 1.0e3,
11819                );
11820                eprintln!(
11821                    "[nvfp4-ep-device-router-phases] calls={calls} issue_us={:.1} \
11822                     join_us={:.1} rank_span_us={:.1} copy_us={:.1} gate_up_us={:.1} \
11823                     activation_us={:.1} down_us={:.1}",
11824                    issue_ns as f64 / calls as f64 / 1.0e3,
11825                    join_ns as f64 / calls as f64 / 1.0e3,
11826                    rank_span_ns as f64 / calls as f64 / 1.0e3,
11827                    copy_ns as f64 / calls as f64 / 1.0e3,
11828                    gate_up_ns as f64 / calls as f64 / 1.0e3,
11829                    activation_ns as f64 / calls as f64 / 1.0e3,
11830                    down_ns as f64 / calls as f64 / 1.0e3,
11831                );
11832            }
11833        }
11834        Ok(output)
11835    }
11836
11837    #[allow(clippy::too_many_arguments)]
11838    fn run_routed_experts_nvfp4_w4a8_device_routed(
11839        &self,
11840        experts: &ResidentNvfp4ExpertParallel,
11841        e: &Engine,
11842        input_dev: &crate::CudaSlice<f32>,
11843        selected_dev: &crate::CudaSlice<i32>,
11844        route_weights_dev: &crate::CudaSlice<f32>,
11845        workspace: &mut Nvfp4EpDeviceWorkspace,
11846        tokens: usize,
11847        experts_per_token: usize,
11848        activation_limit: Option<f32>,
11849        mut pre_join: Option<&mut dyn FnMut() -> Result<(), Box<dyn std::error::Error>>>,
11850    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
11851        static TIMING_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11852        static TIMING_CALLS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11853        static ISSUE_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11854        static JOIN_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11855        static COPY_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11856        static GATE_UP_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11857        static ACTIVATION_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11858        static DOWN_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11859        static RANK_SPAN_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
11860        let timing = std::env::var("MEMRA_STEP_TP_TIMING").as_deref() == Ok("1");
11861        let started = timing.then(std::time::Instant::now);
11862        let pairs = tokens
11863            .checked_mul(experts_per_token)
11864            .ok_or("W4A8 device-routed EP route count overflow")?;
11865        let input_values = tokens
11866            .checked_mul(experts.input_width)
11867            .ok_or("W4A8 device-routed EP input size overflow")?;
11868        let scope = parallel_ep_q8_scope()?.unwrap_or(ParallelEpQ8Scope::All);
11869        let gate_up_paired = parallel_ep_q8_gu_paired_enabled(true, Some(scope));
11870
11871        {
11872            let _main = e.gpu.enter_main()?;
11873            e.memset_zeros_view(
11874                &mut workspace
11875                    .slot_rows
11876                    .slice_mut(0..pairs * experts.input_width),
11877            )?;
11878            workspace.ev_entry.record(&e.stream())?;
11879        }
11880        for (rank_index, engine) in self.ranks.iter().enumerate() {
11881            let _main = engine.gpu.enter_main()?;
11882            if let Some(events) = workspace.phase_events.as_ref() {
11883                events.head[rank_index].record(&engine.stream())?;
11884            }
11885            engine.stream().wait(&workspace.ev_entry)?;
11886            let rank = &experts.ranks[rank_index];
11887            let owner_start = rank.expert_range.start;
11888            let owner_end = rank.expert_range.end;
11889            match scope {
11890                ParallelEpQ8Scope::All | ParallelEpQ8Scope::GateUp => {
11891                    engine.quantize_q8_1_into(
11892                        input_dev,
11893                        tokens,
11894                        experts.input_width,
11895                        &mut workspace.input_q8[rank_index],
11896                        &mut workspace.input_q8_scales[rank_index],
11897                    )?;
11898                    engine.moe_sel_w_mirror(
11899                        selected_dev,
11900                        route_weights_dev,
11901                        &mut workspace.sel[rank_index],
11902                        &mut workspace.route_w[rank_index],
11903                        pairs,
11904                    )?;
11905                    if let Some(events) = workspace.phase_events.as_ref() {
11906                        events.copy_done[rank_index].record(&engine.stream())?;
11907                    }
11908                    if gate_up_paired {
11909                        engine.qmatvec_nvfp4_q8_ep_paired_slots_into(
11910                            &rank.gate,
11911                            &rank.up,
11912                            &workspace.sel[rank_index],
11913                            &workspace.input_q8[rank_index],
11914                            &workspace.input_q8_scales[rank_index],
11915                            &mut workspace.gate_out[rank_index],
11916                            &mut workspace.up_out[rank_index],
11917                            pairs,
11918                            experts_per_token,
11919                            experts.input_width,
11920                            experts.expert_width,
11921                            owner_start,
11922                            owner_end,
11923                            experts.gate_row_bytes,
11924                            rank.gate_expert_bytes,
11925                        )?;
11926                    } else {
11927                        engine.qmatvec_nvfp4_q8_ep_dual_slots_into(
11928                            &rank.gate,
11929                            &rank.up,
11930                            &workspace.sel[rank_index],
11931                            &workspace.input_q8[rank_index],
11932                            &workspace.input_q8_scales[rank_index],
11933                            &mut workspace.gate_out[rank_index],
11934                            &mut workspace.up_out[rank_index],
11935                            pairs,
11936                            experts_per_token,
11937                            experts.input_width,
11938                            experts.expert_width,
11939                            owner_start,
11940                            owner_end,
11941                            experts.gate_row_bytes,
11942                            rank.gate_expert_bytes,
11943                        )?;
11944                    }
11945                }
11946                ParallelEpQ8Scope::Down => {
11947                    engine.nvfp4_ep_stage_inputs(
11948                        input_dev,
11949                        selected_dev,
11950                        route_weights_dev,
11951                        &mut workspace.input_bf16[rank_index],
11952                        &mut workspace.sel[rank_index],
11953                        &mut workspace.route_w[rank_index],
11954                        input_values,
11955                        pairs,
11956                        false,
11957                    )?;
11958                    if let Some(events) = workspace.phase_events.as_ref() {
11959                        events.copy_done[rank_index].record(&engine.stream())?;
11960                    }
11961                    engine.qmatvec_nvfp4_bf16_ep_dual_slots_into(
11962                        &rank.gate,
11963                        &rank.up,
11964                        &workspace.sel[rank_index],
11965                        &workspace.input_bf16[rank_index],
11966                        &mut workspace.gate_out[rank_index],
11967                        &mut workspace.up_out[rank_index],
11968                        pairs,
11969                        experts_per_token,
11970                        experts.input_width,
11971                        experts.expert_width,
11972                        owner_start,
11973                        owner_end,
11974                        experts.gate_row_bytes,
11975                        rank.gate_expert_bytes,
11976                    )?;
11977                }
11978            }
11979            if let Some(events) = workspace.phase_events.as_ref() {
11980                events.gate_up_done[rank_index].record(&engine.stream())?;
11981            }
11982            match scope {
11983                ParallelEpQ8Scope::All | ParallelEpQ8Scope::Down => {
11984                    engine.silu_mul_scaled_host_expf_q8_ep_slots_into(
11985                        &workspace.gate_out[rank_index],
11986                        &workspace.up_out[rank_index],
11987                        &rank.macros_gate,
11988                        &rank.macros_up,
11989                        &workspace.sel[rank_index],
11990                        owner_start,
11991                        owner_end,
11992                        activation_limit,
11993                        &mut workspace.activation_q8[rank_index],
11994                        &mut workspace.activation_q8_scales[rank_index],
11995                        experts.expert_width,
11996                        pairs,
11997                    )?;
11998                    if let Some(events) = workspace.phase_events.as_ref() {
11999                        events.activation_done[rank_index].record(&engine.stream())?;
12000                    }
12001                    engine.qmatvec_nvfp4_q8_ep_down_slots_raw(
12002                        &rank.down,
12003                        &workspace.sel[rank_index],
12004                        &workspace.activation_q8[rank_index],
12005                        &workspace.activation_q8_scales[rank_index],
12006                        &rank.macros_down,
12007                        workspace.slot_rows_raw,
12008                        pairs,
12009                        experts.expert_width,
12010                        experts.input_width,
12011                        owner_start,
12012                        owner_end,
12013                        experts.down_row_bytes,
12014                        rank.down_expert_bytes,
12015                    )?;
12016                }
12017                ParallelEpQ8Scope::GateUp => {
12018                    engine.silu_mul_scaled_host_expf_bf16_ep_slots_into(
12019                        &workspace.gate_out[rank_index],
12020                        &workspace.up_out[rank_index],
12021                        &rank.macros_gate,
12022                        &rank.macros_up,
12023                        &workspace.sel[rank_index],
12024                        owner_start,
12025                        owner_end,
12026                        activation_limit,
12027                        &mut workspace.activation_bf16[rank_index],
12028                        experts.expert_width,
12029                        pairs,
12030                    )?;
12031                    if let Some(events) = workspace.phase_events.as_ref() {
12032                        events.activation_done[rank_index].record(&engine.stream())?;
12033                    }
12034                    engine.qmatvec_nvfp4_bf16_ep_down_slots_raw(
12035                        &rank.down,
12036                        &workspace.sel[rank_index],
12037                        &workspace.activation_bf16[rank_index],
12038                        &rank.macros_down,
12039                        workspace.slot_rows_raw,
12040                        pairs,
12041                        experts.expert_width,
12042                        experts.input_width,
12043                        owner_start,
12044                        owner_end,
12045                        experts.down_row_bytes,
12046                        rank.down_expert_bytes,
12047                    )?;
12048                }
12049            }
12050            if let Some(events) = workspace.phase_events.as_ref() {
12051                events.down_done[rank_index].record(&engine.stream())?;
12052            }
12053            workspace.ev_rank[rank_index].record(&engine.stream())?;
12054        }
12055
12056        if let Some(pre_join) = pre_join.as_mut() {
12057            pre_join()?;
12058        }
12059        let issue_ns_this = started
12060            .as_ref()
12061            .map(|started| started.elapsed().as_nanos() as u64);
12062        let join_started = timing.then(std::time::Instant::now);
12063        let output = {
12064            let _main = e.gpu.enter_main()?;
12065            for event in &workspace.ev_rank {
12066                e.stream().wait(event)?;
12067            }
12068            let mut output = e.uninit(input_values)?;
12069            e.axpy_rows_seq_tokens_into(
12070                &workspace.slot_rows,
12071                route_weights_dev,
12072                &mut output,
12073                experts.input_width,
12074                experts_per_token,
12075                tokens,
12076            )?;
12077            output
12078        };
12079        if let Some(started) = started {
12080            use std::sync::atomic::Ordering;
12081            e.stream().synchronize()?;
12082            let elapsed = started.elapsed().as_nanos() as u64;
12083            let join_ns_this = join_started
12084                .expect("timing join starts with total timing")
12085                .elapsed()
12086                .as_nanos() as u64;
12087            let mut phase_max_ms = [0.0f32; 5];
12088            if let Some(events) = workspace.phase_events.as_ref() {
12089                for rank_index in 0..self.ranks.len() {
12090                    let engine = &self.ranks[rank_index];
12091                    let _main = engine.gpu.enter_main()?;
12092                    phase_max_ms[0] = phase_max_ms[0]
12093                        .max(events.head[rank_index].elapsed_ms(&events.copy_done[rank_index])?);
12094                    phase_max_ms[1] = phase_max_ms[1].max(
12095                        events.copy_done[rank_index]
12096                            .elapsed_ms(&events.gate_up_done[rank_index])?,
12097                    );
12098                    phase_max_ms[2] = phase_max_ms[2].max(
12099                        events.gate_up_done[rank_index]
12100                            .elapsed_ms(&events.activation_done[rank_index])?,
12101                    );
12102                    phase_max_ms[3] = phase_max_ms[3].max(
12103                        events.activation_done[rank_index]
12104                            .elapsed_ms(&events.down_done[rank_index])?,
12105                    );
12106                    phase_max_ms[4] = phase_max_ms[4]
12107                        .max(events.head[rank_index].elapsed_ms(&events.down_done[rank_index])?);
12108                }
12109            }
12110            let phase_ns = phase_max_ms.map(|ms| (ms as f64 * 1.0e6) as u64);
12111            let ns = TIMING_NS.fetch_add(elapsed, Ordering::Relaxed) + elapsed;
12112            let issue_ns = ISSUE_NS.fetch_add(
12113                issue_ns_this.expect("timing issue starts with total timing"),
12114                Ordering::Relaxed,
12115            ) + issue_ns_this.expect("timing issue starts with total timing");
12116            let join_ns = JOIN_NS.fetch_add(join_ns_this, Ordering::Relaxed) + join_ns_this;
12117            let copy_ns = COPY_NS.fetch_add(phase_ns[0], Ordering::Relaxed) + phase_ns[0];
12118            let gate_up_ns = GATE_UP_NS.fetch_add(phase_ns[1], Ordering::Relaxed) + phase_ns[1];
12119            let activation_ns =
12120                ACTIVATION_NS.fetch_add(phase_ns[2], Ordering::Relaxed) + phase_ns[2];
12121            let down_ns = DOWN_NS.fetch_add(phase_ns[3], Ordering::Relaxed) + phase_ns[3];
12122            let rank_span_ns = RANK_SPAN_NS.fetch_add(phase_ns[4], Ordering::Relaxed) + phase_ns[4];
12123            let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
12124            if calls.is_multiple_of(430) {
12125                eprintln!(
12126                    "[nvfp4-ep-q8-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
12127                    ns as f64 / 1.0e6,
12128                    ns as f64 / calls as f64 / 1.0e3,
12129                );
12130                eprintln!(
12131                    "[nvfp4-ep-q8-phases] calls={calls} issue_us={:.1} join_us={:.1} \
12132                     rank_span_us={:.1} copy_us={:.1} gate_up_us={:.1} \
12133                     activation_us={:.1} down_us={:.1}",
12134                    issue_ns as f64 / calls as f64 / 1.0e3,
12135                    join_ns as f64 / calls as f64 / 1.0e3,
12136                    rank_span_ns as f64 / calls as f64 / 1.0e3,
12137                    copy_ns as f64 / calls as f64 / 1.0e3,
12138                    gate_up_ns as f64 / calls as f64 / 1.0e3,
12139                    activation_ns as f64 / calls as f64 / 1.0e3,
12140                    down_ns as f64 / calls as f64 / 1.0e3,
12141                );
12142            }
12143        }
12144        static LOGGED: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
12145        if !LOGGED.swap(true, std::sync::atomic::Ordering::Relaxed) {
12146            let (expert_input, post_activation, numeric_class) = match scope {
12147                ParallelEpQ8Scope::All => ("q8_1", "q8_1", "w4a8-internal"),
12148                ParallelEpQ8Scope::GateUp => ("q8_1", "bf16", "w4a8-gate-up-internal"),
12149                ParallelEpQ8Scope::Down => ("bf16", "q8_1", "w4a8-down-internal"),
12150            };
12151            eprintln!(
12152                "[parallel-ep-q8] devices={:?} tokens={tokens} scope={} \
12153                 expert_input={expert_input} post_activation={post_activation} \
12154                 gate_up_schedule={} \
12155                 external_boundary=bf16 numeric_class={numeric_class} \
12156                 host_expf=true accumulation=token-slot-order performance_claim=false",
12157                self.devices,
12158                scope.label(),
12159                if gate_up_paired {
12160                    "paired-cta"
12161                } else {
12162                    "separate-cta"
12163                },
12164            );
12165        }
12166        Ok(output)
12167    }
12168
12169    /// Device-resident routed NVFP4 expert program (decode shape, t=1 rows). The geometry gift
12170    /// this exploits: gate/up column halves land on the SAME rank that owns the matching down
12171    /// canonical shard (act[rank r] is exactly down-shard r's input-column window), so the whole
12172    /// expert interior — gate, up, macro-scaled SwiGLU, down partial, route-weighted accumulate —
12173    /// runs rank-local with ZERO cross-rank transfer. Per (token, layer): one input upload per
12174    /// rank, one fenced peer copy of the remote accumulator, one root add, one readback.
12175    ///
12176    /// Numeric class: device silu (silu_mul_scaled) with gate/up macros folded as gs/us and the
12177    /// down macro folded into the accumulate scalar (weight * macro_down — exact, both are
12178    /// per-expert constants). This matches the owning-stage MoE dev-path semantics, NOT the
12179    /// host-canonical program bit-for-bit; gate it with argmax + relative bounds against the
12180    /// host-canonical oracle, and with repeat determinism against itself.
12181    /// Clamped layers refuse (they stay on the EP program).
12182    pub fn run_tensor_parallel_routes_nvfp4_device(
12183        &self,
12184        experts: &ResidentNvfp4TensorParallel,
12185        input: &[f32],
12186        selected: &[usize],
12187        route_weights: &[f32],
12188        experts_per_token: usize,
12189        activation_limit: Option<f32>,
12190    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
12191        validate_activations(input, 1, experts.input_width)?;
12192        if selected.len() != experts_per_token || route_weights.len() != experts_per_token {
12193            return Err(format!(
12194                "NVFP4 device routes selected={} weights={} != experts/token {experts_per_token}",
12195                selected.len(),
12196                route_weights.len(),
12197            )
12198            .into());
12199        }
12200        if !route_weights.iter().all(|weight| weight.is_finite()) {
12201            return Err("NVFP4 device route weights contain a non-finite value".into());
12202        }
12203        let world = self.ranks.len();
12204        if world != NVFP4_CANONICAL_ROW_SHARDS {
12205            return Err(format!(
12206                "NVFP4 device routes require world == canonical shard grid \
12207                 ({NVFP4_CANONICAL_ROW_SHARDS}), got {world}"
12208            )
12209            .into());
12210        }
12211        let local_out = experts.expert_width / world;
12212
12213        // MEMRA_STEP_TP_TIMING=1: cumulative wall-clock of this program, printed every 430 calls
12214        // (~one 43-layer decode step's worth) so a bench run decomposes expert-program time vs
12215        // everything else without Nsight.
12216        static TIMING_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
12217        static TIMING_CALLS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
12218        let timing = std::env::var("MEMRA_STEP_TP_TIMING").as_deref() == Ok("1");
12219        let started = timing.then(std::time::Instant::now);
12220
12221        let n_sel = experts_per_token;
12222        let mut workspace_guard = experts
12223            .device_workspace
12224            .lock()
12225            .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
12226        if workspace_guard.is_none() {
12227            let mut gate_out = Vec::with_capacity(world);
12228            let mut up_out = Vec::with_capacity(world);
12229            let mut act_q = Vec::with_capacity(world);
12230            let mut act_d = Vec::with_capacity(world);
12231            let mut sel = Vec::with_capacity(world);
12232            let mut partial = Vec::with_capacity(world);
12233            let mut accumulator = Vec::with_capacity(world);
12234            let mut combine_w = Vec::with_capacity(world);
12235            let mut route_w = Vec::with_capacity(world);
12236            let mut in_q = Vec::with_capacity(world);
12237            let mut in_d = Vec::with_capacity(world);
12238            let mut input = Vec::with_capacity(world);
12239            let mut ev_rank = Vec::with_capacity(world);
12240            let moe_direct = moe_direct_on();
12241            for (rank, engine) in self.ranks.iter().enumerate() {
12242                let _main = engine.gpu.enter_main()?;
12243                gate_out.push(engine.uninit(n_sel * local_out)?);
12244                up_out.push(engine.uninit(n_sel * local_out)?);
12245                act_q.push(engine.uninit_i8(n_sel * local_out)?);
12246                act_d.push(engine.uninit(n_sel * local_out / 32)?);
12247                sel.push(engine.htod_i32(&vec![0i32; n_sel])?);
12248                partial.push(engine.uninit(n_sel * experts.input_width)?);
12249                // Direct join: peer accumulators live on ROOT (single P2P store pass).
12250                if moe_direct && rank != 0 {
12251                    let root = &self.ranks[0];
12252                    let _root_main = root.gpu.enter_main()?;
12253                    accumulator.push(root.zeros(experts.input_width)?);
12254                } else {
12255                    accumulator.push(engine.zeros(experts.input_width)?);
12256                }
12257                combine_w.push(engine.htod(&vec![0.0f32; n_sel])?);
12258                route_w.push(engine.htod(&vec![0.0f32; n_sel])?);
12259                in_q.push(engine.uninit_i8(experts.input_width)?);
12260                in_d.push(engine.uninit(experts.input_width / 32)?);
12261                input.push(engine.uninit(experts.input_width)?);
12262                ev_rank.push(engine.ctx().new_event(None)?);
12263            }
12264            let root = &self.ranks[0];
12265            let _main = root.gpu.enter_main()?;
12266            *workspace_guard = Some(Nvfp4DeviceRoutesWorkspace {
12267                prestaged: false,
12268                rank1_routed: false,
12269                ev_input: None,
12270                fence_flags_raw: 0,
12271                fence_ticket: 0,
12272                gate_out,
12273                up_out,
12274                act_q,
12275                act_d,
12276                sel,
12277                partial,
12278                accumulator,
12279                combine_w,
12280                route_w,
12281                in_q,
12282                in_d,
12283                dev_route_e: None,
12284                in_stage_e: None,
12285                out_stage_e: None,
12286                routes_graph: None,
12287                raw_dev_route_e: None,
12288                raw_combine: None,
12289                raw_input: Vec::new(),
12290                raw_sel: Vec::new(),
12291                raw_route_w: Vec::new(),
12292                remote: root.uninit(experts.input_width)?,
12293                combined: root.uninit(experts.input_width)?,
12294                n_sel,
12295                input,
12296                ev_rank,
12297                ev_done: Some(root.ctx().new_event(None)?),
12298                ev_entry: None,
12299            });
12300        }
12301        let workspace = workspace_guard
12302            .as_mut()
12303            .expect("NVFP4 device routes workspace initialized above");
12304        if workspace.n_sel != n_sel {
12305            return Err(format!(
12306                "NVFP4 device routes experts/token changed: workspace {} != call {n_sel}",
12307                workspace.n_sel
12308            )
12309            .into());
12310        }
12311        for &expert in selected {
12312            if expert >= experts.expert_count {
12313                return Err(format!(
12314                    "NVFP4 device selected expert {expert} outside 0..{}",
12315                    experts.expert_count
12316                )
12317                .into());
12318            }
12319        }
12320        let sel_i32 = selected
12321            .iter()
12322            .map(|&expert| expert as i32)
12323            .collect::<Vec<_>>();
12324
12325        // BATCHED program (2026-08-20): per rank, ONE launch per sweep (gate, up, SwiGLU,
12326        // down) covers every selected expert via the selection array and the contiguous bank —
12327        // the per-expert launch loop was pure host latency (~100 sequential launches/layer,
12328        // 291us wall for ~35us of arithmetic). Per (expert, row) the kernels are bit-identical
12329        // to the per-expert forms, and the route-weight axpy chain keeps its exact sequential
12330        // accumulation order — the program's values are unchanged.
12331        for (rank_index, engine) in self.ranks.iter().enumerate() {
12332            let _main = engine.gpu.enter_main()?;
12333            let device_input = engine.htod(input)?;
12334            let Nvfp4DeviceRoutesWorkspace { in_q, in_d, .. } = &mut *workspace;
12335            engine.quantize_q8_1_into(
12336                &device_input,
12337                1,
12338                experts.input_width,
12339                &mut in_q[rank_index],
12340                &mut in_d[rank_index],
12341            )?;
12342            // device_input frees on this rank's stream after the quantize — same-stream order.
12343        }
12344        self.nvfp4_routes_batched_sweeps(
12345            experts,
12346            workspace,
12347            selected,
12348            route_weights,
12349            &sel_i32,
12350            local_out,
12351            n_sel,
12352            activation_limit,
12353            false,
12354        )?;
12355
12356        // Combine: fence the remote shard's producer stream, peer-copy its accumulator to root,
12357        // reduce in canonical shard order, read back once.
12358        let root = &self.ranks[0];
12359        for engine in &self.ranks[1..] {
12360            let _main = engine.gpu.enter_main()?;
12361            engine.stream().synchronize()?;
12362        }
12363        let _main = root.gpu.enter_main()?;
12364        root.stream()
12365            .memcpy_dtod(&workspace.accumulator[1], &mut workspace.remote)?;
12366        root.add(
12367            &workspace.accumulator[0],
12368            &workspace.remote,
12369            &mut workspace.combined,
12370            experts.input_width,
12371        )?;
12372        let output = root.dtoh(&workspace.combined)?;
12373        if let Some(started) = started {
12374            use std::sync::atomic::Ordering;
12375            let ns = TIMING_NS.fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
12376                + started.elapsed().as_nanos() as u64;
12377            let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
12378            if calls.is_multiple_of(430) {
12379                eprintln!(
12380                    "[nvfp4-dev-routes-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
12381                    ns as f64 / 1.0e6,
12382                    ns as f64 / calls as f64 / 1.0e3,
12383                );
12384            }
12385        }
12386        Ok(output)
12387    }
12388
12389    /// The shared batched sweeps of the device routes program: per rank, upload the selection,
12390    /// reset the accumulator, run the gate/up/SwiGLU/down batched launches, then the
12391    /// route-weight axpy chain in exact sequential per-pair order. Every op queues on the
12392    /// owning rank's stream; callers own input acquisition and the combine.
12393    #[allow(clippy::too_many_arguments)]
12394    fn nvfp4_routes_batched_sweeps(
12395        &self,
12396        experts: &ResidentNvfp4TensorParallel,
12397        workspace: &mut Nvfp4DeviceRoutesWorkspace,
12398        selected: &[usize],
12399        route_weights: &[f32],
12400        sel_i32: &[i32],
12401        local_out: usize,
12402        n_sel: usize,
12403        activation_limit: Option<f32>,
12404        device_routed: bool,
12405    ) -> Result<(), Box<dyn std::error::Error>> {
12406        for rank_index in 0..self.ranks.len() {
12407            self.nvfp4_routes_batched_sweeps_rank(
12408                experts,
12409                workspace,
12410                selected,
12411                route_weights,
12412                sel_i32,
12413                local_out,
12414                n_sel,
12415                activation_limit,
12416                device_routed,
12417                rank_index,
12418            )?;
12419        }
12420        Ok(())
12421    }
12422
12423    /// One rank's sweeps (the per-rank body of `nvfp4_routes_batched_sweeps`) — separated so
12424    /// the graph door can capture each rank's segment on its own stream.
12425    #[allow(clippy::too_many_arguments)]
12426    fn nvfp4_routes_batched_sweeps_rank(
12427        &self,
12428        experts: &ResidentNvfp4TensorParallel,
12429        workspace: &mut Nvfp4DeviceRoutesWorkspace,
12430        selected: &[usize],
12431        route_weights: &[f32],
12432        sel_i32: &[i32],
12433        local_out: usize,
12434        n_sel: usize,
12435        activation_limit: Option<f32>,
12436        device_routed: bool,
12437        rank_index: usize,
12438    ) -> Result<(), Box<dyn std::error::Error>> {
12439        {
12440            let engine = &self.ranks[rank_index];
12441            let _main = engine.gpu.enter_main()?;
12442            if !device_routed {
12443                engine.htod_i32_into(&mut workspace.sel[rank_index], sel_i32)?;
12444                // Folded combine weights (route_weight x down macro) — one 40-byte upload
12445                // replaces the accumulator reset + n_sel sequential axpy launches below.
12446                let folded = (0..n_sel)
12447                    .map(|pair| route_weights[pair] * experts.macros_down[selected[pair]])
12448                    .collect::<Vec<_>>();
12449                let mut view = workspace.combine_w[rank_index].slice_mut(0..n_sel);
12450                engine.stream().memcpy_htod(&folded, &mut view)?;
12451            }
12452            let gate_bank = &experts.gate[rank_index];
12453            let up_bank = &experts.up[rank_index];
12454            let (aq, ad) = (&workspace.in_q[rank_index], &workspace.in_d[rank_index]);
12455            engine.qmatvec_nvfp4_sel_into(
12456                &gate_bank.bank,
12457                &workspace.sel[rank_index],
12458                aq,
12459                ad,
12460                &mut workspace.gate_out[rank_index],
12461                n_sel,
12462                gate_bank.in_features,
12463                gate_bank.local_out,
12464                gate_bank.row_bytes,
12465                gate_bank.expert_bytes,
12466                0,
12467                0,
12468                gate_bank.slot_major,
12469            )?;
12470            engine.qmatvec_nvfp4_sel_into(
12471                &up_bank.bank,
12472                &workspace.sel[rank_index],
12473                aq,
12474                ad,
12475                &mut workspace.up_out[rank_index],
12476                n_sel,
12477                up_bank.in_features,
12478                up_bank.local_out,
12479                up_bank.row_bytes,
12480                up_bank.expert_bytes,
12481                0,
12482                0,
12483                up_bank.slot_major,
12484            )?;
12485            // Fused macro-scaled SwiGLU that EMITS q8_1 directly — down consumes it with no
12486            // separate quantize launch. act[rank] IS down canonical shard `rank_index`'s
12487            // input-column window (the geometry gift; see the method doc).
12488            {
12489                let Nvfp4DeviceRoutesWorkspace {
12490                    gate_out,
12491                    up_out,
12492                    sel,
12493                    act_q,
12494                    act_d,
12495                    ..
12496                } = &mut *workspace;
12497                engine.silu_mul_scaled_q8_1_sel_into(
12498                    &gate_out[rank_index],
12499                    &up_out[rank_index],
12500                    &experts.macros_gate_dev[rank_index],
12501                    &experts.macros_up_dev[rank_index],
12502                    &sel[rank_index],
12503                    activation_limit,
12504                    &mut act_q[rank_index],
12505                    &mut act_d[rank_index],
12506                    local_out,
12507                    n_sel,
12508                )?;
12509            }
12510            let shard = &experts.down[rank_index];
12511            if shard.device_rank != rank_index || shard.local_in != local_out {
12512                return Err(
12513                    "NVFP4 device routes: down canonical shard placement drifted from \
12514                     the gate/up column split"
12515                        .into(),
12516                );
12517            }
12518            // PROGRAM 3 (`MEMRA_NVFP4_SEL_DOWN8`): the down sweep and the route-weight combine
12519            // in ONE launch, one warp per SLOT instead of one warp per (row, slot), and the
12520            // `n_sel x out_f` partial round trip gone. Device-routed only — the host-routed arm
12521            // folds the macro into `combine_w` instead of reading `md` on device — and
12522            // slot-major only, read off the shard. `nsb <= 32` is the fit-block class the reduce
12523            // identity is argued at. Its own door, priced LAST and only on green gates for the
12524            // programs beneath it (lane mandate, milestone 5).
12525            let down8 =
12526                device_routed && sel_down8_on() && shard.slot_major && (shard.local_in >> 5) <= 32;
12527            // ENGAGEMENT RECEIPT for PROGRAM 3, one line per distinct combo. `device_routed`
12528            // and `nsb <= 32` are printed because they are the two eligibility conditions that
12529            // can silently disqualify the arm on a geometry or a route the operator did not
12530            // expect -- exactly the case where a flat perf row would be misread as "no win".
12531            {
12532                static SEEN_D8: std::sync::Mutex<Vec<(bool, bool, bool, bool)>> =
12533                    std::sync::Mutex::new(Vec::new());
12534                let combo = (down8, sel_down8_on(), device_routed, shard.slot_major);
12535                let mut seen = SEEN_D8.lock().unwrap();
12536                if !seen.contains(&combo) {
12537                    seen.push(combo);
12538                    // `door_source` is what makes this line a DEFAULT-flip receipt rather than
12539                    // only an engagement receipt: `door=true door_source=default-on` is the
12540                    // flip doing the work, `env=1` is a recipe doing it, and
12541                    // `down8=false door=true` is the silent-no-op shape that PROGRAM 1's
12542                    // default exists to prevent.
12543                    eprintln!(
12544                        "[nvfp4-sweep] down8={} door={} door_source={} device_routed={} \
12545                         slot_major={} nsb={} in_class={} n_sel={n_sel}",
12546                        down8,
12547                        sel_down8_on(),
12548                        sel_down8_source().1,
12549                        device_routed,
12550                        shard.slot_major,
12551                        shard.local_in >> 5,
12552                        (shard.local_in >> 5) <= 32
12553                    );
12554                }
12555            }
12556            if down8 {
12557                let Nvfp4DeviceRoutesWorkspace {
12558                    sel,
12559                    act_q,
12560                    act_d,
12561                    route_w,
12562                    accumulator,
12563                    ..
12564                } = &mut *workspace;
12565                engine.qmatvec_nvfp4_sel_down8_into(
12566                    &shard.bank,
12567                    &sel[rank_index],
12568                    &act_q[rank_index],
12569                    &act_d[rank_index],
12570                    &route_w[rank_index],
12571                    &experts.macros_down_dev[rank_index],
12572                    &mut accumulator[rank_index],
12573                    n_sel,
12574                    shard.local_in,
12575                    shard.out_features,
12576                    shard.row_bytes,
12577                    shard.expert_bytes,
12578                    local_out,
12579                    local_out / 32,
12580                    shard.slot_major,
12581                )?;
12582            } else {
12583                let Nvfp4DeviceRoutesWorkspace {
12584                    sel,
12585                    act_q,
12586                    act_d,
12587                    partial,
12588                    ..
12589                } = &mut *workspace;
12590                engine.qmatvec_nvfp4_sel_into(
12591                    &shard.bank,
12592                    &sel[rank_index],
12593                    &act_q[rank_index],
12594                    &act_d[rank_index],
12595                    &mut partial[rank_index],
12596                    n_sel,
12597                    shard.local_in,
12598                    shard.out_features,
12599                    shard.row_bytes,
12600                    shard.expert_bytes,
12601                    local_out,
12602                    local_out / 32,
12603                    shard.slot_major,
12604                )?;
12605            }
12606            // Route-weight accumulation: axpy_rows_seq keeps the exact sequential per-pair
12607            // FP chain of the reset + n_sel axpy launches in ONE launch. Device-routed calls
12608            // fold the down macro in-kernel from the device selection. (down8 already produced
12609            // the accumulator inside the sweep.)
12610            if !down8 {
12611                let Nvfp4DeviceRoutesWorkspace {
12612                    partial,
12613                    combine_w,
12614                    route_w,
12615                    sel,
12616                    accumulator,
12617                    ..
12618                } = &mut *workspace;
12619                if device_routed {
12620                    engine.axpy_rows_seq_md_into(
12621                        &partial[rank_index],
12622                        &route_w[rank_index],
12623                        &experts.macros_down_dev[rank_index],
12624                        &sel[rank_index],
12625                        &mut accumulator[rank_index],
12626                        experts.input_width,
12627                        n_sel,
12628                    )?;
12629                } else {
12630                    engine.axpy_rows_seq_into(
12631                        &partial[rank_index],
12632                        &combine_w[rank_index],
12633                        &mut accumulator[rank_index],
12634                        experts.input_width,
12635                        n_sel,
12636                    )?;
12637                }
12638            }
12639        }
12640        Ok(())
12641    }
12642
12643    /// Device-IO twin of `run_tensor_parallel_routes_nvfp4_device`: the layer input arrives as
12644    /// a device row on the model engine `e` and the combined output returns as a fresh
12645    /// `e`-context row — no host round-trip, no host stream sync. Ordering is evented (the v2
12646    /// attention discipline): `ev_entry` is recorded on `e`'s stream AFTER the caller queued
12647    /// the input's producer; each rank waits it before its peer read; the root reduce waits
12648    /// every rank's done event; `e` waits the root's done event before copying out. The
12649    /// program bytes are identical to the host-IO twin — dtoh/htod and dtod preserve f32 bits.
12650    #[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
12651    pub fn run_tensor_parallel_routes_nvfp4_device_io(
12652        &self,
12653        experts: &ResidentNvfp4TensorParallel,
12654        e: &Engine,
12655        input_dev: &crate::CudaSlice<f32>,
12656        selected: &[usize],
12657        route_weights: &[f32],
12658        experts_per_token: usize,
12659        activation_limit: Option<f32>,
12660    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
12661        if input_dev.len() != experts.input_width {
12662            return Err(format!(
12663                "NVFP4 device-io routes input {} != width {}",
12664                input_dev.len(),
12665                experts.input_width
12666            )
12667            .into());
12668        }
12669        if selected.len() != experts_per_token || route_weights.len() != experts_per_token {
12670            return Err(format!(
12671                "NVFP4 device-io routes selected={} weights={} != experts/token {experts_per_token}",
12672                selected.len(),
12673                route_weights.len(),
12674            )
12675            .into());
12676        }
12677        if !route_weights.iter().all(|weight| weight.is_finite()) {
12678            return Err("NVFP4 device route weights contain a non-finite value".into());
12679        }
12680        let world = self.ranks.len();
12681        if world != NVFP4_CANONICAL_ROW_SHARDS {
12682            return Err(format!(
12683                "NVFP4 device routes require world == canonical shard grid \
12684                 ({NVFP4_CANONICAL_ROW_SHARDS}), got {world}"
12685            )
12686            .into());
12687        }
12688        let local_out = experts.expert_width / world;
12689        let n_sel = experts_per_token;
12690
12691        static TIMING_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
12692        static TIMING_CALLS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
12693        let timing = std::env::var("MEMRA_STEP_TP_TIMING").as_deref() == Ok("1");
12694        let started = timing.then(std::time::Instant::now);
12695
12696        let mut workspace_guard = experts
12697            .device_workspace
12698            .lock()
12699            .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
12700        if workspace_guard.is_none() {
12701            drop(workspace_guard);
12702            // Build through the host-IO ensure path exactly once: run it with a zero input.
12703            // Cheaper than duplicating the init; the first real call overwrites everything.
12704            let zero = vec![0.0f32; experts.input_width];
12705            let zero_sel = vec![0usize; n_sel];
12706            let zero_w = vec![0.0f32; n_sel];
12707            let _ = self.run_tensor_parallel_routes_nvfp4_device(
12708                experts,
12709                &zero,
12710                &zero_sel,
12711                &zero_w,
12712                n_sel,
12713                activation_limit,
12714            )?;
12715            workspace_guard = experts
12716                .device_workspace
12717                .lock()
12718                .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
12719        }
12720        let workspace = workspace_guard
12721            .as_mut()
12722            .expect("NVFP4 device routes workspace initialized above");
12723        if workspace.n_sel != n_sel {
12724            return Err(format!(
12725                "NVFP4 device routes experts/token changed: workspace {} != call {n_sel}",
12726                workspace.n_sel
12727            )
12728            .into());
12729        }
12730        for &expert in selected {
12731            if expert >= experts.expert_count {
12732                return Err(format!(
12733                    "NVFP4 device selected expert {expert} outside 0..{}",
12734                    experts.expert_count
12735                )
12736                .into());
12737            }
12738        }
12739        let sel_i32 = selected
12740            .iter()
12741            .map(|&expert| expert as i32)
12742            .collect::<Vec<_>>();
12743
12744        // Entry fence: e's stream position covers the input's producer AND every consumer of
12745        // the previous layer's output (queued on e's stream before this call), guarding the
12746        // workspace reuse exactly like the v2 attention driver.
12747        if let Some((_, device)) = workspace.ev_entry.as_ref() {
12748            if *device != e.ctx().ordinal() {
12749                return Err("NVFP4 device-io routes engine changed".into());
12750            }
12751        } else {
12752            let _main = e.gpu.enter_main()?;
12753            workspace.ev_entry = Some((e.ctx().new_event(None)?, e.ctx().ordinal()));
12754        }
12755        {
12756            let _main = e.gpu.enter_main()?;
12757            let (ev_entry, _) = workspace.ev_entry.as_ref().expect("entry event set above");
12758            ev_entry.record(&e.stream())?;
12759        }
12760        for (rank_index, engine) in self.ranks.iter().enumerate() {
12761            let _main = engine.gpu.enter_main()?;
12762            let (ev_entry, _) = workspace.ev_entry.as_ref().expect("entry event set above");
12763            engine.stream().wait(ev_entry)?;
12764            {
12765                let mut destination = workspace.input[rank_index].slice_mut(0..experts.input_width);
12766                engine
12767                    .stream()
12768                    .memcpy_dtod(&input_dev.slice(0..experts.input_width), &mut destination)?;
12769            }
12770            {
12771                let Nvfp4DeviceRoutesWorkspace {
12772                    input, in_q, in_d, ..
12773                } = &mut *workspace;
12774                engine.quantize_q8_1_into(
12775                    &input[rank_index],
12776                    1,
12777                    experts.input_width,
12778                    &mut in_q[rank_index],
12779                    &mut in_d[rank_index],
12780                )?;
12781            }
12782        }
12783        self.nvfp4_routes_batched_sweeps(
12784            experts,
12785            workspace,
12786            selected,
12787            route_weights,
12788            &sel_i32,
12789            local_out,
12790            n_sel,
12791            activation_limit,
12792            false,
12793        )?;
12794
12795        // Evented combine: rank done events replace the host stream syncs, the reduce runs on
12796        // the root stream in canonical shard order, and e copies the combined row out behind
12797        // the root's done event.
12798        // rank0 == root: its own stream order already covers its sweep; only the PEER
12799        // ranks need the record/wait pair (host-op diet at the #1 eager seam, 2026-08-21).
12800        for (rank_index, engine) in self.ranks.iter().enumerate().skip(1) {
12801            let _main = engine.gpu.enter_main()?;
12802            workspace.ev_rank[rank_index].record(&engine.stream())?;
12803        }
12804        if moe_direct_on() && self.ranks.len() == 2 {
12805            // DIRECT JOIN: rank1's accumulator is root-resident (P2P single-store pass);
12806            // rank0's is root-stream-ordered. One root event + rank1's own event order
12807            // the model engine's single add — same operand order as root's add
12808            // (accumulator[0] + accumulator[1]): BIT-IDENTICAL. Output is a FRESH
12809            // e-context row (NOT an alias of ws state — the reverted zero-copy handoff's
12810            // hazard class does not apply).
12811            {
12812                let root = &self.ranks[0];
12813                let _main = root.gpu.enter_main()?;
12814                workspace
12815                    .ev_done
12816                    .as_ref()
12817                    .expect("device routes done event")
12818                    .record(&root.stream())?;
12819            }
12820            let _main = e.gpu.enter_main()?;
12821            e.stream().wait(
12822                workspace
12823                    .ev_done
12824                    .as_ref()
12825                    .expect("device routes done event"),
12826            )?;
12827            for ev in workspace.ev_rank.iter().skip(1) {
12828                e.stream().wait(ev)?;
12829            }
12830            let mut output = e.uninit(experts.input_width)?;
12831            e.add(
12832                &workspace.accumulator[0],
12833                &workspace.accumulator[1],
12834                &mut output,
12835                experts.input_width,
12836            )?;
12837            let output = output;
12838            if let Some(started) = started {
12839                use std::sync::atomic::Ordering;
12840                let ns = TIMING_NS
12841                    .fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
12842                    + started.elapsed().as_nanos() as u64;
12843                let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
12844                if calls.is_multiple_of(430) {
12845                    eprintln!(
12846                        "[nvfp4-dev-routes-direct-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
12847                        ns as f64 / 1.0e6,
12848                        ns as f64 / calls as f64 / 1.0e3,
12849                    );
12850                }
12851            }
12852            return Ok(output);
12853        }
12854        {
12855            let root = &self.ranks[0];
12856            let _main = root.gpu.enter_main()?;
12857            for ev in workspace.ev_rank.iter().skip(1) {
12858                root.stream().wait(ev)?;
12859            }
12860            root.stream()
12861                .memcpy_dtod(&workspace.accumulator[1], &mut workspace.remote)?;
12862            {
12863                let Nvfp4DeviceRoutesWorkspace {
12864                    accumulator,
12865                    remote,
12866                    combined,
12867                    ..
12868                } = &mut *workspace;
12869                root.add(&accumulator[0], remote, combined, experts.input_width)?;
12870            }
12871            workspace
12872                .ev_done
12873                .as_ref()
12874                .expect("device routes done event")
12875                .record(&root.stream())?;
12876        }
12877        let output = {
12878            let _main = e.gpu.enter_main()?;
12879            e.stream().wait(
12880                workspace
12881                    .ev_done
12882                    .as_ref()
12883                    .expect("device routes done event"),
12884            )?;
12885            // (Zero-copy clone handoff REVERTED 2026-08-21: identity mismatch in the
12886            // routes-diet bisect. The alloc+copy stays until the hazard is understood.)
12887            let mut output = e.uninit(experts.input_width)?;
12888            e.stream().memcpy_dtod(
12889                &workspace.combined.slice(0..experts.input_width),
12890                &mut output.slice_mut(0..experts.input_width),
12891            )?;
12892            output
12893        };
12894        if let Some(started) = started {
12895            use std::sync::atomic::Ordering;
12896            let ns = TIMING_NS.fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
12897                + started.elapsed().as_nanos() as u64;
12898            let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
12899            if calls.is_multiple_of(430) {
12900                eprintln!(
12901                    "[nvfp4-dev-routes-io-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
12902                    ns as f64 / 1.0e6,
12903                    ns as f64 / calls as f64 / 1.0e3,
12904                );
12905            }
12906        }
12907        Ok(output)
12908    }
12909
12910    /// Device-routed twin of `run_tensor_parallel_routes_nvfp4_device_io`: the selection and
12911    /// route weights arrive as the device router's e-context outputs — the per-layer host
12912    /// logits readback disappears. The fresh router outputs are staged into persistent
12913    /// e-context buffers on e's stream (never-free discipline) before the entry event; each
12914    /// rank peer-reads them behind it. The down-macro fold happens in-kernel.
12915    #[allow(clippy::too_many_arguments)]
12916    /// Prestage the routed-expert input: pull the shared row to every rank and quantize it
12917    /// there, WITHOUT the selection — callable before the router so the rank chains overlap
12918    /// it. No-op (returns false) when the workspace is not built yet or the door is off;
12919    /// the routed run then does its own staging as before.
12920    pub fn nvfp4_routes_prestage(
12921        &self,
12922        experts: &ResidentNvfp4TensorParallel,
12923        e: &Engine,
12924        input_dev: &crate::CudaSlice<f32>,
12925    ) -> Result<bool, Box<dyn std::error::Error>> {
12926        self.nvfp4_routes_prestage_with(experts, e, input_dev, |_, _, _, _| Ok(false))
12927    }
12928
12929    /// `nvfp4_routes_prestage` with a PEER-ROUTER hook: after rank1's input pull +
12930    /// quantize, the hook may compute rank1's route selection LOCALLY (replicated router —
12931    /// deterministic kernels on identical input bits produce identical sel/w, so the
12932    /// selection is bit-equal to the root's). Returns true when it wrote sel/route_w; the
12933    /// routed run then skips rank1's sel pull.
12934    pub fn nvfp4_routes_prestage_with(
12935        &self,
12936        experts: &ResidentNvfp4TensorParallel,
12937        e: &Engine,
12938        input_dev: &crate::CudaSlice<f32>,
12939        rank1_router: impl FnOnce(
12940            &Engine,
12941            &crate::CudaSlice<f32>,
12942            &mut crate::CudaSlice<i32>,
12943            &mut crate::CudaSlice<f32>,
12944        ) -> Result<bool, Box<dyn std::error::Error>>,
12945    ) -> Result<bool, Box<dyn std::error::Error>> {
12946        if !routes_prestage_on() || step_tp_graph_enabled()? {
12947            return Ok(false);
12948        }
12949        if input_dev.len() != experts.input_width {
12950            return Err("NVFP4 prestage input width mismatch".into());
12951        }
12952        let mut workspace_guard = experts
12953            .device_workspace
12954            .lock()
12955            .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
12956        let Some(workspace) = workspace_guard.as_mut() else {
12957            return Ok(false);
12958        };
12959        if workspace.ev_input.is_none() {
12960            let _main = e.gpu.enter_main()?;
12961            workspace.ev_input = Some((e.ctx().new_event(None)?, e.ctx().ordinal()));
12962        } else if workspace.ev_input.as_ref().map(|(_, d)| *d) != Some(e.ctx().ordinal()) {
12963            return Err("NVFP4 prestage engine changed".into());
12964        }
12965        {
12966            let _main = e.gpu.enter_main()?;
12967            let (ev, _) = workspace.ev_input.as_ref().expect("armed above");
12968            ev.record(&e.stream())?;
12969        }
12970        for (rank_index, engine) in self.ranks.iter().enumerate() {
12971            let _main = engine.gpu.enter_main()?;
12972            let (ev, _) = workspace.ev_input.as_ref().expect("armed above");
12973            engine.stream().wait(ev)?;
12974            {
12975                let mut destination = workspace.input[rank_index].slice_mut(0..experts.input_width);
12976                engine
12977                    .stream()
12978                    .memcpy_dtod(&input_dev.slice(0..experts.input_width), &mut destination)?;
12979            }
12980            {
12981                let Nvfp4DeviceRoutesWorkspace {
12982                    input, in_q, in_d, ..
12983                } = &mut *workspace;
12984                engine.quantize_q8_1_into(
12985                    &input[rank_index],
12986                    1,
12987                    experts.input_width,
12988                    &mut in_q[rank_index],
12989                    &mut in_d[rank_index],
12990                )?;
12991            }
12992        }
12993        if self.ranks.len() == 2 {
12994            let rank1 = &self.ranks[1];
12995            let _r1 = rank1.gpu.enter_main()?;
12996            let Nvfp4DeviceRoutesWorkspace {
12997                input,
12998                sel,
12999                route_w,
13000                ..
13001            } = &mut *workspace;
13002            let (in1, rest_sel) = (&input[1], &mut sel[1]);
13003            if rank1_router(rank1, in1, rest_sel, &mut route_w[1])? {
13004                workspace.rank1_routed = true;
13005            }
13006        }
13007        workspace.prestaged = true;
13008        Ok(true)
13009    }
13010
13011    /// STEP TP2 GEMM PRIME (`MEMRA_STEP_GEMM_PRIME`, 2026-08-27, TTFT lane): one grouped
13012    /// f16 GEMM per projection over the RESIDENT NVFP4 banks for a prime chunk of `t` tokens.
13013    ///
13014    /// WHY: the t-row walk primes a 4,092-token prompt in 19.8 s at its widest (GEMV-bound) and
13015    /// the generic batch prime's decode-class MoE takes 240 s; the CUTLASS sizing rows put
13016    /// GEMM-class expert math at 170-270 TFLOP/s on this silicon, i.e. a sub-second cold prime.
13017    /// This reuses the grouped f16 lane end to end (`moe_f16g_act` -> `moe_f16_grouped`
13018    /// direct-from-NVFP4 -> silu pairs -> grouped down) once per RANK against that rank's bank
13019    /// half: gate/up are column-halves (silu runs on matching halves), down is the canonical
13020    /// row-shard pair producing partials joined in the pinned shard order, and the final
13021    /// weighted scatter runs a fixed slot-0..n_used-1 sum per token - no atomics anywhere.
13022    /// Per-expert NVFP4 macro scales land where they must: gate/up BEFORE silu (nonlinear),
13023    /// down folded into the scatter weight.
13024    ///
13025    /// NUMERIC CLASS: the f16-mirror grouped-prefill class other families already serve -
13026    /// admission is the prefill-KV acceptance gate plus the ship-shape tape, not byte identity.
13027    #[allow(clippy::too_many_arguments)]
13028    /// MEMRA_MOE_DETERM_STAGE=1: checksum a stage's device buffer so two back-to-back calls of the
13029    /// grouped routine can be compared STAGE BY STAGE. The routine's OUTPUT is nondeterministic above
13030    /// ~400 tokens on the direct lane (1.9e-7 / 99% of elements at t=4096) while its GEMM kernels are
13031    /// bit-exact in isolation, so the divergence enters somewhere between. The first stage whose
13032    /// checksum differs across the two calls is where.
13033    ///
13034    /// Sum-of-bits, not sum-of-floats: float addition would itself reorder and could mask exactly the
13035    /// class of difference being hunted.
13036    fn determ_stage_bytes(v: &[u8]) -> u64 {
13037        v.iter().fold(0u64, |a, b| {
13038            a.wrapping_mul(1_000_003).wrapping_add(*b as u64)
13039        })
13040    }
13041
13042    /// Checksum an i32 index/offset buffer. The CSR, the active-expert ids and the group
13043    /// offsets are inputs the gate kernel dereferences just as much as the activations are;
13044    /// leaving them unchecksummed is what let "identical inputs, different output" stand on a
13045    /// SUBSET of the inputs for six rounds of this investigation.
13046    fn determ_stage_i32(v: &[i32]) -> u64 {
13047        v.iter().fold(0u64, |a, b| {
13048            a.wrapping_mul(1_000_003).wrapping_add(*b as u32 as u64)
13049        })
13050    }
13051
13052    fn determ_stage_sum(v: &[f32]) -> u64 {
13053        v.iter().fold(0u64, |a, x| {
13054            a.wrapping_mul(1_000_003).wrapping_add(x.to_bits() as u64)
13055        })
13056    }
13057
13058    #[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
13059    pub fn run_tensor_parallel_routes_nvfp4_prime_grouped(
13060        &self,
13061        experts: &ResidentNvfp4TensorParallel,
13062        e: &Engine,
13063        z_t: &crate::CudaSlice<f32>,
13064        t: usize,
13065        sel: &[i32],
13066        w: &[f32],
13067        n_used: usize,
13068        activation_limit: Option<f32>,
13069    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
13070        let world = self.ranks.len();
13071        if world != NVFP4_CANONICAL_ROW_SHARDS {
13072            return Err("NVFP4 grouped prime requires the canonical 2-shard grid".into());
13073        }
13074        // The dequant must read the layout the bank was BUILT in (feeding slot-major bytes to
13075        // the v1 kernel was a garbage-output bug this line exists for). Taken from the BANK,
13076        // never from the environment: EP2 banks are always slot-major, TP shard banks are
13077        // slot-major only under PROGRAM 1 (`MEMRA_NVFP4_BANK_SM`). All three banks share one
13078        // decision at build (`nvfp4_repack_bank_matrix`), and the assert below refuses to run a
13079        // prime over banks that disagree instead of silently priming one of them wrong.
13080        //
13081        // THIS IS THE LINE THE 2026-08-29 CORRUPTION WENT THROUGH. `QT_NVFP4_V2` selects the
13082        // `kq_fetch` branch whose two prefetch callers omitted `in_f`; the codes stayed right
13083        // and the per-16 scale came from inside the packed-codes region, so the prime produced
13084        // fluent WRONG text. No v2 gate had ever run this GEMM. It is now covered device-side by
13085        // `nvfp4-bank-oracle` (both step37 layer geometries, all four tile forms) and end-to-end
13086        // by a prefill-heavy byte gate. Keep both: a decode-only byte gate proved nothing here.
13087        let slot_major = experts.gate.iter().all(|b| b.slot_major)
13088            && experts.up.iter().all(|b| b.slot_major)
13089            && experts.down.iter().all(|b| b.slot_major);
13090        let any_slot_major = experts.gate.iter().any(|b| b.slot_major)
13091            || experts.up.iter().any(|b| b.slot_major)
13092            || experts.down.iter().any(|b| b.slot_major);
13093        if any_slot_major != slot_major {
13094            return Err(
13095                "NVFP4 grouped prime: gate/up/down banks disagree on the row layout — \
13096                        one grouped GEMM cannot serve two byte maps"
13097                    .into(),
13098            );
13099        }
13100        let bank_qt = if slot_major {
13101            crate::QT_NVFP4_V2
13102        } else {
13103            crate::QT_NVFP4
13104        };
13105        let width = experts.input_width;
13106        let n_expert = experts.expert_count;
13107        let n_pairs = t * n_used;
13108        if sel.len() < n_pairs || w.len() < n_pairs || z_t.len() < t * width {
13109            return Err("NVFP4 grouped prime geometry".into());
13110        }
13111        // MEMRA_PRIME_PROF=1 sub-split of the grouped prime (2026-08-28). The [moe-prof] mark
13112        // around this whole call reads 90% of the MoE bucket, but the call is not just GEMMs:
13113        // it host-builds the CSR, allocates ~6 large device buffers per rank per layer (z_r is
13114        // 67 MB, act is 84 MB at t=4096), and does 5 H2D copies per rank. Tile form, occupancy,
13115        // padding, B double-buffering and register pressure have ALL come back null, which is
13116        // the signature of time that is not in the kernel. So measure HOST wall with no syncs
13117        // for the build and the issue, and let the join wait absorb the GPU time: host-bound and
13118        // GPU-bound then read differently instead of summing into one opaque number.
13119        let gprof = std::env::var("MEMRA_PRIME_PROF").as_deref() == Ok("1") && t >= 16;
13120        let g_t0 = std::time::Instant::now();
13121        // CSR: expert-major pair lists. Host-built - prime is chunk-granular, and the router
13122        // selections arrive host-side from the sigmoid router oracle.
13123        let mut buckets: Vec<Vec<i32>> = vec![Vec::new(); n_expert];
13124        for (p, &s_id) in sel.iter().take(n_pairs).enumerate() {
13125            let s_id = s_id as usize;
13126            if s_id >= n_expert {
13127                return Err(format!("grouped prime selection {s_id} >= {n_expert}").into());
13128            }
13129            buckets[s_id].push(p as i32);
13130        }
13131        let mut ex_ids: Vec<i32> = Vec::new();
13132        let mut ex_off: Vec<i32> = vec![0];
13133        let mut ex_pairs: Vec<i32> = Vec::new();
13134        for (e_id, b) in buckets.iter().enumerate() {
13135            if !b.is_empty() {
13136                ex_ids.push(e_id as i32);
13137                ex_pairs.extend_from_slice(b);
13138                ex_off.push(ex_pairs.len() as i32);
13139            }
13140        }
13141        let n_active = ex_ids.len();
13142        if n_active == 0 {
13143            return e.zeros(t * width);
13144        }
13145        if n_active > 512 {
13146            return Err("grouped prime n_active > 512 (direct lane cap)".into());
13147        }
13148        let csr_tok: Vec<i32> = ex_pairs.iter().map(|&p| p / n_used as i32).collect();
13149        // pair-id -> CSR row: lets the fused tail read the partials in place, so the prime skips
13150        // a whole [n_pairs, width] permute (532 MB read + write per rank per layer at 4k).
13151        let mut inv = vec![0i32; n_pairs];
13152        for (row, &pair) in ex_pairs.iter().enumerate() {
13153            inv[pair as usize] = row as i32;
13154        }
13155        // Per-CSR-row gate/up macro scales (before silu); down macro folds into the scatter w.
13156        let mg: Vec<f32> = ex_pairs
13157            .iter()
13158            .map(|&p| experts.macros_gate[sel[p as usize] as usize])
13159            .collect();
13160        let mu: Vec<f32> = ex_pairs
13161            .iter()
13162            .map(|&p| experts.macros_up[sel[p as usize] as usize])
13163            .collect();
13164        let wd: Vec<f32> = (0..n_pairs)
13165            .map(|p| w[p] * experts.macros_down[sel[p] as usize])
13166            .collect();
13167        // Pointer tables: built on first use and kept on the bank. Resident banks never move,
13168        // so the old per-rank-per-LAYER rebuild+upload of 3*n_expert u64s was pure prime-path
13169        // host churn (45 layers x 2 ranks x 864 entries per prime).
13170        {
13171            let mut tabs = experts
13172                .prime_tables
13173                .lock()
13174                .map_err(|_| "grouped prime table cache is poisoned")?;
13175            if tabs.len() != world {
13176                tabs.clear();
13177                for rank in 0..world {
13178                    let engine = &self.ranks[rank];
13179                    let _main = engine.gpu.enter_main()?;
13180                    let (gb, ub, db) =
13181                        (&experts.gate[rank], &experts.up[rank], &experts.down[rank]);
13182                    let mut tab = vec![0u64; 3 * n_expert];
13183                    {
13184                        use cudarc::driver::DevicePtr;
13185                        let stream = engine.stream();
13186                        let (pg, _g0) = gb.bank.device_ptr(&stream);
13187                        let (pu, _g1) = ub.bank.device_ptr(&stream);
13188                        let (pd, _g2) = db.bank.device_ptr(&stream);
13189                        for ex in 0..n_expert {
13190                            tab[ex] = pg + (ex * gb.expert_bytes) as u64;
13191                            tab[n_expert + ex] = pu + (ex * ub.expert_bytes) as u64;
13192                            tab[2 * n_expert + ex] = pd + (ex * db.expert_bytes) as u64;
13193                        }
13194                    }
13195                    tabs.push(engine.htod_u64(&tab)?);
13196                }
13197            }
13198        }
13199        let g_csr = g_t0.elapsed().as_secs_f64() * 1e3;
13200        let g_t1 = std::time::Instant::now();
13201        // WHAT ARE THESE RANKS, ACTUALLY (2026-08-28)? The grouped MoE measures join ~ span_sum
13202        // (strictly serialized) at t=4096 while the same kernel hits 40 TFLOP/s standalone, and
13203        // one intervention based on cudarc's peer-copy event was refuted. Before proposing an
13204        // eleventh mechanism, verify the premise the whole question rests on: that the two ranks
13205        // are on DISTINCT devices, contexts and streams. If they share any of those, the
13206        // serialization needs no further explanation. One line per process.
13207        {
13208            static SAID: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
13209            if gprof && !SAID.swap(true, std::sync::atomic::Ordering::Relaxed) {
13210                for rank in 0..world {
13211                    let e_r = &self.ranks[rank];
13212                    let _m = e_r.gpu.enter_main();
13213                    eprintln!(
13214                        "[rank-id] rank={rank} ordinal={} ctx={:?} stream={:?} root_ordinal={} \
13215                         root_stream={:?}",
13216                        e_r.ctx().ordinal(),
13217                        std::sync::Arc::as_ptr(e_r.ctx()),
13218                        e_r.stream().cu_stream(),
13219                        e.ctx().ordinal(),
13220                        e.stream().cu_stream(),
13221                    );
13222                }
13223            }
13224        }
13225
13226        let mut partials: Vec<crate::CudaSlice<f32>> = Vec::with_capacity(world);
13227        let mut ev_rank: Vec<CudaEvent> = Vec::with_capacity(world);
13228        let mut ev_head: Vec<CudaEvent> = Vec::with_capacity(world);
13229        let mut ev_tail_prof: Vec<CudaEvent> = Vec::with_capacity(world);
13230        for rank in 0..world {
13231            let engine = &self.ranks[rank];
13232            let _main = engine.gpu.enter_main()?;
13233            if gprof {
13234                // CU_EVENT_DEFAULT, not None: cudarc's new_event(None) creates the event with
13235                // CU_EVENT_DISABLE_TIMING, and cuEventElapsedTime then returns INVALID_HANDLE.
13236                // That is what failed every span query for two build cycles — the ordering
13237                // events below correctly keep the default, since they are never timed.
13238                let h = engine
13239                    .ctx()
13240                    .new_event(Some(cudarc::driver::sys::CUevent_flags::CU_EVENT_DEFAULT))?;
13241                h.record(&engine.stream())?;
13242                ev_head.push(h);
13243            }
13244            // The grouped-MoE FFI's raw launches follow the RUNTIME API's current device, not
13245            // the pushed driver context — bind it per rank or rank-1 calls die InvalidValue.
13246            engine.bind_runtime_device(engine.ctx().ordinal() as i32)?;
13247            let gb = &experts.gate[rank];
13248            let ub = &experts.up[rank];
13249            let db = &experts.down[rank];
13250            if db.device_rank != rank {
13251                return Err("grouped prime: down shard placement drifted".into());
13252            }
13253            let local_ff = gb.local_out;
13254            if ub.local_out != local_ff || db.local_in != local_ff || db.out_features != width {
13255                return Err("grouped prime: bank width mismatch".into());
13256            }
13257            // All of the rank's host-side staging lands before its first kernel, so the
13258            // launch chain below issues without host copies interleaved.
13259            let csr_tok_d = engine.htod_i32(&csr_tok)?;
13260            let exi_d = engine.htod_i32(&ex_ids)?;
13261            let exoff_d = engine.htod_i32(&ex_off)?;
13262            let mg_d = engine.htod(&mg)?;
13263            let mu_d = engine.htod(&mu)?;
13264            // Per-rank pointer table into the bank shards, slot-major like DevExps::ptr_row.
13265            let tabs_guard = experts
13266                .prime_tables
13267                .lock()
13268                .map_err(|_| "grouped prime table cache is poisoned")?;
13269            let tab_d = &tabs_guard[rank];
13270            let mut z_r = engine.uninit(t * width)?;
13271            {
13272                let mut dst = z_r.slice_mut(0..t * width);
13273                engine
13274                    .stream()
13275                    .memcpy_dtod(&z_t.slice(0..t * width), &mut dst)?;
13276            }
13277            let dstage = std::env::var("MEMRA_MOE_DETERM_STAGE").as_deref() == Ok("1") && t >= 16;
13278            let (z16, zs) = engine.moe_f16g_act(&z_r, Some(&csr_tok_d), width, n_pairs)?;
13279            if dstage {
13280                // z16 is the GEMM's actual DATA input and is a byte buffer; checksumming only
13281                // z_r and zs left "identical inputs" unestablished and produced a localization
13282                // that outran the measurement. Checksum it as bytes.
13283                let zr = engine.dtoh(&z_r)?;
13284                let zsv = engine.dtoh(&zs)?;
13285                let z16v = engine.dtoh_u8(&z16)?;
13286                eprintln!(
13287                    "[determ-stage] rank={rank} t={t} z_r={:016x} zs={:016x} z16={:016x}",
13288                    Self::determ_stage_sum(&zr),
13289                    Self::determ_stage_sum(&zsv),
13290                    Self::determ_stage_bytes(&z16v)
13291                );
13292            }
13293            if dstage {
13294                // INPUT CLOSURE. Everything the gate kernel dereferences, plus the launch
13295                // geometry that decides how it is summed, checksummed in ONE place. A kernel
13296                // proven bit-deterministic on live data, with no atomics, can only diverge if
13297                // (A) some byte it reads differs, (B) the launch differs, or (C) it reads
13298                // outside its declared inputs. This closes A and B; C is what compute-sanitizer
13299                // is for. Partial input sets are how the divergence kept retreating into the
13300                // part that was never measured.
13301                engine.stream().synchronize()?;
13302                let csr_v = engine.dtoh_i32(&csr_tok_d)?;
13303                let exi_v = engine.dtoh_i32(&exi_d)?;
13304                let exo_v = engine.dtoh_i32(&exoff_d)?;
13305                let mg_v = engine.dtoh(&mg_d)?;
13306                let mu_v = engine.dtoh(&mu_d)?;
13307                let tab_v = engine.dtoh_u64(tab_d)?;
13308                eprintln!(
13309                    "[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={}",
13310                    Self::determ_stage_i32(&csr_v),
13311                    Self::determ_stage_i32(&exi_v),
13312                    Self::determ_stage_i32(&exo_v),
13313                    Self::determ_stage_i32(&ex_off),
13314                    Self::determ_stage_sum(&mg_v),
13315                    Self::determ_stage_sum(&mu_v),
13316                    tab_v
13317                        .iter()
13318                        .fold(0u64, |a, b| a.wrapping_mul(1_000_003).wrapping_add(*b)),
13319                    gb.row_bytes
13320                );
13321                // The resident weight bank is the GEMM's OTHER operand and was never checked.
13322                // Opt-in because it is a ~424 MB dtoh per rank per layer.
13323                if std::env::var("MEMRA_MOE_DETERM_BANK").as_deref() == Ok("1") {
13324                    let bank_v = engine.dtoh_u8(&gb.bank)?;
13325                    eprintln!(
13326                        "[determ-closure] rank={rank} t={t} gate_bank={:016x} bytes={}",
13327                        Self::determ_stage_bytes(&bank_v),
13328                        bank_v.len()
13329                    );
13330                }
13331            }
13332            let mut g = engine.moe_f16_grouped(
13333                tab_d,
13334                0,
13335                n_expert,
13336                &exi_d,
13337                &ex_off,
13338                &exoff_d,
13339                &z16,
13340                &zs,
13341                width,
13342                local_ff,
13343                n_active,
13344                n_pairs,
13345                bank_qt,
13346                gb.row_bytes,
13347            )?;
13348            engine.scale_rows(&mut g, &mg_d, local_ff, n_pairs)?;
13349            let mut u = engine.moe_f16_grouped(
13350                tab_d,
13351                1,
13352                n_expert,
13353                &exi_d,
13354                &ex_off,
13355                &exoff_d,
13356                &z16,
13357                &zs,
13358                width,
13359                local_ff,
13360                n_active,
13361                n_pairs,
13362                bank_qt,
13363                ub.row_bytes,
13364            )?;
13365            engine.scale_rows(&mut u, &mu_d, local_ff, n_pairs)?;
13366            // step35 routed SwiGLU clamp (per-layer; live only on layers 43/44 for this
13367            // family): min(silu(g), lim) * clamp(u, +-lim). Dropping it was the second
13368            // correctness bug of the first engaged run.
13369            let act = match activation_limit.filter(|l| *l > 1e-6) {
13370                Some(lim) => {
13371                    let mut a = engine.uninit(n_pairs * local_ff)?;
13372                    engine.swiglu_clamped_mul_scaled(
13373                        &g,
13374                        &u,
13375                        1.0,
13376                        1.0,
13377                        lim,
13378                        &mut a,
13379                        n_pairs * local_ff,
13380                    )?;
13381                    a
13382                }
13383                None => engine.moe_pairs_silu_mul(&g, &u, n_pairs * local_ff)?,
13384            };
13385            if dstage {
13386                let gv = engine.dtoh(&g)?;
13387                let uv = engine.dtoh(&u)?;
13388                let av = engine.dtoh(&act)?;
13389                // A SUM tells you THAT gate differs; it does not tell you HOW. ULP-dense diffs
13390                // (nearly every element, ~1e-8) are an ordering/precision class; a handful of
13391                // huge ones are a corruption class. They need different hunts, so measure the
13392                // shape here instead of inferring it later.
13393                let key = (rank, t);
13394                let mut prev_map = DETERM_PREV
13395                    .get_or_init(|| std::sync::Mutex::new(std::collections::HashMap::new()))
13396                    .lock()
13397                    .map_err(|_| "determ prev map poisoned")?;
13398                let shape = match prev_map.get(&key) {
13399                    Some(prev) if prev.len() == gv.len() => {
13400                        let mut md = 0.0f32;
13401                        let mut n_diff = 0usize;
13402                        let mut n_big = 0usize;
13403                        for (a, b) in prev.iter().zip(gv.iter()) {
13404                            let d = (a - b).abs();
13405                            if d > 0.0 {
13406                                n_diff += 1;
13407                            }
13408                            if d > 1e-3 {
13409                                n_big += 1;
13410                            }
13411                            if d > md {
13412                                md = d;
13413                            }
13414                        }
13415                        format!(
13416                            " | vs_prev maxdiff={md:.3e} differing={n_diff}/{} big(>1e-3)={n_big}",
13417                            gv.len()
13418                        )
13419                    }
13420                    _ => String::new(),
13421                };
13422                prev_map.insert(key, gv.clone());
13423                drop(prev_map);
13424                eprintln!(
13425                    "[determ-stage] rank={rank} t={t} gate={:016x} up={:016x} silu={:016x}{shape}",
13426                    Self::determ_stage_sum(&gv),
13427                    Self::determ_stage_sum(&uv),
13428                    Self::determ_stage_sum(&av)
13429                );
13430            }
13431            let (a16, a_s) = engine.moe_f16g_act(&act, None, local_ff, n_pairs)?;
13432            let d_csr = engine.moe_f16_grouped(
13433                tab_d,
13434                2,
13435                n_expert,
13436                &exi_d,
13437                &ex_off,
13438                &exoff_d,
13439                &a16,
13440                &a_s,
13441                local_ff,
13442                width,
13443                n_active,
13444                n_pairs,
13445                bank_qt,
13446                db.row_bytes,
13447            )?;
13448
13449            // No host sync: both ranks' chains must be in flight before anything waits.
13450            // The rank's tail event orders the root's cross-device pulls below.
13451            if dstage {
13452                engine.stream().synchronize()?;
13453                let a16v = engine.dtoh_u8(&a16)?;
13454                let dv = engine.dtoh(&d_csr)?;
13455                eprintln!(
13456                    "[determ-stage] rank={rank} t={t} a16={:016x} down_partial={:016x}",
13457                    Self::determ_stage_bytes(&a16v),
13458                    Self::determ_stage_sum(&dv)
13459                );
13460            }
13461            let ev = engine.ctx().new_event(None)?;
13462            ev.record(&engine.stream())?;
13463            if gprof {
13464                // Per-rank GPU SPAN (2026-08-28). Keep the tail event; the elapsed time is read
13465                // AFTER the join sync below. Reading it here returns NOT_READY (the work has only
13466                // been queued) and cudarc's elapsed_ms synchronizes, which serialized the very
13467                // ranks this is meant to test: host issue jumped 1.9 ms -> 34-47 ms per call and
13468                // the join wall fell to match. A probe that changes the schedule measures its own
13469                // perturbation.
13470                // CudaEvent is not Clone, so record a second tail event on the same stream —
13471                // adjacent to `ev`, so it carries the same completion timestamp for timing.
13472                let tp = engine
13473                    .ctx()
13474                    .new_event(Some(cudarc::driver::sys::CUevent_flags::CU_EVENT_DEFAULT))?;
13475                tp.record(&engine.stream())?;
13476                ev_tail_prof.push(tp);
13477            }
13478            ev_rank.push(ev);
13479            partials.push(d_csr);
13480        }
13481        let _main = e.gpu.enter_main()?;
13482        e.bind_runtime_device(e.ctx().ordinal() as i32)?;
13483        // Host-only: every rank's chain is queued, nothing has been waited on yet.
13484        let g_issue = g_t1.elapsed().as_secs_f64() * 1e3;
13485        let g_t2 = std::time::Instant::now();
13486        for ev in &ev_rank {
13487            e.stream().wait(ev)?;
13488        }
13489        // Both partials land on the root (rank 1's crosses the link once), then ONE fused pass
13490        // does join + CSR permute + weight + scatter. Shard order stays pinned as (y0 + y1).
13491        let mut y0 = e.uninit(n_pairs * width)?;
13492        {
13493            let mut dst = y0.slice_mut(0..n_pairs * width);
13494            e.stream()
13495                .memcpy_dtod(&partials[0].slice(0..n_pairs * width), &mut dst)?;
13496        }
13497        let mut y1 = e.uninit(n_pairs * width)?;
13498        {
13499            let mut dst = y1.slice_mut(0..n_pairs * width);
13500            e.stream()
13501                .memcpy_dtod(&partials[1].slice(0..n_pairs * width), &mut dst)?;
13502        }
13503        let inv_d = e.htod_i32(&inv)?;
13504        let wd_d = e.htod(&wd)?;
13505        let mut out = e.uninit(t * width)?;
13506        e.moe_prime_join_scatter(&y0, &y1, &inv_d, &wd_d, &mut out, width, n_used, t)?;
13507        if gprof {
13508            let _ = e.stream().synchronize();
13509            let g_join = g_t2.elapsed().as_secs_f64() * 1e3;
13510            // Everything has completed, so both events of every pair are ready and elapsed_ms
13511            // cannot block. A negative entry means the query itself failed and the row must be
13512            // read as missing data, never as a zero-length span.
13513            // cuEventElapsedTime needs the events' OWN context current — computing it under the
13514            // root's pushed context returned an error for every pair, and the first version
13515            // swallowed that into -1.0 with no reason attached. Enter each rank's context, and
13516            // print the failure once so a dead probe can never again look like a zero-length span.
13517            let mut span_ms: Vec<f32> = Vec::with_capacity(world);
13518            for (rank, (h, tp)) in ev_head.iter().zip(ev_tail_prof.iter()).enumerate() {
13519                let guard = self.ranks[rank].gpu.enter_main();
13520                match guard.and_then(|_g| h.elapsed_ms(tp).map_err(|e| e.into())) {
13521                    Ok(v) => span_ms.push(v),
13522                    Err(err) => {
13523                        static SAID: std::sync::atomic::AtomicBool =
13524                            std::sync::atomic::AtomicBool::new(false);
13525                        if !SAID.swap(true, std::sync::atomic::Ordering::Relaxed) {
13526                            eprintln!("[grp-prof] span query failed on rank {rank}: {err}");
13527                        }
13528                        span_ms.push(-1.0);
13529                    }
13530                }
13531            }
13532            eprintln!(
13533                "[grp-prof] t={t} n_active={n_active} csr={g_csr:.1}ms issue={g_issue:.1}ms \
13534                 join={g_join:.1}ms spans={span_ms:?} span_sum={:.1}ms span_max={:.1}ms",
13535                span_ms.iter().sum::<f32>(),
13536                span_ms.iter().cloned().fold(0.0f32, f32::max)
13537            );
13538        }
13539        Ok(out)
13540    }
13541
13542    #[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
13543    pub fn run_tensor_parallel_routes_nvfp4_device_routed(
13544        &self,
13545        experts: &ResidentNvfp4TensorParallel,
13546        e: &Engine,
13547        input_dev: &crate::CudaSlice<f32>,
13548        sel_d: &crate::CudaSlice<i32>,
13549        w_d: &crate::CudaSlice<f32>,
13550        experts_per_token: usize,
13551        activation_limit: Option<f32>,
13552    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
13553        self.run_tensor_parallel_routes_nvfp4_device_routed_prejoin(
13554            experts,
13555            e,
13556            input_dev,
13557            sel_d,
13558            w_d,
13559            experts_per_token,
13560            activation_limit,
13561            || Ok(()),
13562        )
13563    }
13564
13565    /// `run_tensor_parallel_routes_nvfp4_device_routed` with a PREJOIN hook: `pre_join`
13566    /// runs on the host right before the join wait is enqueued on e's stream — work it
13567    /// issues there (e.g. the shexp overlap) executes WHILE the peer rank finishes its
13568    /// sweep, instead of after the join. Value-neutral by construction (the hook only
13569    /// reorders independent host issue).
13570    #[allow(clippy::too_many_arguments)]
13571    pub fn run_tensor_parallel_routes_nvfp4_device_routed_prejoin(
13572        &self,
13573        experts: &ResidentNvfp4TensorParallel,
13574        e: &Engine,
13575        input_dev: &crate::CudaSlice<f32>,
13576        sel_d: &crate::CudaSlice<i32>,
13577        w_d: &crate::CudaSlice<f32>,
13578        experts_per_token: usize,
13579        activation_limit: Option<f32>,
13580        pre_join: impl FnOnce() -> Result<(), Box<dyn std::error::Error>>,
13581    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
13582        self.run_tensor_parallel_routes_nvfp4_device_routed_prejoin_add3(
13583            experts,
13584            e,
13585            input_dev,
13586            sel_d,
13587            w_d,
13588            experts_per_token,
13589            activation_limit,
13590            pre_join,
13591            None,
13592        )
13593    }
13594
13595    /// The prejoin variant with MOE TAIL FUSION M1: when `post_add = Some((sh_raw,
13596    /// scale_raw))`, the direct-join arm folds the shexp apply into the join add
13597    /// (`dst = (acc0+acc1) + sh*scale[0]`, exact split-pair sequence) — the caller skips
13598    /// its apply launch. Raw UVA pointers so no lock is held across the call.
13599    #[allow(clippy::too_many_arguments)]
13600    pub fn run_tensor_parallel_routes_nvfp4_device_routed_prejoin_add3(
13601        &self,
13602        experts: &ResidentNvfp4TensorParallel,
13603        e: &Engine,
13604        input_dev: &crate::CudaSlice<f32>,
13605        sel_d: &crate::CudaSlice<i32>,
13606        w_d: &crate::CudaSlice<f32>,
13607        experts_per_token: usize,
13608        activation_limit: Option<f32>,
13609        pre_join: impl FnOnce() -> Result<(), Box<dyn std::error::Error>>,
13610        post_add: Option<(u64, u64)>,
13611    ) -> Result<crate::CudaSlice<f32>, Box<dyn std::error::Error>> {
13612        if input_dev.len() != experts.input_width {
13613            return Err(format!(
13614                "NVFP4 device-routed input {} != width {}",
13615                input_dev.len(),
13616                experts.input_width
13617            )
13618            .into());
13619        }
13620        let n_sel = experts_per_token;
13621        if sel_d.len() < n_sel || w_d.len() < n_sel {
13622            return Err(format!(
13623                "NVFP4 device-routed routes sel={} w={} < experts/token {n_sel}",
13624                sel_d.len(),
13625                w_d.len()
13626            )
13627            .into());
13628        }
13629        let world = self.ranks.len();
13630        if world != NVFP4_CANONICAL_ROW_SHARDS {
13631            return Err(format!(
13632                "NVFP4 device routes require world == canonical shard grid \
13633                 ({NVFP4_CANONICAL_ROW_SHARDS}), got {world}"
13634            )
13635            .into());
13636        }
13637        let local_out = experts.expert_width / world;
13638
13639        static TIMING_NS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
13640        static TIMING_CALLS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
13641        let timing = std::env::var("MEMRA_STEP_TP_TIMING").as_deref() == Ok("1");
13642        let started = timing.then(std::time::Instant::now);
13643
13644        let mut workspace_guard = experts
13645            .device_workspace
13646            .lock()
13647            .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
13648        if workspace_guard.is_none() {
13649            drop(workspace_guard);
13650            let zero = vec![0.0f32; experts.input_width];
13651            let zero_sel = vec![0usize; n_sel];
13652            let zero_w = vec![0.0f32; n_sel];
13653            let _ = self.run_tensor_parallel_routes_nvfp4_device(
13654                experts,
13655                &zero,
13656                &zero_sel,
13657                &zero_w,
13658                n_sel,
13659                activation_limit,
13660            )?;
13661            workspace_guard = experts
13662                .device_workspace
13663                .lock()
13664                .map_err(|_| "NVFP4 device routes workspace lock is poisoned")?;
13665        }
13666        let workspace = workspace_guard
13667            .as_mut()
13668            .expect("NVFP4 device routes workspace initialized above");
13669        if workspace.n_sel != n_sel {
13670            return Err(format!(
13671                "NVFP4 device routes experts/token changed: workspace {} != call {n_sel}",
13672                workspace.n_sel
13673            )
13674            .into());
13675        }
13676
13677        // GRAPH DOOR (MEMRA_STEP_TP_GRAPH=1): the whole rank+root segment replays as one
13678        // stitched multi-device parent launched on e's stream — no events, no per-token node
13679        // updates (every address is persistent staging). VALUE-IDENTICAL to the eager path:
13680        // the children replay exactly the same kernel/copy sequence.
13681        //
13682        // GRAPH-LAUNCH HEADROOM GUARD (see spec::GRAPH_LAUNCH_MIN_FREE): below the
13683        // driver-free floor on the launching device this call falls through to the
13684        // eager routes path below — the exact body the graph captures, stateless per
13685        // call — instead of feeding cuGraphLaunch an exhausted card
13686        // (lane/graph-launch-guard-sweep-20260831).
13687        if step_tp_graph_enabled()? && step_tp_graph_headroom_ok(e) {
13688            if workspace.dev_route_e.is_none() {
13689                let _main = e.gpu.enter_main()?;
13690                workspace.dev_route_e = Some((
13691                    e.htod_i32(&vec![0i32; n_sel])?,
13692                    e.htod(&vec![0.0f32; n_sel])?,
13693                ));
13694            }
13695            if workspace.in_stage_e.is_none() {
13696                let _main = e.gpu.enter_main()?;
13697                workspace.in_stage_e = Some(e.htod(&vec![0.0f32; experts.input_width])?);
13698                workspace.out_stage_e = Some(e.htod(&vec![0.0f32; experts.input_width])?);
13699            }
13700            if workspace.routes_graph.is_none() {
13701                let graph = self.nvfp4_routes_build_graph(
13702                    experts,
13703                    workspace,
13704                    local_out,
13705                    n_sel,
13706                    activation_limit,
13707                )?;
13708                workspace.routes_graph = Some(graph);
13709                eprintln!(
13710                    "[step-tp-graph] routes segment captured: ranks={world} n_sel={n_sel} \
13711                     children=3 updates=none performance_claim=false"
13712                );
13713            }
13714            let output = {
13715                let _main = e.gpu.enter_main()?;
13716                {
13717                    let (sel_e, w_e) = workspace
13718                        .dev_route_e
13719                        .as_mut()
13720                        .expect("device route staging set above");
13721                    {
13722                        let mut dst = sel_e.slice_mut(0..n_sel);
13723                        e.stream().memcpy_dtod(&sel_d.slice(0..n_sel), &mut dst)?;
13724                    }
13725                    {
13726                        let mut dst = w_e.slice_mut(0..n_sel);
13727                        e.stream().memcpy_dtod(&w_d.slice(0..n_sel), &mut dst)?;
13728                    }
13729                }
13730                {
13731                    let in_stage = workspace
13732                        .in_stage_e
13733                        .as_mut()
13734                        .expect("graph staging set above");
13735                    let mut dst = in_stage.slice_mut(0..experts.input_width);
13736                    e.stream()
13737                        .memcpy_dtod(&input_dev.slice(0..experts.input_width), &mut dst)?;
13738                }
13739                unsafe {
13740                    let r = cudarc::driver::sys::cuGraphLaunch(
13741                        workspace
13742                            .routes_graph
13743                            .as_ref()
13744                            .expect("routes graph built above")
13745                            .exec,
13746                        e.stream().cu_stream() as cudarc::driver::sys::CUstream,
13747                    );
13748                    if r != cudarc::driver::sys::CUresult::CUDA_SUCCESS {
13749                        return Err(format!("routes graph launch: {r:?}").into());
13750                    }
13751                }
13752                let mut output = e.uninit(experts.input_width)?;
13753                {
13754                    let out_stage = workspace
13755                        .out_stage_e
13756                        .as_ref()
13757                        .expect("graph staging set above");
13758                    e.stream().memcpy_dtod(
13759                        &out_stage.slice(0..experts.input_width),
13760                        &mut output.slice_mut(0..experts.input_width),
13761                    )?;
13762                }
13763                output
13764            };
13765            if let Some(started) = started {
13766                use std::sync::atomic::Ordering;
13767                let ns = TIMING_NS
13768                    .fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
13769                    + started.elapsed().as_nanos() as u64;
13770                let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
13771                if calls.is_multiple_of(430) {
13772                    eprintln!(
13773                        "[nvfp4-dev-routed-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
13774                        ns as f64 / 1.0e6,
13775                        ns as f64 / calls as f64 / 1.0e3,
13776                    );
13777                }
13778            }
13779            return Ok(output);
13780        }
13781
13782        // Entry fence + router-output staging, all on e's stream: the fresh sel/w slices are
13783        // copied into the persistent e-context pair, then the event is recorded — the caller's
13784        // sel_d/w_d can free on e's stream with no cross-stream reader.
13785        if let Some((_, device)) = workspace.ev_entry.as_ref() {
13786            if *device != e.ctx().ordinal() {
13787                return Err("NVFP4 device-routed routes engine changed".into());
13788            }
13789        } else {
13790            let _main = e.gpu.enter_main()?;
13791            workspace.ev_entry = Some((e.ctx().new_event(None)?, e.ctx().ordinal()));
13792        }
13793        if workspace.dev_route_e.is_none() {
13794            let _main = e.gpu.enter_main()?;
13795            workspace.dev_route_e = Some((
13796                e.htod_i32(&vec![0i32; n_sel])?,
13797                e.htod(&vec![0.0f32; n_sel])?,
13798            ));
13799        }
13800        // MEMRA_SEL_MIRROR: the staging pair exists so the rank streams read a persistent
13801        // e-context address. The caller's sel_d/w_d ARE persistent (the process-static
13802        // selection rows), so when every consuming rank shares e's device the ranks can read
13803        // them directly and this hop disappears. The graph door keeps the staging (its
13804        // captured copies read the fixed addresses).
13805        let mirror = sel_mirror_on() && !step_tp_graph_enabled()?;
13806        let e_device = e.ctx().ordinal();
13807        // rank1_routed is consumed (taken) below; peek it here for the staging decision.
13808        let rank1_routed_peek = workspace.rank1_routed;
13809        let stage_needed = !mirror
13810            || self.ranks.iter().enumerate().any(|(rank_index, engine)| {
13811                !(rank1_routed_peek && rank_index == 1) && engine.ctx().ordinal() != e_device
13812            });
13813        {
13814            let _main = e.gpu.enter_main()?;
13815            if stage_needed {
13816                let (sel_e, w_e) = workspace
13817                    .dev_route_e
13818                    .as_mut()
13819                    .expect("device route staging set above");
13820                {
13821                    let mut dst = sel_e.slice_mut(0..n_sel);
13822                    e.stream().memcpy_dtod(&sel_d.slice(0..n_sel), &mut dst)?;
13823                }
13824                {
13825                    let mut dst = w_e.slice_mut(0..n_sel);
13826                    e.stream().memcpy_dtod(&w_d.slice(0..n_sel), &mut dst)?;
13827                }
13828            }
13829            let (ev_entry, _) = workspace.ev_entry.as_ref().expect("entry event set above");
13830            ev_entry.record(&e.stream())?;
13831        }
13832        // Prestage door: input pull + quantize were already issued on the rank streams
13833        // (before the router) — the rank stream order suffices, skip them here.
13834        let prestaged = std::mem::take(&mut workspace.prestaged);
13835        let rank1_routed = std::mem::take(&mut workspace.rank1_routed);
13836        for (rank_index, engine) in self.ranks.iter().enumerate() {
13837            let _main = engine.gpu.enter_main()?;
13838            let (ev_entry, _) = workspace.ev_entry.as_ref().expect("entry event set above");
13839            engine.stream().wait(ev_entry)?;
13840            if !prestaged {
13841                let mut destination = workspace.input[rank_index].slice_mut(0..experts.input_width);
13842                engine
13843                    .stream()
13844                    .memcpy_dtod(&input_dev.slice(0..experts.input_width), &mut destination)?;
13845            }
13846            if !(rank1_routed && rank_index == 1) {
13847                // ONE mirror launch instead of two 32-byte copy-engine dispatches; source is
13848                // the caller's persistent rows when this rank shares e's device (UVA, ordered
13849                // by ev_entry), else the staged e-context pair.
13850                let same_dev = engine.ctx().ordinal() == e_device;
13851                if mirror {
13852                    // Split the workspace borrow so the source (the staged pair, when this
13853                    // rank is off-device) and the destination rows coexist.
13854                    let Nvfp4DeviceRoutesWorkspace {
13855                        sel,
13856                        route_w,
13857                        dev_route_e,
13858                        ..
13859                    } = &mut *workspace;
13860                    let (src_sel, src_w): (&crate::CudaSlice<i32>, &crate::CudaSlice<f32>) =
13861                        if same_dev {
13862                            (sel_d, w_d)
13863                        } else {
13864                            let (sel_e, w_e) = dev_route_e
13865                                .as_ref()
13866                                .expect("device route staging set above");
13867                            (sel_e, w_e)
13868                        };
13869                    engine.moe_sel_w_mirror(
13870                        src_sel,
13871                        src_w,
13872                        &mut sel[rank_index],
13873                        &mut route_w[rank_index],
13874                        n_sel,
13875                    )?;
13876                } else {
13877                    let (sel_e, w_e) = workspace
13878                        .dev_route_e
13879                        .as_ref()
13880                        .expect("device route staging set above");
13881                    {
13882                        let mut dst = workspace.sel[rank_index].slice_mut(0..n_sel);
13883                        engine
13884                            .stream()
13885                            .memcpy_dtod(&sel_e.slice(0..n_sel), &mut dst)?;
13886                    }
13887                    {
13888                        let mut dst = workspace.route_w[rank_index].slice_mut(0..n_sel);
13889                        engine
13890                            .stream()
13891                            .memcpy_dtod(&w_e.slice(0..n_sel), &mut dst)?;
13892                    }
13893                }
13894            }
13895            if !prestaged {
13896                let Nvfp4DeviceRoutesWorkspace {
13897                    input, in_q, in_d, ..
13898                } = &mut *workspace;
13899                engine.quantize_q8_1_into(
13900                    &input[rank_index],
13901                    1,
13902                    experts.input_width,
13903                    &mut in_q[rank_index],
13904                    &mut in_d[rank_index],
13905                )?;
13906            }
13907        }
13908        self.nvfp4_routes_batched_sweeps(
13909            experts,
13910            workspace,
13911            &[],
13912            &[],
13913            &[],
13914            local_out,
13915            n_sel,
13916            activation_limit,
13917            true,
13918        )?;
13919
13920        // rank0 == root: its own stream order already covers its sweep; only the PEER
13921        // ranks need the record/wait pair (host-op diet at the #1 eager seam, 2026-08-21).
13922        for (rank_index, engine) in self.ranks.iter().enumerate().skip(1) {
13923            let _main = engine.gpu.enter_main()?;
13924            workspace.ev_rank[rank_index].record(&engine.stream())?;
13925        }
13926        // Doorbell fences (MEMRA_FENCE_MEMOPS=1): rank1 + root ring their flags; e waits
13927        // the tickets instead of the two events. Arm lazily; 0-len = unsupported.
13928        let memops = fence_memops_on() && moe_direct_on() && self.ranks.len() == 2;
13929        let mut ticket = 0u32;
13930        if memops {
13931            use cudarc::driver::sys;
13932            if workspace.fence_flags_raw == 0 {
13933                let root = &self.ranks[0];
13934                let _main = root.gpu.enter_main()?;
13935                let mut ptr: sys::CUdeviceptr = 0;
13936                let r = unsafe { sys::cuMemAlloc_v2(&mut ptr, 8) };
13937                if r != sys::CUresult::CUDA_SUCCESS {
13938                    return Err(format!("fence flag alloc: {r:?}").into());
13939                }
13940                let r = unsafe { sys::cuMemsetD8_v2(ptr, 0, 8) };
13941                if r != sys::CUresult::CUDA_SUCCESS {
13942                    return Err(format!("fence flag memset: {r:?}").into());
13943                }
13944                workspace.fence_flags_raw = ptr as u64;
13945            }
13946            workspace.fence_ticket = workspace.fence_ticket.wrapping_add(1).max(1);
13947            ticket = workspace.fence_ticket;
13948            let base = workspace.fence_flags_raw;
13949            {
13950                let root = &self.ranks[0];
13951                let _main = root.gpu.enter_main()?;
13952                let r = unsafe {
13953                    sys::cuStreamWriteValue32_v2(
13954                        root.stream().cu_stream() as sys::CUstream,
13955                        (base + 4) as sys::CUdeviceptr,
13956                        ticket,
13957                        0,
13958                    )
13959                };
13960                if r != sys::CUresult::CUDA_SUCCESS {
13961                    return Err(format!("fence write root: {r:?}").into());
13962                }
13963            }
13964        }
13965        // PREJOIN hook: rank work is fully issued (dev1 running); independent e-stream
13966        // kernels queued here execute while the peer rank drains its sweep.
13967        pre_join()?;
13968
13969        if moe_direct_on() && self.ranks.len() == 2 {
13970            // DIRECT JOIN: rank1's accumulator is root-resident (P2P single-store pass);
13971            // rank0's is root-stream-ordered. One root event + rank1's own event order
13972            // the model engine's single add — same operand order as root's add
13973            // (accumulator[0] + accumulator[1]): BIT-IDENTICAL. Output is a FRESH
13974            // e-context row (NOT an alias of ws state — the reverted zero-copy handoff's
13975            // hazard class does not apply).
13976            let _main = e.gpu.enter_main()?;
13977            if memops {
13978                use cudarc::driver::sys;
13979                let base = workspace.fence_flags_raw;
13980                let r = unsafe {
13981                    sys::cuStreamWaitValue32_v2(
13982                        e.stream().cu_stream() as sys::CUstream,
13983                        (base + 4) as sys::CUdeviceptr,
13984                        ticket,
13985                        sys::CUstreamWaitValue_flags::CU_STREAM_WAIT_VALUE_GEQ as u32,
13986                    )
13987                };
13988                if r != sys::CUresult::CUDA_SUCCESS {
13989                    return Err(format!("fence wait: {r:?}").into());
13990                }
13991                for ev in workspace.ev_rank.iter().skip(1) {
13992                    e.stream().wait(ev)?;
13993                }
13994            } else {
13995                {
13996                    let root = &self.ranks[0];
13997                    let _rmain = root.gpu.enter_main()?;
13998                    workspace
13999                        .ev_done
14000                        .as_ref()
14001                        .expect("device routes done event")
14002                        .record(&root.stream())?;
14003                }
14004                e.stream().wait(
14005                    workspace
14006                        .ev_done
14007                        .as_ref()
14008                        .expect("device routes done event"),
14009                )?;
14010                for ev in workspace.ev_rank.iter().skip(1) {
14011                    e.stream().wait(ev)?;
14012                }
14013            }
14014            let mut output = e.uninit(experts.input_width)?;
14015            if let Some((sh_raw, scale_raw)) = post_add {
14016                // MOE TAIL FUSION M1: fold the shexp apply into the join add —
14017                // dst = (acc0 + acc1) + sh*scale[0], the exact split-pair sequence.
14018                e.add3_raw(
14019                    &workspace.accumulator[0],
14020                    &workspace.accumulator[1],
14021                    sh_raw,
14022                    scale_raw,
14023                    &mut output,
14024                    experts.input_width,
14025                )?;
14026            } else {
14027                e.add(
14028                    &workspace.accumulator[0],
14029                    &workspace.accumulator[1],
14030                    &mut output,
14031                    experts.input_width,
14032                )?;
14033            }
14034            let output = output;
14035            if let Some(started) = started {
14036                use std::sync::atomic::Ordering;
14037                let ns = TIMING_NS
14038                    .fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
14039                    + started.elapsed().as_nanos() as u64;
14040                let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
14041                if calls.is_multiple_of(430) {
14042                    eprintln!(
14043                        "[nvfp4-dev-routes-direct-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
14044                        ns as f64 / 1.0e6,
14045                        ns as f64 / calls as f64 / 1.0e3,
14046                    );
14047                }
14048            }
14049            return Ok(output);
14050        }
14051        {
14052            let root = &self.ranks[0];
14053            let _main = root.gpu.enter_main()?;
14054            for ev in workspace.ev_rank.iter().skip(1) {
14055                root.stream().wait(ev)?;
14056            }
14057            root.stream()
14058                .memcpy_dtod(&workspace.accumulator[1], &mut workspace.remote)?;
14059            {
14060                let Nvfp4DeviceRoutesWorkspace {
14061                    accumulator,
14062                    remote,
14063                    combined,
14064                    ..
14065                } = &mut *workspace;
14066                root.add(&accumulator[0], remote, combined, experts.input_width)?;
14067            }
14068            workspace
14069                .ev_done
14070                .as_ref()
14071                .expect("device routes done event")
14072                .record(&root.stream())?;
14073        }
14074        let output = {
14075            let _main = e.gpu.enter_main()?;
14076            e.stream().wait(
14077                workspace
14078                    .ev_done
14079                    .as_ref()
14080                    .expect("device routes done event"),
14081            )?;
14082            // (Zero-copy clone handoff REVERTED 2026-08-21: identity mismatch in the
14083            // routes-diet bisect. The alloc+copy stays until the hazard is understood.)
14084            let mut output = e.uninit(experts.input_width)?;
14085            e.stream().memcpy_dtod(
14086                &workspace.combined.slice(0..experts.input_width),
14087                &mut output.slice_mut(0..experts.input_width),
14088            )?;
14089            output
14090        };
14091        if let Some(started) = started {
14092            use std::sync::atomic::Ordering;
14093            let ns = TIMING_NS.fetch_add(started.elapsed().as_nanos() as u64, Ordering::Relaxed)
14094                + started.elapsed().as_nanos() as u64;
14095            let calls = TIMING_CALLS.fetch_add(1, Ordering::Relaxed) + 1;
14096            if calls.is_multiple_of(430) {
14097                eprintln!(
14098                    "[nvfp4-dev-routed-timing] calls={calls} total_ms={:.1} avg_us={:.1}",
14099                    ns as f64 / 1.0e6,
14100                    ns as f64 / calls as f64 / 1.0e3,
14101                );
14102            }
14103        }
14104        Ok(output)
14105    }
14106
14107    /// The fused finish's ROOT section (combine + shadow gathers), event-free: the eager
14108    /// caller wraps it with rank-event waits + the done record; the token graph captures it
14109    /// verbatim (parent edges provide the ordering).
14110    pub(crate) fn decode_v2_finish_root_fused(
14111        &self,
14112        ws: &mut StepTpDecodeV2Ws,
14113    ) -> Result<(), Box<dyn std::error::Error>> {
14114        let root = &self.ranks[0];
14115        let _main = root.gpu.enter_main()?;
14116        if ws.raw_peer_partial != 0 {
14117            // Capture-safe raw seams (arming happened in the stage flow).
14118            raw_copy_bytes(ws.raw_peer_partial, ws.raw_o_partial1, ws.o_out * 4, root)?;
14119        } else {
14120            root.stream()
14121                .memcpy_dtod(&ws.o_partials[1][0], &mut ws.peer_partial)?;
14122        }
14123        {
14124            let StepTpDecodeV2Ws {
14125                o_partials,
14126                peer_partial,
14127                reduce_a,
14128                o_out,
14129                ..
14130            } = &mut *ws;
14131            root.add(&o_partials[0][0], peer_partial, reduce_a, *o_out)?;
14132        }
14133        let shadows = !no_local_shadow_on() || ws.raw_mixed_stage_e != 0;
14134        if shadows {
14135            // rank0's shadows are same-context (root) copies; rank1's cross-context reads go
14136            // raw when armed.
14137            let mut k_dst = ws.k_shadow.slice_mut(0..ws.local_kv_dim);
14138            root.stream().memcpy_dtod(&ws.k[0], &mut k_dst)?;
14139            let mut v_dst = ws.v_shadow.slice_mut(0..ws.local_kv_dim);
14140            root.stream().memcpy_dtod(&ws.v_raw[0], &mut v_dst)?;
14141        }
14142        if shadows && ws.raw_peer_partial != 0 {
14143            raw_copy_bytes(
14144                ws.raw_k_shadow + (ws.local_kv_dim * 4) as u64,
14145                ws.raw_k1,
14146                ws.local_kv_dim * 4,
14147                root,
14148            )?;
14149            raw_copy_bytes(
14150                ws.raw_v_shadow + (ws.local_kv_dim * 4) as u64,
14151                ws.raw_v1,
14152                ws.local_kv_dim * 4,
14153                root,
14154            )?;
14155        } else if shadows {
14156            let start = ws.local_kv_dim;
14157            let mut k_dst = ws.k_shadow.slice_mut(start..start + ws.local_kv_dim);
14158            root.stream().memcpy_dtod(&ws.k[1], &mut k_dst)?;
14159            let mut v_dst = ws.v_shadow.slice_mut(start..start + ws.local_kv_dim);
14160            root.stream().memcpy_dtod(&ws.v_raw[1], &mut v_dst)?;
14161        }
14162        if ws.raw_mixed_stage_e != 0 {
14163            // Token-graph mirrors: the e-glue children read same-context copies of the
14164            // root-produced rows.
14165            raw_copy_bytes(ws.raw_mixed_stage_e, ws.raw_reduce_a, ws.o_out * 4, root)?;
14166            let (k_stage, v_stage) = ws.raw_shadow_stage_e;
14167            raw_copy_bytes(k_stage, ws.raw_k_shadow, 2 * ws.local_kv_dim * 4, root)?;
14168            raw_copy_bytes(v_stage, ws.raw_v_shadow, 2 * ws.local_kv_dim * 4, root)?;
14169        }
14170        Ok(())
14171    }
14172
14173    /// Arm the token-graph e-context mirrors (orchestrator-supplied fixed addresses) plus
14174    /// reduce_a's own pointer.
14175    pub(crate) fn decode_v2_arm_token_mirrors(
14176        &self,
14177        ws: &mut StepTpDecodeV2Ws,
14178        mixed_stage_e: u64,
14179        shadow_stage_e: (u64, u64),
14180    ) -> Result<(), Box<dyn std::error::Error>> {
14181        use cudarc::driver::DevicePtr;
14182        let root = &self.ranks[0];
14183        let _main = root.gpu.enter_main()?;
14184        let stream = root.stream();
14185        let (a, _g) = ws.reduce_a.device_ptr(&stream);
14186        ws.raw_reduce_a = a;
14187        ws.raw_mixed_stage_e = mixed_stage_e;
14188        ws.raw_shadow_stage_e = shadow_stage_e;
14189        Ok(())
14190    }
14191
14192    /// Build one layer's stitched routes graph: per-rank children captured on their own
14193    /// streams (raw cuMemcpyAsync at every cross-context seam — cudarc's slice tracking is
14194    /// capture-illegal there), a root combine child, and a multi-device parent with
14195    /// {rank0, rank1} -> root dependency edges. Zero per-token updates: every address the
14196    /// nodes touch is persistent workspace/staging.
14197    fn nvfp4_routes_build_graph(
14198        &self,
14199        experts: &ResidentNvfp4TensorParallel,
14200        workspace: &mut Nvfp4DeviceRoutesWorkspace,
14201        local_out: usize,
14202        n_sel: usize,
14203        activation_limit: Option<f32>,
14204    ) -> Result<RoutesGraph, Box<dyn std::error::Error>> {
14205        use cudarc::driver::DevicePtr;
14206        use cudarc::driver::sys;
14207        fn cu_try(r: sys::CUresult, what: &str) -> Result<(), Box<dyn std::error::Error>> {
14208            if r == sys::CUresult::CUDA_SUCCESS {
14209                Ok(())
14210            } else {
14211                Err(format!("{what}: {r:?}").into())
14212            }
14213        }
14214        let world = self.ranks.len();
14215        if world != 2 {
14216            return Err("routes graph door is built for the TP2 pair".into());
14217        }
14218        let width = experts.input_width;
14219
14220        // Raw pointers cached before capture (each read with its owner's stream).
14221        let ptr_f32 = |buf: &crate::CudaSlice<f32>, engine: &Engine| -> u64 {
14222            let stream = engine.stream();
14223            let (ptr, _g) = buf.device_ptr(&stream);
14224            ptr
14225        };
14226        let ptr_i32 = |buf: &crate::CudaSlice<i32>, engine: &Engine| -> u64 {
14227            let stream = engine.stream();
14228            let (ptr, _g) = buf.device_ptr(&stream);
14229            ptr
14230        };
14231        let (sel_e, w_e) = workspace
14232            .dev_route_e
14233            .as_ref()
14234            .expect("device route staging set before graph build");
14235        let root_engine = &self.ranks[0];
14236        let p_in_stage = ptr_f32(
14237            workspace.in_stage_e.as_ref().expect("graph staging"),
14238            root_engine,
14239        );
14240        let p_out_stage = ptr_f32(
14241            workspace.out_stage_e.as_ref().expect("graph staging"),
14242            root_engine,
14243        );
14244        let p_sel_e = ptr_i32(sel_e, root_engine);
14245        let p_w_e = ptr_f32(w_e, root_engine);
14246        let p_input: Vec<u64> = (0..world)
14247            .map(|r| ptr_f32(&workspace.input[r], &self.ranks[r]))
14248            .collect();
14249        let p_sel: Vec<u64> = (0..world)
14250            .map(|r| ptr_i32(&workspace.sel[r], &self.ranks[r]))
14251            .collect();
14252        let p_route_w: Vec<u64> = (0..world)
14253            .map(|r| ptr_f32(&workspace.route_w[r], &self.ranks[r]))
14254            .collect();
14255        let p_acc1 = ptr_f32(&workspace.accumulator[1], &self.ranks[1]);
14256        let p_remote = ptr_f32(&workspace.remote, root_engine);
14257        let p_combined = ptr_f32(&workspace.combined, root_engine);
14258
14259        let raw_copy = |dst: u64,
14260                        src: u64,
14261                        bytes: usize,
14262                        engine: &Engine|
14263         -> Result<(), Box<dyn std::error::Error>> {
14264            unsafe {
14265                cu_try(
14266                    sys::cuMemcpyAsync(
14267                        dst as sys::CUdeviceptr,
14268                        src as sys::CUdeviceptr,
14269                        bytes,
14270                        engine.stream().cu_stream() as sys::CUstream,
14271                    ),
14272                    "routes graph cuMemcpyAsync",
14273                )
14274            }
14275        };
14276
14277        let mut children = Vec::with_capacity(3);
14278        for rank in 0..world {
14279            let engine = &self.ranks[rank];
14280            let _main = engine.gpu.enter_main()?;
14281            let (child, _retained) = engine.capture_graph_retained(|_| {
14282                raw_copy(p_input[rank], p_in_stage, width * 4, engine)?;
14283                raw_copy(p_sel[rank], p_sel_e, n_sel * 4, engine)?;
14284                raw_copy(p_route_w[rank], p_w_e, n_sel * 4, engine)?;
14285                {
14286                    let Nvfp4DeviceRoutesWorkspace {
14287                        input, in_q, in_d, ..
14288                    } = &mut *workspace;
14289                    engine.quantize_q8_1_into(
14290                        &input[rank],
14291                        1,
14292                        width,
14293                        &mut in_q[rank],
14294                        &mut in_d[rank],
14295                    )?;
14296                }
14297                self.nvfp4_routes_batched_sweeps_rank(
14298                    experts,
14299                    workspace,
14300                    &[],
14301                    &[],
14302                    &[],
14303                    local_out,
14304                    n_sel,
14305                    activation_limit,
14306                    true,
14307                    rank,
14308                )?;
14309                Ok(())
14310            })?;
14311            children.push(child);
14312        }
14313        {
14314            let root = &self.ranks[0];
14315            let _main = root.gpu.enter_main()?;
14316            let (child, _retained) = root.capture_graph_retained(|_| {
14317                raw_copy(p_remote, p_acc1, width * 4, root)?;
14318                {
14319                    let Nvfp4DeviceRoutesWorkspace {
14320                        accumulator,
14321                        remote,
14322                        combined,
14323                        ..
14324                    } = &mut *workspace;
14325                    root.add(&accumulator[0], remote, combined, width)?;
14326                }
14327                raw_copy(p_out_stage, p_combined, width * 4, root)?;
14328                Ok(())
14329            })?;
14330            children.push(child);
14331        }
14332
14333        let mut parent: sys::CUgraph = std::ptr::null_mut();
14334        unsafe {
14335            cu_try(sys::cuGraphCreate(&mut parent, 0), "routes cuGraphCreate")?;
14336        }
14337        let mut n0: sys::CUgraphNode = std::ptr::null_mut();
14338        let mut n1: sys::CUgraphNode = std::ptr::null_mut();
14339        let mut n2: sys::CUgraphNode = std::ptr::null_mut();
14340        unsafe {
14341            cu_try(
14342                sys::cuGraphAddChildGraphNode(
14343                    &mut n0,
14344                    parent,
14345                    std::ptr::null(),
14346                    0,
14347                    children[0].cu_graph(),
14348                ),
14349                "routes child r0",
14350            )?;
14351            cu_try(
14352                sys::cuGraphAddChildGraphNode(
14353                    &mut n1,
14354                    parent,
14355                    std::ptr::null(),
14356                    0,
14357                    children[1].cu_graph(),
14358                ),
14359                "routes child r1",
14360            )?;
14361            let deps = [n0, n1];
14362            cu_try(
14363                sys::cuGraphAddChildGraphNode(
14364                    &mut n2,
14365                    parent,
14366                    deps.as_ptr(),
14367                    2,
14368                    children[2].cu_graph(),
14369                ),
14370                "routes child root",
14371            )?;
14372        }
14373        let mut exec: sys::CUgraphExec = std::ptr::null_mut();
14374        unsafe {
14375            cu_try(
14376                sys::cuGraphInstantiateWithFlags(&mut exec, parent, 0),
14377                "routes instantiate",
14378            )?;
14379        }
14380        Ok(RoutesGraph {
14381            exec,
14382            parent,
14383            _children: children,
14384        })
14385    }
14386
14387    /// One rank's routes section for the token graph (event-free): staged input copy (raw
14388    /// when the caller supplies the source pointer), quantize, and the batched sweeps.
14389    /// Eager device_routed wraps it with the entry-event wait.
14390    #[allow(clippy::too_many_arguments)]
14391    pub(crate) fn routes_rank_section(
14392        &self,
14393        experts: &ResidentNvfp4TensorParallel,
14394        workspace: &mut Nvfp4DeviceRoutesWorkspace,
14395        raw_input_src: u64,
14396        local_out: usize,
14397        n_sel: usize,
14398        activation_limit: Option<f32>,
14399        rank_index: usize,
14400    ) -> Result<(), Box<dyn std::error::Error>> {
14401        let engine = &self.ranks[rank_index];
14402        {
14403            let _main = engine.gpu.enter_main()?;
14404            // sel/route_w land via raw copies from the e staging (fixed addresses).
14405            let (sel_e_ptr, w_e_ptr) = workspace
14406                .raw_dev_route_e
14407                .ok_or("routes rank section requires armed staging pointers")?;
14408            raw_copy_bytes(
14409                workspace.raw_input[rank_index],
14410                raw_input_src,
14411                experts.input_width * 4,
14412                engine,
14413            )?;
14414            raw_copy_bytes(workspace.raw_sel[rank_index], sel_e_ptr, n_sel * 4, engine)?;
14415            raw_copy_bytes(
14416                workspace.raw_route_w[rank_index],
14417                w_e_ptr,
14418                n_sel * 4,
14419                engine,
14420            )?;
14421            {
14422                let Nvfp4DeviceRoutesWorkspace {
14423                    input, in_q, in_d, ..
14424                } = &mut *workspace;
14425                engine.quantize_q8_1_into(
14426                    &input[rank_index],
14427                    1,
14428                    experts.input_width,
14429                    &mut in_q[rank_index],
14430                    &mut in_d[rank_index],
14431                )?;
14432            }
14433        }
14434        self.nvfp4_routes_batched_sweeps_rank(
14435            experts,
14436            workspace,
14437            &[],
14438            &[],
14439            &[],
14440            local_out,
14441            n_sel,
14442            activation_limit,
14443            true,
14444            rank_index,
14445        )
14446    }
14447
14448    /// The routes ROOT combine section (event-free): peer accumulator read (raw), canonical
14449    /// add, combined row raw-copied into the fixed e-context out stage.
14450    pub(crate) fn routes_root_section(
14451        &self,
14452        experts: &ResidentNvfp4TensorParallel,
14453        workspace: &mut Nvfp4DeviceRoutesWorkspace,
14454    ) -> Result<(), Box<dyn std::error::Error>> {
14455        let root = &self.ranks[0];
14456        let _main = root.gpu.enter_main()?;
14457        let (acc1_ptr, remote_ptr, combined_ptr, out_stage_ptr) = workspace
14458            .raw_combine
14459            .ok_or("routes root section requires armed combine pointers")?;
14460        raw_copy_bytes(remote_ptr, acc1_ptr, experts.input_width * 4, root)?;
14461        {
14462            let Nvfp4DeviceRoutesWorkspace {
14463                accumulator,
14464                remote,
14465                combined,
14466                ..
14467            } = &mut *workspace;
14468            root.add(&accumulator[0], remote, combined, experts.input_width)?;
14469        }
14470        raw_copy_bytes(out_stage_ptr, combined_ptr, experts.input_width * 4, root)?;
14471        Ok(())
14472    }
14473
14474    /// Arm the routes raw pointers (once): staging pair, per-rank input/sel/route_w, and the
14475    /// combine set. Requires dev_route_e + in/out stages already allocated.
14476    pub(crate) fn routes_arm_raw(
14477        &self,
14478        experts: &ResidentNvfp4TensorParallel,
14479        workspace: &mut Nvfp4DeviceRoutesWorkspace,
14480    ) -> Result<(), Box<dyn std::error::Error>> {
14481        use cudarc::driver::DevicePtr;
14482        if workspace.raw_dev_route_e.is_some() {
14483            return Ok(());
14484        }
14485        let _ = experts;
14486        let (sel_e, w_e) = workspace
14487            .dev_route_e
14488            .as_ref()
14489            .ok_or("routes staging not armed")?;
14490        let root = &self.ranks[0];
14491        {
14492            let _main = root.gpu.enter_main()?;
14493            let stream = root.stream();
14494            let (a, _g) = sel_e.device_ptr(&stream);
14495            let (b, _g) = w_e.device_ptr(&stream);
14496            workspace.raw_dev_route_e = Some((a, b));
14497            let (c, _g) = workspace.accumulator[1].device_ptr(&stream);
14498            let (d, _g) = workspace.remote.device_ptr(&stream);
14499            let (f, _g) = workspace.combined.device_ptr(&stream);
14500            let out_stage = workspace
14501                .out_stage_e
14502                .as_ref()
14503                .ok_or("routes out stage not armed")?;
14504            let (g_, _g) = out_stage.device_ptr(&stream);
14505            workspace.raw_combine = Some((c, d, f, g_));
14506        }
14507        for rank in 0..self.ranks.len() {
14508            let engine = &self.ranks[rank];
14509            let _main = engine.gpu.enter_main()?;
14510            let stream = engine.stream();
14511            let (a, _g) = workspace.input[rank].device_ptr(&stream);
14512            let (b, _g) = workspace.sel[rank].device_ptr(&stream);
14513            let (c, _g) = workspace.route_w[rank].device_ptr(&stream);
14514            workspace.raw_input.push(a);
14515            workspace.raw_sel.push(b);
14516            workspace.raw_route_w.push(c);
14517        }
14518        Ok(())
14519    }
14520
14521    /// Routed NVFP4 expert program, host-canonical transport. Native/bulk P2P transport for the
14522    /// NVFP4 bank is a separate increment; this entry point is exactness-first and reports no
14523    /// throughput claim.
14524    #[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
14525    pub fn run_tensor_parallel_routes_nvfp4(
14526        &self,
14527        experts: &ResidentNvfp4TensorParallel,
14528        input: &[f32],
14529        tokens: usize,
14530        selected: &[usize],
14531        route_weights: &[f32],
14532        experts_per_token: usize,
14533        activation_limit: Option<f32>,
14534    ) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
14535        validate_activations(input, tokens, experts.input_width)?;
14536        let pairs = tokens
14537            .checked_mul(experts_per_token)
14538            .ok_or("NVFP4 TP route count overflow")?;
14539        if selected.len() != pairs || route_weights.len() != pairs {
14540            return Err(format!(
14541                "NVFP4 TP routes selected={} weights={} != tokens {tokens} x experts/token \
14542                 {experts_per_token} ({pairs})",
14543                selected.len(),
14544                route_weights.len(),
14545            )
14546            .into());
14547        }
14548        if !route_weights.iter().all(|weight| weight.is_finite()) {
14549            return Err("NVFP4 TP route weights contain a non-finite value".into());
14550        }
14551
14552        let mut output = vec![0.0f32; tokens * experts.input_width];
14553        for token in 0..tokens {
14554            let input_row = &input[token * experts.input_width..(token + 1) * experts.input_width];
14555            for slot in 0..experts_per_token {
14556                let pair = token * experts_per_token + slot;
14557                let expert = selected[pair];
14558                if expert >= experts.expert_count {
14559                    return Err(format!(
14560                        "NVFP4 TP selected expert {expert} outside 0..{}",
14561                        experts.expert_count
14562                    )
14563                    .into());
14564                }
14565                let gate = self.run_column_bank_expert_nvfp4(
14566                    &experts.gate,
14567                    &experts.macros_gate,
14568                    expert,
14569                    input_row,
14570                )?;
14571                let up = self.run_column_bank_expert_nvfp4(
14572                    &experts.up,
14573                    &experts.macros_up,
14574                    expert,
14575                    input_row,
14576                )?;
14577                let activated: Vec<f32> = gate
14578                    .iter()
14579                    .zip(&up)
14580                    .map(|(&gate, &up)| step_expert_activation_host(gate, up, activation_limit))
14581                    .collect();
14582                debug_assert_eq!(activated.len(), experts.expert_width);
14583                let down = self.run_row_bank_expert_nvfp4(
14584                    &experts.down,
14585                    &experts.macros_down,
14586                    expert,
14587                    &activated,
14588                )?;
14589                let weight = route_weights[pair];
14590                for (sum, value) in output
14591                    [token * experts.input_width..(token + 1) * experts.input_width]
14592                    .iter_mut()
14593                    .zip(down)
14594                {
14595                    *sum += weight * value;
14596                }
14597            }
14598        }
14599        Ok(output)
14600    }
14601}
14602
14603#[cfg(test)]
14604mod default_on_door_tests {
14605    use super::door_default_on_value;
14606
14607    /// The DEFAULT-ON parse, pinned in every state — including the two that only matter because
14608    /// the default is ON.
14609    ///
14610    /// While these doors were default OFF the parse was `== Ok("1")` and its failure mode was
14611    /// benign: any typo read as the default, which was OFF, which was the safe program. Flipping
14612    /// the default INVERTS that. Under a naive `!= Ok("0")` rule, `MEMRA_NVFP4_BANK_SM=false`
14613    /// (or `=off`, or `=no`) would leave the program ARMED while the operator believed they had
14614    /// rolled it back — a rollback seam that silently does nothing, on the exact door whose
14615    /// predecessor shipped fluent wrong text. So the unrecognized-value case is a named,
14616    /// tested branch that keeps the default AND warns, rather than an accident of `!=`.
14617    #[test]
14618    fn the_default_on_door_parses_every_state_and_names_its_source() {
14619        // unset: the flip is what arms it, and the source string says so — this is the string a
14620        // default-flip receipt needs, because in the flip arms there is no env var to point at.
14621        assert_eq!(
14622            door_default_on_value("MEMRA_TEST_DOOR", None),
14623            (true, "default-on")
14624        );
14625        // explicit 1: armed by a RECIPE, not by the default. Different fact, different label.
14626        assert_eq!(
14627            door_default_on_value("MEMRA_TEST_DOOR", Some("1")),
14628            (true, "env=1")
14629        );
14630        // THE ROLLBACK SEAM. This is the assertion the flip's safety rests on.
14631        assert_eq!(
14632            door_default_on_value("MEMRA_TEST_DOOR", Some("0")),
14633            (false, "env=0 (rollback seam)")
14634        );
14635        // Unrecognized values keep the DEFAULT (ON) and are flagged as such, for every shape an
14636        // operator plausibly types when they mean "off". Every one of these MUST still read ON:
14637        // a parse that guessed "off" from `false` would be a second, undocumented seam, and a
14638        // parse that guessed "off" from `2` would make a typo a silent program change.
14639        for bad in [
14640            "false", "off", "no", "", " 0", "0 ", "00", "true", "2", "-1",
14641        ] {
14642            let (on, source) = door_default_on_value("MEMRA_TEST_DOOR", Some(bad));
14643            assert!(on, "value {bad:?} must NOT disarm a default-ON door");
14644            assert!(
14645                source.contains("default-on") && source.contains("unrecognized"),
14646                "value {bad:?} gave source {source:?}, which does not announce itself as an \
14647                 ignored value — a receipt reader would take it for a clean default"
14648            );
14649        }
14650    }
14651}
14652
14653#[cfg(test)]
14654mod bank_v2_layout_tests {
14655    use super::{nvfp4_matrix_v2_permute, nvfp4_row_bytes};
14656
14657    /// The slot-major permutation had NO test at all until 2026-08-29, while its (since
14658    /// removed) `MEMRA_NVFP4_BANK_V2` FLAGS row carried a bit-identity claim and the live
14659    /// serving env pinned it on. This pins the DOCUMENTED mapping so a reader can be checked
14660    /// against something: per row, slot g's 16 qs bytes land contiguously at `g*16`, and its
14661    /// two UE4M3 scale bytes at `nslots*16 + g*2`. Source layout is memra `block_nvfp4`:
14662    /// 36-byte superblocks of [4 scale bytes | 32 packed e2m1], two 32-value slots per
14663    /// superblock. The permutation's consumers are the slot-major TP shard banks
14664    /// (`MEMRA_NVFP4_BANK_SM`, `nvfp4_repack_bank_matrix(_, true)`) and the
14665    /// `qmatvec_nvfp4_fast_v2` oracle, which read this exact mapping.
14666    #[test]
14667    fn the_v2_bank_row_is_the_documented_slot_major_permutation() {
14668        // two rows, in_features 128 => 2 superblocks/row, 4 slots/row, 72 bytes/row.
14669        let (out_f, in_f) = (2usize, 128usize);
14670        let row_bytes = nvfp4_row_bytes(in_f);
14671        assert_eq!(row_bytes, 72);
14672        let v1: Vec<u8> = (0..out_f * row_bytes).map(|i| (i % 251) as u8).collect();
14673        let v2 = nvfp4_matrix_v2_permute(&v1, out_f, in_f);
14674        assert_eq!(v2.len(), v1.len(), "a permutation cannot change the size");
14675        let n_slots = in_f / 32;
14676        for row in 0..out_f {
14677            let src = &v1[row * row_bytes..(row + 1) * row_bytes];
14678            let dst = &v2[row * row_bytes..(row + 1) * row_bytes];
14679            for g in 0..n_slots {
14680                let (sblk, h) = (g / 2, g % 2);
14681                let sb = &src[sblk * 36..sblk * 36 + 36];
14682                assert_eq!(
14683                    &dst[g * 16..g * 16 + 16],
14684                    &sb[4 + 16 * h..4 + 16 * h + 16],
14685                    "row {row} slot {g} codes"
14686                );
14687                assert_eq!(
14688                    &dst[n_slots * 16 + g * 2..n_slots * 16 + g * 2 + 2],
14689                    &sb[2 * h..2 * h + 2],
14690                    "row {row} slot {g} scales"
14691                );
14692            }
14693            // and it moves bytes only: same multiset per row, rows never cross.
14694            let (mut a, mut b) = (src.to_vec(), dst.to_vec());
14695            a.sort_unstable();
14696            b.sort_unstable();
14697            assert_eq!(a, b, "row {row} is not a byte permutation");
14698        }
14699    }
14700}
14701
14702#[cfg(test)]
14703mod tests {
14704
14705    #[test]
14706    fn replicated_row_join_is_strictly_tp2_native_and_nonempty() {
14707        assert!(super::validate_tp2_replicated_row_join(2, true, 4096).is_ok());
14708        assert!(
14709            super::validate_tp2_replicated_row_join(1, true, 4096)
14710                .unwrap_err()
14711                .contains("exactly two ranks")
14712        );
14713        assert!(
14714            super::validate_tp2_replicated_row_join(4, true, 4096)
14715                .unwrap_err()
14716                .contains("exactly two ranks")
14717        );
14718        assert!(
14719            super::validate_tp2_replicated_row_join(2, false, 4096)
14720                .unwrap_err()
14721                .contains("native P2P")
14722        );
14723        assert!(super::validate_tp2_replicated_row_join(2, true, 0).is_err());
14724    }
14725
14726    #[test]
14727    fn door_composition_refuses_first_armed_flag_by_name() {
14728        let table: [(&str, &str); 2] = [
14729            ("MEMRA_DOOR_A", "gated on the unsharded walk only"),
14730            ("MEMRA_DOOR_B", "no sharded branches"),
14731        ];
14732        // cold doors pass
14733        super::refuse_door_composition("MEMRA_X_TP", &table, |_| false).expect("cold doors pass");
14734        // an armed door refuses with the exact byte format the glm5 gate asserts on
14735        let err = super::refuse_door_composition("MEMRA_X_TP", &table, |f| f == "MEMRA_DOOR_B")
14736            .expect_err("armed door must refuse");
14737        assert_eq!(
14738            err,
14739            "MEMRA_X_TP + MEMRA_DOOR_B: unproven composition, refused (no sharded branches)"
14740        );
14741        // a flag outside the table never trips it
14742        super::refuse_door_composition("MEMRA_X_TP", &table, |f| f == "MEMRA_DOOR_C")
14743            .expect("foreign flags are not the matrix");
14744    }
14745
14746    /// THE DEFECT, ASSERTED SO IT CANNOT COME BACK. The retired memo key hashed only the K
14747    /// pointer, the base pointer, the layer and t, while the table it returned ALSO carried
14748    /// the V and LEN pointers. Two different allocation generations that happen to share a K
14749    /// address therefore collide, and the entry the map hands back sends a live launch at
14750    /// another allocation's V and len. This test does not assert the key is fine; it asserts
14751    /// the key is BLIND, which is why `rows_tab_restage_on` exists and defaults ON.
14752    #[test]
14753    fn the_retired_rows_tab_key_cannot_see_the_v_and_len_pointers_it_hands_back() {
14754        let (kp, bp) = (0xdead_0000u64, 0u64);
14755        let live = [[kp, 0x00b1_0000u64, 0x00c1_0000u64, bp]];
14756        let recycled = [[kp, 0x00b2_0000u64, 0x00c2_0000u64, bp]];
14757        assert_eq!(
14758            super::retired_rows_tab_key(kp, bp, 20, 2),
14759            super::retired_rows_tab_key(kp, bp, 20, 2),
14760            "same layer and t must hash the same, or the test proves nothing"
14761        );
14762        let a = super::rows_tab_host(&live, 0x9000, true, 1);
14763        let b = super::rows_tab_host(&recycled, 0x9000, true, 1);
14764        assert_ne!(a, b, "the two generations write DIFFERENT tables");
14765        // ... yet one key covers both, which is exactly the use-after-free.
14766        assert_eq!(
14767            super::retired_rows_tab_key(live[0][0], live[0][3], 20, 1),
14768            super::retired_rows_tab_key(recycled[0][0], recycled[0][3], 20, 1),
14769            "the retired key collides across allocation generations"
14770        );
14771    }
14772
14773    /// The restage must be VALUE-NEUTRAL: on a fresh lookup the memo and the restage produce
14774    /// identical bytes, which is what makes spec-on output byte-identical to spec-off.
14775    #[test]
14776    fn rows_tab_layout_is_the_same_bytes_the_memo_would_have_cached() {
14777        let parts = [
14778            [0x00a0u64, 0x00b0u64, 0x00c0u64, 0x00d0u64],
14779            [0x00a1u64, 0x00b1u64, 0x00c1u64, 0x00d1u64],
14780        ];
14781        let same = super::rows_tab_host(&parts, 0x7000, true, 2);
14782        assert_eq!(
14783            same,
14784            vec![
14785                0x00a0u64, 0x00b0u64, 0x00c0u64, 0x00d0u64, 0x7000,
14786                1, // row 0: back = t-1-r = 1
14787                0x00a1u64, 0x00b1u64, 0x00c1u64, 0x00d1u64, 0x7000, 0, // row 1: back = 0
14788            ],
14789            "same-session rows share one counter cell and step back t-1-r"
14790        );
14791        let cross = super::rows_tab_host(&parts, 0x7000, false, 2);
14792        assert_eq!(
14793            cross,
14794            vec![
14795                0x00a0u64, 0x00b0u64, 0x00c0u64, 0x00d0u64, 0x7000, 0, 0x00a1u64, 0x00b1u64,
14796                0x00c1u64, 0x00d1u64, 0x7004, 0,
14797            ],
14798            "cross-session rows get their own counter cell and no step back"
14799        );
14800    }
14801    use super::*;
14802
14803    #[test]
14804    fn step_expert_activation_clamps_each_arm_by_the_official_contract() {
14805        let limit = Some(7.0);
14806        assert_eq!(step_expert_activation_host(20.0, 9.0, limit), 49.0);
14807        assert_eq!(step_expert_activation_host(20.0, -9.0, limit), -49.0);
14808        assert!(
14809            step_expert_activation_host(-20.0, 9.0, limit).abs()
14810                < step_expert_activation_host(-20.0, 9.0, None).abs()
14811        );
14812        assert!(validate_step_expert_activation_limit(Some(f32::NAN)).is_err());
14813        assert!(validate_step_expert_activation_limit(Some(0.0)).is_err());
14814        assert!(validate_step_expert_activation_limit(limit).is_ok());
14815    }
14816
14817    #[test]
14818    fn moe_residual_host_preserves_official_add_order() {
14819        let output = moe_residual_host(&[1.0e20], &[-1.0e20], &[1.0]).unwrap();
14820        assert_eq!(output, [0.0]);
14821        assert_eq!(
14822            moe_residual_host(&[0.0], &[0.0, 1.0], &[0.0]).unwrap_err(),
14823            "MoE residual lengths residual=1 routed=2 shared=1"
14824        );
14825    }
14826
14827    #[test]
14828    fn expert_owner_routes_preserve_global_pair_order_with_local_expert_ids() {
14829        let selected = [0, 36, 72, 108, 144, 180, 216, 252];
14830        let owners = partition_expert_owner_routes(288, 4, 1, 8, &selected).unwrap();
14831        assert_eq!(owners.len(), 4);
14832        for (rank, owner) in owners.iter().enumerate() {
14833            assert_eq!(owner.rank, rank);
14834            assert_eq!(owner.selected, vec![0, 36]);
14835            assert_eq!(owner.token_rows, vec![0, 0]);
14836            assert_eq!(owner.global_pairs, vec![rank * 2, rank * 2 + 1]);
14837        }
14838    }
14839
14840    #[test]
14841    fn expert_owner_routes_validate_geometry_and_selected_experts() {
14842        assert!(partition_expert_owner_routes(288, 5, 1, 8, &[0; 8]).is_err());
14843        assert!(partition_expert_owner_routes(288, 4, 2, 8, &[0; 8]).is_err());
14844        let error = partition_expert_owner_routes(288, 4, 1, 8, &[288; 8]).unwrap_err();
14845        assert!(error.contains("outside 0..288"));
14846    }
14847
14848    #[test]
14849    fn step_grouped_owner_routes_validate_dynamic_top8_shapes() {
14850        let selected = [
14851            1, 73, 80, 145, 152, 159, 217, 224, 12, 84, 91, 156, 163, 170, 228, 235,
14852        ];
14853        assert_eq!(
14854            validate_step_grouped_owner_routes(288, 2, &selected).unwrap(),
14855            16
14856        );
14857        let owners = partition_expert_owner_routes(288, 4, 2, 8, &selected).unwrap();
14858        assert_eq!(
14859            owners
14860                .iter()
14861                .map(|owner| owner.selected.len())
14862                .collect::<Vec<_>>(),
14863            vec![2, 4, 6, 4]
14864        );
14865        assert!(validate_step_grouped_owner_routes(288, 2, &selected[..8]).is_err());
14866        assert!(validate_step_grouped_owner_routes(288, 1, &[0; 8]).is_err());
14867        assert!(validate_step_grouped_owner_routes(287, 2, &selected).is_err());
14868    }
14869
14870    #[test]
14871    fn weighted_route_combine_requires_a_canonical_pair_permutation() {
14872        let owner0 = [0usize, 3];
14873        let owner1 = [1usize, 2];
14874        let owners = [owner0.as_slice(), owner1.as_slice()];
14875        assert_eq!(
14876            validate_weighted_route_combine(4096, 4, 3, 1, &owners, &[0.1, 0.2, 0.3, 0.4],)
14877                .unwrap(),
14878            WeightedRouteCombineShape {
14879                pairs: 4,
14880                max_pairs: 12,
14881            }
14882        );
14883        let duplicate = [owner0.as_slice(), &[1usize, 1][..]];
14884        assert!(
14885            validate_weighted_route_combine(4096, 4, 3, 1, &duplicate, &[0.1, 0.2, 0.3, 0.4],)
14886                .is_err()
14887        );
14888        assert!(
14889            validate_weighted_route_combine(4096, 4, 3, 1, &owners, &[0.1, f32::NAN, 0.3, 0.4],)
14890                .is_err()
14891        );
14892        assert!(
14893            validate_weighted_route_combine(4096, 4, 1, 2, &owners, &[0.1, 0.2, 0.3, 0.4],)
14894                .is_err()
14895        );
14896    }
14897
14898    #[test]
14899    fn native_p2p_door_is_strict_and_default_off() {
14900        assert!(!parse_step_tp_native_p2p(None).unwrap());
14901        assert!(!parse_step_tp_native_p2p(Some("")).unwrap());
14902        assert!(!parse_step_tp_native_p2p(Some("0")).unwrap());
14903        assert!(parse_step_tp_native_p2p(Some("1")).unwrap());
14904        assert!(parse_step_tp_native_p2p(Some("true")).is_err());
14905        assert!(parse_step_tp_native_p2p(Some("2")).is_err());
14906    }
14907
14908    #[test]
14909    fn bulk_p2p_door_is_strict_and_default_off() {
14910        assert!(!parse_step_tp_bulk_p2p(None).unwrap());
14911        assert!(!parse_step_tp_bulk_p2p(Some("")).unwrap());
14912        assert!(!parse_step_tp_bulk_p2p(Some("0")).unwrap());
14913        assert!(parse_step_tp_bulk_p2p(Some("1")).unwrap());
14914        assert!(parse_step_tp_bulk_p2p(Some("true")).is_err());
14915        assert!(parse_step_tp_bulk_p2p(Some("2")).is_err());
14916    }
14917
14918    #[test]
14919    fn ep_device_arithmetic_door_is_strict_and_default_off() {
14920        assert!(!parse_step_ep_device_arithmetic(None).unwrap());
14921        assert!(!parse_step_ep_device_arithmetic(Some("")).unwrap());
14922        assert!(!parse_step_ep_device_arithmetic(Some("0")).unwrap());
14923        assert!(parse_step_ep_device_arithmetic(Some("1")).unwrap());
14924        assert!(parse_step_ep_device_arithmetic(Some("true")).is_err());
14925        assert!(parse_step_ep_device_arithmetic(Some("2")).is_err());
14926    }
14927
14928    #[test]
14929    fn f32_mirror_door_is_strict_and_default_off() {
14930        assert!(!parse_step_tp_f32_mirror(None).unwrap());
14931        assert!(!parse_step_tp_f32_mirror(Some("")).unwrap());
14932        assert!(!parse_step_tp_f32_mirror(Some("0")).unwrap());
14933        assert!(parse_step_tp_f32_mirror(Some("1")).unwrap());
14934        assert!(parse_step_tp_f32_mirror(Some("true")).is_err());
14935        assert!(parse_step_tp_f32_mirror(Some("2")).is_err());
14936    }
14937
14938    fn matrix(out_features: usize, in_features: usize) -> (Vec<u8>, Vec<f32>) {
14939        let codes = (0..out_features * in_features)
14940            .map(|index| (index % 251) as u8)
14941            .collect();
14942        let scales = (0..out_features.div_ceil(FP8_BLOCK) * in_features.div_ceil(FP8_BLOCK))
14943            .map(|index| index as f32 + 1.0)
14944            .collect();
14945        (codes, scales)
14946    }
14947
14948    fn bf16_matrix_bytes(out_features: usize, in_features: usize) -> Vec<u8> {
14949        (0..out_features * in_features)
14950            .flat_map(|value| (value as u16).to_le_bytes())
14951            .collect()
14952    }
14953
14954    fn decode_u16(bytes: &[u8]) -> Vec<u16> {
14955        bytes
14956            .chunks_exact(2)
14957            .map(|bytes| u16::from_le_bytes([bytes[0], bytes[1]]))
14958            .collect()
14959    }
14960
14961    #[test]
14962    fn bf16_matrix_rejects_wrong_byte_count() {
14963        let bytes = vec![0u8; 4 * 4 * 2 - 1];
14964        let matrix = Bf16Matrix {
14965            bytes: &bytes,
14966            out_features: 4,
14967            in_features: 4,
14968        };
14969        assert!(matrix.validate().unwrap_err().contains("4x4x2"));
14970    }
14971
14972    #[test]
14973    fn replicated_device_rows_require_exact_rank_local_shapes() {
14974        assert_eq!(
14975            replicated_device_row_values(3, 4096, 4, &[12_288; 4]).unwrap(),
14976            12_288
14977        );
14978        assert!(replicated_device_row_values(0, 4096, 4, &[0; 4]).is_err());
14979        assert!(replicated_device_row_values(3, 0, 4, &[0; 4]).is_err());
14980        assert!(replicated_device_row_values(3, 4096, 4, &[12_288; 3]).is_err());
14981        assert!(
14982            replicated_device_row_values(3, 4096, 4, &[12_288, 12_288, 12_287, 12_288]).is_err()
14983        );
14984        assert!(replicated_device_row_values(usize::MAX, 2, 1, &[0]).is_err());
14985    }
14986
14987    #[test]
14988    fn replicated_device_row_refresh_requires_exact_root_source() {
14989        assert_eq!(
14990            replicated_device_row_source_values(1, 12_288, 12_288, 3, 3).unwrap(),
14991            12_288
14992        );
14993        assert!(replicated_device_row_source_values(0, 12_288, 0, 3, 3).is_err());
14994        assert!(replicated_device_row_source_values(1, 0, 0, 3, 3).is_err());
14995        assert!(replicated_device_row_source_values(1, 12_288, 12_287, 3, 3).is_err());
14996        assert!(replicated_device_row_source_values(1, 12_288, 12_288, 2, 3).is_err());
14997        assert!(replicated_device_row_source_values(usize::MAX, 2, 0, 3, 3).is_err());
14998    }
14999
15000    #[test]
15001    fn step_bf16_canonical_rows_are_topology_invariant_through_tp8() {
15002        for tp in [1, 2, 4, 8] {
15003            assert_eq!(step_bf16_canonical_chunk_rows(8_192, tp).unwrap(), 1_024);
15004            assert_eq!(step_bf16_canonical_chunk_rows(12_288, tp).unwrap(), 1_536);
15005            assert_eq!(step_bf16_canonical_chunk_rows(1_024, tp).unwrap(), 128);
15006            assert_eq!(step_bf16_canonical_chunk_cols(8_192, tp).unwrap(), 1_024);
15007            assert_eq!(step_bf16_canonical_chunk_cols(12_288, tp).unwrap(), 1_536);
15008        }
15009        assert!(step_bf16_canonical_chunk_rows(12_288, 3).is_err());
15010        assert!(step_bf16_canonical_chunk_rows(1_001, 2).is_err());
15011        assert!(step_bf16_canonical_chunk_cols(12_288, 3).is_err());
15012        assert!(step_bf16_canonical_chunk_cols(1_001, 2).is_err());
15013    }
15014
15015    #[test]
15016    fn cache_rows_split_by_token_then_rank() {
15017        let rows = (0u8..24).collect::<Vec<_>>();
15018        assert_eq!(
15019            cache_rank_rows(&rows, 3, 4, 2, 0).unwrap(),
15020            vec![0, 1, 2, 3, 8, 9, 10, 11, 16, 17, 18, 19]
15021        );
15022        assert_eq!(
15023            cache_rank_rows(&rows, 3, 4, 2, 1).unwrap(),
15024            vec![4, 5, 6, 7, 12, 13, 14, 15, 20, 21, 22, 23]
15025        );
15026        assert!(cache_rank_rows(&rows[..23], 3, 4, 2, 0).is_err());
15027        assert!(cache_rank_rows(&rows, 3, 4, 2, 2).is_err());
15028    }
15029
15030    #[test]
15031    fn bf16_column_shard_preserves_contiguous_output_rows() {
15032        let bytes = bf16_matrix_bytes(4, 4);
15033        let matrix = Bf16Matrix {
15034            bytes: &bytes,
15035            out_features: 4,
15036            in_features: 4,
15037        };
15038        let shard = bf16_column_shard(matrix, 2, 1).unwrap();
15039        assert_eq!(shard.out_features, 2);
15040        assert_eq!(shard.in_features, 4);
15041        assert_eq!(decode_u16(shard.bytes), (8..16).collect::<Vec<_>>());
15042    }
15043
15044    #[test]
15045    fn bf16_row_shard_preserves_each_input_column_window() {
15046        let bytes = bf16_matrix_bytes(3, 4);
15047        let matrix = Bf16Matrix {
15048            bytes: &bytes,
15049            out_features: 3,
15050            in_features: 4,
15051        };
15052        let shard = bf16_row_shard(matrix, 2, 1).unwrap();
15053        assert_eq!(decode_u16(&shard), vec![2, 3, 6, 7, 10, 11]);
15054    }
15055
15056    #[test]
15057    fn bf16_row_block_preserves_global_column_order() {
15058        let bytes = bf16_matrix_bytes(3, 8);
15059        let matrix = Bf16Matrix {
15060            bytes: &bytes,
15061            out_features: 3,
15062            in_features: 8,
15063        };
15064        let block = bf16_row_block(matrix, 2, 3).unwrap();
15065        assert_eq!(decode_u16(&block), vec![2, 3, 4, 10, 11, 12, 18, 19, 20]);
15066    }
15067
15068    #[test]
15069    fn column_shard_preserves_contiguous_weight_and_scale_rows() {
15070        let (codes, scales) = matrix(1280, 4096);
15071        let matrix = E4m3BlockMatrix {
15072            codes: &codes,
15073            scales: &scales,
15074            out_features: 1280,
15075            in_features: 4096,
15076        };
15077        let shard = column_shard(matrix, 2, 1).unwrap();
15078        assert_eq!(shard.out_features, 640);
15079        assert_eq!(shard.codes, &codes[640 * 4096..]);
15080        assert_eq!(shard.scales, &scales[5 * 32..]);
15081    }
15082
15083    #[test]
15084    fn row_shard_preserves_each_weight_and_scale_column_window() {
15085        let (codes, scales) = matrix(4096, 1280);
15086        let matrix = E4m3BlockMatrix {
15087            codes: &codes,
15088            scales: &scales,
15089            out_features: 4096,
15090            in_features: 1280,
15091        };
15092        let (shard_codes, shard_scales) = row_shard(matrix, 2, 1).unwrap();
15093        assert_eq!(shard_codes.len(), 4096 * 640);
15094        assert_eq!(&shard_codes[..640], &codes[640..1280]);
15095        assert_eq!(&shard_codes[640..1280], &codes[1280 + 640..2560]);
15096        assert_eq!(shard_scales.len(), 32 * 5);
15097        assert_eq!(&shard_scales[..5], &scales[5..10]);
15098        assert_eq!(&shard_scales[5..10], &scales[15..20]);
15099    }
15100
15101    #[test]
15102    fn activation_shards_keep_token_rows_separate() {
15103        let activations: Vec<f32> = (0..2 * 8).map(|value| value as f32).collect();
15104        assert_eq!(
15105            activation_shard(&activations, 2, 8, 2, 1),
15106            vec![4.0, 5.0, 6.0, 7.0, 12.0, 13.0, 14.0, 15.0],
15107        );
15108    }
15109
15110    #[test]
15111    fn expert_bank_selects_expert_major_code_and_scale_planes() {
15112        let expert_count = 2;
15113        let out_features = 128;
15114        let in_features = 128;
15115        let code_stride = out_features * in_features;
15116        let codes: Vec<u8> = (0..expert_count * code_stride)
15117            .map(|index| (index % 251) as u8)
15118            .collect();
15119        let scales = vec![1.0f32, 2.0];
15120        let bank = E4m3ExpertBank {
15121            codes: &codes,
15122            scales: &scales,
15123            expert_count,
15124            out_features,
15125            in_features,
15126        };
15127        bank.validate().unwrap();
15128        let expert = bank.expert(1).unwrap();
15129        assert_eq!(expert.codes, &codes[code_stride..]);
15130        assert_eq!(expert.scales, &[2.0]);
15131    }
15132
15133    #[test]
15134    fn expert_bank_rejects_non_positive_scale() {
15135        let codes = vec![0u8; 128 * 128];
15136        let scales = vec![0.0f32];
15137        let bank = E4m3ExpertBank {
15138            codes: &codes,
15139            scales: &scales,
15140            expert_count: 1,
15141            out_features: 128,
15142            in_features: 128,
15143        };
15144        assert!(bank.validate().unwrap_err().contains("non-positive"));
15145    }
15146
15147    #[test]
15148    fn tensor_parallel_column_bank_keeps_each_expert_scale_plane_separate() {
15149        let expert_count = 2;
15150        let out_features = 256;
15151        let in_features = 128;
15152        let code_stride = out_features * in_features;
15153        let scale_stride = 2;
15154        let codes = (0..expert_count * code_stride)
15155            .map(|index| (index % 251) as u8)
15156            .collect::<Vec<_>>();
15157        let scales = vec![10.0f32, 11.0, 20.0, 21.0];
15158        let bank = E4m3ExpertBank {
15159            codes: &codes,
15160            scales: &scales,
15161            expert_count,
15162            out_features,
15163            in_features,
15164        };
15165
15166        let rank = pack_column_bank_rank(bank, 2, 1).unwrap();
15167        assert_eq!(rank.out_features, 128);
15168        assert_eq!(rank.in_features, 128);
15169        assert_eq!(rank.codes.len(), expert_count * 128 * 128);
15170        assert_eq!(rank.scales, vec![11.0, 21.0]);
15171        assert_eq!(&rank.codes[..128 * 128], &codes[128 * 128..256 * 128]);
15172        assert_eq!(
15173            &rank.codes[128 * 128..],
15174            &codes[code_stride + 128 * 128..2 * code_stride]
15175        );
15176        assert_eq!(scale_stride, scales.len() / expert_count);
15177    }
15178
15179    #[test]
15180    fn tensor_parallel_row_bank_keeps_each_expert_scale_plane_separate() {
15181        let expert_count = 2;
15182        let out_features = 128;
15183        let in_features = 256;
15184        let code_stride = out_features * in_features;
15185        let codes = (0..expert_count * code_stride)
15186            .map(|index| (index % 251) as u8)
15187            .collect::<Vec<_>>();
15188        let scales = vec![10.0f32, 11.0, 20.0, 21.0];
15189        let bank = E4m3ExpertBank {
15190            codes: &codes,
15191            scales: &scales,
15192            expert_count,
15193            out_features,
15194            in_features,
15195        };
15196
15197        let rank = pack_row_bank_rank(bank, 2, 1).unwrap();
15198        assert_eq!(rank.out_features, 128);
15199        assert_eq!(rank.in_features, 128);
15200        assert_eq!(rank.k_blocks, Some(1));
15201        assert_eq!(rank.codes.len(), expert_count * 128 * 128);
15202        assert_eq!(rank.scales, vec![11.0, 21.0]);
15203        assert_eq!(&rank.codes[..128], &codes[128..256]);
15204        assert_eq!(
15205            &rank.codes[128 * 128..128 * 128 + 128],
15206            &codes[code_stride + 128..code_stride + 256]
15207        );
15208    }
15209
15210    #[test]
15211    fn tensor_parallel_row_bank_preserves_global_k_block_order() {
15212        let expert_count = 2;
15213        let out_features = 256;
15214        let in_features = 512;
15215        let code_stride = out_features * in_features;
15216        let mut codes = vec![0u8; expert_count * code_stride];
15217        for expert in 0..expert_count {
15218            for row in 0..out_features {
15219                for block in 0..4 {
15220                    let value = (expert * 80 + block * 16 + row % 16) as u8;
15221                    let start = expert * code_stride + row * in_features + block * FP8_BLOCK;
15222                    codes[start..start + FP8_BLOCK].fill(value);
15223                }
15224            }
15225        }
15226        let scales = vec![
15227            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,
15228            112.0, 113.0, 114.0,
15229        ];
15230        let bank = E4m3ExpertBank {
15231            codes: &codes,
15232            scales: &scales,
15233            expert_count,
15234            out_features,
15235            in_features,
15236        };
15237
15238        let rank = pack_row_bank_rank(bank, 2, 1).unwrap();
15239        assert_eq!(rank.out_features, out_features);
15240        assert_eq!(rank.in_features, 256);
15241        assert_eq!(rank.k_blocks, Some(2));
15242        assert_eq!(rank.code_stride, out_features * 256);
15243        assert_eq!(rank.scale_stride, 4);
15244        assert_eq!(&rank.scales[..4], &[3.0, 13.0, 4.0, 14.0]);
15245        assert_eq!(&rank.scales[4..], &[103.0, 113.0, 104.0, 114.0]);
15246
15247        let block_stride = out_features * FP8_BLOCK;
15248        assert!(rank.codes[..FP8_BLOCK].iter().all(|&code| code == 32));
15249        assert!(
15250            rank.codes[block_stride..block_stride + FP8_BLOCK]
15251                .iter()
15252                .all(|&code| code == 48)
15253        );
15254        assert!(
15255            rank.codes[rank.code_stride..rank.code_stride + FP8_BLOCK]
15256                .iter()
15257                .all(|&code| code == 112)
15258        );
15259        assert!(
15260            rank.codes
15261                [rank.code_stride + block_stride..rank.code_stride + block_stride + FP8_BLOCK]
15262                .iter()
15263                .all(|&code| code == 128)
15264        );
15265    }
15266
15267    #[test]
15268    fn automatic_parallel_policy_needs_only_one_device_set_not_layer_recipes() {
15269        assert_eq!(parse_auto_parallel_devices(None, None).unwrap(), None);
15270        assert_eq!(
15271            parse_auto_parallel_devices(Some("auto"), Some("0,1,2,3")).unwrap(),
15272            Some(vec![0, 1, 2, 3])
15273        );
15274        assert!(parse_auto_parallel_devices(Some("auto"), None).is_err());
15275        assert!(parse_auto_parallel_devices(Some("auto"), Some("0,1,1")).is_err());
15276        assert!(parse_auto_parallel_devices(Some("auto"), Some("0,1,2,3,4")).is_err());
15277        assert!(parse_auto_parallel_devices(Some("ep"), Some("0,1")).is_err());
15278    }
15279
15280    #[test]
15281    fn automatic_ep_device_router_flag_is_strict() {
15282        assert!(!parse_parallel_ep_device_router(None).unwrap());
15283        assert!(!parse_parallel_ep_device_router(Some("0")).unwrap());
15284        assert!(parse_parallel_ep_device_router(Some("1")).unwrap());
15285        assert!(parse_parallel_ep_device_router(Some("true")).is_err());
15286    }
15287
15288    #[test]
15289    fn automatic_ep_pair_down_flag_is_strict_and_defaults_off() {
15290        assert!(!parse_parallel_ep_pair_down(None).unwrap());
15291        assert!(!parse_parallel_ep_pair_down(Some("0")).unwrap());
15292        assert!(parse_parallel_ep_pair_down(Some("1")).unwrap());
15293        assert!(parse_parallel_ep_pair_down(Some("true")).is_err());
15294    }
15295
15296    #[test]
15297    fn automatic_ep_q8_activation_flag_is_strict() {
15298        assert!(!parse_parallel_ep_q8_act(None).unwrap());
15299        assert!(!parse_parallel_ep_q8_act(Some("0")).unwrap());
15300        assert!(parse_parallel_ep_q8_act(Some("1")).unwrap());
15301        assert!(parse_parallel_ep_q8_act(Some("true")).is_err());
15302    }
15303
15304    #[test]
15305    fn automatic_ep_q8_scope_is_explicit_and_strict() {
15306        assert_eq!(parse_parallel_ep_q8_scope(None).unwrap(), None);
15307        assert_eq!(
15308            parse_parallel_ep_q8_scope(Some("all")).unwrap(),
15309            Some(ParallelEpQ8Scope::All)
15310        );
15311        assert_eq!(
15312            parse_parallel_ep_q8_scope(Some("gate-up")).unwrap(),
15313            Some(ParallelEpQ8Scope::GateUp)
15314        );
15315        assert_eq!(
15316            parse_parallel_ep_q8_scope(Some("down")).unwrap(),
15317            Some(ParallelEpQ8Scope::Down)
15318        );
15319        assert!(parse_parallel_ep_q8_scope(Some("input")).is_err());
15320    }
15321
15322    #[test]
15323    fn w4a16_device_ep_accepts_a_capacity_backed_active_prefix() {
15324        let width = 4096;
15325        assert_eq!(
15326            nvfp4_ep_active_input_values(160 * width, 44, width).unwrap(),
15327            44 * width
15328        );
15329        assert_eq!(
15330            nvfp4_ep_active_input_values(44 * width, 44, width).unwrap(),
15331            44 * width
15332        );
15333        assert!(nvfp4_ep_active_input_values(43 * width, 44, width).is_err());
15334        assert!(
15335            nvfp4_ep_active_input_values(160 * width, NVFP4_EP_DEVICE_BATCH_CAP + 1, width)
15336                .is_err()
15337        );
15338    }
15339
15340    #[test]
15341    fn step_ep_layer_specs_are_literal_and_fail_closed() {
15342        assert!(parse_step_ep_layer_specs(None).unwrap().is_empty());
15343        assert!(parse_step_ep_layer_specs(Some("0")).unwrap().is_empty());
15344        assert_eq!(
15345            parse_step_ep_layer_specs(Some("24@1,2")).unwrap(),
15346            vec![StepEpLayerSpec {
15347                layer: 24,
15348                devices: vec![1, 2],
15349            }]
15350        );
15351        assert_eq!(
15352            parse_step_ep_layer_specs(Some("24-25@1,2;31@0,2")).unwrap(),
15353            vec![
15354                StepEpLayerSpec {
15355                    layer: 24,
15356                    devices: vec![1, 2],
15357                },
15358                StepEpLayerSpec {
15359                    layer: 25,
15360                    devices: vec![1, 2],
15361                },
15362                StepEpLayerSpec {
15363                    layer: 31,
15364                    devices: vec![0, 2],
15365                },
15366            ]
15367        );
15368        assert!(parse_step_ep_layer_specs(Some("24@1")).is_err());
15369        assert!(parse_step_ep_layer_specs(Some("24@1,1")).is_err());
15370        assert!(parse_step_ep_layer_specs(Some("layer@1,2")).is_err());
15371        assert!(parse_step_ep_layer_specs(Some("25-24@1,2")).is_err());
15372        assert!(parse_step_ep_layer_specs(Some("0-128@1,2")).is_err());
15373        assert!(parse_step_ep_layer_specs(Some("24-25@1,2;25@0,2")).is_err());
15374        assert!(parse_step_ep_layer_specs(Some("all@0,1")).is_err());
15375    }
15376
15377    #[test]
15378    fn step_tp_layer_specs_share_the_fail_closed_layer_contract() {
15379        assert!(parse_step_tp_layer_specs(None).unwrap().is_empty());
15380        assert!(parse_step_tp_layer_specs(Some("0")).unwrap().is_empty());
15381        assert_eq!(
15382            parse_step_tp_layer_specs(Some("24-25@1,2")).unwrap(),
15383            vec![
15384                StepTpLayerSpec {
15385                    layer: 24,
15386                    devices: vec![1, 2],
15387                },
15388                StepTpLayerSpec {
15389                    layer: 25,
15390                    devices: vec![1, 2],
15391                },
15392            ]
15393        );
15394        let error = parse_step_tp_layer_specs(Some("24@1")).unwrap_err();
15395        assert!(error.contains("MEMRA_STEP_TP"));
15396        assert!(parse_step_tp_layer_specs(Some("24@1,1")).is_err());
15397        assert!(parse_step_tp_layer_specs(Some("24-25@1,2;25@0,2")).is_err());
15398
15399        let all = parse_step_tp_layer_specs(Some("all@0,1,2,3,4,5,6,7")).unwrap();
15400        assert_eq!(all.len(), STEP37_TRUNK_LAYERS);
15401        assert_eq!(all.first().unwrap().layer, 0);
15402        assert_eq!(all.last().unwrap().layer, STEP37_TRUNK_LAYERS - 1);
15403        let devices = (0..8).collect::<Vec<_>>();
15404        assert!(all.iter().all(|spec| spec.devices == devices));
15405        assert!(parse_step_tp_layer_specs(Some("all@0,1;44@0,1")).is_err());
15406    }
15407}
15408
15409// ===== Whole-token graph builder (increment B) ==================================================
15410//
15411// The decode fns are already sectioned at every e/rank/root seam (the stage flow, sweeps_rank,
15412// finish splits, the dcw arm). `graph_section` is the one annotation those seams call: eager
15413// mode runs the closure verbatim; build mode wraps it in a stream capture on the section's
15414// device and records a child + its dependency edges. A token then assembles as ONE multi-device
15415// parent (children per section per layer), launched once per token — the launch-collapse the
15416// per-layer minis could not reach (routes-mini negative, 2026-08-21).
15417
15418/// One captured section: the child graph plus which parent node it became, and the CUDA
15419/// context it was captured under (exec memset updates need it).
15420struct TokenGraphChild {
15421    #[allow(dead_code)]
15422    // allow: keep-alive: the child graph must outlive the exec instantiated from it
15423    graph: cudarc::driver::CudaGraph,
15424    node: cudarc::driver::sys::CUgraphNode,
15425    ctx: cudarc::driver::sys::CUcontext,
15426}
15427
15428/// Exec-updatable fa geometry discovered in one attention rank child: the three partial-pool
15429/// memsets, the dcw fa kernel, and its combine — everything a bucket change touches. Node
15430/// handles address the parent's CLONED child graphs (the M1-probed update path).
15431struct TokenGraphFaSite {
15432    ctx: cudarc::driver::sys::CUcontext,
15433    memset_o: cudarc::driver::sys::CUgraphNode,
15434    memset_m: [cudarc::driver::sys::CUgraphNode; 2],
15435    fa: cudarc::driver::sys::CUgraphNode,
15436    combine: cudarc::driver::sys::CUgraphNode,
15437    window: usize,
15438    n_head: usize,
15439    n_head_kv: usize,
15440    head_dim: usize,
15441}
15442
15443pub struct TokenGraphBuilder {
15444    parent: cudarc::driver::sys::CUgraph,
15445    children: Vec<TokenGraphChild>,
15446    /// Nodes every NEXT section must depend on (the frontier): one node for serial flow,
15447    /// several while a parallel group is open.
15448    frontier: Vec<cudarc::driver::sys::CUgraphNode>,
15449    /// Detached sections: forked from the frontier at issue time, joined ONLY by the next
15450    /// non-group section (they never gate a parallel group merge — the SH1 shape).
15451    pending_detached: Vec<cudarc::driver::sys::CUgraphNode>,
15452    /// Open parallel group: sections issued under the same group id fork from the SAME
15453    /// predecessor set and merge into the frontier together when the group closes.
15454    group: Option<(
15455        u32,
15456        Vec<cudarc::driver::sys::CUgraphNode>,
15457        Vec<cudarc::driver::sys::CUgraphNode>,
15458    )>,
15459}
15460
15461// SAFETY: single decode thread; graph handles are process handles.
15462unsafe impl Send for TokenGraphBuilder {}
15463
15464impl TokenGraphBuilder {
15465    pub fn new() -> Result<Self, Box<dyn std::error::Error>> {
15466        use cudarc::driver::sys;
15467        let mut parent: sys::CUgraph = std::ptr::null_mut();
15468        let r = unsafe { sys::cuGraphCreate(&mut parent, 0) };
15469        if r != sys::CUresult::CUDA_SUCCESS {
15470            return Err(format!("token graph create: {r:?}").into());
15471        }
15472        Ok(Self {
15473            parent,
15474            children: Vec::new(),
15475            frontier: Vec::new(),
15476            pending_detached: Vec::new(),
15477            group: None,
15478        })
15479    }
15480
15481    fn push_child(
15482        &mut self,
15483        graph: cudarc::driver::CudaGraph,
15484        parallel_group: Option<u32>,
15485        detached: bool,
15486        absorb: bool,
15487        ctx: cudarc::driver::sys::CUcontext,
15488    ) -> Result<(), Box<dyn std::error::Error>> {
15489        use cudarc::driver::sys;
15490        // Resolve the dependency set: serial sections depend on the current frontier; a
15491        // parallel-group section depends on the frontier AS OF the group opening; a
15492        // DETACHED section forks like a group member but joins only the next serial section.
15493        let deps: Vec<sys::CUgraphNode> = match (&mut self.group, parallel_group) {
15494            (Some((open, base, _)), Some(group)) if *open == group => base.clone(),
15495            (state, Some(group)) => {
15496                // opening a new group (closing any previous one first)
15497                if let Some((_, _, members)) = state.take() {
15498                    self.frontier = members;
15499                }
15500                let base = self.frontier.clone();
15501                *state = Some((group, base.clone(), Vec::new()));
15502                base
15503            }
15504            (state, None) if detached => match state.as_ref() {
15505                Some((_, base, _)) => base.clone(),
15506                None => self.frontier.clone(),
15507            },
15508            (state, None) => {
15509                if let Some((_, _, members)) = state.take() {
15510                    self.frontier = members;
15511                }
15512                let mut deps = self.frontier.clone();
15513                if absorb {
15514                    deps.append(&mut self.pending_detached);
15515                }
15516                deps
15517            }
15518        };
15519        let mut node: sys::CUgraphNode = std::ptr::null_mut();
15520        let r = unsafe {
15521            sys::cuGraphAddChildGraphNode(
15522                &mut node,
15523                self.parent,
15524                if deps.is_empty() {
15525                    std::ptr::null()
15526                } else {
15527                    deps.as_ptr()
15528                },
15529                deps.len(),
15530                graph.cu_graph(),
15531            )
15532        };
15533        if r != sys::CUresult::CUDA_SUCCESS {
15534            return Err(format!("token graph child: {r:?}").into());
15535        }
15536        match (&mut self.group, parallel_group, detached) {
15537            (_, None, true) => self.pending_detached.push(node),
15538            (Some((_, _, members)), Some(_), _) => members.push(node),
15539            _ => self.frontier = vec![node],
15540        }
15541        self.children.push(TokenGraphChild { graph, node, ctx });
15542        Ok(())
15543    }
15544
15545    pub fn finish(mut self) -> Result<TokenGraph, Box<dyn std::error::Error>> {
15546        use cudarc::driver::sys;
15547        if let Some((_, _, members)) = self.group.take() {
15548            self.frontier = members;
15549        }
15550        // Discover the fa sites BEFORE instantiate: the parent's cloned child graphs hold
15551        // the node handles the exec update path (M1) addresses.
15552        let mut fa_sites = Vec::new();
15553        for child in &self.children {
15554            if let Some(site) = discover_fa_site(child.node, child.ctx)? {
15555                fa_sites.push(site);
15556            }
15557        }
15558        let mut exec: sys::CUgraphExec = std::ptr::null_mut();
15559        let r = unsafe { sys::cuGraphInstantiateWithFlags(&mut exec, self.parent, 0) };
15560        if r != sys::CUresult::CUDA_SUCCESS {
15561            return Err(format!("token graph instantiate: {r:?}").into());
15562        }
15563        Ok(TokenGraph {
15564            exec,
15565            parent: self.parent,
15566            _children: self.children,
15567            fa_sites,
15568        })
15569    }
15570}
15571
15572/// Walk one child graph; if it carries the attention-section signature (exactly three MEMSET
15573/// nodes chained memset->memset->memset->fa_kernel->combine_kernel), return its update site.
15574fn discover_fa_site(
15575    child_node: cudarc::driver::sys::CUgraphNode,
15576    ctx: cudarc::driver::sys::CUcontext,
15577) -> Result<Option<TokenGraphFaSite>, Box<dyn std::error::Error>> {
15578    use cudarc::driver::sys;
15579    fn cu_try(r: sys::CUresult, what: &str) -> Result<(), Box<dyn std::error::Error>> {
15580        if r == sys::CUresult::CUDA_SUCCESS {
15581            Ok(())
15582        } else {
15583            Err(format!("{what}: {r:?}").into())
15584        }
15585    }
15586    let mut graph: sys::CUgraph = std::ptr::null_mut();
15587    unsafe {
15588        cu_try(
15589            sys::cuGraphChildGraphNodeGetGraph(child_node, &mut graph),
15590            "fa-site child GetGraph",
15591        )?;
15592    }
15593    let mut count: usize = 0;
15594    unsafe {
15595        cu_try(
15596            sys::cuGraphGetNodes(graph, std::ptr::null_mut(), &mut count),
15597            "fa-site GetNodes(count)",
15598        )?;
15599    }
15600    let mut nodes: Vec<sys::CUgraphNode> = vec![std::ptr::null_mut(); count];
15601    unsafe {
15602        cu_try(
15603            sys::cuGraphGetNodes(graph, nodes.as_mut_ptr(), &mut count),
15604            "fa-site GetNodes",
15605        )?;
15606    }
15607    nodes.truncate(count);
15608    let node_type =
15609        |node: sys::CUgraphNode| -> Result<sys::CUgraphNodeType, Box<dyn std::error::Error>> {
15610            let mut ty = sys::CUgraphNodeType::CU_GRAPH_NODE_TYPE_EMPTY;
15611            unsafe {
15612                cu_try(
15613                    sys::cuGraphNodeGetType(node, &mut ty),
15614                    "fa-site NodeGetType",
15615                )?;
15616            }
15617            Ok(ty)
15618        };
15619    let memsets: Vec<sys::CUgraphNode> = {
15620        let mut v = Vec::new();
15621        for &node in &nodes {
15622            if node_type(node)? == sys::CUgraphNodeType::CU_GRAPH_NODE_TYPE_MEMSET {
15623                v.push(node);
15624            }
15625        }
15626        v
15627    };
15628    if memsets.len() != 3 {
15629        return Ok(None);
15630    }
15631    // Single-stream capture makes the chain linear: follow dependent edges from each memset.
15632    let dependents =
15633        |node: sys::CUgraphNode| -> Result<Vec<sys::CUgraphNode>, Box<dyn std::error::Error>> {
15634            let mut n: usize = 0;
15635            unsafe {
15636                cu_try(
15637                    sys::cuGraphNodeGetDependentNodes_v2(
15638                        node,
15639                        std::ptr::null_mut(),
15640                        std::ptr::null_mut(),
15641                        &mut n,
15642                    ),
15643                    "fa-site GetDependentNodes(count)",
15644                )?;
15645            }
15646            let mut v: Vec<sys::CUgraphNode> = vec![std::ptr::null_mut(); n];
15647            unsafe {
15648                cu_try(
15649                    sys::cuGraphNodeGetDependentNodes_v2(
15650                        node,
15651                        v.as_mut_ptr(),
15652                        std::ptr::null_mut(),
15653                        &mut n,
15654                    ),
15655                    "fa-site GetDependentNodes",
15656                )?;
15657            }
15658            v.truncate(n);
15659            Ok(v)
15660        };
15661    // The LAST memset is the one whose direct dependent is a kernel (fa); the other two are
15662    // ordered among themselves but interchangeable for width updates.
15663    let mut fa: Option<sys::CUgraphNode> = None;
15664    let mut last_memset: Option<sys::CUgraphNode> = None;
15665    for &ms in &memsets {
15666        for dep in dependents(ms)? {
15667            if node_type(dep)? == sys::CUgraphNodeType::CU_GRAPH_NODE_TYPE_KERNEL {
15668                fa = Some(dep);
15669                last_memset = Some(ms);
15670            }
15671        }
15672    }
15673    let (Some(fa), Some(_last)) = (fa, last_memset) else {
15674        return Ok(None);
15675    };
15676    let mut combine: Option<sys::CUgraphNode> = None;
15677    for dep in dependents(fa)? {
15678        if node_type(dep)? == sys::CUgraphNodeType::CU_GRAPH_NODE_TYPE_KERNEL {
15679            combine = Some(dep);
15680        }
15681    }
15682    let Some(combine) = combine else {
15683        return Ok(None);
15684    };
15685    // Read the fa launch geometry from its baked args (arg order pinned by fa_decode_dcw):
15686    // 6=hd 7=nh 8=nhkv 11=win 13=nsp 14=ski.
15687    let mut params: sys::CUDA_KERNEL_NODE_PARAMS = unsafe { std::mem::zeroed() };
15688    unsafe {
15689        cu_try(
15690            sys::cuGraphKernelNodeGetParams_v2(fa, &mut params),
15691            "fa-site KernelNodeGetParams",
15692        )?;
15693    }
15694    let arg_i32 =
15695        |slot: usize| -> i32 { unsafe { *(*params.kernelParams.add(slot) as *const i32) } };
15696    let (hd, nh, nhkv, win) = (arg_i32(6), arg_i32(7), arg_i32(8), arg_i32(11));
15697    // Identify the o-partial memset (hd x wider than the m/l pair).
15698    let width_of = |node: sys::CUgraphNode| -> Result<usize, Box<dyn std::error::Error>> {
15699        let mut mp: sys::CUDA_MEMSET_NODE_PARAMS = unsafe { std::mem::zeroed() };
15700        unsafe {
15701            cu_try(
15702                sys::cuGraphMemsetNodeGetParams(node, &mut mp),
15703                "fa-site MemsetNodeGetParams",
15704            )?;
15705        }
15706        Ok(mp.width)
15707    };
15708    let mut widest = memsets[0];
15709    for &ms in &memsets[1..] {
15710        if width_of(ms)? > width_of(widest)? {
15711            widest = ms;
15712        }
15713    }
15714    let memset_m: Vec<sys::CUgraphNode> =
15715        memsets.iter().copied().filter(|&m| m != widest).collect();
15716    Ok(Some(TokenGraphFaSite {
15717        ctx,
15718        memset_o: widest,
15719        memset_m: [memset_m[0], memset_m[1]],
15720        fa,
15721        combine,
15722        window: win as usize,
15723        n_head: nh as usize,
15724        n_head_kv: nhkv as usize,
15725        head_dim: hd as usize,
15726    }))
15727}
15728
15729pub struct TokenGraph {
15730    exec: cudarc::driver::sys::CUgraphExec,
15731    parent: cudarc::driver::sys::CUgraph,
15732    _children: Vec<TokenGraphChild>,
15733    fa_sites: Vec<TokenGraphFaSite>,
15734}
15735
15736unsafe impl Send for TokenGraph {}
15737
15738impl TokenGraph {
15739    /// Retarget every fa site to a new bucket via exec param updates (M1 path) — replaces the
15740    /// per-bucket whole-graph rebuild (~55ms) with ~450 node updates (~1ms). Per site the
15741    /// bucket caps at the layer window; nsp/ski/gridDimY and the partial-pool memset widths
15742    /// move together so the exec always matches what a fresh build at `bucket` would bake.
15743    pub fn retarget_bucket(&mut self, bucket: usize) -> Result<(), Box<dyn std::error::Error>> {
15744        use cudarc::driver::sys;
15745        fn cu_try(r: sys::CUresult, what: &str) -> Result<(), Box<dyn std::error::Error>> {
15746            if r == sys::CUresult::CUDA_SUCCESS {
15747                Ok(())
15748            } else {
15749                Err(format!("{what}: {r:?}").into())
15750            }
15751        }
15752        for site in &self.fa_sites {
15753            let layer_bucket = if site.window > 0 {
15754                bucket.min(site.window)
15755            } else {
15756                bucket
15757            };
15758            let sp = crate::fa_split_keys(layer_bucket, site.n_head_kv);
15759            let nsp = layer_bucket.div_ceil(sp).max(1);
15760            // fa kernel: nsp (slot 13), ski (slot 14), gridDimY = nsp.
15761            let mut params: sys::CUDA_KERNEL_NODE_PARAMS = unsafe { std::mem::zeroed() };
15762            unsafe {
15763                cu_try(
15764                    sys::cuGraphKernelNodeGetParams_v2(site.fa, &mut params),
15765                    "retarget fa GetParams",
15766                )?;
15767                *(*params.kernelParams.add(13) as *mut i32) = nsp as i32;
15768                *(*params.kernelParams.add(14) as *mut i32) = sp as i32;
15769                params.gridDimY = nsp as u32;
15770                cu_try(
15771                    sys::cuGraphExecKernelNodeSetParams_v2(self.exec, site.fa, &params),
15772                    "retarget fa SetParams",
15773                )?;
15774            }
15775            // combine: nsp (slot 6).
15776            let mut cparams: sys::CUDA_KERNEL_NODE_PARAMS = unsafe { std::mem::zeroed() };
15777            unsafe {
15778                cu_try(
15779                    sys::cuGraphKernelNodeGetParams_v2(site.combine, &mut cparams),
15780                    "retarget combine GetParams",
15781                )?;
15782                *(*cparams.kernelParams.add(6) as *mut i32) = nsp as i32;
15783                cu_try(
15784                    sys::cuGraphExecKernelNodeSetParams_v2(self.exec, site.combine, &cparams),
15785                    "retarget combine SetParams",
15786                )?;
15787            }
15788            // partial-pool memsets: o = nh*nsp*hd elements, m/l = nh*nsp.
15789            let set_width =
15790                |node: sys::CUgraphNode, width: usize| -> Result<(), Box<dyn std::error::Error>> {
15791                    let mut mp: sys::CUDA_MEMSET_NODE_PARAMS = unsafe { std::mem::zeroed() };
15792                    unsafe {
15793                        cu_try(
15794                            sys::cuGraphMemsetNodeGetParams(node, &mut mp),
15795                            "retarget memset GetParams",
15796                        )?;
15797                    }
15798                    mp.width = width;
15799                    unsafe {
15800                        cu_try(
15801                            sys::cuGraphExecMemsetNodeSetParams(self.exec, node, &mp, site.ctx),
15802                            "retarget memset SetParams",
15803                        )?;
15804                    }
15805                    Ok(())
15806                };
15807            set_width(site.memset_o, site.n_head * nsp * site.head_dim)?;
15808            set_width(site.memset_m[0], site.n_head * nsp)?;
15809            set_width(site.memset_m[1], site.n_head * nsp)?;
15810        }
15811        Ok(())
15812    }
15813
15814    pub fn launch(&self, e: &Engine) -> Result<(), Box<dyn std::error::Error>> {
15815        use cudarc::driver::sys;
15816        let _main = e.gpu.enter_main()?;
15817        let r = unsafe { sys::cuGraphLaunch(self.exec, e.stream().cu_stream() as sys::CUstream) };
15818        if r != sys::CUresult::CUDA_SUCCESS {
15819            return Err(format!("token graph launch: {r:?}").into());
15820        }
15821        Ok(())
15822    }
15823}
15824
15825impl Drop for TokenGraph {
15826    fn drop(&mut self) {
15827        unsafe {
15828            let _ = cudarc::driver::sys::cuGraphExecDestroy(self.exec);
15829            let _ = cudarc::driver::sys::cuGraphDestroy(self.parent);
15830        }
15831    }
15832}
15833
15834std::thread_local! {
15835    static TOKEN_GRAPH_BUILDER: std::cell::RefCell<Option<TokenGraphBuilder>> =
15836        const { std::cell::RefCell::new(None) };
15837}
15838
15839/// Arm the thread-local builder (build mode) — the next `graph_section` calls capture.
15840pub fn token_graph_build_begin() -> Result<(), Box<dyn std::error::Error>> {
15841    let builder = TokenGraphBuilder::new()?;
15842    TOKEN_GRAPH_BUILDER.with(|cell| *cell.borrow_mut() = Some(builder));
15843    Ok(())
15844}
15845
15846/// Take the finished parent (ends build mode).
15847pub fn token_graph_build_finish() -> Result<TokenGraph, Box<dyn std::error::Error>> {
15848    let builder = TOKEN_GRAPH_BUILDER
15849        .with(|cell| cell.borrow_mut().take())
15850        .ok_or("token graph build was not begun")?;
15851    builder.finish()
15852}
15853
15854/// True while the thread-local builder is armed.
15855pub fn token_graph_building() -> bool {
15856    TOKEN_GRAPH_BUILDER.with(|cell| cell.borrow().is_some())
15857}
15858
15859/// The section annotation: eager mode runs the closure verbatim; build mode wraps it in a
15860/// stream capture on `engine`'s stream and records the child. Sections sharing a
15861/// `parallel_group` id fork from the same predecessor set and merge together. The closure
15862/// must be capture-safe (raw copies at cross-context seams, no host syncs, no events).
15863pub fn graph_section<F>(
15864    engine: &Engine,
15865    parallel_group: Option<u32>,
15866    f: F,
15867) -> Result<(), Box<dyn std::error::Error>>
15868where
15869    F: FnMut() -> Result<(), Box<dyn std::error::Error>>,
15870{
15871    graph_section_opts(engine, parallel_group, false, false, f)
15872}
15873
15874/// Serial section that ALSO joins every pending detached section (the SH1 consumer shape).
15875pub fn graph_section_absorbing<F>(engine: &Engine, f: F) -> Result<(), Box<dyn std::error::Error>>
15876where
15877    F: FnMut() -> Result<(), Box<dyn std::error::Error>>,
15878{
15879    graph_section_opts(engine, None, false, true, f)
15880}
15881
15882/// `graph_section` with the DETACHED shape: forks from the current frontier (or the open
15883/// group base) and is joined only by the next serial section — never gates a group merge.
15884pub fn graph_section_detached<F>(engine: &Engine, f: F) -> Result<(), Box<dyn std::error::Error>>
15885where
15886    F: FnMut() -> Result<(), Box<dyn std::error::Error>>,
15887{
15888    graph_section_opts(engine, None, true, false, f)
15889}
15890
15891pub fn graph_section_opts<F>(
15892    engine: &Engine,
15893    parallel_group: Option<u32>,
15894    detached: bool,
15895    absorb: bool,
15896    f: F,
15897) -> Result<(), Box<dyn std::error::Error>>
15898where
15899    F: FnMut() -> Result<(), Box<dyn std::error::Error>>,
15900{
15901    let building = token_graph_building();
15902    if !building {
15903        let mut f = f;
15904        return f();
15905    }
15906    let (child, ctx) = {
15907        let _main = engine.gpu.enter_main()?;
15908        let mut ctx: cudarc::driver::sys::CUcontext = std::ptr::null_mut();
15909        let r = unsafe { cudarc::driver::sys::cuCtxGetCurrent(&mut ctx) };
15910        if r != cudarc::driver::sys::CUresult::CUDA_SUCCESS {
15911            return Err(format!("graph section ctx query: {r:?}").into());
15912        }
15913        let mut f = f;
15914        // NO WARMUP RUNS: section bodies carry device side effects (dcw appends, counter
15915        // incs) that a warmup would really execute — the len_d-drift crash of 2026-08-21.
15916        let (child, _retained) = engine.capture_graph_retained_nowarm(|_| f())?;
15917        (child, ctx)
15918    };
15919    TOKEN_GRAPH_BUILDER.with(|cell| {
15920        cell.borrow_mut()
15921            .as_mut()
15922            .expect("builder checked above")
15923            .push_child(child, parallel_group, detached, absorb, ctx)
15924    })
15925}