Claude commited on
Commit
ebddecf
·
unverified ·
1 Parent(s): 13ba1e5

chore(versioning): S0-ter — fix broken narrative across changelog timeline

Browse files

Audit narratif a identifié 6 cassures :

1. Trou narratif `1.2.x → 0.9.0` entre archive et CHANGELOG actif
→ docs/archive/changelog-pre-v2.md : ajout d'une « Note de
transition (2026-05-23) » en tête qui explique :
- Le saut apparent 1.2.x → 0.9.0 est un repositionnement
éditorial assumé, pas une régression du code.
- La cible 1.3.0 (release institutionnelle BnF) n'a jamais
été publiée — pivot vers le rewrite, repositionné en 0.9.0.
- Architecture plus mature au 0.9.0 qu'au 1.2.x ; c'est la
surface fonctionnelle utilisateur qui manque pour 1.0+.

2. Section ``[Unreleased] — towards 1.3.0`` ouverte dans l'archive
→ Renommée ``[Non-livré] — anciennement « [Unreleased] — towards
1.3.0 »`` + note explicite « Section figée par le
repositionnement (2026-05-23) ». Contenu conservé tel quel.

3. Trois sections ``[Unreleased]`` dans CHANGELOG actif précèdent
``[0.9.0]`` du même mois — logiquement absurde
→ Ajout d'une section « Lecture chronologique » qui clarifie :
les 3 [Unreleased] documentent des chantiers parallèles dans
la fenêtre du rewrite, dont l'aboutissement est consigné dans
[0.9.0]. À partir de 0.9.0, le CHANGELOG suit Keep-a-Changelog
strict : une seule section [Unreleased] à la fois.

4. ``tests/golden/fixtures/benchmark_result_v2.json``
→ Renommé en ``benchmark_result_canonical.json`` (le « v2 » du
nom était hérité du codename « v2.0 » du rewrite — ambigu).
Adaptations dans test_benchmark_result_json_stable.py et
test_no_hardcoded_version.py.

5. Convention ``code_version="1.0.0"`` dans ~50 tests non documentée
→ Section « Convention `code_version` dans les tests » ajoutée
en tête de tests/_migration_helpers.py + pointeur dans CLAUDE.md.
Explique que cette valeur est un placeholder de fixture (la
sémantique testée ne dépend pas de la valeur réelle), neutralisé
par PLACEHOLDER_PATTERNS dans le garde-fou.

6. Docstrings de tests d'archi qui parlaient encore de « v2.0 »
→ Reformulés en « clôture du rewrite » / « release 0.9.0 » :
- test_no_legacy_imports_in_rewrite.py (5 occurrences)
- test_file_budgets.py (1 commentaire)

Verification :
- 5161 tests passed, 0 failed, 20 skipped
- make lint : All checks passed
- Lecteur qui parcourt la timeline complète a maintenant un fil
narratif explicite : archive (avec note de transition) → archive
fin (« Non-livré 1.3.0 ») → CHANGELOG actif (note repositionnement
+ note lecture chronologique) → 0.9.0.

https://claude.ai/code/session_01WYDbfkhKPeBZ15BTP4e9Ye

CHANGELOG.md CHANGED
@@ -53,6 +53,30 @@ jalons techniques au fil du chantier.
53
 
54
  ---
55
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  ## [Unreleased] — Migration Option B vers RunOrchestrator (mai 2026)
57
 
58
  Branche `claude/test-alto-pipelines-qyFsL` — chantier de migration
 
53
 
54
  ---
55
 
56
+ ## Lecture chronologique du fichier
57
+
58
+ Les **trois sections `[Unreleased]`** ci-dessous (« Migration Option B »,
59
+ « Audit code-quality », « Chantier post-rewrite ») documentent des
60
+ chantiers parallèles réalisés **pendant la fenêtre du rewrite**
61
+ (mai 2026), dont l'aboutissement est consigné dans la section
62
+ ``[0.9.0] — Legacy retirement complete`` plus bas. Elles ont été
63
+ préservées sous forme `[Unreleased]` pour refléter l'état où chaque
64
+ branche a été rédigée — chaque branche était alors un chantier
65
+ distinct avant que le rewrite ne les absorbe toutes.
66
+
67
+ À partir de la release `0.9.0`, le CHANGELOG suit Keep-a-Changelog
68
+ strict : **une seule section `[Unreleased]` à la fois** au-dessus de
69
+ la version courante.
70
+
71
+ Ordre de lecture chronologique :
72
+
73
+ 1. ``[0.9.0] — Legacy retirement complete (mai 2026)`` — aboutissement.
74
+ 2. ``[Unreleased] — Migration Option B`` — sous-chantier intégré.
75
+ 3. ``[Unreleased] — Audit code-quality`` — sous-chantier intégré.
76
+ 4. ``[Unreleased] — Chantier post-rewrite`` — sous-chantier intégré.
77
+
78
+ ---
79
+
80
  ## [Unreleased] — Migration Option B vers RunOrchestrator (mai 2026)
