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
17 changes: 15 additions & 2 deletions scripts/check_adjoint_prevalidation.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,21 @@
"myia-po-2027:CoursIA-2",
})
# `Grain: <genre> -- lane <machine:workspace>` in the pull request body names the
# lane that carries the work. Same grammar as scripts/check_lane_claim.py.
GRAIN_LANE_RE = re.compile(r"Grain:[^\n]*?\blane\s+([A-Za-z0-9_.-]+:[A-Za-z0-9_.-]+)")
# lane that carries the work. The canonical reader is `grain_tag.extract_lane`,
# the one `scripts/check_lane_claim.py` uses; the patterns below are `findall`
# variants of it, kept because the consumers need EVERY marker of a body, not
# just the first.
#
# #15864 (4th variant of the self-block class) -- a sentence period is admitted
# by the token class (hostnames need it), so `lane myia-po-2023:CoursIA-2.` used
# to be captured as the lane `myia-po-2023:CoursIA-2.` -- a lane no cluster lane
# matches. A token can no longer END on a period; periods INSIDE it survive
# (`Foo.Bar:CoursIA-2` is unchanged), so the constraint only removes prose
# punctuation. Measured on #14549, 2026-10-09: `delivering_lanes` returned
# `myia-po-2023:CoursIA-2.`, and a lane named ONLY under the punctuated form is
# absent from the set -- its own self-attesting dossier then passes the gate.
LANE_TOKEN = r"[A-Za-z0-9_.-]*[A-Za-z0-9_-]:[A-Za-z0-9_.-]*[A-Za-z0-9_-]"
GRAIN_LANE_RE = re.compile(r"Grain:[^\n]*?\blane\s+(" + LANE_TOKEN + r")")
SHARED_GITHUB_LOGIN = "jsboige"
# The gate's only consumer. Every worker lane signs SHARED_GITHUB_LOGIN, so this
# login is the one surface author the coordinator can recognise as itself.
Expand Down
11 changes: 8 additions & 3 deletions scripts/check_closure_dossier.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,14 @@

try:
import gh_identity
from check_adjoint_prevalidation import QUALIFYING_LANES, GRAIN_LANE_RE
from check_adjoint_prevalidation import QUALIFYING_LANES, GRAIN_LANE_RE, LANE_TOKEN
except ImportError: # charge depuis scripts/ en invocation directe
sys.path.insert(0, dirname(abspath(__file__)))
import gh_identity # type: ignore[no-redef]
from check_adjoint_prevalidation import ( # type: ignore[no-redef]
QUALIFYING_LANES,
GRAIN_LANE_RE,
LANE_TOKEN,
)

REPO = "jsboige/CoursIA"
Expand Down Expand Up @@ -121,9 +122,13 @@
_RESIDUE_FOLLOWUP_RE = re.compile(r"^followup\s+#(\d+)$")
_RESIDUE_WAIVER_RE = re.compile(r"^waiver:\s+\S.+")

#: ``[DELIVERED] lane <machine:workspace> ...`` -- protocole lane-claim.
#: ``[DELIVERED] lane <machine:workspace> ...`` -- protocole lane-claim. Le
#: token reprend ``LANE_TOKEN`` (voir check_adjoint_prevalidation) : un point
#: final de phrase n'entre plus dans la lane capturee (#15864, mesure #14549) --
#: sinon une lane marquee uniquement sous forme ponctuee echappe a
#: ``delivering_lanes`` et son dossier d'auto-attestation passe le gate.
_DELIVERED_LANE_RE = re.compile(
r"\[DELIVERED\][^\n]*?\blane\s+([A-Za-z0-9_.-]+:[A-Za-z0-9_.-]+)"
r"\[DELIVERED\][^\n]*?\blane\s+(" + LANE_TOKEN + r")"
)

