refactor(windows): share the atomic-replace retry instead of one writer owning it - #1946
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. 🗂️ Base branches to auto review (2)
Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
✅ READY
Hygiene✅ Deterministic PR hygiene checks passed. |
5315f76 to
ff4408a
Compare
a8cef7d to
a3169db
Compare
ff4408a to
c23031a
Compare
…er owning it src/config.ts:102-123 knew that Windows can refuse rename with EBUSY, EPERM or EACCES while a scanner or sync client still holds the target, and retried twice (25ms then 50ms). Nothing else did. Eight durable publishers called renameSync directly: - src/codex/prompt-journal.ts, whose journal carries full config.toml bytes -- losing that publish is what breaks journal restore; - src/lib/config-ownership.ts, the uninstall manifest; - src/claude/agents-inject.ts, the generated agent definitions; - src/lab/automation/persistence.ts and config-persistence.ts; - src/lab/ledger/purge.ts, the rewritten ledger; - src/storage/cleanup.ts, both the satellite backup (1094) and the restore-pending state file (2438); - src/tray/windows.ts, the tray's owned-file publisher. None corrupts anything on failure; they throw rather than publish a partial file. But under a real-time scanner holding the target they turn a momentary hold into a user-visible failure, and the tolerance to survive it already existed one module away. Three renameSync calls in src/storage/cleanup.ts are deliberately NOT converted. 1639 and 2616 move directories between staging and trash, and 1667 moves one back on rollback: these relocate a directory rather than publishing a temp file over a destination. Windows directory-move failures are a different problem with a different fix, and the callers already handle them. The loop moves to src/lib/windows-atomic-replace.ts rather than becoming an export of config.ts: config-ownership.ts is one of the callers and config.ts already imports config-ownership.ts, so the obvious placement would close an import cycle. config.ts re-exports renameAtomicFile because callers use it; renameAtomicFileAsync stays internal, as it was before. The envelope is unchanged at two retries, and tests/windows-atomic-replace.test.ts now pins it: which codes count as transient, that POSIX never retries, and that the bound is two rather than hopeful. The extracted module had no test of its own before -- config.test.ts exercises it only through atomicWriteFile -- so an accidental widening would have gone unnoticed. That matters because the next commit adds counters specifically to decide whether widening is justified. Verification: bun run typecheck clean; bun test over claude-agents-inject, windows-atomic-replace, config, storage-cleanup and windows-tray.
c23031a to
c5c6644
Compare
|
The Nothing in this PR touches keyring code, CI configuration, or dependencies — it moves a rename retry loop into |
|
Validation before merge: scratch-worktree merge onto |
Summary
src/config.ts:102-123knew that Windows can refuserenamewithEBUSY,EPERMorEACCESwhile a scanner or sync client still holds the target, and retried twice (25ms then 50ms). Nothing else did. Two durable publishers calledrenameSyncdirectly:src/codex/prompt-journal.ts, which publishes a journal carrying fullconfig.tomlbytes — losing that publish is what breaks journal restore — andsrc/lib/config-ownership.ts, which publishes the uninstall manifest.src/lib/windows-atomic-replace.tsrather than becoming an export ofconfig.ts:config-ownership.tsis one of the callers andconfig.tsalready importsconfig-ownership.ts(line 47), so the obvious placement would close an import cycle.config.tsre-exports the names because they are part of its public surface.Third of a stacked chain implementing
devlog/_plan/260817_windows_stability_program/(phase030). Targets #1945; retarget todevonce the parents land.Verification
bun run typecheck— clean--isolaterun over 809 files): batches 1-2 green at 647 and 1032 pass; remaining batches running. One pre-existing failure intests/codex-app-server-processes.test.ts("a defaulted read is memoized") reproduces on cleanorigin/devand is unrelated to this change.Checklist