fix(store): write notes with LF on every platform - #214
Conversation
`_atomic_write` and `paths.atomic_write_text` opened in text mode with the default newline translation, so every `\n` became `os.linesep` on write: the same note was LF on POSIX and CRLF on Windows. Nothing in the code could see it, because text-mode reads translate back. Four bugs came out of that single property, each passing a green Linux run and failing only on the Windows legs: * compliance-log rotation that never fired (#202), * transaction identity hashes that never matched what had just been written, so recovery classified every file as a foreign edit and rolled back nothing, * pre-image restores that translated a second time, growing a blank line in the note each rollback was supposed to restore. An explicit newline="\n" makes the bytes identical everywhere, which also makes note digests, mesh merges, and git diffs platform-stable. It matters most in paths.atomic_write_text, which writes omi-guard.sh: a shell script whose shebang line ends \r\n is not a shell script. Existing CRLF files keep their bytes until something rewrites them; Obsidian, git, and every parser here read LF fine on Windows. Co-Authored-By: Claude Opus 5 <[email protected]>
|
Warning Review limit reached
Next review available in: 28 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (6)
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 |
1 of 6 in the follow-up batch. Ships in v8.1.0.
The root cause behind four bugs
store._atomic_writeandpaths.atomic_write_textopen in text mode withnewline=None, whose documented behaviour is to translate every\ntoos.linesepon write. So the same note was written LF on POSIX and CRLF on Windows — and nothing in the code could see it, because text-mode reads translate back.Every Windows-only failure in this repo's recent history traces here, and each one passed a fully green Linux run first:
Three of those were silent: no crash, no error, just a subsystem quietly not working on one platform.
Fix
newline="\n"on both writers. Bytes are now identical on every OS, which additionally makes note digests, mesh merges, and git diffs platform-stable —note_versioncurrently hashes different bytes for the same logical note depending on where it was written.It matters most in
paths.atomic_write_text: that one writesomi-guard.sh, and a shell script whose shebang line ends\r\nis not a shell script.Compatibility
Existing CRLF files keep their bytes until something rewrites them — this changes what we write, not a migration. Obsidian, git, and every parser in this repo read LF fine on Windows.
Test
test_notes_are_written_with_lf_on_every_platformasserts no\r\nin a written note. It only fails on Windows, which is exactly where the class of bug lives — the Windows legs are the point.Gates
ruff check .·mypy src(strict) ·pytest(885 passed) ·pip-audit— green locally.🤖 Generated with Claude Code