Commit Graph

393 Commits

Author SHA1 Message Date
Dom
d422aa119c docs(coordination): require claude qwen vision guardrails 2026-05-29 13:59:39 +02:00
Dom
7b943926db docs(coordination): clarify vwb learning bridge 2026-05-29 13:46:22 +02:00
Dom
99f89317cb feat(lea): substitute save menu gesture 2026-05-29 13:45:44 +02:00
Dom
6b8114eb97 docs(coordination): recadre lea direct competence flow 2026-05-29 13:41:18 +02:00
Dom
7ef98d8089 feat(lea): expose competence replay api 2026-05-29 13:40:15 +02:00
Dom
8ea4ed0ad2 docs(coordination): record supervised competence replay plan 2026-05-29 11:38:51 +02:00
Dom
a49f59b4d6 feat(competences): plan supervised replay tests 2026-05-29 11:38:12 +02:00
Dom
762e75a077 docs(coordination): record competence catalog integration 2026-05-29 11:29:18 +02:00
Dom
c1a144c673 feat(vwb): expose competence yaml catalog 2026-05-29 11:28:25 +02:00
Dom
e8a0fb0e42 feat(competences): extract batch candidates 2026-05-29 11:25:00 +02:00
Dom
4ba426c205 fix(replay): guard single in-flight dispatch
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.
2026-05-25 11:00:59 +02:00
Dom
7bb8d543ab feat(cognition): dataclasses Trace + SceneExpected + Precondition (Phase 2.1)
Crée les 3 dataclasses du modèle Mandat/Protocoles/Scènes v0.3 dans
core/cognition/, standalone (aucun branchement runtime), avec
sérialisation JSON explicite et tests offline.

Préparation des phases :
- Phase 2.1 plan : objet Trace (mandate_id, intention_id, scene_id,
  affordance_signature, expected_retour, level_of_delegation)
- Workpack A : SceneExpected (monitor_index, app_name, title_patterns,
  title_anti, window_rect_hint, scene_role, accepted_transitions,
  stability_ms) + helper matches_title()
- Workpack B : Precondition (kind, window_title_must_contain/anti,
  critic_question, verify_timeout_ms) + PreconditionRecovery
  (max_attempts, on_recovery_fail, actions)

Toutes les dataclasses sont frozen, immutables, avec to_dict/from_dict
tolérants (champs vides/None -> instance vide). Validation au __post_init__
pour Precondition.kind et PreconditionRecovery.on_recovery_fail.

Aucune dépendance runtime obligatoire : si l'objet n'est pas posé sur
une action, fallback comportement actuel. Aucune modif executor /
api_stream / replay_engine / grounding.

Tests : 22/22 passent (sérialisation JSON, contrats from_dict tolérants,
validation kinds, helpers matches_title/check_title, anti-intention).

Tag rollback : rollback/pre-cognition-dataclasses-2026-05-25_0610
2026-05-25 06:08:18 +02:00
Dom
debd7b423c feat(evaluation): add local Ollama LeaBench adapter 2026-05-24 21:58:06 +02:00
Dom
6544ebe3f0 feat(evaluation): add 16 LeaBench cases from replay failures
Extend LeaBench computer-use coverage with cases mined from
data/training/replay_failures/. Adds 8 distinct categories:
save_as visible, target absent (blank desktop / wrong window),
start button, start-menu search, task-view wrong state, systray
overflow, ambiguous tab labels, modal-blocker dialogs, and a
wrong-window Lea-terminal case.

