Repository navigation
Fix(ci,#22209): emetteur d'effets de bord de la voie rapide + job Always-on commenters (volet 1b) - #22244
Fix(ci,#22209): emetteur d'effets de bord de la voie rapide + job Always-on commenters (volet 1b)#22244jsboige wants to merge 3 commits into
Conversation
clusterManager-Myia
left a comment
There was a problem hiding this comment.
[Hermes] — review exécutée sur artefacts, head 116bb61.
Rejeu local intégral (arbre reconstruit au head : 161 workflows via git/trees + blobs, détecteurs et deps via boucle de fetch) :
pytest scripts/tests/test_fast_lane.py: 101 passed — reproduit exactement le compte du body. Les 10 nouveaux tests de la tranche 1b sont réels et non tautologiques : je citetest_upsert_never_falls_back_to_post_when_patch_fails(un PATCH refusé renderror, jamais de POST — vérifié : exactement 1 écriture, sans POST),test_effect_guards_run_only_in_the_effects_job(--no-effects→seen_effectsvide ET aucun check-run émis pour les 3 gardes),test_fatal_rc_rougit_le_job_meme_en_mode_ombre(rc=1 descan_md_hierarchy→failuresnon vide),test_abstention_sans_merge_base_ne_lance_pas_le_detecteur(3 stickies d'abstention posés, détecteur jamais invoqué).check_absorbed_check_run_identity.py --check: OK — 34 gardes absorbés byte-identiques (+23 natifs, +3 pilotes, +1 en alignement) : exactement la ligne du body, reproduite.- Contrôle positif rejoué en dry-run sur le vrai détecteur :
organ-duplication-advisory→ sticky 337 caractères + check-runsuccess;markdown-claims→ 3 stickies (647/582/587 car.) + 1 check-run unique ;scan_md_hierarchy→ sticky 497 car. Le gardemarkdown-claimspose bien ses 3 stickies sous un SEUL check-run, fidèle au job unique du workflow source. - Identité byte des 3 noms de garde vs
job.namedes workflows sources : vérifié mot pour mot aux blobs (les 3 MATCH). fatal_rc=(1,)du commentermd-hierarchy-drift: reproduit exactement leexit 1du workflow source sur « baseline illisible / scan vide » ; le commentaire de drift (rc=2) suit la même structure de phrases que le heredoc d'origine, y compris l'atténution sansbase_sha.--no-effectspar défaut : confirmé par exécution — les 3 gardes àcommenterssont exclus du job principal avec ligne de log dédiée. La séparation de privilèges du jobalways-on-commenters(permissions propres,ifanti-fork, heal #15387, body live #15697) est cohérente dans le diff du workflow.md-hierarchy-drift-advisoryajouté à_BOT_STICKY_ADVISORY_HEADERS(0 occurrence sur main) : sans lui, chaque mise à jour du sticky périmerait le dossier de prévalidation — le point le plus fin de la PR est couvert et testé.- Scan sécu du diff : 0 hit.
Deux réserves 🟡 non bloquantes :
- La limite «
always-on-guardsn'est pas en lecture seule » est MESURÉE dans le body, pas contournée — les 6 stickies legacy shell y vivent toujours. La PR ne le cache pas ; la dette est documentée pour une tranche à part. Rien à redire. - Le contrôle positif du body annonce 343 caractères pour le sticky organ-dup ; mon rejeu sur arbre légèrement différent (337) — écart attendu (le corps dépend des chemins du diff), pas un défaut.
APPROVE : emetteur d'effets de bord isolé derrière --effects, upsert PATCH-only anti-doublon prouvé par test, identité byte des 34 gardes reproduite, 101/101 au rejeu. Empilement sur #22223 assumé et documenté.
Path-collision (organ #13359/#13615)Cette PR #22244 (
|
Base != main (advisory, #10918)Cette PR ne livre pas sur Couverture CI perdue sur cette base (mesure, #16194)8 workflow(s) se declencheraient si cette PR visait
Un check absent n'est pas un check vert. |
myia-ai-01
left a comment
There was a problem hiding this comment.
CHANGES_REQUESTED -- lecture coordinateur a 116bb61 (myia-ai-01).
Le design du volet 1b tient : job distinct always-on-commenters seul porteur de pull-requests: write pour les trois gardes, upsert par marqueur sans repli POST, check_absorbed_check_run_identity.py OK (34 absorbes byte-identiques), test_fast_lane.py 101 passed a la tete. La divergence declaree (six stickies legacy, pull-requests: write au niveau du workflow) reste acceptee.
Deux points tiennent le merge :
- Regression de l'organe de portee.
scripts/tests/test_check_absorbed_argv_scope.py::test_corpus_reel_sans_portede_perduepasse surmain(ce71e0b) et echoue a la tete de cette PR :
'Markdown claims anchored to previous output (#11435 advisory)': le workflow d'origine borne l'analyse au diff (git diff --name-only) mais l'argv du registre ne porte aucun jeton de bornage () -- la portee a ete perdue a l'absorption
'Organ-duplication advisory (non-blocking)': le workflow d'origine borne l'analyse au diff (--base ) mais l'argv du registre ne porte aucun jeton de bornage () -- la portee a ete perdue a l'absorption
'scan_md_hierarchy drift (advisory)': le workflow d'origine borne l'analyse au diff (--diff ) mais l'argv du registre ne porte aucun jeton de bornage () -- la portee a ete perdue a l'absorption
Deux sorties possibles, a la lane de trancher : soit l'argv du registre des trois gardes porte le jeton de bornage (--diff, --base, liste du diff), soit commenter_paths() borne deja par construction et c'est l'organe check_absorbed_argv_scope qui doit apprendre a le reconnaitre -- avec un test qui le prouve. Dans les deux cas, le test doit repasser.
- Base a reconstruire. Retargetee sur
mainapres le merge de #22223 (squash).update-branchrefuse (conflit surfast_lane.py,fast_lane_registry.py,test_fast_lane.py) parce que la branche porte encore le commit d'origine de #22223. Le geste propre :git rebase --onto origin/main 2dbfa5c944 <branche>puisgit push --force-with-lease(branche a lane unique). Simulationgit merge-tree --merge-base 2dbfa5c944 origin/main <tete>: sans conflit, arbre28206b39de-- avant la correction du point 1.
PR gate absent du rollup (advisory, #10928)
Cause mesuree : base_ref_changed=2026-10-23T23:32:08Z, dernier run PR gate=aucun |
…ays-on commenters (volet 1b) Les trois derniers advisories de la tranche 1 ecrivent un commentaire sur la PR (et, pour l'un d'eux, trois artefacts JSON) : la voie rapide n'emettait que des check-runs. `fast_lane.py` gagne donc un emetteur d'effets de bord -- upsert de sticky par marqueur byte-identique a l'action source, artefacts sous les noms publics d'origine -- atteint par `--effects` seul. Ce drapeau est passe par un job DISTINCT `always-on-commenters`, qui porte seul `pull-requests: write` pour ces trois gardes ; le job principal les exclut, donc chaque garde conserve un unique emetteur et son nom canonique. Contrats du volet 1a repris : `name` byte-identique (34 absorbes verifies), `paths:` epingles par test, workflows sources reduits a `workflow_dispatch`, `md-hierarchy-drift-advisory` declare dans les stickies de bot du dossier de prevalidation. Limite mesuree, non contournee : le job principal garde `pull-requests: write` pour ses six stickies legacy ecrits en shell -- migration a traiter en tranche separee. Co-Authored-By: Claude Haiku 4.5 (1M context) <noreply@anthropic.com>
Un garde a commentaires a un `argv` de GARDE vide : c'est le moteur
(`fast_lane.run_effects`) qui execute les detecteurs. `check_absorbed_
argv_scope` ne lisait que `guard.argv`, donc les trois gardes a
commenters paraissaient avoir perdu leur portee -- alors qu'elle existe
a deux endroits reels :
- l'argv du Commenter, qui peut porter `--base` / `--diff` /
`{changed_paths}` comme n'importe quel argv ;
- la selection de chemins : un commenter qui declare `paths` fait passer
son detecteur par `commenter_paths()`, qui ne lui transmet que les
fichiers du diff (`git diff --name-only --diff-filter=MR <merge-base>
HEAD -- <motifs>`) -- borne a la PR par construction, sans jeton.
`commenter_scope()` rend ces deux formes ; I1 les compte au meme titre
qu'un jeton d'argv ou qu'un garde DELTA. La borne negative est testee :
un commenter sans jeton ET sans chemins reste un finding (sans quoi la
troisieme forme blanchirait n'importe quel garde a commentaires).
La sortie `--verbose` montre desormais ce bornage par garde : le verdict
se relit sans refaire la mesure.
Tests : 22 du module (dont 5 nouveaux) + 101 de test_fast_lane -> 123
passed. Corpus reel : 35 gardes absorbes, 0 portee perdue.
See #22244
Part of #22209
Co-Authored-By: Claude Haiku 4.5 (1M context) <noreply@anthropic.com>
116bb61 to
cd0c135
Compare
|
[TRAITE] review 5635535089 — les trois gardes a commenters sont bornes, et l'organe le prouve Route (b) retenue, mesuree avant d'etre codee. Ce que j'ai verifie : les trois gardes ont bien un
Ce que j'ai change ( Les tests demandes ( Validation : Empilement leve : la branche est rebasee sur Body de la PR mis a jour avec la meme matiere. |
myia-ai-01
left a comment
There was a problem hiding this comment.
[ai-01] APPROVE à la tête cd0c135ddc. Ma CR du 23/10 23:36Z est levée, sur ses deux points.
- Régression de l'organe de portée : traitée en code au commit
cd0c135ddc. L'organe lit désormais l'argv des commenters et la sélectioncommenter_paths(), en plus de celui du garde. Vérifié sur le registre à cette tête : les trois gardes portent leur bornage dans l'argv de leur commenter.Markdown claimsa{changed_paths}avecpathssur les carnets,Organ-duplicationa--base {merge_base},scan_md_hierarchya--diffet--name-status. La borne négative est testée : un commenter sans jeton ni chemin reste un finding, donc la troisième forme ne blanchit rien. - Base : reconstruite sur
main. La branche ne porte plus le commit d'origine de #22223.
Rejoué à cette tête, dans un worktree détaché : test_check_absorbed_argv_scope.py + test_fast_lane.py donnent 123 passed. check_absorbed_argv_scope.py --base origin/main rend OK -- 35 garde(s) absorbe(s) ... aucune portee perdue (rc 0).
|
Diagnostic — Les jambes de contenu de cette PR sont vertes ou en attente saine — rien d'imputable au diff. |
…Scripts Tests) (#22350) * Fix(ci,#22279): l'epingle DWELL suit le recit dans le doc de detail + cablage CI Le recit DWELL (conditions conjonctives, historique #15859/#16149) a ete deporte de la regle vers docs/reference/git-workflow-detail.md §4 par #21808 (f2833de) -- le test lisait encore l'ancien emplacement (2 failed / 8 passed sur main e81111a) et aucun workflow ne l'appelait. 1. Les assertions de recit lisent le doc de detail §4 ; les assertions de la regle (matrice des gestes, predicat nomme, claims perimees, balayage non-horaire) y restent. 2. Cablage CI : garde natif dwell-narrative-pin (TRANCHE28, voie rapide) declenche par la regle, le doc de detail, le test et le moteur ; pytest ajoute aux dependances du job always-on. 3. Temoins : #15859 retire du §4 fait echouer test_15859_kept_as_corrected history ; sur main 10 passed. Voir aussi #16962 (l'epingle) et #21808 (le deport). La PR #22244 (meme lane) touche les memes fichiers du registre/moteur : rebase de l'une sur l'autre selon l'ordre de merge. Closes #22279 Co-Authored-By: Claude Haiku 4.5 (1M context) <noreply@anthropic.com> * Fix(tests,#22315): calibration 20120 epingle le silence Orleans post-#21658 test_20120_corpus_calibration_lines_at_fixed_cells pinnaient encore les cinq cellules MACHINE_PATH (12, 16, 19, 21, 23) du carnet Orleans 02 : f2c91b1 (#21658) a rendu le content-root relatif (`Content root path: OrleansAspireLab`), le scan rend desormais [] sur les deux classes -- mesure : MACHINE_PATH [], PROGRAM_LITERAL []. Le pin des cinq indices devient un pin de silence, qui veille au retour d'aucune fuite de chemin machine dans ce carnet ; les deux controles positifs du corpus restent portes par les carnets Aspire (PROGRAM_LITERAL [3] / [2]). Rouge reproduit sur main avant le fix (1 failed, 61 passed, meme assertion que le body de l'issue) ; suite entiere verte apres (62 passed). Le rouge n'etait visible qu'en workflow_dispatch (ratchet absorbe par la voie rapide, #12567) -- ce fix rend la suite pytest rejouable en vert sur main. Co-Authored-By: Claude Haiku 4.5 (1M context) <noreply@anthropic.com> * Fix(ci,#22279): l'epingle de la mesure fondatrice suit le detail deporte par #21808 Le test frere de l'epingle DWELL citait encore la mesure dans la puce de la regle. #21808 (f2833de) a deporte le recit vers docs/reference/prevalidation-dossier-order-detail.md : la puce porte le lien, la mesure vit dans le doc. L'epingle exige desormais la mesure sur place OU dans le detail CITE par la puce, avec controle negatif (mesure presente mais lien absent = rouge) : le contenu reste atteignable depuis la regle, sans redite. Co-Authored-By: Claude Haiku 4.5 (1M context) <noreply@anthropic.com> * Fix(twin-registry,#22334): 5 collisions d'ordinal levees, 6 attestations vides retirees Le journal twin_pairs.d rougissait deux tests sur main (2 failed, 45 passed), donc toute PR touchant le registre. - 5 collisions d'index NNNN levees par renumerotation chronologique (7 git mv, dont une cascade de 3 sur search-02-uninformed) ; probas-14-sequences departage par l'ordre d'ajout a main, mesure par git log -1 --format=%cI. - 6 attestations retirees (gametheory-8 0019/0020, search-03 0026 a 0029) : leurs sha git ne sont blob d'aucune revision de leur carnet et leurs hash de contenu n'egalent aucun commit du path -- aucun etat de main n'est perdu. Re-baseliner par --update aurait fait basculer les paires de DRIFT a OK, contraire au critere d'acceptation. Apres : 47 passed ; check_twin_parity --check reste OK=143 DRIFT=15. Refs #22334 Co-Authored-By: Claude Haiku 4.5 (1M context) <noreply@anthropic.com> * Fix(ci,#22339): test_prevalidation_order_rule -- la mesure fondatrice se lit dans le detail #21808 (f2833de) a deporte le recit de la boucle de prevalidation hors de la regle : « 17 candidates sur 17 » vit desormais dans docs/reference/prevalidation-dossier-order-detail.md (2 occurrences) et la regle n'en porte plus aucune. Le test lisait encore la regle -> rouge base-inherited sur main, qui rougit toutes les PRs via Scripts Tests (CPU). Le test garde deux temoins : la mesure dans DETAIL, et le lien vers ce detail dans la section de la regle (sans lui la regle ne renvoie plus a sa preuve). Aucune modification de .claude/rules/** : le deport et le slim sont voulus. Closes #22339 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Haiku 4.5 (1M context) <noreply@anthropic.com>
Collision de numerotation : la branche et main avaient chacune defini une TRANCHE28 differente (branche : absorption des advisaries a payload COMMENTAIRE #22209 ; main : epingle DWELL #22279). Resolution : TRANCHE28 de main conservee, la tranche commenters de la branche renumerotee TRANCHE29, cablee dans fast_lane.py (import + somme des gardes) et dans test_fast_lane.py (14 references). Rejoue : test_fast_lane.py 101 passed ; test_check_adjoint_prevalidation.py 249 passed ; git diff --check propre. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
|
[INFO] lane myia-ai-01:CoursIA-2 — reparation P0 : conflit Collision, mesuree. La branche et Resolution deliberee : Rejoue : |
Grain: DEEP/guard — lane myia-ai-01:CoursIA-2 — prev: MED/guard #22223
See #22209
Objet
Volet 1b de #22209, voie A (arbitrage ai-01 du 2026-10-23, c.6372829627) : absorber dans la voie rapide les trois advisories dont la charge utile est un COMMENTAIRE sur la PR — les trois dernières de la tranche 1.
markdown-claims-output-advisory.ymlMarkdown claims anchored to previous output (#11435 advisory)organ-duplication-advisory.ymlOrgan-duplication advisory (non-blocking)scan-md-hierarchy-drift.ymlscan_md_hierarchy drift (advisory)Le volet 1a (PRs #22223) absorbait les trois advisories a label. Ce volet-ci est le seul qui ecrit sur la PR : c'est ce qui impose un emetteur dedie et un job distinct.
Review CHANGES_REQUESTED 5635535089 — traitee (route b)
Le reviewer nommait trois gardes dont le workflow d'origine borne l'analyse au diff alors que l'argv du registre ne porte aucun jeton :
et proposait deux routes : rendre le jeton aux trois argvs, ou constater que
commenter_paths()borne deja par construction et apprendre a l'organecheck_absorbed_argv_scopea le reconnaitre, avec un test qui le prouve.Route retenue : la seconde, et elle est mesuree, pas supposee. Un garde a commentaires a un
argvde GARDE vide — c'est le moteur (fast_lane.run_effects) qui execute les detecteurs ; ne lire queguard.argvrendait ces trois absorptions faussement perdues. Le bornage existe pourtant, a deux endroits reels :Commenter— les trois le portent :--base {merge_base} --head HEAD(organ-duplication),--diff {name_status_file}(md-hierarchy),{changed_paths}(markdown-claims) ;pathsfait passer son detecteur parcommenter_paths(), qui ne lui transmet que les fichiers du diff :git diff --name-only --diff-filter=MR -M50% <merge-base> HEAD -- <motifs>. Le verdict est borne a la PR par construction, sans qu'aucun jeton n'apparaisse dans un argv.commenter_scope()rend ces deux formes ; I1 les compte au meme titre qu'un jeton d'argv ou qu'un garde DELTA, etfindings()publie les deux champs dans sonevidence(commenter_scope_tokens,commenter_selects_paths). Le message de finding nomme desormais les commenters, pas seulement l'argv du garde.La borne negative est testee : un commenter sans jeton et sans chemins reste un finding. Sans elle, la troisieme forme de I1 blanchirait n'importe quel garde a commentaires — exactement ce que l'organe existe pour empecher.
Mesure sur le registre reel,
--verbose:Ce que fait l'emetteur (
scripts/ci/fast_lane.py)upsert_sticky_comment: retrouve le commentaire dont le corps se termine par<!-- Sticky Pull Request Comment<header> -->, le PATCHe ; sinon le POSTe. Un PATCH refuse ne retombe jamais sur un POST — ce serait fabriquer le doublon que l'upsert existe pour eviter.write_artifact: depose la sortie JSON du detecteur sous$FAST_LANE_ARTIFACT_DIR/<nom>/<fichier>, avec les noms d'artefact publics du workflow d'origine.{changed_paths},{merge_base},{base_sha},{pr_body_file},{name_status_file};drop_empty_pairsretire un drapeau dont la valeur est absente (sansbase_sha,--reference-base ""ferait echouer le scanner).--effects: ne lance QUE les gardes acommenters. Defaut (sans drapeau) : elles sont exclues du job, avec une ligne de log qui le dit. Un seul emetteur par garde, dans les deux sens.Separation des privileges
Nouveau job
always-on-commentersdansalways-on-guards.yml, avec ses proprespermissions:(contents: read,checks: write,pull-requests: write). Le job principalalways-on-guardsne passe pas--effects: le code d'un garde absorbe ne peut donc pas ecrire sur une PR.Limite mesuree, et non contournee :
always-on-guardsn'est pas en lecture seule, contrairement a la formulation de l'ordre. Il porte encore sixgh pr commentLEGACY ecrits en shell dans ses propres etapes (light cap G-VAR-2, signaux de genre, diff trivial, ...) et garde doncpull-requests: writeau niveau du workflow. Les migrer vers ce job est une tranche a part : je ne l'ai pas fait ici, et je ne l'annonce pas comme fait.Contrats de l'absorption (identiques au volet 1a)
guard.namebyte-identique aujob.namedu workflow source —check_absorbed_check_run_identity.py --check:OK -- 34 gardes absorbes byte-identiques a leur source.paths:du declencheur retire reproduits dansGuard.paths, epingles par un test (_TRANCHE29_PATHS) : la source ne les porte plus, donc sans epingle un elargissement silencieux ne serait plus confronte a rien.workflow_dispatch, fichier conserve (nom canonique + re-mesure manuelle), ancien declencheur documente en commentaire.marocchino/sticky-pull-request-comment@v2, en FIN de corps.md-hierarchy-drift-advisory, qui n'avait aucun marqueur (un commentaire neuf par push), entre dans_BOT_STICKY_ADVISORY_HEADERS: sans cela chaque mise a jour serait lue comme une surface de discussion modifiee par un tiers et perimerait le dossier de prevalidation.Preuves
pytest scripts/tests/test_check_absorbed_argv_scope.py scripts/tests/test_fast_lane.py: 123 passed apres rebase surmain— 22 pour l'organe de bornage (dont 5 nouveaux : commenter qui porte le jeton, commenter qui selectionne les chemins, commenter sans borne qui reste un finding, dedoublonnage du jeton entre commenters, et le corpus reel35 gardes / 0 portee perdue), 101 pour le moteur (dont 10 du volet 1b : marqueur byte-identique et reconnu par le parseur du dossier, upsert sur une PR qui porte deja le sticky (PATCH de l'id trouve, aucune POST), creation quand aucun sticky, pas de repli POST sur PATCH refuse,--effectslance les trois et eux seuls /--no-effectsn'en emet aucun, abstention sans merge-base sans lancer le detecteur,fatal_rc(rc=1 du scanner) rougit meme en ombre,trunc_note,drop_empty_pairs).369 passed(test_always_on_guards_live_body,test_check_self_hosted_runner_policy,test_guard_comment_upsert,test_hot_subset_ratchet_wiring,test_bash_e_rc_capture,test_detect_oss_signature,test_emit_dead_scope_warnings,test_check_pr_perimeter).check_absorbed_argv_scope.py --base origin/main --verbose:OK -- 35 gardes absorbes verifies, aucune portee perdue.check_self_hosted_runner_policy.py:OK -- all self-hosted jobs satisfy isolation policy(161 workflows, 207 jobs).check_unique_check_run_names.py:OK -- no duplicate rendered names(84 jobs).sticky 'organ-duplication-advisory' -> 343 caracteres,check-run -> success,aucun bloquant en echec.Perimetre
Dix fichiers, aucun autre :
scripts/ci/fast_lane.py— emetteur d'effets de bord, drapeaux--effects/--no-effects.scripts/ci/fast_lane_registry.py—Commenter,TRANCHE29.scripts/ci/check_absorbed_argv_scope.py— troisieme forme de I1 (commenter_scope), evidence et sortie--verbose.scripts/tests/test_fast_lane.py— 10 tests.scripts/tests/test_check_absorbed_argv_scope.py— 5 tests..github/workflows/always-on-guards.yml— jobalways-on-commenters..github/workflows/markdown-claims-output-advisory.yml,organ-duplication-advisory.yml,scan-md-hierarchy-drift.yml— declencheurpull_requestretire.scripts/check_adjoint_prevalidation.py— en-tetemd-hierarchy-drift-advisorydeclare.Empilement
Levee. La PR etait empilee sur #22223 (volet 1a) ; celle-ci est mergee (
76e783f102). La branche a ete rebasee surorigin/main4d241d4b22(git rebase --onto origin/main 2dbfa5c944), les deux commits du volet 1b rejoues sans conflit, et les 123 tests rejoues apres le rebase. Le diff porte desormais 1b seul, contremain.🤖 Generated with Claude Code
Renumerotation (merge
948d4ab7e4) :maina defini sa propreTRANCHE28(epingle DWELL #22279) ; la tranche commenters de cette PR est desormaisTRANCHE29. Cablee dansfast_lane.pyettest_fast_lane.py, rejouee verte (101 + 249 passed).