Skip to content

Document what Engine DJ does to a converted library - #7

Merged
jrgutier merged 1 commit into
mainfrom
docs/engine-desktop-merge
Aug 1, 2026
Merged

Document what Engine DJ does to a converted library#7
jrgutier merged 1 commit into
mainfrom
docs/engine-desktop-merge

Conversation

@jrgutier

@jrgutier jrgutier commented Aug 1, 2026

Copy link
Copy Markdown
Owner

Docs and comments only — no behaviour change.

Two things measured on a real 3,673-track stick that were previously undocumented, and both of which look like defects if you don't know about them.

1. Opening Engine DJ can merge its desktop library onto the stick

Convert → clean verify → open Engine DJ → verify again:

track library: playlist_count: expected=45 actual=48

naming playlists that exist in no rekordbox playlist. Controlled repeat with Engine's desktop database cleared, identical conversion both times:

Engine desktop library Playlists after opening Engine Rows not written by us
Populated 48 (3 added, ids past our allocation) 6
Cleared 45 (none added, no row changed) 0

So the extras were Engine syncing its own desktop library — a legitimate feature, not corruption and not something rb2engine wrote. Their lastEditTime values predated the conversion, consistent with rows that already existed on the desktop side.

verify was correct to report it. Troubleshooting now explains the cause, gives the one-line SQL to tell Engine's rows from ours, and says plainly: verify right after convert, before launching Engine DJ.

The discriminator matters — we pin lastEditTime to the epoch on every playlist row we write, so anything with a real timestamp came from Engine. That survives Engine reassigning ids, which the id watermark does not.

2. Engine populates currentPlayedIndiciator itself

Diffing a pristine conversion against the same database after Engine opened and closed it, across schema, pragmas and every cell (blobs by hash):

Information.currentPlayedIndiciator:  0  →  1698144667125441751

That was the only change. No schema objects added, no pragma changes, and Track, PerformanceData, AlbumArt, Playlist, PlaylistEntity all byte-identical.

Recorded next to _DETERMINISTIC_PLAYED_INDICATOR so the question "should we write that field too?" has a documented answer: no. Engine sets it on first open, and writing an opaque constant would forfeit byte-identical rebuilds for nothing.

Verification

  • 704 tests pass, ruff + mypy clean
  • Stick re-verified end-to-end after a fresh rekordbox re-export: 0 discrepancies, 3,673 matched

🤖 Generated with Claude Code

https://claude.ai/code/session_01V3aF4y4GdsuJta2bfYUZ8w

Two findings from measuring a real 3,673-track stick, both previously unwritten
down and both easy to mistake for defects.

Opening Engine DJ can merge its desktop library onto the stick
--------------------------------------------------------------
A convert followed by a clean verify, then Engine DJ opened, then verify again:
playlist_count expected=45 actual=48, naming playlists in no rekordbox
playlist. Those playlists are real and Engine added them on purpose.

Controlled repeat with Engine's desktop database cleared, same conversion both
times: 48 playlists with the desktop populated, 45 with it cleared, and in the
cleared run not one row changed. So the extras were Engine syncing its own
desktop library, not corruption and not something rb2engine wrote — their
lastEditTime values predated the conversion, consistent with rows that already
existed on the desktop side.

Troubleshooting now covers this, including how to tell Engine's rows from ours:
we pin lastEditTime to the epoch on every playlist we write, so anything with a
real timestamp came from Engine. That discriminator survives Engine reassigning
ids, which the id watermark does not.

Engine populates currentPlayedIndiciator itself
-----------------------------------------------
Diffing a pristine conversion against the same database after Engine had opened
and closed it: Information.currentPlayedIndiciator 0 -> 1698144667125441751 was
the ONLY change. No schema objects, no pragma changes, and Track,
PerformanceData, AlbumArt, Playlist and PlaylistEntity all byte-identical.

Recorded next to the pin so the next reader does not have to re-derive it, and
so the question "should we write that field too?" has a documented answer: no.
Engine sets it on first open, and writing an opaque constant would forfeit
byte-identical rebuilds for nothing.

Docs and comments only — no behaviour change. 704 tests, ruff + mypy clean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V3aF4y4GdsuJta2bfYUZ8w
@jrgutier
jrgutier merged commit 66132ed into main Aug 1, 2026
9 checks passed
@jrgutier
jrgutier deleted the docs/engine-desktop-merge branch August 1, 2026 04:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant