Archilyzer · Source

archilyzer

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

commit 65f6e7d3d424374479cacb33a045be9c5fb8c027
parent 4456b4352441ec37d6cf4468c9fd76f0dbf414ea
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Mon, 28 Sep 2026 14:34:31 -0400

common: the deploy check keys on the source's artefacts and the /source page, not on out/source existing

A --no-source build still renders the /source PAGE into out/source/index.html,
so "out/source exists" refused exactly the build that must deploy as before
(found by running `build homepage --no-source` and then the check). Now: no
/source page at all means the build's source step refused (buildHomepage took
out/source away) or the build predates the page — refuse, rebuild; the page
with no manifest, mirror, tree or tarball beside it is a --no-source build —
deploy; any artefact — validate as before. source.spec's comment says three
data tests, which is what E2E_EXPECT_SOURCE=1 failed in the empty state.

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

Diffstat:
Mcommon/publish/build.test.ts | 8+++++++-
Mcommon/publish/source.test.ts | 8++++++--
Mcommon/publish/source.ts | 20+++++++++++++++++---
Mhomepage/e2e/source.spec.ts | 2+-
4 files changed, 31 insertions(+), 7 deletions(-)

diff --git a/common/publish/build.test.ts b/common/publish/build.test.ts @@ -232,6 +232,7 @@ test("deployHomepage refuses an out/ whose source has no record of the rules it const out = path.join(root, "homepage", "out"); mkdirSync(path.join(out, "source"), { recursive: true }); writeFileSync(path.join(out, "index.html"), "<p>home</p>"); + writeFileSync(path.join(out, "source", "index.html"), "<p>the /source page</p>"); writeFileSync( path.join(out, "source", "manifest.json"), JSON.stringify({ @@ -246,9 +247,14 @@ test("deployHomepage refuses an out/ whose source has no record of the rules it deployHomepage({ paths: p, previewBranch: "r12-source" }), /homepage\/out's source has no record of the rules it was audited under — run `archilyzer build homepage`/, ); - // A half-removed source (no manifest) refuses too. + // A half-removed source (no manifest) refuses too… rmSync(path.join(out, "source", "manifest.json")); + mkdirSync(path.join(out, "source", "archilyzer.git")); await assert.rejects(deployHomepage({ paths: p }), /without a valid manifest — run `archilyzer build homepage`/); + // …and so does a build whose source step refused (buildHomepage took + // out/source away, the page with it). + rmSync(path.join(out, "source"), { recursive: true }); + await assert.rejects(deployHomepage({ paths: p }), /has no \/source page \(its source step refused/); } finally { rmSync(root, { recursive: true, force: true }); } diff --git a/common/publish/source.test.ts b/common/publish/source.test.ts @@ -403,10 +403,14 @@ test("round trip: --check writes nothing; publish; a dumb clone of the mirror is // The deploy check (M1): a build's out/ that is this publish deploys… const out = path.join(dir("out"), "out"); - cpSync(path.join(pub, "source"), path.join(out, "source"), { recursive: true }); - cpSync(path.join(pub, "downloads"), path.join(out, "downloads"), { recursive: true }); const check = { ...files, homeDir: HOME, publicDir: pub, sourceRepo: path.join(repo, ".git") }; const checkPaths = o.paths!; + // A build's out/ always has the /source page; a --no-source one, nothing more. + mkdirSync(path.join(out, "source"), { recursive: true }); + writeFileSync(path.join(out, "source", "index.html"), "<p>No source published in this build.</p>"); + assert.equal(await publishedSourceProblem(checkPaths, out, check), null, "--no-source deploys as before"); + cpSync(path.join(pub, "source"), path.join(out, "source"), { recursive: true }); + cpSync(path.join(pub, "downloads"), path.join(out, "downloads"), { recursive: true }); assert.equal(await publishedSourceProblem(checkPaths, out, check), null); // …a tampered tarball does not… writeFileSync(path.join(out, "downloads", path.basename(TARBALL_HREF)), "other bytes"); diff --git a/common/publish/source.ts b/common/publish/source.ts @@ -887,8 +887,9 @@ export async function clearPublishedSource( * was audited under the rules of its day. It deploys only when the last * publish (the skip key beside public/) was made under TODAY's rules and step * (`rulesHash`), of TODAY's `main`, and is the one in `out/` (its mirror head, - * its tarball). An `out/` with no source at all — a `--no-source` build — - * deploys as it always has. + * its tarball). An `out/` whose /source page shows the empty state — a + * `--no-source` build — deploys as it always has; one with no /source page at + * all (a refused build) does not. */ export async function publishedSourceProblem( paths: Paths, @@ -904,8 +905,21 @@ export async function publishedSourceProblem( ): Promise<string | null> { const outSource = path.join(outDir, "source"); const outTarball = path.join(outDir, "downloads", TARBALL_NAME); - if (!existsSync(outSource) && !existsSync(outTarball)) return null; const rebuild = "run `archilyzer build homepage` (it re-audits), then deploy"; + // The /source/ PAGE is always in a finished build (it renders its empty + // state without a publish). Without it, the build's source step refused — + // it took out/source away — or the build predates the page. + if (!existsSync(path.join(outSource, "index.html"))) { + return `homepage/out has no /source page (its source step refused, or the build predates it) — ${rebuild}`; + } + const artefacts = [ + path.join(outSource, "manifest.json"), + path.join(outSource, MIRROR_DIR), + path.join(outSource, "tree"), + outTarball, + ]; + // A `--no-source` build: the page's empty state and nothing else. + if (!artefacts.some((a) => existsSync(a))) return null; const manifest = parseSourceManifest(await readJson(path.join(outSource, "manifest.json"))); if (!manifest) return `homepage/out holds a source publish without a valid manifest — ${rebuild}`; const state = (await readJson(statePath(sourcePublicDir(paths, opts.publicDir)))) as Partial<PublishState> | null; diff --git a/homepage/e2e/source.spec.ts b/homepage/e2e/source.spec.ts @@ -13,7 +13,7 @@ import { test, expect, type Page } from "@playwright/test"; // the preview deploy's checks (and to app/lib/headers.test.ts). // // E2E_EXPECT_SOURCE=1 (declared in playwright.config.ts) makes the empty state -// a FAILURE of the four data tests, so a gate that published first cannot +// a FAILURE of the three data tests, so a gate that published first cannot // pass with a publish that silently produced nothing, or a loader that always // says "empty". const EXPECT_SOURCE = process.env.E2E_EXPECT_SOURCE === "1";