docs(ordre): pourquoi le glissement ne peut pas défiler — établi par construction

Le moteur soupçonnait un ReorderableListView en conflit avec un défilement
parent. C'est exact, et le mécanisme se lit dans le code sans avoir à toucher
l'écran :

  roles_devices_screen.dart:113   body: ListView(...)        <- le parent défile
  controllable_loads_section:104  ReorderableListView.builder(
                                    shrinkWrap: true,
                                    physics: NeverScrollableScrollPhysics())

En `shrinkWrap`, le viewport de la liste vaut la hauteur de son contenu : son
`maxScrollExtent` est NUL. Or l'auto-défilement du glisser-déposer agit sur le
Scrollable de la liste réordonnable, jamais sur un parent. Il n'a donc nulle
part où aller, et le ListView extérieur n'est pas prévenu.

Conséquence : on ne réordonne que ce qui tient à l'écran en même temps. Un bloc
de domaine déplié fait plus d'un écran, donc le geste qui compte — remonter un
domaine par-dessus un autre — est justement celui qui ne peut pas aboutir.
Replier les blocs le rend possible : contournement immédiat, et contrôle qui
prouve le diagnostic.

Remède structurel : un seul Scrollable, CustomScrollView + SliverReorderableList
— le montage déjà en place dans favorites_screen.dart. PAS fait tant que le
geste n'est pas éprouvé au doigt : l'entrée synthétique ne reproduit pas un
appui-glissé, donc aucun test de ce dépôt ne peut montrer ce défaut ni prouver
sa correction.

Et une piste abandonnée plutôt que remontée : j'ai soupçonné les écritures de
l'app d'effacer `rankOrigin`. Faux — l'aller-retour est verbatim sur les charges
utiles brutes (LIRE -> PATCHER -> RÉÉCRIRE), rien n'est reconstruit depuis le
modèle typé.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GKM8FDNHZWogAsjjfB8pSw
This commit is contained in:
Patrick Schurig 2026-09-08 07:05:56 +02:00
parent 0df80b5b9b
commit dfa327cbcd

View File

@ -101,6 +101,28 @@ class _ControllableLoadsSectionState extends State<ControllableLoadsSection> {
// domaine porte UNE charge, et l'ordre de service se règle donc entre domaines.
// C'est là que la prise doit être. Réordonner deux charges d'un même domaine reste
// possible, par les flèches de leur carte.
//
// ⚠️ **MAIS ce montage ne peut pas défiler pendant un glissement**, et c'est un
// défaut ouvert, pas un choix. Établi par construction le 2026-09-08 :
//
// `roles_devices_screen.dart:113` est un `ListView` — le parent défile. Cette
// liste-ci est en `shrinkWrap: true`, donc son viewport vaut exactement la hauteur
// de son contenu et son `maxScrollExtent` est **nul**. Or l'auto-défilement du
// glisser-déposer agit sur le `Scrollable` de la liste RÉORDONNABLE, jamais sur un
// parent : il n'a donc nulle part où aller, et le `ListView` extérieur n'est même
// pas prévenu.
//
// Conséquence : on ne peut réordonner que ce qui tient à l'écran **en même temps**.
// Or un bloc de domaine déplié fait plus d'un écran à lui seul, donc le geste qui
// compte — remonter un domaine par-dessus un autre — est précisément celui qui ne
// peut pas aboutir. Replier les blocs le rend possible : c'est un contournement,
// et c'est aussi le contrôle qui prouve le diagnostic.
//
// Le remède est structurel : UN seul `Scrollable` sur l'écran, en `CustomScrollView`
// + `SliverReorderableList` — le montage déjà utilisé dans `favorites_screen.dart`.
// Pas fait ici tant que le geste n'a pas été éprouvé au doigt : l'entrée synthétique
// ne reproduit pas un appui-glissé (cf. `tools/rpc/README.md`), donc aucun test de
// ce dépôt ne peut ni montrer le défaut ni prouver sa correction.
ReorderableListView.builder(
shrinkWrap: true,
primary: false,