Archilyzer · Source

archilyzer

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

commit cb8a042d27f4d43546208bd061c78bc3a3bf6c95
parent bddc4e4110303b2b9af6503c4b34919bb1582651
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Tue, 29 Sep 2026 21:37:14 -0400

homepage: the fixture's second list unlists every site in it (buildFixtureInputs sets `listed: false`); the unlisted-site spec also proves the site is in the builder's input and that, listed, it would change the summary (review L1, L2)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

Diffstat:
Mhomepage/e2e/fixture-summary.ts | 41++++++++++++++++++++++++++++++-----------
Mhomepage/e2e/unlisted-site.spec.ts | 17++++++++++++++++-
2 files changed, 46 insertions(+), 12 deletions(-)

diff --git a/homepage/e2e/fixture-summary.ts b/homepage/e2e/fixture-summary.ts @@ -32,7 +32,8 @@ import type { VideoStat } from "../../common/lib/stats"; // also exposes the first site's first channel. The summary names it nowhere // and counts its own channels in no total, so `buildFixtureSummary()` is // exactly `buildFixtureSummary(FIXTURE_SITES, [])` — every number the specs -// read is the six listed sites'. +// read is the six listed sites'. Every site in the second list is unlisted: +// `buildFixtureInputs` sets `listed: false` on it, whatever it carries. export const FIXTURE_SUMMARY_NAME = ".e2e-summary.json"; @@ -48,8 +49,8 @@ export const FIXTURE_PALE_HEX = "#f4c2d7"; // site.json one (a named accent's site, the custom hex's and a site with no // accent have one — the last ends MID-WORD, "Fix" + "ture Three", as // "Jer" + "alyzer" does; the rest show their title plain); `daily` how many -// recordings each channel transcribes a day; `listed` the site.json key -// (absent = listed). +// recordings each channel transcribes a day. Whether a site is listed is the +// list it is passed in (buildFixtureInputs), not a field. export type FixtureSite = { siteId: string; siteTitle: string; @@ -57,7 +58,6 @@ export type FixtureSite = { wordmarkLead?: string; channels: number; daily: number; - listed?: boolean; }; export const FIXTURE_SITES: readonly FixtureSite[] = [ @@ -70,13 +70,13 @@ export const FIXTURE_SITES: readonly FixtureSite[] = [ ]; // The unlisted site (an invented id, as every fixture's). Not in FIXTURE_SITES, -// which is the six the pages show. +// which is the six the pages show; buildFixtureInputs' second list, which +// unlists it. export const FIXTURE_UNLISTED_SITE: FixtureSite = { siteId: "fixture-unlisted", siteTitle: "Fixture Unlisted", channels: 2, daily: 6, - listed: false, }; const DAY = 86_400_000; @@ -94,10 +94,13 @@ function uploadDate(n: number): string { return ymd(d.getTime()); } -export function buildFixtureSummary( +// The builder's inputs: the recordings, the channel → sites map and the sites. +// `fixtureSites` are listed; every site in `unlistedSites` is written with +// `listed: false`, and each also exposes the first listed site's first channel. +export function buildFixtureInputs( fixtureSites: readonly FixtureSite[] = FIXTURE_SITES, unlistedSites: readonly FixtureSite[] = [FIXTURE_UNLISTED_SITE], -) { +): { stats: VideoStat[]; channelSites: Record<string, string[]>; sites: Site[] } { const stats: VideoStat[] = []; const channelSites: Record<string, string[]> = {}; const sites: Site[] = []; @@ -135,7 +138,11 @@ export function buildFixtureSummary( const today = Date.UTC(2026, 8, 15); // A site's own channels, `<siteId>-ch<N>`, each transcribing every day of the // last HISTORY_DAYS; `shared` are other sites' channels it also exposes. - const addSite = (s: FixtureSite, i: number, shared: string[] = []) => { + const addSite = ( + s: FixtureSite, + i: number, + { listed = true, shared = [] }: { listed?: boolean; shared?: string[] } = {}, + ) => { const slugs = Array.from({ length: s.channels }, (_, c) => `${s.siteId}-ch${c + 1}`); for (const slug of [...slugs, ...shared]) (channelSites[slug] ??= []).push(s.siteId); sites.push({ @@ -146,7 +153,7 @@ export function buildFixtureSummary( channels: [...slugs, ...shared].map((slug) => ({ slug })), ...(s.accent ? { accent: s.accent } : {}), ...(s.wordmarkLead ? { wordmarkLead: s.wordmarkLead } : {}), - ...(s.listed === false ? { listed: false } : {}), + ...(listed ? {} : { listed: false }), } as unknown as Site); slugs.forEach((slug, c) => { const name = `${s.siteTitle} Channel ${c + 1}`; @@ -168,8 +175,20 @@ export function buildFixtureSummary( // The unlisted sites LAST, so every listed site's recordings (their numbers, // dates and states) are the same with them or without. unlistedSites.forEach((s, j) => - addSite(s, fixtureSites.length + j, [`${spikeSite.siteId}-ch1`]), + addSite(s, fixtureSites.length + j, { + listed: false, + shared: [`${spikeSite.siteId}-ch1`], + }), ); + return { stats, channelSites, sites }; +} + +// The summary the e2e dev server reads: the real builder over those inputs. +export function buildFixtureSummary( + fixtureSites: readonly FixtureSite[] = FIXTURE_SITES, + unlistedSites: readonly FixtureSite[] = [FIXTURE_UNLISTED_SITE], +) { + const { stats, channelSites, sites } = buildFixtureInputs(fixtureSites, unlistedSites); return buildHomepageSummary(stats, channelSites, sites, FIXTURE_NOW); } diff --git a/homepage/e2e/unlisted-site.spec.ts b/homepage/e2e/unlisted-site.spec.ts @@ -5,6 +5,7 @@ import { FIXTURE_SITES, FIXTURE_SUMMARY_NAME, FIXTURE_UNLISTED_SITE, + buildFixtureInputs, buildFixtureSummary, } from "./fixture-summary"; @@ -19,11 +20,25 @@ import { const NEEDLES = [FIXTURE_UNLISTED_SITE.siteId, FIXTURE_UNLISTED_SITE.siteTitle]; test("the summary the server reads is the one built without the unlisted site", () => { + // The site is in the builder's input: unlisted, with recordings of its own + // and a channel shared with the first listed site. + const { stats, channelSites, sites } = buildFixtureInputs(); + const unlisted = sites.find((s) => s.siteId === FIXTURE_UNLISTED_SITE.siteId); + expect(unlisted?.listed).toBe(false); + const own = stats.filter((s) => s.channelSlug.startsWith(`${FIXTURE_UNLISTED_SITE.siteId}-ch`)); + expect(own.length).toBeGreaterThan(0); + expect(channelSites[`${FIXTURE_SITES[0].siteId}-ch1`]).toContain(FIXTURE_UNLISTED_SITE.siteId); + // Listed, the same site would change the summary: a card, and its recordings. + const withoutIt = buildFixtureSummary(FIXTURE_SITES, []); + const asListed = buildFixtureSummary([...FIXTURE_SITES, FIXTURE_UNLISTED_SITE], []); + expect(asListed.sites.map((s) => s.siteId)).toContain(FIXTURE_UNLISTED_SITE.siteId); + expect(asListed.totals.transcripts).toBe(withoutIt.totals.transcripts + own.length); + const onDisk = JSON.parse( fs.readFileSync(path.resolve(process.cwd(), "e2e", FIXTURE_SUMMARY_NAME), "utf8"), ); // Every array and every total: what the six listed sites alone produce. - expect(onDisk).toEqual(JSON.parse(JSON.stringify(buildFixtureSummary(FIXTURE_SITES, [])))); + expect(onDisk).toEqual(JSON.parse(JSON.stringify(withoutIt))); const text = JSON.stringify(onDisk); for (const needle of NEEDLES) expect(text).not.toContain(needle); expect(onDisk.sites.map((s: { siteId: string }) => s.siteId)).toEqual(