Automação de Desktop Governada
adk-computer-use é uma camada de governança sobre o servidor de automação de desktop computer-use-mcp. Ele não executa nenhuma atuação por si só: ele organiza observação, aprovação, mutação e verificação como um grafo determinístico, e verifica o que o runtime externo retorna.
Vinculação da resposta
O runtime externo é a autoridade, mas suas respostas são verificadas localmente antes de entrarem no estado do grafo. As verificações são executadas no grafo de referência para toda implementação de ComputerUseRuntime, e o adaptador MCP as repete em seu limite de chamada direta. A desserialização tipada prova a forma, não a procedência — ControlLease, TargetReservation e ExecutionReceipt não têm construtor que imponha invariantes, então um objeto bem formado pertencente a uma sessão diferente é analisado sem problemas.
Cada resposta é vinculada de volta à solicitação que a produziu:
| Resposta | Verificado em relação ao envelope |
|---|---|
ControlLease | session_id, principal_id, agent_id, execution_mode, estado ativo, não expirado expires_at, orçamento restante (actions_used < action_budget) e alvo dentro de boundaries |
TargetReservation | session_id, principal_id, agent_id, execution_group_id, intent_id == action_id, estado ativo, expires_at não expirado e escopo exato do alvo do app/janela |
ExecutionReceipt | session_id, action_id e action_digest em relação ao args_digest do envelope |
Uma incompatibilidade produz ComputerUseError::IdentityMismatch nomeando o campo, e a resposta é
rejeitada em vez de armazenada.
use adk_computer_use::runtime::binding::validate_lease;
// Refuses a lease that is well-formed but belongs to another session.
validate_lease(&lease, &envelope)?;
Nota: o digest é o vínculo mais forte disponível.
args_digesté o que recebeu a aprovação, portanto um recibo que carregue um digest diferente descreve um trabalho diferente, mesmo quando todos os identificadores coincidem.
Um campo opcional que retorna ausente é tratado como subespecificação, não como contradição; um campo que está presente e é diferente é uma incompatibilidade.
Revalidação em tempo de execução
A prévia não é autoridade de mutação. O grafo de referência revalida todas as entradas de mutação no
nó execute imediatamente antes de chamar execute_action:
| Entrada | Verificação imediata |
|---|---|
ActionEnvelope | timestamps RFC 3339, janela de validade positiva e now < expires_at |
ControlLease | identidade, modo, estado ativo, orçamento restante, expiração e limites de destino |
TargetReservation | identidade, intenção de ação, estado ativo, expiração e escopo exato do alvo |
| Aprovação | rota, resumo da ação, resumo da política e exatamente uma fonte de autoridade (grantId ou aprovação mantida em tempo de execução) |
A verificação do envelope também é executada quando a pré-visualização retorna, então uma pré-visualização já expirada nunca chega à reserva ou à aprovação. Ela é executada novamente na execução porque uma interrupção de aprovação, reserva do alvo ou aquisição de lease pode consumir a janela de validade restante.
ComputerUseMcpRuntime preserva exatamente o envelope retornado por preview_action. Uma chamada direta a
execute_action é rejeitada se qualquer campo do envelope mudar após a pré-visualização, mesmo quando o
ID da ação ainda corresponde.
Para retomada de checkpoint, o grafo armazena a pré-visualização de tempo de execução em um canal de estado apenas de acréscimo. A aprovação e a execução exigem que esse canal contenha exatamente uma pré-visualização correspondendo à pré-visualização ativa. A entrada de retomada pode adicionar estado, mas não pode substituir o valor checkpointado: uma tentativa de substituição cria uma segunda entrada e falha antes da reserva ou mutação.
Limpeza da reserva
Uma vez que uma reserva é aceita, todo caminho terminal tenta liberá-la:
- falhas na aquisição de lease, autorização, validação, execução, recebimento e verificação;
- verificação bem-sucedida; e
- falhas de validação da reserva ou de serialização quando o tempo de execução retornou uma reserva.
A falha principal continua sendo a principal quando a limpeza tem sucesso. Se a limpeza também falhar, o grafo retorna um erro determinístico contendo ambas as falhas. Uma falha de limpeza após uma verificação bem-sucedida é retornada como erro em vez de ser ocultada.
Verificação não é compromisso
ComputerUseRuntime::verify retorna um VerificationOutcome, não um booleano:
| Resultado | Significado | is_verified() | is_committed() | status() |
|---|---|---|---|---|
Verified | A pós-condição declarada foi observada como satisfeita | true | true | completed |
CommittedUnverified | A execução realizou a ação; nenhuma evidência de pós-condição | false | true | committed_unverified |
Failed | Não confirmado, ou a evidência contradiz a pós-condição | false | false | verification_failed |
O nó verify do grafo escreve verified, committed e um result.verificationDetail
explicando qualquer coisa aquém de Verified.
Importante: um recibo confirmado é um reconhecimento de que a ação foi aceita e executada. Ele não é evidência de que o efeito pretendido ocorreu.
verifyretornava anteriormentereceipt.status == Committed, que reportava uma ação confirmada, mas ineficaz como concluída — a partir de um nó rotulado como "verify".
O que conta como evidência
Para uma pós-condição que declara um digest (valueDigest, contentDigest), a verificação exige
um verification.observedDigest no resultado do recibo que corresponda a ele. Para uma pós-condição
que declara apenas existência, é necessário um verification.satisfied: true explícito.
| Evidência de recebimento | Resultado |
|---|---|
verification.satisfied: false | Failed — uma observação negativa explícita |
observedDigest corresponde ao digest esperado | Verified |
observedDigest difere | Failed |
Nenhum objeto verification | CommittedUnverified |
verification presente, sem observedDigest, digest esperado | CommittedUnverified |
A ausência de evidência nunca é tratada como evidência de sucesso. Se computer-use-mcp verifica antes de emitir um recibo, esse é o seu contrato; este adaptador não assume isso.
Limites de lease
Um lease é recusado, a menos que todas estas condições sejam atendidas:
| Verificação | Rejeitado quando |
|---|---|
| Expiração | expires_at está no passado, ou não pode ser analisado como RFC 3339 |
| Orçamento restante | actions_used >= action_budget |
| Limite de destino | o target.app_id do envelope está ausente de um boundaries.app_ids não vazio |
| Limite de janela | o target.window_id do envelope está ausente de um boundaries.window_ids não vazio |
Bordas vazias significam "não delimitado" e autorizam qualquer destino — a ausência de uma restrição não é uma restrição a nada.
Importante: a primeira versão deste validador verificava
action_budget == 0, que é o orçamento total, então um lease comaction_budget: 1, actions_used: 1passava enquanto autorizava nada. Ele também nunca liaexpires_atouboundaries, então tanto um lease expirado quanto um lease delimitado para uma aplicação diferente eram aceitos. Uma expiração que não pode ser analisada é rejeitada em vez de ignorada: um lease cuja validade não pode ser estabelecida não é válido.