Not to be confused with #590. That one makes tag writes fast; this one makes them survive what can go wrong. Both are prerequisites for batch tag work, for different reasons.
What is missing
No sync_all() before the rename. The atomic write pattern is write-temp, then rename. Without an explicit flush before that rename, a power loss or a crash can leave the rename committed over a temp file whose contents never reached the platter — a file that is neither the old one nor the new one.
Permissions are not carried across. A rewritten file gets whatever the process default gives it, so a file that was read-only, or group-writable, or carried an ACL somebody set on purpose, quietly changes character on the way through.
The Windows read-only attribute is a hard stop. A file marked read-only cannot be replaced, and the operation fails with an error that describes the symptom rather than the cause. Lifting it for the write and putting it back is a few lines, and it is the difference between "cannot save" and saving.
Antivirus holds files open, briefly. On Windows, a freshly written file is frequently scanned before the process can rename over it, and the rename fails with a sharing violation that a retry a moment later would have avoided. One attempt turns a transient lock into a permanent failure the user sees as data loss.
Why it comes before the batch work
Each of these is survivable once and unacceptable three hundred times. A single failed save is an annoyance somebody retries; the same failure rate applied to a folder-wide operation means every batch ends with a handful of files in an unknown state and no way to tell which.
It is also the stated prerequisite for online tag retrieval, which writes across a whole album at once.
Traps
- Pause playback before rewriting the current track's file on Windows, and re-hash blake3 into
track.file_hash afterwards (invariant).
track.file_hash carries two different algorithms — head-and-tail from the scanner, whole-file from the tag editor. Whichever path writes keeps its own convention.
- A retry loop needs a ceiling and a distinction. Retrying a sharing violation is right; retrying a permission error is a hang.
- Cross-volume moves are copy, verify, then delete — never delete-then-copy, and never a rename that silently degrades to a copy without the verify.
Not to be confused with #590. That one makes tag writes fast; this one makes them survive what can go wrong. Both are prerequisites for batch tag work, for different reasons.
What is missing
No
sync_all()before the rename. The atomic write pattern is write-temp, then rename. Without an explicit flush before that rename, a power loss or a crash can leave the rename committed over a temp file whose contents never reached the platter — a file that is neither the old one nor the new one.Permissions are not carried across. A rewritten file gets whatever the process default gives it, so a file that was read-only, or group-writable, or carried an ACL somebody set on purpose, quietly changes character on the way through.
The Windows read-only attribute is a hard stop. A file marked read-only cannot be replaced, and the operation fails with an error that describes the symptom rather than the cause. Lifting it for the write and putting it back is a few lines, and it is the difference between "cannot save" and saving.
Antivirus holds files open, briefly. On Windows, a freshly written file is frequently scanned before the process can rename over it, and the rename fails with a sharing violation that a retry a moment later would have avoided. One attempt turns a transient lock into a permanent failure the user sees as data loss.
Why it comes before the batch work
Each of these is survivable once and unacceptable three hundred times. A single failed save is an annoyance somebody retries; the same failure rate applied to a folder-wide operation means every batch ends with a handful of files in an unknown state and no way to tell which.
It is also the stated prerequisite for online tag retrieval, which writes across a whole album at once.
Traps
track.file_hashafterwards (invariant).track.file_hashcarries two different algorithms — head-and-tail from the scanner, whole-file from the tag editor. Whichever path writes keeps its own convention.