_ADD_PARSER_RE exigeait la parenthèse collée (add_parser\(|add_subparsers\() → `add_subparsers ()` / `add_parser ("build")` (espace avant `(`, Python valide, PEP 8 déconseille sans imposer) silencieusement loupés → sous-scorage −20 pts du critère CLI d'un module sain (symptôme fd99362). Durci en add_parser\s*\(|add_subparsers\s*\(, harmonisé aux 2 frères déjà durcis (_TEST_DEF_RE `def\s+`, _MAIN_GUARD_RE `\s*==\s*`) et à la doctrine écrite du fichier (l.18-30 « détecter la forme, pas une graphie »). 4e fix de cette classe dans ce fichier après ac595d0/fd99362/35de616.
Fix latent (aucun module n'utilise l'espace → quality_report.json byte-identique, check_artifacts vert) mais teeth-prouvé (ancien regex False sur les 2 formes espacées, nouveau True + True sur les formes normales). Cores computationnels commissions/bancable audités CLEAN par ailleurs. run_ci 33 PASS 0 FAIL 0 SKIP · 0 gate (#5) · 0 chiffre inventé (#6) · 0 VPS (#8).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Angle frais jamais balayé (cohérence tri-lingue FR/EN/ES du module seo/). Un
Explore a remonté « es manque 3 mots-clés projet P01 » ; refusé au mot (#6,
verify-non-defects) et prouvé au byte-level un NON-DÉFAUT : l'artefact étant
byte-repro-gaté, l'écart reflète la LOGIQUE du générateur.
Preuve (repro du générateur sans dedup) : génération symétrique par langue →
raw 115/langue identique. L'écart vient du seul dedup (lang,term). country[es]
= « Republica Dominicana » == la localisation générique de 5 projets
(P01/02/03/06/09) → le mot-clé global {type} Republica Dominicana absorbe le
mot-clé projet identique de P01 (dedup correct, terme présent 1× en scope
global). En fr/en country != localisation → pas de collision, P01 garde ses 7
termes. D'où +3 collisions en es → 87 vs 84. Rien n'est perdu ; invariants
(≥ min_keywords_per_lang + unicité (term,lang)) tiennent ; es=84 déjà documenté
et gaté README.md:15 (check_readme_claims). Sortie CORRECTE.
Livrable = note explicative au point de dedup keywords.py:106 (asymétrie subtile
non-évidente qu'un futur balayage refera l'enquête). Aucune logique/fixture/claim
-gaté touché (gates byte visent out/*.json, pas la source). Style aligné ASCII +
em-dash existant, NFC-clean.
run_ci = 33 PASS/0/0 (inchangé). 0 code moteur V18 (#6), 0 logique modifiée,
0 artefact/fixture touché (#6), 0 gate ajouté (#5), 0 VPS (#8), 0 API externe.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
frontend/portails/out_fresh/ (workspace.json + MANIFEST.json) était tracké mais
commité par accident une seule fois (f954cc1, 2026-08-02, scratch « fresh rebuild ») :
byte-identique à out/, produit par RIEN (le générateur n'écrit que dans out/ via
_DEFAULT_OUT), référencé NULLE PART (git grep out_fresh = 0). Il échappait à
check_artifacts (find -type d -name out = match EXACT sur `out`, jamais `out_fresh`)
donc au balayage reverse-bijection → bombe de staleness silencieuse (rien ne le
régénère : dès que la source bouge, out/ se met à jour et out_fresh/ diverge en copie
stale non-possédée). Suppression (out/ intacte, régénère byte-identique). Occurrence
isolée → pas de gate (#5). Candidat is_filled() écarté au byte-level (non-défaut, #6).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>