# Review: pod-comm-tools 実装コミット前レビュー。`cargo build -p pod` clean、`cargo test -p pod --test pod_comm_tools_test` 8/8 pass。 ## 総評 チケット要件の中核(4 ツールの wire 動作、`SpawnedPodRegistry` の共有、scope 回収、stale reclaim トリガー)は達成。テスト構成もモックソケットで実 `pod` バイナリ非依存で速い。ただし以下のうち修正必須項目を解消してから完了にしたい。 ## 指摘と判断 ### 修正必須 #### 1. `SendToPod` が RUNNING 状態を検知しない(設計合意違反) **状況**: `connect_and_send` は `Method::Run` を書いて即切断し、応答 event を読まない。Controller は RUNNING 中の `Run` に対し `Event::Error { code: AlreadyRunning }` を返すが、tool 側はそれを見ないので LLM に「送信成功」と返る。 **設計合意**: pod-comm-tools 議論の結論は「A. SendToPod は `Method::Run` を使い、Pod が IDLE でなければエラーを返す」。 **判断**: 修正必要。書き込み後に short timeout で 1 event 読み、`Error { AlreadyRunning }` を検知したら `ToolError::ExecutionFailed` に変換する。正常時は `TurnStart` など先頭 event を見て「受け付けられた」ことを確認して戻る。 ### チケット文言と実装の整合 #### 2. Pod status (`running / idle / stopped`) の取得手段がない **状況**: チケットは `ReadPodOutput`/`ListPods` 出力に `running / idle / stopped` を含めることを求めているが、`Event::History` にはステータスが乗っておらず、実装は「接続可=alive / 接続不可=stopped」の 2 値のみ。 **判断**: 今回のスコープからは外す。`Greeting` または別 event に `PodStatus` を載せる改修は `Method::GetHistory` のレスポンス設計変更を伴うので、別チケット化する。本チケット文言を `alive / stopped` に揃えて実装と一致させる。 #### 3. `StopPod` は終了確認を待たない **状況**: チケット本文は「`Method::Shutdown` 送信 → 終了確認受信 → 切断」だが、実装は fire-and-forget。scope の明示 release と `scope_lock` 上の stale reclaim で整合性は担保されているので実害なし。 **判断**: チケット文言を「`Method::Shutdown` 送信(応答は待たない)」に修正。 ### 範囲外として明文化 #### 4. `spawned_pods.json` からの再起動復旧は未実装 **状況**: `spawned_pod_registry.rs` のモジュールコメントに「today only write-through is implemented」と明記されている。spawner プロセス再起動後、`ListPods` は空リストを返す。 **判断**: 今回のスコープ外。チケットの範囲外に「spawner 再起動時の `spawned_pods.json` からの復旧」を明記し、必要になったタイミングで別チケットを切る。 #### 5. `ReadPodOutput` cursor の非永続性 **状況**: `SpawnedPodRegistry::cursors` は `HashMap` でインメモリのみ。spawner 再起動後、カーソルは 0 にリセットされ、既読だった assistant text が再送される。モジュールコメントに「cursors intentionally do not persist」と明記されている。 **判断**: 現状のままで OK。設計判断としてレビューで合意し、チケットの「設計で決めること」の回答として本 review に残す。チケット側には残さない(gitで追える)。 ### 軽微 #### 6. `extract_assistant_text` のメッセージ境界 **状況**: 複数の assistant message を `\n` で連結するのみ。メッセージ境界が曖昧になる。 **判断**: `\n\n` に変更して境界を明確にする。修正コスト小。 #### 7. blocking `flock` を async から呼んでいる **状況**: `release_scope` / stale reclaim 経路で `LockFileGuard::open`(内部で `flock(2)`)を async fn から直接呼ぶ。通常は瞬時だが厳密には tokio runtime を一瞬止める。 **判断**: 既存コード全体が同じ慣習なので今回は踏襲。気になったら別タイミングで `spawn_blocking` 化を検討。本チケットでは対応しない。 #### 8. `SpawnedPodRegistry::new` が `Arc` を返す **状況**: コンストラクタが smart pointer を返す API は珍しい。 **判断**: consumer が全員 `Arc` で持つ設計なので許容。リファクタは不要。 ## 完了条件との対応 | 完了条件 | 状態 | |---|---| | SendToPod で spawned Pod にメッセージ送信・Pod が処理 | ✅(指摘 #1 の修正後) | | ReadPodOutput でカーソルベース差分取得 | ✅ | | StopPod で graceful 停止 + scope 返却 | ✅ | | ListPods で既知 Pod の状態一覧 + health check | ⚠️ `alive/stopped` のみ(指摘 #2) | | 接続不可 Pod は `stopped` 扱い + stale 回収トリガー | ✅ | | 各ツール正常系・異常系の単体テスト | ✅(8/8 pass) | ## 完了に向けた作業 1. 指摘 #1: `SendToPod` に応答確認を実装 2. 指摘 #2, #3: チケット本文の文言修正(`running/idle/stopped` → `alive/stopped`、Shutdown 応答待ちの記述削除) 3. 指摘 #4: チケットの「範囲外」に `spawned_pods.json` 復旧を追記 4. 指摘 #6: `extract_assistant_text` の区切りを `\n\n` に