Governed Desktop Automation
adk-computer-use은 computer-use-mcp 데스크톱 자동화 서버 위에 있는 거버넌스 계층입니다. 이 계층 자체는 어떤 동작도 수행하지 않습니다. 대신 관찰, 승인, 변경, 검증을 결정적 그래프로 순서화하고, 외부 런타임이 반환하는 값을 검사합니다.
응답 바인딩
외부 런타임이 권위자이지만, 그 응답은 그래프 상태에 들어가기 전에 로컬에서 검사됩니다. 이러한 검사는 모든 ComputerUseRuntime 구현에 대한 기준 그래프에서 실행되며, MCP 어댑터는 직접 호출 경계에서 이를 반복합니다. 타입이 지정된 역직렬화는 형태만 증명할 뿐 출처는 증명하지 않습니다 — ControlLease, TargetReservation, 그리고 ExecutionReceipt에는 불변식을 강제하는 생성자가 없으므로, 다른 세션에 속한 올바른 형식의 객체도 문제 없이 파싱됩니다.
각 응답은 그것을 생성한 요청에 다시 바인딩됩니다:
| 응답 | envelope와 대조함 |
|---|---|
ControlLease | session_id, principal_id, agent_id, execution_mode, 활성 상태, 만료되지 않은 expires_at, 남은 예산(actions_used < action_budget), 그리고 boundaries 내의 대상 |
TargetReservation | session_id, principal_id, agent_id, execution_group_id, intent_id == action_id, 활성 상태, 만료되지 않은 expires_at, 그리고 정확한 앱/창 대상 범위 |
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)?;
Note: digest는 가장 강한 사용 가능한 결합입니다.
args_digest는 승인이 부여된 대상이므로, 모든 식별자가 일치하더라도 다른 digest를 담은 receipt는 다른 작업을 설명합니다.
선택적 필드가 누락된 채로 돌아오면 이는 모순이 아니라 세부 지정 부족으로 간주됩니다. 존재하면서 값이 다른 필드는 불일치입니다.
실행 시점 재검증
preview는 mutation 권한이 아닙니다. reference graph는 execute 노드에서 모든 mutation 입력을 execute_action를 호출하기 직전에 즉시 재검증합니다:
| 입력 | 즉시 확인 |
|---|---|
ActionEnvelope | RFC 3339 타임스탬프, 양의 유효 기간, 그리고 now < expires_at |
ControlLease | identity, mode, 활성 상태, 남은 예산, 만료, 그리고 대상 경계 |
TargetReservation | identity, action intent, active state, expiry, and exact target scope |
| 승인 | route, action digest, policy digest, and exactly one authority source (grantId or runtime-held approval) |
미리보기가 반환될 때도 봉투 검사가 실행되므로, 이미 만료된 미리보기는 예약이나 승인 단계까지 도달하지 않습니다. 승인 인터럽트, 대상 예약, 또는 리스 획득이 남은 유효 기간을 소모할 수 있으므로 실행 시에도 다시 실행됩니다.
ComputerUseMcpRuntime은 preview_action가 반환한 정확한 봉투를 유지합니다. 미리보기 이후 봉투의 어떤 필드라도 변경되면, 액션 ID가 여전히 일치하더라도 직접적인 execute_action 호출은 거부됩니다.
체크포인트 재개의 경우, 그래프는 런타임 미리보기를 append-only 상태 채널에 저장합니다. 승인과 실행은 해당 채널에 활성 미리보기와 정확히 일치하는 미리보기가 하나만 들어 있음을 요구합니다. 재개 입력은 상태를 추가할 수는 있지만 체크포인트된 값을 대체할 수는 없습니다. 대체를 시도하면 두 번째 항목이 생성되고, 예약 또는 변경 전에 실패합니다.
예약 정리
예약이 승인되면, 모든 종료 경로는 이를 해제하려고 시도합니다:
- 리스 획득, 승인, 검증, 실행, 수신, 검증 실패;
- 검증 성공; 그리고
- 런타임이 예약을 반환한 경우의 예약 검증 또는 직렬화 실패.
정리 작업이 성공하면 주된 실패가 그대로 주된 실패로 유지됩니다. 정리도 실패하면 그래프는 두 실패를 모두 포함하는 하나의 결정적 오류를 반환합니다. 그렇지 않게는 성공적이었던 검증 이후의 정리 실패는 숨겨지지 않고 오류로 반환됩니다.
검증은 약속이 아니다
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 객체 | 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를 전혀 읽지 않았기 때문에, 만료된 임대와 다른 애플리케이션에 범위가 지정된 임대가 모두 허용되었습니다. 구문 분석할 수 없는 만료 시점은 무시되지 않고 거부됩니다: 유효성을 확인할 수 없는 임대는 유효하지 않습니다.