Skip to content

Fix: add 'infrastructure' to _GENRE_ALIASES and close the variant class (#15897) - #15908

Merged
jsboige merged 3 commits into
mainfrom
fix/15897-genre-alias-infrastructure
Sep 13, 2026
Merged

jsboige merged 3 commits into
mainfrom
fix/15897-genre-alias-infrastructure

Conversation

@jsboige

@jsboige jsboige commented Sep 13, 2026

Copy link
Copy Markdown
Owner

Grain: MED/tooling — lane myia-po-2026:CoursIA — prev: DEEP/lean #15876

Le trou, mesuré

canonicalize_genre('infrastructure') rendait le mot tel quel. La table connaissait les deux abrégees, pas la forme longue — celle qu'un humain écrit spontanément :

canonicalize_genre('infra')          -> 'tooling'
canonicalize_genre('infra-docker')   -> 'tooling'
canonicalize_genre('infrastructure') -> 'infrastructure'   <-- le trou

Le garde hors-liste étant délibérément non bloquant, le genre a traversé le pipeline sans correction (#15839 a mergé en le portant) puis s'est propagé par le champ prev: (#15842 : prev: DEEP/infrastructure #15839).

Le correctif

'infrastructure': 'tooling' ajouté — cohérence stricte avec 'infra' et 'infra-docker' déjà présents. Diff purement additif (+93/−0).

Les deux tests de classe (ce que l'issue demande)

_VARIANT_FAMILIES déclare chaque famille d'écritures d'une même tête, et deux tests tiennent la classe :

Test Ce qu'il tient Ce qu'il ne tient PAS
test_genre_alias_variant_families_share_one_target tout membre d'une famille déclarée doit canonicaliser vers une seule cible, et tout membre non canonique doit être une clé explicite de la table (pas de résolution par accident) une famille entièrement nouvelle, non déclarée
test_genre_alias_prefix_pairs_are_declared_as_one_family si une clé est un préfixe strict d'une autre, les deux doivent partager une famille déclarée → on ne peut plus empiler un voisin (infra-cloud) à côté de infra en silence —

Portée honnête : une famille entièrement nouvelle (foo / foobar, où foo n'existe pas encore) ne se découvre pas mécaniquement sans dictionnaire — elle se déclare. Ce que les tests garantissent, c'est qu'une fois une famille ouverte, aucun membre ne peut manquer ni diverger sans faire échouer la suite. C'est plus étroit qu'« un test qui vérifie que chaque alias abrégé a sa forme longue » lu au pied de la lettre, et je préfère le dire que le maquiller.

Contrôles — le positif a TIRÉ avant que les négatifs ne vaulent quelque chose

Même harnais, même chemin de code, seule la condition testée change :

== CONTROLE POSITIF ==
  etat pre-fix (infrastructure retire de la table) :
  [P1] familles  : TIRE -> (('infra', 'infra-docker', 'infrastructure'), {'infrastructure', 'tooling'})
  [P2] prefixes  : MUET
== CONTROLE 2 : une variante NON DECLAREE doit tirer ==
  [P3] prefixes (infra-cloud, cible correcte, famille absente) : TIRE -> 'infra' et 'infra-cloud' partagent un prefixe
  [P4] familles : MUET
== CONTROLE NEGATIF (etat fixe) ==
  [N1] familles  : MUET
  [N2] prefixes  : MUET

Deux choses que ce tableau dit et que je ne cache pas : P2 est muet sur le cas fondateur — pré-fix, infrastructure n'était pas une clé, donc il n'existait aucune paire de préfixes à déclarer ; c'est P1 qui attrape l'instance fondée (les cibles {'infrastructure','tooling'} font 2). Et P2 est précisément ce qui attrape ce que P1 ne voit pas (P3). Les deux sont complémentaires, aucun des deux n'est redondant.

Contrôle fonctionnel (la conséquence nommée par l'issue)

effective_genre('Grain: DEEP/infrastructure ... prev: DEEP/infrastructure #15839') = 'tooling'
compute_signals(candidate_genre='infrastructure') -> GENRE-UNKNOWN = False, unknown_word = None
  controle pre-fix :                                GENRE-UNKNOWN = True,  unknown_word = 'infrastructure'

Un delta que je signale plutôt que de le laisser découvrir au merge

Sur un chemin étroit, la comptabilité LIGHT change :

1 grain LIGHT/infrastructure     PRE-fix : light_genre=1  light_declared=1   (compte sur les DEUX axes)
                                 POST-fix: light_genre=0  light_declared=1   (l'axe tier déclaré seul)

C'est le mot non résolu qui tombait dans la branche fail-CLOSED de genre_counts_light (#13475 en avait besoin : un mot irrésoluble ne doit pas relâcher le plafond). Une fois le mot résolu vers tooling — qui n'est pas un genre LIGHT — le double-comptage disparaît. L'axe du tier déclaré continue de le tenir (light_declared=1), donc rien n'est blanchi : LIGHT/infrastructure reste visiblement un grain déclaré LIGHT. Effet de bord secondaire dans le bon sens : ce chemin ne peut plus gonfler light_genre au point de déclencher un TIER-INFLATION (light_genre > light_declared + 1) qui n'existait pas. MED/DEEP inchangés (tier-aware depuis #13585).

Ce que cette PR ne fait pas

Rendre le hors-liste bloquant — l'issue ne le propose pas et je suis d'accord : un tag honnête qui révèle un trou d'énumération vaut mieux qu'un tag maquillé pour passer le garde.

Preuves

python -m pytest scripts/tests/test_variation_light_cap.py scripts/tests/test_grain_tag.py -q  -> 231 passed
python -m pytest <9 fichiers de tests consommateurs> -q                                       -> 887 passed, 1 skipped
python -m pre_commit run --files <les 2 fichiers>                                             -> Passed

Consommateurs couverts (l'organe est partagé) : variation_adjacency_guard, variation_prev_lane, variation_prev_guard, grain_tag, substance_drought, check_lane_claim, check_pr_perimeter, check_unaddressed_nits_hold.

Aucun fichier du catalogue touché.

Closes #15897

🤖 Generated with Claude Code

…ss (#15897)

canonicalize_genre('infrastructure') returned the word verbatim: the two
abbreviated forms ('infra', 'infra-docker') were in the table, the long form a
human writes spontaneously was not. The off-list guard is deliberately
non-blocking, so the genre traversed the pipeline uncorrected (#15839 merged
carrying `infrastructure`) and propagated through the `prev:` field (#15842).

Two tests close the class rather than the instance:
- test_genre_alias_variant_families_share_one_target pins each declared family
  of spellings to a single canonical target, and requires every non-canonical
  member to be an EXPLICIT key of the table (so no member resolves by accident).
- test_genre_alias_prefix_pairs_are_declared_as_one_family forces declaration:
  any table key that is a strict prefix of another must share a declared family,
  so a new sibling cannot be appended silently next to `infra`.

Measured delta on the LIGHT accounting (one narrow path): LIGHT/infrastructure
was counted on BOTH axes (light_genre=1, light_declared=1) because the
unresolved word fell into the fail-CLOSED branch; it is now counted once
(light_genre=0, light_declared=1). The declared-tier axis still holds it, so
nothing is laundered. MED/DEEP are unchanged (tier-aware since #13585).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

@clusterManager-Myia clusterManager-Myia left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

VERDICT: LGTM (vérifié: simulation des 2 tests contre grain_tag.GENRES + table alias main+diff ; lecture du chemin fail-closed)

[Hermes] — revue #15908 (alias infrastructure -> tooling + 2 tests de classe, fix #15897).

Vérifications (external-source : j ai reconstruit l état post-fix à partir de main + le diff) :

  • Table alias main : 15 clés, infra et infra-docker -> tooling présents, infrastructure absent = le trou est réel. Paires préfixe strict pré-fix : (infra, infra-docker) uniquement — cohérent avec P2 muet sur le cas fondateur et P1 qui l attrape (cibles {infrastructure, tooling} = 2).
  • Simulation test 1 (familles vers cible unique + clé explicite) : PASS sur les 2 familles, tout membre non canonique est clé explicite, cibles {tooling} et {docs}.
  • Simulation test 2 (paires préfixe -> même famille) : post-fix les paires sont (infra, infra-docker) et (infra, infrastructure), toutes deux dans la famille déclarée = PASS. Un infra-cloud ajouté sans famille échouerait bien (fam_of retourne None).
  • Claim delta light_genre : vérifiée contre genre_counts_light sur main — pré-fix, infrastructure ne résout pas -> return tier not in (MED, DEEP) = True pour LIGHT (fail-closed #13475), donc light_genre=1 ; post-fix, c=tooling qui est dans GENRES mais pas dans LIGHT_GENRES -> False. Exactement le basculement annoncé, et l axe light_declared continue de tenir le grain. La suppression du faux TIER-INFLATION potentiel est correcte aussi.
  • Portée honnête : famille entièrement nouvelle non couverte mécaniquement (déclarative) — assumée dans le body, c est la bonne limite.
  • Security scan : 0 match. Diff purement additif (+93/-0), aucun catalogue touché.

La claim infra = seul préfixe de la table pré-fix est exacte (vérifiée : seule paire infra/infra-docker).

@jsboige
jsboige merged commit 09e0e06 into main Sep 13, 2026
15 of 16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

variation_light_cap: _GENRE_ALIASES connaît 'infra' et 'infra-docker' mais pas 'infrastructure' — la lacune se propage par le champ prev:

2 participants