- Symptôme rapporté : clic sur Home → rafale de menus/fenêtres + bande rouge
« You are offline. Changes will sync when connection is restored. ».
- Constat : le masquage de v7.45.3 ne couvrait QUE les swaps partiels fdLoad.
Un chargement COMPLET de document (F5, première visite, navigation servie par
le service worker) peignait toute l'app tant qu'Alpine n'avait pas initialisé
.app-layout : sidebar brute (sections ouvertes, menu utilisateur) + zone brute
dont la bande hors ligne (aucun x-cloak dessus). Le symptôme Home n'est par
ailleurs PAS rejouable en navigateur frais (nav, clic Home en ligne/hors
ligne, plein chargement → 0 frame de contenu brut, 0 erreur console).
- Fix : x-cloak sur le nœud racine Alpine .app-layout (base.html) — sidebar +
zone + bandeau masqués jusqu'au montage d'appState(), retrait par Alpine à
l'init. Le probe asserte que l'attribut est bien retiré et que le node est
visible en fin de parcours (garde-fou contre la page blanche).
- Suppression de la classe fd-navigating (posée à chaque fdLoad, aucune règle
CSS dans le dépôt → code mort).
- e2e/probe_nav_perf.spec.js : 4 scénarios avec assertions (nav 5 pages, clic
Home réel, Home hors ligne avec SW, plein chargement 3 pages) + capture
screenshot auto si contenu brut + collecte console.
Gates : probe_nav_perf 4/4 · regression_partial_nav + regression_editor_mount
+ regression_logout_dnd + smoke = 6 passed (errs=0 sur 7 pages × 3 passages) ·
pytest 1094 passed · ruff OK · OpenAPI 7.45.4.
- Symptôme : à chaque changement de page/section, une rafale de fenêtres /
menus / états s'affiche une fraction de seconde avant la page voulue.
- Cause : pendant la fenêtre x-ignore (swap fdLoad → Alpine.initTree, mise en
place en v7.45.2), .main-wrapper était peint NON montée : tous ses [x-show]
visibles à leur valeur brute, puis masqués d'un coup au montage. Mesure
(e2e/probe_nav_perf.spec.js sur l'instance locale) : 19 éléments bruts
visibles 87 ms sur /library (CLS 0.149, sources lib-loading/lib-empty/
lib-table), 80 éléments pendant 732 ms sur /settings, 7 sur /workspaces.
- Fix (app.js, handler htmx:afterSwap) : opacity:0 + pointer-events:none posés
dans la même task que le swap (aucun paint intermédiaire possible), retirés
APRÈS Alpine.initTree sur les 3 chemins de démontage (scripts chargés, zéro
script, filet 4 s). reveal() est appelé avant les early-returns de done() →
impossible de rester bloqué invisible.
- Après : 0 frame de contenu brut peint sur les 4 navigations du probe,
1–2 frames masquées, zone révélée (opacity:1, pointer-events:auto) et
montée (0 [x-show] non montés, x-ignore absent) à chaque fois.
- Gate : e2e/probe_nav_perf.spec.js — marques htmx, fenêtre x-ignore,
échantillon par frame des [x-show] bruts peints, layout-shift + assertion
(0 brut / zone révélée et montée), exécutable en CI.
- Reste (non traité, voir ROADMAP) : CLS résiduel 0.057 sur /library (états
loading → table), fenêtre x-ignore de ~250 ms sur /settings (coût des
scripts de page), topbar incluse dans .main-wrapper re-swappée à chaque nav.
Gates : probe_nav_perf + regression_partial_nav + regression_editor_mount +
regression_logout_dnd + smoke · pytest 1094 passed · ruff OK ·
OpenAPI 7.45.3.