diff --git a/scripts/notebook_tools/check_output_failure_text.py b/scripts/notebook_tools/check_output_failure_text.py index 2fd52516f18..d73d48f9463 100644 --- a/scripts/notebook_tools/check_output_failure_text.py +++ b/scripts/notebook_tools/check_output_failure_text.py @@ -214,6 +214,39 @@ re.compile(r"workflow execution failed", re.IGNORECASE), re.compile(r"erreur generation image", re.IGNORECASE), re.compile(r"illustration indisponible", re.IGNORECASE), + # Bandeau de repli du carnet LTX-2 (02-5) -- meme famille ComfyUI que + # #21816, meme regime : DUR. La cellule attrape toute exception de + # soumission / polling / recuperation et imprime un bandeau en MAJUSCULES + # a la place de la sortie reelle (le MP4). Ce bandeau ne portait aucun + # marqueur reconnu par l'organe : une re-execution faite sur un poste + # sans le conteneur `comfyui-video` committerait le repli en silence et + # la CI resterait verte. + # + # Mesure (revue Hermes du 05/11 sur #24645) : le mutant du head -- sorties + # reelles remplacees par ce bandeau -- rend `TOOL_FAILURE 0 -> 0`, + # `DECLARED_FALLBACK 0 -> 0`, `capability_downgrades: []`, + # `regressed: false`. Les cinq variantes d'exception realistes + # (URLError / connection refused / TimeoutError / HTTPError 401 / timeout + # de polling / RuntimeError de validation de graphe) etaient toutes + # silencieuses : le motif doit porter sur le MARQUEUR, pas sur le type + # d'exception. + # + # Le motif est epingle au marqueur en MAJUSCULES, SANS IGNORECASE : c'est + # un marqueur machine, et la forme francaise accentuee + # (`generation non executee` dans une prose) ne doit pas le declencher. + # + # ECART ASSUME ET TRACE (#24780, critere 5) : la forme francaise GENERALE + # ` indisponible` n'est PAS couverte par ce motif. Mesure : le + # mot `indisponible` apparait dans 125 carnets du depot, dont des replis + # declares legitimes (`non configuree`, `non disponible`) qui ne doivent + # pas devenir du bruit -- la rendre bloquante transformerait une + # famille de replis assumes en rouge de flotte. Le motif couvre donc la + # forme BANNERE (marqueur en majuscules, une par cellule), pas la forme + # MOT (n'importe quelle prose ou sortie qui cite un service indisponible). + # La forme a couvrir est tracee et assumee ici ; la voie complementaire -- + # un jeton porte par le carnet lui-meme -- est suivie cote carnet dans + # #24786. + re.compile(r"GENERATION NON EXECUTEE"), ) # Witnesses: real strings observed in committed outputs. The self-test asserts @@ -238,6 +271,13 @@ "ERROR:BarbieVsAne:Erreur generation image: Workflow execution failed " "(server reported error)", "WARNING:BarbieVsAne:Illustration indisponible pour cette replique", + # #24490 : le bandeau de repli du carnet LTX-2 (02-5), tel que la cellule + # l'imprime -- prefixe en majuscules + type d'exception. La chaine vient + # de la SOURCE de la branche de la PR (le `print` de la cellule), pas + # d'une sortie commitee : c'est la seule surface ou elle apparait, et + # c'est celle qu'une re-execution ratée produirait. + "GENERATION NON EXECUTEE - stack ComfyUI indisponible " + "(URLError : )", ) # --- benign banners: matched above, and NOT a tool failure ----------------- @@ -1089,6 +1129,33 @@ def _one(text): return scan({"cells": [{"cell_type": "code", "outputs": [ {"output_type": "stream", "text": text}]}]})["TOOL_FAILURE"] + # #24490 : le bandeau de repli LTX-2 doit etre classe TOOL_FAILURE (dur). + # Sans ce cas, un motif ajoute sans temoin fait mentir le jeu de motifs. + _ltx_banner_out = ("GENERATION NON EXECUTEE - stack ComfyUI indisponible " + "(URLError : )\n") + _ltx_banner = scan({"cells": [{"cell_type": "code", + "source": "print(f\"GENERATION NON EXECUTEE - " + "stack ComfyUI indisponible ({e})\")\n", + "outputs": [{"output_type": "stream", + "name": "stdout", + "text": _ltx_banner_out}]}], + "metadata": {}, "nbformat": 4, "nbformat_minor": 5}) + if not _ltx_banner.get("TOOL_FAILURE"): + failures.append("bandeau de repli LTX-2 non classe TOOL_FAILURE : " + + repr(_ltx_banner)) + # La forme francaise, elle, ne declenche pas : c'est un marqueur machine + # en majuscules, pas une formule de prose. + _ltx_prose = scan({"cells": [{"cell_type": "code", + "source": "print('ok')\n", + "outputs": [{"output_type": "stream", + "name": "stdout", + "text": "La generation n'a pas ete " + "executee sur ce poste.\n"}]}], + "metadata": {}, "nbformat": 4, "nbformat_minor": 5}) + if _ltx_prose.get("TOOL_FAILURE"): + failures.append("prose francaise classee TOOL_FAILURE : " + + repr(_ltx_prose)) + if _one(_banner): failures.append("benign transformers fast-path banner still fires") if not _one(_banner + "\nbash: dot: command not found"): diff --git a/scripts/notebook_tools/tests/test_check_output_failure_text.py b/scripts/notebook_tools/tests/test_check_output_failure_text.py index 388bad8a0b9..9bf5c83c94c 100644 --- a/scripts/notebook_tools/tests/test_check_output_failure_text.py +++ b/scripts/notebook_tools/tests/test_check_output_failure_text.py @@ -1013,3 +1013,32 @@ def test_21816_declared_interactive_fallback_stays_out(): got = scan(nb(cell(src, out))) assert got["TOOL_FAILURE"] == [], out assert len(got["DECLARED_FALLBACK"]) == 1, out + + +def test_24490_comfyui_replacement_banner_is_tool_failure(): + """#24490 : le bandeau de repli LTX-2 (02-5) doit etre classe TOOL_FAILURE. + + Mesure de la revue Hermes du 05/11 sur #24645 : le bandeau ne matchait + AUCUN motif de l'organe. Le mutant (sorties reelles remplacees par le + bandeau) rendait `TOOL_FAILURE 0 -> 0`, `DECLARED_FALLBACK 0 -> 0`, + `regressed: false` -- une re-execution sur un poste sans le conteneur + `comfyui-video` aurait commute son repli en silence, la CI serait + restee verte. Le motif porte sur le MARQUEUR en majuscules, pas sur le + type d'exception (les cinq variantes reelles etaient silencieuses). + """ + src = ("print(f\"GENERATION NON EXECUTEE - stack ComfyUI indisponible " + "({e})\")\n") + out = ("GENERATION NON EXECUTEE - stack ComfyUI indisponible " + "(URLError : )\n") + got = scan(nb(cell(src, out))) + assert got["TOOL_FAILURE"], got + assert any("GENERATION NON EXECUTEE" in hit for _, hit in got["TOOL_FAILURE"]) + assert not got["DECLARED_FALLBACK"], got + + +def test_24490_french_sentence_stays_silent(): + # Controle negatif : la forme francaise d'un carnet n'est pas un bandeau + # machine -- le motif est epingle sur le marqueur en majuscules. + out = "La generation n'a pas ete executee sur ce poste.\n" + got = scan(nb(cell("print('ok')\n", out))) + assert got["TOOL_FAILURE"] == [], out