Skip to content

bug(project): ao project add permanently adopts whatever branch is checked out at registration time as the project default, diverging from main #286

@neversettle17-101

Description

@neversettle17-101

Bug

ao project add records the repo's currently checked-out branch as the project's permanent defaultBranch, instead of the repo's actual default branch (origin/HEAD, typically main). If a user happens to be mid-feature-work (e.g. on fix/some-branch) when they register a project, AO mistakes that personal/transient branch for the project's base branch — and every worker spawned afterward bases its worktree off that stale feature branch instead of main, forever, with no resync and no warning.

Source: Discovered live while triaging #284/#285 — the agent-orchestrator project's stored config shows "defaultBranch": "fix/pr-attachment", a personal scratch branch, not main.
Analyzed against: 7c9ae53
Confidence: High — traced the exact code path and reproduced the live DB state.

Reproduction

  1. Check out a non-default branch in a registered repo's working directory (e.g. git checkout -b fix/something).
  2. Run ao project add --path <repo> while that branch is checked out.
  3. project.Config.DefaultBranch is persisted as fix/something.
  4. Switch back to main in the working directory — AO's stored config is unaffected.
  5. Spawn any worker: its worktree bases off fix/something, not main, with no indication anything is wrong.

Confirmed live: ~/.ao/data/ao.dbprojects.config for project agent-orchestrator contains {"defaultBranch":"fix/pr-attachment", ...}fix/pr-attachment was simply the branch checked out in the main working tree at the moment the project was registered, not the repo's actual default branch (origin/HEADmain).

Root Cause

backend/internal/service/project/service.go:

  • Line 202-206 (in Add): if row.Config.DefaultBranch == "" { if branch := resolveDefaultBranch(path); ... { row.Config.DefaultBranch = branch } }
  • Line 254-260: resolveDefaultBranch runs git -C path symbolic-ref --short HEAD — i.e. whatever branch happens to be checked out right now, not the repo's actual default branch.

This was introduced by PR #209 (closing #208), which fixed a real problem — repos on master/develop/trunk previously fell back to a hardcoded main and failed every spawn with BRANCH_NOT_FETCHED. The fix's approach (snapshot symbolic-ref --short HEAD once, at project add time) conflates two different things:

  • The repo's actual default/trunk branch (what origin/HEAD resolves to — stable, shared, intended target for new worktrees)
  • Whatever branch happens to be checked out locally right now (transient, personal, could be any in-progress feature branch)

For a repo cloned fresh and never checked out elsewhere, these coincide, which is presumably why #209's tests passed. But for any already-active local clone (the common case for someone setting up AO on an existing project), they diverge — and once persisted, Config.DefaultBranch is ""-gated (line 202), so it's a one-time snapshot that never self-corrects even after the user returns to main.

Fix (options, not prescriptive)

  • Prefer the repo's actual remote default branch: git -C path symbolic-ref --short refs/remotes/origin/HEAD (falling back to the current symbolic-ref --short HEAD approach only if no origin/HEAD is set, e.g. no remote configured) — this targets the repo's trunk rather than the registrar's transient checkout.
  • Surface the detected defaultBranch in the ao project add output / project settings UI so a user notices if it's wrong, with an easy ao project set-config --default-branch main escape hatch (which already exists per docs/cli/README.md).
  • Consider re-validating/re-resolving on a project's ao project add re-run or via ao project set-config, rather than only ever setting it once at first registration.

Impact

  • Every worker session spawned in an affected project silently bases its work off a stale personal branch instead of main — diffs, PRs, and merges all target/diverge from the wrong base, with no error or warning anywhere in the flow.
  • Affects any project registered while the registrar had a non-default branch checked out — likely common, since ao project add is typically run against an already-active local clone, not a fresh checkout.

Related

  • #208 — the original bug this regressed from (closed)
  • #284 — PR auto-attach disconnection (separate but adjacent: both are "session/project branch tracking goes stale and never resyncs" bugs)

Metadata

Metadata

Labels

bugSomething isn't workingneeds-triageMaintainer needs to evaluate this issue

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions