mirror of
https://github.com/DeusData/codebase-memory-mcp.git
synced 2026-11-04 10:48:20 +00:00
103 lines
4.3 KiB
JavaScript
103 lines
4.3 KiB
JavaScript
// Current release acceptance: unlike the historical W6b proof, this test
|
|
// binds the release report to retained machine-readable proof artifacts.
|
|
// Run: node --test tests/scaffold/release-current.test.mjs
|
|
import { test } from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { execFileSync } from 'node:child_process';
|
|
import { readFileSync } from 'node:fs';
|
|
import { dirname, join, resolve } from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..');
|
|
const read = (path) => readFileSync(join(ROOT, path), 'utf8');
|
|
const git = (...args) => execFileSync('git', args, { cwd: ROOT, encoding: 'utf8' }).trim();
|
|
const report = () => JSON.parse(read('verification/w6/release.json'));
|
|
|
|
const trackedProofs = () => git('ls-files', 'verification')
|
|
.split('\n')
|
|
.filter((path) => path && path !== 'verification/w6/release.json'
|
|
&& !/\.(?:png|jpe?g|webm|mp4|md)$/.test(path))
|
|
.sort();
|
|
|
|
test('AC1: the declared and measured proof inventory exactly matches Git', () => {
|
|
const expected = trackedProofs();
|
|
assert.ok(expected.length > 0, 'the release must declare its machine-readable proof artifacts');
|
|
|
|
const source = read('tools/release-gate.mjs');
|
|
for (const path of expected) {
|
|
assert.ok(source.includes(path), `ausgeschriebener Beweis fehlt im Gate: ${path}`);
|
|
}
|
|
|
|
const r = report();
|
|
const measured = r.artifacts.map((entry) => entry.path)
|
|
.filter((path) => !/\.(?:png|jpe?g|webm|mp4|md)$/.test(path)).sort();
|
|
assert.deepEqual(measured, expected);
|
|
assert.equal(measured.length, expected.length);
|
|
assert.deepEqual(r.missingArtifacts, []);
|
|
assert.deepEqual(r.unlistedArtifacts, []);
|
|
assert.equal(r.allSmokeArtifactsPresent, true);
|
|
});
|
|
|
|
test('AC3: the report is fresh and bound to the current release candidate', () => {
|
|
const r = report();
|
|
const head = git('rev-parse', 'HEAD');
|
|
const parent = git('rev-parse', 'HEAD^');
|
|
let directCandidate = false;
|
|
try {
|
|
directCandidate = git('rev-parse', `${r.sourceHead}^`) === head;
|
|
} catch {
|
|
// An unknown object is neither the current candidate nor its direct child.
|
|
}
|
|
assert.ok([head, parent].includes(r.sourceHead) || directCandidate,
|
|
`Bericht ${r.sourceHead} gehoert nicht zu HEAD ${head}, dessen Elterncommit oder direktem Kandidaten`);
|
|
const ageMs = Date.now() - Date.parse(r.generatedAt);
|
|
assert.ok(Number.isFinite(ageMs) && ageMs >= 0 && ageMs < 24 * 60 * 60 * 1000,
|
|
`Releasebericht ist nicht frisch: ${r.generatedAt}`);
|
|
});
|
|
|
|
test('AC4: the gate enforces a clean, complete candidate instead of merely reporting defects', () => {
|
|
const source = read('tools/release-gate.mjs');
|
|
assert.match(source, /if\s*\(\s*!cleanTree\s*\)/, 'Dirty-Baum muss das Gate rot machen');
|
|
assert.match(source, /if\s*\(\s*unlistedArtifacts\.length\s*>\s*0\s*\)/,
|
|
'ungelistete Artefakte muessen das Gate rot machen');
|
|
|
|
const r = report();
|
|
assert.equal(r.cleanTree, true);
|
|
assert.deepEqual(r.dirtyPaths, []);
|
|
assert.deepEqual(r.unexpectedDirtyPaths, []);
|
|
for (const key of [
|
|
'fullSuitePass', 'unitPass', 'evalCheckPass', 'allSmokeArtifactsPresent',
|
|
'versionMatches',
|
|
]) {
|
|
assert.equal(r[key], true, `${key} muss gruen sein`);
|
|
}
|
|
assert.equal(r.attributionHits, 0);
|
|
assert.equal(r.dashHitsOutsideDocumentedQuotes, 0);
|
|
});
|
|
|
|
test('AC5: the final report carries the suites measured in this run', () => {
|
|
const r = report();
|
|
if (r.scaffold?.seeded === true) {
|
|
assert.match(r.note, /Vorabfassung/);
|
|
return;
|
|
}
|
|
assert.equal(r.extras.unit.exit, 0);
|
|
assert.ok(Number.isFinite(r.extras.unit.tests) && r.extras.unit.tests >= 2019,
|
|
`mindestens 2019 Unit-Tests erwartet, war ${r.extras.unit.tests}`);
|
|
assert.equal(r.scaffold.exit, 0);
|
|
assert.equal(r.scaffold.fail, 0);
|
|
assert.equal(r.scaffold.pass, r.scaffold.tests);
|
|
assert.ok(Number.isFinite(r.scaffold.tests) && r.scaffold.tests >= 193,
|
|
`mindestens 193 Scaffold-Tests erwartet, war ${r.scaffold.tests}`);
|
|
assert.equal(r.testCountSync.synced, true);
|
|
});
|
|
|
|
test('AC6: the public scaffold commands run test files on current Node', () => {
|
|
const pkg = JSON.parse(read('package.json'));
|
|
for (const name of ['test', 'verify']) {
|
|
assert.match(pkg.scripts?.[name] ?? '',
|
|
/node --test tests\/scaffold\/\*\.test\.mjs/,
|
|
`${name} muss die Testdateien statt des Verzeichnisses an Node uebergeben`);
|
|
}
|
|
});
|