Plain Files Can Be Touched
Keeping the notes as plain Markdown was a deliberate gift: the vault opens in any editor with every service stopped. The cost of that gift is that anything can change those files without asking the door. An editor left open on the tree. A sync client that wakes up with an old copy. A script someone wrote in a hurry. A session that opened a path instead of calling soul-vault write. None of those leaves a commit, a request id, an actor or a reason.
The easy reactions are both wrong. Accepting such a change silently makes the door optional: the history and the state stop describing the vault. Reverting it silently throws away what might be Dad's own edit. Soul Vault does neither. It holds the change.
Held, Never Accepted, Never Lost
The external-edit guard is one shared class, HeldChanges in backends/guard.py; a child only tells it where its files and its accepted bytes are. On the Delta store it is always in enforce mode. When the read path or a scan finds a file on the canonical tree whose bytes differ from the accepted revision, or a file that appeared or vanished without a write:
- The new bytes (or the fact of the deletion) are kept in a held entry, so nothing is lost.
- Readers keep getting the accepted bytes, which git still has. Every session on every Mac goes on seeing the vault as the door last committed it.
- Watchfire, the family's monitor, raises one alert per held change, carrying the exact commands that settle it.
Held entries are pending state, not history. They exist only until someone decides.
Two Ways to Settle
- Apply (
soul-vault quarantine apply): the held bytes are written throughwrite_note, with compare-and-swap against the revision the change was held against. The change enters the history like any other write, with an actor and a reason. If a later real write has overtaken it, the apply is refused withrevision_conflict; the guard never resolves a disagreement by last-write-wins. - Discard (
soul-vault quarantine discard): the accepted bytes are put back on the tree and the held entry is dropped. Only a human actor may discard: in practice, only Dad decides that a change made outside the door should vanish.
Before any of this can work, the guard needs a baseline: what "accepted" means for every file. The folder-wrapping child recorded one with quarantine adopt, and a guard asked before that existed refused by name. The Delta store needs no such step: its baseline is its own committed bytes, so quarantine adopt there is refused with unsupported_capability, which says to apply the held change or let Dad discard it. Both settling commands also need --actor, the name of whoever decides; a discard needs --actor-kind human as well.
Run for Real
On the evening of 2026-11-10 the rare-path trial (Coop 1110-42) tested the guard on the live store: an edit, a created file and a removed file were each made directly on the tree. Each was held. Readers on the canonical Mac and on another Mac kept the committed bytes. Watchfire alerted once per held change with the settling commands. A discard by anyone but Dad was refused. Each apply went through write_note and appeared in the note's history. And an apply of an edit that a later write had overtaken was refused with revision_conflict.
Observe Before You Enforce
The guard did not start in enforce mode everywhere. During part 1, when cwkPippa still wrote some notes directly and the old folder's sync was still running, it ran in observe on the canonical Mac: drift was reported (by soul-vault quarantine status) but readers kept the disk. The plan for the old store was explicit: enforce only after the census reached zero and the folder's sync was off. The Delta store is enforce by design, because it arrived after part 1 had moved readers and writers to the door. Turning on a strict guard while honest writers still bypass it only teaches everyone to ignore its alerts.