Skip to content

Keep worktrees and PR-less branches on a fresh base #15938

Description

@mrveiss

Problem

Worktrees drift off the base and nothing catches it until push time. Read-only inventory taken
against current origin/Dev_new_gui:

Branch Commits behind base Last commit On origin PR
issue-13140-slmapibase 1076 5 weeks ago no #13170
issue-13719 781 22 hours ago yes none
research-provider-quota-headroom 334 13 days ago yes #15033
issue-14529-refit 155 5 days ago no none
issue-15036-landing-evidence 144 5 days ago no none
issue-15794-agent-org-gate 44 34 hours ago no #15798

Every other worktree is 0 behind — those are the ones with an open PR, kept fresh by
auto-update-pr-branches.yml. The pattern is exact: freshness today is a side effect of having a
PR.
Before the first push there is no mechanism at all, and issue-13719 was committed to 22
hours ago while 781 commits behind.

This is expensive in the direction that has no feedback: a stale base makes "is this already done?"
answer no when the truth is yes, so the session builds work that already exists, and reviving
such a branch can regress newer code.

Two distinct gaps

  1. Local-only branches — 4 of the 6 above are not on origin. No server-side workflow can see
    them, so no workflow can ever fix them. This half needs a local guard.
  2. issue-13719 is pushed, PR-less, and 781 commits behind — precisely the case
    auto-merge-base-into-parked-branches.yml (cron 0 */6) claims to cover, per its own comment
    that PR-less branches are its reason to exist. It did not. Root-cause why before changing
    anything else; the workflow may be silently skipping branches it should touch.

Scope

