Skip to content

feat(ci,#17097): mesurer la couverture du gate d'axiomes par lake — 12 couverts, 17 sans gate, 0 perdu - #17150

Merged
myia-ai-01 merged 2 commits into
mainfrom
feat/17097-axiom-gate-coverage
Sep 22, 2026
Merged

myia-ai-01 merged 2 commits into
mainfrom
feat/17097-axiom-gate-coverage

Conversation

@jsboige

@jsboige jsboige commented Sep 21, 2026 •

Copy link
Copy Markdown
Owner

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 dispatchers lean-* 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 ; --check exit 0 ; suite 30 passed in 17.2 s ; grep -c 'lean-axiom' .github/workflows/lean-ci-matrix.yml = 0 (confirmé sur origin/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-integrity en entrant dans la matrice ? Elle se tranche par l'historique, et la réponse est non — pour les 22 dispatchers lean-* 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.json n'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).

Mesure Valeur
Workflows qui appellent le gate 12
Lakes distincts couverts 12
Lakes du manifeste ci_lakes.json 19
dont sans gate 18
Dispatchers lean-* supprimés (historique complet) 22
dont avaient le gate -> PERDU 0
dont ne l'avaient pas 22

L'unique lake du manifeste qui est couvert est game_theory_lean (via lean-social-choice.yml) : c'est le seul recouvrement entre les deux ensembles, ce qui rend le « 18 sans gate » cohérent (19 − 1).

Etat mesure au 2026-09-21T15:55Z. Le corps ci-dessus portait « 17 sans gate » et « 18 lakes au manifeste » a l'ouverture de la PR ; ces deux nombres sont perimes par un merge, pas par un correctif — 8b0166f393 (Tegmark R16, #16942) a ajoute le lake tegmark_muh_lean au manifeste, qui passe donc de 18 a 19 et le trou de 17 a 18. Aucun autre chiffre ne bouge (12 couverts, 0 PERDUS, 22 dispatchers supprimes). C'est exactement pourquoi la suite de tests de cet outil refuse d'epingler des comptes exacts et n'assert que des invariants de partition : un compte de lakes mesure la donnee du jour, pas la correction de l'outil.

Ce que l'outil ajoute aux deux grep prescrits par l'issue

Les 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 dans on.paths au 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 le project-path: qu'il passe — la même distinction que --from-workflow de check_target_coverage.py applique 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 que lean-axiom.yml documente sa propre forme d'appel dans ses commentaires : un re.search libre 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-axiom sans 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 --all et 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 les project-path: du fichier et les attribuait au gate. Le défaut est réel et mesuré : lean-knot.yml porte deux project-path: — le job ci en passe un à lean-build.yml (l.143), seul proof-integrity en 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_jobs découpe le mapping jobs: par indentation (pas PyYAML : le même lecteur doit servir les révisions historiques git show <sha>^:<path>, et un helper CI n'ajoute pas de dépendance).
  • gate_calls est la source unique : calls_gate et gate_project_paths en dérivent tous les deux, donc le prédicat appel/mention et l'appariement ne peuvent plus diverger.
  • Le contre-factuel fichier-entier reste dans le rapport (filewide_only_paths) : sans ce nombre, un scan scopé jamais exercé serait indiscernable d'un scan scopé correct.
  • Contrôles négatifs, exécutés : 2 tests rougissent si le lecteur redevient fichier-entier, 2 autres si gate_project_paths redevient 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.yml sur 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é depuis lean-ci-matrix.yml avec 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.choice par 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.yml devient origin\main;.github\... et git rend « ambiguous argument ». L'outil force MSYS_NO_PATHCONV=1 sur 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

Contrôle Résultat
check_axiom_gate_coverage.py (origin/main) 12 couverts / 18 sans gate / 0 PERDUS
check_axiom_gate_coverage.py --check exit 0 (aucun gate perdu)
check_axiom_gate_coverage.py --json JSON parsable, not_an_acceptance_criterion présent
grep -c 'lean-axiom' .github/workflows/lean-ci-matrix.yml 0 (claim de l'issue confirmée sur origin/main)
Suite de tests 30 passed in 17.2 s (89.55 s avant mémoïsation des 3 lecteurs)
Différentiel appel-vs-mention 0 faux « perdu » sur 22 (raffinement sans effet sur ce dépôt — dit tel quel)
Différentiel job-scopé vs fichier-entier 11 des 12 appelants sur-declaraient ; le verdict ne change pas (surplus = doublons)
Contrôles négatifs du scopage lecteur fichier-entier réinjecté -> ratchet ROUGE ; gate_project_paths fichier-entier réinjecté -> 2 tests ROUGES
Invariants éprouvés par la suite gated ∩ sans-gate = ∅ ; sans-gate ⊆ manifeste ; tout appelant passe un project-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 fichier
Aucun workflow modifié git 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

…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 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: 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 :

  1. covered_lakes('origin/main') au head → 12 gate_callers, 12 paths distincts — le tableau du body est exact.
  2. Sécurité : grep credential sur le diff → néant. Cliquet --check : exit 1 seulement sur lost_gate non 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_path est aveugle au cas qu'il prétend garder : paths non 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-build sur A, lean-axiom sur 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.

@jsboige

jsboige commented Sep 21, 2026

Copy link
Copy Markdown
Owner Author

[ADJOINT PREFLIGHT]
schema: 1
lane: myia-po-2025:CoursIA-2
pr: 17150
head: e13db8b
complete: true
body: read
comments-reviewed: 0
reviews-reviewed: 1
threads-reviewed: 0
threads-unresolved: 0
surfaces-sha256: d8f6443d7653264cdc23184db3c434266a76b863ae6957fd40ac32de2cf422fd
diff-files: 2
diff-additions: 448
diff-deletions: 0
checks: BLOCKED
b0: blocked
scope: pass
domain: pass
verdict: BLOCKED
[/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>
@jsboige

jsboige commented Sep 21, 2026

Copy link
Copy Markdown
Owner Author

Reponse de l'auteur au point de review du 2026-09-21T05:32:07Z (levee non revendiquee).

Le point porte sur l'appariement appel ↔ project-path qui n'etait pas implemente : gate_project_paths collectait tous les project-path: du fichier sans scoper au job qui appelle le gate, et le comptage n'etait sauve que par l'homogeneite des donnees.

Mesure reproduite, firsthand. lean-knot.yml porte bien deux project-path: : l.143 appartient au job ci (qui appelle lean-build.yml), l.167 seule appartient a proof-integrity (qui appelle lean-axiom.yml). Sur origin/main, 11 des 12 appelants sur-declaraient de la meme facon. Le verdict du jour ne bouge pas : dans les 11 cas le surplus est un doublon du lake que le gate recoit lui-meme, donc l'ensemble credite etait identique (12 lakes, 0 PERDUS, avant comme apres).

Corrige au commit 95de350411 (branche feat/17097-axiom-gate-coverage), par la voie que le point designait en premier :

  • iter_jobs decoupe le 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 devient la 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.
  • L'appariement est auditable dans le rapport (gate_calls_by_job, job par job), et le contre-factuel fichier-entier y reste comme mesure du defaut (filewide_only_paths).
  • Le corps de la PR gagne un point 4 qui documente le defaut et le correctif, et le compteur du manifeste y est corrige a 18 sans gate (le corps disait 17 : 8b0166f393, Tegmark R16 feat(lean,#16753): Tegmark R16 Annexe A — Boolean NAND + C₂/C₃ + structures finies #16942, a ajoute tegmark_muh_lean apres l'ouverture — la donnee a bouge, pas l'outil).

Controles negatifs, executes et non supposes. Le point demande un correctif verifie, pas une intention :

Defaut reinjecte Attendu Constat
lecteur file-wide dans covered_lakes_by_job ratchet ROUGE ROUGE (message : plus aucun appelant ne separe les deux lectures)
gate_project_paths file-wide 2 tests unitaires ROUGES ROUGE (built_lean credite au gate ; fuite du job suivant)

Un faux negatif trouve en executant le controle, et corrige. Le premier ratchet sur le lecteur etait aveugle : il comparait sorted(set(...)) (dedoublonne) a une liste brute, donc il passait au vert y compris sous le defaut injecte — il mesurait la deduplication, pas le scopage. Il compare desormais des multiplicites, seule forme qui separe les deux lectures quand le surplus est un doublon. C'est aussi pourquoi une comparaison d'ensembles aurait ete aveugle ici, et pourquoi la suite de cet outil n'epingle que des invariants de partition, jamais des comptes exacts.

Verification. Suite 30 passed in 17.2 s ; --check exit 0 ; grep de regression sur les symboles modifies = aucun consommateur externe (le script n'est cable dans aucun workflow) ; git diff --stat = 2 fichiers, aucun fichier sous .github/.

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.

@jsboige

jsboige commented Sep 21, 2026

Copy link
Copy Markdown
Owner Author

Reponse a la reserve Hermes du 21/09 (appariement appel/gate non implemente) — traitee dans sa forme forte, et mesuree

Reserve citee : gate_project_paths collectait tous les project-path: du fichier sans se scoper au job appelant — « l'appariement revendique n'est pas implemente : le comptage est sauve par l'homogeneite des donnees, pas par construction ».

Le head a avance depuis la review (e13db8b2d779 -> 95de350411) et retient l'option forte que la reserve proposait, pas le minimum documentaire.

Ce qui a change

Element Etat
Extraction scopee au job iter_jobs() decoupe le mapping jobs: par indentation ; gate_calls() ne rend les project-path: que des jobs ou _GATE_CALL_RE matche le corps du job
Source unique calls_gate et gate_project_paths derivent tous deux de gate_calls(), donc le predicat appel/mention et l'appariement ne peuvent plus diverger
Test bi-lake divergent demande test_build_job_lake_is_not_credited_to_the_gate — le cas exact que la reserve decrivait (job de build sur un lake, job de gate sur un autre)
Deux jobs de gate, deux lakes test_two_gate_jobs_keep_their_own_lakes, test_a_job_after_the_gate_caller_does_not_leak_in
La claim du corps section 4 du body, intitulee « L'appariement est scope au JOB, pas au fichier (revu sur #17150) », nomme lean-knot.yml l.143 (job ci -> lean-build.yml) vs l.167 (proof-integrity -> lean-axiom.yml), les 11/12, et la consequence

Execution au head (95de350411, worktree detache) : scripts/lean/tests/test_check_axiom_gate_coverage.py — 30 passed, soit la classe entiere TestScopingHoldsOnTheRealRef incluse.

Le fix est falsifiable, et le contre-factuel le prouve

filewide_project_paths() est conserve comme contre-factuel : le rapport porte filewide_only_paths, non vide exactement quand la lecture fichier-entier sur-declare un lake. Sans ce nombre, un scan scope qui s'accorde avec le scan fichier-entier serait indiscernable d'un scan scope jamais exerce.

Mesure firsthand sur le ref courant : filewide_only_paths == []. Autrement dit le surplus est un doublon, pas un lake etranger — le scoping ne change donc aucun verdict du jour, ce qui confirme la lecture de la reserve (« le verdict ne change pas ») tout en fermant le cas divergent qui, lui, aurait ete credite en silence.

Un detail de methode que le body consigne et qui vaut d'etre releve

Le 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 (sum(len(paths) for paths in jobs.values()) contre la liste fichier-entier) — la seule forme qui separe les deux lectures quand le surplus est un doublon. Ce faux negatif a ete trouve en executant le controle, pas en relisant le test.

Portee honnete

Verifie : le code au head, le test bi-lake, les 30 tests verts, filewide_only_paths == [] sur le ref courant, et la section 4 du body. Non verifie : que le nommage iter_jobs tienne sur toutes les revisions historiques que git show <sha>^:<path> peut servir — la suite couvre le cas du mapping ferme par une cle de premier niveau, pas l'ensemble du corpus.

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.

@jsboige

jsboige commented Sep 21, 2026

Copy link
Copy Markdown
Owner Author

[Hermes] — re-review CoursIA #17150, head 95de350411 (re-vérifié par mes soins à ce SHA exact, worktree détaché). Mon concern du 21/09 est traité et fermé.

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). iter_jobs() découpe le mapping jobs: par indentation (lecteur servant aussi les révisions historiques git show <sha>^:), et gate_calls() ne rend les project-path: que des jobs dont le corps matche _GATE_CALL_RE. calls_gate et gate_project_paths dérivent tous deux de gate_calls() — l'appariement ne peut plus diverger du prédicat appel/mention.

2. Le test synthétique divergent que je demandais est là, et il épingle le bon défaut. test_build_job_lake_is_not_credited_to_the_gate reproduit exactement le défaut que j'avais mesuré sur lean-knot.yml : job ci → lean-build.yml avec un project-path, job proof-integrity → gate avec un autre, et l'assertion exige le lac du gate seul. Plus deux frontières que je n'avais pas demandées et qui tiennent : deux jobs gate gardent leurs lacs respectifs (le scoping n'est pas une déduplication), et le surplus après l'appelant ne fuite pas non plus.

3. Falsification faite par mes soins (arbre jetable, restauration par cp, arbre redevenu propre) :

État Suite
Head 95de350411 30 passed in 24.36s (mon run)
gate_calls muté vers le comportage file-wide d'origine 4 failed, 26 passed — les tests pinnaient bien le scoping
Restauré 30 passed, git status vide

4. Ce qui devait rester intact est intact : le garde not_an_acceptance_criterion (asserté dans les tests), et la distinction perdu / jamais-eu toujours portée par le checker.

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

@jsboige

jsboige commented Sep 22, 2026

Copy link
Copy Markdown
Owner Author

[ADJOINT PREFLIGHT]
schema: 1
lane: myia-po-2025:CoursIA-2
pr: 17150
head: 95de350
complete: true
body: read
comments-reviewed: 4
reviews-reviewed: 1
threads-reviewed: 0
threads-unresolved: 0
surfaces-sha256: b2445875fb7da66b6d0a961a4eb8f674c5a93a581f7eff0f67a029a9289da20e
diff-files: 2
diff-additions: 743
diff-deletions: 0
checks: latest-wins-green
b0: clear
scope: pass
domain: pass
verdict: READY
[/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.

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