Automatisation de bureau gouvernée
adk-computer-use est une couche de gouvernance au-dessus du serveur d’automatisation de bureau computer-use-mcp. Elle n’effectue aucune action elle-même : elle ordonne l’observation, l’approbation, la mutation et la vérification sous forme de graphe déterministe, et vérifie ce que renvoie le runtime externe.
Liaison des réponses
Le runtime externe fait autorité, mais ses réponses sont vérifiées localement avant d’entrer dans l’état du graphe. Les vérifications s’exécutent dans le graphe de référence pour chaque implémentation ComputerUseRuntime, et l’adaptateur MCP les répète à sa frontière d’appel direct. La désérialisation typée prouve la forme, pas la provenance — ControlLease, TargetReservation et ExecutionReceipt n’ont pas de constructeur imposant des invariants, donc un objet bien formé appartenant à une autre session se parse correctement.
Chaque réponse est rattachée à la requête qui l’a produite :
| Réponse | Vérifié par rapport à l'enveloppe |
|---|---|
ControlLease | session_id, principal_id, agent_id, execution_mode, état actif, non expiré expires_at, budget restant (actions_used < action_budget), et cible dans boundaries |
TargetReservation | session_id, principal_id, agent_id, execution_group_id, intent_id == action_id, état actif, non expiré expires_at, et portée cible exacte de l'application/de la fenêtre |
ExecutionReceipt | session_id, action_id et action_digest par rapport à args_digest de l'enveloppe |
Une divergence produit ComputerUseError::IdentityMismatch en nommant le champ, et la réponse est rejetée plutôt que stockée.
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 : le digest est la liaison la plus forte disponible.
args_digestest ce qui a reçu l’approbation, donc un reçu portant un digest différent décrit un travail différent même lorsque tous les identifiants correspondent.
Un champ optionnel qui revient absent est traité comme une sous-spécification, et non comme une contradiction ; un champ qui est présent et différent constitue une divergence.
Révalidation au moment de l’exécution
L’aperçu n’est pas une autorité de mutation. Le graphe de référence révalide toutes les entrées de mutation dans le nœud execute juste avant d’appeler execute_action :
| Entrée | Vérification immédiate |
|---|---|
ActionEnvelope | horodatages RFC 3339, fenêtre de validité positive, et now < expires_at |
ControlLease | identité, mode, état actif, budget restant, expiration et limites cibles |
TargetReservation | identité, intention d’action, état actif, expiration et portée cible exacte |
| Approval | route, résumé d’action, résumé de politique et exactement une source d’autorité (grantId ou approbation détenue à l’exécution) |
La vérification de l’enveloppe s’exécute aussi au retour de l’aperçu, de sorte qu’un aperçu déjà expiré n’atteint jamais la réservation ni l’approbation. Elle s’exécute à nouveau lors de l’exécution, car une interruption d’approbation, une réservation de cible ou l’acquisition d’un bail peuvent consommer la fenêtre de validité restante.
ComputerUseMcpRuntime conserve l’enveloppe exacte renvoyée par preview_action. Un appel direct à
execute_action est rejeté si un champ de l’enveloppe change après l’aperçu, même lorsque l’ID
de l’action correspond toujours.
Pour la reprise à partir d’un point de contrôle, le graphe stocke l’aperçu d’exécution dans un canal d’état en ajout uniquement. L’approbation et l’exécution exigent que ce canal contienne exactement un aperçu correspondant à l’aperçu actif. L’entrée de reprise peut ajouter de l’état mais ne peut pas remplacer la valeur mise en point de contrôle : une tentative de remplacement crée une deuxième entrée et échoue avant la réservation ou la mutation.
Nettoyage de la réservation
Une fois une réservation acceptée, chaque chemin terminal tente de la libérer :
- échecs de l’acquisition de bail, de l’autorisation, de la validation, de l’exécution, du reçu et de la vérification ;
- vérification réussie ; et
- échecs de validation ou de sérialisation de la réservation lorsque le runtime a renvoyé une réservation.
L’échec principal reste principal lorsque le nettoyage réussit. Si le nettoyage échoue aussi, le graphe renvoie une erreur déterministe contenant les deux échecs. Un échec de nettoyage après une vérification par ailleurs réussie est renvoyé comme une erreur plutôt que masqué.
La vérification n’est pas l’engagement
ComputerUseRuntime::verify renvoie un VerificationOutcome, pas un booléen :
| Résultat | Signification | is_verified() | is_committed() | status() |
|---|---|---|---|---|
Verified | La postcondition déclarée a été observée comme satisfaite | true | true | completed |
CommittedUnverified | Le runtime a exécuté l’action ; aucune preuve de postcondition | false | true | committed_unverified |
Failed | Non validé, ou les preuves contredisent la postcondition | false | false | verification_failed |
Le nœud verify du graphe écrit verified, committed et un result.verificationDetail
expliquant tout ce qui est inférieur à Verified.
Important : un reçu engagé est une reconnaissance que l’action a été acceptée et exécutée. Ce n’est pas une preuve que l’effet attendu s’est produit.
verifyrenvoyait auparavantreceipt.status == Committed, qui signalait qu’une action engagée mais inefficace était terminée — à partir d’un nœud intitulé « verify ».
Ce qui compte comme preuve
Pour une postcondition déclarant un digest (valueDigest, contentDigest), la vérification nécessite
un verification.observedDigest sur le résultat du reçu qui correspond à celui-ci. Pour une postcondition
déclarant uniquement l’existence, une verification.satisfied: true explicite est requise.
| Preuve de réception | Résultat |
|---|---|
verification.satisfied: false | Failed — une observation négative explicite |
observedDigest correspond au digest attendu | Verified |
observedDigest diffère | Failed |
Aucun objet verification | CommittedUnverified |
verification présent, aucun observedDigest, digest attendu | CommittedUnverified |
L’absence de preuve n’est jamais considérée comme une preuve de succès. Si computer-use-mcp vérifie
avant d’émettre un reçu, c’est son contrat ; cet adaptateur ne le présume pas.
Limites du bail
Un bail est refusé sauf si toutes les conditions suivantes sont remplies :
| Vérification | Rejeté lorsque |
|---|---|
| Expiration | expires_at est dans le passé, ou ne peut pas être analysé comme RFC 3339 |
| Budget restant | actions_used >= action_budget |
| Limite de la cible | target.app_id de l'enveloppe est absent d'un boundaries.app_ids non vide |
| Limite de fenêtre | target.window_id de l'enveloppe est absent d'un boundaries.window_ids non vide |
Des bornes vides signifient « non délimité » et autorisent toute cible — l’absence de restriction n’est pas une restriction à rien.
Important : la première version de ce validateur vérifiait
action_budget == 0, qui est le budget total, donc un bail avecaction_budget: 1, actions_used: 1passait tout en n’autorisant rien. Elle ne lisait jamais non plusexpires_atniboundaries, de sorte qu’un bail expiré et un bail limité à une application différente étaient tous deux acceptés. Une expiration impossible à analyser est rejetée plutôt qu’ignorée : un bail dont la validité ne peut pas être établie n’est pas valide.