You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Output-collapse ratchet: le canal par-PR ne lit jamais le body de la PR (TRANCHE2 sans --pr-body-file) #21552
Le garde bloquant Output-collapse ratchet (base vs PR) (#15327, bloquant depuis T2 #21424) documente une unique échappatoire : une section ## Output-collapse justification dans le body de la PR listant chaque cellule. Le canal qui publie le verdict par-PR ne lit jamais le body, donc l'échappatoire est structurellement injoignable :
fast-lane-shadow.yml : 0 occurrence PR_BODY/pr_body (aucun câblage du corps de PR) et trigger workflow_dispatch seul → github.event.pull_request nul.
Workflow autonomenotebook-output-collapse-ratchet.yml : workflow_dispatch seul ; son COLLAPSE_PR_BODY: ${{ github.event.pull_request.body || '' }} (l.94) est vide par construction en mode dispatch.
Le script (_load_pr_body) ne lit le body que via --pr-body-file ou l'env COLLAPSE_PR_BODY — les deux vides dans les deux canaux. Tout run par-PR rend donc 0 justified in body et tout MAGNITUDE est bloquant, justification ou non.
Body avec section ## Output-collapse justification (cellule 7a064277, motif allegement declare).
Organe local check_output_collapse.py origin/main --pr-body-file <body> : 1 justified in body | 0 unaddressed, rc=0, « Gate passes » (mesuré 2026-10-20 à la tête exacte).
Check-runs CI à la tête : 04:50:45Z (batterie fast-lane) et 06:32:03Z (probe dispatch) — tous deux 0 justified in body, 1 unaddressed, failure.
Rouge non levable par aucun geste de lane.
Deuxième défaut (corrigé côté PR, à consigner dans l'organe)
La v1 du body listait la cellule en basename (Search-11-Metaheuristics.ipynb) ; le matching (_unaddressed, clé (row["notebook"], cell) avec row["notebook"] = path complet, l.394) ne la couvrait pas → unaddressed même avec le body lu. Corrigé dans le body de #21037 (chemin complet repo-relative). Suggéré : le message UNADDRESSED de l'organe devrait indiquer la forme attendue (« chemin complet du carnet, pas le basename ») — c'est la chute que tout auteur va refaire.
Correction attendue
Câbler le body dans le canal par-PR : --pr-body-file dans l'argv TRANCHE2 (écriture /tmp/pr_body.txt type always-on-guards.yml, lue en live) ou un input pr_number sur fast-lane-shadow.yml + fetch API. Inventorier au passage les autres gardes TRANCHE2 qui consomment un body.
[CLAIMED] lane myia-ai-01:CoursIA-2 -- cabler le body de la PR dans le canal par-PR du ratchet Output-collapse, et nommer la forme attendue des cles dans le message UNADDRESSED -- paths: scripts/notebook_tools/check_output_collapse.py, scripts/notebook_tools/tests/test_check_output_collapse.py, .github/workflows/always-on-guards.yml
Mesure avant claim (firsthand, 2026-10-20) :
Le canal par-PR qui produit le check-run bloquant est always-on-guards.yml -> python scripts/ci/fast_lane.py --shadow. Il porte deja FAST_LANE_PR et passe un corps de PR en memoire (MD_CONTENT_LOSS_PR_BODY, l.1294) pour eviter le motif CodeQL actions/code-injection qu'un printf "${{ body }}" > fichier declencherait. Il ne passe rien pour le ratchet.
_load_pr_body (check_output_collapse.py:1018) traite la valeur de COLLAPSE_PR_BODY comme un chemin de fichier. Donc le workflow dedie, qui lui passe le texte (COLLAPSE_PR_BODY: ${{ github.event.pull_request.body || '' }}, l.94), ouvrait un fichier nomme comme le corps de la PR et retombait sur une chaine vide. Les deux canaux sont muets, pour deux raisons differentes.
Aucun test ne couvre COLLAPSE_PR_BODY (grep sur scripts/tests/ et scripts/notebook_tools/tests/ : 0 occurrence).
Perimetre : le script (lecture + message), son fichier de tests, et l'env du seul workflow declenche sur pull_request. scripts/ci/fast_lane_registry.py n'est pas touche (PR #21547 ouverte par une autre lane sur ce fichier) : l'argv TRANCHE2 n'a pas besoin de changer, le corps arrive par l'environnement.
_load_pr_body traitait COLLAPSE_PR_BODY comme un chemin. Le workflow dedie, qui y met le texte du corps, ouvrait donc un fichier du nom de la PR et retombait sur une chaine vide -- son pull_request etait deja mort. Le lecteur accepte maintenant les deux formes : fichier existant -> lu comme chemin, sinon le texte est le corps.
Le message UNADDRESSED nomme la forme attendue des cles (chemin complet repo-relative, pas le basename), et le resume dit si un corps a ete lu (no body read / N chars read) -- un cablage muet ne se confond plus avec une PR sans justification.
Controles a la tete exacte de #21037 (c5063cc5123d), l'instance vivante de l'issue :
corps absent : rc=1, 0 justified (no body read) | 1 unaddressed (le controle negatif rougit toujours) ;
script d'avant, corps en env : rc=1, 0 justified | 1 unaddressed (le defaut, reproduit) ;
script corrige, corps en env : rc=0, 1 justified (7810 chars read) | 0 unaddressed, « Gate passes ».
41 tests unitaires passent (4 neufs sur le canal du corps), self-test de l'organe OK.
scripts/ci/fast_lane_registry.py n'est pas touche (collision #21547 evitee) ; aucun carnet modifie.
Le canal par-PR lit enfin le body de la PR -> --pr-body-file et l env COLLAPSE_PR_BODY dans scripts/notebook_tools/check_output_collapse.py (l.1022 _load_pr_body, l.1157 l option), cables dans .github/workflows/notebook-output-collapse-ratchet.yml et .github/workflows/always-on-guards.yml ; livre par ci(notebooks,#21552): cabler le corps de PR dans le ratchet Output-collapse #21567
Lecture G.9 de l'issue et de ses 2 commentaires, puis verification firsthand sur origin/main.
Le defaut central est corrige : le ratchet output-collapse lisait un body de PR vide, et ne pouvait donc jamais voir la justification ecrite dans le body. La lecture du body est livree, avec les deux formes attendues (--pr-body-file et la variable d'env in-memory), et le workflow qui cable le garde lui passe bien le body de la PR.
La deuxieme correction attendue par l'issue n'est pas livree, et c'est pourquoi le verdict est KEEP.
Ce qui a ete mesure sur main pour etablir cette seconde lacune :
git grep sur origin/main trouve sept gardes qui consomment le body d'une PR : detect_md_content_loss.py (MD_CONTENT_LOSS_PR_BODY), check_output_collapse.py (COLLAPSE_PR_BODY + --pr-body-file), check_added_axioms_cliquet.py (LEAN_CLIQUET_PR_BODY), enrich_quality_ci.py (ENRICH_QUALITY_PR_BODY), detect_notebook_plan_loss.py (PLAN_LOSS_PR_BODY), check_credited_examples.py (--pr-body-file) et la garde nuget de l'advisory dotnet (--pr-body-file).
Aucun de ces sept n'est nomme dans un artefact unique du depot. Le seul inventaire existant, scripts/ci/always_on_body_organs.sh, couvre la famille always-on des organes de protocole, qui lisent le body pour y chercher des marqueurs (Grain:, prev:, mot-cle de fermeture, genre, lane) -- pas le contenu que les sept gardes de contenu analysent.
scripts/ci/fast_lane_registry.py ne cite le canal body qu'a deux endroits, en commentaire, et son bloc TRANCHE2 ne porte aucun drapeau de body dans les argv.
Pourquoi la lacune n'est pas cosine : un garde qui doit lire le body et ne le recoit pas (workflow non cable, variable d'env absente, garde appele hors workflow) ne signale rien -- il rend un verdict sur un body vide. C'est exactement le mode de panne corrige ici pour un seul garde, et rien dans le depot ne permet aujourd'hui de voir les six autres d'un coup d'oeil.
Le residu est donc nommement porte par #22603, qui demande l'inventaire et l'organe qui le verifie, sans toucher au comportement d'un garde deja cable.
Activity
jsboige commentedon Oct 20, 2026
[CLAIMED] lane myia-ai-01:CoursIA-2 -- cabler le body de la PR dans le canal par-PR du ratchet Output-collapse, et nommer la forme attendue des cles dans le message UNADDRESSED -- paths: scripts/notebook_tools/check_output_collapse.py, scripts/notebook_tools/tests/test_check_output_collapse.py, .github/workflows/always-on-guards.yml
Mesure avant claim (firsthand, 2026-10-20) :
always-on-guards.yml->python scripts/ci/fast_lane.py --shadow. Il porte dejaFAST_LANE_PRet passe un corps de PR en memoire (MD_CONTENT_LOSS_PR_BODY, l.1294) pour eviter le motif CodeQLactions/code-injectionqu'unprintf "${{ body }}" > fichierdeclencherait. Il ne passe rien pour le ratchet._load_pr_body(check_output_collapse.py:1018) traite la valeur deCOLLAPSE_PR_BODYcomme un chemin de fichier. Donc le workflow dedie, qui lui passe le texte (COLLAPSE_PR_BODY: ${{ github.event.pull_request.body || '' }}, l.94), ouvrait un fichier nomme comme le corps de la PR et retombait sur une chaine vide. Les deux canaux sont muets, pour deux raisons differentes.COLLAPSE_PR_BODY(grep surscripts/tests/etscripts/notebook_tools/tests/: 0 occurrence).Perimetre : le script (lecture + message), son fichier de tests, et l'env du seul workflow declenche sur
pull_request.scripts/ci/fast_lane_registry.pyn'est pas touche (PR #21547 ouverte par une autre lane sur ce fichier) : l'argv TRANCHE2 n'a pas besoin de changer, le corps arrive par l'environnement.jsboige commentedon Oct 20, 2026
[DELIVERED] lane myia-ai-01:CoursIA-2 -- PR #21567, tete
e35a95b1eb.Le defaut est corrige, et il etait plus large que l'enonce de l'issue : deux canaux muets, pour deux raisons differentes.
always-on-guards.yml->fast_lane.py --shadow, celui qui publie le check-run bloquant) ne passait aucun corps. Il porte maintenantCOLLAPSE_PR_BODY, en memoire, meme motif queMD_CONTENT_LOSS_PR_BODY(fix(guard,#8655): md-content-loss dit 'justifie en review' et ne lit aucune review — aucune porte entre 4 % et 75 % #13491)._load_pr_bodytraitaitCOLLAPSE_PR_BODYcomme un chemin. Le workflow dedie, qui y met le texte du corps, ouvrait donc un fichier du nom de la PR et retombait sur une chaine vide -- sonpull_requestetait deja mort. Le lecteur accepte maintenant les deux formes : fichier existant -> lu comme chemin, sinon le texte est le corps.UNADDRESSEDnomme la forme attendue des cles (chemin complet repo-relative, pas le basename), et le resume dit si un corps a ete lu (no body read/N chars read) -- un cablage muet ne se confond plus avec une PR sans justification.Controles a la tete exacte de #21037 (
c5063cc5123d), l'instance vivante de l'issue :0 justified (no body read) | 1 unaddressed(le controle negatif rougit toujours) ;0 justified | 1 unaddressed(le defaut, reproduit) ;1 justified (7810 chars read) | 0 unaddressed, « Gate passes ».41 tests unitaires passent (4 neufs sur le canal du corps), self-test de l'organe OK.
scripts/ci/fast_lane_registry.pyn'est pas touche (collision #21547 evitee) ; aucun carnet modifie.Lane : myia-ai-01:CoursIA-2, c.2248.
ci(notebooks,#21552): cabler le corps de PR dans le ratchet Output-co…
jsboige commentedon Oct 26, 2026
[CLOSURE PREFLIGHT]
schema: 1
lane: myia-po-2028:CoursIA-3
issue: 21552
verdict: KEEP
acceptance:
--pr-body-fileet l envCOLLAPSE_PR_BODYdansscripts/notebook_tools/check_output_collapse.py(l.1022_load_pr_body, l.1157 l option), cables dans.github/workflows/notebook-output-collapse-ratchet.ymlet.github/workflows/always-on-guards.yml; livre par ci(notebooks,#21552): cabler le corps de PR dans le ratchet Output-collapse #21567scripts/ci/always_on_body_organs.shinventorie la famille always-on (Grain tag, prev:, close-keyword, adjacency, lane-claim), qui est une autre famille ;scripts/ci/fast_lane_registry.pyne cite le canal body qu aux l.2228-2229 et ne porte aucun inventaire, et son bloc TRANCHE2 ne porte aucun drapeau de body dans les argv ; suivi ouvert dans Inventaire des gardes qui consomment le body de la PR -- aucun artefact ne les nomme (suite de #21552) #22603residue: followup Inventaire des gardes qui consomment le body de la PR -- aucun artefact ne les nomme (suite de #21552) #22603
open-prs: 0
comments-reviewed: 2
[/CLOSURE PREFLIGHT]
Lecture G.9 de l'issue et de ses 2 commentaires, puis verification firsthand sur
origin/main.Le defaut central est corrige : le ratchet output-collapse lisait un body de PR vide, et ne pouvait donc jamais voir la justification ecrite dans le body. La lecture du body est livree, avec les deux formes attendues (
--pr-body-fileet la variable d'env in-memory), et le workflow qui cable le garde lui passe bien le body de la PR.La deuxieme correction attendue par l'issue n'est pas livree, et c'est pourquoi le verdict est KEEP.
Ce qui a ete mesure sur
mainpour etablir cette seconde lacune :git grepsurorigin/maintrouve sept gardes qui consomment le body d'une PR :detect_md_content_loss.py(MD_CONTENT_LOSS_PR_BODY),check_output_collapse.py(COLLAPSE_PR_BODY+--pr-body-file),check_added_axioms_cliquet.py(LEAN_CLIQUET_PR_BODY),enrich_quality_ci.py(ENRICH_QUALITY_PR_BODY),detect_notebook_plan_loss.py(PLAN_LOSS_PR_BODY),check_credited_examples.py(--pr-body-file) et la garde nuget de l'advisory dotnet (--pr-body-file).scripts/ci/always_on_body_organs.sh, couvre la famille always-on des organes de protocole, qui lisent le body pour y chercher des marqueurs (Grain:,prev:, mot-cle de fermeture, genre, lane) -- pas le contenu que les sept gardes de contenu analysent.scripts/ci/fast_lane_registry.pyne cite le canal body qu'a deux endroits, en commentaire, et son bloc TRANCHE2 ne porte aucun drapeau de body dans les argv.Pourquoi la lacune n'est pas cosine : un garde qui doit lire le body et ne le recoit pas (workflow non cable, variable d'env absente, garde appele hors workflow) ne signale rien -- il rend un verdict sur un body vide. C'est exactement le mode de panne corrige ici pour un seul garde, et rien dans le depot ne permet aujourd'hui de voir les six autres d'un coup d'oeil.
Le residu est donc nommement porte par #22603, qui demande l'inventaire et l'organe qui le verifie, sans toucher au comportement d'un garde deja cable.
feat(guard,#22603): inventaire mecanique des gardes qui consomment le…