Filarr mobile, lavori in corso: una sincronizzazione che dice la verità
Sull’app mobile di Filarr questa settimana: cinque correzioni alla sincronizzazione, due stati di errore permanenti, lo spazio reale in home e 3.326 test.
Mathis Belouar-Pruvot
· fondatore di Filarr · · 8 min di lettura
Questa settimana sull’app mobile: la sincronizzazione dice la verità. Cinque correzioni, due nuovi stati di errore permanenti, una schermata iniziale che mostra finalmente l’uso del tuo spazio e 3.326 test verdi. L’app mobile di Filarr esce tra uno e due mesi circa.
L’app mobile di Filarr (React Native) è nell’ultimo tratto prima del rilascio. Prima che esca, lo strato di sincronizzazione deve essere onesto, non solo funzionante ma onesto: quando qualcosa non va, l’app deve dire ciò che sa, solo ciò che sa, e smettere di fingere che sistemerà cose che non può sistemare.
È stato il tema di questa settimana.
Fermare l’eterno banner «sincronizzazione interrotta»
Il bug più visibile su mobile era un banner che non se ne andava: «sincronizzazione interrotta». Scavando nei log dei dispositivi, ho trovato tre cause distinte, ciascuna che alimentava le altre in un brutto circolo vizioso.
Voci fantasma nel manifesto. Un file esisteva nel manifesto di sincronizzazione con tutti i metadati giusti, ma il suo oggetto su R2 non c’era più. 404, confermato. Il ciclo di sincronizzazione trattava quel 404 come un errore di rete passeggero («fetch-failed»), il che significava: riprovo. Ma un 404 dal server non è un intoppo temporaneo. È un fatto. Il file non c’è.
La correzione introduce un nuovo stato di errore permanente: missing-remote-object. Scatta solo quando l’assenza è dimostrata (il server ha risposto 404, non silenzio né timeout). Il banner sparisce. Il file riceve una riga onesta nella cassaforte. Nessuna eliminazione: rimuovere la voce sarebbe un’affermazione letta dagli altri dispositivi, e io non ho nulla da affermare, solo da osservare. Ho anche controllato il codice desktop e confermato che una voce assente in remoto viene caricata invece di essere cancellata, quindi nessuna copia locale altrove è a rischio.
Checksum del manifesto non aggiornati. Un’altra causa dell’eterno banner: una discrepanza di checksum. Il manifesto aveva un checksum che non corrispondeva più all’oggetto su R2, un residuo di una migrazione in cui le voci erano state scritte con il checksum crittografato e poi l’oggetto era stato riscritto sulla stessa chiave deterministica. Il controllo di integrità faceva il suo lavoro, ma la discrepanza era permanente, non passeggera.
La correzione ripiega su una prova crittografica invece di rifiutare. I byte sono già scaricati (non serve un secondo viaggio di andata e ritorno). Passano per la verifica del tag AES-GCM con le chiavi candidate. Se la superano, la voce viene riparata: checksum e dimensione aggiornati entrambi, in un compare-and-swap così che una ripubblicazione concorrente abbia l’ultima parola. Se falliscono, il comportamento precedente resta esattamente com’era, e non si conclude nulla da byte non autenticati. Il checksum del manifesto è un controllo preliminare economico che abbiamo scritto noi. Il tag GCM è una prova crittografica sia dell’origine sia dell’integrità. Quando non sono d’accordo, fidati della prova. Per uno sguardo più approfondito su come si sovrappongono in pratica gli strati di crittografia di Filarr, quell’articolo ripercorre l’intera architettura difensiva.
Uno stallo tra voci fantasma e autorità di sincronizzazione. La terza causa era un vero stallo. Eliminare le voci fantasma richiedeva l’autorità di sincronizzazione. Ottenere l’autorità di sincronizzazione richiedeva un ciclo senza corruzione. L’unica «corruzione» rimasta erano proprio le voci fantasma. Il banner mostrava tutte e tre le facce: corruzione, trasferimento interrotto, voce non collocabile. Nessuna spariva.
La correzione ha tre parti. Un nuovo tipo di errore permanente, unplaceable-entry, copre le voci presenti solo in remoto e prive di un percorso locale. È un difetto dello schema, non una violazione dell’integrità. Il banner rosso della corruzione non si accende. L’autorità torna raggiungibile. La migrazione ora pubblica localPath su ogni voce di tipo blob, quindi non nasceranno nuove voci non collocabili. E le voci ridondanti possono essere eliminate sotto autorità quando esiste un duplicato dimostrato nello stesso manifesto, con una protezione specifica: due gemelli non collocabili non si eliminano mai a vicenda.
Versionare la capacità di lettura: i vecchi verdetti non sopravvivono al lettore
A parte il circolo del banner: quattordici file di un profilo desktop restavano segnati come «illeggibili» su mobile, anche dopo un aggiornamento che aggiungeva esattamente la capacità di lettura di cui avevano bisogno. Nessun nuovo tentativo, nessuna ripresa. Il ciclo riproponeva un verdetto salvato da una versione precedente dell’app.
Mettere in cache i verdetti di indisponibilità è sensato in linea di principio: non riscaricare un file che fallirà per lo stesso motivo. Ma «questa versione dell’app mobile non può leggere questo file» è un giudizio emesso da un lettore preciso. Deve portare con sé la sua versione.
Il verdetto salvato è ora accompagnato da READER_CAPABILITY_VERSION. Un verdetto di una versione precedente, o un verdetto nudo anteriore al versionamento, viene considerato scaduto e riprovato una volta. La regola per incrementare il numero: ogni volta che la capacità di lettura si amplia (una nuova famiglia di contenitori, un nuovo formato di trasporto, una nuova chiave candidata). Non per le correzioni di bug che non cambiano nulla di ciò che si può leggere. Ogni incremento costa un download per ogni voce prima indisponibile, quindi non è gratis, ma è onesto.
Schermata iniziale: la tua quota di spazio, ora davvero recuperata
Il blocco sull’uso dello spazio nella schermata iniziale mostrava sempre «uso non disponibile» sugli account cloud. Ogni singola volta.
L’API c’era. Il worker restituisce storageUsed e storageLimit su GET /billing/status. Il client aveva un getBillingStatus tipizzato. La logica di visualizzazione, resolveStorageBlock, sapeva calcolare l’indicatore e la soglia di avviso, con i test. Mancava solo la chiamata. HomeScreen chiamava resolveStorageBlock({ accountMode, tier }) senza mai passare i byte. L’etichetta diceva la verità, senza volerlo, a tempo indeterminato.
La quota ora viene recuperata all’apertura della schermata, al cambio di modalità dell’account e alla fine di ogni ciclo di sincronizzazione completo. Si muove quando carichi file, quindi un numero congelato all’apertura invecchierebbe sotto i tuoi occhi. Al meglio delle possibilità e mai bloccante: offline o con il server muto, il blocco torna onestamente a «non disponibile». Una cifra vecchia di tre giorni presentata come attuale sarebbe peggio di nessuna cifra. Nessuna chiamata sugli account locali: lì il blocco non viene mostrato.
Sopra tutto questo c’è una finestra di freschezza di due minuti. Misurato sul dispositivo prima della correzione: sette chiamate a /billing/status in venti secondi, perché la schermata iniziale si ricarica a ogni ritorno sulla scheda. Il gesto che fa muovere la quota (trascinare per aggiornare) ora forza una rilettura immediata. Due minuti tra le letture automatiche: abbastanza pochi perché un ritorno alla home dopo un’importazione mostri il numero giusto, abbastanza da non far costare nulla la navigazione normale. Il timestamp viene impostato solo in caso di successo, così un disservizio passeggero non condanna il blocco a «non disponibile» per tutta la finestra.
Per il contesto su come la sincronizzazione cloud facoltativa resta zero-knowledge mentre gira tutta questa logica di sincronizzazione, quell’articolo spiega cosa viaggia davvero verso il server: blob crittografati, opachi per noi.
3.326 test, tutti verdi
Ogni correzione di questa settimana è arrivata con i suoi test. La suite degli errori di sincronizzazione copre il rilevamento di missing-remote-object su entrambe le forme di risposta di axios (incapsulata e grezza), il versionamento della capacità di lettura e l’adozione della vecchia cache, il ripiego sui checksum non aggiornati con verifica GCM, la correzione dello stallo compresa la protezione dei gemelli non collocabili, e il comportamento del ciclo sulle cartelle in caso di 404. La parità dell’internazionalizzazione è a 1.477/1.477 stringhe.
Un’aggiunta da segnalare: all’avvio, un marcatore di build finisce ora nel log diagnostico. Sembra banale. Non lo è. Una sessione diagnostica persa mi è costata una volta tempo vero di debug, perché non potevo confermare che il dispositivo stesse eseguendo il codice che pensavo. Il marcatore chiude quel buco.
Cosa arriva dopo
Lo strato di sincronizzazione è ora a un punto in cui lo definirei affidabile. Prossimi passi su mobile:
- Una passata di rifinitura dell’interfaccia: l’elenco delle casseforti, l’editor e il flusso di benvenuto hanno ancora spigoli dovuti all’iterazione rapida
- Le schermate di benvenuto: le schermate di derivazione della chiave e della frase di recupero hanno bisogno di un’ultima revisione grafica prima che le veda un nuovo utente (il modello di crittografia che configurano è lo stesso che gira oggi su desktop)
- Test end-to-end su un dispositivo reale lungo tutto il ciclo di sincronizzazione: caricamento da desktop, lettura su mobile, modifica su mobile, risoluzione dei conflitti di nuovo su desktop
- Una piccola build beta per i primi tester
Se vuoi seguire lo sviluppo o avere un accesso anticipato, l’articolo sul traguardo dei 1.000 utenti offre il quadro completo di dove siamo e di cosa viene dopo l’uscita del mobile. Il codice sorgente del client desktop è già pubblico con la BSL 1.1, e l’app mobile eredita la stessa architettura di crittografia.
Mancano circa uno o due mesi. Sviluppato in pubblico per tutto il percorso.