14 SEPTEMBER 2026 · read from the working tree
Findings
Six things worth knowing before the cron is run, from reading the seeder, the copier and the descriptor list as they stand today. Two are gaps; the rest are either already handled or now closed.
- Already handled
- 2findings 1 and 5
- Gaps
- 2findings 2 and 3
- Changed today
- 2findings 4 and 6
- Blocking the run
- 0none of them
The two gaps are both about narrowing a seed — running one descriptor at a time, or only a chosen few. A full seed in wave order is available now and produces the ordering you asked for.
The six2 gaps
1. The order you asked for already holdsno change needed
seedAll() runs seedWave(OWN_DESTINATION_DESCRIPTORS) to completion, then
seedWave(BORROWED_KEY_DESCRIPTORS). All nine keys you listed are in the first wave; all six
camp_inventory_items.additional_details mirrors are in the second. The sequence you described
— own the file first, then let the mirror point at that destination — is what the code already does.
2. Within a wave there is no sequencegap, if you need a strict one
seedWave groups descriptors by physical column and runs the groups concurrently, up to
pool − 1. So “first equipment categories, then equipment models, then the copilot
columns” is not what happens in that literal order — the eight columns start together.
For these nine it does not matter: they are eight different columns and no two of them can resolve the same destination for the same account, so nothing races. But if a run ever needs a genuine one-at-a-time order, that does not exist today.
3. The seed job takes no descriptor selectiongap
FileMigrationSeedJob extends BaseJob<Record<string, never>> and seedAll()
takes no arguments. Seeding only the nine keys is therefore not possible without a change.
The other two phases can already be narrowed: FileMigrationRunPayload.descriptorKeys restricts which
descriptors a batch is cut from, and the write-back groups its statements by descriptor key. It is the seed alone
that is all-or-nothing.
4. The shape-based two-phase split is gonesuperseded
The earlier PLAIN_SHAPES / seedPhases split — plain columns first, document
columns second — was replaced upstream by the own/borrow waves. The new rule is strictly stronger: shape was a
proxy for ownership and got it wrong in both directions, whereas BORROWED_KEY_DESCRIPTORS names the
dependency outright.
5. Duplicate descriptor keys: now zeroclosed
capture_billings.invoice_path and ezestimator_requests.file_path each appeared twice in
earlier revisions. Neither does now — every one of the 122 keys is unique.
6. QR codes removed from the migrationdone today
qr_codes.image is out, at your request — 123 descriptors down to 122. It was the only
descriptor whose value came from no column at all: nothing stores a QR code’s path, every reader derives it
from the id through qrObjectName, and the seeder derived it the same way.
Left alone deliberately: the [BucketFolder.QR, UploadModule.QrCode] pair in FOLDER_MODULES,
and everything in upload-targets.ts. Removing the folder pair would put qr on the unmapped
list and change how a folder-derived descriptor treats a qr/ path it happens to meet.