From 92ceb1e8c990666cbfc37c6aa47ee29e9833398e Mon Sep 17 00:00:00 2001 From: r-zakarya <82443831+r-zakarya@users.noreply.github.com> Date: Sat, 22 Aug 2026 15:24:01 +0100 Subject: [PATCH] fix(android): the merge lost folders, and the pending dot was on one screen Two defects found by re-reading before adding more, along with a test plan. MergeSnapshots merged entries and tombstones but not folders. A folder created on the phone - offline, or just before another device published - vanished from the list while the entries kept its name: filed under a folder nothing displays, unfindable without knowing it. That is exactly what EnsureFolder was written against, come back through another door. The pending dot sat on the padlock, which only exists in the list. After locking one lands on the home screen - precisely where one decides to sync - and it said nothing there. It is on Sync as well now. TESTS.md records what the reading checked and what it left alone, with reasons for the two defects deliberately not fixed, and a scenario that says what each step must PRODUCE rather than only what to do. --- android-client/PMA.VaultPatch.pas | 19 +++- android-client/TESTS.md | 140 ++++++++++++++++++++++++++++++ android-client/web/app.html | 8 +- 3 files changed, 164 insertions(+), 3 deletions(-) create mode 100644 android-client/TESTS.md diff --git a/android-client/PMA.VaultPatch.pas b/android-client/PMA.VaultPatch.pas index c5bc99e..4016550 100644 --- a/android-client/PMA.VaultPatch.pas +++ b/android-client/PMA.VaultPatch.pas @@ -203,7 +203,8 @@ end; function MergeSnapshots(const ALocalJson, ARemoteJson: string): string; var LLocal, LMerged: TJSONObject; - LLocalEntries, LOutEntries, LLocalStones, LOutStones: TJSONArray; + LLocalEntries, LOutEntries, LLocalStones, LOutStones, + LLocalFolders: TJSONArray; LEntry, LOther: TJSONObject; I, J: Integer; LUuid, LMine, LTheirs, LKilled: string; @@ -223,6 +224,22 @@ begin LMerged.AddPair('tombstones', LOutStones); end; + // 0. LES DOSSIERS DU LOCAL REJOIGNENT CEUX DU DISTANT. + // + // Oubli trouve a la relecture : la fusion ne portait qu'entrees et + // pierres tombales. Un dossier cree ici - hors connexion, ou juste avant + // qu'un autre appareil publie - disparaissait donc de `folders`, tandis + // que les entrees gardaient son nom. Elles se retrouvaient rangees dans + // un dossier que rien n'affiche : introuvables sans le savoir. + // + // Additif, jamais destructif : on n'enleve pas un dossier du distant + // parce qu'il manque ici, c'est aussi la regle du poste. + if LLocal.TryGetValue('folders', LLocalFolders) then + for I := 0 to LLocalFolders.Count - 1 do + if LLocalFolders.Items[I] is TJSONObject then + EnsureFolder(LMerged, + (LLocalFolders.Items[I] as TJSONObject).GetValue('name', '')); + // 1. Les pierres tombales locales rejoignent celles du distant. Avant les // entrees : l'etape suivante s'en sert pour arbitrer. if LLocal.TryGetValue('tombstones', LLocalStones) then diff --git a/android-client/TESTS.md b/android-client/TESTS.md new file mode 100644 index 0000000..a8edda2 --- /dev/null +++ b/android-client/TESTS.md @@ -0,0 +1,140 @@ +# Client Android — relecture et scénario d'essai + +Relecture du 2026-08-22, avant d'ajouter la vérification de fond, les réglages +et les icônes. Le but n'était pas de tout relire mais de chercher là où cette +séance a montré que les défauts se logent : **les frontières entre fichiers, +les chemins d'erreur, et ce qui traverse les threads.** + +--- + +## Ce que la relecture a trouvé + +### 1. La fusion ne transportait pas les dossiers — CORRIGÉ + +`MergeSnapshots` fondait `entries` et `tombstones`, pas `folders`. Un dossier +créé sur le téléphone — hors connexion, ou juste avant qu'un autre appareil +publie — disparaissait donc de la liste, **tandis que les entrées gardaient son +nom**. Elles se retrouvaient rangées dans un dossier que rien n'affiche : +introuvables sans qu'on le sache. + +C'est exactement la panne contre laquelle `EnsureFolder` avait été écrit, et +elle est revenue par une autre porte. Le report est additif — on ne retire pas +un dossier du distant parce qu'il manque ici. + +### 2. Le témoin d'attente n'existait que sur la liste — CORRIGÉ + +Le point orange était posé sur le cadenas, qui n'existe que dans la liste. Or +après un verrouillage on atterrit sur l'accueil — précisément là où l'on décide +de synchroniser. Il est maintenant aussi sur *Sync*. + +### 3. Trois routines ne libèrent pas l'indicateur d'occupation dans un `finally` + +`SaveAttachment`, `RegisterLocal` et `LoginLocal` le font dans le chemin normal +**et** dans leur `except`, ce qui couvre tout ce qui descend d'`Exception`. Une +erreur d'un autre genre laisserait le voile en place. + +**Non corrigé, et assumé** : le minuteur de 25 s le lève de toute façon, et +c'est son rôle. Le signaler ici vaut mieux que d'ajouter trois `finally` qui +donneraient l'illusion d'une garantie que seul le minuteur apporte. + +### 4. `ParseJSONValue(...) as TJSONObject` fuit sur une entrée qui n'est pas un objet + +Le transtypage lève avant l'affectation, donc la valeur analysée n'est jamais +libérée. Dix-sept occurrences. **Non corrigé** : n'arrive que sur un conteneur +corrompu, où l'on a de plus gros ennuis, et le processus est de toute façon en +train d'échouer bruyamment. À traiter le jour où l'on touche à ces fonctions. + +### 5. Ce qui a été vérifié et va bien + +- **Échappement HTML** : `esc()` couvre nom, sous-titre, initiale, URI d'icône, + libellés, valeurs, noms de dossiers, options de liste. Une entrée nommée + `