Deux garde-fous qui ferment des trous identifiés lors du test de replay
chirurgical du 11 avril 2026 sur sess_20260411T084629_2d588e.
## B — Garde qualité en sortie de cascade (_validate_resolution_quality)
Couche de validation ajoutée en sortie du handler /resolve_target, après
que la cascade (_resolve_target_sync) a produit son meilleur candidat.
Single point of insertion, n'altère pas la cascade existante.
Deux checks :
1. Seuil de score minimum par méthode (_RESOLUTION_MIN_SCORES)
- hybrid_text_direct ≥ 0.80
- som_anchor_match / som_text_match ≥ 0.75
- template_matching ≥ 0.85
- vlm_* / grounding ≥ 0.60
- memory_* : pas de seuil (confiance cristallisée)
- v4_uia_local / uia ≥ 0.90
2. Garde de proximité contre coords enregistrées
Si fallback_x/y_pct sont significatifs (pas placeholder 0.5/0.5 ni
0.0/0.0), rejette si drift > 20% de l'écran dans un axe.
Reproduit un faux positif vu en production : SoM a trouvé
"Enregistrer" à (0.505, 0.770) alors que l'enregistrement était à
(0.093, 0.356) — écart de 0.41.
Quand un check rejette : retourne resolved=False avec method=
"rejected_low_score_*" ou "rejected_drift_*" et reason détaillée.
L'action passe alors par le chemin "visual_resolve_failed" côté agent
→ Policy → pause supervisée ou retry selon contexte.
7 tests unitaires inline validés (score bas, drift, mémoire qui passe
toujours, placeholders V4 qui skip la garde drift, etc.).
## C — no_screen_change devient un échec strict en mode strict
Avant : si un clic retourne warning='no_screen_change' (écran inchangé
après action), le replay loggait un warning et CONTINUAIT à l'action
suivante. Trop indulgent pour les workflows critiques.
Maintenant : la branche no_screen_change consulte le flag
success_strict de l'action courante.
- success_strict=True : traité comme vrai échec
→ retry si retry_count < MAX_RETRIES_PER_ACTION
→ stop définitif sinon (status=error, queue vidée, callback)
- success_strict=False (legacy) : comportement inchangé, on continue
Prérequis : _create_replay_state copie maintenant success_strict,
expected_window_before, expected_window_title, intention dans la
version slim de actions stockée dans replay_state. Nécessaire pour
lire le flag depuis current_action_index dans /replay/result.
## Tests
- 7 tests unitaires inline sur _validate_resolution_quality
- 56 tests E2E + Phase0 passent, zéro régression
- Instrumentation [REPLAY] reste pleinement fonctionnelle
## Limites non traitées ici (explicites)
- La latence de 14s entre deux clics (pre-analyze + cascade + agent
polling) reste inchangée. Les menus déroulants Windows peuvent encore
se refermer avant le 2ème clic. Piste A du plan, à traiter séparément.
- L'intégration d'OS-Atlas-Base-7B comme grounder spécialisé reste
dans les cartons (recommandation du rapport état de l'art).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>