Skip to content

fix: an autopilot pull request whose checks fail is never fixed #741

Closed

Description

@soydiloreto

What happened?

An autopilot pull request in DiluxOne/.github whose own self-tests fail is never fixed and waits forever. In .github/workflows/pull-request.yml the review job needs [conventions, actionlint, scripts], so it is skipped when scripts fails; autopilot-fix runs only when needs.review.outputs.blocking == 'true', which a skipped review never sets. Meanwhile scripts/waiting.py puts "the autopilot: fix the failed check" on the board, so nobody is told it is stuck. #738 is in that state now (three self-tests fail after the agent marked it ready; review SKIPPED; board "Waits on the autopilot: fix the failed check"), and #689 sat the same way from 2026-11-07 to 2026-11-14, holding the engine's core and every issue queued behind it. A review that crashes instead of answering (#723: usage: review-type.sh …, exit 2) ends the same way. The organisation's other repositories (org-pull-request.yml) have the same autopilot-fix condition.

Steps to reproduce

  1. Open an autopilot pull request (label autopilot, author dilux-bot) whose diff makes one --test of the scripts job fail.
  2. scripts fails, review is skipped, autopilot-fix is skipped.
  3. No later event starts a fix round; the board says it waits on the autopilot.

Version

main at the merge of #737.

Logs or screenshots

#738 (review SKIPPED, Scripts (self-tests) failing), https://github.com/DiluxOne/.github/actions/runs/43104985993 (#723's review exiting 2).

Proposed solution

A failed required check on an autopilot pull request, or a review that ends without a verdict, starts a fix round with the failed jobs' log, within the same autopilot-rounds cap, the way autopilot-queue already does on dequeued (autopilot.py queue-failed), in pull-request.yml and org-pull-request.yml alike. When the cap is reached it hands the pull request to a person with needs-human, so the board never says the autopilot is fixing something that nothing will fix.

Problem

Autopilot pull requests stall without anyone being told, for days, and one that touches the engine's core blocks every issue queued behind it.

Scope

The fix trigger in pull-request.yml and org-pull-request.yml (a failed required check, a review that ends without a verdict), autopilot.yml's fix mode reading the failed jobs' log, waiting.py's board for that state, their tests, and docs/workflows.md.

Out of scope

Why a given check failed. The review's own crash in #723 (#720).

Acceptance criteria

C1: Given an autopilot pull request whose scripts job fails, when its checks complete, then a fix round starts with the failed jobs' log, without a person.
C2: Given an autopilot pull request whose review ends without a verdict, when its checks complete, then a fix round starts the same way.
C3: Given an autopilot pull request whose rounds reached autopilot-rounds, when a check fails again, then no round starts and it is handed to a person with needs-human.
C4: Given either state, when the board is written, then it names the fix round that is running, or the person, never a fix nothing will start.
C5: Given a repository of the organisation other than DiluxOne/.github, when the same happens there (org-pull-request.yml), then C1 to C4 hold too.

Criticality

Critical

Who works on it

  • I want to work on this myself

🤖 AI-generated · Claude Opus 5.5 (Anthropic)

Spec: approach