#: Un item d'acceptance : ``<critere> -> <preuve>``.
Expand Down
13 changes: 10 additions & 3 deletions scripts/check_unaddressed_nits.py
Original file line number Diff line number Diff line change
Expand Up @@ -4392,12 +4392,19 @@ def _names_author(body: str, author: str) -> bool:
# lift est signe par la lane de la PR SI ET SEULEMENT SI l'extraction lit
# la meme chaine canonique dans les deux sources (le format `CoursIA` vs
# `CoursIA-2` discriminne -- la lane ne peut signer QUE la sienne).
# #15864 (mesure #14549) : un point final de phrase ne peut plus terminer le
# token de lane -- `lane myia-po-2023:CoursIA-2.` etait capture comme une lane
# qui ne matche rien. Les points internes survivent (hostnames). Le meme
# fragment vit dans check_adjoint_prevalidation.LANE_TOKEN ; copie locale pour
# ne pas coupler le gate B.0 au gate d'adjoint. Voie (a) ci-dessous hors
# perimetre : sa lane est delimitee par des crochets, pas suivie de prose.
_LANE_TOKEN = r"[A-Za-z0-9_.-]*[A-Za-z0-9_-]:[A-Za-z0-9_.-]*[A-Za-z0-9_-]"
_PR_LANE_FROM_BODY_RE = re.compile(
# `Grain: ... -- lane <machine>:<workspace>` (corps PR) ; on capture
# la lane canonique ; un prefixe optionnel avant n'est pas admis (la
# balise est en tete de ligne apres decoration markdown).
r"(?m)^[#>*+\-\s]*Grain:[^\n]*?\blane\s+"
r"([A-Za-z0-9_.-]+:[A-Za-z0-9_.-]+)")
r"(" + _LANE_TOKEN + r")")
_LIFT_LANE_SIGNATURE_RE = re.compile(
# Voie (a) -- `[machine:workspace]` en tete de paragraphe.
r"(?m)^[#>*+\-\s]*\[\s*([A-Za-z][\w.\-]*:[A-Za-z][\w.\-]*(?:\s+[^\]]+)?)\]"
Expand All @@ -4407,8 +4414,8 @@ def _names_author(body: str, author: str) -> bool:
# commentaire. Deux formes observees : `-- lane myia-po-XXXX:...`
# (declaration finale separee par `--`) et `lane myia-po-XXXX:...
# -- ...` (dans la meme ligne que le commentaire precedent).
r"(?m)(?:^|\s)--\s*lane\s+([A-Za-z0-9_.-]+:[A-Za-z0-9_.-]+)\s*$"
r"|^lane\s+([A-Za-z0-9_.-]+:[A-Za-z0-9_.-]+)(?:\s*--|\s*$)")
r"(?m)(?:^|\s)--\s*lane\s+(" + _LANE_TOKEN + r")\.?\s*$"
r"|^lane\s+(" + _LANE_TOKEN + r")\.?(?:\s*--|\s*$)")


def _lift_signed_by_pr_lane(lift_body: str, pr_body: str) -> bool:
Expand Down
16 changes: 16 additions & 0 deletions scripts/tests/test_check_adjoint_prevalidation.py
Original file line number Diff line number Diff line change
Expand Up @@ -2941,3 +2941,19 @@ def test_review_threads_single_pr_is_still_one_operation(monkeypatch):

assert len(calls) == 1
assert [t["id"] for t in threads] == ["t9-1"]


