doxa-maps/internal/check-done-evidence.mjs
doxa-maps-88655c70 45888903c9
Some checks are pending
build-gate / build (push) Waiting to run
make check:done-evidence SKIP honestly instead of passing vacuously
Found by the folder-scan agent and verified by simulation. This gate resolves
ROOT at depth 2 while all 40 sibling gates use depth 1, because the backlogs it
reads live in _qa-cycle/ - agentic scratch OUTSIDE the repo, tracked by no git
repository and never cloned with the studio.

On this machine _qa-cycle happens to sit beside the repo, so it passes. An
inheritor who clones only the studio got something worse than a failure: it
printed "0 card(s) across 3 backlog(s), 0 done ... PASS" and exited 0. A
vacuously green gate certifies nothing while looking healthy.

Now it detects the absent directory and SKIPs with an explanation, still
exiting 0 so it cannot break an inheritor's build. Negative-tested both ways:
274 cards still checked here, honest SKIP in a bare clone.
2026-09-22 00:35:07 +00:00

116 lines
5.3 KiB
JavaScript

#!/usr/bin/env node
/**
* check-done-evidence.mjs — a card may not reach status:done with NO evidence.
*
* WHY (2026-09-21)
* Two quality cards were status:done with an EMPTY bluf. Both turned out genuinely done — but
* only because I opened a browser and read the source. A board-wide count then found 18 done
* cards carrying NEITHER a bluf NOR any fields: a status word and nothing else.
*
* ★ THE HAND-OFF IS THE POINT. The Doxa team will read this board to learn what exists. A card
* reading "done" with no evidence cannot be reconciled against the code at all — they cannot
* tell a shipped deliverable from an abandoned one someone closed. This flight found SIX cards
* whose stated status disagreed with reality; an evidence-less card is the unfalsifiable case.
*
* WHAT COUNTS AS EVIDENCE (deliberately generous — this is a floor, not a style guide)
* EITHER a non-empty `bluf` OR a non-empty `fields` object. Both are free to write at the moment
* the work is fresh, which is the only moment the evidence is cheap and accurate.
*
* BASELINE, NOT A CLIFF
* The 10 pre-existing offenders are allow-listed by id. A gate that fails on day one for history
* nobody can fix gets disabled, and then it protects nothing. This fails ONLY on a NEW one — the
* same shape as check-label-joins, which allow-lists two known occurrences.
* ★ TO CLEAR AN ENTRY: add real evidence to the card, then delete its id here. The list should
* only ever shrink; a PR that grows it is doing the thing this gate exists to stop.
*
* NEGATIVE-TESTED: adding a fresh done card with no bluf/fields makes this FAIL naming it,
* EXIT=1; removing it returns PASS.
*/
import { readFileSync, existsSync } from 'node:fs'
import { resolve, dirname, join } from 'node:path'
import { fileURLToPath } from 'node:url'
// ★ DEPTH 2, NOT 1 — and that is deliberate but load-bearing. Every sibling gate in internal/
// resolves ROOT one level up (the repo). This one goes TWO levels up, because the backlogs it
// checks live in `_qa-cycle/`, which is AGENTIC SCRATCH OUTSIDE THE REPO — tracked by no git
// repository, and never cloned with the studio.
//
// THE HAND-OFF DEFECT THIS GUARD FIXES (measured 2026-09-22). On this machine _qa-cycle happens
// to sit beside the repo, so the gate passes. An inheritor who clones ONLY the studio has no
// sibling _qa-cycle — and the gate did NOT fail there. It printed
// "0 card(s) across 3 backlog(s), 0 done" ... "PASS"
// and exited 0. A VACUOUSLY GREEN gate is worse than no gate: it certifies nothing while looking
// healthy, which is exactly the failure shape this repo keeps re-learning.
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..')
const QA = join(ROOT, '_qa-cycle')
if (!existsSync(QA)) {
console.log('DONE-EVIDENCE: SKIP — no _qa-cycle/ beside this repo, so there are no backlogs to check.')
console.log(' This gate reads the AGENTIC BACKLOGS, which live outside the repo and are not cloned')
console.log(' with it. Absence is expected for anyone who checked out the studio on its own; it is')
console.log(' NOT a pass. Run it from a workspace that has _qa-cycle/ as a sibling of this repo.')
process.exit(0)
}
const BACKLOGS = [
'01-ideation-research/backlog.json',
'02-builder-cycle/backlog.json',
'03-deployment-cycle/backlog.json',
]
// Pre-existing, from before the rule. Verified 2026-09-21. SHRINK ONLY.
const BASELINE = new Set([
'BUILD-AGENT-SKILLS',
'BUILD-CAP1-SINGLE-ELEMENT-SHOWCASE',
'BUILD-PLUGIN-STUDIO-VUE-SPA',
'BUILD-README-CLI-COMMANDS',
'BUILD-README-DEDUP-BLUF',
'BUILD-README-SCREENSHOT-MATRIX',
'BUILD-RENAME-PLUGIN-DESIGNS',
'BUILD-RESTORE-MOBILE-SPA',
'BUILD-STARTER-TEMPLATE',
'BUILD-UNIFIED-RESEARCH-DASHBOARD',
])
let checked = 0, done = 0
const offenders = []
const staleBaseline = []
for (const rel of BACKLOGS) {
const p = join(QA, rel)
if (!existsSync(p)) continue
let cards
try { cards = JSON.parse(readFileSync(p, 'utf8')).cards || [] } catch { continue }
for (const c of cards) {
checked++
if (c.status !== 'done') continue
done++
const hasBluf = String(c.bluf || '').trim().length > 0
const hasFields = c.fields && Object.keys(c.fields).length > 0
if (hasBluf || hasFields) {
// A baselined id that now HAS evidence is stale — report it so the list shrinks.
if (BASELINE.has(c.id)) staleBaseline.push(`${c.id} (${rel})`)
continue
}
if (BASELINE.has(c.id)) continue
offenders.push(`${c.id} (${rel})`)
}
}
console.log(`DONE-EVIDENCE: ${checked} card(s) across ${BACKLOGS.length} backlog(s), ${done} done, ` +
`${BASELINE.size} baselined.`)
for (const s of staleBaseline) {
console.log(` i BASELINE NOW STALE — ${s} has evidence; remove its id from check-done-evidence.mjs`)
}
if (offenders.length) {
console.error(`\nDONE-EVIDENCE: FAIL — ${offenders.length} card(s) are done with NO bluf and NO fields:`)
for (const o of offenders) console.error(` ✗ ${o}`)
console.error(
'\n Add ONE of: a `bluf` saying what was done, or a `fields` entry naming the artifact and how\n' +
' it was verified. Write it now, while the work is fresh — reconstructing it later produces a\n' +
' plausible story indistinguishable from a real record.'
)
process.exit(1)
}
console.log('DONE-EVIDENCE: PASS — every newly-done card carries a bluf or fields.')