the downfall has begun

This commit is contained in:
Nathan Rashleigh committed 2026-06-09 18:46:25 +10:00
1 parent f71a2a3512
commit 9ccc3cea95
25 files changed
+4976 -109

No files matched your search

+167
View File
@@ -0,0 +1,167 @@
# KNOWN_DIVERGENCE.md — fields maple's writer intentionally does NOT match
This is the canonical list of bytes that differ between maple's
`captures/maple_acemo.pdb` and the AceMo reference
`data/acemo/PIONEER/rekordbox/export.pdb` **on purpose**, because they are
*history-dependent* artifacts of the particular reference file rather than rules
of the `.pdb` format.
## TL;DR
The AceMo reference `export.pdb` is **not a fresh from-scratch export — it is an
incrementally-edited rekordbox database.** rekordbox's DeviceSQL page manager
edits rows *in place*: when a row changes it appends a new copy, clears the old
slot's presence bit, and advances `used_size` past the dead bytes **without
compacting**. The reference therefore carries the residue of its entire edit
history.
maple writes a **fresh, fully-compacted** database (tightly 4-byte-aligned rows,
no dead rows, no leftover slots). That output is byte-correct for a *from-scratch*
rekordbox export, but it cannot — and should not — reproduce another file's edit
history. The fields below are the consequences of that, and the team has decided
**not to chase them**. They only become matchable against a fresh from-scratch
reference export (export to an empty USB, never edited afterward).
Everything NOT listed here is fair game and must match. The task-#7 diff should
filter out (and reference) this list, then drive the remaining bytes to zero.
## Evidence (tracks table, page 2 of the reference)
5 present rows, each with ~377–417 bytes of real content, yet:
| row id | ofs | real content len | next ofs | gap | gap bytes are… |
|--------|-------|------------------|----------|-------|---------------------------|
| 1 | 428 | 377 | 856 | 51 | zero |
| 5 | 856 | 377 | 1324 | 91 | partial stale string |
| 2 | 1324 | 417 | 1792 | 51 | zero |
| 3 | 1792 | 386 | 2656 | 478 | a whole dead track row |
| 4 | 2656 | 404 | 3996* | 936 | two whole dead track rows |
`used_size=3996`, `free_size=38`. The gap after id=3 holds a dead copy of a row
ending `"...Jelly Fish Jam.mp3"`; the gap after id=4 holds dead copies of
`"Myrtle Ave Party Track"` and `"Smooth Move"` rows. These are previous versions
of edited rows, left uncompacted. (Verified by ASCII-dumping the gap bytes.)
## The fields we do NOT match (and why)
1. **File / page count and `next_unused_page`.**
Reference: 49 pages, `next_unused=53`. maple: 41 pages, `next_unused=41`.
The reference is larger purely because dead-row bloat pushed live rows onto
extra pages. A compacted export needs fewer pages.
2. **Overflow / data-page placement (tracks `last_page`).**
Reference tracks table spans pages **1 → 48** (live track id=7 spilled onto
overflow page 48 because dead rows "filled" page 2). maple spans **1 → 2**
(all 6 tracks fit one compacted page). This is the *only* table-directory
entry that differs — the other 19 tables match first/last page exactly. The
divergence is entirely a function of the dead-row bloat above.
3. **File-header `sequence` value.**
Reference: `353`. maple: an incrementing counter (reads the destination
export's sequence + 1, default 1; see `writer._next_sequence`). rekordbox's
value comes from its internal `master.db` transaction counter and is not
reproducible from content. We match the *semantics* (monotonic increment),
not the absolute value.
4. **Per-page `sequence` (page-header offset 16).**
Reference pages carry assorted values (e.g. 26, 45, 320, 342, 347) — each a
snapshot of the global counter at the moment that page was last rewritten.
maple writes a clean per-build value. Same root cause as (3); not reproducible.
5. **`transaction_row_count` / `transaction_row_index` (page-header u2 pair).**
Reference: nonzero per edited page (e.g. `1/5`, `1/8`, `2/0`). maple: `0/0`.
These track the last in-place transaction on the page; meaningless for a
freshly written, never-edited page.
6. **Dead-row offset arrays + `num_row_offsets` > `num_rows`.**
Reference row groups list offsets for dead slots too: e.g. tracks page 2 has
`nro=9, nrows=5` with offsets `[0,428,856,1324,1792,2224,2656,3112,3568]`
(slots 0,5,7,8 dead); artists page 6 has `nro=9, nrows=1`. maple emits exactly
`nro == nrows` with no dead slots. Reproducing dead offsets would mean
reproducing the edit history.
7. **Live row in a non-zero slot.**
Reference artists page 6 keeps its single live row in **slot 8** (slots 0–7
are dead). maple places the single live row in **slot 0**. A from-scratch
export also writes slot 0.
8. **`free_size` / `used_size` totals on data pages.**
Reference `used+free` totals vary (4034, 4050, …) because `used_size` covers
the dead-row region and the strange-block markers differ. maple's pages total
a clean `4020` (= heap capacity for a single 36-byte row group). Direct
consequence of (6) — dead bytes are counted as "used".
9. **Track row opaque id blob — `0x14`/`0x18`/`0x1a` (8 bytes/track).**
One 8-byte LE value `opaque_track_id_lo | (opaque_seed << 32)`, both halves
stored in rekordbox's internal master.db (a per-install `opaque_seed` + a
per-track `opaque_track_id_lo`). Proven non-derivable from track metadata
across every real export + an exhaustive negative hash search
(FORMAT_SPEC.md s2). **Every real rekordbox export has BOTH halves non-zero**
(this install's seed = `0x21b4a7ab`; `data/MAPLE` = `0xd6d3a567`); the
"unanalyzed default" lo=0/seed=0x78f74a68 was a false lead — it came from
maple's own earlier output (`data/usb`), not a real export. maple emits a
plausible non-zero stand-in of the right shape: `opaque_seed = 0x21b4a7ab`
(module const `TRACK_OPAQUE_SEED`, overridable per install) and a stable
per-track `opaque_track_id_lo` mapped into the real Content-ID band
(`OPAQUE_LO_MIN..MAX` = 0x08000000..0x0F900000, where every observed AceMo lo
lands) via `crc32(id|file_path)`. This will NOT match rekordbox's master.db
id byte-for-byte — unreproducible without its DB — but it is non-zero,
in-range and deterministic, the safest shape for deck acceptance. Players
treat the blob as opaque.
10. **Strange-page free-map extension + per-page seq on tracks/history.**
On the tracks (type 0) and history (type 19) strange pages only, the
free-space map carries an extra accounting word (body offset 16: `01 00`,
offset 20: a u4 = the data page's used_size for history=320; tracks differs
because of its dead-row/overflow state). maple writes the plain free-map.
Tied to the same content/overflow state as items (1)/(2); not reproducible
for a compacted writer. (The rest of every strange page — header, free-map
head, 1004× `f8 ff ff 1f`, the data-page pointer word, and unknown7 — now
matches the fresh reference byte-for-byte.)
11. **Table-directory `empty_candidate` (u32, table_dir entry +4) + header
`next_unused_page`.** Reference: a nonzero per-table `empty_candidate`
(e.g. 0x33, 0x04, 0x2e…); maple: 0. rekordcrate documents this field as
"maybe links to a chain of empty pages if the database is ever garbage
collected", and its fixtures show non-sequential free-pool page indices
(47, 4, 49, 8, 50, 46, 42, 16…). It is free-list/GC allocator state, not
derivable from content. `next_unused_page` (rekordcrate: "points past end of
file", unused) is the same class — see also item (1).
> Canonical reference note: the diff target is now the FRESH export
> `data/acemo_fresh/PIONEER/rekordbox/export.pdb` (7 tracks). It is cleaner than
> the edited `data/acemo` (6 tracks) but still incrementally built per-file, so
> the divergences above still apply — just smaller (e.g. track 7's dead-row span
> is 464B not 3568B, but it still overflows to page 48).
## What IS reproducible (NOW matched against the fresh reference)
- The 20-table directory layout and page placement: an empty table is
strange-page-only; a table gets a data page IFF it has rows (`CORE_TABLES` is
now empty — the old genres data page was an edit-history artifact of the
edited ref).
- `page_flags`: data pages are `0x34` for **tracks and history only**, `0x24`
for every other table (the wider `{0,2,3,13,17,19}` was edited-ref noise);
empty data pages `0x44`; strange pages `0x64`.
- Strange-page body: the full DeviceSQL free-space map — `u4(page_index)`,
`u4(first_data_page or 0x03ffffff)`, the 12-byte const tail, 1004×
`f8 ff ff 1f`, 20 zero bytes — plus header `free=used=0`, `txc=txi=0x1fff`,
`next_page = page_index+1`, and `unknown7 = 1` for tracks/history else 0.
- Track row `index_shift` (`slot_index<<5`) and every other live-row content
field except the opaque blob in divergence item (9).
- Three header fields `re` decoded (FORMAT_SPEC §4/§5/§6) as edit-history state
whose FRESH-export value maple already writes — so they're matched on a fresh
export and only diverge against edited refs:
- file-header offset 16 (`_unnamed4`): fresh=`0` (maple writes 0); edited DBs
accumulate a small nonzero with no structural meaning.
- strange/data-page `unknown7` (0x26): fresh=`0` everywhere (maple writes 0);
nonzero only on edited DBs' strange pages.
- row-group trailing u2: it is the "rows-touched-in-last-transaction" bitmask.
On a fresh export it equals the row-present mask, so maple writes
`presence` (matches 12/14 groups in `data/acemo_fresh`; the 2 misses are
edited pages — divergence). NOTE: `re`'s "keep constant 16" advice came from
reading `data/usb`, which is maple's OWN output, not a real export — a real
fresh export uses the presence value, not 16.
See `re/FORMAT_SPEC.md` for the value-construction rules and `re/README.md` for
the open RE questions.