yoi/tickets/pod-interrupt-prep-internalize.md

51 lines
3.7 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.

# Paused→Run の interrupt 前処理を Pod 内部に閉じる
## 背景
`controller_loop``Method::Run { input }` を受けたとき、Pod の status を見て次のように 2 分岐している (`crates/pod/src/controller.rs:629`):
```rust
pending = Some(if status_before == PodStatus::Paused {
PendingRun::InterruptAndRun(input)
} else {
PendingRun::Run(input)
});
```
そして `drive_turn` 側でも `pod.run(input)``pod.interrupt_and_run(input)` を呼び分けている。
`pod.interrupt_and_run``crates/pod/src/interrupt_and_run.rs`)の中身は:
1. worker history に残る orphan な `Item::ToolCall`(前 turn が中断されて対応する `ToolResult` が未発行)に synthetic `ToolResult` を被せるAnthropic 等の wire-validity 要件)
2. 「直前の作業は中断された」旨の system note を `worker` に push
3. 最後に `self.run(input)` に flow
つまり**入口の前処理が違うだけで、出口は通常の `pod.run` に合流する**。
しかもこの前処理が必要かどうかは、worker が一次情報として持っている `last_run_interrupted` フラグで判定できる(`pod.rs:1808` で既に使用済み)。`PodStatus::Paused` は controller がそれを観測したミラーに過ぎない。
結果として、Controller 層が Pod の内部状態を覗いて分岐するという責務漏れになっている。`PendingRun` enum は `Method::Run` 経由のものが 2 variant に分裂し、本来「parent originated か否か」など Run の意味論を扱うはずの enum に Pod 内部都合の分岐が混ざる。
## 要件
- `PendingRun::InterruptAndRun(input)` バリアントを削除し、`PendingRun::Run(input)` 一本に統合する。
- `controller_loop``Method::Run` ハンドリングは status を見ずに `PendingRun::Run(input)` を stage するだけにする。
- interrupt 前処理orphan tool_result の closure + system note 挿入)は `Pod::run` の入口で `self.worker().last_run_interrupted()` を見て自発的に行う。
- `Pod::interrupt_and_run` メソッドは削除する。`interrupt_and_run.rs` のロジック(`orphan_tool_result_closures` 等)は `Pod::run` の前段として `pod.rs` 側、または同モジュールから `Pod::run` が直接呼ぶ形に再配置する。
- `Method::Resume``PendingRun::Resume`の経路には影響させない。Resume は前 turn の context を生かして続行する別経路で、interrupt 前処理を入れてはいけない。
- 動作上の変化はゼロリファクタ。Paused 中に `Method::Run { input }` が来たときの挙動は今と完全に同じであること。
## 完了条件
- `PendingRun``Run(Vec<Segment>)` / `RunForNotification` / `Resume` の 3 variant のみ。
- `controller_loop``Method::Run` ブランチに `status_before == PodStatus::Paused` 分岐が残っていない。
- `Pod::run` を Paused 直後(`last_run_interrupted == true`の状態で呼ぶと、orphan `ToolCall` の closure と interrupt system note が history に積まれてから新規 input が処理される。これを既存の `interrupt_and_run` のテスト相当でカバーする。
- `Pod::run` を非 Paused 状態で呼ぶと従来通り interrupt 前処理は走らない。
- 既存の Paused 関連 E2E / 結合テストが全て通る。
## 範囲外
- `[[pod-parent-turn-callback]]``is_parent_originated` 判定ロジック自体の変更(本チケット完了後は `Run` / `Resume` の 2 variant が true になる形に自然に整理されるが、本チケットの目的ではない)。
- `worker.last_run_interrupted` のセマンティクス変更。
- TUI 側で Paused 中の送信を `Run` / `Resume` どちらにマップするかの UX 議論。