Files
rpa_vision_v3/docs/superpowers/specs/2026-05-05-qw-suite-mai-design.md
Dom 2a07d8084b docs(qw): spec design QW suite mai 2026 (multi-écrans + LoopDetector + safety_checks hybrides)
Spec issu d'un brainstorming structuré (7 questions clarifiantes,
décisions tranchées) inspiré par l'exploration comparative de 5 frameworks
computer-use (Simular Agent-S, browser-use, OpenAI CUA sample, Coasty
open-cu, Showlab OOTB).

3 quick wins ciblés :
- QW1 multi-écrans : capture/grounding par monitor_index avec fallbacks
- QW2 LoopDetector composite : screen_static (CLIP) + action_repeat + retry
- QW4 safety_checks hybrides : déclaratif workflow + LLM contextuel
  (medgemma:4b, timeout 5s, fallback safe, kill-switch env)

Contraintes inviolables : 100% vision, 100% local Ollama, backward compat.
Plan livraison : QW1+QW2 avant démo GHT, QW4 enchaîné dès validation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-05 22:23:10 +02:00

26 KiB
Raw Blame History

Spec — QW Suite Mai 2026

Champ Valeur
Date 2026-05-05
Auteur Dom + Claude (brainstorming structuré)
Branche feature/qw-suite-mai (depuis feature/feedback-bus)
Backup backup/pre-qw-suite-mai-2026-05-05 à pousser sur Gitea avant 1er commit
Statut Design approuvé — spec à valider par Dom avant writing-plans
Cibles démo GHT Sud 95 (1ère sem mai 2026, date à confirmer)
Contraintes inviolables 100% vision · 100% local (Ollama) · backward compatible

1. Contexte & motivation

Suite à l'exploration comparative de 5 frameworks computer-use (Simular Agent-S, browser-use, OpenAI CUA sample, Coasty open-cu, Showlab OOTB), trois quick wins ont été identifiés comme améliorations à fort ratio valeur/risque pour RPA Vision V3, alignés avec la philosophie du projet (vision pure, souveraineté, supervision médicale) :

  • QW1 — Multi-écrans propre (inspiré OOTB) : capture et grounding sur l'écran cible plutôt que sur le composite tous écrans. Gain de perf grounding + correction des coordonnées.
  • QW2 — LoopDetector composite (inspiré browser-use) : détecter quand Léa exécute des actions techniquement valides mais que l'écran ne progresse pas, et escalader vers l'humain plutôt que de tourner en rond muettement.
  • QW4 — Safety checks hybrides (inspiré OpenAI CUA + browser-use Pydantic registry) : enrichir l'action pause_for_human avec une liste de vérifications à acquitter, mêlant déclaratif (workflow) et contextuel (LLM local).

Effet cumulé attendu : Léa devient observable, robuste et auditable sans rien céder sur le 100% local.

2. Décisions de design (récap)

Sujet Décision
Activation Default-ON pour tous les workflows (Dom recréera ce qui en a besoin)
QW1 — Stratégie ciblage écran monitor_index enregistré à la capture → fallback focus actif → fallback composite (backward)
QW1 — Niveau de stack Client Agent V1 (capture) + serveur (routeur) + core/execution/input_handler.py (capture locale)
QW2 — Signal de boucle Composite OR : screen_static (CLIP) + action_repeat + retry_threshold
QW2 — Sortie replay_state["status"] = "paused_need_help" avec pause_reason structuré
QW4 — Source des checks Hybride : déclaratif workflow + LLM contextuel sur safety_level: "medical_critical"
QW4 — Robustesse LLM medgemma:4b + timeout 5s + format=json Ollama + JSON Schema strict + fallback safe (zéro check additionnel) + kill-switch env var
QW4 — UX VWB Bulle existante préservée + <ChecklistPanel> au-dessus de Continuer (bouton désactivé tant que required non cochés)
Ordre de livraison QW1 → QW2 → QW4 (du moins invasif au plus visible)
Plan timing Option A : QW1+QW2 avant démo ; QW4 enchaîné dès validation des deux premiers
Kill-switches Env vars sur QW2 et QW4, surchargeables par systemctl edit
Backward compatibility 100% — aucun champ obligatoire ajouté au DSL ; workflows existants se comportent comme avant

