feat: garde qualité résolution (B) + no_screen_change strict (C)
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>
This commit is contained in:
@@ -1159,6 +1159,10 @@ def _create_replay_state(
|
||||
"""
|
||||
# Copie slim des actions : on strip les anchor_image_base64 pour ne
|
||||
# pas gonfler la mémoire (anchors peuvent faire 50-200 KB chacun).
|
||||
# On conserve les champs utilisés par :
|
||||
# - la Phase 1 apprentissage (target_spec pour memory_record_success)
|
||||
# - le contrôle strict (success_strict, expected_window_*)
|
||||
# - les logs/audit (intention, action_id, type, coords)
|
||||
actions_slim: List[Dict[str, Any]] = []
|
||||
if actions:
|
||||
for a in actions:
|
||||
@@ -1167,6 +1171,12 @@ def _create_replay_state(
|
||||
"type": a.get("type"),
|
||||
"x_pct": a.get("x_pct"),
|
||||
"y_pct": a.get("y_pct"),
|
||||
# Contrôle strict des étapes (Dom, matin 10 avril 2026)
|
||||
"success_strict": a.get("success_strict", False),
|
||||
"expected_window_before": a.get("expected_window_before", ""),
|
||||
"expected_window_title": a.get("expected_window_title", ""),
|
||||
# Contexte métier utile pour logs et apprentissage
|
||||
"intention": a.get("intention", ""),
|
||||
}
|
||||
ts = a.get("target_spec")
|
||||
if isinstance(ts, dict):
|
||||
|
||||
Reference in New Issue
Block a user