From 81fd6dc7d5099c44c24aa9e07ce7c4a387775a4e Mon Sep 17 00:00:00 2001 From: Doxa Maps Date: Thu, 1 Oct 2026 10:52:55 +0000 Subject: [PATCH] Landing precondition: a library change's freshness scope includes shipped bundles the manifest does not list (template-bundle) --- internal/landing-preconditions.mjs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/internal/landing-preconditions.mjs b/internal/landing-preconditions.mjs index b6d13ca2d..0bac5b302 100644 --- a/internal/landing-preconditions.mjs +++ b/internal/landing-preconditions.mjs @@ -36,7 +36,7 @@ process.stdout.write(`LANDING-PRECONDITIONS: start — pid ${process.pid}, node ${process.version}\n`) import { spawnSync } from 'node:child_process' import { createHash } from 'node:crypto' -import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs' +import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from 'node:fs' import { resolve, dirname } from 'node:path' import { fileURLToPath } from 'node:url' import { TREE_NAME } from './_tree-name.mjs' @@ -181,7 +181,14 @@ if (process.env.DOXA_SKIP_FRESHNESS === '1') { const libSet = new Set(libChanged) const areas = new Set(libChanged.map((f) => (f.match(/^library\/i18n\/locales\/[^/]+\/([^/]+)\.json$/) || [])[1]).filter(Boolean)) const manifest = JSON.parse(readFileSync(resolve(ROOT, 'public', TREE_NAME, 'manifest.json'), 'utf8')) - for (const { bundle } of manifest.bundles) { + // ★ EVERY SHIPPED BUNDLE, NOT ONLY THE MANIFEST'S. A bundle the tree ships but does not list (template-bundle) + // was never in scope, so a library change it imports left it stale with no landing to rebuild it; a final + // all-bundle freshness run found it weeks of library changes behind. Shipped = a plugin with an index.js + // whose built /.js is in the tree. + const shipped = readdirSync(resolve(ROOT, 'plugin-designs')).filter((d) => existsSync(resolve(ROOT, 'plugin-designs', d, 'index.js')) + && existsSync(resolve(ROOT, 'public', TREE_NAME, d, d + '.js'))) + const candidates = [...new Set([...manifest.bundles.map((b) => b.bundle), ...shipped])] + for (const bundle of candidates) { if (!existsSync(resolve(ROOT, 'plugin-designs', bundle, 'index.js'))) continue const graph = bundleGraph(ROOT, bundle).map((f) => f.slice(ROOT.length + 1)) if (graph.some((f) => libSet.has(f)) || (areas.size && areasForBundle(ROOT, bundle).areas.some((a) => areas.has(a)))) own.add(bundle)