統制されたデスクトップ自動化

adk-computer-use は、computer-use-mcp デスクトップ自動化サーバーの上にあるガバナンス層です。これは自体としてはアクチュエーションを行わず、観測、承認、変更、検証を決定論的なグラフとして順序づけ、外部ランタイムが返すものを確認します。

応答のバインディング

外部ランタイムが権威ですが、その応答はグラフ状態に入る前にローカルで検査されます。これらの検査は、すべての ComputerUseRuntime 実装に対して参照グラフ内で実行され、MCP アダプターは直接呼び出し境界でもそれらを繰り返します。型付きデシリアライズは形状を証明しますが、由来は証明しません — ControlLeaseTargetReservation、および ExecutionReceipt には不変条件を強制するコンストラクタがないため、別のセッションに属する整形式のオブジェクトでも問題なく解析されます。

各応答は、それを生成したリクエストに結び付けられます:

応答エンベロープと照合
ControlLeasesession_id, principal_id, agent_id, execution_mode, active state, unexpired expires_at, remaining budget (actions_used < action_budget), and target within boundaries
TargetReservationsession_id, principal_id, agent_id, execution_group_id, intent_id == action_id, active state, unexpired expires_at, and exact app/window target scope
ExecutionReceiptsession_idaction_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 を呼び出す直前に再検証します:

入力即時チェック
ActionEnvelopeRFC 3339 タイムスタンプ、正の有効期間、および now < expires_at
ControlLeaseID、モード、有効状態、残り予算、有効期限、およびターゲット境界
TargetReservationID、アクション意図、アクティブ状態、有効期限、および正確な対象スコープ
承認ルート、アクションダイジェスト、ポリシーダイジェスト、およびちょうど1つの権限ソース(grantIdまたはランタイム保持の承認)

プレビューが戻るときにも封筒チェックが実行されるため、すでに期限切れのプレビューが予約や承認に到達することはありません。実行時にも再度実行されます。これは、承認インタラプト、対象予約、またはリース取得によって残りの有効期限が消費される可能性があるためです。

ComputerUseMcpRuntime は、preview_action によって返された正確な封筒を保持します。プレビュー後に封筒の任意のフィールドが変更された場合、アクション ID が一致していても、直接の execute_action 呼び出しは拒否されます。

チェックポイント再開では、グラフはランタイムのプレビューを追記専用の状態チャネルに保存します。承認と実行には、そのチャネルにアクティブなプレビューと完全に一致するプレビューがちょうど 1 つ含まれている必要があります。再開入力は状態を追加できますが、チェックポイント済みの値を置き換えることはできません。置き換えを試みると 2 つ目のエントリが作成され、予約や変更の前に失敗します。

予約のクリーンアップ

予約が受理されると、すべての終端経路でそれを解放しようとします。

  • リース取得、認可、検証、実行、受領、検証確認の失敗
  • 検証確認の成功
  • ランタイムが予約を返した場合の、予約検証またはシリアライズの失敗

クリーンアップが成功した場合、最初の失敗がそのまま最優先の失敗として残ります。クリーンアップも失敗した場合、グラフは両方の失敗を含む 1 つの決定論的なエラーを返します。ほかは成功して検証確認まで終わっていた後のクリーンアップ失敗も、隠されるのではなくエラーとして返されます。

検証はコミットではない

ComputerUseRuntime::verifyVerificationOutcome を返し、真偽値を返すわけではありません:

結果意味is_verified()is_committed()status()
Verified宣言された事後条件が成り立つことが確認されたtruetruecompleted
CommittedUnverified実行時にアクションは実行されたが、事後条件の証拠はないfalsetruecommitted_unverified
Failedコミットされていない、または証拠が事後条件と矛盾しているfalsefalseverification_failed

グラフの verify ノードは、verifiedcommitted、および result.verificationDetail を書き込み、Verified 未満の内容を説明します。

重要: コミット済みの受領は、そのアクションが受け入れられ、実行されたことの確認です。それは、意図した効果が発生した証拠ではありません。verify は以前、receipt.status == Committed を返していましたが、これはコミットされたものの無効なアクションを完了済みとして報告していました — "verify" とラベル付けされたノードから。

何が証拠に当たるか

ダイジェストを宣言する事後条件(valueDigestcontentDigest)では、検証にはそれに一致する受領結果上の verification.observedDigest が必要です。存在のみを宣言する事後条件では、明示的な verification.satisfied: true が必要です。

受領証拠結果
verification.satisfied: falseFailed — 明示的な否定の観測
observedDigest は期待されるダイジェストと一致するVerified
observedDigest が異なるFailed
No verification objectCommittedUnverified
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_atboundaries を一度も読み取らなかったため、期限切れのリースと別のアプリケーションにスコープされたリースの両方が受け入れられていました。解析できない有効期限は無視ではなく拒否されます。つまり、有効性を確認できないリースは有効ではありません。