An executor must be able to rebase its own branch instead of dying in worktree prep #473

Merged
toasterson merged 3 commits from claude/wi-019fa7d9-an-executor-must-be-able-to-rebase-its-o into main 2026-08-02 13:21:16 +00:00
Owner

Anima work item 019fa7d9-49ab-7ed2-816c-c17685c38173.

POST-PHASING work item. The pre-phasing fix was done by hand on 2026-07-28 (see "Manual fix already applied" below); do NOT re-do that. This item is the durable capability, to be shaped by the ADR 0025-0031 phase-graph work.

Problem

When an agent branch cannot rebase onto its base, worktree prep fails and the runner rejects the assignment:

worktree prep failed (branch `main`): rebase onto origin/main failed
(base advanced since the last round; needs human rebase)

The server then re-dispatches on the next tick, which fails identically. Observed 2026-07-28: WI-234 (Akh-Medu) burned 20 sessions in 3 minutes before parking; WI-349 (Anima) failed 4 dispatches the same way. Each attempt consumes a slot, creates a session row, and produces no work. The failure is terminal for the item until a human intervenes, but nothing tells the human that — it looks like an ordinary retry loop.

Two distinct sub-cases, which today are indistinguishable:

  1. Mechanically rebasable — the branch is behind but has no semantic conflict. Nothing needs a human at all; the runner already has the worktree and the credentials.
  2. Genuinely conflicted — overlapping edits in the same hunks. Needs a decision, and the decision is often "re-implement against current base" rather than "resolve".

Why this is post-phasing

The natural home for case 2 is a phase, not a retry: an item whose branch will not rebase should move to a rebase/conflict phase with its own prompt and its own exit bar, rather than sit in working re-dispatching. That only becomes expressible once the dynamic DB-defined phase graph lands (ADR 0025-0031, WI-393 dispatch branches on PhaseKind, WI-394 per-(item, phase) revisit cap). Building a bespoke retry-counter for this now would be another hand-rolled queue semantic of exactly the kind the RabbitMQ redesign is removing.

Acceptance criteria

  1. A branch that is behind its base but has no conflicting hunks is rebased by the executor itself, with no human step and no failed dispatch. The turn proceeds normally afterwards.
  2. A branch with a genuine conflict does NOT re-dispatch. It transitions to a phase whose prompt names the conflicting files and hunks and whose deliverable is either a resolution or an explicit "re-implement on current base" decision.
  3. The transition in (2) is visible on the phase axis and in the thread — an operator can answer "why is this item not moving?" without reading runner logs.
  4. Repeated worktree-prep failure for the same (item, base) can never exceed the phase's revisit cap. Regression test: seed a conflicting branch, run the scheduler for N ticks, assert exactly one dispatch attempt and one phase transition, not N sessions.
  5. Migration numbering is part of the conflict surface: two branches adding the same NNN_*.sql must be reported as a conflict even though git merges them cleanly (different filenames). See "Migration collision" below.

Field evidence (2026-07-28)

Of 26 open Anima PRs, 11 could not rebase onto main. Separately, 10 different branches each added a different migration all numbered 067, and main had itself since added 067 and 068 — so every one of them would have broken on merge, and git reported none of them as conflicts.

Manual fix already applied (do not repeat)

This session rebased and force-pushed 12 branches and renumbered every colliding migration to a unique number (069-078): PRs 346, 350, 368, 373, 377, 378, 379, 381, 383, 386, 388, 389. Result: 23 of 26 open PR branches now merge cleanly.

Three were deliberately NOT rebased, and each needs a decision rather than a rebase:

  • PR #290 / WI-264 (user-settings foundation) and PR #289 / WI-263 (inbox auto-clear, stacked on it) — superseded. main now has a strictly more complete SettingsService (project-scoped, GetSettings/SetSetting/ListSettingDefs, SettingDef registry) versus the branch's user-scoped GetUserSettings/SetUserSetting. add/add conflicts on proto/anima/v1/settings.proto, services/settings.rs, repo/settings.rs. Porting them is re-implementation, not rebasing. Recommend closing both PRs and re-scoping the WIs against main's settings API.
  • PR #384 / WI-351 (model-provider 429) — collides on the wire. Both sides claim field number 5 on the same heartbeat message: main's repeated ExecutorQuota executor_quotas = 5 versus the branch's repeated LaneStatus lane_status = 5. They are complementary halves (main measures account quota; the branch reacts to a sick lane) and want unifying, but choosing the field numbering and whether LaneStatus subsumes AccountQuota is a design decision, not a merge.
