45 lines
1.7 KiB
JavaScript
45 lines
1.7 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
import { readFile } from 'node:fs/promises';
|
|
import path from 'node:path';
|
|
|
|
const boundary =
|
|
"Detects accidental and incompetent inventory drift within a checkout; does NOT survive an adversary who rewrites baseline, manifest, and verifier consistently — that guarantee requires RM-60's external boundary.";
|
|
const artifacts = [
|
|
'gates/required-gates.baseline.json',
|
|
'gates/gates.manifest.json',
|
|
'docs/PRD.md',
|
|
'docs/ADMIN-GUIDE/quality-gate-registry.md',
|
|
'docs/DEVELOPER-GUIDE/quality-gate-registry.md',
|
|
'docs/remediation/GATE-CLAIMS.md',
|
|
'docs/plans/2026-08-01-rm-02-gate-registry.md',
|
|
'docs/SITEMAP.md',
|
|
];
|
|
const forbidden = [
|
|
/\bindependent\b[^\n.]{0,80}\bbaseline\b/i,
|
|
/independently baselined/i,
|
|
/independently anchored inventory/i,
|
|
/protected (?:inventory )?(?:anchor|baseline)/i,
|
|
/inventory (?:anchor|anchored)/i,
|
|
];
|
|
const failures = [];
|
|
for (const relativePath of artifacts) {
|
|
const contents = await readFile(path.join(process.cwd(), relativePath), 'utf8');
|
|
const claims =
|
|
relativePath === 'gates/gates.manifest.json'
|
|
? JSON.parse(contents)
|
|
.criteria.map((criterion) => criterion.currentText)
|
|
.join('\n')
|
|
: contents;
|
|
if (!claims.includes(boundary)) failures.push(`${relativePath}: narrowed boundary is missing`);
|
|
const overclaim = forbidden.find((pattern) => pattern.test(claims));
|
|
if (overclaim) failures.push(`${relativePath}: inventory protection is overstated`);
|
|
}
|
|
if (failures.length > 0) {
|
|
for (const failure of failures) {
|
|
process.stderr.write(`INVENTORY_CLAIM_OVERSTATED: ${failure}\n`);
|
|
}
|
|
process.exit(84);
|
|
}
|
|
process.stdout.write('inventory drift boundary is stated in both directions; owner RM-60\n');
|