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

@@ -18,8 +18,8 @@
* WRONG source and still be total. The spot-checks below pin the pairs where that
* is most likely, and ADR-2719 designates the Phase 3 (#2723) dual-run as the
* mitigation for the rest. Three real instances of that class were caught while
* building this table (Copilot's `<name>.agent.md` rename, Kimi's `agents/gsd.md`
* root agent, and Copilot's `hooks/gsd-session.json`), all of which passed totality
* building this table (Copilot's `<name>.agent.md` rename, Kimi's `agents/msd.md`
* root agent, and Copilot's `hooks/msd-session.json`), all of which passed totality
* while resolving to repo files that do not exist — which is why the
* "every attributed source exists" test below is a first-class gate, not a nicety.
*
@@ -139,22 +139,22 @@ test('every attributed source exists in the repo (identity/rewrite/derived rules
// ─── Spot-checks: known emitted/source pairs (#2722 "add spot-check tests") ──
test('spot-check: flat skill attributes to commands/gsd, NOT the generated repo skills/ dir', () => {
const got = attributeEmittedPath('skills/gsd-add-tests/SKILL.md', 'claude');
test('spot-check: flat skill attributes to commands/msd, NOT the generated repo skills/ dir', () => {
const got = attributeEmittedPath('skills/msd-add-tests/SKILL.md', 'claude');
assert.equal(got.ruleId, 'skills-from-commands');
assert.deepEqual(got.sources, [`${COMMANDS_SRC}/add-tests.md`]);
// The trap, asserted explicitly. The repo DOES contain
// skills/gsd-add-tests/SKILL.md, but scripts/gen-plugin-skills.cjs generates it
// from commands/gsd/add-tests.md — attributing to it would be false attribution
// skills/msd-add-tests/SKILL.md, but scripts/gen-plugin-skills.cjs generates it
// from commands/msd/add-tests.md — attributing to it would be false attribution
// that still passes totality.
assert.ok(
!got.sources.includes('skills/gsd-add-tests/SKILL.md'),
!got.sources.includes('skills/msd-add-tests/SKILL.md'),
'emitted skills must never attribute to the generated repo skills/ directory',
);
assert.ok(
fs.existsSync(path.join(REPO_ROOT, 'skills', 'gsd-add-tests', 'SKILL.md')),
fs.existsSync(path.join(REPO_ROOT, 'skills', 'msd-add-tests', 'SKILL.md')),
'precondition: the generated repo skills/ dir exists, which is why the trap is live',
);
});
@@ -162,7 +162,7 @@ test('spot-check: flat skill attributes to commands/gsd, NOT the generated repo
test('spot-check: nested skill attributes to its child stem, not its router', () => {
// augment is a real nested-layout host (#69); the key below is verbatim from
// tests/fixtures/golden-install-parity/augment.json, not a constructed path.
const nested = attributeEmittedPath('skills/gsd-ns-manage/skills/config/SKILL.md', 'augment');
const nested = attributeEmittedPath('skills/msd-ns-manage/skills/config/SKILL.md', 'augment');
assert.equal(nested.ruleId, 'skills-nested-from-commands');
assert.deepEqual(nested.sources, [`${COMMANDS_SRC}/config.md`]);
assert.ok(
@@ -171,7 +171,7 @@ test('spot-check: nested skill attributes to its child stem, not its router', ()
);
// The router itself is a normal flat skill and resolves to its own stem.
const router = attributeEmittedPath('skills/gsd-ns-manage/SKILL.md', 'augment');
const router = attributeEmittedPath('skills/msd-ns-manage/SKILL.md', 'augment');
assert.equal(router.ruleId, 'skills-from-commands');
assert.deepEqual(router.sources, [`${COMMANDS_SRC}/ns-manage.md`]);
});
@@ -179,31 +179,31 @@ test('spot-check: nested skill attributes to its child stem, not its router', ()
test('spot-check: alternate skills roots (hermes category, codex .agents) strip correctly', () => {
// Every key here is verbatim from the named runtime's committed manifest.
assert.deepEqual(
attributeEmittedPath('skills/gsd/gsd-ns-context/SKILL.md', 'hermes').sources,
attributeEmittedPath('skills/msd/msd-ns-context/SKILL.md', 'hermes').sources,
[`${COMMANDS_SRC}/ns-context.md`],
);
assert.deepEqual(
attributeEmittedPath('skills/gsd/gsd-ns-context/skills/docs-update/SKILL.md', 'hermes').sources,
attributeEmittedPath('skills/msd/msd-ns-context/skills/docs-update/SKILL.md', 'hermes').sources,
[`${COMMANDS_SRC}/docs-update.md`],
);
// codex — NOT antigravity: codex's skills kind carries a `home` override to
// $HOME/.agents/skills (ADR-1239 upgrade 3 / #2088), which is why its emitted
// skills sit under `.agents/skills/` rather than `skills/`.
assert.deepEqual(
attributeEmittedPath('.agents/skills/gsd-add-tests/SKILL.md', 'codex').sources,
attributeEmittedPath('.agents/skills/msd-add-tests/SKILL.md', 'codex').sources,
[`${COMMANDS_SRC}/add-tests.md`],
);
});
test('spot-check: nativePlugin source is per-runtime, read from the descriptor', () => {
const opencode = attributeEmittedPath('plugins/gsd-core.js', 'opencode');
const kilo = attributeEmittedPath('plugins/gsd-core.js', 'kilo');
const pi = attributeEmittedPath('extensions/gsd.js', 'pi');
const opencode = attributeEmittedPath('plugins/msd-core.js', 'opencode');
const kilo = attributeEmittedPath('plugins/msd-core.js', 'kilo');
const pi = attributeEmittedPath('extensions/msd.js', 'pi');
assert.equal(opencode.ruleId, 'native-plugin');
assert.deepEqual(opencode.sources, ['.opencode/plugins/gsd-core.js']);
assert.deepEqual(kilo.sources, ['.kilo/plugins/gsd-core.js']);
assert.deepEqual(pi.sources, ['pi/gsd.cjs']);
assert.deepEqual(opencode.sources, ['.opencode/plugins/msd-core.js']);
assert.deepEqual(kilo.sources, ['.kilo/plugins/msd-core.js']);
assert.deepEqual(pi.sources, ['pi/msd.cjs']);
// Independence: the SAME emitted key resolves differently per host. A design
// keyed on `rel` alone would silently give kilo opencode's source.
@@ -216,41 +216,41 @@ test('spot-check: nativePlugin source is per-runtime, read from the descriptor',
test('spot-check: agents identity, Copilot rename, Codex toml, and Kimi subagent derivation', () => {
assert.deepEqual(
attributeEmittedPath('agents/gsd-planner.md', 'claude').sources,
['agents/gsd-planner.md'],
attributeEmittedPath('agents/msd-planner.md', 'claude').sources,
['agents/msd-planner.md'],
);
// Copilot renames to <name>.agent.md — attributing that as identity resolved to
// a file that does not exist (real bug found by the source-existence gate).
assert.deepEqual(
attributeEmittedPath('agents/gsd-planner.agent.md', 'copilot').sources,
['agents/gsd-planner.md'],
attributeEmittedPath('agents/msd-planner.agent.md', 'copilot').sources,
['agents/msd-planner.md'],
);
assert.deepEqual(
attributeEmittedPath('agents/gsd-planner.toml', 'codex').sources,
['agents/gsd-planner.md'],
attributeEmittedPath('agents/msd-planner.toml', 'codex').sources,
['agents/msd-planner.md'],
);
// Two emitted paths sharing one source is legal; one path matching two rules is not.
const yaml = attributeEmittedPath('agents/subagents/gsd-planner.yaml', 'kimi');
const md = attributeEmittedPath('agents/subagents/gsd-planner.md', 'kimi');
assert.deepEqual(yaml.sources, ['agents/gsd-planner.md']);
const yaml = attributeEmittedPath('agents/subagents/msd-planner.yaml', 'kimi');
const md = attributeEmittedPath('agents/subagents/msd-planner.md', 'kimi');
assert.deepEqual(yaml.sources, ['agents/msd-planner.md']);
assert.deepEqual(md.sources, yaml.sources);
});
test('spot-check: Kimi root agent is code-derived, not a repo agent file', () => {
const rootYaml = attributeEmittedPath('agents/gsd.yaml', 'kimi');
const rootYaml = attributeEmittedPath('agents/msd.yaml', 'kimi');
assert.equal(rootYaml.ruleId, 'kimi-root-agent');
assert.equal(rootYaml.kind, 'code-derived');
// Built from a literal AND an enumeration of every staged agent, so both are
// declared; the trailing-slash entry is a prefix, not a file.
assert.ok(rootYaml.sources.includes(KIMI_ROOT_AGENT_SRC));
assert.ok(rootYaml.sources.includes('agents/'));
assert.deepEqual(attributeEmittedPath('agents/gsd.md', 'kimi').ruleId, 'kimi-root-agent');
assert.deepEqual(attributeEmittedPath('agents/msd.md', 'kimi').ruleId, 'kimi-root-agent');
});
test('spot-check: hooks attribute to repo source, not the dist build artifact', () => {
assert.deepEqual(
attributeEmittedPath('hooks/gsd-statusline.js', 'claude').sources,
['hooks/gsd-statusline.js'],
attributeEmittedPath('hooks/msd-statusline.js', 'claude').sources,
['hooks/msd-statusline.js'],
);
assert.deepEqual(
attributeEmittedPath('hooks/lib/git-cmd.js', 'claude').sources,
@@ -258,11 +258,11 @@ test('spot-check: hooks attribute to repo source, not the dist build artifact',
);
// Kimi installs the same bundle under its own hooks root.
assert.deepEqual(
attributeEmittedPath('.kimi/hooks/gsd-statusline.js', 'kimi').sources,
['hooks/gsd-statusline.js'],
attributeEmittedPath('.kimi/hooks/msd-statusline.js', 'kimi').sources,
['hooks/msd-statusline.js'],
);
// Copilot's hook REGISTRATION json is a code literal, not a built script.
const reg = attributeEmittedPath('hooks/gsd-session.json', 'copilot');
const reg = attributeEmittedPath('hooks/msd-session.json', 'copilot');
assert.equal(reg.ruleId, 'copilot-hook-registration');
assert.deepEqual(reg.sources, [CLINE_BODY_SRC]);
});
@@ -291,7 +291,7 @@ test('spot-check: Windows-only .cmd shim is code-derived from its generator, not
// its content never does. `sources` must therefore point at the SAME file as
// `transforms` (HOOKS_WINDOWS_SHIM_SRC) — the `code-derived` shape used elsewhere
// in this table — not at the wrapped script.
for (const name of ['gsd-check-update', 'gsd-context-monitor']) {
for (const name of ['msd-check-update', 'msd-context-monitor']) {
const got = attributeEmittedPath(`hooks/${name}.cmd`, 'codex');
assert.equal(got.ruleId, 'hooks-built');
assert.deepEqual(got.sources, [HOOKS_WINDOWS_SHIM_SRC]);
@@ -313,13 +313,13 @@ test('spot-check: Windows-only .cmd shim is code-derived from its generator, not
// A plain (non-.cmd) hook is unaffected: still a straight identity-shaped copy
// sourced from the repo hook it was built from, still no transform (the shim
// generator cannot move a plain hook's bytes).
const plain = attributeEmittedPath('hooks/gsd-statusline.js', 'claude');
assert.deepEqual(plain.sources, ['hooks/gsd-statusline.js']);
const plain = attributeEmittedPath('hooks/msd-statusline.js', 'claude');
assert.deepEqual(plain.sources, ['hooks/msd-statusline.js']);
assert.deepEqual(plain.transforms, []);
});
test('spot-check: cline rules are code-derived (attributable), not exempt', () => {
for (const rel of ['.clinerules/gsd.md', '.clinerules/hooks/PreToolUse']) {
for (const rel of ['.clinerules/msd.md', '.clinerules/hooks/PreToolUse']) {
const got = attributeEmittedPath(rel, 'cline');
assert.equal(got.kind, 'code-derived', `${rel} must stay attributable`);
assert.deepEqual(got.sources, [CLINE_BODY_SRC]);
@@ -332,9 +332,9 @@ test('spot-check: cline rules are code-derived (attributable), not exempt', () =
test('spot-check: install-time state is exempt with an empty source list', () => {
for (const [rel, rt] of [
['.gsd-profile', 'claude'],
['gsd-core/VERSION', 'claude'],
['gsd-core/.gsd-runtime', 'claude'],
['.msd-profile', 'claude'],
['msd-core/VERSION', 'claude'],
['msd-core/.msd-runtime', 'claude'],
['package.json', 'opencode'],
['opencode.json', 'opencode'],
]) {
@@ -347,35 +347,35 @@ test('spot-check: install-time state is exempt with an empty source list', () =>
// ─── Transforms (#2757): derived rules can declare a transform-code source ───
test('agents-toml-derived declares AGENT_TRANSFORM_SRCS as transforms', () => {
const got = attributeEmittedPath('agents/gsd-planner.toml', 'codex');
const got = attributeEmittedPath('agents/msd-planner.toml', 'codex');
assert.equal(got.kind, 'derived');
assert.deepEqual(got.sources, ['agents/gsd-planner.md']);
assert.deepEqual(got.sources, ['agents/msd-planner.md']);
assert.deepEqual(got.transforms, AGENT_TRANSFORM_SRCS);
});
test('agents-verbatim is reclassified to derived with the same transforms, sources unchanged', () => {
const got = attributeEmittedPath('agents/gsd-planner.md', 'claude');
const got = attributeEmittedPath('agents/msd-planner.md', 'claude');
assert.equal(got.kind, 'derived', 'no runtime emits a byte-identical copy — see #2757 design doc');
assert.deepEqual(got.sources, ['agents/gsd-planner.md'], 'sources must be unchanged by the reclassification');
assert.deepEqual(got.sources, ['agents/msd-planner.md'], 'sources must be unchanged by the reclassification');
assert.deepEqual(got.transforms, AGENT_TRANSFORM_SRCS);
});
test('#4482 runtime-note-filtered command and skill surfaces declare their converter transform', () => {
const command = attributeEmittedPath('commands/gsd-plan-phase.md', 'opencode');
const skill = attributeEmittedPath('skills/gsd-plan-phase/SKILL.md', 'opencode');
const workflow = attributeEmittedPath('gsd-core/workflows/mvp-phase.md', 'opencode');
const command = attributeEmittedPath('commands/msd-plan-phase.md', 'opencode');
const skill = attributeEmittedPath('skills/msd-plan-phase/SKILL.md', 'opencode');
const workflow = attributeEmittedPath('msd-core/workflows/mvp-phase.md', 'opencode');
assert.deepEqual(command.transforms, RUNTIME_NOTE_FILTER_TRANSFORM_SRCS);
assert.deepEqual(skill.transforms, RUNTIME_NOTE_FILTER_TRANSFORM_SRCS);
assert.deepEqual(workflow.transforms, RUNTIME_NOTE_FILTER_TRANSFORM_SRCS);
assert.deepEqual(attributeEmittedPath('commands/gsd-plan-phase.md', 'kilo').transforms, RUNTIME_NOTE_FILTER_TRANSFORM_SRCS);
assert.deepEqual(attributeEmittedPath('skills/gsd-plan-phase/SKILL.md', 'cursor').transforms, RUNTIME_NOTE_FILTER_TRANSFORM_SRCS);
assert.deepEqual(attributeEmittedPath('gsd-core/workflows/mvp-phase.md', 'claude-local').transforms, RUNTIME_NOTE_FILTER_TRANSFORM_SRCS);
assert.deepEqual(attributeEmittedPath('gsd-core/workflows/mvp-phase.md', 'copilot').transforms, []);
assert.deepEqual(attributeEmittedPath('commands/msd-plan-phase.md', 'kilo').transforms, RUNTIME_NOTE_FILTER_TRANSFORM_SRCS);
assert.deepEqual(attributeEmittedPath('skills/msd-plan-phase/SKILL.md', 'cursor').transforms, RUNTIME_NOTE_FILTER_TRANSFORM_SRCS);
assert.deepEqual(attributeEmittedPath('msd-core/workflows/mvp-phase.md', 'claude-local').transforms, RUNTIME_NOTE_FILTER_TRANSFORM_SRCS);
assert.deepEqual(attributeEmittedPath('msd-core/workflows/mvp-phase.md', 'copilot').transforms, []);
});
test('a rule with no transforms field still returns an empty array, never undefined', () => {
const got = attributeEmittedPath('agents/gsd-planner.agent.md', 'copilot');
const got = attributeEmittedPath('agents/msd-planner.agent.md', 'copilot');
assert.deepEqual(got.transforms, [], 'absence of transforms must be a stable empty array, not undefined');
});
@@ -477,7 +477,7 @@ test('assertNoIdentityTransforms names only the offending rule, not unrelated va
));
assert.throws(
() => assertNoIdentityTransforms(corrupted),
(err) => !err.message.includes('gsd-core-verbatim'),
(err) => !err.message.includes('msd-core-verbatim'),
'an unrelated valid identity rule must not be named',
);
});
@@ -487,7 +487,7 @@ test('a derived rule may declare an empty transforms array with no special meani
r.id === 'agents-toml-derived' ? { ...r, transforms: [] } : r
));
assert.doesNotThrow(() => assertNoIdentityTransforms(withEmpty));
const got = attributeEmittedPath('agents/gsd-planner.toml', 'codex', withEmpty);
const got = attributeEmittedPath('agents/msd-planner.toml', 'codex', withEmpty);
assert.deepEqual(got.transforms, []);
});
@@ -538,18 +538,18 @@ test('dead rule is reported as drift', () => {
test('removing a rule fails the guard with the unmatched paths named', () => {
// #2722 acceptance criterion, verbatim: "Removing any rule fails the guard with
// the unmatched paths named."
const without = PROVENANCE_RULES.filter((r) => r.id !== 'gsd-core-verbatim');
const without = PROVENANCE_RULES.filter((r) => r.id !== 'msd-core-verbatim');
assert.throws(
() => assertTotality(manifests(), without),
(err) => {
assert.match(err.message, /match no provenance rule/);
// A count is reported, and it is the real one — 5,510 gsd-core paths across
// A count is reported, and it is the real one — 5,510 msd-core paths across
// 19 manifests, not the 10 the message samples.
const m = err.message.match(/(\d+) emitted path\(s\) match no provenance rule/);
assert.ok(m, 'the failure must report how many paths went unattributed');
assert.ok(Number(m[1]) > 5000, `expected the full gsd-core corpus, got ${m[1]}`);
assert.ok(Number(m[1]) > 5000, `expected the full msd-core corpus, got ${m[1]}`);
// Named samples are real emitted paths from the removed rule's family.
assert.match(err.message, /gsd-core\//);
assert.match(err.message, /msd-core\//);
return true;
},
'removing a rule must name the now-unmatched paths and report a count',
@@ -575,8 +575,8 @@ test('wrong-source rule is caught by the spot-check, not by totality', () => {
// rule.sources() and re-deriving the expected value would only re-implement the
// assertion, proving nothing about the shipped code path — the injectable
// `rules` seam is what makes this an actual demonstration.
const got = attributeEmittedPath('skills/gsd-add-tests/SKILL.md', 'claude', corrupted);
assert.deepEqual(got.sources, ['skills/gsd-add-tests/SKILL.md']);
const got = attributeEmittedPath('skills/msd-add-tests/SKILL.md', 'claude', corrupted);
assert.deepEqual(got.sources, ['skills/msd-add-tests/SKILL.md']);
assert.notDeepEqual(
got.sources,
[`${COMMANDS_SRC}/add-tests.md`],
@@ -584,7 +584,7 @@ test('wrong-source rule is caught by the spot-check, not by totality', () => {
);
// The uncorrupted table, same path, same call — the difference IS the spot-check.
assert.deepEqual(
attributeEmittedPath('skills/gsd-add-tests/SKILL.md', 'claude').sources,
attributeEmittedPath('skills/msd-add-tests/SKILL.md', 'claude').sources,
[`${COMMANDS_SRC}/add-tests.md`],
);
@@ -593,7 +593,7 @@ test('wrong-source rule is caught by the spot-check, not by totality', () => {
// generated dir). Existence catches a rule pointing at nothing; only a pinned
// known-pair catches a rule pointing at the wrong real thing.
assert.ok(
fs.existsSync(path.join(REPO_ROOT, 'skills', 'gsd-add-tests', 'SKILL.md')),
fs.existsSync(path.join(REPO_ROOT, 'skills', 'msd-add-tests', 'SKILL.md')),
'the wrong source exists, which is exactly why existence alone cannot catch it',
);
});
@@ -616,12 +616,12 @@ test('attributeEmittedPath throws on an ambiguous table, naming both rules', ()
});
test('emitted paths that could traverse out of the repo are rejected', () => {
// gsd-core-verbatim / scripts-verbatim capture a whole tail with `.+`, so without
// a guard `gsd-core/workflows/../../../etc/passwd` yields a source path that
// msd-core-verbatim / scripts-verbatim capture a whole tail with `.+`, so without
// a guard `msd-core/workflows/../../../etc/passwd` yields a source path that
// path.join(REPO_ROOT, src) resolves OUTSIDE the repo. Real manifest keys never
// traverse; Phase 3 feeds these strings into a diff-consuming check.
for (const bad of [
'gsd-core/workflows/../../../../etc/passwd',
'msd-core/workflows/../../../../etc/passwd',
'scripts/../../../etc/passwd',
'../escape.md',
]) {
@@ -635,9 +635,9 @@ test('emitted paths that could traverse out of the repo are rejected', () => {
assert.throws(() => attributeEmittedPath('', 'claude'), /non-empty string/);
// A dot-prefixed segment is NOT traversal — this must still resolve normally.
// #3547: '.gsd/defaults.json' left the manifests with the collapsed shape; a
// #3547: '.msd/defaults.json' left the manifests with the collapsed shape; a
// dot-prefixed STILL-EMITTED path serves the same not-traversal example.
assert.doesNotThrow(() => attributeEmittedPath('.gsd-profile', 'opencode'));
assert.doesNotThrow(() => attributeEmittedPath('.msd-profile', 'opencode'));
});
test('sampleLimit truncation is exact at limit-1 / limit / limit+1', () => {
@@ -674,7 +674,7 @@ test('rules match POSIX separators only', () => {
// Manifest keys are POSIX by construction (buildParityManifest joins on '/').
// A backslash key must NOT match — rules must never reach for path.sep.
assert.throws(
() => attributeEmittedPath('gsd-core\\workflows\\plan-phase.md', 'claude'),
() => attributeEmittedPath('msd-core\\workflows\\plan-phase.md', 'claude'),
/no rule matches/,
);
});
@@ -776,15 +776,15 @@ test('rule ids are unique', () => {
});
test('attribution is pure and repeatable on a second call', () => {
const first = attributeEmittedPath('skills/gsd-add-tests/SKILL.md', 'claude');
const second = attributeEmittedPath('skills/gsd-add-tests/SKILL.md', 'claude');
const first = attributeEmittedPath('skills/msd-add-tests/SKILL.md', 'claude');
const second = attributeEmittedPath('skills/msd-add-tests/SKILL.md', 'claude');
assert.deepEqual(second, first);
// The rule table itself must not have been mutated by matching.
assert.equal(PROVENANCE_RULES.length, new Set(PROVENANCE_RULES.map((r) => r.id)).size);
});
test('stripSkillPrefix handles prefixed and bare stems', () => {
assert.equal(stripSkillPrefix('gsd-add-tests'), 'add-tests');
assert.equal(stripSkillPrefix('msd-add-tests'), 'add-tests');
assert.equal(stripSkillPrefix('config'), 'config', 'nested child dirs are bare stems');
});