Constat
scripts/check_pr_path_collisions.py:579 poste ses verdicts de collision avec :
["gh", "api", "--method", "POST", f"repos/{repo}/issues/{number}/comments",
"-f", f"body=@{tmp_path}"]
gh api -f n'expanse pas le @. L'aide de l'outil fait autorite :
-F, --field key=value Add a typed parameter in key=value format (use "@<path>" or "@-" to read value from file or stdin)
-f, --raw-field key=value Add a string parameter in key=value format
Le corps effectivement poste est donc la chaine litterale @/tmp/tmpXXXXXXXX.md.
Le fichier temporaire est supprime dans le finally juste apres : le verdict est perdu.
Mesure
Scan de 275 commentaires sur les 60 dernieres PRs (tous etats, triees par age croissant) :
|
|
Commentaires au corps litteral @/tmp/tmpXXXX.md |
45 |
| PRs touchees |
18 |
| Fenetre |
2026-09-03T11:47:16Z -> 2026-09-04T01:24:28Z |
| Introduction de la ligne |
312fdbae4, 2026-09-02T17:41:47Z (#14246, fix de #14236) |
Reparties : #14475 (5), #14483 (5), #14469 (4), #14480 (4), #14488 (4), #14495 (4),
#14474 (3), #14478 (3), #14491 (3), #14511 (2), #14456 (1), #14481 (1), et 6 autres.
Pourquoi aucun garde ne l'a vu
1. Le WARN de #13623 ne peut pas le voir. Il se declenche sur returncode != 0.
Or le POST reussit : l'API accepte un corps de 22 caracteres. rc=0, commentaire cree,
label pose. Tous les signaux sont verts et le contenu a disparu. Un garde cable sur le code
de retour est structurellement aveugle a un envoi reussi au mauvais contenu.
2. La suite de tests est verte. test_post_comment_success_silent et
test_post_comment_warns_and_reports_failure mockent subprocess.run et assertent le rc et
le texte du WARN -- jamais l'argv. Le payload n'est mesure par rien.
3. L'ironie du commit. 312fdbae4 s'intitule « route collision verdicts through REST and
let a mute organ go red » : c'etait le correctif de la mutite de #14236. Il a rendu l'organe
muet d'une autre facon -- non plus en echouant bruyamment, mais en reussissant a vide.
Consequence operationnelle
Ces 45 commentaires polluent la queue que toute lecture de merge-gate doit traverser.
check_unaddressed_nits.py les remonte dans sa liste « commentaires non classes : les lire
avant gh pr merge » -- observe firsthand sur #14416 ce jour. Le rapport signal/bruit du
gate B.0 se degrade a chaque run.
Et le marqueur <!-- ... --> vivant dans le corps jamais poste, find_marker_entry ne
retrouve aucun de ces 45 commentaires : le script corrige en postera de nouveaux a cote,
sans jamais reconcilier les orphelins.
Correctif
Aligner post_comment sur sa fonction soeur edit_comment (ligne 615), qui fait deja juste
avec --input + un fichier JSON. --input est preferable a -F : -F applique une
« magic type conversion » qui coercerait un corps valant true / 123 / null en
non-chaine, alors que --input transmet le JSON tel quel.
Discipline (sans quoi le defaut revient)
- Le test ajoute doit capturer l'argv et prouver que le texte du corps atteint reellement
la charge utile. Un test qui n'assert que le rc laisse repasser exactement cette classe.
- Controle positif obligatoire : verifier que le test propose ECHOUE contre le code
d'avant le fix. Un test ajoute en meme temps que sa correction, jamais vu rouge, ne prouve
rien -- c'est ce qui distingue un garde d'une decoration.
- Nettoyer les 45 orphelins : leur corps est verifiable par egalite stricte a
@/tmp/tmp\w+\.md, aucun ne porte d'information.
Acceptance
Constat
scripts/check_pr_path_collisions.py:579poste ses verdicts de collision avec :gh api -fn'expanse pas le@. L'aide de l'outil fait autorite :Le corps effectivement poste est donc la chaine litterale
@/tmp/tmpXXXXXXXX.md.Le fichier temporaire est supprime dans le
finallyjuste apres : le verdict est perdu.Mesure
Scan de 275 commentaires sur les 60 dernieres PRs (tous etats, triees par age croissant) :
@/tmp/tmpXXXX.md312fdbae4, 2026-09-02T17:41:47Z (#14246, fix de #14236)Reparties : #14475 (5), #14483 (5), #14469 (4), #14480 (4), #14488 (4), #14495 (4),
#14474 (3), #14478 (3), #14491 (3), #14511 (2), #14456 (1), #14481 (1), et 6 autres.
Pourquoi aucun garde ne l'a vu
1. Le WARN de #13623 ne peut pas le voir. Il se declenche sur
returncode != 0.Or le POST reussit : l'API accepte un corps de 22 caracteres.
rc=0, commentaire cree,label pose. Tous les signaux sont verts et le contenu a disparu. Un garde cable sur le code
de retour est structurellement aveugle a un envoi reussi au mauvais contenu.
2. La suite de tests est verte.
test_post_comment_success_silentettest_post_comment_warns_and_reports_failuremockentsubprocess.runet assertent le rc etle texte du WARN -- jamais l'argv. Le payload n'est mesure par rien.
3. L'ironie du commit.
312fdbae4s'intitule « route collision verdicts through REST andlet a mute organ go red » : c'etait le correctif de la mutite de #14236. Il a rendu l'organe
muet d'une autre facon -- non plus en echouant bruyamment, mais en reussissant a vide.
Consequence operationnelle
Ces 45 commentaires polluent la queue que toute lecture de merge-gate doit traverser.
check_unaddressed_nits.pyles remonte dans sa liste « commentaires non classes : les lireavant
gh pr merge» -- observe firsthand sur #14416 ce jour. Le rapport signal/bruit dugate B.0 se degrade a chaque run.
Et le marqueur
<!-- ... -->vivant dans le corps jamais poste,find_marker_entryneretrouve aucun de ces 45 commentaires : le script corrige en postera de nouveaux a cote,
sans jamais reconcilier les orphelins.
Correctif
Aligner
post_commentsur sa fonction soeuredit_comment(ligne 615), qui fait deja justeavec
--input+ un fichier JSON.--inputest preferable a-F:-Fapplique une« magic type conversion » qui coercerait un corps valant
true/123/nullennon-chaine, alors que
--inputtransmet le JSON tel quel.Discipline (sans quoi le defaut revient)
la charge utile. Un test qui n'assert que le rc laisse repasser exactement cette classe.
d'avant le fix. Un test ajoute en meme temps que sa correction, jamais vu rouge, ne prouve
rien -- c'est ce qui distingue un garde d'une decoration.
@/tmp/tmp\w+\.md, aucun ne porte d'information.Acceptance
post_commentpasse par--input; le corps arrive entier-f <key>=@dans le depot (verifie : 1 seule, celle-ci)