PWA iOS : Sauvegarde de la modification bloquée sur « Enregistrement », éditeur inaccessible et texte dicté perdu

J’ai rencontré un problème intermittent lors de la modification d’un message existant sur mon instance Discourse auto-hébergée le 21 octobre 2026. Le composeur est resté bloqué dans son état Enregistrement, et je n’ai pas pu revenir à l’éditeur pour récupérer du texte dicté.

J’ai depuis examiné les journaux d’accès Caddy et nginx ainsi que l’historique des révisions de messages de Discourse.

Environnement

  • Client : iPhone 16 Pro, PWA Safari écran d’accueil

  • iOS : 27.0.1

  • Discourse : 2026.10.0-latest +406 commits, comme indiqué dans le tableau de bord administrateur plus tard ce jour-là (162 mises à jour disponibles)

  • Hébergement : auto-hébergé, archive privée d’études

  • Proxy inverse : Caddy v2.11.4, fournissant HTTP/3 via QUIC

  • Backend : nginx Discourse derrière Caddy utilisant une socket Unix

  • Réseau : Wi-Fi universitaire initialement, suivi par le réseau cellulaire EE

Ce qui s’est passé

J’étais en train de modifier un message contenant une image d’une diapositive de cours de physique.

J’ai dicté des notes mathématiques supplémentaires, y compris des fractions, sous l’image, puis j’ai rapidement appuyé sur Enregistrer la modification.

La barre horizontale bleue Enregistrement est restée visible en bas de l’écran et ne s’est pas terminée.

J’ai essayé de toucher la barre Enregistrement, mais cela n’a pas rouvert le composeur. En conséquence, je n’ai pas pu sélectionner ou copier le texte non enregistré ailleurs.

J’ai attendu plus longtemps que d’habitude.

Ce n’est qu’après que l’opération d’enregistrement était déjà bloquée que j’ai manuellement désactivé le Wi-Fi, espérant que le passage au réseau cellulaire permettrait à la requête de se terminer.

L’interface ne s’est pas immédiatement récupérée. J’ai également subi des ralentissements (buffering) en essayant de naviguer en utilisant le logo du site.

Lorsque j’ai pu à nouveau modifier le message, les fractions dictées étaient manquantes.

Investigation côté serveur

L’heure pertinente était approximativement 12:20 BST le 21 octobre 2026.

Mes journaux Caddy montrent :

Heure (BST) Requête Résultat
12:19:39 POST /drafts.json 200
12:19:40 POST /uploads.json 200
12:19:44 POST /drafts.json 200
12:20:08 PUT /posts/70695 Statut Caddy 0
12:20:55 PUT /posts/70695 200

Le PUT infructueux a utilisé HTTP/3. Caddy a enregistré une durée d’environ 110 ms, tandis que nginx a enregistré une réponse HTTP 400 sans exécution du contrôleur de mise à jour de message Discourse.

De nombreuses autres requêtes provenant de la connexion cellulaire ont également reçu le statut Caddy 0 approximativement au même moment.

Caddy lui-même n’a pas redémarré. Docker signale zéro redémarrage depuis le 15 octobre, et les journaux opérationnels ne contiennent aucun événement de rechargement ou d’arrêt correspondant.

Récupération du brouillon

Il y avait des requêtes de sauvegarde de brouillon réussies juste avant l’incident.

Cependant, je me souviens du contenu antérieur comme étant l’image de la diapositive sans le texte dicté supplémentaire. J’ai saisi les fractions ensuite et j’ai appuyé sur Enregistrer la modification peu après.

Par conséquent, je ne peux pas établir que la dictée manquante était incluse dans l’une des deux sauvegardes automatiques réussies.

Lorsque j’ai ensuite inspecté les révisions du message, la révision réussie à 12:20:55 contenait l’image mais pas les fractions dictées.

J’ai également vérifié les enregistrements de brouillons actuels, mais ni l’ancienne ni la nouvelle clé de brouillon de sujet n’avait de brouillon restant au moment de l’inspection.

Comportement attendu

Si une requête de modification devient bloquée ou est interrompue, je m’attendrais à ce que le composeur conserve son contenu non enregistré et fournisse un moyen de réessayer, d’annuler ou de revenir à la modification.

En particulier, l’interface devrait idéalement ne pas rendre le texte non enregistré inaccessible indéfiniment tout en affichant Enregistrement.

Comportement réel

Le composeur est resté inaccessible, toucher la barre Enregistrement ne l’a pas rouvert, et le texte dicté n’était plus disponible lorsque la modification a repris.

Questions

  1. Le composeur est-il censé rester inaccessible indéfiniment pendant qu’une requête de modification est en attente ?

  2. Y a-t-il un délai d’attente ou un mécanisme de récupération destiné à restaurer la modification lorsqu’une requête réseau est interrompue ?

  3. Une opération d’Enregistrer la modification interrompue doit-elle conserver le texte en mémoire ou le contenu du brouillon, même si la requête n’atteint jamais le contrôleur de mise à jour de message Rails ?

  4. Un enregistrement ou un instrument client spécifique serait-il utile si cela se produit à nouveau sur iOS ?

