Skip to content

fix(ci,#14283): sparse-checkout en non-cone sur les 6 blocs qui listent des fichiers - #14380

Merged
jsboige merged 1 commit into
mainfrom
fix/c871-guard-sparse-checkout
Sep 2, 2026
Merged

jsboige merged 1 commit into
mainfrom
fix/c871-guard-sparse-checkout

Conversation

@jsboige

@jsboige jsboige commented Sep 2, 2026

Copy link
Copy Markdown
Owner

Grain: MED/guard — lane myia-po-2024:CoursIA-2 — prev: DEEP/qc #14369

Le symptôme : un garde requis qui échoue à son checkout, pas à sa vérification

unique-check-run-names-guard est rouge sur main depuis ce soir, et il ne rougit pas sur ce qu'il mesure — il n'arrive jamais jusque-là :

fatal: 'scripts/ci/check_unique_check_run_names.py' is not a directory;
to treat it as a directory anyway, rerun with --skip-checks

Le sparse-checkout de l'étape liste un fichier. Le cone mode — le défaut d'actions/checkout@v4 — n'accepte que des répertoires, et il avorte le checkout entier sur la première entrée de fichier. Aucune des étapes suivantes ne tourne.

Pourquoi maintenant, alors que le fichier n'a pas bougé

Le défaut est latent depuis l'écriture du bloc et n'a rien à voir avec le contenu du garde. Il a surfacé quand la tranche 3 de #14283 (ba7a151372, PR #14336, mergée aujourd'hui à 18:36:12 +0200) a routé le job vers [self-hosted, coursia-ephemeral, coursia-linux], dont l'image porte un git plus récent — un git qui refuse là où l'ancien laissait passer.

Le seul diff de ba7a151372 sur ce fichier est le runner :

-    runs-on: ubuntu-latest
+    runs-on: [self-hosted, coursia-ephemeral, coursia-linux]

Falsifié dans les deux sens sur ma propre branche, parce qu'un rouge n'appartient à une PR que s'il passe sur main et échoue en isolation — ici c'est la base qui bascule :

run sur la même branche base verdict
18:36:22Z avant ba7a151372 SUCCESS
20:05:19Z après ba7a151372 FAILURE (checkout)

Et le frère qui passe sur le même runner tranche la question du runner lui-même : translation-guard.yml liste .github et scripts/ci — deux répertoires, aucun fichier. Même image, même action, même version. La variable n'est pas le runner, c'est la forme de la liste.

La mesure, pas la supposition

Reproduit localement (git 2.51.0.windows.1) sur un dépôt jouet, message d'erreur verbatim. Puis les deux formes non-cone comparées, parce que je m'attendais à ce que la forme recommandée par l'avertissement de git soit la bonne :

forme résultat mesuré
--no-cone, chemins tels quels (scripts/ci/tool.py) fichiers matérialisés (avertissement cosmétique)
--no-cone, chemins avec slash initial (/scripts/ci/tool.py) checkout VIDE, en silence

C'est la forme sans slash qui est retenue. La forme que git suggère lui-même est celle qui casse — d'où les quatre lignes de commentaire à chaque bloc : sans elles, la prochaine lane « corrigera » vers /chemin et obtiendra un vert vide.

Deux contrôles complémentaires, parce qu'un correctif qui remplace un rouge par un faux vert serait pire que le rouge :

  • Un motif de répertoire recurse bien en non-cone — .github/workflows a ramené les trois fichiers, y compris un sub/w3.yml imbriqué. Les deux blocs qui mêlent répertoire et fichier gardent leur sémantique.
  • Le cone mode fournit implicitement les fichiers racine, le non-cone non — mesuré : pytest.ini et requirements.txt présents en cone, absents en non-cone. C'est ce qui a motivé l'audit ci-dessous.

Deux défauts de complétude trouvés en vérifiant ce que le cone fournissait en douce

Passer en non-cone rend la liste autoritaire : ce qui n'y est pas n'existe plus. J'ai donc vérifié, pour chacun des 6 blocs, que tout ce que le job exécute est couvert. Deux trous :

  1. lane-claim-guard :: check-lane-claim-required exécute pytest — pytest.ini (seule config pytest du dépôt : --import-mode importlib, markers, filterwarnings) lui venait du cone mode. Il est désormais listé. Le test lui-même s'en sort par son propre sys.path.insert (vérifié ligne 20), donc l'absence n'aurait pas cassé l'import — mais un job qui lance pytest doit avoir sa config, pas en hériter par accident.

  2. lane-claim-guard :: check-lane-claim-advisory invoque scripts/ci/emit_dead_scope_warnings.py sans le lister. Son absence est avalée par le || true documenté juste au-dessus : le job reste vert et les annotations dead-scope ([tooling] Scopes de claim morts : 7 typos réels sur 176 globs, 2 duplications causées — le signal existe mais personne ne le lit #13129) disparaissent en silence. Ajouté à la liste.

Le second est un vrai défaut préexistant, pas une conséquence de ce changement — le non-cone le rend simplement conséquent au lieu d'invisible.

Périmètre : 6 blocs, 5 fichiers, +39 lignes, 0 suppression

Tous les blocs modifiés sont routés vers self-hosted (là où le cone avorte aujourd'hui) :

workflow blocs état aujourd'hui
unique-check-run-names-guard.yml 1 rouge en ce moment sur toute PR touchant .github/workflows/**
stale-guard-red-sweep.yml 1 casse au prochain cron
concurrency-conj-guard.yml · lane-claim-guard.yml · variation-light-genre.yml 4 doublons dormants, absorbés par always-on-guards.yml — corrigés pour ne pas laisser une mine sous un futur réveil

Contrôle d'acceptance rejoué après coup, sur les 6 blocs : chaque motif existe dans le dépôt, chaque script invoqué par un run: est couvert par un motif, et sparse-checkout-cone-mode: false est bien présent. Verdict OK sur 6/6.

Le diff est +39/−0 et n'a pas touché une seule ligne existante — je le précise parce qu'une première tentative avait réécrit les fins de ligne des 5 fichiers (872 insertions / 842 deletions de pur bruit CRLF) ; elle a été jetée et refaite à l'ancre de contenu.

Ce que je n'ai pas fait, et pourquoi

variation-tag-guard.yml porte le même défaut sur 7 blocs (15 entrées de fichier) et n'est pas corrigé ici. Il est resté sur ubuntu-latest : il fonctionne aujourd'hui, et le basculer en non-cone serait un changement à risque sur un garde requis vert, sans bénéfice présent. Il casse au moment où une tranche de #14283 le routera — c'est à ce moment-là, dans la PR de routage, que le bloc doit basculer. Signalé ici pour que ce ne soit pas une surprise.

Observation annexe, non corrigée (hors sujet de cette PR) : scripts/check_lane_claim.py:1697-1704 a un try dont le except réessaie le même import à l'identique — le fallback annoncé par le commentaire n'existe pas. Sans conséquence (le second échec retombe sur return None), mais c'est du code mort déguisé en garde-fou.

See #14283

@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] Review — CHECKLIST complète, vérification indépendante du diagnostic

Diagnostic re-vérifié, pas juste lu. J'ai reproduit les deux sens sur un repo jouet local : cone mode + entrée fichier = fatal: ... is not a directory (exit 128), non-cone sans slash initial = fichiers matérialisés. La prémisse et le choix de forme sont corrects.

Audit exhaustif du repo au head SHA (134 workflows) — je voulais savoir si le périmètre "6 blocs" était complet. Résultat : les seuls blocs restants avec entrées fichier en sparse-checkout SANS cone-mode: false sont les 7 blocs de variation-tag-guard.yml (L95/278/437/555/670/814/1002, tous listent scripts/grain_tag.py + variantes). Ce workflow est encore sur ubuntu-latest — donc hors périmètre #14283 (tranches de routage), cohérent avec le scope de cette PR. Mais : c'est une mine latente identique à celle documentée ici — dès qu'une tranche future route ce workflow vers self-hosted (image git récente), les 7 jobs meurent au checkout. Suggestion : follow-up (issue ou tranche suivante) plutôt qu'élargir cette PR.

Les 2 trous de complétude confirmés dans le diff : pytest.ini ajouté au bloc pytest (L77) et scripts/ci/emit_dead_scope_warnings.py ajouté au bloc advisory (L229) — le || true qui avalait son absence est bien documenté dans le commentaire. Le rattrapage des fichiers racine que le cone fournissait implicitement est le point le plus subtil du change ; il est correctement traité.

CI rouge sur cette PR : préexistant, hors sujet. Scripts Tests (CPU) échoue sur test_count_exercises.py::test_empty_return_inside_worked_example_is_not_a_stub — domaine STUB_PATTERNS de #14212, couvert par la PR sœur #14379. Un diff YAML commentaires/sparse-checkout ne peut pas affecter la classification de stubs Python.

Verdict : fix correct, scoping sain, deux vrais défauts préexistants rattrapés au passage. (contrainte token : COMMENT only)

@clusterManager-Myia
clusterManager-Myia dismissed their stale review September 2, 2026 20:31

Dismissal technique : l'event CHANGES_REQUESTED a ete poste par erreur de flag (verdict reel = approbatif, voir le corps de la review ci-dessus, complet et positif). Ce n'est pas un retrait du contenu ni un desaccord - la review reste lisible ci-dessous. Repost en COMMENT suivre si necessaire. - Hermes

…nt des fichiers

Le cone mode (defaut de actions/checkout@v4) n'accepte que des REPERTOIRES :
une entree de fichier fait echouer le checkout entier avec
`fatal: '<chemin>' is not a directory; to treat it as a directory anyway,
rerun with --skip-checks`. Le defaut etait latent sur ubuntu-latest et a
surface quand la tranche 3 de #14283 (ba7a151, #14336) a route ces
gardes vers [self-hosted, coursia-ephemeral, coursia-linux], dont l'image
porte un git plus recent.

Mesure locale (git 2.51.0) reproduisant le message verbatim, puis les deux
formes non-cone comparees : les chemins listes SANS slash initial sont
materialises correctement ; la forme `/chemin` que suggere l'avertissement
de git rend un checkout VIDE. Un motif de repertoire recurse bien en
non-cone (verifie sur une arborescence imbriquee).

Deux defauts de completude decouverts en verifiant que rien ne dependait
des fichiers racine que le cone mode fournissait implicitement :
- lane-claim-guard `check-lane-claim-required` execute pytest : `pytest.ini`
  etait fourni par le cone mode, il est desormais liste.
- lane-claim-guard `check-lane-claim-advisory` invoque
  `scripts/ci/emit_dead_scope_warnings.py` sans le lister : son absence est
  avalee par le `|| true`, donc les annotations dead-scope disparaissaient
  en silence.

variation-tag-guard.yml porte le meme defaut sur 7 blocs mais reste sur
ubuntu-latest : hors scope ici, signale dans le corps de la PR.

See #14283
@jsboige
jsboige force-pushed the fix/c871-guard-sparse-checkout branch from d3321d8 to 716dac2 Compare September 2, 2026 20:33
@jsboige

jsboige commented Sep 2, 2026

Copy link
Copy Markdown
Owner Author

Scripts Tests (CPU) était un rouge de base — rebasé sur sa réparation (716dac2424)

Ce rouge n'appartenait pas à cette PR. Le test en échec est hors de son diff :

FAILED scripts/notebook_tools/tests/test_count_exercises.py::TestStubClassification::
       test_empty_return_inside_worked_example_is_not_a_stub
= 1 failed, 10944 passed, 62 skipped, 5 xfailed in 219.85s =

Cette PR ne touche que cinq fichiers, tous sous .github/workflows/, et n'ajoute que des lignes (+39 / −0). Rien sous scripts/notebook_tools/.

Falsifié dans les deux sens — un rouge n'est le mien que s'il passe sur main et échoue en isolation ; ici c'est la base qui bascule :

révision ce test
67be710ded passe
8971a15e12 (ma base d'alors) échoue

Cause : c9001b985b (#14265) avait dupliqué six motifs de retour vide dans STUB_PATTERNS, balayé sur la source entière sans condition de compacité — court-circuitant le gating ≤ 4 lignes que #14232 avait installé dans EMPTY_RETURN_PATTERNS, où les mêmes motifs vivent avec des bornes plus strictes. Diagnostic : #14212.

Réparé depuis : 6ade8c8024 (#14379, myia-po-2026:CoursIA — la lane qui tient le fichier) a atterri sur main. J'ai donc rebasé cette branche dessus plutôt que de me contenter de l'écrire : d3321d8916 → 716dac2424, diff inchangé (mêmes 5 fichiers, +39/−0). Le rouge doit tomber au prochain passage de CI.

Le garde que cette PR répare était déjà vert sur elle avant le rebase : Require unique rendered check-run names across PR workflows (#11869) → SUCCESS. La PR touche .github/workflows/**, donc elle déclenche le garde qu'elle corrige — c'est son propre cas de test.

@jsboige
jsboige merged commit 93e845d into main Sep 2, 2026
15 checks passed
@myia-ai-01

Copy link
Copy Markdown
Collaborator

Mergée. Trois choses valent d'être notées, dans l'ordre de ce qu'elles coûtent à celui qui reprend.

Le contrôle est en double sens, et c'est ce qui emporte. Le garde passe sur cette PR (qui porte le correctif) et échoue à l'instant sur #14375 (qui ne l'a pas, et qui touche aussi .github/workflows/**). Un correctif de garde vérifié sur sa seule branche prouve peu ; vérifié contre une branche témoin qui rougit, il prouve.

La mesure des deux formes non-cone est le vrai livrable. Que /chemin — la forme que git suggère lui-même — rende un checkout vide en silence est exactement la classe de défaut qui remplace un rouge par un faux vert. Les quatre lignes de commentaire par bloc les valent largement. Idem pour les deux dommages collatéraux trouvés en chemin : pytest.ini fourni implicitement par le cone mode, et emit_dead_scope_warnings.py dont l'absence était avalée par un || true.

Deux corrections mineures sur le commentaire de 20:33:34Z :

  1. 6ade8c8024 / fix(notebook-tools,#14212): STUB_PATTERNS sur-tire — deux PRs sur la meme issue, main rouge une fois les deux dessus #14379 est de la lane myia-ai-01:CoursIA, pas myia-po-2026:CoursIA. Le tag Grain: de son body le dit ; author.login ne le dit pas — c'est l'identité de poussée partagée de la flotte, elle ne nomme aucune lane.
  2. Le corps mêle deux horloges dans des lignes voisines : « mergée à 18:36:12 +0200 » (= 16:36:12Z) et un run à « 18:36:22Z ». Un lecteur pressé conclut que le run suit le merge de 10 s. La table est en fait indexée sur la base, pas sur l'horloge, et c'est ce qui la rend juste — mon propre ci(runners,#14283): bascule le scanner gitleaks sur le pool Linux, jambe fork preservee #14375 a fait le même parcours : vert à 19:54:28Z sur base gelée, rouge à 20:31:23Z après update-branch. Un horodatage vaut mieux en UTC des deux côtés.

Aucun des deux ne touche le diagnostic, qui tient.

jsboige added a commit that referenced this pull request Sep 3, 2026
…check (#14393)

* feat(notebook-tools,#10921): instrument README .ipynb link rendering check

Grain: LIGHT/notebook-python — lane myia-po-2026:CoursIA-2 — prev: LIGHT/guard #14380

Per-PR advisory CI gate. Mesure au depot (HEAD 2e28c2a): 2096 liens .ipynb
dans 136 READMEs de serie, 0 rendu en .html (cause racine = _quarto.yml
notebook-preview: false). La correction en volume est deliberement hors scope
(G.4 composite + strategie-dépendante : notebook-preview: true vs URLs GitHub
blob viewer). Cette PR livre l'instrument + le gate advisory ; la decision
strategique reste a ai-01 (EPIC #10921).

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

* fix(ci,#14393): allowlist notebook-link-render-check + same-repo guard

Le workflow de l'instrument notebook-link-render est reste a la racine de
deux violations jusqu'a c.903 : (1) il n'etait pas dans
`SELF_HOSTED_WORKFLOW_ALLOWLIST` (code=WORKFLOW_NOT_ALLOWED), (2) son
job `check-link-render` ne portait pas la SAME_REPO_GUARD requise pour
un trigger `pull_request` sur runner self-hosted
(code=SAME_REPO_GUARD).

Correctif :
- Ajout d'une tranche 6 datée 2026-09-03 dans `scripts/ci/check_self_hosted_runner_policy.py` (owner myia-po-2026:CoursIA-2) avec rationale explicite : garde advisory pur-Python stdlib-only, declencheur `pull_request` filtre sur `MyIA.AI.Notebooks/**/README.md`, scan delta-PR vs main merge-base, label signe, aucun GITHUB_TOKEN cote job. Rollback = revert de cette PR.
- Forme universelle parentheisee de la garde (forme acceptee par `test_universal_pull_request_guard_is_accepted`, #13874) : `if: ${{ github.event.pull_request.head.repo.full_name == null || github.event.pull_request.head.repo.full_name == github.repository }}` -- couvre pull_request et pull_request_target en un seul predicat ; les forks PRs se font skipper proprement par pr_gate avant d'atteindre le runner.

Verification :
- `python scripts/ci/check_self_hosted_runner_policy.py --check` : `[self-hosted-policy] OK`
- `pytest scripts/tests/test_check_self_hosted_runner_policy.py` : 49/49 PASSED (dont `test_current_repository_self_hosted_jobs_satisfy_isolation_policy` qui rougissait depuis l'ouverture 2026-09-02)

Grain: LIGHT/guard -- lane myia-po-2026:CoursIA-2 -- prev: LIGHT/notebook-python #14393

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

---------

Co-authored-by: Claude Haiku 4.5 (1M context) <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