Skip to content

fix(orchestrator): respect custom base branch in exec zero-diff guard (#534 follow-up) #537

@admarble

Description

@admarble

Summary

The zero-diff exec guard added in #534 (phase-executor.ts:hasExecChanges) hardcodes origin/main as the base ref:

execSync("git rev-list --count origin/main..HEAD", { cwd, stdio: "pipe" })

When a worktree is created with a custom base via ./scripts/dev/new-feature.sh <issue> --base feature/X, HEAD already has commits relative to origin/main from the moment the worktree is created (the parent feature branch's diff). The guard sees count > 0, reports hasExecChanges = true, and the exec phase can produce zero new commits without being caught — the same failure mode #534 was trying to prevent, but scoped to custom-base worktrees.

/fullsolve and /exec both document --base feature/<branch> as a supported pattern (for epic-style integration branches and feature flag staging), so this is a real configuration we ship, not a theoretical edge case.

Evidence / Reproduction

  1. Create a worktree off a populated feature branch:
    ./scripts/dev/new-feature.sh 999 --base feature/some-epic
  2. The new worktree's HEAD shares its tip with feature/some-epic, which itself has N commits on top of origin/main.
  3. git rev-list --count origin/main..HEAD → N (not 0).
  4. Run exec against an agent that produces nothing.
  5. hasExecChanges returns true → exec is marked success: true → same end-state as the original fix(orchestrator): treat null QA verdict and zero-diff exec as failure, not success #534 bug: failure surfaces only at PR creation with "No commits between main and feature/…" or passes silently into QA.

Root Cause

hasExecChanges has no notion of the worktree's configured base branch. The correct base is whatever was passed to new-feature.sh --base, stored implicitly in git (the initial commit the branch was created at), or looked up via upstream tracking.

Acceptance Criteria

  • AC-1: hasExecChanges(cwd) resolves the correct base ref for the worktree before counting. At least one of:
    • Read the base ref from a worktree-local marker that new-feature.sh writes (e.g. .sequant/base-ref inside the worktree, containing origin/feature/X).
    • Use the branch's upstream tracking ref if set (git rev-parse --abbrev-ref '@{u}' inside the worktree, falling back to merge-base lookup).
    • Read the base from the branch name convention (e.g. git config branch.<current>.sequantBase) written by new-feature.sh.
  • AC-2: scripts/dev/new-feature.sh records the --base value (defaulting to main) in whichever mechanism AC-1 chose. Backfill recorded base for existing worktrees as part of the migration, OR document that the fix only applies to worktrees created after this change ships.
  • AC-3: hasExecChanges falls back to origin/main when no recorded base exists (backward compatibility with pre-fix worktrees and with non-sequant-managed worktrees). Behavior under fallback matches current fix(orchestrator): treat null QA verdict and zero-diff exec as failure, not success #534 behavior.
  • AC-4: Unit tests cover: custom-base worktree with new commits (passes), custom-base worktree with zero new commits relative to the recorded base (fails with the same error string as fix(orchestrator): treat null QA verdict and zero-diff exec as failure, not success #534), custom-base worktree with uncommitted work (passes), worktree with no recorded base (falls back to origin/main, original fix(orchestrator): treat null QA verdict and zero-diff exec as failure, not success #534 behavior preserved).
  • AC-5: mapAgentSuccessToPhaseResult still calls hasExecChanges(cwd) — the base-resolution logic lives inside the helper, not at the call site. Consumers don't need to know about bases.
  • AC-6: Integration test or documented manual reproducer: create a worktree with --base feature/<branch> on a branch that is N commits ahead of main, run an exec that produces zero new commits, verify the phase is reported as failed. This is the primary validation that the bug is actually fixed end-to-end.
  • AC-7: CHANGELOG.md entry under [Unreleased] / Fixed referencing this issue.

Non-Goals

Dependencies

Complexity

small-to-medium — single helper + one shell script, plus test matrix. Single worktree, no skill-sync. Estimated 1–2 AC-units of implementation, ~50-100 LOC including tests.

Why this matters

Custom-base worktrees are the exact case where #534's failure mode is hardest to spot: the branch is already long-lived, already has commits, and a silent zero-progress exec is easier to miss in review. Leaving this gap means #534 partially fixes the orchestrator but ships a known hole for the epic-integration pattern.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingplannedImplementation plan approved

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions