feat(phase 2.2): atomic write — temp+rename in setActive #24
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/phase-2.2-atomic-write"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Phase 2.2 of the Stream-a-Thon plan. Switches
setActivefromfs.writeFileSyncto a write-tmp-then-renameSyncpattern so a reader (theobs-source-switcherplugin polling at 1000 ms) can never observe a torn / partial / 0-byte state on the${screen}.txtfiles.Evidence
Two 30-minute Mac soaks (1 Hz writer, ~60 Hz reader, 96k+ reads each):
write(oldfs.writeFileSync)rename(new)Both strategies pass on macOS / APFS. The decision picks
renamefor Windows safety: on NTFS,MoveFileEx(MOVEFILE_REPLACE_EXISTING)(what Node'sfs.renameSynccalls) is atomic;fs.writeFileSyncbriefly exposes a truncate-then-write window. Reversibility is a one-commit revert.Full evidence + rationale in
docs/plugin-contract.md§ "Phase 2.2 — Atomic-Write Decision".Files
lib/atomicWrite.ts— sharedatomicWriteFileSynchelper (tmp + rename + cleanup-on-error)app/api/setActive/route.ts:50— call sitelib/__tests__/atomicWrite.test.ts— 5 tests (happy path, no-leftover-tmp, overwrite, unique tmp paths, error cleanup)scripts/atomicWriteSoak.ts+scripts/atomicWriteSoak/— the harness used to produce the evidence, kept in-repo for the Windows F1 follow-updocs/plugin-contract.md— decision sectiondocs/atomic-write-soak-mac.{write,rename}.json— soak evidence artifactspackage.json—npm run soak:atomic-write.gitignore— excludedocs/atomic-write-soak-tmp/Test plan
tsc --noEmitcleannext buildcleannpm run audit:sqlite-openscleandocs/atomic-write-soak-win.rename.jsonTwo 30-min Mac soaks (1 Hz write, ~60 Hz read, 96k+ reads each) showed zero torn reads for both fs.writeFileSync and the temp+renameSync strategy. Strategy A (rename) wins on the Windows safety argument: MoveFileEx(REPLACE_EXISTING) is atomic on NTFS, removing the truncate-then-write window that fs.writeFileSync exposes. Cost on Mac is zero-measurable; reversibility is a single-commit revert. - lib/atomicWrite.ts: shared atomicWriteFileSync helper (write tmp, rename, unlink tmp on rename failure). - app/api/setActive/route.ts: switch the \${screen}.txt write site to atomicWriteFileSync; drop the unused fs import. - scripts/atomicWriteSoak.ts + scripts/atomicWriteSoak/: harness used to produce the evidence, kept in-repo for follow-up Windows soak (F1) and future regressions. - docs/plugin-contract.md: append Phase 2.2 — Atomic-Write Decision section with the soak data, decision rationale, and follow-ups. - docs/atomic-write-soak-mac.{write,rename}.json: evidence artifacts. - package.json: add 'soak:atomic-write' npm script. - .gitignore: exclude docs/atomic-write-soak-tmp/ runtime files. 210/210 jest tests pass; type-check, lint, audit:sqlite-opens, and next build all clean.