Aller au contenu

Une fixture qui suppose la plateforme se refuse localement, pas le mardi suivant

StatutEn vigueur, 2026-09-07
ArticleA2 · Un garde est vu rouge sur sa propre mutation
Chantier#5433 (onze rouges de plateforme en août, quatre en six jours), lot #5437
Vérification probablescripts/adr/5437-fixture-suppose-la-plateforme.py

Contexte

L'ADR 3802 a établi qu'un comportement de plateforme se sonde, et que le test qui reste doit être éprouvable partout, donc passer par une couture. Son enforced_by ne nommait que suite-sous-windows-et-macos.yml.

Ce workflow détecte, et une fois par semaine. Entre deux mardis, une fixture non portable se fusionne sans que rien ne la voie. Quatre l'ont fait entre le 2026-08-31 et le 2026-09-06, après onze de même nature corrigées en août : la décision existait, elle était juste, et rien ne l'appliquait au moment où elle aurait servi.

Décision

Un appel POSIX qui peut jeter, dans l'arbre de test, déclare l'exigence qu'il porte. Un garde local le refuse à chaque demande, cliquet à zéro.

Cinq formes valent déclaration, et ce sont celles que le dépôt employait déjà :

Forme Ce qu'elle dit
@EnabledIf sur la méthode ou la classe la forme de #3778, visible dans le rapport
assumeTrue en tête de méthode la même exigence, moins visible
try / catch (UnsupportedOperationException) le code se replie, il n'éprouve rien de la plateforme
une aide dont tous les appelants du fichier déclarent la délégation que #3778 a voulue
un if dont la condition nomme le prédicat les deux branches sont éprouvées, l'une attendant le succès, l'autre le refus

La cinquième a été trouvée en clôturant, et par le garde lui-même : la passe 6 a écrit le banc qui manquait au prédicat, lequel appelle l'API dans les deux branches d'un if pour confronter ce que le prédicat annonce à ce que le système fait. Le garde a refusé son propre banc de clôture, à juste titre : il ne connaissait pas cette écriture. Seule la condition est lue, jamais le if entier, sinon n'importe quel if placé autour de l'appel vaudrait déclaration.

assumeTrue est accepté à côté de @EnabledIf, alors que #3778 préfère le second. Le mal que cette ADR nomme est celui d'un assumeTrue posé au milieu d'une méthode, qui emporte les assertions n'ayant rien de POSIX. En tête, il protège aussi bien. Refuser la forme ancienne ferait rougir ce garde sur des cas justes, pour une préférence de style qu'une autre décision porte déjà.

Pourquoi l'arbre syntaxique, et non un motif de ligne

Mesuré sur l'arbre du 2026-09-06 : un motif textuel retient sept fichiers, le garde en retient deux, et ce sont les deux qui étaient cassés. Cinq des sept sont légitimes. Un motif qui se trompe ainsi ne peut pas annoncer un zéro qui veuille dire quelque chose : le garde lit donc scripts/_commun/arbre.py.

Deux des faux positifs sont de plus des /// du JEP 467, et tree-sitter est le seul lecteur du dépôt qui les rende fidèlement : Spoon les classe en // et re-sérialise en // /, JavaParser ne les voit pas sous getJavadoc().

Ce qui n'a pas été écrit, et pourquoi

Le second motif du chantier, celui du modificateur clavier, n'existe pas. Sa population illégitime est vide : deux occurrences de KeyCode.CONTROL dans tout l'arbre de test, l'une dans une chaîne de caractères, l'autre juste puisque MainViewTest y est d'accord avec MainController, qui code CONTROL_DOWN en dur.

Un garde qui lirait des centaines de bancs pour rendre zéro sur une règle dont le seul cas réel doit être exempté ne pourrait jamais être vu rouge, et verifie_temoins_non_decoratifs.py le dirait décoratif. C'est la leçon de l'ADR 5398 : une règle sans population écrit ce qu'on imagine du problème, et rien ne dément l'imagination.

La portabilité du geste clavier reste donc tenue par une relecture, et le cas vérifiable est nommé ici plutôt qu'un principe : MainViewTest pousse ^F et a raison de le faire.

Conséquences

  • La question « ce système porte-t-il POSIX ? » a une seule écriture. Elle en avait cinq ; quatre sont absorbées dans fixture.SystemeDeFichiers. Une copie qui diverge de ses soeurs ne fait rougir personne.
  • Ce garde ne prouve pas qu'une déclaration est vraie. Un @EnabledIf nommant un prédicat qui rendrait toujours vrai passerait : il est suivi par son nom, pas par son corps. D'où verification: probable.
  • Une aide appelée depuis un autre fichier échappe. La délégation est suivie dans le fichier seulement, comme le garde 5278 le fait depuis #5353.

Alternatives écartées

  • Amender l'enforced_by de la 3802. Une ADR acceptée ne se réécrit pas ici : elle se complète.
  • Poser le cliquet au-dessus de zéro pour tolérer les deux assumeTrue. Ils sont justes, pas tolérés : un cliquet les aurait comptés comme une dette.