diff --git a/docs/superpowers/cleanup/dqn-cleanup-scoreboard.md b/docs/superpowers/cleanup/dqn-cleanup-scoreboard.md index a36cc256a..fd3c384a5 100644 --- a/docs/superpowers/cleanup/dqn-cleanup-scoreboard.md +++ b/docs/superpowers/cleanup/dqn-cleanup-scoreboard.md @@ -1,7 +1,7 @@ --- -iteration: 9 -last_scan: 2026-04-20T20:05:00Z -last_scoreboard_hash: iter8resolved-fflag013b-dead002-dead003-dead004 +iteration: 10 +last_scan: 2026-04-21T00:00:00Z +last_scoreboard_hash: iter9-newcat-scan-pinmem-romem-lockhot-borrow consecutive_stall_count: 0 status: active --- @@ -46,6 +46,15 @@ Target: every per-step `memcpy_htod` / `clone_htod` / `dtod_copy` on the trainin - [ ] [PINMEM-008] `crates/ml/src/hyperopt/adapters/ppo.rs:1327` — `clone_htod(&action_indices)` in PPO rollout. — S=5 B=5 E=3 score=8.3 - [ ] [PINMEM-009] `crates/ml/src/cuda_pipeline/gpu_ppo_collector.rs:509,800` — `memcpy_htod(&episode_starts / &rng_seed_staging)`. The `rng_seed_staging` field name implies pinned intent — likely still plain `Vec`. — S=5 B=5 E=3 score=8.3 - [ ] [PINMEM-010] `crates/ml/src/cuda_pipeline/gpu_ppo_collector.rs:361` — `memcpy_htod(&rng_seeds, &mut rng_states)` at init. May be constructor-only (benign). Verify. — S=5 B=1 E=1 score=5.0 +- [ ] [PINMEM-011] `crates/ml/src/cuda_pipeline/gpu_experience_collector.rs:1115,1450,1512,1608,1840,1945,2040` — 7 htod sites in the experience collector (saboteur base, tiled actions, mask, bar_indices, episode_starts). Per-step frequency. Biggest hot-spot surface. — S=5 B=5 E=3 score=8.3 +- [ ] [PINMEM-012] `crates/ml/src/cuda_pipeline/gpu_iqn_head.rs:470,478,481` — `clone_htod(&cos_feat_host/&tiled_taus)` in IQN forward. Per-step. — S=5 B=5 E=3 score=8.3 +- [ ] [PINMEM-013] `crates/ml/src/cuda_pipeline/gpu_iqn_head.rs:700-708` — two `dtod_copy` calls for `iqn_rewards` / `iqn_dones`. Per-batch. Switch to async-dtod. — S=5 B=5 E=1 score=25.0 +- [ ] [PINMEM-014] `crates/ml/src/cuda_pipeline/gpu_iqn_head.rs:2030,2078` — `clone_htod(&weights/&host)`. Init/constructor usage — verify then classify. — S=5 B=1 E=1 score=5.0 +- [ ] [PINMEM-015] `crates/ml/src/trainers/dqn/trainer/mod.rs:770` — `stream.clone_htod(&features_flat)` in forward path. — S=5 B=5 E=3 score=8.3 +- [ ] [PINMEM-016] `crates/ml/src/trainers/dqn/trainer/training_loop.rs:380` — `memcpy_htod(&episode_starts, ...)` in training loop. — S=5 B=5 E=3 score=8.3 +- [ ] [PINMEM-017] `crates/ml-dqn/src/gpu_replay_buffer.rs:1086` — `memcpy_htod(&rewards_host, ...)` — classify path. — S=5 B=5 E=3 score=8.3 +- [ ] [PINMEM-018] `crates/ml/src/cuda_pipeline/signal_adapter.rs:264,298,340,389,414` — 5 htod sites. Signal adapter likely batch-path. Verify. — S=5 B=3 E=3 score=5.0 +- [ ] [PINMEM-019] `crates/ml/src/cuda_pipeline/mod.rs:890-895,979-984` — 12 `clone_htod` calls in test-helper constructors. Likely tests/harness (low priority, verify scope). — S=5 B=1 E=3 score=1.7 ### LOCKHOT (severity 5 — lock contention on training hot path) - [ ] [LOCKHOT-001] `std::sync::Mutex` — `crates/ml-dqn/src/network.rs:116`. Locked every forward pass. Move to `&mut self` if single-threaded, else lock-free. — S=5 B=5 E=3 score=8.3 @@ -53,15 +62,25 @@ Target: every per-step `memcpy_htod` / `clone_htod` / `dtod_copy` on the trainin - [ ] [LOCKHOT-003] `Arc>` — `crates/ml-dqn/src/dqn.rs:904`. Locked every training step on experience insert. — S=5 B=5 E=3 score=8.3 - [ ] [LOCKHOT-004] `Arc>` — `crates/ml/src/trainers/dqn/trainer/constructor.rs:550`. Verify read frequency; likely hot. — S=5 B=3 E=3 score=5.0 - [ ] [LOCKHOT-005] `Arc>` — `crates/ml/src/trainers/dqn/trainer/constructor.rs:358`. Read on every trade update. — S=5 B=3 E=3 score=5.0 +- [ ] [LOCKHOT-006] `Arc>` — `crates/ml/src/trainers/ppo.rs:208`. **tokio::sync::Mutex** → held across `.await`. Potential deadlock path. — S=5 B=5 E=3 score=8.3 +- [ ] [LOCKHOT-007] `Arc>>` × 2 — `crates/ml/src/trainers/ppo.rs:216,218`. History buffers locked per-step. — S=5 B=3 E=3 score=5.0 +- [ ] [LOCKHOT-008] `Arc>` — `crates/ml/src/trainers/tlob.rs:119`. **tokio::sync::RwLock** across `.await`. Same deadlock risk as LOCKHOT-006. — S=5 B=5 E=3 score=8.3 +- [ ] [LOCKHOT-009] `Arc>` — `crates/ml/src/trainers/dqn/trainer/mod.rs:167`. Held by trainer; read frequency unclear — verify. — S=5 B=3 E=3 score=5.0 +- [ ] [LOCKHOT-010] `Arc>` — `crates/ml/src/trainers/dqn/trainer/constructor.rs:606`. Safety-critical but per-epoch — likely benign; confirm. — S=5 B=1 E=3 score=1.7 ### ROMEM (severity 5 — write to CPU-read-only memory) - [ ] [ROMEM-001] `*(self.size_pinned as *mut i32)` — `crates/ml-dqn/src/gpu_replay_buffer.rs:349,501`. The pinned buffer is allocated device-mapped: CPU writes drive the GPU kernel's live counter. Verify allocation flag matches (cuMemHostAllocMapped, not ReadOnly). Document invariant. — S=5 B=5 E=1 score=25.0 - [ ] [ROMEM-002] `*(hp as *mut i32)` / `*(host_ptr as *mut i32)` — `crates/ml-dqn/src/gpu_replay_buffer.rs:287,297` in init. Same pinned-mapped pattern; verify. — S=5 B=3 E=1 score=15.0 - [ ] [ROMEM-003] `*mut CudaSlice` cast from `*mut CudaSlice` — `crates/ml-dqn/src/gpu_replay_buffer.rs:690`. Cross-lists with BORROW-001 (aliasing via ptr cast changes element type). See BORROW for real fix. — S=5 B=5 E=3 score=8.3 -- [ ] [ROMEM-004] cuBLAS workspace `*mut c_void` casts — `crates/ml/src/cuda_pipeline/shared_cublas_handle.rs:155,210`, `gpu_curiosity_trainer.rs:94,117,238,241,347`. **Likely benign** (FFI calling convention). Classify as false-positive after verifying cublas_sys doesn't write, then bulk-resolve. — S=5 B=5 E=1 score=25.0 (reclassify) +- [ ] [ROMEM-004] cuBLAS / cuBLASLt / cuDNN workspace `*mut c_void` casts — `shared_cublas_handle.rs:155,210`, `gpu_curiosity_trainer.rs:94,117,238,241,347,352,371,406,411,430`, `gpu_iql_trainer.rs:558-872` (~18 sites), `gpu_iqn_head.rs:1571,1762,1765`, `cublaslt_debug.rs:107,110`. **~40 sites total, likely all benign** (FFI calling convention). Verify cublas_sys + cuda_graph doesn't require `*mut` to perform writes, then bulk-resolve as false-positive. — S=5 B=5 E=1 score=25.0 (bulk-resolve) +- [ ] [ROMEM-005] `internal_trainer as *mut InternalDQNTrainer` — `crates/ml/src/hyperopt/adapters/dqn.rs:1473`. Verify `internal_trainer` binding is `&mut`, not `&`. — S=5 B=3 E=1 score=15.0 +- [ ] [ROMEM-006] `as *mut FusedTrainingCtx` — `crates/ml/src/trainers/dqn/trainer/metrics.rs:572`. Same pattern, verify mutability. — S=5 B=3 E=1 score=15.0 +- [ ] [ROMEM-007] `*(ptr as *mut T)` device-mapped pinned writes — `crates/ml/src/cuda_pipeline/gpu_experience_collector.rs:124,137,1195`, `gpu_iqn_head.rs:501,537`, `gpu_iql_trainer.rs:417`. Same pattern as ROMEM-001/002 (verify cuMemHostAllocMapped allocation). **Likely false-positive** — bulk-resolve with documentation. — S=5 B=5 E=1 score=25.0 +- [ ] [ROMEM-008] `y_ptr as *mut c_void` cuBLAS C-matrix pointer — `crates/ml-dqn/src/noisy_layers.rs:280`. Benign FFI. — S=5 B=1 E=1 score=5.0 ### BORROW (severity 5 — shared-borrow integrity violations) - [ ] [BORROW-001] `&mut *(&mut self.sample_episode_ids as *mut CudaSlice as *mut CudaSlice)` — `crates/ml-dqn/src/gpu_replay_buffer.rs:690`. Changes element type of `&mut` reference through raw-ptr casts — UB under strict aliasing. Fix: declare `CudaSlice` directly or expose typed view API. — S=5 B=5 E=3 score=8.3 +- [ ] [BORROW-002] `RefCell` × 2 — `crates/ml/src/validation/ppo_adapter.rs:37,164`. Docstring says "interior mutability because several PPO operations require…". Verify it's single-threaded (validation harness only); if so classify as justified-unsafe with documented invariant. If multi-threaded, UB. — S=5 B=3 E=3 score=5.0 ### CPURO (severity 5 — CPU reads of GPU-resident data on hot path) *Needs per-site classification — many calls are on CPU Vec (benign). Initial bulk scan recommended iter 9.*