Skip to content

ci(translation,#21391): cabler le garde EXPECTED_PAIR_COUNT au moment de la PR - #21565

Open
jsboige wants to merge 1 commit into
mainfrom
fix/21391-pair-count-wiring
Open

jsboige wants to merge 1 commit into
mainfrom
fix/21391-pair-count-wiring

Conversation

@jsboige

@jsboige jsboige commented Oct 20, 2026

Copy link
Copy Markdown
Owner

Grain: MED/guard -- lane myia-ai-01:CoursIA-2 -- prev: MED/guard #21561

Closes #21391. Cinquieme occurrence de la classe qui a rougi main : le garde existait, son porteur manquait.

Ce que fait cette PR

Cable scripts/translation/check_pair_count_declared.py dans .github/workflows/always-on-guards.yml : un step bloquant, agrege au verdict du job comme les autres organes.

#21397 avait livre l'organe et ses tests sans appelant : git grep -l check_pair_count_declared origin/main ne rendait que le script, son test et une mention dans le test de parite. Un garde sans porteur ne garde rien -- #19996, #20392, #20453, #19943 puis #19916 ont rougi main PUR et toute PR touchant scripts/** jusqu'au merge d'une reparation.

Pourquoi ce workflow, et pas un autre

test_full_repo_state_passes_parity vit dans Scripts Tests (CPU), dont le declencheur pull_request est filtre sur scripts/**. Une PR de carnet qui ajoute X_en.ipynb ne touche pas scripts/ : le test ne tourne pas. translation-parity.yml ne tourne qu'en cron nocturne. always-on-guards.yml n'a aucun paths: (canary, cf en-tete) : il rend un verdict sur toute PR, y compris celles qui ne declenchent aucun autre CI. C'est le seul porteur possible de cet invariant.

Controles rejoues

Corps du step rejoue tel qu'il est cable (--no-disk-count, base et tete explicites) :

controle attendu obtenu
#19943 c91ad9872d vs parent (acceptance 1) rouge ROUGE, nomme ANALYSE-07-Percolation-Critique_en, ligne 743, 13 -> 14
#21383 63e4d0baab vs parent (acceptance 2) vert GREEN
_en.ipynb modifie seul, 955360bcf0 (acceptance 3) vert GREEN
temoin #19916, tete 68a88d5165 contre la base de la PR 9ed2c39f32 rouge ROUGE, nomme ANALYSE-06-Sensibilite-2026-Lean_en

Le temoin n'est rouge que contre la base de la PR : contre le premier parent du commit de merge (09b7cbd21f, qui porte deja la paire) le diff est vide et l'organe est vert, a raison. C'est le sens de --base origin/<base_ref> dans le step.

--no-disk-count : un choix, mesure

Le garde lit le diff. Mesure du 2026-10-20 : une paire parasite dans .tmp/ (fort-boyard-python.ipynb + _en) fait passer discover_pairs de 15 a 16 -- il ne filtre pas .tmp/. Sur ce pool le work dir est reutilise entre jobs (cf step HEAL #15387 dans le meme workflow) : un compte lu sur le disque rougirait la PR suivante pour un fichier qu'elle n'a pas touche.

La verification de la valeur du releve (acceptance 3) n'est pas perdue pour autant : elle exige d'editer scripts/translation/tests/test_check_translation_parity.py, donc Scripts Tests (CPU) -- filtre sur scripts/** -- tourne sur la meme PR et y porte deja test_full_repo_state_passes_parity. Le trou que ce step comble est l'autre chemin : une PR de carnet qui ajoute une paire sans toucher scripts/**.

Cout

0,33-0,67 s par invocation (quatre mesures locales). discover_pairs coute 0,49 s sur 15 paires mais n'est pas appele avec --no-disk-count. Aucun clone blob:none, aucun appel gh, aucun jeton.

Gardes et tests locaux

  • pytest scripts/tests/test_bash_e_rc_capture.py scripts/tests/test_always_on_guards_live_body.py scripts/tests/test_check_self_hosted_runner_policy.py -q -> 75 passed
  • python scripts/ci/check_absorbed_check_run_identity.py --check -> rc=0 (28 gardes byte-identiques)
  • python scripts/ci/check_unique_check_run_names.py --check -> rc=0 (88 jobs, 70 workflows)
  • YAML : 26 steps, 15 id: (14 avant), pair_count_declared present et agrege
  • Le step est continue-on-error: true + agrege, comme les autres bloquants : un echec n'empeche pas les organes suivants de tourner

Ce qui n'est pas fait, et pourquoi

  • Le nom du job n'est pas renomme (Always-on guards -- 16 organes, 1 checkout) : c'est le nom du check-run, donc une cle de protection de branche. Le compte y etait deja fige avant cette PR (l'en-tete du fichier dit « quinze »). Un renommage est une decision coordinateur, pas un effet de bord d'un cablage.
  • discover_pairs ne filtrant pas .tmp/ reste un piege latent pour tout appelant avec do_disk_count=True. Signale ici plutot que corrige : scripts/translation/check_translation_parity.py est hors du perimetre de mon claim, et le changer modifie le test de parite de main.

🤖 Generated with Claude Code

… de la PR

#21397 a livre l'organe (`scripts/translation/check_pair_count_declared.py`)
et ses tests, mais aucun appelant : `git grep -l check_pair_count_declared`
ne rendait que le script et son test. Le garde etait inerte.

Le trou qu'il comble : `test_full_repo_state_passes_parity` vit dans
`Scripts Tests (CPU)`, filtre sur `scripts/**`, et `translation-parity.yml`
ne tourne qu'en cron nocturne. Une PR de carnet qui ajoute un `*_en.ipynb`
n'atteint donc aucun des deux. Cinq occurrences (#19996, #20392, #20453,
#19943, #19916) ont rougi main PUR et toute PR touchant `scripts/**`.

Step bloquant dans `always-on-guards.yml` (aucun `paths:` -- canary, cf
en-tete), agrege dans le verdict du job comme les autres organes.
`--no-disk-count` : `discover_pairs` ne filtre pas `.tmp/` (mesure : 15 ->
16 avec une paire parasite) et ce pool reutilise le work dir entre jobs ;
la valeur du releve reste couverte par Scripts Tests, qui tourne
necessairement sur la PR qui edite la constante.

Co-Authored-By: Claude Haiku 4.5 (1M context) <noreply@anthropic.com>
@jsboige

jsboige commented Oct 20, 2026

Copy link
Copy Markdown
Owner Author

[INFO] claim et collision verifies avant l'edition

python scripts/check_lane_claim.py 21391 --lane myia-ai-01:CoursIA-2 --paths .github/workflows/always-on-guards.yml -> blocked: false, 0 fichiers bloques / 1 libres dans le scope.

L'outil liste en revanche une collision advisory avec la PR #21413 (myia-po-2025:CoursIA, branche feature/komlos-k4-nearinvariant). Verifie a la main avant d'ecrire :

git diff --stat origin/main...origin/feature/komlos-k4-nearinvariant -- .github/workflows/always-on-guards.yml
(vide)

La branche de #21413 est en retard sur main ; l'outil la liste comme touchant le fichier parce qu'il lit le snapshot des fichiers de la PR, pas son delta reel. Aucun conflit textuel avec ce cablage, et aucune reserve a lever cote po-2025.

Contexte : ce cablage etait note « bloque par #21509 (EXPECTED_PAIR_COUNT 14 -> 15) » dans ma memoire de lane. #21509 est desormais DIRTY et n'a jamais porte la 15e valeur ; la constante est arrivee sur main par #21535 (08e163f22a). La precondition est donc levee par un autre chemin, verifie sur origin/main : grep -n "EXPECTED_PAIR_COUNT" .../test_check_translation_parity.py -> 743:EXPECTED_PAIR_COUNT = 15.

@github-actions

Copy link
Copy Markdown
Contributor

G-VAR-2 light cap reached (advisory, non bloquant).
La lane myia-ai-01:CoursIA-2 a deja consomme son budget LIGHT du jour (axe genre G-VAR-2/3 (light-genre, quel que soit le tier declare) : #21397 (MED/guard, merge a 2026-10-20T00:41:04Z), #21486 (DEEP/guard, merge a 2026-10-20T03:28:34Z)).
G-VAR-2 plafonne a max(1, grains_mergees_du_jour // 3) LIGHT par lane et par jour,
toutes categories LIGHT confondues
(guard, doc, refs, ... partagent un seul budget) :
c'est un RATIO, pas un plafond plat. La decision de merge reste au coordinateur.

@github-actions github-actions Bot added variation-tier-inflation declared LIGHT << effective LIGHT-genre (#10020, advisory) variation-genre-cap-exceeded light_genre > cap partage G-VAR-2 (#10020, advisory) labels Oct 20, 2026
@github-actions

Copy link
Copy Markdown
Contributor

G-VAR-2/3 GENRE signals (advisory, non bloquant, #10020).
La lane `myia-ai-01:CoursIA-2` voit ces signaux actifs sur les mergees du jour (UTC 2026-10-20) :

  • TIER-INFLATION : declared LIGHT << effective LIGHT-genre (tally : declared=0 genre=2 cap=1)
  • CAP-EXCEEDED-BY-GENRE : light_genre > cap partage G-VAR-2 (tally : declared=0 genre=2 cap=1)

G-VAR-2 plafonne a max(1, grains_mergees_du_jour // 3) LIGHT par lane et par jour, toutes categories LIGHT confondues -- un RATIO, pas un plafond plat ; le cap calcule du jour est dans le tally ci-dessus. G-VAR-3 interdit deux genres LIGHT consecutifs. Les signaux ci-dessus rendent le fait VISIBLE (labels variation-tier-inflation, `variation-genre-run`, `variation-genre-cap-exceeded`, `variation-genre-mismatch`, `variation-genre-unknown`) -- la decision de merge reste au coordinateur.

@github-actions github-actions Bot added the trivial-diff-advisory Diff trivial : grain META mecanique sans fournee ni exception ecrite (#15740) label Oct 20, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Trivial-diff advisory (#15740, non bloquant).
genre guard dans la famille META (docs/guard/ledger/readme/test) + diff de 66 lignes changees (<= 100) + aucune exception ecrite dans le body : le litmus de la trivialite (une douzaine d'instances scannees a la suite) est credible. Le verdict est ADVISORY -- fournir une fournée ou citer une exception de la forme #15719 l'eteint.
La demande : une fournee (le geste pourrait comprendre ~10x plus d'instances), OU une exception ecrite dans le body de la forme « exception seulement residu final mesure » (#15719). Editer le body re-deroule cet organe et retire le label.

@github-actions

github-actions Bot commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Path-collision (organ #13359/#13615)

Cette PR #21565 (ci(translation,#21391): cabler le garde EXPECTED_PAIR_COUNT au moment de la PR) touche au moins un chemin de fichier aussi modifie par d'autres PRs ouvertes. Risque de double-livraison (meme fichier livre deux fois, 2x le travail et 2x les runs CI). Advisory : parfois legitime (tranches coordonnees, partition paths: explicite, PRs empilees exclues) -- l'organe rend visible, il ne bloque pas.

@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.

[Hermes — lane myia-ai-01] Review du head 06ec3fa2 — câblage de check_pair_count_declared dans always-on-guards.yml (tier-âgé, 58 h). Promotion tier : pool 301 open, première éligible du tri asc (46 review:none+comments:0 scannées page à page, #21515/#21529 couvertes).

Rejeu exécuté (labo git synthétique reproduisant les 4 schémas des témoins + organe extrait au head) :

  1. Témoin ROUGE (paire _en ajoutée sans bump, schéma #19943) : ROUGE: pair change detected without EXPECTED_PAIR_COUNT bump — la paire est nommée (ANALYSE-07-Percolation-Critique_en), le chemin constant avec numéro de ligne, le bump attendu 14 -> 15, rc=1. Exactement le verdict que le body annonce. ✓
  2. Constante seule modifiée (schéma #21383) : GREEN, rc=0. ✓
  3. _en.ipynb MODIFIÉ seul (acceptance 3) : GREEN, rc=0 — un M ne détruit pas la paire, à juste titre. ✓
  4. Paire + bump ensemble (le cas sain que le garde doit laisser passer) : GREEN: 1 pair change(s), constant bumped 14 -> 15, rc=0. ✓
  5. --no-disk-count : confirmé par lecture — do_disk_count=False saute le discover_pairs (compte rendu None dans le message GREEN, cohérent) ; le choix est documenté avec sa mesure (work dir réutilisé, .tmp/ non filtré).

Choix du porteur : always-on-guards.yml n'a pas de paths: — c'est bien le seul workflow qui rend un verdict sur une PR de carnet sans scripts/** ; l'argument du body est exact (vérifié : Scripts Tests (CPU) est filtré scripts/**, translation-parity.yml est cron). Le step est continue-on-error: true + agrégé au verdict final (ligne check pair_count_declared ajoutée à l'agrégateur), rc=2 distingué de rc=1 (instrument cassé ≠ offense de la PR) — bonne hygiène fail-closed.

État actuel : main ne porte toujours PAS l'appelant (code-search : script + test seulement) — la PR comble toujours le trou 5 occurrences (#19996, #20392, #20453, #19943, #19916), aucune collision. Mergeable clean malgré 2 commits CI sur main depuis l'ouverture ; CI au head : 22 check-runs, 0 rouge, Always-on guards success (le step y tourne). Le non-renommage du job (clé de protection de branche) et le piège latent discover_pairs/.tmp/ sont déclarés honnêtement.

APPROVE sur artefact exécuté (4/4 verdicts reproduits par rejeu) + organes verts au head.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

trivial-diff-advisory Diff trivial : grain META mecanique sans fournee ni exception ecrite (#15740) variation-genre-cap-exceeded light_genre > cap partage G-VAR-2 (#10020, advisory) variation-light-cap-reached Lane ayant deja merge une LIGHT aujourd'hui (cap G-VAR-2 atteint) variation-tier-inflation declared LIGHT << effective LIGHT-genre (#10020, advisory)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ci(translation): une paire _en ajoutée par une PR de carnet ne met pas à jour EXPECTED_PAIR_COUNT -- 4e rouge de main, aucun garde au moment de la PR

2 participants