Spaces:
Sleeping
Sleeping
File size: 6,228 Bytes
53f68d5 162c559 53f68d5 162c559 53f68d5 | 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 | """Sprint A14-S3 — geler la fragmentation à plat de ``measurements/``.
Constat de l'audit (cf. ``BACKLOG_POST_LIVRAISON.md`` §2.4) : le
package ``picarones.measurements`` contient ~60 fichiers ``.py`` à
plat, accumulés au fil des Sprints 5-97. Cette fragmentation rend
le code illisible (60 modules sans hiérarchie) et complique la
migration vers la nouvelle structure ``evaluation/metrics/``.
Cette règle **fige** la liste actuelle (snapshot au Sprint S3) et
**interdit** tout nouveau fichier ``.py`` à plat dans
``measurements/``. Toute nouvelle métrique / hook / agrégateur
doit aller dans ``picarones/evaluation/metrics/`` (ou un sous-package
approprié).
Comportement attendu en pratique :
- **Nouveau fichier dans evaluation/metrics/** : OK.
- **Nouveau fichier dans measurements/<sous-package>/** (sous-dossier
comme ``narrative/`` ou ``statistics/`` ou ``runner/``) : OK, le
test ne regarde que le top-level.
- **Nouveau fichier à plat measurements/<nom>.py** : ÉCHEC. Soit
le mettre dans evaluation/metrics/ (préférence forte), soit
dans un sous-package thématique de measurements/.
La whitelist est intentionnellement gelée à la date du Sprint S3.
Si un fichier de la whitelist est supprimé pendant le rewrite (par
exemple migré vers evaluation/metrics/ au Sprint S10), un autre
test (``test_no_orphaned_whitelist_entries``) le détecte.
"""
from __future__ import annotations
from pathlib import Path
REPO_ROOT = Path(__file__).resolve().parents[2]
MEASUREMENTS_DIR = REPO_ROOT / "picarones" / "measurements"
#: Snapshot de l'état au Sprint A14-S3 (mai 2026). 59 fichiers
#: ``.py`` à plat. **Ne pas ajouter d'entrée** sans avoir d'abord
#: tenté de placer le fichier dans evaluation/metrics/ ou dans un
#: sous-package thématique.
WHITELIST_FLAT_FILES_S3: frozenset[str] = frozenset({
"__init__.py",
"abbreviations.py",
"alto_metrics.py",
"baseline_comparison.py",
"builtin_hooks.py",
"builtin_metrics.py",
"calibration.py",
"char_scores.py",
"confusion.py",
"cost_projection.py",
"difficulty.py",
"early_modern_typography.py",
"equivalence_profile.py",
"error_absorption.py",
"hallucination.py",
"history.py",
"image_predictive.py",
"image_quality.py",
"incremental_comparison.py",
"inter_engine.py",
"layout.py",
"levers.py",
"lexical_modernization.py",
"line_metrics.py",
"longitudinal.py",
"marginal_cost.py",
"metrics.py",
"modern_archives.py",
"module_policy.py",
"mufi.py",
"ner.py",
"ner_backends.py",
"normalization.py",
"numerical_sequences.py",
"numerical_sequences_hooks.py",
"philological_hooks.py",
"pipeline_benchmark.py",
"pipeline_comparison.py",
"pipeline_spec_loader.py",
"pricing.py",
"rare_tokens.py",
"readability.py",
"readability_hooks.py",
"reading_order.py",
"reliability.py",
"robustness.py",
"robustness_projection.py",
"roman_numerals.py",
"searchability.py",
"searchability_hooks.py",
"specialization.py",
"structure.py",
"taxonomy.py",
"taxonomy_comparison.py",
"taxonomy_cooccurrence.py",
"taxonomy_intra_doc.py",
"throughput.py",
"unicode_blocks.py",
"worst_lines.py",
})
def _flat_python_files() -> set[str]:
"""Liste des fichiers ``.py`` directement dans ``measurements/``.
Exclut les sous-packages (``narrative/``, ``statistics/``,
``runner/``) et les fichiers ``__pycache__``.
"""
return {
p.name for p in MEASUREMENTS_DIR.glob("*.py")
if "__pycache__" not in p.parts
}
def test_no_new_flat_file_in_measurements() -> None:
"""Toute addition à plat dans ``measurements/`` est interdite.
Si ce test échoue après l'ajout d'un fichier, deux options :
1. **Préférée** : déplacer le fichier dans
``picarones/evaluation/metrics/`` (ou un sous-package
approprié).
2. **Acceptable seulement avec justification** : si le fichier
*doit* vivre dans ``measurements/`` pendant la transition
(ex : refactor d'un fichier de la whitelist qui se scinde),
l'ajouter à WHITELIST_FLAT_FILES_S3 dans ce fichier en
expliquant pourquoi dans le message de commit.
"""
actual = _flat_python_files()
new_files = actual - WHITELIST_FLAT_FILES_S3
assert not new_files, (
"\nNouveaux fichiers ``.py`` à plat dans ``picarones/measurements/`` "
"(plan rewrite-2026 §S3 — fragmentation gelée) :\n"
+ "\n".join(f" - {f}" for f in sorted(new_files))
+ "\n\nDéplacer ces fichiers vers ``picarones/evaluation/metrics/`` "
"ou un sous-package approprié. Voir docs/roadmap/rewrite-2026.md."
)
def test_no_orphaned_whitelist_entries() -> None:
"""La whitelist ne doit pas contenir d'entrée pointant vers un
fichier qui n'existe plus.
Garantit que la migration des fichiers vers ``evaluation/metrics/``
(Sprint S10) entraîne automatiquement la mise à jour de cette
whitelist — pas de dette qui s'accumule.
"""
actual = _flat_python_files()
orphans = WHITELIST_FLAT_FILES_S3 - actual
assert not orphans, (
"\nWhitelist contient des fichiers qui n'existent plus dans "
"``picarones/measurements/`` :\n"
+ "\n".join(f" - {f}" for f in sorted(orphans))
+ "\n\nLe fichier a été déplacé/supprimé — retirer l'entrée "
"de WHITELIST_FLAT_FILES_S3 dans ce fichier."
)
def test_subpackages_not_affected() -> None:
"""Méta-test : les sous-packages existants de ``measurements/``
(narrative, statistics, runner) restent intouchés par ce test."""
expected_subpackages = {"narrative", "statistics", "runner"}
actual = {
p.name for p in MEASUREMENTS_DIR.iterdir()
if p.is_dir() and not p.name.startswith("_") and "__pycache__" not in p.name
}
missing = expected_subpackages - actual
assert not missing, (
f"Sous-packages attendus dans measurements/ absents : {missing}. "
"Si l'un d'eux a été migré vers la nouvelle architecture (S10+), "
"retirer son nom de ``expected_subpackages`` ici."
)
|