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:
@@ -8,13 +8,13 @@
|
||||
|
||||
/**
|
||||
* Failing-first regression tests for #3409 (design:
|
||||
* .gsd/phase/feat-3409-unreachable-shell-guard-lint/40-design.md; matrix:
|
||||
* .gsd/phase/feat-3409-unreachable-shell-guard-lint/50-test-matrix.md,
|
||||
* .msd/phase/feat-3409-unreachable-shell-guard-lint/40-design.md; matrix:
|
||||
* .msd/phase/feat-3409-unreachable-shell-guard-lint/50-test-matrix.md,
|
||||
* section "Regression — the three defects this PR fixes", rows G1-G4).
|
||||
*
|
||||
* Root cause (40-design.md): `gsd-tools.cjs`'s `--pick <field>` extractor
|
||||
* Root cause (40-design.md): `msd-tools.cjs`'s `--pick <field>` extractor
|
||||
* coerces a missing/absent field to the empty string and exits 0. So
|
||||
* `X=$(gsd_run query V --pick F 2>/dev/null || echo D)` can NEVER reach its
|
||||
* `X=$(msd_run query V --pick F 2>/dev/null || echo D)` can NEVER reach its
|
||||
* `|| echo D` arm on field absence — only on a typo in the verb name. Three
|
||||
* shipped shell guards silently rely on that unreachable arm:
|
||||
*
|
||||
@@ -46,9 +46,9 @@
|
||||
* `extractFencedBashAfterAnchor` / `extractAssignmentBlockFor`) and executes it
|
||||
* with `runHook(..., { interpreter: 'bash' })`
|
||||
* (`tests/helpers/process-seam.cjs`), against a temp project fixture, driving
|
||||
* the real CLI at `gsd-core/bin/gsd-tools.cjs` through the real `gsd_run`
|
||||
* the real CLI at `msd-core/bin/msd-tools.cjs` through the real `msd_run`
|
||||
* shell function sourced from the shipped
|
||||
* `gsd-core/workflows/_runtime-launcher.snippet.sh` preamble.
|
||||
* `msd-core/workflows/_runtime-launcher.snippet.sh` preamble.
|
||||
*/
|
||||
|
||||
const { test, describe } = require('node:test');
|
||||
@@ -61,10 +61,10 @@ const { runHook, OUTCOME } = require('./helpers/process-seam.cjs');
|
||||
const { HOOK_FANOUT_TIMEOUT_MS } = require('./helpers/timeouts.cjs');
|
||||
|
||||
const REPO_ROOT = path.join(__dirname, '..');
|
||||
const PLAN_PHASE_PATH = path.join(REPO_ROOT, 'gsd-core', 'workflows', 'plan-phase.md');
|
||||
const COMPLETE_MILESTONE_PATH = path.join(REPO_ROOT, 'gsd-core', 'workflows', 'complete-milestone.md');
|
||||
const LAUNCHER_PATH = path.join(REPO_ROOT, 'gsd-core', 'workflows', '_runtime-launcher.snippet.sh');
|
||||
const GSD_TOOLS_PATH = path.join(REPO_ROOT, 'gsd-core', 'bin', 'gsd-tools.cjs');
|
||||
const PLAN_PHASE_PATH = path.join(REPO_ROOT, 'msd-core', 'workflows', 'plan-phase.md');
|
||||
const COMPLETE_MILESTONE_PATH = path.join(REPO_ROOT, 'msd-core', 'workflows', 'complete-milestone.md');
|
||||
const LAUNCHER_PATH = path.join(REPO_ROOT, 'msd-core', 'workflows', '_runtime-launcher.snippet.sh');
|
||||
const MSD_TOOLS_PATH = path.join(REPO_ROOT, 'msd-core', 'bin', 'msd-tools.cjs');
|
||||
|
||||
// A `cat`-under-blocked-stdin hang (G4) must be bounded well under this, but
|
||||
// give the CI-shape headroom PROBE_TIMEOUT_MS documents for a short CLI call.
|
||||
@@ -142,7 +142,7 @@ function extractAssignmentBlockFor(content, prefix, sourcePath) {
|
||||
* @param {object} [options] - forwarded to runHook (cwd, env, timeoutMs).
|
||||
*/
|
||||
function runBashScript(t, script, options = {}) {
|
||||
const scriptDir = createTempDir('gsd-3409-sh-');
|
||||
const scriptDir = createTempDir('msd-3409-sh-');
|
||||
t.after(() => cleanup(scriptDir));
|
||||
const scriptPath = path.join(scriptDir, 'script.sh');
|
||||
fs.writeFileSync(scriptPath, `#!/usr/bin/env bash\nset -e\n${script}`, { mode: 0o755 });
|
||||
@@ -175,7 +175,7 @@ function parseKeyValueStdout(stdout) {
|
||||
* (G2) case needs a nonzero prior-summary count.
|
||||
*/
|
||||
function buildPhase01Fixture({ withSummary }) {
|
||||
const root = createTempDir('gsd-3409-fixture-');
|
||||
const root = createTempDir('msd-3409-fixture-');
|
||||
const phaseDir = path.join(root, '.planning', 'phases', '01-foundation');
|
||||
fs.mkdirSync(phaseDir, { recursive: true });
|
||||
if (withSummary) {
|
||||
@@ -198,8 +198,8 @@ describe('#3409 G1/G2 — plan-phase.md Walking Skeleton gate observes a real su
|
||||
const script = [
|
||||
`. "${LAUNCHER_PATH}"`,
|
||||
snippet,
|
||||
'echo "GSD_TEST_WALKING_SKELETON=$WALKING_SKELETON"',
|
||||
'echo "GSD_TEST_PRIOR_SUMMARIES=$PRIOR_SUMMARIES"',
|
||||
'echo "MSD_TEST_WALKING_SKELETON=$WALKING_SKELETON"',
|
||||
'echo "MSD_TEST_PRIOR_SUMMARIES=$PRIOR_SUMMARIES"',
|
||||
].join('\n');
|
||||
const result = runBashScript(t, script, {
|
||||
cwd: projectRoot,
|
||||
@@ -210,7 +210,7 @@ describe('#3409 G1/G2 — plan-phase.md Walking Skeleton gate observes a real su
|
||||
padded_phase: '01',
|
||||
},
|
||||
// Bash FAN-OUT: the sourced `_runtime-launcher.snippet.sh` preamble
|
||||
// defines the real `gsd_run` function, which the extracted snippet
|
||||
// defines the real `msd_run` function, which the extracted snippet
|
||||
// then calls — a bash + node invocation, not a single CLI probe. Same
|
||||
// class as the observed CI failures in
|
||||
// tests/quick-branching.test.cjs (PR #3787 run 32668773524) and
|
||||
@@ -227,20 +227,20 @@ describe('#3409 G1/G2 — plan-phase.md Walking Skeleton gate observes a real su
|
||||
test('G1: zero prior summaries — the gate observes a real integer 0, and fires', (t) => {
|
||||
const root = buildPhase01Fixture({ withSummary: false });
|
||||
t.after(() => cleanup(root));
|
||||
const { GSD_TEST_WALKING_SKELETON, GSD_TEST_PRIOR_SUMMARIES } = runWalkingSkeletonGate(t, root);
|
||||
const { MSD_TEST_WALKING_SKELETON, MSD_TEST_PRIOR_SUMMARIES } = runWalkingSkeletonGate(t, root);
|
||||
|
||||
// RED on the current tree: `--pick summaries_total` names a field that
|
||||
// does not exist, so gsd-tools exits 0 with EMPTY stdout and the
|
||||
// does not exist, so msd-tools exits 0 with EMPTY stdout and the
|
||||
// unreachable `|| echo "0"` arm never fires — PRIOR_SUMMARIES is `""`,
|
||||
// not the integer `"0"` this asserts.
|
||||
assert.equal(GSD_TEST_PRIOR_SUMMARIES, '0', 'prior-summary count must resolve to the integer 0, not empty string');
|
||||
assert.equal(GSD_TEST_WALKING_SKELETON, 'true', 'a fresh phase-01 project must enter Walking Skeleton mode');
|
||||
assert.equal(MSD_TEST_PRIOR_SUMMARIES, '0', 'prior-summary count must resolve to the integer 0, not empty string');
|
||||
assert.equal(MSD_TEST_WALKING_SKELETON, 'true', 'a fresh phase-01 project must enter Walking Skeleton mode');
|
||||
});
|
||||
|
||||
test('G2 (load-bearing negative space): a project WITH prior summaries does not enter skeleton mode', (t) => {
|
||||
const root = buildPhase01Fixture({ withSummary: true });
|
||||
t.after(() => cleanup(root));
|
||||
const { GSD_TEST_WALKING_SKELETON, GSD_TEST_PRIOR_SUMMARIES } = runWalkingSkeletonGate(t, root);
|
||||
const { MSD_TEST_WALKING_SKELETON, MSD_TEST_PRIOR_SUMMARIES } = runWalkingSkeletonGate(t, root);
|
||||
|
||||
// RED on the current tree: PRIOR_SUMMARIES is `""` here too (same
|
||||
// unreachable-arm defect), which fails this integer check even though
|
||||
@@ -250,18 +250,18 @@ describe('#3409 G1/G2 — plan-phase.md Walking Skeleton gate observes a real su
|
||||
// WALKING_SKELETON fire unconditionally, which the second assertion
|
||||
// below also catches.
|
||||
assert.match(
|
||||
GSD_TEST_PRIOR_SUMMARIES,
|
||||
MSD_TEST_PRIOR_SUMMARIES,
|
||||
/^[1-9][0-9]*$/,
|
||||
`prior-summary count must resolve to a nonzero integer, got ${JSON.stringify(GSD_TEST_PRIOR_SUMMARIES)}`,
|
||||
`prior-summary count must resolve to a nonzero integer, got ${JSON.stringify(MSD_TEST_PRIOR_SUMMARIES)}`,
|
||||
);
|
||||
assert.equal(GSD_TEST_WALKING_SKELETON, 'false', 'a project with prior summaries must NOT enter Walking Skeleton mode');
|
||||
assert.equal(MSD_TEST_WALKING_SKELETON, 'false', 'a project with prior summaries must NOT enter Walking Skeleton mode');
|
||||
});
|
||||
});
|
||||
|
||||
// ─── G3 — PHASE_REQ_IDS falls back to TBD (plan-phase.md) ─────────────────
|
||||
|
||||
test('#3409 G3: an empty phase_req_ids falls back to TBD, not the empty string', (t) => {
|
||||
const root = createTempDir('gsd-3409-g3-');
|
||||
const root = createTempDir('msd-3409-g3-');
|
||||
t.after(() => cleanup(root));
|
||||
fs.mkdirSync(path.join(root, '.planning', 'phases', '01-foundation'), { recursive: true });
|
||||
// Deliberately no REQUIREMENTS.md / ROADMAP.md — phase 01 with zero
|
||||
@@ -277,10 +277,10 @@ test('#3409 G3: an empty phase_req_ids falls back to TBD, not the empty string',
|
||||
const script = [
|
||||
`. "${LAUNCHER_PATH}"`,
|
||||
block,
|
||||
'echo "GSD_TEST_PHASE_REQ_IDS=$PHASE_REQ_IDS"',
|
||||
'echo "MSD_TEST_PHASE_REQ_IDS=$PHASE_REQ_IDS"',
|
||||
].join('\n');
|
||||
// Bash FAN-OUT: same class as runWalkingSkeletonGate above — the sourced
|
||||
// launcher's `gsd_run` shells out to node. See HOOK_FANOUT_TIMEOUT_MS in
|
||||
// launcher's `msd_run` shells out to node. See HOOK_FANOUT_TIMEOUT_MS in
|
||||
// ./helpers/timeouts.cjs for the class rationale.
|
||||
const result = runBashScript(t, script, {
|
||||
cwd: root,
|
||||
@@ -290,12 +290,12 @@ test('#3409 G3: an empty phase_req_ids falls back to TBD, not the empty string',
|
||||
assert.equal(result.outcome, OUTCOME.EXITED, `PHASE_REQ_IDS script did not exit cleanly: ${result.stderr}`);
|
||||
assert.equal(result.exitCode, 0, `PHASE_REQ_IDS script exited non-zero: ${result.stderr}`);
|
||||
|
||||
const { GSD_TEST_PHASE_REQ_IDS } = parseKeyValueStdout(result.stdout);
|
||||
const { MSD_TEST_PHASE_REQ_IDS } = parseKeyValueStdout(result.stdout);
|
||||
// RED on the current tree: `--pick phase_req_ids` exits 0 with empty
|
||||
// stdout on a `null` field, so the unreachable `|| echo TBD` arm never
|
||||
// fires and PHASE_REQ_IDS resolves to `""` instead of the documented
|
||||
// `TBD` sentinel (plan-phase.md: "Skip if phase_req_ids is null or TBD").
|
||||
assert.equal(GSD_TEST_PHASE_REQ_IDS, 'TBD');
|
||||
assert.equal(MSD_TEST_PHASE_REQ_IDS, 'TBD');
|
||||
});
|
||||
|
||||
// ─── G4 — complete-milestone.md bare `cat <glob>` does not block on stdin ──
|
||||
@@ -311,7 +311,7 @@ test('#3409 G4: the milestone summary read does not hang with no summaries', (t)
|
||||
return;
|
||||
}
|
||||
|
||||
const root = createTempDir('gsd-3409-g4-');
|
||||
const root = createTempDir('msd-3409-g4-');
|
||||
t.after(() => cleanup(root));
|
||||
// Zero-summary milestone: a phase dir exists, but no *-SUMMARY.md file
|
||||
// anywhere under it — the exact condition that makes the glob unmatched.
|
||||
@@ -382,9 +382,9 @@ test('#3409 G4: the milestone summary read does not hang with no summaries', (t)
|
||||
});
|
||||
|
||||
// Sanity: the module under test actually exists at the path every fixture
|
||||
// above points `RUNTIME_DIR`/`gsd_run` at — a moved/renamed CLI would
|
||||
// otherwise make every test above fail with a confusing "gsd-tools.cjs not
|
||||
// above points `RUNTIME_DIR`/`msd_run` at — a moved/renamed CLI would
|
||||
// otherwise make every test above fail with a confusing "msd-tools.cjs not
|
||||
// found" error deep inside a bash script instead of a clear assertion here.
|
||||
test('#3409: gsd-tools.cjs exists at the path this suite drives gsd_run through', () => {
|
||||
assert.equal(fs.existsSync(GSD_TOOLS_PATH), true, `expected ${GSD_TOOLS_PATH} to exist`);
|
||||
test('#3409: msd-tools.cjs exists at the path this suite drives msd_run through', () => {
|
||||
assert.equal(fs.existsSync(MSD_TOOLS_PATH), true, `expected ${MSD_TOOLS_PATH} to exist`);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user