autoland: escalation is permanently terminal with no way back in — re-arm a PR the humans have moved on #188

Open
opened 2026-07-20 18:25:25 +02:00 by dominik.polakovics · 0 comments

Follow-up from landing #187 (issue #182). Not a regression in that PR — the gate works as designed; the design has no exit.

Problem

An outcome='escalated' run makes its PR invisible to the autoland poller forever (EscalatedRunOnBranch, internal/store/afk.go). The docs say re-entry is "exactly one path — a human running the interactive land-pr skill." Three cases break that:

  1. Requeue reuses the branch. The gate keys on (repo_id, branch) with no PR or time scoping, and afk/<N> is derived from the issue number. Discard the escalated run, let a fresh AFK run re-claim the issue, and the brand-new claim PR is invisible from birth — a PR that has never been validated, let alone escalated.
  2. The human fixes it themselves and wants an agent to re-validate. Same PR, still terminal.
  3. The human hands an agent a manual description to fix it. Same PR, still terminal.

All three fail silently: autolandCandidates continues at the gate with no log line, no marker on the new PR, nothing in the SPA. The symptom is "autoland just ignores this PR" with no diagnosis path short of reading the runs table.

Why keying on the PR number is not the fix

The obvious fix — key terminality on the PR, not the branch — only fixes case 1. Cases 2 and 3 are the same PR.

The real problem is that escalation is modelled as a permanent property of a thing, when it is a statement about a moment: "as of these N attempts, agents could not finish this." A human commit or a fresh set of instructions is new information that invalidates the statement, and nothing in the design can express that. A better key makes the gate more accurate, not less permanent.

What to build

A re-arm operation, not an un-escalate:

  • Clears the terminality for the PR and zeroes its fix / escalate counters in autoland_attempts (added by #187, migration 0015). Both halves, together: clearing terminality while leaving the fix budget spent would escalate again on the first rejection — the worst outcome, because it looks like the clear silently did not work.
  • Re-key the terminality gate on the PR rather than the branch while in here. It does not solve the problem on its own, but branch-keying is separately wrong on requeue (case 1) and it is the same gate.
  • Log the suppression at the gate. Independent of everything above, and worth doing even if the rest is deferred: one line turns a silent mystery into a five-second diagnosis.

Open question — the surface

A product call, not an implementation detail. Options:

  • a labctl / lab CLI verb
  • an SPA action in the run history or the PR view
  • both

Worth deciding alongside: should re-arm be implicit on some signal (a new human commit on the head branch? the issue flipping back to ready-for-agent?) rather than an explicit gesture. Implicit is friendlier but re-introduces the auto-requeue smell ADR-0024 forbids — the point of the fix-forward design is that re-engagement carries new information, and "a human pushed something" is arguably exactly that signal. Needs a decision before implementation.

Notes

  • ADR-0048 will need a revision pointer once the terminality semantics change.
  • CONTEXT.md's Escalation entry currently states re-entry is land-pr only; update it with whatever lands.
Follow-up from landing #187 (issue #182). Not a regression in that PR — the gate works as designed; the design has no exit. ## Problem An `outcome='escalated'` run makes its PR invisible to the autoland poller forever (`EscalatedRunOnBranch`, `internal/store/afk.go`). The docs say re-entry is "exactly one path — a human running the interactive land-pr skill." Three cases break that: 1. **Requeue reuses the branch.** The gate keys on `(repo_id, branch)` with no PR or time scoping, and `afk/<N>` is derived from the issue number. Discard the escalated run, let a fresh AFK run re-claim the issue, and the brand-new claim PR is invisible **from birth** — a PR that has never been validated, let alone escalated. 2. **The human fixes it themselves** and wants an agent to re-validate. Same PR, still terminal. 3. **The human hands an agent a manual description** to fix it. Same PR, still terminal. All three fail **silently**: `autolandCandidates` `continue`s at the gate with no log line, no marker on the new PR, nothing in the SPA. The symptom is "autoland just ignores this PR" with no diagnosis path short of reading the runs table. ## Why keying on the PR number is not the fix The obvious fix — key terminality on the PR, not the branch — only fixes case 1. Cases 2 and 3 are the same PR. The real problem is that escalation is modelled as a permanent property of a *thing*, when it is a statement about a *moment*: "as of these N attempts, agents could not finish this." A human commit or a fresh set of instructions is new information that invalidates the statement, and nothing in the design can express that. A better key makes the gate more accurate, not less permanent. ## What to build **A re-arm operation**, not an un-escalate: - Clears the terminality for the PR **and** zeroes its `fix` / `escalate` counters in `autoland_attempts` (added by #187, migration 0015). Both halves, together: clearing terminality while leaving the fix budget spent would escalate again on the first rejection — the worst outcome, because it looks like the clear silently did not work. - Re-key the terminality gate on the PR rather than the branch while in here. It does not solve the problem on its own, but branch-keying is separately wrong on requeue (case 1) and it is the same gate. - **Log the suppression** at the gate. Independent of everything above, and worth doing even if the rest is deferred: one line turns a silent mystery into a five-second diagnosis. ## Open question — the surface A product call, not an implementation detail. Options: - a `labctl` / `lab` CLI verb - an SPA action in the run history or the PR view - both Worth deciding alongside: should re-arm be implicit on some signal (a new human commit on the head branch? the issue flipping back to `ready-for-agent`?) rather than an explicit gesture. Implicit is friendlier but re-introduces the auto-requeue smell ADR-0024 forbids — the point of the fix-forward design is that re-engagement carries new information, and "a human pushed something" is arguably exactly that signal. Needs a decision before implementation. ## Notes - ADR-0048 will need a revision pointer once the terminality semantics change. - CONTEXT.md's **Escalation** entry currently states re-entry is land-pr only; update it with whatever lands.
Sign in to join this conversation.
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
Cloonar/coding-lab#188
No description provided.