Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions test/gh-aw-quality.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -594,3 +594,41 @@ describe('gh-aw: Plan Activate hardening behaviors', () => {
expect(content).toMatch(/degrade gracefully|graceful/i);
});
});

// ---------------------------------------------------------------------------
// Test: Plan Activate atomic task-call contract (#1678 / run 31555893180)
// ---------------------------------------------------------------------------

describe('gh-aw: Plan Activate atomic task-call contract', () => {
const content = readFileSync(SQUAD_WORKFLOW, 'utf8');

it('2c contains explicit ATOMIC CONTRACT heading', () => {
expect(content).toMatch(/ATOMIC CONTRACT/i);
});

it('2c requires immediate call after each task body (one compose → one call)', () => {
// Must encode the sequential compose/call/verify pattern
expect(content).toMatch(/compose.*call.*verify|compose only that task.*call.*immediately/i);
});

it('2c explicitly forbids batching task bodies before calls', () => {
expect(content).toMatch(/DO NOT.*compose.*batch|DO NOT.*buffer|not.*compose.*multiple.*before/i);
});

it('2c task body is compact: one sentence scope, 1-2 acceptance criteria', () => {
expect(content).toMatch(/one sentence.*scope|1-2 acceptance criteria/i);
});

it('2d incomplete fallback calls report_incomplete with created/expected counts', () => {
expect(content).toContain('report_incomplete');
expect(content).toMatch(/created.*expected|expected.*created/i);
});

it('2d incomplete fallback never noops on count mismatch', () => {
expect(content).toMatch(/never noop/i);
});

it('2d states re-run is idempotent via title match', () => {
expect(content).toMatch(/idempotent via title match/i);
});
});
9 changes: 7 additions & 2 deletions workflows/squad.md
Original file line number Diff line number Diff line change
Expand Up @@ -743,14 +743,19 @@ Root → Epics → Tasks. Phase-specific: filter to matching phase heading.
**⚠️ DO NOT STOP after epics. Tasks MUST follow immediately.**

**2c. Create Task Issues:** `create-issue` per task in dependency order.

> **⚠️ ATOMIC CONTRACT — strictly one task at a time:**
> For each task: compose ONLY that task's body → call `create-issue` immediately → verify the returned issue number → then move to the next task.
> **DO NOT** compose or buffer multiple task bodies before making calls. One compose → one call → one verify, repeated per task.

- Title: task title
- Labels: `squad` (0075ca), `squad:{agent}` (e4e669). No `size:*` labels unless policy says so.
- Body: scope (2-3 sentences), acceptance criteria, context (parent epic, size, deps)
- Body: one sentence describing scope; 1-2 acceptance criteria; one compact context line (parent epic, size, deps)
- Parent: sub-issue of EPIC (not root)
- Milestone: same as parent epic
- Size: Project field if available, else body line

**2d. Self-Validation:** Compare created counts vs expected. If mismatch: report partial activation with counts, note idempotent re-run.
**2d. Self-Validation:** Compare created/recognized task count vs expected. If created count is below expected: call `report_incomplete` immediately with `created={N}`, `expected={M}`, and the last verified issue number — never noop. Re-runs are idempotent via title match.

Labels must have descriptions and intentional colors.

Expand Down