test(#3335): fold the workflow-content & phase-lifecycle fix-* cluster — Wave 3 (#3373)

* test(#3335): fold the workflow-content & phase-lifecycle fix-* cluster — Wave 3

Folds 13 legacy fix-*.test.cjs regression files (131 test() blocks) into
their module's main suite, per H3 (#3315) of the test-hygiene epic (#3053):

- 6 files with no prior target coverage: renamed (git mv) into new suites
  (spike-manifest-scoping, ship-note, add-todo, workflow-jq-dependency,
  resolve-execution-dynamic-routing, clock)
- 7 files merged into 5 pre-existing suites (worktree-base-ref x2,
  model-resolver, phase-locator x2, frontmatter, verification-status),
  deduplicated against existing coverage

Zero net test-coverage loss: every source assertion preserved or verified
as a genuine pre-existing duplicate. No production code changed.

Last fix-* wave (Wave 1 #3341, Wave 2 #3342 already merged); 4 issue-*
waves remain in #3315.

* test(#3335): fix orthogonal-review findings — Wave 3 fold

Standards-axis review + Memtrace graph pass found real defects in the
just-folded suites, all fixed here:

- phase-locator.test.cjs: pinned an unseeded fast-check property test
  (CONTRIBUTING.md determinism requirement), matching the sibling test's
  seed:7 convention.
- phase-locator.test.cjs: added assert.ok() presence guards after 9
  data.plans.find() calls that were dereferenced unguarded, inconsistent
  with 5 sibling tests in the same file that already guard correctly.
  Latent robustness gap — an omitted plan would throw an opaque TypeError
  instead of a clear assertion failure.
- Standardized the fold-wrapper convention (block-scoped __foldDescribe)
  across worktree-base-ref.test.cjs, verification-status.test.cjs, and
  phase-locator.test.cjs to match the pattern already established in
  frontmatter.test.cjs and model-resolver.test.cjs from earlier folds.
- worktree-base-ref.test.cjs: moved a mid-file require to the top-of-file
  require block.
- Eliminated duplicated env-isolation helpers: model-resolver.test.cjs and
  phase-locator.test.cjs each reimplemented GSD_WORKSTREAM/GSD_PROJECT
  save-restore independently; factored a shared isolateWorkstreamEnv()/
  restoreWorkstreamEnv() into tests/helpers.cjs and pointed both call
  sites at it.

No test() count changed in any file. No production code touched.

---------

Co-authored-by: sim <sim@local>
This commit is contained in:
Tom Boucher
2026-08-11 22:23:55 -04:00
committed by GitHub
parent ae7dc52972
commit a875372f18
19 changed files with 1906 additions and 1983 deletions

View File

@@ -14,6 +14,7 @@
const { describe, test } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const { makeFaultyGit } = require('./helpers/faulty-deps.cjs');
@@ -1037,3 +1038,199 @@ describe('cmdWorktreeBaseCheck — user/global cascade (#1013)', () => {
assert.strictEqual(result.reason, 'fork-ref-unknown');
});
});
// ─── workflow dispatch-site coverage: worktree.base-check gates (folded from
// fix-1941-quick-worktree-stale-base.test.cjs and
// fix-2649-diagnose-issues-worktree-stale-base.test.cjs, #3335) ──────────────
//
// allow-test-rule: source-text-is-the-product #1941 #2649
// Workflow .md files are the installed AI instructions — their text IS what the
// runtime loads. Testing text content tests the deployed contract. Per
// CONTRIBUTING.md exception matrix.
//
// Root cause shared by #1941 and #2649: Claude Code's isolation="worktree"
// forks new worktrees from origin/HEAD, not the live local HEAD. When prior
// local commits advance local HEAD without an intervening `git push`,
// origin/HEAD stays pinned to a stale ancestor and the executor's
// worktree_branch_check guard halts with a base-mismatch fatal. The fix ports
// the worktree.base-check auto-degrade pattern (originally execute-phase
// #683/#1369) into each not-yet-covered dispatch site: quick.md's
// single-dispatch path (#1941), and diagnose-issues.md's spawn_agents step
// plus execute-plan.md's Pattern A single-plan dispatch (#2649, fixed
// together per that bug's acceptance criterion 5 — same bug class, same
// one-line gate).
{
const { describe: __foldDescribe } = require('node:test');
__foldDescribe('folded:fix-1941-quick-worktree-stale-base', () => {
const QUICK_WORKFLOW_PATH = path.join(__dirname, '..', 'gsd-core', 'workflows', 'quick.md');
describe('quick: pre-dispatch worktree base re-check (#1941)', () => {
test('workflow file exists', () => {
assert.ok(fs.existsSync(QUICK_WORKFLOW_PATH), 'workflows/quick.md should exist');
});
test('Step 6 runs worktree.base-check before capturing EXPECTED_BASE', () => {
const content = fs.readFileSync(QUICK_WORKFLOW_PATH, 'utf-8');
const step6Idx = content.indexOf('**Step 6: Spawn executor**');
const baseCheckIdx = content.indexOf('worktree.base-check', step6Idx);
const expectedBaseIdx = content.indexOf('EXPECTED_BASE=$(git rev-parse HEAD)', step6Idx);
assert.ok(step6Idx !== -1, '"Step 6: Spawn executor" must exist in quick.md');
assert.ok(baseCheckIdx !== -1, 'worktree.base-check must be invoked within Step 6');
assert.ok(expectedBaseIdx !== -1, 'EXPECTED_BASE capture must exist within Step 6');
assert.ok(
baseCheckIdx < expectedBaseIdx,
'worktree.base-check must run BEFORE EXPECTED_BASE is captured so the degrade decision reflects the most current local HEAD'
);
});
test('degrade check references #1941 for traceability', () => {
const content = fs.readFileSync(QUICK_WORKFLOW_PATH, 'utf-8');
assert.ok(content.includes('#1941'), 'quick.md must reference #1941');
});
test('degrade check clears BOTH USE_WORKTREES and ISOLATION when shouldDegrade is true', () => {
const content = fs.readFileSync(QUICK_WORKFLOW_PATH, 'utf-8');
const baseCheckIdx = content.indexOf('worktree.base-check');
const block = content.slice(baseCheckIdx, baseCheckIdx + 900);
assert.ok(block.includes('shouldDegrade'), 'degrade check must branch on shouldDegrade');
// Both must move together (#2652). Dispatch keys on ISOLATION while the prompt
// guard and worktree manifest key on USE_WORKTREES; clearing only one dispatches
// an isolated executor with no base guard and no manifest, then blocks in cleanup
// looking for a manifest that was never initialized.
assert.ok(block.includes('USE_WORKTREES=false'), 'degrade must set USE_WORKTREES=false');
assert.ok(
block.includes('ISOLATION=none'),
'degrade must ALSO set ISOLATION=none — dispatch reads ISOLATION, so clearing only ' +
'USE_WORKTREES still passes the harness isolation flag (#2652)'
);
});
// #2652: this assertion previously required `RUNTIME = "claude"`, encoding the
// pre-#2584 premise that worktree isolation is Claude-specific. #2584 replaced
// that with the negotiated dispatch.isolation capability, so the guard now keys
// on the capability — Cursor also declares harness-worktree.
test('degrade check guards on the negotiated capability, not a runtime id', () => {
const content = fs.readFileSync(QUICK_WORKFLOW_PATH, 'utf-8');
const baseCheckIdx = content.indexOf('worktree.base-check');
const block = content.slice(Math.max(0, baseCheckIdx - 300), baseCheckIdx + 200);
assert.ok(
block.includes('ISOLATION') && block.includes('harness-worktree'),
'degrade check must guard on ISOLATION = harness-worktree'
);
assert.ok(
!/\[\s*"\$RUNTIME"\s*=/.test(block),
'degrade check must NOT branch on a RUNTIME literal (#2584/#2652)'
);
});
test('degrade check names origin/HEAD as the stale fork base', () => {
const content = fs.readFileSync(QUICK_WORKFLOW_PATH, 'utf-8');
const step6Idx = content.indexOf('**Step 6: Spawn executor**');
const nextSection = content.indexOf('\n---', step6Idx);
const section = content.slice(step6Idx, nextSection === -1 ? undefined : nextSection);
assert.ok(section.includes('origin/HEAD'), 'Step 6 must name origin/HEAD as the stale fork base');
});
});
});
}
{
const { describe: __foldDescribe } = require('node:test');
__foldDescribe('folded:fix-2649-diagnose-issues-worktree-stale-base', () => {
const DIAGNOSE_ISSUES_PATH = path.join(__dirname, '..', 'gsd-core', 'workflows', 'diagnose-issues.md');
const EXECUTE_PLAN_PATH = path.join(__dirname, '..', 'gsd-core', 'workflows', 'execute-plan.md');
describe('diagnose-issues: pre-dispatch worktree base-check (#2649)', () => {
test('workflow file exists', () => {
assert.ok(fs.existsSync(DIAGNOSE_ISSUES_PATH), 'workflows/diagnose-issues.md should exist');
});
test('spawn_agents step runs worktree.base-check before the Agent() dispatch', () => {
const content = fs.readFileSync(DIAGNOSE_ISSUES_PATH, 'utf-8');
const spawnIdx = content.indexOf('<step name="spawn_agents">');
assert.ok(spawnIdx !== -1, '"spawn_agents" step must exist in diagnose-issues.md');
const baseCheckIdx = content.indexOf('worktree.base-check', spawnIdx);
assert.ok(baseCheckIdx !== -1, 'worktree.base-check must be invoked within the spawn_agents step');
// The load-bearing invariant is "base-check BEFORE the Agent() dispatch" so the
// degrade decision can drop isolation from the spawn. (Where EXPECTED_BASE is
// captured relative to the check is cosmetic — the check only reads HEAD, never
// mutates it — so assert the real invariant, not a loose disjunction.)
const agentIdx = content.indexOf('Agent(', spawnIdx);
assert.ok(agentIdx !== -1, 'spawn_agents must contain an Agent() dispatch');
assert.ok(
baseCheckIdx < agentIdx,
'worktree.base-check must run before the Agent() dispatch so the degrade decision can drop isolation from the spawn',
);
});
test('verify-only worktree_branch_check backstop remains embedded in the Agent() prompt', () => {
// Acceptance criterion #4: the base-check is a PRE-DISPATCH degrade; the
// <worktree_branch_check> guard is a POST-FORK fail-closed backstop. Both
// layers must survive — a future edit that dropped the backstop embedding
// would re-open the silent-stale-base class. Guard its continued presence.
const content = fs.readFileSync(DIAGNOSE_ISSUES_PATH, 'utf-8');
const spawnIdx = content.indexOf('<step name="spawn_agents">');
assert.ok(spawnIdx !== -1, '"spawn_agents" step must exist');
assert.ok(
content.indexOf('worktree-branch-check.md', spawnIdx) !== -1,
'spawn_agents must still materialize the <worktree_branch_check> backstop after the base-check gate (#2649 acceptance criterion 4)',
);
});
test('degrade check sets USE_WORKTREES=false when shouldDegrade is true', () => {
const content = fs.readFileSync(DIAGNOSE_ISSUES_PATH, 'utf-8');
const baseCheckIdx = content.indexOf('worktree.base-check');
const block = content.slice(baseCheckIdx, baseCheckIdx + 600);
assert.ok(
block.includes('shouldDegrade') && block.includes('USE_WORKTREES=false'),
'degrade check must override USE_WORKTREES=false when shouldDegrade is true',
);
});
test('degrade check references #2649 for traceability', () => {
const content = fs.readFileSync(DIAGNOSE_ISSUES_PATH, 'utf-8');
assert.ok(content.includes('#2649'), 'diagnose-issues.md must reference #2649');
});
});
describe('execute-plan Pattern A: pre-dispatch worktree base-check (#2649)', () => {
test('workflow file exists', () => {
assert.ok(fs.existsSync(EXECUTE_PLAN_PATH), 'workflows/execute-plan.md should exist');
});
test('Pattern A runs the worktree base-check before spawning the executor', () => {
const content = fs.readFileSync(EXECUTE_PLAN_PATH, 'utf-8');
const patternAIdx = content.indexOf('**Pattern A:**');
assert.ok(patternAIdx !== -1, '"Pattern A:" must exist in execute-plan.md');
// The base-check instruction must appear within the Pattern A description,
// before the isolation="worktree" embedding instruction.
const patternAEnd = content.indexOf('**Pattern B:**', patternAIdx);
const patternA = content.slice(patternAIdx, patternAEnd === -1 ? undefined : patternAEnd);
assert.ok(
patternA.includes('#2649') && /worktree\.base-check|base-check/.test(patternA),
'Pattern A must run the #2649 worktree base-check before dispatching the executor',
);
assert.ok(
patternA.includes('shouldDegrade'),
'Pattern A base-check must consult shouldDegrade',
);
});
test('Pattern A documents the auto-degrade (drop isolation on shouldDegrade)', () => {
const content = fs.readFileSync(EXECUTE_PLAN_PATH, 'utf-8');
const patternAIdx = content.indexOf('**Pattern A:**');
const patternAEnd = content.indexOf('**Pattern B:**', patternAIdx);
const patternA = content.slice(patternAIdx, patternAEnd === -1 ? undefined : patternAEnd);
assert.ok(
/degrad|sequential/i.test(patternA),
'Pattern A must document auto-degrading to sequential mode when shouldDegrade is true',
);
});
});
});
}