Was kostet es, Historie spaeter moeglich zu halten? #22

Closed
opened 2026-08-28 09:22:44 +00:00 by RDietermann · 2 comments
Owner

Part of #16

Question

Was kostet es, eine Historie später möglich zu halten — und schließt eine naive Schreib-Entscheidung sie aus?

Hintergrund: Beim Council zu diesem Vorhaben warnte eine Stimme, dass die Schreib-Entscheidung, einmal getroffen und ein halbes Jahr verdrahtet, Historie und Undo über Sitzungen hinweg nur noch als Aufsatz zulässt. Vorgeschlagen war ein Append-Log neben der Notiz, aus dem die .md als lesbare Sicht materialisiert wird.

Historie ist nicht geplant. Dieses Ticket beschafft nur die Fakten, damit die Schreib-Entscheidung in #19 bewusst statt versehentlich fällt.

Konkret zu klären:

  • Wie lösen vergleichbare lokale Markdown-Editoren das (Obsidian mit seiner Dateiversionierung, Logseq, Zettlr)? Legen sie Zwischenstände an, und wo?
  • Was würde ein Append-Log konkret kosten — zusätzliche Dateien pro Notiz, Aufräumen, Größenwachstum, und was passiert, wenn jemand die .md von außen ändert, ohne dass das Log es mitbekommt?
  • Gibt es einen billigeren Mittelweg: etwa eine einzelne Sicherungskopie der Vorfassung, oder das Auslagern der Historie in ein Git-Repository im Workspace?
  • Und die eigentliche Frage: Gibt es eine Schreib-Entscheidung, die Historie später unmöglich oder unverhältnismäßig teuer macht — oder ist das in Wahrheit jederzeit nachrüstbar?

Zielgröße: eine belastbare Antwort auf die letzte Frage, mit Begründung. Wenn Historie jederzeit nachrüstbar ist, ist der Einwand entkräftet und #19 kann frei entscheiden.

Part of #16 ## Question Was kostet es, eine Historie später *möglich* zu halten — und schließt eine naive Schreib-Entscheidung sie aus? Hintergrund: Beim Council zu diesem Vorhaben warnte eine Stimme, dass die Schreib-Entscheidung, einmal getroffen und ein halbes Jahr verdrahtet, Historie und Undo über Sitzungen hinweg nur noch als Aufsatz zulässt. Vorgeschlagen war ein Append-Log neben der Notiz, aus dem die `.md` als lesbare Sicht materialisiert wird. Historie ist **nicht** geplant. Dieses Ticket beschafft nur die Fakten, damit die Schreib-Entscheidung in #19 bewusst statt versehentlich fällt. Konkret zu klären: - Wie lösen vergleichbare lokale Markdown-Editoren das (Obsidian mit seiner Dateiversionierung, Logseq, Zettlr)? Legen sie Zwischenstände an, und wo? - Was würde ein Append-Log konkret kosten — zusätzliche Dateien pro Notiz, Aufräumen, Größenwachstum, und was passiert, wenn jemand die `.md` von außen ändert, ohne dass das Log es mitbekommt? - Gibt es einen billigeren Mittelweg: etwa eine einzelne Sicherungskopie der Vorfassung, oder das Auslagern der Historie in ein Git-Repository im Workspace? - Und die eigentliche Frage: Gibt es eine Schreib-Entscheidung, die Historie später **unmöglich** oder unverhältnismäßig teuer macht — oder ist das in Wahrheit jederzeit nachrüstbar? Zielgröße: eine belastbare Antwort auf die letzte Frage, mit Begründung. Wenn Historie jederzeit nachrüstbar ist, ist der Einwand entkräftet und #19 kann frei entscheiden.
RDietermann added the wayfinder:research label 2026-08-28 09:22:44 +00:00
RDietermann added a new dependency 2026-08-28 09:24:09 +00:00
RDietermann self-assigned this 2026-08-28 09:25:38 +00:00
Author
Owner

Antwort: Nein — Historie ist jederzeit nachruestbar. Der Einwand ist entkraeftet, #19 kann frei entscheiden.

Recherche liegt in docs/research/historie-nachruesten.md auf Branch research/historie (nicht gepusht).

Die Kernfrage

Ein Schreibverfahren "temporaere Datei schreiben, dann umbenennen" schliesst eine spaetere Historie nicht aus — es ist im Gegenteil das guenstigere der beiden zur Wahl stehenden Verfahren.

Historie braucht vier Dinge: einen Ausloeser, die Vorfassung, einen Ablageort, eine Aufraeumregel. Nur die ersten beiden haengen ueberhaupt am Schreibverfahren — und beide fallen bei temp+rename ohnehin an: Der Ausloeser ist der Aufruf der Schreibfunktion, und die Vorfassung liegt im Moment vor dem Umbenennen noch unversehrt unter ihrem Pfad. Man muss sie nur lesen, bevor man umbenennt.

