Nothing Obviously Broke
A Claude Code restart wrote valid but empty Sentience Agent Execution Records. A first backfill wrote accurate records with the wrong implication. Both were correct evidence that meant something other than it appeared to.
Six minutes after putting our own governance tool into daily use, I ran
sentience status to confirm it was capturing, and read this:
Last session:
ID: 7100bd9c-52ed-48ee-a3ee-f4daa16f92c8
Time: 2026-08-25 11:39
Events: 2
I did not recognize that session. I had been working all morning in a conversation that had been open for months. This one was seconds old and contained two events.
My first instinct was that the tool had bound itself to the wrong session, and I said so out loud. That instinct was wrong. What it caught was real, and it was more interesting than a wrong session.
Some context for what I was looking at. Sentience Governor evaluates agent actions against declared governance context and records governance evidence without blocking execution. The last Governor’s Log ended on a promise: we had found our own capture path silently dead for five weeks, shipped the fix, and said the tool would keep itself running from then on. What we had not done was run it. So that Monday morning I installed it on the machine where Sentience Governor is built, governing Claude Code in two repositories. Hooks wired, about two minutes of setup, finished at 11:33.
Two events and nothing else
Each session gets a Sentience Agent Execution Record, one trace file on disk. A working session accumulates thousands of events: a scope assertion for every tool call, a context snapshot for every result, token counts at the end.
The file behind that session ID had two events and 1,351 bytes:
AGENT_REGISTERED 18:39:30.769Z
INTENT_DECLARED 18:39:30.770Z
intent_source: none
stated_objective: null
Registered and declared in the same millisecond, then nothing. No tool call, no snapshot, no end. A session that was announced and never did anything.
Nineteen minutes later I restarted the app and got a second file. Same two events, same 1,351 bytes. By evening there were eight.
The diagnosis came out of the record itself, which is worth saying precisely because it is the argument for the whole product. The record narrowed the cause to one execution path. A source check confirmed it.
Every trace carries structure: which events fired, in what order, with what timestamps. That two-event signature ruled out almost everything by itself. A pre-tool hook would have produced at least four events. A post-tool hook would have produced three. Exactly one path produces two: a session-ended event arriving as the first thing Sentience Governor ever hears about a session, for a session with no transcript to read.
Which is exactly what an app restart does. Claude Code opens a session, closes it immediately, and reports that it ended. Sentience Governor registered it before discovering there was nothing in it. I checked whether those session IDs appeared anywhere in Claude Code’s own history, and they did not. Those sessions were real enough to be announced and never real enough to be written down.
Capture never failed
Here is the part that took me longer to see than the bug.
Nothing broke. Capture was live the entire time. The observed events were well formed and the files were valid. The eight junk files harmed nothing, sitting in a hidden directory consuming eleven kilobytes.
What degraded was something else: the newest file wins the “last session”
line, so every restart quietly pushed my actual work out of the report.
The command answered. The answer was true, in the narrow sense that a
session by that ID did exist and did have two events. And it was
misleading, because the thing I was actually asking, the thing anyone
running status is asking, was is this tool capturing my work?
The system stayed operational while its trust surface degraded. That gap is the whole story, and it showed up twice that morning.
The same failure, wearing different clothes
The second instance was larger and I nearly missed it.
When the app quit that first time, Sentience Governor did what it is designed to do at session end: read the conversation transcript and record token usage per turn. The conversation in question had been open since April. So it read four months of history and wrote 14,294 records in a single minute.
Every one of those records is accurate. Each corresponds to a real turn that really happened. The parsing is incremental, so it never repeats itself, and I confirmed that on the next restart when it added eleven records instead of another fourteen thousand.
And yet the resulting picture is wrong in a way no individual record is wrong. Read a report built from that session and you see months of activity presented as one governed session, nearly all of it flagged as undeclared, almost none of it from a period when governance was even installed. The data is right. What it appears to mean is not.
Two incidents. One shape:
real action
↓
recorded event
↓
plausible report
↓
wrong interpretation
Every link in that chain holds. The end of the chain is still wrong.
Why this is worse at agent speed
A person working alone generates evidence at the speed they can read it. An agent does not. In the session I was watching, Claude issued more than twelve thousand tool calls across the corpus and over five thousand shell commands in a single conversation. Nobody reads that. You read a summary, and you trust that the summary stands for the thing it summarizes.
That trust is the thing at risk, and the risk is not that the system fails loudly. It is that it does not fail at all, in any way you would notice. The work finishes. The command returns an answer. The trace file exists and parses. You move on.
The question underneath all of this is not did the system work? It is:
Can I trust that the thing being shown to me actually represents what I think it represents?
Logs alone do not answer that. You can have complete, valid, well structured logs and still have a record whose meaning has drifted away from reality. That is what happened to us twice before lunch, on a tool built by people who think about exactly this problem.
The sentence the fix turned on
The repair itself is small: before creating anything for a session-ended event, look at the transcript first, and write nothing when there is nothing to record.
The plan went through three revisions. Two of the corrections were about wording. One was about knowledge, and it is the one worth reading.
My first version said: parse the transcript, and if it yields no usable turns, create nothing. The reviewer’s correction:
Do not equate a transcript parse or read exception with zero emittable turns. Suppress creation only when the empty condition is positively established.
That distinction sounds academic until you follow it. Under my version, a transcript that could not be read at all, because of a permissions error or an I/O failure or a crash in the parser, would have been treated as an empty session. Sentience Governor would have silently discarded a session that might have been entirely real, and the discarding would have looked exactly like the correct behavior.
I found nothing and I could not establish what happened cannot be the same state. Collapsing them is how a tool starts lying with a clean conscience.
So the shipped code has three outcomes rather than two. Positively empty: write nothing. Positively has content: write everything. Uncertain: keep the old behavior and preserve the file. Uncertainty costs a junk file. The alternative cost evidence, and evidence is the entire product.
Proving the record with the record
The fix claims that a restart no longer creates an empty file. That is a negative claim, and negatives are slippery. If I restart and nothing appears, it could mean the fix worked, or it could mean the conditions never arose. Worse, this release also changed the reporting commands, so “no empty session appeared” could mean nothing more than the tool declining to show me one.
The first half was settled by the filesystem, not by any Sentience Governor output: eleven trace files before the restart, eleven after, no new file of any kind, and the eight existing ones untouched.
The second half was settled by an accident of design. When the app quits, Sentience Governor writes that batch of token records, which produces a distinctive burst of one event type with almost none of the others. It is an unmistakable fingerprint of a quit, and it exists for reasons that have nothing to do with this bug.
Every quit that day carried it, and every empty file followed one:
18:35Z quit → empty session at 18:39Z
18:54Z quit → empty session at 18:58Z
20:20Z quit → two empty sessions at 20:21Z
23:37Z quit → none
The last row is the fix. Same fingerprint, spanning two sessions at once, matching the shape of the quit that had produced two files three hours earlier. Zero created.
The record proved its own repair. There is a test suite too, and it fails without the fix. But the thing that established the claim on a real machine was evidence the tool had already collected without being asked.
What we have not solved
The honest place to end is with the part we did not fix.
The backfill is still there. The first time Sentience Governor meets a long-running conversation, it will still read the whole history and attribute months of activity to a single session, and nothing on any surface will tell you that most of those records predate your install. The data will be correct and the impression will be wrong, which is precisely the failure this post is about.
We left it out of this release deliberately, because deciding what a governed record should say about pre-governance history is a product question, not a bug fix, and answering it badly in a hurry would be worse than leaving it open.
So I want to be careful about the claim. Governance ought to expose when a record should not be taken at face value, and in places ours does: existing empty sessions are labeled rather than hidden, while positively empty restarts now create no new record. There is also a command whose job is explaining how the reported numbers were counted. The backfill is where it does not do that yet. Naming the gap is not a substitute for closing it.
What we changed
v0.3.0.4 is out. Restarting Claude Code no longer leaves an empty
session in your trace directory. sentience status reports your newest
session with recorded activity and tells you how many empty ones it
passed over. sentience list still shows them, labeled as what they
are.
Files already on your disk are not deleted, rewritten, or compacted. They are evidence, even when the only thing they are evidence of is that something briefly existed. A tool that edits its own record to look tidier is not a tool you should trust with a record.
If you have been running Sentience Governor across a few restarts, you probably have some of these. Now you know what they are.
Read the record
- v0.3.0.4 release notes
- The issue this fixed, filed from the incident described above
- Changelog and the package itself
At agent speed, a system can keep giving you plausible results while the evidence underneath them is subtly misleading. Governance does not eliminate that problem. It gives you a way to detect it and reason about it.