A landing whose tree is stale is refused: regenerating it must change nothing

fix:sri rehashes the leaf pages but does not carry a <profile>.meta.json
change into their BASE_CONFIG, so a pinHint, a label or a mobile flag could
land in the source and stay invisible in the tree until some later landing
happened to regenerate it (PPLR's pinHint:false did exactly that).

The generator is deterministic: a clean tree regenerates to 0 changed
files, in about 3 seconds. So landing-preconditions now runs it (step 2b)
and refuses if anything under public/ changes, naming the files and the
command to run. Checked both ways: a meta.json change without the tree
regenerates one leaf page (refused); after `bun run tree` it is 0 (passes).
This commit is contained in:
Doxa Maps 2026-09-29 08:13:08 +00:00
parent 2795455688
commit 3233df2bc1

View file

@ -18,6 +18,8 @@
* files that are not in the commit. * files that are not in the commit.
* 2. ONE FOLDER public/ holds exactly the configured tree (vite.doxa-maps-build-config.json "name") and * 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. * README.md. A build made under a different tree name writes a different folder: refused.
* 2b. TREE regenerating the tree (generate-tree) changes 0 files: a meta.json change must reach the
* leaf pages, not only the source.
* 3. SRI every leaf's baked integrity matches the bundle it loads (check:sri). * 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). * 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). * 3b. MOUNTS every capability-4/5 composite mounts headless in en and ar (check:composites-mount).
@ -105,6 +107,19 @@ if (JSON.stringify(entries) !== JSON.stringify(want)) {
} }
console.log(`LANDING-PRECONDITIONS: 2 one folder — public/ = README.md + ${TREE_NAME}/ (${since()})`) console.log(`LANDING-PRECONDITIONS: 2 one folder — public/ = README.md + ${TREE_NAME}/ (${since()})`)
// 2b. TREE — regenerating the tree changes nothing. fix:sri rehashes leaves but does not carry a
// <profile>.meta.json change (pinHint, a label, the mobile flag) into the leaf pages' BASE_CONFIG: PPLR's
// pinHint:false sat invisible in the tree until a later landing happened to regenerate it. The generator is
// deterministic (a clean tree regenerates to 0 changed files), so a stale leaf config or a stale integrity
// both show up here as a diff, in ~3 s.
const regen = run(process.execPath, ['internal/generate-tree.mjs'], 5 * 60 * 1000)
if (regen.status !== 0) refuse('the tree generator failed', (regen.stdout + regen.stderr).trim().split('\n').slice(-6).join('\n'))
const drift = git(['status', '--porcelain', '--', 'public'])
if (drift.status !== 0) refuse('could not read git status after regenerating the tree')
if (drift.stdout.trim()) refuse('regenerating the tree changes the commit: a meta.json or config change reached the source without reaching public/',
drift.stdout.trim().split('\n').slice(0, 10).join('\n') + '\nRun `bun run tree` (and `bun run fix:sri` if a bundle changed), commit public/, and land again.')
console.log(`LANDING-PRECONDITIONS: 2b tree — regenerating it changes 0 files (${since()})`)
// 3. SRI // 3. SRI
const sri = run(process.execPath, ['internal/sri-consistency-check.mjs']) 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')) if (sri.status !== 0) refuse('check:sri failed', (sri.stdout + sri.stderr).trim().split('\n').slice(-6).join('\n'))