Ein direktes fs::write zerstoert die Vorfassung dagegen nach dem ersten Byte. Wer dort Historie nachruestet, muss die Datei zusaetzlich vorher lesen. Also: Die Entscheidung, die #19 zu treffen hat, macht Historie nicht teurer, sondern billiger.

Was Historie tatsaechlich teuer machen wuerde

Nicht das Wie des Schreibens, sondern das Wo: mehrere Schreibstellen im Code. Wenn Autosave hier schreibt, "Notiz verlassen" dort und "Fenster schliessen" an dritter Stelle, muss Historie an jeder Stelle nachgezogen werden, und jede vergessene ist ein Loch, das man erst durch einen Bug bemerkt.

Das ist die einzige echte Auflage an #19 — und sie kostet heute exakt nichts, weil es aktuell ueberhaupt keine Schreibstelle im Code gibt (verifiziert: keine Fundstelle fuer fs::/write/File:: unter src/).

Der Preis, Historie moeglich zu halten, betraegt: eine Funktion. Keine Datei, kein Format, kein Byte auf der Platte, keine Dependency.

Die Asymmetrie laeuft andersherum als behauptet

Richtung Aufwand
"Datei ist die Wahrheit" -> "Datei plus Sicherungen" Ergaenzung. Eine Funktion erweitern, ein Ordner, eine Aufraeumregel. Bestehende Notizen laufen unveraendert weiter.
"Log ist die Wahrheit" -> zurueck Migration. Alles materialisieren, Logs entsorgen, gesammelte Historie wegwerfen.

Wer sich die Option offenhalten will, haelt sie gerade dadurch offen, dass er den Append-Log nicht baut. Der Log ist die Einbahnstrasse, nicht das schlichte Schreiben.

Wie die Vergleichbaren es loesen (alles gegen Primaerquellen)

Werkzeug Wo Format Intervall Aufbewahrung
Obsidian File recovery App-Systemordner %APPDATA%\Obsidian\, ausserhalb des Vault Volltext-Snapshots 5 Min 7 Tage
Joplin Note History Tabelle revisions in SQLite (es gibt keine .md) Diff-Kette, diff-match-patch 10 Min 90 Tage
Logseq 0.10.9 logseq/bak/<datei>/ im Graph-Ordner Volltext, Zeitstempel im Namen nur bei Konflikt/Schreibfehler 6 pro Datei
Zettlr — es gibt keine — — —
Syncthing (kein Editor) .stversions/ im Sync-Ordner Volltext, Zeitstempel pro Aenderung logarithmisch ausgeduennt

Drei Befunde stechen heraus:

  1. Obsidian ist der Existenzbeweis. Gleiche Ausgangslage wie DioNotes — lose .md in einem Ordner — und die Historie ist ein nachtraeglich aufgesetztes Core-Plugin, das mit dem Schreibverfahren des Kerns nichts zu tun hat und komplett ausserhalb des Vault lebt. Genau das Modell "Historie ist eine Schicht ueber dem Schreiben", in Produktion vorgefuehrt.
  2. Zettlr hat seit Jahren gar keine und verweist in der Doku auf Cloud-Backup. "Historie nicht bauen" ist eine tragfaehige Produktentscheidung, kein Aufschub.
  3. Logseq sichert nur, wenn es brenzlig wird — nicht bei jedem Speichern, sondern bei erkanntem Konflikt, Schreibfehler oder externer Aenderung. Maintainer woertlich: "It's a safe net."

Der Append-Log konkret

  • Kosten: eine Sidecar-Datei pro Notiz (500 Notizen -> 1.000 Dateien), monotones Wachstum mit der Zahl der Bearbeitungen statt mit der Textgroesse, und Aufraeumen heisst zwangslaeufig Historie wegwerfen. Die Autosave-Entscheidung aus #18 wuerde dadurch zur Speicherplatz-Entscheidung.
  • Der Ausschlussgrund ist aber ein anderer: zwei Wahrheiten. Es gibt bewusst keinen Filewatcher, und #20 rechnet ausdruecklich damit, dass Dropbox/Syncthing/Git die Dateien aendern, waehrend die App laeuft. Aendert jemand die .md von aussen, weiss der Log nichts davon — und ueberschreibt die Aenderung beim naechsten Materialisieren stillschweigend. Beim "Datei ist die Wahrheit"-Modell gibt es dieses Problem gar nicht: eine veraltete Sicherungskopie ist eine weniger nuetzliche Sicherungskopie, kein inkonsistenter Zustand.
  • Und er bricht das Versprechen. Die .md wird zur Ausgabe; eine Aenderung an ihr ist wirkungslos. Der Nutzer darf seine Dateien dann nur noch lesen, nicht mehr bearbeiten.

