Archilyzer · Source

archilyzer

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

commit ef987279bed05be673c522ab14a6b222740ba2fa
parent 286c422999e8d65b57187aa19d6f6b02d6c2c7f2
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Tue, 29 Sep 2026 20:46:18 -0400

common: the hub does not list an unlisted site — not in hub-sites.json, so not a member, not in federated search, the hub's corpus.json or llms.txt

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

Diffstat:
Mcommon/bin/compose-hub.test.ts | 40++++++++++++++++++++++++++++++++++++++++
Mcommon/bin/compose-hub.ts | 12++++++++----
2 files changed, 48 insertions(+), 4 deletions(-)

diff --git a/common/bin/compose-hub.test.ts b/common/bin/compose-hub.test.ts @@ -130,3 +130,43 @@ test("in a worktree, compose-hub writes its own files and never through the link rmSync(root, { recursive: true, force: true }); } }); + +// Release 14 slice HS: an unlisted site builds and deploys, and the hub does +// not list it — not a member, so not in federated search, corpus.json or +// llms.txt. +test("an unlisted site is in none of the hub's files; a listed one is in each", async () => { + const root = mkdtempSync(path.join(tmpdir(), "compose-hub-")); + const log = console.log; + try { + const paths = fixturePaths(root); + const write = (id: string, site: Record<string, unknown>) => { + mkdirSync(path.join(paths.sitesDir, id), { recursive: true }); + writeFileSync(path.join(paths.sitesDir, id, "site.json"), JSON.stringify(site)); + }; + write("fixture-shown", { siteTitle: "Shown Fixture", siteUrl: "https://fixture-shown.example" }); + write("fixture-unlisted", { + siteTitle: "Unlisted Fixture", + siteUrl: "https://fixture-unlisted.example", + listed: false, + }); + const lines: string[] = []; + console.log = (...a: unknown[]) => void lines.push(a.join(" ")); + await main({ paths }); + console.log = log; + const pool = JSON.parse( + readFileSync(path.join(paths.exportPublicDir, "hub-sites.json"), "utf8"), + ) as Array<{ siteId: string }>; + assert.deepEqual(pool.map((s) => s.siteId), ["fixture-shown"]); + for (const f of ["hub-sites.json", "corpus.json", "llms.txt"]) { + const text = readFileSync(path.join(paths.exportPublicDir, f), "utf8"); + assert.ok(text.includes("fixture-shown.example"), `${f} lists the listed site`); + for (const needle of ["fixture-unlisted", "Unlisted Fixture"]) { + assert.ok(!text.includes(needle), `${f} names ${needle}`); + } + } + assert.match(lines.join("\n"), /compose-hub: 1 built-in pool site\(s\)/); + } finally { + console.log = log; + rmSync(root, { recursive: true, force: true }); + } +}); diff --git a/common/bin/compose-hub.ts b/common/bin/compose-hub.ts @@ -4,7 +4,8 @@ // there is no SITE_ID and no per-site data: the hub is a federating shell that // reads every archive cross-origin at runtime. It emits: // -// public/hub-sites.json <- the built-in trusted pool (listSites with a siteUrl) +// public/hub-sites.json <- the built-in trusted pool (listSites with a siteUrl, +// listed — site.json `listed`, isListedSite) // public/hub-summary.json <- the official instances' numbers, the homepage's // own (lib/hubSummary.ts) — OPTIONAL: skipped when // there is no index to walk @@ -19,7 +20,7 @@ import { existsSync } from "node:fs"; import { cp, rm, access } from "node:fs/promises"; import { getPaths, type Paths } from "../lib/paths"; import { accentHex } from "../lib/accent"; -import { listSites, resolveHubUrl } from "../lib/site"; +import { isListedSite, listSites, resolveHubUrl } from "../lib/site"; import { getHomepageConfig } from "../lib/homepage"; import { SITE_DESCRIPTOR_VERSION } from "../lib/siteDescriptor"; import { @@ -79,7 +80,10 @@ export async function main(opts: { paths?: Paths } = {}): Promise<void> { const paths = opts.paths ?? getPaths(); const publicDir = paths.exportPublicDir; - // Built-in pool: every configured site that publishes a public URL. The entry + // Built-in pool: every configured site that publishes a public URL and is + // listed. An unlisted site (`listed: false`) still builds and deploys, but the + // hub does not list it: not a member, not in federated search, not in the + // hub's corpus.json or llms.txt (both are built from this list). The entry // the hub registry loads at boot to seed its trusted built-in pool, and the // input buildHubCorpus maps — ONE type for both (lib/archive/contract.ts // HubMemberInput), where this file used to restate it as a local @@ -88,7 +92,7 @@ export async function main(opts: { paths?: Paths } = {}): Promise<void> { // a siteUrl can't be federated and is dropped — by both consumers. const builtins: HubMemberInput[] = []; for (const site of listSites(paths)) { - if (!site.siteUrl) continue; + if (!site.siteUrl || !isListedSite(site)) continue; builtins.push({ siteId: site.siteId, siteTitle: site.siteTitle,