Plainva 0.6.8: ein Konto, so oft Du es auch verbindest
Der letzte Release hat den Anker in einer Aufgaben-Notiz repariert. Dieser hier repariert das, was den Anker weggeworfen hat.
Neu verbinden ist die Reparatur
Eine abgelaufene Anmeldung ist kein exotischer Zustand. Tokens laufen ab, ein Anbieter zieht eine Zustimmung zurück, Du änderst ein Passwort — und der naheliegende Weg zurück ist, das Konto erneut zu verbinden. Bisher entstand dabei ein zweites Konto neben dem ersten, und der Aufgaben-Abgleich behandelte es als Fremden: jede gespiegelte Aufgabe wurde ein weiteres Mal angelegt.
Die Zeile, um die es geht, heißt pim_task_state. Sie ist das Einzige, was eine Aufgaben-Notiz mit ihrer Aufgabe beim Anbieter verbindet. Geht sie verloren, erkennt der Abgleich die Notiz nicht mehr, legt die Aufgabe ein zweites Mal an und hört auf, ihre Löschung zu melden — genau die Gefahr, die der Release davor schon beim Namen genannt hatte.
Deshalb werden die Zeilen umgehängt statt verworfen, und bei einer Kollision gewinnt das Ziel: seine Zeile trägt die Historie, die frische hat höchstens einen halben Zyklus hinter sich. Adoptiert wird nur auf eine vom Anbieter bestätigte Identität hin — nicht auf einen Anzeigenamen. Zwei Menschen in einer Firma heißen leicht gleich, und der Einstellungs-Sync verweigert die Zusammenlegung auf ein Label hin aus genau diesem Grund. Bei CalDAV, wo es keine bestätigte Identität gibt, entsteht wie bisher ein eigener Eintrag. Das ist eine Grenze, die ich lieber benenne als übertünche.
Zwei Reihenfolgen, die das Ganze tragen
Beim Lesen kam etwas heraus, womit ich nicht gerechnet hatte: das Validieren der Verbindung erneuert den Token bereits, und Microsoft rotiert ihn dabei. Der rotierte liegt unter der Wegwerf-ID, weil das die ID ist, mit der der Auth-Provider gebaut wurde. Wer die Zugangsdaten des Aufrufers unter die Ziel-ID schriebe, legte dem überlebenden Konto einen verbrauchten Token hin.
Zwei Reihenfolgen halten das zusammen, jede durch eine eigene Rot-Gegenprobe gesichert: die Zeilen wandern vor dem Löschen der Wegwerf-Konto-Zeile (Kalender und Aufgabenlisten kaskadieren daran), und der Token wird vor dem Räumen des Wegwerf-Slots geschrieben.
Über die Prüfung selbst habe ich dabei auch etwas gelernt. Eine Gegenprobe blieb grün, als ich nur den frühen Identitäts-Wächter entfernte — der Schutz liegt doppelt, und es fiel die Nachbar-Zusicherung. Beide zusammen messen das Verhalten, nicht einen bestimmten Wächter; das steht jetzt neben dem Test.
Woher eine Notiz kommt
Google hat im Juli OKF 0.2 veröffentlicht. Der Sprung ist additiv — ein 0.1-Bundle läuft unverändert weiter — und bringt fünf optionale Familien, die eine Frage beantworten: wie sehr traust Du diesem Dokument?
Eine Notiz kann jetzt tragen, woher sie kommt (generated, sources), wer sie geprüft hat (verified), ob sie Entwurf oder veraltet ist (status) und ab wann sie als überholt gilt (stale_after). Plainva stempelt das nur dort, wo eine Maschine schreibt: Import, Mail-Erfassung und der Aufgaben-Abgleich, dort nur bei der Anlage. Der Editor fasst eine Trust-Familie nie an, und Bestand wird nicht nachträglich bestempelt. Deine Notizen gehören Dir; ein Werkzeug, das nachträglich Urheberschaft an ihnen beansprucht, würde lügen.
Die einzige Trust-Aktion eines Menschen ist „Als geprüft markieren”. Sie hängt human:<Name> an die Liste an, statt sie zu ersetzen — die Liste ist die Prüfhistorie, ein zweiter Prüfer überschreibt den ersten nie.
Die Regel, ohne die das Ganze Schaden angerichtet hätte, ist die Form-Prüfung vor der Beanspruchung: eine Aufgaben-Notiz mit eigener Spalte status: Offen behält ihre gewöhnliche Eigenschaft und bekommt kein Badge. Sonst hätte jede Aufgaben-Datenbank über Nacht Lifecycle-Semantik gehabt.
Zwei Dinge sind bewusst nicht gebaut. log.md gehört dem KI-Harness, nicht hierher — heute gäbe es keinen Leser, mechanische Einträge verfehlten den Prosa-Anspruch der Spec, und ein Log bei jedem Speichern wäre die konfliktträchtigste Datei des Vaults. Und Trust ist Anzeige, keine Durchsetzung: ein veraltetes Dokument wird markiert, nicht gesperrt.
Vier Dinge, die dem Telefon fehlten
Vault-weites Suchen und Ersetzen. Ordner-Übersichten. Der Import mit 27 Quellen samt Notion. Und die OKF-Konvertierung.
Die Reihenfolge war nicht beliebig — die Anforderung an die Datensicherheit steigt von der ersten zur letzten. Suchen und Ersetzen schreibt in viele Notizen, aber jede für sich. Ordner-Übersichten schreiben und benennen um, also müssen Links mitziehen. Der Import schreibt einen ganzen Vault und fasst zum ersten Mal ein fremdes Geheimnis an (der Notion-Token geht in den Zugangsdaten-Speicher, nie in den Vault und nie in den Einstellungs-Sync). Und die Konvertierung schreibt in jede Notiz — während ein Telefon ihr jederzeit den Strom nehmen kann.
Deshalb ist der Lauf gehoben, nicht nachgebaut. Sicherung je Datei, Prüfung nach dem Schreiben, Überspringen mit Bericht, Abbruch, Trockenlauf — all das lag am Desktop, und die unveränderten Desktop-Tests sind der Beweis, dass sich beim Heben nichts bewegt hat. Obendrauf kommt nur, was ein Telefon wirklich braucht: ein Journal vor der ersten Änderung (eine Datei, atomar, außerhalb des Containers, damit kein halber Zustand zu anderen Geräten reist; ohne Journal wird nicht konvertiert), eine Wiederaufnahme beim Start, die fragt statt zu handeln, und eine Vorschau, die die Notizen beim Namen nennt.
Die offene Frage meines Plans hat sich beim Bauen selbst beantwortet: der Backup-Ordner IST das Register. Der Lauf kopiert jede Datei unmittelbar vor dem Überschreiben — der Ordner ist damit schon das vollständige Verzeichnis dessen, was angefasst wurde. Fortsetzen schreibt in denselben Ordner; zwei Ordner hießen zwei Rückgängigs, von denen keines allein den Vault herstellt.
„Später” ist eine echte Antwort, gefragt einmal pro App-Start. Ein Blatt, das man auf dem eigenen Telefon nicht wegbekommt, ist schlimmer als der Zustand, vor dem es warnt. Und der Desktop hat dieselbe Wiederaufnahme in diesem Release bekommen: ein Desktop-Prozess wird zwar nicht mitten im Lauf abgeräumt, ein Stromausfall ist aber genau dieser Fall und hinterlässt genau diesen halb konvertierten Vault.
Eine 90-MB-Datei, alle zwei Minuten geändert
Plainva sichert bei jedem Schreibvorgang eine Momentaufnahme, damit Du zurückkannst. Bei einem großen Anhang wird diese Rechnung schnell unschön: neunzig Megabyte, alle zwei Minuten geändert, konnten hundert Kopien in .plainva hinterlassen — neun Gigabyte für eine Datei.
Oberhalb von 5 MB behält ein Schreibvorgang jetzt eine Momentaufnahme statt des vollen Verlaufs, entschieden an der Dateigröße vor dem Lesen, sodass die neunzig Megabyte gar nicht erst in den Speicher kommen. Nur Schreibvorgänge, und das ist die Regel selbst: ein Write lässt die neue Fassung auf der Platte, der Verlauf ist dort Komfort. Eine Löschung ist der Fall, in dem die Momentaufnahme das Einzige ist, was zurückholt — und wird weiterhin vollständig gesichert.
Einen Regler dafür gibt es bewusst nicht. Wer ihn auf null stellt, bekommt die neun Gigabyte zurück.
Der erste externe Code-Beitrag
KDOJP hat etwas Konkretes und Echtes gefunden: Auf macOS wird ein Ordnername mit kombinierenden Zeichen zerlegt indiziert (ü als u + ¨), während eine per Tastatur getippte .base ihn zusammengesetzt trägt. SQLite vergleicht Byte für Byte — die Datenbank rendert und bleibt leer. Betroffen ist jeder Mac-Vault mit Umlauten im Ordnernamen, nicht nur der japanische, der es ans Licht gebracht hat.
Überzeugt hat mich die Ebene, die er getroffen hat. Pfad-Identität ist in Plainva bewusst nicht normalisierungs-insensitiv, weil das sync_state und den Index jedes bestehenden Vaults neu verschlüsselte. Er hat nicht am Index gedreht, sondern zur Abfragezeit beide Formen gefragt.
Die Bringschuld lag eine Ebene tiefer, und ich habe sie im selben Release mitgenommen: der In-Memory-Evaluator — der bei verschachtelten Filtergruppen übernimmt — verglich weiter byte-exakt, eine reparierte Datenbank wäre also wieder leer gewesen, sobald jemand eine Filtergruppe anlegt. Und der Test misst jetzt das Verhalten statt der Form des SQL: echtes SQLite, eine Notiz unter einem zerlegt benannten Ordner, abgefragt aus einer zusammengesetzten Quelle.
iOS verlangt 16.4
Das Bündel verlangt Safari 16.4, seit die geteilten Pakete Lookbehind nutzen. Das Xcode-Projekt deklarierte weiter 15.0 — der App Store bot die App also Geräten an, auf denen sie nur weiß bleiben konnte. Das Anheben kostet nichts, was je lief.
Und das Telefon konnte es nicht einmal sagen: sein Fatal-Overlay lebte innerhalb des Modulgraphen, tot in genau dem Fall, für den es geschrieben wurde. Es hat jetzt den Wächter des Desktops. Die beiden Plattformen brauchen dabei verschiedene Sätze: auf iOS kommt die Engine mit dem System, eine Versionsangabe ist dort die einzige wahre Aussage; auf Android ist die WebView getrennt aktualisierbar, dort ist die ehrliche Antwort eine Handlung statt einer Zahl.
Alles liegt auf GitHub. Bestehende Installationen aktualisieren sich selbst. Wenn Du auf etwas stößt, sag es mir — der letzte Release enthielt einen Fix, der als weggeworfener Halbsatz von jemandem angefangen hat.