Landing precondition: one freshness pass per tree, so the merge-queue lock is held for minutes

The freshness precondition rebuilds every bundle in its scope (~10 min for a library change) and ran
inside the lock, so a build-owner landing held main for 30+ minutes while other landings timed out
behind it. Its verdict depends only on the committed tree and the scope, so a PASS is now recorded
against both (in the repo's git dir). The landing runs the precondition before taking the lock; the
scan inside the lock finds the record and skips the rebuild. A different tree or a wider scope has no
record and is checked in full, as before.
This commit is contained in:
Doxa Maps 2026-09-26 00:06:02 +00:00
parent 57bf76422f
commit 5f1db2350f

View file

@ -22,6 +22,7 @@
* DOXA_SKIP_FRESHNESS=1 skips (4) — for a DRY check only; main-capture scan never sets it.
*/
import { spawnSync } from 'node:child_process'
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
import { resolve, dirname } from 'node:path'
import { fileURLToPath } from 'node:url'
import { TREE_NAME } from './_tree-name.mjs'
@ -73,6 +74,20 @@ if (process.env.DOXA_SKIP_FRESHNESS === '1') {
const own = [...new Set(changed.map((f) => (f.match(/^plugin-designs\/([^/]+)\//) || [])[1]).filter(Boolean))]
const scope = shared ? ['--all'] : (own.length ? ['--bundles', own.join(',')] : [])
console.log(`LANDING-PRECONDITIONS: 4 fresh — scope: ${shared ? 'EVERY bundle (shared code changed' + (base ? '' : '; no merge-base') + ')' : 'composites' + (own.length ? ' + ' + own.join(', ') : '')}`)
// ★ ONE PASS PER TREE, NOT ONE PER SCAN. This check rebuilds every bundle in its scope (~10 min for
// --all), and it used to run INSIDE the merge-queue lock, so a build-owner landing held main for 30+ min
// while every other landing queued (2026-09-25). The verdict is a function of the committed tree and the
// scope, so a PASS is recorded against both; the landing script runs this precondition BEFORE taking the
// lock, and the scan inside the lock finds the record and does not rebuild again. A different tree or a
// wider scope has no record and is checked in full. The record lives in the repo's own git dir.
const treeId = run('git', ['rev-parse', 'HEAD^{tree}']).stdout.trim()
const stampDir = resolve(ROOT, run('git', ['rev-parse', '--git-common-dir']).stdout.trim(), 'doxa-fresh')
const stamp = resolve(stampDir, `${treeId}.${scope.join('_').replace(/[^\w,.-]/g, '') || 'composites'}`)
if (treeId && existsSync(stamp)) {
console.log(`LANDING-PRECONDITIONS: 4 fresh — this exact tree (${treeId.slice(0, 10)}) already passed at this scope, ${readFileSync(stamp, 'utf8').trim()}`)
console.log('LANDING-PRECONDITIONS: PASS — this commit may land.')
process.exit(0)
}
const fresh = run(process.execPath, ['internal/check-composite-freshness.mjs', ...scope])
if (fresh.status !== 0) refuse(
'a committed composite is not what its source builds (stale consumers).\n' +
@ -82,5 +97,6 @@ if (process.env.DOXA_SKIP_FRESHNESS === '1') {
'own plugin is stale, rebuild just it: BUNDLE=<name> bun x vite build && bun run tree && bun run fix:sri.',
(fresh.stdout + fresh.stderr).trim().split('\n').filter((l) => /✗|STALE|FAIL/.test(l)).slice(0, 8).join('\n'))
console.log('LANDING-PRECONDITIONS: 4 fresh — every composite rebuilds to its committed bytes')
if (treeId) { mkdirSync(stampDir, { recursive: true }); writeFileSync(stamp, `${new Date().toISOString()} (commit ${run('git', ['rev-parse', '--short', 'HEAD']).stdout.trim()})\n`) }
}
console.log('LANDING-PRECONDITIONS: PASS — this commit may land.')