fix(quality): anchor quantified registry populations
ci/woodpecker/pr/ci Pipeline was successful

This commit is contained in:
2026-08-01 12:39:49 -05:00
parent 32b490a712
commit fbb6191298
14 changed files with 594 additions and 37 deletions
+105
View File
@@ -6,6 +6,12 @@ import { spawnSync } from 'node:child_process';
import test from 'node:test';
const verifier = path.join(process.cwd(), 'scripts', 'gate-verify.mjs');
const fixtureRunner = path.join(
process.cwd(),
'scripts',
'test-support',
'gate-verify-fixture-runner.mjs',
);
const fixtureBase = path.join(process.cwd(), '.mosaic-test-work', `gate-verify-${process.pid}`);
async function fixture(name = 'case') {
@@ -38,6 +44,7 @@ function baseManifest() {
{
id: 'meta-fixture',
source: 'gates/meta-fixture.sh',
evidenceSubject: 'meta-fixture',
invocation: ['gates/meta-fixture.sh'],
deployment: { kind: 'none', reason: 'test fixture only' },
inertMutation: {
@@ -73,6 +80,14 @@ async function writeManifest(root, manifest) {
}
function verify(root, extraArgs = []) {
return spawnSync(
process.execPath,
[fixtureRunner, '--root', root, '--manifest', 'gates/gates.manifest.json', ...extraArgs],
{ cwd: root, encoding: 'utf8', env: { ...process.env, HOME: os.homedir() } },
);
}
function verifyProductionStructure(root, extraArgs = []) {
return spawnSync(
process.execPath,
[
@@ -82,6 +97,7 @@ function verify(root, extraArgs = []) {
'--manifest',
'gates/gates.manifest.json',
'--skip-history',
'--structure-only',
...extraArgs,
],
{ cwd: root, encoding: 'utf8', env: { ...process.env, HOME: os.homedir() } },
@@ -96,6 +112,95 @@ test.after(async () => {
await rm(fixtureBase, { recursive: true, force: true });
});
test('universally quantified registry checks reject empty populations before evaluation', async () => {
const root = await fixture('empty-registry-populations');
await mkdir(path.join(root, 'empty-gate-root'), { recursive: true });
const manifest = baseManifest();
manifest.gateRoots = ['empty-gate-root'];
manifest.criteria = [];
manifest.proseClaims = [];
manifest.compatibilityScenarios = [];
manifest.gates = [];
await writeManifest(root, manifest);
const result = verifyProductionStructure(root);
assert.notEqual(result.status, 0);
assert.match(output(result), /criteria population.*non-empty.*anchored/i);
assert.match(output(result), /gates population.*non-empty.*anchored/i);
assert.match(output(result), /proseClaims population.*non-empty.*anchored/i);
assert.match(output(result), /compatibilityScenarios population.*non-empty.*anchored/i);
});
test('production verifier exposes no fixture-profile population bypass', async () => {
const root = await fixture('no-production-fixture-profile');
const result = verifyProductionStructure(root, ['--fixture-profile']);
assert.notEqual(result.status, 0);
assert.match(output(result), /unknown option: --fixture-profile/i);
});
test('anchored gate inventory and population criteria cannot shrink together', async () => {
const source = JSON.parse(
await readFile(path.join(process.cwd(), 'gates', 'gates.manifest.json'), 'utf8'),
);
const root = await fixture('shrunken-gate-population');
source.gates = source.gates.filter((gate) => gate.id !== 'hook-pre-push');
for (const criterion of source.criteria) {
if (criterion.gateRefs) {
criterion.gateRefs = criterion.gateRefs.filter((gateId) => gateId !== 'hook-pre-push');
}
criterion.caseRefs = criterion.caseRefs.filter(
(caseRef) => !caseRef.startsWith('hook-pre-push/'),
);
}
await writeManifest(root, source);
const result = verifyProductionStructure(root);
assert.notEqual(result.status, 0);
assert.match(output(result), /gates population is not anchored.*hook-pre-push/i);
});
test('general population criteria cannot delete their gateRefs binding', async () => {
const requiredCriteria = [
'RM02-EVIDENCE-SUBJECT-BINDING',
'RM02-TYPE-STRICT-SCHEMA',
'RM02-NONEMPTY-ANCHORED-QUANTIFICATION',
];
for (const criterionId of requiredCriteria) {
const source = JSON.parse(
await readFile(path.join(process.cwd(), 'gates', 'gates.manifest.json'), 'utf8'),
);
const root = await fixture(`missing-gate-refs-${criterionId}`);
delete source.criteria.find((criterion) => criterion.id === criterionId).gateRefs;
await writeManifest(root, source);
const result = verifyProductionStructure(root);
assert.notEqual(result.status, 0);
assert.match(
output(result),
new RegExp(`${criterionId}.*gateRefs.*required`, 'i'),
criterionId,
);
}
});
test('general population criteria must span every registered gate', async () => {
const source = JSON.parse(
await readFile(path.join(process.cwd(), 'gates', 'gates.manifest.json'), 'utf8'),
);
const root = await fixture('incomplete-gate-refs');
source.criteria.find((criterion) => criterion.id === 'RM02-EVIDENCE-SUBJECT-BINDING').gateRefs =
source.criteria
.find((criterion) => criterion.id === 'RM02-EVIDENCE-SUBJECT-BINDING')
.gateRefs.filter((gateId) => gateId !== 'quality-lint');
await writeManifest(root, source);
const result = verifyProductionStructure(root);
assert.notEqual(result.status, 0);
assert.match(
output(result),
/RM02-EVIDENCE-SUBJECT-BINDING.*gate population binding is missing quality-lint/i,
);
});
test('an externally inerted failure branch makes verification nonzero and names the gate', async () => {
const root = await fixture('external-inert');
await writeGate(root, '#!/bin/sh\nexit 0\n');