3. Architecture globale

┌─────────────────────────┐         ┌─────────────────────────────────┐
│   Agent V1 (Windows)    │         │     Serveur Streaming (5005)    │
│                         │         │                                 │
│  ┌──────────────────┐   │         │  ┌───────────────────────────┐  │
│  │ ScreenCapture    │   │         │  │     LoopDetector  [QW2]   │  │
│  │  + monitor_index │───┼────────▶│  │  • screen_static (CLIP)   │  │
│  │     [QW1]        │   │  HTTP   │  │  • action_repeat          │  │
│  └──────────────────┘   │         │  │  • retry_threshold        │  │
│                         │         │  │  → paused_need_help       │  │
│  ┌──────────────────┐   │         │  └───────────────────────────┘  │
│  │ FeedbackBus lea:*│◀──┼─────────┤                                 │
│  │   chat_window    │   │         │  ┌───────────────────────────┐  │
│  └──────────────────┘   │         │  │   SafetyChecksProvider    │  │
└─────────────────────────┘         │  │           [QW4]           │  │
                                    │  │  • declarative (workflow) │  │
                                    │  │  • LLM contextual         │  │
                                    │  │     medgemma:4b 5s/JSON  │  │
                                    │  │     fallback safe        │  │
                                    │  │  • kill-switch env var    │  │
                                    │  └───────────────────────────┘  │
                                    │                                 │
                                    │  ┌───────────────────────────┐  │
                                    │  │ MonitorRouter   [QW1]     │  │
                                    │  │  • cible monitor_index    │  │
                                    │  │  • fallback focus actif   │  │
                                    │  └───────────────────────────┘  │
                                    └─────────────────────────────────┘
                                                    │
                                                    ▼
                                    ┌─────────────────────────────────┐
                                    │       VWB Frontend (3002)       │
                                    │                                 │
                                    │  PauseDialog (étendu) [QW4-UX]  │
                                    │  • bulle existante préservée    │
                                    │  • + ChecklistPanel             │
                                    │    (cases à cocher acquittables)│
                                    │  • + pause_reason si loop       │
                                    │  Continuer désactivé tant que   │
                                    │  required-checks non cochés     │
                                    └─────────────────────────────────┘

Principes invariants

  1. Aucun nouveau service, aucune nouvelle DB. Tout dans la stack existante (Agent V1 + serveur 5005 + VWB 3002).
  2. 3 modules serveur isolés (monitor_router.py, loop_detector.py, safety_checks_provider.py) — couplage faible, testables individuellement, désactivables par env var.
  3. Backward compatible : workflows sans nouveaux champs se comportent comme avant.
  4. Kill-switches env vars sur QW2 et QW4, override possible via systemctl edit pendant la démo.
  5. 100% vision : QW1 pure capture + grounding ; QW2 réutilise le _clip_embedder déjà chargé ; QW4 LLM = Ollama local strict.
  6. Bus lea:* étendu de 4 events d'observabilité : lea:loop_detected, lea:safety_checks_generated, lea:safety_checks_llm_failed, lea:monitor_routed.

Surface de modification (ordre A)

QW Fichiers nouveaux Fichiers modifiés
QW1 agent_v0/server_v1/monitor_router.py agent_v0/agent_v1/capture/screen_capture.py, core/execution/input_handler.py, agent_v0/server_v1/api_stream.py (~10 lignes)
QW2 agent_v0/server_v1/loop_detector.py agent_v0/server_v1/replay_engine.py (~30 lignes), agent_v0/server_v1/api_stream.py (~20 lignes)
QW4 agent_v0/server_v1/safety_checks_provider.py, visual_workflow_builder/frontend_v4/src/components/PauseDialog.tsx agent_v0/server_v1/replay_engine.py, agent_v0/server_v1/api_stream.py (/replay/resume), visual_workflow_builder/frontend_v4/src/types.ts, visual_workflow_builder/frontend_v4/src/components/PropertiesPanel.tsx

