[{"data":1,"prerenderedAt":538},["ShallowReactive",2],{"finding:p3-refine-nondrain":3,"finding-runs:p3-refine-nondrain":365,"finding-related:p3-refine-nondrain":423},{"meta":4,"impact":56,"sections":62},{"id":5,"title":6,"subtitle":7,"eyebrow":8,"date":9,"status":10,"category":11,"polarity":12,"axes":13,"tags":16,"task_code":25,"commit":26,"branch":27,"config_paths":28,"related_runs":39,"related_findings":50},"p3-refine-nondrain","C2 施策 #4 — refine tick drain の non-draining 化。drain は構造的に必須、snapshot read の GPU blit 化 (`refine_gpu_snapshot`) は 12.5k n=3 gate で棄却","`B_it` 統合 CB の Adam encoder が param\u002Fadam 全 15 buffer を書くため、\u003Ccode>wait(B_it)\u003C\u002Fcode> 自体は depth3 化 (buffer 2 世代化、実装コスト大) なしには消せない — refine tick drain の \u003Cstrong>構造的な必要性\u003C\u002Fstrong>を確認した。縮められるのは drain の中身: `refine()` の CPU snapshot read (15 buffer中 \u003Ccode>sh_coeffs\u003C\u002Fcode>\u002F\u003Ccode>m_sh_coeffs\u003C\u002Fcode>\u002F\u003Ccode>v_sh_coeffs\u003C\u002Fcode> が支配的、407k splats で ~250MB\u002Ftick) を host memcpy から \u003Ccode>B_it\u003C\u002Fcode> CB 末尾 (Adam encoder 直後、同一 CB 内で hazard tracking により直列化) への GPU blit に置き換える \u003Ccode>[backend] refine_gpu_snapshot\u003C\u002Fcode> を実装した。\u003Ccode>raw_opacities\u003C\u002Fcode> は brush 互換 opacity decay が blit 後に書き換えるため対象外、grad RMW \u002F MCMC noise・relocation が同 tick で発火する場合は \u003Ccode>refine_tick_wants_gpu_snapshot\u003C\u002Fcode> が安全側にフォールバックする。bit-exact 性は「iter tag が一致したときだけ消費、それ以外は無条件 host snapshot」という \u003Ccode>Option::take()\u003C\u002Fcode> ベースの機構で保証 (誤った iteration の値を使うことは構造的に起きない)。unit test 3 本 (advisor 指摘の 2 trap + capacity overflow 生存性)・integration test 2 本 を追加、\u003Ccode>cargo test --workspace --release\u003C\u002Fcode> 全 pass。\u003Cstrong>2026-08-30 実施の 12.5k n=3 交互 A\u002FB gate では Δ -0.2365% (閾値 max(2σ_off,1%)=1.000%) で実質ノイズ水準の null 結果、pair 一貫性も 2\u002F3 に留まり、advisor 試算 (-1.2〜-1.9%) の pessimistic 側にすら届かなかった。PSNR guard (+0.0553dB) は pass するが wallclock が閾値の 24% にしか届かず棄却、`refine_gpu_snapshot` の default は false のまま維持。\u003C\u002Fstrong>","2026-09 ゼミ milestones · C2 施策 #4 · refine tick drain non-draining 化 (12.5k gate 棄却)","2026-08-30","stable","experiment","negative",[14,15],1,3,[5,17,18,19,20,21,22,23,24],"c2","refine","gpu-snapshot","drain","non-draining","in-flight-invariant","lego","gate-rejected","C2 施策 #4: refine tick drain の non-draining 化","実装: 初版 b095abe41106 (host memcpy が残ったままの実装ミス版) → 修正版 78abe88 (`Cow\u003C[f32]>` zero-copy 化) → overflow regression test a39fcb1 → main merge e555b9b。gate はこの merge 済み main HEAD (`2cb044bde530a425b89c3e90d2532d0e37673021`、binary sha256 `66c07056de004237d3c3c01d2aaa6d2cbdf019566dc1030af1339b6b4b240cdb`) 上で実施","main (実装は worktree-agent-aa9fd8299b2a2d779 で merge 済み、gate は main 上で実施)",[29,30,31,32,33,34,35,36,37,38],"splat\u002Fconfigs\u002F2026-08-30-rnd-12500-off-r1.toml","splat\u002Fconfigs\u002F2026-08-30-rnd-12500-off-r2.toml","splat\u002Fconfigs\u002F2026-08-30-rnd-12500-off-r3.toml","splat\u002Fconfigs\u002F2026-08-30-rnd-12500-on-r1.toml","splat\u002Fconfigs\u002F2026-08-30-rnd-12500-on-r2.toml","splat\u002Fconfigs\u002F2026-08-30-rnd-12500-on-r3.toml","splat\u002Fconfigs\u002F2026-08-30-refine-nondrain-smoke-1000-gpu-snapshot.toml","splat\u002Fconfigs\u002F2026-08-30-refine-nondrain-smoke-1000-off.toml","splat\u002Fconfigs\u002F2026-08-30-rnd-12500-prof-off.toml","splat\u002Fconfigs\u002F2026-08-30-rnd-12500-prof-on.toml",[40,41,42,43,44,45,46,47,48,49],"refine-nondrain-smoke-1000-gpu-snapshot","refine-nondrain-smoke-1000-off","rnd-12500-off-r1","rnd-12500-on-r1","rnd-12500-off-r2","rnd-12500-on-r2","rnd-12500-off-r3","rnd-12500-on-r3","rnd-12500-prof-off (instrumentation-only, n=1, not in gate stats)","rnd-12500-prof-on (instrumentation-only, n=1, not in gate stats)",[51,52,53,54,55],"p3-c2-bubble-attribution","p3-s4-host-shadow","p3-refine-3pass","p3-refine-every-200","p2-s3-iteration-pipelining",{"summary":57,"rank":58,"verdict":59,"delta_psnr":60,"delta_wallclock":61},"`p3-c2-bubble-attribution` §6 施策 #4 (refine tick drain の non-draining 化、期待 -1.5〜-2.5%) を検討・実装した。\u003Cstrong>advisor との構造分析で「drain 自体は構造的に必須、縮められるのは中身」と reframe\u003C\u002Fstrong>: `Depth2Pipeline::step` の `B_it` 統合 CB は Adam encoder で param\u002Fadam 全 15 buffer を書き換えるため、`refine()` の snapshot read はこの書き込み完了 (`wait(B_it)`) を待たないと race になる。task が提示した候補 (a) tick を `B_it` commit 直後に前倒し、(b) 候補選定だけ先に走らせる 2 段化、(c) 再充填コスト削減 は、いずれも「`B_it` の GPU 実行中に host が snapshot を読む\u002F書く」という同じ race を踏むか、staleness (1 tick 分古い grad\u002Fparam を使う意味論変更) を受け入れる必要があり、後者は `p3-refine-every-200` (densify 予算副作用で PSNR guard 8.4 倍超過、棄却) と同種のリスクを持つ。一方、advisor が提案した第 4 の道 (host memcpy を GPU blit に置き換えて `B_it` CB 自体を延長する) は staleness を一切受け入れずに host の逐次コピーコストを消せる — \u003Cstrong>これを `[backend] refine_gpu_snapshot` として実装した\u003C\u002Fstrong>。snapshot 対象 15 buffer のうち `raw_opacities` (opacity decay が blit 後に書き換える) を除く 14 buffer を、Adam encoder 直後に追加した 1 blit command encoder (14 `copy_from_buffer`) で GPU 側 mirror buffer にコピーし、`refine()` はその mirror を読む。安全性は 2 層: (1) encode 時点で `pipeline::refine_tick_wants_gpu_snapshot` が「Adam が同一 CB 内で完了するか (`!grad_rmw_pending`)」「`wait(B_it)` 後に MCMC noise\u002Frelocation がこれらの buffer を触らないか」を判定し、条件を満たさない tick では blit を encode しない、(2) `refine()` 側は `gpu_snapshot_ready_for.take() == Some(it)` のときだけ消費し、iteration が食い違えば (万一 (1) の判定が pipeline とズレても) 無条件に host snapshot へフォールバックする — 誤った iteration の値を使うバグが構造的に起きない設計。`cargo test --workspace --release` 全 pass (0 failed、新規 5 test 込み)。1000 iter smoke (Lego) で crash なし、`refine_gpu_snapshot: true` が実際に解決され `ts_refine_snapshot_blit` が refine tick 数 (6 回) と一致する回数だけ発火することを確認。\u003Cstrong>2026-08-30、main 上で 12.5k n=3 交互 A\u002FB gate (off→on×3) を実施\u003C\u002Fstrong>: train elapsed (internal timer) off mean 122.6467s (σ 0.330%) → on mean 122.3567s (σ 0.301%) = Δ **-0.2365%**。有意閾値 max(2σ_off,1%)=1.000% の **24%** にしか届かず、pair 一貫性も 3 組中 2 組 (r1: -0.788%, r2: -0.082%) が on 優位、r3 (+0.163%) は逆方向という系統性の無い結果。事前の advisor 試算 (-1.2〜-1.9%) が明記した「pessimistic ケースでは不通過もあり得る」を超え、実測は pessimistic ケースの想定 (max(2σ,1%) 近傍での僅差) よりもさらに小さい、実質ノイズ水準の null 結果だった。PSNR は +0.0553dB で guard (-0.05dB 以内) を pass するが、wallclock が閾値に遠く及ばないため\u003Cstrong>棄却確定、`refine_gpu_snapshot` の default は false のまま維持、code は変更しない\u003C\u002Fstrong>。汚染判定 (`p3-tier1-bit-exact.toml` §5 の事前登録条件、load spike AND 3σ超 の AND) は off-r1 の load1 window mean が他 run よりやや高い (2.41 vs 0.80-1.38) ものの偏差 1.07σ (\u003C3σ) で条件不成立、かつ off-r1 を除外しても Δ は -0.060% とさらに小さくなるだけで結論は変わらないため retry は実施しなかった。","low","structural-drain-necessity-confirmed \u002F snapshot-read-gpu-blit-implemented \u002F gate-rejected-null-effect","12.5k n=3 gate: on mean 36.1937dB (36.179\u002F36.203\u002F36.199) vs off mean 36.1383dB (36.113\u002F36.187\u002F36.115) = **+0.0553dB**、guard (-0.05dB 以内) は pass。gradient 非変更の bit-exact 設計のため理論上は差が出ないはずで、この +0.055dB は backward atomic の run-to-run noise とみなすのが妥当 (`p3-s4b-ssim-reduce` と同型の解釈)","12.5k n=3 gate (2026-08-30, off→on×3): train elapsed off mean **122.6467s** (σ 0.330%) → on mean **122.3567s** (σ 0.301%) = Δ **-0.2365%**。有意閾値 max(2σ_off,1%)=1.000% の 24% にしか届かず不通過。advisor 試算 (-1.2〜-1.9%) を大きく下回る null 結果、pair 一貫性も 2\u002F3 に留まる (§7 参照)",[63,66,69,81,83,119,124,126,157,160,162,193,197,199,216,218,225,227,241,309,313,315,318,320,323,359,362],{"type":64,"text":65},"lead","task は refine tick drain (3.0〜3.8s、wall の 2.4〜3.1%) の non-draining 化を求めた。実装に入る前に advisor と行った構造分析で、\u003Cstrong>drain (`wait(B_it)`) 自体は depth3 化なしには除去できない\u003C\u002Fstrong>ことが判明し、task が提示した 3 候補はいずれも staleness を受け入れるか低い ceiling (6.4ms の backward shadow に押し込めるだけ) にとどまることが分かった。本 finding は (1) drain が構造的に必要な理由、(2) 3 候補 + advisor 提案の第 4 候補の比較、(3) 採用した設計 (`refine_gpu_snapshot`) の bit-exact 性・安全性、(4) test\u002Fsmoke 結果、(5) gate config と期待値、の順で記録する。",{"type":67,"text":68},"heading","1. なぜ drain が構造的に必要か — Adam encoder が B_it 内で全 15 buffer を書く",{"type":70,"items":71},"kv",[72,75,78],{"key":73,"value":74},"事実","`encode_loss_backward_chain` (`pipeline.rs`) は `grad_rmw_pending == false` (grad への CPU RMW が無い iter、Lego 12.5k final-stack config はこれに該当) のとき `ts_adam` (Adam step) を **`B_it` 統合 CB の内側**にエンコードする。Adam step は `param.means`\u002F`log_scales`\u002F`rot_quats`\u002F`raw_opacities`\u002F`sh_coeffs` と `adam_state` の m\u002Fv 全 10 buffer、計 15 buffer を GPU 上で書き換える。",{"key":76,"value":77},"帰結","`refine()` が `param`\u002F`adam_state` の値を host から読む (`take_snapshot`) には、その GPU 書き込みが完了していること (= `B_it` の `wait_until_completed()`) が **race を避けるための必要条件**になる。これは A7(b) `refine_direct_write` の安全性論証 (`Depth2Pipeline::debug_assert_drained`) と同じ前提であり、既に `p3-refine-3pass.toml` で明文化済みだった。",{"key":79,"value":80},"depth3 化すれば理論上は消せる","buffer をもう 1 世代持てば、host は 1 世代前の (確定済みの) 値を読みながら GPU は次の世代に書き込める。しかし `pipeline.rs` module doc が明記する通り depth3 (in-flight CB をもう 1 本増やす) は「禁忌」スコープ — メモリコスト (2 世代化だけで Lego 407k で ~275MB、depth3 はさらに増える) と正しさの論証の複雑化に見合わないと判断されている。本 finding はこの前提を覆さない。",{"type":67,"text":82},"2. 設計候補の比較 — task 提示の 3 案 + advisor 提案の第 4 案",{"type":84,"columns":85,"align":91,"rows":94},"table",[86,87,88,89,90],"#","案","bit-exact 性","ceiling","採否",[92,92,92,93,92],"left","right",[95,101,107,113],[96,97,98,99,100],"(a)","tick を `B_it` commit 直後・`F_{it+1}` encode 前に置き、`B_it` の GPU 実行と host densify を重ねる","**意味論変更** — `B_it` はこの時点でまだ実行中 (Adam 未完了) なので、host が読む grad\u002Fparam は前 iteration (`it-1`) までの値になる。1 tick 分 stale","6.379ms (`B_it` shadow) しかなく、advisor 試算で refine bucket (~24ms\u002Ftick) の ~27% (≈0.6s、0.5%程度) が上限。stale の代償に見合わない","不採用",[102,103,104,105,106],"(b)","densify の host 計算 (候補選定・index 計算) だけ先に走らせ、buffer 書き換えは drain 後に短時間で行う 2 段化","**(a) と同じ race を踏む** — 候補選定は `old_raw_opacities`\u002F`old_log_scales` 等を読む必要があり、これらも Adam 未完了の値になる。真に安全にするには (a) と同じ staleness を受け入れる必要があり、2 段化しても race 条件は変わらない","(a) と同じ 6.379ms shadow 制約","不採用 (机上で (a) に帰着すると判明)",[108,109,110,111,112],"(c)","再充填コストの削減 (tick 直後の `F` を通常 depth2 で即 overlap)","bit-exact (staleness なし)","**ceiling ≈ 0** — `F_{it+1}` は post-refine の param\u002Fnum_splats に依存するため refine() 完了前には encode できず、host は refine() 完了直後に `F_{it+1}` を encode するしかない (現状の実装と同じ)。オーバーラップできる相手が構造的に存在しない","不採用 (効果なしと判明)",[114,115,116,117,118],"(4, advisor 提案)","host memcpy による snapshot read を `B_it` 統合 CB 末尾 (Adam 直後) への GPU blit に置き換える (`B_it` の CB 自体を延長する — 何かと重ねるのではない)","**bit-exact** — blit は Adam の直後・同一 CB 内 (hazard tracking で直列化) から同じバイトをコピーするだけ。staleness ゼロ","6.4ms shadow の制約を受けない (「重ねる」設計ではないため)。ceiling は snapshot read が refine tick drain bucket に占める割合 (advisor 試算 ~半分)","**採用**",{"type":120,"label":121,"variant":122,"text":123},"callout","(a)\u002F(b) が同じ race に帰着する理由 — advisor 指摘","warning","(a)\u002F(b) の狙いは「host の CPU 作業を `B_it` の GPU 実行時間に重ねる」ことだが、`B_it` の Adam encoder が `refine()` の読み書き対象と**同じ 15 buffer**を書いているため、「重ねる」こと自体が race になる。狙いを達成するには「重ねる」のではなく「対象を `B_it` 完了前の世代に限定する」しかなく、それは即ち staleness の受容に等しい。\u003Cstrong>(4) が (a)\u002F(b) と質的に違うのは、`B_it` と並行して host が読み書きするのではなく、`B_it` 自身の CB に blit を追加して GPU 側で完結させる点\u003C\u002Fstrong> — 「重ねる」候補ではなく「host 作業を GPU に移す」候補であり、この違いが 6.4ms shadow の制約を受けない理由になっている。",{"type":67,"text":125},"3. 採用した設計 — `[backend] refine_gpu_snapshot`",{"type":84,"columns":127,"align":131,"rows":132},[128,129,130],"確認内容","file:symbol","備考",[92,92,92],[133,137,141,145,149,153],[134,135,136],"blit 対象 14 buffer の定義・確保","`splat-train-v1\u002Fsrc\u002Frefine.rs` `RefineGpuSnapshot` struct + `RefineGpuSnapshot::new`","`raw_opacities` (値そのもの) のみ除外。`m_raw_opacities`\u002F`v_raw_opacities` は opacity decay が触らないので対象に含む",[138,139,140],"blit の encode (B_it CB 末尾)","`refine.rs` `RefineState::encode_gpu_snapshot_blit` — Adam encoder 直後に呼ぶ","呼び出し側 (`Depth2Pipeline::step`) が commit **前**に呼ぶ制約を守る (`pipeline.rs` の呼び出し箇所コメント参照)",[142,143,144],"安全条件の判定 (encode してよいか)","`pipeline.rs` `refine_tick_wants_gpu_snapshot` — grad RMW \u002F MCMC noise \u002F 同 it の MCMC relocation を除外","`param_mutated_after_step` の姉妹関数、「`train_loop` の実際の分岐条件と 1:1 対応させること」という同じ規約を継承",[146,147,148],"host memcpy を実際に消す (**修正済み**)","`refine.rs` `refine()` 冒頭、`Cow\u003C[f32]>` で `Cow::Borrowed`(GPU mirror への zero-copy `&[f32]`) \u002F `Cow::Owned`(`take_snapshot` の host memcpy Vec) を分岐","**gate 前に advisor レビューで発覚した実装ミスの修正箇所**。初版は `take_snapshot` の引数 (読み出し元 buffer) を差し替えただけで memcpy 自体を呼び続けており、GPU blit を「追加」しただけで host コピーを「置換」できていなかった (net で純増、下記コールアウト参照)",[150,151,152],"bit-exact な消費 (iteration tag)","`refine.rs` `refine()` 冒頭 `refine_state.gpu_snapshot_ready_for.take() == Some(it)`","`Option::take()` で毎回無条件にクリアするため、iteration 不一致時に stale な値を誤って使うことは構造的に起きない (最適化されないだけに縮退)",[154,155,156],"`[backend]` flag \u002F validate","`config.rs` `BackendConfig::refine_gpu_snapshot` (default false) + `validate()` の `pipelining != Depth2` hard error","`refine_scratch_persist`\u002F`refine_direct_write` と同じ配線パターン (`apply_backend_config` の exhaustive destructure に追加)",{"type":120,"label":158,"variant":122,"text":159},"gate 前に発覚した実装ミス — 「読み出し元を変える」だけでは host memcpy は消えない","初版実装は `old_means = take_snapshot(&mut ..., persist, means_buf, n)` のように、`means_buf` を `&param.means` から `&snap.means` (GPU mirror) に差し替えるだけだった。しかし `take_snapshot` 自体は `buf.contents()` から `Vec::extend_from_slice` で **host CPU memcpy** する実装のままで、読み出し元アドレスが変わっただけで memcpy は消えていなかった — つまり tick ごとに \u003Cstrong>host memcpy (~250MB) + GPU blit (~250MB) の両方\u003C\u002Fstrong>を行っており、net で純増になっていた。1000 iter smoke (7k splats 規模、advisor 指摘どおりこの規模では効果は測れないが方向性は検出できる) で `ts_refine` per-call を比較したところ、初版は off (365.6µs\u002Fcall) より on (618.9µs\u002Fcall) の方が **遅い** — 実際に純増していたことを既存ログのみで確認した (advisor 助言「30 秒で確認できる」の通り、新規 GPU run 不要)。修正 (`Cow\u003C[f32]>` 化、host memcpy を `Cow::Borrowed` 分岐で完全にスキップ) 後、同条件で on 370.5µs\u002Fcall ≈ off 365.6µs\u002Fcall まで復帰 (この小規模 regime では snapshot read 自体が `ts_refine` の小部分のため、劇的な差は出ない — 12.5k\u002F407k splats 規模で初めて有意な差が出る想定、advisor 試算 -1.2〜-1.9%)。\u003Cstrong>この bug を含む版で 12.5k gate を実施していたら、「効果なし〜わずかに悪化」という誤った結論に達していたはず\u003C\u002Fstrong> — 実装完了後・gate 実施前の advisor レビューが機能した事例として記録する。",{"type":67,"text":161},"4. test \u002F smoke 結果",{"type":84,"columns":163,"align":167,"rows":168},[164,165,166],"test","何を確認するか","結果",[92,92,92],[169,173,176,179,182,185,189],[170,171,172],"`refine_gpu_snapshot_matches_host_snapshot_when_blitted` (unit)","blit した GPU snapshot を消費した `refine()` が、host snapshot 経路と全 15 buffer bit-exact に一致すること","PASS",[174,175,172],"`refine_gpu_snapshot_wrong_iter_falls_back_to_host_snapshot` (unit)","`gpu_snapshot_ready_for` の iteration が呼び出し時の `it` と食い違うとき、stale な blit 値ではなく live buffer (blit 後に意図的に変更した値) を読むこと — フォールバックが実際に機能する証拠",[177,178,172],"`refine_grows_capacity_on_overflow_gpu_snapshot` (unit、advisor 指摘で追加)","capacity overflow (`param.resize_capacity`\u002F`adam_state.resize_capacity` が live buffer を新しい Metal buffer に差し替える) を GPU snapshot 経由で発生させ、mirror buffer への `Cow::Borrowed` スライスが resize を跨いでも有効であり続け、host snapshot 経路と bit-exact に一致すること",[180,181,172],"`pipelining_depth2_refine_gpu_snapshot_matches_off_across_refine_ticks` (integration)","advisor 指摘の trap 1 (opacity_decay_rate > 0 が実際に発火するシナリオ) を通しつつ Off と Depth2+flag が一致すること",[183,184,172],"`pipelining_depth2_refine_gpu_snapshot_falls_back_with_grad_rmw` (integration)","advisor 指摘の trap 2 (`scale_reg.weight > 0` で grad RMW が有効、Adam が CB 外で走る) で `refine_gpu_snapshot=true` でも安全にフォールバックし Off と一致すること",[186,187,188],"`cargo test --workspace --release` (全 crate)","既存 test (refine 22 本、pipelining\u002Ftrain_loop 系含む) の regression 無し","全 pass (0 failed)、新規 5 test 込み",[190,191,192],"1000 iter smoke (`2026-08-30-refine-nondrain-smoke-1000-gpu-snapshot.toml`、修正版で再実行)","実バイナリで crash なし、`[backend] BackendConfig {...}` line で `refine_gpu_snapshot: true` が実際に解決、`ts_refine_snapshot_blit` の呼び出し回数が refine tick 数と一致、`ts_refine` per-call が off と同水準に復帰 (純増バグが直った証拠)","PASS — `ts_refine_snapshot_blit` 6 回 (= `ts_refine`\u002F`ts_opacity_decay` と同数、tick 500\u002F600\u002F700\u002F800\u002F900\u002F1000)、49.8µs\u002Fcall、`sync_iters=6\u002F1000`、`ts_refine` 370.5µs\u002Fcall (off 365.6µs\u002Fcall とほぼ同水準)",{"type":120,"label":194,"variant":195,"text":196},"smoke の on\u002Foff 比較は splat 数・PSNR が一致しない — これは想定通り (バグではない)","info","1000 iter smoke を on (`refine_gpu_snapshot=true`) \u002F off で走らせたところ final splats (6816 vs 6766) \u002F PSNR (19.551 vs 19.611 dB) が一致しなかった。これは実装のバグではなく、\u003Cstrong>フル Lego シーン (複数カメラ view) の GPU atomic float 累積順が run ごとに非決定的\u003C\u002Fstrong>という既知の特性 (`per_kernel_single_texel_run_to_run_deterministic_1iter` の doc 参照 — 決定性が保証されるのは single-texel fixture の 1 iter のみ) — 同じ off config を 2 回走らせただけでも final splats が 6766→6948、PSNR が 19.611→19.548 と同程度ばらつくことを確認して裏付けた。bit-exact 性は unit test (決定的な single-texel 相当の fixture、固定 seed) で確認済みであり、smoke の役割は crash-freedom と計装確認に限定される。",{"type":67,"text":198},"5. gate config (12.5k n=3、実施済み — §7 参照)",{"type":70,"items":200},[201,204,207,210,213],{"key":202,"value":203},"config","`splat\u002Fconfigs\u002F2026-08-30-rnd-12500-{off,on}-r{1,2,3}.toml`、base は `2026-08-30-final-12500-r{1,2,3}.toml` ([backend] `refine_gpu_snapshot` の 1 field のみ diff、他は現行採用スタック — M4 simd_ballot + A7 refine_scratch_persist\u002Frefine_direct_write + S4b ssim_reduce=gpu (default) — と bit-exact。base config は `ssim_reduce` を明示していないため S4b flip 後の default である `Gpu` がそのまま両 arm に効くことを 6 run の `[backend] BackendConfig {...}` ログで確認済み)",{"key":205,"value":206},"PSNR guard","task 指定の相対 guard (on mean ≥ off mean - 0.05dB) で判定 (pass、§7 参照)。参考: `p3-final-stack` n=3 mean 36.219 dB を中心にした絶対 guard (±0.05dB → [36.169, 36.269]) で読むと **off (36.138) は帯外・on (36.194) は帯内**になるが、両 arm とも同程度に低く flag 由来の系統差ではなく `p3-final-stack` 基準からの baseline drift (session 間の atomic 非決定性) と読むのが妥当 — この読み替えは棄却\u002F採用の結論を動かさない",{"key":208,"value":209},"採用閾値","A7\u002FS4b と同じ `max(2σ_off, 1%)` 規約 (σ_off は off arm 3 run から算出)",{"key":211,"value":212},"期待 Δ (gate 前の宣言)","advisor 試算: refine tick drain bucket (2.4〜3.1%) のうち snapshot read が占める割合を概算半分とすると **-1.2〜-1.9%**。pessimistic ケース (閾値 1.612% 相当) では不通過もあり得ることを明記しておく — A7\u002FS4 の教訓 (期待帯を事前登録し、null 結果も解釈可能にする) に従う",{"key":214,"value":215},"実施状況","**2026-08-30、main HEAD `2cb044bde530a425b89c3e90d2532d0e37673021` (binary sha256 `66c07056de004237d3c3c01d2aaa6d2cbdf019566dc1030af1339b6b4b240cdb`) 上で実施済み** — `splat\u002Fscripts\u002Fgate-ab-n.sh configs\u002F2026-08-30-rnd-12500-off configs\u002F2026-08-30-rnd-12500-on rnd-12500 3` を nohup+disown で detach し、DONE sentinel を待って完了。結果は §7 参照、**棄却確定**",{"type":67,"text":217},"6. 規約 \u002F 次段への含意",{"type":219,"items":220},"list",[221,222,223,224],"**refine tick drain は構造的に必須** — `B_it` の Adam encoder が param\u002Fadam 全 15 buffer を書くため、`wait(B_it)` を depth3 化なしに除去することはできない。今後 refine tick drain の追加最適化を検討する際は、この制約を前提にすること (staleness を受け入れるか、depth3 化するかの二択になる)","**「GPU shadow に重ねる」系の最適化 (S4 host_schedule と同型) は refine には向かない** — refine の snapshot read\u002Fwrite は `B_it` 自身が触る buffer と同一のため、S4 (`p3-s4-host-shadow`、既に棄却確定) と同じ race 構造を持つ。今回 advisor が提案した「host 作業を GPU 側に移す」(重ねるのではない) アプローチ自体は設計として妥当だったが、**実測 Δ は -0.24% でノイズ水準に留まり、棄却**","**次段のアクション**: `refine_gpu_snapshot` は default false のまま維持、`p3-c2-bubble-attribution` §6 の施策 #4 を「実装済み・12.5k gate で棄却 (効果量が harness 分解能未満)」に更新すること。読みは §7 の機構解釈 (snapshot read 自体は refine tick drain bucket 内で相対的に小さく、host memcpy の絶対コストが元々小さかった可能性) を参照","gate 実施・棄却確定により本 finding は `status = \"stable\"` に更新した。code 変更は行っていない (`refine_gpu_snapshot` の default \u002F validate は変更なし)",{"type":67,"text":226},"7. 12.5k n=3 gate (2026-08-30、rnd-12500 series) — 棄却根拠",{"type":70,"items":228},[229,232,235,238],{"key":230,"value":231},"前提","AC 接続 (`pmset -g batt` で `AC Power` 確認)、GPU 権は main から付与済み・他 agent の GPU 使用なし。`cargo build --release` (HEAD `2cb044bde530a425b89c3e90d2532d0e37673021`、binary sha256 `66c07056de004237d3c3c01d2aaa6d2cbdf019566dc1030af1339b6b4b240cdb`)。起動直前に `pgrep -fl \"target\u002Frelease\u002Fsplat\"` が空であることを確認、config 6 本は `splat check` で ok を確認済み",{"key":233,"value":234},"driver","`splat\u002Fscripts\u002Fgate-ab-n.sh configs\u002F2026-08-30-rnd-12500-off configs\u002F2026-08-30-rnd-12500-on rnd-12500 3` (nohup+disown で detach、`rnd-12500-gate.DONE` sentinel で完了検出)。6 run とも rc=0、series 前後で binary sha256 \u002F git rev 不変を driver ログで確認",{"key":236,"value":237},"flag 実測確認 (6\u002F6)","全 6 run の `[backend] BackendConfig { … }` で他の全 flag (backward=Simd, loss_path=Gpu, binning=Resident, pipelining=Depth2, host_schedule=ForwardShadow, ssim_reduce=Gpu [S4b default 追従], refine_scratch_persist=true, refine_direct_write=true 等) が off\u002Fon 間で完全同一であることを確認、差分は `refine_gpu_snapshot: false` (off 3\u002F3) \u002F `refine_gpu_snapshot: true` (on 3\u002F3) のみ",{"key":239,"value":240},"汚染 \u002F retry 判定","事前登録条件 (`p3-tier1-bit-exact.toml` §5、(i) load 証拠 AND (ii) 自 arm内 3σ超 の **AND**) を適用。off-r1 の run 窓内 load1 (mean 2.41, max 3.49) は他の off run (0.80\u002F0.87) よりやや高いが、off-r1 の off arm内偏差は 1.07σ (\u003C3σ) で条件 (ii) 不成立、よって retry 対象なし。感度チェックとして off-r1 を除外した場合の Δ も算出したところ **-0.060%** (さらに閾値から遠ざかる) で、いずれの扱いでも結論 (棄却) は変わらない",{"type":84,"columns":242,"align":250,"rows":251},[243,244,245,246,247,248,249,130],"実行順","arm","run","train elapsed (s)","PSNR (dB)","final splats","run 窓内 load1 mean\u002Fmax",[92,92,92,93,93,93,93,92],[252,260,267,273,279,285,291,298,303],[253,254,42,255,256,257,258,259],"1","off (A)","123.08","36.113","408,798","2.41 \u002F 3.49","採用",[261,262,43,263,264,265,266,259],"2","on (B)","122.11","36.179","405,242","1.10 \u002F 1.59",[268,254,44,269,270,271,272,259],"3","122.28","36.187","405,976","0.80 \u002F 1.04",[274,262,45,275,276,277,278,259],"4","122.18","36.203","406,688","1.38 \u002F 2.05",[280,254,46,281,282,283,284,259],"5","122.58","36.115","407,562","0.87 \u002F 1.17",[286,262,47,287,288,289,290,259],"6","122.78","36.199","409,949","0.96 \u002F 1.15",[292,293,294,295,296,297,294,294],"**mean (n=3)**","**off**","—","**122.6467** (σ 0.330%)","**36.1383**","407,445",[292,299,294,300,301,302,294,294],"**on**","**122.3567** (σ 0.301%)","**36.1937**","407,293",[304,294,294,305,306,307,294,308],"**Δ**","**-0.2365%**","**+0.0553**","-0.037%","閾値 max(2σ_off,1%)=1.000% を大きく下回り不通過",{"type":120,"label":310,"variant":311,"text":312},"判定 — wallclock 閾値未達 (実測は閾値の 24%)、pair 一貫性も 2\u002F3 に留まり棄却","danger","wallclock: Δ **-0.2365%** は有意閾値 max(2σ_off,1%)=1.000% の **24%** にしか届かず、明確に不通過。pair は r1 (-0.788%, on 優位) \u002F r2 (-0.082%, on 優位だがごく小) \u002F r3 (+0.163%, on が逆に遅い) で \u003Cstrong>3 組中 2 組のみ on 優位、系統的な一貫性はない\u003C\u002Fstrong>。PSNR: Δ **+0.0553dB** で guard (-0.05dB 以内) は pass するが、`refine_gpu_snapshot` は snapshot read の読み出し元を変えるだけで gradient には一切触れない bit-exact 設計のため、この値は改善の証拠ではなく §2b (`p3-s4b-ssim-reduce`) と同型の背景 atomic noise と解釈すべきもの。\u003Cstrong>wallclock が閾値に遠く及ばない以上、PSNR guard の pass に関わらず棄却\u003C\u002Fstrong>。",{"type":67,"text":314},"8. Δ 実測 (-0.24%) が advisor 試算 (-1.2〜-1.9%) を大きく下回ったことの機構解釈",{"type":120,"label":316,"variant":195,"text":317},"snapshot read の host memcpy コスト自体が想定より小さかった可能性","advisor 試算は「refine tick drain bucket (2.4〜3.1%) のうち snapshot read が占める割合を概算半分」という比例配分だったが、`p3-c2-bubble-attribution` のブラケットは drain bucket 全体 (snapshot read + action 決定 + compact write + zero_tail) の合算であり、snapshot read 単体の絶対コストは当時計装 (`ts_refine` のサブラベル分割) されていなかった (§4 未解決点 (2) が明記していた計装ギャップ)。**§9 の instrumentation-only 実測 (n=1、12.5k 規模) がこれを直接測定した**: 12500 iter 中の refine tick は `start_iter=500, every=100` により **121 回** (500,600,…,12500)、`ts_refine` per-call が off 20.744ms → on 16.032ms (削減 4.712ms\u002Ftick) なので、121 tick × 4.712ms\u002Ftick = **0.570s** — `ts_refine` の合計値 (2.510s − 1.940s = 0.570s) と独立に一致する。~123s の wall に対し **0.46%** であり、これが本施策の実測上限 (ceiling)。12.5k n=3 gate の Δ -0.2365% はこの 0.46% ceiling とノイズ帯の範囲で整合する — 逆算や頻度論は不要で、**advisor 試算の「drain bucket の約半分」という配分そのものが過大評価だった**、という単純な説明で足りる。",{"type":67,"text":319},"9. instrumentation-only 検証 (n=1、`profile=true`) — blit が 12.5k で実際に発火したことの直接証拠",{"type":120,"label":321,"variant":122,"text":322},"advisor 指摘への対応 — BackendConfig ログだけでは blit 発火の証拠にならない","§7 の 6 run はいずれも `profile = false` (他の全 gate と同じ設定) で `ts_*` 計装ログが出力されないため、`[backend] BackendConfig { refine_gpu_snapshot: true }` は flag が parse されたことしか示さず、`refine_tick_wants_gpu_snapshot` が実際に true を返し `refine()` が `Cow::Borrowed` 分岐 (GPU blit 経路) を取ったことの証拠にはならない。§3 コールアウトが記録した過去の実装ミス (host memcpy が消えていないまま blit だけ追加していた) は `ts_refine` の on\u002Foff 比較でのみ検出できた前例であり、本 gate も同じ確認を経ないと「効果なし」と「計測していない」が区別できない。この懸念に対応するため、gate 6 run とは別に `profile = true` の n=1 pair (`2026-08-30-rnd-12500-prof-{off,on}.toml`、name\u002Frun_dir を gate run と衝突しないよう変更、統計には含めない instrumentation-only run) を追加で実行した。",{"type":84,"columns":324,"align":328,"rows":329},[325,326,327,130],"計装","off (rnd-12500-prof-off)","on (rnd-12500-prof-on)",[92,93,93,92],[330,335,340,344,349,354],[331,332,333,334],"`ts_refine_snapshot_blit` 発火回数","(該当なし)","**121 \u002F 121**","`start_iter=500, every=100, stop_iter=12500` → refine tick 数 (500,600,…,12500) と完全一致。blit が全 refine tick で実際に発火したことの直接証拠",[336,337,338,339],"`ts_refine` (per-call)","20.744ms\u002Fcall (合計 2.510s, 121 call)","16.032ms\u002Fcall (合計 1.940s, 121 call)","**-22.7%\u002Fcall** — snapshot read の host memcpy 除去による `refine()` 自体の短縮は実際に起きている",[341,294,342,343],"`ts_refine_snapshot_blit` (per-call)","12.009µs\u002Fcall (合計 1.453ms)","blit 自体の GPU encode コストは極小 (1000 iter smoke の 49.8µs\u002Fcall より小さい — 407k splats 規模でも支配的コストにならない)",[345,346,347,348],"`ts_chain_commit_wait` (`B_it` 完了待ち、drain 本体)","82.855s (57.1%)","87.983s (57.2%)","**+5.128s** だが下記コールアウト参照 — blit のコストではなく run 単体のノイズと判断",[350,351,352,353],"`ts_forward` (参考、flag が一切触れないはずの経路)","26.300s","28.309s","**+2.009s** — `refine_gpu_snapshot` は forward path に一切配線されていないにもかかわらず増加しており、on-arm instrumentation run 全体が (profiling オーバーヘッドか偶発的な system jitter で) 一般的に遅かったことを示す独立した証拠",[355,356,357,358],"`training done in`","123.18s","129.68s","n=1・instrumentation-only。on 側は gate の on 3 run (122.11-122.78s) から明確に外れており、下記コールアウトの通り run 単体のノイズと判断、統計には含めない",{"type":120,"label":360,"variant":195,"text":361},"機構解釈 — 実測上限は `ts_refine` の -0.570s (≈0.46%)、advisor 試算 (半分配分) が過大評価だった","`ts_chain_commit_wait` の +5.128s は blit の GPU コストではない、と判断する根拠は 3 点: (1) 大きさが合わない — 121 回の blit に均せば 42ms\u002Fblit 相当になるが、同じ log の `ts_refine_snapshot_blit` encode コストは 12.009µs\u002Fcall、~250MB の unified memory `copy_from_buffer` の実行コストも概算 1ms 未満のオーダーで、42ms\u002Ftick は 2 桁近く合わない。(2) 同じ log 内に独立した反証がある — `refine_gpu_snapshot` は一切配線されていない `ts_forward` (count 12500) も +2.009s 増えており、`ts_chain_commit_wait` (同じく count 12500、wall の 57%) は system 全体が遅いときにそのまま増える場所である。(3) `training done in` 自体が on 側で gate の on 3 run から明確に外れている (129.68s vs 122.11-122.78s) — これは on-arm instrumentation run 単体が (profiling オーバーヘッドか偶発的な負荷で) 全体的に遅かったことの直接証拠であり、その run のバケット差分を『blit の構造的コスト』として解釈するのは誤り。\u003Cstrong>したがって本施策の実測上限は `ts_refine` の削減分のみ: -0.570s ≈ wall (123s) の 0.46%\u003C\u002Fstrong>。これは 12.5k n=3 gate の Δ -0.2365% (ノイズ帯) とほぼ整合する — §8 で「host memcpy コスト自体が想定より小さかった」と推測した読みが正しく、advisor 試算 (-1.2〜-1.9%、drain bucket の約半分という配分) の方が過大評価だった、という単純な説明で足りる。blit 自体の追加コストが `wait(B_it)` を有意に伸ばしているという証拠は無い (§8 のまま維持)。",{"type":120,"label":363,"variant":195,"text":364},"未解決点","(1) ~~snapshot read が refine tick drain bucket に占める正確な割合は計装していない~~ → **§9 で解消**: 12.5k 規模 instrumentation-only run (n=1) で `ts_refine_snapshot_blit` 121\u002F121 発火・`ts_refine` per-call -22.7% (20.744ms→16.032ms、合計 -0.570s ≈ wall の 0.46%) を実測。これが本施策の実測上限であり advisor 試算 (-1.2〜-1.9%) は過大評価だったと判明した (`ts_chain_commit_wait` の +5.128s は同 run の `ts_forward` +2.009s [flag が触れない経路] と合わせて run 単体のノイズと判定、§9 参照)。`ts_refine` のさらに細かいサブラベル分割 (`snapshot`\u002F`action`\u002F`compact`\u002F`zero_tail`) は依然未実施。(2) MCMC 有効時 (grad RMW \u002F SGLD noise \u002F relocation) の safety fallback は integration test 1 本 (`scale_reg` 経由) のみで確認しており、`mean_noise_weight`\u002Frelocation 経由の fallback は明示的な test を追加していない。(3) 4 flag 一括ではなく単独 flag の gate だったため他施策との相互作用は未検証だが、効果量が既にノイズ水準のため優先度は低い。(4) `config.rs:511` (`refine_gpu_snapshot` field doc)・`config.rs:558` (`BackendConfig::default()` のコメント)・`refine.rs:64` (module doc) にはいずれも「default = false (gate 待ち)」の文言が残っている — 棄却が確定した以上、`p3-tier1-bit-exact.toml` §6 が指摘した規約 (「verdict が変わったら doc を同じ commit で更新する」) に照らすと doc-only で「棄却確定 (2026-08-30 gate、`p3-refine-nondrain` 参照)」に追随させるべきだが、本 task の指示 (「棄却なら code 不変」) に従い `.rs` は一切変更していない。`p3-tier1-bit-exact` 系の未処理の同種 doc (`ssim_clear`\u002F`raster_grad_clear`\u002F`backward_uniform` の「gate 待ち」文言、`config.rs:406\u002F412\u002F420\u002F428\u002F433`) も含め、main の判断で doc-only commit として一括処理することを推奨する。",[366,377,384,390,396,402,408,417],{"id":42,"title":42,"subtitle":367,"date":9,"workspace":368,"tags":369,"verdict":372,"psnr":373,"psnr_unit":-1,"wallclock":374,"splats":375,"summary_url":376,"detail_path":376},"C2 policy 4 (refine_gpu_snapshot) gate arm A (baseline, refine_gpu_snapshot = false): Lego 12.5k full run repeat 1\u002F3","splat",[5,17,370,371,23],"refine-gpu-snapshot","gpu-gate","partial",36.113399505615234,"2m 3s",408798,"\u002Fruns\u002Frnd-12500-off-r1\u002F",{"id":44,"title":44,"subtitle":378,"date":9,"workspace":368,"tags":379,"verdict":372,"psnr":380,"psnr_unit":-1,"wallclock":381,"splats":382,"summary_url":383,"detail_path":383},"C2 policy 4 (refine_gpu_snapshot) gate arm A (baseline, refine_gpu_snapshot = false): Lego 12.5k full run repeat 2\u002F3",[5,17,370,371,23],36.186988830566406,"2m 2s",405976,"\u002Fruns\u002Frnd-12500-off-r2\u002F",{"id":46,"title":46,"subtitle":385,"date":9,"workspace":368,"tags":386,"verdict":372,"psnr":387,"psnr_unit":-1,"wallclock":381,"splats":388,"summary_url":389,"detail_path":389},"C2 policy 4 (refine_gpu_snapshot) gate arm A (baseline, refine_gpu_snapshot = false): Lego 12.5k full run repeat 3\u002F3",[5,17,370,371,23],36.11488723754883,407562,"\u002Fruns\u002Frnd-12500-off-r3\u002F",{"id":43,"title":43,"subtitle":391,"date":9,"workspace":368,"tags":392,"verdict":372,"psnr":393,"psnr_unit":-1,"wallclock":381,"splats":394,"summary_url":395,"detail_path":395},"C2 policy 4 (refine_gpu_snapshot) gate arm B (candidate, refine_gpu_snapshot = true): Lego 12.5k full run repeat 1\u002F3",[5,17,370,371,23],36.1786003112793,405242,"\u002Fruns\u002Frnd-12500-on-r1\u002F",{"id":45,"title":45,"subtitle":397,"date":9,"workspace":368,"tags":398,"verdict":372,"psnr":399,"psnr_unit":-1,"wallclock":381,"splats":400,"summary_url":401,"detail_path":401},"C2 policy 4 (refine_gpu_snapshot) gate arm B (candidate, refine_gpu_snapshot = true): Lego 12.5k full run repeat 2\u002F3",[5,17,370,371,23],36.20277786254883,406688,"\u002Fruns\u002Frnd-12500-on-r2\u002F",{"id":47,"title":47,"subtitle":403,"date":9,"workspace":368,"tags":404,"verdict":372,"psnr":405,"psnr_unit":-1,"wallclock":381,"splats":406,"summary_url":407,"detail_path":407},"C2 policy 4 (refine_gpu_snapshot) gate arm B (candidate, refine_gpu_snapshot = true): Lego 12.5k full run repeat 3\u002F3",[5,17,370,371,23],36.198814392089844,409949,"\u002Fruns\u002Frnd-12500-on-r3\u002F",{"id":40,"title":40,"subtitle":409,"date":410,"workspace":368,"tags":411,"verdict":372,"psnr":413,"psnr_unit":-1,"wallclock":414,"splats":415,"summary_url":416,"detail_path":416},"C2 施策 #4 smoke: refine_gpu_snapshot=true、crash なし + BackendConfig line 確認 (wallclock 判定はしない — 1k regime では refine tick 数・splat 数が gate 規模に遠く及ばない)","2026-08-16",[5,17,412],"smoke",19.55087661743164,"3.77s",6816,"\u002Fruns\u002Frefine-nondrain-smoke-1000-gpu-snapshot\u002F",{"id":41,"title":41,"subtitle":409,"date":410,"workspace":368,"tags":418,"verdict":372,"psnr":419,"psnr_unit":-1,"wallclock":420,"splats":421,"summary_url":422,"detail_path":422},[5,17,412],19.548084259033203,"4.25s",6948,"\u002Fruns\u002Frefine-nondrain-smoke-1000-off\u002F",[424,448,470,489,507],{"id":51,"title":425,"date":9,"status":10,"polarity":426,"category":427,"axes":428,"tags":429,"task_code":439,"related_runs":440,"delta_psnr":442,"delta_wallclock":443,"rank":444,"verdict":445,"impact_summary":446,"detail_path":447},"C2 実測 — 残差 bubble は host-late 支配 (7.2〜8.1s)、refine tick drain は A7 で半減済み (3.0〜3.8s)。handoff は定常帯で headroom ほぼ無し","mixed","measurement",[14,15],[17,430,431,432,433,434,435,436,437,23,438],"gap-report","cb-gap","host-lead","drvproc","handoff","residual-bubble","refine-drain","post-m4-a7","measurement-only","C2: 12.5k の残差 bubble 帰属計測と分析",[441],"c2-12500-depth2-prof","n=1 self-eval: 36.068 dB (100 views)。C2 は測定目的の run で PSNR gate 対象ではないが、p3-final-stack の n=3 mean (36.219 dB) からの乖離は n=1 ノイズ帯として妥当な範囲","train elapsed 124.75s (n=1)。p3-final-stack n=3 mean 124.393s (σ0.756%) の guard 内 — profile=true + gap report 計装のオーバーヘッドは計測可能な歪みを生んでいない、と読める","high","residual-is-host-late-dominated \u002F handoff-headroom-thin \u002F refine-drain-already-halved-by-a7","`p3-kernel-share-post-s3.toml` §4\u002F§8 の宿題 (「残差は既存計装では分解不能、実装後も 12.5k 実測がまだ無い」) を、`2026-08-30-c2-12500-depth2-prof.toml` (M4+A7 default 込み、S3 gate arm B と [backend] bit-exact) の 1 run で埋めた。\u003Cstrong>reliable=true \u002F dropped=0 \u002F kernel_invalid=0 \u002F sum\u002Funion=1.000000x\u003C\u002Fstrong> — 信頼性ゲート健全、全列使用可。wall 124.75s \u002F busy 113.627s (91.1%) \u002F sync-tax 11.126〜11.129s は `p3-final-stack` の n=3 mean (124.393s, σ0.756%) の guard 内 (n=1 の点推定として妥当)。\u003Cstrong>Σcb_gap=11.085s が sync-tax 全量の 99.6% を説明\u003C\u002Fstrong>し、`p50×n` (band 別合計 7.244s) と `mean×n` (11.081s) の差 3.837s を refine tick 由来の外れ値と読むと、\u003Cstrong>残差 (通常境界) 7.2〜8.1s (5.8〜6.5%) \u002F refine tick drain 3.0〜3.8s (2.4〜3.1%)\u003C\u002Fstrong> にブラケットできる。refine 側は `ts_refine`(2.869s)+`ts_opacity_decay`(0.185s)=3.054s の独立 host 実測が下限とほぼ一致し、クロスチェックが成立した。\u003Cstrong>旧 3 分解 (refine 6.26s \u002F encode(B) 3.41s \u002F 残差 4.54s、旧 sync-tax 全量 14.206s) との整合\u003C\u002Fstrong>: 旧「残差」+「encode(B)」= 4.54+3.41=7.95s ≈ 新「通常境界」7.24s (wall が 151.70→124.75s に縮んだ分を割り引けば近い) — \u003Cstrong>旧 encode(B) バケツは独立した加算成分ではなく、非重複だった encode コストが host-late として `cb_gap` に同じ形で現れていた\u003C\u002Fstrong>と判明し、旧 3 分解を「refine drain \u002F それ以外 (通常境界)」の 2 分解へ訂正する形になった。\u003Cstrong>帰属の結論: 通常境界の bubble は host-late が支配的、driver 処理 (`drvproc`) と GPU キュー待ち (`handoff`) は定常帯で中央値がほぼゼロ (headroom 薄い)\u003C\u002Fstrong> — task が例示した「handoff → CB 統合」は主因ではないと実測が明示的に否定した。","\u002Ffindings\u002Fp3-c2-bubble-attribution\u002F",{"id":53,"title":449,"date":9,"status":10,"polarity":450,"category":11,"axes":451,"tags":452,"task_code":460,"related_runs":461,"delta_psnr":464,"delta_wallclock":465,"rank":466,"verdict":467,"impact_summary":468,"detail_path":469},"A7 refine 3-pass 削減 — 採用確定 (2026-08-30 gate)","positive",[14,15],[53,453,18,454,455,456,22,23,457,458,459],"a7","scratch-persist","direct-write","alloc-churn","gate-adopted","default-flip","contaminated-series","docs\u002Fstrategy\u002F2026-08-next-phase-tasklist.md Tier2 A7 (refine の 3-pass 削減)",[462,463],"splat\u002Fruns-logs\u002Fa7-12500-*.log (1回目 series、棄却・保存)","splat\u002Fruns-logs\u002Fa7v2-12500-*.log (2回目 series、採用根拠)","+0.0197 dB (12.5k n=3、guard 内。書き込みロジック自体は不変なので理論上の期待通りノイズレベル)","**-2.149%** (12.5k n=3、閾値 max(2σ_off,1%)=1.612%、3\u002F3 pair 一貫)。tasklist 期待帯 -1.3〜-2.6% にちょうど収まる","mid","adopted","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)。","\u002Ffindings\u002Fp3-refine-3pass\u002F",{"id":54,"title":471,"date":9,"status":10,"polarity":12,"category":11,"axes":472,"tags":473,"task_code":479,"related_runs":480,"delta_psnr":484,"delta_wallclock":485,"rank":58,"verdict":486,"impact_summary":487,"detail_path":488},"refine.every 100→200 — 不採用 (PSNR guard 大幅超過、2026-08-30 gate)",[14,15],[54,474,18,475,476,477,23,24,478],"re200","hyperparameter","psnr-guard-fail","densification-coupling","contaminated-pair-retry","docs\u002Ffindings\u002Fp3-c2-bubble-attribution.toml §6 施策 #5 (refine.every 100→200)",[481,482,483],"splat\u002Fruns-logs\u002Fre200-12500-*.log (メイン series)","splat\u002Fruns-logs\u002Fre200-12500-*-retry.log (r2 pair retry)","splat\u002Fruns-logs\u002Fre200-12500-loadsamples.log \u002F re200-12500-retry-loadsamples.log","**-0.421 dB** (12.5k n=3、guard `on mean >= off mean - 0.05dB` を約 8.4 倍超過 — 不通過)。3\u002F3 pair で一貫して on &lt; off (-0.361 \u002F -0.544 \u002F -0.397 dB)","**-25.6%** (12.5k n=3、off mean 126.497s [off-r2 は load 汚染が retry 後も残存、参考値] → on mean 94.063s [on-r2 は retry で clean 値に置換]) — off の clean 2 値のみ (off-r1\u002Fr3 平均 124.92s) を使うと Δ **-24.7%**、いずれにせよ §6 施策 #5 が想定した drain 削減の期待帯 (-1.2〜-1.5%) を遥かに超える。分解すると drain 削減自体はほぼ的中 (sync_iters 121→61 で ~-1.2〜-1.5% 相当) だが、残り約 -23〜24% は最終 splat 数 -35% による rasterize コスト減の副作用","rejected","refine tick 頻度を \u003Ccode>[refine] every\u003C\u002Fcode> 100→200 に変更する hyperparameter 実験 (非 bit-exact、学習 dynamics が変わる)。12.5k Lego n=3 交互 A\u002FB (off=every100 baseline \u002F on=every200 candidate、他の refine パラメータ (\u003Ccode>stop_iter\u003C\u002Fcode> 等) は不変) で、PSNR guard (n=3 で on mean &gt;= off mean - 0.05dB) と最終 splat 数の変化を主眼に計測した。\u003Cstrong>PSNR Δ -0.421dB で guard を約 8.4 倍超過 — 不採用\u003C\u002Fstrong>。wallclock は Δ -25.6% と大幅短縮したが、tick drain 半減 (sync_iters 121→61、期待帯 -1.2〜-1.5% 相当) は寄与のごく一部に過ぎず、大半は densification 予算削減による最終 splat 数 -35% (407.7k→266.7k) の副作用。\u003Ccode>refine.every\u003C\u002Fcode> は tick drain の独立ノブではなく、growth\u002Fclone\u002Fsplit イベント頻度と opacity decay 累積量 (`opacity_decay_rate` は refine cadence で適用) を同時に変える hyperparameter であることが判明した。r2 pair は事前登録条件 (load spike AND 3σ超) を満たし 1 回 retry したが、PSNR guard の判定には影響しない (PSNR は決定論的、load は wallclock のみに影響)。\u003Cstrong>default config の書き換えはしない — 採否はユーザー判断待ち\u003C\u002Fstrong>。","\u002Ffindings\u002Fp3-refine-every-200\u002F",{"id":52,"title":490,"date":9,"status":10,"polarity":12,"category":11,"axes":491,"tags":492,"task_code":498,"related_runs":499,"delta_psnr":503,"delta_wallclock":504,"rank":58,"verdict":486,"impact_summary":505,"detail_path":506},"S4 — post-backward accumulate を backward CB shadow に配置する host_schedule flag — 棄却確定 (2026-08-30 gate)",[14,15],[493,17,494,495,496,497,24,478],"s4","host-schedule","pipelining","depth2","refine-accumulate","S4: C2 施策 #1 (post-backward host 仕事の backward shadow 配置) 実装 + gate",[500,501,502],"splat\u002Fruns-logs\u002Fs4-12500-*.log (n=3 主系列、r1 pair は汚染で破棄・保存)","splat\u002Fruns-logs\u002Fs4-12500-retry4-*.log (r1 pair retry、r4 として採用)","splat\u002Fruns-logs\u002Fs4-12500-predecision.log (事前登録判定規則)","+0.027 dB (guard 内、ただし wallclock 不通過のため判定は変わらない)","**逆符号 (on が遅い) — どの扱いでも正符号、代表値は使わないこと**。採用条件 Δ ≤ -1% に対し: r1→r4 置換 n=3 で **+5.63%** (on-r4 の大外れ値 141.77s が支配)、on-r4 を外れ値として除外した n=2 相当で **+1.8%**、r1 込み (retry 前) n=3 で **+1.02%**。σ_on 6.36% という広い散らばりに対し +5.63% は解像できる効果量ではなく、**真の効果量は ~1〜2% (harness 分解能付近) で null〜わずかな悪化、`p3-tier1-bit-exact` v1→v2 と同種の『単一外れ値が代表値を膨らませる』パターン**とみるのが妥当。どの扱いでも符号は一貫して不通過 (on≥off) なので棄却の結論自体は変わらない","C2 施策 #1 (post-backward host 仕事を backward CB shadow に配置) を `[backend] host_schedule` flag として実装し、12.5k n=3 交互 A\u002FB gate を実施した。**棄却 — ただしどの尺度で見ても符号は on≥off で一貫**: 採用セット (r1→r4 置換) の点推定は +5.63% だが、これは on-r4=141.77s という単一の大外れ値に支配された数字であり (on-r4 を除くと +1.8%、r1 込みの retry 前でも +1.02%)、σ_on 6.36% の広さを踏まえると真の効果量は ~1〜2% (harness 分解能付近) で null〜わずかな悪化とみるのが妥当 (`p3-tier1-bit-exact` v1 が経験した「単一の汚染値が代表値を膨らませる」パターンの符号違い版)。r1 pair は series 独立 load sampler で load1 max 7.91\u002F8.90 (LOAD_LIMIT 6.0 超) を検知し事前登録条件 (i)(ii) を満たしたため 1 回だけ retry (r4) に置換 — ただし (i) の判定は max ベースで行っており、mean ベースでは off-r1 (mean 2.72) は 1.5×中央値 (3.765) 未満で非該当になる (次回の predecision には mean\u002Fmax のどちらで評価するか明記すべき教訓、§8 参照)。retry 後の on-r4 (141.77s) はさらに大きな外れ値だが、走行中 load1 は終始 clean (mean 1.64 \u002F max 3.19) — 事前登録条件 (i) load 証拠が不成立のため追加 retry はせず (`p3-tier1-bit-exact` §5 の教訓通り、条件 (ii) 単独での retry 連鎖を回避)。discarded r1 pair 自体は on\u003Coff (on が速かった) — 「3\u002F3 一貫」は採用セットに限った話で、破棄分含む 4 pair 全体では 3\u002F4 が on>off。ms\u002Fiter trace は on-r4 で iter 2000 以降一貫して高い (discrete spike ではなく持続的) — A7 §7 off-r3 と同型の GPU thermal 蓄積の可能性はあるが host_schedule 由来と特定する根拠はない。全 pair とも off→on の順で実行 (ABAB、ABBA 均衡化なし) — on arm は常に「温まった後」の機体条件で走っており、末尾の on-r4 が最遅であることと整合するが、同構造の A7 gate では on 側が一貫して速かったこともあり主要因とは考えにくい。棄却により `.rs` は一切変更していない。","\u002Ffindings\u002Fp3-s4-host-shadow\u002F",{"id":55,"title":508,"date":509,"status":10,"polarity":450,"category":11,"axes":510,"tags":511,"task_code":521,"related_runs":522,"delta_psnr":533,"delta_wallclock":534,"rank":444,"verdict":535,"impact_summary":536,"detail_path":537},"S3 iteration pipelining depth 2 — 12.5k -18.1% \u002F busy 78 → 91% (default flip)","2026-08-17",[14,15],[512,513,514,515,516,517,518,519,23,520],"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)",[523,524,525,526,527,528,529,530,531,532],"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 の効果を過小評価する)","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",1790227327660]