Die billigeren Mittelwege (alle nachruestbar, keiner verlangt heute etwas)

Option Zusaetzliche Dateien Wachstum Aufraeumen Dependency
Eine Sicherungskopie der Vorfassung 1 pro Notiz keins entfaellt keine
Zeitstempel-Ordner, logarithmisch ausgeduennt (Syncthing-Modell) N pro Notiz beschraenkt ~1 Funktion keine
Git im Workspace .git/, >=3 lose Objekte pro Commit unbeschraenkt git gc, teuer gix oder git2

Zu Git: gc.auto = 6700 lose Objekte, also ~2.200 Commits bis zum ersten automatischen Repack — bei "ein Commit pro Speichern" mit Autosave eine Frage von Wochen. Bemerkenswert: Zettlr empfiehlt Git nicht, Logseq nutzt es nur lesend und setzt voraus, dass der Nutzer es selbst eingerichtet hat. Niemand richtet dem Nutzer ein Repo ein.

Belastbarkeit

  • Hart belegt: Obsidian betreibt eine produktive Historie fuer lose .md als aufgesetzte, vom Schreibverfahren entkoppelte Schicht. Ein Werkzeug mit derselben Ausgangslage hat das Problem nachweislich nachtraeglich geloest.
  • Argumentation (nicht durch Quelle belegt): dass genau eine Schreibstelle die einzige load-bearing Auflage ist. Folgt aber zwingend daraus, dass eine Schicht ueber N Aufrufstellen N Aenderungen kostet und ueber einer eine.
  • Nicht belegbar geblieben: konkrete Groessenzahlen fuer CRDT-/Append-Log-Bibliotheken. Fuer die Entscheidung folgenlos, weil der Ausschlussgrund das Zwei-Wahrheiten-Problem ist, nicht die Groesse. Ebenso: Obsidians Schreibverfahren (Closed Source, keine offizielle Aussage) und die kolportierten GB-grossen Logseq-bak-Ordner (belegt ist unbegrenztes Ordner-Wachstum, keine Groessenangabe).

Randbefunde fuer #19 und #20

Fielen bei der Recherche mit an, sind im Dokument ausfuehrlich belegt:

  • Weder Rust noch Microsoft dokumentieren rename als atomar — das Wort kommt in beiden Doku-Seiten nicht vor. Microsoft empfiehlt fuer "document-like data" ausdruecklich ReplaceFile, nicht MoveFileEx. Kein Rust-Crate nutzt das.
  • temp+rename verliert Erstellungszeit, DACLs, Alternate Data Streams, Object ID, EFS/Compression (bewiesen per Kontrast aus den ReplaceFileW-Remarks). Folge: ein "erstellt am" gehoert ins Frontmatter, nicht ins Dateisystem.
  • Realistischstes Fehlerbild: ERROR_SHARING_VIOLATION, wenn Defender oder ein Sync-Client die Zieldatei ohne FILE_SHARE_DELETE offen haelt. tempfile::NamedTempFile::persist gibt die Temp-Datei im PersistError zurueck — genau fuer den Retry gebaut.
  • Fuer #20: Zettlr und Logseq loesen den Konflikt beide ueber Inhaltsvergleich, nicht ueber mtime allein. Zettlrs Code-Kommentar woertlich: mtime nur "neuer", nicht "ungleich" pruefen, "to prevent sluggish cloud synchronization services (e.g. OneDrive and Box) from having text appear to 'jump'".
  • Fuer #18: Dropbox nennt als dokumentierte Ursache Nr. 3 fuer Conflicted Copies woertlich "applications with an auto-save feature" — Argument fuers Entprellen.

Fazit

Der Einwand aus dem Council trifft eine reale Gefahr, aber am falschen Ort. #19 darf allein nach seinen eigenen Kriterien entscheiden — Absturzsicherheit, Sichtbarkeit der temporaeren Datei, Dateirechte, Aufraeumen. Historie legt genau eine Auflage auf, und die ist heute gratis: eine einzige Funktion, durch die alles Schreiben laeuft.

Ticket bleibt offen.