4. QW1 — Multi-écrans

4.1 Composants

Client Agent V1agent_v0/agent_v1/capture/screen_capture.py (existant à modifier)

  • Enrichit chaque heartbeat / event avec :
    • monitor_index: int
    • monitors_geometry: [{idx, x, y, w, h, primary}]
  • Détection via screeninfo (port direct depuis Showlab OOTB)
  • Capture de l'écran actif uniquement (poids réseau identique à aujourd'hui)
  • Si screeninfo indisponible côté Windows : envoie monitors_geometry: [], comportement composite préservé

Serveur — nouveau agent_v0/server_v1/monitor_router.py (~80 lignes)

  • API : resolve_target_monitor(action: dict, session_state: dict) → MonitorTarget
  • MonitorTarget = {idx, offset_x, offset_y, w, h, source: "action" | "focus" | "composite_fallback"}
  • Stratégie :
    1. Lit action.get("monitor_index") si présent → cible cet écran
    2. Sinon session_state.get("last_focused_monitor") → cible focus actif
    3. Sinon monitors[0] composite (comportement actuel — backward)

Input local Linuxcore/execution/input_handler.py modifs ciblées

  • Signature changée : _capture_screen(monitor_idx=None) → (image, w, h, offset_x, offset_y)
  • Quand monitor_idx fourni : capture uniquement ce monitor
  • Toutes les fonctions _grounding_* (_grounding_ocr, _grounding_ui_tars, _grounding_vlm) propagent l'offset pour traduire les coords retournées en coords absolues écran

4.2 Data flow replay

Action [monitor_index=1] reçue par serveur
  → MonitorRouter.resolve()
  → target_monitor = {idx:1, offset:(1920,0), w:1920, h:1080, source:"action"}
  → grounding capture monitor 1 uniquement (image 1920×1080, pas 3840×1080)
  → UI-TARS / OCR / VLM cherche cible → coords locales (640, 540)
  → coords absolues = (640+1920, 540+0) = (2560, 540)
  → pyautogui.click(2560, 540)
  → bus.emit("lea:monitor_routed", {idx:1, source:"action"})

4.3 Error handling

Cas Comportement
monitor_index absent (vieille session) Fallback focus actif, log info lea:monitor_routed source=focus
Monitor enregistré n'existe plus (2nd écran débranché) Fallback focus actif, event lea:monitor_unavailable warning
mss.monitors[i] hors limites Fallback monitors[0] composite, event lea:monitor_invalid_index error
screeninfo non installé côté Agent V1 monitors_geometry: [], fallback composite (comportement actuel) — pas de blocage

4.4 Tests QW1

  • tests/unit/test_monitor_router.py : 4 cas (cible OK, fallback focus, fallback composite, monitor débranché)
  • tests/integration/test_grounding_offset.py : capture 1 monitor + clic résolu avec offset (mock pyautogui)
  • Smoke : 1 workflow Easily rejoué, vérification visuelle que le clic atterrit au bon endroit

4.5 Compat workflows existants

Aucune action n'a monitor_index aujourd'hui → 100% des workflows existants partent en fallback focus actif → comportement quasi-identique au composite actuel mais sur un seul écran (gain de perf grounding même sans recréation de workflow).

5. QW2 — LoopDetector composite

5.1 Composants

Nouveau agent_v0/server_v1/loop_detector.py (~150 lignes)

  • Classe LoopDetector avec 3 sous-détecteurs
  • API : evaluate(replay_state, screenshot_history, action_history) → LoopVerdict
  • LoopVerdict = {detected: bool, reason: str, signal: str, evidence: dict}

