Some checks are pending
build-gate / build (push) Waiting to run
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.
111 lines
5.8 KiB
JavaScript
111 lines
5.8 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* check-quoted-scripts.mjs — a doc that QUOTES package.json must still match package.json.
|
|
*
|
|
* THE BUG THIS EXISTS TO PREVENT (real, twice)
|
|
* documentation/README-SECTION-3-cli-commands.md reproduces the `scripts` block verbatim so a reader can
|
|
* see every command without opening package.json. It carries its own warning two lines above the
|
|
* block: "If you edit package.json, re-transcribe this block — a doc that QUOTES a config is
|
|
* claiming to be ground truth, and this one had silently stopped being it."
|
|
*
|
|
* It then silently stopped being it AGAIN. Two entries had drifted on 2026-09-21:
|
|
* - `cap:sync` still showed `bunx cap sync android` — the exact command that does not exist in
|
|
* this environment (exit 127) and that package.json had ALREADY been fixed away from.
|
|
* - `build:unlocked` was missing `check:public-hygiene` and `check:label-joins`. That is the
|
|
* worst shape of this defect: a reader auditing what the build verifies would conclude the
|
|
* SECRET-SCAN is not in the chain. An omission in a quoted list is invisible — there is no
|
|
* wrong character to notice, just a step that is not there.
|
|
*
|
|
* ★ WHY A GATE AND NOT A BETTER WARNING. The file already had the warning, written by someone who
|
|
* had just been burned, and the warning did not work — because re-transcribing by hand is exactly
|
|
* the kind of mechanical task a human or an agent skips when the edit felt unrelated. The rule was
|
|
* enforced only by remembering. This is the same failure the library-index gate was built for:
|
|
* a documented invariant with no mechanism behind it is a wish.
|
|
*
|
|
* WHY COMPARE AGAINST package.json AND NOT A SNAPSHOT
|
|
* package.json is the thing that RUNS. The doc is the copy. So the authority is unambiguous and
|
|
* the fix direction is always "update the doc" — never the reverse.
|
|
*
|
|
* WHAT IT TOLERATES DELIBERATELY
|
|
* - Trailing ` # comment` in a package.json body: several scripts carry an inline explanation
|
|
* that the doc block reasonably omits. Compared against the code half only.
|
|
* - JSON escaping (\" in the doc's fenced block) and a trailing comma.
|
|
* - Entries the doc chooses NOT to quote: this checks the ones it DOES quote, so the doc can
|
|
* stay a curated subset. It reports the count so shrinkage is visible.
|
|
*
|
|
* ★ THE MATCHER MUST NOT SILENTLY MATCH NOTHING. The first version of this regex required each
|
|
* line to END in a quote (`"$`). Nine of the ten entries end in `",` — a trailing comma — so it
|
|
* matched exactly ONE (`phone`, the last entry, the only one without a comma) and reported
|
|
* "0 drifted". That is a pass that means nothing, and it looks identical to a real clean run.
|
|
* (My first guess at the cause was "the block is indented"; it is NOT indented — checking rather
|
|
* than assuming is what found the trailing comma. A plausible explanation for a broken measurement
|
|
* is still a fabricated one until verified.)
|
|
* Hence MIN_EXPECTED below: too few matches is itself a FAILURE, not a quiet success.
|
|
*
|
|
* NEGATIVE-TESTED: reverting `cap:sync` in the doc to `bunx cap sync android` makes this FAIL
|
|
* naming that entry and showing both sides; restoring it returns PASS. Breaking the regex so it
|
|
* matches < MIN_EXPECTED also FAILs rather than passing vacuously.
|
|
*/
|
|
import { readFileSync, existsSync } from 'node:fs'
|
|
import { resolve, dirname, join } from 'node:path'
|
|
import { fileURLToPath } from 'node:url'
|
|
|
|
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..')
|
|
const PKG = join(ROOT, 'package.json')
|
|
const DOC = join(ROOT, 'documentation', 'README-SECTION-3-cli-commands.md')
|
|
|
|
// The doc quoted 10 entries when this gate was written. If the matcher suddenly finds far fewer,
|
|
// the matcher is broken, not the doc.
|
|
const MIN_EXPECTED = 6
|
|
|
|
if (!existsSync(DOC)) {
|
|
console.log('QUOTED-SCRIPTS: SKIP — documentation/README-SECTION-3-cli-commands.md not present.')
|
|
process.exit(0)
|
|
}
|
|
|
|
const scripts = JSON.parse(readFileSync(PKG, 'utf8')).scripts || {}
|
|
const doc = readFileSync(DOC, 'utf8')
|
|
|
|
// Indent-tolerant: the block is inside a fenced code block and is indented.
|
|
const RE = /^[ \t]*"([a-z0-9:_-]+)":\s+"(.*?)",?[ \t]*$/gm
|
|
|
|
const drift = [], unknown = []
|
|
let quoted = 0
|
|
|
|
for (const m of doc.matchAll(RE)) {
|
|
const name = m[1]
|
|
const shown = m[2].replace(/\\"/g, '"').replace(/,$/, '').trim()
|
|
if (!(name in scripts)) { unknown.push(name); continue }
|
|
quoted++
|
|
const real = scripts[name]
|
|
const realCode = real.split(/\s{2,}#/)[0].trim() // drop an inline ` # …` explanation
|
|
if (shown !== real.trim() && shown !== realCode) drift.push({ name, shown, real: realCode })
|
|
}
|
|
|
|
console.log(`QUOTED-SCRIPTS: ${quoted} quoted entr(ies) compared against package.json.`)
|
|
|
|
if (quoted < MIN_EXPECTED) {
|
|
console.error(`\nQUOTED-SCRIPTS: FAIL — only ${quoted} entries matched (expected >= ${MIN_EXPECTED}).`)
|
|
console.error(' The MATCHER is broken, not the doc. A checker that matches almost nothing')
|
|
console.error(' reports "0 drifted" and looks exactly like a clean pass — fix the regex in')
|
|
console.error(' internal/check-quoted-scripts.mjs before trusting this result.')
|
|
process.exit(1)
|
|
}
|
|
|
|
if (unknown.length) {
|
|
console.log(` i quoted but not in package.json (ignored): ${unknown.join(', ')}`)
|
|
}
|
|
|
|
if (drift.length) {
|
|
console.error(`\nQUOTED-SCRIPTS: FAIL — ${drift.length} quoted script(s) no longer match package.json:`)
|
|
for (const d of drift) {
|
|
console.error(`\n ✗ ${d.name}`)
|
|
console.error(` doc : ${d.shown}`)
|
|
console.error(` real : ${d.real}`)
|
|
}
|
|
console.error('\n package.json is what RUNS; the doc is the copy — update the DOC to match.')
|
|
console.error(' An omitted step in a quoted list is invisible: there is no wrong character to')
|
|
console.error(' notice, just a check the reader believes is not in the chain.')
|
|
process.exit(1)
|
|
}
|
|
console.log('QUOTED-SCRIPTS: PASS — every quoted script matches package.json.')
|