Add a private in-flight helper for replay dispatch, block machine retargeting while an action is still pending on the previous session, and warn on duplicate in-flight entries for the same replay triplet.
Freeze the Notepad runtime dialog success path and add integration coverage for single in-flight dispatch, watchdog late-report documentation, and the known concurrent-poll race as an xfail.
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
Léa avait déjà une infra pour les dialogs runtime (`_match_known_runtime_dialog`
+ `_handle_known_runtime_dialog`) mais avec un catalog local limité à
2 entrées. Le DialogResolver R2 côté serveur a 10 entrées centralisées.
P1.MVP : `_try_dialog_resolver_server()` consulte l'endpoint
`/api/v1/dialog/resolve` quand le catalog local n'a pas matché. La
réponse `DialogResolution` est convertie en dialog_spec compatible
avec `_handle_known_runtime_dialog` qui réutilise la cascade existante
(serveur VLM grounding + template matching local).
- Flag `RPA_DIALOG_RESOLVER_AGENT_ENABLED` (OFF par défaut) — rollback runtime
- Auth Bearer via `_auth_headers()` existant
- Timeout 3s, fail-safe sur exception/503/no-match → fallback humain intact
- Zéro régression sur les chemins existants (le catalog local reste 1ère ligne)
Tests unitaires en local (6/6 OK) :
- flag OFF → None
- serveur 503 → None
- matched=False → None
- policy=pause (UAC) → None
- match auto + click_button → dialog_spec valide
- exception réseau → None
Tag rollback : rollback/pre-P1-2026-05-24_2105
Friction UX remontée par Dom sur replay live (replay_sess_63a1313b) :
latence excessive 2-3 minutes après un échec d'action avant que Léa
ne reprenne la main. 120s = trop long pour un humain en supervision.
10s d'inactivité reste le critère prioritaire (déjà en place), donc :
- humain actif : la correction est captée et le replay reprend en ~1s
- humain absent : on libère après 30s au lieu de 120s
5 sites d'appel + signature de fonction (default param) alignés.
Tag rollback : rollback/pre-P0.8-2026-05-24_1912
Référence : message 2026-05-24_1910_claude-to-codex_p07-memory-sanity-fix-human-supervised-bug-frictions-ux.md