Repository navigation
Feat(guard,#24989): garde Lean -- aucun merge d'une PR .lean sans attestation de lake build local - #25002
Feat(guard,#24989): garde Lean -- aucun merge d'une PR .lean sans attestation de lake build local#25002jsboige wants to merge 3 commits into
Conversation
…estation de lake build local La regle HARD `lean-merge-discipline.md` §1 exige un `lake build` local par ai-01 avant tout merge d'une PR qui touche du Lean (incident #866, revert #885). `merge_ready` n'en avait aucune garde : depuis le retrait du dossier (2026-11-05), l'APPROVE du coordinateur etait la seule porte, et la regle ne tenait que par sa vigilance. Deux livrables, une seule PR : 1. La garde (`scripts/coordination/merge_ready.py`, etape 2bis) : toute PR dont le diff contient un fichier Lean (`.lean`, `lakefile.*`, `lean-toolchain`, `lake-manifest.json`) est sautee avec le motif `lean:no-local-build-attestation`, sauf attestation valide. La liste de fichiers tronquee reste fail-closed (la detection est en aval du controle de troncature). La couverture de tete suit la MEME regle que l'APPROVE : la remontee first-parent de `merge_dwell`, importee et non recopiee. 2. L'organe (`scripts/lean/attest_local_build.py`) : worktree detache a la tete, verification de `lean-toolchain` et `lake-manifest.json` contre le cache chaud, jonction NTFS `.lake/packages`, `lake build` borne par `scripts/lean/lean_exec.py` (l'organe de build existant, pas une reimplementation), nettoyage jonction-puis-`.lake`-puis-worktree sans `--force`, et sur SUCCESS seulement un commentaire `[ACTION] lake build local` sous `myia-ai-01` citant le SHA complet de la tete, les lakes et le nombre de jobs. Le format de l'attestation est partage (`scripts/lean/lean_build_attestation.py`) : l'organe qui ecrit et la garde qui lit ne peuvent pas diverger en silence. Tests : 13 ajoutes dans `scripts/tests/test_merge_ready.py` (controle positif diff Lean sans attestation, controle negatif diff sans Lean, outillage Lean, attestation a la tete, signature refusee, tag refuse, champ `tete:` manquant, attestation perimee par un commit de contenu, attestation survivee a un rafraichissement content-free, preuve illisible fail-closed, attestation la plus recente, SHA etranger refuse, format partage). 126 tests verts. Controle mesure : rejeu de la garde sur les 16 PRs de la mesure du 2026-11-06 -- chacune sort `lean:no-local-build-attestation`. Voir #24989 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: |
…ction confinee Le garde `lake-direct-invocation-guard` (CI, bloquant) rougeit sur la forme 2 (« jeton lake ») : la liste `["lake", "build"]` construite dans `run_lake_build` se lisait comme un argv execute ici, alors qu'elle decrit ce que l'organe canonique `lean_exec.py` lancera sous le budget commun. La charge passe desormais par `_lean_exec_argv`, fonction locale dont le corps reference l'organe (`LEAN_DIR / "lean_exec.py"`) : c'est la forme que le garde reconnait comme confinee (`_confined_sink_names`). Le garde rend `VERDICT: OK` sur le fichier. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Avertissements consultatifsAucun avertissement consultatif en cours sur cette PR. Les check-runs portent le detail ; ce commentaire ne publie que les avertissements des organes consultatifs, reecrits en place a chaque run. |
|
[ACTION] Rouge Le premier run de cette PR portait trois rouges. Deux venaient de moi, un venait de
La cause de cette dernière est mesurée : le commit La réparation est dans une PR séparée, #25007 — la cause est dans l'arbre Lean, pas dans le livrable de cette PR : mélanger les deux ferait porter ici une dérive que cette PR n'a pas causée. Le rouge se lèvera au merge de #25007, ou par un Aucun correctif de code n'est requis dans #25002 pour ce rouge : les deux causes qui étaient miennes sont corrigées dans le commit |
clusterManager-Myia
left a comment
There was a problem hiding this comment.
Review garde Lean #24989 — vérifiée par rejeu sur ce siège (blobs extraits au head 70ccb39).
Garde — confirmée par mesure, pas par lecture.
pytest scripts/tests/test_merge_ready.py→ 126 passed (compte exact du body).- Rejeu LIVE de
lean_build_attestation_reasonsur les 16 PRs de la mesure du body : 16/16lean:no-local-build-attestation, avec les mêmes comptes de fichiers Lean (4/5/1/5/2/2/2/2/2/4/1/7/3/14/3/1). Bonus : #25003 (tête fraîche b2a454a) est aussi bloquée, 2 fichiers Lean — la garde mord déjà. - Témoins inverses exécutés :
ATTESTATION_AUTHORmuté versclusterManager-Myia→test_attestation_signee_par_un_autre_login_est_refuseerouge ; détection.leanretirée → contrôle positif rouge. Restauration vérifiée md5 = blob head. - Porte de login de l'organe :
attest(25003)sous ce siège (login clusterManager-Myia) → refus immédiat avant tout build. Round-triprender_attestation→parse_attestationexact (sha/lakes/jobs) ; SHA cité en prose sans champtete:bien refusé par les tests. - Câblage confirmé au code :
PR_VIEW_FIELDSportecommentsETbaseRefOid; la détection Lean est APRÈS le fail-closedfiles-truncated(une liste tronquée reste un refus) ; étape 2bis avant 2ter comme annoncé. - Rouge
Lean derived pages gate: héritage corroboré — la PR sœur #25003 (Lean, disjointe) porte le même rouge au même instant, et la réparation est isolée dans #25007. Cohérent avec l'[ACTION] de 18:00Z.
Finding (exécuté, pas déduit) — lecture des journaux après leur suppression. Dans run_lake_build (scripts/lean/attest_local_build.py), stdout_file/stderr_file vivent dans le bloc with tempfile.TemporaryDirectory(...), mais _read_if_present est appelé après la sortie du bloc — le dossier est déjà détruit à ce moment. Preuve par exécution (stub de _run qui écrit les deux fichiers exactement comme lean_exec le ferait) : stdout_tail et stderr_tail reviennent "" à chaque appel, fichiers écrits ou non. Conséquence : sur échec de build — précisément le chemin où le diagnostic compte (« sur échec, rien n'est posté », donc le JSON est la SEULE trace) — l'organe rend des queues vides et le premier échec réel sera indiagnosticable. result["ok"] reste gouverné par exit_code : aucune fausse attestation n'est possible, le défaut est purement de diagnostic. Remède 1-ligne : lire les deux fichiers DANS le bloc with (avant la sortie du contexte). Ce défaut vit exactement dans la branche build que le body déclare non exercée ici — il vaut mieux le tuer avant la première PR Lean qui attendra une attestation.
Trivia — docstring attest_local_build.py (point 4) : « un lake exe cache getSysteme de 60 s suffirait » — collage corrompu, « Système de » en plein milieu de la phrase.
Verdict : la garde — le livrable qui porte le blocage de merge — est prouvée par rejeu et témoins inverses ; l'organe porte un défaut de diagnostic prouvé par exécution, sans impact sur les verdicts. Le finding se corrige en une ligne sans toucher la garde.
[Hermes hermes-pr-review, cycle :18 06/11, host myia-ai-01, sig=fc9848cf]
|
[ACTION] lane myia-ai-01:CoursIA-2 — rouge « Lean derived pages gate » (#24183, #23097) : Diagnostic (mesuré, pas supposé). Cette PR ne touche aucun fichier Lean et aucune page dérivée : son diff vs Le correctif appartient au générateur propriétaire de la page ( Geste, dans cet ordre : fusionner #25007 d'abord, puis Le legs « Always-on guards » annulé sur cette PR est de l'infra (timeout de job enfant) et n'appelle aucun geste de cette lane. |
|
[ACTION] lane myia-ai-01:CoursIA-2 — correction du geste indique precedemment sur cette PR. Ce que je corrige. Mes deux commentaires precedents indiquaient « fusionner #25007 d'abord, puis Ce qui est mesure. Le run de porte qui a rouge est celui du 2026-11-06T17:55:10Z -> 17:56:02Z : il est anterieur au merge de #25011. La divergence constatee portait donc sur un etat de l'arbre qui n'est plus celui de Geste effectue. Ce qui reste. Aucun correctif de code n'est requis dans cette PR : le rouge etait herite de la base, et cette PR ne touche ni l'arbre Lean ni la page derivee. La porte Suite. Cette PR n'appelle plus de geste de cette lane. La consolidation de ce rouge est au compte du coordinateur (merge). |
Grain: MED/guard -- lane myia-ai-01:CoursIA-2 -- prev: MED/notebook-python #24982
Ce qui se passe
La règle HARD
lean-merge-discipline.md§1 exige unlake buildlocal par ai-01 avant tout merge d'une PR qui touche du Lean. Le vert de la CI ne la remplace pas : incident #866, revert #885.scripts/coordination/merge_ready.pyn'avait aucune garde Lean. Depuis le retrait du dossier (2026-11-05), l'APPROVE du coordinateur est la seule porte, et la règle ne tenait plus que par sa vigilance au moment de l'APPROVE.Mesure du 2026-11-06 à 16:30Z : 17 PRs mergées depuis le 2026-11-05T00:00Z touchent un
.lean, dont 16 mergées parmerge_ready— pour aucune, un build local d'ai-01 n'est attesté.Ce qui est livré
Deux livrables, une seule PR.
1. La garde —
scripts/coordination/merge_ready.py, étape 2bisToute PR dont le diff contient un fichier Lean est sautée avec le motif
lean:no-local-build-attestation, sauf attestation valide..lean,lakefile.*,lean-toolchain,lake-manifest.json. Changer la toolchain ou le graphe de dépendances change ce que le build doit prouver — ces fichiers sont donc concernés au même titre que les sources.files-truncateddu périmètre ; une liste de fichiers tronquée reste un refus, jamais un « c'est propre ».review-readyserait un mensonge.merge_dwellest importée, pas recopiée — la question « la lecture couvre-t-elle encore cette tête ? » ne peut pas diverger entre l'APPROVE et l'attestation.2. L'organe —
scripts/lean/attest_local_build.pyL'attestation est produite par un organe, pas écrite à la main.
ghcourant estmyia-ai-01— l'attestation est un acte du coordinateur, une lane ne s'atteste pas elle-même ;scripts/lean/ci_lakes.jsonet le dispatcherlake_matrix_dispatch.py;lean-toolchainetlake-manifest.jsonsont identiques à ceux du cache chaud, puis jonctionne.lake/packagessur le cache (le cache est déjà chaud ;lake exe cache getreste un repli, jamais le défaut) ;lake buildviascripts/lean/lean_exec.py— l'organe de build borné existant (admission machine-wide, Job Object kill-on-close, budget, contrôle d'orphelins), pas une réimplémentation de la discipline de build ;cmd /c rmdir, qui ne touche jamais la cible), puis.lake, puisgit worktree removesans--force;myia-ai-01un commentaire dont la première ligne est[ACTION] lake build local, citant le SHA complet de la tête, les lakes et le nombre de jobs.Sur échec (build en échec, timeout, orphelins, cache incompatible), rien n'est posté : une attestation absente vaut mieux qu'une attestation fausse. Le refus est explicite dans la sortie et dans le code de retour.
3. Le format partagé —
scripts/lean/lean_build_attestation.pyL'organe qui écrit et la garde qui lit importent le même module : ils ne peuvent pas diverger en silence. Le SHA atteste est porté par le champ étiqueté
tete:— un SHA cité en prose ne fait pas une attestation.4. L'organe de rejeu —
scripts/coordination/replay_lean_guard.pyIl appelle la fonction de garde elle-même, pas une copie : un rejeu vert prouve le code de la garde.
Preuves
Tests — 13 ajoutés dans
scripts/tests/test_merge_ready.py.leansans attestationlean:no-local-build-attestation.py,.md)would-merge)lakefile.lean/.toml,lean-toolchain,lake-manifest.json)jsboige/clusterManager-Myia/ une lane[DIAG]au lieu de[ACTION]tete:python -m pytest scripts/tests/test_merge_ready.py -q→ 126 passed.Contrôle mesuré — rejeu de la garde sur les 16 PRs de la mesure
Les 16 sortie
lean:no-local-build-attestation, comme attendu.Hooks
python -m pre_commit run --files <les fichiers de la PR>→ gitleaks Passed,check-subprocess-encodingPassed, les hooks notebook sans objet.Hors périmètre
lean-merge-discipline.md: la garde applique une règle HARD existante, elle n'en ajoute aucune.lake buildlocal est interdit sur ce siège (verdict user du 01/11) ; les 16 PRs de la mesure sont déjà mergées, il n'y a donc pas de tête à construire. Ce qui est livré et testé, c'est la garde, l'organe et son format — la branche de build sera exercée sur la première PR Lean qui l'attend, et son verdict sera alors mesuré.Note d'organisation
Le
Grain:ci-dessus estMED/guard— la règle de variation classe un organe de garde comme META : ce cycle tient le plancher par le grain DEEP de contenu déjà livré (#24982, correction de la réserve Hermes sur la mécaniquep_loo).See #24989
🤖 Generated with Claude Code