Skip to content

feat(durability): atomic writes + registry lock (Theme N1)#29

Merged
NagyVikt merged 1 commit into
mainfrom
agent/n1-durability
May 17, 2026
Merged

feat(durability): atomic writes + registry lock (Theme N1)#29
NagyVikt merged 1 commit into
mainfrom
agent/n1-durability

Conversation

@NagyVikt
Copy link
Copy Markdown
Collaborator

Summary

Theme N1 from docs/future/17-ROADMAP.md — eliminate the two known data-loss windows in registry.json / snapshot writes.

  • src/infra/fs/atomic-write.ts — temp+rename with fsync(fd) and POSIX fsync(dir) after rename; mode applied before rename so 0600 files are never visible at a looser mode.
  • src/infra/fs/registry-lock.tsO_EXCL advisory lock with PID-liveness probe + 30 s wall-clock stale-lock heuristic.
  • persistRegistryAtomic is the single registry write path; it reloads under the lock and unions account entries before writing.
  • secureWriteFile now delegates to atomicWriteFile so every snapshot, current, and sessions.json write fsyncs.
  • AccountService.useAccount no longer calls saveRegistry directly — public method signatures unchanged.

Exit criteria covered (Theme N1)

  • src/infra/fs/atomic-write.ts lands with fsync-before-rename.
  • Every fsp.writeFile for registry.json, current, sessions.json, and snapshot files routes through atomicWriteFile (via secureWriteFile).
  • src/infra/fs/registry-lock.ts lands with stale-lock reaping (PID liveness + 30 s wall-clock).
  • AccountService.persistRegistry is the only write path; it reloads-under-lock then merges deltas.
  • src/tests/registry-durability.test.ts simulates the writer dying between writeFile and rename and asserts the registry still parses.
  • Release notes in releases/v0.1.25.md include a Durability section.

Verification

npm run build           # tsc clean
npm test                # 88/88 tests pass
node -e "..."           # saveRegistry still exported

Notes

  • Sibling PRs from N3 (errors taxonomy) and N4 (paths deprecation) are running in parallel; expect a rebase if they land first.
  • Dir-fsync is gated on process.platform !== "win32" since Windows does not allow opening a directory as a file.
  • In-process callers that share process.pid block each other instead of reaping the lock; cross-process stale ownership is handled by the liveness probe + 30 s heuristic.

Test plan

  • npm run build
  • npm test — all 88 tests green, including 3 new ones in src/tests/registry-durability.test.ts
  • node -e "require('./dist/lib/accounts/registry.js').saveRegistry" resolves
  • Singleton at src/lib/accounts/index.ts still constructs

🤖 Generated with Claude Code

- 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>
@NagyVikt NagyVikt merged commit e903003 into main May 17, 2026
12 checks passed
@NagyVikt NagyVikt deleted the agent/n1-durability branch May 17, 2026 15:31
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant