commit df2f2ff142110700ff9844188fa0cb7505769ade
parent dcea35544c8e28c14faf675a3240be8a624060d0
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date: Fri, 25 Sep 2026 16:27:24 -0400
common: homepage summary monthly ends at the last complete month — the build month is partial and charted as a collapse
Transcripts uploaded in the build month join monthlyUnplaced, so placed +
unplaced still equals the official transcripts. homepageSummary.test.ts: the
fixture gains a build-month upload (not emitted, counted unplaced) and a
January case where the last complete month is the previous December.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Diffstat:
2 files changed, 47 insertions(+), 20 deletions(-)
diff --git a/common/lib/homepageSummary.test.ts b/common/lib/homepageSummary.test.ts
@@ -9,9 +9,10 @@ import type { Site } from "./site";
// (the sum over the public sites, not the instance-wide totals).
//
// Limits, pinned here rather than discovered: `monthly` is NOT capped — it runs
-// from the earliest upload month to the build month, however old. A transcript
-// whose upload date is missing, malformed or after the build month is not
-// placed in any month; `monthlyUnplaced` counts it. Channels exposed by no
+// from the earliest upload month to the last COMPLETE month, however old. The
+// build month is never emitted (it is partial). A transcript whose upload date
+// is missing, malformed, in the build month or later is not placed in any
+// month; `monthlyUnplaced` counts it. Channels exposed by no
// public site (pool-only, or a site without a siteUrl) are outside `monthly`,
// the site numbers and `official`, but still inside `totals`.
@@ -73,6 +74,8 @@ const STATS: VideoStat[] = [
stat({ channelSlug: "b1", id: "y2", uploadDate: "" }),
stat({ channelSlug: "b1", id: "y3", uploadDate: "2026-01" }),
stat({ channelSlug: "b1", id: "y4", uploadDate: "20260501" }),
+ // uploaded in the build month (2026-03): partial, so not placed
+ stat({ channelSlug: "b1", id: "y5", uploadDate: "20260310" }),
// pool-only (no public site): counted in totals, nowhere else
stat({ channelSlug: "p1", id: "z1", uploadDate: "20200101", status: "deleted" }),
];
@@ -82,16 +85,17 @@ test("monthly: upload months, zero-filled from first upload to the build month,
assert.equal(s.version, HOMEPAGE_SUMMARY_VERSION);
assert.deepEqual(
s.monthly!.map((m) => m.month),
- ["2025-11", "2025-12", "2026-01", "2026-02", "2026-03"],
+ ["2025-11", "2025-12", "2026-01", "2026-02"],
);
assert.deepEqual(s.monthly![0].bySite, { alpha: 2, beta: 0 });
assert.deepEqual(s.monthly![1].bySite, { alpha: 0, beta: 0 });
assert.deepEqual(s.monthly![2].bySite, { alpha: 0, beta: 1 });
assert.deepEqual(s.monthly![3].bySite, { alpha: 1, beta: 0 });
- assert.deepEqual(s.monthly![4].bySite, { alpha: 0, beta: 0 });
+ // A month equal to the generation month is not emitted.
+ assert.ok(!s.monthly!.some((m) => m.month === "2026-03"));
// Placed + unplaced = every transcribed public-universe record.
const placed = s.monthly!.reduce((a, m) => a + m.bySite.alpha + m.bySite.beta, 0);
- assert.equal(s.monthlyUnplaced, 3);
+ assert.equal(s.monthlyUnplaced, 4);
assert.equal(placed + s.monthlyUnplaced!, s.official!.transcripts);
});
@@ -106,25 +110,37 @@ test("per-site numbers and official totals sum over the public sites only", () =
);
assert.deepEqual(
[beta.channels, beta.recordings, beta.transcribed.total, beta.hoursArchived, beta.gone],
- [1, 4, 4, 4, 0], // 7200 + 3 x 1800 s = 3.5 h -> 4
+ [1, 5, 5, 4, 0], // 7200 + 4 x 1800 s = 4 h
);
// Hours are rounded once over the summed seconds, not per site.
assert.deepEqual(s.official, {
sites: 2,
channels: 3,
- recordings: 8,
- transcripts: 7,
- hoursArchived: 6, // 21600 s
+ recordings: 9,
+ transcripts: 8,
+ hoursArchived: 7, // 23400 s = 6.5 h -> 7
gone: 1,
});
// The instance-wide totals still count the pool-only channel.
- assert.equal(s.totals.transcripts, 8);
+ assert.equal(s.totals.transcripts, 9);
assert.equal(s.availability!.byState.deleted, 2);
});
test("no transcribed public content: monthly is empty, not a run of zeroes", () => {
- const s = buildHomepageSummary([STATS[8]], CHANNEL_SITES, SITES, NOW);
+ const s = buildHomepageSummary(STATS.filter((x) => x.id === "z1"), CHANNEL_SITES, SITES, NOW);
assert.deepEqual(s.monthly, []);
assert.equal(s.monthlyUnplaced, 0);
assert.equal(s.official!.sites, 0);
});
+
+test("the build month is never emitted, even in January (the year rolls back)", () => {
+ const s = buildHomepageSummary(
+ [stat({ channelSlug: "a1", id: "j1", uploadDate: "20251215" }),
+ stat({ channelSlug: "a1", id: "j2", uploadDate: "20260105" })],
+ CHANNEL_SITES,
+ SITES,
+ new Date("2026-01-20T00:00:00Z"),
+ );
+ assert.deepEqual(s.monthly!.map((m) => m.month), ["2025-12"]);
+ assert.equal(s.monthlyUnplaced, 1);
+});
diff --git a/common/lib/homepageSummary.ts b/common/lib/homepageSummary.ts
@@ -163,12 +163,14 @@ export type HomepageSummary = {
recent: HomepageRecentItem[];
// Instance-wide state census. Optional — absent from pre-v4 summaries.
availability?: HomepageAvailability;
- // v5. Full history, one entry per month from the earliest upload month in the
- // public universe to the build month, zero-filled between. Every site in
- // `sites` has a key in every entry (zero included). Empty when there is no
- // transcribed public content. Transcripts whose upload date is missing,
- // malformed or after the build month are not placed; `monthlyUnplaced`
- // counts them so nothing is dropped silently.
+ // v5. Full history of COMPLETE months: one entry per month from the earliest
+ // upload month in the public universe to the month BEFORE the build month,
+ // zero-filled between. The build month itself is never emitted — it is
+ // partial, and charted it reads as a collapse. Every site in `sites` has a
+ // key in every entry (zero included). Empty when there is nothing to place.
+ // Transcripts whose upload date is missing, malformed, in the build month or
+ // later are not placed; `monthlyUnplaced` counts them so nothing is dropped
+ // silently.
monthly?: HomepageMonth[];
monthlyUnplaced?: number;
official?: HomepageOfficialTotals;
@@ -192,6 +194,14 @@ function uploadMonthOf(date: string | null | undefined): string | null {
return `${date.slice(0, 4)}-${date.slice(4, 6)}`;
}
+// "YYYY-MM" -> the calendar month before it.
+function previousMonth(ym: string): string {
+ const [y, m] = ym.split("-").map(Number);
+ return m === 1
+ ? `${String(y - 1).padStart(4, "0")}-12`
+ : `${String(y).padStart(4, "0")}-${String(m - 1).padStart(2, "0")}`;
+}
+
function monthRange(start: string, end: string): string[] {
const out: string[] = [];
let [y, m] = start.split("-").map(Number);
@@ -371,7 +381,7 @@ export function buildHomepageSummary(
acc.channels.add(s.channelSlug);
acc.seconds += s.duration > 0 ? s.duration : 0;
const um = uploadMonthOf(s.uploadDate);
- if (um && um <= nowMonth) uploadItems.push({ month: um, siteId });
+ if (um && um < nowMonth) uploadItems.push({ month: um, siteId });
else monthlyUnplaced += 1;
transcribedItems.push({ date: s.transcribedDate as string, channelSlug: s.channelSlug, siteId });
}
@@ -462,8 +472,9 @@ export function buildHomepageSummary(
for (const it of uploadItems) {
if (firstMonth === null || it.month < firstMonth) firstMonth = it.month;
}
+ const lastComplete = previousMonth(nowMonth);
const monthly: HomepageMonth[] = firstMonth
- ? monthRange(firstMonth, nowMonth).map((month) => ({
+ ? monthRange(firstMonth, lastComplete).map((month) => ({
month,
bySite: Object.fromEntries(keptIds.map((id) => [id, 0])),
}))