Local guard (gap 1) — the branch is the record, so the check belongs where work starts and where
it leaves:

  • Worktree creation fetches and branches from current origin/Dev_new_gui, never from a local ref
    that may itself be stale.
  • scripts/pr-preflight.sh (Local preflight must cover the 10 required checks #15933) fails when the branch is behind base by more than a threshold,
    so a stale branch cannot reach a PR.
  • A cheap behind-count warning at commit time, using the last fetch rather than forcing a network
    call on every commit.

Server-side (gap 2) — fix auto-merge-base-into-parked-branches.yml so PR-less pushed branches
are actually kept current, and make its skips visible rather than silent.

Constraints:

  • Never touch another session's worktree. This issue delivers a guard and a report, not a sweep.
    Nothing here rebases, resets, or removes a branch a session may be using.
  • A branch that is far behind is unfinished work, not debris. The guard reports and blocks a stale
    push; it never discards.

Acceptance criteria

  • Worktree creation branches from a freshly fetched origin/Dev_new_gui — cite the script and line
  • scripts/pr-preflight.sh fails on a branch behind base beyond the threshold, with the exact rebase command in the message
  • Root cause for issue-13719 (pushed, PR-less, 781 behind) identified and fixed in auto-merge-base-into-parked-branches.yml, with the skip path made observable
  • Re-run the inventory: no PR-less pushed branch more than 50 commits behind
  • No mechanism added that mutates or removes a branch — guard and report only

Implementation Order

Wave: 2
Depends on: #15933

Umbrella: #15932

Activity

  1. github-actions commented on Sep 11, 2026

    @github-actions
    Contributor

    PR #16128 (merged to Dev_new_gui) references this issue with a close keyword.

    fix(ci): the parked-branch merger has never merged anything (#15938)

    If this issue is fully resolved, close it manually. If work remains, no action is needed.

  2. mrveiss commented on Sep 11, 2026

    @mrveiss
    OwnerAuthor

    Status against merged base (24211c208, #16128). Four criteria met in code; AC4 is not met, and it cannot be met by waiting — leaving this open. Closes #15938 does not fire on this base.

    AC1 — worktree creation branches from a freshly fetched origin/Dev_new_gui — met. autobot-backend/services/task_workspace.py:

    :56   _WORKSPACE_BASE_REF = os.environ.get("AUTOBOT_WORKSPACE_BASE_REF") or "origin/Dev_new_gui"
    :356  def _fetched_base_ref(root) -> fetches, then rev-parse --verify; an unresolvable ref RAISES
    :405  base_ref = _fetched_base_ref(root)
    :406  add_argv = ["git", "worktree", "add", "-b", branch, str(workspace_dir)]
    :407  if base_ref is not None: add_argv.append(base_ref)
    

    I checked the None branch because it looks like a fallback to HEAD. It is reachable only in a repository with no remotes at all, where HEAD is the only base that exists, and the docstring defends that case. A configured remote with the ref missing raises ("refusing to branch from the main tree's HEAD"), and a failing git remote also raises rather than being read as "no remotes".

    AC2 — pr-preflight.sh fails beyond the threshold, with the exact rebase command in the message — met.

    :50   MAX_BEHIND="${PREFLIGHT_MAX_BEHIND:-50}"
    fail "branch is $behind commits behind $BASE (limit $MAX_BEHIND), measured against $behind_basis"
    note "rebase before opening the PR:  git fetch origin && git rebase $BASE"
    

    A non-numeric override fails rather than reading as a pass, and a failed fetch states that the count is a lower bound.

    AC3 — root cause fixed in auto-merge-base-into-parked-branches.yml, skip path observable — met in the file. Branches are sorted into updated / conflicted / current / skipped / pushfail / errored / unreachable, with ::warning:: lines for each non-success. The comment at :166 names #15938 as the reason the --no-rebase was removed. rescued/* is excluded by policy (EXCLUDED_PREFIXES, rationale at :32).

    AC5 — no mechanism added that mutates or removes a branch — met. The merger predates this work: added in 7952df898 on 2026-08-30 (#15316). #16128 repaired an existing mechanism, and the workspace and preflight changes create and report; neither mutates.

    AC4 — re-run the inventory: no PR-less pushed branch more than 50 behind — not met. Measured today:

    PR-less remote branches                      42
      more than 50 behind                        30
        rescued/*  (excluded by policy)          19
        ordinary work branches                   11   worst: issue-13719 884, research-provider-quota-headroom 437
    

    issue-13719 — the root-cause case AC3 names, at 781 behind when this was filed — is now 884 behind. The fix is not the reason: the fixed merger has not run, and on its schedule it never will. Scheduled workflows execute the default branch's copy, the default branch is main, and main is 310 commits behind with a merger that mentions #15938 zero times. Every run from 9–11 September reports head=b94f51a4c3, main's tip. Detail and the current count are on #15318, which already tracks this.

    So AC4 needs one of two things, and neither is code in this repository:

    Two further notes for whoever closes this. AC4 has no stated exception, but the 19 rescued/* branches are excluded from the merger by documented policy. Closing it honestly means either amending AC4 to exclude them or accepting that they will never meet it.

  3. mrveiss commented on Sep 11, 2026

    @mrveiss
    OwnerAuthor

    Status against base a12b4bf79d, after #16128 (squash 24211c208d): 3 of 5 criteria met, so this stays open. AC4 is unmet and AC5 needs an owner decision.

    AC Status Evidence
    1. Worktree creation branches from a freshly fetched base met, ticked autobot-backend/services/task_workspace.py:388: _fetched_base_ref (:356) runs fetch --quiet origin Dev_new_gui; :405 calls it and :407-408 appends the result as the worktree add -b start point. The base ref is origin/Dev_new_gui (:56, env AUTOBOT_WORKSPACE_BASE_REF). If offline, it falls back to the last-known base with a warning (:389-392); if the ref can't be resolved, it errors (:396).
    2. pr-preflight.sh fails behind the threshold, with the rebase command met, ticked scripts/pr-preflight.sh:50 MAX_BEHIND="${PREFLIGHT_MAX_BEHIND:-50}"; :228-229 fail with "branch is N commits behind … (limit …)" plus the note git fetch origin && git rebase $BASE; a non-numeric override fails (:217-220) instead of passing.
    3. Root cause for issue-13719 fixed, and the skip path observable met, ticked Root cause (#16128): the workflow ran git merge --no-rebase, a git pull flag that git merge rejects, so it never merged anything. Observable: summary() writes to $GITHUB_STEP_SUMMARY (:215), each branch gets an outcome line, there are annotations at :150,161,191,206,269,286, and an unexplained failure exits 1 (:271). The latest scheduled run, 34617902513 (2026-09-11 18:44 Riga), reports issue-13719 is 894 behind … CONFLICTS — skipped. The merger runs now, and the reason it can't catch this branch up is visible.
    4. Inventory: no PR-less pushed branch more than 50 behind not met Re-run just now: 39 PR-less remote branches, 30 of them more than 50 behind. 19 are rescued/*, which the workflow excludes by design (header :32-33, EXCLUDED_PREFIXES :97). 11 are work branches: feat/gantt-timeline-view 2783, issue-13719 894, research-provider-quota-headroom 447, issue-14100-unit-and-docs 273, issue-13539-release-flip 231, issue-15650-slm-shell-publish 173, issue-15882-stale-base-rule 126, issue-15868-ratchet-format 121, issue-15909-extract-model-pricing 120, issue-16025-gate-blindspots 77, issue-16040-gate-state 75. The latest run shows updated=0 current=1 conflicted=19: every stale work branch conflicts, so no automated path brings them under 50. Each is unfinished work its owner has to land or record.
    5. No mechanism added that mutates or removes a branch left unticked, needs a decision #16128 added no new mechanism. It repaired the existing parked-branch merger, which pushes merge commits without forcing (:191) and removes nothing. Whether a repaired merger that now actually changes branches meets "guard and report only" is the author's call. The same goes for whether rescued/* counts toward AC4.

    What's left: a decision on AC5 and on the rescued/* scope, plus owners for the 11 conflicted work branches.

  4. added this to the v0.9.0 milestone on Sep 12, 2026
  5. mrveiss commented on Sep 12, 2026

    @mrveiss
    OwnerAuthor

    Stale-issue sweep (never auto-closed — Dev_new_gui wasn't GitHub's default branch at merge time). Verified against current origin/main; leaving open.

    MET: task_workspace.py:356 _fetched_base_ref() used as base_ref for git worktree add (:405-408); pr-preflight.sh's MAX_BEHIND="${PREFLIGHT_MAX_BEHIND:-50}" (:50) with a rebase-failure message; the invalid --no-rebase flag removed from auto-merge-base-into-parked-branches.yml, non-conflict failures now bucketed as errored and fail the job.

    NOT MET: AC4 — the delivering PR (#16128) states this itself, having re-run the inventory post-merge: "no PR-less pushed branch more than 50 commits behind. Measured now: 258 PR-less pushed branches, 206 of them more than 50 behind (worst: 2736)." This is a live-state fact the diff can't retroactively fix — the backlog needs the fixed workflow's 6-hourly cron to actually run and drain it over time.

  6. modified the milestones: v0.9.0, v0.10.0 on Sep 17, 2026
  7. mrveiss commented on Sep 20, 2026

    @mrveiss
    OwnerAuthor

    Triage: both branches dead (both on the revival-hazard trap list); 3 of 5 ACs done, 2 need a fresh measurement

    Both candidates (issue-15938-fresh-base, rescue-15938-parked-branch-merger) are ~1870/unmeasured files off current origin/main and both are flagged on the branch-freeze scan's revival-hazard trap list (predate a later fix elsewhere) -- not reviving either. issue-15938-fresh-base's own staleness is a small irony given its name.

    Confirmed done: ~/.claude/scripts/branch-for-issue:30 branches from base=$(git rev-parse origin/main) -- freshly resolved at creation time, matching AC1's own citation. scripts/pr-preflight.sh (#15933, already verdicted superseded/done elsewhere in this sweep) and .github/workflows/auto-merge-base-into-parked-branches.yml (#15306, also already verdicted in this sweep) both exist and match AC2/AC3's descriptions.

    Not verifying the remaining 2 ACs myself -- "re-run the inventory: no PR-less pushed branch more than 50 commits behind" needs a fresh, repo-wide branch-behind-count sweep, which is exactly the kind of large measurement already running in parallel as part of today's branch-freeze effort (931/710/150/560 population counts). Re-deriving a second, smaller version of that same sweep here would duplicate work rather than add to it. Given #15306's own 2026-08-30 measurement found 73 of 85 branches could not even merge cleanly (conflicts, not just staleness), I'd expect this AC to still be failing in practice even though the mechanism exists -- stated as an expectation, not a measurement, since I haven't run the count.

    Not recommending closure -- 2 real ACs outstanding, pending the inventory re-run.

  8. added
    needs-decisionBlocked on an owner decision; options and a recommendation are on the issue
    on Oct 3, 2026
  9. mrveiss commented on Oct 3, 2026

    @mrveiss
    OwnerAuthor

    Closure check (2026-10-03): 4 of 5. The fifth contradicts the third and needs a ruling

    Criterion 4: inventory re-run. Met. From the server (git ls-remote --heads origin), there are 10 heads. Excluding main, release and Dev_new_gui leaves 7, of which 5 are heads of open PRs. The 2 PR-less branches are each 1 commit behind origin/main (1edec3064c): issue-16516-deliberate-hang (a parked scratch branch) and automation/test-durations (the bot's refresh branch). 0 PR-less branches are more than 50 behind.

    Criterion 5: "No mechanism added that mutates or removes a branch — guard and report only." Not ticked, because it conflicts with criterion 3.

    Recommendation: read criterion 5 as "no new mutating mechanism", which is consistent with criterion 3 requiring the merger fix. Under that reading it is met and this issue closes. Labelled needs-decision.

    Side note worth a line in CLAUDE.md: it currently says "the auto-update bot only refreshes branches that already have a PR". That is true of auto-update-pr-branches.yml, but PR-less branches are refreshed too, by this merger, which a session pushing a parked branch needs to know (its next push will be non-fast-forward).

  10. mrveiss commented on Oct 3, 2026

    @mrveiss
    OwnerAuthor

    Stated plainly, so the next reader does not resolve it the other way: criteria 3 and 5 of this issue contradict each other as written. Criterion 3 (ticked) required repairing the parked-branch merger, and #16128 made it mutate PR-less branches. Criterion 5 forbids any mechanism that mutates a branch. Both cannot hold. The repair proposed above is to read 5 as "no new mutating mechanism". Do not satisfy criterion 5 by reverting #16128: criterion 4's measurement (0 PR-less branches more than 50 behind) depends on it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions