yoi/tickets/pod-comm-tools.review.md
2026-04-19 06:32:44 +09:00

86 lines
5.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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<String, usize>` でインメモリのみ。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<Self>` を返す
**状況**: コンストラクタが 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`