feat(durability): atomic writes + registry lock (Theme N1)#29
Merged
Conversation
- Add src/infra/fs/atomic-write.ts: temp-file write, fsync(fd), chmod before rename, rename, fsync(dir). Dir fsync gated on non-Windows per POSIX. - Add src/infra/fs/registry-lock.ts: O_EXCL lock with PID-liveness probe and 30 s wall-clock stale-lock heuristic. In-process callers block instead of reaping each other. - Make secureWriteFile a thin wrapper over atomicWriteFile so every snapshot, current, and sessions.json write fsyncs. - Add persistRegistryAtomic: single registry write path that reloads under the lock and unions account entries before writing. - Route AccountService.persistRegistry and useAccount's direct saveRegistry call through the locked atomic path; no public method signature changes. - Add src/tests/registry-durability.test.ts covering the rename-fails-mid- write window, in-process lock serialization, and stale-lock reaping. - Release notes in releases/v0.1.25.md include a Durability section. Refs: docs/future/17-ROADMAP.md Theme N1, docs/future/01-ARCHITECTURE.md §5. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 17, 2026
NagyVikt
added a commit
that referenced
this pull request
May 18, 2026
Bumps package.json + package-lock.json from 0.1.24 to 0.1.25 and extends releases/v0.1.25.md to cover every theme that landed since v0.1.24: - N1 durability (#29): atomic writes, registry lock, fsync-before-rename - N2 account-service split (#30): 1675 LOC -> 164 LOC orchestrator + 12 modules - N3 error taxonomy + --json (#28): AuthmuxError base, stable codes, JSON envelope - N4 lazy path resolvers (#27): bare constants deprecated for v0.2.0 - P0 wave (#26): secure perms, [y/N] update prompt, kiro ENOENT, CI matrix, registry proxy-source round-trip, 18k-line improvement docs Notes follow the canonical 7-section shape from docs/future/17-ROADMAP.md (Added, Changed, Fixed, Deprecated, Removed, Security, Migration), with the prior Durability section folded into a "Theme deep-dives" appendix so the canonical shape is intact. No code changes. No npm publish. Verification: - npm run build: clean - npm test: 129/129 pass - node -e "require('./package.json').version" -> 0.1.25 - node -e "require('./package-lock.json').version" -> 0.1.25 Co-authored-by: NagyVikt <nagy.viktordp@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Theme N1 from
docs/future/17-ROADMAP.md— eliminate the two known data-loss windows inregistry.json/ snapshot writes.src/infra/fs/atomic-write.ts— temp+rename withfsync(fd)and POSIXfsync(dir)after rename; mode applied before rename so 0600 files are never visible at a looser mode.src/infra/fs/registry-lock.ts—O_EXCLadvisory lock with PID-liveness probe + 30 s wall-clock stale-lock heuristic.persistRegistryAtomicis the single registry write path; it reloads under the lock and unions account entries before writing.secureWriteFilenow delegates toatomicWriteFileso every snapshot,current, andsessions.jsonwrite fsyncs.AccountService.useAccountno longer callssaveRegistrydirectly — public method signatures unchanged.Exit criteria covered (Theme N1)
src/infra/fs/atomic-write.tslands withfsync-before-rename.fsp.writeFileforregistry.json,current,sessions.json, and snapshot files routes throughatomicWriteFile(viasecureWriteFile).src/infra/fs/registry-lock.tslands with stale-lock reaping (PID liveness + 30 s wall-clock).AccountService.persistRegistryis the only write path; it reloads-under-lock then merges deltas.src/tests/registry-durability.test.tssimulates the writer dying betweenwriteFileandrenameand asserts the registry still parses.releases/v0.1.25.mdinclude a Durability section.Verification
Notes
process.platform !== "win32"since Windows does not allow opening a directory as a file.process.pidblock each other instead of reaping the lock; cross-process stale ownership is handled by the liveness probe + 30 s heuristic.Test plan
npm run buildnpm test— all 88 tests green, including 3 new ones insrc/tests/registry-durability.test.tsnode -e "require('./dist/lib/accounts/registry.js').saveRegistry"resolvessrc/lib/accounts/index.tsstill constructs🤖 Generated with Claude Code