Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 22 additions & 5 deletions scripts/check_unaddressed_nits.py
Original file line number Diff line number Diff line change
Expand Up @@ -2904,7 +2904,10 @@ def collect_followup_lifts(pr_data: dict, cutoff: datetime,
Une phrase de l'auteur de la PR ne leve pas la reserve d'un tiers
(voie 1 close pour lui, #11145), mais un report nomme avant merge est
un geste delibere que B.0 credite — l'auteur de la PR est explicitement
ouvert comme nommeur (borne #13563).
ouvert comme nommeur (borne #13563). #14705 elargit au coordinateur
(``LIFT_OVERRIDE_LOGINS``) : B.0 est son gate, et un report se falsifie
en n'ouvrant pas l'issue — ce que les conditions 1-6 verifient deja —
pas en se declarant.

`issue_info=None` coupe la voie — `analyse()` reste pur pour les tests
(aucun appel reseau n'y est tolere). Retourne des tuples
Expand Down Expand Up @@ -3859,7 +3862,12 @@ def _lift_eligible(lift_author: str, nit_author: str,
and _lift_eligible(lifter, login, lift_body, body)
for (t, lifter, lift_body) in explicit_lifts)
# #14218 conditions 5+6 — voir commentaire `followup_lifts`
or any(when < t < cutoff and namer in (login, pr_author)
# #14705 — le coordinateur est un nommeur credite : la
# voie 3 REPORT (elle n'affirme pas la reserve traitee),
# et B.0 est le gate du coordinateur.
or any(when < t < cutoff
and (namer in (login, pr_author)
or namer in LIFT_OVERRIDE_LOGINS)
and when < info.created_at
and _issue_references_pr(info, pr_number)
for (t, namer, info) in followup_lifts))
Expand Down Expand Up @@ -3888,8 +3896,13 @@ def _lift_eligible(lift_author: str, nit_author: str,
# garantie — l'issue existe et fut creee AVANT le cutoff —
# et reste ouverte a l'auteur : un report nomme avant
# merge est un geste delibere que B.0 credite. Borne
# nommeur (c.705) : {auteur du blocage, auteur de la PR}.
or any(when < t < cutoff and namer in (login, pr_author)
# nommeur (c.705) : {auteur du blocage, auteur de la PR}
# ; #14705 y ajoute le coordinateur (LIFT_OVERRIDE_LOGINS)
# — B.0 est son gate, et un report se falsifie en n'ouvrant
# pas l'issue, ce que les conditions 1-6 verifient deja.
or any(when < t < cutoff
and (namer in (login, pr_author)
or namer in LIFT_OVERRIDE_LOGINS)
and when < info.created_at
and _issue_references_pr(info, pr_number)
for (t, namer, info) in followup_lifts)):
Expand All @@ -3907,7 +3920,11 @@ def _lift_eligible(lift_author: str, nit_author: str,
when < t < cutoff and _lift_eligible(lift_author, login, lift_body, body)
for (t, lift_author, lift_body) in explicit_lifts
) or _approved_lifts_reserve(login, when, pr_author)
or any(when < t < cutoff and namer in (login, pr_author)
# #14705 — meme elargissement nommeur que les deux surfaces
# voie 3 ci-dessus (reserve Hermes, blocage).
or any(when < t < cutoff
and (namer in (login, pr_author)
or namer in LIFT_OVERRIDE_LOGINS)
and when < info.created_at
and _issue_references_pr(info, pr_number)
for (t, namer, info) in followup_lifts)):
Expand Down
105 changes: 105 additions & 0 deletions scripts/tests/test_check_unaddressed_nits_followup.py
Original file line number Diff line number Diff line change
Expand Up @@ -430,3 +430,108 @@ def test_14218_mutation_si_predicat_retire_les_fp_rougissent():
# mutation representative, et on documente la borne.
finally:
mod._issue_references_pr = saved


# --- #14705 — voie 3 ouverte au coordinateur (B.0 est son gate) -----------------
#
# Cas fondateur : #14673 (réserve Hermes du 2026-09-04, report #14704 nommé
# par myia-ai-01). Toutes les conditions de substance passaient ; seule
# l'identité du nommeur échouait (`namer='myia-ai-01'` hors
# `(login, pr_author)`), et le merge a dû passer par `[OVERRIDE] lane` — la
# porte d'arbitrage EXCEPTIONNEL — pour un report que B.0 prévoit comme voie
# ORDINAIRE.
#
# La borne nommeur garde sa raison d'être sur les voies 1/2 (se lever
# soi-même n'est pas répondre, #11145/#12798) ; elle ne transpose pas à la
# voie 3, qui affirme le CONTRAIRE — la réserve n'est pas traitée, elle est
# reportée. Un report se falsifie en n'ouvrant pas l'issue ; les conditions
# 1-6 (#14218) le vérifient côté serveur. L'identité du nommeur n'y ajoute
# rien — sauf à retirer au coordinateur la seule voie que B.0 lui donne.

_PR_14705 = 14673 # la PR réelle du cas fondateur

REPORT_COORD = {
"author": {"login": "myia-ai-01"},
"createdAt": at(12),
"body": "Le nit d'attribution est reporte sciemment sur l'issue #500.",
}


def test_14705_coordinateur_leve_reserve_hermes():
"""Le cas mesuré (#14673) : réserve Hermes, pr-auteur == jsboige,
nommeur == coordinateur, issue ouverte postérieure référençant la PR —
lève SANS [OVERRIDE]."""
res = run([REPORT_COORD], reviews=[HERMES_NIT],
issue_info=resolver(ISSUE_OK, pr_number=_PR_14705),
number=_PR_14705)
assert res["blocked"] is False, (
"Un report nommé par le coordinateur satisfaisant les conditions 1-6 "
"doit lever la réserve sans [OVERRIDE] (#14705).")


def test_14705_coordinateur_leve_blocage():
"""Surface blocage : même élargissement nommeur (borne c.705 + #14705)."""
block = {"author": {"login": "myia-po-2025"}, "createdAt": at(10),
"body": "[BLOCAGE] lane myia-po-2025:CoursIA — l'attribution "
"est fausse, pas de merge sans correctif."}
res = run([block, REPORT_COORD],
issue_info=resolver(ISSUE_OK, pr_number=_PR_14705),
number=_PR_14705)
assert res["blocked"] is False, (
"La voie 3 d'un blocage doit créditer le report du coordinateur.")


def test_14705_coordinateur_leve_changes_requested():
"""Surface re-review CHANGES_REQUESTED : même élargissement nommeur."""
cr = {"author": {"login": "hermes-bot"}, "state": "CHANGES_REQUESTED",
"submittedAt": at(10),
"body": "CHANGES_REQUESTED: 2 edge cases non couverts."}
res = run([REPORT_COORD], reviews=[cr],
issue_info=resolver(ISSUE_OK, pr_number=_PR_14705),
number=_PR_14705)
assert res["blocked"] is False, (
"La voie 3 d'un CHANGES_REQUESTED doit créditer le report du "
"coordinateur.")


def test_14705_tiers_non_coordinateur_ne_leve_pas():
"""Contrôle négatif (acceptance #14705) : un compte tiers QUELCONQUE (ni
nit-auteur, ni pr-auteur, ni coordinateur) ne lève toujours pas —
l'élargissement AJOUTE le coordinateur à la borne, il ne la supprime pas."""
third = dict(REPORT, author={"login": "myia-po-2025"})
res = run([USER_NIT, third],
issue_info=resolver(ISSUE_OK, pr_number=_PR_14705),
number=_PR_14705)
assert res["blocked"] is True, (
"Un tiers non coordinateur ne doit pas lever via la voie 3.")


def test_14705_coordinateur_conditions_toujours_exigees():
"""L'élargissement ne court-circuite pas les conditions 1-6 : un report du
coordinateur sur une issue qui ne RÉFÉRENCE PAS la PR ne lève pas."""
unrelated = make_issue(
_PR_14705, datetime(2026, 8, 14, 11, 0, tzinfo=timezone.utc),
title="Inspection du lundi", body="Quelques notes sans rapport.")
resolver_unrelated = lambda n: unrelated if n == 500 else None
res = run([USER_NIT, REPORT_COORD], issue_info=resolver_unrelated,
number=_PR_14705)
assert res["blocked"] is True, (
"Le coordinateur reste soumis à la condition 6 (l'issue doit citer "
"la PR) : l'identité ne remplace pas la substance.")


def test_14705_mutation_sans_constante_les_fp_rougissent():
"""Mutation (précédent #14218) : `LIFT_OVERRIDE_LOGINS` vidé -> les
contrôles positifs coordinateur rougissent. Prouve que les tests
#14705 valident la borne coordinateur, pas un vert par hasard."""
saved = mod.LIFT_OVERRIDE_LOGINS
try:
mod.LIFT_OVERRIDE_LOGINS = set()
res = run([REPORT_COORD], reviews=[HERMES_NIT],
issue_info=resolver(ISSUE_OK, pr_number=_PR_14705),
number=_PR_14705)
assert res["blocked"] is True, (
"Sans LIFT_OVERRIDE_LOGINS, le report coordinateur ne doit plus "
"lever — sinon les tests #14705 ne testent pas la borne.")
finally:
mod.LIFT_OVERRIDE_LOGINS = saved
Loading