Sans FireDAC.Phys.SQLiteWrapper.Stat, FireDAC charge sqlite3.dll au
demarrage. Sur ce poste ca marchait quand meme : le dossier bin
d'Embarcadero, qui en contient un, est dans le PATH. Sur une machine
sans Delphi, l'exe refusait de demarrer.
C'est le Win64 qui l'a revele — la DLL du PATH est 32 bits — mais le
Win32 livre etait casse de la meme facon chez quiconque n'a pas Delphi,
paquet prepare pour un tiers compris.
Prouve avec un PATH reduit a Windows : avec l'unite SQLite s'ouvre
(3.42.0), sans elle l'erreur exacte. Lire la table d'import ne
suffisait pas, le chargement est dynamique.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Le groupe Base_Win64 du .dproj n'avait ni prefixes d'unites — d'ou
"Unite 'Windows' non trouvee" en recompilant TMS — ni Cfg_1_Win64 :
l'exe aurait compile sans icone et sans PerMonitorV2, donc flou sur un
ecran haute resolution. Complete en miroir exact de Win32, et Win64
coche dans l'IDE.
Builds Release 32 et 64 bits produits sur E:, un dossier .dcu par
plateforme — c'est ce qui empeche la pollution des sources TMS qui avait
casse le build Win32 le 7 septembre. Verifie : aucun .dcu depose.
Empreinte de licence identique en 32 et 64 bits, les deux couches a
TRUE des deux cotes : une licence vaut pour les deux exe.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
\a s'etait change en BEL dans E:\a pmanager. Le commit precedent
affirmait qu'il ne restait plus rien sans l'avoir mesure apres coup —
c'est ce qui l'a laisse passer. Mesure cette fois : zero.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
\t et \r s'etaient changes en tabulation et en retour chariot dans les
chemins du piege TMS. Verifie apres coup : plus aucun caractere de
controle parasite dans le fichier.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
L'ecran d'activation ne consultait qu'un branchement : le rapiecer
ouvrait tout, l'API ne demandant rien. Chaque route de PM.Router passe
maintenant par PM.LicenceGate.ApiLicenceOk avant son handler.
Aucune fonction de decision partagee avec PM.Licence — sinon un seul
rapiecage ouvrirait les deux couches. La verification est refaite de
bout en bout, appels CNG redeclares compris ; seules la cle publique et
le nom de la pref sont partages, parce que ce sont des donnees.
Branchee dans DispatchRequest : les fichiers de l'ecran d'activation
passent par TryServeEmbedded, non garde, sinon l'ecran ne se chargerait
plus. Un oui est retenu pour le processus, un non jamais.
Le risque etait qu'elle refuse un client licencie. Auto-test sur un
vecteur lie a une empreinte fixe, sens accepte en premier ; et accord
verifie en conditions reelles sur ce poste : IsLicensed = TRUE,
ApiLicenceOk = TRUE.
Documente aussi le piege du jour, sans lien avec ce code : des .dcu TMS
x64 deposes a cote des sources cassaient le build Win32, et la sortie
redirigee vers E: faute de place sur Z:.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
origin pointe sur le Gitea auto-heberge. CLAUDE.md affirmait "pas de
remote configure (dev local)", ce qui a cesse d'etre vrai sans que le
document suive — 427 commits d'avance au moment du constat.
Rien n'est pousse automatiquement, et c'est note : lire "il y a un
remote" ne doit pas se comprendre comme "c'est sauvegarde ailleurs".
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Le formulaire New entry n'avait pas le champ et AddEntry ecrivait
totp_secret = '' en dur : il fallait enregistrer l'entree puis la rouvrir
pour poser un second facteur, alors que l'editeur portait deja le champ.
Meme intitule que l'editeur ("2FA secret"), masque pour une note comme
site et identifiant, et achemine par &o= — t, s, u, p, k, d etaient
pris.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Differe volontairement : l'APK ne part chez personne aujourd'hui. Le
jour venu, l'instantane publie par le poste portera la licence et le
telephone exigera d'y en trouver une — il le lit deja, donc aucun
nouveau format, aucune empreinte Android, aucune emission de plus.
Les trois raisons de ne pas refaire un second dispositif sont notees
pour ne pas les re-deriver : Java attend du DER la ou CNG accepte r||s
brut, ANDROID_ID est remis a zero par une reinitialisation d'usine (donc
des clients legitimes refuses), et un APK se repaquette en dix minutes.
Et l'APK n'aura PAS a verifier la signature, seulement la presence :
payer le DER et le JNI pour durcir un controle que le repaquetage retire
serait le mauvais echange.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A, B, C, D, E2, E3 passes, rien a corriger. E1 (autre compte Windows)
reste non joue, faute d'un second compte : note comme tel plutot que
presente comme verifie.
E3 ajoute au plan pendant la campagne — remplacer l'exe d'une
installation existante par une nouvelle version. C'est le cas qu'on vit
reellement a chaque livraison, et une desactivation a la mise a jour ne
se verrait qu'au premier client mecontent.
Deux observations gardees : C3 a ete plus probant que prevu (le port
avait change entre les deux lancements, donc l'origine aussi), et un
port ephemere sans ligne de repli dans le journal n'est pas un defaut
mais un config.txt absent ou port=0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
LICENCE-TESTS.md : cinq series. B eprouve ce qui doit tomber (chaine
quelconque, licence tronquee, charge utile trafiquee, autre poste, autre
paire de cles), C le risque symetrique et plus couteux — refuser un
client qui a paye (espaces colles, retour a la ligne, redemarrage
machine). D est dediee a la stabilite de l'empreinte, le defaut deja
rencontre. E delimite la portee de l'activation.
Le plan citait cmd://licence/clear sans moyen de l'appeler : un bouton
"Deactivate (debug)" au bas de Settings -> Licence, revele seulement
quand config.txt existe. Il donne au passage son unique appelant a
ClearLicence, qui etait du code mort.
Le document dit aussi ce qu'aucun essai ne prouve : rapiecer l'exe reste
possible, il n'y a pas de revocation, et le brouillage n'est pas du
chiffrement.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
La premiere privee a ete supprimee sans copie : plus aucune licence
nouvelle n'etait emettable. Regeneration + reemission, indolore
aujourd'hui parce qu'une seule licence circulait.
licence.ps1 ecrit desormais la cle dans %USERPROFILE%\Documents, hors du
depot. Elle vivait dans tools\, ou elle n'attendait qu'un menage : le
.gitignore la protegeait du depot, rien ne la protegeait de son
proprietaire.
Verifie : la licence de la nouvelle paire passe, celle de la paire
perdue tombe — la regeneration a bien remplace, pas ajoute.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Le frontend etait lisible dans l'onglet Image de Process Explorer, avec
les commentaires. BuildAssets.ps1 brouille chaque fichier avant brcc32,
PM.EmbeddedAssets le debrouille au moment de servir.
C'est de l'opacite, pas du secret : la cle est dans l'exe. Ca supprime
strings et l'onglet Image ; la memoire, un debogueur et la reponse HTTP
rendent toujours le texte. D'ou XOR plutot qu'AES — a securite egale
(nulle contre qui a l'exe), dix lignes, et aucune force affichee qu'on
n'a pas.
Une magie PMA1 prefixe le clair : sans elle, deux constantes qui derivent
serviraient du binaire au navigateur, ecran blanc sans trace.
Verifie en comparant les flux des deux cotes bloc par bloc, puis par
aller-retour sur app.js, index.html et style.css. Le frontend ne se
trouve plus dans le binaire.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Porteur, courriel, date d'emission et Installation ID, lus dans la charge
utile deja verifiee. Rempli une fois au demarrage sur les deux chemins
(deja licencie, activation reussie) : rien n'y change pendant une
session. Section masquee hors navigateur hote.
Les champs sont echappes avant interpolation dans ExecuteJavaScript bien
qu'ils viennent d'une charge utile signee — signee ne veut pas dire
inoffensive.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
BoardUUID s'appuyait sur un COM initialise par quelqu'un d'autre. Appele
apres WebView2 il lisait le vrai UUID de carte mere, appele avant il
echouait et retombait sur MachineGuid : deux empreintes pour une seule
machine, et une licence liee a l'une que l'autre refuse. Il suffisait que
licence/status parte avant l'init du navigateur pour verrouiller
l'utilisateur hors de son coffre.
CoInitializeEx est desormais appele sur place. Pas de CoUninitialize
symetrique : essaye, il rend une violation d'acces — les mandataires WMI
et le cache de type-info de ComObj se liberent plus tard, dans un
appartement qu'on vient de fermer.
Verifie avec un harnais qui n'initialise PAS COM : il rend maintenant la
meme empreinte que l'application.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Une cle flottante etait sortie. Un schema hors ligne n'a pas de
revocation — rien ne peut aller dire a un exe installe qu'une cle ne vaut
plus — donc la seule prise est de cesser d'accepter toute la classe.
MachineMatches exige desormais une empreinte, et -Floating disparait du
script : il ne peut plus fabriquer une cle que l'exe rejetterait.
Effet de bord assume : plus de licence de site, et un poste sans
empreinte exploitable n'est plus licenciable du tout — mieux qu'une
empreinte degeneree qui ouvrirait partout.
Verifie : liee a ce poste acceptee, liee a un autre refusee, les deux
flottantes deja emises refusees.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
C'etait la decision prise, et je l'avais mal lue : "pour le moment 1"
repondait a la question 1, pas "une seule licence".
PM.MachineId melange l'UUID de la carte mere (WMI) et la serie du volume
systeme, puis n'en publie que 16 hexa : l'empreinte se recopie dans un
courriel, l'UUID brut n'a pas a circuler. Un UUID nul ou tout a FF est
rejete — VM et images clonees l'annoncent, et deux postes tomberaient
alors sur la meme empreinte.
Le champ m est compare APRES la signature. m absent = licence flottante,
acceptee : seule la cle privee peut en emettre, et le champ ne peut pas
etre retire sans casser la signature. Cote script -Machine est
obligatoire sauf -Floating explicite.
L'ecran d'activation affiche l'Installation ID : une licence liee ne peut
plus etre emise avant l'installation.
Verifie sur ce poste : liee a lui acceptee, liee a un autre refusee,
flottante acceptee.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Le cyan de .auth-hint dit "voici l'etat des choses" (session expiree,
coffre verrouille). Un refus n'est pas un etat, c'est un echec : il doit
se distinguer a la couleur avant d'etre lu. Variante .is-error posee sur
le refus, retiree a chaque nouvel essai.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
L'ecran d'activation devient franchissable. Verifie en executant l'unite
contre la vraie cle : licence emise acceptee et charge utile lue, licence
signee par une AUTRE paire refusee — c'est celle-la qui prouve que la cle
tient reellement la porte — charabia et chaine vide refuses.
La cle privee reste hors du depot (gitignoree) et doit etre deplacee dans
un coffre : qui la detient fabrique des licences.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ensureLicence() en tete d'init(), avant tout le reste : un ecran
d'authentification qui s'affiche puis se fait recouvrir donnerait
l'impression que le coffre etait accessible.
L'ecran reprend les classes de l'ecran d'authentification — zero style
nouveau hormis un z-index. Le statut est demande deux fois avant de le
montrer : un demarrage a froid lent manquerait la fenetre de reponse, et
le silence se lirait comme un refus.
Une cle refusee ne dit pas pourquoi, et le journal note le verdict sans
jamais la cle.
ATTENTION : tant que LicencePublicKeyBlob est a zero, l'ecran est
infranchissable. Poser la cle publique avant de deployer.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
PM.Licence verifie une chaine charge-utile.signature contre la cle
publique de l'editeur, via BCryptVerifySignature. Aucun ASN.1 : la
signature du script est deja en r||s brut et les coordonnees se rangent
telles quelles dans un BCRYPT_ECCPUBLIC_BLOB.
La cle publique est livree A ZERO — tant que la sortie de licence.ps1
-Init n'y est pas collee, aucune licence n'est valide. C'est le defaut
sur : un blob par defaut qui accepterait quelque chose serait pire.
IsLicensed REVERIFIE la licence rangee plutot que de lire un drapeau.
La signature est verifiee AVANT que la charge utile soit analysee.
SelfTestLicence a l'initialization rejoue un vecteur fige signe par une
paire de test : valable accepte, un octet retourne refuse. Verifie en
executant l'unite, pas seulement en la compilant.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Script a lancer chez soi, jamais livre. -Init cree la paire et imprime
la constante Delphi du BCRYPT_ECCPUBLIC_BLOB ; -For emet une licence
payload.signature en base64url.
.NET sur Windows EST CNG : la signature produite (r||s brut, 64 octets)
est celle qu'attend BCryptVerifySignature, et les coordonnees exportees
se rangent telles quelles dans le blob. Aucun ASN.1 des deux cotes.
Verifie en rejouant l'import du blob par CngKey.Import : licence valide
acceptee, un octet retourne dans la charge utile la fait tomber.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
localStorage meurt avec l'origine a chaque lancement, donc un autofill
desactive revenait sur ON. Miroite en pref DPAPI comme unlockMode et
rememberedUsername ; la copie DPAPI fait autorite, relue dans enterApp
juste avant la poussee des combos vers Delphi.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Le lien n'etait garde par rien : un port pris levait, et l'application
s'ouvrait sur une boite d'erreur. Trois essais desormais - le premier
honore le port de config.txt, que l'utilisateur a peut-etre choisi
expres, les suivants prennent un ephemere.
SE LIER EST LE TEST. Sonder le port avant serait plus faible - un service
qui ecoute sans repondre passerait inapercu - et sujet a une course : le
port peut etre pris entre le sondage et le lien. Chaque deplacement est
journalise, un serveur qui change de port en silence etant pire qu'un
serveur qui refuse de demarrer.
Trouve en chemin : Randomize n'est appele NULLE PART, donc le port
"aleatoire" de port=0 etait le meme a chaque lancement - l'aleatoire cense
compliquer un balayage exterieur n'existait pas. Il vient maintenant de
RandomBytes, donc de BCryptGenRandom, deja utilise pour le jeton d'acces.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
La barrette et le raccourci se rejoignent des FireAutofillRequest, donc
tout ce qui suit etait journalise sous "hotkey" - y compris un
remplissage declenche a la souris. Un diagnostic de lenteur qui ne sait
pas par ou l'on est entre cherche au mauvais endroit.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Un autofill lent apres une periode d'inactivite peut l'etre pour des
raisons sans rapport qui se ressemblent parfaitement de l'exterieur : le
moteur WebView2 qui se reveille, la prise du premier plan, ou l'attente
de la relache des modificateurs. Elles se corrigent a des endroits
opposes, donc on les separe au lieu de deviner laquelle accuser.
Trois marques : le temps que met la PAGE a repondre au raccourci, le
total, et le detail des deux attentes internes.
Premiere mesure : 13 ms de reponse apres 23 minutes en tray, total
635 ms. Le renderer ne dormait donc pas - l'hypothese la plus evidente
etait fausse - et 635 ms est le cout nominal de la sequence, faite de
pauses fixes (80 + 120 + 60 + 200 + 200). Le cas lent reste a attraper.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Le premier nomme la chose, le second decrivait l'utilisateur. Le signe
qui a tranche : l'ancien libelle avait besoin d'une parenthese pour se
faire comprendre - "Lazy mode (fill with the mouse)" - et c'etait elle
qui portait le sens.
Seul le libelle change. Les identifiants internes gardent "lazy" -
FLazyWnd, LAZY_*, et surtout les prefs lazyOn / lazyPos / lazyAlphaPct :
renommer ces cles perdrait les reglages deja poses sur la machine.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
L'APK signe existe. Le chemin -Release n'avait jamais tourne et a butte
quatre fois - dossier de mise en scene absent, volume plein, cinq
doublons refuses par aapt, ressources generees jamais rangees. Toutes des
choses que seule une release partant d'un terrain vierge pouvait
rencontrer.
La verification de la section Debug est corrigee : chercher wipelocal
dans le .so ne prouve rien, la page HTML embarquee la contient dans les
deux configurations. Seule la chaine du gestionnaire Pascal tranche, et
en UTF-16LE. La garantie est "inatteignable et sans effet", pas
"absente".
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Le Build depose a plat dans Android64\<Config>\ les ressources d'Android
- styles.xml, strings.xml, les variantes -v21/-v31, l'icone adaptative -
et c'est le Deploy qui devrait les ranger dans res\. Il le fait en DEBUG
et pas en RELEASE, alors que les proprietes Android_* du .dproj sont
communes aux deux configurations et qu'aucune entree de deploiement ne
les nomme.
Sans elles, aapt refuse le paquet sur "@style/AppTheme" introuvable : le
manifeste reference un theme que plus rien ne definit.
Le script les range donc lui-meme, avant nos propres ressources pour que
notre colors.xml garde le dernier mot. La correspondance nom-fichier vers
sous-dossier est transcrite explicitement : un fichier nouveau se
signalera au lieu d'etre range au hasard.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Le deploiement de Delphi depose a la racine de res\ une copie a plat de
cinq de ses ressources - ic_launcher_*, splash_* - alors que les vraies
sont dans res\drawable\. Or aapt n'accepte que des DOSSIERS a cette
racine : il refusait le paquet entier, "invalid resource directory name",
une fois par fichier.
On les retire avant l'appel, et rien n'est perdu : ce sont des doublons,
verifies presents dans drawable.
Ne se voyait pas en debogage, ou l'arbre traine depuis longtemps. C'est
la premiere release qui l'a montre, comme le dossier de mise en scene
absent juste avant.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
L'arbre de mise en scene est creuse par l'etape Deploy, qui vient APRES
les trois copies qui s'y deversent. En debogage il existait deja, laisse
par un deploiement anterieur, et personne ne s'en apercevait ; pour une
configuration jamais empaquetee, la premiere copie tombait sur un chemin
absent - "Could not find a part of the path".
Les creer d'abord ne coute rien quand elles existent. C'est exactement le
defaut que TESTS.md annoncait : le chemin -Release n'avait jamais tourne.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
FRemoteAhead etait remis a faux a trois endroits - publication,
publication differee, rafraichissement - et aucun ne le disait a la page.
Seul l'allumage etait pousse. Le point bleu restait donc affiche apres la
synchronisation qui venait de le rendre caduc, jusqu'au retour suivant
sur l'accueil.
Un temoin qui reste allume apres qu'on a fait ce qu'il demandait ne
demande plus rien : il decore, et on apprend a ne plus le regarder.
Le drapeau et son affichage passent maintenant par SetRemoteAhead, dans
les deux sens. Meme asymetrie, meme correction que pour le point orange.
PROBE_EVERY_TICKS revient a 40 : la bascule a 8 n'etait que pour rendre
la serie E observable en deux minutes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Le chien de garde mesurait la duree TOTALE, alors que son message dit
"no reply from the server". Sur un coffre devenu gros - 286 Ko - la
reponse arrivait en 841 ms et les vingt secondes suivantes partaient dans
la derivation de la cle puis l'affichage : il criait donc a l'absence de
reponse alors que tout avait reussi, cache ecrit compris. Un faux echec
est pire qu'un vrai, il apprend a se mefier de ce que l'application dit.
Il est desarme des que le statut HTTP est connu, quel qu'il soit : ce qui
suit ne depend plus du reseau, et le voile est leve par le finally.
Au passage, les boutons des reglages n'avaient pas de margin-top : le
champ du code et ses deux boutons se touchaient et se lisaient comme un
seul bloc. Les piles de l'accueil ont leur gap ; ici les elements se
suivent en flux normal, donc c'est au bouton de reserver sa place.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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>
Synchroniser est une ACTION, pas un reglage. Elle n'existait qu'au fond
du panneau des reglages, a cote de l'URL et du jeton : on l'y configure
une fois, on la declenche tous les jours.
Sans URL, sans "Enable sync" ou sans mot de passe de sync, l'appui ouvre
les reglages ET DESCEND jusqu'a la section - un bouton qui ne peut
qu'echouer ne vaut pas mieux que pas de bouton, et repondre "Sync not
configured" laisse chercher ou reparer. Le panneau n'a pas d'onglets,
c'est une colonne longue : le battement dit lequel des blocs on est venu
chercher.
L'etat est lu SANS les secrets - hasEncPwd dit que le mot de passe existe
sans le lire, ce que loadSyncConfig documente : les tirer les planterait
dans le renderer pour la vie du processus.
L'entree disparait sans le pont, comme la section : le frontend PHP n'a
pas de sortie reseau.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Le meme defaut, par une autre porte : restaurer une sauvegarde par-dessus
des entrees existantes passe aussi par encryptImportEntry puis PUT, donc
re-chiffre un mot de passe inchange et fait croire au serveur qu'il a
change. La sync etait la cause de ce qui se voyait, pas la seule.
La regle est extraite en une fonction, keepCiphertextIfSamePassword,
appelee par les deux. Les re-publications partielles - tag, dossier,
migration des metadonnees - sont hors de cause : elles reutilisent deja
le chiffre stocke.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
L'instantane transporte le mot de passe EN CLAIR, et encryptImportEntry
le re-chiffre avec un IV neuf : le chiffre differe donc toujours, meme
quand le mot de passe n'a pas bouge. Or le serveur decide d'ecrire une
version dans l'historique en comparant les chiffres
(`encrypted_password <> :newenc`) - il voyait une difference la ou il n'y
en avait aucune, et chaque synchronisation qui redescendait une entree y
deposait un doublon date du jour. L'historique montrait la meme valeur
deux fois, a des jours d'ecart.
Le serveur ne peut pas trancher, il ne voit que du chiffre. Seul le
client connait les deux clairs : il compare, et rend le chiffre d'origine
quand ils sont egaux - ce que le commentaire du handler appelle deja
"JS reuses originalEncrypted bit-for-bit".
Trouve en deroulant la serie H sur le telephone.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
"+ new folder" n'existait qu'a l'edition. Creer une entree ET son dossier
demandait donc trois gestes - creer, rouvrir, changer le dossier - pour
ce que le meme controle sait faire ailleurs en un seul. L'asymetrie ne se
voyait qu'en s'en servant.
Deux cas que le chemin de l'edition ne posait pas : un champ laisse vide
et le marqueur interne du "+ new folder" retombent tous deux sur All -
sans quoi valider sans rien taper aurait envoye au coffre un nom de
dossier fait d'un caractere de controle.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
FPending est relu au demarrage, mais PM.setPending n'etait pousse que par
OpenLocalNow : la page n'apprenait donc l'attente qu'en OUVRANT le
coffre. Un demarrage a froid montrait Sync sans point orange - l'ecran ou
l'on decide de synchroniser, et le seul moment ou ce drapeau relu au
demarrage sert a quelque chose. Il fallait ouvrir puis reverrouiller pour
qu'il paraisse.
Les deux temoins se reposent maintenant dans ShowUnlock, donc a chaque
retour sur l'accueil.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
La serie A guette un point orange sur un coffre ne ici, ou il ne peut pas
paraitre : CommitChange voit LLocalOnly, ecrit localement et ne publie
rien - il n'y a pas de depot tant qu'on n'a pas reconcilie. On aurait
conclu a un defaut la ou il n'y a que l'ordre.
C reconcilie, donc C passe avant A.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Plusieurs series agissent sur une entree existante, sans dire d'ou elle
vient. Partir d'un coffre vide les rend ininterpretables : on ne
distingue pas "la modification n'a pas voyage" de "il n'y avait rien a
faire voyager".
Etat de depart : coffre neuf, une seule entree, un seul dossier - All, et
c'est le premier enregistrement qui le fait apparaitre.
Le coffre vide reste un cas a eprouver, mais nomme comme tel : c'est lui
qui a revele que "coffre ouvert" se lisait sur le nombre d'entrees.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
La version precedente decrivait une application qui n'existe plus - deux
secrets confondus, des reglages qui n'appliquaient rien sur-le-champ, un
coffre qui s'ouvrait sans rien demander.
Trois series nouvelles : les deux secrets (C), l'ouverture qui demande
quelque chose (D), et le clavier avec le retour d'application (I). F est
reprise en entier. La remise a zero passe desormais par le bouton Debug
plutot que par adb, ce qui rend le scenario deroulable sans machine.
En tete, ce que la seance a vraiment appris : les defauts se tiennent par
la main, et le journal doit se lire AVANT de retenter - la
synchronisation le vide.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Il vit en bas des reglages, apres tout le reste, et demande deux appuis :
un effacement sans retour ne se declenche pas sur un doigt qui glisse.
Absent en release, et pas seulement cache : la commande du pont n'est pas
compilee et Delphi ne devoile la section que dans une version de
debogage. Le bouton ne peut donc pas reapparaitre par accident. Verifie -
Release compte 8060 lignes contre 8072 en debug, soit exactement ce bloc.
DropLocalVault efface le cache, le conteneur local et le drapeau
d'attente, chacun sous son propre try : un fichier absent ou verrouille
ne doit pas empecher les deux autres de partir. Les reglages du depot
restent - c'est le coffre qu'on jette, pas la facon d'aller le rechercher.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Retenir le focus au mousedown fait atteindre la cible du premier coup,
mais laissait le clavier ouvert : apres "Open vault" il restait dresse
par-dessus la liste. Les deux moities vont ensemble - on retient le focus
le temps de l'appui, on le lache des que l'action est partie.
Sauf si le bouton agit sur le champ lui-meme : un oeil qui devoile, une
fleche qui deroule. Ceux-la vivent dans la meme rangee que le champ, et
replier le clavier apres eux obligerait a le rouvrir pour continuer.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Le toast vit a bottom: 14px, donc sous le clavier des que celui-ci est
leve : il ne se decouvrait qu'en quittant l'ecran, quand le clavier se
repliait. Et depuis qu'un appui sur un bouton ne vole plus le focus, le
clavier RESTE ouvert - ce qui a rendu systematique un defaut jusque-la
occasionnel.
Il remonte au-dessus de la reserve que body.typing menage deja pour le
clavier : meme mesure, meme raison.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Un bouton touche pendant qu'un champ a le focus recevait d'abord le
blur : le clavier se repliait, la reserve de body.typing disparaissait,
la page remontait - et le bouton n'etait plus sous le doigt quand le clic
partait. Il fallait appuyer deux fois, la premiere ne servant qu'a fermer
le clavier.
Empecher le defaut du mousedown empeche le TRANSFERT DE FOCUS, pas le
clic : le champ garde le curseur, rien ne bouge, et l'appui atteint sa
cible du premier coup. Pose sur toute la page - le piege n'a aucune
raison d'etre propre aux reglages.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Le toast n'avait pas de z-index : il se peignait DERRIERE l'ecran des
reglages, qui est a 80. "Unlock code set" partait bien, mais sous la
page, et ne se decouvrait qu'en sortant - quand il ne s'etait pas deja
eteint. Un message qui ne se voit pas la ou on l'a provoque ne sert a
rien.
La section du code de deverrouillage ne parait plus que coffre ouvert.
Poser comme retirer exigent le clair en main : coffre ferme, les deux ne
pouvaient que refuser, et proposer une action qui refuse toujours vaut
moins que ne rien proposer.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sans biometrie utilisable et sans code pose, le cache s'ouvrait sans rien
demander - or il CONTIENT le mot de passe de sync. Qui tenait le
telephone deverrouille obtenait donc le coffre ET le secret du depot.
Il est desormais scelle sous le mot de passe qui vient de le rapporter :
celui-ci est deja dans ce fichier, donc rien de neuf n'est expose, et
l'utilisateur le connait puisqu'il vient de le taper. C'est aussi la
seule forme de cache qui survive a une reinitialisation du verrouillage
d'ecran.
Pas quand l'appareil sait authentifier : VER_PIN et VER_WRAP s'excluent,
et imposer une frappe a qui a une empreinte serait un recul.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Register et Login mettaient leur gestionnaire d'erreur en file avec
TThread.Queue, puis y lisaient E.ClassName et E.Message. Or la file
s'execute sur le thread principal bien apres que le except a rendu la
main, et Delphi libere E en sortant du gestionnaire : c'etait une lecture
apres liberation.
Elle rendait un message vide - "Login failed: EPMACrypto - " sans la
raison - et parfois une violation d'acces qui remontait a FMX sans rien
laisser au journal. Le vrai motif de l'echec n'a donc jamais ete affiche.
On ne met plus en file que des chaines, qui survivent.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Le dispatch n'etait garde par rien : une faute dans un handler remontait
jusqu'a FMX, qui affichait "Access violation" avec une adresse, tandis
que le journal ne montrait que la commande recue suivie de rien. On
savait qu'une commande echouait, jamais laquelle ni pourquoi.
On attrape, on nomme, et on rend la main - une commande fautive ne doit
pas laisser l'interface voilee derriere une boite de dialogue.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>