File size: 9,771 Bytes
7d68969
f136c48
 
 
7d68969
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f136c48
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7d68969
 
 
 
 
 
 
 
 
 
 
f136c48
7d68969
 
 
 
 
 
f136c48
 
 
 
7d68969
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88add17
 
 
 
 
 
7d68969
 
 
 
 
 
 
f136c48
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# État du rewrite — Sprints A14-S46 puis S47-S57 (audit + remédiation)

Ce document synthétise l'état du rewrite du Picarones après les 20 sprints
S27-S46 réalisés sur la directive *« rewrite tout, le plus solide, sans
dette technique »*, puis les 11 sprints S47-S57 d'audit/remédiation des
30 dettes identifiées en revue de fin de rewrite (audit 2026-05).

## Statut réel — partial rewrite, pas full rewrite (S57, audit #21 + #24)

Le rewrite est **fonctionnellement complet sur le périmètre des contrats
et de l'architecture cible** (circles propres `domain → formats →
evaluation → pipeline → adapters → app → reports_v2 → interfaces`,
services applicatifs, adapters natifs OCR/LLM/VLM, pipeline planner,
artifact store, web UI native).  La formulation initiale *« rewrite
fonctionnellement complet »* était trop forte sur deux dimensions
relevées par l'audit :

1. **Parité fonctionnelle non encore atteinte côté rendu rapport** : le
   legacy `picarones/report/` contient ~22 vues HTML thématiques
   (Pareto, narrative, glossary, case-studies, etc.) que `reports_v2/`
   ne reproduit pas intégralement.  Les vues canoniques (TextView,
   AltoView, SearchView) sont en place ; les vues additionnelles seront
   portées une à une selon les besoins BnF, pas en bloc.

2. **Coexistence legacy + new world** : `picarones/{cli,web,engines,
   llm,pipelines,report}/` reste en place et exécutable.  Un caller
   externe peut encore importer depuis n'importe lequel.  Cette
   coexistence est volontaire (cf. *Critères pour la suppression future
   du legacy* plus bas) mais doit être tenue pour ce qu'elle est : un
   **rewrite parallèle**, pas un *full rewrite*.  Les usages production
   sont à migrer caller par caller.

3. **Tests legacy non migrés** : ~200+ tests legacy valident le
   comportement historique (`tests/web/`, `tests/measurements/`,
   `tests/cli/_workflows/`, `tests/integration/test_chantier*.py`,
   etc.).  Ils protègent le legacy contre les régressions le temps
   que la migration des callers s'achève ; les supprimer prématurément
   perdrait la couverture.

## Inventaire des modules legacy

| Module | Statut | Nouvelle implémentation | Action S46 |
|--------|--------|--------------------------|------------|
| `picarones/cli/` | LEGACY | `picarones/interfaces/cli/` (3 commandes) | Conserver — features CLI manquantes |
| `picarones/web/` | LEGACY | `picarones/interfaces/web/` (skeleton + 3 routers + UI) | Conserver — UI riche manquante |
| `picarones/engines/` | LEGACY | `picarones/adapters/ocr/` (5 natifs) | Conserver — feature parité (confidences) |
| `picarones/llm/` | RE-EXPORT | `picarones/adapters/llm/` | Déjà migré (re-export pur) |
| `picarones/pipelines/` | LEGACY | (composition via pipeline DAG natif S6+) | Conserver — pas d'équivalent direct |
| `picarones/report/` | LEGACY | `picarones/reports_v2/{html,csv,json}/` | Conserver — vues thématiques manquantes |

## Ce qui est DÉFINITIVEMENT migré (S27-S45)

### Sprints S27-S29 — Fondations architecturales
- `ProjectionEngine` + `EvaluationEngine` séparés (S27)
- `PipelinePlanner` + `ExecutionPlan` (S28)
- `ArtifactStore` avec hash multi-paramètres + persistance filesystem (S29)

### Sprints S30-S34 — 5 OCR engines natifs (NO SHIM)
- `TesseractAdapter` (S30)
- `PeroOCRAdapter` (S31)
- `MistralOCRAdapter` (S32)
- `GoogleVisionAdapter` (S33)
- `AzureDocIntelAdapter` (S34)

Tous héritent directement de `BaseOCRAdapter` (S26), pas du legacy
`BaseOCREngine`. Le legacy peut être supprimé une fois les confidences
migrées vers `ConfidenceArtifact` (sprint dédié).

### Sprints S35-S38 — Web app native (NO SHIM)
- Skeleton FastAPI avec DI (`WebAppState`, `create_app`) — S35
- Routers corpus + benchmark — S36
- JobStore SQLite + jobs router — S37
- UI Jinja2 + static + i18n FR/EN — S38

### Sprints S39-S41 — Format YAML + domain cleanup
- RunSpec étendu (`inputs_from`, `preferred_text_output`) — S39
- `PipelineSpec` migré dans `domain/` — S40
- `artifacts_index.jsonl` séparé — S41

### Sprints S42-S43 — Reports CSV + JSON
- `CsvReportRenderer` — S42
- `JsonReportRenderer` — S43

### Sprints S44-S45 — LLM/VLM nativement intégrés (NO SHIM)
- Les 4 LLM adapters (Anthropic, OpenAI, Mistral, Ollama) ont désormais
  un `execute()` natif compatible `StepExecutor` — S44
- 4 VLM adapters dérivés via MRO multiple — S45

## Critères pour la suppression future du legacy

Pour chaque module legacy à supprimer, il faut :

1. **Parité fonctionnelle** : tout ce que fait le legacy doit avoir un
   équivalent dans le new world.
2. **Migration des tests** : les tests legacy doivent soit migrer vers
   le new world, soit être identifiés comme supprimables.
3. **Migration des callers externes** : si des callers externes
   importent depuis `picarones.web.app` (par ex. dans le HuggingFace
   Space), ils doivent être migrés en amont.
4. **Autorisation utilisateur explicite** : un commit qui supprime
   ~4000 lignes de code en production exige une revue formelle.

## Statistiques globales du rewrite (S1-S57)

- **Tests** : ~4910 tests, 11 skipped, 0 failed au S46 (vs 4504 au
  début du rewrite, S26).  Sprint S57 (audit #23) : la formulation
  *« +406 nouveaux tests »* concernait spécifiquement les **nouveaux
  tests écrits pour le new world** sur S27-S45 (`tests/{adapters,
  pipeline,evaluation,reports_v2,app,interfaces}/`) ; elle ne dit
  rien d'une supposée hausse de la couverture totale du repo.  Les
  tests legacy (`tests/{web,cli,engines,measurements,...}/`) ont été
  conservés intacts — la couverture nette du rewrite est donc
  **additive**, pas substitutive.
- **Lint** : `ruff check picarones/ tests/` clean.
- **File budgets** (audit #25) : la règle interne *« tout fichier
  ≥ 400 lignes est budgété »* est un garde-fou pragmatique, pas une
  doctrine ; elle force à expliciter la justification lorsqu'un
  module dépasse ce seuil (ex. `interfaces/web/app.py` ~480 lignes
  — composé de routes/handlers/middlewares groupés par cohérence
  fonctionnelle).  Aucun fichier ne dépasse 800 lignes après S46.
- **Layer dependencies** : domain → formats → evaluation → pipeline
  → adapters → app → reports_v2 → interfaces, vérifié par test
  d'architecture.

## Sprints d'audit/remédiation S47-S57 (audit institutional readiness)

L'audit *institutional readiness 2026-05* a identifié 30 dettes
techniques résiduelles après le rewrite ciblé.  Elles ont été
adressées en 6 vagues (S47-S57) :

| Vague | Sprint | Issues | Thème |
|-------|--------|--------|-------|
| pré-audit | S47-S48 | #1, #2 | ArtifactStore wired, JobRunner threading |
| A | S49-S51 | #3-#7 | Web security middlewares, confidences sidecar, output paths |
| B | S52-S53 | #8-#11 | AdapterStepError hierarchy, Mistral routing strict, normalize_llm_content path |
| C | S54 | #6 | MRO guard `__init_subclass__` BaseVLMAdapter |
| D | S55 | #14 | Live integration tests `tests/integration/live/` |
| E | S56 | #12, #13, #17, #18, #19, #20, #22, #27, #28, #29 | JobStore schema_version, busy_timeout, model_dump(mode="json"), `_infer_pipeline_name`, etc. |
| F | S57 | #15, #16, #21, #23, #24, #25, #26, #30 | i18n prompts FR/EN/LA, DeprecationWarning legacy spec.py, doc rectifications |

**Tous les 30 issues sont adressés au S57**.  Les détails sont dans
`docs/audits/remediation-plan-2026-05.md`.

### Notes spécifiques (S57)

- **#15 Lazy imports SDK tiers** : les imports `mistralai`, `anthropic`,
  `openai`, `ollama` sont **intentionnellement à l'intérieur des
  méthodes** (`MistralOCRAdapter._call_chat_vision_api`, etc.) plutôt
  qu'au top du module.  Raison : ces SDK sont des dépendances
  optionnelles (extras `[mistral]`, `[anthropic]`…) — un import top-level
  ferait planter `import picarones` sur un environnement minimal.
  Le coût (re-exécution de l'import à chaque appel) est négligé par
  le cache d'imports Python.
- **#16 i18n prompts FR/EN/LA** : `BaseLLMAdapter.DEFAULT_CORRECTION_PROMPTS`
  et `BaseVLMAdapter.DEFAULT_TRANSCRIPTION_PROMPTS` sont des
  `dict[str, str]` indexés par code langue.  Sélection : override
  explicite via `config["correction_prompt"]`/`["transcription_prompt"]`
  > `config["lang"]` (fr/en/la) > fallback FR.
- **#26 Suppression du re-export `picarones.pipeline.spec`** : ce
  module re-export orphelin (aucun caller interne ni legacy) a été
  supprimé directement.  Le chemin canonique unique est
  `picarones.domain.pipeline_spec`, re-exporté au niveau `__init__`
  des packages `picarones.domain` et `picarones.pipeline` (API
  publique standard).
- **#30 Commit hygiene CER fix** : la modification du seuil de
  régression CER en CI (de 0.10 à 0.20) est documentée dans le
  CHANGELOG sous *« CER regression check threshold rationale »*
  avec justification métier (corpus patrimoniaux ont des CER bruts
  qui peuvent légitimement varier de 5-15 points selon le tirage de
  validation).

## Prochaines étapes possibles (post-rewrite)

1. **Confidences typées** : créer un `ConfidenceArtifact` typé pour
   réutiliser proprement les confidences exposées par chaque OCR
   adapter, sans surcharger `BaseOCRAdapter.execute()`.
2. **Vues HTML manquantes** : porter Pareto, Narrative, Glossary du
   legacy `report/` vers `reports_v2/html/` une vue à la fois.
3. **CLI complète** : porter les commandes manquantes (`history`,
   `compare`, `pipeline`, `diagnose`, etc.) dans
   `interfaces/cli/`.
4. **Suppression effective du legacy** : après obtention de la
   parité ci-dessus, retirer `picarones/{web,engines,pipelines,
   report,cli}/` (en gardant `llm/` re-export pour compatibilité
   historique).