Anima work item `019fa7d9-49ab-7ed2-816c-c17685c38173`. POST-PHASING work item. The pre-phasing fix was done by hand on 2026-07-28 (see "Manual fix already applied" below); do NOT re-do that. This item is the durable capability, to be shaped by the ADR 0025-0031 phase-graph work. ## Problem When an agent branch cannot rebase onto its base, `worktree prep` fails and the runner rejects the assignment: ``` worktree prep failed (branch `main`): rebase onto origin/main failed (base advanced since the last round; needs human rebase) ``` The server then re-dispatches on the next tick, which fails identically. Observed 2026-07-28: WI-234 (Akh-Medu) burned 20 sessions in 3 minutes before parking; WI-349 (Anima) failed 4 dispatches the same way. Each attempt consumes a slot, creates a session row, and produces no work. The failure is terminal for the item until a human intervenes, but nothing tells the human that — it looks like an ordinary retry loop. Two distinct sub-cases, which today are indistinguishable: 1. **Mechanically rebasable** — the branch is behind but has no semantic conflict. Nothing needs a human at all; the runner already has the worktree and the credentials. 2. **Genuinely conflicted** — overlapping edits in the same hunks. Needs a decision, and the decision is often "re-implement against current base" rather than "resolve". ## Why this is post-phasing The natural home for case 2 is a phase, not a retry: an item whose branch will not rebase should *move* to a rebase/conflict phase with its own prompt and its own exit bar, rather than sit in `working` re-dispatching. That only becomes expressible once the dynamic DB-defined phase graph lands (ADR 0025-0031, WI-393 dispatch branches on PhaseKind, WI-394 per-(item, phase) revisit cap). Building a bespoke retry-counter for this now would be another hand-rolled queue semantic of exactly the kind the RabbitMQ redesign is removing. ## Acceptance criteria 1. A branch that is behind its base but has no conflicting hunks is rebased by the executor itself, with no human step and no failed dispatch. The turn proceeds normally afterwards. 2. A branch with a genuine conflict does NOT re-dispatch. It transitions to a phase whose prompt names the conflicting files and hunks and whose deliverable is either a resolution or an explicit "re-implement on current base" decision. 3. The transition in (2) is visible on the phase axis and in the thread — an operator can answer "why is this item not moving?" without reading runner logs. 4. Repeated worktree-prep failure for the same (item, base) can never exceed the phase's revisit cap. Regression test: seed a conflicting branch, run the scheduler for N ticks, assert exactly one dispatch attempt and one phase transition, not N sessions. 5. Migration numbering is part of the conflict surface: two branches adding the same `NNN_*.sql` must be reported as a conflict even though git merges them cleanly (different filenames). See "Migration collision" below. ## Field evidence (2026-07-28) Of 26 open Anima PRs, 11 could not rebase onto main. Separately, **10 different branches each added a different migration all numbered 067**, and main had itself since added 067 and 068 — so every one of them would have broken on merge, and git reported none of them as conflicts. ## Manual fix already applied (do not repeat) This session rebased and force-pushed 12 branches and renumbered every colliding migration to a unique number (069-078): PRs 346, 350, 368, 373, 377, 378, 379, 381, 383, 386, 388, 389. Result: 23 of 26 open PR branches now merge cleanly. Three were deliberately NOT rebased, and each needs a decision rather than a rebase: - **PR #290 / WI-264** (user-settings foundation) and **PR #289 / WI-263** (inbox auto-clear, stacked on it) — superseded. `main` now has a strictly more complete `SettingsService` (project-scoped, `GetSettings`/`SetSetting`/`ListSettingDefs`, `SettingDef` registry) versus the branch's user-scoped `GetUserSettings`/`SetUserSetting`. `add/add` conflicts on `proto/anima/v1/settings.proto`, `services/settings.rs`, `repo/settings.rs`. Porting them is re-implementation, not rebasing. Recommend closing both PRs and re-scoping the WIs against main's settings API. - **PR #384 / WI-351** (model-provider 429) — collides on the wire. Both sides claim **field number 5** on the same heartbeat message: main's `repeated ExecutorQuota executor_quotas = 5` versus the branch's `repeated LaneStatus lane_status = 5`. They are complementary halves (main measures account quota; the branch reacts to a sick lane) and want unifying, but choosing the field numbering and whether `LaneStatus` subsumes `AccountQuota` is a design decision, not a merge.
toasterson force-pushed claude/wi-019fa7d9-an-executor-must-be-able-to-rebase-its-o from e060c58e10 to 95eadfe48c 2026-08-02 09:57:47 +00:00 Compare
The previous implementation had three nested if-let statements that
clippy (with -D warnings) flagged as collapsible. Combined them into
a single if-let chain using && for cleaner code.

This was causing the CI to fail with exit code 101 when running
`cargo clippy --workspace -- -D warnings`.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
toasterson changed title from WIP: An executor must be able to rebase its own branch instead of dying in worktree prep to An executor must be able to rebase its own branch instead of dying in worktree prep 2026-08-02 11:19:16 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
toasterson/Anima!473
No description provided.