- 16 new cases in benchmarks/computer_use/cases/leabench_extended_2026-05-24.jsonl
- 0 duplicate case_id vs notepad_replay_failures_2026-05-24.jsonl
- Validated with: python3 tools/lea_bench.py --cases ... --json
- pytest tests/unit/test_computer_use_bench.py: 7 passed
2026-05-24 21:57:24 +02:00
Dom
10136f0ee0 feat(agent): add standalone anchor-relative resolver 2026-05-24 21:54:39 +02:00
Dom
054279feb4 feat(evaluation): add LeaBench model prompt packs 2026-05-24 21:53:24 +02:00
Dom
ea1f57afb1 feat(evaluation): add LeaBench computer-use scorer 2026-05-24 21:21:17 +02:00
Dom
345762330b fix(agent): respect server visual reject before text fallback 2026-05-24 21:10:42 +02:00
Dom
b1b32187ba fix(agent): P0.6 guard human corrections 2026-05-24 21:07:12 +02:00
Dom
ad24d16d83 fix(executor): P0.9 double-check stabilité post-transition fenêtre
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
2026-05-24 20:24:46 +02:00
Dom
a76f3db682 feat(executor): P1 DialogResolver serveur en fallback du catalog local
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
2026-05-24 19:59:22 +02:00
Dom
9a029a221d fix(executor): timeout _capture_human_correction 120s → 30s
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
2026-05-24 19:14:12 +02:00
Dom
5ed1810ef3 fix(memory): rejeter coords (0,0) et hors [0,1] dans memory_record_success
Bug observé sur replay_sess_63a1313b 2026-05-24 18:31-18:32 :
_capture_human_correction() côté Léa retourne des human_actions sans
clic humain réel (cause racine côté agent à investiguer = P0.6).
En cascade, memory_record_success était appelé avec coords (0.0, 0.0)
et stockait des entrées poison dans target_memory.db.

Le sanity check existant rejetait < 0 ou > 1 mais laissait passer (0,0)
qui est mathématiquement valide. Au prochain replay, memory_lookup
trouvait l'entrée poison et faisait cliquer Léa au coin haut-gauche.

Patch : rejet explicite de (0,0) + warning au lieu de debug pour les
coords hors [0,1] (besoin de tracabilité runtime).

Filet en aval — la vraie cause côté Léa reste à corriger (P0.6).

Tag rollback : rollback/pre-P0.7-2026-05-24_1850
2026-05-24 19:01:18 +02:00
Dom
c9878f0a76 fix(validator-v2): override success=False uniquement sur TERMINATE
Symptôme observé sur replay_sess_7a4c8e72 (24/05 17:57) :
- Action act_setup_sess_verify (type=verify_screen) échoue 4x (+3 retries)
- Logs: [VALIDATOR_V2] override success→False verdict=continue conf=0.30
  failure_category=None reason='Aucun changement visible pour
  verify_screen (normal pour ce type d'action)'
- Replay tombe en status=error à 7/15 (régression vs 12/15 sans V2)

Cause: api_stream.py:3674 testait `if verdict != COMPLETE` (trop large) →
toute action qui ne change pas drastiquement l'écran (verify_screen, wait,
key_combo Ctrl+S avant ouverture dialog, etc.) renvoie verdict=CONTINUE
conf=0.30 du PixelDiffChecker via le default_checker de l'orchestrator,
ce qui était traité comme un échec à overrider.

Fix: override SEULEMENT sur verdict=TERMINATE (échec certain avec
failure_category). CONTINUE = faible signal = on laisse le pipeline
historique trancher.

COMPLETE n'a pas besoin d'être traité ici car on est déjà dans
`if report.success:` (success initial vrai).

Effet:
- verify_screen/wait/key_combo non-interactif → orchestrator retourne
  CONTINUE conf=0.30 → V2 ne touche pas report.success (comportement
  legacy préservé)
- click qui rate (act_raw_6c1432b3 type cible) → OcrRoiChecker retourne
  TERMINATE conf=0.85 failure_category=WRONG_APPLICATION → override OK

Tests R1 inchangés (TERMINATE branch testée explicitement).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 17:59:35 +02:00
Dom
08701761e6 merge(R2): DialogResolver MVP P0 (worktree a86565d0) 2026-05-24 17:53:35 +02:00
Dom
a13d6d0052 merge(R1): Validator MVP P0 (worktree a0dcb652) 2026-05-24 17:53:30 +02:00
Dom
84d2d4a667 feat(dialog): R2 MVP P0 — DialogResolver + catalogue 10 entrées (flag OFF default)
- agent_v0/server_v1/core/dialog/ : catalogue compact + DialogResolver
  stateless (match titre + evidence, trichotomie stricte auto/pause/skip).
