Fetching https://<site>/favicon.ico directly would resolve a DNS name - and open a connection - to EVERY domain kept in the vault. The list of sites where someone holds an account is precisely what this vault protects; handing it to the network for a sixteen-pixel drawing would be a poor trade. The relay sees only that someone is interested in one domain, which is why the call is asked for entry by entry and never happens on its own. Two tries: the full host, then the second-level domain - chat.qwen.ai has no icon at the relay, qwen.ai does. The type comes from the first bytes, never from the extension: the relay answers PNG under a .ico address. A dedicated patch rather than PatchEntryField, because icon_custom is a NUMBER in the snapshot and writing it as a string would give "0" - which the desktop reads with GetValue<Boolean> and would choke on. It is set to zero: the icon comes from an automatic lookup, not from a choice, and that flag is what stops the desktop from ever replacing a chosen icon during a refresh. Base64 without line breaks. Delphi's encoder wraps at 76 characters by default, a wrapped data: URI does not display, and that trap has already been paid once on the containers.
9.2 KiB
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<script>ne s'exécute pas. C'était le risque réel — le coffre contient du texte arbitraire et la page construit son HTML parinnerHTML. - La file de commandes du pont libère
sendingdans unfinally: une exception au retrait de l'iframe ne peut plus rendre l'interface muette. - Les états du
body(typing,selecting,searching,on-list,on-detail,is-busy) ne portent le nom d'aucun élément — le piège qui éteignait la page entière ne se répète nulle part.
Scénario d'essai
À dérouler dans l'ordre. Chaque étape dit ce qu'il faut voir, pas seulement ce qu'il faut faire : un test dont on ne sait pas ce qu'il doit produire ne prouve rien.
A. Enregistrement hors connexion — le plus important
- Coffre ouvert, couper les données (mode avion).
- Modifier un mot de passe → message « saved here, not published yet », et point orange sur le cadenas.
- Verrouiller → le point doit être sur le bouton Sync de l'accueil.
- Fermer complètement l'application (glisser depuis les récentes), rouvrir, ouvrir le coffre → le point doit être encore là. C'est l'étape qui éprouve la persistance du drapeau ; sans elle, le reste ne prouve rien.
- Rétablir le réseau, Sync → « Offline changes published », point éteint.
- Sur le poste, synchroniser → la modification doit y être.
B. La fusion, qui est le cœur du sujet
- Téléphone hors ligne, modifier l'entrée X.
- Sur le poste, modifier une autre entrée Y, synchroniser.
- Téléphone en ligne, Sync.
- Les deux modifications doivent survivre. Si une seule survit, c'est
l'arbitrage sur
updated_atqu'il faut regarder. - Variante avec un dossier créé hors connexion sur le téléphone : il doit apparaître dans la barre de dossiers après la fusion, et sur le poste après sa synchronisation. C'est le défaut n° 1 ci-dessus.
C. Notes multilignes
- + → Note → zone de texte pleine largeur, Site et Username disparus.
- Taper plusieurs lignes — la touche Entrée doit insérer un saut, pas replier le clavier.
- Enregistrer, rouvrir → les ruptures doivent être là en lecture.
- Basculer Login → Note après avoir tapé : la saisie doit survivre.
- Contre-épreuve : dans un champ d'une ligne (Name, code de déverrouillage), Entrée doit toujours replier le clavier.
D. Sélection et actions de liste
- Appui long → barre contextuelle, compteur.
- Deuxième ligne → compteur à 2.
- Dupliquer → deux copies, suffixées (copy).
- Supprimer → confirmation en deux temps, puis les lignes disparaissent.
- Touche retour pendant une sélection → elle s'annule sans verrouiller.
- Sur le poste, synchroniser → les suppressions doivent y être répercutées.
E. Le dépôt a bougé — témoin bleu
- Coffre ouvert sur le téléphone, le laisser ouvert.
- Sur le poste, modifier une entrée et synchroniser.
- Attendre — la vérification bat toutes les dix minutes. Le journal doit
dire
remote has moved - sync to bring it in, et un point bleu paraître sur Sync et sur le cadenas. - Rien ne doit changer à l'écran de soi-même. Si l'entrée qu'on regarde se met à jour toute seule, c'est que le sondage adopte au lieu de signaler.
- Sync → le point bleu s'éteint.
- Les deux ensemble : provoquer A puis E sans synchroniser → orange et bleu côte à côte. Ils demandent deux gestes différents ; les confondre dirait « quelque chose ne va pas » sans dire quoi.
F. Réglages
- Roue dentée dans la liste, ou Settings sur l'accueil → l'écran s'ouvre.
- Les trois champs du dépôt doivent porter les valeurs en place, pas du vide : ils ne sont qu'une vue des champs que Delphi connaît déjà.
- Modifier l'URL, revenir par la flèche, Sync → la nouvelle valeur sert. C'est la contre-épreuve du report à la fermeture : un réglage modifié puis refermé sans quitter le champ doit compter.
- Touche retour dans les réglages → elle referme sans verrouiller ni revenir à la liste.
- Poser un code depuis les réglages : taper, Set this code, puis ouvrir le coffre → « Unlock code changed ». Le sceau se pose toujours à l'ouverture, et nulle part ailleurs.
- Retirer le code : Remove the unlock code, deux appuis → « Unlock code removed ». Fermer l'application, rouvrir → le code n'est plus demandé.
- Contre-épreuve du retrait : verrouiller, puis essayer de retirer le code sans avoir ouvert le coffre → refus « Open the vault first ». C'est ce qui empêche quelqu'un tenant le téléphone déverrouillé de lever la protection sans la connaître.
G. Icônes
- Ouvrir une entrée dont le Site est une adresse —
git.ai-agents4you.com. - Trois points → Fetch icon → l'icône doit apparaître dans la liste.
- Une entrée dont le site n'est pas une adresse (Gitea, ou vide) → refus « no web address to look up ». Sans point dans le nom, il n'y a rien à demander au relais.
- Un domaine à trois niveaux (
chat.qwen.ai) doit retomber sur le second niveau : c'est le deuxième essai. - Remove icon → l'entrée reprend son initiale.
- Synchroniser depuis le poste : l'icône doit y arriver, et le poste ne doit pas la traiter comme une icône choisie — c'est le rôle du drapeau de provenance, mis à zéro par une recherche automatique.
H. Pièces jointes
- Ligne Attachment → flèche de téléchargement → le fichier apparaît dans Téléchargements sous son nom, accents et arabe compris.
I. Code de déverrouillage
- Poser un code, ouvrir le coffre, fermer, rouvrir → il est demandé.
- Code faux → « Wrong unlock code », et Open vault reste offert (le coffre n'est pas déclaré illisible).
- Changer le code : ancien dans le premier champ, nouveau dans le second, Open vault → « Unlock code changed ».
- Contre-épreuve : taper n'importe quoi dans le champ du code puis Sync → le code ne doit pas changer.
J. Empaquetage
build-apk.ps1 -Release -Keystore ... -Alias ...→ la sortie doit afficherSigner #1 certificate DN: CN=R Zakarya. Si elle afficheCN=Android Debug, la release ne vaut rien.- Elle ne s'installe pas d'elle-même, et c'est voulu.
Ce qui n'est toujours pas éprouvé
- Le chemin
-Releasedu script n'a jamais tourné. - §1 point 4 — l'invalidation de la clé par enrôlement d'une empreinte, désamorcée par le code de déverrouillage tant qu'un code est posé.
MergeSelfChecktourne au démarrage en débogage et écritmerge selfcheck: the four rules holddans le journal. Personne ne l'a encore lu.