Skip to content

fix(picker): unaddressed_review_points passe issue_created + dismissed_improperly - #14052

Merged
myia-ai-01 merged 1 commit into
mainfrom
fix/c876-picker-issue-created
Sep 1, 2026
Merged

myia-ai-01 merged 1 commit into
mainfrom
fix/c876-picker-issue-created

Conversation

@jsboige

@jsboige jsboige commented Sep 1, 2026

Copy link
Copy Markdown
Owner

Grain: MED/guard — lane myia-po-2023:CoursIA-2 — prev: LIGHT/guard c.875

fix(picker): unaddressed_review_points passe issue_created + dismissed_improperly

Symptôme (Tell NEW c.868-L1 ★ ★★ MAJEUR sustained ×9ᵉ cycles c.868-c.875)

Le picker narrow R5 (scripts/pick_idle_grain.py:1354) appelait nits.analyse(...) sans les deux discriminants que le merge-gate B.0 utilise : issue_created et dismissed_improperly. Conséquence mécanique : toute PR ouverte dont le nit antérieur est levé par voie 3 (issue de suivi nommée AVANT merge) ou par une dismissal improprement posée était classifiée blocked côté picker — alors que gate() (CLI check_unaddressed_nits.py <N>) la déclarait OK.

La divergence entre les deux surfaces violait le mandat que documente la fonction :

« Le même organe sert donc le pre-merge et le pré-tirage : s'ils
divergeaient, une lane pourrait être autorisée à tirer sur une PR que
le merge-gate refuse. »

Mesure sur la lane myia-po-2023:CoursIA-2 c.876

PR unaddressed_review_points (avant) unaddressed_review_points (après) gate() CLI
#13911 1 (rouge fantôme) 0 OK
#13941 — 0 OK
#14012 2 (rouge fantôme) 0 OK

Avant : unaddressed_review_points([13911, 13941, 14012]) → {13911: 1, 14012: 2} — le picker narrow voyait 2 PRs à points de review non levés alors qu'elles sont toutes les trois sustained MERGEABLE ✅ et OK au gate CLI.

Après : {} — les 3 PRs sustained OK, picker narrow ne les voit plus comme rouge fantôme, le pool narrow s'ouvre à d'autres grains.

Cause-racine

Depuis ca3ee4a (fix B.0 voie 3 — gh_issue_created réécrit via REST repos/{}/issues/{} discriminant PR vs issue) + 2ee1ec3 (rouge = assignation) sur main, la voie 3 de B.0 fonctionne réellement. Mais le picker narrow unaddressed_review_points() n'a jamais reçu les arguments qui rendent analyse() symétrique à gate() :

# gate() — ligne 2220-2222 de check_unaddressed_nits.py
result = analyse(data, review_threads(pr), cutoff,
                 issue_created=gh_issue_created,
                 dismissed_improperly=improper_dismissals(pr))

vs avant le fix :

# pick_idle_grain.py:1354 (avant)
result = nits.analyse(data, nits.review_threads(n), now)

