From f5a3badb56f749d9efc6018cd205a5f94fdcb112 Mon Sep 17 00:00:00 2001 From: Frank Date: Fri, 30 Oct 2026 21:41:56 -0700 Subject: [PATCH] feat(media): the relayout executor names the reap its moves leave behind MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- scripts/media-apply.py | 9 +++++++++ tests/media_relayout.bats | 3 +++ 2 files changed, 12 insertions(+) diff --git a/scripts/media-apply.py b/scripts/media-apply.py index 8b66f7b..cf7fe65 100755 --- a/scripts/media-apply.py +++ b/scripts/media-apply.py @@ -114,6 +114,13 @@ def read_plan(path, root, force): 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): """Preflight everything, then folders, then renames. Never a partial start.""" problems = [] @@ -195,6 +202,7 @@ def do_apply(args, root, journal, mkdirs, keeps, moves): f" {dirs_new} folders created, {len(keeps)} files stayed put") print(f"journal: {journal.path} — undo with: media-apply.py rollback" f" --journal {journal.path} --root {root} --apply") + print(METADATA_HINT) return 0 @@ -378,6 +386,7 @@ def do_rollback(args, root, journal): t=datetime.datetime.now(datetime.timezone.utc).isoformat()) print(f"rolled back: {undone} files back where the census found them," f" {dirs_gone} empty folders removed, {recreated} swept folders recreated") + print(METADATA_HINT) return 0 diff --git a/tests/media_relayout.bats b/tests/media_relayout.bats index 20a1a1b..b6afef0 100755 --- a/tests/media_relayout.bats +++ b/tests/media_relayout.bats @@ -402,6 +402,9 @@ apply_plan() { moved=$(python3 -c 'import json,sys print(sum(1 for l in open(sys.argv[1]) if json.loads(l).get("op") == "move"))' "$JOURNAL") [ "$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" [ "$status" -eq 0 ] }