File size: 5,565 Bytes
3bffe86
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2b782d0
 
 
3bffe86
2b782d0
3bffe86
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2b782d0
 
3bffe86
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
# Cohérence documentation — contrat d'écriture

> Sprint A2 du plan de remédiation institutionnelle
> ([`docs/audits/remediation-plan-2026-05.md`](../audits/remediation-plan-2026-05.md)).

Picarones expose plusieurs documents de premier contact (README.md,
SPECS.md, CHANGELOG.md, CITATION.cff, …). Pour qu'un primo-lecteur
ne soit jamais induit en erreur, **la documentation publiée doit
refléter le code réel**. Le suite de tests `tests/docs/` matérialise
ce contrat.

## TL;DR

```bash
make doc-check       # rapport en < 5 s
# ou directement :
pytest tests/docs/ -v
```

Si vous ajoutez un moteur OCR, une commande CLI, un endpoint web ou
modifiez le compteur de tests, lisez la suite ci-dessous.

---

## Tests posés en A2

### `test_readme_consistency.py`

Vérifie que :

| Item | Source de vérité | Sens du contrat |
|---|---|---|
| Moteurs OCR | `picarones/adapters/ocr/*.py` | Tout moteur listé dans le tableau « Supported Engines » du README doit avoir un adapter |
| Commandes CLI | `picarones/interfaces/cli/*.py` (Click) | Toute commande listée dans le README doit apparaître dans `picarones --help` |
| Endpoints API | `picarones/interfaces/web/app.py` (`app.openapi()`) | Tout endpoint listé doit exister dans la spec OpenAPI |
| Compteur de tests | `pytest --collect-only` | Toute mention « N tests » ou « N passed » doit être à 5 % près du baseline |
| Variables `AWS_*` | `picarones/adapters/ocr/aws*.py` | Si documentées, un adapter doit exister |

**Direction unidirectionnelle** : on vérifie que ce qui est *annoncé*
existe — pas que tout ce qui existe est annoncé. La direction réciproque
est posée en Sprint A13 (refonte intégrale du README).

### `test_specs_consistency.py`

Vérifie que :

- SPECS.md existe et déclare une version + une date.
- Toute promesse explicitement *abandonnée* depuis SPECS v1 (AWS Textract,
  Calamari, OCRopus, Recommandation automatique, Export PDF, k-means
  clustering, Annotations inline, Badge SVG) doit être marquée par un
  des trois mécanismes acceptés (cf. § « Mécanismes de tolérance » plus bas).

### `test_changelog_links.py`

Vérifie que :

- Le CHANGELOG existe, suit Keep-a-Changelog, contient des sections
  versionnées.
- Toute référence `Sprint NN` résout dans CHANGELOG ou CLAUDE.md.
- Tout lien interne (`docs/...`, `picarones/...`) pointe vers un
  fichier existant.

### `test_sprint_numbering.py`

Audit **informatif** (warnings, non bloquant) : trous de numérotation
des fichiers `test_sprintNN_*.py`, doublons, docstrings manquants.
Pour rendre bloquant ponctuellement : `pytest -W error::UserWarning
tests/docs/test_sprint_numbering.py`.

---

## Mécanismes de tolérance

Trois mécanismes permettent une exception ponctuelle :

### 1. Marqueur ligne par ligne (`test_readme_consistency.py`)

Pour autoriser une ligne de tableau temporairement non vérifiable :

```markdown
| Engine | Type | … |
|--------|------|---|
| **NewEngine** | Local Python | (en cours) | <!-- doc-check: skip-engine -->
```

Marqueurs reconnus : `skip-engine`, `skip-cli`, `skip-endpoint`,
`skip-env`. À utiliser avec modération — **tout `skip-*` doit être
expliqué en revue de PR**.

### 2. Bloc d'abandon global (`test_specs_consistency.py`)

Pour SPECS, les promesses explicitement abandonnées sont listées dans
un bloc unique en tête de l'addendum :

```markdown
<!-- specs-check: known-abandoned-start -->

- **AWS Textract** : adapter non implémenté ; reporté.
- **Calamari** : adapter non implémenté ; reporté.
- …

<!-- specs-check: known-abandoned-end -->
```

Le test accepte qu'une promesse listée dans ce bloc apparaisse aussi
ailleurs dans SPECS sans note de deprecation locale.

### 3. Note de deprecation locale (`test_specs_consistency.py`)

Alternative à la #2 quand on veut documenter une décision *à proximité*
de la mention :

```markdown
La recommandation automatique (§7.1) est **abandonnée** au profit du
moteur narratif factuel (Sprint 19) ; cf. la note de neutralité
éditoriale dans CLAUDE.md.
```

Le test scanne une fenêtre de 200 caractères autour de chaque mention
et accepte si l'un des mots `reporté`, `abandonné`, `non implémenté`,
`deferred`, `not implemented`, etc. est présent.

---

## Workflow de modification

| Vous modifiez… | Vous devez aussi… |
|---|---|
| `picarones/adapters/ocr/<X>.py` (nouveau) | Ajouter une ligne dans le tableau « Supported Engines » du README |
| `picarones/interfaces/cli/_<X>.py` (nouveau) | Ajouter la commande dans la table CLI du README |
| Un nouveau endpoint FastAPI | Ajouter dans la table « API endpoints » du README |
| Le nombre de tests | Mettre à jour les 3 mentions dans README (l/583, l/623, l/660) |
| Une promesse SPECS qui devient sans objet | Soit retirer la mention, soit ajouter dans le bloc `known-abandoned`, soit ajouter une note locale |

Le test `make doc-check` (ou directement `pytest tests/docs/`) tournera
automatiquement en CI à chaque PR. Un échec bloque le merge.

---

## À venir (Sprint A13)

La refonte du README en Sprint A13 ajoutera de la **génération
automatique** : les tableaux d'engines / CLI / endpoints / structure
projet seront générés depuis le code via `scripts/gen_readme_tables.py`,
insérés dans le README via des balises HTML
`<!-- generated:engines -->`. À ce moment-là, la direction réciproque
deviendra naturellement vérifiée (« tout ce qui existe est annoncé »).

D'ici là, ce contrat **uni-directionnel** est suffisant pour bloquer
les divergences les plus visibles.