mirror of
https://github.com/AgentSeal/codeburn.git
synced 2026-11-01 12:01:05 +00:00
writeDockEnabled still did its own read, mutate and atomic write of windows-dock.json, outside the lock the rest of the module takes. It is the Node side of the dock's enabled switch, reached from the desktop app's Sidebar toggle, so a toggle there could still land between the tray app's read and its rename and erase whatever it had just stored, which in practice is the rail's placement. It now merges through patchTrayFile, which takes the lock for the whole cycle; enabled is already an accepted dock key, so nothing is dropped on the way. Stale-lock recovery could hand out two owners at once. Both sides did "if abandoned, unlink and retry", and nothing stood between the check and the unlink: contender A could already have removed the stale lock and created a fresh one of its own, and B's unlink then deleted A's fresh lock, leaving both of them holding the file. Windows' share mode hides this most of the time, because a lock a live holder still has open will not unlink at all, but the same protocol runs on Linux and macOS, where the unlink always succeeds. Removing an abandoned lock is now itself arbitrated, by the same exclusive create the lock uses, on a sibling <lock>.takeover file. Only its winner may unlink, and only after re-checking staleness under that right, so a rival that reclaimed first keeps the lock it now holds. A takeover file is dropped on every path out, never held across the wait, and one left behind by a reclaimer that died is freed by the same staleness rule as the lock itself. The cross-process test asserted only each side's final value, so it noticed a lost update only when the last writes happened to collide: on a deliberately broken lock it passed about one run in three, which is weak evidence for the property it exists to prove. Each side now writes a counter that only rises, and a reader thread watches the file for the whole run. A separate reader is the point: neither writer can see its own counter rolled back, because in the unlocked cycle each carries the other side's value forward itself, so what it reads back is never older than what it last read. With the lock both counters only ever rise in the file; without it one falls. It now fails on every unlocked run. Also: a placement that cannot be saved is logged instead of discarded silently, since losing the lock under contention is a new way for the rail to revert at the next launch; and the Codex sameLogin comment now states outright that a replacement document carrying none of the three identifying fields reads as the same login and is written over, which is the deliberate side to err on. |
||
|---|---|---|
| .. | ||
| after-pack.cjs | ||
| buildStamp.test.ts | ||
| buildStamp.ts | ||
| snap-grants.test.ts | ||
| stage-cli.mjs | ||
| stage-menubar.mjs | ||
| tray-settings-xproc-worker.ts | ||
| verify-windows-installer.mjs | ||
| verify-windows-installer.test.ts | ||
| windows-installer-paths.d.mts | ||
| windows-installer-paths.mjs | ||