← Alle Beiträge

Plainva 0.7.0: mehr als ein Fenster, mehr als ein Vault

24. August 2026

Ein Fenster war nie die Grenze. Die Grenze war, dass „der Vault” eine Sache war.

Was sich wirklich ändern musste

Die sichtbare Funktion ist schnell erzählt: Notiz, Datenbank, Graph, Aufgaben, Kalender und Mail können je in einem eigenen Fenster des Betriebssystems liegen. Zweiter Monitor, eigene Taskbar-Kachel, Alt+Tab.

Die Arbeit darunter war keine neue Fähigkeit, sondern eine Trennung. Was bisher „der Vault” hieß, ist jetzt eine Registry von Laufzeiten, gehalten nach Fenster-Label. Alle leben im Heap der Zentrale, weil jedes Fenster eine eigene JavaScript-Insel ist — eine Modul-Map deckt damit den ganzen Prozess.

Tragbar gemacht hat das ein Fund, der schon im Code stand: von 61 Konsumenten von useVault() lesen nur neun App-Ebene, alle übrigen ausschließlich Dienste. Der Kontext wird deshalb geteilt, nicht umgeschrieben.

Ein Prozess, und die Zentrale behält jeden Hintergrunddienst und jeden Schreibzugriff. Zusatzfenster lesen lokal und delegieren Änderungen über einen Fenster-Bus. Das ist keine Nebensache: damit arbeitet die gesamte Sync-Härtung aus dem Juli weiter gegen genau einen Schreiber. Die tragende Regel ist eine Verneinung — ein Inhalt ist app-weit nur einmal offen. Die zweite Anfrage bringt sein Fenster nach vorn. Das erschlägt die Token-Rotations- und Speichern-Rennen strukturell, statt sie zu verwalten.

Die teuerste Zeile war eine Reihenfolge, keine Funktion

Der Erinnerungs-Scheduler hing in der App-Shell — und die rendert nur der Vault, den ein Fenster zeigt. Ein Vault, den ein Fenster für ein anderes offen hält, hätte Sync-Worker, Indexer und Watcher gehabt und keine Uhr. Seine Termine wären nie gemeldet worden.

Dieselbe Klasse in klein: zipRunning war ein Flag statt einer Menge, zwei Archive wurden also zu einer Warteschlange; und der Sync-Status lag unter „dem Vault” statt unter einem Vault.

Ein Refresh-Token gehört einem Grant

Das war der scharfe Punkt. Ein Refresh-Token gehört einem Grant — einer bestätigten Identität plus dem OAuth-Client, der ihn ausgestellt hat —, nicht einem Vault. Und Microsoft wie Dropbox rotieren bei jeder Erneuerung. Mit zwei offenen Vaults hätte die Erneuerung des einen die Kopie des anderen entwertet.

Zwei Hälften, von denen keine die andere ersetzt: ein Tor nach Grant, sodass zwei Fenster in derselben Sekunde sich einen Roundtrip teilen, und ein Durchschreiben in jeden anderen Slot desselben Grants, das den sequentiellen Fall deckt und einen gerade geschlossenen Vault heilt. Ein Label ist dabei keine Identität; ohne bestätigte Identität wird nichts geteilt.

Zwei Vaults, von denen einer im anderen liegt, werden an jeder Tür abgelehnt, mit benanntem Grund, auch bei der Wiederherstellung — Ordner wandern zwischen Sitzungen. Derselbe Vault zweimal bleibt erlaubt. Und das letzte Fenster, das einen Vault schließt, drainiert statt nur zu stoppen: erst setzen sich die Schreibvorgänge, dann läuft der Zyklus zu Ende. Das erzeugt ein neues Rennen, das strukturell geschlossen ist: die React-Aufräumung kann nicht awaiten, also wird das Versprechen geparkt und das nächste Öffnen desselben Vaults wartet darauf.

Einstellungen reisen, wenn Du nie widersprochen hast

Es gibt eine Verhaltensänderung, die Bestandsnutzer merken, und die gehört offen gesagt.

Der Einstellungs-Sync war Opt-in, und ein frischer Vault schrieb undefined in den Schalter — und undefined hieß „aus”. Tagesnotiz-Format, Vorlagen-Ordner und Backup-Regeln blieben also auf jedem Gerät einzeln stehen, und gefragt wurde nie. Die Regel ist jetzt !== false: nie gefragt heißt an, ausgeschaltet bleibt aus.

Das ist dieselbe Semantik, die der Geheimnis-Transport seit jeher führt, nur mit umgekehrtem Default — und die Anmeldungen behalten ihre bewusst. Deine Zugangsdaten reisen weiterhin nur, wenn Du es sagst.

Der erste externe Code-Beitrag erreicht Nutzer

Pedro Algarvio meldete einen Vault, der sich nicht öffnen ließ: ein Obsidian-Vault mit einem Python-venv und einem Linter-Cache darin, auf Arch Linux, installiert über ein AUR-Paket. Das ist nebenbei ein Befund über die Verbreitung — die Doku kennt AUR bisher nur als „optional später”, tatsächlich installieren Leute schon darüber.

