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.
157 lines
8.3 KiB
JavaScript
157 lines
8.3 KiB
JavaScript
'use strict';
|
|
|
|
/**
|
|
* msd-quick-batch-quick-regression.test.cjs — row 48 of the #3676 test
|
|
* matrix: ordinary `/msd:quick` (non-batch) stays byte-identical after
|
|
* Phase 4 lands.
|
|
*
|
|
* Named `msd-quick-batch-*` (not `quick-batch-*`) so `scripts/
|
|
* lint-test-file-count.cjs`'s longest-prefix bucketing does not fold this
|
|
* markdown-only test into the already-capped `quick-batch` production-module
|
|
* bucket (2/2 test files from the CORE-layer pass).
|
|
*
|
|
* `commands/msd/quick.md` / `msd-core/workflows/quick.md` are never touched
|
|
* by this phase (design doc row 38/48) — quick-batch adds new call sites
|
|
* onto shared primitives, never edits the ordinary quick command/workflow.
|
|
* Asserted via the same base-ref resolution helper `tests/
|
|
* emitted-attribution.test.cjs` already uses (`resolveBase`/`resolveChangedPaths`,
|
|
* `tests/helpers/emitted-runtime.cjs`) — a three-dot diff against the merge
|
|
* base, never a hand-rolled git call.
|
|
*/
|
|
|
|
const { describe, test } = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const {
|
|
git,
|
|
resolveBase,
|
|
resolveChangedPaths,
|
|
baseRefCandidates,
|
|
} = require('./helpers/emitted-runtime.cjs');
|
|
const {
|
|
INLINE_RESPONSE_LANGUAGE_DIRECTIVE,
|
|
importsDirectiveReference,
|
|
} = require('../scripts/lint-response-language-coverage.cjs');
|
|
|
|
// The canonical launcher preamble, read from its single source of truth. A
|
|
// `sync-runtime-launcher.cjs` propagation rewrites this one line inside every
|
|
// msd_run-calling workflow — quick.md included — without touching a word of
|
|
// ordinary quick content.
|
|
const CANONICAL_LAUNCHER_PREAMBLE = require('node:fs')
|
|
.readFileSync(require('node:path').join(__dirname, '..', 'msd-core', 'workflows', '_runtime-launcher.snippet.sh'), 'utf8')
|
|
.replace(/\r?\n$/, '');
|
|
|
|
// A diff line that swaps the launcher preamble removes the OLD canonical line
|
|
// as well as adding the new one, so equality with today's snippet is not
|
|
// enough. Recognize a launcher-preamble line structurally instead: the shim
|
|
// name assignment plus the resolver's PATH probe and function definition —
|
|
// the same definition-shape discriminator
|
|
// tests/no-bare-msd-tools-command-position.test.cjs uses for its EXCLUSION_RE.
|
|
const looksLikeLauncherPreambleLine = (body) =>
|
|
body.startsWith('_MSD_SHIM_NAME=')
|
|
&& body.includes('command -v msd_run')
|
|
&& body.includes('msd_run()');
|
|
|
|
/**
|
|
* Does this path's diff say anything beyond the shared response-language
|
|
* directive (#2529)?
|
|
*
|
|
* The two accepted forms are read from `scripts/lint-response-language-coverage.cjs`
|
|
* rather than restated here, so a reworded contract cannot leave this carve-out
|
|
* matching prose the lint itself no longer recognizes as coverage. A file the
|
|
* branch ADDED answers true, every line being new — which is what a real
|
|
* #3676-phase branch looks like.
|
|
*
|
|
* #4834 adds the third mechanical-sweep carve-out, in the same family as the
|
|
* #3730 and #2529-round-40 scopings below: a line that IS the canonical
|
|
* launcher preamble is a `sync-runtime-launcher.cjs` propagation, not
|
|
* quick-batch phase work. The snippet's byte changes reach every workflow in
|
|
* one mechanical pass; treating them as ordinary-quick edits would freeze the
|
|
* launcher out of quick.md forever, while the preamble's own content stays
|
|
* policed by tests/runtime-launcher-parity.test.cjs and the emitted-attribution
|
|
* gate. Any OTHER line — ordinary quick prose, steps, contracts — still trips
|
|
* this row exactly as before.
|
|
*/
|
|
function editsBeyondSharedDirective(base, file) {
|
|
const diff = git(['diff', '--unified=0', `${base}...HEAD`, '--', file]);
|
|
return diff.split('\n').some((line) => {
|
|
if (!/^[+-]/.test(line) || line.startsWith('+++') || line.startsWith('---')) return false;
|
|
const body = line.slice(1).trim();
|
|
if (body === '' || body === INLINE_RESPONSE_LANGUAGE_DIRECTIVE) return false;
|
|
if (body === CANONICAL_LAUNCHER_PREAMBLE.trim()) return false;
|
|
if (looksLikeLauncherPreambleLine(body)) return false;
|
|
return !importsDirectiveReference(body);
|
|
});
|
|
}
|
|
|
|
describe('quick-batch: /msd:quick command + workflow stay byte-identical (row 48)', () => {
|
|
test('commands/msd/quick.md and msd-core/workflows/quick.md are not in this branch\'s changed-path set', (t) => {
|
|
// Environmental skip (ADR-2719 §6 idiom) — same as tests/emitted-attribution.test.cjs:
|
|
// a base ref is not universally resolvable (msd-test's shallow-merged container
|
|
// carries no origin/* remote-tracking refs). t.skip is REPORTED as skipped, unlike
|
|
// a bare `return`, which node:test scores as a silent pass.
|
|
const resolved = resolveBase();
|
|
if (!resolved) {
|
|
t.skip(
|
|
'no base ref resolvable — tried ' + baseRefCandidates().join(', ') +
|
|
'. Set MSD_EMITTED_BASE=<ref|sha> to run this regression check elsewhere.',
|
|
);
|
|
return;
|
|
}
|
|
|
|
const changed = resolveChangedPaths(resolved.ref);
|
|
// #3730 review: row 48 is the #3676 PHASE's invariant — quick-batch adds new
|
|
// call sites onto shared primitives without editing ordinary quick. Judging
|
|
// every FUTURE branch by it would freeze quick.md forever (observed: the
|
|
// #3730 migration note tripped this row on an unrelated branch). Scope the
|
|
// row to branches that actually touch the quick-batch surface; an unrelated
|
|
// branch's quick.md edit is none of this guard's business.
|
|
// tests/ excluded: this guard file's own name matches, which would make
|
|
// the scope check self-satisfying on every branch that edits it.
|
|
// #2529 review round 40: a branch can touch the whole quick-batch surface
|
|
// without being #3676 phase work. The response-language coverage sweep adds
|
|
// one shared directive line to EVERY workflow, quick-batch.md and its
|
|
// fragments included, which made this scope check true — and the row then
|
|
// read that branch's ordinary-quick edit, the same one directive line, as a
|
|
// phase violation. That is the false positive the #3730 note already scoped
|
|
// this row away from, arriving by the other door: not a branch that misses
|
|
// the surface, but one that touches all of it. So a path counts only when
|
|
// its diff says something other than the coverage contract.
|
|
const isPhaseWork = (p) => editsBeyondSharedDirective(resolved.ref, p);
|
|
const touchesQuickBatch = changed.some((p) =>
|
|
/quick-batch/.test(p) && !p.startsWith('tests/') && isPhaseWork(p));
|
|
if (!touchesQuickBatch) {
|
|
t.skip(
|
|
`branch does no quick-batch phase work (${changed.length} changed paths; any ` +
|
|
'quick-batch path it touches carries only the shared response-language directive) — ' +
|
|
'row 48 governs #3676-phase branches only',
|
|
);
|
|
return;
|
|
}
|
|
// Same reading on both sides of the row: a directive-only edit is the
|
|
// coverage contract every workflow carries, not a quick-batch edit.
|
|
assert.ok(
|
|
!(changed.includes('commands/msd/quick.md') && isPhaseWork('commands/msd/quick.md')),
|
|
'commands/msd/quick.md must stay untouched by the #3676 quick-batch phase',
|
|
);
|
|
assert.ok(
|
|
!(changed.includes('msd-core/workflows/quick.md') && isPhaseWork('msd-core/workflows/quick.md')),
|
|
'msd-core/workflows/quick.md must stay untouched by the #3676 quick-batch phase',
|
|
);
|
|
// The step fragments under quick/steps/ are likewise untouched — quick-batch
|
|
// has its own, separate quick-batch/steps/ tree.
|
|
//
|
|
// plan-checker-loop.md is excluded (#3916 round 4): 2f64e6230 (#3676's own landing commit)
|
|
// CREATED quick-batch/steps/plan-checker-loop.md as a new, independent 119-line file, not a
|
|
// call-site into quick/'s copy — the "shared primitives" invariant this row protects was
|
|
// never about this file, which was always meant to carry its own per-flow copy of whatever
|
|
// revision-loop contract applies (same pattern as ui-phase.md/verify-work.md). A branch
|
|
// fixing that contract in both independent copies is not the regression row 48 exists to
|
|
// catch; same false-positive class already scoped away twice above (#3730, #2529 round 40).
|
|
const touchedQuickSteps = changed
|
|
.filter((p) => p.startsWith('msd-core/workflows/quick/steps/'))
|
|
.filter((p) => !p.endsWith('/plan-checker-loop.md'))
|
|
.filter(isPhaseWork);
|
|
assert.deepEqual(touchedQuickSteps, [], `unexpected changes under msd-core/workflows/quick/steps/: ${touchedQuickSteps.join(', ')}`);
|
|
});
|
|
});
|