doxa-maps/internal/check-capability-exemplars.mjs
doxa-maps-88655c70 9dc4dda8cf
Some checks are pending
build-gate / build (push) Waiting to run
consolidate docs into documentation/ and deployment shells into deployment/
Driver 2026-09-21: 'a folder called deployment which will store the capacitor
folder, wordpress folder and tauri folder', and 'a folder called documentation
to store the contributing folder so docs are in one place'.

docs/ + contributing/ + CONTRIBUTING.md -> documentation/ (three doc homes into
one). capacitor/ + wordpress/ + src-tauri/ -> deployment/.

The public/ -> dist/ rename the Driver asked about is NOT here: after seeing the
measured blast radius (855 tracked files, 54 source refs, and public/ is the
served web-root four consumers point at) the Driver withdrew it - 'keep the
public folder the same'.

Path references were rewritten mechanically (258 across 87 files), but three
classes needed hand fixes because a prefix regex cannot see them:
  - join(ROOT,'docs',...) in 10 internal scripts - a quoted SEGMENT, not a prefix
  - tauri frontendDist '../public' -> '../../public', since src-tauri is now one
    level deeper; check:tauri caught this exactly as the card predicted
  - the WordPress contract test's dirname(__DIR__,2) -> 3, same reason

Also reverted one over-reach: the rewrite renamed a FINDING-CATEGORY label
'docs' in public-hygiene-check.mjs, which is a rule name in its own header, not
a path.

Verified: full build ALL GUARDS PASS, SRI consistent; check:tauri, check:mobile
(cap sync + webDir OK), check:wp-embed, quoted-scripts, capability-citations,
capability-exemplars, library-index, public-hygiene, parse and drop all pass.
2026-09-21 23:23:23 +00:00

64 lines
3.2 KiB
JavaScript

#!/usr/bin/env node
/**
* check-capability-exemplars.mjs — the generated exemplar table must match the manifest.
*
* Companion to generate-capability-exemplars.mjs. That file's header explains WHY the table is
* derived; this one makes the "derived, so it cannot drift" claim true by REGENERATING and
* comparing, rather than trusting mtimes.
*
* ★ WHY CONTENT-COMPARE AND NOT MTIME. check:library-index compares mtimes, which is right there
* (its generator scans library/ directly, so a source edit really does invalidate the output).
* Here the input is manifest.json, which a full build REWRITES EVERY TIME even when nothing
* changed — so an mtime rule would fail after every build for no reason, and a gate that cries
* wolf gets switched off. Comparing regenerated CONTENT fails only when the answer actually moved.
*
* The same reasoning is why CI regenerates-and-diffs the library index instead of using mtimes:
* a fresh checkout gives every file the same timestamp.
*
* NEGATIVE-TESTED: deleting a row from the table makes this FAIL showing the diff; regenerating
* returns PASS. Deleting the file entirely also FAILs rather than silently skipping.
*/
import { readFileSync, existsSync } from 'node:fs'
import { execFileSync } from 'node:child_process'
import { resolve, dirname, join } from 'node:path'
import { fileURLToPath } from 'node:url'
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..')
const OUT = join(ROOT, 'documentation', 'reference-capability-exemplars.md')
const GEN = join(ROOT, 'internal', 'generate-capability-exemplars.mjs')
const MANIFEST = join(ROOT, 'public', 'doxa-maps', 'manifest.json')
if (!existsSync(MANIFEST)) {
console.log('CAPABILITY-EXEMPLARS: SKIP — no manifest.json (nothing built yet).')
process.exit(0)
}
if (!existsSync(OUT)) {
console.error('CAPABILITY-EXEMPLARS: FAIL — documentation/reference-capability-exemplars.md does not exist.')
console.error(' It is the authoritative answer to "which bundle is the capability-N example?",')
console.error(' a question that has been answered wrongly in three separate artifacts.')
console.error(' Fix: bun run capability-exemplars')
process.exit(1)
}
const before = readFileSync(OUT, 'utf8')
execFileSync(process.execPath, [GEN], { stdio: 'pipe' })
const after = readFileSync(OUT, 'utf8')
if (before !== after) {
// Restore what was committed so the check itself never mutates the tree.
const { writeFileSync } = await import('node:fs')
writeFileSync(OUT, before)
const bl = before.split('\n'), al = after.split('\n')
const diff = []
for (let i = 0; i < Math.max(bl.length, al.length) && diff.length < 10; i++) {
if (bl[i] !== al[i]) diff.push(` line ${i + 1}\n file: ${bl[i] ?? '(missing)'}\n real: ${al[i] ?? '(missing)'}`)
}
console.error('\nCAPABILITY-EXEMPLARS: FAIL — the table disagrees with the manifest:')
console.error(diff.join('\n'))
console.error('\n The manifest is what the BUILD computed from each folder\'s real shape.')
console.error(' Fix: bun run capability-exemplars (then commit the regenerated file).')
process.exit(1)
}
const rows = (after.match(/^\| `/gm) || []).length
console.log(`CAPABILITY-EXEMPLARS: PASS — ${rows} exemplar row(s) match the manifest.`)