sapix technical notes
← all notes

Aug 9, 2026

The rule it obeyed

Two assistants were working in the same folder at once. One of them ran my end of session ritual and committed the other one's unfinished work under a message about an unrelated task. The ritual had a rule against exactly this. It followed the rule. The rule could not have helped, and it took me two occurrences to see why.

I now run two AI clients side by side, sometimes in the same project at the same time. That is new, and it broke something in a way I did not anticipate.

At the end of a working session I run a ritual. It reviews what changed, groups it into commits, writes the messages, saves what should be remembered. It is one of the most useful things I have, and it is shared: the same instructions, the same steps, whichever client is running.

One evening it ran in the second client while the first was in the middle of an implementation, files half written on disk. The ritual gathered everything it found, split it into two commits, wrote confident messages about an issue it had been working on, and committed. The first client came back a few seconds later, went to stage its own work, and found nothing to stage. Its prepared messages were gone. The work survived by luck, because the changes happened to be complete.

The next day the same thing, one layer worse. My in flight changes were swept into a commit whose message was entirely about a different subject, and then the branch was rewound underneath me. Nothing was lost that time either, and again only by luck: a merge had already carried the content elsewhere. I spent twenty minutes proving that to myself before I could go back to work.

Now, the ritual has a rule about this. It is written in its instructions, in capitals, and it has been there for months: stage exact files, never everything at once.

It obeyed. Both times.

That is the part that took me two occurrences to understand. Staging exact files means it lists them one by one instead of sweeping the folder. But it gets that list by asking the version control system what has changed, and in that answer another agent’s edits look exactly like its own. Same folder, same shape, no author, no timestamp that distinguishes anything, no marker of intent. A perfectly obedient ritual produces the same commit.

So the instruction was correct, and it was correct in a way that could never work, because it addressed the writing and the failure was in the seeing. Whatever I did next, the thing to add was not a firmer rule. It was a signal that did not exist.

There is a name for what was happening, and it is old. Two writers changing shared state with no isolation between them is a lost update. The database literature is direct about it: those races have to be prevented, either automatically by the system, or by manual safeguards such as locks. Version control gives you none of the automatic half for a shared working folder. It was never designed for two authors typing into the same checkout at the same second. The manual half was mine to build.

I picked the cheapest signal that covers the actual failures. When a session starts, remember where the branch is. Before the ritual commits anything, look again. If it moved, someone else has been here: stop, show me what arrived, and do not commit into a contested tree. Both of my incidents move it, the foreign commit and the rewind alike, so one comparison catches both without needing to know who wrote which file.

This is the optimistic approach, which the same literature warns degrades badly under contention, since everybody keeps aborting and retrying. That warning is about many writers fighting over the same rows. Two assistants meeting occasionally in one folder is the opposite end, and the objection does not apply.

Two decisions inside it that I would defend more than the mechanism.

It fails open. If it cannot find the record it took at the start, the verdict is unverified, not refused. A guard that blocks because it cannot read its own cache would cost me the very commit it exists to protect, which is a worse outcome than the problem. But unverified has to be reported as unverified, and never rounded up to fine. That distinction between not knowing and knowing it is good is the thing systems quietly erase, and I caught myself doing exactly that again the same evening, merging a change while the service that judges it was still answering “I have not worked it out yet”.

And after the ritual makes its own commit, it updates the record. Without that, a session landing three commits would flag its own second and third as foreign, and a check that cries wolf gets ignored inside a week. I have a post about that from a few days ago.

What it does not do is the honest part. It only guards work that goes through the ritual, so an assistant typing a commit directly is unguarded. And the rewind never passes through a commit at all, so nothing here would have stopped it. That one stays a rule for humans: you do not rewind a branch that is not yours.

The larger thing I take from this is about where to look when an instruction fails. My reflex is to ask whether the rule was followed, and if not, to make it louder. Here it was followed, which meant the question was wrong. The useful question is whether the actor could see the difference the rule depends on. If it cannot, the rule is not a weak safeguard. It is a description of a decision nobody was in a position to make.