Files
msd-core/tests/audit-uat-acknowledged.test.cjs
Jakub Zych a9a7a328e6 refactor: hard-fork GSD -> MSD (Make Software Done)
Mechanical rename produced by scripts/msd-rename.cjs: gsd/Gsd/GSD -> msd/Msd/MSD
across contents and paths, upstream package/repo coordinates -> @golem15/msd-core
and golem15com/msd-core. Deep links into upstream history, sibling upstream
packages, the GSD-2 import feature, CHANGELOG.md and .changeset/ are kept as-is.

Hand edits on top: MSD block-letter banner and logos, LICENSE copyright line,
package/plugin identity, regenerated lockfile, install-tree fixtures, derived
registries and benchmark baseline; migration checksum baseline re-locked
(MSD keeps its own install state, so no install had applied the old sums);
sort-order and regex-escaped expectations in tests adjusted.
2026-10-06 01:47:40 +02:00

142 lines
5.5 KiB
JavaScript

'use strict';
// ─────────────────────────────────────────────────────────────────────────────
// #3805 — audit-uat must honour the audit_acknowledged marker that
// audit-open honours.
//
// isAuditItemAcknowledged is the ONE shared suppression predicate, but its
// "every scanner below" scope ended at audit.cts's file boundary:
// cmdAuditUat (src/uat.cts) hand-rolled discovery over the SAME UAT and
// VERIFICATION artifacts and never read the marker — so the documented,
// self-invalidating "this item is moot" seam worked for audit-open and was
// ignored by audit-uat, leaving no honest way to close a moot item.
// ─────────────────────────────────────────────────────────────────────────────
const { test, describe } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const { createTempProject, cleanup, runMsdTools } = require('./helpers.cjs');
const UAT_BODY = [
'## Tests',
'',
'### 1. Deleted Feature Probe',
'expected: The deleted admin route no longer exists',
'result: pending',
'',
].join('\n');
function seedUatPhase(tmpDir, phaseDir, frontmatterExtra) {
const dir = path.join(tmpDir, '.planning', 'phases', phaseDir);
fs.mkdirSync(dir, { recursive: true });
const fm = [
'---',
'status: human_needed',
...(frontmatterExtra || []),
'---',
'',
].join('\n');
fs.writeFileSync(path.join(dir, `${phaseDir}-UAT.md`), fm + UAT_BODY);
return dir;
}
function seedVerificationPhase(tmpDir, phaseDir, frontmatterExtra) {
const dir = path.join(tmpDir, '.planning', 'phases', phaseDir);
fs.mkdirSync(dir, { recursive: true });
const fm = [
'---',
'status: human_needed',
...(frontmatterExtra || []),
'---',
'',
].join('\n');
fs.writeFileSync(path.join(dir, `${phaseDir}-VERIFICATION.md`), fm + [
'# Verification',
'',
'## Human Verification',
'',
'1. **Test:** the deleted route stays deleted',
' - **Result:** pending',
'',
].join('\n'));
return dir;
}
function roadmapWith(phases) {
const lines = ['# Roadmap', ''];
for (const p of phases) lines.push(`### Phase ${p}: P${p}`, '- [ ] w', '');
return lines.join('\n');
}
function runAudit(cwd) {
const r = runMsdTools(['query', 'audit-uat'], cwd);
assert.ok(r.success, r.error);
return JSON.parse(r.output);
}
describe('#3805: audit-uat honours audit_acknowledged', () => {
test('#3805: an acknowledged UAT file is suppressed and counted', (t) => {
const tmpDir = createTempProject('msd-3805-uat-');
t.after(() => cleanup(tmpDir));
fs.writeFileSync(path.join(tmpDir, '.planning', 'ROADMAP.md'), roadmapWith(['02']));
seedUatPhase(tmpDir, '02-probe', [
'audit_acknowledged:',
' milestone: v1.0',
' at: 2026-08-24',
' gap_snapshot: human_needed::scenarios=1',
]);
// Note: the gap_snapshot must match the CURRENT derived value for the
// marker to suppress (self-invalidation on edit).
const out = runAudit(tmpDir);
assert.equal(out.summary.total_items, 0,
`#3805: the acknowledged UAT item must be suppressed; got ${JSON.stringify(out.results)}`);
assert.equal(out.acknowledged_files, 1,
'#3805: the suppressed file must be visible in acknowledged_files (audit-open honesty model)');
});
test('#3805: a STALE gap_snapshot (content changed since ack) still surfaces', (t) => {
const tmpDir = createTempProject('msd-3805-uatstale-');
t.after(() => cleanup(tmpDir));
fs.writeFileSync(path.join(tmpDir, '.planning', 'ROADMAP.md'), roadmapWith(['03']));
// Marker snapshots scenarios=2 but the file now has 1 — self-invalidation.
seedUatPhase(tmpDir, '03-probe', [
'audit_acknowledged:',
' milestone: v1.0',
' at: 2026-08-24',
' gap_snapshot: human_needed::scenarios=2',
]);
const out = runAudit(tmpDir);
assert.ok(out.summary.total_items > 0,
'a marker whose snapshot no longer matches must NOT suppress (self-invalidation)');
assert.equal(out.acknowledged_files, 0, 'a stale marker does not count as acknowledged');
});
test('#3805: an acknowledged VERIFICATION file is suppressed (status snapshot)', (t) => {
const tmpDir = createTempProject('msd-3805-ver-');
t.after(() => cleanup(tmpDir));
fs.writeFileSync(path.join(tmpDir, '.planning', 'ROADMAP.md'), roadmapWith(['04']));
seedVerificationPhase(tmpDir, '04-probe', [
'audit_acknowledged:',
' milestone: v1.0',
' at: 2026-08-24',
' status: human_needed',
]);
const out = runAudit(tmpDir);
assert.equal(out.summary.total_items, 0,
`#3805: the acknowledged VERIFICATION item must be suppressed; got ${JSON.stringify(out.results)}`);
assert.equal(out.acknowledged_files, 1,
'#3805: the suppressed VERIFICATION file must be visible in acknowledged_files');
});
test('#3805 control: an unacknowledged open UAT file still surfaces', (t) => {
const tmpDir = createTempProject('msd-3805-ctl-');
t.after(() => cleanup(tmpDir));
fs.writeFileSync(path.join(tmpDir, '.planning', 'ROADMAP.md'), roadmapWith(['05']));
seedUatPhase(tmpDir, '05-probe');
const out = runAudit(tmpDir);
assert.ok(out.summary.total_items > 0, 'no marker → item surfaces (pre-existing behavior)');
});
});