Files
msd-core/tests/bug-3096-ai-integration-phase-parallel-race.test.cjs
Tom Boucher d993e71adf fix(#3096): enforce sequential Steps 7+8 + Edit-only tool discipline in ai-integration-phase (#3143)
* fix(#3096): enforce sequential Steps 7+8 + Edit-only discipline in ai-integration-phase

Root cause: Steps 7 (gsd-ai-researcher) and 8 (gsd-domain-researcher)
were listed without an explicit sequential constraint. An orchestrator
optimizing for speed could parallelize them since sections appeared
disjoint. gsd-domain-researcher's Write at finalization replaced the
full AI-SPEC.md with its in-memory copy (pre-researcher state), losing
Sections 3/4. Confirmed at 40% incidence (2/5 agents on a real run).
Recovery cost: one extra ai-researcher dispatch, ~18 min wall.

Fix:
  - Explicit 'MUST run sequentially' note on Step 7 (ordering note)
  - 'Wait for Step 7 to complete before spawning Step 8' on Step 8
  - Edit-only tool discipline injected into both agent prompts:
      'Use Edit exclusively - NEVER use Write on this file'
    prevents the last-writer-wins overwrite regardless of dispatch order

Suite: 7043/7043. Closes #3096.

* fix(lint): allow-test-rule for ai-integration-phase structural contract test
2026-05-05 15:02:23 -04:00

74 lines
3.2 KiB
JavaScript

'use strict';
// allow-test-rule: reads product workflow markdown (ai-integration-phase.md) to verify structural ordering contract — not a source-grep test
// Regression guard for bug #3096.
//
// ai-integration-phase.md listed Steps 7+8 (gsd-ai-researcher +
// gsd-domain-researcher) without an explicit sequential ordering constraint.
// An orchestrator optimizing for speed could reasonably parallelize them
// since the sections appeared disjoint. When parallelized, gsd-domain-researcher's
// Write call at finalization replaced the whole AI-SPEC.md file with its
// in-memory copy (pre-researcher state), silently overwriting Sections 3/4.
//
// Confirmed at 40% incidence rate on a real run (2 of 5 worktree agents hit it).
// Recovery cost: one extra ai-researcher dispatch (~18 min wall).
//
// Fix:
// 1. Explicit "MUST run sequentially" note on Steps 7 and 8
// 2. Edit-only tool discipline injected into both agent prompts
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 src = fs.readFileSync(
path.join(ROOT, 'get-shit-done', 'workflows', 'ai-integration-phase.md'),
'utf8',
);
describe('bug #3096: ai-integration-phase sequential ordering and Edit-only discipline', () => {
test('Step 7 documents sequential ordering requirement', () => {
assert.ok(
src.includes('sequentially') || src.includes('sequential'),
'Steps 7+8 ordering note is missing — parallel dispatch race can recur',
);
});
test('Step 7 gsd-ai-researcher prompt includes Edit-only tool discipline', () => {
// The discipline block must appear before </objective> for gsd-ai-researcher
const step7Idx = src.indexOf('## 7. Spawn gsd-ai-researcher');
const step8Idx = src.indexOf('## 8. Spawn gsd-domain-researcher');
assert.ok(step7Idx !== -1, 'Step 7 not found');
assert.ok(step8Idx !== -1, 'Step 8 not found');
const step7Block = src.slice(step7Idx, step8Idx);
assert.ok(
step7Block.includes('Edit tool') && step7Block.includes('NEVER use Write'),
'Step 7 agent prompt missing Edit-only tool discipline',
);
});
test('Step 8 gsd-domain-researcher prompt includes Edit-only tool discipline', () => {
const step8Idx = src.indexOf('## 8. Spawn gsd-domain-researcher');
const step9Idx = src.indexOf('## 9. Spawn gsd-eval-planner');
assert.ok(step8Idx !== -1, 'Step 8 not found');
assert.ok(step9Idx !== -1, 'Step 9 not found');
const step8Block = src.slice(step8Idx, step9Idx);
assert.ok(
step8Block.includes('Edit tool') && step8Block.includes('NEVER use Write'),
'Step 8 agent prompt missing Edit-only tool discipline',
);
});
test('Step 8 references the wait instruction', () => {
const step8Idx = src.indexOf('## 8. Spawn gsd-domain-researcher');
const step9Idx = src.indexOf('## 9. Spawn gsd-eval-planner');
const step8Block = src.slice(step8Idx, step9Idx);
assert.ok(
step8Block.includes('Wait') || step8Block.includes('wait') || step8Block.includes('complete'),
'Step 8 does not instruct orchestrator to wait for Step 7',
);
});
});