diff --git a/internal/landing-preconditions.mjs b/internal/landing-preconditions.mjs index 27a7a9d60..938780f60 100644 --- a/internal/landing-preconditions.mjs +++ b/internal/landing-preconditions.mjs @@ -19,6 +19,7 @@ * 2. ONE FOLDER public/ holds exactly the configured tree (vite.doxa-maps-build-config.json "name") and * README.md. A build made under a different tree name writes a different folder: refused. * 3. SRI every leaf's baked integrity matches the bundle it loads (check:sri). + * 3c. SIZE every shipped bundle is under the 1,500,000-byte ceiling (verify-bundles-shipped). * 3b. MOUNTS every capability-4/5 composite mounts headless in en and ar (check:composites-mount). * 4. FRESH every composite rebuilds to exactly its committed bytes (check:composite-freshness). * @@ -109,6 +110,13 @@ const sri = run(process.execPath, ['internal/sri-consistency-check.mjs']) if (sri.status !== 0) refuse('check:sri failed', (sri.stdout + sri.stderr).trim().split('\n').slice(-6).join('\n')) console.log(`LANDING-PRECONDITIONS: 3 sri — every leaf loads the bundle its integrity names (${since()})`) +// 3c. SIZE — every shipped bundle is under the ceiling (verify-bundles-shipped). It lived only inside +// `verify`, in gates:post, so a landing that grew a bundle past 1,500,000 bytes landed and THEN went red +// (694b00991, country-posters at 1,662,962). Here it runs on the rebuilt tree, before the push. ~0.2 s. +const size = run(process.execPath, ['library/scripts/research/verify-bundles-shipped.mjs']) +if (size.status !== 0) refuse('a shipped bundle is over the size ceiling or missing (verify-bundles-shipped)', (size.stdout + size.stderr).trim().split('\n').filter((l) => /✗|FAIL|FATAL/.test(l)).slice(0, 8).join('\n')) +console.log(`LANDING-PRECONDITIONS: 3c size — every shipped bundle is under the ceiling (${since()})`) + // 3b. MOUNTS — every capability-4/5 composite mounts headless in en and ar without a setup/watcher/mount // error (check:composites-mount, ~20 s). 08f89f55 left Big Picture and Simple Research BLANK while every // other check passed; a landing that blanks a composite is now refused. diff --git a/library/scripts/research/verify-bundles-shipped.mjs b/library/scripts/research/verify-bundles-shipped.mjs index 2a1282b3b..b7962dd84 100644 --- a/library/scripts/research/verify-bundles-shipped.mjs +++ b/library/scripts/research/verify-bundles-shipped.mjs @@ -66,9 +66,13 @@ for (const b of bundles) { // has already happened here: a single import took two bundles to 2.0MB / 2.9MB. // With a 7.7MB people-groups file now in public/assets, an accidental import // would produce an ~8MB bundle. A ceiling catches it the moment it happens. - const MAX = 1_500_000; // ~2x the largest legitimate bundle (683KB) + // The ceiling was set at ~2x the largest bundle of its day (683 KB); country-posters now sits at about + // 1.47 MB of it, so there is little headroom left and a per-bundle pin may fit better (open question). + // Reported in BYTES: the old MiB figures printed "1.4MB" for a 1,500,000-byte ceiling and "1.6MB" for + // 1,662,962 bytes, which is two different units in one sentence. + const MAX = 1_500_000; if (bytes > MAX) { - fail(`${b.bundle}: ${b.output} is ${(bytes / 1048576).toFixed(1)}MB (ceiling ${(MAX / 1048576).toFixed(1)}MB) ` + fail(`${b.bundle}: ${b.output} is ${bytes.toLocaleString('en-US')} bytes (ceiling ${MAX.toLocaleString('en-US')}) ` + '— a data file was almost certainly IMPORTED instead of fetched. public/ assets must be fetch()ed at runtime, never imported.'); } if (!(b.elements || []).length) fail(`${b.bundle}: declares NO custom elements — nothing to mount`);