Beide Pull Requests trafen die richtige Ebene. .attachments/.gitkeep scheiterte am Capability-Scope des Dateisystems, weil require_literal_leading_dot auf Unix per Default an ist und kein Muster zwei Dot-Segmente hintereinander abdeckt. Und ein symlinktes Verzeichnis — lib64 -> lib in jedem venv — wurde als Datei klassifiziert, weil readDir seine isDirectory-Angabe nicht über Symlinks auflöst.

Drei Dinge folgten, die keiner der beiden PRs von außen sehen konnte.

Die Ausschlussliste war der eigentliche Fehler, und sie steckte in der falschen Schicht. Naheliegend wäre, .venv und __pycache__ zu ergänzen. Das wäre in zwei Fallen gelaufen. Erstens hätte es wie eine Massenlöschung ausgesehen: der Voll-Scan meldet jede Datei, die im Index steht und auf der Platte fehlt — der Ausschluss macht also Tausende venv-Dateien schlagartig „fehlend”, und die Löschungen wären in die Sync-Queue gelaufen. Der Voll-Scan trennt jetzt: aus dem Index entfernen ja, an den Sync melden nur, was kein interner Pfad ist. Zweitens galt die Regel nur im Desktop-Adapter, sodass der mobile Walk node_modules/**/*.md indizierte. Sie liegt jetzt im geteilten Kern.

Der Zyklus-Guard konnte zwei Wege auf dasselbe Verzeichnis nicht unterscheiden. #72 sagt das in seinem eigenen Kommentar und setzt einen Tiefen-Deckel als Notausgang, der das Hängen verhindert, nicht aber die doppelte Indizierung: visited hielt Pfade, und lib64 sieht neben lib wie ein anderer Ordner aus. Er schlüsselt jetzt auf die Identität des Verzeichnisses — und das kostet keinen zusätzlichen Dateisystem-Aufruf: der stat(), der die Identität liefert, ersetzt das exists(), das an derselben Stelle wachte.

Und ein Test pinnte die Form der Konfiguration statt ihrer Wirkung. Er überlebt einen Umbau der Capability-Patterns — genau die Änderung, die für die Trusted-Roots-Arbeit ansteht — während die Abdeckung, für die er steht, still bricht. Es gibt jetzt einen Rust-Test, der die echten Patterns gegen den echten Flag matcht, mit demselben glob und denselben Match-Optionen, die das Plugin benutzt.

Zwei Wächter, die etwas über sich selbst gelernt haben

Der Startwächter trifft eine einzige Aussage — „nach acht Sekunden hat nichts gerendert” — und hat sie nie wieder überprüft. Ein langsamer Start widerlegt sie einen Moment später, und die Vollbild-Meldung blieb trotzdem stehen: „Plainva didn’t start” über einer laufenden App, die jeden Klick abfing. Gefunden hat das ein Push, in dem 47 von 265 End-to-End-Tests genau dorthin klickten — das Element darunter war jedes Mal visible, enabled and stable.

Ein Nutzer auf einer ausgelasteten Maschine hätte dasselbe gesehen und es geglaubt. Deshalb war die naheliegende Abhilfe — die Gnadenfrist hochsetzen — die falsche: sie tauscht eine willkürliche Schwelle gegen die nächste und begräbt eine funktionierende App weiterhin, nur später. Der Zweig kennt jetzt seine eigene Prämisse und nimmt sein Schild zurück, sobald die App nachweislich gemountet ist. Der Fehler-Zweig bleibt unangetastet und behält den Schirm für immer: dort wurde die Prämisse nie widerlegt.

Der zweite ist das eingefrorene Budget. Ein Wächter hielt zwölf Dateien mit vierzig Fundstellen fest — die Bauform, die zweimal ein weißes Fenster ausgeliefert hat — und sein eigener Kommentar sagte, das sei kein Freispruch, sondern nur noch keine Chunk-Reihenfolge, die es trifft. Multi-Window ist diese Reihenfolge. Das Budget steht deshalb nur noch auf den drei Einstiegspunkten, und das ist eine Entscheidung, kein Rest: ein Einstiegsmodul ist der Anfang des Graphen, und es gibt keine Chunk-Reihenfolge, die es vor sich selbst setzt.

Was nicht drin ist

Alles in diesem Release ist eine Erstauslieferung; nichts davon war je in einem Release. Bewusst weiter offen: die Verschlüsselung hat kein unabhängiges Review, die Signatur-Gegenprobe mit einem manipulierten Artefakt steht aus, und hier gibt es kein macOS-Gerät — der Ordner-Lösch-Befund aus einem früheren Issue bleibt unreproduziert.

Und die Abnahme der Fenster-Arbeit läuft noch. Drei gemeldete Befunde sind behoben, aber am echten Fenster ungeprüft; sie werden an diesem Build nachgeholt. Das ist ein benanntes Risiko, kein Versehen — ein Fehler in einem Zusatzfenster kostet keine Daten, weil die Zentrale jeden Schreibzugriff behält.