autoland fix-forward loop: fix runs on rejection, spawn-count bound, escalation #182
Labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Cloonar/coding-lab#182
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What to build
The loop's second half: fix-forward runs on rejection, the attempt bound, and escalation. This is the "reject → re-queue-to-AFK loop" ADR-0024 deferred, implemented as fix-forward (bounded, carries new information) — NOT the forbidden auto-requeue.
max_fix_attempts→ spawn a fix run. The trigger is forge state, so a human's rejection review feeds the same loop as a lander's.afk/<N>claim branch (the original AFK run was reaped at PR-open; sessions are never resumed — this is a fresh run on the existing claim). Fresh run credentials; provider/model inherited from the run that authored the branch; budget clock and three-strikes accounting apply. Seed prompt carries the issue, the PR, and the rejection review verbatim.labctl pr rerequest— the explicit forge-observable done-signal, symmetric withpr createfor AFK runs. Review re-requested + no live run → the poller spawns a lander again (next validation round).ready-for-agent→ready-for-humanvia labctl, push notification fired off the run outcome.Acceptance criteria
pr rerequestleads to a fresh lander validation roundmax_fix_attempts: digest comment on the issue,ready-for-agent→ready-for-humanflip, push notification; no further autoland activity on that PR afterwardsBlocked by
Agent Brief
Category: enhancement
Summary: Autoland fix-forward loop — fix runs spawned on rejection, a spawn-count attempt bound, and agent-executed escalation to ready-for-human. This implements the reject → re-engage loop ADR-0024 deferred, as fix-forward (bounded, carries the rejection review as new information) — NOT the grep-guard-forbidden auto-requeue.
Current behavior:
After #181, a lander (or a human) can post a changes-requested review, but the PR then sits: nothing re-engages an agent, the rejection findings go unread, and the only path forward is a human running the interactive land-pr skill. The original AFK run was reaped at PR-open and sessions are never resumed, so re-engagement must be a fresh run on the surviving claim branch.
Desired behavior:
max_fix_attempts→ spawn a fix run. The trigger is forge state, so a human's rejection review feeds the same loop as a lander's.afk/<N>claim branch — a fresh run on the existing claim, never a session resume. Fresh run credentials; provider/model inherited from the run that authored the branch; budget clock and three-strikes accounting apply. Seed prompt carries the issue, the PR, and the rejection review verbatim.labctl pr rerequest— the explicit forge-observable done-signal, symmetric withpr createfor AFK runs. Review re-requested + no live run → the poller spawns a lander again (next validation round).ready-for-agent→ready-for-humanvia labctl, push notification fired off the run outcome.Key interfaces:
pr rerequestfrom #180 as the fix run's done-signal; labctl label verbs for the ready-for-human flip; push notification off run outcomeAcceptance criteria:
pr rerequestleads to a fresh lander validation roundmax_fix_attempts: digest comment on the issue,ready-for-agent→ready-for-humanflip, push notification; no further autoland activity on that PR afterwardsOut of scope:
Land-PR audit — PR #187
Verdict: PASS (after fixes applied on the branch). Merging.
Verification signal relied on: Forgejo Actions
ci / native, green in 6m42s onef284fd(run 211) — the head commit as merged, not the original green on01bcf7f. Not re-run locally.Checked
origin/main; Conventional Commits title; body carriesCloses #182.run_tokensrows; both dialects' CHECKs admit every enum value the Go code writes.Blockers found and fixed on the branch (
ef284fd)Both from one root cause: the attempt bound counted runs ROWS, which record a spawn that reached a live session — not a spawn that was attempted.
CreateRunfailure, and pre-CreateRunfailures never write one. A deterministically-failing launch retried every tick forever, never escalating — a miss against acceptance criterion 3.reapRunexcludes escalate from the consecutive-failure counter in both directions, and the candidate sorts atStageFix, ahead of new AFK work — one wedged branch would starve its repo's new-work pipeline.Fixed by counting spawn INTENTS in
autoland_attempts(migration 0015, keyed repo+branch+kind), incremented atautolandLaunch;ErrOverCapchecked first and never burns. Escalate gainsMaxEscalateAttempts = 3, then the poller goes quiet and logs at error level. Regression testsTestSpawnOnce_failedFixLaunchBurnsAttemptandTestSpawnOnce_escalateArmIsBounded, both verified to fail against the unfixed code.Not blocking — carried forward
pr escalateis repo-scoped, not PR-scoped — the first irreversible verb on a surface ADR-0048 already notes is not PR-confined.tracker.CommentcarriesAuthorand nothing reads it.CONTEXT.md's duplicate Escalation glossary entry (conflicting definitions from #180 and #182) was collapsed as part of the fix commit.