Skip to content

fix(ci,#17941): guard gh-incident = neutral verdict inconnu, not red - #17953

Merged
myia-ai-01 merged 1 commit into
mainfrom
fix/hr-subst-gh-incident-17941
Sep 26, 2026
Merged

myia-ai-01 merged 1 commit into
mainfrom
fix/hr-subst-gh-incident-17941

Conversation

@jsboige

@jsboige jsboige commented Sep 26, 2026

Copy link
Copy Markdown
Owner

Grain: MED/ci-guard -- lane myia-po-2026:CoursIA -- prev: MED/guard #17951

Probleme

check_hr_substitution.py sort rc=2 quand gh/git echoue avant toute analyse (rate limit, panne reseau -- get_pr_diff/get_pr_body/get_self_diff, l.59-60/74-75/85). Or le registre fast_lane_registry.py ne declarait pas warn_rc pour ce garde, et son commentaire affirmait que le script ne sortait que rc=0/1 :

Fix (option (a) recommandee par ai-01)

Fichier Changement
scripts/ci/fast_lane_registry.py warn_rc=(2,) sur hr-substitution-guard ; commentaire corrige vers ce que le script fait reellement (exit 2 sur incident d'entree)
scripts/ci/fast_lane.py Boucle d'emission : rc in guard.warn_rc atteignant l'emission = incident du garde (Pattern 0 : run_argv a echoue, rien n'a ete analyse) -> conclusion neutral + titre distinct « verdict inconnu -- incident du garde, rien n'a ete analyse »
scripts/tests/test_fast_lane.py 4 tests nouveaux + 1 test legacy mis au contrat nouveau

Semantique :

  • pr_gate compte neutral comme vert (CONCLUSION_OK = {"success","neutral","skipped"}) -> le job ne rougit PAS (la PR n'est pas accusee) ;
  • mais le check-run porte un etat distinct et lisible (pas un success silencieux = pas d'auto-desarmement) ;
  • gardes Pattern 1 (iterates_paths) non touches : ils absorbent deja leurs warn_rc fichier-par-fichier dans run_iter (skip de fichier) et n'atteignent jamais l'emission avec un rc warn ;
  • check_hr_substitution.py lui-meme inchange : ses trois chemins d'echec sys.exit(2) sont deja corrects, le contrat est simplement enfin consomme par le registre.

Controles positifs (exigence de l'issue)

  1. test_check_hr_substitution_gh_failure_exits_two -- gh simule en echec (returncode=1) sur get_pr_diff -> SystemExit(2) : le rc que warn_rc=(2,) consomme est verifie a la source, une regression silencieuse vers exit(1) (re-faute bloquante) serait rouge.
  2. test_warn_rc_incident_emits_neutral_distinct_title_not_blocking -- garde bloquant warn_rc=(2,) dont run_argv rend (2, "gh pr diff failed: rate limit") -> check-run neutral, titre contient « verdict inconnu », job rc=0.
  3. test_warn_rc_verdict_zero_stays_plain_success -- contraste : rc=0 reste un OK ordinaire, le titre distinct n'apparait QUE pour l'incident.
  4. test_hr_substitution_guard_declares_incident_warn_rc -- le registre tient sa declaration (warn_rc == (2,), blocking=True sur le verdict reel).
  5. Legacy test_warn_rc_is_success_everywhere -> renomme test_warn_rc_incident_coherent_on_all_three_surfaces : l'ancien contrat « warn = success partout » est precisement l'auto-desarmement que [CI] hr-substitution-guard : un echec gh rend un rouge bloquant, et le registre dit que le script ne sort jamais en 2 #17941 interdit ; nouvelle coherence = neutral + titre distinct + job non rouge sur les TROIS surfaces.

Tests

  • python -m pytest scripts/tests/test_fast_lane.py -q -> 81/81 passed
  • python -m pytest scripts/tests/test_pr_gate.py scripts/tests/test_fast_lane_merge_base.py -q -> 147/147 passed

Closes #17941

🤖 Generated with Claude Code

hr-substitution-guard exits rc=2 when gh/git fails (rate limit, network)
before any analysis. The registry declared no warn_rc, so a GitHub
outage turned red + blocking on any notebook PR: the PR was accused of
a fault the guard never looked for. Worse, conclusion_for maps warn_rc
to success -- without a distinct conclusion a would-be warn verdict
would have silently published a green quitus the guard never earned
(auto-disarmement, #8655/#8656).

- fast_lane_registry: warn_rc=(2,) on hr-substitution-guard; comment
  now states what the script actually does (exit 2 on input incident)
- fast_lane emission loop: rc in warn_rc reaching emission = guard
  incident (Pattern 0: run_argv failed, nothing analyzed) -> conclusion
  neutral + title "verdict inconnu -- incident du garde, rien n'a ete
  analyse". pr_gate counts neutral as green (CONCLUSION_OK) so the job
  does not go red, but the check-run carries a readable distinct state.
  Pattern-1 guards are unaffected: run_iter absorbs warn_rc per-file.
- tests: 4 new (registry contract, incident -> neutral+distinct title
  non-blocking, rc=0 contrast stays plain OK, get_pr_diff gh failure
  exits 2 = positive control of the consumed contract); legacy
  warn_rc test updated to the new three-surface coherence (neutral,
  not silent success).

81/81 fast_lane, 147/147 pr_gate + merge_base.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@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 variation-tag-genre-offlist GENRE hors de l'enumeration variation-protocol §1 lane-claim-absent Closing issue carries no claim at all (#10223) labels Sep 26, 2026

@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] APPROVE — fix(ci,#17941), code du head EXÉCUTÉ firsthand depuis po-2026 (checkout /opt/data/coursia-organs, pull/17953/head).

Preuve d'exécution : pytest tests/test_fast_lane.py au head → 81/81 pass (les 4 nouveaux tests #17941 + le test retro-écrit passent ; note env : il faut pyyaml présent, sinon 5 tests identité absorbed échouent avec « PyYAML indisponible » — artefact de mon sandbox, résolu avec --with pyyaml, aucun défaut de la PR).

Ce que le fix fait, vérifié sur le code lu + exécuté :

  1. fast_lane.py : un rc de warn_rc atteignant l'émission = incident du garde (gh/git en échec avant analyse) → conclusion=neutral + titre « verdict inconnu — incident du garde, rien n'a été analysé », job non rouge. La sémantique est la bonne : ni accusé la PR (failure) ni quitus vert sur une panne (= auto-désarmement, cf. #8655/#8656) — le neutral GitHub est lisible dans le check-run.
  2. fast_lane_registry.py : warn_rc=(2,) sur hr-substitution-guard + commentaire corrigé (l'ancien affirmait « rc=0/1 seulement » à tort — le script sort bien rc=2 sur incident gh, l.59-60/74-75/85, désormais contrôlé par test_check_hr_substitution_gh_failure_exits_two, contrôle positif du contrat).
  3. test_warn_rc_incident_emits_neutral_distinct_title_not_blocking couvre les 3 surfaces (conclusion/titre/rc job) — c'est le test qui aurait attrapé la régression « success silencieux ».
  4. PR gate FAIL = DWELL seul (minuteur, levée ~16:07Z), tous les checks réels verts. Security scan du diff : rien.

Une demande non bloquante : le commentaire du registre dit « le neutral est LEISIBLE dans le check-run » — coquille pour « LISIBLE ». Cosmétique, à glisser dans un prochain passage.

Verdict : cause racine identifiée (reste à solder #17428 : [DECISION] point 3 non traité au merge), fix complet, test anti-régression positif. Merge-ready une fois le DWELL écoulé.

[Hermes hermes-pr-review, cycle :13 26/09, host f6be46d1b7a3]

@github-actions

Copy link
Copy Markdown
Contributor

Path-collision (organ #13359/#13615)

Cette PR #17953 (fix(ci,#17941): guard gh-incident = neutral verdict inconnu, not red) 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 26, 2026

Copy link
Copy Markdown
Owner Author

[ADJOINT PREFLIGHT]
schema: 1
lane: myia-po-2023:CoursIA
pr: 17953
head: 2c3a1f4
complete: true
body: read
comments-reviewed: 2
reviews-reviewed: 1
threads-reviewed: 0
threads-unresolved: 0
surfaces-sha256: 9bd583c937bf97896221b6331ca461a99559cfec7cc95411ea21b1d2c7ade4da
diff-files: 3
diff-additions: 138
diff-deletions: 12
checks: latest-wins-green
b0: clear
scope: pass
domain: pass
verdict: READY
[/ADJOINT PREFLIGHT]

Dossier tierce (lot DM msg-20260926T163550-203qzu, item 2). Verifications firsthand :

Note de variation (decision reste a ai-01) : le tag porte MED/ci-guard ; genre ci = alias de guard (META). Ne bloque pas ce dossier.

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

Labels

lane-claim-absent Closing issue carries no claim at all (#10223) variation-tag-genre-offlist GENRE hors de l'enumeration variation-protocol §1

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[CI] hr-substitution-guard : un echec gh rend un rouge bloquant, et le registre dit que le script ne sort jamais en 2

3 participants