test(#1976): consolidate 17 agent regression tests into agent-contract suites
Fold 17 issue-named agent-markdown regression files into their canonical agent suites: agent-frontmatter (shared agent-body-contract catch-all: read-loop guards, retired-slash-ref bans, sycophancy hardening, doc-writer/code-fixer/review-fix/mapper contracts, write-truncation), planner-language-regression (planner directive/grep/phase contract), executor-mvp-tdd-section, verifier-behavior-unverified, intel, and research-agent-profiles. Verbatim block-scoped describe wrappers; 98 subtests conserved 1:1. All unit (markdown-content) tests — no CLI/env surface. No new files. Regenerates regression-name allowlist (222->207), ratchets file-count allowlist (intel entry removed, phase 4->3), makes 13 relocated allow-test-rule exemptions issue-ref- compliant (ADR-456; prunes stale ids). No CONTEXT.md/ADR refs named the moved files. lint:ci green. Part of epic #1969. Closes #1976. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -96,3 +96,130 @@ describe('gsd-executor — state.* calls use the named-only router form (#1863 r
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// ────────────────────────────────────────────────────────────────────────
|
||||
// Folded from tests/bug-3097-3099-executor-worktree-path-safety.test.cjs — consolidation epic #1969 (B7 #1976)
|
||||
// ────────────────────────────────────────────────────────────────────────
|
||||
{
|
||||
const { describe: __foldDescribe } = require('node:test');
|
||||
__foldDescribe("folded:bug-3097-3099-executor-worktree-path-safety (consolidation epic #1969 B7 #1976)", () => {
|
||||
'use strict';
|
||||
// allow-test-rule: reads markdown product files (gsd-executor.md, worktree-path-safety.md) to verify structural protocol — not source-grep (see #3097)
|
||||
|
||||
// Regression guards for bug #3097 and #3099.
|
||||
//
|
||||
// #3097: gsd-executor's worktree HEAD guard used `if [ -f .git ]` to detect
|
||||
// worktree mode. After a Bash `cd` out of the worktree into the main repo,
|
||||
// `.git` is a DIRECTORY (not a file), so the test is false and the entire
|
||||
// HEAD safety block is silently skipped. Commits then land on whatever branch
|
||||
// the main repo has checked out — not the per-agent worktree branch.
|
||||
//
|
||||
// #3099: Executor agents construct absolute paths from `pwd` captured in the
|
||||
// orchestrator context (main repo root). Edit/Write calls using these paths
|
||||
// resolve to the main repo, not the worktree. git commit from the worktree
|
||||
// sees a clean tree; the work is silently lost or leaks to main.
|
||||
|
||||
const { describe, test } = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
|
||||
const ROOT = path.join(__dirname, '..');
|
||||
const executorSrc = fs.readFileSync(
|
||||
path.join(ROOT, 'agents', 'gsd-executor.md'), 'utf8',
|
||||
);
|
||||
const executePhaseSrc = fs.readFileSync(
|
||||
path.join(ROOT, 'gsd-core', 'workflows', 'execute-phase.md'), 'utf8',
|
||||
);
|
||||
|
||||
describe('bug #3097: cwd-drift sentinel in gsd-executor.md', () => {
|
||||
test('task_commit_protocol has cwd-drift assertion step (0a)', () => {
|
||||
const protocolIdx = executorSrc.indexOf('<task_commit_protocol>');
|
||||
const protocolEnd = executorSrc.indexOf('</task_commit_protocol>');
|
||||
assert.ok(protocolIdx !== -1 && protocolEnd !== -1, 'task_commit_protocol block not found');
|
||||
const protocol = executorSrc.slice(protocolIdx, protocolEnd);
|
||||
assert.ok(
|
||||
protocol.includes('cwd') || protocol.includes('drift') || protocol.includes('gsd-spawn-toplevel'),
|
||||
'task_commit_protocol missing cwd-drift assertion step — #3097 fix not applied',
|
||||
);
|
||||
});
|
||||
|
||||
test('sentinel uses git rev-parse --git-dir to detect worktree', () => {
|
||||
const protocolIdx = executorSrc.indexOf('<task_commit_protocol>');
|
||||
const protocolEnd = executorSrc.indexOf('</task_commit_protocol>');
|
||||
const protocol = executorSrc.slice(protocolIdx, protocolEnd);
|
||||
assert.ok(
|
||||
protocol.includes('rev-parse --git-dir') || protocol.includes('worktrees/'),
|
||||
'cwd-drift detection does not use git rev-parse --git-dir or .git/worktrees/ pattern',
|
||||
);
|
||||
});
|
||||
|
||||
test('cwd-drift check precedes HEAD assertion', () => {
|
||||
const protocolIdx = executorSrc.indexOf('<task_commit_protocol>');
|
||||
const protocolEnd = executorSrc.indexOf('</task_commit_protocol>');
|
||||
const protocol = executorSrc.slice(protocolIdx, protocolEnd);
|
||||
const driftIdx = protocol.search(/cwd.drift|gsd-spawn-toplevel|drift.*assertion/i);
|
||||
const headIdx = protocol.indexOf('Pre-commit HEAD safety assertion');
|
||||
assert.ok(driftIdx !== -1, 'cwd-drift assertion not found');
|
||||
assert.ok(headIdx !== -1, 'HEAD assertion not found');
|
||||
assert.ok(driftIdx < headIdx, 'cwd-drift assertion must precede HEAD assertion (step 0a before step 0)');
|
||||
});
|
||||
});
|
||||
|
||||
describe('bug #3099: absolute-path safety guidance in gsd-executor.md', () => {
|
||||
test('task_commit_protocol documents absolute-path safety', () => {
|
||||
const protocolIdx = executorSrc.indexOf('<task_commit_protocol>');
|
||||
const protocolEnd = executorSrc.indexOf('</task_commit_protocol>');
|
||||
const protocol = executorSrc.slice(protocolIdx, protocolEnd);
|
||||
assert.ok(
|
||||
(protocol.includes('absolute') || protocol.includes('absolute-path')) &&
|
||||
(protocol.includes('worktree') || protocol.includes('WT_ROOT')),
|
||||
'task_commit_protocol missing absolute-path safety guidance — #3099 fix not applied',
|
||||
);
|
||||
});
|
||||
|
||||
test('execute-phase.md parallel_execution block references path safety', () => {
|
||||
const parallelIdx = executePhaseSrc.indexOf('<parallel_execution>');
|
||||
assert.ok(parallelIdx !== -1, 'parallel_execution block not found in execute-phase.md');
|
||||
// Verify the worktree-path-safety.md reference is present in the execution_context
|
||||
// (loaded via @ reference rather than inlined — the safe extract pattern)
|
||||
assert.ok(
|
||||
executePhaseSrc.includes('worktree-path-safety.md'),
|
||||
'execute-phase.md does not reference worktree-path-safety.md in execution_context',
|
||||
);
|
||||
});
|
||||
|
||||
test('execute-phase prompt anchors subagent file paths to project_root before files_to_read (#280)', () => {
|
||||
const filesIdx = executePhaseSrc.indexOf('<files_to_read>');
|
||||
assert.ok(filesIdx !== -1, 'files_to_read block not found in execute-phase.md');
|
||||
const dispatchSnippet = executePhaseSrc.slice(filesIdx, filesIdx + 1800);
|
||||
assert.ok(
|
||||
dispatchSnippet.includes('PROJECT_ROOT=$(git rev-parse --show-toplevel'),
|
||||
'executor dispatch must compute PROJECT_ROOT in the prompt before file reads',
|
||||
);
|
||||
assert.ok(
|
||||
dispatchSnippet.includes('${PROJECT_ROOT}/'),
|
||||
'executor files_to_read paths must be anchored to ${PROJECT_ROOT}/',
|
||||
);
|
||||
});
|
||||
|
||||
test('worktree-path-safety.md reference file exists', () => {
|
||||
assert.ok(
|
||||
fs.existsSync(path.join(ROOT, 'gsd-core', 'references', 'worktree-path-safety.md')),
|
||||
'gsd-core/references/worktree-path-safety.md does not exist',
|
||||
);
|
||||
});
|
||||
|
||||
test('worktree-path-safety.md contains cwd-drift and absolute-path guards', () => {
|
||||
const safetySrc = fs.readFileSync(
|
||||
path.join(ROOT, 'gsd-core', 'references', 'worktree-path-safety.md'), 'utf8',
|
||||
);
|
||||
assert.ok(safetySrc.includes('gsd-spawn-toplevel') || safetySrc.includes('cwd-drift'),
|
||||
'worktree-path-safety.md missing cwd-drift sentinel content');
|
||||
assert.ok(safetySrc.includes('WT_ROOT') || safetySrc.includes('absolute'),
|
||||
'worktree-path-safety.md missing absolute-path guard content');
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user