## Antwort: Nein — Historie ist jederzeit nachruestbar. Der Einwand ist entkraeftet, #19 kann frei entscheiden. Recherche liegt in `docs/research/historie-nachruesten.md` auf Branch `research/historie` (nicht gepusht). ### Die Kernfrage **Ein Schreibverfahren "temporaere Datei schreiben, dann umbenennen" schliesst eine spaetere Historie nicht aus — es ist im Gegenteil das guenstigere der beiden zur Wahl stehenden Verfahren.** Historie braucht vier Dinge: einen Ausloeser, die Vorfassung, einen Ablageort, eine Aufraeumregel. Nur die ersten beiden haengen ueberhaupt am Schreibverfahren — und beide fallen bei temp+rename ohnehin an: Der Ausloeser ist der Aufruf der Schreibfunktion, und die Vorfassung liegt im Moment vor dem Umbenennen noch unversehrt unter ihrem Pfad. Man muss sie nur lesen, bevor man umbenennt. Ein direktes `fs::write` zerstoert die Vorfassung dagegen nach dem ersten Byte. Wer *dort* Historie nachruestet, muss die Datei zusaetzlich vorher lesen. Also: Die Entscheidung, die #19 zu treffen hat, macht Historie nicht teurer, sondern billiger. ### Was Historie tatsaechlich teuer machen wuerde Nicht das *Wie* des Schreibens, sondern das *Wo*: **mehrere Schreibstellen im Code.** Wenn Autosave hier schreibt, "Notiz verlassen" dort und "Fenster schliessen" an dritter Stelle, muss Historie an jeder Stelle nachgezogen werden, und jede vergessene ist ein Loch, das man erst durch einen Bug bemerkt. Das ist die einzige echte Auflage an #19 — und sie kostet heute exakt nichts, weil es aktuell **ueberhaupt keine Schreibstelle im Code gibt** (verifiziert: keine Fundstelle fuer `fs::`/`write`/`File::` unter `src/`). > **Der Preis, Historie moeglich zu halten, betraegt: eine Funktion.** Keine Datei, kein Format, kein Byte auf der Platte, keine Dependency. ### Die Asymmetrie laeuft andersherum als behauptet | Richtung | Aufwand | |---|---| | "Datei ist die Wahrheit" -> "Datei plus Sicherungen" | **Ergaenzung.** Eine Funktion erweitern, ein Ordner, eine Aufraeumregel. Bestehende Notizen laufen unveraendert weiter. | | "Log ist die Wahrheit" -> zurueck | **Migration.** Alles materialisieren, Logs entsorgen, gesammelte Historie wegwerfen. | **Wer sich die Option offenhalten will, haelt sie gerade dadurch offen, dass er den Append-Log nicht baut.** Der Log ist die Einbahnstrasse, nicht das schlichte Schreiben. ### Wie die Vergleichbaren es loesen (alles gegen Primaerquellen) | Werkzeug | Wo | Format | Intervall | Aufbewahrung | |---|---|---|---|---| | **Obsidian** File recovery | App-Systemordner `%APPDATA%\Obsidian\`, **ausserhalb** des Vault | Volltext-Snapshots | 5 Min | 7 Tage | | **Joplin** Note History | Tabelle `revisions` in SQLite (es gibt keine `.md`) | Diff-Kette, `diff-match-patch` | 10 Min | 90 Tage | | **Logseq** 0.10.9 | `logseq/bak/<datei>/` **im** Graph-Ordner | Volltext, Zeitstempel im Namen | **nur bei Konflikt/Schreibfehler** | 6 pro Datei | | **Zettlr** | — es gibt keine | — | — | — | | **Syncthing** (kein Editor) | `.stversions/` im Sync-Ordner | Volltext, Zeitstempel | pro Aenderung | logarithmisch ausgeduennt | Drei Befunde stechen heraus: 1. **Obsidian ist der Existenzbeweis.** Gleiche Ausgangslage wie DioNotes — lose `.md` in einem Ordner — und die Historie ist ein *nachtraeglich aufgesetztes Core-Plugin*, das mit dem Schreibverfahren des Kerns nichts zu tun hat und komplett ausserhalb des Vault lebt. Genau das Modell "Historie ist eine Schicht ueber dem Schreiben", in Produktion vorgefuehrt. 2. **Zettlr hat seit Jahren gar keine** und verweist in der Doku auf Cloud-Backup. "Historie nicht bauen" ist eine tragfaehige Produktentscheidung, kein Aufschub. 3. **Logseq sichert nur, wenn es brenzlig wird** — nicht bei jedem Speichern, sondern bei erkanntem Konflikt, Schreibfehler oder externer Aenderung. Maintainer woertlich: *"It's a safe net."* ### Der Append-Log konkret - **Kosten:** eine Sidecar-Datei pro Notiz (500 Notizen -> 1.000 Dateien), monotones Wachstum mit der Zahl der Bearbeitungen statt mit der Textgroesse, und Aufraeumen heisst zwangslaeufig Historie wegwerfen. Die Autosave-Entscheidung aus #18 wuerde dadurch zur Speicherplatz-Entscheidung. - **Der Ausschlussgrund ist aber ein anderer: zwei Wahrheiten.** Es gibt bewusst keinen Filewatcher, und #20 rechnet ausdruecklich damit, dass Dropbox/Syncthing/Git die Dateien aendern, waehrend die App laeuft. Aendert jemand die `.md` von aussen, weiss der Log nichts davon — und ueberschreibt die Aenderung beim naechsten Materialisieren stillschweigend. **Beim "Datei ist die Wahrheit"-Modell gibt es dieses Problem gar nicht:** eine veraltete Sicherungskopie ist eine weniger nuetzliche Sicherungskopie, kein inkonsistenter Zustand. - **Und er bricht das Versprechen.** Die `.md` wird zur Ausgabe; eine Aenderung an ihr ist wirkungslos. Der Nutzer darf seine Dateien dann nur noch lesen, nicht mehr bearbeiten. ### Die billigeren Mittelwege (alle nachruestbar, keiner verlangt heute etwas) | Option | Zusaetzliche Dateien | Wachstum | Aufraeumen | Dependency | |---|---|---|---|---| | Eine Sicherungskopie der Vorfassung | 1 pro Notiz | keins | entfaellt | keine | | Zeitstempel-Ordner, logarithmisch ausgeduennt (Syncthing-Modell) | N pro Notiz | beschraenkt | ~1 Funktion | keine | | Git im Workspace | `.git/`, >=3 lose Objekte pro Commit | unbeschraenkt | `git gc`, teuer | `gix` oder `git2` | Zu Git: `gc.auto` = 6700 lose Objekte, also **~2.200 Commits bis zum ersten automatischen Repack** — bei "ein Commit pro Speichern" mit Autosave eine Frage von Wochen. Bemerkenswert: Zettlr empfiehlt Git *nicht*, Logseq nutzt es nur lesend und setzt voraus, dass der Nutzer es selbst eingerichtet hat. **Niemand richtet dem Nutzer ein Repo ein.** ### Belastbarkeit - **Hart belegt:** Obsidian betreibt eine produktive Historie fuer lose `.md` als aufgesetzte, vom Schreibverfahren entkoppelte Schicht. Ein Werkzeug mit derselben Ausgangslage hat das Problem nachweislich nachtraeglich geloest. - **Argumentation (nicht durch Quelle belegt):** dass genau *eine* Schreibstelle die einzige load-bearing Auflage ist. Folgt aber zwingend daraus, dass eine Schicht ueber N Aufrufstellen N Aenderungen kostet und ueber einer eine. - **Nicht belegbar geblieben:** konkrete Groessenzahlen fuer CRDT-/Append-Log-Bibliotheken. Fuer die Entscheidung folgenlos, weil der Ausschlussgrund das Zwei-Wahrheiten-Problem ist, nicht die Groesse. Ebenso: Obsidians Schreibverfahren (Closed Source, keine offizielle Aussage) und die kolportierten GB-grossen Logseq-bak-Ordner (belegt ist unbegrenztes *Ordner*-Wachstum, keine Groessenangabe). ### Randbefunde fuer #19 und #20 Fielen bei der Recherche mit an, sind im Dokument ausfuehrlich belegt: - **Weder Rust noch Microsoft dokumentieren `rename` als atomar** — das Wort kommt in beiden Doku-Seiten nicht vor. Microsoft empfiehlt fuer "document-like data" ausdruecklich **`ReplaceFile`**, nicht `MoveFileEx`. Kein Rust-Crate nutzt das. - **temp+rename verliert Erstellungszeit, DACLs, Alternate Data Streams, Object ID, EFS/Compression** (bewiesen per Kontrast aus den `ReplaceFileW`-Remarks). Folge: ein "erstellt am" gehoert ins Frontmatter, nicht ins Dateisystem. - **Realistischstes Fehlerbild: `ERROR_SHARING_VIOLATION`**, wenn Defender oder ein Sync-Client die Zieldatei ohne `FILE_SHARE_DELETE` offen haelt. `tempfile::NamedTempFile::persist` gibt die Temp-Datei im `PersistError` zurueck — genau fuer den Retry gebaut. - **Fuer #20:** Zettlr und Logseq loesen den Konflikt beide ueber **Inhaltsvergleich**, nicht ueber mtime allein. Zettlrs Code-Kommentar woertlich: mtime nur "neuer", nicht "ungleich" pruefen, *"to prevent sluggish cloud synchronization services (e.g. OneDrive and Box) from having text appear to 'jump'"*. - **Fuer #18:** Dropbox nennt als dokumentierte Ursache Nr. 3 fuer Conflicted Copies woertlich *"applications with an auto-save feature"* — Argument fuers Entprellen. ### Fazit Der Einwand aus dem Council trifft eine reale Gefahr, aber am falschen Ort. **#19 darf allein nach seinen eigenen Kriterien entscheiden — Absturzsicherheit, Sichtbarkeit der temporaeren Datei, Dateirechte, Aufraeumen. Historie legt genau eine Auflage auf, und die ist heute gratis: eine einzige Funktion, durch die alles Schreiben laeuft.** Ticket bleibt offen.
Author
Owner

