commit 0d9116019a8baae2aa813146a9f04314df379641
parent 5bd1d69241df58fa9a80e1a8089c70e16b910c5a
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date: Fri, 2 Oct 2026 01:09:32 -0400
common, editor: the re-point names migrate-tier for a legacy channel; the reconcile spec's changed file differs in length
A legacy channel on a location is refused by the re-point preflight with the
migrate-tier sentence (it has no media link to rewrite). The reconcile case's
changed live chat now differs in size too: rsync's quick check compares size
and a one-second mtime.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Diffstat:
3 files changed, 38 insertions(+), 1 deletion(-)
diff --git a/common/controller/storageLocations.test.ts b/common/controller/storageLocations.test.ts
@@ -187,6 +187,30 @@ test("channelsOnLocation buckets ok / unreachable / moving and ignores channels
});
});
+test("re-point refuses a legacy channel on the location, naming migrate-tier", async () => {
+ await withTmp(async (h) => {
+ const oldTarget = path.join(h.rootA, "old", "data");
+ await mkdir(oldTarget, { recursive: true });
+ await mkdir(path.join(h.rootB, "old", "data"), { recursive: true });
+ const oldDir = path.join(h.paths.channelsDir, "old");
+ await mkdir(oldDir, { recursive: true });
+ await writeFile(
+ path.join(oldDir, "config.json"),
+ JSON.stringify({ handling: "transcribe", url: "https://x/o", dataDir: oldTarget }) + "\n",
+ );
+ await symlink(oldTarget, path.join(oldDir, "data"));
+ await setLocations(h, [loc("a", h.rootA)]);
+ const pre = await preflightRepoint({
+ paths: h.paths,
+ locationId: "a",
+ newRoot: h.rootB,
+ io: h.io,
+ });
+ assert.equal(pre.ok, false);
+ assert.match(pre.problems.join("\n"), /old: .*archilyzer storage migrate-tier old/);
+ });
+});
+
// THE RETIRED LAYOUT (release 17): a channel whose whole `data/` was moved
// before the media tier is still ON its location (by its retired `dataDir`),
// counted unreachable — its text and media are held until migrate-tier — and
diff --git a/common/controller/storageLocations.ts b/common/controller/storageLocations.ts
@@ -613,6 +613,16 @@ export async function preflightRepoint(opts: {
slug,
relocatedMediaDir(newRoot, slug),
);
+ // THE RETIRED LAYOUT (release 17) is migrated, never re-pointed: its
+ // `data` link is not the media link a re-point rewrites.
+ if (media.status === "legacy") {
+ base.problems.push(
+ `${slug}: ${media.detail ?? "its media layout is the retired whole-directory one"}. ` +
+ `A re-point rewrites the media link, which this channel does not ` +
+ `have until it is migrated.`,
+ );
+ continue;
+ }
if (!resumable && media.status !== "ok" && media.status !== "unreachable") {
base.problems.push(
`${slug}: its media reads as ${media.status} — ` +
diff --git a/editor/e2e/channel-storage.spec.ts b/editor/e2e/channel-storage.spec.ts
@@ -1010,9 +1010,12 @@ test("Reconcile and resume settles an extra and a changed file on the destinatio
const scratch = join(target, VIDEO, ".audio.mp3.parakeet");
await mkdir(scratch, { recursive: true });
await writeFile(join(scratch, "meta.json"), "{}");
+ // A different LENGTH as well as different words: rsync's quick check
+ // compares size and a one-second mtime, and both files were written within
+ // the same second.
await writeFile(
join(target, VIDEO, "transcript.live_chat.json"),
- '[{"stale":true}]',
+ '[{"stale":true,"from":"an older copy"}]',
);
await writeFile(
resolvePath(`test-transcripts/channels/${SLUG}/.relocating.json`),