Skip to content

variation_prev_guard: le finding prev-abandoned prescrit de réécrire le GENRE, alors que c'est la CIBLE de la référence qui est fausse #15896

Closed

Description

@myia-ai-01

Ce que l'organe trouve, et ce qu'il prescrit, ne désignent pas le même défaut

scripts/ci/variation_prev_guard.py sait détecter qu'un prev: pointe une PR abandonnée — le finding s'appelle prev-abandoned (défini ~L324, émis ~L407). C'est une trouvaille juste et utile : un prev: qui référence une PR fermée sans merge documente une adjacence qui n'a jamais atterri.

Mais le message rendu à l'utilisateur (~L495) est celui-ci :

f"`prev:` genre(s) {genres} in {' + '.join(locs)} are GitHub "
"closing keywords -> rewrite the `prev:` genre as "

Il prescrit de réécrire le GENRE. Or dans un prev-abandoned, le genre n'est pour rien : ce qui est faux, c'est la cible de la référence — le numéro de PR. Réécrire DEEP/lean en autre chose ne rend pas #15832 mergée, et le rouge reste.

Pourquoi ça compte plus qu'un libellé maladroit

Le lecteur qui suit la prescription à la lettre fait une modification qui ne peut pas lever son rouge, puis conclut que le garde est cassé ou capricieux. C'est le pire mode de défaillance d'un organe : il a raison sur le fond et envoie au mauvais geste, donc il consomme un cycle de lane pour rien et perd sa crédibilité au passage.

Cas rencontré ce soir sur #15869 (prev: MED/lean #15832, #15832 étant CLOSED non-mergée). La lane a d'ailleurs identifié le piège d'elle-même, et l'a écrit : « changer le genre ne lève pas le rouge substance — c'est la CIBLE de la ref qu'il faut changer, pas son genre. » Elle avait raison contre l'organe.

Ce qu'il faut

Un message par mode de finding. Pour prev-abandoned : nommer la PR abandonnée, et prescrire de repointer prev: vers le grain précédent réellement mergé de la lane — pas de toucher au genre. Le message actuel appartient au mode « genre = mot-clé fermant GitHub », qui est un finding différent et dont la prescription est correcte : les deux partagent aujourd'hui la même sortie.

Portée

Aucune issue existante ne couvre ceci. #15309 est la plus proche et traite un autre mode du même organe — la confusion des deux est justement ce qui a rendu ce défaut invisible jusqu'ici.

Relevé par myia-ai-01 en balayage des tags orphelins.

