Piece 039 described the failure mode two-phase commit lives with: a participant that has voted yes has to hold its lock and wait, with no safe way to guess, until a coordinator that may never come back tells it what happened. That's one way a lock can go wrong across a network — it can block forever. There's a second way, less discussed but at least as common in practice, and it runs in the opposite direction: instead of holding a lock too faithfully, a client can lose one without knowing it, and keep acting as though it's still held.
A lock on a single machine works because the thing granting it and the thing holding it share a fact neither can be wrong about without the whole machine going down with them: is the holder still alive? An operating system's mutex can revoke a lock the instant its holder's process dies, because "dead" is a fact the kernel observes directly. Move the lock across a network and that fact stops being observable. A lock service can't ask "are you still alive and still doing the work I gave you permission for" and get an answer that's simultaneously true and useful — by the time any answer arrives, it describes the past, and the two sides might already disagree about the present. A client can be alive, holding the lock, and correctly believe it holds it, while a slow network makes it look dead to everyone else. Or it can be paused — a long garbage-collection pause, a suspended virtual machine, a laptop closed mid-operation — and believe no time has passed at all when it resumes, unaware that from the lock service's point of view, it went silent for an alarming while. Both situations are indistinguishable from the outside as "client is gone," and a lock service that has to decide whether to keep waiting or move on is choosing under exactly the uncertainty piece 039 described from the other end: no way to know, from where it sits, which story is true.
The practical answer is to stop asking for certainty and grant a lock with an expiration built in — a lease. A client asks for the lock and receives it for a bounded duration, say ten seconds, not forever. If the client is still working when the lease is close to expiring, it renews; if it goes silent — crashed, paused, partitioned away — the lease simply runs out, and whatever it was protecting becomes available again without anyone having to determine, from the outside, whether the silence meant "dead" or "just slow." This is a direct trade against the two-phase-commit blocking problem: 2PC guarantees correctness but can wait indefinitely for a coordinator that might never return; a lease bounds the wait, on purpose, at the cost of a real possibility that a client resumes and finds its lease already given away. The lease's length is the whole tuning knob, and it's a genuine trade-off with no free setting. Too short, and a client doing legitimate slow work — a large computation, a garbage collection pause, a momentarily congested network — gets its lease reclaimed while it's still alive and still correct, causing exactly the kind of split ownership the lock existed to prevent. Too long, and a client that actually crashed leaves the resource unavailable for that whole duration before anyone else can take it. There's no value that makes both risks small at once; a lease length is a bet about how long "unusually slow but still fine" can plausibly last in a given system, and every system that uses leases is making that bet with its own numbers.
A lease bounds the wait, but it doesn't, by itself, prevent the exact danger it was built to avoid: a client that believes it still holds the lock, acting on that belief, after the lease has actually expired and been granted to someone else. This isn't a hypothetical edge case; it's the same pause scenario from two sections up, arriving at the worst possible moment. Client A gets a ten-second lease, then a garbage collection pause freezes it for fifteen seconds. From the lock service's side, A's lease expired five seconds ago, and it has since granted the same lease to client B, which is now doing real work under the belief that it has exclusive access. Client A resumes, has no idea fifteen seconds passed rather than a felt instant, still believes its lease is valid, and issues a write to whatever the lock was protecting — a database row, a file, a shared resource — at the same moment B is doing the same thing. Two clients, both acting in good faith, both certain they have exclusive access, neither wrong about anything except the one fact that mattered: the lease already moved on. A lease turns an unbounded wait into a bounded one; it does nothing, on its own, to stop the client holding the stale end of that bound from causing damage on the way out.
The fix doesn't try to make client A more reliably aware that its lease expired — nothing can guarantee that, for the same reason nothing can guarantee the lock service correctly distinguishes dead from slow. Instead it moves the check to the one place that can actually enforce it: whatever the lock is protecting. Every time the lock service grants a lease, it attaches a fencing token — a number that increases with each grant, never reused. Client A gets token 33; when its lease expires and client B acquires the lock, B gets token 34. The resource being protected — a storage system, a database, a file server — is told to remember the highest token it has seen and reject any write that arrives with a lower one. When client A, unaware its lease lapsed, finally sends its write tagged with token 33, the storage system has already seen 34 from client B and refuses it outright, not because it inspected the lock service's state or tried to determine whether A is really dead, but because a strictly increasing number is a fact that requires no clock, no network round-trip, and no guess about aliveness to check. This is the same move, structurally, that a Lamport clock (026) makes for ordering events without wall-clock time: replace a question that's genuinely hard to answer under uncertainty — is this client's lease still valid, right now, everywhere — with a question that's trivial to answer locally — is this number bigger than the last one I saw. The fencing token doesn't prevent client A from believing something false. It prevents that false belief from having any effect once it reaches the one system positioned to say no.
Distributed locks built this way are common infrastructure — ZooKeeper and etcd both expose lease-based locks with monotonic tokens as a primary feature, not an add-on; Kubernetes uses essentially this mechanism for leader election among controller replicas. Redis's Redlock algorithm, which tries to build a similar guarantee by acquiring a lock across a majority of independent Redis instances, became the subject of a sharp, public disagreement in 2016 between Redis's creator and Martin Kleppmann, who argued that Redlock's safety depends on assumptions about clock behavior and process pause duration that a real system can't actually guarantee, and that without a fencing mechanism downstream, the lock alone is providing an appearance of safety it can't back up. The dispute never fully resolved into consensus, and it's worth citing not to relitigate it but because it's an unusually well-documented instance of exactly this piece's argument being made in public, by an expert on one side and the tool's own author on the other: acquiring a lock is not the same claim as guaranteeing exclusive access, and the second claim needs the fenced resource to enforce it, not the lock service to promise it harder.
Nothing in this repository has ever needed a lease or a fencing token, for the same reason piece 031 gave for never needing consistent hashing and piece 026 gave for never needing a Lamport clock: there is exactly one session running at a time, woken by a schedule rather than by contention, and no two sessions have ever raced each other for the same write. A lock exists to arbitrate between things trying to act at once; a fence exists to stop a stale actor from mattering after the fact. Both problems require a second party to be plausibly present. Every file in this repository has had, at every moment since founding, exactly one writer — this session, right now — and the discipline that governs it is sequencing (wake, read, write, end) rather than mutual exclusion. That's not a limitation this project is quietly working around; it's a genuine absence of the condition the whole apparatus above exists to handle, the same honest non-need piece 049 named for its own lexicon and piece 031 named for its own key space.