Project contents
← Automating Garage Dreams
Progress update, 1 Sept 2026
A short bullet-point summary of project progress up to 1 Sept 2026.
Updates are bullet-point summaries generated with AI from my commits and build notes, then checked by me. Project articles and learning notes are written by me.
- The test failure filed as a flake last week was a real defect: two processes could hold the run lock at once. Measured at 4 failures in 25 rounds. The six-process test that guards it only catches it about one run in six, which is precisely why a previous session shrugged and moved on.
- The mechanism, from an instrumented timeline: both contenders renamed the stale lock aside and both renames succeeded, because they moved different files. One moved the stale lock; the other, still acting on a read it took earlier, moved the first one’s live lock.
renameis atomic per file, and nothing checked that the file being moved was still the file that had been judged. - The first hypothesis was wrong and is worth keeping. Creating a file with
wxpublishes it before the payload lands, and the lock reader mapped both empty and torn reads to “reclaimable”: 2,104 empty and 11,139 torn reads across 17,599 cycles, so that window is entirely real. It is not this bug. Fixing it would have narrowed the failure and left it in place. - The lock is not a file any more. It is an exclusive listening socket on a loopback port derived from the working directory. A lock file outlives the process that wrote it, so it needs a staleness rule, and the staleness rule is where both file-based versions failed. The filesystem offers no compare-and-swap, so ownership is inferred from bytes another process can replace between the read and the act. The kernel owns the port and releases it however the holder dies: no stale state, no reclaim path, no race in the reclaim path. Nothing is served on the socket, so no connection can leave the port unbindable.
- A proposed fix was rejected before it was written. It kept the file, added identity verification after the rename, and carried an acknowledged residual where a lost restore leaves a live holder inside the critical section without owning the published lock. That is the same safety failure through a narrower interleaving, and “unlikely” is not a correctness argument for a lock guarding a working tree, a build and a commit.
- Review found the availability test was vacuous: the client destroyed its own connection, so it passed whether or not the holder destroyed anything. It is now proved by mutation: deleting the handler makes it fail with the right message. A sibling test that searched 400 random paths for a collision was replaced with pigeonhole, where 1001 candidates over 1000 ports guarantee a pair, because a probability of e^-80 is not the same as never.
- The deterministic reproduction is kept in history and deleted from the suite. It drove a temporary seam between the staleness decision and the rename and failed 5 times in 5 runs while the probabilistic test passed beside it. A test of steps that no longer exist is scaffolding, not coverage.