All Governor’s Log Field Report / Runtime Governance

The Fix That Grew

The failure mode we built Sentience to catch showed up in Sentience first: silent, fail-open, invisible from inside the loop. This is the record of how we found it, fixed it, and watched the fix grow.

Sentience Governor evaluates agent actions against declared governance context and records governance evidence without blocking execution.

We were designing its next feature, a retrospective reader: point Sentience at the Claude Code history already sitting on your machine and let it tell you what your agents have been doing. To design it, we inspected our own history.

Claude Code’s records showed thousands of tool actions across five weeks. The Sentience Agent Execution Record showed nothing. Not reduced activity. Nothing, since July 16.

That discrepancy is the incident.

The bug

Sentience configures Claude Code to invoke a Sentience hook executable around tool activity and at session end. Installation writes the absolute path of that hook into the project’s Claude configuration.

The package had been uninstalled. The path pointed into a Python environment that no longer existed. Claude kept trying to invoke the configured path, and nothing happened.

That silence is deliberate. A governance layer that crashes your agent because of its own bug is worse than no governance layer, so ours is built to fail quietly and never interrupt the work. The cost of that choice is exactly what we hit: a hook that is missing looks identical to a hook that ran and had nothing to say.

Why did nobody notice for five weeks? Not carelessness, and not an excuse: that capture path simply was not being consulted during the period, so nothing in the normal workflow forced the absence into view. Silence looks the same whether the tool has nothing to report or has stopped existing. We saw the gap only because designing the retrospective reader forced us to inspect our own history. The feature was not built yet. Designing it had already found its first failure: ours.

The sentence that cost us three revisions

We wrote a root cause record. It contains this line:

“The defect is not that paths break. Paths break. The defect is that nobody finds out.”

That reads like insight. It is where the whole thing went wrong.

It quietly converts a problem about state (the configuration is stale) into a problem about experience (the operator was not told). Those have different solution spaces. If the configuration is stale, you fix the configuration. If nobody was told, you build a way to tell them.

We built the way to tell them.

What we built instead

Three revisions of a plan, each internally reasonable:

  • a health check command that inspects the configuration
  • a vocabulary of configuration states to report
  • a structured output contract so machines could read those states
  • a new exit code, so a broken state was distinguishable from an empty one
  • a repair verb the operator would run after reading the report

By the third revision, fixing a dangling file path had grown a nine-state model and four new command-line contracts. Every step followed from the one before it. None of them was wrong on its own terms.

Every design also had the same shape: notice, then run a command, then run another command. We had put a human in the middle of the loop and never asked why the human was there.

Two reviews that improved the wrong plan

We ran the plan past two independent technical reviews. They were good. Between them they found seventeen real defects: an ownership rule that would have deleted a user’s own configuration, a path-matching rule that would have failed on any install directory containing a space, a repair instruction that pointed at a command which refused to run.

We fixed all seventeen. The plan got genuinely better.

It was still the wrong plan.

A review checks whether the thing you built is correct. It does not ask whether you should have built it. Both reviewers worked inside our framing, because the framing was the part that looked settled. Passing two review rounds made a contract that should not have existed feel earned.

The question that collapsed it

Then the operator asked one:

Why does the user need to know a migration happened at all?

The tool knows where it is installed. It knows what the configuration should look like. When it runs and the configuration is stale, it can simply bring it up to date and get on with the job.

No health command. No state vocabulary. No structured contract. No new exit code. No repair verb. Seven of the seventeen review findings stopped existing, because the contract that produced them was gone.

Here is the part worth being precise about, because the easy version of this story is false. The four new interfaces disappeared, and the test count initially fell with them. Then it grew again, well past where it started, because removing the user-facing machinery uncovered the actual hard problem: safely changing configuration you can only infer you manage, without touching anything you do not, and without ever creating two live capture paths. Which entries are ours when nothing records provenance. What happens when a team’s shared file and a machine’s local file disagree. What a hand-modified entry means. What a concurrent writer does to your compare-and-replace.

The interface got dramatically simpler. The engineering did not. The simplification was real, but what it bought was not less work. It was the right work.

Why we are publishing this

The pitch for a governance product is that it tells you the truth about what execution actually did, including when that is unflattering. It would be strange to make that argument and then only publish the parts where we looked competent.

And this incident is the product connection at its most literal, no analogy required: Claude Code’s history showed five weeks of execution. Sentience had no corresponding record. The two histories did not line up, and the mismatch was the finding. That is what retrospection is for. The investigation that was designing it found the outage before the feature existed.

The planning story rhymes with the same thesis, and we will only claim the rhyme: work drifted from its declared purpose one locally reasonable step at a time, and nobody inside the loop could see it. Sentience evaluates agent actions against declared governance context; it does not evaluate human planning, and it was not running during any of this. But the shape is the one we build for, and it is easier to recognise in others once you have watched yourself do it.

What we changed

The fix shipped in v0.3.0.3. When Sentience runs and finds its own configuration in a project, it brings that configuration up to date: stale paths, historical partial setups, duplicated entries. Configuration that does not match the structure Sentience knows how to manage is left alone; anything Sentience-like but hand-modified is reported rather than guessed at, because a tool that rewrites your deliberate customisations is a worse problem than the one it is solving.

A new machine-local file announces itself with one line, and configuration that cannot be updated safely produces one warning. Everything else is silent. The user is no longer the repair mechanism. That is the point.

Postscript: the release that outran its own checklist

The fix shipped. And on the way out the door, we repeated the pattern.

Our written release protocol is explicit: merge, tag, and CI-validate the exact commit first, publish to the package index last, because publishing a version there is the one step that can never be undone. We published first, then merged, then tagged.

No single decision did it. An instruction said “publish,” and the agent executed it literally instead of raising the ordering question it had noticed. The human approved, trusting the checklist ordering was being held. The checklist sat unread at the exact moment it existed for. Byte-identity between the published artifacts and the merged commit, verified afterward, is what made it harmless; “verified afterward” is the tell.

And the detail that makes it this article’s coda rather than a separate confession: minutes earlier we had proven the release by letting it govern our own session, live. Then we cleaned up the test hooks, as hygiene demands. Then we published. The governance tool’s own release crossed its one irreversible boundary after the test capture had been removed, and the last governed action in the trace is the cleanup that removed the hooks.

Could Sentience have caught it? A profile configured to treat package publishing as high-consequence could record and flag such an upload without blocking the command. Evaluating ordering, this action is only valid after that one, is a capability we have deliberately not claimed to have shipped. What exists today is plainer: the written protocol says one thing, the execution record shows another, and a human who puts them side by side afterward faces no ambiguity about what happened.

The fix went where fixes belong, out of memory and into the written protocol, which now states the canonical order as binding and records why.

Two incidents, one shape. We keep relearning our own pitch.