ブラウザEvaluate CDPリファクタリング計画

背景

act:evaluateはページ内でユーザー提供のJavaScriptを実行する。現在はPlaywright(page.evaluateまたはlocator.evaluate)経由で動作する。PlaywrightはCDPコマンドをページごとにシリアライズするため、スタックした長時間実行のevaluateがページコマンドキューをブロックし、そのタブの後続アクションがすべて「スタック」したように見える。

PR #13498は実用的なセーフティネット(制限付きevaluate、abort伝播、ベストエフォートリカバリ)を追加する。このドキュメントでは、act:evaluateをPlaywrightから本質的に分離し、スタックしたevaluateが通常のPlaywright操作を妨げないようにするより大規模なリファクタリングを説明する。

目標

  • act:evaluateが同一タブの後続ブラウザアクションを永久にブロックしない。
  • タイムアウトがエンドツーエンドで単一のソースオブトゥルースとなり、呼び出し側がバジェットに依存可能。
  • abortとタイムアウトがHTTPとインプロセスディスパッチの両方で同じように処理される。
  • evaluate用の要素ターゲティングが、すべてをPlaywrightから切り替えずにサポートされる。
  • 既存の呼び出し側とペイロードとの後方互換性を維持。

非目標

  • すべてのブラウザアクション(click、type、waitなど)をCDP実装に置き換えること。
  • PR #13498で導入された既存のセーフティネットを削除すること(有用なフォールバックとして残す)。
  • 既存のbrowser.evaluateEnabledゲート以上の新しい安全でない機能の導入。
  • evaluate用のプロセス分離(ワーカープロセス/スレッド)の追加。このリファクタリング後もリカバリ困難なスタック状態が発生する場合、それはフォローアップのアイデア。

提案アーキテクチャ

1. デッドライン伝播

単一のバジェット概念を導入し、すべてをそこから派生:

  • 呼び出し側がtimeoutMs(またはデッドライン)を設定。
  • 外側のリクエストタイムアウト、ルートハンドラーロジック、ページ内の実行バジェットがすべて同じバジェットを使用(シリアライズオーバーヘッド用の小さなヘッドルーム付き)。
  • abortはAbortSignalとしてどこにでも伝播され、キャンセルが一貫。

2. 分離Evaluateエンジン(CDPパス)

PlaywrightのページごとのコマンドキューをCDPベースのevaluate実装で共有しない。重要な特性は、evaluateトランスポートが別のWebSocket接続とターゲットにアタッチされた別のCDPセッションであること。

3. Refの仕組み(全面書き換えなしの要素ターゲティング)

困難な部分は要素ターゲティング。CDPにはDOMハンドルまたはbackendDOMNodeIdが必要だが、現在のほとんどのブラウザアクションはスナップショットからのrefに基づくPlaywrightロケーターを使用。

推奨アプローチ: 既存のrefを維持しつつ、オプションのCDP解決可能なIDを追加。

4. 最終手段のリカバリパスを維持

CDPベースのevaluateでも、タブや接続をウェッジする他の方法が存在する。既存のリカバリメカニズム(実行終了+Playwright切断)を最終手段として以下の場合に維持:

  • レガシー呼び出し側
  • CDPアタッチがブロックされる環境
  • 予期しないPlaywrightのエッジケース

テスト計画

  • ユニットテスト:
    • (role, name, nth)マッチングロジック(rolerefとAXツリーノード間)。
    • バジェットヘルパーの動作(ヘッドルーム、残り時間計算)。
  • インテグレーションテスト:
    • CDPのevaluateタイムアウトがバジェット内で返り、次のアクションをブロックしない。
    • abortがevaluateをキャンセルし、ベストエフォートで終了をトリガー。
  • コントラクトテスト:
    • BrowserActRequestBrowserActResponseの互換性を維持。

リスクと緩和策

  • マッピングが不完全:
    • 緩和策: ベストエフォートマッピング、Playwright evaluateへのフォールバック、デバッグツーリングの追加。
  • Runtime.terminateExecutionに副作用がある:
    • 緩和策: タイムアウト/abort時のみ使用し、エラー内の動作をドキュメント化。
  • 追加オーバーヘッド:
    • 緩和策: スナップショットがリクエストされた場合のみAXツリーを取得、ターゲットごとにキャッシュ、CDPセッションを短命に保つ。

未解決の問題

  • 新しいエンジンはplaywrightcdpautoで設定可能にすべきか?
  • 上級ユーザー向けに新しい「nodeRef」フォーマットを公開するか、refのみを維持するか?
  • フレームスナップショットとセレクタースコープスナップショットはAXマッピングにどう参加すべきか?