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.
This commit is contained in:
Jakub Zych
2026-10-06 01:47:40 +02:00
parent fe069b2a56
commit a9a7a328e6
2763 changed files with 78465 additions and 78434 deletions

View File

@@ -3,10 +3,10 @@
/**
* tests/shadow-report.test.cjs — pure IR unit suite for
* `install-shadow-report.cts`'s `buildShadowReport` (#2873, epic #2866 Phase
* 4a — governed by `.gsd/phase/feat-2873-cross-scope-shadowing/40-design.md`).
* 4a — governed by `.msd/phase/feat-2873-cross-scope-shadowing/40-design.md`).
*
* Implements matrix section A (`buildShadowReport()`, rows A1-A24) and
* properties F1/F4 from `.gsd/phase/feat-2873-cross-scope-shadowing/50-test-matrix.md`.
* properties F1/F4 from `.msd/phase/feat-2873-cross-scope-shadowing/50-test-matrix.md`.
* The matrix's own "Suites" section names this file `install-shadow-report
* .test.cjs`; it is shipped as `shadow-report.test.cjs` instead so its
* `lint-test-file-count.cjs` prefix is `shadow` (0 files before this PR, at
@@ -43,10 +43,10 @@ const {
renderShadowReport,
sanitizeForRender,
SHADOW_REASON,
} = require('../gsd-core/bin/lib/install-shadow-report.cjs');
const { resolveScope } = require('../gsd-core/bin/lib/install-scope.cjs');
const { MANIFEST_NAME } = require('../gsd-core/bin/lib/installer-migrations.cjs');
const { resolveSpecRootReference } = require('../gsd-core/bin/lib/runtime-artifact-conversion.cjs');
} = require('../msd-core/bin/lib/install-shadow-report.cjs');
const { resolveScope } = require('../msd-core/bin/lib/install-scope.cjs');
const { MANIFEST_NAME } = require('../msd-core/bin/lib/installer-migrations.cjs');
const { resolveSpecRootReference } = require('../msd-core/bin/lib/runtime-artifact-conversion.cjs');
// ─── Fixture helpers (mirrors tests/installed-surface-resolver.test.cjs) ───
@@ -72,9 +72,9 @@ function baseOpts(home, cwd, overrides = {}) {
return { home, cwd, env: {}, existsSync: () => false, ...overrides };
}
/** `commands/gsd/*.md` stems shipped by the real repo — used so A1's "71
/** `commands/msd/*.md` stems shipped by the real repo — used so A1's "71
* entries" tracks the real roster instead of a hardcoded, driftable count. */
const REAL_COMMANDS_DIR = path.join(__dirname, '..', 'commands', 'gsd');
const REAL_COMMANDS_DIR = path.join(__dirname, '..', 'commands', 'msd');
const REAL_STEMS = fs.readdirSync(REAL_COMMANDS_DIR)
.filter((f) => f.endsWith('.md'))
.map((f) => f.slice(0, -3))
@@ -82,13 +82,13 @@ const REAL_STEMS = fs.readdirSync(REAL_COMMANDS_DIR)
function skillFilesFor(stems) {
const files = {};
for (const s of stems) files[`skills/gsd-${s}/SKILL.md`] = 'x';
for (const s of stems) files[`skills/msd-${s}/SKILL.md`] = 'x';
return files;
}
function commandFilesFor(stems) {
const files = {};
for (const s of stems) files[`commands/gsd-${s}.md`] = 'x';
for (const s of stems) files[`commands/msd-${s}.md`] = 'x';
return files;
}
@@ -115,7 +115,7 @@ describe('buildShadowReport — shape (A1-A6)', () => {
assert.strictEqual(report.triggers.length, REAL_STEMS.length);
assert.deepStrictEqual(report.winner, { kind: 'skills', scope: 'global' });
assert.deepStrictEqual(report.shadowedSide, { kind: 'commands', scope: 'local' });
assert.deepStrictEqual(report.triggers.map((t) => t.trigger).sort(), REAL_STEMS.map((s) => `gsd-${s}`));
assert.deepStrictEqual(report.triggers.map((t) => t.trigger).sort(), REAL_STEMS.map((s) => `msd-${s}`));
});
test('no report for a single scope, global only (A2)', () => {
@@ -163,8 +163,8 @@ describe('buildShadowReport — shape (A1-A6)', () => {
const cwd = '/fixture/a5-cwd';
const homes = scopeHomes('windsurf', home, cwd);
const byConfigHome = new Map([
[homes.global, manifest({ manifestVersion: 2, runtime: 'windsurf', scope: 'global', files: { 'agents/gsd-planner.md': 'a' } })],
[homes.local, manifest({ manifestVersion: 2, runtime: 'windsurf', scope: 'local', files: { 'workflows/gsd-plan-phase.md': 'a' } })],
[homes.global, manifest({ manifestVersion: 2, runtime: 'windsurf', scope: 'global', files: { 'agents/msd-planner.md': 'a' } })],
[homes.local, manifest({ manifestVersion: 2, runtime: 'windsurf', scope: 'local', files: { 'workflows/msd-plan-phase.md': 'a' } })],
]);
const report = buildShadowReport('windsurf', baseOpts(home, cwd, { readManifest: mkReadManifest(byConfigHome) }));
assert.strictEqual(report.shadowed, false);
@@ -405,8 +405,8 @@ describe('buildShadowReport — independence across calls (A18)', () => {
describe('buildShadowReport — production call shape (A19)', () => {
test('production call shape resolves, matches the injected-dep rows\' shape', (t) => {
const home = createTempDir('gsd-shadow-a19-home-');
const cwd = createTempDir('gsd-shadow-a19-cwd-');
const home = createTempDir('msd-shadow-a19-home-');
const cwd = createTempDir('msd-shadow-a19-cwd-');
t.after(() => { cleanup(home); cleanup(cwd); });
const globalDir = path.join(home, '.claude');
@@ -463,7 +463,7 @@ describe('buildShadowReport — per-scope truth filter (A21-A24)', () => {
const stems = ['plan-phase', 'milestone-complete', 'phase-create'];
const report = buildShadowReport('claude', coexistenceOpts(home, cwd, stems));
assert.strictEqual(report.shadowed, true);
assert.deepStrictEqual(report.triggers.map((t) => t.trigger).sort(), stems.map((s) => `gsd-${s}`).sort());
assert.deepStrictEqual(report.triggers.map((t) => t.trigger).sort(), stems.map((s) => `msd-${s}`).sort());
});
test('global strict superset of local (full vs core profile): only the intersection is reported (A22)', () => {
@@ -479,7 +479,7 @@ describe('buildShadowReport — per-scope truth filter (A21-A24)', () => {
assert.strictEqual(report.shadowed, true);
// Only 'a' is a REAL local artifact — 'b' and 'c' must never be reported
// as shadowed local commands; there is no local artifact for either.
assert.deepStrictEqual(report.triggers.map((t) => t.trigger), ['gsd-a']);
assert.deepStrictEqual(report.triggers.map((t) => t.trigger), ['msd-a']);
});
test('local has a stem global does not: not reported as shadowed (A23)', () => {
@@ -494,7 +494,7 @@ describe('buildShadowReport — per-scope truth filter (A21-A24)', () => {
assert.strictEqual(report.shadowed, true);
// 'z' exists ONLY at local (no global artifact "wins" it) — must not
// appear in the shadowed set at all.
assert.deepStrictEqual(report.triggers.map((t) => t.trigger), ['gsd-a']);
assert.deepStrictEqual(report.triggers.map((t) => t.trigger), ['msd-a']);
});
test('disjoint stem sets: shadowed is false (A24)', () => {
@@ -538,7 +538,7 @@ describe('buildShadowReport — property (F1)', () => {
// only reported when a real artifact exists at BOTH scopes.
const expectedShadowed = globalStems
.filter((s) => localStems.includes(s))
.map((s) => `gsd-${s}`)
.map((s) => `msd-${s}`)
.sort();
const actualShadowed = report.triggers.map((t) => t.trigger).sort();
assert.deepStrictEqual(actualShadowed, expectedShadowed);
@@ -667,19 +667,19 @@ describe('sanitizeForRender — properties (F2, F3)', () => {
});
// ─── E1-E12 — resolveSpecRootReference direct unit coverage ───────────────
// Matrix section E (`.gsd/phase/feat-2873-cross-scope-shadowing/50-test-matrix.md`).
// Matrix section E (`.msd/phase/feat-2873-cross-scope-shadowing/50-test-matrix.md`).
// Only the E13/E14 installed-output integration pair (in
// tests/install-runtime-artifacts.test.cjs) and F4's idempotence property
// (above) touched this exported function before this block — these rows
// exercise it DIRECTLY, one behavior at a time.
describe('resolveSpecRootReference — direct unit coverage (E1-E12)', () => {
test('global skill body: the include is replaced by the two-step imperative form naming both candidates (E1)', () => {
const body = '@~/.claude/gsd-core/workflows/plan-phase.md';
const body = '@~/.claude/msd-core/workflows/plan-phase.md';
const result = resolveSpecRootReference(body);
assert.notStrictEqual(result, body);
assert.ok(!result.startsWith('@'), 'the static @-include must be gone');
assert.ok(
result.includes('.claude/gsd-core/workflows/plan-phase.md') && result.includes('~/.claude/gsd-core/workflows/plan-phase.md'),
result.includes('.claude/msd-core/workflows/plan-phase.md') && result.includes('~/.claude/msd-core/workflows/plan-phase.md'),
`expected both the project-local and global candidate paths named in: ${JSON.stringify(result)}`,
);
});
@@ -691,7 +691,7 @@ describe('resolveSpecRootReference — direct unit coverage (E1-E12)', () => {
// config dir, never `~`, so this never has the `@~/.claude/` shape
// WORKFLOW_SPEC_ROOT_INCLUDE_RE requires in the first place — a genuine
// non-qualifying condition, not a hand-waved one.
const body = '@/Users/dev/myrepo/.claude/gsd-core/workflows/plan-phase.md';
const body = '@/Users/dev/myrepo/.claude/msd-core/workflows/plan-phase.md';
assert.strictEqual(resolveSpecRootReference(body), body);
});
@@ -699,14 +699,14 @@ describe('resolveSpecRootReference — direct unit coverage (E1-E12)', () => {
// Real literal shapes emitted for other runtimes (verified empirically
// against a real --cursor --global install): no `.claude/` segment at
// all, so none of them ever match the claude-only spec-root regex.
const cursorGlobal = '@$HOME/gsd-core/workflows/plan-phase.md';
const genericLocal = '@./gsd-core/workflows/plan-phase.md';
const cursorGlobal = '@$HOME/msd-core/workflows/plan-phase.md';
const genericLocal = '@./msd-core/workflows/plan-phase.md';
assert.strictEqual(resolveSpecRootReference(cursorGlobal), cursorGlobal);
assert.strictEqual(resolveSpecRootReference(genericLocal), genericLocal);
});
test('a references/ include is a different spec root and stays static (E4)', () => {
const body = '@~/.claude/gsd-core/references/ui-brand.md';
const body = '@~/.claude/msd-core/references/ui-brand.md';
assert.strictEqual(resolveSpecRootReference(body), body);
});
@@ -716,12 +716,12 @@ describe('resolveSpecRootReference — direct unit coverage (E1-E12)', () => {
});
test('an include inside a fenced code block is untouched, byte-identical (E6)', () => {
const body = ['```', '@~/.claude/gsd-core/workflows/plan-phase.md', '```'].join('\n');
const body = ['```', '@~/.claude/msd-core/workflows/plan-phase.md', '```'].join('\n');
assert.strictEqual(resolveSpecRootReference(body), body);
});
test('an include mentioned in inline backticks is untouched, byte-identical (E7)', () => {
const body = 'See `@~/.claude/gsd-core/workflows/plan-phase.md` for the spec.';
const body = 'See `@~/.claude/msd-core/workflows/plan-phase.md` for the spec.';
assert.strictEqual(resolveSpecRootReference(body), body);
});
@@ -732,24 +732,24 @@ describe('resolveSpecRootReference — direct unit coverage (E1-E12)', () => {
test('two independent workflow includes both resolve (E9)', () => {
const body = [
'@~/.claude/gsd-core/workflows/plan-phase.md',
'@~/.claude/gsd-core/workflows/execute-phase.md',
'@~/.claude/msd-core/workflows/plan-phase.md',
'@~/.claude/msd-core/workflows/execute-phase.md',
].join('\n');
const result = resolveSpecRootReference(body);
assert.ok(!result.includes('@~/.claude/gsd-core/workflows/plan-phase.md'));
assert.ok(!result.includes('@~/.claude/gsd-core/workflows/execute-phase.md'));
assert.ok(result.includes('.claude/gsd-core/workflows/plan-phase.md'));
assert.ok(result.includes('.claude/gsd-core/workflows/execute-phase.md'));
assert.ok(!result.includes('@~/.claude/msd-core/workflows/plan-phase.md'));
assert.ok(!result.includes('@~/.claude/msd-core/workflows/execute-phase.md'));
assert.ok(result.includes('.claude/msd-core/workflows/plan-phase.md'));
assert.ok(result.includes('.claude/msd-core/workflows/execute-phase.md'));
});
test('prose merely mentioning gsd-core/workflows/x.md is untouched (E10)', () => {
const body = 'See gsd-core/workflows/plan-phase.md for background on how this works.';
test('prose merely mentioning msd-core/workflows/x.md is untouched (E10)', () => {
const body = 'See msd-core/workflows/plan-phase.md for background on how this works.';
assert.strictEqual(resolveSpecRootReference(body), body);
});
test('a CRLF body emits identically to LF, no orphaned \\r (E11)', () => {
const bodyLf = '@~/.claude/gsd-core/workflows/plan-phase.md\nSecond line.';
const bodyCrlf = '@~/.claude/gsd-core/workflows/plan-phase.md\r\nSecond line.';
const bodyLf = '@~/.claude/msd-core/workflows/plan-phase.md\nSecond line.';
const bodyCrlf = '@~/.claude/msd-core/workflows/plan-phase.md\r\nSecond line.';
const resultLf = resolveSpecRootReference(bodyLf);
const resultCrlf = resolveSpecRootReference(bodyCrlf);
assert.strictEqual(resultCrlf, resultLf.replace('\n', '\r\n'));
@@ -760,7 +760,7 @@ describe('resolveSpecRootReference — direct unit coverage (E1-E12)', () => {
});
test('applying the transform twice over an installed tree is idempotent (E12)', () => {
const body = 'intro\n@~/.claude/gsd-core/workflows/plan-phase.md\noutro';
const body = 'intro\n@~/.claude/msd-core/workflows/plan-phase.md\noutro';
const once = resolveSpecRootReference(body);
const twice = resolveSpecRootReference(once);
assert.strictEqual(twice, once);
@@ -780,9 +780,9 @@ describe('resolveSpecRootReference — unit (fence detection, #2873 review Findi
test('mismatched fence types (``` opened, ~~~ inside, ``` closes) leave BOTH includes untouched', () => {
const body = [
'```',
'@~/.claude/gsd-core/workflows/alpha.md',
'@~/.claude/msd-core/workflows/alpha.md',
'~~~',
'@~/.claude/gsd-core/workflows/beta.md',
'@~/.claude/msd-core/workflows/beta.md',
'```',
].join('\n');
@@ -796,7 +796,7 @@ describe('resolveSpecRootReference — unit (fence detection, #2873 review Findi
const body = [
'````',
'```',
'@~/.claude/gsd-core/workflows/nested.md',
'@~/.claude/msd-core/workflows/nested.md',
'```',
'````',
].join('\n');
@@ -809,7 +809,7 @@ describe('resolveSpecRootReference — unit (fence detection, #2873 review Findi
test('an unterminated fence covers to end-of-string, leaving the include untouched', () => {
const body = [
'```',
'@~/.claude/gsd-core/workflows/orphan.md',
'@~/.claude/msd-core/workflows/orphan.md',
].join('\n');
const result = resolveSpecRootReference(body);
@@ -820,9 +820,9 @@ describe('resolveSpecRootReference — unit (fence detection, #2873 review Findi
test('a fence opened with a longer run (````) is NOT closed by a shorter run (```)', () => {
const body = [
'````',
'@~/.claude/gsd-core/workflows/longshort.md',
'@~/.claude/msd-core/workflows/longshort.md',
'```',
'@~/.claude/gsd-core/workflows/other.md',
'@~/.claude/msd-core/workflows/other.md',
'````',
].join('\n');
@@ -841,7 +841,7 @@ describe('resolveSpecRootReference — unit (fence detection, #2873 review Findi
describe('resolveSpecRootReference — property (F4)', () => {
test('spec-root transform is idempotent over arbitrary bodies', () => {
// A bare fc.string() body would almost never contain the exact
// `@~/.claude/gsd-core/workflows/<stem>.md` shape `resolveSpecRootReference`
// `@~/.claude/msd-core/workflows/<stem>.md` shape `resolveSpecRootReference`
// matches, making the property vacuous (see this suite's F4 comment and
// CONTRIBUTING's writer-seeded-vs-document-shaped generator guidance).
// Instead, bodies are assembled from chunks that actually exercise every
@@ -849,14 +849,14 @@ describe('resolveSpecRootReference — property (F4)', () => {
// block wrapping the SAME include shape (left untouched — Claude Code
// documents backticks as the way to prevent an `@`-import), a
// `@.planning/…` include (a different spec root, untouched), plain prose
// that merely MENTIONS `gsd-core/workflows/<stem>.md` without the
// that merely MENTIONS `msd-core/workflows/<stem>.md` without the
// line-start `@` (untouched), and arbitrary free text.
const stemArb = fc.stringMatching(/^[a-z][a-z0-9._-]{0,20}$/);
const includeLineArb = stemArb.map((s) => `@~/.claude/gsd-core/workflows/${s}.md`);
const proseMentionArb = stemArb.map((s) => `See gsd-core/workflows/${s}.md for background.`);
const includeLineArb = stemArb.map((s) => `@~/.claude/msd-core/workflows/${s}.md`);
const proseMentionArb = stemArb.map((s) => `See msd-core/workflows/${s}.md for background.`);
const planningIncludeArb = stemArb.map((s) => `@.planning/${s}.md`);
const fencedIncludeArb = fc.tuple(fc.constantFrom('```', '~~~'), stemArb).map(
([fence, s]) => `${fence}\n@~/.claude/gsd-core/workflows/${s}.md\n${fence}`,
([fence, s]) => `${fence}\n@~/.claude/msd-core/workflows/${s}.md\n${fence}`,
);
// #2873 review Finding 1: a same-type-only generator is structurally
// incapable of producing the mismatched-delimiter defect the review
@@ -870,13 +870,13 @@ describe('resolveSpecRootReference — property (F4)', () => {
stemArb,
).map(
([[openFence, midFence], s1, s2]) =>
`${openFence}\n@~/.claude/gsd-core/workflows/${s1}.md\n${midFence}\n@~/.claude/gsd-core/workflows/${s2}.md\n${openFence}`,
`${openFence}\n@~/.claude/msd-core/workflows/${s1}.md\n${midFence}\n@~/.claude/msd-core/workflows/${s2}.md\n${openFence}`,
);
const nestedFencedIncludeArb = fc.tuple(fc.constantFrom('```', '~~~'), stemArb).map(
([fenceChar, s]) => {
const inner = fenceChar.repeat(3);
const outer = fenceChar.repeat(4);
return `${outer}\n${inner}\n@~/.claude/gsd-core/workflows/${s}.md\n${inner}\n${outer}`;
return `${outer}\n${inner}\n@~/.claude/msd-core/workflows/${s}.md\n${inner}\n${outer}`;
},
);
const plainTextArb = fc.string({ maxLength: 40 });