Skip to content

bug(scm): PR invisible to AO when a worker pushes from a branch other than the one AO assigned #285

@neversettle17-101

Description

@neversettle17-101

Bug

The SCM observer looks up a session's PR by the branch name stored in the session's DB metadata at spawn time (sessions.branch). If the worker agent renames/checks out a different local branch and opens its PR from that branch instead, AO never discovers the PR — the session's branch column is never updated after spawn, so the lookup always queries the wrong (original) branch name.

Source: Discovered while triaging #251 (PR hydration bug) | Reported by: Aditi Chauhan
Analyzed against: 96d1649
Confidence: High

Reproduction

  1. Spawn a worker session (e.g. agent-orchestrator-3); AO assigns the default branch ao/agent-orchestrator-3 and stores it in sessions.branch.
  2. Inside the worker's worktree, the agent runs git checkout -b fix/some-other-name and pushes/opens a PR from that branch instead (observed live: PR #279, head=fix/251-pr-details-not-populated, for session agent-orchestrator-3).
  3. GET /api/v1/sessions/agent-orchestrator-3/pr returns {"prs": []} even though the PR is OPEN on GitHub and clearly tied to that session's work.
  4. Daemon log confirms the lookup target: scm observer: no PR detected for branch session=agent-orchestrator-3 branch=ao/agent-orchestrator-3 — querying the stale branch name, not fix/251-pr-details-not-populated.

Root Cause

  • backend/internal/session_manager/manager.go sets domain.SessionMetadata.Branch only at spawn (line 217) and restore (line 508) — there is no code path anywhere in backend/internal that updates sessions.branch afterward (confirmed via grep -rn "Metadata.Branch\s*=", only those two spawn/restore sites).
  • backend/internal/observe/scm/observer.go line 419-420 reads sess.Metadata.Branch as the sole input to DetectPRByBranch (line 526), which queries the provider (GitHub) for an open PR matching that exact branch name.
  • Nothing prevents (or detects) the spawned agent from running git checkout -b <new-name> inside its own worktree and pushing/opening a PR from a different branch than the one AO recorded. Once that happens, the stored branch and the actual branch permanently diverge, and the observer's per-branch lookup can never find the real PR — it's not a transient miss, it never self-heals.
  • This silently breaks every downstream feature that depends on PR detection: Session Inspector Summary tab, the kanban Board's PR badge, the /prs page, and any CI/review reaction nudges gated on PR state (e.g. #243, #265).

Fix

Two complementary angles:

  1. Detect drift: when the workspace adapter or agent hooks observe the worktree's actual current branch differs from sessions.branch, update the stored value (or at minimum log/flag it) so the SCM observer's lookup target stays accurate.
  2. Fallback lookup: DetectPRByBranch could fall back to detecting an open PR by HEAD commit SHA or by querying "PRs from this fork/repo with any head branch authored after sessions.created_at" rather than relying solely on an exact, immutable branch-name match — though this is a heavier change and may belong in a separate design discussion.

(1) is the minimal, low-risk fix; (2) is a more robust but bigger lift — flagging both rather than guessing further without maintainer input on which direction is preferred.

Impact

  • PR state (CI, mergeability, review) silently never surfaces for any session whose agent diverges from its assigned branch — no error, just permanently stale "no PR yet" everywhere in the UI.
  • Affects reaction/nudge logic gated on PR observation (see related issues below) — a worker could sit stalled waiting for a nudge that never fires because the PR is invisible.

Related

  • #251 — PR hydration bug in the frontend (separate, already fixed in PR fix(frontend): populate session.pullRequest from /pr endpoint (#251) #279 — ironically the PR that surfaced this branch-mismatch bug)
  • #243 — CI-failing nudge never fires when check was cancelled (same subsystem: PR observation driving reactions)
  • #265 — sendOnce blocking I/O issue (same subsystem: PR nudges)
  • #111 — CLI: surface PR observation in ao session get (would also be affected by this gap)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingpriority: mediumFix when convenient

    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