Hook dans agent_v0/server_v1/api_stream.py

  • Après chaque report_action_result, appel loop_detector.evaluate(...) si RPA_LOOP_DETECTOR_ENABLED=1 (défaut)
  • Si verdict.detected :
    • replay_state["status"] = "paused_need_help"
    • replay_state["pause_reason"] = verdict.reason
    • replay_state["pause_message"] = f"Léa semble bloquée — {verdict.signal}"
    • bus.emit lea:loop_detected avec {signal, evidence, replay_id}

Étendu dans replay_engine.py :

  • _create_replay_state() ajoute :
    • "_screenshot_history": [] (anneau de 5 derniers embeddings CLIP)
    • "_action_history": [] (anneau des 5 dernières actions)
  • _pre_check_screen_state() continue indépendamment (signal différent : check pré-action vs détection post-action de stagnation)

5.2 Signaux composites

Signal Détecteur Seuil par défaut Source
screen_static A 4 captures consécutives avec CLIP similarity > 0.99 _clip_embedder déjà chargé serveur
action_repeat B 3 actions consécutives identiques (type + coords) _action_history
retry_threshold C 3 retries sur même action_id replay_state["retried_actions"] (déjà existant)

Un seul signal positif suffit à déclencher l'escalade.

5.3 Data flow

Action exécutée → result reçu via /replay/result
  ↓
LoopDetector.evaluate(state, screenshots, actions) si RPA_LOOP_DETECTOR_ENABLED=1
  ├─ A.check_screen_static() → embed(latest), compare aux N-1 derniers
  ├─ B.check_action_repeat() → compare action_history[-3:]
  └─ C.check_retry_threshold() → state["retried_actions"] >= 3
  ↓
Si verdict.detected:
  state["status"] = "paused_need_help"
  state["pause_reason"] = verdict.reason
  state["pause_message"] = f"Léa semble bloquée — {verdict.signal} ({evidence})"
  bus.emit("lea:loop_detected", {signal, evidence, replay_id})

5.4 Error handling

