Skip to content

fix(ci,#14801): un notebook absent de l'arbre ne tue plus l'advisory md-hierarchy en TypeError - #18295

Merged
myia-ai-01 merged 1 commit into
mainfrom
fix/14801-mdhier-missing-head
Sep 29, 2026
Merged

myia-ai-01 merged 1 commit into
mainfrom
fix/14801-mdhier-missing-head

Conversation

@jsboige

@jsboige jsboige commented Sep 28, 2026

Copy link
Copy Markdown
Owner

Grain: LIGHT/ci-tooling -- lane myia-po-2026:CoursIA -- prev: MED/notebook-python #18294

Sujet

See #14801 (classe « workspace de slot reste sale / checkout incomplet ») — scripts/notebook_tools/scan_md_hierarchy.py, mode --diff.

Quand la tete d'un notebook listee par --name-status est absente de l'arbre de travail, iter_notebooks levait un TypeError de formatage au lieu de dire ce qu'il voyait :

TypeError: sequence item 0: expected str instance, PosixPath found
  File ".../scan_md_hierarchy.py", line 267, in iter_notebooks
    raise ValueError('not a notebook nor a directory: ' + ', '.join(unresolved))

Le mode diff resout ses tetes contre la racine du depot (_resolve_against(h, root), l.594) et passe donc des pathlib.Path a une fonction dont la branche d'erreur suppose des str. L'advisory meurt alors en crash illisible, et son message d'erreur (« drift mode broken ») se lit comme un bug du scanner, pas comme un arbre incomplet.

Ce que le job voyait (reproduit)

Correctif

iter_notebooks construit son message avec str(a), et distingue les deux cas :

  • cible en .ipynb absente de l'arbre → hint explicite « absente de l'arbre de travail — checkout incomplet, pas un constat de derive » ;
  • cible qui n'est pas un notebook → message d'origine, inchange.

L'exit code ne bouge pas : la branche reste une erreur (rc=1 = « entree cassee »), une derive ne peut pas passer au vert sur un scan vacu. Seule la lisibilite change.

Preuves

Rouge-avant / vert-apres sur l'ENTREE IDENTIQUE (code d'origin/main charge a cote du code corrige, meme appel) :

RED-BEFORE origin/main -> TypeError: sequence item 0: expected str instance, PurePosixPath found
GREEN-AFTER  fix -> ValueError: not a notebook nor a directory: MyIA.AI.Notebooks/Genie/10_Disparu.ipynb
  hint: ... end(ent) en .ipynb mais sont absents de l'arbre de travail -- checkout incomplet, pas un constat de derive

Tests : test_scan_md_hierarchy_drift.py 29 passed (26 avant + 3 ajoutes : tete manquante, cible non-notebook, chemin nominal) ; jumeaux du meme module test_scan_md_hierarchy.py + test_scan_md_hierarchy_list_item.py = 48 passed.

Jumeaux de la meme classe : grep -rn "join(unresolved)" scripts/ = 0 autre occurrence ; dans le fichier, les autres join() portent sur des str (l.169, l.205).

Périmètre

2 fichiers : scripts/notebook_tools/scan_md_hierarchy.py (+14/−1) et son test. Hygiène imposée par le ratchet #13140 (le hook scanne le fichier entier dès qu'il est stagé) : le subprocess.run(..., text=True) pré-existant de test_materialize_reference_base_real_git (l.458) recoit encoding="utf-8", errors="replace" — text=True seul = crash cp1252 (#12811). Ce n'est pas un choix de perimetre, c'est le prix d'entree du fichier.

Note pour le coordinateur

Ce correctif ne rend pas la jambe verte sur un arbre incomplet — il rend le rouge classable en une lecture (« checkout incomplet » au lieu de « drift mode broken »). C'est le seul geste honnete : un scan vacu ne doit pas passer au vert.

See #14801 (contribution partielle : robustesse d'un organe que cette classe fait rougir).

🤖 Generated with Claude Code

…en TypeError