Nachtrag: Die Append-Log-Kosten sind jetzt belegt

Im ersten Kommentar stand, konkrete Groessenzahlen fuer CRDT-/Append-Log-Bibliotheken haetten sich nicht belegen lassen. Die Recherche dazu ist nachgekommen und war ergiebig. Die Kernantwort auf #22 aendert sich nicht — sie wird an einer Stelle sogar haerter. Dokument aktualisiert, Commit 66bff57 auf research/historie.

1. Die Groessenzahl: der Unterschied zwischen 1,5x und 70x heisst Compaction

Aus dem offiziellen Benchmark-Repo des Yjs-Autors Kevin Jahns (dmonad/crdt-benchmarks), B4-Trace mit 182.315 Einfuegungen, 77.463 Loeschungen, 104.852 Zeichen Endtext:

Yjs 13.6.11 Automerge 2.1.10
Dokument gemerged 159.929 B ≈ 1,53x Rohtext 129.116 B ≈ 1,23x Rohtext
Summe aller Einzel-Updates 7.306.126 B ≈ 70x Rohtext —
Parse-Zeit 39 ms 1.805 ms

Das ist eine zweigeteilte Aussage, und beide Haelften sind wichtig:

  • Ein zusammengefasstes CRDT-Dokument ist erstaunlich billig — 1,2 bis 1,5x des Rohtextes, mit voller Historie. Guenstiger, als man intuitiv erwartet.
  • Ein ungekuerzter Append-Log — also genau das, was der Vorschlag beschreibt — kostet rund 70x den Rohtext.