Cas Comportement
CLIP embedder unavailable Signal A désactivé (warning log 1×), B+C continuent. Pas de blocage.
_screenshot_history < N Signal A skip silencieusement (pas assez d'historique)
embed_image() lève une exception Catch + log warning, replay continue (verdict = detected=False)
RPA_LOOP_DETECTOR_ENABLED=0 Module entier bypassé, comportement antérieur
Faux positif détecté en pleine démo RPA_LOOP_DETECTOR_ENABLED=0 via systemctl edit rpa-streaming + restart → reprise immédiate

5.5 Configuration env vars

  • RPA_LOOP_DETECTOR_ENABLED=1 (défaut)
  • RPA_LOOP_SCREEN_STATIC_THRESHOLD=0.99
  • RPA_LOOP_SCREEN_STATIC_N=4
  • RPA_LOOP_ACTION_REPEAT_N=3
  • RPA_LOOP_RETRY_THRESHOLD=3

5.6 Tests QW2

  • tests/unit/test_loop_detector.py : 8 cas (chaque signal isolé, chaque combinaison, kill-switch, embedder absent)
  • tests/integration/test_loop_detector_replay.py : 3 cas — replay simulé qui boucle → vérifier transition running → paused_need_help avec bonne raison
  • Pas de smoke démo (impossible à reproduire fiable, on s'appuie sur les tests intégration)

5.7 Compat VWB

Aucune côté frontend pour QW2 : la pause paused_need_help existe déjà. Le pause_reason enrichi sera affiché par le composant PauseDialog étendu en QW4. Avant la livraison de QW4, la raison s'affichera en texte dans le pause_message (donc utile dès le commit QW2).

6. QW4 — Safety checks hybrides

6.1 Contrat de l'action étendue (rétro-compatible)

{
  "type": "pause_for_human",
  "parameters": {
    "message": "Validation T2A avant codage",
    "safety_level": "medical_critical",
    "safety_checks": [
      {"id": "check_ipp", "label": "Vérifier IPP patient", "required": true},
      {"id": "check_cim10", "label": "Confirmer code CIM-10", "required": true}
    ]
  }
}

safety_level et safety_checks sont optionnels. Action sans ces champs → comportement actuel (bulle simple, aucun appel LLM).

6.2 Composants serveur

Nouveau agent_v0/server_v1/safety_checks_provider.py (~180 lignes)

  • API : build_pause_payload(action, replay_state, last_screenshot) → PausePayload
  • Concatène : checks déclaratifs (workflow) + checks contextuels (LLM si safety_level == "medical_critical")
  • Chaque check porte sa source : source: "declarative" | "llm_contextual" et son evidence (vide pour déclaratif, justification courte pour LLM)
  • Format check final :
    {
      "id": "check_xxx",
      "label": "...",
      "required": true,
      "source": "declarative" | "llm_contextual",
      "evidence": null | "..."
    }
    

LLM contextual call — sous-fonction _call_llm_for_contextual_checks()

  • Modèle : medgemma:4b (env RPA_SAFETY_CHECKS_LLM_MODEL)
  • Timeout dur : 5s (env RPA_SAFETY_CHECKS_LLM_TIMEOUT_S)
  • format=json natif Ollama + JSON Schema strict :
    {"additional_checks": [{"label": "string", "evidence": "string"}]}
    
  • Max 3 checks ajoutés (env RPA_SAFETY_CHECKS_LLM_MAX_CHECKS)
  • Prompt : screenshot heartbeat actuel + workflow message + liste des checks déclaratifs (évite doublons)
  • Tout échec (timeout, exception, JSON invalide post-schema) → additional_checks = [], event lea:safety_checks_llm_failed, replay continue

Hook dans replay_engine.py — branche action_type == "pause_for_human"

  • Avant de basculer en paused_need_help, appel safety_checks_provider.build_pause_payload(...)
  • Stocke replay_state["safety_checks"] = payload.checks
  • Stocke replay_state["pause_payload"] = payload (pour debug/audit)

Modif api_stream.py — endpoint /replay/resume

  • Reçoit {acknowledged_check_ids: [...]} dans le body POST
  • Vérifie : tous les checks required=true doivent être dans acknowledged_check_ids
    • Sinon : 400 {error: "required_checks_missing", missing: [...]}
  • Stocke replay_state["checks_acknowledged"] = acknowledged_check_ids (audit trail)
  • Reprise normale du replay

6.3 Composants frontend VWB

Nouveau visual_workflow_builder/frontend_v4/src/components/PauseDialog.tsx (~200 lignes)

  • Props : pauseMessage, pauseReason, safetyChecks, onResume(ackIds), onCancel
  • Si safetyChecks.length === 0 : rend la bulle existante (legacy, comportement actuel)
  • Sinon : bulle + <ChecklistPanel> avec checkboxes
  • Bouton Continuer disabled tant que checks.filter(c => c.required && !checked).length > 0
  • POST /replay/resume avec body {acknowledged_check_ids: [...]}
  • Visuel source :
    • Badge [Léa] pour source: "llm_contextual" (avec tooltip evidence)
    • Badge [obligatoire] pour required: true

Étendu types.ts

  • PauseAction['parameters'] : ajout safety_level?, safety_checks?
  • Execution : ajout pause_reason?, safety_checks?

Étendu PropertiesPanel.tsx:1356 — éditeur de l'action pause_for_human

  • Section "Niveau de sécurité" : dropdown standard | medical_critical
  • Section "Checks à valider" : liste éditable (id + label + required)

6.4 Data flow complet

Action pause_for_human (medical_critical, 2 checks déclaratifs) atteinte
  ↓
SafetyChecksProvider.build_pause_payload()
  ├─ checks = [...declarative]  (2 entrées)
  ├─ if safety_level == "medical_critical" and RPA_SAFETY_CHECKS_LLM_ENABLED=1:
  │     llm_checks = _call_llm_for_contextual_checks()  (max 3, timeout 5s)
  │     checks += llm_checks
  └─ return PausePayload(checks, pause_reason, message)
  ↓
replay_state["status"] = "paused_need_help"
replay_state["safety_checks"] = checks
bus.emit("lea:safety_checks_generated", {count, sources})
  ↓
Frontend VWB poll /replay/state → reçoit pause_payload
  ↓
<PauseDialog> rend ChecklistPanel
  ↓
Médecin coche les 4 checks → clique Continuer
  ↓
POST /replay/resume {acknowledged_check_ids: [4 ids]}
  ↓
Serveur valide (tous required acquittés) → reprise du replay
replay_state["checks_acknowledged"] = [...] (audit trail conservé)

6.5 Error handling

Cas Comportement
safety_level absent Pas d'appel LLM ; checks déclaratifs uniquement (peut être []) → bulle simple si vide, checklist sinon
Ollama timeout 5s Event lea:safety_checks_llm_failed, additional_checks=[], fallback safe (déclaratifs seuls)
Ollama JSON malformé (post format=json — théoriquement impossible) Idem timeout, fallback safe
LLM produit un check absurde Accepté tel quel, le superviseur ignore (pas de filtrage en V1)
Frontend reçoit safety_checks=[] Bulle simple, comportement legacy
RPA_SAFETY_CHECKS_LLM_ENABLED=0 Couche LLM bypassée, déclaratifs gardés
/replay/resume sans acknowledged_check_ids sur required 400 required_checks_missing
Frontend POST /replay/resume rejeté Toast d'erreur côté UI, état pause conservé, possibilité de cocher manquants et réessayer

6.6 Configuration env vars

  • RPA_SAFETY_CHECKS_LLM_ENABLED=1 (défaut)
  • RPA_SAFETY_CHECKS_LLM_MODEL=medgemma:4b
  • RPA_SAFETY_CHECKS_LLM_TIMEOUT_S=5
  • RPA_SAFETY_CHECKS_LLM_MAX_CHECKS=3

6.7 Tests QW4

  • tests/unit/test_safety_checks_provider.py : 7 cas (déclaratif seul, hybride réussi, LLM timeout, LLM JSON invalide, kill-switch, max_checks respecté, déclaratif vide)
  • tests/integration/test_replay_resume_acknowledgments.py : 3 cas (resume OK, missing required → 400, audit trail enregistré dans checks_acknowledged)
  • Frontend : tests/components/PauseDialog.test.tsx si suite Vitest existe (à confirmer pendant l'implémentation), sinon test manuel avec checklist écrite
  • Smoke : 1 workflow Easily avec pause_for_human medical_critical enrichi → vérification full chain

6.8 Compat workflows existants

100% backward — pause_for_human actuels n'ont ni safety_level ni safety_checks → comportement strictement identique. Aucune recréation forcée. Dom enrichira uniquement les workflows qu'il veut promouvoir au niveau medical_critical.

7. Tests, sécurité de la branche, livraison

7.1 Filet de sécurité avant TOUT commit sur feature/qw-suite-mai

  1. Branche backup poussée Gitea : backup/pre-qw-suite-mai-2026-05-05
  2. Capture baseline E2E :
    pytest tests/test_pipeline_e2e.py \
           tests/test_phase0_integration.py \
           tests/integration/test_stream_processor.py \
           -q 2>&1 | tee .qw-baseline.log
    
  3. Smoke démo : 1 dérouler complet d'un workflow Easily Assure, archivage screenshot/vidéo de référence
  4. État VWB validé : démarrage Vite local, ouverture d'un workflow, lancement d'un replay simple, screenshot "tout va bien"

7.2 Discipline TDD légère par QW

  • Test unitaire écrit AVANT le code de production (1 test rouge → 1 implémentation → vert)
  • Pas de TDD complet sur le frontend (Vitest + React = trop d'outillage à valider en parallèle), test manuel cadré avec checklist écrite
  • Re-run de la suite baseline après chaque commit QW, comparaison au log archivé
  • Toute régression bloque le passage au QW suivant tant qu'elle n'est pas comprise et résolue

7.3 Compat VWB — checklist explicite avant commit QW4

  • Workflow ancien (sans safety_checks) → bulle simple s'affiche normalement
  • Workflow nouveau avec safety_checks déclaratifs uniquement → checklist visible, pas d'appel Ollama (vérification logs)
  • Workflow medical_critical → checklist + checks LLM apparaissent (vérification logs Ollama call dans les 5s)
  • Continuer désactivé tant que required non cochés
  • POST /replay/resume avec mauvais payload → toast d'erreur côté UI, pas de crash
  • PropertiesPanel : édition de safety_checks ne casse pas l'édition d'autres params de pause_for_human
  • DB workflows.db : ouverture après commit, aucune migration cassante (schéma JSON est libre)

7.4 Plan de commits

1. test(qw1): tests monitor_router + grounding_offset (rouges)
2. feat(qw1): multi-écrans piloté par monitor_index (verts)
3. test(qw2): tests loop_detector composite (rouges)
4. feat(qw2): LoopDetector composite avec kill-switch env
5. test(qw4): tests safety_checks_provider + replay_resume (rouges)
6. feat(qw4): safety_checks hybride déclaratif + LLM contextuel
7. feat(vwb): PauseDialog + ChecklistPanel + extension PropertiesPanel
8. docs(qw): docs/QW_SUITE_MAI.md + mise à jour MEMORY.md

Chaque commit signé Co-Authored-By Claude. Branche poussée régulièrement sur Gitea pour backup distant.

7.5 Stratégie en cas de régression critique pendant la démo

Kill-switches env vars surchargeables sans redéploiement code :

systemctl edit rpa-streaming
# Ajouter sous [Service] :
Environment=RPA_LOOP_DETECTOR_ENABLED=0
Environment=RPA_SAFETY_CHECKS_LLM_ENABLED=0
systemctl restart rpa-streaming

Si problème grave au-delà des kill-switches : rollback à backup/pre-qw-suite-mai-2026-05-05.

git checkout backup/pre-qw-suite-mai-2026-05-05
./svc.sh restart

7.6 Plan de livraison (Option A validée)

Avant démo GHT (cette semaine) — Sprint priorité 1

  • QW1 : tests + code + smoke (~1j)
  • QW2 : tests + code + tests intégration (~2j)
  • Capture baseline + replay smoke entre chaque
  • Si QW1+QW2 validés et probants → on enchaîne sur QW4 dès que possible (Dom accepte le weekend si "effet waouh" auprès de spécialistes RPA)

Après démo / dès validation QW1+QW2 — Sprint priorité 2

  • QW4 serveur (provider + LLM + endpoint resume) (~3j)
  • QW4 frontend (PauseDialog + PropertiesPanel) (~2j)
  • Doc + mise à jour MEMORY.md

Total estimé : ~8.5j-h ingénieur senior, étalable selon le retour démo.

8. Ce qui n'est PAS dans ce spec (out of scope)

  • F1 (DSL d'actions Pydantic-first) : refactor de fond, sera son propre spec après la démo.
  • F2 (Mixture-of-Grounding routeur adaptatif) : nécessite F1, son propre spec.
  • F3 (Best-of-N + Reflection) : nécessite F1, son propre spec.
  • QW3 (output_model_schema Pydantic pour extract_text) : opportuniste, sera intégré quand on touchera extract_text pour autre chose.
  • Toute introduction de Pydantic-AI / instructor / Playwright / accessibility-tree : interdit (contraintes inviolables).
  • Refonte du composant pause en <PauseDialog> à 3 modes (option C de Q6) : reportée après démo si retour utilisateurs justifie l'investissement.

9. Open questions

Aucune. Toutes les décisions de design ont été tranchées via les 7 questions clarifiantes du brainstorming du 5 mai 2026.