Plainva 0.6.5: fertig gebaut, nie aufgerufen
Drei Menschen meldeten drei Dinge, die nichts miteinander zu tun hatten: einen Anhang, der die App einfrieren ließ, einen Ordner, der sich nicht löschen ließ, und ein weißes Fenster auf einem Mac. Beim Beheben kam dreimal dieselbe Form heraus — etwas Fertiges, das im Code lag und das nie jemand aufgerufen hat.
94 Millionen Zahlen
Die erste Meldung war die klarste. Ein 90-MB-Anhang ließ Plainva einfrieren, abstürzen oder ein weißes Fenster zurück. Drei Symptome, und ich habe eine Weile angenommen, es seien drei Probleme.
Es war eines. Plainvas HTTP-Schicht verwandelt einen Request-Body in Array.from(new Uint8Array(buffer)) und danach in JSON. Bei 90 MB sind das rund 94 Millionen geboxte Zahlen — weit über ein Gigabyte Spitzenspeicher, der Hauptthread minutenlang blockiert. Ob daraus ein Einfrieren, ein Absturz oder ein weißes Fenster wird, hängt davon ab, wie viel Speicher der Rechner zufällig übrig hatte.
Die Lösung ist keine Größengrenze. Ich wurde direkt gefragt, ob wir Uploads begrenzen, und die Antwort war nein: Die Grenze soll die Deines Dienstes sein, nicht die, die meine Architektur gerade überlebt. Also betritt der Inhalt die Anzeigeschicht gar nicht mehr. Ein nativer Befehl nimmt die Datei und streamt sie direkt zum Server. Der Speicherverbrauch bleibt flach, ob die Datei 2 MB oder 2 GB hat.
Darunter saß ein zweites Problem, das mit Speicher nichts zu tun hatte. Die Zeitgrenze einer Anfrage umfasste den Upload selbst — feste 30 Sekunden hießen also nicht „der Server antwortet nicht mehr”, sondern „dieser Upload muss 3 MB/s halten”. Das schafft keine normale Hausleitung für 90 MB. Der Abbruch erschien dann als Netzwerkfehler, und Uploads wiederholen die bewusst nie, weil ein wiederholter Schreibvorgang eine Änderung verdoppeln kann. Die Datei kam schlicht nie an, und nichts sagte, warum. Die Frist wächst jetzt mit der Datei, gegen einen absichtlich pessimistischen Boden.
Ein Fall läuft weiterhin über den alten Weg, und ich sage das lieber, als dass Du es findest: ein verschlüsselter Workspace. Eine Datei zu versiegeln braucht ihre Klartext-Bytes in der Hand, und daran vorbeizustreamen bräuchte ein gechunktes AEAD-Format — das ist eigene Arbeit und nicht etwas, das hier still mitläuft.
Fertig, und nie aufgerufen
Der zweite Strang fällt mir schwerer zu schreiben, weil es kein Fehler im üblichen Sinn ist.
Eine in Plainva angelegte Aufgabe blieb eine Notiz. Sie erschien nie in Google Tasks, nie in den iCloud-Erinnerungen, nie in Microsoft To Do. Ich hatte angenommen, hier fehle Anbieter-Arbeit — jemand müsste die drei Anbindungen erst schreiben.
Sie waren geschrieben. createTask ist in allen drei Anbietern implementiert, vollständig, getestet. Und hatte im gesamten Repository keinen einzigen Aufrufer.
Was fehlte, war nie die Fähigkeit. Es war die Antwort auf „in welche Liste?” — und die gehört der Datenbank, nicht jedem Dialog, der zufällig eine Aufgabe anlegt. Eine Aufgaben-Datenbank kann jetzt eine nennen, mit Keine — bleibt eine Notiz als erster Option. Und alle drei Wege, auf denen eine Aufgabe entsteht — die Eingabe + Neue Aufgabe, eine beförderte Checkbox, eine als Aufgabe erfasste Mail — laufen durch einen Dienst. Nur den ersten zu verdrahten hätte bedeutet, dass es davon abhängt, wo eine Aufgabe geboren wurde, ob sie Deinen Anbieter erreicht — und es hätte an allen drei Stellen richtig ausgesehen, weil die Notiz ohnehin da ist.
Dieselbe Form tauchte noch dreimal auf, während ich dort war. Ein geteilter Kern für Notiz-Einbettungen, aus dem Desktop-Code geschrieben und von niemandem gerufen. Eine Cursor-Spalte im Kalender-Cache, ungenutzt seit dem Tag ihrer Anlage — und jeder Schreibvorgang hätte sie gelöscht, weil ein weggelassenes Feld als „leeren” gelesen wurde. Ein Abbruch-Flag für eine hängende Anmeldung, das nur eine einzige Funktion erreichen konnte, weshalb das Schließen des Browser-Tabs die App drei Minuten warten ließ, ohne dass es etwas zu drücken gab.
Eine Endung ist eine Behauptung, kein Beweis
In 0.6.4 habe ich .csv, .svg und .txt an das Standardprogramm des Systems übergeben. Für das Problem vor mir war das richtig und insgesamt falsch, und dieser Release nimmt es zurück: Textdateien öffnen wieder in Plainva, mit Hervorhebung passend zum Dateinamen.
Das ordentlich zu tun braucht zwei Dinge, die ich nicht hatte.
Das erste ist ein Veto. Eine Dateiendung ist eine Behauptung, die jemand aufgestellt hat, kein Beweis über den Inhalt. Ein umbenanntes .log, ein Datenbank-Abzug namens .csv — die dekodieren verlustbehaftet, und diesen Text zurückzuschreiben zerstört die Datei. Also entscheiden die ersten Bytes: Was nicht sauber dekodiert, geht an die System-App, statt angezeigt und beim Speichern still ruiniert zu werden.
Das zweite ist, die Datei in Ruhe zu lassen. Plainvas Editor hat Windows-Zeilenenden immer auf Unix-Zeilenenden normalisiert und so zurückgeschrieben. Für eine Notiz ist das richtig — Markdown in einem Plainva-Vault ist per Hausregel UTF-8 mit LF — und für eine .ini aus Windows oder eine .csv mit dem Byte-Order-Mark, den Excel will, ist es falsch. Ein Speichern hätte jede Zeile der Datei umgeschrieben: eine Änderung, ein Komplett-Diff, und bei einer .bat eine Änderung dessen, was die Datei tut.
Der Ordner, der sich nicht löschen ließ
Die dritte Meldung las sich wie ein Berechtigungsproblem. Ordner löschen, Fehler bekommen, Ordner immer noch da.
Es war ein Index-Defekt, und der Ordner war tatsächlich von der Platte verschwunden. Wird ein Ordner umbenannt, schreibt die Sync-Warteschlange den gespeicherten Pfad jeder Datei darin um, lässt die Identität der Zeile aber in Ruhe — sie muss, denn an dieser Identität hängen Links, Tags und Eigenschaften. Nur: Die Identität wird aus dem Pfad abgeleitet. Ab diesem Moment sind die Zeilen in sich widersprüchlich, und die nächste Auffrischung fügt eine neue Zeile ein, die mit der bereits vorhandenen kollidiert.
Zwei Dinge machten das unsichtbar. Ein Voll-Scan wird als ein atomarer Block geschrieben, eine einzige schlechte Zeile rollt also den ganzen Scan zurück. Und jeder Aufrufer schluckte den Fehler. Der Index blieb über Neustarts hinweg kaputt — deshalb half nichts, was der Melder versuchte, und deshalb meldete das Löschen das Gegenteil der Wahrheit: Der Ordner war entfernt, die Neu-Indizierung direkt danach warf, und der Baum wurde nie aufgefrischt.
Der Index repariert sich beim nächsten Durchlauf von selbst. Niemand muss etwas aufräumen.
Was ich nicht getan habe
Drei Dinge, um die ich gebeten wurde und die ich abgelehnt habe — das zu sagen ist nützlicher, als sie stillschweigend nicht zu tun.
Ich habe Upload-Größen nicht begrenzt. Ich habe die Engine-Anforderung auf dem Mac mit dem weißen Fenster nicht gesenkt — der Startwächter nennt jetzt, welche Fähigkeit ihm fehlte, und druckt den User-Agent dazu; eine Untergrenze auf Verdacht zu senken ist der Weg zu einer App, die startet und dann an einer unauffälligeren Stelle scheitert. Und ich habe das Standard-Sync-Intervall nicht von 15 auf 300 Sekunden erhöht, was als Mittel gegen das Einfrieren vorgeschlagen worden war: Überlappende Zyklen kann es nicht geben — ein bereits laufender Zyklus kehrt sofort zurück — ein trägerer Standard hätte also ein Symptom verdeckt, dessen Ursache das Speicherproblem oben war.
Außerdem in diesem Release
Verschlüsselte Workspaces lassen sich vom Telefon aus stilllegen, übertragen und Geräten entziehen (weiterhin experimentell — die Kryptografie hat kein unabhängiges Review). Mehrere Dienste eines Kontos am Telefon zu verbinden braucht weniger Zustimmungen, weil die erste eines Durchlaufs gleich mehrere Dienste abdeckt, und der Anbieter, den Du antippst, ist endlich der, dessen Formular sich öffnet. Der Kalender zieht nur noch Änderungen, wo der Anbieter das anbietet. Eine tote Kalender-Anmeldung kostet nicht mehr alle zwei Minuten eine Netzrunde. Und http://-Server im Heimnetz sind unter Android erreichbar, was sie nicht waren — der Release-Build behielt die https-only-Vorgabe der Plattform.
Plainva bleibt, was es ist: Deine Notizen als reine Markdown-Dateien, auf Deiner Platte, in Ordnern, die Du gewählt hast. Lokal zuerst, AGPL, kein Konto nötig.