2. Und genau dieses Zusammenfassen ist bei CRDT-Logs nicht vorgesehen

Das ist der eigentliche Nachtrag, und er kommt aus Maintainer-Mund. Peter van Hardenberg (Automerge) in Issue #799, woertlich:

"Discarding the history is not currently possible without replacing the document: if you don't have the same history, you can't merge the same changes. That's because we use a git-like commit hash for each change to ensure integrity."

"Shallow clone" und "cherry pick" nennt er nuetzlich und "not yet implemented"; nachgefasst 2024: "I don't know when it will happen." Der Automerge-2.0-Blogpost kuendigt dasselbe seit Januar 2023 an: "the best way to remove something from an Automerge document's history is to recreate the document from scratch". Bis heute nicht geliefert. (Issue #348 wurde 2026 mit Verweis auf die neue Storage-Engine hexane geschlossen — die ist laut offiziellem Blogpost "around 2–9x faster", liefert also Kompression, keine Truncation.)

Yjs begruendet es formal in der README:

"CRDTs that are suitable for shared text editing suffer from the fact that they only grow in size. […] We can't garbage collect deleted structs (tombstones) while ensuring a unique order of the structs."

Im Code bestaetigt: beim normalen Loeschen wird nur der content durch ContentDeleted(len) ersetzt — das komplette Item-Struct mit id, origin, rightOrigin, parent bleibt stehen. Und Updates zusammenfassen hilft nicht: "doesn't garbage-collect deleted content". Wer Snapshots will, muss GC ganz abschalten (der Code wirft sonst).

Damit ist der Punkt "der Log ist die Einbahnstrasse" nicht mehr nur mein Architektur-Argument, sondern die dokumentierte Position der Bibliotheks-Autoren selbst.

3. Das Gegenargument, das fairerweise dazugehoert

Das offizielle Automerge-Cookbook schreibt:

"Martin Kleppmann did some experiments […] The savings are not all that great, which is why we haven't prioritised history truncation so far."

Das ist ernst zu nehmen — es gilt fuer Kleppmanns Messfall: ein grosses, weitgehend linear getipptes Dokument mit wenigen Actor-IDs. Eine Notiz-App hat das umgekehrte Profil: viele kleine Dokumente, ueber Jahre in vielen kurzen Sitzungen angefasst. Ob die Oekonomie dort kippt, ist nicht belegt — die 70x-Zahl legt es nahe, ist aber am B4-Trace gemessen, nicht am Notiz-Profil. Steht so im Dokument, damit uns das Zitat nicht spaeter um die Ohren fliegt.

Ebenso fair: Die Yjs-FAQ sagt "Size is very rarely a practical problem as long as you deal with human-entered text input." Deshalb steht der Ausschlussgrund weiterhin beim Zwei-Wahrheiten-Problem und nicht bei der Groesse.

4. Sidecar-Dateien in Sync-Ordnern: zwei belegte Fallstricke

  • Platzhalter werden als geloescht interpretiert. Obsidians Sync-FAQ: Cloud-Dienste mit "Files on-demand" / "Online-only files" — "since these files are not always available locally, Obsidian Sync will interpret them as deleted, leading to their removal from your remote vault." Plus: "iCloud Drive on Windows may lead to file duplication or corruption."
  • Schon das Nachsehen, ob eine Datei existiert, kann die App einfrieren. Apples TN3150: Materialisierung "may cause the app to become unresponsive […] the system may terminate the app and trigger a watchdog crash", ausgeloest unter anderem durch "enumerating a directory's contents and checking whether a file exists". Fuer jede Notiz die zugehoerige Log-Datei zu statten ist genau dieses Muster. (Apple-Plattformen; Uebertragung auf OneDrive Files On-Demand unter Windows ist als Vermutung markiert.)

Bezeichnend: Apple empfiehlt fuer mehrteilige Dokumente File Packages statt nebeneinanderliegender Dateien — fuer uns untauglich, weil die .md dann keine eigenstaendige Datei mehr waere.

Was NICHT belegt ist: dass die blosse Verdopplung der Dateizahl schadet. Die harten Limits sprechen eher dagegen (Dropbox 300.000 Dateien / 1 Mio. Writes pro 24 h; OneDrive 300.000 Items) — bei unseren Workspace-Groessen unkritisch.

Drei naheliegende Belege habe ich gegengeprueft und verworfen: Zoteros "extremely likely to corrupt your database" betrifft SQLite und File Locking; git-annex' Dropbox-Warnung beruht auf Case-Insensitivity und Symlinks; fuer DVC gibt es keine offizielle Warnung. Keiner davon taugt als Beleg gegen Sidecars.

Fazit unveraendert

Historie bleibt jederzeit nachruestbar, temp+rename schliesst sie nicht aus, und die einzige Auflage an #19 ist weiterhin: genau eine Funktion, durch die alles Schreiben laeuft. Neu ist nur, dass der Append-Log jetzt auch mit Zahlen und Maintainer-Zitaten als die teure, schwer umkehrbare Variante dasteht — statt nur mit meiner Argumentation.

Ticket bleibt offen.

## Nachtrag: Die Append-Log-Kosten sind jetzt belegt Im ersten Kommentar stand, konkrete Groessenzahlen fuer CRDT-/Append-Log-Bibliotheken haetten sich nicht belegen lassen. Die Recherche dazu ist nachgekommen und war ergiebig. **Die Kernantwort auf #22 aendert sich nicht** — sie wird an einer Stelle sogar haerter. Dokument aktualisiert, Commit `66bff57` auf `research/historie`. ### 1. Die Groessenzahl: der Unterschied zwischen 1,5x und 70x heisst Compaction Aus dem offiziellen Benchmark-Repo des Yjs-Autors Kevin Jahns ([dmonad/crdt-benchmarks](https://github.com/dmonad/crdt-benchmarks)), B4-Trace mit 182.315 Einfuegungen, 77.463 Loeschungen, **104.852 Zeichen Endtext**: | | Yjs 13.6.11 | Automerge 2.1.10 | |---|---|---| | Dokument **gemerged** | 159.929 B ≈ **1,53x Rohtext** | 129.116 B ≈ **1,23x Rohtext** | | **Summe aller Einzel-Updates** | **7.306.126 B ≈ 70x Rohtext** | — | | Parse-Zeit | 39 ms | 1.805 ms | Das ist eine zweigeteilte Aussage, und beide Haelften sind wichtig: - Ein **zusammengefasstes** CRDT-Dokument ist erstaunlich billig — 1,2 bis 1,5x des Rohtextes, **mit voller Historie**. Guenstiger, als man intuitiv erwartet. - Ein **ungekuerzter Append-Log** — also genau das, was der Vorschlag beschreibt — kostet **rund 70x den Rohtext**. ### 2. Und genau dieses Zusammenfassen ist bei CRDT-Logs nicht vorgesehen Das ist der eigentliche Nachtrag, und er kommt aus Maintainer-Mund. **Peter van Hardenberg (Automerge)** in [Issue #799](https://github.com/automerge/automerge/issues/799), woertlich: > "**Discarding the history is not currently possible without replacing the document**: if you don't have the same history, you can't merge the same changes. That's because we use a git-like commit hash for each change to ensure integrity." "Shallow clone" und "cherry pick" nennt er nuetzlich und "**not yet implemented**"; nachgefasst 2024: "I don't know *when* it will happen." Der [Automerge-2.0-Blogpost](https://automerge.org/blog/automerge-2/) kuendigt dasselbe seit **Januar 2023** an: "the best way to remove something from an Automerge document's history is to **recreate the document from scratch**". Bis heute nicht geliefert. (Issue #348 wurde 2026 mit Verweis auf die neue Storage-Engine `hexane` geschlossen — die ist laut [offiziellem Blogpost](https://automerge.org/blog/2026-july/) "around 2–9x faster", liefert also Kompression, keine Truncation.) **Yjs** begruendet es formal in der [README](https://github.com/yjs/yjs/blob/main/README.md): > "CRDTs that are suitable for shared text editing suffer from the fact that they **only grow in size**. […] **We can't garbage collect deleted structs (tombstones) while ensuring a unique order of the structs.**" Im Code bestaetigt: beim normalen Loeschen wird nur der `content` durch `ContentDeleted(len)` ersetzt — das komplette Item-Struct mit `id`, `origin`, `rightOrigin`, `parent` bleibt stehen. Und Updates zusammenfassen hilft nicht: "**doesn't garbage-collect deleted content**". Wer Snapshots will, muss GC ganz abschalten (der Code wirft sonst). **Damit ist der Punkt "der Log ist die Einbahnstrasse" nicht mehr nur mein Architektur-Argument, sondern die dokumentierte Position der Bibliotheks-Autoren selbst.** ### 3. Das Gegenargument, das fairerweise dazugehoert Das offizielle [Automerge-Cookbook](https://automerge.org/docs/cookbook/modeling-data/) schreibt: > "Martin Kleppmann did some experiments […] **The savings are not all that great, which is why we haven't prioritised history truncation so far.**" Das ist ernst zu nehmen — es gilt fuer Kleppmanns Messfall: **ein grosses, weitgehend linear getipptes Dokument mit wenigen Actor-IDs.** Eine Notiz-App hat das umgekehrte Profil: viele kleine Dokumente, ueber Jahre in vielen kurzen Sitzungen angefasst. Ob die Oekonomie dort kippt, ist **nicht belegt** — die 70x-Zahl legt es nahe, ist aber am B4-Trace gemessen, nicht am Notiz-Profil. Steht so im Dokument, damit uns das Zitat nicht spaeter um die Ohren fliegt. Ebenso fair: Die Yjs-FAQ sagt "**Size is very rarely a practical problem** as long as you deal with human-entered text input." Deshalb steht der Ausschlussgrund weiterhin beim Zwei-Wahrheiten-Problem und nicht bei der Groesse. ### 4. Sidecar-Dateien in Sync-Ordnern: zwei belegte Fallstricke - **Platzhalter werden als geloescht interpretiert.** Obsidians [Sync-FAQ](https://help.obsidian.md/sync/faq): Cloud-Dienste mit "Files on-demand" / "Online-only files" — "since these files are not always available locally, **Obsidian Sync will interpret them as deleted, leading to their removal from your remote vault.**" Plus: "iCloud Drive on Windows may lead to **file duplication or corruption**." - **Schon das Nachsehen, ob eine Datei existiert, kann die App einfrieren.** Apples [TN3150](https://developer.apple.com/documentation/technotes/tn3150-getting-ready-for-data-less-files): Materialisierung "may cause the app to become unresponsive […] the system may terminate the app and **trigger a watchdog crash**", ausgeloest unter anderem durch "**enumerating a directory's contents and checking whether a file exists**". Fuer jede Notiz die zugehoerige Log-Datei zu statten ist genau dieses Muster. (Apple-Plattformen; Uebertragung auf OneDrive Files On-Demand unter Windows ist als **Vermutung** markiert.) Bezeichnend: Apple empfiehlt fuer mehrteilige Dokumente **File Packages statt nebeneinanderliegender Dateien** — fuer uns untauglich, weil die `.md` dann keine eigenstaendige Datei mehr waere. **Was NICHT belegt ist:** dass die blosse Verdopplung der Dateizahl schadet. Die harten Limits sprechen eher dagegen (Dropbox 300.000 Dateien / 1 Mio. Writes pro 24 h; OneDrive 300.000 Items) — bei unseren Workspace-Groessen unkritisch. **Drei naheliegende Belege habe ich gegengeprueft und verworfen:** Zoteros "extremely likely to corrupt your database" betrifft SQLite und File Locking; git-annex' Dropbox-Warnung beruht auf Case-Insensitivity und Symlinks; fuer DVC gibt es keine offizielle Warnung. Keiner davon taugt als Beleg gegen Sidecars. ### Fazit unveraendert Historie bleibt jederzeit nachruestbar, temp+rename schliesst sie nicht aus, und die einzige Auflage an #19 ist weiterhin: **genau eine Funktion, durch die alles Schreiben laeuft.** Neu ist nur, dass der Append-Log jetzt auch mit Zahlen und Maintainer-Zitaten als die teure, schwer umkehrbare Variante dasteht — statt nur mit meiner Argumentation. Ticket bleibt offen.
Sign in to join this conversation.