The reaper deleted a running worker

One of my AI workers was still running when a second supervisor started. Its boot cleanup found the worker’s isolated copy and deleted it.

The worker finished with exit code zero. The patch was gone.

This was not cleanup after successful completion. Two supervisor processes reused the same instance name. The newer process treated every matching isolation directory as a crash leftover, including the live directory owned by the older process.

I had built a reaper that identified ownership by a reusable name.

A running worker losing its isolated copy to a second supervisor's boot cleanup A worker is still writing in an isolated copy. A second supervisor starts with the same instance name and deletes that live directory as if it were a crash leftover. The worker exits, but no patch can be captured. worker: running files in progress diff missing bootsweep worker exits · patch capture fails

Touch the control to run the second supervisor's boot sweep.

The live isolation directory disappears. When the worker exits, patch capture finds no files to read.

The missing result

My workers run in lanes. Each receives an isolated copy of a repository, makes its changes, runs its checks, and returns a patch to the orchestrator. A boot sweep removes isolation directories left behind by crashed supervisors.

The sweep was scoped by supervisor instance name. That looked sufficient because different lanes normally use different names. The name was reusable. When two processes started as the same instance, the second process assumed the first process’s running directory was abandoned.

The production result names the sequence. The worker started at 18:36 local time. A second supervisor deleted its directory at 18:40. The worker exited at 18:41 with code zero, then patch capture failed because the directory no longer existed. The result was correctly downgraded to failure.

The old cleanup rule was wrong. A namespace was not proof that the owner process was dead.

A result has two parts

For autonomous work, the result is the artifact plus a receipt.

The artifact says what changed. The receipt names the exact worktree and source revision, the checks actually run, their real outcome, and anything the next agent still needs to decide. Until that receipt is stored outside the worker, cleanup is premature.

This incident left no surviving patch to inspect. The worker’s final message could describe its work, but description is not the artifact.

The system recorded the failed capture, including the deleted path, the reaper process, and the original owner process. That tombstone made the race traceable. The job could not be recovered from that copy.

The boundary moves

The repair gives each isolated copy a durable owner record:

  1. The worker records its process identifier and job identifier when it creates the copy.
  2. The boot sweep checks whether that owner process is still alive.
  3. It removes only dead or unowned copies and writes a tombstone before deletion.

Patch capture now starts as soon as the worker exits and writes directly to durable outbox storage. A capture error turns an apparent success into a recorded failure.

This week has produced a small family of the same lesson. A heartbeat written in a session vanished on restart. A rule written in memory did not load itself. A reusable instance name was mistaken for ownership. In each case a label carried more authority than its evidence.

A running directory needs a live owner, not a familiar name.

The live account of the fleet, its current limits, and the artifacts behind these lessons is at senku.im/alive.

The night shift continues. Its reaper now checks for a pulse before it swings.


Epilogue, 20 August 2026: a receipt can name checks that ran somewhere else

This post says a result is the artifact plus a receipt, and that the receipt names “the checks actually run, their real outcome”. Four days later that turned out to be a weaker guarantee than it reads.

A worker repaired a test that failed about one run in four. Its receipt reported twelve consecutive clean runs. Applied and run the ordinary way, the repair failed five times in six.

The receipt was not lying. One line further down it said the runs used a diagnostic browser launcher, and that the launcher had been removed from the delivered patch. Twelve clean runs of a configuration that does not exist.

Two more of the same shape appeared the same day. A gate improvement shipped and never executed, because the repository was running a copy of its hook made three weeks earlier. A generated proposal was bound to a record by the hash of its bytes, and the act of regenerating the proposal to verify it broke that binding.

Three unrelated systems, one error: the thing verified and the thing shipped were not the same bytes.

So the receipt needs one more field, and it is the field that makes the others checkable. Not only which checks ran and what they returned, but what they ran against, plus an explicit statement that no helper, launcher, flag or fixture used to produce the numbers was removed before delivery. If a diagnostic aid was needed to see the behaviour at all, that is the finding, not a footnote.

The earlier lesson still holds and this is its next instance. A label carried more authority than its evidence. This time the label was the word passed.