Fix: Implement proper branch lifecycle management

Resolved 💬 4 comments Opened Nov 5, 2025 by sl-factory[bot] Closed Jan 9, 2026

Summary

Implement proper branch lifecycle management: create unique branches per ticket, cleanup after merge, ensure clean state between tickets.

Problem (Bug #6 from #167)

Ticket #1 created feature/ticket-1-project-structure, PR #17 merged.
Ticket #2 started without creating new branch, continued working on feature/ticket-1-project-structure, created PR #18 on the same branch.

Impact:

  • Branch pollution (multiple PRs on same branch)
  • Merge conflicts between tickets
  • Hard to track which commit belongs to which ticket
  • Can't work on tickets in parallel

Root Cause

Two problems:

  1. Orchestrator doesn't clean up after PR merge
  • After merging PR, repository stays on feature branch
  • No checkout to main
  • No branch deletion
  1. Developer doesn't create new branch per ticket
  • Developer starts working without checking current branch
  • Continues on whatever branch is checked out
  • No validation that branch is unique to this ticket

Solution

Fix 1: Orchestrator branch cleanup

Location: src/factory/orchestration/ticket_executor.py after merge_pr_and_close_ticket()

def execute_ticket(self, ticket_id: int, sprint: Sprint) -> tuple[TicketExecutionResult, Sprint]:
    # ... existing code ...

    if review_outcome == "APPROVED":
        # Merge PR and close ticket
        self.github.merge_pr_and_close_ticket(
            ticket_id,
            pr_number,
            metrics=metrics,
        )

        # NEW: Clean up branch after merge
        try:
            # Get branch name from PR
            pr = self.github.get_pull_request(pr_number)
            branch_name = pr.head.ref

            # Switch back to main and pull latest
            subprocess.run(
                ["git", "checkout", "main"],
                cwd=self.project_path,
                check=True,
                capture_output=True,
            )
            subprocess.run(
                ["git", "pull"],
                cwd=self.project_path,
                check=True,
                capture_output=True,
            )

            # Delete feature branch locally
            subprocess.run(
                ["git", "branch", "-d", branch_name],
                cwd=self.project_path,
                check=False,  # Don't fail if branch doesn't exist
                capture_output=True,
            )

            logger.info(f"Cleaned up branch {branch_name}")
        except Exception as e:
            logger.warning(f"Branch cleanup failed: {e}")
            # Don't fail ticket execution for cleanup issues

Fix 2: Developer must create unique branch

Location: src/factory/prompts/developer.md

Add to Developer instructions:

## Branch Management (CRITICAL)

**ALWAYS create a new branch at the start of each ticket:**

1. Check current branch: Use `run_command("git branch --show-current")`
2. If not on 'main', checkout main first: `run_command("git checkout main && git pull")`
3. Create unique branch: `create_branch(f"feature/ticket-{ticket_id}-{slug}")`
   - Use ticket ID in branch name
   - Use short slug from ticket title
   - Example: `feature/ticket-42-add-authentication`

**NEVER reuse existing feature branches.**

If you find yourself on a feature branch from another ticket, STOP and checkout main first.

Location: src/factory/agents/developer.py in implement_ticket()

Add validation:

def implement_ticket(self, project_path: str, ticket_id: int, stream: bool = True) -> AgentResponse:
    # Check current branch before starting
    result = subprocess.run(
        ["git", "branch", "--show-current"],
        cwd=project_path,
        capture_output=True,
        text=True,
    )
    current_branch = result.stdout.strip()

    # Warn if not on main (agent should switch)
    if current_branch != "main":
        logger.warning(
            f"Starting ticket #{ticket_id} on branch '{current_branch}' (expected 'main'). "
            f"Developer should checkout main and create new branch."
        )

    # ... rest of implementation ...

Test Plan

  1. Unit test for branch cleanup:
  • Mock successful PR merge
  • Verify git checkout main called
  • Verify git pull called
  • Verify git branch -d <branch> called
  1. E2E test:
  • Execute two tickets sequentially
  • After Ticket #1 merge, verify on 'main' branch
  • Verify Ticket #2 creates NEW branch (not reusing Ticket #1's)
  • Verify both PRs on different branches
  1. Validation test:
  • Start ticket while on feature branch
  • Verify warning logged
  • Verify Developer switches to main and creates new branch

Acceptance Criteria

  • [ ] Orchestrator cleans up branch after PR merge
  • [ ] Orchestrator switches to main and pulls latest
  • [ ] Developer prompt includes branch management instructions
  • [ ] Developer checks current branch before starting
  • [ ] Warning logged if starting on wrong branch
  • [ ] Unit tests for branch cleanup
  • [ ] E2E test: two tickets use different branches
  • [ ] Documentation: Branch lifecycle

Related Issues

  • Fixes Bug #6 in #167
  • Prerequisite for parallel ticket execution (#173)

Priority

High - Prevents branch pollution and merge conflicts.

View original on GitHub ↗

This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