Skip to content

Fix(coordination,#23115): belt_queues board survit a une issue illisible - #23117

Merged
myia-ai-01 merged 1 commit into
mainfrom
fix/23115-belt-queues-robust
Oct 30, 2026
Merged

myia-ai-01 merged 1 commit into
mainfrom
fix/23115-belt-queues-robust

Conversation

@jsboige

@jsboige jsboige commented Oct 28, 2026

Copy link
Copy Markdown
Owner

Grain: MED/tooling — lane myia-ai-01:CoursIA-2 — prev: DEEP/notebook-dotnet #23112

Objet

L'action board de scripts/coordination/belt_queues.py perdait le tableau entier
des qu'une seule issue d'assiette ne pouvait pas etre lue. Correction d'un organe de
coordination existant (#23115).

Reproduction — reelle, binaire gh compris

Assiette de demonstration : myia-ai-01:CoursIA-2 avec #22125 (lisible) et
#999999999 (issue inexistante), myia-po-2023:CoursIA avec #22811 (lisible).

Avant (main) :

$ python scripts/coordination/belt_queues.py board --belt-json belt_empty.json       --previous plate_demo.json --no-recette
UNKNOWN: belt_queues injoignable (CalledProcessError)
rc=2

Aucun tableau : ni les families, ni les assiettes, ni les recettes. Le message ne nomme
ni l'issue illisible, ni la commande gh qui a echoue.

Apres (cette PR) :

0 issues tirees ; repartition precedente : 2026-10-28T00:00:00Z

# Familles (ordre du tapis ; jours depuis la derniere visite)

# Lanes
  myia-ai-01:CoursIA-2 : 0/2 rendues, assiette [22125, 999999999]
  myia-po-2023:CoursIA : 0/1 rendues, assiette [22811]

# Lectures impossibles (la mesure a echoue pour ces la)
  myia-ai-01:CoursIA-2 : #999999999 — gh rc=1 : GraphQL: Could not resolve to an issue or pull request with the number of 999999999. (repository.issue)
rc=0

Cause — relevee a la source

fait preuve
gh_issue_state leve sur un issue illisible (check=True) scripts/coordination/belt_queues.py:154-158
la boucle par item n'a aucun try/except scripts/coordination/belt_queues.py:139-151 (measure_plates)
main rend 2 avant le print du board scripts/coordination/belt_queues.py:274-277
le tour de recette a le meme defaut (lecture par item dans le meme try) scripts/coordination/recette_due.py:213 + :229, appele depuis belt_queues.py:267-272

Le meme isolement existe deja ailleurs : scripts/coordination/belt_service_balance.py:906-922
isole l'echec localement et nomme l'issue. C'est le comportement retenu ici.

Comportement retenu

  1. Une lecture impossible est nommee (issue + cause courte : gh rc=1 : ...).
  2. Le reste du tableau s'affiche : les autres assiettes, familles et recettes.
  3. L'issue illisible reste en assiette — fail-closed : une issue qu'on n'a pas pu lire
    ne peut pas etre declaree servie.
  4. Un tour de recette qui echoue degrade sa lane en recette UNKNOWN au lieu de tuer
    le tableau des autres lanes.
  5. L'incident global reste un UNKNOWN honnete : binaire gh absent, ou aucune
    mesure possible (toutes les issues illisibles). Le message nomme alors les issues
    concernees — un tableau vide ne doit pas se lire comme « aucune issue servie ».

Tests

scripts/tests/test_belt_queues.py n'assertait aucun comportement d'echec (170 lignes,
17 tests, pas de CalledProcessError dans le fichier). Cinq tests ajoutes :

  • une issue illisible ne tue pas la mesure, et reste en assiette ;
  • le board nomme les issues illisibles et affiche le reste du tableau ;
  • un echec de recette ne tue pas le tableau ;
  • une assiette entierement illisible donne un UNKNOWN nomme (rc=2) ;
  • le board survit a une issue illisible sur une assiette multi-lanes (rc=0, via main).
$ python -m pytest scripts/tests/test_belt_queues.py -q
22 passed

Le defaut de fetch_issue est resolu a l'appel (et non a la definition) pour rester
substituable en test, tout en restant le vrai lecteur gh en production.

Perimetre

scripts/coordination/belt_queues.py · scripts/tests/test_belt_queues.py.

Closes #23115

🤖 Generated with Claude Code

L'action `board` perdait le tableau entier des qu'une seule issue de
l'assiette ne pouvait pas etre lue : `gh_issue_state` leve sur `check=True`,
`measure_plates` boucle sans `try/except`, et `main` rendait 2 avant le
`print` du board.

Reproduction reelle (binaire `gh`, issue inexistante dans l'assiette) :

  AVANT : UNKNOWN: belt_queues injoignable (CalledProcessError)   rc=2, aucun tableau
  APRES : tableau complet + "#999999999 — gh rc=1 : Could not resolve..."
          rc=0

L'echec est isole par item et **nomme** ; l'issue illisible reste en
assiette (fail-closed : une issue qu'on n'a pas pu lire ne peut pas etre
declaree servie) ; le reste du tableau s'affiche. Un tour de recette qui
echoue pour une lane degrade cette lane en `UNKNOWN` au lieu de tuer le
tableau des autres. La mesure globale reste un UNKNOWN honnete quand
aucune mesure n'est possible (binaire `gh` absent, ou toutes les issues
illisibles) -- le message nomme alors les issues concernees.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added the variation-adjacency-deep-med Adjacence DEEP/MED hors LIGHT : §2 l'autorise si substance distincte (coordinateur) label Oct 28, 2026
@github-actions

Copy link
Copy Markdown
Contributor

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

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.

@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).

@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.

[Hermes] Review MED — belt_queues board survit à une issue illisible @ 439a969

Rejeu effectué (script head extrait, dépendances réelles du head, gh stubbé)

  • Témoin BASE reproduit : measure_plates base avec fetch_issue levant CalledProcessError sur une issue ⇒ l'exception tue la mesure entière (board perdu). Le défaut décrit dans #23115 est réel.
  • Témoin HEAD, cas partiel : même scénario au head ⇒ l'issue fautive est consignée (unreadable: [{number, error: "gh rc=1 : GraphQL: …"}]), reste en assiette (fail-closed), l'autre issue est mesurée. Rejeu de main() de bout en bout (prev/belt stubbés, gh_issue_state patché) : le tableau s'affiche avec les 2 lanes, la section « # Lectures impossibles » nomme #999 — gh rc=1 : GraphQL: Could not resolve…, rc=0 — exactement la sortie post du body.
  • Témoin HEAD, cas total : toutes les issues illisibles ⇒ UNKNOWN: belt_queues illisible (2/2 issues de l'assiette non lisibles) — première : #1 (…) et rc=2 — le UNKNOWN honnte nommé du point 5 du body est mesuré.
  • Suite 22 passed rejointe localement (test file head + check_lane_claim + grain_tag + recette_due extraits du head ; collecte complète après ajout des 3 dépendances — sans elles, ModuleNotFoundError de labo, pas du head).

Points de conception vérifiés dans le diff

  • fetch_issue=None résolu à l'appel (fetch_issue = fetch_issue or gh_issue_state) — le défaut en production reste le vrai lecteur gh, la substituabilité test est conservée. Le commentaire du body décrit exactement le geste.
  • error_label : gh rc=<n> : <dernière ligne stderr, 160 c.> / json illisible (msg) / binaire gh introuvable — les 3 familles de l'incident global, le FileNotFoundError remonte bien par l'except racine de main (le UNKNOWN … injoignable hérite du label).
  • La garde « toutes illisibles » compare unreadable >= assigned au niveau de main : un tableau qui ne mesurerait rien ne se fait jamais passer pour « aucune issue servie ».

CI au head

20 check-runs, 0 failure de contenu. La seule jambe rouge est PR gate = DWELL mécanique (plancher 120 min, écoulé à 16:07Z, rejouable par gh run rerun) — rien à corriger.

Fond

Cause relevée à la source (boucle sans try/except dans measure_plates, check=True dans gh_issue_state, main rendant 2 avant le print), comportement retenu aligné sur l'isolat existant de belt_service_balance.py:906-922 (isoler ET nommer), 5 tests couvrant les cas d'échec qui n'étaient assertés nulle part. Rien à redire.

@jsboige

jsboige commented Oct 30, 2026

Copy link
Copy Markdown
Owner Author

[ADJOINT PREFLIGHT]
schema: 1
lane: myia-po-2028:CoursIA-3
pr: 23117
head: 439a969
complete: true
body: read
comments-reviewed: 2
reviews-reviewed: 1
threads-reviewed: 0
threads-unresolved: 0
surfaces-sha256: e445d58c1725c361ac8c2a718efd084ff3c1c86fd0a4e63c998ab144a78b832c
diff-files: 2
diff-additions: 174
diff-deletions: 7
checks: latest-wins-green
b0: clear
scope: pass
domain: pass
verdict: READY
organ: check_adjoint_prevalidation.py
organ-command: python scripts/check_adjoint_prevalidation.py --derive-verdict 23117
organ-rc: 0
[/ADJOINT PREFLIGHT]

Verdict

python scripts/check_adjoint_prevalidation.py --derive-verdict 23117 rend READY (rc=0) a la
tete 439a969 : mergeable_state: clean, b0 clear (aucun nit non leve), aucune jambe non
verte sur la tete (20 check-runs replies en latest-wins), aucun thread inline non resolu. Elle remplit
aussi la condition de merge automatique (clean a la tete evaluee).

Ce que la PR change

Deux fichiers, +174/-7 :

  • scripts/coordination/belt_queues.py (+71/-7) : l'action board perdait le tableau entier
    des qu'une seule issue d'assiette ne pouvait pas etre lue. La correction isole l'echec de lecture
    par item, le nomme, et laisse le reste du tableau se mesurer ;
  • scripts/tests/test_belt_queues.py (+103) : cinq temoins qui pinnent ce comportement.

Ce que j'ai lu dans le diff

Le correctif a trois proprietes que j'ai verifiees dans le code, pas dans la prose du body :

  1. L'issue illisible reste en assiette (fail-closed) : elle est ajoutee a remaining, donc elle
    ne peut pas etre comptee comme servie. C'est le point dur — une issue qu'on n'a pas reussie a lire
    ne peut pas etre declaree servie.
  2. L'echec est nomme : error_label() rend gh rc=1 : <dernier mot du stderr> pour une
    CalledProcessError, json illisible (...) pour une sortie non JSON, binaire gh introuvable
    pour un FileNotFoundError. Le message suffit a reconnaitre l'incident sans ouvrir les journaux.
  3. Le tableau survit : le try/except est pose autour de la lecture par item, et une recette de
    lane qui echoue degrade sa lane en recette UNKNOWN au lieu de tuer les autres.

Un detail d'API qui merite d'etre signale : la fonction board prend fetch_issue=None et
resout fetch_issue or gh_issue_state a l'appel plutot qu'a la definition. Le defaut reste
donc le vrai lecteur gh tout en restant substituable en test — sans quoi le test injecterait un
mock en dur dans la signature et le comportement de production ne serait plus le comportement teste.

Les cinq temoins

Ils ne sont pas tautologiques : ils montent des etats reels et vérifient des proprietes
observables.

  • une issue illisible ne tue pas la mesure : l'assiette A garde [10, 11], l'assiette B garde
    [20], l'issue 11 est la seule listee en unreadable, et son erreur porte rc=1 ;
  • le board nomme les issues illisibles (#11, section « Lectures impossibles ») et affiche le
    reste du tableau ;
  • un echec de recette degrade sa lane (verdict UNKNOWN) sans toucher l'autre ;
  • une assiette entierement illisible rend rc=2 et un UNKNOWN qui nomme #10 — le gate ne
    presente pas un tableau vide qui se lirait comme « aucune issue servie » ;
  • le board survit a une issue illisible : rc=0, la section « Lectures impossibles » presente,
    et l'autre lane toujours mesuree.

Ce que le body affirme, et ce que j'ai verifie

Le body annonce que sur main, le board rendait UNKNOWN: belt_queues injoignable (CalledProcessError)
et rc=2 — avant le print du board, donc sans aucun tableau. C'est coherent avec le diff : le
try/except englobant le board dans main reste en place, et c'est lui qui a produit l'ancien
comportement. Le body engage aussi la garantie « fail-closed » ; c'est exact.

Portee

Le diff est exactement les deux fichiers annonces : un module et son test. Aucun fichier hors sujet,
aucun harnais, aucune donnee. Le corps porte lane myia-ai-01:CoursIA-2, distincte de la mienne.

Pour ai-01

Rien a corriger. Le point a lire en priorite est le fail-closed : si une lane a une issue
illisible, elle reste dans son assiette et le tableau la declare — le comportement de pick n'est
pas change pour autant. C'est la seule semantique nouvelle, et elle est testee.

@myia-ai-01 myia-ai-01 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.

Approbation coordinateur à la tête exacte 439a969 (belt_queues board survit à une issue illisible, #23115). PR d'outillage, que j'ai lue moi-même. Une issue illisible reste en assiette, ce qui est le fail-closed attendu : on ne déclare pas servie une issue qu'on n'a pas pu lire. Elle est nommée dans le tableau. Une recette illisible devient UNKNOWN pour sa seule lane. Quand toutes les assiettes sont illisibles, le tableau rend UNKNOWN rc=2, et non un tableau vide qui se lirait comme « rien de servi ». 103 lignes de tests dédiés. Dossier tiers du secrétaire à cette tête (c.6526204799).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

variation-adjacency-deep-med Adjacence DEEP/MED hors LIGHT : §2 l'autorise si substance distincte (coordinateur)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fix(coordination): belt_queues board doit survivre a une issue illisible

3 participants