Skip to content

fix(picker,#16926): la file de reparation ne compte plus un CHANGES_REQUESTED deja leve - #19073

Merged
myia-ai-01 merged 1 commit into
mainfrom
fix/picker-cr-lift-blind-state
Oct 4, 2026
Merged

myia-ai-01 merged 1 commit into
mainfrom
fix/picker-cr-lift-blind-state

Conversation

@jsboige

@jsboige jsboige commented Oct 4, 2026

Copy link
Copy Markdown
Owner

Grain: MED/tooling — lane myia-po-2025:CoursIA — prev: MED/notebook-python #19011

Le defaut, mesure

Le picker ouvre chaque session d'une lane par sa file de reparation : les PRs qu'elle porte et qui sont bloquees. C'est le premier geste du cycle, avant tout grain neuf — donc une cause fausse y coûte le cycle entier.

Pour sa cause 3 (CHANGES_REQUESTED non leve), blocking_causes lisait reviews[].state brut :

for login, review in latest.items():
    if review["state"] == "CHANGES_REQUESTED":
        causes.append(f"CHANGES_REQUESTED non leve ({login})")

Or GitHub conserve la derniere review par auteur. Une reserve posee par un tiers reste donc CHANGES_REQUESTED a jamais, meme quand une review tierce posterieure l'a levee. §B.0 du CLAUDE.md documente ce champ comme structurellement aveugle — et le meme fichier delegue deja a l'organe pour sa cause 4. Les deux chemins avaient diverge.

Mesure fondatrice — #18829 (lane myia-po-2025:CoursIA, celle de cette PR) :

Evenement Horodatage / valeur
CR Hermes (clusterManager-Myia) 2026-10-02 10:29:39Z
Levee formelle par myia-ai-01 2026-10-04 02:35:33Z, apres recalcul mecanique des 4 listes
Verdict de l'organe du merge-gate check_unaddressed_nits.py 18829 → rc=0
Ce que le picker rendait FILE DE REPARATION -- #18829 ... CHANGES_REQUESTED non leve (clusterManager-Myia)

La PR etait mss=CLEAN, approuvee par le coordinateur, sans conflit ni rouge requis. Deux dossiers [ADJOINT PREFLIGHT] anterieurs a la levee l'avaient laissee BLOCKED sur ce seul champ — leur note dit explicitement que la substance etait prete. Aucun travail n'etait dû, et la lane etait envoyee en reparation.

Le correctif

Trois changements, tous dans scripts/pick_idle_grain.py :

  1. blocking_causes — nouveau kwarg review_points_clear (defaut False). Quand il est vrai, l'appelant declare que l'organe B.0 a evalue les surfaces de review de cette PR et n'y a rien trouve de non leve : un CHANGES_REQUESTED natif n'est alors pas une cause.
  2. unaddressed_review_points — rend desormais 0 pour une PR evaluee et declaree claire (avant : aucune entree, indistinguable de « jamais evaluee »). Le 0 est l'information ; son absence veut dire « non evaluee ».
  3. red_backlog — review_points_clear=nits_by_pr.get(pr["number"]) == 0.

Le == 0 (et non un not ...) est deliberé : c'est lui qui preserve le fail-closed. Une PR absente du dict n'a pas ete evaluee (panne par-PR, exception avalee) et la cause est alors conservee. Le defaut du kwarg est False, donc tout autre appelant garde le comportement anterieur — seul l'appelant qui detient le verdict d'organe s'en sert.

Preuves

Tests — 4 ajoutes dans scripts/tests/test_pick_idle_grain.py, dont le controle positif qui manquait : aucun test du fichier ne couvrait la cause 3 (grep CHANGES_REQUESTED y rendait 0), c'est par la qu'elle a derive de la doctrine que le docstring du meme fichier enonce.

$ python -m pytest scripts/tests/test_pick_idle_grain.py -q -k "changes_requested or review_points"
12 passed, 170 deselected

Controle par mutation — un test qui ne peut pas rougir ne prouve rien. Garde neutralisee (if review_points_clear: → if False:), le test de la levee rougit :

FAILED ...::test_changes_requested_lifted_by_a_third_party_is_not_a_cause
E   AssertionError: assert ['CHANGES_REQUESTED non leve (clusterManager-Myia)'] == []

puis restaure (aucune trace de la mutation dans le fichier commite).

Bout-en-bout sur l'etat REEL de #18829 (organe et API en direct, pas une fixture) :

unaddressed_review_points([18829]) = {18829: 0}
  -> organe a evalue et declare claire : True

AVANT (cause brute, ce que la lane recevait) : ['CHANGES_REQUESTED non leve (clusterManager-Myia)']
APRES (verdict d'organe)                     : []

Le consommateur reel — CLI du picker sur la lane, apres correctif :

occurrences 'FILE DE REPARATION' : 0
occurrences '18829'             : 0
occurrences 'CHANGES_REQUESTED non leve' : 0

La section a disparu ; la lane passe directement au tirage. Avant le correctif, le meme appel l'ouvrait sur #18829.

Non-regression — suite picker complete :

490 passed, 1 skipped in 101.05s

Ce que cette PR ne fait pas

Recouvrement avec #18870 (verifie, L898)

#18870 (lane myia-ai-01:CoursIA, MED/guard) touche le meme fichier. Contrôle des hunks fait avant le push : les siens sont en @@ -3900 / @@ -3907 (fonctions belt_*) et @@ -5265 (main) ; les miens en 104 / 2871-2892 / 3009 / 3202-3226 / 3511. Regions disjointes — les deux PRs se mergent dans n'importe quel ordre sans conflit. Aucune action demandee de part et d'autre.

🤖 Generated with Claude Code

…EQUESTED deja leve

`blocking_causes` lisait `reviews[].state` brut pour sa cause 3. GitHub
conserve la derniere review PAR AUTEUR : la reserve d'un tiers reste
`CHANGES_REQUESTED` a jamais, meme quand une review TIERCE posterieure l'a
levee. L'organe du merge-gate B.0, lui, lit la levee -- et le picker delegue
DEJA a cet organe pour la cause 4, dans le meme fichier. Les deux chemins
avaient diverges.

Mesure fondatrice (#18829, lane myia-po-2025:CoursIA) : CR Hermes du
02/10 10:29Z, leve par ai-01 le 04/10 02:35Z, organe rc=0. Le picker ouvrait
quand meme une FILE DE REPARATION sur la PR -- premier geste de la session,
sur un travail deja fait et deja approuve.

- `blocking_causes` : nouveau kwarg `review_points_clear` (defaut False).
  Quand il est vrai, un `CHANGES_REQUESTED` natif n'est pas une cause.
- `unaddressed_review_points` : rend desormais `0` pour une PR EVALUEE et
  declaree claire. Le `0` est l'information qui distingue « evaluee, claire »
  de « jamais evaluee » -- sans lui, le correctif serait fail-OPEN sur toute
  panne par-PR.
- `red_backlog` : `review_points_clear=nits_by_pr.get(n) == 0`. Le `== 0`
  (et non `not ...`) est ce qui preserve le fail-closed : une PR absente du
  dict n'a pas ete evaluee, la cause est conservee.

Le defaut par defaut est False : sans verdict d'organe, le comportement
anterieur est inchange. Le seul appelant qui sait est celui qui a le verdict.

Preuves :
- 4 tests, dont le CONTROLE POSITIF qui manquait -- aucun test ne couvrait
  la cause 3, c'est par la qu'elle a derive de la doctrine que le docstring
  du meme fichier enonce ;
- controle par MUTATION : garde neutralisee -> le test de la levee rougit
  (`assert ['CHANGES_REQUESTED non leve (clusterManager-Myia)'] == []`) ;
- bout-en-bout sur l'etat REEL de #18829 : avant
  `['CHANGES_REQUESTED non leve (clusterManager-Myia)']`, apres `[]` ;
- CLI du picker sur la lane : section `FILE DE REPARATION` absente
  (0 occurrence de `FILE DE REPARATION`, de `18829` et de la cause), la lane
  passe directement au tirage ;
- 490 passed, 1 skipped sur la suite picker (aucune regression).

See #16926

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 4, 2026

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

@jsboige

jsboige commented Oct 4, 2026

Copy link
Copy Markdown
Owner Author

[ADJOINT PREFLIGHT]
schema: 1
lane: myia-po-2025:CoursIA-2
pr: 19073
head: 298b13c
complete: true
body: read
comments-reviewed: 1
reviews-reviewed: 0
threads-reviewed: 0
threads-unresolved: 0
surfaces-sha256: adbcaff5d4d675c2879f5feade4ef0c1e79ed43e33dcacdcbc8253d40fdfff5d
diff-files: 2
diff-additions: 101
diff-deletions: 4
checks: latest-wins-green
b0: clear
scope: pass
domain: pass
verdict: READY
[/ADJOINT PREFLIGHT]

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants