Archilyzer · Source

archilyzer

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

commit d223c0e20c7e6da333178232c42e1acf5be76bb9
parent d85aafb4b2f2f415f6e30c0cb77a25cbf0049273
Author: I Mean I'm Just Saying <imeanimjustsaying@kiwifarms.st>
Date:   Wed, 30 Sep 2026 10:17:45 -0400

common: a withdrawal never fails over the render cache — a cache it cannot remove is one masked line, and the refusal's exit 1 and the withdrawn source stand (re-review); test with a read-only cache dir

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

Diffstat:
Mcommon/publish/source.test.ts | 33+++++++++++++++++++++++++++++++++
Mcommon/publish/source.ts | 17+++++++++++++++--
2 files changed, 48 insertions(+), 2 deletions(-)

diff --git a/common/publish/source.test.ts b/common/publish/source.test.ts @@ -914,3 +914,36 @@ test("history: pages that would take the publish over the step's file limit are assert.ok(existsSync(path.join(o.publicDir!, "source", MIRROR_DIR, "info", "refs")), "the rest is published"); assert.ok(!("history" in JSON.parse(readFileSync(path.join(o.publicDir!, "source", "manifest.json"), "utf8")))); }); + +test("history: a refusal with a render cache it cannot remove still exits 1 and withdraws the source; one masked line says so (re-review)", async () => { + const repo = sourceRepo(); + const planted = "plantedinhistory"; + const files = operatorFiles("", ""); + const logs: string[] = []; + const log = path.join(dir("stagit-log"), "calls"); + const cacheDir = cacheDirIn(dir("cache-home")); + const o = opts(repo, files, logs, { + filterRepo: ["true"], + stagit: fakeStagit(log, { extra: `said ${planted} here` }), + tokensFile: TOKENS_FILE, + historyCacheDir: cacheDir, + }); + assert.equal(await publishSource(o), 0, logs.join("\n")); + assert.ok(existsSync(path.join(cacheDir, "key.json"))); + // The cache becomes read-only; then a rule denies what its pages say. + chmodSync(cacheDir, 0o555); + try { + writeFileSync(files.denylistFile, `${planted}\n`); + logs.length = 0; + assert.equal(await publishSource(o), 1, "the refusal's exit stands"); + const text = logs.join("\n"); + assert.match(text, /AUDIT REFUSED/); + assert.match(text, /the previous publish was WITHDRAWN/); + assert.match(text, /\[source\] the history's render cache .* could not be removed \(EACCES\); remove it by hand/); + assert.ok(!text.includes(planted)); + assert.ok(!existsSync(path.join(o.publicDir!, "source")), "the source is withdrawn"); + assert.ok(!existsSync(path.join(path.dirname(o.publicDir!), ".source-publish.json"))); + } finally { + chmodSync(cacheDir, 0o755); + } +}); diff --git a/common/publish/source.ts b/common/publish/source.ts @@ -712,8 +712,21 @@ export async function publishSource(opts: SourcePublishOpts = {}): Promise<numbe "[source] the previous publish was WITHDRAWN (mirror, tree, history, tarball): it was audited under rules that may not be today's. /source shows its empty state until a publish passes.", ); } - // The history's render cache was rendered under those rules too. - if (progress.historyCache) await dropHistoryCache(progress.historyCache); + // The history's render cache was rendered under those rules too. It is + // never why a withdrawal fails: one line, and the refusal stands. + if (progress.historyCache) { + try { + await dropHistoryCache(progress.historyCache); + } catch (err) { + const why = (err as NodeJS.ErrnoException)?.code ?? (err as Error)?.message ?? String(err); + onLog( + maskLiterals( + `[source] the history's render cache ${tildify(progress.historyCache)} could not be removed (${why}); remove it by hand`, + ctx.literals, + ), + ); + } + } }; let code: number; try {