From ba0cdea4428b21ed0ff131a1618b5585efcb5c4a Mon Sep 17 00:00:00 2001 From: Claude Sonnet 5 Date: Sun, 20 Sep 2026 23:46:38 +0200 Subject: [PATCH] fix(ci,#17065): dossier [ADJOINT PREFLIGHT] ouvrant = attestation entiere, queue narrative comprise MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _strip_adjoint_dossier (#16442) ne retirait que le bloc delimite ; la queue narrative qui suit [/ADJOINT PREFLIGHT] -- ignore expressement par le gate check_adjoint_prevalidation.py -- restait scannee par B.0. La phrase d'attestation obligatoire « Aucun merge, APPROVED ou CHANGES_REQUESTED effectue ici » etait comptee comme une reserve POSEE : le dossier portant b0: clear devenait son propre bloquant (#16862), et via la delegation du picker (4e cause de repair -> ce meme organe), la lane emettrice se verrouillait hors du tirage (8/8 lanes en repair, 313/390 issues admissibles, mesure ai-01 2026-09-20). Un commentaire qui OUVRE sur un bloc bien delimite est desormais un dossier dans son integralite : strip integral, la garde attestation-pure existante de classify rend None. Fail-closed inchange : bloc malforme -> rien retire ; prose precedent le bloc reste lue ; explicit_lifts utilise le meme strip (un dossier ne lève rien, queue comprise). CONCERN_MARKERS intact (critere 3), aucune heuristique de negation en prose (critere 4). Tests : 8 -> 12 (faux positifs #16862 inscrits + controles). Co-Authored-By: Claude Sonnet 5 --- scripts/check_unaddressed_nits.py | 28 ++++++- ..._check_unaddressed_nits_adjoint_dossier.py | 79 +++++++++++++++++++ 2 files changed, 106 insertions(+), 1 deletion(-) diff --git a/scripts/check_unaddressed_nits.py b/scripts/check_unaddressed_nits.py index 34c4002912..ba8a3b0246 100644 --- a/scripts/check_unaddressed_nits.py +++ b/scripts/check_unaddressed_nits.py @@ -3861,7 +3861,33 @@ def can_lift(comment: dict) -> bool: def _strip_adjoint_dossier(body: str) -> str: - """Retirer les spans d'attestation [ADJOINT PREFLIGHT] bien delimites.""" + """Retirer les spans d'attestation [ADJOINT PREFLIGHT] bien delimites. + + #17065 -- deux formes d'inertie, l'une ancienne, l'une nouvelle : + + 1. (depuis #16442) tout bloc bien delimite est retire du corps, ou qu'il + soit ; la prose autour reste lue. + 2. (nouveau) un commentaire qui OUVRE sur un bloc bien delimite est un + dossier DANS SON INTEGRALITE : la prose qui suit le marqueur fermant + est la NARRATIVE du dossier (verifications firsthand, disposition), + pas des remarques. Le gate `check_adjoint_prevalidation.py` lit le + bloc et ignore expressement cette queue (« Prose FOLLOWING the + closing marker is ignored, not refused ») : le dossier communique + par le gate, pas par les marqueurs B.0. Defaut mesure (#16862, + 2026-09-19) : la phrase d'attestation obligatoire « Aucun merge, + APPROVED ou CHANGES_REQUESTED effectue ici » de la queue narrative + etait comptee comme une reserve POSEE -- le dossier qui portait + `b0: clear` devenait son propre bloquant, et via la delegation du + picker (4e cause de repair -> ce meme organe), 8 lanes sur 8 se + retrouvaient en mode repair pendant que 313 issues sur 390 + restaient admissibles. + + Fail-closed inchange : un bloc MALFORME (ouvrant sans fermant) n'est pas + retire ni n'inertit rien ; la prose PRECEDANT le bloc (tete de pierre + tombale comprise) reste lue normalement. + """ + if _ADJOINT_DOSSIER_SPAN.match(body.lstrip("\r\n \t")): + return "" # dossier ouvrant : attestation entiere, queue comprise return _ADJOINT_DOSSIER_SPAN.sub("", body) diff --git a/scripts/tests/test_check_unaddressed_nits_adjoint_dossier.py b/scripts/tests/test_check_unaddressed_nits_adjoint_dossier.py index a2b8558188..d4200a2019 100644 --- a/scripts/tests/test_check_unaddressed_nits_adjoint_dossier.py +++ b/scripts/tests/test_check_unaddressed_nits_adjoint_dossier.py @@ -155,3 +155,82 @@ def test_strip_neutralise_le_span_et_garde_le_reste(): assert "verdict: BLOCKED" not in stripped assert "Avant le dossier." in stripped assert "Apres le dossier." in stripped + + +# --- #17065 : la QUEUE NARRATIVE du dossier n'est pas une reserve POSEE --- +# +# Defaut mesure (2026-09-19, #16862) : le strip #16442 ne retirait que le +# bloc delimite ; la queue narrative qui suit [/ADJOINT PREFLIGHT] -- que le +# gate ignore expressement (« Prose FOLLOWING the closing marker is ignored, +# not refused », check_adjoint_prevalidation.py) -- restait scannee par B.0. +# La phrase d'attestation OBLIGATOIRE « Aucun merge, APPROVED ou +# CHANGES_REQUESTED effectue ici » etait comptee comme une reserve posee : +# le dossier portant `b0: clear` devenait son propre bloquant, et via la +# delegation du picker (4e cause de repair -> cet organe), 8 lanes sur 8 en +# mode repair pendant que 313 issues sur 390 restaient admissibles. +# +# Forme reelle reconstruite du dossier #16862 (issuecomment 5745712744) : +# bloc schema v1 READY + queue de verifications firsthand + disposition. + +DOSSIER_16862_AVEC_QUEUE = """[ADJOINT PREFLIGHT] +schema: 1 +lane: myia-po-2027:CoursIA +pr: 16862 +head: 0ee7c042750692c9015f6ae00fea30379fa665a1 +complete: true +body: read +comments-reviewed: 4 +reviews-reviewed: 0 +threads-reviewed: 0 +threads-unresolved: 0 +surfaces-sha256: aadc60f68502db3e049fa3b46ab3d456836cab1bb9f2c1db0a4dff8359c9ff61 +diff-files: 1 +diff-additions: 140 +diff-deletions: 140 +checks: latest-wins-green +b0: clear +scope: pass +domain: pass +verdict: READY +[/ADJOINT PREFLIGHT] + +Dossier de prevalidation tierce (gate #16907, Phase 4) — premier dossier sur cette PR. + +### Verifications firsthand au head exact 0ee7c04275 + +- **B.0** : rc=0 ; 4 commentaires lus, 0 review, 0 thread inline. + +**Disposition : READY pour lecture finale ai-01.** Aucun merge, APPROVED ou CHANGES_REQUESTED effectue ici. +""" + + +def test_dossier_ouvrant_queue_narrative_nest_pas_un_nit(): + # Echoue sur le code d'avant #17065 : la queue portait la phrase + # d'attestation dont « CHANGES_REQUESTED » etait vivant. + assert mod.classify("jsboige", DOSSIER_16862_AVEC_QUEUE) is None + + +def test_dossier_ouvrant_nest_pas_une_levee_queue_comprise(): + # La queue ne leve rien non plus (symetrie attestation, #16443) : un + # dossier dont la queue RACONTE une disposition ne compte pas comme + # evenement de levee. + queue_levee = DOSSIER_16862_AVEC_QUEUE.replace( + "**Disposition : READY pour lecture finale ai-01.**", + "La reserve Hermes est levee par reponse ecrite a 22:10Z. **Disposition : READY.**", + ) + stripped = mod._strip_adjoint_dossier(queue_levee) + assert stripped == "" + assert mod.has_live_lift(stripped) is False + + +def test_reserve_avant_le_dossier_ouvrant_reste_vivante(): + # Une vraie remarque PRECEDANT le bloc ouvrant reste lue normalement : + # l'inertie ne s'etend qu'a la queue, jamais a la tete. + prose = "Le fil inline #2 reste a nuancer sur la formulation exacte." + assert mod.classify("jsboige", prose + "\n\n" + DOSSIER_16862_AVEC_QUEUE) is not None + + +def test_vraie_reserve_hors_dossier_reste_vivante(): + # Controle positif du contexte (pas de la liste) : une review qui POSE + # un CHANGES_REQUESTED en dehors de tout dossier reste BOT-CONCERN. + assert mod.classify("jsboige", "CHANGES_REQUESTED : decide casse en identifiant Lean, cellule 12.") is not None