- 10 entrées P0 : confirm-save-overwrite, notepad-unsaved-changes,
  windows-file-explorer (fallback replay 4c38dbb8), easily-save/overwrite/
  confirm-action/clinical-warning, windows-uac, windows-hello-credui,
  edge-update.
- Validateur déclaratif `system_modals_cannot_be_overridden` : rejette
  toute surcharge auto/skip sur modaux SYSTÈME (windows-/defender-).
- Endpoint POST /api/v1/dialog/resolve derrière flag
  RPA_DIALOG_RESOLVER_ENABLED (OFF par défaut → 503). Aucun
  rebranchement côté agent_v1 (executor.py inchangé, P1 plus tard).
- 25 tests pytest passants (19 unit + 6 intégration HTTP).

Spec : docs/recherche/SPEC_POPUPS_CATALOGUE.md §2bis / §3.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 17:52:38 +02:00
Dom
1b4e64960b feat(validator): R1 MVP P0 — OcrRoiChecker + orchestrator (flag OFF default)
Package core/validation/ minimal :
- result.py : Verdict, FailureCategory, ValidationResult
- pixel_diff_checker.py : wrapper de ReplayVerifier.verify_action
- ocr_roi_checker.py : ROI 80px autour du clic, détecte WRONG_APPLICATION
  via SUSPECT_TOKENS (edge/https/explorateur de fichiers/…)
- orchestrator.py : Validator dispatch action_type → checkers + agrégation

Wiring api_stream.py:3646 derrière RPA_VALIDATOR_V2_ENABLED (OFF par défaut).
Si verdict ≠ COMPLETE, override report.success=False et expose failure_category
dans result_entry. Zero régression flag OFF.

Tests :
- tests/unit/test_validator_v2.py : 13 tests (Checkers + Validator + sérialisation)
- tests/integration/test_validator_step10.py : 2 tests reproduisant le bug
  replay_sess_4c38dbb8 / act_raw_6c1432b3 (clic Enregistrer fait basculer
  vers Explorateur de fichiers) — Validator retourne WRONG_APPLICATION

Activation pour test live : RPA_VALIDATOR_V2_ENABLED=true

Cf. docs/recherche/SPEC_VALIDATOR_MATRICE.md, AXE_B2_DEEP_VALIDATOR.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 17:52:06 +02:00
Dom
bd100bc538 fix(critic): R0 — réveiller l'enrichissement gemma4 (Critic sémantique)
Symptôme observé replay_sess_4c38dbb8 (24/05) :
- 0/15 actions avec expected_result rempli
- Conséquence : api_stream.py:3630 verify_with_critic() jamais appelé
  (conditionné à action.expected_result non vide)
- Donc Critic sémantique (Ollama) désarmé en production, seul le
  pixel-diff tournait

Causes racines identifiées :
1. _GEMMA4_PORT=11435 hardcodé (legacy Docker dédié supprimé) →
   check /api/tags timeout silencieux → fonction sort early
2. _CRITIC_MODEL="gemma4:e4b" hardcodé → modèle non installé
3. "think": True dans le payload → "qwen2.5vl:7b-rpa" does not
   support thinking → 400 sur tous les appels → if not resp.ok: continue
4. Prompt sans few-shot → qwen2.5vl converse au lieu de respecter
   le format strict INTENTION/AVANT/APRES → parsing vide

