fix(dictation): make daily transcript appends crash-safe (atomic write)#1325
Draft
r3dbars wants to merge 2 commits into
Draft
fix(dictation): make daily transcript appends crash-safe (atomic write)#1325r3dbars wants to merge 2 commits into
r3dbars wants to merge 2 commits into
Conversation
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Dictation is the highest-frequency capture surface, and its day-file append was the one capture write that wasn't atomic: appendSection opened the existing Dictations_YYYY-MM-DD.md with a FileHandle, seeked to the end, and wrote the new section in place. A crash or interruption part way through that in-place write would glue a half-written section onto the file and corrupt every earlier entry for the day. Rewrite the append to match the safe-write pattern the rest of the app already uses for meeting artifacts (atomic write-temp-then-rename): read the existing day file, concatenate the new section, and write the whole file with String.write(atomically: true). The prior content survives untouched until the new file is renamed into place, so a failed write can lose only the in-flight section, never the existing day. New-file creation and the delete-rebuild path were already atomic; this closes the last gap. Add a regression test that simulates an interrupted append (read-only day folder so the atomic temp write throws mid-write) and asserts the existing day file is byte-for-byte intact with no partial second entry leaked in. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.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.
Why
Dictation is the highest-frequency capture surface, and its day-file save was the one capture write that wasn't atomic. Everything else (meeting artifacts, journals, JSON state) already uses
Data.write(options: .atomic)/String.write(atomically: true). Dictation appends did not.DictationTranscriptWriter.appendSectionopened the existingDictations_YYYY-MM-DD.mdwith aFileHandle, seeked to the end, and wrote the new section in place. A crash, power loss, or interruption part way through that write would leave a half-written section glued onto the file and corrupt every earlier entry for that day.What changed
Sources/Dictation/DictationTranscriptWriter.swift—appendSectionnow reads the existing day file, concatenates the new section, and writes the whole file atomically viaString.write(atomically: true)(write-temp-then-rename) — the same safe-write pattern the rest of the app uses. The prior content survives untouched until the new file is renamed into place, so a failed write can lose only the in-flight section, never the existing day. Removed the now-unusedfileEndsWithBlankLinebyte-probe helper (replaced by ahasSuffix("\n\n")check on the in-memory string).String.write(atomically: true)) and the delete-rebuild path (DictationTranscriptStore) were already atomic — this closes the last gap.Markdown layout is unchanged (same
\n\nseparator and section shape), so theTranscriptedCaptureKitday-file parser needs no change.Test
Added a regression suite in
Tests/DictationTranscriptWriterTests.swift: it saves a first entry, then simulates an interrupted/failed append by making the day folder read-only so the atomic temp write throws mid-write, and asserts the existing day file is byte-for-byte intact with the second (doomed) entry never leaking in.Verification
bash build.sh --no-open✅bash run-tests.sh✅ (10157 passed, 0 failed)🤖 Generated with Claude Code