Per user directive, ran rg scans for PINMEM, ROMEM, LOCKHOT, BORROW,
CPURO and populated the scoreboard with concrete file:line findings.
PINMEM: 10 new findings (PINMEM-011..019, plus rescan confirmed 001-010)
- Biggest surface: gpu_experience_collector.rs (7 htod sites)
- High priority: gpu_iqn_head.rs dtod_copy for iqn_rewards/iqn_dones
(PINMEM-013, score 25.0, switch to async-dtod, E=1)
ROMEM: 5 new findings (004 expanded, 005-008 added)
- ROMEM-004 now covers ~40 cuBLAS/cuBLASLt/cuDNN workspace casts across
shared_cublas_handle.rs, gpu_iql_trainer.rs, gpu_iqn_head.rs,
gpu_curiosity_trainer.rs, cublaslt_debug.rs — bulk false-positive
candidates (FFI convention, not actual RO writes)
- ROMEM-007 adds 6 more device-mapped pinned write sites (same pattern
as ROMEM-001/002 — benign cuMemHostAllocMapped)
LOCKHOT: 5 new findings (006-010)
- LOCKHOT-006/008: tokio::sync::Mutex<PPO> and RwLock<TLOBTransformer>
held across .await — deadlock risk. High priority.
- LOCKHOT-007: Arc<Mutex<VecDeque<f64>>> history locks per step
BORROW: 1 new finding (002)
- BORROW-002: RefCell<PPO> × 2 in validation/ppo_adapter.rs —
documented single-threaded, needs invariant verified
CPURO: deferred — .len()/.shape() scan returns hundreds of mostly-Vec
matches; left CPURO-000 task for next iter to classify per-site.
Scoreboard now has ~40 open findings across 12 active categories.
Expanding the scanner surface per user directive "all should be
addressed". Four distinct root causes for CPU-side violations around
GPU-owned data — each with its own scan command, fix hierarchy, and
learned-patterns entry.
- CPURO: CPU reads of GPU-resident data (sizes, reductions) that
force implicit sync. Cache at construction, keep stats on device.
- ROMEM: `*(ptr as *mut T)` writes where ptr came from a const /
read-only source. CUDA mapped-memory flags matter; cuBLAS/cuDNN
workspace casts are benign FFI.
- LOCKHOT: Mutex/RwLock on per-step path. High-value hits already
visible: Mutex<GpuDropout>, Mutex<Option<DropoutScheduler>> in
network.rs (every forward pass), Arc<Mutex<NStepBuffer>> in dqn.rs.
Never hold tokio::sync::RwLock across .await.
- BORROW: shared-&T promoted to &mut T via unsafe ptr casts or
UnsafeCell/RefCell. Real example shipped: gpu_replay_buffer.rs:690
changes CudaSlice<i32> → CudaSlice<u32> through raw-ptr cast.
Scoreboard seeded with 10 findings. Top scores:
- ROMEM-001 (25.0) - size_pinned mapped write, verify allocation flag
- ROMEM-004 (25.0) - cuBLAS workspace casts, likely false-positive bulk
- ROMEM-002 (15.0) - init-time pinned mapped writes
- LOCKHOT-001/002/003 (8.3) - dropout + nstep_buffer locks on hot path
- BORROW-001 (8.3) - CudaSlice element-type aliasing
CPURO is seeded with a scan-task (CPURO-000) to populate per-site
findings in iter 9 — too many Vec::len() false positives to list upfront.
Per user directive: htod/dtod transfers on the training hot path that
bounce through pageable host memory are a top-priority cleanup target.
Pinned memory (cuMemHostAlloc) + memcpy_htod_async enables DMA + stream
overlap. The codebase already has the pattern (size_pinned,
rng_step_pinned in gpu_replay_buffer.rs) — extend it to every per-step
transfer.
Prompt changes:
- New PINMEM category in §3 table (severity 5)
- Scan command excludes tests/benches/examples/smoke_tests
- New §6 learned pattern entry with 3-tier fix hierarchy:
(1) eliminate via on-device compute → (2) stage through pinned →
(3) async for dtod
- Added PINMEM to category ID allowlist in §2
Scoreboard seed: 10 initial findings from an iter-9 scan. Top-scoring:
PINMEM-003 (scratch_f32 scalar, E=1, score=25) and PINMEM-004 (init
scalars, score=15). Hot-path candidates include NoisyNet epsilon
refresh, PER replay-buffer inserts, target-net sync, PPO rollout.
Per user directive from iter 7 ("no deferred tasks, solve properly"),
the Needs-human review escape hatch is closed. Updated:
- Step 6c: replaced "move to Needs human review" with split-into-
sub-findings guidance; every finding must be solved.
- Step 6e: cargo-check failure now requires diagnosis + retry, not
deferral. Pre-existing external errors go to Known external state.
- Step 8 summary line: dropped the "deferred j" counter.
- Rule 7: similar rephrasing.
- New §6: learned patterns from iters 1-8 (dead flag chains,
aspirational config, dishonest fallbacks, inference-side flag flips,
accounting-only values, orphan files, hidden GPU sync).
Ralph re-feeds this file verbatim, so the next iteration picks up the
updated rules automatically.