Files
msd-core/tests/shipped-reference-cites.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

133 lines
5.8 KiB
JavaScript

// docs-guard-exempt: this file's own header comment states docs/ is deliberately OUT of scope for its citation scan.
'use strict';
// allow-test-rule: source-text-is-the-product (#3576) — this gate reads shipped
// runtime-loaded .md files and asserts on their literal citation text; the text IS
// the deployed contract, so reading it is the behavior under test.
/**
* #3576 — dead-citation gate for the shipped trees.
*
* A backticked bare `references/<name>.md` cite resolves from NO install location:
* agents install to ~/.claude/agents/, workflows to ~/.claude/msd-core/workflows/,
* references to a sibling of workflows — a bare relative `references/` path is dead
* from every one of them. The canonical form (what every <required_reading> block
* and @~/ include already uses) is `msd-core/references/<file>.md`.
*
* #3206 fixed one file; PR #3435 swept agents/msd-verifier.md and stopped at its
* scope. This gate ends the class (epic #3473's B6 shape; #3518's drift guard is
* the precedent). Scope: the runtime-loaded trees the issue prescribes — agents/,
* msd-core/{workflows,references,templates,contexts}, commands/, capabilities/.
* docs/ (incl. translations) is deliberately OUT: human-facing, per-locale drift,
* ranked lower severity by the issue — the recorded remainder.
*
* The trap the issue names: a guard that skips whole LINES containing `@~/` misses
* a bare cite sharing a line with an include — strip only the `@~/…` token.
*/
const { describe, test } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const REPO_ROOT = path.join(__dirname, '..');
const SCAN_ROOTS = [
'agents',
'msd-core/workflows',
'msd-core/references',
'msd-core/templates',
'msd-core/contexts',
'commands',
'capabilities',
];
// A bare cite is BACKTICK-ANCHORED: `` `references/x.md` ``. The anchor is what
// excludes the genuinely relative href (`../references/…` — its backtick precedes
// `..`, not `references/`) and non-backticked prose mentions.
const BARE_CITE_RE = /`references\/([a-z0-9-]*\.md)`/g;
// The @~/ include token, stripped PER-TOKEN (never line-wise) before scanning.
const INCLUDE_TOKEN_RE = /@~\/[^\s`]+/g;
function walkShippedMarkdown() {
const files = [];
for (const root of SCAN_ROOTS) {
const rootDir = path.join(REPO_ROOT, root);
if (!fs.existsSync(rootDir)) continue;
// readdirSync returns platform-separated relative paths; normalize
// unconditionally (repo convention) so diagnostics read identically on Windows.
for (const f of fs.readdirSync(rootDir, { recursive: true })) {
const normalized = String(f).split(path.sep).join('/');
if (normalized.endsWith('.md')) files.push({ rel: `${root}/${normalized}`, abs: path.join(rootDir, f) });
}
}
return files;
}
/** Find bare cites in one document, after per-token @~/ stripping. */
function findBareCites(text) {
const stripped = text.replace(INCLUDE_TOKEN_RE, '');
const offenders = [];
let m;
while ((m = BARE_CITE_RE.exec(stripped)) !== null) {
offenders.push(`references/${m[1]}`);
}
return offenders;
}
/** Canonical `msd-core/references/<name>` cites (backticked) — targets must exist. */
function findCanonicalCites(text) {
const re = /`msd-core\/references\/([a-z0-9-]*\.md)`/g;
const found = [];
let m;
while ((m = re.exec(text)) !== null) found.push(m[1]);
return found;
}
describe('#3576 gate: shipped reference citations resolve', () => {
test('#3576 gate: no bare references/ cites across shipped trees', () => {
const offenders = [];
for (const { rel, abs } of walkShippedMarkdown()) {
// allow-test-rule: source-text-is-the-product (#3576) — shipped text is the runtime contract
const text = fs.readFileSync(abs, 'utf-8');
for (const cite of findBareCites(text)) {
offenders.push(`${rel}: \`${cite}\` — bare cite resolves from no install location; use \`msd-core/${cite}\``);
}
}
assert.deepEqual(
offenders,
[],
'Bare `references/<name>.md` cites are dead pointers at runtime (#3576). '
+ 'Rewrite to the canonical `msd-core/references/<file>.md` form:\n'
+ offenders.join('\n'),
);
});
test('#3576 gate: every canonical reference cite target exists on disk', () => {
const missing = [];
for (const { rel, abs } of walkShippedMarkdown()) {
// allow-test-rule: source-text-is-the-product (#3576) — shipped text is the runtime contract
const text = fs.readFileSync(abs, 'utf-8');
for (const name of findCanonicalCites(text)) {
if (!fs.existsSync(path.join(REPO_ROOT, 'msd-core', 'references', name))) {
missing.push(`${rel}: \`msd-core/references/${name}\` — target does not exist`);
}
}
}
assert.deepEqual(missing, [], 'Canonical cites must name files that exist:\n' + missing.join('\n'));
});
test('#3576 gate unit: @~/ token stripped per-token, never line-skipped; relative and canonical forms pass', () => {
const includePlusBare = 'Read @~/msd-core/references/tdd.md and `references/tdd.md` too';
assert.deepEqual(
findBareCites(includePlusBare),
['references/tdd.md'],
'a bare cite sharing a line with an @~/ include must still be flagged (the issue-named trap)',
);
assert.deepEqual(findBareCites('see `../references/mvp-concepts.md`'), [], 'genuinely relative href is not a bare cite');
assert.deepEqual(findBareCites('see `msd-core/references/tdd.md`'), [], 'canonical cite is not a bare cite');
assert.deepEqual(findBareCites('the references/ directory'), [], 'non-backticked prose mention is not a cite');
assert.deepEqual(findBareCites('Read @~/msd-core/references/tdd.md now'), [], 'a lone @~/ include line is clean after stripping');
});
});