7.9 KiB
7.9 KiB
Review: Paused→Run の interrupt 前処理を Pod 内部に閉じる
対象コミット: 62af74c update: Paused→Run の interrupt 前処理を Pod::run に内包
前提・要件の確認
PendingRun::InterruptAndRun(input)バリアントを削除しPendingRun::Run(input)一本に統合する: 達成。crates/pod/src/controller.rs:97のPendingRun定義からInterruptAndRunが削除され、is_parent_originated(crates/pod/src/controller.rs:109) とpending_run_parent_origin_tableテスト (crates/pod/src/controller.rs:940-944) もそれに合わせて整理されている。controller_loopのMethod::Runハンドリングは status を見ずにPendingRun::Run(input)を stage するだけにする: 達成。crates/pod/src/controller.rs:584-611でstatus_beforeバインドが削除され、shared_state.get_status() == PodStatus::Runningの防御チェックは残しつつ、Paused 判定の分岐は完全に消えている。- interrupt 前処理は
Pod::run入口でself.worker().last_run_interrupted()を見て自発的に行う: 達成。crates/pod/src/pod.rs:1155-1157でworker.last_run_interrupted()をゲートとしてapply_interrupt_prepを呼んでいる。前処理本体はcrates/pod/src/pod.rs:1422-1442。 Pod::interrupt_and_runは削除し、orphan_tool_result_closures等をPod::runの前段として再配置: 達成。crates/pod/src/interrupt_and_run.rsがcrates/pod/src/interrupt_prep.rsにリネームされ、pub(crate)の純関数orphan_tool_result_closuresのみを公開する形に縮退。Pod::run側 (apply_interrupt_prep) が直接これを呼ぶ。lib.rs:14のモジュール宣言もinterrupt_prepに更新。Method::Resume(PendingRun::Resume)の経路には影響させない: 達成。Pod::resume(crates/pod/src/pod.rs:1542-1554) はapply_interrupt_prepを呼ばないため、Resume 経路から interrupt 前処理は発火しない。do_compact_and_resumeの再帰 (crates/pod/src/pod.rs:1687) もresume()側に閉じている。run_for_notificationも無関係: 確認済み。crates/pod/src/pod.rs:1528-1539はprepare_for_run→worker.resume()の経路でPod::runを経由しないため、Notify 経路にも前処理は混入しない。- 動作上の変化はゼロ(リファクタ): 達成。
- 前処理の中身(
orphan_tool_result_closuresのロジック、extend_historyでの closures push、push_itemでの system_note push)はバイト単位で一致。 - 順序も維持: 旧
interrupt_and_runではvalidate → extend(closures) → push(note) → self.run(input)で、run内部でprepare_for_run → commit_entry(UserInput)が走る。新Pod::runではvalidate → apply_interrupt_prep → prepare_for_run → commit_entry(UserInput)と同じ並び。 - 旧コードに残っていた
interrupt_and_run側の重複validate_workflow_invocationsは自然に解消(旧コメントが「duplicate call is cheap (read-only) and collapses naturally once interrupt_and_run folds into Pod::run」と予告していた通り)。
- 前処理の中身(
- 完了条件のテスト:
paused_then_run_closes_orphan_tool_use_for_next_request(crates/pod/tests/controller_test.rs:1312) が新経路でも従来通り orphan closure + system note + 新 user message を 2 nd LLM request に詰めることを検証しており、コメントもlast_run_interruptedベースに更新済み。interrupt_prepの純粋ロジック 4 テストもcargo test -p pod --lib interrupt_prepで全て pass。
アーキテクチャ・スコープ
- 「Controller が Pod 内部状態 (
PodStatus::Paused) を覗いて分岐していた責務漏れ」が解消されている。PendingRunenum が「parent originated か否か」「Run / Resume / RunForNotification」という Run の意味論だけを表すよう純化された。 interrupt_prep.rsはorphan_tool_result_closuresのみをpub(crate)で公開する単機能モジュール。Pod::apply_interrupt_prep自体はpod.rs側に置かれ、prompt catalog 引きと worker 操作という Pod 固有の責務をPodimpl に集約している。モジュール分割の粒度として妥当(インライン化するとpod.rsが膨らみ過ぎ、逆にinterrupt_prep側に押し込むと catalog アクセスを跨ぐ)。Pod::runの冒頭はvalidate → interrupt prep → prepare_for_run → commit UserInput → flatten → lock+runの素直なシーケンスになり、コメントも更新済み (crates/pod/src/pod.rs:1146-1157,1413-1419)。- llm-worker 層には触っていない。
last_run_interruptedは既存 API のまま読み取りに使われており、層境界を歪めていない。 - 範囲外 (
is_parent_originatedの表現変更、last_run_interruptedセマンティクス変更、TUI 側議論) は変更していない。
LLM コンテキスト加工原則
- orphan tool_result closure と interrupt system note は
extend_history/push_itemでworker.historyに append されており、context-only な差し込みではない。CLAUDE.md の「許される変換 vs 禁止される非再現的差し込み」の禁止側には該当しない。 - 注意: これらは旧
interrupt_and_runと同じくextend_history(callback なし) とpush_itemを使うため、Worker::on_history_append経由のLogEntry::ToolResult/LogEntry::SystemItemへの即時 commit は走らない。persist_turnのフォールバック側でもhistory_beforeの手前に置かれているため拾われない。結果として「worker history (in-memory) には載るが session-log には独立エントリとして残らない」状態であり、これは本コミット以前から同じ振る舞いで、本ティケットの「動作上の変化はゼロ」要件を満たしている。session-log 永続化のセマンティクスは別のチケットで扱うべき独立した論点。
指摘事項
Blocking
- なし。
Non-blocking / Follow-up
- interrupt prep 由来の history append が session-log に独立エントリとして残らない問題: 旧実装からの引き継ぎで、本チケットでは正しく不変。ただし「Notify / PodEvent /
<system-reminder>系は history に append して commit する」という CLAUDE.md の原則と整合させるかは将来のチケット (notify-history-persist系の流儀に合わせる) として検討する余地がある。本ティケットの責務外。 controller_test.rs::double_run_returns_errorの flakiness: 5 回中 1 回程度 fail する timing-sensitive テスト。本コミットの変更とは独立で、Method::Runブランチの構造変更はstatus_beforeバインドの除去のみで意味的影響なし(PodStatus::Runningでの AlreadyRunning 防御も維持)。旧コミットでも同等の race window が存在していた。観測のため記録のみ。
Nits
crates/pod/src/interrupt_prep.rs:14-16のuse順がcargo fmt既定と不一致(crate::をllm_worker::より先に置くのが rustfmt 既定)。cargo fmt -p pod --checkが当該箇所で diff を出す。本コミットで新規導入された唯一のフォーマット差分。fmt -p podをかければ閉じる。- なお
pod.rs/notify_buffer.rsの})?;改行もfmt --checkで diff になるが、これらは62af74c^(d076258) 時点で既に存在する別件で、本コミットの責任範囲ではない。
- なお
判断
Approve with follow-up — 要件は全て満たされ、コードベースの責務分離もきれいに整った。動作変更ゼロのリファクタとして十分。interrupt_prep.rs の use 順だけ気が向いたら cargo fmt を当てておく程度の nit が残るのみで、ブロッキングは無い。