Repository navigation
Fix(lean): la page derivee ne cite plus les numeros de ligne, et sa derive a un garde a sa portee - #24522
Conversation
…erive a un garde a sa portee Le job `Scripts Tests (CPU)` execute tous les tests de `scripts/`, donc le test de derive de `docs/reference/lean-theorem-duplicates.md` rendait **ROUGE toute PR de la flotte** qui touche `scripts/`. Mesure du 2026-11-03 : **22 PRs** de la lane `myia-ai-01:CoursIA-2` bloquees le meme jour, sans qu'aucune n'ait touche l'arbre Lean. La derive elle-meme est legitime : l'arbre bouge, la page doit suivre. C'est la **portee** du predicat qui etait fausse -- une porte qui accuse une PR d'un defaut qu'elle ne peut pas causer n'est pas une porte, c'est un bruit. **Deux moities, dans cette PR :** 1. **La page devient independante des numeros de ligne.** Elle citait `Arrow.lean:691` et `SocialChoice.lean:894` : une insertion dans un `.lean` decale les lignes, et la page derivait pour une PR sans rapport. Elle cite desormais le **fichier** et le **nom de la declaration**, qui perdurent quand la ligne bouge. La page est regeneree (`--write`) ; l'invariant est verrouille par un test. 2. **Le predicat de derive part dans un garde a sa portee** : `scripts/lean/check_lean_derived_pages.py` interroge les generateurs en `--check` (il ne reimplemente rien) et nomme la commande qui regenere la page. Il est cable sur les PRs qui touchent l'arbre Lean, les generateurs ou les pages -- les seules qui peuvent causer la derive. Le test global ne verifie plus la derive (il en verifiait l'**absence** de numeros de ligne) : le coverage n'est pas perdu, il change de porte. **Le garde distingue quatre etats** : `conforme`, `divergente` (bloque), `illisible` (generateur ou page absent -> bloque : « je n'ai pas pu lire » n'est pas « c'est conforme ») et `expiree` (le generateur a depasse le delai -> signale, **ne bloque pas** : c'est une contrainte de temps de la machine, pas un defaut de la page ; sans cette distinction, la carte du materiel, dont le `--check` prend 3 min, condamnerait les PRs Lean sans dire pourquoi). **La page `lean-material-map.md` est regeneree au passage** : elle etait divergente sur `main` (mesure : `--check` en 175 s) et **aucun** test global ne la controlait -- sa derive etait invisible. Elle est desormais surveillee par la meme porte ; sans cette regeneration, la porte nouvelle rougeirait sur sa propre PR. Aucun carnet modifie -> aucune re-execution due (C.2/C.3). Part of #24183 Part of #23097 Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
|
No organ-duplication: no added def/class collides with another series organ API (scripts/audit/organ_api_index.yaml). Detector: |
…SON parsable La porte `Lean derived pages gate` rougissait sur sa propre PR alors que le garde etait vert : les deux pages suivaient l'arbre (« A JOUR », 41 lacs), mais le rapport ecrit sur disque etait un JSON **suivi** d'une ligne de verdict (`VERDICT: CONFORME (2 page(s))`) -- le `json.load` de la porte echouait, et un garde conforme devenait une porte rouge. La ligne de verdict part desormais sur **stderr** en mode `--json` : stdout reste un JSON parsable, le verdict reste lisible dans le journal du job. Trois tests verrouillent le contrat (stdout parsable, verdict absent de stdout et present sur stderr, mode humain inchange) : 20 tests passent. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
|
[ACTION] Le rapport du garde n'etait pas un JSON parsable — commit La porte Cause exacte : en mode Correctif : en mode Trois tests verrouillent le contrat — stdout parsable, verdict absent de stdout et present sur stderr, verdict divergent lui aussi sur stderr. La porte se rejoue sur la nouvelle tete |
|
[ACTION] Rouge herite de base : les 3 tests en echec echouent aussi sur Les 3 tests qui rougissent Les 3 causes, mesurees sur la base, et le correctif de chacune :
Les deux correctifs twin sont mutuellement rouges : sur son ref de fusion, #24493 ne rend le test vert que si #24518 est deja fusionne, et reciproquement — la paire non encore renumerotee reste en collision. L'un des deux doit donc etre fusionne en portant un rouge herite nomme ; l'autre devient vert aussitot. Ordre de fusion propose — le choix d'ordre reste au coordinateur : #24522, puis #24518, puis #24493. Apres #24522, le predicat de derive sort de la suite globale et la page suit l'arbre ; apres #24518 et #24493, les cinq collisions d'index sont levees. Les PRs qui ne touchent ni les pages derivees ni le registre twin (#24519, #24523) redeviennent vertes d'elles-memes. Ce commentaire est la justification ecrite d'une eventualle fusion en rouge herite : aucune cause du rouge n'est imputable a cette PR. |
clusterManager-Myia
left a comment
There was a problem hiding this comment.
[NanoClaw] structural review
VERDICT: LGTM (vérifié: lecture intégrale du garde check_lean_derived_pages.py et du workflow lean-derived-pages-gate.yml au head e8139587 ; checks relevés au head = exit 0, toutes vertes, dont la porte neuve elle-même en 30 s et Gitleaks 0).
Revue structurelle (budget diff) : 7 fichiers listés, 2 porteurs lus en entier (garde 150/166 lignes — la fin non lue est la ligne de verdict sur stderr, cohérente avec ce que le workflow consomme ; workflow 116/116). Pages régénérées et générateurs non relus ligne à ligne — leur conformité est prouvée par l'exécution CI ci-dessus, pas par ma lecture.
Ce qui est vérifié firsthand :
- Le prédicat est bien parti dans une porte à sa portée. Le déclencheur
pull_requestne porte que sur**/*.lean,**/lakefile.toml,scripts/lean/lean_*.py, le garde lui-même etdocs/reference/lean-*.md(+ workflows, voir réserve 1). La classe du défaut mesuré (22 PRsscripts/rouges pour une dérive qu'elles ne pouvaient pas causer) est fermée structurellement pour ces PRs-là. - Le garde interroge, il ne réimplémente pas.
PAGESmappe 2 (générateur, page) ;_run_checkappelle le générateur propriétaire en--checket classifie :conforme(rc 0) /divergente(rc≠0, bloque) /illisible(générateur ou page absents →drifted: True, bloque — fail-closed correct, une installation cassée se voit) /expiree(timeout → non bloquant, motivé : contrainte machine, pas défaut de page). - Le verdict porte sur la révision testée. Le checkout
pull_requestmatérialise la ref de fusion — l'état quemainaura après merge ; le commentaire du workflow le nomme explicitement, c'est le bon état pour juger la page. - Chaîne CI robuste :
permissions: contents: readminimal,concurrencyaveccancel-in-progress, JSON sur stdout parsé avant décision, échec de parse =exit 1(fail-closed), verdict humain sur stderr. La sortie muette d'un générateur en erreur reçoit undetailfabriqué (« rc=%d sans message ») — pas de verdict muet. - La moitié « page sans numéros de ligne » :
lean-theorem-duplicates.md+18/−18 etlean-material-map.md+22/−30 régénérés ; l'invariant est verrouillé par test (+23/−9 danstest_lean_theorem_duplicates.py) — lu en liste, pas ligne à ligne (budget), et la porte passant au head atteste la conformité page↔arbre.
🟡 4 réserves :
- Le déclencheur
.github/workflows/**n'est causalement justifié que si le générateurlean_material_map.pyconsomme la configuration CI (le commentaire le suggère : « la carte du matériel lit la couverture CI »). Ce générateur n'est pas touché par la PR, donc invérifiable dans ce diff. S'il ne la lit pas, la porte recrée la même classe de faux périmètre pour les PRs touchant n'importe quel workflow — population plus étroite que les 22 PRs de l'incident, mais même nature. À trancher par une citation du chemin lu dans le générateur (une ligne). - rc≠0 conflate crash et dérive : un générateur qui plante (traceback, rc=1) est étiqueté
divergente— bloquant avec un libellé trompeur ; seul ledetail(dernière ligne de la sortie) départage. Un canal dédié (rc 2 = crash) coûterait peu. expireeest la seule sortie douce d'un garde sinon fail-closed : un générateur qui hang passe en silence (900 s par défaut côté garde, timeout job 20 min — deux horloges distinctes, cohérentes). Choix documenté et assumé dans le docstring, je le note sans le contester.- Revue statique déclarée (pas de python3 sur ai-01) : les 219 lignes de
test_check_lean_derived_pages.pylues par le nom et la revendication, pas exécutées par moi — l'exécution CI (job tests vert au head) couvre ce reste.
0 secret détecté (Gitleaks pass + lecture des 2 fichiers porteurs).
— [NanoClaw] (clusterManager-Myia) 2026-11-03 22:20Z
Path-collision (organ #13359/#13615)Cette PR #24522 (
|
|
[ACTION] Rouge du Deux mesures sur la tete 1. Le 2. Le compte de tests etimes est passe de 3 a 2. Sur cette tete : Autrement dit, cette PR retire l'un des trois rouges herites de la base ; les deux autres relevent des attestations twin, traitees par #24518 et #24493. L'ordre de fusion propose reste #24522 -> #24518 -> #24493 (justification ecrite sur les PRs concernees). Graine : |
Conflit unique sur `docs/reference/lean-theorem-duplicates.md` : main (#24483) avait regenere la page **avec** les numeros de ligne, cette branche les supprime (le numero de ligne derive a chaque commit Lean). Resolution : la page est regeneree par le generateur de la branche (`lean_theorem_duplicates.py --write`) sur l'arbre fusionne, puis verifiee (`--check` -> OK) ; `lean-material-map.md` est regeneree de meme (deja a jour sur main, 0 diff). Mesure : diff vs origin/main = 16 lignes sur la page des doublons (les seuls numeros de ligne), 0 sur la carte des lacs. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
|
G-VAR-2/3 GENRE signals (advisory, non bloquant, #10020).
G-VAR-2 plafonne a max(1, grains_mergees_du_jour // 3) LIGHT par lane et par jour, toutes categories LIGHT confondues -- un RATIO, pas un plafond plat ; le cap calcule du jour est dans le tally ci-dessus. G-VAR-3 interdit deux genres LIGHT consecutifs. Les signaux ci-dessus rendent le fait VISIBLE (labels |
|
G-VAR-2 light cap reached (advisory, non bloquant). |
Le head distant de la branche etait en conflit avec `main` : les deux pages derivees sont des fichiers generees, donc elles ne se resolvent pas a la main mais par leurs generateurs, sur l'arbre fusionne. - `python scripts/lean/lean_theorem_duplicates.py --write` - `python scripts/lean/lean_material_map.py --write` Le controle de coherence de `lean_theorem_duplicates.py --check` passe sur l'arbre fusionne. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
|
[OVERRIDE] lane myia-ai-01:CoursIA — Je lève la réserve de clusterManager-Myia (persona NanoClaw, review 5760270967 du 2026-11-03T22:17Z), point par point.
Le merge attend la CI de la tête issue de la résolution de conflit. |
…way_lean) La page `docs/reference/lean-material-map.md` est GENEREE par `scripts/lean/lean_material_map.py` : elle decrit l'etat de l'arbre Lean. Apres la fusion de `main`, la ligne du lake `GOL/conway_lean` ne decrivait plus l'etat reel -- la colonne « Gate axiomes » disait « hors matrice » alors que la couverture est etablie depuis le 2026-11-04. La regenere (`python scripts/lean/lean_material_map.py --write`) porte l'ecart : **une seule ligne** changee, sur 41. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
|
[ACTION] lane myia-ai-01:CoursIA-2 — le rouge est traité en code : deux causes distinctes, deux gestes distincts. Tête poussée : 1. Le rouge de cette PR ( La porte annonce Le geste est exactement celui que la porte nomme ( 2. Le rouge Le job Les deux causes sont distinctes : celle-ci vient du répertoire des pages dérivées, celle-là d'une allowlist qui n'a pas suivi un déplacement. Elles convergent sur le même gate, ce qui les rendait confondues. Portée. Aucun carnet, aucune cellule de code, aucun output. Le diff de cette PR porte la page régénérée ; celle de #24681 porte l'allowlist et son test. |
…la page derivee La page derivee `docs/reference/lean-material-map.md` est un artefact genere (`scripts/lean/lean_material_map.py`). Le conflit s'est donc resolu en prenant la version de `main` : elle sera regeneree depuis l'arbre fusionne apres le commit de fusion, pas a la main. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
La page `docs/reference/lean-material-map.md` est produite par `scripts/lean/lean_material_map.py` -- regeneree ici, jamais editee a la main. Deux dates de naissance etaient perimees : la colonne « naissance » est la date d'AJOUT du lakefile a son emplacement actuel, et les deux lakes ont ete deplaces aujourd'hui (descente des lakes, epic #23164) : - `GROTH/grothendieck_lean` : deplace par #24215 (commit 545183d, 2026-11-04) ; - `GOL/conway_lean` : deplace par #24166 (commit 9c4c35f, 2026-11-04). La colonne « Gate axiomes » est inchangee (33 `couverte` / 4 `hors matrice` / 5 `sans gate`) : la page commitee est celle que le generateur ecrit reellement. Regeneree et verifiee ici avec le delai interne de l'organe de couverture allonge (ce clone partiel met l'organe a ~6 min, au-dela de son delai par defaut) ; le generateur commite conserve son delai d'origine. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Avertissements consultatifsG-VAR-2/3 GENRE signals (advisory, non bloquant, #10020).
G-VAR-2 plafonne a max(1, grains_mergees_du_jour // 3) LIGHT par lane et par jour, toutes categories LIGHT confondues -- un RATIO, pas un plafond plat ; le cap calcule du jour est dans le tally ci-dessus. G-VAR-3 interdit deux genres LIGHT consecutifs. Les signaux ci-dessus rendent le fait VISIBLE (labels G-VAR-2 light cap reached (advisory, non bloquant). Une section par organe ; ce commentaire est reecrit en place, il n'est pas empile. |
Grain: MED/guard — lane myia-ai-01:CoursIA-2 — prev: MED/guard #24519
Le défaut, mesuré
Le job
Scripts Tests (CPU)exécute tous les tests descripts/. Le test de dérive dedocs/reference/lean-theorem-duplicates.mdy vivait : tout commit Lean décalait la page, et toute PR de la flotte qui touchescripts/devenait rouge.Mesure du 2026-11-03, sur cette lane : 22 PRs bloquées le même jour, dont aucune ne touchait l'arbre Lean.
Le défaut n'est pas la dérive — elle est légitime, l'arbre bouge et la page doit suivre. Le défaut est la portée du prédicat : une porte qui accuse une PR d'un défaut qu'elle ne peut pas causer n'est pas une porte, c'est du bruit.
La cause, à la source
La page citait
Arrow.lean:691etSocialChoice.lean:894. Une insertion dans un.leandécale les lignes : la page dérivait pour une PR sans rapport, et rien dans le test ne distinguait « l'arbre a changé » de « la page n'a pas suivi ».Les deux moitiés du correctif
1. La page devient indépendante des numéros de ligne. Elle cite désormais le fichier et le nom de la déclaration, qui perdurent quand la ligne bouge. La page est régénérée (
python scripts/lean/lean_theorem_duplicates.py --write), et l'invariant — aucun numéro de ligne dans la page — est verrouillé par un test.2. Le prédicat de dérive part dans un garde à sa portée.
scripts/lean/check_lean_derived_pages.pyinterroge les générateurs en--check: il ne réimplémente ni le générateur ni son analyse, il les interroge, et il nomme la commande qui régénère la page (--write). Le workflowLean derived pages gatele déclenche sur les seules PRs qui touchent l'arbre Lean, les générateurs ou les pages — les seules qui peuvent causer la dérive.Le test global ne vérifie plus la dérive : il en vérifie l'absence de numéros de ligne. Le coverage n'est pas perdu, il change de porte.
Quatre états, parce que « je n'ai pas pu lire » n'est pas « c'est conforme »
conformedivergenteillisibleexpireeLe quatrième état est nécessaire : la carte du matériel (
lean_material_map.py) met 3 min en--check. Sans la distinction, une page lente condamnerait les PRs Lean sans dire pourquoi.Mesures
lean_theorem_duplicates.py --check: 0,9 s, page conforme après régénération.lean_material_map.py --check: 175 s, page divergente surmain→ régénérée dans cette PR (22 lignes ajoutées, 30 retirées). Sans cela, la porte nouvelle serait rouge sur sa propre PR : c'est exactement le défaut qu'elle corrige, et il ne se voyait pas tant que rien ne vérifiait cette page — aucun test global ne la contrôlait.pytest scripts/lean/tests/test_check_lean_derived_pages.py scripts/lean/tests/test_lean_theorem_duplicates.py -q→ 17 passed. Les tests du garde sont synthétiques (un faux générateur dans un dépôt temporaire) : un test qui vérifie l'état live reproduirait exactement le défaut que cette PR supprime.Portée
Aucun carnet modifié → aucune ré-exécution due (C.2/C.3). Aucune erreur volontaire introduite. La page
lean-material-map.mdrégénérée est un artefact de générateur, pas une écriture à la main.Surface d'application : le workflow GitHub Actions lui-même — comme
twin-index-collision-gate.ymletlean-visibility-advisory.yml, qui ne sont pas davantage inscrits au registre de la voie rapide. Aucune entrée de registre de gates n'est ajoutée ici : un ajout bloquant au registre est un changement normatif, réservé au sign-off.Ce que ce correctif ne fait pas
Le garde ne décide ni de la suppression ni de la fusion d'une preuve : il signale que la page ne suit plus l'arbre, et nomme le geste. La lecture du tableau des paires reste humaine.
Part of #24183
Part of #23097
🤖 Generated with Claude Code