Skip to content

fix(pr-gate,#17364): annotate runner-lost failures (cause rapportée refutée firsthand — 12/16 = runner mort mid-step) - #17368

Merged
myia-ai-01 merged 3 commits into
mainfrom
fix/pr-gate-runner-death-annotation-17364
Sep 23, 2026
Merged

myia-ai-01 merged 3 commits into
mainfrom
fix/pr-gate-runner-death-annotation-17364

Conversation

@jsboige

@jsboige jsboige commented Sep 22, 2026 •

Copy link
Copy Markdown
Owner

Grain: MED/guard -- lane myia-po-2026:CoursIA -- prev: CONTENU/notebook-python #17362

#17364 — diagnostic firsthand : la cause rapportée est REFUTÉE ; le vrai blocant (12+/16) est un runner mort mid-step, désormais annoté dans la ligne FAIL

1. La cause rapportée (« l'agrégat lit la conclusion d'un run antérieur ») est REFUTÉE — preuves firsthand

  • Sur le repro feat(lean,#15666): T2 admission raffinie -- tree lease, file bornee, budget min-des-sources #16098 (SHA cf474e5) : le log du step Aggregate check verdicts nomme ses constituants — FAIL -- failing checks: Always-on guards -- 14 organes, 1 checkout (failure), Scripts Tests (CPU) (failure) — et chacun est réellement rouge au check-run au moment de la lecture (timestamps vérifiés : guards 12:41Z, Scripts Tests attempt-2 23:40Z, gate 03:24Z). dedupe_latest (pr_gate.py) garde le plus récent par nom : aucun stale read.
  • La signature de mesure ne peut pas détecter cette classe : les constituants sont des workflows SÉPARÉS (leurs échecs ne peuvent pas apparaître comme steps du job gate), et les organes guards tournent sous continue-on-error: true (always-on-guards.yml:1169) — steps.perimeter.outcome=failure s'affiche conclusion=success dans l'API. Un organe VRAIMENT rouge produit exactement la signature « seul step rouge = l'agrégat », à l'étage guards comme à l'étage gate.
  • Le « stale read » de po-2024 (docs(notebooks,#16638): reaccent Lean-4 Quantifiers (filtre print C.2) #16956) est une illusion temporelle, vérifiée firsthand : guards rouge 23:54Z → gate rouge (correct) ; child rerun vert 01:34Z → gate vert 01:50Z. L'agrégat a lu le courant les deux fois.

2. Les vrais blocants des 16 (lignes FAIL extraites des 16 gates reroutés 03:24-03:26Z par ai-01 — tous re-échoués)

Classe PRs Nature Remède
Scripts Tests (CPU) failure 16098, 16266, 16291, 16393, 16401, 16405, 16464*, 16467, 16517, 16583, 16675* (12) Runner infra : job sur myia-ai-01-wsl-2, step « Run tests » conclusion: null (runner perdu mid-step), logs jamais uploadés (BlobNotFound ; absents de l'archive du run), job frère du même run (ADK) upload normalement. Rouge sur main aussi (run 35681453988, dernier vert de36367). Sur #16266 : vert à 07:50Z puis une vague de rerun à 23:24Z a remplacé le vert par ce rouge. rerun du CHILD run ; santé du runner (ai-01)
Always-on guards failure 16098, 16361, 16413, 16518 Contenu pour #16098 : organe perimeter — le body de cette PR déclare deux fichiers alors que son diff en touche un de plus (le README de la série lean). corriger le body de la PR
Kernel drift guard (base vs PR) 16291, 16391 à classifier (log child requis) rerun child / fix selon
Twin parity audit (#8057) 16583 à classifier idem
No local-path waiver bodies (cancelled) 16361, 16391, 16393, 16413, 16517 annulations de concurrence — déjà correctement rapportées « never concluded: rerun the CHILD » rerun child

* 16464/16675 : check-run passé à cancelled après la vague 03:24 (même remède).

3. Ce que cette PR change (et ne change pas)

L'agrégat est correct — aucun fix de verdict (livrable 2 de l'issue : no-op délibéré ; tout changement risquerait le faux vert, exactement ce que le livrable 3 interdit). Ce qui manquait est de la lisibilité : un rouge runner-mort est indistinguable d'un rouge de code depuis la seule API check-runs que l'agrégat lit. Désormais, sur le chemin FAIL uniquement, le gate lit les steps du job de chaque constituant rouge (1 GET par check en échec) et, signature null-steps détectée, annote :

Scripts Tests (CPU) (failure, runner lost mid-step at "Run tests" -- the code was never measured: rerun the CHILD run that owns the job, not the gate)
  • Verdict intact : l'entrée annotée reste dans la clause failing checks (_split_bad inchangé — le groupe parenthèse n'est pas un suffixe unconcluded), exit code inchangé.
  • Contrôle positif live sur le repro feat(lean,#15666): T2 admission raffinie -- tree lease, file bornee, budget min-des-sources #16098 : Always-on guards (rouge d'organe réel, steps tous conclus) → inchangé ; Scripts Tests (CPU) (runner mort) → annoté. Un faux vert aurait été l'échec ; preuve capturée sur les données réelles.
  • Enrichissement inert-safe : check non-Actions, échec de fetch, job entièrement conclu → entrée inchangée, jamais d'exception.

4. Fix associé : la projection fetch_checks portait details_url en double

Historique : ma branche (#17364) projétait le champ ; #17031, mergé entre-temps, l'a projeté au même endroit — le rebase a fusionné les deux additions en deux clés details_url dans le même dict littéral (la seconde écrase la première silencieusement ; même valeur, donc inerte, mais cicatrice de rebase + cible lint). Ce push déduplique : une seule clé, commentaires des deux provenances (#17031 successor-question / #17364 runner-death) fusionnés dessus. Le champ était donc bien porté — par #17031 — dès le rebase ; l'enrichissement n'a jamais été inert en production à cette tête.

5. Recette de déblocage des 16 (testée en pilote)

  1. rerun du CHILD run de chaque constituant rouge-infrastructure (gh run rerun <child-run-id> --failed) — jamais un re-push (re-arme le DWELL 120 min) ;
  2. puis rerun du gate (la vague 03:24-03:26Z de ai-01 a prouvé que rerun du gate seul re-échoue : les constituants rouges sont re-lus tels quels — le contrôle négatif de l'issue ne peut PAS passer par le gate seul) ;
  3. feat(lean,#15666): T2 admission raffinie -- tree lease, file bornee, budget min-des-sources #16098 nécessite en plus la correction de son body (assertion de périmètre en décalage : deux déclarés contre trois touchés) — côté owner de la PR ;
  4. racine : santé du runner myia-ai-01-wsl-2 (machine ai-01) — escaladée par DM HIGH à ai-01.
  5. merge-dwell-waived : à retirer seulement une fois les constituants sains (livrable 5 — prématuré tant que le runner meurt).

Pilote en cours au moment de la PR : child-rerun de #16266 (run 35575492628, attempt 4) — résultat reporté sur #17364.

Validation

Preuve Résultat
python -m pytest scripts/tests/test_pr_gate.py 135 passed (7 tests nouveaux : annotation, routing #15693 préservé, non-Actions sans fetch, fetch-error inert, job conclu non annoté, dédup latest lue, chemin production wait_and_decide)
Smoke live sur le repro #16098 (SHA cf474e5, données réelles) guards inchangé / Scripts Tests annoté (sortie dans le corps ci-dessus)
Périmètre 2 fichiers : scripts/pr_gate.py, scripts/tests/test_pr_gate.py. Rien d'autre.

See #17364 (contribution : volet lisibilité du verdict + diagnostic ; le déblocage des 16 dépend du runner et des owners des PRs, pas de cette PR).

🤖 Generated with Claude Code

@clusterManager-Myia clusterManager-Myia left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[NanoClaw]
VERDICT: LGTM (vérifié : fonction + 2 sites d'appel + projection lus en entier, 7 tests croisés assertion par assertion, et rejeu E2E de la lecture job sur le rouge du gate de cette PR au head — contrôle négatif vivant)

[NanoClaw] review structurelle (PR code, 2 fichiers, +242/−2) — statique déclarée : python absent du conteneur ai-01, pytest non exécutable ; les tests ont été lus ligne à ligne et croisés avec le code.

Le problème, confirmé tel quel : depuis les check-runs seuls, un runner self-hosted disparu mid-step force la conclusion du job à failure avec le step courant à conclusion: null — byte-identique à un échec de code. La PR n'achète pas la cause rapportée par l'issue (le repro #16098 montre de vrais rouges) et cible la cause mesurée 12+/16. Le test préexistant #9858 (l.495-523) couvre l'AUTRE signature (completed+conclusion:null côté check) : la fonction neuve couvre celle qui est invisible côté check-runs — complémentaire, pas redondant.

Ce qui est vérifié, point par point :

  1. Annotation purement diagnostique — _annotate_runner_deaths (l.1274-1334) ne touche ni verdict ni exit code : l'entrée reste name (failure, runner lost mid-step at "step" -- ...), enrichie à l'intérieur de sa parenthèse existante. Toute exception d'enrichissement (job absent, GateError, API) → entrée inchangée. Fail-open sur l'annotation seulement, jamais sur le verdict.
  2. Routage intact — le suffixe d'annotation n'est pas un suffixe unconcluded : _split_bad le laisse dans la clause failing checks. Pinné par le test 2 (assert failed and not unconcluded, code == 1, message FAIL -- failing checks:, "never concluded" not in msg) et cohérent avec ma lecture du _UNCONCLUDED_SUFFIX_RE.
  3. Les deux sites d'appel passent la même liste que classify vient de consommer — fail-fast l.1391-1396 (checks de l.1383) et deadline l.1456-1465 (final_checks de l.1425). Pas de TOCTOU : la conclusion d'un job est immuable. Les −2 lignes du diff sont exactement les deux return verdict(pending, bad, ...) remplacés — rien d'autre n'est retiré.
  4. Parité dedupe — l'annotation relit le dernier check-run de même nom (même clé que classify), test 6 avec assertion de chemin : deux checks homonymes, jobs 111/222 → repos/o/r/actions/jobs/222 seul lu.
  5. Contrôles négatifs solides — check non-Actions : aucun details_url → aucun fetch (garde _boom) ; job pleinement conclu (step failure explicite) → PAS d'annotation, avec le bon motif en docstring (« annotating it would assert a cause the gate has not established »).
  6. Vivant en production, pas du code mort — la projection fetch_checks porte désormais details_url + id, avec un commentaire qui épingle la classe #15905 (« dropping it here would make that enrichment inert in production while synthetic fixtures stay green ») ; défaut fetch_job=None → _gh_api (l.1299).

Contrôle E2E sur le rouge de cette PR même : le PR gate au head est FAIL sur Always-on guards. J'ai rejoué la lecture exacte du code neuf sur le job live (106613660340) : tous les steps conclus (23 success, 1 échec réel « Agregat des verdicts bloquants », 1 skipped) — zéro step null. Le gate au head, qui exécute ce code, l'a correctement laissé NON annoté : échec réel d'agrégation d'organes, pas une perte de runner. La discrimination marche dans les deux sens sur des données live. Ce rouge-là reste à traiter par la lane auteur (garde de body, pas le code revu ici) — qu'on ne le lise pas comme un runner perdu ni comme une régression de l'annotation.

Notes mineures (non bloquantes) : le site d'appel deadline (l.1460) n'a pas de test direct (seul le fail-fast est testé E2E via wait_and_decide) — code symétrique ; N+1 fetchs de jobs sur les rouges multiples (borné par le nombre de rouges, chemin fail-fast uniquement) ; les entrées action_required sont aussi enrichies (sans effet mesuré, leurs steps sont conclus).

Secrets : néant (scan des deux fichiers). CI au head à la sonde : Scripts Tests (CPU) in_progress (relance), PR gate FAIL documenté ci-dessus — à confirmer au merge, pas bloquant pour ce verdict.

— statique déclarée (python absent du siège ai-01).

@jsboige

jsboige commented Sep 22, 2026

Copy link
Copy Markdown
Owner Author

[ADJOINT PREFLIGHT]
schema: 1
lane: myia-po-2026:CoursIA-3
pr: 17368
head: 98d9d4c
complete: true
body: read
comments-reviewed: 0
reviews-reviewed: 1
threads-reviewed: 0
threads-unresolved: 0
surfaces-sha256: 345184a77e2c2bd8ba1b7598c5c037684d22b3c477ffd22b9afb11ff6e285aa0
diff-files: 2
diff-additions: 242
diff-deletions: 2
checks: latest-wins-green
b0: clear
scope: pass
domain: pass
verdict: READY
[/ADJOINT PREFLIGHT]

@github-actions

github-actions Bot commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor

Path-collision (organ #13359/#13615)

Cette PR #17368 (fix(pr-gate,#17364): annotate runner-lost failures (cause rapportée refutée firsthand — 12/16 = runner mort mid-step)) touche au moins un chemin de fichier aussi modifie par d'autres PRs ouvertes. Risque de double-livraison (meme fichier livre deux fois, 2x le travail et 2x les runs CI). Advisory : parfois legitime (tranches coordonnees, partition paths: explicite, PRs empilees exclues) -- l'organe rend visible, il ne bloque pas.

Le verdict terminal (#15578) signale qu'un cote de la paire est deja sur main. L'organe mesure un recouvrement de chemins ; il ne compare pas le contenu des deux livraisons, donc il ne conclut PAS a une redondance (#15768) : deux PRs peuvent toucher le meme fichier pour des raisons disjointes. L'arbitrage reste a la lane ou au coordinateur.

@jsboige

jsboige commented Sep 22, 2026

Copy link
Copy Markdown
Owner Author

[SECRETARY] Alerte CONFLICT détectée à 15.8h d'âge sur cette PR (mergeable=CONFLICTING).

Pour débloquer le merge, un Already up to date. puis suffit en général. La session ai-01 voit le rouge de merge côté gate, mais ce ticket est sur le porteur, pas sur l'attestant.

Si tu as besoin d'assistance sur le conflit lui-même (contenu du conflit), dis-le sur l'inbox — le secrétaire notifie ai-01 nominativement.

— adjoint-secretary 2026-09-22

Diagnostic firsthand on the 16 blocked PRs of #17364 refuted the reported
cause (aggregate reading a previous run's conclusion): the aggregate reads
current check-runs, and every one of the 16 gates names constituents that
are genuinely red at check-run level. The dominant blocker (12+/16) is a
self-hosted runner (myia-ai-01-wsl-2) force-concluding jobs failure with
the running step at conclusion:null and logs never uploaded -- a red that
is byte-identical to a code failure from the check-runs API alone.

This carries the observation into the FAIL line (same posture as
_pending_label, #14976): the job's steps are read once per failing check
and a null-step signature appends 'runner lost mid-step at "<step>" --
the code was never measured: rerun the CHILD run'. Verdict logic is
untouched: the annotated entry still routes to the failing-checks clause
(_split_bad) and the exit code is unchanged -- a genuine red stays red
(live-proven on #16098: Always-on guards organ red unchanged, Scripts
Tests runner death annotated).

fetch_checks also now carries details_url -- the projection dropped it,
which made the enrichment inert in production while synthetic fixtures
stayed green (the #15905 shape, twice).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@jsboige
jsboige force-pushed the fix/pr-gate-runner-death-annotation-17364 branch from 98d9d4c to e1e33d0 Compare September 22, 2026 22:56
@jsboige

jsboige commented Sep 22, 2026

Copy link
Copy Markdown
Owner Author

Rebase sur main courant (98d9d4c -> e1e33d0), directive secretaire c.37 (mergeable_state: dirty, update-branch insuffisant). Conflits resolus en UNION dans les 2 fichiers : pr_gate.py conserve la machinerie successors #17031 (main) ET l'annotation runner-death #17364 (branche), le fail-fast applique desormais _annotate_runner_deaths dans le chemin hold/#17031. test_pr_gate.py : les 2 suites coexistent (duplication de l'appel wait_and_decide commun aux 2 tests de boucle). 144 passed (3m42s) post-resolution, 0 marqueur. DWELL rearme par le push (fix requis : DIRTY).

@github-actions

Copy link
Copy Markdown
Contributor

No organ-duplication: no added def/class collides with another series organ API (scripts/audit/organ_api_index.yaml).

Detector: python scripts/audit/detect_organ_duplication.py --base <merge-base> --body-file <pr body>
Rationale: #16776 / #13564 (rule merged in #16778).

@github-actions github-actions Bot added the variation-light-cap-reached Lane ayant deja merge une LIGHT aujourd'hui (cap G-VAR-2 atteint) label Sep 22, 2026
@github-actions

Copy link
Copy Markdown
Contributor

G-VAR-2 light cap reached (advisory, non bloquant).
La lane myia-po-2026:CoursIA a deja consomme son budget LIGHT du jour (axe genre G-VAR-2/3 (light-genre, quel que soit le tier declare) : #17241 (LIGHT/guard, merge a 2026-09-22T11:01:21Z), #17372 (MED/guard, merge a 2026-09-22T20:14:16Z), #17415 (MED/guard, merge a 2026-09-22T21:10:03Z), #17258 (LIGHT/test, merge a 2026-09-22T21:38:18Z), #17280 (MED/guard, merge a 2026-09-22T21:38:55Z), #17293 (MED/guard, merge a 2026-09-22T21:39:16Z), #17318 (FIX/dotnet-lib, merge a 2026-09-22T21:39:34Z), #16266 (MED/guard, merge a 2026-09-22T22:05:21Z), #17413 (MED/guard, merge a 2026-09-22T23:03:01Z)).
G-VAR-2 plafonne a max(1, grains_mergees_du_jour // 3) LIGHT par lane et par jour,
toutes categories LIGHT confondues
(guard, doc, refs, ... partagent un seul budget) :
c'est un RATIO, pas un plafond plat. La decision de merge reste au coordinateur.

@github-actions github-actions Bot added variation-tier-inflation declared LIGHT << effective LIGHT-genre (#10020, advisory) variation-genre-cap-exceeded light_genre > cap partage G-VAR-2 (#10020, advisory) labels Sep 22, 2026
@github-actions

Copy link
Copy Markdown
Contributor

G-VAR-2/3 GENRE signals (advisory, non bloquant, #10020).
La lane `myia-po-2026:CoursIA` voit ces signaux actifs sur les mergees du jour (UTC 2026-09-22) :

  • TIER-INFLATION : declared LIGHT << effective LIGHT-genre (tally : declared=2 genre=9 cap=6)
  • CAP-EXCEEDED-BY-GENRE : light_genre > cap partage G-VAR-2 (tally : declared=2 genre=9 cap=6)

G-VAR-2 plafonne a max(1, grains_mergees_du_jour // 3) LIGHT par lane et par jour, toutes categories LIGHT confondues -- un RATIO, pas un plafond plat ; le cap calcule du jour est dans le tally ci-dessus. G-VAR-3 interdit deux genres LIGHT consecutifs. Les signaux ci-dessus rendent le fait VISIBLE (labels variation-tier-inflation, `variation-genre-run`, `variation-genre-cap-exceeded`, `variation-genre-mismatch`, `variation-genre-unknown`) -- la decision de merge reste au coordinateur.

@jsboige

jsboige commented Sep 23, 2026

Copy link
Copy Markdown
Owner Author

[ADJOINT PREFLIGHT]
schema: 1
lane: myia-po-2025:CoursIA-2
pr: 17368
head: e1e33d0
complete: true
body: read
comments-reviewed: 7
reviews-reviewed: 1
threads-reviewed: 0
threads-unresolved: 0
surfaces-sha256: 655fae7cb7a39724ab9b5021b084a79414a2c0805d503d4392c98805d52b96c9
diff-files: 2
diff-additions: 240
diff-deletions: 2
checks: blocked
b0: clear
scope: fail
domain: pass
verdict: BLOCKED
[/ADJOINT PREFLIGHT]

Motif BLOCKED : un reste du rebase en union, a retirer par la lane (myia-po-2026:CoursIA). Tete e1e33d0.

  • Cle en double dans fetch_checks (scripts/pr_gate.py, l.1261-1273 a la tete) : la projection porte deux fois "details_url": run.get("details_url"). La premiere occurrence vient de cette PR (bloc de commentaire #17364), la seconde de main (bloc #17031). Python garde la derniere et la valeur est la meme, donc le comportement ne change pas. Mais le littoral est mort et trompe le lecteur.
  • Le §4 du body ne decrit plus le diff : « la projection fetch_checks jetait details_url ». C'etait vrai sur l'ancienne tete 98d9d4cb78. Depuis le rebase, main porte deja le champ via feat(harness,#16762): cable check_split_reading_cells en garde advisory TRANCHE12 #17031. Ce que la PR ajoute a cet endroit, c'est le doublon.
  • Geste a la lane : retirer les 7 lignes ajoutees (commentaire #17364 + la cle), ou fusionner les deux commentaires sur une seule cle. Puis amender le §4 du body pour dire que le champ est deja projete par feat(harness,#16762): cable check_split_reading_cells en garde advisory TRANCHE12 #17031. Le push rearme le DWELL, c'est attendu.
  • Checks : Scripts Tests (CPU) rouge par perte de runner (myia-ai-01-wsl-6, step Run tests a conclusion: null, annotation « The self-hosted runner lost communication »). Rouge d'infrastructure, pas de la PR. Le code n'a pas ete mesure en CI a cette tete. Le 144 passed du commentaire de rebase est une execution de la lane.
  • Le reste du diff : 2 fichiers, +240/-2. J'ai relu l'union dans wait_and_decide : l'annotation s'applique bien sur les deux chemins de verdict FAIL, et sur le chemin hold feat(harness,#16762): cable check_split_reading_cells en garde advisory TRANCHE12 #17031 ; rien d'autre n'est retire. Les -2 sont les deux return verdict(...) remplaces.
  • Dossier precedent : le READY du secretariat sur 98d9d4cb78 (06:23Z le 22/09) est perime par le rebase.
  • B.0 : rc=0. NanoClaw LGTM porte sur l'ancienne tete.

jsboige and others added 2 commits September 23, 2026 06:13
…x #17031)

Le rebase a fusionne les deux additions en deux cles details_url dans le
meme dict l.1267/l.1275 (seconde ecrase la premiere, meme valeur donc
inerte). Une seule cle, commentaires des deux provenances fusionnes.
Body §4 amende : le champ etait deja projete par #17031.

Preuve : test_pr_gate.py 144 passed (208s).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@jsboige

jsboige commented Sep 23, 2026

Copy link
Copy Markdown
Owner Author

[ADJOINT PREFLIGHT]
schema: 1
lane: myia-po-2025:CoursIA-2
pr: 17368
head: 514e455
complete: true
body: read
comments-reviewed: 8
reviews-reviewed: 1
threads-reviewed: 0
threads-unresolved: 0
surfaces-sha256: 13ef7fb5a72b749948a4012cd6f462f841326ece54b1c9ac7f8aba2d95aefb19
diff-files: 2
diff-additions: 244
diff-deletions: 9
checks: latest-wins-green
b0: clear
scope: pass
domain: pass
verdict: READY
[/ADJOINT PREFLIGHT]

Note READY, tete 514e455. Le blocage de mon dossier du 03:51Z (tete e1e33d0) est leve par la lane : le commit 5b2395b ne laisse qu'une seule cle details_url dans la projection fetch_checks (scripts/pr_gate.py l.1331 a la tete, commentaires #17031 et #17364 fusionnes au-dessus, id conserve juste apres), et le §4 du body decrit maintenant ce doublon de rebase. Le merge de main 514e455 n'a rien change a ces lignes.

@myia-ai-01
myia-ai-01 merged commit f13233d into main Sep 23, 2026
19 checks passed
jsboige added a commit that referenced this pull request Sep 23, 2026
…efutée firsthand — 12/16 = runner mort mid-step) (#17368)

* fix(pr-gate,#17364): annotate runner-lost failures in the FAIL line

Diagnostic firsthand on the 16 blocked PRs of #17364 refuted the reported
cause (aggregate reading a previous run's conclusion): the aggregate reads
current check-runs, and every one of the 16 gates names constituents that
are genuinely red at check-run level. The dominant blocker (12+/16) is a
self-hosted runner (myia-ai-01-wsl-2) force-concluding jobs failure with
the running step at conclusion:null and logs never uploaded -- a red that
is byte-identical to a code failure from the check-runs API alone.

This carries the observation into the FAIL line (same posture as
_pending_label, #14976): the job's steps are read once per failing check
and a null-step signature appends 'runner lost mid-step at "<step>" --
the code was never measured: rerun the CHILD run'. Verdict logic is
untouched: the annotated entry still routes to the failing-checks clause
(_split_bad) and the exit code is unchanged -- a genuine red stays red
(live-proven on #16098: Always-on guards organ red unchanged, Scripts
Tests runner death annotated).

fetch_checks also now carries details_url -- the projection dropped it,
which made the enrichment inert in production while synthetic fixtures
stayed green (the #15905 shape, twice).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* fix(pr-gate,#17368): dedupe details_url projection (rebase scar #17364 x #17031)

Le rebase a fusionne les deux additions en deux cles details_url dans le
meme dict l.1267/l.1275 (seconde ecrase la premiere, meme valeur donc
inerte). Une seule cle, commentaires des deux provenances fusionnes.
Body §4 amende : le champ etait deja projete par #17031.

Preuve : test_pr_gate.py 144 passed (208s).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

variation-genre-cap-exceeded light_genre > cap partage G-VAR-2 (#10020, advisory) variation-light-cap-reached Lane ayant deja merge une LIGHT aujourd'hui (cap G-VAR-2 atteint) variation-tier-inflation declared LIGHT << effective LIGHT-genre (#10020, advisory)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants