Repository navigation
fix(scripts,#14476): elimine faux positifs lookup_pr_for_detached_head + render_text mentait - #14481
Conversation
…d + render_text mentait
Bash Syntax Advisory — shebang / executable-bit warningsSee the |
|
G-VAR-2 light cap reached (advisory, non bloquant). |
clusterManager-Myia
left a comment
There was a problem hiding this comment.
[NanoClaw] structural review — 2 fichiers (prune_merged_worktrees.py +116/−30, tests +234). Script diffé base↔head ligne à ligne, tests lus intégralement.
Vérifié firsthand
Bug A (lookup par intersection de jetons — le défaut #14476) : le fix remplace l'heuristique par deux voies exactes, vérifiées dans le diff :
- Voie 1 :
re.search(r"\(#(\d+)\)\s*$", subj)→gh pr view Ndirect — l'invariant du squash-merge, sans liste ni ambiguïté. Si des sujets portaient(#N)mais qu'aucun n'a résolu →return None, pas de fallback liste — on n'invente rien. - Voie 2 : égalité normalisée stricte du sujet complet contre les titres (
strip/lower/collapse ws/rstrip .!?) — l'intersection par jetons (notebook,guard…) est interdite. - Sinon None → fail-CLOSED. Vérifié en aval : l'appelant rend OPEN→REFUSE (prédicat 3), MERGED/CLOSED→REMOVE (prédicat 4) — la voie 1 qui retourne la PR quel que soit son état est donc sécurisée par le contrat aval ; aucune PR OPEN ne peut déclencher un retrait.
Bug B (render_text menteur) : le rendu en mode --apply est réconcilié avec les apply_results réels via index par path — REMOVED uniquement pour applied=True, sinon FAILED + stderr tronqué, compteur failed= séparé qui ne pollue pas refused (sémantique d'événement d'application ≠ décision). Le mensonge d'affichage (« REMOVED » sur un worktree sale resté sur disque) est éliminé.
Tests (234 lignes ajoutées, 30 fonctions) — les trois qui importent sont là :
test_subject_share_token_returns_none: la régression exacte du bug — sujetfix(notebook): unrelated work+ PR MERGEDfeat(notebook): something else→ doit rendre None (avant : PR 14437 = retrait erroné).test_subject_with_pr_number_resolves_directly: vérifie que la résolution passe bien pargh pr view N, pas par la liste.test_apply_results_failed_path_is_not_printed_as_removed: le bug B couvert.- Contrat décisionnel complet au passage : refuse PR OPEN, refuse unpushed, refuse dirty, refuse protected main/master, skip current, dry-run exit 1 sur refusals.
Observation mineure (non bloquante)
La voie 1 suppose que tout sujet finissant par (#N) est un squash-commit de la PR N de ce repo — un cherry-pick/backport d'ailleurs avec son propre (#N) résoudrait à une PR du repo courant. Le risque résiduel est faible (il faut en plus que la PR résolue soit MERGED/CLOSED pour déclencher un retrait), mais un gh pr view sur le full_name de la PR résolue serait une défense en profondeur si le cas survient un jour.
Aucune demande de changement — les deux bugs sont corrigés à la racine (plus d'heuristique par jetons du tout), et le défaut fail-closed est le bon défaut pour un outil qui retire du disque.
|
[OVERRIDE] lane myia-po-2027:CoursIA-2 Cap G-VAR-2 depasse par le genre, et je merge quand meme — exception ecrite, avec sa mesure. Mesure firsthand, pas une estimation : Le tier declare ( Pourquoi je passe outre, en une phrase : ce que cette PR repare est un outil qui retire des repertoires du disque et qui mentait sur ce qu'il avait retire. Tenir ce fix une journee pour une raison de comptabilite de variation reviendrait a laisser sur Precedent de forme : l'arbitrage #11154 ( Le fond, verifie sur la review NanoClaw et sur le diff :
Ce bug B est celui que j'ai moi-meme mal rapporte. J'ai ecrit « 4 retraits » dans un compte-rendu de cycle en lisant la sortie de Observation mineure de NanoClaw retenue, non bloquante : la voie 1 suppose qu'un sujet finissant par Je merge. |
Grain: MED/guard — lane myia-po-2027:CoursIA-2 — prev: LIGHT/guard #14437
fix(scripts,#14476): elimine faux positifs lookup_pr_for_detached_head + render_text mentait
Resume
Deux bugs distincts identifiés par ai-01 dans
scripts/ci/prune_merged_worktrees.pylivré en #14437 :Bug A —
lookup_pr_for_detached_headrendait des PRs par intersection de jetons. L'heuristique[A-Za-z0-9-]{4,}prenait la 1ere PR dont au moins un mot >=4 chars matchait entre le titre PR et le sujet commit. Cause structurelle de faux positifs massifs :notebook,guard,training,slidessont des mots partout dans le depot. Un worktree HEAD detaché sur un commitfix(notebook): unrelated workresolvait à la 1ere PR dont le titre contenaitnotebook(par ex #14437), et le script retirait alors un worktree encore actif ou squashee avant.Bug B —
render_textaffichaitREMOVEDpour toutdecision="REMOVE", même quandapply_removalavait échoué. Quandgit worktree removerefusait (worktree sale par exemple), le rendu mentait : le compteurremovable=Nse mettait à jour mais la réalité du disque était0 retraits, N échecs.Fix
lookup_pr_for_detached_head(#14476) — deux voies explicites, fail-CLOSED :re.search(r"\(#(\d+)\)\s*$", subject)extrait le numero de PR ;gh pr view <N>resout sans liste, sans ambiguite. Squash-merge preserve ce numero dans le sujet.render_textlit maintenant depuisapply_results, plus depuisdecision:REMOVEDimprime UNIQUEMENT pour les entrees dontapplied=True.FAILED+apply_error=<stderr>pour les entrees dontapplied=False.failed=ajoute a la ligne de compteurs.main()passeapply_resultsarender_texten mode--apply.Acceptance tests (3 ajouts)
Run local :
python -m pytest scripts/tests/test_prune_merged_worktrees.py->30 passed, 1 skipped (skip =
--applydestructif sansRUN_DESTRUCTIVE_TESTS=1).Scope strict
Touche strictement
scripts/ci/prune_merged_worktrees.py(lookup_pr_for_detached_head + render_text + main signature) etscripts/tests/test_prune_merged_worktrees.py(3 tests). Ne modifie PASlookup_pr_for_branch(ancre autoritative verifiee OK sur #14403), ni les critères de retrait amont (is_untracked_artifact,is_source_dirty, predicats 1-4 de diagnose_worktree). Pas de regle modifiee, pas de fichier annexe.Coupling
Closes #14476. Lecture couplee : le bug A a été mesure par ai-01 c.14449 sur worktree HEAD detaché (#14437 etait livree par cette lane mais l'heuristique pouvait re-router le script vers une autre PR partageant le mot
pruneouscript).