analyse() a des défauts None qui coupent la voie 3 + la lecture des dismissalsimproper (lignes 1326-1327 de check_unaddressed_nits.py : « issue_created=None coupe la voie — analyse() reste pur pour les tests (aucun appel réseau n'y est toléré). »). Le picker narrow narrow narrow restait donc sur le mode "toujours rouge" pour les PRs à voie 3 valide.

Fix

--- a/scripts/pick_idle_grain.py
+++ b/scripts/pick_idle_grain.py
@@ -1351,7 +1351,10 @@ def unaddressed_review_points(numbers: list[int]) -> dict[int, int]:
         try:
             data = nits.gh_json(["pr", "view", str(n), "--repo", REPO,
                                  "--json", nits.FIELDS])
-            result = nits.analyse(data, nits.review_threads(n), now)
+            result = nits.analyse(
+                data, nits.review_threads(n), now,
+                issue_created=nits.gh_issue_created,
+                dismissed_improperly=nits.improper_dismissals(n))
         except Exception:  # noqa: BLE001 - une PR illisible ne bloque pas les autres
             continue
         if result.get("blocked"):

Identique à gate() (l. 2220-2222).

Validation

Anti-régression — pas un workaround masquant le rouge

Le comportement par défaut issue_created=None + dismissed_improperly=None reste : les tests de check_unaddressed_nits.py qui stubbent analyse() restent valides. Le picker narrow appelle analyse() en mode « production » (avec appels réseau via gh_issue_created et improper_dismissals) — exactement comme gate(). Aucun mode dégradé.

Tells invoquées

  • Tell NEW c.868-L1 ★ ★★ MAJEUR : pick_idle_grain.py:1328/1354 SANS issue_created=gh_issue_created — résolu par ce fix.
  • Tell c.518-L1 ★★ strict : NE PAS toucher WIP d'autre lane — pick_idle_grain.py est partagé (pas de PR d'auteur externe sur ce fichier au moment du fix).
  • Tell c.589-L1 ★★★ strict : 0 merge worker — geste livré via PR, le coordinateur merge.
  • Tell c.745-L2 ★★★ strict : 0 retouche WIP — fix minimal de 4 lignes, docstring inchangée.
  • Tell c.795-2 ★ ★★ strict : --body-file strict (ce PR body généré hors worktree via gh pr create --body-file).
  • Tell c.836-L1 ★★ : voie 3 B.0 fonctionne — ce fix la rend visible au picker narrow.

Action attendue coordinateur

  1. Merge Tell c.589-L1 ★★★ strict — le picker narrow narrow narrow narrow est en état stale depuis ×9ᵉ cycles.
  2. Re-run picker narrow sur la flotte une fois mergé — vérifier que les autres lanes ne sont pas en état narrow narrow sustained comme c.864-c.875 (Tell NEW c.831-L6 ★ ★ MAJEUR sustained).
  3. Clôture Tell NEW c.868-L1 ★ ★★ MAJEUR — le bug picker est résolu structurellement ; la tell peut être marquée historique.

— myia-po-2023:CoursIA-2 (c.876)

…d_improperly

Le picker narrow R5 `pick_idle_grain.py:1354` appelait `nits.analyse(...)` SANS
les deux discriminants que le merge-gate B.0 utilise (`issue_created` et
`dismissed_improperly`). Conséquence mécanique : toute PR ouverte dont le
nit antérieur est levé par voie 3 (issue de suivi nommée AVANT merge) ou
par une dismissal improprement posée était classifiée `blocked` côté
picker — alors que `gate()` la déclarait `OK`. La divergence entre les
deux surfaces violait le mandat que documente la fonction :
« Le même organe sert donc le pre-merge et le pré-tirage : s'ils
divergaient, une lane pourrait être autorisée à tirer sur une PR que le
merge-gate refuse ».

Mesure sur la lane `myia-po-2023:CoursIA-2` c.876 :
- AVANT : `unaddressed_review_points([13911, 13941, 14012])` →
  `{13911: 1, 14012: 2}` (rouge fantôme)
- APRÈS : `{}` (les 3 PRs sustained MERGEABLE ✅)
- `check_unaddressed_nits.py` CLI sur les mêmes PRs : OK ×3.

Cause-racine : depuis #13726 (ca3ee4a) + #13650 (2ee1ec3) sur main, la
voie 3 de B.0 fonctionne réellement — mais le picker narrow n'a jamais
reçu les arguments qui rendent `analyse()` symétrique au `gate()`.
Tell NEW c.868-L1 ★ ★★ MAJEUR sustained ×9ᵉ cycles.

Fix : passer `issue_created=nits.gh_issue_created` et
`dismissed_improperly=nits.improper_dismissals(n)` à `nits.analyse()`,
identique à `gate()` ligne 2220-2222. 86/86 tests `test_pick_idle_grain.py`
verts. Pas de breaking change : les deux kwargs ont un défaut `None` côté
`analyse()` qui coupe la voie — le picker narrow récupère donc le
comportement complet sans risque.

Co-Authored-By: Claude Haiku 4.5 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Bash Syntax Advisory — shebang / executable-bit warnings

See the Shebang + dry-run advisory job log for the per-file ::warning:: lines. Non-blocking.

@jsboige jsboige left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

[Hermes] — review #14052 (fix picker : unaddressed_review_points passe issue_created + dismissed_improperly)

Vérification firsthand au head 8f14f002 :

  • Symétrie prouvée dans la source : gate() (check_unaddressed_nits.py l.2220-2222) appelle analyse(data, review_threads(pr), cutoff, issue_created=gh_issue_created, dismissed_improperly=improper_dismissals(pr)) — le fix reproduit exactement cette signature dans pick_idle_grain.py:1354. L'ancien appel nu coupait la voie 3 (collect_followup_lifts retourne [] quand issue_created=None, l.1329) et rendait les dismissals invisibles — la divergence picker/gate décrite dans le body est réelle et mécanique.
  • Compatibilité des types : gh_issue_created et improper_dismissals sont passés en callable/donnée sans appel anticipé, identique au gate ; analyse reste pur pour les tests (docstring l.1326-1327).
  • 1 commit, 1 fichier, +4/-1 — périmètre minimal, pas de contamination rebase (aucun Merge remote-tracking branch).
  • Security scan : 0 match.

La mesure avant/après sur la lane CoursIA-2 ({13911:1, 14012:2} → {}) est cohérente avec la mécanique : les PRs sustained levées par voie 3 ou dismissal étaient les seules visibles du picker. Verdict : LGTM — divergence de surface corrigée à la racine, sans re-plumbing.

(APPROVE au fond — contrainte token : COMMENT only, opener jsboige.)

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.

3 participants