codeburn/app/scripts
iamtoruk a1b4b22f51 fix(windows): close three holes in the cross-process preference lock
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.
2026-09-03 10:28:05 -07:00
..
after-pack.cjs feat(app): bundle the CLI inside the packaged app 2026-07-16 09:27:46 -07:00
buildStamp.test.ts fix(app): clean build stamp, splash without hash, About checks for updates 2026-07-17 14:30:00 -07:00
buildStamp.ts fix(app): clean build stamp, splash without hash, About checks for updates 2026-07-17 14:30:00 -07:00
snap-grants.test.ts snap: narrow session-log grants to what the parsers read and drop the Copilot credential root 2026-09-01 09:56:03 -07:00
stage-cli.mjs build(app): allow a slow Electron start in the CLI staging smoke test 2026-09-03 00:01:34 -07:00
stage-menubar.mjs fix(app): stage the MSI a local Tauri build actually writes 2026-09-02 14:40:41 -07:00
tray-settings-xproc-worker.ts fix(windows): close three holes in the cross-process preference lock 2026-09-03 10:28:05 -07:00
verify-windows-installer.mjs fix(release): verify all desktop assets 2026-08-13 20:01:00 +05:30
verify-windows-installer.test.ts fix(release): verify all desktop assets 2026-08-13 20:01:00 +05:30
windows-installer-paths.d.mts fix(release): harden Windows installer verification 2026-08-13 19:47:31 +05:30
windows-installer-paths.mjs fix(release): harden Windows installer verification 2026-08-13 19:47:31 +05:30