The PRD passes G1: the problem is clear and C1 to C5 can each be tested from the pipelines' YAML and the scripts' pure functions.

  1. Trigger (C1, C2, C5). Each pipeline's autopilot-fix gets needs: on every job the review waits on (pull-request.yml: [conventions, actionlint, scripts, review]; org-pull-request.yml: [conventions, review]). Its if: keeps every guard it has now: always(), pull_request, not edited, the autopilot label, dilux-bot as author, and the repository clause. Only the trigger part becomes needs.review.outputs.blocking == 'true' || needs.review.result == 'failure' || needs.<gate>.result == 'failure' (one clause for each gate). That covers a gate that failed (the review is then skipped and has no outputs) and a review that ended without a verdict, whether its verdict step said so (blocking=true, "did not finish") or the job died before that step (fix: the bug reproduced from #720 #723: no outputs). The two conditions stay the same apart from the repository and the gate list, and the existing fix: the autopilot answers a review in the organisation's repository #504 test checks this.

  2. Fix mode reads the failed jobs' log (C1, C2). No new input: org-pull-request.yml calls autopilot.yml@v7, and the queue round (ci: test before the pull request, a faster queue, an unstuck autopilot #479) avoided a new input for the same reason. In fix mode, autopilot.py gets a checks-failed command and inputs fix gets a matching branch. They read the jobs of the calling run (GITHUB_RUN_ID; a reusable workflow's jobs belong to it). Two cases make a check round: a failed job other than the review's, or a failed review job with no verdict at the head (the bot's dx-review summary says "did not finish", or its record is not at the head SHA). The failed jobs' gh run view --job <id> --log-failed goes into .dx-io/checks.md, scrubbed and cut like queue.md: queue_log_text is generalised and keeps the queue's text. prompt_fix(..., checks=True) points the agent at that file instead of review.md, and the round writes no review ids. A review that blocks with a verdict keeps today's review round. A round that fails as the round before did still stops on the existing dx-prepr-sig.

  3. Cap (C3). The rounds check in "May it start" stays where it is (ROUND > autopilot-rounds → needs-human, a comment, and the issue opened to claims). Its comment now comes from a pure rounds_spent(max, checks) in autopilot.py, so it says "its checks still fail" on a check round instead of always "the review still blocks". next_step gets a checks_failed state, so the sweep and the board's next step agree with the trigger: one round below the cap, the person at the cap.

  4. Board (C4). waiting.py blocker: an autopilot pull request whose failed checks include at least one the pipeline fixes (check-run names conventions /, review /, actionlint, Scripts (self-tests)) waits on "the autopilot's fix round", with rounds left. Rounds left means the highest autopilot:round-N label is below autopilot-rounds, read from policy/autonomy.yml. At the cap, or when only other checks failed (a repository's own workflow, which nothing re-runs), it waits on the maintainer, with the action to take it over (needs-human already comes first). The board then never tells the autopilot to "fix the failed check".

Options a maintainer may care about:

  • (A, recommended, within scope) The round starts only on the jobs of the organisation's pipeline (conventions, the review and, here, actionlint and scripts). On the board, a repository's own failing workflow goes to the maintainer.
  • (B) Also start rounds on a repository's own required workflows, such as a WordPress plugin's suites. That needs a new workflow_run/check_suite trigger outside the two pipelines, which is beyond the PRD's scope, so it is listed as a finding instead.

What this widens: a fix round (the agent's job, with the Claude subscription and a read-only token) now also starts on a failed gate or a review without a verdict. It stays within the same autopilot-rounds and runs caps. No new permission or secret is needed: reading the run's jobs needs actions: read, which autopilot.yml's prep job already holds or will be given, and the pull request says which. In repositories other than this one it takes effect once v7 is moved by a release.

Spec: files

  • .github/workflows/pull-request.yml
  • .github/workflows/org-pull-request.yml
  • .github/workflows/autopilot.yml
  • scripts/autopilot.py
  • scripts/waiting.py
  • scripts/fixtures/waiting.json
  • docs/workflows.md

Spec: tests

  • C1 → scripts/autopilot.py (--test: pull-request.yml's autopilot-fix needs the gates and fires on needs.scripts.result == 'failure'; checks-failed/checks_log_text select the failed jobs and their log; prompt_fix(checks=True) reads .dx-io/checks.md)
  • C2 → scripts/autopilot.py (--test: the condition fires on needs.review.result == 'failure' and on a blocking review; a review job that failed without a verdict at the head is a check round, one with a verdict a review round)
  • C3 → scripts/autopilot.py (--test: next_step with checks_failed past autopilot-rounds waits on a person; rounds_spent text; the fix branch of "May it start" adds needs-human above the cap)
  • C4 → scripts/waiting.py (--test with scripts/fixtures/waiting.json: an autopilot pull request whose scripts or review check failed with rounds left waits on the autopilot's fix round; at the cap, or with only a repository's own check failed, it waits on the maintainer; never "fix the failed check" for the autopilot)
  • C5 → scripts/autopilot.py (--test: org-pull-request.yml's autopilot-fix carries the same trigger as pull-request.yml's apart from the repository and its gate list, which is conventions and review)

Activity

  1. added theissue type on Nov 14, 2026
  2. dilux-bot commented on Nov 14, 2026

    @dilux-bot
    Contributor

    The issue's board

    Gate State
    G1 Issue ready ✓ the PRD follows the schema
    G2 Accepted ✓ by soydiloreto at 2026-11-14T04:14:33Z; PRD sealed 13fd4e90eee7
    Autopilot ✓ merged · 5 of 5 criteria · #746
    G7 Merged ✓ #746 by soydiloreto; receipt in receipts/issues/741/merged-2026-11-14T05:06:35Z.json
    Waits on the autopilot: the autopilot's work (link)

    🤖 AI-generated · Claude Opus 5.5 (Anthropic)

  3. added a commit that references this issue on Nov 14, 2026
  4. added
    acceptedA maintainer accepted this issue; a pull request may close it
    on Nov 14, 2026
  5. dilux-bot commented on Nov 14, 2026

    @dilux-bot
    Contributor

    You wrote this Bug with the maintain or admin role, so it is accepted with its writing: no triage classifies it and no reproduction runs, and its PRD is sealed in your name. The autopilot codes it now in the organisation's runners, starting from a failing test.

    🤖 AI-generated · Claude Opus 5.5 (Anthropic)

  6. dilux-bot commented on Nov 14, 2026

    @dilux-bot
    Contributor

    The autopilot waits for #736: that open autopilot pull request already changes the engine's core (org.yml core), which this issue's Spec touches too, and two changes to the core at once keep putting each other in conflict. It starts this one on its own once #736 merges or closes.

    🤖 AI-generated · Claude Opus 5.5 (Anthropic)

  7. added
    autopilot:core-waitOn an issue: the autopilot waits for another pull request on the engine's core
    autopilot:continueOn an issue: the autopilot continues its draft pull request, or starts it
    and removed
    autopilot:core-waitOn an issue: the autopilot waits for another pull request on the engine's core
    autopilot:continueOn an issue: the autopilot continues its draft pull request, or starts it
    on Nov 14, 2026
  8. added a commit that references this issue on Nov 14, 2026
  9. soydiloreto commented on Nov 14, 2026

    @soydiloreto
    MemberAuthor

    For the next run: the first attempt (#744, closed) was blocked by its review with one major. Avoid it from the start: (1) a capped review with a stale blocking verdict must not be read as a fresh one (scripts/autopilot.py, around run_end/the review state); (2) checks_failed must be carried by the state the production code builds (autopilot.yml's what step and sweep_step), not only by the tests; (3) when the failed jobs cannot be read, it must not stop with an empty list ("could not read which checks failed ()"), which is how #744 stopped itself; (4) --paginate when listing a run's jobs; (5) docs/configuration.md (autopilot-rounds) and docs/pull-requests.md say rounds also start from a failed check.

    🤖 AI-assisted · Claude Opus 5.5 (Anthropic)

  10. added
    acceptedA maintainer accepted this issue; a pull request may close it
    and removed
    acceptedA maintainer accepted this issue; a pull request may close it
    on Nov 14, 2026
  11. dilux-bot commented on Nov 14, 2026

    @dilux-bot
    Contributor

    Issue ready (G1): the PRD has every section of the schema (5 acceptance criteria).

    🤖 AI-generated · Claude Opus 5.5 (Anthropic)

  12. added a commit that references this issue on Nov 14, 2026
  13. moved this to Accepted in Platformon Nov 14, 2026
  14. added a commit that references this issue on Nov 14, 2026
  15. added a commit that references this issue on Nov 14, 2026
  16. moved this from Accepted to Done in Platformon Nov 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

acceptedA maintainer accepted this issue; a pull request may close itbugSomething isn't working

Type

Projects

  • Status
    Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions