Skip to main content
When a process dies holding an effect key, nothing happens. No sweeper frees it, no timer fires, and the process that comes back does not scan or repair — it waits to be asked for an effect key, exactly as it did before it died. That is deliberate, and this page is why.

What a process may conclude

A process that finds a record reserved or executing may conclude exactly two things: what state the record is in, and whether its lease is still live. It may not conclude that the holder is gone. “The holder is dead” is not knowable from the store, and no column makes it knowable. The record carries an action id, which names an attempt and not a process. There is deliberately no holder host and no holder pid, because the first thing anyone writes against those columns is a reclaimer — if the holder is not alive, free the key — and that reclaimer is wrong on the day it matters, when a container that stopped answering a health check still has an open socket to a payment API. A field that invites a false inference is worse than no field.

What actually happens

An expired lease that is never contended stays executing in the table, and ctrlrun effects prints it as executing (lease expired). Reading is not a transition: listing effects, inspecting one, or opening the store moves nothing. The effect record’s resolved_by column holds cli:local for a person, not their username. CTRLRun does not authenticate the person at the terminal, so a name there would be a claim about somebody made from a value that somebody controls. cli:local says exactly what is known: somebody with the operator’s terminal. The EFFECT_RESOLVED event carries the same string in its resolver field, which is what lets you join the two, and the coarser human or reconcile in its own resolved_by.

A continuation held by a dead process

An elicitation holds a reservation open across a round trip. The row survives the process, and with a shared store a different process may finish it. One resumption is admitted and no more, because the token is consumed in the transaction that admits it. If the lease lapsed first, the resumption is refused and the effect becomes AMBIGUOUS by the ordinary path. Nothing in the library hands a continuation leg a FAILED, since v0.7. A continuation exists only because the remote answered once already and is holding the exchange, so nothing on the second leg can say the remote did nothing. ctrlrun.transport refuses to claim NotExecuted on a resumed run, and the MCP gateway records an unknown outcome for every path that could otherwise reach FAILED there: a connection it never established, a pre-dispatch JSON-RPC code, the 401 rule, and a tool error under an operator’s not_executed_on_error: true, which is a claim about the call that tool answers and not about the one carrying the effect. At 0.6.1 each of those recorded FAILED, and the gateway answered -41011 “not executed”, which permitted a retry of an effect the upstream may have been part-way through; it is -41010 and a ctrlrun resolve now. An executor that raises NotExecuted on its own evidence is still believed, as it always was. What changed is that nothing in the library will hand it one on a continuation.

What this does not do

  • Nothing sweeps. No background thread, no timer, no cron, no reap command. The lapse is noticed lazily, by the next contender, and never by anything running on a schedule.
  • An expired lease frees nothing. It is a refusal, not a reclaim. The next attempt is refused and the record is now unknown.
  • A restart repairs nothing and reports nothing. Opening the store migrates it and reads nothing else.
  • No receipt records the resolution. A receipt is written when the action reaches a terminal state; a resolution happens afterwards, often days later and by somebody who was not the actor. Mutating the receipt would be an alteration the chain would correctly report. ctrlrun effects and ctrlrun inspect are where you find it.
Verified by T159AMBIGUOUS survives a restart and still refuses a blind retry, against every store — T160 for the expired lease that frees nothing and the reads that transition nothing, T161 for the two authorities and what each is recorded as, T162 for the process identity that is deliberately absent, T163 for the continuation held by a dead process, and T177d for the display that is not a transition. G5 in ctrlrun verify grades the blocked blind retry on your store’s backend, in a scratch store of its own.

Next