diff --git a/codev-skeleton/protocols/aspir/builder-prompt.md b/codev-skeleton/protocols/aspir/builder-prompt.md index 48ec8a425..266fd7b96 100644 --- a/codev-skeleton/protocols/aspir/builder-prompt.md +++ b/codev-skeleton/protocols/aspir/builder-prompt.md @@ -53,13 +53,23 @@ Follow the implementation plan at: `{{plan.path}}` {{task_text}} {{/if}} -## Multi-PR Workflow +## PR Strategy -Your worktree is persistent — it survives across PR merges. You can produce multiple PRs sequentially: +**Do not autonomously open a PR per implementation phase.** Plan phases ship as git commits within a single PR, not as separate PRs. The plan's instruction that "each phase commits independently" refers to git commits, not PRs. + +By default, the PR is opened during/after the final implement phase, with all phase-commits already on the branch. + +### Architect-requested PRs + +The architect MAY request a PR at any point — for spec review, mid-implementation feedback, slicing a large spec into shippable PRs, etc. When the architect explicitly asks for a PR earlier (or for additional PRs), follow that direction. The prohibition is specifically on the *builder* autonomously deciding to open per-phase PRs without architect request. + +### Multi-PR Mechanics (when the architect requests sequential PRs) + +Your worktree is persistent — it survives across PR merges. When the architect asks for sequential PRs (e.g., to slice a large spec into shippable pieces), use this loop: 1. Cut a branch, open a PR, wait for merge 2. After merge: `git fetch origin main && git checkout -b origin/main` -3. Continue to the next phase, open another PR +3. Continue to the next slice, open another PR **Important**: Do NOT run `git checkout main` — git worktrees cannot check out a branch that's checked out elsewhere. Always branch off `origin/main` via fetch. diff --git a/codev-skeleton/protocols/spir/builder-prompt.md b/codev-skeleton/protocols/spir/builder-prompt.md index 1abf4b289..4e4e81d8f 100644 --- a/codev-skeleton/protocols/spir/builder-prompt.md +++ b/codev-skeleton/protocols/spir/builder-prompt.md @@ -53,13 +53,23 @@ Follow the implementation plan at: `{{plan.path}}` {{task_text}} {{/if}} -## Multi-PR Workflow +## PR Strategy -Your worktree is persistent — it survives across PR merges. You can produce multiple PRs sequentially: +**Do not autonomously open a PR per implementation phase.** Plan phases ship as git commits within a single PR, not as separate PRs. The plan's instruction that "each phase commits independently" refers to git commits, not PRs. + +By default, the PR is opened during/after the final implement phase, with all phase-commits already on the branch. + +### Architect-requested PRs + +The architect MAY request a PR at any point — for spec review, mid-implementation feedback, slicing a large spec into shippable PRs, etc. When the architect explicitly asks for a PR earlier (or for additional PRs), follow that direction. The prohibition is specifically on the *builder* autonomously deciding to open per-phase PRs without architect request. + +### Multi-PR Mechanics (when the architect requests sequential PRs) + +Your worktree is persistent — it survives across PR merges. When the architect asks for sequential PRs (e.g., to slice a large spec into shippable pieces), use this loop: 1. Cut a branch, open a PR, wait for merge 2. After merge: `git fetch origin main && git checkout -b origin/main` -3. Continue to the next phase, open another PR +3. Continue to the next slice, open another PR 4. Repeat **Important**: Do NOT run `git checkout main` — git worktrees cannot check out a branch that's checked out elsewhere. Always branch off `origin/main` via fetch. diff --git a/codev/projects/bugfix-744-spir-builder-prompt-ambiguous-/status.yaml b/codev/projects/bugfix-744-spir-builder-prompt-ambiguous-/status.yaml new file mode 100644 index 000000000..654c26321 --- /dev/null +++ b/codev/projects/bugfix-744-spir-builder-prompt-ambiguous-/status.yaml @@ -0,0 +1,12 @@ +id: bugfix-744 +title: spir-builder-prompt-ambiguous- +protocol: bugfix +phase: verified +plan_phases: [] +current_plan_phase: null +gates: {} +iteration: 1 +build_complete: false +history: [] +started_at: '2026-05-14T20:58:56.293Z' +updated_at: '2026-05-14T21:12:13.608Z' diff --git a/codev/protocols/aspir/builder-prompt.md b/codev/protocols/aspir/builder-prompt.md index 2715ed877..3ea4c9fac 100644 --- a/codev/protocols/aspir/builder-prompt.md +++ b/codev/protocols/aspir/builder-prompt.md @@ -53,6 +53,16 @@ Follow the implementation plan at: `{{plan.path}}` {{task_text}} {{/if}} +## PR Strategy + +**Do not autonomously open a PR per implementation phase.** Plan phases ship as git commits within a single PR, not as separate PRs. The plan's instruction that "each phase commits independently" refers to git commits, not PRs. + +By default, the PR is opened during/after the final implement phase, with all phase-commits already on the branch. + +### Architect-requested PRs + +The architect MAY request a PR at any point — for spec review, mid-implementation feedback, slicing a large spec into shippable PRs, etc. When the architect explicitly asks for a PR earlier (or for additional PRs), follow that direction. The prohibition is specifically on the *builder* autonomously deciding to open per-phase PRs without architect request. + ## Notifications Always use `afx send architect "..."` to notify the architect at key moments: - **Gate reached**: `afx send architect "Project {{project_id}}: ready for approval"` diff --git a/codev/protocols/spir/builder-prompt.md b/codev/protocols/spir/builder-prompt.md index c905b4696..e3afa0e79 100644 --- a/codev/protocols/spir/builder-prompt.md +++ b/codev/protocols/spir/builder-prompt.md @@ -53,6 +53,16 @@ Follow the implementation plan at: `{{plan.path}}` {{task_text}} {{/if}} +## PR Strategy + +**Do not autonomously open a PR per implementation phase.** Plan phases ship as git commits within a single PR, not as separate PRs. The plan's instruction that "each phase commits independently" refers to git commits, not PRs. + +By default, the PR is opened during/after the final implement phase, with all phase-commits already on the branch. + +### Architect-requested PRs + +The architect MAY request a PR at any point — for spec review, mid-implementation feedback, slicing a large spec into shippable PRs, etc. When the architect explicitly asks for a PR earlier (or for additional PRs), follow that direction. The prohibition is specifically on the *builder* autonomously deciding to open per-phase PRs without architect request. + ## Notifications Always use `afx send architect "..."` to notify the architect at key moments: - **Gate reached**: `afx send architect "Project {{project_id}}: ready for approval"` diff --git a/packages/codev/src/__tests__/bugfix-744-spir-pr-strategy.test.ts b/packages/codev/src/__tests__/bugfix-744-spir-pr-strategy.test.ts new file mode 100644 index 000000000..4a4d2aa7e --- /dev/null +++ b/packages/codev/src/__tests__/bugfix-744-spir-pr-strategy.test.ts @@ -0,0 +1,60 @@ +/** + * Regression test for GitHub Issue #744 + * + * The SPIR/ASPIR builder-prompt templates did not state the PR-strategy + * convention explicitly. Builders interpreted "each phase commits + * independently" as "each phase gets its own PR" and shipped per-phase + * PRs that the architect then had to close. + * + * This test verifies that all four SPIR/ASPIR builder-prompt files contain: + * 1. An explicit prohibition on the builder autonomously opening a PR + * per implementation phase. + * 2. The clarification that "each phase commits independently" refers + * to git commits, not PRs. + * 3. The architect-override carve-out — the architect may still request + * a PR at any point (spec review, mid-impl feedback, slicing, etc.). + */ + +import { describe, it, expect } from 'vitest'; +import * as fs from 'node:fs'; +import * as path from 'node:path'; + +const repoRoot = path.resolve(__dirname, '..', '..', '..', '..'); + +const PROMPT_FILES = [ + 'codev/protocols/spir/builder-prompt.md', + 'codev-skeleton/protocols/spir/builder-prompt.md', + 'codev/protocols/aspir/builder-prompt.md', + 'codev-skeleton/protocols/aspir/builder-prompt.md', +]; + +describe('bugfix-744: SPIR/ASPIR builder-prompt PR strategy', () => { + for (const relPath of PROMPT_FILES) { + const fullPath = path.join(repoRoot, relPath); + + it(`${relPath} — prohibits builder from autonomously opening per-phase PRs`, () => { + const content = fs.readFileSync(fullPath, 'utf-8'); + expect(content).toMatch(/Do not autonomously open a PR per implementation phase/); + }); + + it(`${relPath} — clarifies phase-commits are git commits, not PRs`, () => { + const content = fs.readFileSync(fullPath, 'utf-8'); + expect(content).toMatch(/refers to git commits, not PRs/); + }); + + it(`${relPath} — preserves architect-override carve-out`, () => { + const content = fs.readFileSync(fullPath, 'utf-8'); + // The architect must be explicitly allowed to request a PR at any point — + // the prohibition is on autonomous builder action, not on PRs themselves. + expect(content).toMatch(/architect MAY request a PR/i); + }); + + it(`${relPath} — states the default PR-timing (during/after final implement phase)`, () => { + const content = fs.readFileSync(fullPath, 'utf-8'); + // The new default replaces the old rigid "ONE PR per spec, opened at the end of + // the implement phase" wording. Builders need to know *when* the default PR opens + // so they don't fall back to per-phase PRs in the absence of architect direction. + expect(content).toMatch(/By default, the PR is opened during\/after the final implement phase/); + }); + } +});