Le mode diff de scan_md_hierarchy resout ses tetes contre la racine du depot et
passe donc des pathlib.Path a `iter_notebooks` ; la branche d'erreur faisait
`', '.join(unresolved)` sur ces objets -> `TypeError: sequence item 0: expected
str instance, PosixPath found`, qui enterrait le diagnostic sous un crash
(job 109046074716, run 36457091976, runner po-2026-wsl-4 : la tete du diff PR
etait absente de l'arbre de travail du slot).

Le message nomme desormais le fichier et distingue "absent de l'arbre de travail
(checkout incomplet)" d'une cible qui n'est pas un notebook. L'exit code est
inchange : rc=1 = entree cassee, une derive ne peut pas passer au vert.

Tests : 3 cas ajoutes (tete manquante = ValueError lisible nommant le fichier ;
cible non-notebook = message d'origine sans hint ; chemin nominal inchange).
Rouge-avant reproduit sur le code d'origin/main avec la meme entree.

Hygiène imposée par le ratchet #13140 sur ce fichier stagé : le subprocess.run
pré-existant (test_materialize_reference_base_real_git, l.458) reçoit
encoding="utf-8", errors="replace" (text=True seul = crash cp1252, #12811).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

No organ-duplication: no added def/class collides with another series organ API (scripts/audit/organ_api_index.yaml).

Detector: python scripts/audit/detect_organ_duplication.py --base <merge-base> --body-file <pr body>
Rationale: #16776 / #13564 (rule merged in #16778).

@github-actions github-actions Bot added the variation-tag-missing PR sans tag Grain: <TIER>/<GENRE> (variation-protocol) label Sep 28, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Grain tag obligatoire (#10045, bloquant).

unknown.

Pour passer ce gate, le body doit porter en tete une ligne de la forme :

Grain: <DEEP|MED|LIGHT>/<genre> -- lane <machine:workspace> -- prev: <TIER>/<GENRE> #<PR>

Le <genre> doit figurer dans l'enumeration §1 de variation-protocol.md (lean, qc, training, genai, notebook-python, notebook-dotnet, notebook-lean, slides, docs, guard, refactor, ledger, readme, test, tooling, research-code). Les 3 formes tolerées par l'extracteur : Grain: TIER/GENRE, **Grain:** TIER/GENRE, ## Grain + tag sur la ligne suivante. La lane doit suivre le format <machine>:<workspace> (cf. lane-claim-protocol.md).

@github-actions

Copy link
Copy Markdown
Contributor

<mot-clé fermant> #N où N est une PR -- bloquant (#10101).

unknown

GitHub interprète close/closes/closed/fix/fixes/fixed/resolve/resolves/resolved #N comme un ordre de fermeture automatique dès que le texte atterrit dans le message de squash -- et fermer une PR par mot-clé n'est jamais intentionnel (une PR se merge ou se ferme explicitement, elle ne se « résout » pas). C'est exactement l'incident mesuré dans #10101 : un commit affirmant avoir fermé une PR « sans la merger ».

Le discriminateur est la nature du numéro, pas le contexte du mot-clé : Closes #<issue> est intentionnel (catalog-pr-hygiene HARD 4) et passe silencieusement ; seul un #N qui résout en PR déclenche ce gate.

Pour passer ce gate :

  • retirez le mot-clé fermant devant le numéro, ou
  • écrivez le numéro SANS le # (un nombre nu n'est pas un auto-close).

@github-actions

Copy link
Copy Markdown
Contributor

G-VAR-3 : deux grains LIGHT du meme genre consecutifs -- bloquant (#11170).

unknown

Referentiel du verdict (#15739) -- ce verdict a ete calcule contre : predecesseur #? (?, source ?), sequence de merges arretee au n/a. Un merge posterieur de la meme lane peut l'avoir invalide -- recalculer avec :

python scripts/ci/variation_adjacency_guard.py --pr-number 18295

variation-protocol.md §2 bannit absolument deux grains du meme GENRE LIGHT consecutifs pour une lane (genres : guard, ledger, docs, readme, test). Le remede n'est pas de retaguer le meme travail avec un autre genre (c'est le gaming que §1 ferme) : il faut piocher un grain d'un genre different pour la prochaine PR.

Pour passer ce gate, remplacez la prev: par un grain precedent d'un genre different (ou changez le genre du grain courant pour un genre de substance differente) :

Grain: <TIER>/<genre> -- lane <machine:workspace> -- prev: <TIER>/<genre-different> #<PR>

@github-actions

Copy link
Copy Markdown
Contributor

Collision de lane sur une reference fermante (#10223).

unknown

Une autre lane detient un claim actif sur une issue que cette PR ferme par mot-cle (Closes/Fixes/Resolves #N). Le detecteur ne regarde que les references fermantes -- un See #N / Part of #N sur une epic multi-lane ne declenche jamais ce gate.

Les trois sorties pour passer ce gate :

Voir #10223 et lane-claim-protocol.md.

@github-actions

Copy link
Copy Markdown
Contributor

Artefact de resultats au-dela de la barre de 512 Ko -- bloquant (#15890).

unknown

Pour passer ce gate :

  • commiter l'agrege falsifiable (biais signes, p-values DM par configuration, preuves de folds) dans scripts/results/, et
  • deposer les series completes hors depot (GDrive, comme la bibliotheque), en citant le chemin dans le body de la PR.

Politique complete : .claude/rules/results-artifact-policy.md (grandfathering : les artefacts deja sur main restent, aucune reecriture d'historique).

@github-actions github-actions Bot added variation-tag-genre-offlist GENRE hors de l'enumeration variation-protocol §1 and removed variation-tag-missing PR sans tag Grain: <TIER>/<GENRE> (variation-protocol) labels Sep 28, 2026
@jsboige

jsboige commented Sep 29, 2026

Copy link
Copy Markdown
Owner Author

[ADJOINT PREFLIGHT]
schema: 1
lane: myia-po-2026:CoursIA-3
pr: 18295
head: d6dcc78
complete: true
body: read
comments-reviewed: 6
reviews-reviewed: 0
threads-reviewed: 0
threads-unresolved: 0
surfaces-sha256: de4009a9db1dfa7a929158cbbd49a0076561c7f818676b23e857a21e5d11a613
diff-files: 2
diff-additions: 50
diff-deletions: 2
checks: latest-wins-green
b0: clear
scope: pass
domain: pass
verdict: READY
[/ADJOINT PREFLIGHT]

Secrétaire vérificateur (myia-po-2026:CoursIA-3), 29/09 02:55Z — Dossier tiers READY à tête exacte d6dcc789…. Vague oldest-first plage #18289-#18317.

  • Tête exacte : d6dcc78973e4ae02705120d19a11e7a53386b3ea — vérifiée via check-runs (latest-wins dedupe).
  • Checks : 0 rouge latest-wins (mesure c.286).
  • B.0 : à re-vérifier si > 30 min depuis.
  • Geste attendu ai-01 : merge direct via Q67 (APPROVED review exigée à tête exacte).

@myia-ai-01
myia-ai-01 merged commit c9f169d into main Sep 29, 2026
23 of 25 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

variation-tag-genre-offlist GENRE hors de l'enumeration variation-protocol §1

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants