commit 8f6c4b81a6dba250e27493cab11171bef65a89e5
parent 842ccbf311c749296cfe01e2010e54cf3dfe76fa
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date: Fri, 25 Sep 2026 11:34:13 -0400
common: (review fix) the deferred list is tested, and ties sort by code point
autoQueueStatus.test +1: lapsed and boundary (until === now) entries drop,
out-of-order input comes out soonest first with tied untils by videoId,
the shape is {videoId, channelSlug, untilMs}, transcription is [], and a
later injected clock drops what has lapsed. The tie-break is code-point
order rather than localeCompare, so the order does not depend on the locale.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Diffstat:
2 files changed, 33 insertions(+), 1 deletion(-)
diff --git a/common/views/autoQueueStatus.test.ts b/common/views/autoQueueStatus.test.ts
@@ -98,6 +98,32 @@ test("a cooldown is filtered by the injected clock, newest first", () => {
);
});
+test("deferred videos: live only, soonest first, ties by id, clock-driven", () => {
+ const state = emptyAutoQueueState();
+ // Inserted out of order on purpose; the strip must not depend on key order.
+ state.download.videoDeferrals = {
+ late: { until: NOW + 6 * 3_600_000, channelSlug: "beta" },
+ tieB: { until: NOW + 60_000, channelSlug: "alpha" },
+ lapsed: { until: NOW - 1_000, channelSlug: "alpha" },
+ // Strictly greater-than, like the cooldowns: lapsing exactly now has lapsed.
+ boundary: { until: NOW, channelSlug: "alpha" },
+ tieA: { until: NOW + 60_000, channelSlug: "gamma" },
+ };
+ const payload = buildAutoQueueStatusPayload(inputs({ state }));
+ assert.deepEqual(payload.download.deferred, [
+ { videoId: "tieA", channelSlug: "gamma", untilMs: NOW + 60_000 },
+ { videoId: "tieB", channelSlug: "alpha", untilMs: NOW + 60_000 },
+ { videoId: "late", channelSlug: "beta", untilMs: NOW + 6 * 3_600_000 },
+ ]);
+ assert.deepEqual(payload.transcription.deferred, []);
+ // Past the tied pair, only the 6 h one is left.
+ assert.deepEqual(
+ buildAutoQueueStatusPayload(inputs({ state, now: () => NOW + 60_000 }))
+ .download.deferred,
+ [{ videoId: "late", channelSlug: "beta", untilMs: NOW + 6 * 3_600_000 }],
+ );
+});
+
test("transcription's hold is the pool's, every other lane's is the gate", () => {
// The asymmetry is deliberate and is the reason `pool` is on these inputs at
// all: transcription's hold is LIVE on the worker pool, while every other
diff --git a/common/views/autoQueueStatus.ts b/common/views/autoQueueStatus.ts
@@ -163,7 +163,13 @@ function buildKind(
channelSlug: d.channelSlug,
untilMs: d.until,
}))
- .sort((a, b) => a.untilMs - b.untilMs || a.videoId.localeCompare(b.videoId));
+ // Ties by id in CODE-POINT order, not localeCompare: YouTube ids are
+ // mixed-case and the strip's order must not depend on the server's locale.
+ .sort(
+ (a, b) =>
+ a.untilMs - b.untilMs ||
+ (a.videoId < b.videoId ? -1 : a.videoId > b.videoId ? 1 : 0),
+ );
return {
kind,
policy,