feat(rb-dates): preserve Rekordbox "Date Added" across a lossy→lossless swap#15
Open
deviationist wants to merge 1 commit into
Open
feat(rb-dates): preserve Rekordbox "Date Added" across a lossy→lossless swap#15deviationist wants to merge 1 commit into
deviationist wants to merge 1 commit into
Conversation
…ss swap Replacing a file forces a re-add in Rekordbox, which resets djmdContent.created_at to now and loses the original "Date Added". New `rb-dates` subcommand rescues it via a two-phase, path-keyed flow: - `snapshot` (read-only): resolve each lossy file to its Rekordbox row, read the raw created_at, and stash it in a sidecar JSON keyed by the lossless path. Also exposed as a `lossless-tags --snapshot-dates` hook so capture happens in the tag-copy pass, before any --delete-lossy. - `apply` (read-only/dry-run by default): re-resolve the re-added lossless row by path and restore the date. This is the FIRST and only sanctioned write to the Rekordbox DB (every other access stays mode=ro). The write (RekordboxDBWriter) opens the real master.db read-write, is USN-correct (bumps the row's rb_local_usn + agentRegistry.localUpdateCount as a normal local edit does), and wal_checkpoint(TRUNCATE)s so the Resilio-synced file stays consistent. It is heavily guarded (rb_db_safety): WRITE-RB-DATES token + a "free up the DB" checklist (close Rekordbox everywhere, pause Resilio), non-empty-WAL refusal, file-stability probe, local lsof check, and a mandatory master.db backup. Pairing logic extracted to utils/pairing.py and shared with lossless-tags. Path identity bridged host→container→Rekordbox via resolve_rb_id_by_host_path. Verified end-to-end against a copy of the live encrypted DB (created_at written, USN bumped 341737→341738, WAL truncated, idempotent re-apply). 19 new unit tests; full suite 141 passing; ruff/black/mypy clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
deviationist
force-pushed
the
feat/rb-date-preservation
branch
from
June 11, 2026 23:31
13d7a61 to
890258a
Compare
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.
What & why
Replacing a file forces a re-add in Rekordbox (re-analyze won't do for a format change), which resets
djmdContent.created_atto now and loses the original "Date Added" — the very field thedatescommand syncs into Plex. This adds arb-datessubcommand that rescues it: capture the old date before the swap, restore it after you re-add the file. Keyed by file path.Two phases
snapshot(read-only): resolve each lossy file to its Rekordbox row, read the rawcreated_at, and stash it in a sidecar JSON keyed by the lossless path (raw string → byte-exact restore). Also exposed as alossless-tags --snapshot-dateshook so it's captured during the tag copy, before any--delete-lossy.apply(read-only/dry-run by default): re-resolve the re-added lossless row by path and write the date back.Every other Rekordbox access is strictly
mode=ro. The single write path (rekordbox/RekordboxDBWriter.py):master.dbread-write.rb_local_usn+ the globalagentRegistry.localUpdateCount, exactly as Rekordbox does for a local edit.wal_checkpoint(TRUNCATE)s so the Resilio-synced file stays consistent across workstations.It is heavily guarded (
utils/rb_db_safety.py): theWRITE-RB-DATEStoken + a typed "free up the DB" checklist (close Rekordbox on every workstation, pause Resilio), a non-empty-WAL refusal, a file-stability probe, a locallsofcheck, and a mandatorymaster.dbbackup. Successfully-restored entries are pruned from the sidecar (idempotent re-runs).Verification
Exercised end-to-end against a copy of the live encrypted DB:
created_atwritten, global USN 341737→341738, rowrb_local_usn→341738, idempotent re-apply, WAL truncated to 0 — live DB untouched. 19 new unit tests (sidecar store, safety guards, USN SQL builder, pairing); full suite 141 passing;ruff/black/mypyclean. Docs updated (CLAUDE.md, README runbook,.env.example,.gitignore).🤖 Generated with Claude Code