81
 
82
  Branche `claude/test-alto-pipelines-qyFsL` — chantier de migration
CLAUDE.md CHANGED
@@ -132,6 +132,14 @@ NB : utiliser ``python -m pytest tests/`` plutôt que ``pytest tests/``
132
  directement — l'installation via ``uv tool install pytest`` masque
133
  les deps Picarones et produit ~160 collection errors trompeurs.
134
 
 
 
 
 
 
 
 
 
135
  ### Bugs documentés antérieurement — tous résolus
136
 
137
  | Bug | Statut | Sprint de résolution |
 
132
  directement — l'installation via ``uv tool install pytest`` masque
133
  les deps Picarones et produit ~160 collection errors trompeurs.
134
 
135
+ **Convention `code_version` dans les tests** : la valeur ``"1.0.0"``
136
+ utilisée dans ~50 fichiers de tests (``RunContext``,
137
+ ``ProvenanceRecord``, ``ArtifactKey``…) est un **placeholder de
138
+ fixture**, pas la version réelle du projet. Documentée dans
139
+ [`tests/_migration_helpers.py`](tests/_migration_helpers.py) en tête
140
+ de module. Le garde-fou ``test_no_hardcoded_version`` la neutralise
141
+ explicitement.
142
+
143
  ### Bugs documentés antérieurement — tous résolus
144
 
145
  | Bug | Statut | Sprint de résolution |
docs/archive/changelog-pre-v2.md CHANGED
@@ -1,20 +1,56 @@
1
- # Changelog pre-v2.0 — Picarones (archive historique)
2
 
3
  > **Archived document.** Historical reference only.
4
  > For current changelog see [`/CHANGELOG.md`](../../CHANGELOG.md).
5
 
6
- Ce fichier conserve l'historique des versions **antérieures à v2.0**
7
- (janvier 2025 → mai 2026, pré-rewrite et migration legacy). Pour
8
- l'ère v2.0 et au-delà, voir [`/CHANGELOG.md`](../../CHANGELOG.md) à
9
- la racine.
10
 