def test_grain_lane_re_refuse_le_point_final_de_phrase():
"""#15864 (mesure #14549) -- la classe de token admet le point (hostnames),
donc `lane myia-po-2023:CoursIA-2.` etait capture comme une lane fantome.
Un token ne peut plus se TERMINER par un point ; les points internes
survivent."""
dotted = "Grain: DEEP/genai — lane myia-po-2023:CoursIA-2. Enonce reecrit."
assert mod.GRAIN_LANE_RE.findall(dotted) == ["myia-po-2023:CoursIA-2"]
clean = "Grain: DEEP/genai — lane myia-po-2023:CoursIA-2"
assert mod.GRAIN_LANE_RE.findall(clean) == ["myia-po-2023:CoursIA-2"]
host = "Grain: MED/docs — lane foo.bar.baz:CoursIA-2."
assert mod.GRAIN_LANE_RE.findall(host) == ["foo.bar.baz:CoursIA-2"]
# Aucune lane ne se reduit a un point : machine et workspace requis.
assert mod.GRAIN_LANE_RE.findall("Grain: MED/docs — lane :CoursIA-2") == []
assert mod.GRAIN_LANE_RE.findall("Grain: MED/docs — lane myia-po-2023:") == []
20 changes: 20 additions & 0 deletions scripts/tests/test_check_closure_dossier.py
Original file line number Diff line number Diff line change
Expand Up @@ -697,3 +697,23 @@ def fake_gh_json(args):
out = _merged_referring_prs("o/r", 15578)
assert out == []



def test_delivering_lanes_refuse_le_point_final_de_phrase():
"""#15864 (mesure #14549, 2026-10-09) -- un marqueur ponctue doit reduire a
la lane REELLE : sinon une lane nommee uniquement sous forme ponctuee est
absente de l'ensemble d'exclusion et son dossier d'auto-attestation passe
le gate. Instance mesuree : `myia-po-2023:CoursIA-2.` dans delivering_lanes."""
snap = _snapshot(
comments=[_comment("[DELIVERED] lane myia-po-2023:CoursIA-2. "
"Tranche livree, voir PR.")],
merged_prs=[
{"number": 17901, "merged_at": "2026-09-19T10:00:00Z",
"body": "Grain: DEEP/notebook-python — lane myia-po-2024:CoursIA. "
"-- See #17900."},
],
)
lanes = ccd.delivering_lanes(snap)
assert "myia-po-2023:CoursIA-2" in lanes
assert "myia-po-2024:CoursIA" in lanes
assert not any(ln.endswith(".") for ln in lanes), sorted(lanes)
21 changes: 21 additions & 0 deletions scripts/tests/test_check_unaddressed_nits_18149.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,3 +181,24 @@ def test_18149_garde_unitaire_voxel_marker_lane():
# PR sans tag `Grain:`
assert mod._lift_signed_by_pr_lane(
lift_body, "SYNTHESE sans tag Grain.") is False


def test_18149_point_final_de_phrase_ne_forme_pas_la_lane():
"""#15864 (mesure #14549) -- un pied de signature ponctue reste la lane
qui signe : `-- lane myia-po-2024:CoursIA.` doit etre lu comme
`myia-po-2024:CoursIA`, pas comme une lane qui ne matche rien."""
pr_body = "Grain: MED/notebook-python -- lane myia-po-2024:CoursIA"
# Voie (b), forme `-- lane X.` : le point final est de la prose.
lift_footer = "Leve au commit abc123. -- lane myia-po-2024:CoursIA."
assert mod._lift_signed_by_pr_lane(lift_footer, pr_body) is True
# Voie (b), forme `lane X. -- ...` dans la meme ligne.
lift_inline = "lane myia-po-2024:CoursIA. -- Leve au commit abc123."
assert mod._lift_signed_by_pr_lane(lift_inline, pr_body) is True
# Le tag Grain du PR lui-meme ponctue : la lane carrier reste lisible.
pr_dotted = "Grain: MED/notebook-python -- lane myia-po-2024:CoursIA."
assert mod._PR_LANE_FROM_BODY_RE.search(pr_dotted).group(1) \
== "myia-po-2024:CoursIA"
# Un point INTERNE (hostname) survit : ce n'est pas de la prose.
pr_host = "Grain: MED/docs -- lane foo.bar:CoursIA-2"
assert mod._PR_LANE_FROM_BODY_RE.search(pr_host).group(1) \
== "foo.bar:CoursIA-2"
Loading