doxa-maps/internal/check-no-new-driver-references.mjs
Doxa Maps 7d2decab5b Shipped text stops gaining references to the Driver: a forward-only gate with a baseline that may only shrink
The standing rule is that comments, docs and UI strings say what the code does and why, never who said
what. Several hundred existing lines break it; owners remove them in one sweep per area before the public
giveaway. Until then check:no-new-driver-references (gates:pre) fails any NEW line that refers to the
Driver and baselines the rest, keyed by file and line text with counts rather than line numbers, so
parallel sweeps only ever shrink it. It matches the role word, not a GPU or device driver, and its
self-test proves both that and that a new line beside baselined ones is isolated.
2026-09-29 03:46:37 +00:00

106 lines
5.8 KiB
JavaScript

#!/usr/bin/env node
/**
* check-no-new-driver-references — shipped text neither quotes nor cites the Driver, and the references
* already in it may only go away.
*
* The rule: a comment, doc, UI string or commit says what the code does and why, never who said what.
* An open decision reads "provisional, pending a product decision". Measured on 2026-09-29, several
* hundred lines already referred to the Driver. Owners remove them in one sweep per area before the
* public giveaway; until then this gate holds the line FORWARD-ONLY:
* - a line that refers to the Driver and is not in the baseline FAILS (a new reference);
* - a baselined line that is gone is fine (owners sweep in parallel); --shrink tidies the baseline.
*
* WHAT COUNTS: the role word, `Driver` with a capital D as a whole word (not a GPU or device driver, not
* WebDriver, not an env name like DRIVER_MERGE). KEYED by file plus the line's normalised text, with a
* count, not by line number, so edits elsewhere in a file never trip it; a new line with the same text
* in the same file raises the count and fails.
*
* node internal/check-no-new-driver-references.mjs check
* node internal/check-no-new-driver-references.mjs --shrink drop what is gone (never adds)
* node internal/check-no-new-driver-references.mjs --init write the baseline, only if none exists
*
* Node only. Exit 0 pass · 1 fail.
*/
import { readFileSync, writeFileSync, existsSync } from 'node:fs'
import { execFileSync } from 'node:child_process'
import { join, resolve, dirname } from 'node:path'
import { fileURLToPath } from 'node:url'
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..')
const SELF = 'internal/check-no-new-driver-references.mjs'
const BASELINE_REL = 'internal/fixtures/driver-references-baseline.json'
const BASELINE = join(ROOT, BASELINE_REL)
const ROLE = /\bDriver\b/
const AREAS = ['library', 'plugin-designs', 'internal', 'documentation', 'skills', 'README.md']
export function referencesIn(text) {
const out = []
text.split('\n').forEach((line, i) => {
if (ROLE.test(line)) out.push({ line: i + 1, norm: line.replace(/\s+/g, ' ').trim() })
})
return out
}
const keyOf = (file, norm) => `${file}\u0000${norm}`
function shippedFiles() {
const listed = execFileSync('git', ['-C', ROOT, 'ls-files', ...AREAS], { encoding: 'utf8' })
return listed.split('\n').filter((f) => /\.(vue|js|mjs|md|json|html|css)$/.test(f) && !f.includes('/data/')
&& f !== SELF && f !== BASELINE_REL)
}
function tally(files, read) {
const counts = new Map(); const where = new Map()
for (const f of files) {
let text
try { text = read(f) } catch { continue }
for (const r of referencesIn(text)) {
const k = keyOf(f, r.norm)
counts.set(k, (counts.get(k) || 0) + 1)
if (!where.has(k)) where.set(k, { file: f, line: r.line, text: r.norm })
}
}
return { counts, where }
}
// ── self-test: the role word is found, a device driver is not, and a new line beside a baselined one is isolated
{
const found = referencesIn('// the Driver ruled that numerals stay en-US\n// the GPU driver and WebDriver and DRIVER_MERGE\n')
if (found.length !== 1) { console.error('DRIVER-REFS: SELF-TEST FAILED — the role word is not told apart from other drivers'); process.exit(1) }
const { counts } = tally(['a.vue'], () => '// Driver: old\n// Driver: old\n// Driver: new\n')
const base = new Map([[keyOf('a.vue', '// Driver: old'), 2]])
const fresh = [...counts].filter(([k, n]) => n > (base.get(k) || 0))
if (fresh.length !== 1 || !fresh[0][0].endsWith('new')) { console.error('DRIVER-REFS: SELF-TEST FAILED — a new reference beside baselined ones was not isolated'); process.exit(1) }
}
const { counts, where } = tally(shippedFiles(), (f) => readFileSync(join(ROOT, f), 'utf8'))
const args = process.argv.slice(2)
const toObj = (m) => Object.fromEntries([...m].sort(([a], [b]) => (a < b ? -1 : 1)))
if (args.includes('--init')) {
if (existsSync(BASELINE)) { console.error(`DRIVER-REFS: --init refused, ${BASELINE_REL} exists (use --shrink)`); process.exit(1) }
writeFileSync(BASELINE, JSON.stringify({ about: 'Lines in shipped text that referred to the Driver on 2026-09-29, keyed by file and text, to be removed by the owners\' sweep before the public giveaway. Forward-only: this list may only shrink (--shrink).', counts: toObj(counts) }, null, 1) + '\n')
console.log(`DRIVER-REFS: baseline written: ${counts.size} line(s) in ${new Set([...where.values()].map((w) => w.file)).size} file(s)`)
process.exit(0)
}
const baseline = existsSync(BASELINE) ? JSON.parse(readFileSync(BASELINE, 'utf8')) : { counts: {} }
const base = new Map(Object.entries(baseline.counts || {}))
if (args.includes('--shrink')) {
const kept = new Map()
for (const [k, n] of base) { const now = counts.get(k) || 0; if (now > 0) kept.set(k, Math.min(n, now)) }
writeFileSync(BASELINE, JSON.stringify({ ...baseline, counts: toObj(kept) }, null, 1) + '\n')
console.log(`DRIVER-REFS: baseline shrunk ${base.size} -> ${kept.size} line(s) (it never grows)`)
process.exit(0)
}
const fresh = [...counts].filter(([k, n]) => n > (base.get(k) || 0)).map(([k]) => where.get(k))
const gone = [...base.keys()].filter((k) => !counts.has(k)).length
if (fresh.length) {
console.error(`DRIVER-REFS: FAIL — ${fresh.length} new reference(s) to the Driver in shipped text:`)
for (const w of fresh.slice(0, 20)) console.error(` ✗ ${w.file}:${w.line} ${w.text.slice(0, 120)}`)
console.error(' Keep the engineering reason and drop the speaker; an open decision reads "provisional, pending a product decision".')
process.exit(1)
}
console.log(`DRIVER-REFS: PASS — no new reference to the Driver; ${base.size - gone} older line(s) still baselined for the sweep`
+ (gone ? `, ${gone} already swept (tidy with --shrink)` : '') + '.')