11
  Le format suit [Keep a Changelog](https://keepachangelog.com/fr/1.0.0/).
12
  La numérotation de version suit [Semantic Versioning](https://semver.org/lang/fr/).
13
 
14
  ---
15
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
 
17
- ## [Unreleased] — towards 1.3.0 (release institutionnelle BnF) — 2026-05
 
 
 
 
 
 
 
 
 
 
18
 
19
  > Section unique conforme à Keep-a-Changelog. Les chantiers actifs
20
  > sont regroupés ci-dessous par thème ; chaque thème reflète un audit
 
1
+ # Changelog pré-rewrite — Picarones (archive historique)
2
 
3
  > **Archived document.** Historical reference only.
4
  > For current changelog see [`/CHANGELOG.md`](../../CHANGELOG.md).
5
 
6
+ Ce fichier conserve l'historique des versions **antérieures au
7
+ rewrite architectural** (janvier 2025 → mai 2026, pré-rewrite et
8
+ migration legacy). Pour la période suivante (depuis `0.9.0`), voir
9
+ [`/CHANGELOG.md`](../../CHANGELOG.md) à la racine.
10
 
11
  Le format suit [Keep a Changelog](https://keepachangelog.com/fr/1.0.0/).
12
  La numérotation de version suit [Semantic Versioning](https://semver.org/lang/fr/).
13
 
14
  ---
15
 
16
+ ## Note de transition (2026-05-23) — pourquoi le saut `1.2.x → 0.9.0`
17
+
18
+ La timeline de ce fichier culmine en **`1.2.x` (avril 2026)** et
19
+ en une section ``[Unreleased] — towards 1.3.0`` qui décrit les
20
+ chantiers de mai 2026 — chantiers qui devaient devenir la release
21
+ institutionnelle BnF `1.3.0`.
22
+
23
+ Cette release **n'est jamais sortie**. À la place, Picarones a
24
+ entrepris un rewrite architectural complet en 8 couches, désigné
25
+ en interne sous le nom « v2.0 » (mai 2026). À la clôture de ce
26
+ rewrite, la maturité fonctionnelle réelle du projet (pas d'UI
27
+ finalisée, parité importeurs incomplète, rapport HTML pas refondu)
28
+ ne justifiait pas une release publique « 2.0 ».
29
+
30
+ **Le projet a donc été repositionné en `0.9.0` (pré-1.0 honnête)**,
31
+ événement consigné dans la « Note de repositionnement » en tête du
32
+ [CHANGELOG actif](../../CHANGELOG.md). Les chantiers de
33
+ ``[Unreleased] — towards 1.3.0`` ci-dessous ont été soit intégrés
34
+ au rewrite, soit reportés dans la roadmap vers `1.0.0` (cf.
35
+ [`docs/explanation/versioning.md`](../explanation/versioning.md)).
36
+
37
+ Le saut apparent `1.2.x → 0.9.0` reflète donc un **repositionnement
38
+ éditorial assumé**, pas une régression du code : l'architecture
39
+ est plus mature au `0.9.0` qu'elle ne l'était au `1.2.x` ; c'est la
40
+ surface fonctionnelle utilisateur qui n'a pas atteint le niveau
41
+ qu'on attend d'une release stable `1.0+`.
42
 
43
+ ---
44
+
45
+ ## [Non-livré] — anciennement « `[Unreleased]` — towards 1.3.0 » — 2026-05
46
+
47
+ > **Section figée par le repositionnement (2026-05-23).** Les
48
+ > chantiers listés ci-dessous étaient en cours en mai 2026 quand le
49
+ > projet a pivoté vers le rewrite + repositionnement en `0.9.0`.
50
+ > La cible `1.3.0` n'a jamais été publiée ; le contenu a été soit
51
+ > intégré au rewrite (cf. [CHANGELOG actif](../../CHANGELOG.md)
52
+ > entrée `[0.9.0]`), soit reporté dans la roadmap vers `1.0.0`.
53
+ > Conservé ici tel quel pour la traçabilité.
54
 
55
  > Section unique conforme à Keep-a-Changelog. Les chantiers actifs
56
  > sont regroupés ci-dessous par thème ; chaque thème reflète un audit
tests/_migration_helpers.py CHANGED
@@ -17,6 +17,33 @@ Ce helper ``run_via_orchestrator`` est un **outil de test**
17
  constitue pas de la dette technique en production : il n'y a pas
18
  de shim équivalent dans ``picarones/`` (les call sites CLI/Web
19
  font le pattern 3 étapes explicitement).
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  """
21
 
22
  from __future__ import annotations
 
17
  constitue pas de la dette technique en production : il n'y a pas
18
  de shim équivalent dans ``picarones/`` (les call sites CLI/Web
19
  font le pattern 3 étapes explicitement).
20
+
21
+ Convention « ``code_version`` dans les tests »
22
+ ==============================================
23
+
24
+ De nombreux tests (~50+ fichiers) instancient des ``RunContext``,
25
+ ``ProvenanceRecord``, ``ArtifactKey``, ``RunSpec`` avec
26
+ ``code_version="1.0.0"`` en littéral. **Cette valeur est un
27
+ placeholder de fixture**, pas une assertion sur la version réelle
28
+ de Picarones au moment du test.
29
+
30
+ Picarones suit SemVer pré-1.0 et sa version courante est résolue
31
+ dynamiquement via ``picarones.__version__`` (voir
32
+ ``docs/explanation/versioning.md``). Les tests utilisent ``"1.0.0"``
33
+ comme valeur arbitraire stable parce que :
34
+
35
+ - la sémantique testée ne dépend pas de la valeur réelle (cache,
36
+ manifeste, provenance — ce qui compte est l'**égalité** ou la
37
+ **non-égalité** entre deux ``code_version``, pas la valeur) ;
38
+ - une string ``"X.Y.Z"`` cohérente PEP 440 facilite les assertions
39
+ sur la structure ;
40
+ - la stabilité historique évite de devoir réécrire 50+ tests à
41
+ chaque bump de version.
42
+
43
+ Le garde-fou ``tests/architecture/test_no_hardcoded_version.py``
44
+ neutralise spécifiquement les patterns ``code_version="X.Y.Z"`` via
45
+ ``PLACEHOLDER_PATTERNS`` pour ne pas les confondre avec de vraies
46
+ mentions de version Picarones.
47
  """
48
 
49
  from __future__ import annotations
tests/architecture/test_file_budgets.py CHANGED
@@ -43,7 +43,7 @@ FILE_BUDGETS: dict[str, int] = {
43
  # --- God-modules : budget actuel + 15 % de marge.
44
  # Le rétrécissement sera l'objet d'un sprint de refactor dédié.
45
  # Phase 4.6 audit code-quality (2026-05) — commentaires retirés :
46
- # ils décrivaient des modules supprimés en v2.0 (``measurements/``,
47
  # ``core/``, ``report/``, ``pipelines/legacy_*``) qui ne sont plus
48
  # référencés ailleurs. L'historique reste accessible via git log
49
  # + CHANGELOG.
 
43
  # --- God-modules : budget actuel + 15 % de marge.
44
  # Le rétrécissement sera l'objet d'un sprint de refactor dédié.
45
  # Phase 4.6 audit code-quality (2026-05) — commentaires retirés :
46
+ # ils décrivaient des modules supprimés à la clôture du rewrite (``measurements/``,
47
  # ``core/``, ``report/``, ``pipelines/legacy_*``) qui ne sont plus
48
  # référencés ailleurs. L'historique reste accessible via git log
49
  # + CHANGELOG.
tests/architecture/test_no_hardcoded_version.py CHANGED
@@ -132,7 +132,7 @@ PLACEHOLDER_PATTERNS: tuple[re.Pattern[str], ...] = (
132
  re.compile(r"""["']version["']\s*:\s*["'][\w.\-+]+["']"""),
133
  )
134
 
135
- #: Placeholder utilisé dans les fixtures golden ``benchmark_result_v2.json``.
136
  #: Substitué au load-time du test ; doit être ignoré ici.
137
  GOLDEN_PLACEHOLDER = "<CURRENT_VERSION>"
138
 
 
132
  re.compile(r"""["']version["']\s*:\s*["'][\w.\-+]+["']"""),
133
  )
134
 
135
+ #: Placeholder utilisé dans les fixtures golden ``benchmark_result_canonical.json``.
136
  #: Substitué au load-time du test ; doit être ignoré ici.
137
  GOLDEN_PLACEHOLDER = "<CURRENT_VERSION>"
138
 
tests/architecture/test_no_legacy_imports_in_rewrite.py CHANGED
@@ -3,8 +3,9 @@
3
 
4
  L'arborescence canonique 8 couches (``domain → formats → evaluation
5
  → pipeline → adapters → app → reports → interfaces``) est autonome
6
- depuis la v2.0 (mai 2026). Tous les paquets legacy historiquement
7
- listés ont été supprimés au cours des sprints A-H.
 
8
 
9
  Phase 4.5 de l'audit code-quality (2026-05) : avant cette refonte,
10
  ``LEGACY_PACKAGES = ()`` rendait ``test_rewrite_modules_dont_import_from_legacy``
@@ -36,7 +37,7 @@ from pathlib import Path
36
 
37
  REPO_ROOT = Path(__file__).resolve().parents[2]
38
 
39
- #: Paquets de l'arborescence canonique v2.0.
40
  REWRITE_PACKAGES: tuple[str, ...] = (
41
  "domain",
42
  "formats",
@@ -56,7 +57,7 @@ REWRITE_PACKAGES: tuple[str, ...] = (
56
  #: cas, le retirer de cette liste avec un commentaire expliquant
57
  #: pourquoi le sens a changé.
58
  #:
59
- #: Source : CHANGELOG v2.0 et ``docs/archives/migration/``.
60
  RESURRECTED_LEGACY_NAMES: tuple[str, ...] = (
61
  "core",
62
  "measurements",
@@ -163,7 +164,7 @@ def test_no_resurrected_legacy_package_directory() -> None:
163
  assert not resurrected, (
164
  "Paquet(s) legacy ressuscité(s) :\n"
165
  + "\n".join(f" - {p}" for p in resurrected)
166
- + "\n\nLe retrait v2.0 (sprints A-H) avait acté la suppression "
167
  "définitive. Si la réintroduction est intentionnelle, retirer "
168
  "le nom de ``RESURRECTED_LEGACY_NAMES`` / "
169
  "``RESURRECTED_LEGACY_SUBPACKAGES`` avec un commentaire dans "
@@ -203,7 +204,7 @@ def test_no_imports_of_resurrected_legacy_module() -> None:
203
  f"\n{len(offenders)} import(s) ciblant un nom legacy "
204
  f"ressuscité :\n\n{sample}{more}\n\n"
205
  "Le code source rewrite ne doit pas importer depuis les "
206
- "paquets supprimés en v2.0. Migrer l'import vers la "
207
  "couche canonique correspondante."
208
  )
209
 
 
3
 
4
  L'arborescence canonique 8 couches (``domain → formats → evaluation
5
  → pipeline → adapters → app → reports → interfaces``) est autonome
6
+ depuis la clôture du rewrite (release `0.9.0`, mai 2026). Tous les
7
+ paquets legacy historiquement listés ont été supprimés au cours
8
+ des sprints A-H.
9
 
10
  Phase 4.5 de l'audit code-quality (2026-05) : avant cette refonte,
11
  ``LEGACY_PACKAGES = ()`` rendait ``test_rewrite_modules_dont_import_from_legacy``
 
37
 
38
  REPO_ROOT = Path(__file__).resolve().parents[2]
39
 
40
+ #: Paquets de l'arborescence canonique (post-rewrite, release 0.9.0+).
41
  REWRITE_PACKAGES: tuple[str, ...] = (
42
  "domain",
43
  "formats",
 
57
  #: cas, le retirer de cette liste avec un commentaire expliquant
58
  #: pourquoi le sens a changé.
59
  #:
60
+ #: Source : CHANGELOG entrée 0.9.0 et ``docs/archive/2026-migration/``.
61
  RESURRECTED_LEGACY_NAMES: tuple[str, ...] = (
62
  "core",
63
  "measurements",
 
164
  assert not resurrected, (
165
  "Paquet(s) legacy ressuscité(s) :\n"
166
  + "\n".join(f" - {p}" for p in resurrected)
167
+ + "\n\nLe retrait du legacy (sprints A-H, clôture du rewrite) avait acté la suppression "
168
  "définitive. Si la réintroduction est intentionnelle, retirer "
169
  "le nom de ``RESURRECTED_LEGACY_NAMES`` / "
170
  "``RESURRECTED_LEGACY_SUBPACKAGES`` avec un commentaire dans "
 
204
  f"\n{len(offenders)} import(s) ciblant un nom legacy "
205
  f"ressuscité :\n\n{sample}{more}\n\n"
206
  "Le code source rewrite ne doit pas importer depuis les "
207
+ "paquets supprimés à la clôture du rewrite. Migrer l'import vers la "
208
  "couche canonique correspondante."
209
  )
210
 
tests/golden/fixtures/{benchmark_result_v2.json → benchmark_result_canonical.json} RENAMED
File without changes
tests/golden/test_benchmark_result_json_stable.py CHANGED
@@ -6,7 +6,7 @@ Garantit que la sérialisation JSON de ``BenchmarkResult.as_dict``/
6
  - **Stable** : deux sérialisations successives produisent les mêmes
7
  bytes (modulo la clé ``run_date`` qui est forcée déterministe).
8
  - **Conforme au snapshot** : le JSON correspond à un golden file
9
- versionné dans ``tests/golden/fixtures/benchmark_result_v2.json``.
10
 
11
  Si le snapshot n'existe pas au premier run, il est créé et le test
12
  échoue avec un message demandant de commit le fichier.
@@ -21,7 +21,7 @@ import pytest
21
 
22
 
23
  GOLDEN_PATH = (
24
- Path(__file__).parent / "fixtures" / "benchmark_result_v2.json"
25
  )
26
 
27
 
@@ -139,7 +139,7 @@ def _build_deterministic_benchmark_result():
139
  # chaîne littérale. Découple le snapshot du bump de version
140
  # courante (un release `0.10.0` ne touche pas au fichier
141
  # golden). Convention partagée avec
142
- # ``tests/golden/fixtures/benchmark_result_v2.json``.
143
  picarones_version="<CURRENT_VERSION>",
144
  metadata={"sprint": "S5", "deterministic": True},
145
  )
 
6
  - **Stable** : deux sérialisations successives produisent les mêmes
7
  bytes (modulo la clé ``run_date`` qui est forcée déterministe).
8
  - **Conforme au snapshot** : le JSON correspond à un golden file
9
+ versionné dans ``tests/golden/fixtures/benchmark_result_canonical.json``.
10
 
11
  Si le snapshot n'existe pas au premier run, il est créé et le test
12
  échoue avec un message demandant de commit le fichier.
 
21
 
22
 
23
  GOLDEN_PATH = (
24
+ Path(__file__).parent / "fixtures" / "benchmark_result_canonical.json"
25
  )
26
 
27
 
 
139
  # chaîne littérale. Découple le snapshot du bump de version
140
  # courante (un release `0.10.0` ne touche pas au fichier
141
  # golden). Convention partagée avec
142
+ # ``tests/golden/fixtures/benchmark_result_canonical.json``.
143
  picarones_version="<CURRENT_VERSION>",
144
  metadata={"sprint": "S5", "deterministic": True},
145
  )