統制されたデスクトップ自動化
adk-computer-use は、computer-use-mcp デスクトップ自動化サーバーの上にあるガバナンス層です。これは自体としてはアクチュエーションを行わず、観測、承認、変更、検証を決定論的なグラフとして順序づけ、外部ランタイムが返すものを確認します。
応答のバインディング
外部ランタイムが権威ですが、その応答はグラフ状態に入る前にローカルで検査されます。これらの検査は、すべての ComputerUseRuntime 実装に対して参照グラフ内で実行され、MCP アダプターは直接呼び出し境界でもそれらを繰り返します。型付きデシリアライズは形状を証明しますが、由来は証明しません — ControlLease、TargetReservation、および ExecutionReceipt には不変条件を強制するコンストラクタがないため、別のセッションに属する整形式のオブジェクトでも問題なく解析されます。
各応答は、それを生成したリクエストに結び付けられます:
| 応答 | エンベロープと照合 |
|---|---|
ControlLease | session_id, principal_id, agent_id, execution_mode, active state, unexpired expires_at, remaining budget (actions_used < action_budget), and target within boundaries |
TargetReservation | session_id, principal_id, agent_id, execution_group_id, intent_id == action_id, active state, unexpired expires_at, and exact app/window target scope |
ExecutionReceipt | session_id、action_id、およびaction_digestを、エンベロープのargs_digestに対して |
不一致があると、そのフィールド名を示す ComputerUseError::IdentityMismatch が発生し、レスポンスは保存されずに拒否されます。
use adk_computer_use::runtime::binding::validate_lease;
// Refuses a lease that is well-formed but belongs to another session.
validate_lease(&lease, &envelope)?;
注: digest は利用可能な中で最も強いバインディングです。
args_digestは承認が与えられた対象であるため、異なる digest を持つ receipt は、すべての識別子が一致していても別の作業を表します。
省略可能なフィールドが戻り値に含まれない場合は、矛盾ではなく仕様不足として扱われます。存在していて値が異なる場合は不一致です。
実行時の再検証
Preview は mutation の権限を持ちません。reference graph は、execute ノード内のすべての mutation 入力を、execute_action を呼び出す直前に再検証します:
| 入力 | 即時チェック |
|---|---|
ActionEnvelope | RFC 3339 タイムスタンプ、正の有効期間、および now < expires_at |
ControlLease | ID、モード、有効状態、残り予算、有効期限、およびターゲット境界 |
TargetReservation | ID、アクション意図、アクティブ状態、有効期限、および正確な対象スコープ |
| 承認 | ルート、アクションダイジェスト、ポリシーダイジェスト、およびちょうど1つの権限ソース(grantIdまたはランタイム保持の承認) |
プレビューが戻るときにも封筒チェックが実行されるため、すでに期限切れのプレビューが予約や承認に到達することはありません。実行時にも再度実行されます。これは、承認インタラプト、対象予約、またはリース取得によって残りの有効期限が消費される可能性があるためです。
ComputerUseMcpRuntime は、preview_action によって返された正確な封筒を保持します。プレビュー後に封筒の任意のフィールドが変更された場合、アクション ID が一致していても、直接の execute_action 呼び出しは拒否されます。
チェックポイント再開では、グラフはランタイムのプレビューを追記専用の状態チャネルに保存します。承認と実行には、そのチャネルにアクティブなプレビューと完全に一致するプレビューがちょうど 1 つ含まれている必要があります。再開入力は状態を追加できますが、チェックポイント済みの値を置き換えることはできません。置き換えを試みると 2 つ目のエントリが作成され、予約や変更の前に失敗します。
予約のクリーンアップ
予約が受理されると、すべての終端経路でそれを解放しようとします。
- リース取得、認可、検証、実行、受領、検証確認の失敗
- 検証確認の成功
- ランタイムが予約を返した場合の、予約検証またはシリアライズの失敗
クリーンアップが成功した場合、最初の失敗がそのまま最優先の失敗として残ります。クリーンアップも失敗した場合、グラフは両方の失敗を含む 1 つの決定論的なエラーを返します。ほかは成功して検証確認まで終わっていた後のクリーンアップ失敗も、隠されるのではなくエラーとして返されます。
検証はコミットではない
ComputerUseRuntime::verify は VerificationOutcome を返し、真偽値を返すわけではありません:
| 結果 | 意味 | is_verified() | is_committed() | status() |
|---|---|---|---|---|
Verified | 宣言された事後条件が成り立つことが確認された | true | true | completed |
CommittedUnverified | 実行時にアクションは実行されたが、事後条件の証拠はない | false | true | committed_unverified |
Failed | コミットされていない、または証拠が事後条件と矛盾している | false | false | verification_failed |
グラフの verify ノードは、verified、committed、および result.verificationDetail を書き込み、Verified 未満の内容を説明します。
重要: コミット済みの受領は、そのアクションが受け入れられ、実行されたことの確認です。それは、意図した効果が発生した証拠ではありません。
verifyは以前、receipt.status == Committedを返していましたが、これはコミットされたものの無効なアクションを完了済みとして報告していました — "verify" とラベル付けされたノードから。
何が証拠に当たるか
ダイジェストを宣言する事後条件(valueDigest、contentDigest)では、検証にはそれに一致する受領結果上の verification.observedDigest が必要です。存在のみを宣言する事後条件では、明示的な verification.satisfied: true が必要です。
| 受領証拠 | 結果 |
|---|---|
verification.satisfied: false | Failed — 明示的な否定の観測 |
observedDigest は期待されるダイジェストと一致する | Verified |
observedDigest が異なる | Failed |
No verification object | CommittedUnverified |
verification が存在し、observedDigest はなく、digest は期待される | CommittedUnverified |
証拠の不在は、成功の証拠として扱われることはありません。computer-use-mcpが領収書を発行する前に検証する場合、それはその契約であり、このアダプターはそれを前提にしません。
リース制限
以下のすべてが満たされない限り、リースは拒否されます:
| チェック | 拒否される条件 |
|---|---|
| 有効期限 | expires_at が過去である、または RFC 3339 として解析できない |
| 残り予算 | actions_used >= action_budget |
| 対象境界 | 封筒のtarget.app_idは、空でないboundaries.app_idsに存在しない |
| ウィンドウ境界 | 封筒のtarget.window_idは、空でないboundaries.window_idsに存在しない |
空の境界は「スコープされていない」ことを意味し、任意の対象を許可します。制約が存在しないことは、何も制約しないことを意味します。
重要: このバリデータの最初の版は
action_budget == 0をチェックしていましたが、これは 総 バジェットでした。そのため、action_budget: 1, actions_used: 1のリースは、何も許可していないにもかかわらず 通過していました。また、expires_atやboundariesを一度も読み取らなかったため、期限切れのリースと別のアプリケーションにスコープされたリースの両方が受け入れられていました。解析できない有効期限は無視ではなく拒否されます。つまり、有効性を確認できないリースは有効ではありません。