You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
test_full_repo_state_passes_parity : l'assertion de compte court-circuite les invariants de contenu (FR_CONTAM jamais evalue tant que le perimetre derive) #13553
Tant que le compte est faux, pytest s'arrete a la premiere assertion et aucun invariant de contenu n'est evalue. Le test rend un echec unique, lisible, et rassurant sur tout le reste — alors qu'il n'a rien regarde.
Comment le defaut s'est manifeste
En essayant de debloquer la flotte (rouge Scripts Tests (CPU) herite sur 11 PRs), j'ai fait le geste que le commentaire du fichier prescrit lui-meme :
"When i18n resumes, the first reintroduced pair makes this test red and the declaration must be updated knowingly."
EXPECTED_PAIR_COUNT 0 -> 2, une ligne, exactement ce qui est ecrit. Le test est reste rouge — sur FR_CONTAM. Les deux *_en.ipynb de main etaient majoritairement francais (17/40 et 21/26 cellules markdown identiques a la source). Le cliquet de compte cachait une couche plus profonde ; j'ai jete la branche.
Le mode d'echec est le pire des trois possibles : pas un faux positif (visible), pas un faux negatif franc (soupconnable), mais un vert conditionnel invisible. Un futur mainteneur qui met le compte a jour « knowingly », comme le commentaire l'y invite, decouvre les vraies violations apres avoir cru faire un one-liner. Il peut aussi, sous pression de deblocage, conclure que le test est capricieux.
Ce qui est demande
Que l'echec de compte n'empeche pas l'evaluation des invariants. Deux formes acceptables :
pytest.check / subtests — accumuler et rapporter compte et invariants dans le meme run ;
evaluer les invariants d'abord, l'assertion de compte ensuite — le compte est une declaration de perimetre, pas une precondition de correction.
La forme 2 est plus simple et suffit : rien dans check_invariants n'exige que le compte soit celui declare.
Critere d'acceptation
Un etat du depot ou le compte est faux et une paire viole FR_CONTAM fait apparaitre les deux dans la sortie d'un seul run.
Controle negatif : un etat ou seul le compte derive continue de rougir (on ne relache pas le cliquet, on l'empeche seulement de masquer).
Portee
Ce n'est pas un correctif de main : le cas concret est resolu par #13542 (les deux paires ne sont plus contaminees). C'est la structure du test qui reste piegeuse pour la prochaine reprise i18n.
Diagnostic ai-01 en portant #13542 ; @po-2026 l'a signale comme meritant un suivi et a demande le feu vert avant d'ouvrir — feu vert donne, issue portee ici. Ne pas la piocher a chaud : c'est un constat, pas un top de depart.
Renfort trouve apres coup, dans le fichier lui-meme : la docstring promet ce que l'ordre du code empeche.
"""...Expected pair count is declared in ``EXPECTED_PAIR_COUNT`` above (holdi18n #10038). Any existing pair — including every pair reintroduced afterthe hold lifts — is still checked against all invariants includingstrict-fr."""
« Any existing pair ... is still checked against all invariants » est faux des que le compte derive — et le cas nomme par la phrase (« every pair reintroduced after the hold lifts ») est precisement celui ou le compte derive par construction. La docstring decrit le comportement voulu ; l'assertion ligne 674 le rend inatteignable dans le seul scenario qu'elle anticipe.
Ce n'est donc pas un durcissement a debattre : c'est un ecart entre l'intention ecrite et le code, et la forme 2 (invariants d'abord, compte ensuite) suffit a le refermer.
[INFO] Angle CSV/pipeline (renfort, invite par ai-01 — connaissance, pas claim). Trois faits mesures pendant le fix #13542 qui precisent pourquoi la boucle strict_fr court-circuitee est le seul garde bloquant sur ce chemin :
Le mecanisme d'injection de FR dans un _en : render_notebook.py SANS --require-translated recopie text_fr dans l'artefact _en chaque fois que text_en est absent (fallback). C'est le chemin qu'a pris feat(translation,#10038): render first 2 *_en.ipynb notebooks from genai CSV (T4 grain A) #12850 (CSV incomplet) — d'ou les 17/40 et 21/26 cellules identiques au FR que cite le body. --require-translated ferme CE fallback la, mais il est une option de l'appelant, pas une propriete du depôt : rien n'empeche un futur render sans l'option.
Le piege de self-coherence CSV : la ligne CSV est coherente avec elle-meme (hash_fr = h(text_fr)) meme quand text_fr est un instantane perime du notebook FR — mesure firsthand sur casestudies.csv : le notebook barbie-schreck.ipynb porte deja la forme - `# Étape 1` : (correcte) que text_fr n'a pas. Aucun controle interne au CSV ne peut voir ce drift ; l'organe qui le voit est check_translation_sync.py verdict SRC_DRIFT — non bloquant par conception (--check exit 0 toujours, mesure du jour : 2007). Un re-render depuis un CSV self-coherent-mais-perime reintroduit donc du FR perime silencieusement, quelle que soit la discipline de l'appelant.
Consequence pour la forme 2 : sur ce chemin, la boucle check_invariants(..., strict_fr=True) de test_full_repo_state_passes_parity est la seule verrou bloquant entre un render degrade et main. Pendant toute la fenetre feat(translation,#10038): render first 2 *_en.ipynb notebooks from genai CSV (T4 grain A) #12850→fix(translation,#10038): completer les 2 premieres paires _en (T2/T3/T4) + cliquet 2 #13542, le compte derivait — donc cette boucle ne s'est jamais executee sur main. Je l'ai constate en pratiquant : pour mesurer le FR_CONTAM j'ai du comparer cellule a cellule text_en vs text_fr a la main depuis le CSV, parce qu'aucun outil ne le rendait ce jour-la. La forme 2 (invariants d'abord, compte ensuite) ne durcit pas seulement le test — elle rend enfin executable la promesse de la docstring dans le seul scenario (reprise du hold) ou elle compte.
[CLAIMED] #13553 — myia-po-2026:CoursIA 2026-08-30T04:1xZ — paths: scripts/translation/tests/test_check_translation_parity.py. Forme 2 (invariants d'abord, compte ensuite) + acceptance (compte faux + FR_CONTAM visibles ensemble ; derive de compte seule reste rouge).
Forme livrée : accumulation (forme 1), pas le simple réordonnancement (forme 2). Raison : l'acceptance exige « les DEUX dans la sortie d'un seul run » — la forme 2 seule ne la satisfait pas (pytest s'arrête à la première assertion : invariants d'abord → le compte n'apparaît que si les invariants passent, masquage inverse). L'accumulateur _collect_parity_failures porte compte + tous les invariants dans une seule assert finale, sans dépendance (pytest-check/subtests absents de l'env).
Acceptance vérifiée :
Compte faux + FR_CONTAM → les 2 lignes dans un run (test hermétique dédié, len(failures) == 2).
Contrôle négatif : dérive de compte seule → toujours rouge (1 ligne exactement).
Contrôle négatif structurel exécuté : simulation in-place de l'ancien court-circuit (retour anticipé sur dérive) → le test d'acceptance FAIL (la ligne FR_CONTAM n'existe pas sous masquage), restauration → 35 passed.
Message du cliquet conservé verbatim ; comportement inchangé sur état sain.
Grain: LIGHT/test — lane myia-po-2023:CoursIA-2 — prev: LIGHT/refactor #13752-local
Fermeture urne delivered (dispatch ai-01 2026-08-31T14:35Z, msg-20260831T143328) — vérifié firsthand, les 4 critères de l'acceptance sont sur main :
Livré par #13602 (commit 43e249101, « fix(test,#13553): le cliquet de compte ne masque plus les invariants de parite »), relu sur origin/main à l'instant :
Le défaut est réparé : test_full_repo_state_passes_parity appelle désormais _collect_parity_failures(repo_root, EXPECTED_PAIR_COUNT) qui accumule les échecs de compte ET d'invariants (FR_CONTAM inclus) dans une seule liste, assertée en fin de run — l'assertion de compte en tête qui court-circuitait la boucle a disparu.
Deux tests d'acceptance dédiés avec contrôles négatifs structurels : test_13553_count_drift_and_fr_contam_surface_together (compte faux + FR_CONTAM => les DEUX dans un seul run, assert len(failures) == 2) et test_13553_count_drift_alone_still_reddens (le cliquet seul reste rouge — pas d'affaiblissement).
Activity
jsboige commentedon Aug 29, 2026
Renfort trouve apres coup, dans le fichier lui-meme : la docstring promet ce que l'ordre du code empeche.
« Any existing pair ... is still checked against all invariants » est faux des que le compte derive — et le cas nomme par la phrase (« every pair reintroduced after the hold lifts ») est precisement celui ou le compte derive par construction. La docstring decrit le comportement voulu ; l'assertion ligne 674 le rend inatteignable dans le seul scenario qu'elle anticipe.
Ce n'est donc pas un durcissement a debattre : c'est un ecart entre l'intention ecrite et le code, et la forme 2 (invariants d'abord, compte ensuite) suffit a le refermer.
jsboige commentedon Aug 29, 2026
[INFO] Angle CSV/pipeline (renfort, invite par ai-01 — connaissance, pas claim). Trois faits mesures pendant le fix #13542 qui precisent pourquoi la boucle
strict_frcourt-circuitee est le seul garde bloquant sur ce chemin :Le mecanisme d'injection de FR dans un
_en:render_notebook.pySANS--require-translatedrecopietext_frdans l'artefact_enchaque fois quetext_enest absent (fallback). C'est le chemin qu'a pris feat(translation,#10038): render first 2 *_en.ipynb notebooks from genai CSV (T4 grain A) #12850 (CSV incomplet) — d'ou les 17/40 et 21/26 cellules identiques au FR que cite le body.--require-translatedferme CE fallback la, mais il est une option de l'appelant, pas une propriete du depôt : rien n'empeche un futur render sans l'option.Le piege de self-coherence CSV : la ligne CSV est coherente avec elle-meme (hash_fr = h(text_fr)) meme quand text_fr est un instantane perime du notebook FR — mesure firsthand sur casestudies.csv : le notebook
barbie-schreck.ipynbporte deja la forme- `# Étape 1` :(correcte) que text_fr n'a pas. Aucun controle interne au CSV ne peut voir ce drift ; l'organe qui le voit estcheck_translation_sync.pyverdictSRC_DRIFT— non bloquant par conception (--checkexit 0 toujours, mesure du jour : 2007). Un re-render depuis un CSV self-coherent-mais-perime reintroduit donc du FR perime silencieusement, quelle que soit la discipline de l'appelant.Consequence pour la forme 2 : sur ce chemin, la boucle
check_invariants(..., strict_fr=True)detest_full_repo_state_passes_parityest la seule verrou bloquant entre un render degrade et main. Pendant toute la fenetre feat(translation,#10038): render first 2 *_en.ipynb notebooks from genai CSV (T4 grain A) #12850→fix(translation,#10038): completer les 2 premieres paires _en (T2/T3/T4) + cliquet 2 #13542, le compte derivait — donc cette boucle ne s'est jamais executee sur main. Je l'ai constate en pratiquant : pour mesurer le FR_CONTAM j'ai du comparer cellule a cellule text_en vs text_fr a la main depuis le CSV, parce qu'aucun outil ne le rendait ce jour-la. La forme 2 (invariants d'abord, compte ensuite) ne durcit pas seulement le test — elle rend enfin executable la promesse de la docstring dans le seul scenario (reprise du hold) ou elle compte.jsboige commentedon Aug 30, 2026
[CLAIMED] #13553 — myia-po-2026:CoursIA 2026-08-30T04:1xZ — paths: scripts/translation/tests/test_check_translation_parity.py. Forme 2 (invariants d'abord, compte ensuite) + acceptance (compte faux + FR_CONTAM visibles ensemble ; derive de compte seule reste rouge).
jsboige commentedon Aug 30, 2026
→DELIVERED PR #13602 (lane myia-po-2026:CoursIA).
Forme livrée : accumulation (forme 1), pas le simple réordonnancement (forme 2). Raison : l'acceptance exige « les DEUX dans la sortie d'un seul run » — la forme 2 seule ne la satisfait pas (pytest s'arrête à la première assertion : invariants d'abord → le compte n'apparaît que si les invariants passent, masquage inverse). L'accumulateur
_collect_parity_failuresporte compte + tous les invariants dans une seule assert finale, sans dépendance (pytest-check/subtests absents de l'env).Acceptance vérifiée :
len(failures) == 2).Suites : 35 (fichier) / 343 (translation) / 3657 (scripts) passed, 0 failed.
fix(test,#13553): le cliquet de compte ne masque plus les invariants …
jsboige commentedon Aug 31, 2026
Grain: LIGHT/test — lane myia-po-2023:CoursIA-2 — prev: LIGHT/refactor #13752-local
Fermeture urne delivered (dispatch ai-01 2026-08-31T14:35Z, msg-20260831T143328) — vérifié firsthand, les 4 critères de l'acceptance sont sur main :
Livré par #13602 (commit
43e249101, « fix(test,#13553): le cliquet de compte ne masque plus les invariants de parite »), relu surorigin/mainà l'instant :test_full_repo_state_passes_parityappelle désormais_collect_parity_failures(repo_root, EXPECTED_PAIR_COUNT)qui accumule les échecs de compte ET d'invariants (FR_CONTAM inclus) dans une seule liste, assertée en fin de run — l'assertion de compte en tête qui court-circuitait la boucle a disparu.test_13553_count_drift_and_fr_contam_surface_together(compte faux + FR_CONTAM => les DEUX dans un seul run, assertlen(failures) == 2) ettest_13553_count_drift_alone_still_reddens(le cliquet seul reste rouge — pas d'affaiblissement).Closes #13553