Fix (stream_processor.py) :
- _GEMMA4_PORT default 11435 → 11434 (Ollama native)
- _CRITIC_MODEL = os.environ.get("RPA_CRITIC_MODEL", "qwen2.5vl:7b-rpa")
- Remplacement de 3 "gemma4:e4b" hardcodés → _CRITIC_MODEL
- _unload_gemma4() → no-op (legacy Docker n'existe plus)
- Prompt enrichissement : ajout exemple few-shot (Cliquer Enregistrer)
- "think": True → False (qwen2.5vl ne supporte pas)

Config .env.local :
- RPA_VLM_MODEL=qwen2.5vl:7b → qwen2.5vl:7b-rpa (variant num_ctx=8192,
  créé via Modelfile pour permettre offload partiel GPU sur RTX 5070
  12 GB ; sans ça, num_ctx=128k par défaut = 12.5 GB requis = OOM full
  CPU fallback observé 17:11 le 24/05)

Validation :
- Avant fix : 0/8 actions enrichies (110 ms total = appels échoués
  immédiatement avec 400)
- Après fix : 5/8 actions enrichies en 35s (~7s/action, cohérent avec
  appels VLM réels qwen2.5vl)

Side effects systemd (à committer séparément côté infra) :
- OLLAMA_KEEP_ALIVE: 5m → 24h
- t2a-viewer.service stopped + disabled (libère ~2.9 GB VRAM)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 17:42:44 +02:00
Dom
1647e42d32 fix(agent_v1): keepalive headless quand pystray ne peut pas tenir le main thread
Symptome (3 incidents 24h les 24/05) : apres relance distante de Lea via SSH,
les polls /replay/next repartent un moment puis s'arretent. Diagnostic :
- agent_v1/ui/smart_tray.py:875 utilise pystray.Icon.run() comme boucle principale
- main.py:132-133 lance _replay_poll_loop et _background_heartbeat_loop en
  daemon threads
- Quand Lea est lancee via sshpass sans session interactive Windows, pystray
  echoue (pas de systray accessible) et icon.run() sort
- agent.run() retourne, main() retourne, main thread termine
- Les daemon threads meurent avec le main thread (par design Python)

Fix : _headless_keepalive() maintient le main thread vivant via threading.Event
quand agent.run() sort en laissant agent.running=True (cas anormal). Handlers
SIGTERM/SIGINT/SIGBREAK pour shutdown propre.

Invisible en mode interactif normal (icon.run() ne sort jamais).
Pas de modification de smart_tray ni de la cascade visuelle.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 16:51:19 +02:00
Dom
7df51d2c79 snapshot: WIP 5j replay reliability (B1 watchdog + dialog handlers + grounding drift)
Snapshot avant correction du blocage relance Léa (3 incidents 24h: SSH refusé,
polls morts ×2). Point de rollback stable.

Contenu:
- agent_v1/core/executor.py: 5 patchs dialog handling (saveas drift, close_tab
  hotkey fallback, confirm_save Unicode apostrophe, foreground dialog
  recontextualization, runtime_dialog in-loop) + helpers normalize_window_hint,
  requires_post_verify_window_transition
- agent_v1/core/grounding.py: garde drift template fix (fallback_x/y plumbed)
- server_v1/replay_watchdog.py (NEW): orphan watchdog B1, scan 10s timeout 30s
- server_v1/api_stream.py: dispatched_action plumbing, watchdog lifespan,
  metrics endpoint
- server_v1/replay_engine.py: _schedule_retry préserve original_action +
  dispatched_action
- stream_processor.py: gardes _infer_tab_switch_target (no false switch_tab
  on save_as dialog open) + _attach_expected_window_before
- tests/integration: test_replay_watchdog.py (8 cas), test_stream_processor.py
- tests/unit: test_executor_verify_window_guard.py (start_button, close_tab,
  runtime_dialog, post_verify, transition fallbacks)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 16:48:37 +02:00
Dom
5ea4960e65 backup: snapshot post-démo GHT 2026-05-19
Some checks failed
tests / Lint (ruff + black) (push) Successful in 1m50s
tests / Tests unitaires (sans GPU) (push) Failing after 1m50s
tests / Tests sécurité (critique) (push) Has been skipped
Backup état complet après enregistrement vidéo démo de bout en bout.
À utiliser comme point de référence pour la consolidation post-démo.

Changements majeurs de la session 18-19 mai :
- AIVA-URGENCE : page autonome avec preset URL + auto-focus chain
- Workflow Demo_urgence_3_db : merge linux_db + steps AIVA + pause humaine NoMachine
- Bypass LLM (static_result / static_text) dans replay_engine
  pour démos déterministes sans appel Ollama
- Fix api_stream:3013 — replay_paused au premier polling /next
- dag_execute : lift duration_ms vers top-level pour wait runtime
- NPM bypass auth /aiva-urgence/ via location ^~ (proxy_host/10.conf hors git)
- scripts/cancel-replays.sh — workaround Stop VWB qui ne purge pas la queue

Anchors visuels (468) forcés dans le commit pour garantir restorabilité.
DB workflows actuelle + ~12 .bak DB de la journée incluses.

Sujets identifiés pour consolidation post-démo (TODO) :
1. Bug VWB recapture anchor ne régénère pas le PNG
2. Léa client accumule état mémoire (restart périodique requis)
3. Stop VWB ne purge pas la queue serveur (lien manquant vers /replay/cancel)
4. Bug coord client mss tronqué 2560x60 → mapping Y cassé
5. delay_before/delay_after ignorés au runtime (fix partiel duration_ms)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 14:55:06 +02:00
Dom
f2212e77e3 feat(t2a): bench_t2a_dryrun.py + t2a_mappings.py - mini-bench standalone 11 dossiers POC
Bench standalone qui exécute build_dpi_enriched + appel LLM sur les 11
dossiers POC GHT Sud 95 (docs/clients/ght_sud_95/mockup_easily_assure/data.js),
sans passer par Demo_urgence_2 ni Léa/Windows. Permet de mesurer la
convergence durée/décision Python ↔ LLM sur un panel représentatif AVANT
d'écrire le garde-fou serveur du commit 2.

core/llm/t2a_mappings.py :
- Module partagé TERRAIN_VERS_T2A (4 entrées validées par Dom 12/05)
- Importé par le bench, sera importé aussi par le garde-fou serveur commit 2
- Cas non mappés volontairement documentés (Retour structure d'origine,
  chaîne vide pour statut_attente)

scripts/bench_t2a_dryrun.py :
- Parsing data.js via node (vm.runInContext) → 11 dossiers en JSON
- Reconstruction d'un dpi_raw plat simulant l'OCR scroll auto :
  bandeau Easily Assure répété 5x (1 par onglet) + sections motif /
  examens / imagerie / notes médicales / Synthèse Urgences au format
  LIBELLÉ    VALEUR
- NE bypasse PAS build_dpi_enriched : le dpi_raw est texte plat re-parsé
  par la fonction (test de robustesse réel du parser regex)
- Appel LLM déterministe : temperature=0, seed=42, model=gemma4:31b-cloud
- Vérification empirique du respect du seed (2 appels successifs sur 1er
  dossier, comparaison decision/durée/justif) → warning si bruit cloud
- 4 traces structurées par dossier dans logs/t2a_dryrun/<IPP>_<ts>.log :
  [t2a_dryrun_metadata] / [t2a_dryrun_prompt] / [t2a_dryrun_response]
  ou [t2a_dryrun_error] en cas d'échec API
- Filet data_quality_warning (incohérence âge déclaré vs date naissance,
  motif vs diagnostic principal, décision vide) — filet, pas analyse
  exhaustive ; signale sans corriger (anonymisation v1 incertaine)
- Tableau récap stdout 9 colonnes + CSV scripts/bench_t2a_dryrun_<ts>.csv
- Stats agrégées : convergence durée X/N, convergence décision X/N
  mappés, liste détaillée des divergences avec pointeurs vers logs
- Recommandation auto : réécrire PROMPT 3 ou non selon convergence durée

Activation : T2A_DRYRUN=1 python scripts/bench_t2a_dryrun.py
Options : --ipp <IPP> (1 dossier), --skip-seed-check

Smoke test pré-commit (sans LLM) : parsing + dpi_raw + build_dpi_enriched
sur les 11 dossiers → 11/11 metadata complets, 0 parsing_warning,
durées calculées de 2.0h à 12.02h, décompo décisions terrain conforme
(7 Consultation + 1 Hosp + 1 UHCD + 1 Transfert + 1 Retour structure).

Brief complet : docs/handoffs/2026-05-12_brief_S1_build_dpi_enriched.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 18:55:57 +02:00
Dom
9872f4510c feat(t2a): build_dpi_enriched - extraction déterministe horaires + classifications cliniques
Préprocesseur Python qui injecte un bloc FAITS_CALCULÉS en tête du DPI
avant l'appel LLM, pour neutraliser l'hallucination de durée (bug "23h"
sur cas MOREL, confusion avec "depuis 23h" de l'Observ. IDE Urg).

Extrait depuis le bandeau Easily Assure et la Synthèse Urgences :
- âge (dateutil.relativedelta)
- date admission / sortie + durée passage (format humain + décimal)
- CCMU / GEMSA libellé complet (parser multi-ligne)
- priorité IAO, mode de venue / médicalisation / mode d'entrée
- diagnostic principal
- decision_terrain + orientation_terrain (metadata only, jamais injectés
  dans le prompt pour ne pas biaiser le LLM)

Retour tuple (dpi_enriched, metadata) pour permettre les garde-fous
serveur Python ↔ LLM au commit 2.

Robustesse :
- re.search 1re occurrence + WARNING si bandeau divergent multi-occurrences
- Synthèse Urgences priorité sur bandeau pour dates
- Valeur exigée sur même ligne que label (évite capture de section title)
- Cas négatif (horaires absents) → "NON CALCULABLE" + parsing_warnings
- Jamais de crash, retour tuple toujours valide

Tests : 4/4 verts (golden MOREL string + metadata, négatif sortie absente,
DPI vide). Pas de régression sur tests/integration/test_t2a_extract.py.

Brief complet : docs/handoffs/2026-05-12_brief_S1_build_dpi_enriched.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 18:49:49 +02:00
Dom
2eeaa806bb docs(handoff): clôture session 2026-05-09
Session de 6h consacrée au fix DETTE-006 (bug d'échelle pixel
grounding). Bilan : 2/5 commits fix faits (smart_resize + refactor
parser bbox_2d), 3/5 bloqués par découverte DETTE-010 (divergence
factor 28 vs 32 sur checkpoint Qwen3-VL-8B-Instruct, à instruire
demain matin).

Effets de bord positifs : registre dette technique créé
(14 entrées P1/P2/P3), investigation mémoire visuelle orpheline
documentée, infra clarifiée (vLLM absent, Transformers direct retenu,
checkpoint Qwen3-VL-8B fp16 téléchargé 17 GB).

Voir docs/handoffs/2026-05-09_session_audit.md pour détail.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
demo-stable-2026-05-12
2026-05-09 15:53:26 +02:00
Dom
df5ad59330 docs(dette): MAJ DETTE-010 (config trouvé, divergences) + création DETTE-014 (smart_resize calé sur mauvaise référence)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 15:46:46 +02:00
Dom
bfbf0f9c3e refactor(grounding): centralise parser bbox_2d
Avant : 4 occurrences de parsing en cascade dans resolve_engine.py
(L840-885, L903-915, L2569-2580, ~110 lignes au total).

Après : centralisation dans core/grounding/bbox_parser.py avec
paramètre formats= permettant de filtrer les formats reconnus
selon le contrat sémantique de chaque site d'appel.

Préservation des contrats sémantiques (strict no-op) :
- Occ 1+2 (cascade principale) : tous formats (par défaut)
- Occ 3 (retry multi-image) : formats={"xy_json", "raw_array"}
  pour respecter le prompt qui impose {"x": NNN, "y": NNN} in pixels
- Occ 4 (_locate_popup_button) : formats={"bbox_2d"} pour respecter
  le prompt qui demande "bounding box"

Notes :
- Mini-bug Occ 3 retry multi-image (division systématique sans
  heuristique x>1, produisait coordonnées aberrantes ~0.0004 si
  VLM retournait déjà du pourcentage) corrigé incidemment via
  centralisation. Pas de régression possible (résultat précédent
  aberrant par construction).
- Occ 4 : bbox_2d strict 4-coords élargi à bbox_2d 2 ou 4 coords.
  Contrat sémantique "bounding box" respecté ; un point 2-coords
  interprété comme centre de bbox.

Tests : 26 cas dans test_bbox_parser.py (tous formats × cascade
+ filtre formats= + validated). 121 PASS / 0 FAIL sur le périmètre
refactor (5 fichiers ciblés).

Net : -96 lignes dans resolve_engine.py, +120 lignes module
+ 250 lignes tests.

refs DETTE-006 (étape 2/5 du fix smart_resize)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 15:30:25 +02:00
Dom
ecc5a233a7 docs(dette): création DETTE-013 env tests dev local
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 14:49:57 +02:00
Dom
293e54b4e6 docs(dette): création DETTE-012 (vLLM hors scope) + maj DETTE-010 (cible Transformers + AWQ)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 13:47:21 +02:00
Dom
0d7bcd18ac feat(grounding): module smart_resize officiel Qwen3-VL
Module pur core/grounding/smart_resize.py implémentant la formule
smart_resize officielle (transformers.qwen2_vl.image_processing_qwen2_vl,
utilisée par Qwen3VLProcessor pour les images via wrap Qwen2VLImageProcessor).

Helpers exposés : _round_by_factor, _floor_by_factor, _ceil_by_factor.
Constantes : FACTOR_DEFAULT=28, MIN_PIXELS_DEFAULT=3136,
MAX_PIXELS_DEFAULT=1_003_520, MAX_RATIO_DEFAULT=200.

Tests : tests/unit/test_smart_resize.py — 32 cas, 100% coverage sur le
module (mesure via coverage API directe, pytest-cov bloqué par bug cv2
préexistant tracé dans DETTE-011).

refs DETTE-006 (étape 1/5 du fix smart_resize)
refs DETTE-007 (création de la 3ème implémentation, à unifier post-démo)
refs DETTE-010 (vérif preprocessor_config.json checkpoint Qwen3-VL-8B
                bloquante avant Étape 2)
refs DETTE-011 (bug cv2 contourné pour mesure coverage)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 12:42:47 +02:00
Dom
4df1ba5779 docs(dette): création DETTE-011 bug cv2 Python 3.12
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 12:42:36 +02:00
Dom
e9702b4df9 docs(dette): création DETTE-010 vérif preprocessor_config Qwen3-VL
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 12:08:08 +02:00
Dom
e0b47e4518 docs(refs): commit groupé docs de référence session 2026-05-08
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 11:32:52 +02:00
Dom
5dc20cc85b docs(dette): rectif mapping DETTE-005 + DETTE-008/009 + investigation mémoire visuelle orpheline
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 11:23:45 +02:00
Dom
88ed103de5 docs(dette): création registre dette technique + 7 entrées rétroactives
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-09 10:43:27 +02:00
Dom
194853cebb docs(handoff): clôture session 2026-05-08
3 commits du jour : pré-check OCR réactivé + instrumenté + bug
spatial documenté. Plan demain : fix smart_resize vLLM ciblé
selon MIGRATION_VLM_PLAN_2026-05-09.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 22:33:35 +02:00
Dom
626823d327 docs(bug): pré-check OCR spatialement aveugle - dette identifiée
Bug découvert pendant test live du 2026-05-08.
_text_match_fuzzy valide la présence du texte dans le crop (560×560 px)
sans vérifier sa position au point cliqué. Sur onglets serrés (3 px),
valide à tort les clics adjacents.

À fixer post-démo Kerella - Option B préférée
(bboxes EasyOCR + distance).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 22:31:56 +02:00
Dom
2e76b44ff3 feat(observability): log positif pré-check OCR pour traçabilité runtime
Avant : succès silencieux (seul rejet loggé)
Après : log INFO à chaque appel avec by_text, position, méthode,
observed, is_valid, latence

Permet de valider en runtime que le pré-check OCR tourne bien
sur les résolutions resolved=True (cf commit 731b5bcae).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 22:23:32 +02:00
Dom
731b5bcae2 fix(replay): réactivation pré-check OCR avec calibrage chirurgical
- Flag RPA_ENABLE_TEXT_PRECHECK défaut true (vs false pendant prépa démo)
- radius_px 200 → 280 (englobe textes longs type "Synthèse Urgences")
- min_token_ratio 0.60 → 0.50 (tolère onglets fragmentés par OCR)
- Commentaire historique restructuré avec procédure troubleshooting
- Docstring synchronisée avec valeur effective

Audit complet : docs/AUDIT_CONTROLES_DEBRANCHES_2026-05-08.md
Réactive contrôle #3 sur 5 identifiés (les 4 autres restent désactivés
pour aujourd'hui — décision chirurgicale 1 par 1).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 14:27:21 +02:00
Dom
8648e375fe docs(handoff): session audit 2026-05-08 - controles debranches 2026-05-08 11:37:40 +02:00