2 Commits

Author SHA1 Message Date
Patrick Schurig
e76d01160d fix(brouillon): « j'ai décidé de ne rien changer » est un état, et il se conclut
Le geste sans repli de cet écran — déplacer une plage — puis le geste inverse
laissaient un brouillon qui rend exactement la configuration de la box. L'écran
le traitait comme n'importe quel brouillon, et n'offrait plus pour en sortir que
des portes mal nommées. Quatre messages, tous faux au même instant :

  la barre                 « Modifications en attente »
  la sortie d'écran        « vos changements n'ont pas été envoyés »
  adopter un rang          « enregistrez ou annulez vos modifications »
  retirer une charge       idem

Il n'y avait plus rien à enregistrer, ni rien à perdre.

`draftIsNoOp` nomme l'état : un brouillon dont les charges utiles brutes, clés
triées, sont identiques à celles de la box — ce qui couvre l'ordre ET un patch
de champ. `hasSubstantiveChanges` garde désormais les trois portes ; la barre,
elle, continue de s'afficher, parce que c'est là qu'est la sortie.

Elle dit maintenant « L'ordre est revenu à celui de la box — il n'y a rien à
enregistrer » et n'offre qu'un geste, « Terminer ». Pas « Enregistrer » :
réécrire tout l'ensemble pour n'y rien changer reconstruirait les charges et
réarmerait les verrous, au prix de zéro.

⚠️ Le remède n'est PAS d'effacer le brouillon dès qu'il devient sans effet : la
barre disparaîtrait sous le doigt à l'instant où l'utilisateur repose la plage,
et « j'ai décidé » redeviendrait « il ne s'est rien passé ». Un état se conclut,
il ne s'évapore pas. Un test le fige.

Et la note sur le glissement est REPRISE. J'y affirmais un défaut ; le test au
doigt montre que le réordonnancement fonctionne, liste dépliée comprise. Le
mécanisme du shrinkWrap reste écrit — il est probablement juste — mais comme une
LIMITE CONNUE non reproduite, avec le protocole en trois gestes (A témoin,
B discriminant, C cause), le contournement (replier les blocs) et le remède
nommé. On ne réécrit pas un écran qui marche sur la foi d'une lecture de code.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKM8FDNHZWogAsjjfB8pSw
2026-09-08 07:30:12 +02:00
Patrick Schurig
438f261de7 feat(config): quitter avec un brouillon demande, et « Placer en dernier » rejoint « Renommer »
Deux retours d'usage, tous deux sur la même carte.

1. « Placer en dernier » poussait « Configurer » hors de sa place. Il rejoint « Renommer »
   sur une ligne à part : ce sont les deux gestes qui ne touchent pas au mécanisme, et un
   bouton d'action principale ne se fait pas déplacer par un geste secondaire.

2. Quitter l'écran avec des modifications non enregistrées ne demandait rien — et ce
   silence cachait pire qu'une perte : le brouillon vit dans LoadConfigProvider, pas dans
   l'écran, donc il SURVIT à la navigation. On repartait en laissant une configuration
   modifiée invisible, qui réapparaissait au retour sans contexte, ou disparaissait à la
   première relecture de la box (LoadConfigChanged, reconnexion) sans que personne ait
   choisi. Les deux issues sont mauvaises pour la même raison : l'utilisateur ne sait pas
   ce qu'il laisse derrière lui.

GardeBrouillon (PopScope) s'interpose sur les DEUX écrans qui partagent ce brouillon — la
liste des charges et l'écran de mécanisme. L'alerte dit l'état de la BOX, pas seulement
celui de l'écran : « vos changements n'ont pas été envoyés, elle porte toujours la
configuration d'avant ». Deux issues, toutes deux explicites : rester, ou quitter en
abandonnant — un brouillon fantôme qui ressort trois écrans plus loin est pire qu'une
modification perdue qu'on a accepté de perdre.

Aucune écriture n'est proposée depuis la boîte de dialogue : enregistrer depuis une sortie
ferait partir une configuration que personne n'a relue.

Quatre tests, dont le contrôle négatif — sans brouillon, on sort sans être interrogé. Une
alerte qui se déclenche pour rien apprend à passer outre sans lire.

235 tests (+4), flutter analyze inchangé à 27 remarques.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SQbZKrWqsMFP1Lh2jjjd9f
2026-08-29 12:02:04 +02:00