Archilyzer · Source

archilyzer

Archilyzer
git clone https://archilyzer.pages.dev/source/archilyzer.git
Log | Files | Refs | README | LICENSE

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:
Mcommon/lib/homepageSummary.test.ts | 40++++++++++++++++++++++++++++------------
Mcommon/lib/homepageSummary.ts | 27+++++++++++++++++++--------
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])), }))