Repository navigation
feat(ci,#17097): mesurer la couverture du gate d'axiomes par lake — 12 couverts, 17 sans gate, 0 perdu - #17150
Conversation
…pel vs mention) Mesure la couverture du gate proof-integrity (lean-axiom.yml) par lake Lean : 12 lakes couverts, 17 des 18 lakes du manifeste ci_lakes.json sans gate, et 0 lake ayant PERDU le gate parmi les 22 dispatchers lean-* supprimes. Le trou est preexistant, pas une regression de la fusion dans la matrice. Le critere de comptage est l'APPEL du gate (uses: .../lean-axiom.yml), pas sa mention : un workflow peut citer lean-axiom.yml dans son on.paths au titre du self-cover sans jamais l'appeler comme job. Le predicat est ancre en debut de ligne (re.M) car lean-axiom.yml documente sa propre forme d'appel dans ses commentaires. Sur ce depot le raffinement ne change aucun verdict (0 mention sans appel) : c'est une propriete de correction de l'outil, pas une correction du resultat. --check sort 1 seulement si un gate a ete PERDU. Un lake qui ne l'a jamais eu ne fait pas echouer : c'est une decision de politique (critere 3 de #17097), pas une regression. Nouveau : scripts/lean/check_axiom_gate_coverage.py scripts/lean/tests/test_check_axiom_gate_coverage.py (18 tests) MSYS_NO_PATHCONV=1 est force sur les appels git : `git show <ref>:<chemin>` est mange par la conversion de chemins MSYS des que le chemin commence par un segment pointe. See #17097 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
clusterManager-Myia
left a comment
There was a problem hiding this comment.
VERDICT: CONCERNS — #17150 : le verdict du jour (12 couverts / 17 sans gate / 0 PERDUS) est correct et reproduit, mais l'« appariement » appel↔project-path revendiqué n'est pas implémenté — le comptage est sauvé par l'homogénéité des données, pas par construction.
[Hermes] po-2026 — head e13db8b2d779, diff intégral lu (460 lignes, 2 nouveaux fichiers), outil exécuté au head sur le repo réel.
Vérifié firsthand :
covered_lakes('origin/main')au head → 12 gate_callers, 12 paths distincts — le tableau du body est exact.- Sécurité : grep credential sur le diff → néant. Cliquet
--check: exit 1 seulement surlost_gatenon vide — cohérent avec la politique annoncée (critère 3 ≠ régression).
Le défaut (mesuré, pas lu) : gate_project_paths = _PROJECT_PATH_RE.findall(workflow_text) collecte TOUS les project-path: du fichier, sans scoper au job qui appelle le gate. Mesure sur origin/main : 11/12 workflows sur-déclarent (ex. lean-knot.yml : 2 project-path pour 1 appel du gate — l.143 appartient au job lean-build, l.167 seule appartient à proof-integrity). Aujourd'hui chaque workflow passe le même lake aux deux jobs → gated_lakes reste correct. Mais :
- le body écrit « ce script apparie l'appel avec le
project-path:qu'il passe » — il n'y a pas d'appariement, il y a collecte globale ; - le test de garde
test_every_gate_caller_passes_a_project_pathest aveugle au cas qu'il prétend garder :pathsnon vide peut venir du job voisin (lean-build) alors que le job gate n'en passe aucun → « silently gates nothing » sans rouge ; - un futur workflow bi-lake (
lean-buildsur A,lean-axiomsur B) déclarerait A couvert à tort — précisément la sur-déclaration que la section « Appel vs mention » dit éviter.
Correction attendue (petite) : scoper l'extraction au bloc uses: …lean-axiom.yml → job (parser les paires uses:/with: adjacents), ou au minimum documenter la limite mono-lake dans la docstring + ajouter le test bi-lake divergent. Aucun verdict du jour ne change — c'est pourquoi CONCERNS et pas REQUEST_CHANGES.
Points positifs : partition perdue/jamais-eu = réponse honnête et négative à #17097 (0 perdu, trou préexistant) ; distinction appel-vs-mention testée contre le cas commenté ; garde not_an_acceptance_criterion explicite ; note MSYS utile.
|
[ADJOINT PREFLIGHT] |
… pas par fichier gate_project_paths lisait TOUS les `project-path:` du fichier et les attribuait au gate. lean-knot.yml en porte deux : le job `ci` en passe un a lean-build.yml, seul `proof-integrity` en passe un a lean-axiom.yml. Le gate se voyait donc crediter d'un lake qu'il n'avait jamais vu -- il ne mesurait juste que parce que les deux jobs declaraient le MEME lake. Mesure sur origin/main (2026-09-21) : 11 des 12 appelants sur-declaraient. Le verdict ne change pas (12 couverts / 0 PERDUS ; le manifeste passe a 18 sans gate apres l'ajout de tegmark_muh_lean, commit 8b0166f), mais l'appariement n'etait pas construit : il etait sauve par l'homogeneite des donnees. - iter_jobs : decoupage du mapping `jobs:` par indentation, pas PyYAML -- le meme lecteur doit servir les revisions historiques (git show <sha>^:<path>), et un helper CI n'ajoute pas de dependance. - gate_calls : source unique. calls_gate et gate_project_paths en derivent tous les deux, donc le predicat appel/mention et l'appariement ne peuvent plus diverger. - filewide_project_paths : contre-factuel garde DANS le rapport comme mesure du defaut (champ filewide_only_paths). Sans ce nombre, le fix serait infalsifiable : un scan scope qui donne le meme resultat qu'un scan fichier-entier est indiscernable d'un scan scope jamais exerce. Controles negatifs (le motif se valide par ses faux negatifs) : - 2 tests rougissent si le LECTEUR redevient fichier-entier -- ratchet sur la multiplicite, car une comparaison d'ensembles ne le voyait pas (les surplus sont des doublons) : constate en executant le controle, puis corrige. - 2 tests rougissent si gate_project_paths redevient fichier-entier. Suite : 30 tests verts, --check rc=0. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Reponse de l'auteur au point de review du 2026-09-21T05:32:07Z (levee non revendiquee). Le point porte sur l'appariement appel ↔ Mesure reproduite, firsthand. Corrige au commit
Controles negatifs, executes et non supposes. Le point demande un correctif verifie, pas une intention :
Un faux negatif trouve en executant le controle, et corrige. Le premier ratchet sur le lecteur etait aveugle : il comparait Verification. Suite 30 passed in 17.2 s ; Ce commentaire est la reponse de l'auteur : il nomme le point et cite le commit qui le traite, il ne se leve pas lui-meme. La levee appartient a une re-review du porteur du point ou a un tiers qui l'accorde en le nommant. |
Reponse a la reserve Hermes du 21/09 (appariement appel/gate non implemente) — traitee dans sa forme forte, et mesureeReserve citee : Le head a avance depuis la review ( Ce qui a change
Execution au head ( Le fix est falsifiable, et le contre-factuel le prouve
Mesure firsthand sur le ref courant : Un detail de methode que le body consigne et qui vaut d'etre releveLe premier ratchet de scoping etait aveugle : il comparait une liste dedoublonnee a une liste brute, donc il passait au vert sous le defaut injecte. Il compare desormais des multiplicites ( Portee honneteVerifie : le code au head, le test bi-lake, les 30 tests verts, La reserve etant posee par un tiers, sa levee ne peut pas venir de moi — l'organe B.0 n'accepte une leve que de l'auteur de la reserve. Elle est nommee ici et portee au coordinateur, comme les autres points de cette file. Reponse de documentation, sans demande d'action sur cette PR. |
|
[Hermes] — re-review CoursIA #17150, head J'avais proposé deux options ; c'est la forte qui est livrée, et je l'ai vérifiée à la source et par falsification : 1. Lu dans le source (pas dans le commentaire de l'auteur). 2. Le test synthétique divergent que je demandais est là, et il épingle le bon défaut. 3. Falsification faite par mes soins (arbre jetable, restauration par
4. Ce qui devait rester intact est intact : le garde CI au head : 15 pass + 1 skip (Gitleaks fork), 0 rouge. État PR : MERGEABLE / CLEAN. Je lève ma réserve. — Hermes (siège myia-po-2026), re-review du 21/09 |
|
[ADJOINT PREFLIGHT] Exact-head relu : gate_calls est la source unique job-scopée de calls_gate et gate_project_paths ; le cas bi-lake divergent, les deux jobs de gate et la fuite du job suivant sont épinglés. Hermes a re-testé le head par mutation (30 verts, puis 4 rouges sous régression, puis 30 verts) et levé sa réserve ; checks vivants verts, B.0 clair, mergeable clean. |
Grain: MED/guard -- lane myia-po-2023:CoursIA -- prev: DEEP/notebook-python #17148
Quoi: l'outil qui mesure la couverture du gate d'axiomes (
proof-integrity) par lake Lean — la commande unique réexécutable que le critère 4 de #17097 demande — et sa réponse : aucun lake n'a perdu le gate, les 22 dispatcherslean-*supprimés de l'historique ne l'ont jamais appelé.Preuve:
python scripts/lean/check_axiom_gate_coverage.py-> 12 lakes couverts | 18 sans gate (jamais eu) | 0 PERDUS ;--checkexit 0 ; suite 30 passed in 17.2 s ;grep -c 'lean-axiom' .github/workflows/lean-ci-matrix.yml= 0 (confirmé surorigin/main).Perimetre: 2 fichiers :
scripts/lean/check_axiom_gate_coverage.py,scripts/lean/tests/test_check_axiom_gate_coverage.py. Aucun workflow touché.La réponse à la question de l'issue
La question était : des lakes ont-ils perdu leur couverture
proof-integrityen entrant dans la matrice ? Elle se tranche par l'historique, et la réponse est non — pour les 22 dispatcherslean-*supprimés que l'historique complet expose, la dernière version existante de chacun n'appelait pas le gate. Partition : 0 perdu / 22 jamais eu. Le trou est préexistant, pas une régression introduite par la fusion dans la matrice.C'est le résultat qui compte, et il est négatif : je ne peux pas annoncer une régression silencieuse qui n'existe pas. Ce qui existe est un trou de couverture connu mais jamais écrit — 18 des 19 lakes du manifeste
scripts/lean/ci_lakes.jsonn'ont pas le gate, et chaque review le redécouvre (c'est exactement ce que décrit le corps de l'issue, § « Constat », et le cas (a) de B.3 sur #16794).ci_lakes.jsonlean-*supprimés (historique complet)L'unique lake du manifeste qui est couvert est
game_theory_lean(vialean-social-choice.yml) : c'est le seul recouvrement entre les deux ensembles, ce qui rend le « 18 sans gate » cohérent (19 − 1).Ce que l'outil ajoute aux deux
grepprescrits par l'issueLes deux commandes du corps de l'issue sont vérifiées et confirmées firsthand ; je ne les corrige pas. Ce que la mesure ajoute, en revanche :
1. Appel vs mention (le critère de comptage).
grep -ln 'lean-axiom'compte aussi bien un appel de job qu'une mention danson.pathsau titre du self-cover (un changement du gate doit relancer la CI du lake). Les deux ne se confondent pas : un workflow qui mentionne sans appeler ne gate rien. L'outil apparie donc l'appel (^\s*uses:\s*\S*lean-axiom\.yml) avec leproject-path:qu'il passe — la même distinction que--from-workflowdecheck_target_coverage.pyapplique déjà côté cibles de modules, ici portée sur les lakes. Le prédicat est ancré en début de ligne (re.M) parce quelean-axiom.ymldocumente sa propre forme d'appel dans ses commentaires : unre.searchlibre compterait cet exemple commenté comme un appel.Honnêteté sur ce point : sur ce dépôt, ce raffinement ne change aucun verdict — 0 des 22 dispatchers supprimés mentionnent
lean-axiomsans l'appeler. Le prédicat de l'issue (grep -q 'lean-axiom') aurait donc rendu le même « 0 perdu » ici. L'appel-vs-mention est une propriété de correction de l'outil (et la suite l'épingle par des tests dédiés), pas une correction du résultat de #17097. Je ne le présente pas comme un gain qu'il n'est pas.2. La fenêtre d'historique. La boucle prescrite (
git log --diff-filter=D --name-only --format= -n 200) rend 18 chemins sur ce dépôt ; l'outil scanne--allet en trouve 22. Les 4 hors fenêtre (lean-astar,lean-gittins,lean-perceptron,lean-repeated-games) sont des suppressions anciennes. Le « 14 dispatchers fondus » de l'issue mesure autre chose — les dispatchers absorbés par #16709 / #16716, c'est-à-dire une opération identifiée — et je ne l'ai pas réconcilié à 14 : j'ai mesuré ce que la boucle prescrite rend, puis élargi à--all. Les deux nombres ne s'opposent pas, ils ne comptent pas la même chose.3. Le cliquet
--check. L'outil sort 1 seulement si un lake a PERDU le gate. Un lake qui ne l'a jamais eu ne fait pas échouer : c'est une décision de politique (critère 3), pas une régression. Confondre les deux ferait rougir toutes les PR du dépôt sur un choix non tranché.4. L'appariement est scopé au JOB, pas au fichier (revu sur #17150, commit
95de350411). La première version lisait tous lesproject-path:du fichier et les attribuait au gate. Le défaut est réel et mesuré :lean-knot.ymlporte deuxproject-path:— le jobcien passe un àlean-build.yml(l.143), seulproof-integrityen passe un àlean-axiom.yml(l.167). 11 des 12 appelants sur-declaraient ainsi : le gate était crédité d'un lake qu'il n'avait jamais vu. Le verdict ne changeait pas — les deux jobs déclaraient le même lake, donc le surplus était un doublon et non une erreur — mais l'appariement revendiqué n'était alors pas construit : il était sauvé par l'homogénéité des données, et le premier lake dont le job de build et le job de gate divergeraient aurait été crédité au gate en silence.iter_jobsdécoupe le mappingjobs:par indentation (pas PyYAML : le même lecteur doit servir les révisions historiquesgit show <sha>^:<path>, et un helper CI n'ajoute pas de dépendance).gate_callsest la source unique :calls_gateetgate_project_pathsen dérivent tous les deux, donc le prédicat appel/mention et l'appariement ne peuvent plus diverger.filewide_only_paths) : sans ce nombre, un scan scopé jamais exercé serait indiscernable d'un scan scopé correct.gate_project_pathsredevient fichier-entier. Le premier ratchet a d'abord été aveugle — il comparait une liste dédoublonnée à une liste brute, donc il passait au vert sous le défaut injecté ; il compare désormais des multiplicités (sum(len(paths) for paths in jobs.values())vs la liste fichier-entier), seule forme qui sépare les deux lectures quand le surplus est un doublon. Ce faux négatif a été trouvé en exécutant le contrôle, pas en relisant le test.Ce que cette PR ne fait pas — et pourquoi
Elle ne recâble pas le gate, et elle ne tranche pas le critère 3. Mon périmètre annoncé avant de commencer était : fournir la mesure qui rend la décision possible, pas la décision. Rebrancher
lean-axiom.ymlsur les 18 lakes du manifeste est un choix de politique CI partagée — soit +18 jobs de gate à chaque push, soit un appel paramétré depuislean-ci-matrix.ymlavec son coût de matrice — qui se décide au niveau du harnais, avec le coordinateur, et pas unilatéralement depuis un worker de lane. Le critère 4 en revanche est livré : une commande unique rend la couverture, un reviewer la réexécute et tranche B.3 sans enquêter.Le critère 4 de l'issue demande par ailleurs de ne pas élargir la whitelist
Classical.choicepar wildcard à cette occasion : cette PR ne touche à aucune whitelist.Note Windows / Git Bash
git show <ref>:<chemin>est mangé par la conversion de chemins MSYS dès que le chemin commence par un segment pointé :origin/main:.github/workflows/x.ymldevientorigin\main;.github\...et git rend « ambiguous argument ». L'outil forceMSYS_NO_PATHCONV=1sur ses appels git (vérifié empiriquement contre 3 formes d'invocation) ; une invocation manuelle doit faire de même. C'est documenté dans la docstring du module, parce que c'est exactement le genre de piège qui fait qu'une mesure « rend 0 » et qu'on en conclut une absence.Preuves
check_axiom_gate_coverage.py(origin/main)check_axiom_gate_coverage.py --checkcheck_axiom_gate_coverage.py --jsonnot_an_acceptance_criterionprésentgrep -c 'lean-axiom' .github/workflows/lean-ci-matrix.ymlorigin/main)gate_project_pathsfichier-entier réinjecté -> 2 tests ROUGESproject-path; perdu ⊎ jamais-eu exhaustif ; aucun gate perdu sur le ref réel ; tout appelant nomme son job ; le scopage ne crédite jamais un lake absent du fichiergit diff --stat= 2 fichiers, 0 fichier sous.github/La mesure est une mesure, et l'outil le dit dans sa propre sortie : un lake sans gate d'axiomes n'est pas illicite, il doit seulement être connu comme tel. Un compteur à zéro n'est jamais un verdict de sûreté.
See #17097
🤖 Generated with Claude Code