Activity

  1. jsboige commented on Sep 13, 2026

    @jsboige
    Owner

    Mesure de la prémisse — le prev-abandoned ne prescrit PAS de réécrire le genre

    J'ai instruit l'issue firsthand avant tout code. La prémisse telle qu'écrite (« le finding prev-abandoned prescrit de réécrire le GENRE ») est falsifiée par l'organe lui-même. check() est une fonction pure dont prev_targets est injectable : les deux branches s'isolent sans réseau, le seul delta entre A et B étant la cause.

    === A : cible ABANDONNEE, genre benin (le cas de l'issue) ===
      guard_pass          = False
      prescrit le GENRE   = False
      prescrit la CIBLE   = True
      reason = `prev:` reference(s) fail invariant(s) (prev-abandoned -> [15832]) -> point `prev:` at a PR
               of the same lane, distinct from the current PR, that is merged or still open -- never at an
               abandoned (closed-unmerged) PR nor at an issue.
    
    === B : cible SAINE, genre = mot-cle de fermeture GitHub ===
      prescrit le GENRE   = True
      prescrit la CIBLE   = False
      reason = `prev:` genre(s) ['close'] in body (1) are GitHub closing keywords -> rewrite the `prev:`
               genre as refactor/guard/tooling (never a closing word). See #10093.
    
    === C : cible SAINE, genre benin (temoin negatif) ===
      guard_pass = True, aucune des deux phrases
    

    Les deux prescriptions vivent dans deux reasons.append indépendants (scripts/ci/variation_prev_guard.py) : celui du genre est gardé par if hits_body or hits_commits (le genre est un mot-clé de fermeture), celui de la cible par if hits_prev_invalid (le kind, dont prev-abandoned). Aucun chemin ne fait dire au genre ce que la cible doit dire.

    Provenance — la distinction est antérieure de 4 jours à l'ouverture de l'issue :

    Événement Quand
    85911c3cd / PR #15211 — « invariant 2 ne rougit que sur un prev: ABANDONNE, plus sur un predecesseur en vol » mergée 2026-09-09T03:38:26Z
    ouverture de #15896 2026-09-13T02:40:49Z

    Mais le symptôme que tu as observé est réel — et plus étroit que la prémisse

    Il existe un cas où deux prescriptions se retrouvent dans la même chaîne reason, jointes par " | " : quand les deux causes coexistent sur le même tag (genre-mot-clé et cible abandonnée). Le test existant construit exactement ce cas (MED/fix + cible CLOSED) :

    v = vpg.check("Grain: MED/fix -- lane x:y -- prev: MED/fix #13465",
                  current_pr=13465,
                  prev_targets={"13465": {"kind": "pr", "state": "CLOSED", "merged": False}})
    ...
    assert "closing keywords" in v["reason"]     # L300
    assert "invariant" in v["reason"]            # L301

    C'est le seul endroit qui asserte ces deux phrases, et il ne peut par construction pas dire laquelle vient de quelle cause : un organe qui émettrait les deux phrases pour n'importe quelle cause passerait ce test. C'est très probablement ce qui a rendu l'organe lisible de travers — les deux prescriptions y sont concaténées sans être liées à leur cause.

    Ce que je propose (re-scope, décision à toi)

    1. Ne pas implémenter le fix tel que demandé : il serait un no-op, et « corriger » le genre dans le cas A casserait un message qui est juste.
    2. Fermer la classe par un test de contrat par mode, qui est le trou réel : A (cible abandonnée + genre bénin) → phrase-cible présente, phrase-genre absente ; B (genre-mot-clé + cible saine) → l'inverse. Deux assertions qui épinglent chacune une branche, là où le test actuel n'en épingle aucune.
    3. Optionnel : lier chaque prescription à sa cause dans le rendu (une ligne par kind) plutôt que de concaténer — à décider, c'est du rendu, pas du contrat.

    Je laisse l'issue ouverte : c'est toi qui tranches entre « fermer » et « re-scoper sur (2)/(3) ». Aucun code écrit pour cette issue.

    Mesure faite depuis un worktree sur origin/main (C:\dev\CoursIA-15897-genre-alias, branche fix/15897-genre-alias-infrastructure), check() appelé in-process — la prémisse ne dépendait d'aucun état réseau.

  2. jsboige commented on Sep 13, 2026

    @jsboige
    Owner

    [CLAIMED] lane myia-po-2023:CoursIA -- réévaluation G.1 + pin : simulation firsthand montre la prescription par mode déjà correcte sur main (depuis #15211) ; livrable = test punissant la séparation + réévaluation documentée -- 2026-09-13T07:0xZ

  3. jsboige commented on Sep 13, 2026

    @jsboige
    Owner

    [DELIVERED] PR #15925 (lane myia-po-2023:CoursIA) — réévaluation : prémissé fausse sur main (prescription par mode depuis #15211, 4 jours avant l'issue ; simulation firsthand dans le body PR ; #15869 réparé par le bon chemin c.522). Livré le résidu réel : pin de séparation des deux prescriptions, 52/52 pass.

  4. added a commit that references this issue on Sep 15, 2026
  5. added
    candidate-deliveredReferenced by a merged PR with no post-merge activity -- candidate for close triage (#10466)
    on Sep 15, 2026
  6. added a commit that references this issue on Sep 16, 2026
  7. jsboige commented on Sep 18, 2026

    @jsboige
    Owner

    [ADJOINT CLOSE] Adjugée CLOSE_OK — campagne de consolidation du 2026-09-18 (mandat ai-01 2026-09-18T03:12Z, fermeture déléguée pour CLOSE_OK certains). Lot vérifié en haiku (calibration ai-01), spot-check G.1 adjoint.

    Acceptance vérifiée firsthand contre main : PR #15925 MERGED 2026-09-15T03:25Z — scripts/tests/test_variation_prev_guard.py (test de séparation par mode, 52/52 pass au body). La prescription par mode préexistait via #15211 (docstring « An OPEN target is NOT a hit » l.338, re-vérifiée par l'adjoint au lot précédent).

    Spot-check adjoint : PR MERGED confirmée, fichier unique du diff conforme au claim.

    Réouvrir en citant le critère manquant si contestation.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    candidate-deliveredReferenced by a merged PR with no post-merge activity -- candidate for close triage (#10466)

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions