NAOMS Devlog

Building a sovereign, local-first memory & identity system โ€” in the open, honestly.

One Door In

Why every write to the ledger goes through a single locked path

Technology Architect free April 7, 2026ยท4 min readยทstorage-sync
TL;DR Every change to your data is a signed entry in an append-only log, and the picture you see is derived from that log by replaying it. Routing every change through that one audited door is what gives it a receipt โ€” here is how it works, and the week we shut the side window that let writes skip it.

How a write to your data is supposed to happen

Underneath NAOMS is a ledger: an append-only log of everything that has happened. Append-only means entries are added at the end and never edited or removed, so the log is a history rather than a current picture. Every message, every membership grant, every memory is an event in that log โ€” signed by whoever caused it, hashed so that any later alteration is detectable, and recorded in order.

The picture you actually look at on screen is not that log. It is a graph โ€” people, messages, memories and the links between them โ€” and it is derived. A projection step reads each new event and updates the graph to match, which is why you write to the log and read from the projection. The log is the source of truth; the graph is a view of it, and it can be thrown away and rebuilt by replaying the log from the start.

So the correct way to change anything is one path, and only one: you append a signed event to the ledger, and the projection turns that event into graph state. That is the audited append.

Three properties fall out of having exactly one audited door, and you cannot get any of them halfway:

  1. Provability. Every state change has a signed event behind it. "Who changed this, and when?" always has an answer, because there is no other way for it to have changed.
  2. Ordering. The ledger gives a total order within a scope. Derived graph state is a deterministic function of the event sequence โ€” replay the ledger, get the same graph, every time.
  3. Enforceability. Once there is one door, you can put a guard on it. An automated check flags any direct write to the graph in production code, so the property cannot silently erode the next time a convenient shortcut is tempting.

That third point is the real prize. A one-time cleanup decays; a cleanup plus a rule that fails the build when someone re-opens a window holds.

A house with one locked door is securable. The guarantee is only ever as strong as the narrowest way in โ€” which means the engineering work in a design like this is not building the door. It is making sure there is not a second one.

What was wrong: there was a second way in

For most of this project's early life there were two ways to change the data.

Alongside the audited append there was a direct write, straight to the graph store. Convenient, fast, and completely outside the ledger: no signed event, no entry in the append-only log, no projection step turning a recorded fact into state. A direct write happened, but the system could not prove it happened, or by whom, or in what order.

That is precisely the property the project's Honesty axiom forbids โ€” no silent mutations. And it is worse than having no ledger at all, because the ledger looks authoritative. A house with one locked door and a dozen open windows is not secure; it is a house that misleads you about being secure. With a second write path in existence, the audited one is decorative.

How it was fixed โ€” and what "mid-flight" looked like

The decision to make the audited append the only write path was that week's quiet refactor, and the day-to-day of it is worth recording honestly, because this is the part that never shows up in a changelog.

On 7 April the work was mid-flight, and the day was spent fixing the audited path itself rather than calling it:

  • One fix corrected inconsistent field naming in the append calls and added a guard so callers stop getting it wrong.
  • Another added integration tests and fixed real bugs in the new path, in real feature handlers โ€” the voice and forecast code โ€” caught by tests written the same day.
  • A third hardened the write boundary so the append path is validated at the moment the system starts.

This is the unglamorous middle of a migration: the single door exists, but it sticks, and every handler you route through it finds a new way it sticks. The honest version of "we funnelled all writes through one path" is "we spent days making the one path good enough to deserve all the writes." Slowing down to harden the thing everything else will lean on is exactly the part that decides whether the guarantee is real.

The work was marked complete on 2026-04-09 โ€” two days after the day described here โ€” with the audited append established as the required write path, and the direct write taken off the public graph interface โ€” surviving only behind a deprecated, underscore-prefixed name that the checker flags at every call site. (A companion piece covers that landing and its blast radius.) The 7 April work above is the in-progress middle of that migration; the completion is dated two days later, and is labelled as such rather than backdated to here.

The shape of the lesson generalises past ledgers. Any time you have a guarantee that depends on a narrow path โ€” an audit log, a permission check, an encryption boundary โ€” the engineering work is not adding the path. It is removing every other path, then nailing the remaining one shut so it stays the only one.


Written by AI agents from real project logs; owned and edited by Mujo.

โ† more in Technology   home โœฆ   all โ†’