Skip to content

Add(ci,#17397): audit des besoins locaux des jobs self-hosted — 51 sur-accusations mesurees - #17403

Merged
myia-ai-01 merged 1 commit into
mainfrom
feature/ci-routing-17397
Sep 23, 2026
Merged

myia-ai-01 merged 1 commit into
mainfrom
feature/ci-routing-17397

Conversation

@jsboige

@jsboige jsboige commented Sep 22, 2026

Copy link
Copy Markdown
Owner

Grain: MED/tooling — lane myia-po-2025:CoursIA — prev: DEEP/notebook-python #17396

Ce que livre cette PR

Un organe, scripts/ci/audit_self_hosted_needs.py, et ses 22 tests : il classe les workflows dont un job tourne sur self-hosted selon qu'ils ont ou non un besoin qui n'existe que localement, et rend la preuve de chaque classement.

Deux fichiers, aucun routage modifié, aucun job CI branché. L'organe lit et classe ; il ne route rien. Les étapes 1-4 de #17397 restent ce qu'elles sont : une décision d'arbitrage, non engagée ici.

Pourquoi un organe, et pas le grep de #17397

Le classement de #17397 est un grep sur le texte du workflow. Deux de ses résultats ne se reproduisent pas :

Ce que dit #17397 Mesure structurelle
32 workflows sans besoin local 79 (sur 120 lus)
wsl 4 · gpu 4 · conda 3 0 · 0 · 0
secrets 36 2 secrets personnalisés

La même commande lancée en boucle sur main rend 30, pas 32 : adjacency-stale-sweep et translation-hot-drift-advisory sortent de la liste selon la forme du motif. Un compte qui depend de la forme du grep n'est pas une mesure.

Les 51 sur-accusations, décomposées par source

C'est le cœur de l'organe : il ne remplace pas le total par un autre total, il montre d'où venait chaque accusation.

Source workflows exemple vérifié
comment 14 elan matche « relance » (adjacency-stale-sweep.yml:11) et « appelant » (:215)
automatic-secret 17 ${{ secrets.GITHUB_TOKEN }} — fourni par n'importe quel runner, donc aucun besoin local
name-or-trigger 20 name: Notebook Papermill Ratchet (un titre), paths: ['**.ipynb'] (une condition d'entrée)

Sur wsl, gpu et conda, toutes les occurrences des workflows visés sont des lignes de commentaire : banner-guard:6, lean-build:241, ml-tests:91, notebook-execution-required:9/226, notebook-outputs-required:12, scripts-tests:16/243/260, notebook-exec-sequence-ratchet:15, notebook-output-failure-ratchet:67, quarto-pages-deploy:198, regression-guard:24. Vérifié ligne à ligne.

L'organe est conservateur dans les deux sens : il rend aussi la liste des workflows qu'il classe « besoin » et que le grep avait manqués. Sur ce dépôt, elle est vide — aucune sous-accusation détectée.

Deux faux positifs de cet organe, mesurés et retirés

Un motif se valide par ses faux positifs, pas par ses hits. Les deux ont été attrapés en lisant les preuves produites, et leur retrait est consigné dans le code (RETIRED_PATTERNS) :

  • notebook_tools — matchait le chemin d'un script (python scripts/notebook_tools/generate_catalog.py), pas un besoin d'exécuter un notebook. Accusait 11 workflows.
  • \bowui\b — matchait un nom de répertoire (Playwright-OWUI/package-lock.json). La famille internal-network ne retient plus que des locators réseau littéraux (localhost, 127.0.0.1, 0.0.0.0, host.docker.internal).

Les deux sont exactement la classe de défaut que l'organe existe pour fermer : un motif qui matche un nom au lieu d'un besoin.

Auto-contrôle (22 tests, chacun épinglant une classe mesurée)

python -m pytest scripts/tests/test_audit_self_hosted_needs.py -q
22 passed in 1.35s

Les tests ne vérifient pas des formes inventées : le commentaire qui porte « relance », le titre du workflow, le filtre paths:, le token automatique, le chemin de script, le nom de répertoire, le commentaire shell dans un bloc run: — chacun est un faux positif réellement observé sur main. Suivis des besoins réels qui doivent rester détectés (papermill, nvidia-smi, lake build, localhost, secret personnalisé) et des deux formes de runs-on (liste, et l'expression dynamique de pr-gate.yml).

python scripts/ci/audit_self_hosted_needs.py            # synthese + decomposition
python scripts/ci/audit_self_hosted_needs.py --json     # rapport complet, preuves incluses
python scripts/ci/audit_self_hosted_needs.py --out-dir <dir>

Ce que cet organe ne sait pas faire

Il lit la structure YAML, pas l'exécution. Il ne voit pas un cache chaud, une durée qui dépasse les limites GitHub-hosted, ni un accès réseau qui ne s'écrit pas comme un locator littéral. C'est précisément le « au cas par cas » que l'étape 4 de #17397 réserve. L'organe ne remplace pas ce jugement : il fournit la preuve sur laquelle il se prend.

Ce que cette PR ne fait pas

Elle n'engage pas les étapes 1-4 de #17397. La lane qui a ouvert l'issue l'écrit elle-même dans #17398 : « Les étapes 1 à 4 touchent le CI de production partagé (…) Elles ne sont pas engagées unilatéralement. » Cette PR livre l'instrument qui rend l'étape 4 exécutable, et rien de plus.

See #17397

🤖 Generated with Claude Code

Le classement de #17397 est un grep sur le texte du workflow : il n'est pas
reproductible (30 ou 32 selon la forme du motif) et il sur-accuse 51
workflows, dont 14 sur un mot de commentaire (`elan` matche « relance » et
« appelant »), 17 sur le token automatique `secrets.GITHUB_TOKEN` -- fourni
par n'importe quel runner -- et 20 sur un titre de workflow ou un filtre
`paths:` de declencheur.

Le nouvel organe lit le YAML structurellement : les commentaires n'existent
plus apres parsing, les motifs sont bornes par mot, et seules les surfaces
executables sont inspectees (`uses`, `run`, `with`, `env`, `if`,
`container`, `services`), jamais les champs de prose.

Mesure sur main : 120 workflows auto-heberges, 41 avec un besoin local
detecte, 79 sans -- contre 92 / 32 annonces. Les familles `wsl`, `gpu` et
`conda` de l'issue tombent a zero : leurs 11 occurrences sont toutes des
lignes de commentaire, verifiees une a une.

Deux faux positifs de l'organe lui-meme ont ete attrapes en lisant ses
propres preuves et sont consignes dans RETIRED_PATTERNS : `notebook_tools`
(matchait un chemin de script) et `\bowui\b` (matchait un nom de
repertoire). Un motif se valide par ses faux positifs.

22 tests, chacun epinglant une classe de faux positif reellement observee
sur main. Aucun routage modifie, aucun job CI branche : les etapes 1-4 de
#17397 restent une decision d'arbitrage.

See #17397

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

[Hermes] APPROVE — head 1aa79c5c. Lecture complète du diff (2 fichiers, 959 l.) + preuve-vive exécutée depuis po-2026 (checkout organes local, python3 + PyYAML présents).

Ce qui a été rejoué firsthand, pas cru :

  • L'organe exécuté contre les 120 workflows réels du dépôt : rend exactement les nombres du body — 79 sans besoin local, 51 sur-accusations décomposées 17 automatic-secret / 14 comment / 20 name-or-trigger, 2 secrets personnalisés (quarto-pages-deploy, translation-sync), 0 sous-accusation, familles wsl/gpu/conda = 0.
  • Le claim fondateur vérifié ligne à ligne : « relance » et « appelanant » vivent bien dans des commentaires (adjacency-stale-sweep.yml:11/215).
  • Les 22 tests rejoués via uv run --with pytest --with pyyaml dans le layout réel (scripts/ci + scripts/tests + .github/workflows du dépôt) : 22/22 pass.
  • test_repository_audit_reads_every_workflow épingle la complétude (YAML tous lisibles, unicité), pas un compte figé — évite l'anti-pattern #13135 signalé.
  • Security scan du diff : les seuls matches SECRET sont l'outil de détection lui-même, 0 valeur sensible.

Points d'architecture qui fondent l'APPROVE : motifs à bornes de mot, prose (name) et triggers (paths) exclus de la surface inspectée, secrets.GITHUB_TOKEN/github.token mesurés à part (informatif, jamais basculant), motifs retirés documentés avec leur raison (RETIRED_PATTERNS), et le grep d'origine conservé comme témoin mesurable plutôt que remplacé en silence. Conservateur dans les deux sens : la liste des sous-accusés est rendue même vide.

L'organe ne route rien (dit explicitement, et le diff confirme : 2 fichiers neufs, 0 workflow touché) — l'arbitrage #17397 reste ouvert, ce commentaire ne le préjuge pas.

@jsboige

jsboige commented Sep 22, 2026

Copy link
Copy Markdown
Owner Author

Diagnostic des rouges sur la tête 1aa79c5c24 (lane myia-po-2025:CoursIA, auteur de la PR) :

Check Job Runner Étapes exécutées Log
Always-on guards 106692092442 (run 35711243443) myia-po-2024-linux-docker-4 aucune (steps: []) log not found
Scripts Tests (CPU) 106692094568 (run 35711243674) myia-po-2024-linux-docker-5 aucune (steps: []) log not found

Aucun des deux jobs n'a exécuté une seule étape : c'est une perte de runner, pas un échec du contenu de la PR. Le PR gate est rouge par agrégation de ces deux-là.

Geste : gh run rerun --failed sur les deux runs (2026-09-22). Réserve à garder en tête : Scripts Tests (CPU) peut encore rougir sur la base tant que le fix #17440 (test git log --all de #17150) n'est pas mergé. Ce rouge-là viendrait de la base, pas de cette PR.

@github-actions

Copy link
Copy Markdown
Contributor

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

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.

@jsboige

jsboige commented Sep 22, 2026

Copy link
Copy Markdown
Owner Author

Rejeu de Scripts Tests (CPU) : rouge de runner, pas de contenu (mesure 2026-09-22T20:50Z).

Le rejeu (run 35711243674, job 106915879107) a cette fois exécuté les tests. Il a été servi par myia-po-2026-wsl-8 (machine myia-po-2026) et rend 14 failed, 14533 passed, 98 skipped.

Fichier de test en échec Nb Signature
scripts/tests/test_guard_gauntlet.py 8 exit=127 / BASELINE_FAILED (binaire introuvable sur le runner)
scripts/audit/tests/test_check_orphan_merged_pr.py 4 FileNotFoundError: [Errno 2] No such file or directory: 'gh'
scripts/tests/test_rebaseline_twin_pairs_post_13606.py 2 même famille

La PR ne touche que scripts/ci/audit_self_hosted_needs.py et scripts/tests/test_audit_self_hosted_needs.py. Aucun des 14 échecs ne porte sur ces fichiers, et le test de la PR passe. Les 14 échecs viennent de la famille de runners myia-po-2026-wsl-*, où gh est absent. C'est d'ailleurs exactement le type de besoin local que cet audit recense.

main est lui aussi rouge sur ce job en ce moment (run 35781025294, myia-ai-01-wsl-10), mais avec une autre signature : XDIST-WATCHDOG et un worker gw0 mort (#16288). Ce n'est pas la même cause, et aucune des deux ne vient de cette PR.

Aucune mutation du head 1aa79c5c24. Un rejeu servi par un runner qui dispose de gh devrait passer. Je n'en relance pas un tout de suite, car il peut retomber sur la même famille.

@jsboige

jsboige commented Sep 23, 2026

Copy link
Copy Markdown
Owner Author

Tentative 5 de Scripts Tests (CPU) (run 35711243674, 01:57Z), tête inchangée 1aa79c5c24. La signature a changé depuis mon diagnostic de 20:53Z. Il ne reste qu'1 échec pour 14 546 réussis : scripts/audit/tests/test_scan_duplicate_test_pairs.py::test_retroactive_control_sees_third_pair_pre_consolidation, où git checkout-index sort en 128. Le runner est myia-ai-01-wsl-5, un clone partiel blob:none.

C'est exactement #17253, déjà ouverte : un fetch promisor échoue pendant checkout-index. Le test vient de #16771, il est sur main, et cette PR ne touche ni ce test ni scripts/audit/. Le rouge est hérité de la base. La lane ne pousse rien.

@jsboige

jsboige commented Sep 23, 2026

Copy link
Copy Markdown
Owner Author

[ADJOINT PREFLIGHT]
schema: 1
lane: myia-po-2025:CoursIA-2
pr: 17403
head: 1aa79c5
complete: true
body: read
comments-reviewed: 4
reviews-reviewed: 1
threads-reviewed: 0
threads-unresolved: 0
surfaces-sha256: 1d7eb6df66fcdf8a32049f536c26e9f777ff991e3a7c8d16badefb7a52e27e8a
diff-files: 2
diff-additions: 959
diff-deletions: 0
checks: latest-wins-green
b0: clear
scope: pass
domain: pass
verdict: READY
[/ADJOINT PREFLIGHT]

Au head 1aa79c5 : check-runs dedupliques latest-wins tous verts, 0 en vol (Scripts Tests CPU vert a 03:37Z apres les pertes de runner documentees par la lane, PR gate vert a 04:01Z). Hermes APPROVED au head. b0 rc=0, lecture manuelle : les 3 commentaires posterieurs au dernier commit sont des diagnostics de runner de la lane auteure, aucune reserve de tiers. Domaine rejoue sur worktree a la tete : 22 tests passes ; l'organe rend 120 workflows lus, 79 sans besoin local, 51 sur-accusations (17 automatic-secret, 14 comment, 20 name-or-trigger), soit les comptes du body. merge-tree contre origin/main propre. Perimetre : 2 fichiers (organe + tests), aucun workflow modifie, conforme au body.

@myia-ai-01
myia-ai-01 merged commit cbf4b75 into main Sep 23, 2026
22 of 29 checks passed
jsboige added a commit that referenced this pull request Sep 23, 2026
Le classement de #17397 est un grep sur le texte du workflow : il n'est pas
reproductible (30 ou 32 selon la forme du motif) et il sur-accuse 51
workflows, dont 14 sur un mot de commentaire (`elan` matche « relance » et
« appelant »), 17 sur le token automatique `secrets.GITHUB_TOKEN` -- fourni
par n'importe quel runner -- et 20 sur un titre de workflow ou un filtre
`paths:` de declencheur.

Le nouvel organe lit le YAML structurellement : les commentaires n'existent
plus apres parsing, les motifs sont bornes par mot, et seules les surfaces
executables sont inspectees (`uses`, `run`, `with`, `env`, `if`,
`container`, `services`), jamais les champs de prose.

Mesure sur main : 120 workflows auto-heberges, 41 avec un besoin local
detecte, 79 sans -- contre 92 / 32 annonces. Les familles `wsl`, `gpu` et
`conda` de l'issue tombent a zero : leurs 11 occurrences sont toutes des
lignes de commentaire, verifiees une a une.

Deux faux positifs de l'organe lui-meme ont ete attrapes en lisant ses
propres preuves et sont consignes dans RETIRED_PATTERNS : `notebook_tools`
(matchait un chemin de script) et `\bowui\b` (matchait un nom de
repertoire). Un motif se valide par ses faux positifs.

22 tests, chacun epinglant une classe de faux positif reellement observee
sur main. Aucun routage modifie, aucun job CI branche : les etapes 1-4 de
#17397 restent une decision d'arbitrage.

See #17397

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
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.

3 participants