| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335 |
- """Setup helpers for wave execution drill scenarios.
- Each helper creates a test repository with a plan file that exercises a
- specific aspect of the wave decomposition algorithm:
- - create_wave_test_repo: full 5-task plan spanning 3 waves
- - create_wave_test_repo_minimal: smaller 3-task plan for faster runs
- - create_waves_file: full 5-task plan pre-decomposed to .waves.md
- - create_waves_file_minimal: 3-task plan pre-decomposed to .waves.md
- - create_waves_file_with_broken_task: 3-task plan where Task 3 is structurally
- impossible (exercises failure escalation)
- - create_false_overlap_repo: same filename in different directories
- - create_dependency_chain_repo: semantic (import-based) dependencies
- - create_conflict_surface_repo: implicit barrel-file conflicts
- """
- from __future__ import annotations
- from pathlib import Path
- from setup_helpers.base import _git
- # ----------------------------------------------------------------------------
- # Shared fixture content
- # ----------------------------------------------------------------------------
- PACKAGE_JSON = """\
- {
- "name": "wave-test-fixture",
- "version": "0.1.0",
- "private": true,
- "scripts": {
- "test": "jest",
- "lint": "echo 'no lint configured' && exit 0",
- "build": "tsc -p tsconfig.json"
- },
- "devDependencies": {
- "typescript": "^5.4.0",
- "jest": "^29.7.0",
- "@types/jest": "^29.5.12",
- "ts-jest": "^29.1.2"
- }
- }
- """
- TSCONFIG_JSON = """\
- {
- "compilerOptions": {
- "target": "ES2022",
- "module": "commonjs",
- "lib": ["ES2022"],
- "strict": true,
- "esModuleInterop": true,
- "skipLibCheck": true,
- "forceConsistentCasingInFileNames": true,
- "declaration": true,
- "outDir": "dist",
- "rootDir": "."
- },
- "include": ["src/**/*.ts", "tests/**/*.ts"],
- "exclude": ["node_modules", "dist"]
- }
- """
- # jest.config.js uses ts-jest preset so implementers can write TypeScript
- # test files that import from src/ without configuring anything themselves.
- # This is deliberately provided up-front so the implementer never has to
- # diagnose jest/ts-jest interop issues mid-task.
- JEST_CONFIG_JS = """\
- /** @type {import('jest').Config} */
- module.exports = {
- preset: 'ts-jest',
- testEnvironment: 'node',
- testMatch: ['<rootDir>/tests/**/*.test.ts'],
- rootDir: '.',
- moduleNameMapper: {
- '^@/(.*)$': '<rootDir>/src/$1',
- },
- };
- """
- CLAUDE_MD = """\
- # Project Commands
- **install**: npm ci
- **test**: npm test
- **lint**: npm run lint
- **build**: npm run build
- """
- README_MD = """\
- # Wave Test Fixture
- Synthetic project used by drill scenarios to exercise the wave decomposition
- algorithm. Do not edit by hand — this file is generated by
- `setup_helpers/wave.py`.
- """
- # ----------------------------------------------------------------------------
- # Internal helpers
- # ----------------------------------------------------------------------------
- def _init_base_repo(workdir: Path) -> None:
- """Create the base TypeScript repo on main with the standard fixture files."""
- workdir.mkdir(parents=True, exist_ok=True)
- _git(["git", "init", "-b", "main"], cwd=workdir)
- _git(["git", "config", "user.email", "drill@test.local"], cwd=workdir)
- _git(["git", "config", "user.name", "Drill Test"], cwd=workdir)
- (workdir / "package.json").write_text(PACKAGE_JSON)
- (workdir / "README.md").write_text(README_MD)
- (workdir / "tsconfig.json").write_text(TSCONFIG_JSON)
- (workdir / "jest.config.js").write_text(JEST_CONFIG_JS)
- (workdir / "CLAUDE.md").write_text(CLAUDE_MD)
- _git(
- ["git", "add", "package.json", "README.md", "tsconfig.json",
- "jest.config.js", "CLAUDE.md"],
- cwd=workdir,
- )
- _git(["git", "commit", "-m", "initial commit"], cwd=workdir)
- def _write_file(workdir: Path, rel_path: str, content: str) -> None:
- """Write a file, creating parent directories as needed."""
- target = workdir / rel_path
- target.parent.mkdir(parents=True, exist_ok=True)
- target.write_text(content)
- def _ensure_dir(workdir: Path, rel_path: str) -> None:
- """Create a directory and drop a .gitkeep so git can track it."""
- d = workdir / rel_path
- d.mkdir(parents=True, exist_ok=True)
- (d / ".gitkeep").write_text("")
- def _commit_all_on_feature_branch(workdir: Path) -> None:
- """Checkout feature/test-implementation and commit every remaining change."""
- _git(["git", "checkout", "-b", "feature/test-implementation"], cwd=workdir)
- _git(["git", "add", "-A"], cwd=workdir)
- _git(["git", "commit", "-m", "add wave test plan and fixtures"], cwd=workdir)
- # ----------------------------------------------------------------------------
- # Plan bodies
- # ----------------------------------------------------------------------------
- WAVE_TEST_PLAN = """\
- # Wave Decomposition Test Implementation Plan
- > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development
- > (recommended) or superpowers:executing-plans to implement this plan task-by-task.
- **Goal:** Exercise the full wave decomposition algorithm across 3 waves.
- **Architecture:** Foundation types feed independent services which are wired
- together by an API routes layer. This shape intentionally produces one
- sequential task in Wave 1, three parallel tasks in Wave 2, and one
- sequential integration task in Wave 3.
- **Tech Stack:** TypeScript, Jest.
- ---
- ### Task 1: Foundation types
- **Files:**
- - Create: `src/types/auth.ts`
- - Create: `src/types/users.ts`
- - Create: `src/types/billing.ts`
- - Modify: `src/types/index.ts`
- **Acceptance Criteria:**
- - `src/types/auth.ts` exports `User` and `Session` interfaces.
- - `src/types/users.ts` exports a `UserProfile` interface with `id` and `email`.
- - `src/types/billing.ts` exports `Plan` and `Subscription` interfaces.
- - `src/types/index.ts` re-exports everything from the three files above.
- - `npm run build` succeeds with no type errors.
- - [ ] **Step 1: Create src/types/auth.ts with User and Session interfaces.**
- - [ ] **Step 2: Create src/types/users.ts with UserProfile interface.**
- - [ ] **Step 3: Create src/types/billing.ts with Plan and Subscription interfaces.**
- - [ ] **Step 4: Update src/types/index.ts to re-export the three modules.**
- - [ ] **Step 5: Run `npm run build` and commit.**
- ---
- ### Task 2: Auth service
- **Files:**
- - Create: `src/services/auth.ts`
- - Create: `tests/auth.test.ts`
- **Acceptance Criteria:**
- - `src/services/auth.ts` exports an `AuthService` class with a `login(email, password)` method.
- - `AuthService.login` returns a `Session` imported from `src/types/auth.ts`.
- - `tests/auth.test.ts` covers the happy-path login case.
- - `tests/auth.test.ts` covers an invalid-credentials failure case.
- - `npm test -- tests/auth.test.ts` passes.
- - [ ] **Step 1: Write tests/auth.test.ts covering login success and failure.**
- - [ ] **Step 2: Implement src/services/auth.ts to make the tests pass.**
- - [ ] **Step 3: Run `npm test -- tests/auth.test.ts` and commit.**
- ---
- ### Task 3: Users service
- **Files:**
- - Create: `src/services/users.ts`
- - Create: `tests/users.test.ts`
- **Acceptance Criteria:**
- - `src/services/users.ts` exports a `UsersService` class with `getProfile(id)`.
- - `UsersService.getProfile` returns a `UserProfile` imported from `src/types/users.ts`.
- - `tests/users.test.ts` covers the happy-path lookup case.
- - `tests/users.test.ts` covers a not-found case.
- - `npm test -- tests/users.test.ts` passes.
- - [ ] **Step 1: Write tests/users.test.ts covering getProfile success and missing.**
- - [ ] **Step 2: Implement src/services/users.ts to make the tests pass.**
- - [ ] **Step 3: Run `npm test -- tests/users.test.ts` and commit.**
- ---
- ### Task 4: Billing service
- **Files:**
- - Create: `src/services/billing.ts`
- - Create: `tests/billing.test.ts`
- **Acceptance Criteria:**
- - `src/services/billing.ts` exports a `BillingService` class with `subscribe(userId, planId)`.
- - `BillingService.subscribe` returns a `Subscription` imported from `src/types/billing.ts`.
- - `tests/billing.test.ts` covers a successful subscription.
- - `tests/billing.test.ts` covers a failed subscription.
- - `npm test -- tests/billing.test.ts` passes.
- - [ ] **Step 1: Write tests/billing.test.ts covering subscribe success and failure.**
- - [ ] **Step 2: Implement src/services/billing.ts to make the tests pass.**
- - [ ] **Step 3: Run `npm test -- tests/billing.test.ts` and commit.**
- ---
- ### Task 5: API routes
- **Files:**
- - Create: `src/api/routes.ts`
- - Modify: `src/index.ts`
- **Acceptance Criteria:**
- - `src/api/routes.ts` imports `AuthService`, `UsersService`, and `BillingService`.
- - `src/api/routes.ts` exports a `registerRoutes(app)` function that wires the three services.
- - `src/index.ts` imports `registerRoutes` and calls it with the app.
- - `npm run build` succeeds.
- - `npm test` passes end to end.
- - [ ] **Step 1: Create src/api/routes.ts that composes the three services.**
- - [ ] **Step 2: Update src/index.ts to register the routes on startup.**
- - [ ] **Step 3: Run `npm run build && npm test` and commit.**
- """
- FALSE_OVERLAP_PLAN = """\
- # False Overlap Test Implementation Plan
- > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development
- > (recommended) or superpowers:executing-plans to implement this plan task-by-task.
- **Goal:** Verify that wave decomposition uses full paths, not bare filenames,
- when detecting file overlap between tasks.
- **Architecture:** Three fully-independent domains (auth, users, billing) each
- define a locally-scoped `types.ts`. A decomposer that keys on filename alone
- would serialize these tasks. A correct decomposer keys on full paths and
- parallelizes them.
- **Tech Stack:** TypeScript, Jest.
- ---
- ### Task 1: Auth domain scaffolding
- **Files:**
- - Create: `src/auth/types.ts`
- - Create: `src/auth/service.ts`
- **Acceptance Criteria:**
- - `src/auth/types.ts` exports an `AuthToken` interface local to the auth domain.
- - `src/auth/service.ts` exports an `AuthService` class that uses `AuthToken`.
- - Nothing outside `src/auth/` is touched.
- - `npm run build` succeeds.
- - [ ] **Step 1: Create src/auth/types.ts with AuthToken.**
- - [ ] **Step 2: Create src/auth/service.ts importing AuthToken locally.**
- - [ ] **Step 3: Run `npm run build` and commit.**
- ---
- ### Task 2: Users domain scaffolding
- **Files:**
- - Create: `src/users/types.ts`
- - Create: `src/users/service.ts`
- **Acceptance Criteria:**
- - `src/users/types.ts` exports a `UserRecord` interface local to the users domain.
- - `src/users/service.ts` exports a `UsersService` class that uses `UserRecord`.
- - Nothing outside `src/users/` is touched.
- - `npm run build` succeeds.
- - [ ] **Step 1: Create src/users/types.ts with UserRecord.**
- - [ ] **Step 2: Create src/users/service.ts importing UserRecord locally.**
- - [ ] **Step 3: Run `npm run build` and commit.**
- ---
- ### Task 3: Billing domain scaffolding
- **Files:**
- - Create: `src/billing/types.ts`
- - Create: `src/billing/service.ts`
- **Acceptance Criteria:**
- - `src/billing/types.ts` exports an `Invoice` interface local to the billing domain.
- - `src/billing/service.ts` exports a `BillingService` class that uses `Invoice`.
- - Nothing outside `src/billing/` is touched.
- - `npm run build` succeeds.
- - [ ] **Step 1: Create src/billing/types.ts with Invoice.**
- - [ ] **Step 2: Create src/billing/service.ts importing Invoice locally.**
- - [ ] **Step 3: Run `npm run build` and commit.**
- """
- DEPENDENCY_CHAIN_PLAN = """\
- # Dependency Chain Test Implementation Plan
- > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development
- > (recommended) or superpowers:executing-plans to implement this plan task-by-task.
- **Goal:** Verify that wave decomposition detects semantic (import-based)
- dependencies, not just file-overlap dependencies.
- **Architecture:** Two independent type modules (auth, billing) can be built
- in parallel. A session service consumes the auth types but never touches
- the billing types — the decomposer should recognize this asymmetric
- dependency via the import, even though there is no file overlap.
- **Tech Stack:** TypeScript, Jest.
- ---
- ### Task 1: Create auth types
- **Files:**
- - Create: `src/types/auth.ts`
- **Acceptance Criteria:**
- - `src/types/auth.ts` exports a `User` interface with `id` and `email`.
- - `src/types/auth.ts` exports a `Session` interface with `userId` and `token`.
- - No other file is modified.
- - `npm run build` succeeds.
- - [ ] **Step 1: Create src/types/auth.ts with User and Session interfaces.**
- - [ ] **Step 2: Run `npm run build` and commit.**
- ---
- ### Task 2: Create billing types
- **Files:**
- - Create: `src/types/billing.ts`
- **Acceptance Criteria:**
- - `src/types/billing.ts` exports a `Plan` interface with `id` and `price`.
- - `src/types/billing.ts` exports a `Subscription` interface with `userId` and `planId`.
- - No other file is modified.
- - `npm run build` succeeds.
- - [ ] **Step 1: Create src/types/billing.ts with Plan and Subscription interfaces.**
- - [ ] **Step 2: Run `npm run build` and commit.**
- ---
- ### Task 3: Create session service
- **Files:**
- - Create: `src/services/session.ts`
- **Acceptance Criteria:**
- - `src/services/session.ts` **imports** `User` and `Session` from `src/types/auth.ts`.
- - `src/services/session.ts` does **not** import from `src/types/billing.ts`.
- - `src/services/session.ts` does **not** modify `src/types/auth.ts`.
- - `src/services/session.ts` exports a `SessionService` class with `create(user: User): Session`.
- - `npm run build` succeeds.
- - [ ] **Step 1: Create src/services/session.ts importing User and Session from ../types/auth.**
- - [ ] **Step 2: Implement SessionService.create.**
- - [ ] **Step 3: Run `npm run build` and commit.**
- """
- WAVE_TEST_PLAN_MINIMAL = """\
- # Wave Execution Minimal Test Implementation Plan
- > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development
- > (recommended) or superpowers:executing-plans to implement this plan task-by-task.
- **Goal:** Exercise wave execution across two waves with the smallest
- possible surface — a single foundation task followed by two independent
- parallel services.
- **Architecture:** Foundation types feed two independent, parallel
- utility services. This produces one sequential task in Wave 1 and two
- parallel tasks in Wave 2.
- **Tech Stack:** TypeScript, Jest.
- ---
- ### Task 1: Foundation types
- **Files:**
- - Create: `src/types/core.ts`
- - Modify: `src/types/index.ts`
- **Acceptance Criteria:**
- - `src/types/core.ts` exports a `User` interface with `id` and `email`.
- - `src/types/core.ts` exports a `Session` interface with `userId` and `token`.
- - `src/types/index.ts` re-exports everything from `src/types/core.ts`.
- - `npm run build` succeeds with no type errors.
- - [ ] **Step 1: Create src/types/core.ts with User and Session interfaces.**
- - [ ] **Step 2: Update src/types/index.ts to re-export from ./core.**
- - [ ] **Step 3: Run `npm run build` and commit.**
- ---
- ### Task 2: Logger service
- **Files:**
- - Create: `src/services/logger.ts`
- - Create: `tests/logger.test.ts`
- **Acceptance Criteria:**
- - `src/services/logger.ts` exports a `Logger` class with an `info(message: string)` method.
- - `Logger.info` appends a timestamped entry to an internal buffer.
- - `tests/logger.test.ts` covers a happy-path info case.
- - `tests/logger.test.ts` covers a repeated-call buffering case.
- - `npm test -- tests/logger.test.ts` passes.
- - [ ] **Step 1: Write tests/logger.test.ts covering info and buffering.**
- - [ ] **Step 2: Implement src/services/logger.ts to make the tests pass.**
- - [ ] **Step 3: Run `npm test -- tests/logger.test.ts` and commit.**
- ---
- ### Task 3: Clock service
- **Files:**
- - Create: `src/services/clock.ts`
- - Create: `tests/clock.test.ts`
- **Acceptance Criteria:**
- - `src/services/clock.ts` exports a `Clock` class with a `now(): number` method.
- - `Clock.now` returns the current Unix timestamp in milliseconds.
- - `tests/clock.test.ts` covers a happy-path now case.
- - `tests/clock.test.ts` covers the return value being a finite number.
- - `npm test -- tests/clock.test.ts` passes.
- - [ ] **Step 1: Write tests/clock.test.ts covering now success and type.**
- - [ ] **Step 2: Implement src/services/clock.ts to make the tests pass.**
- - [ ] **Step 3: Run `npm test -- tests/clock.test.ts` and commit.**
- """
- CONFLICT_SURFACE_PLAN = """\
- # Conflict Surface Test Implementation Plan
- > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development
- > (recommended) or superpowers:executing-plans to implement this plan task-by-task.
- **Goal:** Verify the conflict-surface heuristic catches implicit barrel-file
- modifications that the task file lists intentionally omit.
- **Architecture:** `src/services/index.ts` exists as a barrel file before the
- plan runs. Each task creates a new service module and needs to add an
- export line to `src/services/index.ts`, but the task Files list only
- names the new module. A pure file-overlap decomposer would parallelize
- these tasks; the conflict-surface heuristic should recognize that every
- task needs to touch the barrel file and either serialize them or add the
- barrel file to each task's list.
- **Tech Stack:** TypeScript, Jest.
- ---
- ### Task 1: Create auth service
- **Files:**
- - Create: `src/services/auth.ts`
- **Acceptance Criteria:**
- - `src/services/auth.ts` exports an `AuthService` class with a `login` method.
- - `AuthService` is re-exported from `src/services/index.ts` (add export to index).
- - Importing `AuthService` from `src/services` works at build time.
- - `npm run build` succeeds.
- - [ ] **Step 1: Create src/services/auth.ts with AuthService.**
- - [ ] **Step 2: Add `export * from './auth';` to src/services/index.ts.**
- - [ ] **Step 3: Run `npm run build` and commit.**
- ---
- ### Task 2: Create users service
- **Files:**
- - Create: `src/services/users.ts`
- **Acceptance Criteria:**
- - `src/services/users.ts` exports a `UsersService` class with a `getProfile` method.
- - `UsersService` is re-exported from `src/services/index.ts` (add export to index).
- - Importing `UsersService` from `src/services` works at build time.
- - `npm run build` succeeds.
- - [ ] **Step 1: Create src/services/users.ts with UsersService.**
- - [ ] **Step 2: Add `export * from './users';` to src/services/index.ts.**
- - [ ] **Step 3: Run `npm run build` and commit.**
- ---
- ### Task 3: Create billing service
- **Files:**
- - Create: `src/services/billing.ts`
- **Acceptance Criteria:**
- - `src/services/billing.ts` exports a `BillingService` class with a `subscribe` method.
- - `BillingService` is re-exported from `src/services/index.ts` (add export to index).
- - Importing `BillingService` from `src/services` works at build time.
- - `npm run build` succeeds.
- - [ ] **Step 1: Create src/services/billing.ts with BillingService.**
- - [ ] **Step 2: Add `export * from './billing';` to src/services/index.ts.**
- - [ ] **Step 3: Run `npm run build` and commit.**
- """
- # ----------------------------------------------------------------------------
- # Public helpers
- # ----------------------------------------------------------------------------
- def create_wave_test_repo(workdir: Path) -> None:
- """Create a 5-task plan exercising the full wave decomposition algorithm.
- Expected decomposition:
- - Wave 1: Task 1 (foundation types)
- - Wave 2: Tasks 2, 3, 4 (parallel, independent service implementations)
- - Wave 3: Task 5 (API routes integration, depends on services)
- """
- workdir = Path(workdir)
- _init_base_repo(workdir)
- # Pre-create the barrel file and stub directories the plan references.
- _write_file(workdir, "src/types/index.ts", "export {};\n")
- for d in ("src/auth", "src/users", "src/billing", "src/api", "tests"):
- _ensure_dir(workdir, d)
- _write_file(workdir, "docs/superpowers/plans/test-plan.md", WAVE_TEST_PLAN)
- _commit_all_on_feature_branch(workdir)
- def create_false_overlap_repo(workdir: Path) -> None:
- """Create a plan where three tasks share a filename but no full-path overlap.
- Expected decomposition:
- - Wave 1: Tasks 1, 2, 3 all parallel (no true file overlap)
- """
- workdir = Path(workdir)
- _init_base_repo(workdir)
- for d in ("src/auth", "src/users", "src/billing"):
- _ensure_dir(workdir, d)
- _write_file(workdir, "docs/superpowers/plans/test-plan.md", FALSE_OVERLAP_PLAN)
- _commit_all_on_feature_branch(workdir)
- def create_dependency_chain_repo(workdir: Path) -> None:
- """Create a plan where Task 3 semantically depends on Task 1 via imports.
- Expected decomposition:
- - Wave 1: Tasks 1, 2 (parallel — independent type modules)
- - Wave 2: Task 3 (depends on Task 1's src/types/auth.ts)
- """
- workdir = Path(workdir)
- _init_base_repo(workdir)
- _ensure_dir(workdir, "src/types")
- _ensure_dir(workdir, "src/services")
- _write_file(workdir, "docs/superpowers/plans/test-plan.md", DEPENDENCY_CHAIN_PLAN)
- _commit_all_on_feature_branch(workdir)
- def create_wave_test_repo_minimal(workdir: Path) -> None:
- """Create a 3-task plan exercising wave execution with minimal surface.
- Expected decomposition:
- - Wave 1: Task 1 (foundation types)
- - Wave 2: Tasks 2, 3 (parallel, independent logger + clock services)
- """
- workdir = Path(workdir)
- _init_base_repo(workdir)
- # Pre-create the barrel file and stub directories the plan references.
- _write_file(workdir, "src/types/index.ts", "export {};\n")
- for d in ("src/services", "tests"):
- _ensure_dir(workdir, d)
- _write_file(workdir, "docs/superpowers/plans/test-plan.md", WAVE_TEST_PLAN_MINIMAL)
- _commit_all_on_feature_branch(workdir)
- # ----------------------------------------------------------------------------
- # Pre-decomposed waves files
- # ----------------------------------------------------------------------------
- WAVE_TEST_SPEC = """\
- # Wave Decomposition Test Specification
- ## Overview
- This specification describes a synthetic TypeScript project used to exercise
- the full wave execution pipeline. The feature is a small, illustrative API
- surface composed of three independent services (auth, users, billing) wired
- together behind a thin routes layer. It exists solely so drill scenarios can
- verify that an agent correctly runs an already-decomposed waves file from
- start to finish.
- ## Scope
- The spec covers:
- - A shared types module that declares the core domain interfaces.
- - Three independent service classes, each with a small happy-path and
- failure-path test suite.
- - An API routes module that composes the three services.
- ## Non-goals
- - Real persistence, real HTTP handling, real authentication. The exercise is
- purely about wave execution mechanics, not production-quality code.
- """
- WAVE_TEST_SPEC_MINIMAL = """\
- # Minimal Wave Execution Test Specification
- ## Overview
- This specification describes a minimal TypeScript project used to exercise
- the wave execution pipeline with the smallest possible task surface. The
- feature is a tiny utility layer composed of two independent services
- (logger, clock) built on top of a shared types module.
- ## Scope
- The spec covers:
- - A shared types module that declares `User` and `Session` interfaces.
- - A logger service with a buffered `info` method.
- - A clock service with a `now()` method returning the current Unix
- timestamp in milliseconds.
- ## Non-goals
- - Log rotation, log transport, time sources other than `Date.now()`, or
- any production-grade concerns. The fixture exists purely to exercise
- wave execution over a small set of parallelizable tasks.
- """
- WAVE_TEST_WAVES_FULL = """\
- ---
- run_id: testw5
- source_plan: docs/superpowers/plans/test-plan.md
- spec_path: docs/superpowers/specs/test-spec.md
- feature_branch: feature/test-implementation
- status: approved
- sequential_time: 8h
- parallel_time: 4h
- savings: 50%
- waves:
- - {wave: 1, strategy: sequential, tasks: [1], depends_on: []}
- - {wave: 2, strategy: parallel, tasks: [2, 3, 4], depends_on: [1]}
- - {wave: 3, strategy: sequential, tasks: [5], depends_on: [2, 3, 4]}
- ---
- # Wave Decomposition Test — Waves File
- ## Waves Overview
- | Wave | Strategy | Tasks | Depends On | Notes |
- |------|------------|-----------|------------|-----------------------------------------|
- | 1 | sequential | 1 | — | Foundation types, must land first |
- | 2 | parallel | 2, 3, 4 | 1 | Independent service implementations |
- | 3 | sequential | 5 | 2, 3, 4 | API routes integration glue |
- **Sequential time estimate:** 8h
- **Parallel time estimate:** 4h
- **Savings:** 50%
- ---
- ## Wave 1 — Foundation (sequential)
- Task 1 must land before any service work can begin because every Wave 2
- service imports from `src/types/index.ts`.
- ### Task 1: Foundation types
- **Files:**
- - Create: `src/types/auth.ts`
- - Create: `src/types/users.ts`
- - Create: `src/types/billing.ts`
- - Modify: `src/types/index.ts`
- **Acceptance Criteria:**
- - `src/types/auth.ts` exports `User` and `Session` interfaces.
- - `src/types/users.ts` exports a `UserProfile` interface with `id` and `email`.
- - `src/types/billing.ts` exports `Plan` and `Subscription` interfaces.
- - `src/types/index.ts` re-exports everything from the three files above.
- - `npm run build` succeeds with no type errors.
- - [ ] **Step 1: Create src/types/auth.ts with User and Session interfaces.**
- - [ ] **Step 2: Create src/types/users.ts with UserProfile interface.**
- - [ ] **Step 3: Create src/types/billing.ts with Plan and Subscription interfaces.**
- - [ ] **Step 4: Update src/types/index.ts to re-export the three modules.**
- - [ ] **Step 5: Run `npm run build` and commit.**
- ---
- ## Wave 2 — Independent services (parallel)
- Tasks 2, 3, and 4 have no file overlap and no cross-task imports; they
- can be executed in parallel in isolated worktrees and merged at the
- wave boundary.
- ### File ownership
- ```
- Task 2 (auth service):
- - src/services/auth.ts [create]
- - tests/auth.test.ts [create]
- Task 3 (users service):
- - src/services/users.ts [create]
- - tests/users.test.ts [create]
- Task 4 (billing service):
- - src/services/billing.ts [create]
- - tests/billing.test.ts [create]
- ```
- No two tasks in Wave 2 touch the same path.
- ### Task 2: Auth service
- **Files:**
- - Create: `src/services/auth.ts`
- - Create: `tests/auth.test.ts`
- **Acceptance Criteria:**
- - `src/services/auth.ts` exports an `AuthService` class with a `login(email, password)` method.
- - `AuthService.login` returns a `Session` imported from `src/types/auth.ts`.
- - `tests/auth.test.ts` covers the happy-path login case.
- - `tests/auth.test.ts` covers an invalid-credentials failure case.
- - `npm test -- tests/auth.test.ts` passes.
- - [ ] **Step 1: Write tests/auth.test.ts covering login success and failure.**
- - [ ] **Step 2: Implement src/services/auth.ts to make the tests pass.**
- - [ ] **Step 3: Run `npm test -- tests/auth.test.ts` and commit.**
- ### Task 3: Users service
- **Files:**
- - Create: `src/services/users.ts`
- - Create: `tests/users.test.ts`
- **Acceptance Criteria:**
- - `src/services/users.ts` exports a `UsersService` class with `getProfile(id)`.
- - `UsersService.getProfile` returns a `UserProfile` imported from `src/types/users.ts`.
- - `tests/users.test.ts` covers the happy-path lookup case.
- - `tests/users.test.ts` covers a not-found case.
- - `npm test -- tests/users.test.ts` passes.
- - [ ] **Step 1: Write tests/users.test.ts covering getProfile success and missing.**
- - [ ] **Step 2: Implement src/services/users.ts to make the tests pass.**
- - [ ] **Step 3: Run `npm test -- tests/users.test.ts` and commit.**
- ### Task 4: Billing service
- **Files:**
- - Create: `src/services/billing.ts`
- - Create: `tests/billing.test.ts`
- **Acceptance Criteria:**
- - `src/services/billing.ts` exports a `BillingService` class with `subscribe(userId, planId)`.
- - `BillingService.subscribe` returns a `Subscription` imported from `src/types/billing.ts`.
- - `tests/billing.test.ts` covers a successful subscription.
- - `tests/billing.test.ts` covers a failed subscription.
- - `npm test -- tests/billing.test.ts` passes.
- - [ ] **Step 1: Write tests/billing.test.ts covering subscribe success and failure.**
- - [ ] **Step 2: Implement src/services/billing.ts to make the tests pass.**
- - [ ] **Step 3: Run `npm test -- tests/billing.test.ts` and commit.**
- ---
- ## Wave 3 — Integration (sequential)
- Task 5 depends on every Wave 2 service being merged; it can only start
- once Wave 2 is fully integrated onto the feature branch.
- ### Task 5: API routes
- **Files:**
- - Create: `src/api/routes.ts`
- - Modify: `src/index.ts`
- **Acceptance Criteria:**
- - `src/api/routes.ts` imports `AuthService`, `UsersService`, and `BillingService`.
- - `src/api/routes.ts` exports a `registerRoutes(app)` function that wires the three services.
- - `src/index.ts` imports `registerRoutes` and calls it with the app.
- - `npm run build` succeeds.
- - `npm test` passes end to end.
- - [ ] **Step 1: Create src/api/routes.ts that composes the three services.**
- - [ ] **Step 2: Update src/index.ts to register the routes on startup.**
- - [ ] **Step 3: Run `npm run build && npm test` and commit.**
- """
- WAVE_TEST_WAVES_MINIMAL = """\
- ---
- run_id: testw3
- source_plan: docs/superpowers/plans/test-plan.md
- spec_path: docs/superpowers/specs/test-spec.md
- feature_branch: feature/test-implementation
- status: approved
- sequential_time: 3h
- parallel_time: 2h
- savings: 33%
- waves:
- - {wave: 1, strategy: sequential, tasks: [1], depends_on: []}
- - {wave: 2, strategy: parallel, tasks: [2, 3], depends_on: [1]}
- ---
- # Minimal Wave Execution — Waves File
- ## Waves Overview
- | Wave | Strategy | Tasks | Depends On | Notes |
- |------|------------|-------|------------|-----------------------------------|
- | 1 | sequential | 1 | — | Foundation types, must land first |
- | 2 | parallel | 2, 3 | 1 | Independent logger + clock |
- **Sequential time estimate:** 3h
- **Parallel time estimate:** 2h
- **Savings:** 33%
- ---
- ## Wave 1 — Foundation (sequential)
- ### Task 1: Foundation types
- **Files:**
- - Create: `src/types/core.ts`
- - Modify: `src/types/index.ts`
- **Acceptance Criteria:**
- - `src/types/core.ts` exports a `User` interface with `id` and `email`.
- - `src/types/core.ts` exports a `Session` interface with `userId` and `token`.
- - `src/types/index.ts` re-exports everything from `src/types/core.ts`.
- - `npm run build` succeeds with no type errors.
- - [ ] **Step 1: Create src/types/core.ts with User and Session interfaces.**
- - [ ] **Step 2: Update src/types/index.ts to re-export from ./core.**
- - [ ] **Step 3: Run `npm run build` and commit.**
- ---
- ## Wave 2 — Independent services (parallel)
- Tasks 2 and 3 have no file overlap and no cross-task imports; they can
- be executed in parallel in isolated worktrees and merged at the wave
- boundary.
- ### File ownership
- ```
- Task 2 (logger service):
- - src/services/logger.ts [create]
- - tests/logger.test.ts [create]
- Task 3 (clock service):
- - src/services/clock.ts [create]
- - tests/clock.test.ts [create]
- ```
- No two tasks in Wave 2 touch the same path.
- ### Task 2: Logger service
- **Files:**
- - Create: `src/services/logger.ts`
- - Create: `tests/logger.test.ts`
- **Acceptance Criteria:**
- - `src/services/logger.ts` exports a `Logger` class with an `info(message: string)` method.
- - `Logger.info` appends a timestamped entry to an internal buffer.
- - `tests/logger.test.ts` covers a happy-path info case.
- - `tests/logger.test.ts` covers a repeated-call buffering case.
- - `npm test -- tests/logger.test.ts` passes.
- - [ ] **Step 1: Write tests/logger.test.ts covering info and buffering.**
- - [ ] **Step 2: Implement src/services/logger.ts to make the tests pass.**
- - [ ] **Step 3: Run `npm test -- tests/logger.test.ts` and commit.**
- ### Task 3: Clock service
- **Files:**
- - Create: `src/services/clock.ts`
- - Create: `tests/clock.test.ts`
- **Acceptance Criteria:**
- - `src/services/clock.ts` exports a `Clock` class with a `now(): number` method.
- - `Clock.now` returns the current Unix timestamp in milliseconds.
- - `tests/clock.test.ts` covers a happy-path now case.
- - `tests/clock.test.ts` covers the return value being a finite number.
- - `npm test -- tests/clock.test.ts` passes.
- - [ ] **Step 1: Write tests/clock.test.ts covering now success and type.**
- - [ ] **Step 2: Implement src/services/clock.ts to make the tests pass.**
- - [ ] **Step 3: Run `npm test -- tests/clock.test.ts` and commit.**
- """
- WAVE_TEST_PLAN_BROKEN_TASK = """\
- # Wave Execution Failure Test Implementation Plan
- > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development
- > (recommended) or superpowers:executing-plans to implement this plan task-by-task.
- **Goal:** Exercise wave execution's failure escalation path. Tasks 1 and 2
- should succeed normally. Task 3 is **structurally impossible** — its
- pre-existing test file contains mutually contradictory assertions that
- no implementation can satisfy, and the task scope explicitly forbids
- modifying the test file.
- **Architecture:** Foundation types feed two parallel services. The second
- parallel service (Task 3) is wired up so that the orchestrator must
- detect a real failure, retry once, and escalate to the user.
- **Tech Stack:** TypeScript, Jest.
- ---
- ### Task 1: Foundation types
- **Files:**
- - Create: `src/types/core.ts`
- - Modify: `src/types/index.ts`
- **Acceptance Criteria:**
- - `src/types/core.ts` exports a `User` interface with `id` and `email`.
- - `src/types/core.ts` exports a `Session` interface with `userId` and `token`.
- - `src/types/index.ts` re-exports everything from `src/types/core.ts`.
- - `npm run build` succeeds with no type errors.
- - [ ] **Step 1: Create src/types/core.ts with User and Session interfaces.**
- - [ ] **Step 2: Update src/types/index.ts to re-export from ./core.**
- - [ ] **Step 3: Run `npm run build` and commit.**
- ---
- ### Task 2: Logger service
- **Files:**
- - Create: `src/services/logger.ts`
- - Create: `tests/logger.test.ts`
- **Acceptance Criteria:**
- - `src/services/logger.ts` exports a `Logger` class with an `info(message: string)` method.
- - `Logger.info` appends a timestamped entry to an internal buffer.
- - `tests/logger.test.ts` covers a happy-path info case.
- - `tests/logger.test.ts` covers a repeated-call buffering case.
- - `npm test -- tests/logger.test.ts` passes.
- - [ ] **Step 1: Write tests/logger.test.ts covering info and buffering.**
- - [ ] **Step 2: Implement src/services/logger.ts to make the tests pass.**
- - [ ] **Step 3: Run `npm test -- tests/logger.test.ts` and commit.**
- ---
- ### Task 3: Counter service (impossible — DO NOT modify test file)
- **Files:**
- - Create: `src/services/counter.ts`
- - Pre-existing (DO NOT modify): `tests/counter.test.ts`
- **Acceptance Criteria:**
- - `src/services/counter.ts` exports a `Counter` class with a `compute(n: number): number` method.
- - `tests/counter.test.ts` already exists. **You MUST NOT modify or delete it.**
- - `npm test -- tests/counter.test.ts` passes against the pre-existing test file.
- - `npm run build` succeeds.
- - [ ] **Step 1: Read the pre-existing tests/counter.test.ts and understand its assertions.**
- - [ ] **Step 2: Implement src/services/counter.ts to satisfy every assertion in the existing test file (without changing the test file).**
- - [ ] **Step 3: Run `npm test -- tests/counter.test.ts` and `npm run build`, then commit.**
- """
- # Pre-existing test file for the broken Task 3. This file is committed
- # to the repo BEFORE the implementer runs. It contains mutually
- # contradictory assertions: compute(1) is asserted to equal both 1 AND
- # 2 in two separate `it` blocks. No implementation of `compute` can
- # satisfy both assertions simultaneously, so `npm test` will always
- # report a failing test for one of the two cases, no matter what the
- # implementer writes. The implementer cannot modify the test file
- # because the task acceptance criteria explicitly forbid it. This
- # produces a structural failure that the orchestrator must detect.
- COUNTER_FAILING_TEST = """\
- import { Counter } from '../src/services/counter';
- describe('Counter', () => {
- // The two assertions below are mutually contradictory by design.
- // No implementation of compute(n) can make both tests pass at once,
- // and the task scope forbids modifying this file. The orchestrator
- // should detect the failure, retry once, then escalate to the user.
- it('compute(1) returns 1', () => {
- const counter = new Counter();
- expect(counter.compute(1)).toBe(1);
- });
- it('compute(1) returns 2', () => {
- const counter = new Counter();
- expect(counter.compute(1)).toBe(2);
- });
- });
- """
- WAVE_TEST_SPEC_BROKEN_TASK = """\
- # Wave Execution Failure Test Specification
- ## Overview
- This specification describes a synthetic TypeScript project used to
- exercise the wave execution skill's failure-handling and escalation
- path. It is intentionally constructed so that one task in a parallel
- wave cannot succeed.
- ## Scope
- The spec covers:
- - A shared types module that declares `User` and `Session` interfaces.
- - A logger service with a buffered `info` method (Task 2 — should pass).
- - A counter service whose pre-existing test file contains mutually
- contradictory assertions (Task 3 — must fail).
- ## Non-goals
- - A working counter service. Task 3 is a deliberate failure injection,
- not a real feature. The fixture exists purely to verify that the
- orchestrator detects the failure, retries once per the failure
- handling matrix, and escalates to the user instead of silently
- proceeding.
- """
- WAVE_TEST_WAVES_BROKEN_TASK = """\
- ---
- run_id: testfwf
- source_plan: docs/superpowers/plans/test-plan.md
- spec_path: docs/superpowers/specs/test-spec.md
- feature_branch: feature/test-implementation
- status: approved
- sequential_time: 3h
- parallel_time: 2h
- savings: 33%
- waves:
- - {wave: 1, strategy: sequential, tasks: [1], depends_on: []}
- - {wave: 2, strategy: parallel, tasks: [2, 3], depends_on: [1]}
- ---
- # Wave Execution Failure Test — Waves File
- ## Waves Overview
- | Wave | Strategy | Tasks | Depends On | Notes |
- |------|------------|-------|------------|------------------------------------------------|
- | 1 | sequential | 1 | — | Foundation types, must land first |
- | 2 | parallel | 2, 3 | 1 | Logger (passes) + Counter (structurally fails) |
- **Sequential time estimate:** 3h
- **Parallel time estimate:** 2h
- **Savings:** 33%
- ---
- ## Wave 1 — Foundation (sequential)
- ### Task 1: Foundation types
- **Files:**
- - Create: `src/types/core.ts`
- - Modify: `src/types/index.ts`
- **Acceptance Criteria:**
- - `src/types/core.ts` exports a `User` interface with `id` and `email`.
- - `src/types/core.ts` exports a `Session` interface with `userId` and `token`.
- - `src/types/index.ts` re-exports everything from `src/types/core.ts`.
- - `npm run build` succeeds with no type errors.
- - [ ] **Step 1: Create src/types/core.ts with User and Session interfaces.**
- - [ ] **Step 2: Update src/types/index.ts to re-export from ./core.**
- - [ ] **Step 3: Run `npm run build` and commit.**
- ---
- ## Wave 2 — Independent services (parallel)
- Tasks 2 and 3 have no file overlap and no cross-task imports; they can
- be executed in parallel in isolated worktrees and merged at the wave
- boundary.
- ### File ownership
- ```
- Task 2 (logger service):
- - src/services/logger.ts [create]
- - tests/logger.test.ts [create]
- Task 3 (counter service):
- - src/services/counter.ts [create]
- - tests/counter.test.ts [pre-existing — DO NOT modify]
- ```
- No two tasks in Wave 2 touch the same path.
- ### Task 2: Logger service
- **Files:**
- - Create: `src/services/logger.ts`
- - Create: `tests/logger.test.ts`
- **Acceptance Criteria:**
- - `src/services/logger.ts` exports a `Logger` class with an `info(message: string)` method.
- - `Logger.info` appends a timestamped entry to an internal buffer.
- - `tests/logger.test.ts` covers a happy-path info case.
- - `tests/logger.test.ts` covers a repeated-call buffering case.
- - `npm test -- tests/logger.test.ts` passes.
- - [ ] **Step 1: Write tests/logger.test.ts covering info and buffering.**
- - [ ] **Step 2: Implement src/services/logger.ts to make the tests pass.**
- - [ ] **Step 3: Run `npm test -- tests/logger.test.ts` and commit.**
- ### Task 3: Counter service (impossible — DO NOT modify test file)
- **Files:**
- - Create: `src/services/counter.ts`
- - Pre-existing (DO NOT modify): `tests/counter.test.ts`
- **Acceptance Criteria:**
- - `src/services/counter.ts` exports a `Counter` class with a `compute(n: number): number` method.
- - `tests/counter.test.ts` already exists. **You MUST NOT modify or delete it.**
- - `npm test -- tests/counter.test.ts` passes against the pre-existing test file.
- - `npm run build` succeeds.
- - [ ] **Step 1: Read the pre-existing tests/counter.test.ts and understand its assertions.**
- - [ ] **Step 2: Implement src/services/counter.ts to satisfy every assertion in the existing test file (without changing the test file).**
- - [ ] **Step 3: Run `npm test -- tests/counter.test.ts` and `npm run build`, then commit.**
- """
- def _commit_waves_file(workdir: Path) -> None:
- """Stage and commit the waves file + spec on the feature branch.
- Assumes the caller already created the underlying plan repo and is
- sitting on feature/test-implementation (the create_wave_test_repo*
- helpers leave us there).
- """
- _git(["git", "add", "-A"], cwd=workdir)
- _git(["git", "commit", "-m", "add pre-decomposed waves file and spec"], cwd=workdir)
- def create_waves_file(workdir: Path) -> None:
- """Create the full 5-task repo with a pre-decomposed .waves.md file.
- This is the starting point for `executing-waves` scenarios that
- want the full 3-wave experience. The waves file is marked
- `status: approved` so the executing-waves pre-flight check passes.
- """
- workdir = Path(workdir)
- create_wave_test_repo(workdir)
- _write_file(
- workdir,
- "docs/superpowers/specs/test-spec.md",
- WAVE_TEST_SPEC,
- )
- _write_file(
- workdir,
- "docs/superpowers/plans/test-plan.waves.md",
- WAVE_TEST_WAVES_FULL,
- )
- _commit_waves_file(workdir)
- def create_waves_file_minimal(workdir: Path) -> None:
- """Create the 3-task minimal repo with a pre-decomposed .waves.md file.
- This is the starting point for smaller `executing-waves` scenarios
- that exercise the same execution pipeline over 1 sequential task +
- 2 parallel tasks. The waves file is marked `status: approved` so
- the executing-waves pre-flight check passes.
- """
- workdir = Path(workdir)
- create_wave_test_repo_minimal(workdir)
- _write_file(
- workdir,
- "docs/superpowers/specs/test-spec.md",
- WAVE_TEST_SPEC_MINIMAL,
- )
- _write_file(
- workdir,
- "docs/superpowers/plans/test-plan.waves.md",
- WAVE_TEST_WAVES_MINIMAL,
- )
- _commit_waves_file(workdir)
- def create_waves_file_with_broken_task(workdir: Path) -> None:
- """Create a 3-task waves repo where Task 3 is structurally impossible.
- This is the starting point for `executing-waves` failure scenarios.
- Layout:
- - Wave 1 (sequential): Task 1 — foundation types (passes normally)
- - Wave 2 (parallel): Task 2 — logger service (passes normally)
- Task 3 — counter service (always fails)
- Task 3's failure is structural, not a prompt trick: a pre-existing
- `tests/counter.test.ts` file is committed before the implementer
- runs and contains two contradictory assertions (`compute(1) === 1`
- AND `compute(1) === 2`). The acceptance criteria explicitly forbid
- modifying the test file. No implementation can make both tests
- pass, so `npm test` always reports a failure for one of the two
- cases.
- Expected orchestrator behavior (per failure-handling.md):
- 1. Detect Task 3 failure after the parallel wave runs.
- 2. Merge Task 2 (the successful task) onto the feature branch.
- 3. Retry Task 3 once from the updated tip.
- 4. Retry also fails.
- 5. Escalate to the user with the standard escalation message.
- """
- workdir = Path(workdir)
- create_wave_test_repo_minimal(workdir)
- # Overwrite the plan with the broken-task variant.
- _write_file(
- workdir,
- "docs/superpowers/plans/test-plan.md",
- WAVE_TEST_PLAN_BROKEN_TASK,
- )
- # Pre-create the failing test fixture for Task 3. The implementer
- # must NOT modify it (per the task acceptance criteria), so the
- # contradictory assertions guarantee a structural failure.
- _write_file(
- workdir,
- "tests/counter.test.ts",
- COUNTER_FAILING_TEST,
- )
- _write_file(
- workdir,
- "docs/superpowers/specs/test-spec.md",
- WAVE_TEST_SPEC_BROKEN_TASK,
- )
- _write_file(
- workdir,
- "docs/superpowers/plans/test-plan.waves.md",
- WAVE_TEST_WAVES_BROKEN_TASK,
- )
- _commit_waves_file(workdir)
- def create_conflict_surface_repo(workdir: Path) -> None:
- """Create a plan where three tasks implicitly modify the same barrel file.
- The `src/services/index.ts` barrel file is pre-created so the
- decomposer sees it during directory scanning. Each task in the plan
- lists only its new module file but the steps mention adding an
- export to the barrel — the conflict-surface heuristic should notice
- this and either add the barrel file to each task's list or serialize
- the tasks.
- Expected decomposition (under a correct heuristic): either
- - all tasks in one wave with `src/services/index.ts` added to each
- task's file list, or
- - sequential waves (serialized) to avoid the shared barrel.
- """
- workdir = Path(workdir)
- _init_base_repo(workdir)
- # The barrel file MUST exist before the plan runs.
- _write_file(workdir, "src/services/index.ts", "export {};\n")
- _write_file(workdir, "docs/superpowers/plans/test-plan.md", CONFLICT_SURFACE_PLAN)
- _commit_all_on_feature_branch(workdir)
|