From ad24d16d831206fa2aba6d7dc525c2541d53af7d Mon Sep 17 00:00:00 2001 From: Dom Date: Sun, 24 May 2026 20:24:46 +0200 Subject: [PATCH] =?UTF-8?q?fix(executor):=20P0.9=20double-check=20stabilit?= =?UTF-8?q?=C3=A9=20post-transition=20fen=C3=AAtre?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug observé sur replay_sess_56c10222 (2026-05-24 20:14) : action 11 (clic 'Enregistrer' expected_after='Enregistrer sous') marquée success=True alors que 2 actions plus tard la fenêtre observée est 'NoMachine Desktop Viewer'. Le polling post-vérif a probablement matché brièvement 'Enregistrer sous' puis l'écran a changé sans qu'on ne revérifie. Dom : "Le contrat est rompu : Léa passe d'une action à l'autre sans vérifier que la précédente est bonne. Il faut un contrôle de résultat, si on ne sait pas on demande." Patch : juste après le match initial, attendre 0.5s et reverifier la fenêtre active. Si elle a divergé (race condition, dialog auto- fermée, focus change OS) → matched=False, le flow strict existant prend le relais avec wrong_window + needs_human. Ne touche que les cas où expected_after est défini ET pas de runtime_dialog géré entre temps (le runtime_dialog est légitime de changer la fenêtre). Tag rollback : rollback/pre-P0.9-2026-05-24_2148 --- agent_v0/agent_v1/core/executor.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/agent_v0/agent_v1/core/executor.py b/agent_v0/agent_v1/core/executor.py index 85733c2ca..8d12e16d8 100644 --- a/agent_v0/agent_v1/core/executor.py +++ b/agent_v0/agent_v1/core/executor.py @@ -1862,6 +1862,23 @@ class ActionExecutorV1: max_runtime_dialog_handles, ) continue + # P0.9 — double-check de stabilité post-transition (~0.5s). + # Race condition observée sur replay_sess_56c10222 act 11 : + # la fenêtre attendue ('Enregistrer sous') peut matcher + # brièvement puis disparaître (dialog auto-fermée par un + # clic parasite ultérieur, ou focus change OS). Sans + # double-check, on valide une transition qui n'est plus là. + if matched and expected_after and not runtime_dialog_handled: + time.sleep(0.5) + recheck_info = get_active_window_info() + recheck_title = recheck_info.get("title", "") + if not _matches_expected_window(recheck_title): + logger.warning( + f"P0.9 transition instable : matched '{post_title}' " + f"puis '{recheck_title}' à T+0.5s ≠ '{expected_after}'" + ) + matched = False + post_title = recheck_title if matched: if runtime_dialog_handled: result["warning"] = "runtime_dialog_handled_post_verify"