test(#1977): consolidate 22 misc + repo-invariant regression tests
Final epic-#1969 batch. Fold 22 issue-named files: the 4 genuine repo-wide invariant scans (551-eslint-bin-lib-coverage, bug-3054 stale /gsd-next, bug-3810 no-gsd-sdk-runtime-refs, feat-3593 cli-negative-universal) into a NEW shared repo-invariants.test.cjs; the other 18 as singletons into their nearest module suite (model-resolver, codex-config, runtime-converters, security, state-transition, worktree-safety, roadmap-parser, etc.). Verbatim block-scoped describe wrappers; 334 subtests conserved 1:1. Host-env pre-check (B2+B6): the 6 CLI folds into GSD_TEST_MODE-setting hosts (model-resolver/ codex-config/runtime-converters) are benign — each origin independently sets GSD_TEST_MODE=1 itself (idempotent), unlike the B6 real-install case. Regenerates regression-name allowlist (222->213), ratchets file-count allowlist (state 17->16), makes 7 relocated allow-test-rule exemptions issue-ref-compliant (ADR-456; prunes stale ids). Repoints 2 tests/ refs in docs/TESTING-SUITES.md. lint:ci green. Part of epic #1969. Closes #1977. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -2575,3 +2575,88 @@ describe('gsd-validate-commit.sh delegates to git-cmd.js', () => {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// ────────────────────────────────────────────────────────────────────────
|
||||
// Folded from tests/bug-3384-secondary-defects.test.cjs — consolidation epic #1969 (B8 #1977)
|
||||
// ────────────────────────────────────────────────────────────────────────
|
||||
{
|
||||
const { describe: __foldDescribe } = require('node:test');
|
||||
__foldDescribe("folded:bug-3384-secondary-defects (consolidation epic #1969 B8 #1977)", () => {
|
||||
// allow-test-rule: source-text-is-the-product (see #3384)
|
||||
const { describe, test } = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
|
||||
const repoRoot = path.resolve(__dirname, '..');
|
||||
const WORKTREE_BRANCH_CHECK_FRAGMENT = path.join(repoRoot, 'gsd-core', 'references', 'worktree-branch-check.md');
|
||||
|
||||
function read(relPath) {
|
||||
return fs.readFileSync(path.join(repoRoot, relPath), 'utf8');
|
||||
}
|
||||
|
||||
describe('bug #3384: adjacent worktree data-loss guards', () => {
|
||||
test('worktree cleanup CLI preserves caller cwd instead of resolving project root', () => {
|
||||
const source = read('gsd-core/bin/gsd-tools.cjs');
|
||||
const skipSet = source.slice(
|
||||
source.indexOf('const SKIP_ROOT_RESOLUTION = new Set(['),
|
||||
source.indexOf('if (!SKIP_ROOT_RESOLUTION.has(command))'),
|
||||
);
|
||||
|
||||
assert.match(skipSet, /'worktree'/);
|
||||
});
|
||||
|
||||
test('diagnose-issues references canonical fragment; fragment is verify-only and fails closed (#48)', () => {
|
||||
// diagnose-issues.md now references the canonical fragment rather than
|
||||
// inlining the block. Verify (a) it references the fragment and (b) the
|
||||
// fragment itself has the correct ordering: symbolic-ref/HEAD assertion and
|
||||
// ^worktree-agent- allow-list appear before any work, and (c) the fragment
|
||||
// is verify-only — no destructive self-recovery.
|
||||
const diagnoseSource = read('gsd-core/workflows/diagnose-issues.md');
|
||||
assert.ok(
|
||||
diagnoseSource.includes('worktree-branch-check.md'),
|
||||
'diagnose-issues.md must reference the canonical worktree-branch-check.md fragment'
|
||||
);
|
||||
|
||||
const fragmentSource = fs.readFileSync(WORKTREE_BRANCH_CHECK_FRAGMENT, 'utf8');
|
||||
const branchCheck = fragmentSource.indexOf('HEAD_REF=$(git symbolic-ref --quiet HEAD || echo');
|
||||
const namespaceCheck = fragmentSource.indexOf('^worktree-agent-');
|
||||
|
||||
assert.ok(branchCheck > 0, 'canonical fragment must assert HEAD before any work');
|
||||
assert.ok(namespaceCheck > branchCheck, 'canonical fragment must require disposable worktree-agent branch');
|
||||
// #48: verify-only — the destructive self-recovery is gone; the fragment fails closed instead.
|
||||
assert.ok(!fragmentSource.includes('git reset --hard {EXPECTED_BASE}'), 'canonical fragment must not self-recover via reset --hard — orchestrator owns recovery (#48)');
|
||||
assert.ok(fragmentSource.includes('exit 42'), 'canonical fragment must fail closed with exit 42 on base mismatch (#48)');
|
||||
});
|
||||
|
||||
test('remove-workspace fails closed when git worktree remove fails', () => {
|
||||
const source = read('gsd-core/workflows/remove-workspace.md');
|
||||
const init = source.indexOf('REMOVE_FAILED=false');
|
||||
const loop = source.indexOf('For each repo in the workspace');
|
||||
const remove = source.indexOf('git worktree remove "$WORKSPACE_PATH/$REPO_NAME"');
|
||||
|
||||
assert.doesNotMatch(
|
||||
source,
|
||||
/git worktree remove "\$WORKSPACE_PATH\/\$REPO_NAME" 2>&1 \|\| true/,
|
||||
'worktree removal failures must not be swallowed',
|
||||
);
|
||||
assert.ok(init > 0 && init < loop, 'REMOVE_FAILED must initialize once before the per-repo loop');
|
||||
assert.ok(remove > loop, 'worktree removal should remain inside the per-repo loop');
|
||||
assert.match(source, /Refusing to delete "\$WORKSPACE_PATH"/);
|
||||
});
|
||||
|
||||
test('validate health warns when worktree inventory cannot be listed', () => {
|
||||
const source = read('gsd-core/bin/lib/verify.cjs');
|
||||
// Accept both hand-written dot access and the tsc-compiled bracket form
|
||||
// (ADR-457: verify.cjs is now emitted from src/verify.cts):
|
||||
// hand-written: worktreeHealth.reason === 'git_list_failed'
|
||||
// tsc-compiled: worktreeHealth['reason'] === 'git_list_failed'
|
||||
const failureBranch = source.search(/worktreeHealth(?:\.reason|\['reason'\]) === 'git_list_failed'/);
|
||||
const warning = source.indexOf("addIssue('warning', 'W020'", failureBranch);
|
||||
|
||||
assert.ok(failureBranch > 0, 'verify health should branch on git_list_failed');
|
||||
assert.ok(warning > failureBranch, 'git_list_failed should emit W020 degraded-health warning');
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user