Skip to main content

memra_engine/
pp.rs

1//! M2 pipeline-parallel N-stage runtime (generalizes the M1 2-stage seam).
2//!
3//! Door: `MEMRA_PP_STAGES=N` (default OFF — unset/0/1 = no behavior change anywhere).
4//! Stage map: N stages over the trunk layers with N-1 cuts. `MEMRA_PP_SPLITS=c1,..,cN-1`
5//! sets the cuts explicitly (strictly increasing, in (0, n_layers)); `MEMRA_PP_SPLIT=<i>`
6//! is the N=2 back-compat spelling; default = even split (cut s = s*n_layers/N).
7//! Placement: `MEMRA_PP_DEVICES=d0,..,dN-1` maps stage s to device ds (default: all on
8//! the primary engine's device).
9//!
10//! M1 history (increments 1-2, merged + hardened on the 8x box 2026-08-02): seam + gate
11//! single-device; then real transport — per-stage streams/events, device placement,
12//! peer-copy boundary (M0: cudaMemcpyPeerAsync beats NCCL 2.8x at PP activation sizes),
13//! per-context PDL module caches, default-mempool peer grants. All five r3 gates PASS
14//! bit-identical (receipts ~/receipts/m1-pp2/ on <bench-instance>).
15//!
16//! M2 increment 1 (this file): N-STAGE GENERALIZATION — `Pp2Rt` becomes `PpNRt`:
17//!   - `stages`: Vec of per-stage execution homes (device, context, stream, remote Engine);
18//!   - `boundaries`: N-1 boundary runtimes, each with TWO persistent double-buffered slots
19//!     (ev_tx/ev_rx per slot) and its own overlap step counter; transport is selected PER
20//!     BOUNDARY (dtod same-device / cudaMemcpyPeerAsync cross-device by default; opt-in
21//!     `MEMRA_PP_HOST_BOUNCE=1` uses pinned D2H + H2D instead);
22//!   - the default peer transport grants peer + default-mempool access between EVERY distinct
23//!     pair of devices in use. Host bounce skips serving-time grants; its boot diagnostics
24//!     transiently enable peer + pool access, then revoke the pool grants and disable peer access
25//!     before proceeding. Sharded weights plus stage-local auxiliary buffers ensure that no peer
26//!     read can bypass the bounced boundary.
27//!
28//! M2 increment 2 (weight sharding): the loader uploads each stage's layer range THROUGH
29//! that stage's engine (`layer_engine`), so weights land on the device that runs them —
30//! the bring-up peer-read placement dies. `output_norm` + lm head load through the LAST
31//! stage's engine; the embed table stays host-side with stage 0. Split-plane/f16 decode
32//! mirrors are built per layer through the owning stage's engine too (the rp4 mirrors ARE
33//! the decode weights on the q8 path — leaving them on dev0 would fake the kill).
34//! Rollback seam: `MEMRA_PP_SHARD=0` = M1 bring-up placement (all weights on primary,
35//! remote stages peer-read).
36//!
37//! M2 increment 3 (deferred readback — the pipelining seed): `PendingLogits` — the eager
38//! decode arm can END a step without the logits D2H (`decode_step_h_ppn_deferred`): the
39//! logits stay device-resident with a completion event; `wait()` drains them through a
40//! DEDICATED readback stream (waits the event, copies, syncs) so tokens t+1.. keep
41//! enqueuing on the stage streams while token t drains. Per-token math is fully
42//! event-ordered (same slots, same ev_tx/ev_rx chain) — scheduling changes, math does
43//! not; the pipelined replay arm of `ppn-gate` proves bit-identity per step.
44//!
45//! Ownership across a boundary (unchanged from M1):
46//!   - hidden state [n_embd] f32 is the ONLY tensor that crosses;
47//!   - KV/linear-attn cache entries are per-layer: stage s exclusively owns cache state
48//!     for its layer range (and, under MEMRA_PP_DEVICES, allocates it on its device);
49//!   - position/rope state is the scalar `cache.pos` snapshot taken once per step; every stage
50//!     uploads its own position buffer on its own stream (no cross-device position pointer);
51//!   - the embed table lives with stage 0, output_norm + lm head with the last stage.
52//!
53//! THE MULTI-STREAM LAW (why this is safe with cudarc event tracking disabled): all
54//! cross-stage bytes flow through the persistent boundary slots, ordered by ev_tx/ev_rx;
55//! per-stage scratch is allocated AND freed on that stage's stream (stream-ordered); the
56//! async mem pool runs with opportunistic reuse OFF + internal dependencies ON
57//! (memra-runtime), so a block freed on stream A and reused on stream B carries a
58//! driver-inserted dependency. Weights are load-time state no stage stream can precede,
59//! and the step's terminal logits readback (sync D2H, or PendingLogits' event-ordered
60//! readback stream) drains the last stage, whose TX-wait chain transitively drains all.
61//!
62//! Scope: plain eager decode only (generic arm N-stage; gemma4 arm 2-stage). NOT wired:
63//! batch/dc/graph/spec loops and the gemma4-E4B eager arm.
64//!
65//! CORRECTION (pp2-hardening 2026-08-06): this header used to add "(`warn_unwired_once`
66//! fires)" to that list, which was wrong. `warn_unwired_once` has exactly two call sites
67//! and BOTH are gemma4-specific (decode.rs, hybrid_forward.rs) — the batch/dc/graph/spec
68//! loops never warned. Worse, the batched loop did not merely run unsplit: it walked the
69//! whole trunk on the primary stream and, under a sharded cross-device placement,
70//! peer-read every remote stage's weights each step — 28x slower at B=1 with all three
71//! `decode-batch-gate` gates PASSING (peer reads are byte-exact, so only perf broke).
72//! `decode_step_batch` now FAILS CLOSED in that regime via `pp_sharded_cross_device()`
73//! (`MEMRA_PP_ALLOW_UNSPLIT_BATCH=1` = measurement override). "Unwired" for dc/graph/spec
74//! still means "runs unsplit, silently" — audit each before trusting it on a pair.
75
76use std::cell::RefCell;
77use std::marker::PhantomData;
78use std::rc::Rc;
79use std::sync::atomic::{AtomicBool, AtomicU64, AtomicUsize, Ordering};
80use std::sync::{Arc, Mutex, OnceLock, Weak};
81
82use cudarc::driver::{CudaContext, CudaEvent, CudaSlice, CudaStream};
83
84use crate::Engine;
85
86/// Restores the caller's primary CUDA context on every return path, including panic unwind. The
87/// explicit `restore` call preserves the bind error for normal Result propagation; Drop is the
88/// final safety net when a scoped host worker or head-stage callback panics.
89pub(crate) struct PrimaryContextRestore<'a> {
90    engine: &'a Engine,
91    restored: bool,
92}
93
94impl<'a> PrimaryContextRestore<'a> {
95    pub(crate) fn new(engine: &'a Engine) -> Self {
96        Self {
97            engine,
98            restored: false,
99        }
100    }
101
102    pub(crate) fn restore(mut self) -> Result<(), Box<dyn std::error::Error>> {
103        let result = self.engine.ctx().bind_to_thread();
104        self.restored = result.is_ok();
105        result?;
106        Ok(())
107    }
108}
109
110impl Drop for PrimaryContextRestore<'_> {
111    fn drop(&mut self) {
112        if !self.restored {
113            let _ = self.engine.ctx().bind_to_thread();
114        }
115    }
116}
117
118/// Returns the stage fence iff the ppN door is open: `MEMRA_PP_STAGES=N` (N >= 2) with a
119/// valid cut list. The fence has N+1 entries: `[0, c1, .., cN-1, n_layers]`; stage s runs
120/// layers `[fence[s], fence[s+1])`. Reads the environment on every call (gates toggle the
121/// door in-process); the cost is a few getenv per decode step, eager-loop noise.
122pub fn pp_cuts(n_layers: usize) -> Option<Vec<usize>> {
123    let n_st: usize = match std::env::var("MEMRA_PP_STAGES") {
124        Ok(v) if v.is_empty() || v == "0" || v == "1" => return None,
125        Ok(v) => match v.parse::<usize>() {
126            Ok(n) => n,
127            Err(_) => {
128                warn_bad_once(&format!("MEMRA_PP_STAGES={v} unparseable; door stays OFF"));
129                return None;
130            }
131        },
132        Err(_) => return None,
133    };
134    if n_st < 2 || n_st > n_layers {
135        warn_bad_once(&format!(
136            "MEMRA_PP_STAGES={n_st} outside [2, n_layers={n_layers}]; door stays OFF"
137        ));
138        return None;
139    }
140    let mut fence = Vec::with_capacity(n_st + 1);
141    fence.push(0usize);
142    if let Ok(s) = std::env::var("MEMRA_PP_SPLITS") {
143        let parts: Result<Vec<usize>, _> =
144            s.split(',').map(|p| p.trim().parse::<usize>()).collect();
145        match parts {
146            Ok(cuts) if cuts.len() == n_st - 1 => fence.extend(cuts),
147            _ => {
148                warn_bad_once(&format!(
149                    "MEMRA_PP_SPLITS={s} invalid (want {} comma-separated cuts); door stays OFF",
150                    n_st - 1
151                ));
152                return None;
153            }
154        }
155    } else if let Ok(v) = std::env::var("MEMRA_PP_SPLIT") {
156        // N=2 back-compat spelling. With N>2 a single split is ambiguous — fail the door
157        // loudly rather than guess (a silent even-split would fake a gate config).
158        if n_st != 2 {
159            warn_bad_once(&format!(
160                "MEMRA_PP_SPLIT={v} set with MEMRA_PP_STAGES={n_st}; use MEMRA_PP_SPLITS \
161                 for N>2 — door stays OFF"
162            ));
163            return None;
164        }
165        match v.parse::<usize>() {
166            Ok(c) => fence.push(c),
167            Err(_) => {
168                warn_bad_once(&format!("MEMRA_PP_SPLIT={v} unparseable; door stays OFF"));
169                return None;
170            }
171        }
172    } else {
173        for s in 1..n_st {
174            fence.push(s * n_layers / n_st);
175        }
176    }
177    fence.push(n_layers);
178    for w in fence.windows(2) {
179        if w[0] >= w[1] {
180            warn_bad_once(&format!(
181                "pp stage fence {fence:?} not strictly increasing over [0, {n_layers}]; \
182                 door stays OFF"
183            ));
184            return None;
185        }
186    }
187    Some(fence)
188}
189
190/// N=2 back-compat view of the door (the gemma4 arm and `pp2-gate` are 2-stage): `Some(cut)`
191/// iff the door is open with EXACTLY two stages.
192pub fn pp2_split(n_layers: usize) -> Option<usize> {
193    pp_cuts(n_layers).filter(|f| f.len() == 3).map(|f| f[1])
194}
195
196/// The stage that owns layer `il` under `fence` (see `pp_cuts`).
197pub fn stage_of(fence: &[usize], il: usize) -> usize {
198    debug_assert!(fence.len() >= 2);
199    match fence[1..fence.len() - 1].binary_search(&il) {
200        // fence[1..][k] == il means il is the FIRST layer of stage k+1
201        Ok(k) => k + 1,
202        Err(k) => k,
203    }
204}
205
206/// MEMRA_PP_STREAMS=0: rollback to the increment-1 same-stream seam (boundary = two plain
207/// dtod copies on the ambient compute stream, no per-stage streams/events/devices).
208pub fn pp2_streams_off() -> bool {
209    matches!(std::env::var("MEMRA_PP_STREAMS").as_deref(), Ok("0"))
210}
211
212/// `MEMRA_PP_EXIT_PUBLISH` — the ppN EXIT-PUBLICATION guard (lane/glm5-accrace 2026-09-01).
213///
214/// **DEFAULT ON, and the default is the measurement, not a preference** (the new-flags law:
215/// ON/OFF by design, receipts attached, FLAGS.md row in the same commit). With per-stage
216/// streams on ONE device the hc ppN bodies published nothing to the caller except a
217/// last-stage drain, so a caller allocation could land under still-queued stage work: the
218/// prime over a fixed prompt returned three distinct logit fingerprints inside one process
219/// (32/110 non-canonical), and one glm5 spec round silently lost an acceptance. See
220/// [`PpNRt::publish_all_to`] for the anatomy and
221/// `research/glm53-flash-bringup-20260827/accrace-20260901/LANE.md` for the receipts.
222///
223/// `0` restores the pre-lane behaviour exactly — the ROLLBACK/CONTROL seam (flags doctrine:
224/// rollback seams are a legitimate flag class). It is a KNOWN-RACY arm: never a serving
225/// configuration, only an A/B control.
226///
227/// Read PER CALL rather than latched: the gate matrices drive both arms in one process.
228///
229/// POLARITY IS DELIBERATE, AND DO NOT COPY IT BLIND (review note, 2026-09-01): the test is
230/// "anything except exactly `0` is ON", so a typo'd rollback (`=false`, `=O`, `=00`) leaves the
231/// guard ON. That FAILS SAFE **here** — the ON arm is the correctness fix, the OFF arm is the
232/// known-racy control — and it is why this flag is written loosely on purpose rather than
233/// parsed strictly. The polarity is only safe because of which arm is dangerous. A default-ON
234/// flag whose `0` disables something HAZARDOUS needs the mirror shape (`Ok("1")`-style strict
235/// opt-in, or a parse that refuses an unrecognized value), because there the same typo would
236/// silently keep the hazard armed. Pick the polarity from which side fails safe, never by
237/// copying this line.
238pub fn pp_exit_publish() -> bool {
239    !matches!(std::env::var("MEMRA_PP_EXIT_PUBLISH").as_deref(), Ok("0"))
240}
241
242/// True iff the ppN door would put TWO OR MORE stage streams on ONE device (devices
243/// unset = all stages on the primary; or an explicit placement with a repeated device).
244/// The deferred-readback (pipelined) arm is REFUSED in this regime: the 2026-08-02 x20
245/// soak record — singledev pipelined 13/20 PASS default, 7 failures each diverging at a
246/// different step (timing-race signature); MEMRA_PDL=0 went 20/20 on one soak but a
247/// second same-config soak on the auto-gated build failed 2/20 (n2) and battery-4 failed
248/// n4 — so PDL narrows the window without closing it, and the true root cause (same
249/// Engine kernels concurrent on two streams of one device) is NOT fixed by any flag yet.
250/// Cross-device pipelined (one stage stream per device) is 23/23 clean post-fix. Refuse
251/// loudly rather than return silently-wrong logits. Env-only read (callable pre-runtime).
252///
253/// ONE MECHANISM OF THAT OPEN ROOT CAUSE IS NOW NAMED AND CLOSED (lane/glm5-accrace
254/// 2026-09-01), stated narrowly because it was measured on the SERIAL arm, not this
255/// refused pipelined one: a ppN body that returned to its caller published only the
256/// producing last stage, so a caller allocation could land under work still queued on a
257/// caller-CO-RESIDENT stage stream. That is exactly a "same Engine, two streams, one
258/// device" corruption, and it is the reason this predicate's regime is the dangerous one —
259/// on a DISTINCT-device placement only the head stage shares the caller's context, and a
260/// body's terminal drain already covers it. See [`PpNRt::publish_all_to`] and
261/// [`pp_exit_publish`]. Whether the pipelined arm's remaining flake is the same mechanism
262/// is UNMEASURED; this refusal stands.
263pub fn pp_multi_stream_same_device() -> bool {
264    let stages_open = std::env::var("MEMRA_PP_STAGES")
265        .map(|v| v.parse::<usize>().map(|n| n >= 2).unwrap_or(false))
266        .unwrap_or(false);
267    let devices = std::env::var("MEMRA_PP_DEVICES")
268        .ok()
269        .filter(|v| !v.is_empty());
270    if (!stages_open && devices.is_none()) || pp2_streams_off() {
271        return false;
272    }
273    match devices {
274        None => true, // door open, no placement: every stage stream lands on the primary
275        Some(s) => pp_devices_repeat(&s),
276    }
277}
278
279fn pp_devices_repeat(raw: &str) -> bool {
280    let Ok(mut devices) = raw
281        .split(',')
282        .map(|part| part.trim().parse::<usize>())
283        .collect::<Result<Vec<_>, _>>()
284    else {
285        // Runtime construction will return the precise parse error. Treat malformed input as
286        // unsafe here so a second environment interpretation can never admit a wavefront.
287        return true;
288    };
289    let count = devices.len();
290    devices.sort_unstable();
291    devices.dedup();
292    devices.len() < count
293}
294
295/// True iff the ppN door is open AND the placement spans 2+ DISTINCT devices AND the
296/// per-stage sharded loader is on — i.e. some layers' weights live on a device other than
297/// the primary. Any path that walks the WHOLE trunk on one stream in this regime reads
298/// those weights over PCIe every step. Env-only read (callable pre-runtime).
299///
300/// Measured cost of doing that (pp2-hardening 2026-08-06, 2x RTX PRO 6000, PCIe Gen5 x16
301/// P2P, decode-batch-bench q9, N=5 interleaved, `research/pp2-hardening-20260806`):
302/// **B=1 7.4 vs 208.9 tok/s (28x), B=4 29.8 vs 491.3 (16.5x), B=8 47.4 vs 657.0 (13.9x)**.
303/// The same sweep with `MEMRA_PP_SHARD=0` (weights all home) returns 178.5/491.1/656.6 —
304/// identical to the single-device door-open arm — so the entire cliff is the peer read,
305/// not the door and not the placement plumbing. Exactness is NOT the issue: peer reads
306/// return identical bytes and every `decode-batch-gate` gate PASSED on this config, which
307/// is precisely why it needs a refusal rather than a gate.
308pub fn pp_sharded_cross_device() -> bool {
309    let stages_open = std::env::var("MEMRA_PP_STAGES")
310        .map(|v| v.parse::<usize>().map(|n| n >= 2).unwrap_or(false))
311        .unwrap_or(false);
312    // MEMRA_PP_STREAMS=0 (2026-08-06, pp2-batch): the same-stream rollback seam ALSO turns
313    // the sharded loader off — `layer_engine` returns the primary engine whenever
314    // `pp2_streams_off()`, and `new_cache` skips `Cache::new_ppn` on the same condition. So
315    // in that regime every weight and every cache is home on the primary and an unsplit walk
316    // peer-reads NOTHING. Without this term the guard refused that config too: a spurious
317    // refusal of a placement that is sound and full-speed. Found wiring the batched pp arm.
318    if !stages_open || pp_shard_off() || pp2_streams_off() {
319        return false;
320    }
321    match pp2_devices_env() {
322        None => false, // no placement: every stage is the primary device, nothing remote
323        Some(s) => {
324            let mut v: Vec<&str> = s.split(',').map(|p| p.trim()).collect();
325            v.sort_unstable();
326            v.dedup();
327            v.len() >= 2
328        }
329    }
330}
331
332/// The shared fail-closed guard for EVERY decode path that has no pp stage split.
333/// Returns `Err` iff `pp_sharded_cross_device()` — i.e. the caller would walk the whole
334/// trunk on one stream while some layers' weights live on another device, peer-reading
335/// them every step. `path` names the refusing function so the operator knows which loop
336/// they hit; `alt` names the working alternative for that loop.
337///
338/// One helper rather than four copies because the audit found FOUR paths with the same
339/// hole (`decode_step_batch`, `decode_step_dc`, the graph capture that wraps dc, and
340/// `decode_step_t*` verify), and a per-path copy is how one gets missed on the next
341/// addition. Override: `MEMRA_PP_ALLOW_UNSPLIT_BATCH=1` (one door for all of them —
342/// they are the same measurement question).
343pub fn refuse_unsplit_if_remote(path: &str, alt: &str) -> Result<(), Box<dyn std::error::Error>> {
344    if pp_host_bounce_active() {
345        return Err(format!(
346            "{path}: refused with MEMRA_PP_HOST_BOUNCE=1 on sharded cross-device PP — \
347             this unsplit path peer-reads remote weights, while host bounce covers only \
348             explicit stage-boundary transfers. Use {alt}; the \
349             MEMRA_PP_ALLOW_UNSPLIT_BATCH override is unavailable on a broken-peer host."
350        )
351        .into());
352    }
353    if pp_sharded_cross_device()
354        && std::env::var("MEMRA_PP_ALLOW_UNSPLIT_BATCH").as_deref() != Ok("1")
355    {
356        return Err(format!(
357            "{path}: refused with the ppN door open across 2+ devices — this path has no pp \
358             stage split, so it would walk ALL layers on one stream and peer-read every \
359             remote stage's weights each step (measured 28x slower at B=1, 13.9x at B=8 on \
360             a PRO 6000 pair over PCIe Gen5 x16 P2P; research/pp2-hardening-20260806). \
361             Exactness is unaffected — peer reads return identical bytes and the exactness \
362             gates PASS on this config — which is exactly why it must refuse instead of \
363             being caught by a gate. Fixes, in order: {alt}; or MEMRA_PP_SHARD=0 (all \
364             weights home on the primary — full speed, forfeits the capacity PP-2 exists \
365             for); or close the pp door. MEMRA_PP_ALLOW_UNSPLIT_BATCH=1 overrides for \
366             measurement."
367        )
368        .into());
369    }
370    Ok(())
371}
372
373/// MEMRA_BATCH_PP=0: rollback/A-B seam for the BATCHED stage split (pp2-batch 2026-08-06).
374/// Default ON — with the ppN door open the batched decode step takes its own stage split
375/// (`decode_step_batch_ppn`) exactly as the eager step does. Setting 0 sends the batched
376/// path back through the unsplit body, which under a sharded cross-device placement is
377/// then caught by `refuse_unsplit_if_remote` (the 28x peer-read regime) rather than run
378/// silently. Exists so the bit-identity gate can A/B split vs unsplit IN ONE PROCESS
379/// against the same loaded weights — read per step, never memoized, for that reason.
380pub fn batch_pp_on() -> bool {
381    std::env::var("MEMRA_BATCH_PP").as_deref() != Ok("0")
382}
383
384/// Largest PP wavefront admitted by the RTX PRO 6000 product shape. The underlying placement
385/// runtime remains N-stage, but the serving wave scheduler is deliberately bounded to the 2--4
386/// card surface that has a concrete qualification plan.
387pub const PP_WAVE_MAX_STAGES: usize = 4;
388
389/// Strict opt-in for the PP3/PP4 request wavefront. PP2 keeps its independently qualified
390/// `MEMRA_DUAL_PP` default; a new stage count never inherits that default without its own target
391/// receipts.
392pub fn pp_wave_on_value(value: Option<&str>) -> Result<bool, &'static str> {
393    match value {
394        None | Some("0") => Ok(false),
395        Some("1") => Ok(true),
396        Some(_) => Err("MEMRA_PP_WAVE must be 0 or 1"),
397    }
398}
399
400pub fn pp_wave_on() -> Result<bool, &'static str> {
401    match std::env::var_os("MEMRA_PP_WAVE") {
402        None => pp_wave_on_value(None),
403        Some(value) => value
404            .to_str()
405            .ok_or("MEMRA_PP_WAVE must be valid UTF-8 and exactly 0 or 1")
406            .and_then(|value| pp_wave_on_value(Some(value))),
407    }
408}
409
410/// Split one scheduler tick into at most one wave per stage. Earlier waves carry the remainder so
411/// priority order is preserved, every row appears exactly once, and the largest wave is
412/// `ceil(batch / min(batch, stages))`.
413pub fn pp_wave_ranges(batch: usize, stages: usize) -> Vec<(usize, usize)> {
414    if batch == 0 || stages == 0 {
415        return Vec::new();
416    }
417    let waves = batch.min(stages);
418    let base = batch / waves;
419    let extra = batch % waves;
420    let mut out = Vec::with_capacity(waves);
421    let mut start = 0usize;
422    for wave in 0..waves {
423        let len = base + usize::from(wave < extra);
424        out.push((start, start + len));
425        start += len;
426    }
427    debug_assert_eq!(start, batch);
428    out
429}
430
431/// Cells on one pipeline anti-diagonal, returned as `(wave, stage)`. Cells in a diagonal never
432/// share a wave (request/cache state) or a stage (Engine scratch/stream), so they may be driven by
433/// scoped host threads without reintroducing the shared-Engine race that quarantined the old
434/// deferred PP walker.
435pub fn pp_wave_diagonal(stages: usize, waves: usize, diagonal: usize) -> Vec<(usize, usize)> {
436    if stages == 0 || waves == 0 || diagonal >= stages + waves - 1 {
437        return Vec::new();
438    }
439    let first_stage = diagonal.saturating_sub(waves - 1);
440    let last_stage = diagonal.min(stages - 1);
441    (first_stage..=last_stage)
442        .map(|stage| (diagonal - stage, stage))
443        .collect()
444}
445
446/// Fail-closed topology gate for the unqualified PP3/PP4 wavefront. Native peer transport and one
447/// physical device per stage are required for the first implementation; host bounce and repeated
448/// devices retain the serial PP-N walker.
449pub fn pp_wave_eligibility(
450    stages: usize,
451    double_slot: bool,
452    host_bounce: bool,
453    repeated_device: bool,
454) -> Result<(), &'static str> {
455    if !(3..=PP_WAVE_MAX_STAGES).contains(&stages) {
456        return Err("PP wavefront requires 3 or 4 stages; PP2 is owned by MEMRA_DUAL_PP");
457    }
458    if !double_slot {
459        return Err("PP wavefront requires MEMRA_PP_OVERLAP=1 double-buffered boundaries");
460    }
461    if host_bounce {
462        return Err(
463            "PP wavefront is unqualified with MEMRA_PP_HOST_BOUNCE=1; use native peer transport",
464        );
465    }
466    if repeated_device {
467        return Err("PP wavefront requires one distinct CUDA device per stage");
468    }
469    Ok(())
470}
471
472/// The PP3/PP4 scheduler decomposes one serving batch into narrower stage waves. A preserved-BF16
473/// W4A16 artifact therefore needs the row-wise BF16 matvec program: the default f32-expanded
474/// cuBLAS path is batch-width dependent, and HY3 B=4/B=8 changed every logit row when wave cells
475/// narrowed to B=1/B=2. `MEMRA_BF16_MMV=1` keeps the same checkpoint BF16 values and runs one
476/// deterministic per-row reduction program at every width.
477pub const PP_WAVE_W4A16_BF16_REFUSAL: &str = "PP wavefront for a W4A16 artifact with preserved BF16 non-expert weights requires \
478     MEMRA_BF16_MMV=1; without the row-wise BF16 program, wave batch-width decomposition changes \
479     logits. Keep MEMRA_PP_WAVE=0 or enable and qualify MEMRA_BF16_MMV=1";
480
481pub fn pp_wave_numeric_eligibility(
482    weight_only_nvfp4: bool,
483    bf16_mmv: bool,
484) -> Result<(), &'static str> {
485    if weight_only_nvfp4 && !bf16_mmv {
486        return Err(PP_WAVE_W4A16_BF16_REFUSAL);
487    }
488    Ok(())
489}
490
491/// One routing predicate shared by decode and prime: requesting the wave door without the
492/// double-slot policy is the documented serial rollback, not a late per-request refusal.
493pub fn pp_wave_route_enabled(
494    requested: bool,
495    overlap: bool,
496    stages: usize,
497    work_items: usize,
498) -> bool {
499    requested && overlap && (3..=PP_WAVE_MAX_STAGES).contains(&stages) && work_items >= 2
500}
501
502static PP_WAVE_ACTIVE_CELLS: AtomicUsize = AtomicUsize::new(0);
503static PP_WAVE_OVERLAPS: AtomicUsize = AtomicUsize::new(0);
504static PP_WAVE_TICKS: AtomicUsize = AtomicUsize::new(0);
505static PP_WAVE_CELLS: AtomicUsize = AtomicUsize::new(0);
506
507pub(crate) struct PpWaveCellGuard;
508
509/// Mark one host-driven PP3/PP4 cell active. An overlap increment is proof that two distinct
510/// stage walkers were simultaneously inside their model range; enqueue order alone is not proof
511/// for MoE paths whose router readback synchronizes the host.
512pub(crate) fn enter_pp_wave_cell() -> PpWaveCellGuard {
513    let active = PP_WAVE_ACTIVE_CELLS.fetch_add(1, Ordering::AcqRel);
514    if active > 0 {
515        PP_WAVE_OVERLAPS.fetch_add(1, Ordering::Relaxed);
516    }
517    PP_WAVE_CELLS.fetch_add(1, Ordering::Relaxed);
518    PpWaveCellGuard
519}
520
521impl Drop for PpWaveCellGuard {
522    fn drop(&mut self) {
523        let active = PP_WAVE_ACTIVE_CELLS.fetch_sub(1, Ordering::AcqRel);
524        debug_assert!(active > 0, "PP wave active-cell counter underflow");
525    }
526}
527
528pub(crate) fn record_pp_wave_tick() {
529    PP_WAVE_TICKS.fetch_add(1, Ordering::Relaxed);
530}
531
532/// `(completed ticks, entered cells, observed concurrent-cell overlaps)`.
533pub fn pp_wave_snapshot() -> (usize, usize, usize) {
534    (
535        PP_WAVE_TICKS.load(Ordering::Relaxed),
536        PP_WAVE_CELLS.load(Ordering::Relaxed),
537        PP_WAVE_OVERLAPS.load(Ordering::Relaxed),
538    )
539}
540
541/// MEMRA_DUAL_PP three-state mode for the dual-active PP-2 batched decode path.
542/// Default ON (owner flip 2026-08-11) after the box1 PRO-pair re-gate: correctness
543/// bit-identity B=1..5, servestress no-thrash, 10-boot soak 929/929 golden matches with
544/// 0 slot collisions across 9123 pairs (research/dualpp2-20260811/RESULTS-regate.md), plus
545/// the dualpp1 c>=8 interleaved perf floor (+20.753% minimum,
546/// research/dualpp1-20260811/RESULTS.md).
547///
548/// The three states carry different failure semantics on purpose:
549/// - `Off` (`MEMRA_DUAL_PP=0`): the serial rollback seam. Overlap also follows OFF unless
550///   `MEMRA_PP_OVERLAP` is set explicitly, so one flag restores the exact pre-flip naked path.
551/// - `Forced` (`MEMRA_DUAL_PP=1`): the pre-flip explicit request. A placement that cannot
552///   run dual (single-slot boundary, host bounce, non-PP-2 fence) REFUSES with the binding
553///   quoted reason before any token or cache advance — the gate negative cells pin this.
554/// - `Auto` (unset): the flipped default. Dual runs where the re-gate validated it
555///   (PP-2 fence, double-slot, peer transport, B>=2) and silently degrades to the serial
556///   PP-N walker everywhere else — naked PP-3 serving and the MEMRA_PP_HOST_BOUNCE=1
557///   broken-peer escape hatch must keep decoding, not refuse.
558#[derive(Clone, Copy, PartialEq, Eq, Debug)]
559pub enum DualPpMode {
560    Off,
561    Forced,
562    Auto,
563}
564
565/// Pure resolution for MEMRA_DUAL_PP, split from the env read so the flip regression tests
566/// cannot race parallel test threads on process env.
567pub fn dual_pp_mode_resolve(v: Option<&str>) -> DualPpMode {
568    match v {
569        Some("0") => DualPpMode::Off,
570        Some("1") => DualPpMode::Forced,
571        _ => DualPpMode::Auto,
572    }
573}
574
575pub fn dual_pp_mode() -> DualPpMode {
576    dual_pp_mode_resolve(std::env::var("MEMRA_DUAL_PP").ok().as_deref())
577}
578
579/// True when the dual-active door is open (Forced or Auto). Read per step so the
580/// model-level gate can replay serial and waved arms against one loaded checkpoint.
581pub fn dual_pp_on() -> bool {
582    dual_pp_mode() != DualPpMode::Off
583}
584
585/// Engine-entry routing for the dual-active path, kept pure for the flip regression
586/// tests. `Forced` routes every B>=2 PP-2 call into `decode_step_batch_dual` even when
587/// the placement cannot run it, so the binding refusals stay reachable and loud.
588/// `Auto` routes only the exact re-gated regime and leaves everything else on the serial
589/// PP-N walker. `dual_pp_eligibility` remains behind this as defense in depth.
590pub fn dual_pp_route(
591    mode: DualPpMode,
592    batch: usize,
593    stages: usize,
594    double_slot: bool,
595    host_bounce: bool,
596) -> bool {
597    if batch < 2 {
598        return false;
599    }
600    match mode {
601        DualPpMode::Off => false,
602        DualPpMode::Forced => true,
603        DualPpMode::Auto => stages == 2 && double_slot && !host_bounce,
604    }
605}
606
607/// Binding-amendment refusal text. The negative gate quotes this exact line and requires the
608/// decode call to return before producing a token or advancing a cache.
609pub const DUAL_PP_SINGLE_SLOT_REFUSAL: &str = "decode_step_batch_dual: refused: PP boundary is single-slot; set MEMRA_PP_OVERLAP=1 so both alternating boundary slots are prepared before dual-active decode";
610pub const DUAL_PP_HOST_BOUNCE_REFUSAL: &str = "decode_step_batch_dual: refused: MEMRA_PP_HOST_BOUNCE=1 is unvalidated for dual-active decode; disable MEMRA_DUAL_PP or use peer transport";
611
612/// Pure schedule policy shared by the runtime and kernel-check manifest cells. A single row
613/// has no second wave and must stay on the serial PP-N walker.
614#[allow(clippy::manual_div_ceil)] // allow: explicit (n + k - 1) / k is the load-bearing sizing form, kept textually identical to the kernel-side math
615pub fn dual_pp_wave_mid(batch: usize) -> Option<usize> {
616    (batch >= 2).then_some((batch + 1) / 2)
617}
618
619/// Fail-closed eligibility check kept pure so the negative manifest cell cannot accidentally
620/// initialize CUDA state. Slot preparation itself remains `PpNRt::prepare_overlap_slots`.
621pub fn dual_pp_eligibility(
622    stages: usize,
623    double_slot: bool,
624    host_bounce: bool,
625) -> Result<(), &'static str> {
626    if stages != 2 {
627        return Err(
628            "decode_step_batch_dual: refused: dual-active decode requires exactly two PP stages",
629        );
630    }
631    if !double_slot {
632        return Err(DUAL_PP_SINGLE_SLOT_REFUSAL);
633    }
634    if host_bounce {
635        return Err(DUAL_PP_HOST_BOUNCE_REFUSAL);
636    }
637    Ok(())
638}
639
640/// Liveness is counted only while the two host-driven decode layer walkers are both active.
641/// Enqueue order is not proof for Step: its router readback synchronizes the issuing thread.
642static DUAL_PP_OVERLAPS: AtomicUsize = AtomicUsize::new(0);
643static DUAL_PP_ACTIVE_STAGES: AtomicUsize = AtomicUsize::new(0);
644static DUAL_PP_STAGE_NS: [AtomicU64; 4] = [
645    AtomicU64::new(0),
646    AtomicU64::new(0),
647    AtomicU64::new(0),
648    AtomicU64::new(0),
649];
650static DUAL_PP_STAGE_SAMPLES: [AtomicUsize; 4] = [
651    AtomicUsize::new(0),
652    AtomicUsize::new(0),
653    AtomicUsize::new(0),
654    AtomicUsize::new(0),
655];
656static DUAL_PP_TIMING_DROPPED: AtomicUsize = AtomicUsize::new(0);
657static DUAL_PP_SLOT_PAIRS: AtomicUsize = AtomicUsize::new(0);
658static DUAL_PP_SLOT_USES: [AtomicUsize; 2] = [AtomicUsize::new(0), AtomicUsize::new(0)];
659static DUAL_PP_SLOT_COLLISIONS: AtomicUsize = AtomicUsize::new(0);
660
661pub const DUAL_PP_STAGE_NAMES: [&str; 4] = [
662    "wave_a_stage0",
663    "wave_a_stage1",
664    "wave_b_stage0",
665    "wave_b_stage1",
666];
667
668pub fn dual_pp_overlaps() -> usize {
669    DUAL_PP_OVERLAPS.load(Ordering::Relaxed)
670}
671
672/// Record the two boundary slots selected for one dual-active wave pair. A same-slot pair is
673/// rejected by the caller before wave B can consume a residual; the collision counter makes that
674/// fail-closed path observable to the detached soak instead of relying only on log scanning.
675pub(crate) fn record_dual_pp_slot_pair(slot_a: usize, slot_b: usize) -> bool {
676    debug_assert!(slot_a < DUAL_PP_SLOT_USES.len());
677    debug_assert!(slot_b < DUAL_PP_SLOT_USES.len());
678    if slot_a == slot_b {
679        DUAL_PP_SLOT_COLLISIONS.fetch_add(1, Ordering::Relaxed);
680        return false;
681    }
682    DUAL_PP_SLOT_USES[slot_a].fetch_add(1, Ordering::Relaxed);
683    DUAL_PP_SLOT_USES[slot_b].fetch_add(1, Ordering::Relaxed);
684    DUAL_PP_SLOT_PAIRS.fetch_add(1, Ordering::Relaxed);
685    true
686}
687
688/// `(completed wave pairs, [slot 0 uses, slot 1 uses], rejected same-slot pairs)`.
689pub fn dual_pp_slot_snapshot() -> (usize, [usize; 2], usize) {
690    (
691        DUAL_PP_SLOT_PAIRS.load(Ordering::Relaxed),
692        std::array::from_fn(|i| DUAL_PP_SLOT_USES[i].load(Ordering::Relaxed)),
693        DUAL_PP_SLOT_COLLISIONS.load(Ordering::Relaxed),
694    )
695}
696
697/// CUDA-event timing is a diagnostic-only process door. The scored N=5 block runs without
698/// it; the companion box1 diagnostic process enables it and exports cumulative per-wave
699/// stage spans through `/metrics`.
700pub fn dual_pp_timing_on() -> bool {
701    static ON: OnceLock<bool> = OnceLock::new();
702    *ON.get_or_init(|| std::env::var("MEMRA_DUAL_PP_TIMING").as_deref() == Ok("1"))
703}
704
705pub(crate) fn record_dual_pp_stage_ms(stage: usize, ms: f32) {
706    assert!(
707        stage < DUAL_PP_STAGE_NS.len(),
708        "dual PP timing stage out of range"
709    );
710    let ns = (f64::from(ms) * 1_000_000.0).round() as u64;
711    DUAL_PP_STAGE_NS[stage].fetch_add(ns, Ordering::Relaxed);
712    DUAL_PP_STAGE_SAMPLES[stage].fetch_add(1, Ordering::Relaxed);
713}
714
715/// Timing is diagnostic only: a CUDA event that is not ready (or otherwise fails) must not
716/// change decode control flow. Count and warn once, then leave the scored-path result intact.
717pub(crate) fn record_dual_pp_timing_drop(context: &str, err: &dyn std::fmt::Display) {
718    let previous = DUAL_PP_TIMING_DROPPED.fetch_add(1, Ordering::Relaxed);
719    if previous == 0 {
720        eprintln!(
721            "[dual-pp] WARN: skipped diagnostic timing sample at {context}: {err}; decode continues"
722        );
723    }
724}
725
726pub(crate) fn record_dual_pp_stage_result<E: std::fmt::Display>(
727    stage: usize,
728    elapsed: Result<f32, E>,
729) {
730    match elapsed {
731        Ok(ms) => record_dual_pp_stage_ms(stage, ms),
732        Err(err) => record_dual_pp_timing_drop(DUAL_PP_STAGE_NAMES[stage], &err),
733    }
734}
735
736pub fn dual_pp_timing_dropped() -> usize {
737    DUAL_PP_TIMING_DROPPED.load(Ordering::Relaxed)
738}
739
740/// `(total_nanoseconds, samples)` for wave-A stage0/stage1 then wave-B stage0/stage1.
741pub fn dual_pp_timing_snapshot() -> ([u64; 4], [usize; 4]) {
742    (
743        std::array::from_fn(|i| DUAL_PP_STAGE_NS[i].load(Ordering::Relaxed)),
744        std::array::from_fn(|i| DUAL_PP_STAGE_SAMPLES[i].load(Ordering::Relaxed)),
745    )
746}
747
748pub(crate) struct DualPpStageGuard;
749
750pub(crate) fn enter_dual_pp_stage() -> DualPpStageGuard {
751    let active = DUAL_PP_ACTIVE_STAGES.fetch_add(1, Ordering::AcqRel);
752    if active > 0 {
753        DUAL_PP_OVERLAPS.fetch_add(1, Ordering::Relaxed);
754    }
755    DualPpStageGuard
756}
757
758impl Drop for DualPpStageGuard {
759    fn drop(&mut self) {
760        let active = DUAL_PP_ACTIVE_STAGES.fetch_sub(1, Ordering::AcqRel);
761        debug_assert!(active > 0, "dual PP active-stage counter underflow");
762    }
763}
764
765/// MEMRA_PRIME_PP=0: rollback/A-B seam for the PRIME (chunked prefill) stage split
766/// (lane/pp-leverb 2026-08-08). Default ON — with the ppN door open the chunked prime takes
767/// its own per-stage range walk exactly as the eager/batched/verify steps do. Setting 0 sends
768/// prime back through the unsplit whole-trunk walk. NOTE: unlike batch/dc/graph/spec, prime
769/// keeps NO `refuse_unsplit_if_remote` — its unsplit walk over a sharded placement is the
770/// measured 22% amortized peer-read tax (research/pp-prefill-20260807 anatomy: m=4096
771/// amortizes the weight reads), not the decode 28x cliff, and the unsplit walk IS the
772/// split-vs-unsplit gate's reference arm (`prime-split-gate`), so it must stay callable.
773/// Read per call, never memoized (the gate A/Bs both arms in one process).
774pub fn prime_pp_on() -> bool {
775    std::env::var("MEMRA_PRIME_PP").as_deref() != Ok("0")
776}
777
778/// MEMRA_PRIME_PIPE=0: rollback/A-B seam for the PP-2 PRIME CHUNK PIPELINE
779/// (lane/cx-pipeline-prime 2026-08-08). Default ON when the prime stage split is live;
780/// setting 0 keeps the serial per-chunk stage walk. Read per prime call so the exactness
781/// gate can replay both schedules against one loaded model.
782pub fn prime_pipe_on() -> bool {
783    std::env::var("MEMRA_PRIME_PIPE").as_deref() != Ok("0")
784}
785
786/// SPLIT-LIVENESS COUNTER for the prime stage split: bumped ONCE per prime chunk that
787/// actually executed the per-stage walk. The `prime-split-gate` requires this to ADVANCE
788/// during its split arm — bit-identity of two identical UNSPLIT walks is vacuous, so a gate
789/// that only compared bits would go green while the walker doesn't exist. With the counter,
790/// the gate is RED until the walker lands (the tickinv35 pattern: the gate exists and fails
791/// before the mechanism does). Relaxed ordering: single-threaded host issue, count-only.
792pub static PRIME_SPLIT_CHUNKS: AtomicUsize = AtomicUsize::new(0);
793
794/// Read the split-liveness counter (gate-side).
795pub fn prime_split_chunks() -> usize {
796    PRIME_SPLIT_CHUNKS.load(Ordering::Relaxed)
797}
798
799/// PIPELINE-LIVENESS COUNTER: bumped only when a second PP-2 prime stage enters its layer
800/// walker while the other stage's walker is still active. Step's per-layer router readback
801/// synchronizes the host, so enqueue order alone is not liveness: a single host thread can
802/// call stage 0(N+1) before the stage-1 epilogue and still serialize all trunk computation.
803pub static PRIME_PIPE_OVERLAPS: AtomicUsize = AtomicUsize::new(0);
804
805/// Read the prime-pipeline overlap counter (gate-side).
806pub fn prime_pipe_overlaps() -> usize {
807    PRIME_PIPE_OVERLAPS.load(Ordering::Relaxed)
808}
809
810static PRIME_PIPE_ACTIVE_STAGES: AtomicUsize = AtomicUsize::new(0);
811
812pub(crate) struct PrimePipeStageGuard;
813
814/// Mark one host-driven stage walker active. With PP-2, a transition 1 -> 2 proves the
815/// two device walkers overlap in wall time; exactly one transition is counted per pair.
816pub(crate) fn enter_prime_pipe_stage() -> PrimePipeStageGuard {
817    let active = PRIME_PIPE_ACTIVE_STAGES.fetch_add(1, Ordering::AcqRel);
818    if active > 0 {
819        PRIME_PIPE_OVERLAPS.fetch_add(1, Ordering::Relaxed);
820    }
821    PrimePipeStageGuard
822}
823
824impl Drop for PrimePipeStageGuard {
825    fn drop(&mut self) {
826        let active = PRIME_PIPE_ACTIVE_STAGES.fetch_sub(1, Ordering::AcqRel);
827        debug_assert!(active > 0, "prime pipeline active-stage counter underflow");
828    }
829}
830
831/// Step35 cross-request prime liveness counters (lane/cx-prime-batch, 2026-08-08).
832/// The exactness gate requires BOTH to advance: a successful step35 batch alone is not
833/// sufficient under PP-N if it walked the whole sharded trunk on one stream.
834pub static STEP35_PRIME_BATCHES: AtomicUsize = AtomicUsize::new(0);
835pub static STEP35_PRIME_BATCH_SPLITS: AtomicUsize = AtomicUsize::new(0);
836
837pub fn step35_prime_batches() -> usize {
838    STEP35_PRIME_BATCHES.load(Ordering::Relaxed)
839}
840
841pub fn step35_prime_batch_splits() -> usize {
842    STEP35_PRIME_BATCH_SPLITS.load(Ordering::Relaxed)
843}
844
845/// MEMRA_SPEC_PP=0: rollback/A-B seam for the SPEC VERIFY stage split (pp2-spec 2026-08-06).
846/// Default ON — with the ppN door open the verify forward (`decode_step_t_core_ppn`) takes its
847/// own stage split exactly as the eager and batched steps do. Setting 0 sends verify back through
848/// the unsplit trunk walk, which under a sharded cross-device placement is then caught by
849/// `refuse_unsplit_if_remote` (the 28x peer-read regime) rather than running silently. Exists so
850/// the bit-identity gate can A/B split vs unsplit IN ONE PROCESS against the same loaded weights
851/// — read per verify call, never memoized, for that reason.
852pub fn spec_pp_on() -> bool {
853    std::env::var("MEMRA_SPEC_PP").as_deref() != Ok("0")
854}
855
856/// MEMRA_PP_OVERLAP: alternate the double-buffered boundary slots per step (the
857/// pipelining seed). Scheduling structure only, never math. Read per step so gates can
858/// A/B in-process.
859///
860/// Unset follows the dual-PP mode (owner flip 2026-08-11): `Auto` resolves ON — the naked
861/// serve path is the box1 re-gate's dual arm (MEMRA_DUAL_PP=1 MEMRA_PP_OVERLAP=1,
862/// 929/929 golden, 0/9123 slot collisions). `Off` resolves OFF so MEMRA_DUAL_PP=0 alone
863/// restores the exact pre-flip serial naked path. `Forced` resolves OFF so the binding
864/// single-slot refusal of the explicit pre-flip request stays reachable — the
865/// decode-batch-gate negative cell pins and asserts precisely that combination.
866pub fn pp2_overlap() -> bool {
867    pp2_overlap_resolve(
868        std::env::var("MEMRA_PP_OVERLAP").ok().as_deref(),
869        dual_pp_mode(),
870    )
871}
872
873/// Pure resolution for MEMRA_PP_OVERLAP, split from the env read for the flip
874/// regression tests.
875pub fn pp2_overlap_resolve(v: Option<&str>, mode: DualPpMode) -> bool {
876    match v {
877        Some("1") => true,
878        Some(_) => false,
879        None => mode == DualPpMode::Auto,
880    }
881}
882
883/// Broken-peer escape hatch: stage-boundary activations travel through page-locked host
884/// memory instead of `cudaMemcpyPeerAsync`. Default OFF; captured when `PpNRt` is built.
885pub fn pp_host_bounce_on() -> bool {
886    matches!(std::env::var("MEMRA_PP_HOST_BOUNCE").as_deref(), Ok("1"))
887}
888
889/// True when host bounce is the live transport for a sharded cross-device placement.
890/// Callers use this to close paths that still peer-read non-boundary state.
891pub fn pp_host_bounce_active() -> bool {
892    (pp_host_bounce_on() || PEER_RUNTIME_HOST_BOUNCE.load(Ordering::Acquire))
893        && pp_sharded_cross_device()
894}
895
896/// M2 increment 2 rollback seam: MEMRA_PP_SHARD=0 = the M1 bring-up placement (all
897/// weights upload through the primary engine; remote stages peer-read). Default ON —
898/// under MEMRA_PP_DEVICES each stage's layer range uploads through its own engine.
899pub fn pp_shard_off() -> bool {
900    matches!(std::env::var("MEMRA_PP_SHARD").as_deref(), Ok("0"))
901}
902
903/// Raw `MEMRA_PP_DEVICES` (parsed/validated at PpNRt build — a bad string must fail the
904/// decode step loudly, never silently fall back to same-device and fake a gate PASS).
905fn pp2_devices_env() -> Option<String> {
906    std::env::var("MEMRA_PP_DEVICES")
907        .ok()
908        .filter(|v| !v.is_empty())
909}
910
911static WARNED_BAD: AtomicBool = AtomicBool::new(false);
912fn warn_bad_once(msg: &str) {
913    if !WARNED_BAD.swap(true, Ordering::Relaxed) {
914        eprintln!("[pp] {msg}");
915    }
916}
917
918static WARNED_UNWIRED: AtomicBool = AtomicBool::new(false);
919/// One-time notice when the door is set but the executing path has no pp arm
920/// (M2 wires the generic eager decode at any N and the gemma4 eager arm at N=2).
921pub fn warn_unwired_once(path: &str) {
922    let open = std::env::var("MEMRA_PP_STAGES")
923        .map(|v| !v.is_empty() && v != "0" && v != "1")
924        .unwrap_or(false);
925    if open && !WARNED_UNWIRED.swap(true, Ordering::Relaxed) {
926        eprintln!("[pp] MEMRA_PP_STAGES set but `{path}` has no pp arm at this N; running unsplit");
927    }
928}
929
930// ======================================================================================
931//  PpNRt: the M2 transport runtime (per-stage streams, per-boundary events + slots)
932// ======================================================================================
933
934/// One pipeline stage's execution home: device, context, launch stream, and (for a stage
935/// remote to the primary engine's device) a dedicated Engine in that device's primary
936/// context (CUmodules are per-context).
937pub struct StageRt {
938    pub dev: usize,
939    pub ctx: Arc<CudaContext>,
940    pub stream: Arc<CudaStream>,
941    pub blas: Arc<cudarc::cublaslt::CudaBlasLT>,
942    /// `Some` only when `dev` differs from the primary engine's device.
943    engine: Option<Engine>,
944}
945
946/// One boundary slot: a persistent RX-side buffer + its TX/RX completion events.
947/// PERSISTENT because the buffer is written by the TX stage's stream and read by the RX
948/// stage's: a per-step alloc/free would enqueue the free on ONE stream while the other
949/// might still be reading (the cross-stream free hazard) — a never-freed slot cannot race.
950struct BoundarySlot {
951    buf: Mutex<Option<CudaSlice<f32>>>,
952    /// Recorded on the TX stage's stream after the TX copy; RX waits on it. Created in
953    /// the TX stage's context (cuEventRecord requires event ctx == stream ctx).
954    ev_tx: CudaEvent,
955    /// Recorded on the RX stage's stream after the RX copy; the NEXT TX into this slot
956    /// waits on it (write-after-read guard). Created in the RX stage's context. Waiting
957    /// on a never-recorded event is a defined no-op, so step 0 needs no special case.
958    ev_rx: CudaEvent,
959}
960
961/// Boundary b sits between stage b (TX) and stage b+1 (RX). Two slots, alternating per
962/// step under MEMRA_PP_OVERLAP=1 (each boundary counts its own steps — a decode step
963/// crosses every boundary exactly once, so the counters stay in lockstep).
964struct BoundaryRt {
965    slots: [BoundarySlot; 2],
966    step: AtomicUsize,
967    /// true iff stage b and stage b+1 live on different devices (peer transport).
968    cross: bool,
969}
970
971#[derive(Clone, Copy, Debug, PartialEq, Eq)]
972enum BoundaryTransport {
973    Local,
974    Peer,
975    HostBounce,
976}
977
978#[derive(Clone, Copy)]
979struct BoundaryPath {
980    boundary: usize,
981    src_stage: usize,
982    dst_stage: usize,
983    transport: BoundaryTransport,
984}
985
986fn boundary_transport(cross: bool, host_bounce: bool) -> BoundaryTransport {
987    match (cross, host_bounce) {
988        (false, _) => BoundaryTransport::Local,
989        (true, false) => BoundaryTransport::Peer,
990        (true, true) => BoundaryTransport::HostBounce,
991    }
992}
993
994const PEER_PROBE_FIXED_BYTES: usize = 16 * 1024;
995const PEER_PROBE_TOKEN_WIDTHS: [usize; 4] = [1, 8, 16, crate::cache::PRIME_CHUNK_MAX_TOKENS];
996
997/// Native cross-device boundary copies between low-frequency runtime integrity probes.
998/// Fixed rather than operator-tunable: this is a safety gate, not a performance experiment.
999pub const PEER_RUNTIME_PROBE_INTERVAL_COPIES: u64 = 8 * 1024;
1000/// One complete runtime width rotation. The maximum-chunk rung runs once per cycle.
1001pub const PEER_RUNTIME_PROBE_CYCLE_COPIES: u64 =
1002    PEER_RUNTIME_PROBE_INTERVAL_COPIES * PEER_PROBE_TOKEN_WIDTHS.len() as u64;
1003/// Consecutive runnable probe intervals that may be blocked by live speculative UVA state before
1004/// integrity coverage becomes explicitly degraded. Four intervals are one full width rotation.
1005pub const PEER_RUNTIME_PROBE_DEFERRAL_BOUND_INTERVALS: u64 = PEER_PROBE_TOKEN_WIDTHS.len() as u64;
1006/// Maximum measured owner-thread wall cost that may remain on an interactive scheduler boundary.
1007const PEER_RUNTIME_PROBE_BUDGET_NS: u64 = 5_000_000;
1008
1009pub const PEER_PROBE_REQUIRED_REFUSAL: &str = "PP bring-up refused: MEMRA_PEER_PROBE=0 cannot authorize native peer transport for a \
1010     sharded cross-device placement while MEMRA_PP_HOST_BOUNCE!=1; leave MEMRA_PEER_PROBE \
1011     enabled or set MEMRA_PP_HOST_BOUNCE=1";
1012
1013#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1014pub enum PeerProbeStartupPolicy {
1015    Allowed,
1016    BypassedWithHostBounce,
1017}
1018
1019/// Pure startup policy so unit tests and kernel-check pin the entire refusal matrix without
1020/// mutating process-global environment variables.
1021pub fn peer_probe_startup_policy(
1022    probe_on: bool,
1023    sharded_cross_device: bool,
1024    host_bounce: bool,
1025) -> Result<PeerProbeStartupPolicy, &'static str> {
1026    match (probe_on, sharded_cross_device, host_bounce) {
1027        (false, true, false) => Err(PEER_PROBE_REQUIRED_REFUSAL),
1028        (false, true, true) => Ok(PeerProbeStartupPolicy::BypassedWithHostBounce),
1029        _ => Ok(PeerProbeStartupPolicy::Allowed),
1030    }
1031}
1032
1033static PEER_PROBE_BYPASSED: AtomicU64 = AtomicU64::new(0);
1034static PEER_BOUNDARY_COPIES: AtomicU64 = AtomicU64::new(0);
1035static PEER_RUNTIME_PROBES: AtomicU64 = AtomicU64::new(0);
1036static PEER_RUNTIME_PROBE_FAILURES: AtomicU64 = AtomicU64::new(0);
1037static PEER_RUNTIME_PROBE_DEFERRED: AtomicU64 = AtomicU64::new(0);
1038static PEER_RUNTIME_PROBE_INTEGRITY_DEGRADED: AtomicBool = AtomicBool::new(false);
1039static PEER_RUNTIME_PROBE_FAILED: AtomicBool = AtomicBool::new(false);
1040static PEER_RUNTIME_HOST_BOUNCE: AtomicBool = AtomicBool::new(false);
1041static PEER_RUNTIME_NEXT_PROBE_COPY: [AtomicU64; PEER_PROBE_TOKEN_WIDTHS.len()] = [
1042    AtomicU64::new(PEER_RUNTIME_PROBE_INTERVAL_COPIES),
1043    AtomicU64::new(2 * PEER_RUNTIME_PROBE_INTERVAL_COPIES),
1044    AtomicU64::new(3 * PEER_RUNTIME_PROBE_INTERVAL_COPIES),
1045    AtomicU64::new(4 * PEER_RUNTIME_PROBE_INTERVAL_COPIES),
1046];
1047static PEER_RUNTIME_PROBE_MAX_COST_NS: [AtomicU64; PEER_PROBE_TOKEN_WIDTHS.len()] = [
1048    AtomicU64::new(0),
1049    AtomicU64::new(0),
1050    AtomicU64::new(0),
1051    AtomicU64::new(0),
1052];
1053
1054#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
1055pub struct PeerProbeMetrics {
1056    pub bypassed: u64,
1057    pub boundary_copies: u64,
1058    pub runtime_probes: u64,
1059    pub runtime_failures: u64,
1060    pub deferred_total: u64,
1061    pub integrity_degraded: bool,
1062    pub degraded_to_host_bounce: bool,
1063}
1064
1065pub fn peer_probe_metrics() -> PeerProbeMetrics {
1066    PeerProbeMetrics {
1067        bypassed: PEER_PROBE_BYPASSED.load(Ordering::Relaxed),
1068        boundary_copies: PEER_BOUNDARY_COPIES.load(Ordering::Relaxed),
1069        runtime_probes: PEER_RUNTIME_PROBES.load(Ordering::Relaxed),
1070        runtime_failures: PEER_RUNTIME_PROBE_FAILURES.load(Ordering::Relaxed),
1071        deferred_total: PEER_RUNTIME_PROBE_DEFERRED.load(Ordering::Relaxed),
1072        integrity_degraded: PEER_RUNTIME_PROBE_INTEGRITY_DEGRADED.load(Ordering::Acquire),
1073        degraded_to_host_bounce: PEER_RUNTIME_HOST_BOUNCE.load(Ordering::Acquire),
1074    }
1075}
1076
1077#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1078pub enum RuntimePeerProbeStatus {
1079    NotRun,
1080    Deferred,
1081    Passed,
1082    DegradedToHostBounce,
1083}
1084
1085impl RuntimePeerProbeStatus {
1086    pub fn ran(self) -> bool {
1087        matches!(self, Self::Passed | Self::DegradedToHostBounce)
1088    }
1089}
1090
1091fn publish_runtime_peer_probe_deferral(
1092    deferred_total: &AtomicU64,
1093    integrity_degraded: &AtomicBool,
1094    intervals: u64,
1095    bound_reached: bool,
1096) {
1097    deferred_total.fetch_add(intervals, Ordering::Relaxed);
1098    if bound_reached {
1099        integrity_degraded.store(true, Ordering::Release);
1100    }
1101}
1102
1103/// Publish newly observed copy-count intervals where a runnable peer probe was blocked by live
1104/// speculative UVA state. The worker coalesces scheduler polls before calling this function.
1105pub fn record_runtime_peer_probe_deferral(intervals: u64, bound_reached: bool) {
1106    publish_runtime_peer_probe_deferral(
1107        &PEER_RUNTIME_PROBE_DEFERRED,
1108        &PEER_RUNTIME_PROBE_INTEGRITY_DEGRADED,
1109        intervals,
1110        bound_reached,
1111    );
1112}
1113
1114/// A completed native probe or validated transport failover restores an explicit integrity state.
1115pub fn clear_runtime_peer_probe_integrity_degraded() {
1116    PEER_RUNTIME_PROBE_INTEGRITY_DEGRADED.store(false, Ordering::Release);
1117}
1118
1119fn runtime_peer_probe_idle_only(width_index: usize, measured_cost_ns: u64) -> bool {
1120    width_index + 1 == PEER_PROBE_TOKEN_WIDTHS.len()
1121        || measured_cost_ns > PEER_RUNTIME_PROBE_BUDGET_NS
1122}
1123
1124/// Pick the oldest runnable per-width deadline. Idle-only overdue work is skipped rather than
1125/// blocking later cheap deadlines, so the small integrity ladder keeps its copy-count cadence.
1126fn runtime_peer_probe_candidate(
1127    copies: u64,
1128    next_probe_copy: [u64; PEER_PROBE_TOKEN_WIDTHS.len()],
1129    measured_cost_ns: [u64; PEER_PROBE_TOKEN_WIDTHS.len()],
1130    scheduler_idle: bool,
1131) -> Option<(usize, usize)> {
1132    let mut selected: Option<(usize, u64)> = None;
1133    for width_index in 0..PEER_PROBE_TOKEN_WIDTHS.len() {
1134        let due = next_probe_copy[width_index];
1135        if copies < due
1136            || (!scheduler_idle
1137                && runtime_peer_probe_idle_only(width_index, measured_cost_ns[width_index]))
1138        {
1139            continue;
1140        }
1141        if selected.is_none_or(|(_, selected_due)| due < selected_due) {
1142            selected = Some((width_index, due));
1143        }
1144    }
1145    selected.map(|(width_index, _)| (width_index, PEER_PROBE_TOKEN_WIDTHS[width_index]))
1146}
1147
1148/// Advance a late per-width deadline to the first future cycle. Missed idle opportunities
1149/// collapse into one probe instead of producing an owner-thread catch-up burst.
1150fn runtime_peer_probe_next_copy(due: u64, copies: u64) -> u64 {
1151    let cycles = copies.saturating_sub(due) / PEER_RUNTIME_PROBE_CYCLE_COPIES + 1;
1152    due.saturating_add(PEER_RUNTIME_PROBE_CYCLE_COPIES.saturating_mul(cycles))
1153}
1154
1155/// Fail closed before arming the fallback, then publish host bounce only after its staging check
1156/// succeeds. The two atomics are parameters so unit tests never mutate process-global state.
1157fn latch_runtime_host_bounce<E>(
1158    native_failed: &AtomicBool,
1159    degraded_to_host_bounce: &AtomicBool,
1160    arm_and_validate: impl FnOnce() -> Result<(), E>,
1161) -> Result<(), E> {
1162    native_failed.store(true, Ordering::Release);
1163    arm_and_validate()?;
1164    degraded_to_host_bounce.store(true, Ordering::Release);
1165    Ok(())
1166}
1167
1168fn peer_probe_on() -> bool {
1169    std::env::var("MEMRA_PEER_PROBE").as_deref() != Ok("0")
1170}
1171
1172#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1173enum PeerProbeDecision {
1174    Clean,
1175    ProceedWithHostBounce { mismatches: usize },
1176}
1177
1178fn peer_probe_mismatch_count(expected: &[u8], readback: &[u8]) -> usize {
1179    expected
1180        .iter()
1181        .zip(readback)
1182        .filter(|(a, b)| a != b)
1183        .count()
1184        + expected.len().abs_diff(readback.len())
1185}
1186
1187fn peer_probe_decision(
1188    expected: &[u8],
1189    readback: &[u8],
1190    host_bounce: bool,
1191) -> Result<PeerProbeDecision, String> {
1192    let mismatches = peer_probe_mismatch_count(expected, readback);
1193    if mismatches == 0 {
1194        Ok(PeerProbeDecision::Clean)
1195    } else if host_bounce {
1196        Ok(PeerProbeDecision::ProceedWithHostBounce { mismatches })
1197    } else {
1198        Err(format!("{mismatches} mismatched byte(s)"))
1199    }
1200}
1201
1202fn peer_probe_pattern(bytes: usize, boundary: usize, src_dev: usize, dst_dev: usize) -> Vec<u8> {
1203    let mut state = 0xD1B5_4A32_D192_ED03u64
1204        ^ (bytes as u64).rotate_left(7)
1205        ^ (boundary as u64).rotate_left(19)
1206        ^ (src_dev as u64).rotate_left(31)
1207        ^ (dst_dev as u64).rotate_left(43);
1208    (0..bytes)
1209        .map(|_| {
1210            state ^= state << 13;
1211            state ^= state >> 7;
1212            state ^= state << 17;
1213            state as u8
1214        })
1215        .collect()
1216}
1217
1218fn peer_probe_bytes_to_f32(bytes: &[u8]) -> Vec<f32> {
1219    assert_eq!(bytes.len() % std::mem::size_of::<f32>(), 0);
1220    bytes
1221        .chunks_exact(std::mem::size_of::<f32>())
1222        .map(|chunk| f32::from_bits(u32::from_ne_bytes(chunk.try_into().unwrap())))
1223        .collect()
1224}
1225
1226fn peer_probe_f32_to_bytes(values: &[f32]) -> Vec<u8> {
1227    values
1228        .iter()
1229        .flat_map(|value| value.to_bits().to_ne_bytes())
1230        .collect()
1231}
1232
1233/// A legacy `cuMemAlloc` buffer used only by the boot probe. Unlike memra's normal
1234/// stream-ordered allocations, it becomes peer-visible through `cuCtxEnablePeerAccess`
1235/// without requiring the default-pool grants that deliberately happen after the probe.
1236struct PeerProbeBuffer {
1237    ctx: Arc<CudaContext>,
1238    ptr: cudarc::driver::sys::CUdeviceptr,
1239}
1240
1241impl PeerProbeBuffer {
1242    fn new(ctx: &Arc<CudaContext>, bytes: usize) -> Result<Self, Box<dyn std::error::Error>> {
1243        ctx.bind_to_thread()?;
1244        let ptr = unsafe { cudarc::driver::result::malloc_sync(bytes)? };
1245        Ok(Self {
1246            ctx: ctx.clone(),
1247            ptr,
1248        })
1249    }
1250}
1251
1252impl Drop for PeerProbeBuffer {
1253    fn drop(&mut self) {
1254        if self.ctx.bind_to_thread().is_ok() {
1255            let _ = unsafe { cudarc::driver::result::free_sync(self.ptr) };
1256        }
1257    }
1258}
1259
1260fn peer_probe_copy(
1261    src: &StageRt,
1262    dst: &StageRt,
1263    expected: &[u8],
1264) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
1265    let bytes = expected.len();
1266    let src_buf = PeerProbeBuffer::new(&src.ctx, bytes)?;
1267    unsafe {
1268        cudarc::driver::result::memcpy_htod_sync(src_buf.ptr, expected)?;
1269    }
1270
1271    let dst_buf = PeerProbeBuffer::new(&dst.ctx, bytes)?;
1272    let poison: Vec<u8> = expected.iter().map(|b| !b).collect();
1273    unsafe {
1274        cudarc::driver::result::memcpy_htod_sync(dst_buf.ptr, &poison)?;
1275    }
1276
1277    src.ctx.bind_to_thread()?;
1278    unsafe {
1279        cudarc::driver::result::memcpy_peer_async(
1280            dst.ctx.cu_ctx(),
1281            dst_buf.ptr,
1282            src.ctx.cu_ctx(),
1283            src_buf.ptr,
1284            bytes,
1285            src.stream.cu_stream(),
1286        )?;
1287    }
1288
1289    // Publish the peer write to the receiving context exactly like the live BoundarySlot
1290    // transport does. A host-side synchronize of only the TX stream is not the production
1291    // cross-context visibility contract; the RX stream waits on a TX event before touching the
1292    // destination allocation. Keeping the integrity probe on that same ordering path avoids
1293    // diagnosing an intentionally unordered destination-context read as fabric corruption.
1294    let published = src.ctx.new_event(None)?;
1295    published.record(&src.stream)?;
1296
1297    dst.ctx.bind_to_thread()?;
1298    dst.stream.wait(&published)?;
1299    dst.stream.synchronize()?;
1300    let mut readback = vec![0u8; bytes];
1301    unsafe {
1302        cudarc::driver::result::memcpy_dtoh_sync(&mut readback, dst_buf.ptr)?;
1303    }
1304    Ok(readback)
1305}
1306
1307fn run_peer_probe_pass(
1308    stages: &[StageRt],
1309    peer_capable: &[(usize, usize)],
1310    host_bounce: bool,
1311    label: &str,
1312    bytes: usize,
1313) -> Result<(), Box<dyn std::error::Error>> {
1314    if bytes == 0 {
1315        return Err(format!("PP peer byte-integrity probe {label} size is zero").into());
1316    }
1317    let started = std::time::Instant::now();
1318    let mut copies = 0usize;
1319    let mut skipped = 0usize;
1320    let mut total_mismatches = 0usize;
1321
1322    for boundary in 0..stages.len() - 1 {
1323        if stages[boundary].dev == stages[boundary + 1].dev {
1324            continue;
1325        }
1326        for (src_idx, dst_idx) in [(boundary, boundary + 1), (boundary + 1, boundary)] {
1327            let src = &stages[src_idx];
1328            let dst = &stages[dst_idx];
1329            if !peer_capable.contains(&(src.dev, dst.dev)) {
1330                if host_bounce {
1331                    skipped += 1;
1332                    eprintln!(
1333                        "[pp] peer byte-integrity probe SKIP: boundary={boundary} \
1334                         dev{}->dev{} label={label} bytes={bytes} (peer capability unavailable; \
1335                         MEMRA_PP_HOST_BOUNCE=1 remains fail-safe)",
1336                        src.dev, dst.dev,
1337                    );
1338                    continue;
1339                }
1340                return Err(format!(
1341                    "PP peer byte-integrity probe cannot run boundary={boundary} \
1342                     dev{}->dev{}: peer access was not enabled",
1343                    src.dev, dst.dev,
1344                )
1345                .into());
1346            }
1347
1348            let expected = peer_probe_pattern(bytes, boundary, src.dev, dst.dev);
1349            let readback = match peer_probe_copy(src, dst, &expected) {
1350                Ok(readback) => readback,
1351                Err(err) if host_bounce => {
1352                    skipped += 1;
1353                    eprintln!(
1354                        "[pp] peer byte-integrity probe ERROR: boundary={boundary} \
1355                         dev{}->dev{} label={label} bytes={bytes}: {err}; \
1356                         MEMRA_PP_HOST_BOUNCE=1, proceeding on the host-staged path",
1357                        src.dev, dst.dev,
1358                    );
1359                    continue;
1360                }
1361                Err(err) => {
1362                    return Err(format!(
1363                        "PP peer byte-integrity probe FAILED: boundary={boundary} \
1364                         dev{}->dev{} label={label} bytes={bytes}: {err}; refusing native P2P \
1365                         (set MEMRA_PP_HOST_BOUNCE=1 to use the host-staged path; \
1366                         MEMRA_PEER_PROBE=0 cannot authorize sharded native peer transport)",
1367                        src.dev, dst.dev,
1368                    )
1369                    .into());
1370                }
1371            };
1372            copies += 1;
1373            match peer_probe_decision(&expected, &readback, host_bounce) {
1374                Ok(PeerProbeDecision::Clean) => {}
1375                Ok(PeerProbeDecision::ProceedWithHostBounce { mismatches }) => {
1376                    total_mismatches += mismatches;
1377                    eprintln!(
1378                        "[pp] peer byte-integrity probe CORRUPTION: boundary={boundary} \
1379                         dev{}->dev{} label={label} bytes={bytes} mismatches={mismatches}; \
1380                         MEMRA_PP_HOST_BOUNCE=1, proceeding on the host-staged path",
1381                        src.dev, dst.dev,
1382                    );
1383                }
1384                Err(mismatch) => {
1385                    return Err(format!(
1386                        "PP peer byte-integrity probe FAILED: boundary={boundary} \
1387                         dev{}->dev{} label={label} bytes={bytes}: {mismatch}; refusing native \
1388                         P2P (set MEMRA_PP_HOST_BOUNCE=1 to use the host-staged path; \
1389                         MEMRA_PEER_PROBE=0 cannot authorize sharded native peer transport)",
1390                        src.dev, dst.dev,
1391                    )
1392                    .into());
1393                }
1394            }
1395        }
1396    }
1397
1398    let status = if total_mismatches > 0 {
1399        "BOUNCE"
1400    } else if skipped > 0 && copies > 0 {
1401        "PARTIAL"
1402    } else if skipped > 0 {
1403        "SKIP"
1404    } else {
1405        "PASS"
1406    };
1407    eprintln!(
1408        "[pp] peer byte-integrity probe {}: label={label} bytes={bytes} copies={copies} \
1409         skipped={skipped} mismatches={total_mismatches} elapsed_ms={:.3}",
1410        status,
1411        started.elapsed().as_secs_f64() * 1e3,
1412    );
1413    Ok(())
1414}
1415
1416fn host_bounce_capacity(n_embd: usize) -> Result<(usize, usize), String> {
1417    if n_embd == 0 {
1418        return Err("MEMRA_PP_HOST_BOUNCE needs non-zero model n_embd".into());
1419    }
1420    let elems = n_embd
1421        .checked_mul(crate::cache::PRIME_CHUNK_MAX_TOKENS)
1422        .ok_or_else(|| format!("host-bounce element count overflows for n_embd={n_embd}"))?;
1423    let bytes = elems
1424        .checked_mul(std::mem::size_of::<f32>())
1425        .ok_or_else(|| format!("host-bounce byte count overflows for n_embd={n_embd}"))?;
1426    Ok((elems, bytes))
1427}
1428
1429fn boundary_slot_growth_elements(current: [usize; 2], required: usize) -> usize {
1430    current.into_iter().fold(0usize, |total, len| {
1431        total.saturating_add(required.saturating_sub(len))
1432    })
1433}
1434
1435/// One bidirectional-DMA staging allocation. `CU_MEMHOSTALLOC_PORTABLE` matters here: the
1436/// D2H producer and H2D consumer are in distinct CUDA primary contexts. Cacheable memory is
1437/// intentional (rather than cudarc's write-combined pinned slice) because this allocation is
1438/// the destination of D2H as well as the source of H2D.
1439struct PinnedHostBounce {
1440    ptr: *mut f32,
1441    len: usize,
1442}
1443
1444unsafe impl Send for PinnedHostBounce {}
1445unsafe impl Sync for PinnedHostBounce {}
1446
1447impl PinnedHostBounce {
1448    fn new(len: usize) -> Result<Self, Box<dyn std::error::Error>> {
1449        let bytes = len
1450            .checked_mul(std::mem::size_of::<f32>())
1451            .ok_or("host-bounce pinned allocation size overflow")?;
1452        let ptr = unsafe {
1453            cudarc::driver::result::malloc_host(
1454                bytes,
1455                cudarc::driver::sys::CU_MEMHOSTALLOC_PORTABLE,
1456            )?
1457        } as *mut f32;
1458        if ptr.is_null() {
1459            return Err("cuMemHostAlloc returned a null host-bounce pointer".into());
1460        }
1461        Ok(Self { ptr, len })
1462    }
1463
1464    fn prefix(&self, n: usize) -> &[f32] {
1465        assert!(
1466            n <= self.len,
1467            "host-bounce source {n} > capacity {}",
1468            self.len
1469        );
1470        unsafe { std::slice::from_raw_parts(self.ptr, n) }
1471    }
1472
1473    fn prefix_mut(&mut self, n: usize) -> &mut [f32] {
1474        assert!(
1475            n <= self.len,
1476            "host-bounce destination {n} > capacity {}",
1477            self.len
1478        );
1479        unsafe { std::slice::from_raw_parts_mut(self.ptr, n) }
1480    }
1481}
1482
1483impl Drop for PinnedHostBounce {
1484    fn drop(&mut self) {
1485        let _ = unsafe { cudarc::driver::result::free_host(self.ptr.cast()) };
1486    }
1487}
1488
1489struct HostBounceRt {
1490    n_embd: usize,
1491    capacity: usize,
1492    slots: Vec<Option<[Mutex<PinnedHostBounce>; 2]>>,
1493}
1494
1495impl HostBounceRt {
1496    fn new(n_embd: usize, boundaries: &[BoundaryRt]) -> Result<Self, Box<dyn std::error::Error>> {
1497        let (capacity, _) = host_bounce_capacity(n_embd)?;
1498        let mut slots = Vec::with_capacity(boundaries.len());
1499        for boundary in boundaries {
1500            slots.push(if boundary.cross {
1501                Some([
1502                    Mutex::new(PinnedHostBounce::new(capacity)?),
1503                    Mutex::new(PinnedHostBounce::new(capacity)?),
1504                ])
1505            } else {
1506                None
1507            });
1508        }
1509        Ok(Self {
1510            n_embd,
1511            capacity,
1512            slots,
1513        })
1514    }
1515
1516    fn slot(
1517        &self,
1518        boundary: usize,
1519        slot: usize,
1520    ) -> Result<&Mutex<PinnedHostBounce>, Box<dyn std::error::Error>> {
1521        self.slots
1522            .get(boundary)
1523            .and_then(Option::as_ref)
1524            .and_then(|slots| slots.get(slot))
1525            .ok_or_else(|| format!("host-bounce slot {boundary}:{slot} is not initialized").into())
1526    }
1527}
1528
1529pub struct PpNRt {
1530    stages: Vec<StageRt>,
1531    boundaries: Vec<BoundaryRt>,
1532    /// Whole-walk ownership for the shared boundary slot/event sequence. Boundary-local atomics
1533    /// choose alternating slots but cannot distinguish two interleaved callers; one generation
1534    /// lease therefore spans entry fencing through final publication/result collection.
1535    walk_active: Arc<AtomicU64>,
1536    walk_next: AtomicU64,
1537    /// A deferred decode window intentionally owns several in-flight logits tickets. The weak
1538    /// reference lets consecutive enqueue calls on the same CUDA-owner thread join that window;
1539    /// the active generation is released only after the final `PendingLogits` is drained/dropped.
1540    deferred_walk: Mutex<Weak<PpWalkState>>,
1541    /// true iff ANY boundary crosses devices.
1542    cross_any: bool,
1543    /// Startup selection captured at runtime construction. A runtime probe failure may promote
1544    /// the process-wide one-way host-bounce latch without mutating this value.
1545    host_bounce: bool,
1546    /// Boot-time peer validation is default-on; `MEMRA_PEER_PROBE=0` is diagnostics-only.
1547    peer_probe: bool,
1548    /// Directed device pairs for which `cuDeviceCanAccessPeer` succeeded.
1549    peer_capable: Vec<(usize, usize)>,
1550    /// Sticky one-time model-width probe result. The value is the one-row geometry byte count.
1551    peer_probe_geometry: OnceLock<Result<usize, String>>,
1552    /// Lazily allocated after the authoritative model width is known at cache creation.
1553    bounce: OnceLock<Result<HostBounceRt, String>>,
1554    /// Dedicated readback stream in the LAST stage's context (deferred logits D2H —
1555    /// waiting there instead of on the compute stream keeps later tokens enqueuable).
1556    readback: Arc<CudaStream>,
1557}
1558
1559#[derive(Debug)]
1560struct PpWalkState {
1561    active: Arc<AtomicU64>,
1562    generation: u64,
1563    runtime_id: usize,
1564    deferred_owner: Option<std::thread::ThreadId>,
1565}
1566
1567impl PpWalkState {
1568    fn is_active(&self) -> bool {
1569        self.active.load(Ordering::Acquire) == self.generation
1570    }
1571}
1572
1573impl Drop for PpWalkState {
1574    fn drop(&mut self) {
1575        let _ =
1576            self.active
1577                .compare_exchange(self.generation, 0, Ordering::AcqRel, Ordering::Acquire);
1578    }
1579}
1580
1581/// Opaque lifetime token for one complete PP boundary walk. Clones are allowed only through an
1582/// explicit coordinator permit or the same-thread deferred enqueue window; the active generation
1583/// clears when the final clone is dropped.
1584#[derive(Debug)]
1585pub struct PpWalkLease {
1586    state: Arc<PpWalkState>,
1587}
1588
1589/// Explicit authority for a coordinator whose two host lanes intentionally share one PP walk.
1590#[derive(Clone, Debug)]
1591pub(crate) struct PpWalkPermit {
1592    state: Arc<PpWalkState>,
1593}
1594
1595thread_local! {
1596    static PP_WALK_BORROWS: RefCell<Vec<Arc<PpWalkState>>> = const { RefCell::new(Vec::new()) };
1597}
1598
1599/// Thread-local borrowed authority. It is deliberately !Send so a caller must install the permit
1600/// independently in each scoped coordinator lane.
1601pub(crate) struct PpWalkBorrowGuard {
1602    prior_len: usize,
1603    _not_send: PhantomData<Rc<()>>,
1604}
1605
1606impl Drop for PpWalkBorrowGuard {
1607    fn drop(&mut self) {
1608        PP_WALK_BORROWS.with(|borrows| borrows.borrow_mut().truncate(self.prior_len));
1609    }
1610}
1611
1612fn next_pp_walk_generation(next: &AtomicU64) -> u64 {
1613    loop {
1614        let generation = next.fetch_add(1, Ordering::Relaxed);
1615        if generation != 0 {
1616            return generation;
1617        }
1618    }
1619}
1620
1621fn acquire_pp_walk(
1622    active: &Arc<AtomicU64>,
1623    next: &AtomicU64,
1624    runtime_id: usize,
1625    deferred_owner: Option<std::thread::ThreadId>,
1626    path: &str,
1627) -> Result<PpWalkLease, String> {
1628    let generation = next_pp_walk_generation(next);
1629    active
1630        .compare_exchange(0, generation, Ordering::AcqRel, Ordering::Acquire)
1631        .map_err(|_| {
1632            format!(
1633                "{path}: refused concurrent PP walk; shared boundary slots already have an owner"
1634            )
1635        })?;
1636    Ok(PpWalkLease {
1637        state: Arc::new(PpWalkState {
1638            active: active.clone(),
1639            generation,
1640            runtime_id,
1641            deferred_owner,
1642        }),
1643    })
1644}
1645
1646fn borrowed_pp_walk(runtime_id: usize) -> Option<PpWalkLease> {
1647    PP_WALK_BORROWS.with(|borrows| {
1648        borrows
1649            .borrow()
1650            .iter()
1651            .rev()
1652            .find(|state| state.runtime_id == runtime_id && state.is_active())
1653            .cloned()
1654            .map(|state| PpWalkLease { state })
1655    })
1656}
1657
1658fn lock_deferred_walk<'a>(
1659    deferred: &'a Mutex<Weak<PpWalkState>>,
1660    path: &str,
1661) -> Result<std::sync::MutexGuard<'a, Weak<PpWalkState>>, String> {
1662    deferred
1663        .lock()
1664        .map_err(|_| format!("{path}: deferred PP walk owner lock is poisoned"))
1665}
1666
1667fn validate_walk_state(state: &PpWalkState, runtime_id: usize, path: &str) -> Result<(), String> {
1668    if state.runtime_id != runtime_id {
1669        return Err(format!(
1670            "{path}: PP walk permit belongs to a different runtime"
1671        ));
1672    }
1673    if !state.is_active() {
1674        return Err(format!(
1675            "{path}: PP walk permit generation is no longer active"
1676        ));
1677    }
1678    Ok(())
1679}
1680
1681/// M1 name kept alive for external callers (`pp-transport-smoke`, receipts, docs).
1682pub type Pp2Rt = PpNRt;
1683
1684static RTN: OnceLock<Result<PpNRt, String>> = OnceLock::new();
1685
1686impl PpNRt {
1687    /// The process-wide transport runtime, built on first use against the primary engine.
1688    /// The stage count + device map freeze at first build (one config per process — gates
1689    /// run one placement per invocation). Build errors are sticky and loud.
1690    pub fn get(e: &Engine) -> Result<&'static PpNRt, Box<dyn std::error::Error>> {
1691        RTN.get_or_init(|| Self::build(e).map_err(|err| err.to_string()))
1692            .as_ref()
1693            .map_err(|s| -> Box<dyn std::error::Error> { s.clone().into() })
1694    }
1695
1696    fn build(e: &Engine) -> Result<PpNRt, Box<dyn std::error::Error>> {
1697        // Validate the experimental PP3/PP4 door at runtime construction so an invalid value is a
1698        // boot refusal, never a silently-disabled serving policy discovered on the first request.
1699        pp_wave_on().map_err(|reason| -> Box<dyn std::error::Error> { reason.into() })?;
1700        let primary_dev = e.ctx().ordinal();
1701        // Stage count: MEMRA_PP_DEVICES length wins when set (it IS the placement);
1702        // else MEMRA_PP_STAGES; else 2 (the M1 default — pp-transport-smoke runs doorless).
1703        let devices: Vec<usize> =
1704            match pp2_devices_env() {
1705                Some(s) => {
1706                    let parts: Result<Vec<usize>, _> =
1707                        s.split(',').map(|p| p.trim().parse::<usize>()).collect();
1708                    match parts {
1709                        Ok(v) if v.len() >= 2 => v,
1710                        _ => return Err(format!(
1711                            "MEMRA_PP_DEVICES={s} unparseable (want <d0>,..,<dN-1> e.g. 0,1,2,3)"
1712                        )
1713                        .into()),
1714                    }
1715                }
1716                None => {
1717                    let n_st = std::env::var("MEMRA_PP_STAGES")
1718                        .ok()
1719                        .and_then(|v| v.parse::<usize>().ok())
1720                        .filter(|&n| n >= 2)
1721                        .unwrap_or(2);
1722                    vec![primary_dev; n_st]
1723                }
1724            };
1725        if let Ok(v) = std::env::var("MEMRA_PP_STAGES")
1726            && let Ok(n) = v.parse::<usize>()
1727            && n >= 2
1728            && n != devices.len()
1729        {
1730            return Err(format!(
1731                "MEMRA_PP_DEVICES lists {} devices but MEMRA_PP_STAGES={n} — \
1732                         refusing an ambiguous placement",
1733                devices.len()
1734            )
1735            .into());
1736        }
1737        let n_st = devices.len();
1738        let cross_any = devices.iter().any(|&d| d != devices[0]);
1739        let host_bounce = pp_host_bounce_on();
1740        let peer_probe = peer_probe_on();
1741        let sharded_cross_device = cross_any && !pp_shard_off();
1742        if host_bounce && cross_any {
1743            if pp_shard_off() {
1744                return Err(
1745                    "MEMRA_PP_HOST_BOUNCE=1 refuses MEMRA_PP_SHARD=0: the boundary can bounce, \
1746                     but remote stages would still peer-read primary-device weights"
1747                        .into(),
1748                );
1749            }
1750            if devices.last().copied() != Some(primary_dev) {
1751                return Err(format!(
1752                    "MEMRA_PP_HOST_BOUNCE=1 requires the primary engine on the last/head stage \
1753                     (primary dev{primary_dev}, placement {devices:?}); otherwise returned \
1754                     logits/hidden state remain peer reads"
1755                )
1756                .into());
1757            }
1758        }
1759        let peer_probe_policy =
1760            peer_probe_startup_policy(peer_probe, sharded_cross_device, host_bounce)?;
1761        if peer_probe_policy == PeerProbeStartupPolicy::BypassedWithHostBounce {
1762            PEER_PROBE_BYPASSED.fetch_add(1, Ordering::Relaxed);
1763            eprintln!(
1764                "[pp] SECURITY RED: peer_probe_bypassed: MEMRA_PEER_PROBE=0 on a sharded \
1765                 cross-device placement; MEMRA_PP_HOST_BOUNCE=1 is the only enabled transport"
1766            );
1767        }
1768
1769        // Validate every placement ordinal in both transports. Native peer transport requires
1770        // access both ways. Host bounce remains usable without it, but records any capable pairs
1771        // so the byte probe can still diagnose a lying peer path before selecting the fallback.
1772        let mut used: Vec<usize> = devices.clone();
1773        used.push(primary_dev);
1774        used.sort_unstable();
1775        used.dedup();
1776        let mut peer_capable = Vec::new();
1777        if used.len() > 1 {
1778            let n = cudarc::driver::result::device::get_count()? as usize;
1779            for &d in &used {
1780                if d >= n {
1781                    return Err(format!(
1782                        "MEMRA_PP_DEVICES={devices:?} but only {n} CUDA device(s) present"
1783                    )
1784                    .into());
1785                }
1786            }
1787            if !host_bounce || peer_probe {
1788                for &a in &used {
1789                    for &b in &used {
1790                        if a == b {
1791                            continue;
1792                        }
1793                        let da = cudarc::driver::result::device::get(a as i32)?;
1794                        let db = cudarc::driver::result::device::get(b as i32)?;
1795                        let mut can: i32 = 0;
1796                        let capability = unsafe {
1797                            cudarc::driver::sys::cuDeviceCanAccessPeer(&mut can, da, db).result()
1798                        };
1799                        if let Err(err) = capability {
1800                            if host_bounce {
1801                                eprintln!(
1802                                    "[pp] peer byte-integrity probe capability query failed for \
1803                                     dev{a}->dev{b}: {err}; MEMRA_PP_HOST_BOUNCE=1 remains active"
1804                                );
1805                                continue;
1806                            }
1807                            return Err(err.into());
1808                        }
1809                        if can == 0 {
1810                            if !host_bounce {
1811                                return Err(format!(
1812                                    "device {a} cannot peer-access device {b} \
1813                                     (cuDeviceCanAccessPeer=0); ppN cross-device needs P2P — \
1814                                     refusing a silently-staged path"
1815                                )
1816                                .into());
1817                            }
1818                        } else {
1819                            peer_capable.push((a, b));
1820                        }
1821                    }
1822                }
1823            }
1824        }
1825
1826        // PER-STAGE ENGINE ISOLATION (2026-08-02 singledev pipelined find): Engine owns
1827        // lazily-grown SHARED scratch pools (fa_part_pool, fa_vf16_scratch, argmax
1828        // partials, ...) that are stable-pointer by design — safe on one stream, a data
1829        // race the moment two stage streams run concurrently through the SAME Engine
1830        // (deferred readback, >=2 tokens in flight: token t+1's stage-0 fa memsets the
1831        // partials while token t's stage-s fa still reads them — the nondeterministic
1832        // all-logits divergence; cross-device arms were immune because remote stages
1833        // already got their own Engine). Every stage s>0 gets its OWN Engine even on the
1834        // primary device: same CUcontext (primary retain), so the per-context CUmodule
1835        // cache makes it cheap; scratch pools are per-Engine, so stages never share.
1836        // Stage 0 keeps the primary engine (single-threaded host issue: the only
1837        // concurrent user of `e` during a pp walk is stage 0 itself).
1838        let mk_stage = |dev: usize, s: usize| -> Result<StageRt, Box<dyn std::error::Error>> {
1839            if dev == primary_dev && s == 0 {
1840                let ctx = e.ctx().clone();
1841                let stream = ctx.new_stream()?;
1842                let blas = Arc::new(cudarc::cublaslt::CudaBlasLT::new(stream.clone())?);
1843                Ok(StageRt {
1844                    dev,
1845                    ctx,
1846                    stream,
1847                    blas,
1848                    engine: None,
1849                })
1850            } else {
1851                let eng = Engine::new(dev)?;
1852                let ctx = eng.ctx().clone();
1853                let stream = ctx.new_stream()?;
1854                let blas = Arc::new(cudarc::cublaslt::CudaBlasLT::new(stream.clone())?);
1855                Ok(StageRt {
1856                    dev,
1857                    ctx,
1858                    stream,
1859                    blas,
1860                    engine: Some(eng),
1861                })
1862            }
1863        };
1864        let mut stages = Vec::with_capacity(n_st);
1865        for (s, &d) in devices.iter().enumerate() {
1866            stages.push(mk_stage(d, s)?);
1867        }
1868
1869        if cross_any
1870            && !peer_probe
1871            && peer_probe_policy != PeerProbeStartupPolicy::BypassedWithHostBounce
1872        {
1873            eprintln!(
1874                "[pp] WARNING: MEMRA_PEER_PROBE=0 skips the boot-time peer byte-integrity \
1875                 gate; diagnostics escape hatch active"
1876            );
1877        }
1878
1879        if used.len() > 1 {
1880            if !host_bounce {
1881                // A context per distinct device (first stage that lives there; the primary's
1882                // context for the primary device).
1883                let ctx_of = |d: usize| -> &Arc<CudaContext> {
1884                    if d == primary_dev {
1885                        e.ctx()
1886                    } else {
1887                        &stages.iter().find(|s| s.dev == d).unwrap().ctx
1888                    }
1889                };
1890                // Enable peer access BOTH ways for every distinct pair (idempotent;
1891                // ALREADY_ENABLED is success).
1892                for &a in &used {
1893                    for &b in &used {
1894                        if a == b {
1895                            continue;
1896                        }
1897                        ctx_of(a).bind_to_thread()?;
1898                        let rc = unsafe {
1899                            cudarc::driver::sys::cuCtxEnablePeerAccess(ctx_of(b).cu_ctx(), 0)
1900                        };
1901                        use cudarc::driver::sys::cudaError_enum as E;
1902                        if rc != E::CUDA_SUCCESS && rc != E::CUDA_ERROR_PEER_ACCESS_ALREADY_ENABLED
1903                        {
1904                            return Err(format!(
1905                                "cuCtxEnablePeerAccess(dev{a} -> dev{b}) failed: {rc:?}"
1906                            )
1907                            .into());
1908                        }
1909                    }
1910                }
1911                // The fixed-size byte gate runs immediately after peer enable and before pool
1912                // grants. Legacy allocations make it exercise the exact `cuMemcpyPeerAsync` API
1913                // without depending on the pool setup that follows.
1914                if peer_probe && cross_any {
1915                    let probe = run_peer_probe_pass(
1916                        &stages,
1917                        &peer_capable,
1918                        host_bounce,
1919                        "fixed-16KiB",
1920                        PEER_PROBE_FIXED_BYTES,
1921                    );
1922                    e.ctx().bind_to_thread()?;
1923                    probe?;
1924                }
1925                // MEM-POOL access grant (8x box 2026-08-02, M1 cross-device fix #2):
1926                // cuCtxEnablePeerAccess does NOT map STREAM-ORDERED POOL allocations, and every
1927                // engine buffer/weight goes through the device default pool (cuMemAllocAsync via
1928                // cudarc; memra-runtime configures that pool). A stage kernel dereferencing
1929                // another device's weights — or a boundary peer TX writing the RX slot — needs
1930                // cuMemPoolSetAccess on the OWNING device's default pool for the ACCESSING
1931                // device; without it the first remote dereference is CUDA_ERROR_ILLEGAL_ADDRESS
1932                // (reported at the next API call in the poisoned context). Grant all pairs.
1933                for &owner in &used {
1934                    for &accessor in &used {
1935                        if owner == accessor {
1936                            continue;
1937                        }
1938                        let dev = cudarc::driver::result::device::get(owner as i32)?;
1939                        let mut pool: cudarc::driver::sys::CUmemoryPool = std::ptr::null_mut();
1940                        unsafe {
1941                            cudarc::driver::sys::cuDeviceGetDefaultMemPool(&mut pool, dev)
1942                                .result()?;
1943                        }
1944                        let desc = cudarc::driver::sys::CUmemAccessDesc {
1945                        location: cudarc::driver::sys::CUmemLocation {
1946                            type_: cudarc::driver::sys::CUmemLocationType::CU_MEM_LOCATION_TYPE_DEVICE,
1947                            id: accessor as i32,
1948                        },
1949                        flags: cudarc::driver::sys::CUmemAccess_flags::CU_MEM_ACCESS_FLAGS_PROT_READWRITE,
1950                    };
1951                        let rc = unsafe { cudarc::driver::sys::cuMemPoolSetAccess(pool, &desc, 1) };
1952                        if rc != cudarc::driver::sys::cudaError_enum::CUDA_SUCCESS {
1953                            return Err(format!(
1954                            "cuMemPoolSetAccess(dev{owner} pool -> dev{accessor}) failed: {rc:?}"
1955                        )
1956                        .into());
1957                        }
1958                    }
1959                }
1960                // MEM-POOL access grant (8x box 2026-08-02, cross-device fix #2):
1961                // cuCtxEnablePeerAccess does NOT map STREAM-ORDERED POOL allocations, and every
1962                // engine buffer/weight goes through the device default pool (cuMemAllocAsync via
1963                // cudarc; memra-runtime configures that pool). A stage-1 kernel dereferencing
1964                // dev0 weights — or the stage-0 peer TX writing dev1's RX slot — needs
1965                // cuMemPoolSetAccess on the OWNING device's default pool for the ACCESSING
1966                // device; without it the first remote dereference is CUDA_ERROR_ILLEGAL_ADDRESS
1967                // (reported at the next API call in the poisoned context). Grant both ways.
1968                for (owner, accessor) in [
1969                    (stages[0].dev, stages[1].dev),
1970                    (stages[1].dev, stages[0].dev),
1971                ] {
1972                    let dev = cudarc::driver::result::device::get(owner as i32)?;
1973                    let mut pool: cudarc::driver::sys::CUmemoryPool = std::ptr::null_mut();
1974                    unsafe {
1975                        cudarc::driver::sys::cuDeviceGetDefaultMemPool(&mut pool, dev).result()?;
1976                    }
1977                    let desc = cudarc::driver::sys::CUmemAccessDesc {
1978                    location: cudarc::driver::sys::CUmemLocation {
1979                        type_: cudarc::driver::sys::CUmemLocationType::CU_MEM_LOCATION_TYPE_DEVICE,
1980                        id: accessor as i32,
1981                    },
1982                    flags: cudarc::driver::sys::CUmemAccess_flags::CU_MEM_ACCESS_FLAGS_PROT_READWRITE,
1983                };
1984                    let rc = unsafe { cudarc::driver::sys::cuMemPoolSetAccess(pool, &desc, 1) };
1985                    if rc != cudarc::driver::sys::cudaError_enum::CUDA_SUCCESS {
1986                        return Err(format!(
1987                            "cuMemPoolSetAccess(dev{owner} pool -> dev{accessor}) failed: {rc:?}"
1988                        )
1989                        .into());
1990                    }
1991                }
1992                // restore the primary context for the caller's subsequent work
1993                e.ctx().bind_to_thread()?;
1994                eprintln!(
1995                    "[pp] cross-device transport: {} (cudaMemcpyPeerAsync per cross boundary; \
1996                 peer + default-pool access granted all pairs over {used:?}; weight home: {})",
1997                    devices
1998                        .iter()
1999                        .enumerate()
2000                        .map(|(s, d)| format!("stage{s}=dev{d}"))
2001                        .collect::<Vec<_>>()
2002                        .join(" "),
2003                    if pp_shard_off() {
2004                        format!("dev{primary_dev} (MEMRA_PP_SHARD=0 bring-up placement)")
2005                    } else {
2006                        "per-stage (sharded loader)".to_string()
2007                    }
2008                );
2009            } else {
2010                e.ctx().bind_to_thread()?;
2011                eprintln!(
2012                    "[pp] cross-device transport: {} (HOST-STAGED pinned D2H -> H2D per cross \
2013                     boundary; MEMRA_PP_HOST_BOUNCE=1; peer-pool grants bypassed; \
2014                     diagnostic peer access is removed before host-staged serving; \
2015                     weight home: per-stage (sharded loader))",
2016                    devices
2017                        .iter()
2018                        .enumerate()
2019                        .map(|(s, d)| format!("stage{s}=dev{d}"))
2020                        .collect::<Vec<_>>()
2021                        .join(" "),
2022                );
2023            }
2024        }
2025
2026        let mk_slot =
2027            |tx: &StageRt, rx: &StageRt| -> Result<BoundarySlot, Box<dyn std::error::Error>> {
2028                Ok(BoundarySlot {
2029                    buf: Mutex::new(None),
2030                    ev_tx: tx.ctx.new_event(None)?,
2031                    ev_rx: rx.ctx.new_event(None)?,
2032                })
2033            };
2034        let mut boundaries = Vec::with_capacity(n_st - 1);
2035        for b in 0..n_st - 1 {
2036            let (tx, rx) = (&stages[b], &stages[b + 1]);
2037            boundaries.push(BoundaryRt {
2038                slots: [mk_slot(tx, rx)?, mk_slot(tx, rx)?],
2039                step: AtomicUsize::new(0),
2040                cross: tx.dev != rx.dev,
2041            });
2042        }
2043        let readback = stages[n_st - 1].ctx.new_stream()?;
2044        let rt = PpNRt {
2045            stages,
2046            boundaries,
2047            walk_active: Arc::new(AtomicU64::new(0)),
2048            walk_next: AtomicU64::new(1),
2049            deferred_walk: Mutex::new(Weak::new()),
2050            cross_any,
2051            host_bounce,
2052            peer_probe,
2053            peer_capable,
2054            peer_probe_geometry: OnceLock::new(),
2055            bounce: OnceLock::new(),
2056            readback,
2057        };
2058        if rt.peer_probe && rt.cross_any && rt.host_bounce {
2059            rt.run_host_bounce_legacy_probe(e)?;
2060        }
2061        Ok(rt)
2062    }
2063
2064    pub fn n_stages(&self) -> usize {
2065        self.stages.len()
2066    }
2067
2068    /// Acquire exclusive ownership of the PP boundary/event sequence for one complete model walk.
2069    /// Fail fast rather than blocking. A nested call can join only when its thread has an explicit
2070    /// coordinator borrow installed; merely running on the original thread is not authority.
2071    pub fn acquire_walk(
2072        &'static self,
2073        path: &str,
2074    ) -> Result<PpWalkLease, Box<dyn std::error::Error>> {
2075        let runtime_id = self as *const Self as usize;
2076        if let Some(lease) = borrowed_pp_walk(runtime_id) {
2077            return Ok(lease);
2078        }
2079        acquire_pp_walk(&self.walk_active, &self.walk_next, runtime_id, None, path)
2080            .map_err(|error| -> Box<dyn std::error::Error> { error.into() })
2081    }
2082
2083    /// Join the one intentional multi-enqueue deferred window. Only the thread that opened the
2084    /// window may add work; unrelated callers still fail fast while any pending result exists.
2085    pub(crate) fn acquire_deferred_walk(
2086        &'static self,
2087        path: &str,
2088    ) -> Result<PpWalkLease, Box<dyn std::error::Error>> {
2089        let runtime_id = self as *const Self as usize;
2090        let current_thread = std::thread::current().id();
2091        let mut weak = lock_deferred_walk(&self.deferred_walk, path)
2092            .map_err(|error| -> Box<dyn std::error::Error> { error.into() })?;
2093        if let Some(state) = weak.upgrade() {
2094            validate_walk_state(&state, runtime_id, path)
2095                .map_err(|error| -> Box<dyn std::error::Error> { error.into() })?;
2096            if state.deferred_owner.as_ref() != Some(&current_thread) {
2097                return Err(format!(
2098                    "{path}: refused cross-thread join of the active deferred PP window"
2099                )
2100                .into());
2101            }
2102            return Ok(PpWalkLease { state });
2103        }
2104        let lease = acquire_pp_walk(
2105            &self.walk_active,
2106            &self.walk_next,
2107            runtime_id,
2108            Some(current_thread),
2109            path,
2110        )
2111        .map_err(|error| -> Box<dyn std::error::Error> { error.into() })?;
2112        *weak = Arc::downgrade(&lease.state);
2113        Ok(lease)
2114    }
2115
2116    /// Mint coordinator authority from an active owner lease. Passing this object is the only way
2117    /// another host thread can make nested PP calls within that same generation.
2118    pub(crate) fn walk_permit(
2119        &'static self,
2120        lease: &PpWalkLease,
2121        path: &str,
2122    ) -> Result<PpWalkPermit, Box<dyn std::error::Error>> {
2123        let runtime_id = self as *const Self as usize;
2124        validate_walk_state(&lease.state, runtime_id, path)
2125            .map_err(|error| -> Box<dyn std::error::Error> { error.into() })?;
2126        if lease.state.deferred_owner.is_some() {
2127            return Err(
2128                format!("{path}: deferred PP windows cannot mint coordinator permits").into(),
2129            );
2130        }
2131        Ok(PpWalkPermit {
2132            state: lease.state.clone(),
2133        })
2134    }
2135
2136    /// Install a coordinator permit on the current host thread for the lifetime of the guard.
2137    pub(crate) fn borrow_walk(
2138        &'static self,
2139        permit: &PpWalkPermit,
2140        path: &str,
2141    ) -> Result<PpWalkBorrowGuard, Box<dyn std::error::Error>> {
2142        let runtime_id = self as *const Self as usize;
2143        validate_walk_state(&permit.state, runtime_id, path)
2144            .map_err(|error| -> Box<dyn std::error::Error> { error.into() })?;
2145        let prior_len = PP_WALK_BORROWS.with(|borrows| {
2146            let mut borrows = borrows.borrow_mut();
2147            let prior_len = borrows.len();
2148            borrows.push(permit.state.clone());
2149            prior_len
2150        });
2151        Ok(PpWalkBorrowGuard {
2152            prior_len,
2153            _not_send: PhantomData,
2154        })
2155    }
2156
2157    /// True iff any boundary crosses devices.
2158    pub fn cross_device(&self) -> bool {
2159        self.cross_any
2160    }
2161
2162    pub fn host_bounce_active(&self) -> bool {
2163        self.host_bounce || PEER_RUNTIME_HOST_BOUNCE.load(Ordering::Acquire)
2164    }
2165
2166    /// Actual stage placement frozen when this runtime was built. Environment strings may be
2167    /// mutated by in-process gates later and are not authoritative for scheduler safety.
2168    pub fn repeated_stage_device(&self) -> bool {
2169        let mut devices: Vec<_> = self.stages.iter().map(|stage| stage.dev).collect();
2170        devices.sort_unstable();
2171        devices.dedup();
2172        devices.len() != self.stages.len()
2173    }
2174
2175    fn context_for_dev<'a>(
2176        &'a self,
2177        e: &'a Engine,
2178        dev: usize,
2179    ) -> Result<&'a Arc<CudaContext>, Box<dyn std::error::Error>> {
2180        if dev == e.ctx().ordinal() {
2181            return Ok(e.ctx());
2182        }
2183        self.stages
2184            .iter()
2185            .find(|stage| stage.dev == dev)
2186            .map(|stage| &stage.ctx)
2187            .ok_or_else(|| format!("PP peer probe has no CUDA context for dev{dev}").into())
2188    }
2189
2190    fn enable_probe_peer_access(
2191        &self,
2192        e: &Engine,
2193        pairs: &[(usize, usize)],
2194    ) -> Result<Vec<(usize, usize)>, Box<dyn std::error::Error>> {
2195        let mut enabled = Vec::new();
2196        for &(src_dev, dst_dev) in pairs {
2197            let enable = (|| -> Result<(), Box<dyn std::error::Error>> {
2198                let src_ctx = self.context_for_dev(e, src_dev)?;
2199                let dst_ctx = self.context_for_dev(e, dst_dev)?;
2200                src_ctx.bind_to_thread()?;
2201                let rc = unsafe { cudarc::driver::sys::cuCtxEnablePeerAccess(dst_ctx.cu_ctx(), 0) };
2202                use cudarc::driver::sys::cudaError_enum as E;
2203                if rc == E::CUDA_SUCCESS || rc == E::CUDA_ERROR_PEER_ACCESS_ALREADY_ENABLED {
2204                    Ok(())
2205                } else {
2206                    Err(format!("{rc:?}").into())
2207                }
2208            })();
2209            if let Err(err) = enable {
2210                eprintln!(
2211                    "[pp] peer byte-integrity probe could not enable \
2212                     dev{src_dev}->dev{dst_dev}: {err}; MEMRA_PP_HOST_BOUNCE=1 remains active"
2213                );
2214            } else {
2215                enabled.push((src_dev, dst_dev));
2216            }
2217        }
2218        Ok(enabled)
2219    }
2220
2221    fn disable_probe_peer_access(
2222        &self,
2223        e: &Engine,
2224        pairs: &[(usize, usize)],
2225    ) -> Result<(), Box<dyn std::error::Error>> {
2226        let mut failures = Vec::new();
2227        for &(src_dev, dst_dev) in pairs {
2228            let disable = (|| -> Result<(), Box<dyn std::error::Error>> {
2229                let src_ctx = self.context_for_dev(e, src_dev)?;
2230                let dst_ctx = self.context_for_dev(e, dst_dev)?;
2231                src_ctx.bind_to_thread()?;
2232                let rc = unsafe { cudarc::driver::sys::cuCtxDisablePeerAccess(dst_ctx.cu_ctx()) };
2233                use cudarc::driver::sys::cudaError_enum as E;
2234                if rc == E::CUDA_SUCCESS || rc == E::CUDA_ERROR_PEER_ACCESS_NOT_ENABLED {
2235                    Ok(())
2236                } else {
2237                    Err(format!("{rc:?}").into())
2238                }
2239            })();
2240            if let Err(err) = disable {
2241                failures.push(format!("dev{src_dev}->dev{dst_dev}: {err}"));
2242            }
2243        }
2244        e.ctx().bind_to_thread()?;
2245        if failures.is_empty() {
2246            eprintln!(
2247                "[pp] peer byte-integrity probe teardown: disabled {} diagnostic pair(s); \
2248                 host-bounce serving has no probe-enabled peer access",
2249                pairs.len(),
2250            );
2251            Ok(())
2252        } else {
2253            Err(format!(
2254                "PP peer probe could not disable diagnostic peer access ({}); \
2255                 refusing host-bounce serving",
2256                failures.join(", "),
2257            )
2258            .into())
2259        }
2260    }
2261
2262    fn grant_probe_pool_access(
2263        &self,
2264        e: &Engine,
2265        pairs: &[(usize, usize)],
2266    ) -> Result<Vec<(usize, usize)>, Box<dyn std::error::Error>> {
2267        let mut granted = Vec::new();
2268        for &(src_dev, dst_dev) in pairs {
2269            let grant = (|| -> Result<(), Box<dyn std::error::Error>> {
2270                self.context_for_dev(e, dst_dev)?.bind_to_thread()?;
2271                let dev = cudarc::driver::result::device::get(dst_dev as i32)?;
2272                let mut pool: cudarc::driver::sys::CUmemoryPool = std::ptr::null_mut();
2273                unsafe {
2274                    cudarc::driver::sys::cuDeviceGetDefaultMemPool(&mut pool, dev).result()?;
2275                }
2276                let desc = cudarc::driver::sys::CUmemAccessDesc {
2277                    location: cudarc::driver::sys::CUmemLocation {
2278                        type_: cudarc::driver::sys::CUmemLocationType::CU_MEM_LOCATION_TYPE_DEVICE,
2279                        id: src_dev as i32,
2280                    },
2281                    flags:
2282                        cudarc::driver::sys::CUmemAccess_flags::CU_MEM_ACCESS_FLAGS_PROT_READWRITE,
2283                };
2284                let rc = unsafe { cudarc::driver::sys::cuMemPoolSetAccess(pool, &desc, 1) };
2285                if rc == cudarc::driver::sys::cudaError_enum::CUDA_SUCCESS {
2286                    Ok(())
2287                } else {
2288                    Err(format!("{rc:?}").into())
2289                }
2290            })();
2291            if let Err(err) = grant {
2292                eprintln!(
2293                    "[pp] production-slot probe could not grant dev{src_dev} access to \
2294                     dev{dst_dev}'s default pool: {err}; MEMRA_PP_HOST_BOUNCE=1 remains active"
2295                );
2296            } else {
2297                granted.push((src_dev, dst_dev));
2298            }
2299        }
2300        Ok(granted)
2301    }
2302
2303    fn revoke_probe_pool_access(
2304        &self,
2305        e: &Engine,
2306        pairs: &[(usize, usize)],
2307    ) -> Result<(), Box<dyn std::error::Error>> {
2308        let mut failures = Vec::new();
2309        for &(src_dev, dst_dev) in pairs {
2310            let revoke = (|| -> Result<(), Box<dyn std::error::Error>> {
2311                self.context_for_dev(e, dst_dev)?.bind_to_thread()?;
2312                let dev = cudarc::driver::result::device::get(dst_dev as i32)?;
2313                let mut pool: cudarc::driver::sys::CUmemoryPool = std::ptr::null_mut();
2314                unsafe {
2315                    cudarc::driver::sys::cuDeviceGetDefaultMemPool(&mut pool, dev).result()?;
2316                }
2317                let desc = cudarc::driver::sys::CUmemAccessDesc {
2318                    location: cudarc::driver::sys::CUmemLocation {
2319                        type_: cudarc::driver::sys::CUmemLocationType::CU_MEM_LOCATION_TYPE_DEVICE,
2320                        id: src_dev as i32,
2321                    },
2322                    flags: cudarc::driver::sys::CUmemAccess_flags::CU_MEM_ACCESS_FLAGS_PROT_NONE,
2323                };
2324                let rc = unsafe { cudarc::driver::sys::cuMemPoolSetAccess(pool, &desc, 1) };
2325                if rc == cudarc::driver::sys::cudaError_enum::CUDA_SUCCESS {
2326                    Ok(())
2327                } else {
2328                    Err(format!("{rc:?}").into())
2329                }
2330            })();
2331            if let Err(err) = revoke {
2332                failures.push(format!("dev{src_dev}->dev{dst_dev}: {err}"));
2333            }
2334        }
2335        e.ctx().bind_to_thread()?;
2336        if failures.is_empty() {
2337            Ok(())
2338        } else {
2339            Err(format!(
2340                "PP peer probe could not revoke diagnostic pool access ({}); \
2341                 refusing host-bounce serving",
2342                failures.join(", "),
2343            )
2344            .into())
2345        }
2346    }
2347
2348    fn run_host_bounce_legacy_probe(&self, e: &Engine) -> Result<(), Box<dyn std::error::Error>> {
2349        let enabled = self.enable_probe_peer_access(e, &self.peer_capable)?;
2350        let probe = run_peer_probe_pass(
2351            &self.stages,
2352            &enabled,
2353            true,
2354            "fixed-16KiB-legacy-preflight",
2355            PEER_PROBE_FIXED_BYTES,
2356        );
2357        let disable = self.disable_probe_peer_access(e, &enabled);
2358        disable?;
2359        probe
2360    }
2361
2362    fn new_peer_probe_boundary(
2363        &self,
2364        src_stage: usize,
2365        dst_stage: usize,
2366    ) -> Result<BoundaryRt, Box<dyn std::error::Error>> {
2367        let tx = &self.stages[src_stage];
2368        let rx = &self.stages[dst_stage];
2369        let mk_slot = || -> Result<BoundarySlot, Box<dyn std::error::Error>> {
2370            Ok(BoundarySlot {
2371                buf: Mutex::new(None),
2372                ev_tx: tx.ctx.new_event(None)?,
2373                ev_rx: rx.ctx.new_event(None)?,
2374            })
2375        };
2376        Ok(BoundaryRt {
2377            slots: [mk_slot()?, mk_slot()?],
2378            step: AtomicUsize::new(0),
2379            cross: tx.dev != rx.dev,
2380        })
2381    }
2382
2383    fn production_probe_readback(
2384        &self,
2385        path: BoundaryPath,
2386        boundary: &BoundaryRt,
2387        expected: &[u8],
2388        n: usize,
2389        slot_idx: usize,
2390    ) -> Result<Vec<u8>, Box<dyn std::error::Error>> {
2391        debug_assert_eq!(expected.len(), n * std::mem::size_of::<f32>());
2392        let host = peer_probe_bytes_to_f32(expected);
2393        let poison_bytes: Vec<u8> = expected.iter().map(|byte| !byte).collect();
2394        let poison = peer_probe_bytes_to_f32(&poison_bytes);
2395        let src = &self.stages[path.src_stage];
2396        let dst = &self.stages[path.dst_stage];
2397
2398        // Pre-poison the exact stream-ordered BoundarySlot allocation so a missing or partial
2399        // peer write cannot accidentally agree where the deterministic source contains zeroes.
2400        dst.ctx.bind_to_thread()?;
2401        let poison_buf = dst.stream.clone_htod(&poison)?;
2402        dst.stream.synchronize()?;
2403        let replaced = boundary.slots[slot_idx]
2404            .buf
2405            .lock()
2406            .unwrap()
2407            .replace(poison_buf);
2408        drop(replaced);
2409        dst.stream.synchronize()?;
2410
2411        src.ctx.bind_to_thread()?;
2412        let x = src.stream.clone_htod(&host)?;
2413        self.tx_slot_path(path, boundary, &x, n, slot_idx)?;
2414
2415        dst.ctx.bind_to_thread()?;
2416        let work = self.rx_slot_path(path, boundary, slot_idx, n)?;
2417        let back = dst.stream.clone_dtoh(&work)?;
2418        dst.stream.synchronize()?;
2419        Ok(peer_probe_f32_to_bytes(&back))
2420    }
2421
2422    fn clear_peer_probe_boundary(
2423        &self,
2424        boundary: &BoundaryRt,
2425        src_stage: usize,
2426        dst_stage: usize,
2427    ) -> Result<(), Box<dyn std::error::Error>> {
2428        self.stages[dst_stage].ctx.bind_to_thread()?;
2429        for slot in &boundary.slots {
2430            let buffer = slot.buf.lock().unwrap().take();
2431            drop(buffer);
2432        }
2433        self.stages[src_stage].stream.synchronize()?;
2434        self.stages[dst_stage].stream.synchronize()?;
2435        Ok(())
2436    }
2437
2438    fn run_production_peer_probe_widths(
2439        &self,
2440        enabled_pairs: &[(usize, usize)],
2441        host_bounce: bool,
2442        n_embd: usize,
2443        widths: &[usize],
2444    ) -> Result<(), Box<dyn std::error::Error>> {
2445        let started = std::time::Instant::now();
2446        let mut copies = 0usize;
2447        let mut skipped = 0usize;
2448        let mut total_mismatches = 0usize;
2449        let mut largest_clean_payload = 0usize;
2450
2451        for boundary_idx in 0..self.stages.len() - 1 {
2452            if self.stages[boundary_idx].dev == self.stages[boundary_idx + 1].dev {
2453                continue;
2454            }
2455            for (src_stage, dst_stage) in [
2456                (boundary_idx, boundary_idx + 1),
2457                (boundary_idx + 1, boundary_idx),
2458            ] {
2459                let src_dev = self.stages[src_stage].dev;
2460                let dst_dev = self.stages[dst_stage].dev;
2461                if !enabled_pairs.contains(&(src_dev, dst_dev)) {
2462                    if host_bounce {
2463                        skipped += widths.len();
2464                        eprintln!(
2465                            "[pp] production-slot peer probe SKIP: boundary={boundary_idx} \
2466                             dev{src_dev}->dev{dst_dev} widths_tokens={:?} \
2467                             (peer or pool access unavailable; MEMRA_PP_HOST_BOUNCE=1 remains \
2468                             fail-safe)",
2469                            widths,
2470                        );
2471                        continue;
2472                    }
2473                    return Err(format!(
2474                        "PP production-slot peer probe cannot run boundary={boundary_idx} \
2475                         dev{src_dev}->dev{dst_dev}: peer/pool access is not enabled"
2476                    )
2477                    .into());
2478                }
2479
2480                let probe_boundary = self.new_peer_probe_boundary(src_stage, dst_stage)?;
2481                let path = BoundaryPath {
2482                    boundary: boundary_idx,
2483                    src_stage,
2484                    dst_stage,
2485                    transport: BoundaryTransport::Peer,
2486                };
2487                let mut direction_copies = 0usize;
2488                let mut direction_skipped = 0usize;
2489                let mut direction_mismatches = 0usize;
2490                let mut direction_largest_clean = 0usize;
2491                let mut failure = None;
2492
2493                for (width_idx, tokens) in widths.iter().copied().enumerate() {
2494                    let n = n_embd.checked_mul(tokens).ok_or_else(|| {
2495                        format!(
2496                            "PP production-slot probe element count overflows for \
2497                             n_embd={n_embd} tokens={tokens}"
2498                        )
2499                    })?;
2500                    let bytes = n.checked_mul(std::mem::size_of::<f32>()).ok_or_else(|| {
2501                        format!(
2502                            "PP production-slot probe byte count overflows for \
2503                             n_embd={n_embd} tokens={tokens}"
2504                        )
2505                    })?;
2506                    let expected = peer_probe_pattern(bytes, boundary_idx, src_dev, dst_dev);
2507                    let readback = match self.production_probe_readback(
2508                        path,
2509                        &probe_boundary,
2510                        &expected,
2511                        n,
2512                        width_idx % 2,
2513                    ) {
2514                        Ok(readback) => readback,
2515                        Err(err) if host_bounce => {
2516                            skipped += 1;
2517                            direction_skipped += 1;
2518                            eprintln!(
2519                                "[pp] production-slot peer probe ERROR: \
2520                                 boundary={boundary_idx} dev{src_dev}->dev{dst_dev} \
2521                                 tokens={tokens} bytes={bytes}: {err}; \
2522                                 MEMRA_PP_HOST_BOUNCE=1, proceeding on the host-staged path"
2523                            );
2524                            continue;
2525                        }
2526                        Err(err) => {
2527                            failure = Some(format!(
2528                                "PP production-slot peer probe FAILED: \
2529                                 boundary={boundary_idx} dev{src_dev}->dev{dst_dev} \
2530                                 tokens={tokens} bytes={bytes}: {err}; refusing native P2P \
2531                                 (set MEMRA_PP_HOST_BOUNCE=1 to use the host-staged path; \
2532                                 MEMRA_PEER_PROBE=0 cannot authorize sharded native peer \
2533                                 transport)"
2534                            ));
2535                            break;
2536                        }
2537                    };
2538                    copies += 1;
2539                    direction_copies += 1;
2540                    let mismatches = peer_probe_mismatch_count(&expected, &readback);
2541                    if mismatches == 0 {
2542                        largest_clean_payload = largest_clean_payload.max(bytes);
2543                        direction_largest_clean = direction_largest_clean.max(bytes);
2544                    } else if host_bounce {
2545                        total_mismatches += mismatches;
2546                        direction_mismatches += mismatches;
2547                        eprintln!(
2548                            "[pp] production-slot peer probe CORRUPTION: \
2549                             boundary={boundary_idx} dev{src_dev}->dev{dst_dev} tokens={tokens} \
2550                             bytes={bytes} mismatches={mismatches}; MEMRA_PP_HOST_BOUNCE=1, \
2551                             proceeding on the host-staged path"
2552                        );
2553                    } else {
2554                        failure = Some(format!(
2555                            "PP production-slot peer probe FAILED: boundary={boundary_idx} \
2556                             dev{src_dev}->dev{dst_dev} tokens={tokens} bytes={bytes}: \
2557                             {mismatches} mismatched byte(s); refusing native P2P \
2558                             (set MEMRA_PP_HOST_BOUNCE=1 to use the host-staged path; \
2559                             MEMRA_PEER_PROBE=0 cannot authorize sharded native peer transport)"
2560                        ));
2561                        break;
2562                    }
2563                }
2564
2565                self.clear_peer_probe_boundary(&probe_boundary, src_stage, dst_stage)?;
2566                if let Some(err) = failure {
2567                    return Err(err.into());
2568                }
2569                eprintln!(
2570                    "[pp] production-slot peer probe direction: boundary={boundary_idx} \
2571                     dev{src_dev}->dev{dst_dev} copies={direction_copies} \
2572                     skipped={direction_skipped} mismatches={direction_mismatches} \
2573                     largest_clean_payload_bytes={direction_largest_clean}"
2574                );
2575            }
2576        }
2577
2578        let status = if total_mismatches > 0 {
2579            "BOUNCE"
2580        } else if skipped > 0 && copies > 0 {
2581            "PARTIAL"
2582        } else if skipped > 0 {
2583            "SKIP"
2584        } else {
2585            "PASS"
2586        };
2587        eprintln!(
2588            "[pp] production-slot peer probe {status}: widths_tokens={:?} copies={copies} \
2589             skipped={skipped} mismatches={total_mismatches} \
2590             largest_clean_payload_bytes={largest_clean_payload} elapsed_ms={:.3}",
2591            widths,
2592            started.elapsed().as_secs_f64() * 1e3,
2593        );
2594        Ok(())
2595    }
2596
2597    fn run_production_peer_probe(
2598        &self,
2599        enabled_pairs: &[(usize, usize)],
2600        host_bounce: bool,
2601        n_embd: usize,
2602    ) -> Result<(), Box<dyn std::error::Error>> {
2603        self.run_production_peer_probe_widths(
2604            enabled_pairs,
2605            host_bounce,
2606            n_embd,
2607            &PEER_PROBE_TOKEN_WIDTHS,
2608        )
2609    }
2610
2611    fn run_host_bounce_production_probe(
2612        &self,
2613        e: &Engine,
2614        n_embd: usize,
2615    ) -> Result<(), Box<dyn std::error::Error>> {
2616        let enabled = self.enable_probe_peer_access(e, &self.peer_capable)?;
2617        let granted = self.grant_probe_pool_access(e, &enabled)?;
2618        let probe = self.run_production_peer_probe(&granted, true, n_embd);
2619        // Teardown always runs, but the probe verdict wins: a CORRUPTION verdict (probe is
2620        // Err) must never be masked by a teardown failure. `revoke?; disable?; probe`
2621        // short-circuited teardown errors BEFORE probe was inspected, discarding the byte-
2622        // integrity signal on any teardown hiccup (hermes 9d6ae8d3). Surface teardown errors
2623        // only when the probe itself succeeded.
2624        let revoke = self.revoke_probe_pool_access(e, &granted);
2625        let disable = self.disable_probe_peer_access(e, &enabled);
2626        probe?;
2627        revoke?;
2628        disable?;
2629        Ok(())
2630    }
2631
2632    fn init_peer_probe_geometry(
2633        &self,
2634        e: &Engine,
2635        n_embd: usize,
2636    ) -> Result<(), Box<dyn std::error::Error>> {
2637        if !self.peer_probe || !self.cross_any {
2638            return Ok(());
2639        }
2640        let bytes = n_embd
2641            .checked_mul(std::mem::size_of::<f32>())
2642            .ok_or_else(|| format!("PP boundary-slot byte count overflows for n_embd={n_embd}"))?;
2643        let result = self.peer_probe_geometry.get_or_init(|| {
2644            let probe = if self.host_bounce_active() {
2645                self.run_host_bounce_production_probe(e, n_embd)
2646            } else {
2647                self.run_production_peer_probe(&self.peer_capable, false, n_embd)
2648            };
2649            let restore = e.ctx().bind_to_thread();
2650            match (probe, restore) {
2651                (Ok(()), Ok(())) => Ok(bytes),
2652                (Err(err), _) => Err(err.to_string()),
2653                (_, Err(err)) => Err(err.to_string()),
2654            }
2655        });
2656        let probed = result
2657            .as_ref()
2658            .map_err(|err| -> Box<dyn std::error::Error> { err.clone().into() })?;
2659        if *probed != bytes {
2660            return Err(format!(
2661                "peer probe initialized for boundary-slot bytes={probed} but model requests \
2662                 bytes={bytes}; one PP runtime supports one model geometry per process"
2663            )
2664            .into());
2665        }
2666        Ok(())
2667    }
2668
2669    fn init_host_bounce_staging(
2670        &self,
2671        e: &Engine,
2672        n_embd: usize,
2673    ) -> Result<(), Box<dyn std::error::Error>> {
2674        if !self.cross_any {
2675            return Ok(());
2676        }
2677        e.ctx().bind_to_thread()?;
2678        let result = self.bounce.get_or_init(|| {
2679            HostBounceRt::new(n_embd, &self.boundaries)
2680                .inspect(|rt| {
2681                    let bytes = rt.capacity * std::mem::size_of::<f32>();
2682                    eprintln!(
2683                        "[pp] host-bounce staging ready: n_embd={n_embd} max_tokens={} \
2684                         slot_bytes={bytes} slots_per_cross_boundary=2",
2685                        crate::cache::PRIME_CHUNK_MAX_TOKENS,
2686                    );
2687                })
2688                .map_err(|err| err.to_string())
2689        });
2690        let bounce = result
2691            .as_ref()
2692            .map_err(|err| -> Box<dyn std::error::Error> { err.clone().into() })?;
2693        if bounce.n_embd != n_embd {
2694            return Err(format!(
2695                "host-bounce runtime initialized for n_embd={} but model requests n_embd={n_embd}; \
2696                 one PP runtime supports one model geometry per process",
2697                bounce.n_embd,
2698            )
2699            .into());
2700        }
2701        Ok(())
2702    }
2703
2704    /// Exercise the newly armed staging through the real D2H/event/H2D boundary path before the
2705    /// live transport latch can observe it. One row per cross boundary is enough to validate the
2706    /// pinned capacity, event ordering, contexts, and byte continuity without touching peer DMA.
2707    fn validate_host_bounce_staging(
2708        &self,
2709        e: &Engine,
2710        n_embd: usize,
2711    ) -> Result<(), Box<dyn std::error::Error>> {
2712        let bytes = n_embd
2713            .checked_mul(std::mem::size_of::<f32>())
2714            .ok_or_else(|| {
2715                format!("host-bounce validation byte count overflows for n_embd={n_embd}")
2716            })?;
2717        for boundary_idx in 0..self.stages.len() - 1 {
2718            if !self.boundaries[boundary_idx].cross {
2719                continue;
2720            }
2721            let src_stage = boundary_idx;
2722            let dst_stage = boundary_idx + 1;
2723            let probe_boundary = self.new_peer_probe_boundary(src_stage, dst_stage)?;
2724            let path = BoundaryPath {
2725                boundary: boundary_idx,
2726                src_stage,
2727                dst_stage,
2728                transport: BoundaryTransport::HostBounce,
2729            };
2730            let expected = peer_probe_pattern(
2731                bytes,
2732                boundary_idx,
2733                self.stages[src_stage].dev,
2734                self.stages[dst_stage].dev,
2735            );
2736            let readback =
2737                self.production_probe_readback(path, &probe_boundary, &expected, n_embd, 0);
2738            let clear = self.clear_peer_probe_boundary(&probe_boundary, src_stage, dst_stage);
2739            let readback = readback?;
2740            clear?;
2741            let mismatches = peer_probe_mismatch_count(&expected, &readback);
2742            if mismatches > 0 {
2743                return Err(format!(
2744                    "runtime host-bounce staging validation FAILED: boundary={boundary_idx} \
2745                     bytes={bytes} mismatches={mismatches}"
2746                )
2747                .into());
2748            }
2749        }
2750        e.ctx().bind_to_thread()?;
2751        eprintln!(
2752            "[pp] runtime host-bounce staging validation PASS: row_bytes={bytes} \
2753             cross_boundaries={}",
2754            self.boundaries
2755                .iter()
2756                .filter(|boundary| boundary.cross)
2757                .count(),
2758        );
2759        Ok(())
2760    }
2761
2762    fn arm_runtime_host_bounce(
2763        &self,
2764        e: &Engine,
2765        row_bytes: usize,
2766    ) -> Result<(), Box<dyn std::error::Error>> {
2767        if row_bytes == 0 || !row_bytes.is_multiple_of(std::mem::size_of::<f32>()) {
2768            return Err(format!(
2769                "runtime host-bounce cannot recover n_embd from row_bytes={row_bytes}"
2770            )
2771            .into());
2772        }
2773        let n_embd = row_bytes / std::mem::size_of::<f32>();
2774        self.init_host_bounce_staging(e, n_embd)?;
2775        self.validate_host_bounce_staging(e, n_embd)
2776    }
2777
2778    /// Finish boot-time transport setup from the authoritative model width. This runs the
2779    /// production `BoundarySlot` ladder at 1/8/16/`PRIME_CHUNK_MAX_TOKENS` `[n_embd] f32` rows
2780    /// once, then allocates host-bounce slots when selected. The loader calls it before uploading
2781    /// the first model weight; `new_cache` repeats the call as an idempotent guard before the first
2782    /// forward.
2783    pub fn init_boundary_transport(
2784        &self,
2785        e: &Engine,
2786        n_embd: usize,
2787    ) -> Result<(), Box<dyn std::error::Error>> {
2788        if PEER_RUNTIME_PROBE_FAILED.load(Ordering::Acquire)
2789            && !PEER_RUNTIME_HOST_BOUNCE.load(Ordering::Acquire)
2790        {
2791            return Err(
2792                "PP runtime peer byte-integrity probe previously failed; refusing native P2P \
2793                 reuse because runtime host-bounce staging could not be armed"
2794                    .into(),
2795            );
2796        }
2797        self.init_peer_probe_geometry(e, n_embd)?;
2798        if !self.host_bounce_active() || !self.cross_any {
2799            return Ok(());
2800        }
2801        self.init_host_bounce_staging(e, n_embd)
2802    }
2803
2804    /// Run one due peer re-probe at a scheduler boundary on the CUDA owner thread. Each width has
2805    /// an independent copy-count deadline: an idle-only rung can remain pending while later cheap
2806    /// rungs keep running. The probe synchronizes the stage streams it exercises; no background
2807    /// thread touches CUDA.
2808    fn service_runtime_peer_probe(
2809        &self,
2810        e: &Engine,
2811        scheduler_idle: bool,
2812        probe_allowed: bool,
2813    ) -> Result<RuntimePeerProbeStatus, Box<dyn std::error::Error>> {
2814        if !self.peer_probe || !self.cross_any || self.host_bounce_active() {
2815            return Ok(RuntimePeerProbeStatus::NotRun);
2816        }
2817        if PEER_RUNTIME_PROBE_FAILED.load(Ordering::Acquire) {
2818            return Err(
2819                "PP runtime peer byte-integrity probe previously failed; native P2P is latched off"
2820                    .into(),
2821            );
2822        }
2823        let row_bytes = match self.peer_probe_geometry.get() {
2824            Some(Ok(bytes)) => *bytes,
2825            _ => return Ok(RuntimePeerProbeStatus::NotRun),
2826        };
2827
2828        let copies = PEER_BOUNDARY_COPIES.load(Ordering::Relaxed);
2829        let (width_index, tokens) = loop {
2830            let next_probe_copy = std::array::from_fn(|width_index| {
2831                PEER_RUNTIME_NEXT_PROBE_COPY[width_index].load(Ordering::Relaxed)
2832            });
2833            let measured_cost_ns = std::array::from_fn(|width_index| {
2834                PEER_RUNTIME_PROBE_MAX_COST_NS[width_index].load(Ordering::Relaxed)
2835            });
2836            let Some(candidate) = runtime_peer_probe_candidate(
2837                copies,
2838                next_probe_copy,
2839                measured_cost_ns,
2840                scheduler_idle,
2841            ) else {
2842                return Ok(RuntimePeerProbeStatus::NotRun);
2843            };
2844            // A mismatch immediately revokes native peer access before validated host bounce is
2845            // published. Live speculative sessions still dereference token/position state through
2846            // UVA outside the bounced boundary, so the worker may defer a runnable cheap rung until
2847            // those sessions retire. Do not consume its deadline or completed-probe counter.
2848            if !probe_allowed {
2849                return Ok(RuntimePeerProbeStatus::Deferred);
2850            }
2851            let due = next_probe_copy[candidate.0];
2852            let next = runtime_peer_probe_next_copy(due, copies);
2853            if PEER_RUNTIME_NEXT_PROBE_COPY[candidate.0]
2854                .compare_exchange(due, next, Ordering::AcqRel, Ordering::Relaxed)
2855                .is_ok()
2856            {
2857                break candidate;
2858            }
2859        };
2860        let probe_index = PEER_RUNTIME_PROBES.fetch_add(1, Ordering::Relaxed);
2861        let probe_bytes = row_bytes.checked_mul(tokens);
2862        let started = std::time::Instant::now();
2863        let probe = match probe_bytes {
2864            Some(_) => self.run_production_peer_probe_widths(
2865                &self.peer_capable,
2866                false,
2867                row_bytes / std::mem::size_of::<f32>(),
2868                &[tokens],
2869            ),
2870            None => Err(format!(
2871                "PP runtime peer probe byte count overflows for row_bytes={row_bytes} \
2872                 tokens={tokens}"
2873            )
2874            .into()),
2875        };
2876        let restore = e.ctx().bind_to_thread();
2877        let elapsed_ns = started.elapsed().as_nanos().min(u64::MAX as u128) as u64;
2878        let previous_max =
2879            PEER_RUNTIME_PROBE_MAX_COST_NS[width_index].fetch_max(elapsed_ns, Ordering::Relaxed);
2880        let verdict = match (probe, restore) {
2881            (Ok(()), Ok(())) => Ok(()),
2882            (Err(err), _) => Err(err.to_string()),
2883            (_, Err(err)) => Err(err.to_string()),
2884        };
2885        if let Err(err) = verdict {
2886            PEER_RUNTIME_PROBE_FAILURES.fetch_add(1, Ordering::Relaxed);
2887            let arm = latch_runtime_host_bounce(
2888                &PEER_RUNTIME_PROBE_FAILED,
2889                &PEER_RUNTIME_HOST_BOUNCE,
2890                || {
2891                    self.arm_runtime_host_bounce(e, row_bytes)
2892                        .map_err(|arm_err| arm_err.to_string())
2893                },
2894            );
2895            if let Err(arm_err) = arm {
2896                let message = format!(
2897                    "PP runtime peer byte-integrity re-probe FAILED after \
2898                     boundary_copies={copies} rung={}/{} tokens={tokens}: {err}; native P2P is \
2899                     latched off and host-bounce staging could not be armed: {arm_err}",
2900                    width_index + 1,
2901                    PEER_PROBE_TOKEN_WIDTHS.len(),
2902                );
2903                eprintln!("[pp] SECURITY RED: {message}; worker must stop");
2904                return Err(message.into());
2905            }
2906            eprintln!(
2907                "[pp] SECURITY RED: PP runtime peer byte-integrity re-probe FAILED after \
2908                 boundary_copies={copies} rung={}/{} tokens={tokens}: {err}; native P2P is \
2909                 latched off and the live transport DEGRADED to validated host bounce for the \
2910                 remainder of this process",
2911                width_index + 1,
2912                PEER_PROBE_TOKEN_WIDTHS.len(),
2913            );
2914            return Ok(RuntimePeerProbeStatus::DegradedToHostBounce);
2915        }
2916        if width_index + 1 != PEER_PROBE_TOKEN_WIDTHS.len()
2917            && previous_max <= PEER_RUNTIME_PROBE_BUDGET_NS
2918            && elapsed_ns > PEER_RUNTIME_PROBE_BUDGET_NS
2919        {
2920            eprintln!(
2921                "[pp] runtime peer re-probe rung exceeded the {:.3}ms owner-thread budget: \
2922                 tokens={tokens} measured_ms={:.3}; future runs are idle-only",
2923                PEER_RUNTIME_PROBE_BUDGET_NS as f64 / 1e6,
2924                elapsed_ns as f64 / 1e6,
2925            );
2926        }
2927        eprintln!(
2928            "[pp] runtime peer byte-integrity re-probe PASS: \
2929             boundary_copies={copies} interval_copies={PEER_RUNTIME_PROBE_INTERVAL_COPIES} \
2930             rung={}/{} tokens={tokens} bytes={} probe_index={probe_index} elapsed_ms={:.3} \
2931             scheduler_idle={scheduler_idle}",
2932            width_index + 1,
2933            PEER_PROBE_TOKEN_WIDTHS.len(),
2934            probe_bytes.unwrap(),
2935            elapsed_ns as f64 / 1e6,
2936        );
2937        Ok(RuntimePeerProbeStatus::Passed)
2938    }
2939
2940    fn bounce_rt(&self) -> Result<&HostBounceRt, Box<dyn std::error::Error>> {
2941        self.bounce
2942            .get()
2943            .ok_or_else(|| -> Box<dyn std::error::Error> {
2944                "MEMRA_PP_HOST_BOUNCE=1 staging was not initialized from model geometry".into()
2945            })?
2946            .as_ref()
2947            .map_err(|err| -> Box<dyn std::error::Error> { err.clone().into() })
2948    }
2949
2950    /// The engine a stage's subgraph must run through: the primary engine when the stage
2951    /// lives on the primary device, else the stage's own (remote-context) engine.
2952    pub fn engine<'a>(&'a self, s: usize, primary: &'a Engine) -> &'a Engine {
2953        self.stages[s].engine.as_ref().unwrap_or(primary)
2954    }
2955
2956    /// Bind this OS thread to stage `s`'s CUDA context before issuing work there.
2957    pub fn bind_stage(&self, s: usize) -> Result<(), Box<dyn std::error::Error>> {
2958        self.stages[s].ctx.bind_to_thread()?;
2959        Ok(())
2960    }
2961
2962    /// Enter stage `s`: until the guard drops, every engine op on this thread launches on
2963    /// the stage's stream (memra_runtime ambient-stream override).
2964    pub fn enter(&self, s: usize) -> memra_runtime::StreamOverride {
2965        memra_runtime::push_stream_override(
2966            self.stages[s].stream.clone(),
2967            self.stages[s].blas.clone(),
2968        )
2969    }
2970
2971    /// Allocate/grow BOTH slots for a boundary before pipelined issue starts. `tx()` can
2972    /// grow a slot lazily, but first-use ordering requires synchronizing the RX stream
2973    /// after that allocation. If slot 1 first grows after stage 1 of chunk N has already
2974    /// been queued, that sync drains chunk N and erases the only overlap in a two-chunk
2975    /// prime. Prewarming both slots pays the same one-time sync before either stage starts.
2976    pub fn prepare_overlap_slots(
2977        &self,
2978        b: usize,
2979        n: usize,
2980    ) -> Result<(), Box<dyn std::error::Error>> {
2981        let bd = &self.boundaries[b];
2982        let s_rx = &self.stages[b + 1].stream;
2983        let mut grew = false;
2984        for sl in &bd.slots {
2985            let mut guard = sl.buf.lock().unwrap();
2986            if guard.as_ref().map(|bf| bf.len() < n).unwrap_or(true) {
2987                *guard = Some(s_rx.alloc_zeros::<f32>(n)?);
2988                grew = true;
2989            }
2990        }
2991        if grew {
2992            s_rx.synchronize()?;
2993        }
2994        Ok(())
2995    }
2996
2997    /// Project only the additional device bytes needed to grow this process-global boundary to
2998    /// `n` elements per slot. Admission must not charge the full persistent high-water to every
2999    /// session after it already exists.
3000    pub fn boundary_slot_growth_bytes(
3001        &self,
3002        b: usize,
3003        n: usize,
3004    ) -> Result<usize, Box<dyn std::error::Error>> {
3005        let boundary = self
3006            .boundaries
3007            .get(b)
3008            .ok_or_else(|| format!("PP boundary {b} is outside the runtime"))?;
3009        let mut current = [0usize; 2];
3010        for (index, slot) in boundary.slots.iter().enumerate() {
3011            let guard = slot
3012                .buf
3013                .lock()
3014                .map_err(|_| format!("PP boundary {b} slot lock is poisoned"))?;
3015            current[index] = guard.as_ref().map_or(0, CudaSlice::len);
3016        }
3017        let elements = boundary_slot_growth_elements(current, n);
3018        Ok(elements.saturating_mul(std::mem::size_of::<f32>()))
3019    }
3020
3021    /// Boundary TX at boundary `b` (call within the stage-`b` scope; `x` = the
3022    /// materialized [n] residual): wait for the slot's previous RX (write-after-read
3023    /// guard), copy `x` into the slot's persistent buffer via the boundary's transport on
3024    /// stage-b's stream (the owning-stream/publication law), record ev_tx. Returns the
3025    /// slot index for the paired rx().
3026    ///
3027    /// `n` is the PAYLOAD ELEMENT COUNT, not a fixed model constant: the eager arm passes
3028    /// `n_embd` (one row), the batched arm passes `b_n * n_embd` (B stacked rows, the
3029    /// [B, n_embd] boundary). The slot buffer is GROW-ONLY and the transport moves exactly
3030    /// the first `n` elements — batched serving changes B every tick (chunk fill), and a
3031    /// realloc-on-every-size-change would host-sync the RX stream per width change (see the
3032    /// SLOT FIRST-USE ORDERING note below for why each allocation needs that sync). Growing
3033    /// to the high-water mark makes the syncs O(distinct widths) instead of O(width changes).
3034    pub fn tx(
3035        &self,
3036        b: usize,
3037        x: &CudaSlice<f32>,
3038        n: usize,
3039    ) -> Result<usize, Box<dyn std::error::Error>> {
3040        assert_eq!(x.len(), n, "pp tx: residual length mismatch");
3041        let bd = &self.boundaries[b];
3042        let slot_idx = if pp2_overlap() {
3043            bd.step.fetch_add(1, Ordering::Relaxed) % 2
3044        } else {
3045            0
3046        };
3047        self.tx_slot(b, x, n, slot_idx)
3048    }
3049
3050    /// Pipelined boundary TX: always alternate the shared double-buffer slots, independent
3051    /// of the decode-side `MEMRA_PP_OVERLAP` experiment flag. The boundary-local atomic
3052    /// keeps concurrent callers on one slot sequence rather than each restarting at A.
3053    pub fn tx_pipelined(
3054        &self,
3055        b: usize,
3056        x: &CudaSlice<f32>,
3057        n: usize,
3058    ) -> Result<usize, Box<dyn std::error::Error>> {
3059        assert_eq!(x.len(), n, "pp tx: residual length mismatch");
3060        let slot_idx = self.boundaries[b].step.fetch_add(1, Ordering::Relaxed) % 2;
3061        self.tx_slot(b, x, n, slot_idx)
3062    }
3063
3064    fn tx_slot(
3065        &self,
3066        b: usize,
3067        x: &CudaSlice<f32>,
3068        n: usize,
3069        slot_idx: usize,
3070    ) -> Result<usize, Box<dyn std::error::Error>> {
3071        let bd = &self.boundaries[b];
3072        let path = BoundaryPath {
3073            boundary: b,
3074            src_stage: b,
3075            dst_stage: b + 1,
3076            transport: boundary_transport(bd.cross, self.host_bounce_active()),
3077        };
3078        let copied_slot = self.tx_slot_path(path, bd, x, n, slot_idx)?;
3079        if path.transport == BoundaryTransport::Peer {
3080            PEER_BOUNDARY_COPIES.fetch_add(1, Ordering::Relaxed);
3081        }
3082        Ok(copied_slot)
3083    }
3084
3085    fn tx_slot_path(
3086        &self,
3087        path: BoundaryPath,
3088        bd: &BoundaryRt,
3089        x: &CudaSlice<f32>,
3090        n: usize,
3091        slot_idx: usize,
3092    ) -> Result<usize, Box<dyn std::error::Error>> {
3093        debug_assert!(slot_idx < 2);
3094        let sl = &bd.slots[slot_idx];
3095        let s_tx = &self.stages[path.src_stage].stream;
3096        s_tx.wait(&sl.ev_rx)?;
3097        let mut guard = sl.buf.lock().unwrap();
3098        if guard.as_ref().map(|bf| bf.len() < n).unwrap_or(true) {
3099            // allocated on the RX stage's stream: the buffer lives on the RX device.
3100            let s_rx = &self.stages[path.dst_stage].stream;
3101            *guard = Some(s_rx.alloc_zeros::<f32>(n)?);
3102            // SLOT FIRST-USE ORDERING (2026-08-02 pipelined-gate find): the lazy alloc's
3103            // pool-alloc + memset enqueue on the RX stream; the TX copy below issues on
3104            // the TX stream, and on a slot's FIRST use ev_rx has never been recorded —
3105            // nothing orders them. With >=2 tokens in flight the RX stream is still busy
3106            // with the previous token, the memset lands AFTER the TX copy, and the
3107            // boundary residual is zeroed (window=1 passed, window>=2 failed at the
3108            // slot-1 first-use step; -overlap arms passed because the synchronous serial
3109            // arm pre-warmed both slots). Host-sync the RX stream once per slot
3110            // allocation — at most 2*(N-1) one-time syncs per process, all during prime.
3111            s_rx.synchronize()?;
3112        }
3113        let buf = guard.as_mut().unwrap();
3114        match path.transport {
3115            BoundaryTransport::Local => s_tx.memcpy_dtod(x, buf)?,
3116            BoundaryTransport::HostBounce => {
3117                debug_assert_eq!(path.src_stage, path.boundary);
3118                debug_assert_eq!(path.dst_stage, path.boundary + 1);
3119                let bounce = self.bounce_rt()?;
3120                if n > bounce.capacity {
3121                    return Err(format!(
3122                        "pp host-bounce payload {n} exceeds geometry-sized capacity {} \
3123                         (n_embd={}, max prime tokens={})",
3124                        bounce.capacity,
3125                        bounce.n_embd,
3126                        crate::cache::PRIME_CHUNK_MAX_TOKENS,
3127                    )
3128                    .into());
3129                }
3130                let mut host = bounce.slot(path.boundary, slot_idx)?.lock().unwrap();
3131                // D2H is issued on the producing stage's stream. ev_tx below publishes the
3132                // completed host bytes to the receiving stream; the exact prefix avoids moving
3133                // a full 64 MiB slot for a one-row decode, and no peer pointer is formed here.
3134                s_tx.memcpy_dtoh(x, host.prefix_mut(n))?;
3135            }
3136            BoundaryTransport::Peer => {
3137                // cudaMemcpyPeerAsync (M0: 2.8x NCCL at PP activation sizes), issued on the
3138                // publishing TX stream with explicit src/dst contexts.
3139                use cudarc::driver::{DevicePtr, DevicePtrMut};
3140                let (sp, _g0) = x.device_ptr(s_tx);
3141                let (dp, _g1) = buf.device_ptr_mut(s_tx);
3142                self.stages[path.src_stage].ctx.bind_to_thread()?;
3143                unsafe {
3144                    cudarc::driver::result::memcpy_peer_async(
3145                        self.stages[path.dst_stage].ctx.cu_ctx(),
3146                        dp,
3147                        self.stages[path.src_stage].ctx.cu_ctx(),
3148                        sp,
3149                        n * std::mem::size_of::<f32>(),
3150                        s_tx.cu_stream(),
3151                    )?;
3152                }
3153            }
3154        }
3155        sl.ev_tx.record(s_tx)?;
3156        Ok(slot_idx)
3157    }
3158
3159    /// Boundary RX at boundary `b` (call within the stage-`b+1` scope): wait on the slot's
3160    /// ev_tx, copy the boundary buffer into a fresh working buffer (dtod on the RX stream —
3161    /// local on the RX device in both transports), record ev_rx. The returned buffer is
3162    /// RX-stage-owned: allocated, consumed, and eventually freed on that stage's stream.
3163    pub fn rx(
3164        &self,
3165        b: usize,
3166        slot_idx: usize,
3167        n: usize,
3168    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
3169        let bd = &self.boundaries[b];
3170        let path = BoundaryPath {
3171            boundary: b,
3172            src_stage: b,
3173            dst_stage: b + 1,
3174            transport: boundary_transport(bd.cross, self.host_bounce_active()),
3175        };
3176        self.rx_slot_path(path, bd, slot_idx, n)
3177    }
3178
3179    fn rx_slot_path(
3180        &self,
3181        path: BoundaryPath,
3182        bd: &BoundaryRt,
3183        slot_idx: usize,
3184        n: usize,
3185    ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
3186        let sl = &bd.slots[slot_idx];
3187        let s_rx = &self.stages[path.dst_stage].stream;
3188        s_rx.wait(&sl.ev_tx)?;
3189        let mut guard = sl.buf.lock().unwrap();
3190        let buf = guard.as_mut().expect("pp rx before tx");
3191        assert!(
3192            buf.len() >= n,
3193            "pp rx: slot holds {} < requested {n}",
3194            buf.len()
3195        );
3196        if path.transport == BoundaryTransport::HostBounce {
3197            debug_assert_eq!(path.src_stage, path.boundary);
3198            debug_assert_eq!(path.dst_stage, path.boundary + 1);
3199            let bounce = self.bounce_rt()?;
3200            let host = bounce.slot(path.boundary, slot_idx)?.lock().unwrap();
3201            let mut dst = buf.slice_mut(0..n);
3202            // The destination stream already waits ev_tx, so this H2D cannot observe the
3203            // staging slot before the source stream's D2H completes.
3204            s_rx.memcpy_htod(host.prefix(n), &mut dst)?;
3205        }
3206        // uninit working buffer (fully overwritten by the copy), allocated explicitly on
3207        // the stage stream so rx() is correct even outside an enter() scope.
3208        let mut work = unsafe { s_rx.alloc::<f32>(n)? };
3209        // Slice the slot to the payload: the buffer is grow-only (see tx), so at a narrower
3210        // width it is LONGER than `work` and cudarc's memcpy_dtod (dst.len() >= src.len())
3211        // would assert. The paired tx wrote exactly these first n elements.
3212        s_rx.memcpy_dtod(&buf.slice(0..n), &mut work)?;
3213        sl.ev_rx.record(s_rx)?;
3214        Ok(work)
3215    }
3216
3217    /// PUBLISH a DEVICE-RESIDENT result off the last stage to the caller's stream
3218    /// (lane/pp2-spec 2026-08-06).
3219    ///
3220    /// Every ppN body before this one returned HOST values — `decode_step_h_ppn` and
3221    /// `decode_step_batch_ppn` both `dtoh` inside the last-stage scope, and a dtoh on the
3222    /// producing stream is self-ordering. The verify trunk is the FIRST ppN body whose
3223    /// contract is device-resident output (`decode_step_t_h_emb_dev` exists precisely so the
3224    /// accept walk argmaxes on-device instead of moving T x n_vocab f32 per round), and
3225    /// device slices carry no stream affinity: the caller resumes on the PRIMARY stream and
3226    /// dereferences buffers whose producing kernels are still queued on the last stage's
3227    /// stream. Nothing orders them.
3228    ///
3229    /// Why this only ever failed on ONE device: with stages on separate devices the caller's
3230    /// first touch is a cross-device copy that the driver orders against the source context,
3231    /// and the readback path syncs. Two streams on the SAME device genuinely overlap, so the
3232    /// primary stream reads a buffer whose matmul has not run — nondeterministic garbage
3233    /// (measured: NaN, 3155.677, and 2.87e-5 where the reference had -2.0048926), and it
3234    /// poisons the NEXT arm in the same process because the corrupted KV persists. This is
3235    /// the same class as the SLOT FIRST-USE ORDERING find above, one level up: there the
3236    /// unordered pair was alloc-memset vs TX copy, here it is stage-N compute vs the
3237    /// caller's consumer.
3238    ///
3239    /// Fix = the boundary law applied to the exit: record an event on the producing stage
3240    /// stream, make the caller's stream wait on it. Event-wait, not a device sync, so the
3241    /// stage streams keep running for the deferred-readback arm. Call INSIDE the last-stage
3242    /// scope, after the last enqueue, with the caller's (pre-`enter`) stream.
3243    pub fn publish_to(
3244        &self,
3245        s: usize,
3246        dst: &Arc<CudaStream>,
3247    ) -> Result<(), Box<dyn std::error::Error>> {
3248        let st = &self.stages[s];
3249        // Same stream (STREAMS=0 rollback, or a caller already on the stage stream): the
3250        // stream orders itself; recording+waiting would be a no-op with a stray event.
3251        if Arc::ptr_eq(&st.stream, dst) {
3252            return Ok(());
3253        }
3254        let ev = st.ctx.new_event(None)?;
3255        ev.record(&st.stream)?;
3256        dst.wait(&ev)?;
3257        Ok(())
3258    }
3259
3260    /// PUBLISH EVERY STAGE to the caller (lane/glm5-accrace 2026-09-01) — the exit half of
3261    /// the boundary law, applied to ALL stages instead of only the producing one.
3262    ///
3263    /// WHY `publish_to(last, …)` IS NOT ENOUGH. A ppN body's terminal drain (a `dtoh` in
3264    /// the last-stage scope, or `publish_to(n_st-1, …)`) orders the caller behind the last
3265    /// stage, and the TX-wait chain transitively covers every earlier stage's work UP TO
3266    /// its `ev_tx`. It does NOT cover what each earlier stage's stream still holds AFTER
3267    /// its tx: the stage-scope locals (`pos_d`, the embedded/expanded rows, the boundary
3268    /// residual, every per-layer transient, and a verify round's ckpt clones) are dropped
3269    /// with the stage override still active, so their `free_async` enqueues on the STAGE
3270    /// stream after `ev_tx`. The caller then resumes on its own stream and allocates —
3271    /// and, per the `fence_stages_behind` anatomy above, cudarc's drop carries no read
3272    /// guard, so the pool can hand the caller a block whose stage-stream lifetime has not
3273    /// retired and the caller's writes land under queued stage work.
3274    ///
3275    /// MEASURED (research/glm53-flash-bringup-20260827/accrace-20260901/): with per-stage
3276    /// streams on one device, the hc ppN PRIME over a fixed 24-token prompt returned THREE
3277    /// distinct logit fingerprints within a single process — the first prime always
3278    /// canonical, later ones drifting — while `MEMRA_PP_STREAMS=0` returned one
3279    /// fingerprint 11/11. Downstream, one glm5 spec round silently lost an acceptance
3280    /// (14/42 -> 13/42) and the e2e tape diverged.
3281    ///
3282    /// Event waits, never a device sync: the stage streams keep running. Call at a ppN
3283    /// body's EXIT with the pre-`enter` caller stream (a stage stream that IS the caller's
3284    /// stream is skipped by `publish_to`).
3285    ///
3286    /// `MEMRA_PP_EXIT_PUBLISH=0` is the ROLLBACK SEAM (see [`pp_exit_publish`]) and
3287    /// restores the pre-lane, racy program exactly — it exists so the fix can be A/B'd in
3288    /// ONE binary and so a future perf question has a control arm, not because the guard is
3289    /// optional.
3290    pub fn publish_all_to(&self, dst: &Arc<CudaStream>) -> Result<(), Box<dyn std::error::Error>> {
3291        if !pp_exit_publish() {
3292            return Ok(());
3293        }
3294        for s in 0..self.stages.len() {
3295            self.publish_to(s, dst)?;
3296        }
3297        Ok(())
3298    }
3299
3300    /// REVERSE PUBLICATION (#87 root cause, lane/pp2spec-crash 2026-08-07): order every
3301    /// STAGE stream behind the CALLER's stream — the mirror of `publish_to`.
3302    ///
3303    /// `publish_to` orders caller READS behind stage COMPUTE. Nothing ordered the other
3304    /// direction: buffers ALLOCATED on a stage stream (the verify's returned logits/hidden,
3305    /// the VerifyCkpt stashes) are CONSUMED by kernels the caller enqueues on the PRIMARY
3306    /// stream, and when they drop, cudarc enqueues `free_async` on the ALLOCATING (stage)
3307    /// stream. With event tracking elided (the decode-path default) the drop carries no
3308    /// read-guard, so the pool can hand the block to the NEXT stage-stream allocation and
3309    /// its writes overwrite memory the queued primary-stream consumer has not read yet.
3310    /// Measured (research/pp2spec-crash-20260807): the spec round-seed read 13/4096 NaN =
3311    /// the uninitialized-bits signature (P(NaN|random u32) ~ 1/256), clean by host re-read
3312    /// time — a read-before-write race, fatal via the argmax-sentinel -> embed_gather MMU
3313    /// fault, and gated on c>=2 because a backed-up primary stream widens the window.
3314    ///
3315    /// Fix law: before a ppN body enqueues NEW stage-stream work (allocations that may
3316    /// reuse freed blocks), every stage stream waits the caller's stream at its current
3317    /// point. All primary consumers of the previous round's stage-allocated buffers are
3318    /// enqueued by then (single host thread), so reuse-writes land strictly after them.
3319    /// Call at ppN-body ENTRY with the pre-`enter` caller stream. Door-shut configs never
3320    /// build a PpNRt, so single-card behavior is untouched.
3321    pub fn fence_stages_behind(
3322        &self,
3323        src: &Arc<CudaStream>,
3324    ) -> Result<(), Box<dyn std::error::Error>> {
3325        let ev = src.context().new_event(None)?;
3326        ev.record(src)?;
3327        for st in &self.stages {
3328            if Arc::ptr_eq(&st.stream, src) {
3329                continue;
3330            }
3331            st.stream.wait(&ev)?;
3332        }
3333        Ok(())
3334    }
3335
3336    /// Deferred readback: record a fresh completion event on the LAST stage's stream
3337    /// (call after the step's logits matmul has been enqueued there).
3338    pub fn record_done(&self) -> Result<CudaEvent, Box<dyn std::error::Error>> {
3339        let last = &self.stages[self.stages.len() - 1];
3340        let ev = last.ctx.new_event(None)?;
3341        ev.record(&last.stream)?;
3342        Ok(ev)
3343    }
3344
3345    /// The dedicated readback stream (last stage's context).
3346    pub fn readback_stream(&self) -> &Arc<CudaStream> {
3347        &self.readback
3348    }
3349}
3350
3351/// Service a due runtime peer probe without constructing a PP runtime on door-shut placements.
3352/// Must be called by the CUDA owner thread at a scheduling boundary.
3353pub fn service_runtime_peer_probe(
3354    e: &Engine,
3355    scheduler_idle: bool,
3356    probe_allowed: bool,
3357) -> Result<RuntimePeerProbeStatus, Box<dyn std::error::Error>> {
3358    let Some(rt) = RTN.get() else {
3359        return Ok(RuntimePeerProbeStatus::NotRun);
3360    };
3361    let rt = rt
3362        .as_ref()
3363        .map_err(|err| -> Box<dyn std::error::Error> { err.clone().into() })?;
3364    rt.service_runtime_peer_probe(e, scheduler_idle, probe_allowed)
3365}
3366
3367/// M2 increment 3: a step's logits, still device-resident on the LAST stage. `wait()`
3368/// orders the readback stream behind the step's completion event, copies, and syncs —
3369/// tokens enqueued after this step keep running on the stage streams while the caller
3370/// drains token t. Dropping without waiting is safe (buffers free stream-ordered).
3371pub struct PendingLogits {
3372    logits: CudaSlice<f32>,
3373    ev: CudaEvent,
3374    rb: Arc<CudaStream>,
3375    _walk: PpWalkLease,
3376}
3377
3378impl PendingLogits {
3379    pub(crate) fn new(
3380        logits: CudaSlice<f32>,
3381        ev: CudaEvent,
3382        rb: Arc<CudaStream>,
3383        walk: PpWalkLease,
3384    ) -> Self {
3385        PendingLogits {
3386            logits,
3387            ev,
3388            rb,
3389            _walk: walk,
3390        }
3391    }
3392
3393    /// Blocks until this step's logits are computed, returns them host-side. Only this
3394    /// step's work is waited on (event-ordered) — NOT later tokens already enqueued on
3395    /// the stage streams.
3396    pub fn wait(self) -> Result<Vec<f32>, Box<dyn std::error::Error>> {
3397        self.rb.wait(&self.ev)?;
3398        let host = self.rb.clone_dtoh(&self.logits)?;
3399        self.rb.synchronize()?;
3400        // logits drop AFTER the sync: the D2H has fully completed, so the stream-ordered
3401        // free on the compute stream cannot race the copy.
3402        Ok(host)
3403    }
3404}
3405
3406/// Bring up the PP transport while model geometry is known but before model weights upload.
3407/// Door-shut and placement-free loads remain untouched.
3408pub fn init_model_transport(
3409    e: &Engine,
3410    cfg: &memra_gguf::config::ModelConfig,
3411    n_trunk: usize,
3412) -> Result<(), Box<dyn std::error::Error>> {
3413    if pp2_streams_off() || pp2_devices_env().is_none() || pp_cuts(n_trunk).is_none() {
3414        return Ok(());
3415    }
3416    PpNRt::get(e)?.init_boundary_transport(e, cfg.n_embd as usize)
3417}
3418
3419/// Stage-owned cache allocation door: when the ppN door is open AND `MEMRA_PP_DEVICES`
3420/// is set (placement plumbing), each layer's cache is allocated by its OWNING stage's
3421/// engine — on one device this is byte-for-byte today's allocation (gated); cross-device
3422/// it puts each stage's KV on that stage's HBM. Door shut or devices unset: plain
3423/// `Cache::new` (zero behavior change). Trailing MTP/NextN layers (beyond the trunk)
3424/// map to the LAST stage.
3425pub fn new_cache(
3426    e: &Engine,
3427    cfg: &memra_gguf::config::ModelConfig,
3428    max_ctx: usize,
3429) -> Result<crate::cache::Cache, Box<dyn std::error::Error>> {
3430    new_cache_inner(e, cfg, None, max_ctx)
3431}
3432
3433pub fn new_cache_planned(
3434    e: &Engine,
3435    cfg: &memra_gguf::config::ModelConfig,
3436    plan: &memra_gguf::model_plan::ModelPlan,
3437    max_ctx: usize,
3438) -> Result<crate::cache::Cache, Box<dyn std::error::Error>> {
3439    new_cache_inner(e, cfg, Some(plan), max_ctx)
3440}
3441
3442fn new_cache_inner(
3443    e: &Engine,
3444    cfg: &memra_gguf::config::ModelConfig,
3445    plan: Option<&memra_gguf::model_plan::ModelPlan>,
3446    max_ctx: usize,
3447) -> Result<crate::cache::Cache, Box<dyn std::error::Error>> {
3448    let n_trunk = (cfg.n_layer - cfg.nextn_predict_layers) as usize;
3449    if let Some(fence) = pp_cuts(n_trunk) {
3450        if pp2_devices_env().is_some() && !pp2_streams_off() {
3451            let rt = PpNRt::get(e)?;
3452            rt.init_boundary_transport(e, cfg.n_embd as usize)?;
3453            let n_st = fence.len() - 1;
3454            assert_eq!(
3455                rt.n_stages(),
3456                n_st,
3457                "PpNRt stage count {} != fence stages {n_st}",
3458                rt.n_stages()
3459            );
3460            // #87 REVERSE PUBLICATION at ADMISSION (lane/pp2spec-crash): this is the one
3461            // stage-stream allocation site OUTSIDE the ppN step bodies — a NEW session's
3462            // KV alloc_zeros enqueue on the STAGE streams, and their pool blocks can be
3463            // reuse of buffers freed from ANOTHER session's in-flight verify whose
3464            // primary-stream reads are still queued (the c=2 residual: exactly one trap
3465            // per admission collision, round 0, after the step-body fences landed).
3466            // Order the stage streams behind the caller before the memsets can clobber.
3467            // Anatomy: `PpNRt::fence_stages_behind`.
3468            rt.fence_stages_behind(&e.stream())?;
3469            let devs: Vec<&dyn memra_kv::KvDev> = (0..n_st)
3470                .map(|s| rt.engine(s, e) as &dyn memra_kv::KvDev)
3471                .collect();
3472            let cache = match plan {
3473                Some(plan) => {
3474                    crate::cache::Cache::new_ppn_planned(&devs, &fence, cfg, plan, max_ctx)?
3475                }
3476                None => crate::cache::Cache::new_ppn(&devs, &fence, cfg, max_ctx)?,
3477            };
3478            sync_stages_after_load(e, n_trunk)?;
3479            return Ok(cache);
3480        }
3481        if !pp2_streams_off() {
3482            // CACHE BIRTH BARRIER (2026-08-02 pipelined-arm residual race): with the door
3483            // open but no device placement, Cache::new's alloc_zeros memsets enqueue on
3484            // the PRIMARY worker stream while the first KV appends / recurrent-state
3485            // reads run on the per-stage streams — no event orders them, and under
3486            // deferred readback the stage streams are hot immediately (a memset tail
3487            // can zero an already-appended KV row; intermittent, ~1-in-3 gate FAIL).
3488            // One context-sync per cache creation kills the class.
3489            let cache = match plan {
3490                Some(plan) => crate::cache::Cache::new_planned(e, cfg, plan, max_ctx)?,
3491                None => crate::cache::Cache::new(e, cfg, max_ctx)?,
3492            };
3493            sync_stages_after_load(e, n_trunk)?;
3494            return Ok(cache);
3495        }
3496    }
3497    match plan {
3498        Some(plan) => crate::cache::Cache::new_planned(e, cfg, plan, max_ctx),
3499        None => crate::cache::Cache::new(e, cfg, max_ctx),
3500    }
3501}
3502
3503/// M2 increment 2 LOAD BARRIER: weight uploads and decode-mirror builds enqueue on the
3504/// loading engines' WORKER streams; the first consumer launches on a DIFFERENT stream
3505/// with no load->decode event — the door-off reference walk on the primary worker
3506/// stream (sharded load: remote builds still in flight), or a fresh per-stage stream.
3507/// The 2026-08-02 gate finds (n2-dev01 step-0 168k-logit graze; split5 ref=0.0 head —
3508/// a half-built rp4 mirror — poisoning step-0 KV and every later step): one
3509/// context-wide synchronize per stage at load end kills the class. No-op when the door
3510/// is shut at load (single-stream load+decode is ordered by the stream itself).
3511pub fn sync_stages_after_load(
3512    e: &Engine,
3513    n_trunk: usize,
3514) -> Result<(), Box<dyn std::error::Error>> {
3515    if pp2_streams_off() || pp_cuts(n_trunk).is_none() {
3516        return Ok(());
3517    }
3518    let rt = PpNRt::get(e)?;
3519    for s in 0..rt.n_stages() {
3520        rt.stages[s].ctx.bind_to_thread()?;
3521        unsafe {
3522            cudarc::driver::sys::cuCtxSynchronize().result()?;
3523        }
3524    }
3525    e.ctx().bind_to_thread()?;
3526    unsafe {
3527        cudarc::driver::sys::cuCtxSynchronize().result()?;
3528    }
3529    Ok(())
3530}
3531
3532/// M2 increment 2 (weight sharding): the engine that should UPLOAD layer `il`'s weights
3533/// (and build its decode mirrors) — the owning stage's engine when the door is open with
3534/// device placement and sharding not rolled back; else the primary. `il >= n_trunk`
3535/// (MTP/NextN blocks) maps to the last stage. The head (output_norm + lm head) belongs
3536/// to the last trunk layer's stage — call with `il = n_trunk - 1`.
3537pub fn layer_engine(
3538    e: &Engine,
3539    n_trunk: usize,
3540    il: usize,
3541) -> Result<&Engine, Box<dyn std::error::Error>> {
3542    if pp_shard_off() || pp2_devices_env().is_none() || pp2_streams_off() {
3543        return Ok(e);
3544    }
3545    let Some(fence) = pp_cuts(n_trunk) else {
3546        return Ok(e);
3547    };
3548    let rt = PpNRt::get(e)?;
3549    let s = stage_of(&fence, il.min(n_trunk - 1));
3550    Ok(rt.engine(s, e))
3551}
3552
3553/// Why a checkpoint restore refused a layer's distributed (TP) KV mirror.
3554#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3555pub(crate) enum TpRestoreRefusal {
3556    /// Snapshot recorded a distributed length but the in-place target has no mirror to rewind.
3557    TargetAbsent,
3558    /// Grow path: the snapshot recorded a distributed length the parked source cannot supply.
3559    SourceAbsent,
3560    /// Grow path: the freshly allocated target already holds a mirror it should not have.
3561    GrowTargetNotFresh,
3562    /// The whole-token TP CUDA graph door is open. That graph is MODEL-level state which bakes
3563    /// the rank-cache pointers, so freeing a mirror under it strands the captured parent.
3564    TokenGraphDoorOpen,
3565}
3566
3567/// What a checkpoint restore must do with one layer's distributed (TP) KV mirror.
3568#[derive(Debug, Clone, Copy, PartialEq, Eq)]
3569pub(crate) enum TpRestore {
3570    /// Neither side holds a mirror: nothing to do.
3571    Nothing,
3572    /// In-place rewind of the target's existing mirror to the recorded committed length.
3573    Rewind(usize),
3574    /// Grow path: build the target's mirror from the parked source's, truncated to `len`.
3575    Grow(usize),
3576    /// The snapshot PREDATES this layer's lazily-created mirror. Clear it: the mirror is derived
3577    /// state, and `ensure_step_tp_kv_cache` rebuilds it from the authoritative local plane on the
3578    /// next TP use, at whatever length that plane then holds.
3579    DropMirror,
3580    Refuse(TpRestoreRefusal),
3581}
3582
3583/// Resolve the distributed-KV arm of a checkpoint restore for ONE layer.
3584///
3585/// MECHANISM (lane/step37, 2026-08-28). `tp_kv[il]` is created LAZILY on a layer's first TP use
3586/// (`hybrid_forward.rs::ensure_step_tp_kv_cache`, reached only from the two TP DECODE paths and
3587/// the TP-PREFILL path). When rank-local TP prefill is not engaged, a cold prime never touches
3588/// it, so the session-affinity checkpoint captured mid-prime at the stable boundary records
3589/// `tp_kv_len[il] = None` for EVERY layer. The first decode step then materializes the mirror.
3590/// At reuse time the recorded `None` met a live `Some(..)` and the whole checkpoint was refused
3591/// at layer 0, so affinity reuse was 100% dead on step37 and every turn paid a full re-prime.
3592///
3593/// WHY DROPPING IS EXACT, NOT LENIENT. The mirror is not an independent plane: it is created by
3594/// hydrating from the local plane, and every TP decode gathers its rank shards back and appends
3595/// them into the local plane in the same step (`append_kv_quantized` into `local.k/v`, then
3596/// `local.len = base_len + 1`), which is why every TP entry point asserts
3597/// `distributed.committed_len() == local.len`. The local plane is therefore authoritative and
3598/// complete. Clearing the mirror reproduces the checkpoint-time state LITERALLY (the snapshot
3599/// says this layer had no mirror), and the rebuild reads the same bytes the checkpoint saw.
3600///
3601/// WHY THE `MEMRA_NO_LOCAL_SHADOW=1` DOOR DOES NOT BREAK THIS. That door skips the local-plane
3602/// gathers and appends in the eager v2 TP decode: lengths still advance, contents go STALE
3603/// (tp.rs::no_local_shadow_on). It is ON in the step37 serving env, so "the local plane is
3604/// authoritative" is NOT true of rows written by a TP decode under that door. The drop is
3605/// nonetheless safe, and self-guarding: `DropMirror` fires ONLY when the snapshot recorded NO
3606/// mirror for the layer, and a snapshot with no mirror is proof that no TP decode had yet run in
3607/// that cache's life (the mirror is created by the first TP use). Since the restore truncates the
3608/// local plane to exactly that snapshot length, every surviving row predates the first TP decode
3609/// and was therefore written by a PRIME, which always writes the local plane in full. The
3610/// rehydration cannot read a shadow-skipped row. Rows above the boundary are discarded and
3611/// re-primed by the suffix. The door also never rebases the local ring during decode (it does not
3612/// call `prepare_kv_append`), so the physical layout below the boundary is exactly as the prime
3613/// left it.
3614///
3615/// WHY NOT "MATERIALIZE BEFORE SNAPSHOT". The checkpoint is captured MID-PRIME. Nothing in the
3616/// non-TP-prefill prime path maintains a mirror, so a mirror created at capture time would be
3617/// stranded at the boundary length while the rest of the prime appends to the local plane only,
3618/// and the first decode would hard-error on `cache lengths diverged before decode`. Eager
3619/// materialization converts a re-prime into an outage.
3620///
3621/// Every genuinely inconsistent arm still refuses.
3622/// `source_has_tp`: `None` = in-place rewind; `Some(has_tp)` = restore into a freshly grown cache.
3623pub(crate) fn tp_restore_plan(
3624    snap_len: Option<usize>,
3625    source_has_tp: Option<bool>,
3626    target_has_tp: bool,
3627    token_graph_door: bool,
3628) -> TpRestore {
3629    match (source_has_tp, snap_len) {
3630        (None, Some(len)) => {
3631            if target_has_tp {
3632                TpRestore::Rewind(len)
3633            } else {
3634                TpRestore::Refuse(TpRestoreRefusal::TargetAbsent)
3635            }
3636        }
3637        (None, None) => {
3638            if !target_has_tp {
3639                TpRestore::Nothing
3640            } else if token_graph_door {
3641                TpRestore::Refuse(TpRestoreRefusal::TokenGraphDoorOpen)
3642            } else {
3643                TpRestore::DropMirror
3644            }
3645        }
3646        (Some(source_has_tp), Some(len)) => {
3647            if !source_has_tp {
3648                TpRestore::Refuse(TpRestoreRefusal::SourceAbsent)
3649            } else if target_has_tp {
3650                TpRestore::Refuse(TpRestoreRefusal::GrowTargetNotFresh)
3651            } else {
3652                TpRestore::Grow(len)
3653            }
3654        }
3655        (Some(_), None) => {
3656            if target_has_tp {
3657                // A freshly allocated cache must not already carry a mirror.
3658                TpRestore::Refuse(TpRestoreRefusal::GrowTargetNotFresh)
3659            } else {
3660                // The snapshot predates the source's mirror (or the source never had one). Leave
3661                // the grown target without one: the next TP use hydrates it from the local rows
3662                // this restore just copied in. Before the step37 fix a source that HELD a mirror
3663                // here was a hard refusal, which killed every grow-path affinity reuse too.
3664                TpRestore::Nothing
3665            }
3666        }
3667    }
3668}
3669
3670/// Restore a cache checkpoint through each layer's owning engine.
3671///
3672/// `source = None` is an in-place rewind: the target already owns the append-only KV bytes and
3673/// only its lengths plus recurrent state move back to the snapshot. `Some(source)` restores into
3674/// a freshly allocated larger cache: checkpoint-valid KV rows are copied from the parked cache,
3675/// rank-local TP sidecars are rebuilt through their model-owned runtimes, and recurrent state
3676/// always comes from the checkpoint's owned device copies.
3677///
3678/// This cannot use `Cache::rollback(e, ...)` under cross-device PP: a single primary engine is
3679/// not the owner of every stage's cache buffers. The rare rewind/grow boundary synchronizes open
3680/// PP contexts before publishing the restored cache to the next request.
3681pub fn restore_cache_checkpoint(
3682    e: &Engine,
3683    model: &crate::hybrid::HybridModel,
3684    source: Option<&crate::cache::Cache>,
3685    target: &mut crate::cache::Cache,
3686    snap: &crate::cache::CacheSnapshot,
3687) -> Result<(), Box<dyn std::error::Error>> {
3688    target.ensure_usable("restore_cache_checkpoint target")?;
3689    if let Some(source) = source {
3690        source.ensure_usable("restore_cache_checkpoint source")?;
3691    }
3692    let cfg = &model.cfg;
3693    let n = target.kv.len();
3694    if target.recur.len() != n
3695        || target.tp_kv.len() != n
3696        || snap.kv_len.len() != n
3697        || snap.tp_kv_len.len() != n
3698        || snap.conv.len() != n
3699        || snap.ssm.len() != n
3700        || source.is_some_and(|s| s.kv.len() != n || s.recur.len() != n || s.tp_kv.len() != n)
3701    {
3702        return Err("checkpoint cache layer-count mismatch".into());
3703    }
3704    if snap.pos > target.max_ctx {
3705        return Err(format!(
3706            "checkpoint pos {} exceeds target capacity {}",
3707            snap.pos, target.max_ctx,
3708        )
3709        .into());
3710    }
3711
3712    let n_trunk = (cfg.n_layer - cfg.nextn_predict_layers) as usize;
3713    // Read the door ONCE: the refusal it drives must be uniform across layers within a restore.
3714    let token_graph_door = crate::tp::step_tp_graph_enabled().unwrap_or(false);
3715    let mut dropped_mirrors = 0usize;
3716    for il in 0..n {
3717        let owner = layer_engine(e, n_trunk, il)?;
3718        let src_kv = source.map(|s| &s.kv[il]);
3719        match (src_kv, target.kv[il].as_mut(), snap.kv_len[il]) {
3720            (Some(Some(src)), Some(dst), Some(len)) => {
3721                if len > src.len || len > target.max_ctx {
3722                    return Err(format!(
3723                        "checkpoint layer {il} len {len} exceeds source {} or target {}",
3724                        src.len, target.max_ctx,
3725                    )
3726                    .into());
3727                }
3728                if src.kv_dim_k != dst.kv_dim_k
3729                    || src.kv_dim_v != dst.kv_dim_v
3730                    || src.k_tok_bytes != dst.k_tok_bytes
3731                    || src.v_tok_bytes != dst.v_tok_bytes
3732                {
3733                    return Err(format!("checkpoint KV layout mismatch at layer {il}").into());
3734                }
3735                match (&src.ring, dst.ring.as_ref()) {
3736                    (Some(sring), Some(dring)) => {
3737                        // SWA ring: `len` is ABSOLUTE and can exceed the physical row count once
3738                        // the ring has lapped (the 2026-08-29 warm-turn-at-40k panic: a flat
3739                        // `len`-row copy sliced past the window-sized buffer). Copy only the
3740                        // aligned live window and rebase the fresh target to its start — the
3741                        // same geometry `ResidentTpKvCache::prepare_grow` already uses.
3742                        if dring.base() != 0 {
3743                            return Err(format!(
3744                                "checkpoint SWA restore at layer {il} requires a fresh target \
3745                                 ring (base {}, expected 0)",
3746                                dring.base(),
3747                            )
3748                            .into());
3749                        }
3750                        let (new_base, phys) = sring.restore_plan(len).map_err(|e| {
3751                            format!("checkpoint SWA restore refused at layer {il}: {e}")
3752                        })?;
3753                        let rows = phys.len();
3754                        let kb = rows * src.k_tok_bytes;
3755                        let vb = rows * src.v_tok_bytes;
3756                        if kb > 0 {
3757                            owner.copy_u8_range_into(
3758                                &mut dst.k,
3759                                0,
3760                                &src.k,
3761                                phys.start * src.k_tok_bytes,
3762                                kb,
3763                            )?;
3764                        }
3765                        if vb > 0 {
3766                            owner.copy_u8_range_into(
3767                                &mut dst.v,
3768                                0,
3769                                &src.v,
3770                                phys.start * src.v_tok_bytes,
3771                                vb,
3772                            )?;
3773                        }
3774                        dst.ring
3775                            .as_mut()
3776                            .expect("ring presence checked above")
3777                            .apply_rebase(new_base);
3778                        if let Some(base_d) = dst.base_d.as_mut() {
3779                            owner.set_i32_one(base_d, new_base as i32)?;
3780                        }
3781                    }
3782                    (None, None) => {
3783                        let kb = len * src.k_tok_bytes;
3784                        let vb = len * src.v_tok_bytes;
3785                        if kb > 0 {
3786                            owner.copy_u8_into(&mut dst.k, 0, &src.k, kb)?;
3787                        }
3788                        if vb > 0 {
3789                            owner.copy_u8_into(&mut dst.v, 0, &src.v, vb)?;
3790                        }
3791                    }
3792                    _ => {
3793                        return Err(
3794                            format!("checkpoint ring/flat KV mismatch at layer {il}").into()
3795                        );
3796                    }
3797                }
3798                dst.len = len;
3799                owner.set_i32_one(&mut dst.len_d, len as i32)?;
3800            }
3801            (None, Some(dst), Some(len)) => {
3802                if len > dst.len || len > target.max_ctx {
3803                    return Err(format!(
3804                        "checkpoint layer {il} len {len} exceeds live {} or target {}",
3805                        dst.len, target.max_ctx,
3806                    )
3807                    .into());
3808                }
3809                if let Some(ring) = &dst.ring
3810                    && !ring.can_rewind_to(len)
3811                {
3812                    return Err(format!(
3813                        "checkpoint SWA rewind at layer {il} has been lapped \
3814                             (len {len}, ring base {}); full re-prime required",
3815                        ring.base(),
3816                    )
3817                    .into());
3818                }
3819                dst.len = len;
3820                owner.set_i32_one(&mut dst.len_d, len as i32)?;
3821            }
3822            (Some(None), None, None) | (None, None, None) => {}
3823            _ => return Err(format!("checkpoint KV kind mismatch at layer {il}").into()),
3824        }
3825
3826        match tp_restore_plan(
3827            snap.tp_kv_len[il],
3828            source.map(|s| s.tp_kv[il].is_some()),
3829            target.tp_kv[il].is_some(),
3830            token_graph_door,
3831        ) {
3832            TpRestore::Nothing => {}
3833            TpRestore::Rewind(len) => target.tp_kv[il]
3834                .as_mut()
3835                .expect("tp_restore_plan::Rewind implies a present target mirror")
3836                .rewind_to(len)?,
3837            TpRestore::Grow(len) => {
3838                let src = source
3839                    .and_then(|s| s.tp_kv[il].as_ref())
3840                    .expect("tp_restore_plan::Grow implies a present source mirror");
3841                let runtime = model.step_tp_runtime_for_layer(il).ok_or_else(|| {
3842                    format!("checkpoint TP KV layer {il} has no distributed runtime")
3843                })?;
3844                let grown = runtime.grow_tp_kv_cache(src, target.max_ctx, len)?;
3845                target.tp_kv[il] = Some(grown);
3846            }
3847            TpRestore::DropMirror => {
3848                // The snapshot predates this layer's lazily-created distributed mirror. Clear it
3849                // and let `ensure_step_tp_kv_cache` rebuild it from the authoritative local
3850                // plane on the next TP use. See `tp_restore_plan` for why this is exact.
3851                if target.tp_kv[il].take().is_some() {
3852                    dropped_mirrors += 1;
3853                }
3854            }
3855            TpRestore::Refuse(reason) => {
3856                return Err(format!(
3857                    "checkpoint TP KV restore refused at layer {il}: {} \
3858                     (snap.tp_kv_len={:?}, snap.kv_len={:?}, snap.pos={}, \
3859                     source_has_tp={:?}, target_has_tp={}, target_committed={})",
3860                    match reason {
3861                        TpRestoreRefusal::TargetAbsent =>
3862                            "the snapshot recorded a distributed length but the target holds no \
3863                             distributed cache to rewind",
3864                        TpRestoreRefusal::SourceAbsent =>
3865                            "the snapshot recorded a distributed length the parked source cannot \
3866                             supply",
3867                        TpRestoreRefusal::GrowTargetNotFresh =>
3868                            "the freshly allocated grow target already holds a distributed cache",
3869                        TpRestoreRefusal::TokenGraphDoorOpen =>
3870                            "MEMRA_STEP_TP_GRAPH is open, and its model-level whole-token graph \
3871                             bakes the rank-cache pointers, so the stale mirror cannot be freed",
3872                    },
3873                    snap.tp_kv_len[il],
3874                    snap.kv_len[il],
3875                    snap.pos,
3876                    source.map(|s| s.tp_kv[il].is_some()),
3877                    target.tp_kv[il].is_some(),
3878                    target.tp_kv[il]
3879                        .as_ref()
3880                        .map(|c| c.committed_len())
3881                        .unwrap_or(0),
3882                )
3883                .into());
3884            }
3885        }
3886
3887        match (target.recur[il].as_mut(), &snap.conv[il], &snap.ssm[il]) {
3888            (Some(dst), Some(conv), Some(ssm)) => {
3889                if conv.len() != dst.conv_state.len() || ssm.len() != dst.ssm_state.len() {
3890                    return Err(
3891                        format!("checkpoint recurrent layout mismatch at layer {il}").into(),
3892                    );
3893                }
3894                owner.copy_into(&mut dst.conv_state, 0, conv, conv.len())?;
3895                owner.copy_into(&mut dst.ssm_state, 0, ssm, ssm.len())?;
3896            }
3897            (None, None, None) => {}
3898            _ => {
3899                return Err(format!("checkpoint recurrent kind mismatch at layer {il}").into());
3900            }
3901        }
3902    }
3903    target.pos = snap.pos;
3904    if dropped_mirrors > 0 {
3905        // ENGAGEMENT RECEIPT. Before this fix the same condition returned "checkpoint TP KV kind
3906        // mismatch at layer 0" and the caller dropped the session for a full re-prime. This line
3907        // proves the restore took the rebuild path instead.
3908        eprintln!(
3909            "[pp] checkpoint restore: cleared {dropped_mirrors} stale distributed KV mirror(s) \
3910             at pos {} (snapshot predates lazy TP hydration); the next TP use rehydrates them \
3911             from the local plane",
3912            snap.pos,
3913        );
3914    }
3915
3916    // Open PP uses per-stage streams/contexts; publish every restored plane before the caller
3917    // starts the next prime. Door-shut single-stream restores remain naturally ordered.
3918    sync_stages_after_load(e, n_trunk)?;
3919    if source.is_some() {
3920        // A grown cache replaces and drops the source immediately after this returns. Bound the
3921        // D2D copies first so an async-pool free cannot recycle a source plane prematurely.
3922        e.stream().synchronize()?;
3923    }
3924    Ok(())
3925}
3926
3927#[cfg(test)]
3928mod host_bounce_tests {
3929    use super::{
3930        BoundaryTransport, DUAL_PP_HOST_BOUNCE_REFUSAL, DUAL_PP_SINGLE_SLOT_REFUSAL,
3931        PEER_PROBE_FIXED_BYTES, PEER_PROBE_REQUIRED_REFUSAL, PEER_PROBE_TOKEN_WIDTHS,
3932        PEER_RUNTIME_PROBE_BUDGET_NS, PEER_RUNTIME_PROBE_CYCLE_COPIES,
3933        PEER_RUNTIME_PROBE_DEFERRAL_BOUND_INTERVALS, PEER_RUNTIME_PROBE_INTERVAL_COPIES,
3934        PP_WAVE_MAX_STAGES, PeerProbeDecision, PeerProbeStartupPolicy, acquire_pp_walk,
3935        boundary_slot_growth_elements, boundary_transport, dual_pp_eligibility,
3936        dual_pp_timing_dropped, dual_pp_timing_snapshot, dual_pp_wave_mid, enter_pp_wave_cell,
3937        host_bounce_capacity, latch_runtime_host_bounce, peer_probe_bytes_to_f32,
3938        peer_probe_decision, peer_probe_f32_to_bytes, peer_probe_mismatch_count,
3939        peer_probe_pattern, peer_probe_startup_policy, pp_devices_repeat, pp_wave_diagonal,
3940        pp_wave_eligibility, pp_wave_numeric_eligibility, pp_wave_on_value, pp_wave_ranges,
3941        pp_wave_route_enabled, pp_wave_snapshot, publish_runtime_peer_probe_deferral,
3942        record_dual_pp_stage_result, record_pp_wave_tick, runtime_peer_probe_candidate,
3943        runtime_peer_probe_next_copy,
3944    };
3945
3946    // ---- lane/step37 session-affinity TP-mirror regression (2026-08-28) -------------------
3947    //
3948    // BEFORE this fix `restore_cache_checkpoint` refused with "checkpoint TP KV kind mismatch at
3949    // layer 0" whenever a checkpoint captured mid-prime (tp_kv not yet lazily created) met a
3950    // target whose first decode had since materialized the mirror. That is EVERY step37
3951    // session-affinity reuse, so reuse was 100% dead and every turn paid a full re-prime.
3952    // The `mismatch_*` cases below assert the new outcome; each of them was a hard refusal
3953    // before. The `refuses_*` cases pin the arms that must STILL fail closed.
3954
3955    use super::{TpRestore, TpRestoreRefusal, tp_restore_plan};
3956
3957    #[test]
3958    fn mismatch_snapshot_predating_lazy_tp_drops_the_mirror_instead_of_refusing() {
3959        // in-place rewind, snapshot has no distributed length, target materialized one.
3960        assert_eq!(
3961            tp_restore_plan(None, None, true, false),
3962            TpRestore::DropMirror
3963        );
3964    }
3965
3966    #[test]
3967    fn mismatch_on_the_grow_path_leaves_the_fresh_target_without_a_mirror() {
3968        // Grow path, snapshot predates the source's mirror, fresh target has none. Build none and
3969        // let the next TP use hydrate from the copied local rows. This arm REFUSED before the fix.
3970        assert_eq!(
3971            tp_restore_plan(None, Some(true), false, false),
3972            TpRestore::Nothing
3973        );
3974    }
3975
3976    #[test]
3977    fn drop_is_refused_while_the_token_graph_door_bakes_rank_pointers() {
3978        assert_eq!(
3979            tp_restore_plan(None, None, true, true),
3980            TpRestore::Refuse(TpRestoreRefusal::TokenGraphDoorOpen)
3981        );
3982    }
3983
3984    #[test]
3985    fn healthy_arms_are_untouched() {
3986        assert_eq!(
3987            tp_restore_plan(None, None, false, false),
3988            TpRestore::Nothing
3989        );
3990        assert_eq!(tp_restore_plan(None, None, false, true), TpRestore::Nothing);
3991        assert_eq!(
3992            tp_restore_plan(Some(15222), None, true, false),
3993            TpRestore::Rewind(15222)
3994        );
3995        assert_eq!(
3996            tp_restore_plan(Some(15222), Some(true), false, false),
3997            TpRestore::Grow(15222)
3998        );
3999        assert_eq!(
4000            tp_restore_plan(None, Some(false), false, false),
4001            TpRestore::Nothing
4002        );
4003    }
4004
4005    #[test]
4006    fn refuses_a_recorded_distributed_length_with_no_target_mirror() {
4007        assert_eq!(
4008            tp_restore_plan(Some(15222), None, false, false),
4009            TpRestore::Refuse(TpRestoreRefusal::TargetAbsent)
4010        );
4011    }
4012
4013    #[test]
4014    fn refuses_a_recorded_distributed_length_the_source_cannot_supply() {
4015        assert_eq!(
4016            tp_restore_plan(Some(15222), Some(false), false, false),
4017            TpRestore::Refuse(TpRestoreRefusal::SourceAbsent)
4018        );
4019    }
4020
4021    #[test]
4022    fn refuses_a_grow_target_that_is_not_fresh() {
4023        assert_eq!(
4024            tp_restore_plan(Some(15222), Some(true), true, false),
4025            TpRestore::Refuse(TpRestoreRefusal::GrowTargetNotFresh)
4026        );
4027        assert_eq!(
4028            tp_restore_plan(None, Some(true), true, false),
4029            TpRestore::Refuse(TpRestoreRefusal::GrowTargetNotFresh)
4030        );
4031    }
4032
4033    // ---- 2026-08-11 default-flip safety regression (owner-ordered) ----------------------
4034    // All pure-resolution tests: no env mutation (parallel test threads share process env).
4035
4036    #[test]
4037    fn flip_default_is_dual_auto_with_explicit_off_and_forced_seams() {
4038        use super::{DualPpMode, dual_pp_mode_resolve};
4039        assert_eq!(dual_pp_mode_resolve(None), DualPpMode::Auto);
4040        assert_eq!(dual_pp_mode_resolve(Some("0")), DualPpMode::Off);
4041        assert_eq!(dual_pp_mode_resolve(Some("1")), DualPpMode::Forced);
4042        // Any other value is not a silent third state: treat as the default.
4043        assert_eq!(dual_pp_mode_resolve(Some("2")), DualPpMode::Auto);
4044        assert_eq!(dual_pp_mode_resolve(Some("")), DualPpMode::Auto);
4045    }
4046
4047    #[test]
4048    fn flip_overlap_follows_mode_and_one_flag_restores_preflip_serial() {
4049        use super::{DualPpMode, pp2_overlap_resolve};
4050        // Naked default = the re-gated dual arm: overlap ON.
4051        assert!(pp2_overlap_resolve(None, DualPpMode::Auto));
4052        // MEMRA_DUAL_PP=0 ALONE restores the exact pre-flip naked path (single-slot serial).
4053        assert!(!pp2_overlap_resolve(None, DualPpMode::Off));
4054        // The explicit pre-flip request keeps its binding single-slot refusal reachable.
4055        assert!(!pp2_overlap_resolve(None, DualPpMode::Forced));
4056        // Explicit values always win over the mode.
4057        for mode in [DualPpMode::Off, DualPpMode::Forced, DualPpMode::Auto] {
4058            assert!(pp2_overlap_resolve(Some("1"), mode));
4059            assert!(!pp2_overlap_resolve(Some("0"), mode));
4060        }
4061    }
4062
4063    #[test]
4064    fn flip_auto_routes_only_the_regated_regime_and_degrades_serially_elsewhere() {
4065        use super::{DualPpMode, dual_pp_route};
4066        // The exact box1 re-gate regime: PP-2, double-slot, peer transport, B>=2.
4067        assert!(dual_pp_route(DualPpMode::Auto, 2, 2, true, false));
4068        assert!(dual_pp_route(DualPpMode::Auto, 17, 2, true, false));
4069        // Outside it, Auto must DEGRADE (serial PP-N walker), never refuse:
4070        assert!(!dual_pp_route(DualPpMode::Auto, 1, 2, true, false)); // no second wave
4071        assert!(!dual_pp_route(DualPpMode::Auto, 2, 3, true, false)); // naked PP-3 keeps serving
4072        assert!(!dual_pp_route(DualPpMode::Auto, 2, 2, false, false)); // single-slot boundary
4073        assert!(!dual_pp_route(DualPpMode::Auto, 2, 2, true, true)); // host-bounce escape hatch
4074        // Forced routes every B>=2 call into the dual body so the binding refusals fire loud.
4075        assert!(dual_pp_route(DualPpMode::Forced, 2, 3, false, true));
4076        assert!(!dual_pp_route(DualPpMode::Forced, 1, 2, true, false));
4077        // Off is the rollback seam: never dual.
4078        assert!(!dual_pp_route(DualPpMode::Off, 8, 2, true, false));
4079    }
4080
4081    #[test]
4082    fn pp_wave_flag_is_strict_and_does_not_inherit_the_pp2_default() {
4083        assert_eq!(pp_wave_on_value(None), Ok(false));
4084        assert!(pp_wave_on_value(Some("")).is_err());
4085        assert_eq!(pp_wave_on_value(Some("0")), Ok(false));
4086        assert_eq!(pp_wave_on_value(Some("1")), Ok(true));
4087        assert!(pp_wave_on_value(Some("auto")).is_err());
4088        assert!(pp_wave_on_value(Some("2")).is_err());
4089    }
4090
4091    #[test]
4092    fn pp_wave_route_treats_overlap_off_and_single_work_item_as_serial_rollback() {
4093        assert!(pp_wave_route_enabled(true, true, 3, 2));
4094        assert!(pp_wave_route_enabled(true, true, 4, 8));
4095        assert!(!pp_wave_route_enabled(true, false, 3, 8));
4096        assert!(!pp_wave_route_enabled(false, true, 3, 8));
4097        assert!(!pp_wave_route_enabled(true, true, 2, 8));
4098        assert!(!pp_wave_route_enabled(true, true, 4, 1));
4099    }
4100
4101    #[test]
4102    fn pp_wave_ranges_are_balanced_contiguous_and_priority_preserving() {
4103        assert!(pp_wave_ranges(0, 4).is_empty());
4104        assert!(pp_wave_ranges(8, 0).is_empty());
4105        assert_eq!(pp_wave_ranges(1, 4), vec![(0, 1)]);
4106        assert_eq!(pp_wave_ranges(2, 4), vec![(0, 1), (1, 2)]);
4107        assert_eq!(pp_wave_ranges(8, 4), vec![(0, 2), (2, 4), (4, 6), (6, 8)]);
4108        assert_eq!(
4109            pp_wave_ranges(17, 4),
4110            vec![(0, 5), (5, 9), (9, 13), (13, 17)]
4111        );
4112        for batch in 1..=64 {
4113            for stages in 2..=PP_WAVE_MAX_STAGES {
4114                let ranges = pp_wave_ranges(batch, stages);
4115                assert_eq!(ranges.len(), batch.min(stages));
4116                assert_eq!(ranges.first().copied().unwrap().0, 0);
4117                assert_eq!(ranges.last().copied().unwrap().1, batch);
4118                assert!(ranges.iter().all(|(lo, hi)| lo < hi));
4119                assert!(ranges.windows(2).all(|pair| pair[0].1 == pair[1].0));
4120                let widths: Vec<_> = ranges.iter().map(|(lo, hi)| hi - lo).collect();
4121                assert!(widths.windows(2).all(|pair| pair[0] >= pair[1]));
4122                assert!(widths.first().unwrap() - widths.last().unwrap() <= 1);
4123            }
4124        }
4125    }
4126
4127    #[test]
4128    fn pp_wave_diagonals_cover_the_grid_without_stage_or_wave_aliasing() {
4129        for stages in 3..=PP_WAVE_MAX_STAGES {
4130            for waves in 1..=stages {
4131                let mut seen = vec![vec![false; stages]; waves];
4132                for diagonal in 0..stages + waves - 1 {
4133                    let cells = pp_wave_diagonal(stages, waves, diagonal);
4134                    let mut stage_seen = vec![false; stages];
4135                    let mut wave_seen = vec![false; waves];
4136                    for (wave, stage) in cells {
4137                        assert_eq!(wave + stage, diagonal);
4138                        assert!(!stage_seen[stage]);
4139                        assert!(!wave_seen[wave]);
4140                        assert!(!seen[wave][stage]);
4141                        stage_seen[stage] = true;
4142                        wave_seen[wave] = true;
4143                        seen[wave][stage] = true;
4144                    }
4145                }
4146                assert!(seen.into_iter().flatten().all(|cell| cell));
4147            }
4148        }
4149        assert!(pp_wave_diagonal(4, 4, 7).is_empty());
4150    }
4151
4152    #[test]
4153    fn pp_wavefront_refuses_every_unqualified_transport_shape() {
4154        assert!(pp_wave_eligibility(3, true, false, false).is_ok());
4155        assert!(pp_wave_eligibility(4, true, false, false).is_ok());
4156        assert!(pp_wave_eligibility(2, true, false, false).is_err());
4157        assert!(pp_wave_eligibility(5, true, false, false).is_err());
4158        assert!(pp_wave_eligibility(3, false, false, false).is_err());
4159        assert!(pp_wave_eligibility(3, true, true, false).is_err());
4160        assert!(pp_wave_eligibility(3, true, false, true).is_err());
4161    }
4162
4163    #[test]
4164    fn pp_wavefront_requires_width_invariant_bf16_for_w4a16() {
4165        assert!(pp_wave_numeric_eligibility(false, false).is_ok());
4166        assert!(pp_wave_numeric_eligibility(false, true).is_ok());
4167        assert!(pp_wave_numeric_eligibility(true, true).is_ok());
4168        assert!(pp_wave_numeric_eligibility(true, false).is_err());
4169    }
4170
4171    #[test]
4172    fn pp_device_aliases_cannot_bypass_the_distinct_stage_gate() {
4173        assert!(!pp_devices_repeat("0,1,2,3"));
4174        assert!(pp_devices_repeat("0,00,1"));
4175        assert!(pp_devices_repeat("2,1,2"));
4176        assert!(pp_devices_repeat("0,nope,1"));
4177    }
4178
4179    #[test]
4180    fn pp_walk_owner_refuses_reentry_and_releases_at_scope_end() {
4181        let active = std::sync::Arc::new(std::sync::atomic::AtomicU64::new(0));
4182        let next = std::sync::atomic::AtomicU64::new(1);
4183        let first = acquire_pp_walk(&active, &next, 7, None, "first").unwrap();
4184        let held_clone = super::PpWalkLease {
4185            state: first.state.clone(),
4186        };
4187        let error = acquire_pp_walk(&active, &next, 7, None, "second").unwrap_err();
4188        assert!(error.contains("refused concurrent PP walk"));
4189        drop(first);
4190        assert!(acquire_pp_walk(&active, &next, 7, None, "third").is_err());
4191        drop(held_clone);
4192        assert!(acquire_pp_walk(&active, &next, 7, None, "fourth").is_ok());
4193    }
4194
4195    #[test]
4196    fn pp_walk_coordinator_borrow_is_explicit_and_thread_local() {
4197        let active = std::sync::Arc::new(std::sync::atomic::AtomicU64::new(0));
4198        let next = std::sync::atomic::AtomicU64::new(1);
4199        let lease = acquire_pp_walk(&active, &next, 11, None, "owner").unwrap();
4200        let state = lease.state.clone();
4201        super::PP_WALK_BORROWS.with(|borrows| borrows.borrow_mut().push(state.clone()));
4202        assert!(super::borrowed_pp_walk(11).is_some());
4203        std::thread::spawn(move || {
4204            assert!(super::borrowed_pp_walk(11).is_none());
4205            drop(state);
4206        })
4207        .join()
4208        .unwrap();
4209        super::PP_WALK_BORROWS.with(|borrows| borrows.borrow_mut().clear());
4210        drop(lease);
4211        assert_eq!(active.load(std::sync::atomic::Ordering::Acquire), 0);
4212    }
4213
4214    #[test]
4215    fn boundary_growth_charges_first_allocation_and_only_missing_high_water_afterward() {
4216        assert_eq!(boundary_slot_growth_elements([0, 0], 4096), 8192);
4217        assert_eq!(boundary_slot_growth_elements([4096, 4096], 4096), 0);
4218        assert_eq!(boundary_slot_growth_elements([4096, 2048], 4096), 2048);
4219        assert_eq!(boundary_slot_growth_elements([8192, 8192], 4096), 0);
4220    }
4221
4222    #[test]
4223    fn pp_wave_liveness_snapshot_counts_ticks_cells_and_real_overlap() {
4224        let before = pp_wave_snapshot();
4225        let first = enter_pp_wave_cell();
4226        let second = enter_pp_wave_cell();
4227        drop(second);
4228        drop(first);
4229        record_pp_wave_tick();
4230        let after = pp_wave_snapshot();
4231        assert!(after.0 > before.0);
4232        assert!(after.1 >= before.1 + 2);
4233        assert!(after.2 > before.2);
4234    }
4235
4236    #[test]
4237    fn dual_pp_split_is_honest_at_one_and_ceil_first_afterward() {
4238        assert_eq!(dual_pp_wave_mid(1), None);
4239        assert_eq!(dual_pp_wave_mid(2), Some(1));
4240        assert_eq!(dual_pp_wave_mid(3), Some(2));
4241        assert_eq!(dual_pp_wave_mid(8), Some(4));
4242        assert_eq!(dual_pp_wave_mid(16), Some(8));
4243        assert_eq!(dual_pp_wave_mid(31), Some(16));
4244        assert_eq!(dual_pp_wave_mid(32), Some(16));
4245    }
4246
4247    #[test]
4248    fn dual_pp_refuses_single_slot_and_non_pp2_shapes() {
4249        assert_eq!(
4250            dual_pp_eligibility(2, false, false),
4251            Err(DUAL_PP_SINGLE_SLOT_REFUSAL)
4252        );
4253        assert!(dual_pp_eligibility(2, true, false).is_ok());
4254        assert!(dual_pp_eligibility(3, true, false).is_err());
4255    }
4256
4257    #[test]
4258    fn dual_pp_refuses_unvalidated_host_bounce_transport() {
4259        assert_eq!(
4260            dual_pp_eligibility(2, true, true),
4261            Err(DUAL_PP_HOST_BOUNCE_REFUSAL),
4262        );
4263    }
4264
4265    #[test]
4266    #[allow(clippy::int_plus_one)] // allow: the +1 form states the at-least-one-more-drop bound
4267    fn dual_pp_timing_error_is_counted_without_recording_a_sample() {
4268        let dropped_before = dual_pp_timing_dropped();
4269        let (_, samples_before) = dual_pp_timing_snapshot();
4270        record_dual_pp_stage_result(0, Err::<f32, _>("CUDA_ERROR_NOT_READY"));
4271        let (_, samples_after) = dual_pp_timing_snapshot();
4272        assert_eq!(samples_after[0], samples_before[0]);
4273        assert!(dual_pp_timing_dropped() >= dropped_before + 1);
4274    }
4275
4276    #[test]
4277    fn corrupted_peer_readback_fails_closed_unless_host_bounce_is_selected() {
4278        assert_eq!(
4279            PEER_PROBE_TOKEN_WIDTHS,
4280            [1, 8, 16, crate::cache::PRIME_CHUNK_MAX_TOKENS],
4281        );
4282        let largest_payload_bytes = PEER_PROBE_TOKEN_WIDTHS[3] * 4096 * std::mem::size_of::<f32>();
4283        assert_eq!(largest_payload_bytes, 64 * 1024 * 1024);
4284        assert!(largest_payload_bytes >= 1024 * 1024);
4285        let expected = peer_probe_pattern(PEER_PROBE_FIXED_BYTES, 2, 0, 1);
4286        assert_eq!(
4287            peer_probe_f32_to_bytes(&peer_probe_bytes_to_f32(&expected)),
4288            expected,
4289        );
4290        let mut corrupted = expected.clone();
4291        for offset in [0, 8_191, PEER_PROBE_FIXED_BYTES - 1] {
4292            corrupted[offset] ^= 0x5a;
4293        }
4294
4295        assert_eq!(peer_probe_mismatch_count(&expected, &corrupted), 3);
4296        assert_eq!(
4297            peer_probe_decision(&expected, &corrupted, false),
4298            Err("3 mismatched byte(s)".to_string()),
4299        );
4300        assert_eq!(
4301            peer_probe_decision(&expected, &corrupted, true),
4302            Ok(PeerProbeDecision::ProceedWithHostBounce { mismatches: 3 }),
4303        );
4304    }
4305
4306    #[test]
4307    fn probe_off_refusal_matrix_is_fail_closed_only_for_sharded_native_peer() {
4308        for probe_on in [false, true] {
4309            for sharded in [false, true] {
4310                for host_bounce in [false, true] {
4311                    let got = peer_probe_startup_policy(probe_on, sharded, host_bounce);
4312                    let expected = match (probe_on, sharded, host_bounce) {
4313                        (false, true, false) => Err(PEER_PROBE_REQUIRED_REFUSAL),
4314                        (false, true, true) => Ok(PeerProbeStartupPolicy::BypassedWithHostBounce),
4315                        _ => Ok(PeerProbeStartupPolicy::Allowed),
4316                    };
4317                    assert_eq!(
4318                        got, expected,
4319                        "probe_on={probe_on} sharded={sharded} host_bounce={host_bounce}",
4320                    );
4321                }
4322            }
4323        }
4324        assert!(PEER_PROBE_REQUIRED_REFUSAL.contains("MEMRA_PEER_PROBE=0"));
4325        assert!(PEER_PROBE_REQUIRED_REFUSAL.contains("MEMRA_PP_HOST_BOUNCE!=1"));
4326    }
4327
4328    #[test]
4329    fn runtime_reprobe_keeps_cheap_deadlines_live_while_expensive_work_waits_for_idle() {
4330        let every = PEER_RUNTIME_PROBE_INTERVAL_COPIES;
4331        assert_eq!(PEER_RUNTIME_PROBE_CYCLE_COPIES, 4 * every);
4332        let mut next = [every, 2 * every, 3 * every, 4 * every];
4333        let measured_ns = [1_000_000, 2_000_000, 3_000_000, 0];
4334
4335        assert_eq!(
4336            runtime_peer_probe_candidate(every - 1, next, measured_ns, false),
4337            None,
4338        );
4339        assert_eq!(
4340            runtime_peer_probe_candidate(every, next, measured_ns, false),
4341            Some((0, 1)),
4342        );
4343
4344        // Pretend the three cheap deadlines completed. The maximum rung is due but must not run
4345        // on the interactive boundary.
4346        next[..3].copy_from_slice(&[5 * every, 6 * every, 7 * every]);
4347        assert_eq!(
4348            runtime_peer_probe_candidate(4 * every, next, measured_ns, false),
4349            None,
4350        );
4351        // Once the next cheap deadline arrives, it remains runnable even though the older max
4352        // deadline is still pending.
4353        assert_eq!(
4354            runtime_peer_probe_candidate(5 * every, next, measured_ns, false),
4355            Some((0, 1)),
4356        );
4357        // An idle boundary drains the oldest pending rung first.
4358        assert_eq!(
4359            runtime_peer_probe_candidate(5 * every, next, measured_ns, true),
4360            Some((3, crate::cache::PRIME_CHUNK_MAX_TOKENS)),
4361        );
4362    }
4363
4364    #[test]
4365    fn runtime_reprobe_moves_any_measured_over_budget_rung_to_idle_only() {
4366        let every = PEER_RUNTIME_PROBE_INTERVAL_COPIES;
4367        let next = [u64::MAX, every, u64::MAX, u64::MAX];
4368        let mut measured_ns = [0; PEER_PROBE_TOKEN_WIDTHS.len()];
4369        measured_ns[1] = PEER_RUNTIME_PROBE_BUDGET_NS + 1;
4370        assert_eq!(
4371            runtime_peer_probe_candidate(every, next, measured_ns, false),
4372            None
4373        );
4374        assert_eq!(
4375            runtime_peer_probe_candidate(every, next, measured_ns, true),
4376            Some((1, 8)),
4377        );
4378    }
4379
4380    #[test]
4381    fn late_runtime_reprobe_advances_once_instead_of_bursting_catchup() {
4382        let every = PEER_RUNTIME_PROBE_INTERVAL_COPIES;
4383        let due = every;
4384        assert_eq!(runtime_peer_probe_next_copy(due, due), due + 4 * every);
4385        assert_eq!(runtime_peer_probe_next_copy(due, 20 * every), 21 * every);
4386    }
4387
4388    #[test]
4389    fn runtime_reprobe_deferral_metric_counts_intervals_and_publishes_bound_state() {
4390        use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
4391
4392        assert_eq!(
4393            PEER_RUNTIME_PROBE_DEFERRAL_BOUND_INTERVALS * PEER_RUNTIME_PROBE_INTERVAL_COPIES,
4394            PEER_RUNTIME_PROBE_CYCLE_COPIES,
4395        );
4396        let deferred = AtomicU64::new(0);
4397        let degraded = AtomicBool::new(false);
4398        publish_runtime_peer_probe_deferral(&deferred, &degraded, 1, false);
4399        assert_eq!(deferred.load(Ordering::Relaxed), 1);
4400        assert!(!degraded.load(Ordering::Acquire));
4401
4402        publish_runtime_peer_probe_deferral(
4403            &deferred,
4404            &degraded,
4405            PEER_RUNTIME_PROBE_DEFERRAL_BOUND_INTERVALS - 1,
4406            true,
4407        );
4408        assert_eq!(
4409            deferred.load(Ordering::Relaxed),
4410            PEER_RUNTIME_PROBE_DEFERRAL_BOUND_INTERVALS,
4411        );
4412        assert!(degraded.load(Ordering::Acquire));
4413    }
4414
4415    #[test]
4416    fn runtime_probe_failure_latches_native_before_publishing_validated_bounce() {
4417        use std::sync::atomic::{AtomicBool, Ordering};
4418
4419        let failed = AtomicBool::new(false);
4420        let degraded = AtomicBool::new(false);
4421        let armed = latch_runtime_host_bounce(&failed, &degraded, || Ok::<_, String>(()));
4422        assert!(armed.is_ok());
4423        assert!(failed.load(Ordering::Acquire));
4424        assert!(degraded.load(Ordering::Acquire));
4425
4426        let failed = AtomicBool::new(false);
4427        let degraded = AtomicBool::new(false);
4428        let refused = latch_runtime_host_bounce(&failed, &degraded, || {
4429            Err::<(), _>("injected staging mismatch".to_string())
4430        });
4431        assert_eq!(refused, Err("injected staging mismatch".to_string()));
4432        assert!(failed.load(Ordering::Acquire));
4433        assert!(!degraded.load(Ordering::Acquire));
4434    }
4435
4436    #[test]
4437    fn transport_selection_keeps_peer_default_and_bounces_only_cross_device() {
4438        assert_eq!(boundary_transport(false, false), BoundaryTransport::Local);
4439        assert_eq!(boundary_transport(false, true), BoundaryTransport::Local);
4440        assert_eq!(boundary_transport(true, false), BoundaryTransport::Peer);
4441        assert_eq!(
4442            boundary_transport(true, true),
4443            BoundaryTransport::HostBounce
4444        );
4445    }
4446
4447    #[test]
4448    fn step37_geometry_sizes_each_slot_from_the_prime_cap() {
4449        let (elems, bytes) = host_bounce_capacity(4096).expect("valid Step-3.7 geometry");
4450        assert_eq!(elems, 4096 * crate::cache::PRIME_CHUNK_MAX_TOKENS);
4451        assert_eq!(bytes, 64 * 1024 * 1024);
4452    }
4453
4454    #[test]
4455    fn host_bounce_capacity_rejects_invalid_or_overflowing_geometry() {
4456        assert!(host_bounce_capacity(0).is_err());
4457        assert!(host_bounce_capacity(usize::MAX).is_err());
4458    }
4459}