diff --git a/docs/CARTO_CODE_NON_BRANCHE_2026-07-02.md b/docs/CARTO_CODE_NON_BRANCHE_2026-07-02.md new file mode 100644 index 000000000..3108f0007 --- /dev/null +++ b/docs/CARTO_CODE_NON_BRANCHE_2026-07-02.md @@ -0,0 +1,186 @@ +# CARTO CODE NON BRANCHÉ — carte de référence wiring (2026-07-02) + +> **But** : carte « existing-first » de référence. AVANT tout chantier/bench/proposition, +> consulter ce doc pour savoir si une brique existe et si elle est **réellement branchée au +> runtime**. Recadrage Dom 02/07 : « vérifier ce qui existe et non branché, c'est le BABA ». +> +> **Méthode** : verdict prouvé par chaîne d'imports depuis un point d'entrée actif +> (fichier:ligne), imports lazy inclus, gates de config citées. Jamais de conclusion sur un +> grep seul. Sources fusionnées : agent Claude « intelligence » + carto Qwen (volet 1 +> détection) + `AUDIT_CODE_MORT_2026-07-02.md` (Qwen) + vérifs ponctuelles Claude. +> +> **Légende** : **WIRED** (chaîne prouvée) · **GATED** (branché mais derrière flag, défaut +> cité) · **ORPHELIN** (0 appelant runtime, recherche exhaustive) · **INCERTAIN** (non tranché, +> raison donnée). +> +> **Points d'entrée actifs runtime** : `api_stream.py` (streaming 5005, `rpa-streaming`) · +> `run_worker.py` (worker VLM 5099) · VWB `app.py` (5002) · `web_dashboard/app.py` (5001) · +> `agent_chat/app.py` (5004) · `server/api_upload.py` (8000). + +--- + +## 0. Résumé exécutif — les découvertes qui changent une décision + +1. **Self-healing = façade morte, malgré doc « wired ».** Chaîne d'import réelle (VWB → + `core/healing`), routes REST répondent, MAIS déclenchement **impossible** : le code teste + `hasattr(healing_integration, 'enable_healing')` et cette méthode **n'existe nulle part** + (`execution_integration.py:421`). `handle_execution_failure` = 0 appelant d'exécution. + Preuve d'inertie : `logs/healing/recovery.log` = **0 octet, mtime déc. 2025**. Le pont + manquant tient à **une méthode**, pas un module. → `PLAN_MENAGE_CODE_MORT` le classait + « wired — NE PAS TOUCHER » : **doc fausse**. + +2. **`core/navigation` (commit du matin `f9a053132`) = write-only.** Le handler résout le + login et écrit `navigate_login_coords` dans `replay_state["variables"]`, mais **aucun + consommateur** : le compilateur `_edge_to_normalized_actions` n'a pas de branche `navigate` + et produit des coords littérales, jamais de templates `{{navigate_login_coords.x_pct}}`. + Détail : `docs/DESIGN_NAVIGATE_COORDS_CONSUMPTION_2026-07-02.md`. Décision D1 en attente Dom. + +3. **AutonomousPlanner : coût sans usage.** Instancié au boot d'`agent_chat` (charge LLM + + OWL detector via `autonomous_planner.py:36`), mais **aucune route n'appelle une méthode de + planification** — seuls des setters. Type même du « code écrit jamais invoqué ». + +4. **PaddleOCR installé, jamais importé.** `paddleocr 3.4.0` + `paddlepaddle 3.3.1` (CPU) + présents dans `.venv`, **0 `import paddle` dans le code**, 0 requirements, 0 deploy. Piste + bench en cours (Qwen), pas un composant actif. + +5. **YOLO cascade de résolution = mort.** `_resolve_by_yolo` défini + (`resolve_engine.py:458`) + importé (`api_stream.py:6114`) mais **jamais appelé** ; aucune + branche `yolo` dans la cascade compilée. ⚠ À NE PAS confondre avec le YOLO de `som_engine` + (OmniParser SoM), lui **WIRED**. + +6. **`server/api_core.py`** : blueprint Flask complet (capture/detect/embed/faiss) **jamais + enregistré** — orphelin absent du plan ménage. + +7. **Nos propres cartos avaient 4 erreurs** (cf. §4). Re-prouver était justifié. + +--- + +## 1. Chaîne détection / grounding / résolution + +| Module | Verdict | Preuve (fichier:ligne) | Remarque | +|--------|---------|------------------------|----------| +| `core/detection/som_engine.py` | **WIRED** | resolve_engine.py:1192 (replay) · stream_processor.py:643 (recording) · api_stream.py:1958 (temps réel) | 3 chemins indépendants, singleton thread-safe. Tire YOLO weights direct. | +| `core/detection/omniparser_adapter.py` | **B-DORMANT** (branché lazy, fallback vide) | phase25_analyzer.py:388 · resolve_engine.py:437 · désactivé côté VWB (`_omniparser_available=False`) | Import lazy try/except, singleton. 7 zones cartographiées (§ audit Qwen). | +| `core/detection/owl_detector.py` | **WIRED (via AutonomousPlanner) — mais planner inerte** | autonomous_planner.py:36 | Chargé au boot agent_chat pour rien (cf. §0.3). 4 méthodes internes C-MORT. | +| `core/detection/ollama_client.py` | **WIRED partiel** | `classify_element_complete()` actif ; 5 vieilles méthodes + `check_ollama_available()` standalone = C-MORT | Duplicat VWB (D2). | +| `_resolve_by_yolo` (resolve_engine.py:458) | **ORPHELIN** | importé api_stream.py:6114, **0 appel réel**, 0 branche cascade | ≠ YOLO de som_engine (wired). | +| `core/grounding/bbox_parser.py` | **WIRED** | resolve_engine.py:29 | | +| `core/grounding/smart_resize.py` | **ORPHELIN (C-MORT)** | 0 appelant prod, DETTE-007 triple impl (2 autres existent) | | +| `core/grounding/server.py` | **WIRED** | service HTTP Flask port 8200 standalone | Upgrade C→A (Qwen). | +| `visual_workflow_builder/.../api/ui_detection.py` | **WIRED** | VWB app.py:310 (blueprint) · fast_detector.py:117 | UI-DETR-1 du recording, modèle rfdetr RFDETRMedium, 5 endpoints `/api/ui-detection`. | +| `core/semantic/phase25_analyzer.py` | **WIRED** | api_stream.py:7690 (route `lea_competence_persist:7435`) | | +| `core/extraction/{field_extractor,vlm_client,role_mapper}` | **WIRED-transitif** | field_extractor ← input_handler.py:121/504/722 (lazy) · vlm_client+role_mapper ← core/navigation/__init__.py:69, action_resolver.py:109 | Le plan ménage 23/06 (« 4/5 morts ») précède navigation. | +| `core/llm/` (ocr_extractor, extract_grid) | **WIRED** | api_stream.py:1766 · replay_engine.py:2115-2403 · resolve_engine.py:2597 | | +| `core/navigation/` | **WIRED (boot) / write-only (fonctionnel)** | api_stream.py:440 top-level NON gardé · handler résout mais 0 consommateur coords | cf. §0.2. ⚠ import non gardé → si casse, 5005 ne boote pas (garde-fou test_navigate_wiring.py). | +| PaddleOCR (venv) | **ORPHELIN** | 0 import, 0 requirements, 0 deploy | cf. §0.4. | + +--- + +## 2. Modules « intelligence » + +| Module | Verdict | Preuve (fichier:ligne) | Remarque | +|--------|---------|------------------------|----------| +| `core/healing/` | **ORPHELIN de fait** (importé, indéclenchable) | chaîne VWB app.py:217 → api/self_healing.py → services/self_healing_integration.py, MAIS `enable_healing` inexistant (execution_integration.py:421) ; `handle_execution_failure` 0 appelant | cf. §0.1. `logs/healing/recovery.log` vide depuis déc. 2025. | +| `core/coaching/` | **WIRED** | VWB app.py:284-285 (blueprint) → api/coaching_sessions.py:17,22 · exec : execution_integration.py:869 · front WebSocket | REST blueprint peut-être non consommé par l'UI (front = socket.io). | +| `core/cognition/working_memory` | **WIRED-transitif** | observe_reason_act.py:30,506 · ORALoop ← VWB execute.py:1542,2075 | Les 4 autres sous-modules cognition = MORTS (tests only). | +| `core/learning/` (4/5) | **WIRED** | target_memory_store: resolve_engine.py:1865 + api_stream.py:5132 · continuous_learner: stream_processor.py:3147 · learning_manager: VWB learning_integration.py:36, api/workflows.py:696 · feedback_processor: execution_loop.py:317 | `versioned_store` ORPHELIN. `record_observation` = **0 appelant** (learning_manager.py:54). | +| `core/execution/` | **WIRED massif** | observe_reason_act ← execute.py:1542 · input_handler ← execute.py:69 · dag_executor+llm_actions ← dag_execute.py:33,40 · action_executor/target_resolver/error_handler/execution_loop ← agent_chat app.py:328-340 · +transitifs | Morts : spatial_index, target_memory, workflow_runner (⚠ encore exporté par `__init__.py:10`). | +| `core/auth/` | **GATED — défaut OFF** | api_stream.py:278-286 : import lazy SSI `RPA_AUTH_VAULT_PATH` **et** `RPA_AUTH_VAULT_PASSWORD` définis (absents par défaut). Seul lieu qui les définit : CI `.gitea/workflows/tests.yml:35` | Vault inactif en prod. TOTP dans la même chaîne gated. | +| `core/federation/` | **WIRED manuel, write-only** | routes actives non gated : GET learning-pack/export api_stream.py:6431 · POST import :6476 | `GlobalFAISSIndex.search()` = **0 appelant**. Aucun auto-déclenchement. | +| `core/gpu/` (2/6) | **WIRED** | device_policy ← resolve_engine.py:1750 (hot-path) · gpu_resource_manager ← agent_chat app.py:53,266 | clip_manager, ollama_manager, vram_monitor, preflight = morts. | +| `core/embedding/` | **WIRED (lazy)** | construction CLIP/FAISS ← stream_processor.py:2560 `_ensure_initialized` (appelé process_screenshot:2804 + finalize_session:2969) · lecture web_dashboard app.py:309+ | Se déclenche au 1er screenshot / finalisation, pas au boot. | +| `agent_chat/autonomous_planner` | **INSTANCIÉ mais INERTE** | import app.py:48, instancié :358, mais seuls appels = setters :362,367 ; 0 route de planification | cf. §0.3. Tire owl_detector pour rien. | +| `agent_chat/urgences_orchestrator` | **WIRED** | import lazy app.py:2740, routes `/api/urgences/*` | | +| `agent_chat/gesture_catalog` | **WIRED ×2** | agent_chat app.py:377,955 · **api_stream.py:269,3598** (hot-path replay `optimize_replay_actions`) | Pas seulement le chat. | +| `core/validation/` | **GATED — défaut OFF** | flag `RPA_VALIDATOR_V2_ENABLED` défaut OFF (api_stream.py:91), consommé report_action_result:4924 | | + +**WIRED confirmés (survol)** : capture, models, competences, corrections, data, graph, +knowledge, monitoring, persistence, pipeline, system, workflow, visual, config.py, +anonymisation (PII), matching/training (transitifs). +**ORPHELINS confirmés** : variants, precision, supervision, interfaces (0 importeur non-test) · +`core/evaluation/` (consommé seulement par `tools/lea_bench*.py`, outillage CLI) · +`server/api_core.py` (blueprint jamais enregistré). + +--- + +## 3. Zones GATED (flags + défaut) — activation supervisée + +| Flag | Défaut | Effet si ON | Preuve | +|------|--------|-------------|--------| +| `RPA_AUTH_VAULT_PATH` + `RPA_AUTH_VAULT_PASSWORD` | absents | active `core/auth` (vault Fernet + TOTP) | api_stream.py:278-286 | +| `RPA_VALIDATOR_V2_ENABLED` | OFF | active validation V2 (report_action_result) | api_stream.py:91 | +| `RPA_R1_AUTO_IMPORT` | OFF | active import auto core→DB VWB (R1) | api_stream.py:~4480 (revue en cours) | +| `RPA_AUTO_UPDATE_ENABLED` | OFF | MAJ silencieuse client (DETTE-022) | agent_v1/config.py:103 | +| `RPA_GROUNDING_ENGINE=qwen3vl_vllm` | legacy Qwen2.5-VL | grounder Qwen3-VL (override DGX runtime) | resolve_engine.py:1001-1007 | + +--- + +## 4. Divergences corrigées avec les docs existants + +1. **`core/healing` : doc `PLAN_MENAGE` = « wired, NE PAS TOUCHER » → FAUX.** Indéclenchable + (`enable_healing` fantôme, log vide déc. 2025). Le pont est à une méthode près. +2. **`feedback_processor` : CARTO 16/06 = ORPHELIN → FAUX.** Instancié à chaque ExecutionLoop + (execution_loop.py:317). +3. **`core/cognition` : CARTO 16/06 = tout orphelin → FAUX pour working_memory** (vivant au + runtime VWB via observe_reason_act). +4. **`core/extraction` : plan ménage « 4/5 morts » → périmé.** vlm_client + role_mapper + branchés via `core/navigation` (postérieur au doc). + +Upgrades C→A/B confirmés par Qwen : autonomous_planner (C→A, mais inerte cf. §0.3), +seeclick_adapter (C→B), grounding/server.py (C→A), get_grounding_profile (C→A). + +--- + +## 5. Code mort candidat suppression → voir `AUDIT_CODE_MORT_2026-07-02.md` + +Résumé : **8 C-MORT** (~843 lignes, ex. deploy_windows.py, smart_resize.py, 7 config classes +dépréciées, agent_chat 410 endpoints) · **5 B-ORPHELIN** (à conserver, projections) · **4 +duplicats** (décision Dom). Suppression = GO Dom par lot, worktree isolé + tests après chaque +lot. ⚠ Prudence renforcée vu les 4 erreurs de doc du §4 : re-prouver chaque item avant +suppression. + +--- + +## 6. Cascade de résolution UI (`resolve_engine.py`) — ordre RÉEL prouvé + +Point d'entrée unique au replay : le client Léa (`executor.py:2847`, **`strict_mode=True` hardcodé** +:2870) → route `resolve_target` (`api_stream.py:6131`) → `_resolve_target_sync` +(`resolve_engine.py:1804`). `replay_engine.py` ne résout pas (il construit le target_spec). + +**Ordre réel au replay (mode strict VLM-first, `resolve_engine.py:1957`)** : +``` +0. Mémoire persistante (replay_memory.memory_lookup:1869) — hit → skip toute la cascade +0c. dialog_button → OCR seul (1920-1952) +── strict VLM-first (1957) ── +S0a. Grounding VLM (_resolve_by_grounding:2019) si by_text_source ∈ {ocr, vlm} +S0b. Template matching icônes (2057) sinon +S0.5 OCR direct (_resolve_by_ocr_text:2105) si by_text +S1. VLM Quick Find (_vlm_quick_find:2158) +S1.5 SoM + VLM (_resolve_by_som:2207) +S2. Template matching fallback (2238) +S3. STOP replay resolved=False (2283) +``` +Note : grounding VLM (S0a) et VLM Quick Find (S1) sont **deux appels VLM distincts**. + +**Statut resolvers** : `_resolve_by_grounding`, `_resolve_by_template_matching`, +`_resolve_by_ocr_text`, `_vlm_quick_find`, `_resolve_by_som`, `replay_memory` = **WIRED** +(preuves lignes ci-dessus). Grounder Qwen3-VL : bascule dans `_resolve_by_grounding:1006` +(flag `RPA_GROUNDING_ENGINE=qwen3vl_vllm`, sinon legacy Qwen2.5-VL) — change modèle/endpoint/ +prompt/parser, pas le flux. + +**3 branches MORTES dans la cascade** : +- `_resolve_by_yolo` (:458) — importé api_stream.py:6114, **0 appel réel**. ORPHELIN. +- **Vérification CLIP** (:1972-2008) — **dead gate** : lit `target_spec["clip_embedding"]` + qui n'est **jamais peuplé** dans tout `agent_v0/` → branche jamais exécutée. +- **V4 pré-compilé** (`_resolve_with_precompiled_order:1601`, ordre figé `["ocr","template", + "vlm"]`) — **WIRED mais dormant en replay normal** : alimenté uniquement par l'endpoint + `/replay/plan` (`execution_plan_runner.py:173`), jamais par le flux VWB→Léa. + +**Verdict README « OCR→template→YOLO→VLM » = FAUX** : (1) YOLO mort, (2) l'ordre est +VLM-first, (3) la séquence `ocr,template,vlm` n'existe que dans le V4 dormant. + +## 7. Zones restantes non re-vérifiées (honnêteté) + +- `core/analytics/` : ~13 sous-modules orphelins non re-vérifiés un par un (conforme doc). +- Reste couvert : chaîne détection/grounding/résolution + intelligence = prouvés. **Carto + considérée complète sur le périmètre runtime actif.**