Je reconnais que le changement de réseau peut expliquer les annulations ultimes des requêtes. Cependant, l’interface Enregistrement était déjà devenue bloquée avant que je change manuellement de réseaux.

Je n’ai pas établi si le retard initial provenait du JavaScript de Discourse, du réseau iOS/WebKit ou de la connexion universitaire.

Discussions connexes

J’ai une discussion existante sur MPTCP / continuité de connexion iOS, où j’ai décrit cet même incident sous l’angle de la couche transport.

J’ai également signalé précédemment que des messages modifiés restent parfois obsolètes dans DiscourseHub sur iOS. Dans ce problème distinct, les modifications avaient réussi à atteindre le serveur, mais le message déjà rendu ne s’est pas mis à jour jusqu’à un rafraîchissement. Un autre utilisateur a rapporté avoir remarqué ce comportement aussi.

Je ne sais pas si les deux problèmes partagent une cause. L’incident actuel est différent car la requête initiale de modification du message n’a pas été traitée avec succès.

J’ai également trouvé deux rapports antérieurs impliquant un composeur bloqué dans Enregistrement :

Les deux avaient des causes identifiées différentes, et je ne suppose pas qu’ils expliquent cet incident.

J’ai joint un ZIP discourse_ios_save_evidence_2026-10-21_domain_redacted.zip (6,3 Ko) contenant des extraits diagnostiques Caddy/nginx sélectionnés et masqués, des informations de révision et la chronologie décrite ci-dessus.

J’apprécierais tout conseil sur la manière dont le composeur est censé se récupérer d’une requête en panne, en particulier lorsque des modifications non enregistrées ne peuvent pas être copiées avant une interruption réseau.

Mise à jour supplémentaire suite à certains problèmes de PWA sur iOS le 28 octobre 2026, désormais sur iOS 27.2 (iPhone 16 Pro).

Il ne s’agissait pas d’une reproduction exacte du problème initial de dictée perdue, mais j’ai consulté les journaux Caddy et nginx pour comprendre ce qui s’est passé.

10h58 GMT — Opération sur un sujet bloquée

En quittant la bibliothèque, une opération sur un sujet semblait se bloquer dans l’interface.

Caddy a enregistré deux requêtes HTTP/3 vers POST /t/13515/merge-topic :

  • 10:58:16 : statut 0, durée d’environ 0,15 ms.
  • 10:58:41 : HTTP 200, durée d’environ 595 ms.

La requête réussie apparaît également dans nginx sous la forme topics/merge_topic, HTTP 200.

Cela confirme qu’une requête ultérieure a été traitée avec succès, mais n’établit pas pourquoi la requête antérieure s’est terminée sans réponse complète.

12h26 GMT — Problèmes de chargement de la PWA

Pendant que j’étais dans une salle de cours, je n’ai pas pu charger la PWA normalement.

Caddy a enregistré quatre requêtes HTTP/3 pour le bundle JavaScript principal de Discourse, complétées entre 12:27:05 et 12:27:42.

Toutes ont renvoyé HTTP 200 et ont journalisé 627 219 octets de réponse, mais leurs durées étaient d’environ 31,4, 27,1, 29,4 et 17,3 secondes.

La même ressource se chargeait normalement en moins d’une seconde, tant avant qu’après cet intervalle.

12h42 GMT — Autre problème de chargement de la PWA

Une autre requête HTTP/3 pour le même bundle JavaScript a pris environ 24,3 secondes.

À 12:42:41, Caddy a également journalisé une réponse de proxy inversé HTTP/2 incomplète :

aborting with incomplete response
writing: write tcp ...: connection reset by peer

L’amont était le socket Unix existant vers nginx. L’erreur s’est produite pendant que Caddy écrivait vers la connexion TCP orientée client, plutôt que d’être un échec identifié du socket Unix.

Les journaux ne permettent pas d’établir si la réinitialisation a été initiée par iOS ou par l’infrastructure réseau entre le client et le VPS.

Je n’ai pas modifié manuellement les paramètres réseau de l’iPhone lors des deux incidents en salle de cours.

Pertinence par rapport au rapport initial

Je comprends que ces problèmes de chargement et d’opération sur les sujets puissent avoir une cause différente du problème initial de « Sauvegarder la modification ».

Cependant, ils démontrent que la PWA iOS a rencontré des retards de requête substantiels et une réponse interrompue dans des circonstances où je m’appuie dessus pour éditer mes notes.

Ma question principale reste de savoir si le composeur est censé conserver et rendre accessible le texte non sauvegardé lorsqu’une requête « Sauvegarder la modification » se bloque, au lieu de le laisser inaccessible derrière l’état « Enregistrement ».

Je vous serais reconnaissant de toute orientation concernant des diagnostics côté client utiles ou le comportement de récupération prévu du composeur.