Skip to content

fix(ci,#15766): comparer les liens casses a la base, pas au fichier fige - #15804

Merged
myia-ai-01 merged 1 commit into
mainfrom
fix/15766-docs-links-base-compare
Sep 12, 2026
Merged

myia-ai-01 merged 1 commit into
mainfrom
fix/15766-docs-links-base-compare

Conversation

@jsboige

@jsboige jsboige commented Sep 12, 2026

Copy link
Copy Markdown
Owner

Grain: MED/guard — lane myia-po-2023:CoursIA — prev: LIGHT/docs #15795

Le defaut

scripts/check_docs_links.py --check n'excusait un lien casse que s'il figurait dans scripts/tests/baseline_docs_links.json — un fichier fige a broken_links: []. Or --baseline, le seul mode qui l'ecrit, n'est appele par aucune automatisation (ni workflow, ni cron, ni script). Consequence mesuree : un seul lien casse sur main, meme introduit par une PR mergee, est rapporte comme « REGRESSION » sur toute PR ouverte, et rougit trois checks d'un coup — check-links, Always-on guards (Organes bloquants en echec : fastlane) et PR gate.

Le rouge est vrai mais mal attribue : il ne dit rien sur la PR qu'il annote.

La voie choisie, et pourquoi

L'issue proposait deux voies. C'est la voie 1 (comparer a la base) qui est livree : elle supprime la classe de defaut, pas seulement l'instance, et elle est deja la forme des autres ratchets du depot (« Output-failure ratchet base vs PR », « Translation hot-drift base vs PR »).

La voie 2 (rafraichir la reference sur main par un cron) est ecartee explicitement : passer broken_links de 0 a 1 cache le lien casse au lieu de le reparer, piege que l'issue nomme elle-meme. Sans compter qu'un cron sur main ne rendrait toujours pas le verdict dependant de la PR.

Ce que fait le correctif

  • --check --base <ref> : lit l'arbre de la base (git ls-tree -r) et l'excuse les liens deja casses la-bas.
  • Un lien n'est excuse que si les trois conditions tiennent : la source existait a la base, elle portait la meme cible, et cette cible y manquait deja. Donc restent detectees — et c'est le controle positif — un lien ajoute par la branche, et une cible que la branche supprime (le lien existait et resolvait a la base).
  • scan_file scinde en scan_content(content, rel_source) + enveloppe : le meme scanner sert l'arbre de travail et un git show <ref>:<path>. Aucune duplication de la logique de scan (blocs de code, spans inline, _is_valid_target).
  • L'oracle d'existence sur l'arbre git mirroir de check_link : traversal hors depot, sous-modules, cibles html generees par Quarto (notebook frere + project.render).
  • Le fichier fige garde son role sur les voies ou aucune base n'est disponible (dispatch manuel, scan complet). Les deux excuses sont independantes et se cumulent.
  • Garde de voie rapide check-links : passage a --base {base_ref} avec needs_base=True, la convention des gardes base-vs-head du depot. Le commentaire de docs-link-check.yml documente desormais l'ecart voulu entre les deux voies.

Le code de retour de git est inspecte avant de lire stdout : un clone partiel peut sortir non-zero en emettant un corps partiel, qui serait scanne comme s'il etait le fichier (#15387).

Preuves

Instance vivante de l'issue — lien MyIA.AI.Notebooks/IIT/ICT-Series/README.md:214 -> ICT-22b-CausalInterventionEngine.ipynb (ajoute par #15752 MERGED, cible vivant dans la PR ouverte #15609), arbre origin/main propre :

$ python scripts/check_docs_links.py --check
REGRESSION: 1 new broken link(s):
  MyIA.AI.Notebooks/IIT/ICT-Series/README.md:214 -> ICT-22b-CausalInterventionEngine.ipynb
$ echo $?
1

$ python scripts/check_docs_links.py --check --base origin/main
OK: No new broken links. (1 pre-existing, 6845 total)
$ echo $?
0

Acceptance 2 — controle positif, un lien neuf injecte dans un fichier scanne :

$ python scripts/check_docs_links.py --check --base origin/main
REGRESSION: 1 new broken link(s):
  docs/reference/common-commands.md:84 -> ./NOPE-missing-target-15766.md

Excused: 0 from baseline + 1 already broken at origin/main.
$ echo $?
1

Acceptance 1 et 2 satisfaites. Acceptance 3 (le lien README lui-meme redevient valide) n'est pas livree ici : elle releve de #15609, et l'issue la decrit comme l'autre moitie — c'est pourquoi cette PR dit See et non Closes.

Tests

scripts/tests/test_check_docs_links.py : 66 passent, dont 9 neufs — excuse par la base, non-masquage d'un lien neuf, cumul baseline+base, semantique inchangee sans base, oracle d'arbre (fichier, traversal interne, traversal hors depot, cible repertoire, html/Quarto liste ou non, sous-module), et un scenario git reel en tmp_path (depot init + 2 commits) verifiant les trois verdicts d'un coup, plus la revision illisible qui rend None.

$ python -m pytest scripts/tests/test_check_docs_links.py -q
66 passed

$ python -m pytest scripts/tests/test_check_docs_links.py scripts/tests/test_fast_lane.py scripts/tests/test_fast_lane_merge_base.py -q
141 passed

scripts/tests est execute par scripts-tests.yml (declencheur scripts/**), donc ces tests tournent bien en CI.

Perimetre

4 fichiers, 345 insertions / 38 suppressions : le checker, son test, la garde de voie rapide, et le commentaire du workflow absorbe. Catalogue byte-identique a main (non touche). Aucun notebook.

Residuel, signale et non traite

  • Le lien README lui-meme reste casse sur main jusqu'au merge de feat(ict,#15479): consumer notebook ICT-22b causal intervention engine (tranche 3/n) #15609. Cette PR rend le garde juste ; elle ne retire pas la cause.
  • La durabilite du fichier fige : il n'est toujours ecrit par personne. Il ne sert plus que les voies sans base, donc il ne peut plus produire de faux rouge de PR — mais le jour ou un dispatch manuel tombera dessus avec un main casse, il dira « REGRESSION ». C'est le comportement voulu (pas de base a comparer), pas une dette a rembourser.

See #15766

🤖 Generated with Claude Code

`--check` n'excusait un lien casse que s'il figurait dans
`baseline_docs_links.json` — un fichier fige a `broken_links: []` qu'aucune
automatisation ne regenere (`--baseline` n'est appele nulle part). Un seul
lien casse sur `main`, meme introduit par une PR mergee, etait donc rapporte
comme « REGRESSION » sur TOUTE PR ouverte, et rougissait trois checks d'un
coup : `check-links`, `Always-on guards` et `PR gate`.

Voie 1 de l'issue : `--check --base <ref>` lit l'arbre de la base et
soustrait les liens deja casses la-bas. Un lien n'est excuse que si la source
existait a la base, portait la meme cible, et que cette cible y manquait
deja. Un lien ajoute par la branche, ou une cible que la branche supprime,
restent donc des regressions. Le fichier fige garde son role sur les voies
sans base disponible (dispatch manuel, scan complet).

`scan_file` est scinde en `scan_content(content, rel_source)` + enveloppe :
le meme scanner sert l'arbre de travail et un `git show <ref>:<path>`. Le
code de retour de git est inspecte AVANT de lire stdout (#15387).

La garde de voie rapide `check-links` passe desormais `--base {base_ref}`
avec `needs_base=True` — la convention des gardes base-vs-head du depot.

Mesure sur un arbre `origin/main` propre (lien ICT-Series/README.md:214
introduit par #15752 MERGED, dont la cible ne vit que dans la PR ouverte
#15609) :

    avant : REGRESSION: 1 new broken link(s): ...           -> exit 1
    apres : OK: No new broken links. (1 pre-existing, 6845) -> exit 0

Controle positif — un lien neuf injecte reste designe :

    REGRESSION: 1 new broken link(s):
      docs/reference/common-commands.md:84 -> ./NOPE-...md  -> exit 1

Tests : 66 dans `test_check_docs_links.py` (dont 9 neufs : excuse par la
base, non-masquage d'un lien neuf, oracle d'arbre git, traversal, cible
html/Quarto, sous-module, revision illisible), 141 avec les suites
fast-lane. `scripts/tests` est execute par `scripts-tests.yml`, donc ces
tests tournent en CI.

See #15766 — l'acceptance 3 (le lien README lui-meme redevient valide)
releve de #15609 : les deux moities sont complementaires.

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é: logs CI firsthand — 22/22 checks green hors DWELL ; test_check_docs_links.py 66 dots verts dans Scripts Tests (CPU) exécuté sur le head ; needs_base=True + --base {base_ref} conforme au pattern des autres ratchets base-vs-PR du registre)

[Hermes] — #15804 review head b66a59b7. R=0 sur ce SHA, aucune review ni commentaire pré-existant.

Issue-first method match (#15766) : la voie 1 de l'issue (« comparer à la base ») est exactement celle livrée — --check --base <ref> excusant un lien déjà cassé à la base, voie 2 (cron refresh du baseline) explicitement écartée avec le piège nommé (cacher le lien cassé au lieu de le réparer). Pas de substitution de méthode.

Vérifié firsthand :

  1. Code : _git_show inspecte le return code AVANT stdout (#15387 partial-clone — correct) ; preexisting_broken exige les 3 conditions (source existait à la base, même cible, cible déjà absente) — un lien ajouté par la branche OU une cible supprimée par la branche reste une régression. Contrôle positif couvert par test_unrelated_preexisting_does_not_mask_a_new_link. L'oracle _link_exists_in_tree est bien le miroir de check_link (traversal hors dépôt, sous-modules, html/Quarto).
  2. Exécution réelle : run 34709836414 (Scripts Tests CPU, head) — test_check_docs_links.py 2×33 dots verts, suite totale 13225 passed. Le rouge PR gate est un DWELL anti-flapping (log [pr-gate] settled: 22 check(s) green, plancher 120 min, sweep horaire) — pas un défaut substance.
  3. Registre : needs_base=True + --base {base_ref} = même convention que les gardes 183/194/201/314 (Output-failure ratchet, Translation hot-drift) — cohérence du pattern confirmée sur le fichier head.
  4. Security scan : 0 match.

Note (mineure, non bloquant) : la 3ᵉ case d'acceptance de l'issue (le lien README redevient valide) est hors scope assumé — relève de #15609, la PR dit See et non Closes. Cohérent, et le body le documente.

@myia-ai-01
myia-ai-01 merged commit 14f016a into main Sep 12, 2026
24 of 25 checks passed
jsboige added a commit that referenced this pull request Sep 12, 2026
…ige (#15804)

`--check` n'excusait un lien casse que s'il figurait dans
`baseline_docs_links.json` — un fichier fige a `broken_links: []` qu'aucune
automatisation ne regenere (`--baseline` n'est appele nulle part). Un seul
lien casse sur `main`, meme introduit par une PR mergee, etait donc rapporte
comme « REGRESSION » sur TOUTE PR ouverte, et rougissait trois checks d'un
coup : `check-links`, `Always-on guards` et `PR gate`.

Voie 1 de l'issue : `--check --base <ref>` lit l'arbre de la base et
soustrait les liens deja casses la-bas. Un lien n'est excuse que si la source
existait a la base, portait la meme cible, et que cette cible y manquait
deja. Un lien ajoute par la branche, ou une cible que la branche supprime,
restent donc des regressions. Le fichier fige garde son role sur les voies
sans base disponible (dispatch manuel, scan complet).

`scan_file` est scinde en `scan_content(content, rel_source)` + enveloppe :
le meme scanner sert l'arbre de travail et un `git show <ref>:<path>`. Le
code de retour de git est inspecte AVANT de lire stdout (#15387).

La garde de voie rapide `check-links` passe desormais `--base {base_ref}`
avec `needs_base=True` — la convention des gardes base-vs-head du depot.

Mesure sur un arbre `origin/main` propre (lien ICT-Series/README.md:214
introduit par #15752 MERGED, dont la cible ne vit que dans la PR ouverte
#15609) :

    avant : REGRESSION: 1 new broken link(s): ...           -> exit 1
    apres : OK: No new broken links. (1 pre-existing, 6845) -> exit 0

Controle positif — un lien neuf injecte reste designe :

    REGRESSION: 1 new broken link(s):
      docs/reference/common-commands.md:84 -> ./NOPE-...md  -> exit 1

Tests : 66 dans `test_check_docs_links.py` (dont 9 neufs : excuse par la
base, non-masquage d'un lien neuf, oracle d'arbre git, traversal, cible
html/Quarto, sous-module, revision illisible), 141 avec les suites
fast-lane. `scripts/tests` est execute par `scripts-tests.yml`, donc ces
tests tournent en CI.

See #15766 — l'acceptance 3 (le lien README lui-meme redevient valide)
releve de #15609 : les deux moities sont complementaires.

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