The thing that clicked today: equal byte totals do not prove a correct copy, a delete that frees nothing has not deleted anything, and a migration's real blast radius is in the data files, not the code.
It started with a screenshot of a photo-server app on my phone showing a version-check error. Fixing that led into the storage layout under it, and the layout led into everything below.
Built / shipped
The audit. Loupe had pulled 4,921 "edited" renders from the cloud photo library over the previous weeks, on the basis of the library's own has-adjustments flag. Each render was checked against the precomputed content hash already in the metadata database, reading only the renders and never re-reading the originals: 3,777 were byte-identical to their originals. 77%. 2,817 images and 960 videos, the video pass alone 110.6 GB in about nineteen minutes at 95 MB/s. The cause: the export tool trusts the library's "has adjustments" flag, and a round trip through a second photo service had set that flag on thousands of items without changing a pixel. Purged; the render catalog went from 4,921 to 1,134 rows with ten pre-existing stale rows cleared; about 108 GB reclaimed.
A 3.4 TB move in zero bytes. The library moved from a nested path to a top-level one on the storage box, over a shell session on the box itself: 21 top-level items, instant rename, nothing transferred, because source and destination were on the same volume. The same trick as the 462 GB move in June, with the same proof.
Capture dates repaired per file. A set of filename-dated assets had wrong capture times. The correction derived the UTC offset per file from the file's modification time, because the library spans two time zones five months apart; a single hardcoded zone would have shifted 291 files by two hours. The derived distribution came out to the three offsets the library actually spans.
Problems & fixes
The delete that freed nothing. Removing 110 GB over the network share did not move the free-space number at all. The storage box's recycle bin silently kept everything. Caught by disbelieving a 110 GB delete that changed nothing; emptied explicitly by name over a shell session on the box. Check free space on the actual mount point, not its parent.
Equal byte totals, wrong copy. Four items with colons or leading spaces in their names came across the network share mangled into short eight-dot-three names, because the protocol cannot represent those characters. The byte totals still matched. Only a hash spot-check exposed it. Pushed back over a secure-shell copy, never the share.
41,925 stale absolute paths, in data, not code. The first sweep for the old path grepped only source and service files. The real blast radius was in work lists and JSON manifests: one video list alone held 40,641 of the old paths, and a re-run of the full pipeline would have failed on every video. Grep everything.
A loop that rescued one file out of seven. A remote-shell command inside a read-loop swallowed the loop's input, so the loop ran once and exited cleanly. The fix is a flag that tells the remote shell not to read standard input. Silent, and caught only by counting.
A vendoring invariant broken and restored. A docstring edit forked one copy of a script from the original it is supposed to match byte for byte. Fixed by applying the change to both, then made structural with a test that fails if they ever differ again.
The photo server trashed a present, intact original during a scan. Restored from its trash; cause unexplained. Caught only by comparing asset counts before and after the scan. Recorded as unexplained rather than explained away.
A filename search pattern that matched everything, because the character I was searching for is itself a wildcard in that tool. Character class instead.
Decisions
Audit renders against existing hashes, never re-read originals.
Same-volume move, proven instant, over a shell on the box.
Derive time offsets per file from evidence, never from an assumed zone.
Verify copies by hash spot-check, not byte totals; verify deletes by free space on the mount itself.
Grep data files, not just code, for a path migration.
Learned
A flag that says "edited" is a claim. 77% of the renders it produced were no-ops.
Five independent ways a storage operation lies: a recycle bin behind a delete, name mangling behind equal totals, stale paths in data, a loop starved of input, a scan that trashed a file. Every one was caught by checking a count or a hash rather than trusting the command's exit.
A library that spans time zones needs per-file offsets. One zone is wrong for part of it by construction.
Still open / next
The photo server's trashing of a present original is unexplained and deserves a reproduction attempt with counts diffed around a scan. And the vendoring test now exists, which is the structural version of a rule I broke by hand.