Repository navigation
fix(ci): check_c2_compliance --json viole son contrat sur cible vide -> un rouge indiscernable d'un defaut de carnet #20198
Description
Sans parent : residuel du garde introduit par #14799 (ferme) ; c'est le volet depot de l'episode runner dont le volet infra vit sur #20174.
Le defaut
check_c2_compliance.py --json ne respecte pas son contrat --json quand la liste de cibles est vide : il imprime une chaine humaine et sort en 0.
# scripts/notebook_tools/check_c2_compliance.py:313-317
targets = get_target_notebooks(args)
if not targets:
print("No notebooks to check.")
return 0Le garde CI du workflow notebook-validation.yml (l.102-113) redirige cette sortie dans /tmp/c2_results.json et la parse comme du JSON :
python scripts/notebook_tools/check_c2_compliance.py --json > /tmp/c2_results.json || C2_EXIT=$?
VIOLATIONS=$(python -c "import json; data=json.load(open('/tmp/c2_results.json')); ...")
if ! VIOLATIONS=$(... 2>/tmp/c2_parse.err); then
echo "::error::C.2 results not parseable as JSON — scanner wrote non-JSON or truncated output (#14799)"
exit 1
fi
Resultat : un return 0 (succes du scanner) devient un exit 1 du job, avec un message qui nomme un carnet et un fichier de resultats, jamais la cause.
Pourquoi ce n'est pas qu'un detail cosmetique
Mesure firsthand du 2026-10-10, sur #19590 (tete 8eed473259), job validate-notebooks (run 38005462188) :
##[error]C.2 results not parseable as JSON — scanner wrote non-JSON or truncated output
(file starts with: 'No notebooks to check. ') (#14799)
Cette PR modifie bien un carnet (MyIA.AI.Notebooks/IIT/ICT-Series/ICT-23-PersonaCatastrophe-Python.ipynb, +28/-6). En local, meme tete, arbre propre : --json rend un JSON valide commencant par [, et le carnet y figure.
Le vrai declencheur est un arbre de travail ampute cote runner (cause racine sparse-checkout herite, suivie sur #20174) : le catalogue commite est lu, mais aucun des carnets qu'il liste n'existe sur le disque, donc targets == []. Sur un arbre sain, c'est impossible — le catalogue absent fait basculer sur rglob("*.ipynb"), qui rend des centaines de carnets.
Le cout est un cycle de diagnostic par lane : le rouge est indiscernable d'un defaut de contenu. Une lane qui ne rejoue pas l'organe en local conclut a tort que son carnet est casse, corrige un diff qui n'a rien, ou re-diagnostique la meme cause que ses voisines.
Proposition de correction (minimale, deux fichiers)
check_c2_compliance.py— en mode--json, toujours emettre du JSON. Cible vide ->[]. Le contrat est verifie par un test.notebook-validation.yml— traiter la cible vide comme une erreur explicite et nommee, jamais comme un succes : quandlen(results) == 0, sortir en 1 avec un message qui dit la cause probable (checkout incomplet : le catalogue liste N carnets, aucun n'est present sur le disque).
Le point 2 est indispensable : sans lui, le point 1 masque le defaut d'environnement ([] -> 0 notebooks, 0 cells -> le else du workflow imprime « All notebooks C.2 compliant. »). Le contrat JSON et la distinction vide/panne sont les deux moities de la meme correction, et aucune ne doit partir seule.
Criteres d'acceptation
python scripts/notebook_tools/check_c2_compliance.py --jsonsur une cible vide rend une sortie parseable (rc a definir explicitement, et ce choix teste).- Un test couvre le cas « cible vide » et affirme le contrat JSON.
- Le workflow
notebook-validationrougit sur cible vide avec un message qui nomme la cause probable, et ne peut plus presenter ce cas comme un succes. - Aucun changement de verdict sur une cible non vide (non-regression : le comportement nominal est inchange).
Contexte de decouverte
Remonte par la lane myia-po-2023:CoursIA-2 (cycle c.1241) en drainant sa file de reparation P0. Le diagnostic complet et les cinq organes mesures a la tete exacte sont sur #19590 (commentaire 6092628798), et l'escalade fleet est sur le dashboard global, avec la cause racine chez #20174.
Activity
jsboige commentedon Oct 10, 2026
[CLAIMED] lane myia-po-2023:CoursIA-2 -- fix du contrat
--jsondu scanner C.2 sur cible vide + erreur nommee dans le workflow (2 fichiers, tests)jsboige commentedon Oct 10, 2026
[INFO] lane
myia-po-2023:CoursIA-2— correction livree en branchefeature/20198-c2-json-empty-target(commitd9b7947766), PR differee au lever du plafond WIP de la lane (27/15, consigne coordinateur).check_c2_compliance.py: en--json, cible vide ->[]parseable, rc 0 explicite (le vide est un resultat de scan valide ; la distinction vide/panne appartient a l'appelant).notebook-validation.yml: liste vide apres parse =::error::nomme (checkout incomplet : le scanner n'a trouve AUCUN carnet (catalogue lu mais fichiers absents du disque ?)) et exit 1 — le cas ne peut plus s'afficher « All notebooks C.2 compliant. ».[], le garde rend 0 => le bloc sort en 1 avec l'erreur nommee ; cible reelle (1 carnet) -> garde rend 1 => verdict C.2 normal inchange.yaml.safe_loadOK) ; diff : 3 fichiers, +56/-1.Merge origin/main into fix/20198-c2-json-contract
fix(ci,#20198): check_c2_compliance --json emet [] sur cible vide, et…