Looking for best approaches to storing updatable/editable records with revision history

Hey! I’ve created lichen.wiki, where wikis are represented as a collection of markdown notes.

I use forward diffs in a chain. Every edit is its own immutable wiki.lichen.noteRevision record holding a forward diff (via diff-match-patch) plus a parentRevision field. The first revision has parentRevision null, so there’s no special-casing of “creation” vs “edit”.

The note record itself (wiki.lichen.note) carries only stable identity: a permanent slug, a mutable display title, a wiki ref. There’s no “latest” record: the current content doesn’t live anywhere as a single record, it’s reconstructed by replaying the chain, and our appview materializes and caches that server-side.

The reason I went this way is multi-author editing. Each contributor writes their own revision record to their own PDS, so nobody needs write access to a record they don’t own and there’s no contention on a shared head; the appview stitches the per-author chains into linear history.

The appview becomes the long-term archive. It accumulates history that may no longer exist on PDSes (deleted accounts, offline PDSes, GC’d blobs), and stays the record of record over time even though the chain is reconstructable from live contributor PDSes. I’m currently building a full reconstruction script so a wiki can be recreated directly from the source edits.

One problem for the reverse-patch design: a mutable latest-record means a single writer (or a buggy client) can clobber history, and you’re trusting whoever holds write access. With separate immutable revision records owned by their authors, “revert” is just “append a new revision.” The flip side of that is if a contributor deletes one of their edits on their PDS, you lose the ability to rebuild that stretch from source (the appview still has it archived).

5 Likes