[{"data":1,"prerenderedAt":349},["ShallowReactive",2],{"finding:p3-refine-3pass":3,"finding-runs:p3-refine-3pass":270,"finding-related:p3-refine-3pass":271},{"meta":4,"impact":43,"sections":49},{"id":5,"title":6,"subtitle":7,"eyebrow":8,"date":9,"status":10,"category":11,"polarity":12,"axes":13,"tags":16,"task_code":27,"commit":28,"branch":29,"config_paths":30,"related_runs":37,"related_findings":40},"p3-refine-3pass","A7 refine 3-pass 削減 — 採用確定 (2026-08-30 gate)","refine tick (100 iter に 1 回) の CPU compact 実装が、毎 tick 30 本の scratch \u003Ccode>Vec\u003C\u002Fcode> (15 read snapshot + 15 write staging、Lego 407k splats で ~576MB\u002Ftick) を \u003Ccode>Vec::with_capacity\u003C\u002Fcode>\u002F\u003Ccode>vec![0.0; ..]\u003C\u002Fcode> で新規確保し、最後に \u003Ccode>write_vec\u003C\u002Fcode> で Metal buffer へ一括コピーする「pass 4」を経由していた。\u003Ccode>[backend] refine_scratch_persist\u003C\u002Fcode> (scratch を \u003Ccode>RefineState\u003C\u002Fcode> に永続化) と \u003Ccode>refine_direct_write\u003C\u002Fcode> (compact loop が Metal buffer に直接書き、pass 4 を削除) の 2 flag で実装した。(b) の安全性は「tick 時点で in-flight command buffer が 0」に依存し、depth2 pipelining はこの前提を構造的に満たす (\u003Ccode>param_mutated_after_step()\u003C\u002Fcode> が refine tick で先行 forward encode を skip し、\u003Ccode>step()\u003C\u002Fcode> は戻る前に \u003Ccode>B_it\u003C\u002Fcode> を \u003Ccode>wait_until_completed()\u003C\u002Fcode> する)。書き込みロジック自体は 1 つも変えていないため、新設した parity test \u003Ccode>refine_flag_combinations_produce_identical_output\u003C\u002Fcode> は 4 通りの flag 組合せが bit-exact に一致することを確認する。\u003Cstrong>12.5k n=3 gate (2 回目 series、1 回目は load 汚染で棄却) で Δ -2.149% (閾値 1.612%)、PSNR +0.0197dB guard 内、3\u002F3 pair 一貫 — 採用確定、default を true に flip\u003C\u002Fstrong>。","docs\u002Fstrategy\u002F2026-08-next-phase-tasklist.md · Tier2 A7 · refine 3-pass 削減","2026-08-30","stable","experiment","positive",[14,15],1,3,[5,17,18,19,20,21,22,23,24,25,26],"a7","refine","scratch-persist","direct-write","alloc-churn","in-flight-invariant","lego","gate-adopted","default-flip","contaminated-series","docs\u002Fstrategy\u002F2026-08-next-phase-tasklist.md Tier2 A7 (refine の 3-pass 削減)","4f843e59bf9b (実装) \u002F gate + default flip は main HEAD 3fc6dea 上、後続 commit","worktree-agent-ad7792615eaff0d3a (実装、main merge 済み) \u002F main (gate)",[31,32,33,34,35,36],"splat\u002Fconfigs\u002F2026-08-30-a7-12500-off-r1.toml","splat\u002Fconfigs\u002F2026-08-30-a7-12500-off-r2.toml","splat\u002Fconfigs\u002F2026-08-30-a7-12500-off-r3.toml","splat\u002Fconfigs\u002F2026-08-30-a7-12500-on-r1.toml","splat\u002Fconfigs\u002F2026-08-30-a7-12500-on-r2.toml","splat\u002Fconfigs\u002F2026-08-30-a7-12500-on-r3.toml",[38,39],"splat\u002Fruns-logs\u002Fa7-12500-*.log (1回目 series、棄却・保存)","splat\u002Fruns-logs\u002Fa7v2-12500-*.log (2回目 series、採用根拠)",[41,42],"p2-s3-iteration-pipelining","p3-tier1-bit-exact",{"summary":44,"rank":45,"verdict":46,"delta_wallclock":47,"delta_psnr":48},"A7 (refine の 3-pass 削減) を実装・gate した。(a) \u003Ccode>refine_scratch_persist\u003C\u002Fcode>: compact pass の scratch \u003Ccode>Vec\u003C\u002Fcode> 30 本を \u003Ccode>RefineState\u003C\u002Fcode> (新設 \u003Ccode>RefineScratch\u003C\u002Fcode>) に永続化し \u003Ccode>std::mem::take\u003C\u002Fcode> で借り出し・tick 末尾で書き戻す。allocation の出所が変わるだけで計算は 1 つも変えない。(b) \u003Ccode>refine_direct_write\u003C\u002Fcode>: compact 書き込み先の抽象 \u003Ccode>Dst\u003C\u002Fcode> (\u003Ccode>Vec\u003C\u002Fcode> か Metal buffer 生ポインタ) を導入し、\u003Ccode>direct_write = true\u003C\u002Fcode> のとき新規 \u003Ccode>Vec\u003C\u002Fcode> を一切作らず compact loop が \u003Ccode>param.*\u003C\u002Fcode>\u002F\u003Ccode>adam_state.*\u003C\u002Fcode> に直接書く。実装中に見つけた subtle な罠: Clone の複製先 \u002F Respawn \u002F Split の子スロットは旧実装では「新規 0 埋め \u003Ccode>Vec\u003C\u002Fcode>」から無料で Adam m\u002Fv = 0 を得ていたが、direct 経路は \u003Cstrong>stale データが残っている可能性のある live buffer\u003C\u002Fstrong> に書くため、この暗黙の 0 を前提にできない — \u003Ccode>zero_adam_at\u003C\u002Fcode> ヘルパーで明示的に 0 を書くよう修正した (無修正だと A7(b) 単体で MCMC 論文の「新規 slot は Adam fresh start」不変条件が壊れていた)。不変条件 I (\u003Ccode>[num_splats, capacity)\u003C\u002Fcode> は常に 0) は direct 経路でも \u003Ccode>zero_tail\u003C\u002Fcode> による \u003Ccode>[n_new, n_write)\u003C\u002Fcode> の明示 0 埋めで維持する。\u003Cstrong>gate: 12.5k n=3 交互 A\u002FB (2回目 series、a7v2-12500) で Δ -2.149% (閾値 max(2σ_off,1%)=1.612%)、PSNR +0.0197dB (guard 内)、3\u002F3 pair 一貫 (on&lt;off)。1回目 series は load 汚染 (6 run 中 3 run に load1 スパイク) で棄却\u003C\u002Fstrong>。default flip 実施: \u003Ccode>BackendConfig::default()\u003C\u002Fcode> の両 flag を \u003Ccode>true\u003C\u002Fcode> に変更。field 単独の \u003Ccode>#[serde(default)]\u003C\u002Fcode> は付けない (bool 型に付けると \u003Ccode>bool::default()\u003C\u002Fcode>=false に固定され struct 側の true を上書きするため — \u003Ccode>target_cache\u003C\u002Fcode>\u002F\u003Ccode>shader_fast_math\u003C\u002Fcode> と同じ規約)、これは 1 iter smoke で config 省略時に \u003Ccode>refine_scratch_persist: true, refine_direct_write: true\u003C\u002Fcode> が実際に解決されることを確認済み。\u003Ccode>cargo test --workspace --release\u003C\u002Fcode> 全 pass (0 failed)。","mid","adopted","**-2.149%** (12.5k n=3、閾値 max(2σ_off,1%)=1.612%、3\u002F3 pair 一貫)。tasklist 期待帯 -1.3〜-2.6% にちょうど収まる","+0.0197 dB (12.5k n=3、guard 内。書き込みロジック自体は不変なので理論上の期待通りノイズレベル)",[50,53,56,71,73,90,92,125,127,159,161,202,207,209,254,258,262,264],{"type":51,"text":52},"lead","旧実装は 1 tick ごとに 30 本の scratch \u003Ccode>Vec\u003C\u002Fcode> (15 read snapshot + 15 write staging) を新規確保し、compact 結果をローカル \u003Ccode>Vec\u003C\u002Fcode> に書いてから \u003Ccode>write_vec\u003C\u002Fcode> で Metal buffer へ丸ごとコピーする「pass 4」を経由していた。A7 はこの 2 点をそれぞれ独立の \u003Ccode>[backend]\u003C\u002Fcode> flag で除去する。\u003Cstrong>12.5k n=3 gate で採用確定、default を true に flip した\u003C\u002Fstrong> — §7\u002F§8 に gate 実測 (1 回目の棄却と 2 回目の採用根拠) を記す。",{"type":54,"text":55},"heading","1. (a) scratch 永続化 — RefineState::scratch + mem::take パターン",{"type":57,"items":58},"kv",[59,62,65,68],{"key":60,"value":61},"field 追加","`RefineState` に非 pub `scratch: RefineScratch` を追加。`RefineScratch` は old_* 15 本 + new_* 15 本の `Vec\u003Cf32>` (計 30)。`Vec::new()` は allocation しないので `scratch_persist = false` のコストは 0",{"key":63,"value":64},"借用パターン","`take_snapshot(slot, persist, buf, n)` \u002F `take_zeroed(slot, persist, n)` が `persist=true` のとき `std::mem::take(slot)` で永続 `Vec` を借り出し `clear()` してから再利用、`persist=false` のとき毎回 `Vec::new()`。各呼び出しは `refine_state.scratch.X` を一瞬だけ借りるだけなので、`&mut RefineState` の他フィールド (`grad_xy_accum` 等) との同時借用は起きない",{"key":66,"value":67},"書き戻し","tick 末尾 (`refine_state.reset()` の直前) で `persist=true` のときだけ `refine_state.scratch.X = x;` と代入し、確保済み capacity を次 tick に持ち越す。old_* は常に、new_* は `direct_write=false` のときだけ書き戻す (`direct_write=true` のとき new_* は使わないので空のまま)",{"key":69,"value":70},"値への影響","**ゼロ**。allocation の出所が変わるだけで、`refine()` 内の計算・書き込み値は 1 バイトも変わらない",{"type":54,"text":72},"2. (b) compact 直書き — Dst 抽象 + pass 4 削除 + 見つかった罠",{"type":57,"items":74},[75,78,81,84,87],{"key":76,"value":77},"`Dst` 抽象","`enum Dst\u003C'a> { Vec(&'a mut Vec\u003Cf32>), Ptr(*mut f32) }` に `set`\u002F`add` メソッド。`copy_splat`\u002F`copy_adam` を `&mut [f32]` から `&mut Dst` 受け取りに書き換え、compact loop 本体は 1 つのまま両経路 (Vec 経由 \u002F Metal buffer 直書き) を共有する — 経路ごとにロジックを複製すると「2 つの実装が将来ズレる」リスクがあるため、単一ロジック + 実行時 dispatch (enum match) を選んだ (refine は 100 iter に 1 回しか呼ばないので match のコストは無視できる)",{"key":79,"value":80},"pass 4 削除","`direct_write = true` のとき 15 本の `new_*` `Vec` を一切作らず、`Dst::Ptr(param.means.contents() as *mut f32)` 等で compact loop が直接 Metal buffer に書く。最後の `write_vec` × 15 (旧 pass 4) を丸ごとスキップ",{"key":82,"value":83},"**実装中に見つけた罠 (修正済み)**","旧実装の Clone 複製先 \u002F Respawn \u002F Split 子スロットは「compact 先 `Vec` が `vec![0.0; ..]` で事前 0 埋め済み」に暗黙依存して Adam m\u002Fv への明示 0 書き込みを省略していた。direct 経路は書き込み先が **live Metal buffer (前回 tick までの stale データが残っている)** なので、この暗黙の 0 が成立しない。放置すると MCMC 論文 Algorithm 1 の「新規 slot は Adam fresh start」が (a) と組み合わせなくても (b) 単体で壊れる不変条件バグになっていた。`zero_adam_at` ヘルパーを追加し、該当 3 ケースで明示的に 0 を書くよう修正した (`direct_write = false` でも呼ぶが 0→0 の no-op)",{"key":85,"value":86},"不変条件 I の維持","`[n_new, n_write)` の 0 埋めは旧実装では「新規確保 `Vec` の初期値」から free に得ていたが、direct 経路は書き込み後に `zero_tail` (15 buffer × 該当範囲) で明示的に 0 埋めする。範囲は `[0, n_new)` (compact loop が書く範囲) と素で disjoint なので、compact loop の書き込みを踏みつぶす心配はない",{"key":88,"value":89},"**安全性の前提: in-flight CB = 0**","unified memory 上の buffer を GPU が読み書き中に host が直接上書きすると race になる。depth2 pipelining はこの前提を構造的に満たす — `param_mutated_after_step()` が true になる iteration (refine tick を含む) は `Depth2Pipeline::step` の手順 4 (先行 F_{it+1} encode) を skip し、手順 5 で B_it を `wait_until_completed()` してから return する。`pipelining = off` の逐次経路も `train_step` が毎 iteration wait するので同じく in-flight は常に 0",{"type":54,"text":91},"3. 不変条件の確認箇所 (コード上のエビデンス)",{"type":93,"columns":94,"align":98,"rows":100},"table",[95,96,97],"確認内容","file (commit 4f843e59bf9b 時点)","備考",[99,99,99],"left",[101,105,109,113,117,121],[102,103,104],"refine tick で先行 encode を skip する条件","splat-train-v1\u002Fsrc\u002Fpipeline.rs:340 `param_mutated_after_step()` (373-376 が refine_tick の分岐)","`train_loop.rs:655-664` の `prefetch_next` 計算がこの関数の戻り値を直接使う",[106,107,108],"skip 時に B_it を wait してから return する","splat-train-v1\u002Fsrc\u002Fpipeline.rs:593-603 (`Depth2Pipeline::step()` 手順 4〜5、`prefetched` 分岐 + `chain.cmd.wait_until_completed()`)","手順 4 が false 分岐 (596 行目 `self.sync_iters += 1`) のとき `self.pending` は None のまま、手順 5 の wait (603 行目) は手順 4 の分岐に関わらず必ず実行される",[110,111,112],"呼び出し側で明示的に検査する API","splat-train-v1\u002Fsrc\u002Fpipeline.rs:457 `Depth2Pipeline::debug_assert_drained()` (新設)","`self.pending.is_none()` と `self.limiter.live() == 0` を debug_assert。`train_loop.rs:764` (refine tick 直前) で呼ぶ。**`debug_assert!` は release ビルドでは生成されないため、12.5k gate run (release) 自体にはこの実行時チェックは乗らない** — 保護は「構造的な論証 (drain 点の設計)」+「debug ビルドの regression test 群」の組合せであり、gate run 中に何かを検出する仕組みではない点に注意",[114,115,116],"既存の tolerance 比較 regression (前提の pin、direct_write 自体は未使用)","splat-train-v1\u002Fsrc\u002Ftrain_loop.rs:1394 `pipelining_depth2_matches_off_across_refine_ticks`","`BackendConfig::default()` (両 A7 flag は false) で Off\u002FDepth2 が refine tick を跨いで一致する (`assert_history_matches`\u002F`assert_params_close`、tolerance 比較 — atomic float 由来の ulp 差を許容する既存方針。厳密な byte-exact ではない) ことを pin する — **`refine_direct_write` の安全性が依存する「refine tick で in-flight = 0」という前提条件そのものを検査する test**であって、(b) の直書きコードパスは通っていない",[118,119,120],"A7 flag 有効時の tolerance 比較 regression (direct_write を実際に通す)","splat-train-v1\u002Fsrc\u002Ftrain_loop.rs:1432 `pipelining_depth2_matches_off_across_refine_ticks_with_a7_direct_write` (新設)","上と同じシナリオを `refine_scratch_persist = true` \u002F `refine_direct_write = true` で実行し Off\u002FDepth2 が一致することを確認 (同じく tolerance 比較)。in-flight ≠ 0 の状態で refine が走れば GPU 書き込みと host 直書きが競合し、この test が不一致で fail するはず — (b) の安全性論証を実際に運動させる唯一の test",[122,123,124],"不変条件 I (`[num_splats, capacity)` は常に 0) の direct 経路 pin","splat-train-v1\u002Fsrc\u002Frefine.rs `zero_tail()` (633-649 の呼び出し箇所) + test `refine_flag_combinations_produce_identical_output` (1423 行目付近) の `assert_zero_tail`","4 通りの flag 組合せ全てで確認",{"type":54,"text":126},"4. test 計画 — 全て GPU 実行済み・全 PASS",{"type":93,"columns":128,"align":132,"rows":133},[129,130,131],"test","何を確認するか","実行状況",[99,99,99],[134,138,142,146,149,152,155],[135,136,137],"既存 refine test 7 本 (`refine_prunes_low_opacity` 等)","`RefineFlags::default()` (両 flag true、旧 default false 挙動と bit-exact — parity test で確認済みなので値は不変) で旧実装と同じ挙動","PASS (`cargo test --workspace --release`)",[139,140,141],"`relocation_growth_after_refine_sees_zero_adam_state` + 3 flag variant (`_scratch_persist` \u002F `_direct_write` \u002F `_persist_and_direct`)","refine の write スコープ縮小 (n_old=8→n_new=6、n_write=8) + relocation growth の Adam fresh start 回帰。**`_direct_write` 系 2 本が `zero_tail` の shrink 経路 (`[n_new, n_write)` = `[6,8)` が非空) を運動させる唯一の test** — `refine_flag_combinations_produce_identical_output` の 2 tick は両方 growth (`n_write = n_new`) なのでこの経路を検出できない","PASS",[143,144,145],"新設 `refine_flag_combinations_produce_identical_output`","2 tick 構成 (tick1: prune→respawn\u002Fkeep\u002Fclone\u002Fsplit 全種、tick2: tick1 出力を再 poison した上で growth) で `RefineFlags` の 4 通り (persist × direct_write) が **bit-exact に同一の全 15 buffer** を返すこと。**各 tick 直前に `poison_adam` で active slot を非 0 にする** — これが無いと `AdamState::new` の初期値がそもそも全 0 なので、`zero_adam_at` を丸ごと削除しても test が通ってしまう false-negative になる (実装レビューで実際に指摘された、下記「実装中に見つけた罠」参照)。tick2 は scratch_persist の cross-tick 再利用と、Clone\u002FSplit の 2 つ目の出力が tick1 由来の poison 値を持つ live buffer 位置に上書きされるケースの両方を運動させる","PASS。**direct_write = true を踏む唯一の unit test** (既存 7 本は全て default flag のみ)",[147,148,141],"`refine_grows_capacity_on_overflow` + `_direct_write` variant","capacity overflow (4→8) 発生時、`resize_capacity` の呼び出しが `Dst::Ptr` (直書き先ポインタ) の取得より**前**であることの regression。`_direct_write` 版が唯一この順序に依存するコードパスを通す — 順序が壊れると (誤って resize 前に pointer を取ってしまうと) compact 結果 (m_means slot 0 の目印値保持) が壊れて fail するはず",[150,151,141],"`assert_zero_tail`","全 test で before\u002Fafter 両方 pin (既存 15 buffer × 10 test + 新設 test × 4 combo)",[153,154,141],"`pipelining_depth2_matches_off_across_refine_ticks_with_a7_direct_write`","A7 flag 有効時の Off\u002FDepth2 tolerance 比較 regression。`refine_direct_write` の安全性が依存する「refine tick で in-flight = 0」を実際に運動させる唯一の test",[156,157,158],"`cargo test --workspace --release` (全 crate)","workspace 全体の regression","**全 pass (0 failed)**、12.5k gate と同時期の main HEAD 3fc6dea 上で実行",{"type":54,"text":160},"7. 1 回目 gate series (a7-12500) — load 汚染で棄却",{"type":93,"columns":162,"align":167,"rows":169},[163,164,165,166,97],"arm","run","train elapsed (s)","PSNR (dB)",[99,99,168,168,99],"right",[170,176,182,187,192,197],[171,172,173,174,175],"off","off-r1","127.534","36.219","load1 正常 (baseline 127.53s と一致)",[177,178,179,180,181],"on","on-r1","125.747","36.276","load1 正常",[171,183,184,185,186],"off-r2","138.022","36.125","**load1 spike 17.86 (走行中〜終了直後)、discrete jump が iter 9000-10000 で ms\u002Fiter に出現**",[177,188,189,190,191],"on-r2","124.902","36.209","load1 は spike 1 の decay tail で 2-3 に緩やかに上昇していたが結果自体は最速 (影響ほぼ無し)",[171,193,194,195,196],"off-r3","143.663","36.163","**iter 2000 から一貫して ms\u002Fiter が高い (discrete spike ではなく持続的、GPU thermal throttling の疑い)。全 6 run 中最遅**",[177,198,199,200,201],"on-r3","131.281","36.238","**load1 spike 8.64 (走行中、iter5000-6000 の ms\u002Fiter に discrete bump として出現、その後回復)**",{"type":203,"label":204,"variant":205,"text":206},"callout","1 回目 series の棄却理由 — 事前登録 retry 条件が評価不能","warning","off arm 3値中 2値 (off-r2, off-r3) に load 汚染の証拠があり、事前登録した retry 条件 (i) load evidence AND (ii) 自 arm 他値から 3σ超 の (ii) を計算する基準点 (「汚染されていない他の値」) が off arm には 1 個 (off-r1) しか残らない。単一 pair の置換を想定した retry プロトコルはこの状況に適用できない (`p3-tier1-bit-exact.toml` §5 の r6 10.3σ 自己言及的失敗と同種の罠)。ms\u002Fiter trace の discriminator 分析で off-r2\u002Fon-r3 は discrete transient (再実行で解消見込み) だが off-r3 は iter 2000 から一貫して高く transient パターンと一致しない — 6 run 連続実行による GPU thermal 蓄積の可能性を排除できない。単純計算の Δ (naive) は -6.67% だが、off arm σ が 6.00% と巨大なため閾値 max(2σ,1%)=12.0% を大きく下回り不通過。加えて A7 の期待帯 (refine drain 予算 4.1% 以内) を明らかに超える Δ であり、A7 由来の測定ではないと判断。**series 全体を破棄し、削除せず `runs-logs\u002Fa7-12500-*` として保存、run_prefix を変えて再実行した**。ambient の原因として、同機上で稼働する他 claude セッション (`dangerously-skip-permissions`) の CPU 負荷が疑われる (GPU は占有していないため train run への直接干渉ではないが、host 側処理の遅延に寄与した可能性がある)。",{"type":54,"text":208},"8. 2 回目 gate series (a7v2-12500) — クリーン、採用根拠",{"type":93,"columns":210,"align":212,"rows":213},[163,164,165,166,211],"run 窓内 load1",[99,99,168,168,168],[214,218,222,226,230,234,238,244,249],[171,172,215,216,217],"128.315","36.286","1.24-3.37 (正常)",[177,178,219,220,221],"125.176","36.261","0.87-2.10 (正常)",[171,183,223,224,225],"126.379","36.228","1.24-1.24 (正常)",[177,188,227,228,229],"124.616","36.247","0.81-0.87 (正常)",[171,193,231,232,233],"127.947","36.150","0.81-0.95 (正常)",[177,198,235,236,237],"124.628","36.215","0.81-1.71 (正常)",[239,240,241,242,243],"**mean (n=3)**","**off**","**127.547** (σ 0.806%)","**36.2213**","series 独立 load sampler 最大値 4.74、series 全体を通じ LOAD_LIMIT=6.0 未満",[239,245,246,247,248],"**on**","**124.807** (σ 0.256%)","**36.2410**","—",[250,248,251,252,253],"**Δ**","**-2.149%**","**+0.0197**","閾値 max(2σ_off,1%)=1.612% を有意にクリア",{"type":203,"label":255,"variant":256,"text":257},"判定 — 採用 (wallclock AND PSNR guard 両方 pass)","success","wallclock: Δ -2.149% ≤ -閾値 1.612% で pass。3\u002F3 pair とも on&lt;off で一貫 (r1: 125.176&lt;128.315、r2: 124.616&lt;126.379、r3: 124.628&lt;127.947)。PSNR: Δ +0.0197dB ≥ -0.05dB guard で pass。tasklist の期待帯 -1.3〜-2.6% にちょうど収まっており、1 回目 series の -6.67% (汚染由来で過大) とは対照的に物理的に妥当な範囲。\u003Cstrong>採用確定\u003C\u002Fstrong>、`BackendConfig::default()` の `refine_scratch_persist`\u002F`refine_direct_write` を true に flip、`cargo test --workspace --release` 全 pass。",{"type":203,"label":259,"variant":260,"text":261},"σ 非対称パターンの再確認 (このコンフィグ族で 3 例目)","info","1 回目 series では off arm が異常に不安定 (σ 6.00% vs on 2.72%、ただし load 汚染由来と特定済み)、2 回目のクリーンな series でも off arm σ (0.806%) が on arm σ (0.256%) の 3.1 倍と、より小さいスケールながら同じ方向の非対称が残る。`p3-tier1-bit-exact.toml` の分散構造の非対称性 callout (v1: off 不安定 4.66×、v2: on 不安定 1.81〜5.40×) に続き、この 12.5k Lego \u002F depth2 pipelining config family では **off 側 (=変更前の baseline stack) が on 側より不安定な傾向が複数の gate で観測されている** (tier1 v1, A7 v1(汚染), A7 v2(クリーン) の 3\u002F4 例が off 不安定方向、tier1 v2 のみ逆)。原因は本 finding の範囲では特定できず、次に同系列の gate を組む際の申し送り事項として記録する。",{"type":54,"text":263},"9. 未解決点 \u002F 次の判断",{"type":265,"items":266},"list",[267,268,269],"(a)(b) は互いに独立な flag として実装したが、gate では 2×2 の全組合せではなく `off\u002Foff` vs `on\u002Fon` の 2 arm だけを比較した (tasklist の見積りが 2 施策合算のため)。個別の寄与分解が必要なら追加 gate (off\u002Foff, a-only, b-only, on\u002Fon の 4 arm) を検討","A7(b) の `Dst` 抽象は enum match による実行時 dispatch — 100 iter に 1 回のみの呼び出しなのでコスト影響は無視できる想定だが、per-tick `ts_refine` 内訳での確認は未実施","off 側不安定パターン (§8 callout) の原因調査は次の gate 系列への申し送り",[],[272,317],{"id":42,"title":273,"date":9,"status":10,"polarity":274,"category":11,"axes":275,"tags":276,"task_code":291,"related_runs":292,"delta_psnr":311,"delta_wallclock":312,"rank":313,"verdict":314,"impact_summary":315,"detail_path":316},"M2 Tier1 (A1-A4 bit-exact) 12.5k gate v1+v2 — 棄却維持 (v1: Δ-5.0%だが2σ未達+PSNR guard抵触 \u002F v2 n=5 radix ballot上: PSNR分離は反証、wallclockは効果量≤1%で判定不能)","negative",[14,15],[277,278,279,280,281,282,283,23,284,285,286,287,288,289,290],"m2","tier1","ssim-clear","raster-grad-clear","backward-uniform","lazy-c3-scratch","gpu-gate","rejected","atomic-nondeterminism","psnr-guard","v2-regate","n5","radix-ballot-baseline","contamination-retry","2026-09 第 5 回ゼミ milestones — M2 Tier1 (A1-A4)",[293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310],"t1-12500-off-r1","t1-12500-on-r1","t1-12500-off-r2","t1-12500-on-r2","t1-12500-off-r3","t1-12500-on-r3","t1v2-12500-off-r1 (CONTAMINATED, discarded)","t1v2-12500-on-r1 (CONTAMINATED, discarded)","t1v2-12500-off-r2","t1v2-12500-on-r2","t1v2-12500-off-r3","t1v2-12500-on-r3","t1v2-12500-off-r4","t1v2-12500-on-r4","t1v2-12500-off-r5","t1v2-12500-on-r5","t1v2-12500-off-r6 (retry replacing r1)","t1v2-12500-on-r6 (retry replacing r1)","v1 (n=3): on **36.140 dB** (36.165\u002F36.097\u002F36.157) vs off **36.205 dB** (36.201\u002F36.195\u002F36.219) = **-0.065 dB**、n=3 全 pair で on \u003C off の完全分離、task 指定 guard (on mean ≥ off mean - 0.05 dB) に **抵触**。config header の絶対 guard (36.202 ± 0.1 dB) では両 arm とも帯内で pass — 2 guard の定義差は本文 §1 参照。final splats は on 407,775 \u002F off 408,721 (-0.23%)。\u003Cbr>\u003Cstrong>v2 (n=5、r1→r6 置換後)\u003C\u002Fstrong>: on **36.1982 dB** (36.218\u002F36.159\u002F36.196\u002F36.221\u002F36.197) vs off **36.1704 dB** (36.112\u002F36.220\u002F36.102\u002F36.237\u002F36.181) = **+0.0278 dB**、guard に **pass**。5 pair の符号は on&gt;off (r1,r3,r5) \u002F on&lt;off (r2,r4) の**混在**で系統性なし — off 側の散らばり (36.102-36.237) が on 側 (36.159-36.221) より大きく、v1 の系統分離とは対照的。v2 の結果は「PSNR 散らばりは atomic 非決定性の床であり flag 由来ではない」という読みを支持し、v1 の「静かな壊れ」仮説を反証する","v1 (n=3) mean (train elapsed, internal timer): **155.40 → 147.64s = -4.99%**、σ off 2.56% \u002F on 0.55% (比 4.66×)、有意閾値 max(2σ_off,1%) = 5.11%、実測 Δ は**閾値の 97.7%、0.12 pt 差で未達**。\u003Cbr>\u003Cstrong>v2 (n=5、新 baseline 127.4s 上、r1→r6 置換後)\u003C\u002Fstrong>: off **127.386s** (σ 0.527%) → on **125.972s** (σ 0.956%) = **-1.11%**、有意閾値 max(2σ_off,1%) = 1.054%、実測 Δ は**閾値の 105%、0.06 pt 差で形式上通過**。ただし感度分析 3 通り (汚染 r1 込み生データ Δ-0.30%\u002F不通過、r1→r6 置換後 n=5 Δ-1.11%\u002F通過、両試行を n=6 として残す Δ-0.15%\u002F不通過) のうち\u003Cstrong>通過するのは 1 通りのみ\u003C\u002Fstrong>で判定が 1 点の去就に依存する。σ 非対称は v1 が off 側 4.66× だったのに対し v2 は on 側 (n=5 で 1.81×、r1 の両試行を含む n=6 で見ると **5.40×**) と\u003Cstrong>逆転しており、両 gate とも分散構造が clean ではない\u003C\u002Fstrong>。v1 (-7.76s) と v2 (-1.41s) の絶対削減量が 5.5× 食い違う点は、A1-A4 が host 側 memset\u002Falloc 除去 (per-iter 削減量はほぼ一定のはず) である以上、\u003Cstrong>v1 の -4.99% は off arm の汚染 (σ2.56%) で膨らんでいた可能性が高く、真の効果量は ~1% 前後 = 本 harness の n=5 分解能未満\u003C\u002Fstrong>という解釈と整合する","medium","rejected-v2-wallclock-inconclusive-psnr-guard-resolved","M2 Tier1 の 4 flag (A1 SSIM memset 除去 \u002F A2 work_grad blit 化 \u002F A3 backward uniform set_bytes 化 \u002F A4 lazy C3 scratch) を全 ON\u002F全 OFF の 2 arm にまとめ gate した。\u003Cstrong>v1 (n=3, 旧 baseline)\u003C\u002Fstrong>: train elapsed (internal timer) off 155.40s (σ 2.56%) → on 147.64s (σ 0.55%) = -4.99%、3 pair 全てで on が速い一貫した方向を示したが有意閾値 max(2σ\u003Csub>off\u003C\u002Fsub>, 1%) = 5.11% を 0.12 pt 差で下回り不通過。同時に PSNR は on 側で完全分離 (mean Δ -0.065 dB) し task 指定 guard に抵触した。\u003Cstrong>v2 (n=5, 2026-08-30 M4 radix ballot 採用後の新 baseline 127.4s 上で再 gate)\u003C\u002Fstrong>: PSNR は mean **+0.028 dB**、5 pair 中 on&gt;off 3 \u002F on&lt;off 2 の符号混在で \u003Cstrong>v1 の系統分離は再現せず、「A1\u002FA2 chained path の静かな壊れ」仮説は反証\u003C\u002Fstrong>された。wallclock は r1 pair の load 汚染 (on-r1 走行中に load1 が 9.09 まで spike) を検知し 1 回だけ再実行 (r6 で置換、元 log は `*-CONTAMINATED-*` として保存) した後の値で Δ **-1.11%**、有意閾値 1.05% を 0.06 pt 差で形式上通過する。しかし①汚染 r1 を生のまま使うと Δ-0.30% (不通過)、②両方の r1 試行を n=6 として残すと Δ-0.15% (不通過) と\u003Cstrong>1 点の去就で判定が反転する脆い pass\u003C\u002Fstrong>であり、さらに③置換先の r6 自身が事前登録した再実行条件 (自 arm 他値から3σ超) を独立 load 証拠の裏付けなしに 10.3σ で踏む (条件だけでは停止しない除外連鎖になる設計上の欠陥が判明)。advisor レビューの指摘により、0.06pt の脆い pass を根拠に default flip して M7 最終スタック・卒論数値の土台にするのは不適切と判断し、\u003Cstrong>棄却を維持\u003C\u002Fstrong>した (根拠は v1 の「PSNR guard 抵触」から v2 の「wallclock 効果量 ≤1% で本 harness (n=5) の分解能未満、判定不能」に変わった)。両 gate とも `cargo test --workspace` (A1 sentinel probe \u002F A2+A3 4 組合せ parity \u002F A4 self-heal 含む) は全 pass — 実装レベルの correctness bug は一貫して否定的。\u003Cstrong>結論: 棄却維持、4 flag の default は変更しない、config.rs は一切触らない\u003C\u002Fstrong>。","\u002Ffindings\u002Fp3-tier1-bit-exact\u002F",{"id":41,"title":318,"date":319,"status":10,"polarity":12,"category":11,"axes":320,"tags":321,"task_code":331,"related_runs":332,"delta_psnr":343,"delta_wallclock":344,"rank":345,"verdict":346,"impact_summary":347,"detail_path":348},"S3 iteration pipelining depth 2 — 12.5k -18.1% \u002F busy 78 → 91% (default flip)","2026-08-17",[14,15],[322,323,324,325,326,327,328,329,23,330],"1x-roadmap-v2","s3","iteration-pipelining","command-buffer","gpu-busy","sync-tax","double-buffering","scratch-generation","unified-memory","2026-08 1× 工程表 v2 — AC 復帰後 計測 queue #2' (S3 gate)",[333,334,335,336,337,338,339,340,341,342],"s3-smoke-1000-off","s3-smoke-1000-depth2","s3-12500-off-prof","s3-12500-depth2-prof","s3-12500-off-r1","s3-12500-off-r2","s3-12500-off-r3","s3-12500-depth2-r1","s3-12500-depth2-r2","s3-12500-depth2-r3","12.5k **同一 session 交互 A\u002FB** n=3 mean: depth2 **36.202 dB** (36.195 \u002F 36.179 \u002F 36.231) vs off **36.185 dB** (36.178 \u002F 36.192 \u002F 36.186) = **+0.016 dB** (guard 36.167 ± 0.1 の内側、n=3 mean 判定 — n=1 判定なし)。final splats は depth2 406,439 \u002F off 408,874 で **depth2 のほうが 0.6% 少ない** (前段の profile pair では逆に +0.6% で、方向が一致しない = 既存 atomic 非決定性の chaos 増幅の範囲)","12.5k full run **同一 session 交互 A\u002FB n=3 mean: 185.21 → 151.70s = -18.1%** (train elapsed)。process wallclock では **188.33 → 154.00s = -18.2%**。σ は off 3.33% \u002F depth2 1.18% なので有意閾値 max(2σ,1%) = 6.7%、実測 Δ は**その 2.7 倍**。同一 session の off arm は S2 gate 当日の S2 arm (train 184.61s \u002F process 187.65s) を **+0.3% で再現**しており、session の健全性が確認できている。参考: profile=true の 1 対 1 比較では 180.49 → 162.72s = -9.85% (計装自体が host 側 critical path に乗るため S3 の効果を過小評価する)","high","s3-adopted-default-flip-pipelining-depth2","1× 工程表 v2 が「S2 後の単独本命」に指定していた S3 を gate し、採用した。S2 までの施策が \u003Cstrong>CB の数\u003C\u002Fstrong>を減らすものだったのに対し、S3 は \u003Cstrong>CB の並び方\u003C\u002Fstrong>を変える — iteration N の loss\u002Fbackward CB (B\u003Csub>N\u003C\u002Fsub>) を commit したら wait せずに iteration N+1 の forward CB (F\u003Csub>N+1\u003C\u002Fsub>) を組んで commit し、\u003Ccode>wait(B\u003Csub>N\u003C\u002Fsub>)\u003C\u002Fcode> の後の host readback \u002F \u003Ccode>accumulate\u003C\u002Fcode> を F\u003Csub>N+1\u003C\u002Fsub> の GPU 実行の影に置く。\u003Cstrong>12.5k 同一 session 交互 A\u002FB n=3 で 185.21 → 151.70s = -18.1%\u003C\u002Fstrong> (閾値 max(2σ,1%) = 6.7% の 2.7 倍)。\u003Cstrong>GPU busy 77.5 → 91.3% \u002F sync-tax 3.244 → 1.136 ms\u002Fiter (-65%)\u003C\u002Fstrong> で counter session が置いた「busy 100% = 理論上限」への距離は 22.5 pt → 8.7 pt に縮んだ。\u003Cstrong>1k smoke では busy 65.8 → 72.0% にしか上がらず判定不能だった\u003C\u002Fstrong> — smoke の splat 数 6.8k では forward の GPU 影 (1.06 ms\u002Fiter) が image size 固定の host 仕事 (~1.7 ms\u002Fiter) を隠しきれないためで、これは \u003Cstrong>「pipelining の gate は smoke では代替できない」という harness 上の教訓\u003C\u002Fstrong>として残す。残 bubble の内訳も確定した: \u003Cstrong>refine tick の drain 6.04s (43%) &gt; encode(B) 4.66s (33%) &gt; 残差 3.28s (23%)\u003C\u002Fstrong> — 次の一手が roadmap の「即効ペア (refine capacity スコープバグ修正)」であることが実測で決まった。msplat 同日等価 gap \u003Cstrong>1.105× → 0.907×\u003C\u002Fstrong>、Phase 0 からの累計 766.07 → 154.0s = \u003Cstrong>-79.9%\u003C\u002Fstrong> (全て数学的同値の施策のみ)。","\u002Ffindings\u002Fp2-s3-iteration-pipelining\u002F",1790227327657]