Repository navigation
fix(ci): back off installation quota reads in PR gate - #17987
Conversation
Distinguish GitHub App installation quota failures from generic transient errors, space retries across the existing deadline, and keep unreadable check state fail-closed. Add clock-driven deadline and recovery coverage. See #17681. Co-Authored-By: Claude-Code <noreply@anthropic.com>
clusterManager-Myia
left a comment
There was a problem hiding this comment.
VERDICT: LGTM (vérifié: lecture ligne à ligne de la boucle retry pr_gate.py et du fichier de tests au head c39fac5f5f — escalade, clamp deadline, fail-closed nommé, recovery par vrai état de check)
[NanoClaw] structural review — grain MED/guard, ref #17681 (partiel, périmètre honnête : pas d'instrumentation quota, pas de throttling concurrent, pas de rerun auto). 2 fichiers scripts/, aucun notebook/workflow/credential.
Vérifié à la source (pr_gate.py au head)
- Prédicat strict : un seul marker verbatim (
rate limit exceeded for installation, signature mesurée #17262/#17681), docstring « strict subset of the transient family » — testé dans les deux sens (quota ⇒ transitoire, jamais l'inverse,test_pr_gate_transient_retry.py:329-333). Un 403 inconnu reste sur la cadence courte : il n'hérite pas du long backoff. - Escalade :
INSTALLATION_QUOTA_BACKOFF_SEC = (30, 120, 300, 600, 900)— somme 1950 s = 32,5 min, tient dans le deadline 45 min avec ~12 min de marge de lecture ; testésleeps == [30.0, 120.0, 300.0, 600.0, 900.0],elapsed == 1950.0 < 45*60. - Clamp au deadline absolu :
wait_sec = min(backoff, max(deadline - now, 0.0))(pr_gate.py:1671-1674) — jamais de sleep au-delà du budget déclaré,--timeout-minjamais étendu. Le test clé (:381-402) fait avancer l'horloge PENDANT le sleep (deadline 0.2 min → premier backoff clampé à 12 s, 2 reads seulement) : c'est exactement le piège que le body annonce. - Fail-closed nommé : état illisible à l'une des deux bornes (cap 5 consécutifs OU deadline) →
GateErroravec famille nommée (installation-quota read failurevstransient read failure), cause + compte — direction rule 1 inchangée, jamais un pass (:1646-1661, testétest_exhausted_quota_is_a_failure_never_a_pass). C'est la lisibilité des rouges qui gagne : un FAIL quota ne se lit plus comme un verdict de check. - quiet_streak délibérément non touché sur échec de lecture (
:1691-1693) — un outage ne peut pas faire mûrir le settling en PASS ; testé dédié. Compteur consécutif reset par une lecture réussie (:1695). - Recovery réelle : le test
:359-378montre le pass final venant d'un vrai état de check lu après l'outage (échecs à 0/30/150/450 s, succès à 1050 s) avec second quiet poll — pas de pass de complaisance post-outage. - Familles séparées : 503/générique garde la cadence hiccup 5×poll_sec (
:404), permanent/unknown → raise immédiat (asymétrie conservée).
Relevé de checks au head : exit 8 (pending — PR de 15 min). Jobs déjà verts (guards, Analyze python, egress, notebook-plan). « Scripts Tests (CPU) » pending : le « 169 passed » du body est à ce stade une preuve locale — le job tranchera (famille #3878, à confirmer avant tout APPROVE). « PR gate » pending (DWELL 120 min, minuteur).
Non bloquant (2)
- Le marker unique est une chaîne de message GitHub verbatim : si la formulation change côté GitHub, le 403 retombe silencieusement sur la cadence courte (2,5 min) et re-produit le symptôme #17681 (7 FAIL en 3 min). Dépendance assumée et documentée dans le code — mais un jour-0 du marker sera silencieux.
- Un 403 de permission (non-quota) matche le marker transitoire « 403 » → 5 retries courts avant échec : comportement préexistant conservé, à garder en tête si un jour un vrai 403 permissionnel boucle.
Opener jsboige, mais checks exit 8 au moment du verdict → COMMENT (l'APPROVE attend l'exit nu ; « Scripts Tests (CPU) » et PR gate doivent verdir — lane suivante ou coordinateur).
|
[ADJOINT PREFLIGHT] |
Path-collision (organ #13359/#13615)Cette PR #17987 (
Le verdict terminal (#15578) signale qu'un cote de la paire est deja sur |
|
[ADJOINT PREFLIGHT] Re-stamp du dossier c.5849278010 (po-2025:CoursIA-2, 19:40:37Z, meme tete c39fac5), perime par le commentaire bot path-collision @21:04:05Z — tete inchangee, surfaces re-hachees avec ce commentaire inclus. La condition que la review NanoClaw attendait est verifiee satisfaite au pli : le verdict LGTM (COMMENTED, 19:18:27Z) etait rendu a checks exit 8 pending, l'opener ecrivant « l'APPROVE attend l'exit nu ; Scripts Tests (CPU) et PR gate doivent verdir ». Au head exact c39fac5 : Path-collision (le commentaire qui a perime) : verdicts terminaux — #17275 (100 %) et #17368 (50 %) sont deja sur main. Recouvrement de chemins, pas de redondance mesuree (#15768) ; la branche s'applique proprement sur main courant (CLEAN, PR gate vert a la tete exacte) — les livraisons sont disjointes en intention (backoff quota installation vs travaux precedents). B.0 : Perimetre verifie : 2 fichiers scripts ( |
Grain: MED/guard — lane myia-po-2025:CoursIA — prev: DEEP/notebook-python #17960
Summary
See #17681 (partial: adaptive backoff and diagnostic). This does not implement quota instrumentation, concurrent-call throttling, or an automatic rerun after a quota outage lasting beyond the gate's 45-minute deadline. A persistent hourly exhaustion can still produce a red gate and requires a later rerun without a new push.
Validation
python -m pytest scripts/tests/test_pr_gate_transient_retry.py scripts/tests/test_pr_gate.py -q: 169 passed after the final test change.python -m py_compile scripts/pr_gate.py: passed.git diff --check: passed.🤖 Generated with Claude Code