AUTOLOCK_MINUTES = 3 verrouille apres trois minutes d'inactivite, tandis que PROBE_EVERY_TICKS = 40 - quinze secondes le battement - demande dix minutes de coffre OUVERT. Le compteur n'avance que tant qu'il l'est, et LockVault sort avant de l'incrementer. "Laisser ouvert dix minutes sans y toucher" verrouillait donc a la troisieme, et le sondage ne partait jamais. Ce n'est pas un defaut : le temoin sert pendant qu'on se sert du coffre, et qui s'en sert le touche. Mais sans le dire, on cherche un point qui ne peut pas paraitre. La serie demande maintenant de toucher toutes les deux minutes, et offre la contre-epreuve courte - PROBE_EVERY_TICKS a 8 le temps d'un essai. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
17 KiB
Client Android — relecture et scénario d'essai
Réécrit le 2026-08-28, après une séance qui a remué les deux secrets du coffre, l'écran des réglages, le code de déverrouillage et le clavier. La version précédente décrivait une application qui n'existe plus.
Ce que cette séance a confirmé, et qui vaut plus que n'importe quelle liste : les défauts se tiennent par la main. Corriger le clavier qui volait le premier appui a laissé le clavier ouvert ; le clavier ouvert recouvrait le message ; et le message invisible cachait qu'une action avait réussi. Aucun des deux derniers n'était observable tant que le premier tenait. D'où la règle qui suit : quand un essai échoue, lire le journal AVANT de retenter, parce que la synchronisation le vide.
Ce que la séance a corrigé, et pourquoi c'est éprouvable
1. Le journal ne perdait plus les causes — CORRIGÉ, et c'est le plus important
Trois trous, tous du même genre : une faute arrivait, et rien ne la nommait.
- Les gestionnaires d'erreur lisaient l'exception après sa libération.
RegisterLocaletLoginLocalmettaient leur handler en file avecTThread.Queue, puis y lisaientE.Message— or Delphi libèreEen sortant duexcept, bien avant que la file s'exécute. Résultat : un message vide, et parfois une violation d'accès. Le vrai motif n'a jamais été affiché de toute l'histoire de ce chemin. - Le dispatch du pont n'était gardé par rien : une faute dans un handler remontait à FMX, qui affichait « Access violation » avec une adresse pendant que le journal montrait la commande reçue suivie de rien.
- Le retour sur le thread principal (
TThread.Queue) n'était couvert ni par leexceptdu thread, ni par celui du pont : il s'exécute après que les deux ont rendu la main.
Ce que ça change pour les essais : un échec porte désormais un nom. Si un essai ci-dessous échoue sans laisser de ligne au journal, c'est un quatrième trou du même genre, et il faut le traiter avant de chercher le défaut.
2. Deux secrets, longtemps confondus — CORRIGÉ
Le mot de passe de création scellait le conteneur local et prétendait sceller l'instantané du dépôt. Un coffre créé ici publiait donc sous son propre mot de passe, que le poste ne savait plus ouvrir.
FVaultPwdouvrevault-local.json, et rien d'autre.- Le secret du dépôt vit dans les réglages, doit être identique sur tous les appareils, et lui seul ouvre et rescelle l'instantané.
- Ils ne se rencontrent qu'à un endroit, la réconciliation : le conteneur local s'ouvre sous le sien, puis la clé est jetée avant qu'on touche au dépôt.
Migration : rien à rechiffrer. Les coffres existants ont simplement les deux valeurs égales, et cessent d'être forcés de le rester.
3. « Coffre ouvert » se lisait sur le nombre d'entrées — CORRIGÉ
Un coffre vide en compte zéro, comme un coffre fermé. Le garde de DoSync
restait donc vrai après l'ouverture, réarmait la reprise, et l'on tournait en
rond. Le même idiome coupait OnIdleTimer : un coffre vide ne s'auto-verrouillait
jamais. Les trois lisent FPlain, le clair en main.
4. Ce qui reste assumé, sans correction
SaveAttachment,RegisterLocaletLoginLocallibèrent l'indicateur d'occupation dans leurexceptplutôt que dans unfinally. Le minuteur de 25 s le lève de toute façon, et c'est son rôle.ParseJSONValue(...) as TJSONObjectfuit sur une entrée qui n'est pas un objet — le transtypage lève avant l'affectation. N'arrive que sur un conteneur corrompu, où l'on a de plus gros ennuis.- Le nom d'utilisateur ne sert à rien dans l'APK. Il est écrit dans l'instantané à la création, et c'est le poste qui s'en sert pour refuser de fondre deux coffres différents. À la connexion il ne protège rien : le mot de passe seul ouvre, et le vrai nom est lu dans le conteneur.
Scénario d'essai
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.
L'ordre n'est pas alphabétique : Préparation → C → A → B → D → E → …. La
série C réconcilie, et c'est elle qui fait du coffre né ici un coffre publié.
Tant qu'il ne l'est pas, CommitChange voit LLocalOnly, écrit « save: written
locally » et ne publie rien — il n'y a pas de dépôt. La série A guetterait donc
un point orange qui ne peut pas paraître, et conclurait à un défaut là où il n'y
a que l'ordre.
Outil de remise à zéro : Settings → Debug → Delete the local vault (deux appuis). Il efface cache, conteneur local et drapeau d'attente, et garde les réglages du dépôt — on retélécharge sans rien retaper. Absent en release : la commande n'y est même pas compilée.
Préparation — l'état de départ, et il compte
Plusieurs séries agissent sur une entrée existante. Partir d'un coffre vide les rendrait ininterprétables : on ne sait pas distinguer « la modification n'a pas voyagé » de « il n'y avait rien à faire voyager ».
- Settings → Debug → Delete the local vault, puis Create vault. Le coffre
naît vide : zéro entrée, et aucun dossier —
NewEmptySnapshotécrit un tableaufoldersvide. - Créer une seule entrée, avec un mot de passe reconnaissable. Elle se range
dans
All, et c'est ce premier enregistrement qui fait apparaître le dossier :AddEntryposefolder = 'All'parce que c'est le dossier par défaut du poste, pas parce que c'est joli. - Vérifier qu'il n'y a qu'un dossier dans la barre. Deux au départ voudrait dire qu'un instantané traîne encore.
C'est le point de départ de tout ce qui suit. Y revenir entre deux séries qui se gênent coûte deux appuis.
Un coffre vide reste un cas à éprouver, mais explicitement : c'est lui qui a révélé que « coffre ouvert » se lisait sur le nombre d'entrées (défaut n° 3), et que l'auto-verrouillage se coupait de lui-même. À reprendre au moins une fois sans entrée : Sync ne doit pas boucler, et le coffre doit finir par se verrouiller seul.
A. Enregistrement hors connexion — le plus important
Exige un coffre PUBLIÉ — donc la série C d'abord. Sur un coffre né ici et jamais réconcilié, il n'y a rien à publier et rien ne se met en attente.
- Coffre ouvert, couper les données (mode avion).
- Modifier un mot de passe → « 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 : il doit apparaître dans la barre de dossiers après la fusion, et sur le poste après sa synchronisation.
C. Les deux secrets — nouveau, et jamais éprouvé de bout en bout
- Effacer le coffre local (bouton Debug). Les trois champs du dépôt doivent rester remplis — c'est la moitié de ce que ce bouton promet.
- Create vault avec un mot de passe différent de celui du dépôt.
- Ouvrir les réglages : le champ sync password doit porter celui du dépôt, pas celui qu'on vient de choisir. C'est toute la séparation en une capture.
- Sync → la réconciliation lit le dépôt et republie sous le secret du dépôt. Contre-épreuve décisive : le poste doit relire le dépôt sans se plaindre. S'il échoue, c'est que la clé du conteneur local a servi à resceller l'instantané.
- Après la réconciliation,
vault-local.jsondoit avoir disparu — c'est ce geste qui passe l'autorité au dépôt.
D. Ouvrir demande quelque chose — nouveau
- Effacer le coffre, puis Download vault.
- Fermer complètement l'application, rouvrir → le champ de code doit paraître et réclamer le mot de passe de sync. Le cache est scellé sous lui, parce qu'il le contient déjà : l'ouvrir sans rien livrait le coffre et le secret du dépôt.
- Vérification par le fichier, si adb est à portée :
run-as com.embarcadero.pmserverApk od -An -tu1 -N1 files/vault.bindoit rendre 4 (VER_PIN) et non 1. - Un mauvais code → « Wrong unlock code » en rouge, et Open vault reste offert : le cache n'est pas déclaré illisible.
- Sur un appareil avec biométrie, rien de tout cela :
VER_WRAPgarde déjà la porte, et imposer une frappe serait un recul. C'est volontaire.
E. Le dépôt a bougé — témoin bleu
Cette série était impossible telle qu'elle était écrite, et la mesure le dit :
AUTOLOCK_MINUTES = 3 verrouille après trois minutes d'inactivité, tandis que
PROBE_EVERY_TICKS = 40 — à quinze secondes le battement — demande dix minutes
de coffre ouvert. Le compteur n'avance que tant que le coffre l'est, et
LockVault sort avant de l'incrémenter. « Laisser ouvert dix minutes sans y
toucher » verrouillait donc à la troisième, et le sondage ne partait jamais.
Ce n'est pas un défaut de l'application : le témoin sert pendant qu'on se sert du coffre, et quelqu'un qui s'en sert le touche. Mais il faut le dire, sinon on cherche un point qui ne peut pas paraître.
- Coffre ouvert sur le téléphone. Le toucher toutes les deux minutes — faire défiler la liste suffit, il ne faut surtout pas synchroniser : un Sync, comme une ouverture, remet le compteur à zéro.
- Sur le poste, modifier une entrée et synchroniser.
- Continuer à toucher jusqu'à dix minutes de coffre ouvert. 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. Cette condition compte autant que le témoin : si l'entrée qu'on regarde se met à jour toute seule, le sondage adopte au lieu de signaler, ce qui est plus grave qu'un témoin absent.
- 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.
Si tu préfères ne pas veiller dix minutes, la contre-épreuve courte : mets
PROBE_EVERY_TICKS à 8 — deux minutes — recompile, éprouve les points 3 à 6,
puis remets 40. C'est la seule série du plan où le réglage de production rend
l'observation coûteuse.
F. Réglages — largement réécrits, à reprendre en entier
- Coffre fermé, ouvrir les réglages depuis l'accueil → la section Unlock code doit être absente. Poser comme retirer exigent le clair en main : coffre fermé, les deux ne pourraient que refuser.
- Ouvrir le coffre, roue dentée → la section paraît.
- Poser un code : taper, Set this code → « Unlock code set » immédiatement, sans quitter l'écran. Plus de « ouvre le coffre pour l'appliquer » : le code s'applique sur-le-champ.
- Le message doit se voir au-dessus du clavier resté ouvert. C'est le défaut le plus discret de la séance : le toast vivait sous le clavier.
- Un seul appui doit suffire sur Set this code. S'il en faut deux, le premier est mangé par le clavier et la correction du focus a régressé.
- Retirer le code : Remove the unlock code sans rien taper → refus « Type the current unlock code to remove it ». Puis taper le code courant, deux appuis → « Unlock code removed ». Fermer l'application, rouvrir → le code n'est plus demandé.
- Contre-épreuve : Set this code avec un champ vide ne doit pas retirer le code — c'était une porte dérobée vers le retrait sans le connaître.
- Le champ sync password doit porter le mot de passe du coffre détenu, pas une valeur de premier lancement.
- Touche retour dans les réglages → referme sans verrouiller ni changer de vue.
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. Anciens mots de passe
Le poste doit synchroniser d'abord : il ne les envoie que depuis peu, et un instantané publié avant ne porte aucun historique.
- Sur le poste, changer le mot de passe d'une entrée, puis synchroniser.
- Téléphone : Sync, ouvrir l'entrée, trois points → Previous passwords. L'ancienne version doit être là, avec sa date.
- Copier l'une d'elles → « Previous password copied ».
- Touche retour → le voile se referme sans toucher au coffre.
- Une entrée jamais modifiée → « No previous password recorded », et non un écran vide.
- Contre-épreuve : verrouiller, rouvrir, Previous passwords → la liste doit être reconstruite, jamais celle d'avant restée à l'écran.
I. Clavier, mise en page, retour d'application — nouveau
- Taper dans un champ, appuyer sur un bouton hors de sa rangée (Open vault, Sign in, Set this code) → un seul appui, et le clavier se replie ensuite.
- Taper dans un champ, appuyer sur un bouton de sa rangée (l'œil d'un champ secret) → le clavier reste ouvert et le curseur en place. Les deux moitiés comptent : la première sans la seconde laisse le clavier dressé.
- Réglages ouverts coffre FERMÉ, verrouiller le téléphone, déverrouiller → la page doit revenir. C'était un aplat bleu sans rien dessus : le masquage ne demandait rien, la restitution exigeait un coffre ouvert.
- Même chose coffre ouvert : passé le délai de grâce, le verrouillage doit avoir lieu et ramener sur l'accueil — pas sur la liste.
- Accueil sans coffre : l'ordre doit être Download vault → Settings → username / password → Create vault, espacements réguliers, et Download vault doit porter la couleur d'accent quand un dépôt est configuré.
- Les boutons du bandeau (roue, +, cadenas) et ceux de la barre de sélection sont ronds.
J. 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.
K. Notes multilignes
- + → Note → zone de texte pleine largeur, Site et Username disparus.
- Taper plusieurs lignes — 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, Entrée doit toujours replier le clavier.
L. 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.
M. 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.
- Vérifier que la section Debug des réglages est absente de cette version. Elle ne peut pas y être — la commande n'est pas compilée — mais c'est le genre de garantie qu'on regarde une fois plutôt que de la croire.
Ce qui n'est toujours pas éprouvé
- Le chemin
-Releasedu script n'a jamais produit d'APK signé. Il compile, c'est tout ce qu'on sait. - L'invalidation de la clé par le système (§ D.5 pour la biométrie) : le message « Device protection changed » existe et son drapeau est posé là où l'invalidation se constate, mais personne ne l'a vu s'afficher. Il faudrait retirer le verrouillage d'écran d'un appareil qui en a un.
MergeSelfChecktourne au démarrage en débogage et écritmerge selfcheck: the four rules holddans le journal. Il passe ; personne ne l'a lu en cherchant à le mettre en défaut.- Le mode
login(conteneur local sans cache) ne s'atteint qu'en supprimant le cache à la main. C'est là qu'a été trouvée la lecture après libération : il n'avait jamais tourné.