feat(media): the relayout executor names the reap its moves leave behind

A relayout renames on the raw array; the sidecars the media servers wrote live in
the NVMe upper layer of the view and stay at the old coordinates, which is how a
ghost folder (artwork and an .nfo, no video) is born. apply and rollback now
print the follow-up — scripts/media-view.sh reap — at the moment the operator
needs it, and the existing apply seam asserts the hint is in the output.
This commit is contained in:
Frank committed 2026-10-30 21:41:56 -07:00
1 parent 3e4b4f24f7
commit f5a3badb56
2 files changed
+12

No files matched your search

+9
View File
@@ -114,6 +114,13 @@ def read_plan(path, root, force):
return mkdirs, keeps, moves return mkdirs, keeps, moves
# A relayout moves bytes on the raw array; the sidecars the media servers wrote
# live in the SSD overlay and stay at the old coordinates. Naming the follow-up
# here is the point of use for that fact — see the Media Metadata View page.
METADATA_HINT = ("note: sidecars written through the metadata view did not follow"
" these moves — next: scripts/media-view.sh reap")
def do_apply(args, root, journal, mkdirs, keeps, moves): def do_apply(args, root, journal, mkdirs, keeps, moves):
"""Preflight everything, then folders, then renames. Never a partial start.""" """Preflight everything, then folders, then renames. Never a partial start."""
problems = [] problems = []
@@ -195,6 +202,7 @@ def do_apply(args, root, journal, mkdirs, keeps, moves):
f" {dirs_new} folders created, {len(keeps)} files stayed put") f" {dirs_new} folders created, {len(keeps)} files stayed put")
print(f"journal: {journal.path} — undo with: media-apply.py rollback" print(f"journal: {journal.path} — undo with: media-apply.py rollback"
f" --journal {journal.path} --root {root} --apply") f" --journal {journal.path} --root {root} --apply")
print(METADATA_HINT)
return 0 return 0
@@ -378,6 +386,7 @@ def do_rollback(args, root, journal):
t=datetime.datetime.now(datetime.timezone.utc).isoformat()) t=datetime.datetime.now(datetime.timezone.utc).isoformat())
print(f"rolled back: {undone} files back where the census found them," print(f"rolled back: {undone} files back where the census found them,"
f" {dirs_gone} empty folders removed, {recreated} swept folders recreated") f" {dirs_gone} empty folders removed, {recreated} swept folders recreated")
print(METADATA_HINT)
return 0 return 0
+3
View File
@@ -402,6 +402,9 @@ apply_plan() {
moved=$(python3 -c 'import json,sys moved=$(python3 -c 'import json,sys
print(sum(1 for l in open(sys.argv[1]) if json.loads(l).get("op") == "move"))' "$JOURNAL") print(sum(1 for l in open(sys.argv[1]) if json.loads(l).get("op") == "move"))' "$JOURNAL")
[ "$moved" -eq "$planned" ] [ "$moved" -eq "$planned" ]
# The media servers' sidecars live in the metadata overlay and did not follow
# these moves, so the run names that cleanup at the moment it is needed.
[[ "$output" == *"media-view.sh reap"* ]]
run python3 "$APPLY" verify --plan "$OUT" --root "$LIB" --journal "$JOURNAL" run python3 "$APPLY" verify --plan "$OUT" --root "$LIB" --journal "$JOURNAL"
[ "$status" -eq 0 ] [ "$status" -eq 0 ]
} }