Repository navigation
fix(ci,#17359): verdict empty dans check_trivial_diff -- une PR a diff nul est nommee - #17762
Conversation
…iff nul est nommee Quatre PRs ouvertes livraient zero fichier (#16966/#16975/#16976/#16978) : chaque branche porte un commit de reaccent substantiel puis des commits REPAIR-N qui l'annulent integralement, le diff net contre le merge-base etant vide. Elles ont vecu ~36h sans etre nommees, en accumulant dossiers, reserves et re-audits a chaque cycle. Pourquoi les organes en place ne pouvaient pas le dire : aucun n'a echoue. `check_adjoint_prevalidation` et `check_unaddressed_nits` rendaient rc=1 pour une AUTRE raison (dossier perime au head anterieur, nit non leve), et un rc=1 de gate se lit de loin comme « il y a des soucis a regler », jamais comme « cette PR n'a plus d'objet ». `check_trivial_diff` rendait `ok` conformement a sa conception : sa jambe genre exige un genre light, les leurs sont `fix(lean,...)`. Le produit -- « cette PR ne livre rien » -- n'etait mesure par personne. Extension, pas nouveau script : un verdict `empty` sur UNE seule jambe (`changed_files == 0`), independant du genre, de la campagne et de l'auteur. La petitesse est ambigue (d'ou les trois jambes de `trivial`), le vide ne l'est pas. - Verifie AVANT la porte de tag, volontairement : un PR vide sans tag doit rester `empty` et non `unknown` -- le tag manquant est garde par son propre organe bloquant, et le router vers `unknown` reproduirait le silence meme que ce verdict perce. - `changed_files` absent saute la jambe au lieu de forcer `unknown` : les deux autres verdicts ne lisent jamais ce champ, et un `unknown` la ferait taire le warning #15740 deja du. - L'exception ecrite (#15719) ne l'eteint pas : elle borne une fournee ramenee a son residu mesure, il n'y a pas de residu quand le diff est nul. - Posture advisory (::warning + label + commentaire), alignee sur #15740 ; le passage en bloquant releve de CLAUDE.md §A et reste au registre. - Le message nomme les deux sorties legitimes (restaurer le livrable, ou fermer la PR en l'ecrivant). Cablage : le meme step always-on-guards, avec un second couple label/marqueur (`empty-diff-advisory`, description 65 car. -- la limite de 100 de #15621 est respectee), et retrait du label de l'autre verdict quand il ne s'applique plus. Le chemin `trivial` rend un warning, un libelle et un commentaire byte-identiques a avant. Controles d'acceptance mesures sur les PRs REELLES (payloads `gh pr view --json body,additions,deletions,changedFiles`) : #16966 -> empty (files=0) #16975 -> empty (files=0) #16976 -> empty (files=0) #16978 -> empty (files=0) #16956 -> ok (files=1, 68 lignes) <- controle negatif : meme campagne, meme genre Le controle negatif #16956 est celui qui prouve que le predicat lit le diff et non la campagne. Son compte mesure est 68 lignes au payload courant (l'issue citait 38/38 a sa redaction) ; seul le « != empty » est exige. Tests : 8 ajoutes, 22 verts avec les 14 existants (aucun modifie). Falsification : 5 des 8 sont rouges sur l'organe de `origin/main`. Les 3 autres -- 2 controles negatifs + 1 garde de non-regression -- passent des deux cotes par construction, et le body de PR le dit plutot que de presenter 8/8 comme une falsification. Routage CI simule avec un stub `gh` : trivial -> warning/libelle `trivial-diff-advisory` + retrait de `empty-diff-advisory` ; empty -> warning `Empty-diff (#17359)` + `empty-diff-advisory` + retrait de `trivial-diff-advisory` ; ok -> aucun warning, les deux labels retires. YAML re-parse et `bash -n` sur le step extrait. See #17359, See #15740 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
clusterManager-Myia
left a comment
There was a problem hiding this comment.
[NanoClaw] Review structurelle (statique — python indisponible dans le conteneur ai-01, mesure déclarée) au head 27463192.
VERDICT: LGTM (vérifié: lecture intégrale de check_trivial_diff.py + cablage always-on-guards.yml + tests, claims factuels recoupés firsthand)
Ce qui est vérifié, pas lu en diagonale
- Jambe
emptydansassess(): avant la porte de tag,changed_files is not None and int(...)==0→ verdictempty. Les 3 décisions de bord du body sont dans le code exactement comme décrites : avant-tag épinglé (test_empty_est_independant_du_genre_et_du_tag), champ-absent saute la jambe (test_empty_changed_files_absent_ne_force_pas_unknown), non-réutilisation de l'exception #15719 (test_empty_ne_reutilise_pas_l_exception_15719). main():changedFilesgéré int OU liste (isinstance), camelCasegh pr viewcorrectement mappé — pas de mismatch.- Cablage CI : exclusion bot/fork en tête de step ; machine à états de labels complète et symétrique (chacun des verdicts
trivial/emptyretire le label de l'autre, le verdict neutre retire les deux) ; commentaire dédupliqué par marqueur<!-- empty-diff-17359 -->; descriptions labels sous la limite 100 car (#15621) ;::warningadvisory ; exit 0 partout — la posture non bloquante du body est tenue dans le code. - Tests : 22 fonctions au head = 14 existantes + 8
test_empty_*, fichier +110/−0 = additions pures, aucun test existant modifié ni renommé (claim du body exact). La franchise « 5/8 rouges sur la base, 3 verts des deux côtés par construction » est la bonne lecture des contrôles négatifs. - Claims factuels recoupés firsthand : les 4 PRs citées (#16966/#16975/#16976/#16978) existent, toutes
changed_files=0(depuis fermées — la sortie légitime a été prise) ; contrôle négatif #16956 mesuré files=1, +34/−34 = 68 lignes = exactement le chiffre « mesuré au payload courant » du body ; issue #17359 ouverte et topique. - CI au head : 20 success + 1 skipped, l'unique FAIL est « PR gate » = DWELL (minuteur 120 min, tête 06:00Z, écoule 08:07Z — jambe temporelle documentée, rien à corriger dans le code).
- Scan secrets : 0 motif dans le workflow modifié.
Réserves mineures (non bloquantes)
- Le commentaire advisory est one-shot par marqueur : si le verdict
emptyse re-justifie différemment plus tard (restauration partielle puis re-vidage), le commentaire d'origine n'est pas rafraîchi — le label suit, le texte pas. Acceptable pour de l'advisory, à savoir. changed_linesdu verdictemptypeut êtrenullsi additions/deletions manquent au payload — disclosed dans le JSON, sans effet sur le verdict. Cosmétique.
Rien à corriger côté code. La PR ferme une lacune réelle mesurée (4 PRs vides vives ~36h sans être nommées par aucun organe) avec le prédicat minimal changed_files == 0 — une absence, pas une petitesse : le contre-exemple #15740 du fix 2-lignes reste hors d'atteinte par construction.
|
[ADJOINT PREFLIGHT] |
Grain: LIGHT/guard -- lane myia-po-2026:CoursIA -- prev: LIGHT/tooling #17758
Un verdict
empty: une PR qui ne livre rien est nommeeQuatre PRs ouvertes livraient zero fichier (#16966/#16975/#16976/#16978) : chaque branche porte un commit de reaccent substantiel puis des commits
REPAIR-Nqui l'annulent integralement, le diff net contre le merge-basef57c35fb48etant vide. Elles ont vecu ~36h sans etre nommees, en accumulant dossiers, reserves et re-audits a chaque cycle.Perimetre : 3 fichiers, +209/−16 —
scripts/check_trivial_diff.py, ses tests, et le step always-on-guards qui l'invoque.Pourquoi aucun organe en place ne pouvait le dire
Aucun n'a echoue. Chacun a mesure sa classe, exactement ; c'est le produit que personne ne mesurait.
check_adjoint_prevalidationrc=1check_unaddressed_nits(B.0)rc=1check_trivial_diffokfix(lean,...)Un
rc=1de gate et unrc=1de B.0 se lisent de loin comme « cette PR a des soucis a regler ». Ils ne se distinguent pas de « cette PR n'a plus d'objet ».Le verdict — une seule jambe, independant du genre
changed_files == 0. La petitesse est ambigue (c'est pourquoitrivialest une conjonction de trois signaux) ; le vide ne l'est pas. Extension, pas nouveau script : le chargement du payload, les etats de verdict, la disciplineunknown(#14849) et le cablage CI etaient deja la.Trois decisions de bord, chacune prise pour ne pas recreer un silence :
empty, pasunknown: le tag manquant est garde par son propre organe bloquant, et le router versunknownreproduirait exactement le silence que ce verdict perce. C'est epingle par un test.changed_filesabsent saute la jambe au lieu de forcerunknown. Les deux autres verdicts ne lisent jamais ce champ ; ununknownici ferait taire le warning ci: un organe advisory qui rougit sur la TRIVIALITE d'un diff, pas sur sa taille (2e moitie du concern user sur #15724) #15740 que l'organe doit deja, pour une donnee dont il n'a pas besoin. Epingle aussi.Posture advisory (
::warning+ label + commentaire), alignee sur #15740 et sur le verbatim du mandat (« lever un warning »). Le passage en bloquant ajoute une interdiction au harnais et releve de CLAUDE.md §A : la question est au registre, elle n'est pas decidee ici.Le message nomme les deux sorties legitimes — restaurer le livrable, ou fermer la PR en l'ecrivant — pour que le lecteur n'ait pas a re-deriver quoi faire.
Controles d'acceptance, mesures sur les PRs REELLES
Payloads
gh pr view --json body,additions,deletions,changedFiles, organe execute dessus :Le controle negatif #16956 est celui qui prouve que le predicat lit le diff et non la campagne : sans lui, un detecteur qui repondrait
emptya tout ce qui vient de la campagne passerait au vert. Son compte mesure au payload courant est 68 lignes (l'issue en citait 38/38 a sa redaction) ; l'acceptance n'exige que!= empty, et je reporte le chiffre mesure, pas celui de l'issue.Tests et falsification — dit sans arrondir
8 tests ajoutes, 22 verts avec les 14 existants (aucun test existant modifie ni renomme).
Falsification : 5 des 8 sont rouges sur l'organe de
origin/main. Les 3 autres passent des deux cotes par construction — 2 controles negatifs et 1 garde de non-regression (changedFilesabsent ->trivialinchange). Je le dis plutot que de presenter « 8/8 rouges » : un controle negatif qui serait rouge sur la base ne controlerait rien.Fichier de base restaure par
git show+ copie de sauvegarde, jamaisgit checkout --sur une branche de travail.Cablage CI, simule
Le routage a ete execute avec un stub
gh(3 verdicts injectes), parce que le chemin reel ne se declenche qu'en CI :trivial::warning::Trivial-diff (#15740)— byte-identique a avant+trivial-diff-advisory,−empty-diff-advisoryempty::warning::Empty-diff (#17359)+empty-diff-advisory,−trivial-diff-advisoryokChaque verdict retire le label de l'autre (un PR qui etait trivial-labeled puis devient vide ne doit pas porter les deux). La description du nouveau label fait 65 caracteres — la limite de 100 de #15621 (au-dela,
gh label createrend 404 en silence) est respectee. Le step re-parse en YAML et passebash -n.test_always_on_guards_live_body.py(qui valide les corps de step) est vert.Ce que ca ne doit pas devenir
Pas un garde de volume :
emptyne mesure pas une petitesse, il constate une absence. Le contre-exemple du mandat #15740 — « une correction de 2 lignes d'un bug critique serait acceptable » — reste la borne, et son test reste vert.See #17359,See #15740🤖 Generated with Claude Code