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

3.9 KiB
Raw Blame History

Paused→Run の interrupt 前処理を Pod 内部に閉じる

背景

controller_loopMethod::Run { input } を受けたとき、Pod の status を見て次のように 2 分岐している (crates/pod/src/controller.rs:629):

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_runcrates/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_loopMethod::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::ResumePendingRun::Resumeの経路には影響させない。Resume は前 turn の context を生かして続行する別経路で、interrupt 前処理を入れてはいけない。
  • 動作上の変化はゼロリファクタ。Paused 中に Method::Run { input } が来たときの挙動は今と完全に同じであること。

完了条件

  • PendingRunRun(Vec<Segment>) / RunForNotification / Resume の 3 variant のみ。
  • controller_loopMethod::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 議論。

Review