Skip to content

Autofix pushes cancel in-progress review-pr, creating a self-reinforcing loop on bot-authored PRs #8888

Closed

Description

@yiliang114

What happened?

On bot-authored PRs (qwen-code-dev-bot), the autofix workflow and the review-pr workflow form a self-reinforcing cancellation loop:

  1. Autofix bot pushes a commit to address review feedback
  2. GitHub fires pull_request_target: synchronize on the push
  3. qwen-code-pr-review.yml has cancel-in-progress: true on synchronize events — the in-progress review-pr run is killed immediately
  4. A new review-pr starts from scratch on the new head
  5. The autofix bot picks up partial review output from the previous (now-cancelled) run, pushes more fixes → goto 2

This means the review-pr never gets enough uninterrupted time to complete a full review pass. Each autofix push resets hours of review work.

Concrete case: PR #8830

Time (UTC) Event Review-pr status
04:27 PR created (efb6fee, 2 files) review-pr starts
05:10 bot push 38569c9 review-pr killed (ran 43 min)
05:29 bot merge main (a1faea1) review-pr killed (ran 19 min)
05:49 human reviewer finds tsc error —
06:20 bot push acb6475 (fix type) review-pr killed (ran 51 min)
08:43 review-pr finally posts findings (7 issues) longest window: 2h23m
09:46 bot push 01f27b1 review-pr killed (ran 63 min)
12:02 review-pr round 2 posts findings —
12:45 bot push 3300977 review-pr killed (ran 43 min)
13:57 bot merge main (0e16199) review-pr killed (ran ~72 min)
now — review-pr still in_progress
  • 7 commits in ~9.5 hours
  • review-pr cancelled and restarted at least 6 times
  • Longest uninterrupted review window: ~3h26m (06:20→09:46), but the review took 2h23m to produce output
  • PR scope: 2 files → 15+ files across 3 packages
  • concurrency cost ledger for this PR: 83 API calls, ~8.7M input tokens, ~199K output tokens

Root cause

qwen-code-pr-review.yml line 65:

cancel-in-progress: "${{ github.event_name == 'pull_request_target' && (github.event.action == 'synchronize' || github.event.action == 'closed') }}"

Every autofix push is a synchronize event to the PR, which unconditionally cancels the in-progress review-pr.

Why this matters

  1. Reviews are incomplete — the review bot never finishes a full pass, so findings are fragmented across multiple runs
  2. PR scope explodes — each partial review catches new issues in the previous fix, and the autofix bot keeps expanding the PR to address them
  3. Humans can't keep up — by the time a human reviewer opens the PR, the bot has already pushed 3-4 rounds of changes
  4. Massive CI waste — every review-pr cancellation discards compute/token work; PR fix(core): compute stored provider version from built-in template so 'update all' clears the prompt #8830 alone consumed ~8.7M tokens

Suggested fix

Options (not mutually exclusive):

  1. Don't cancel review-pr on autofix bot pushes — skip cancel-in-progress when the push author is qwen-code-dev-bot (the autofix bot's own pushes, not human pushes or base updates)
  2. Add a cooldown — after an autofix push, wait for review-pr to complete (or timeout) before allowing the next autofix round
  3. Run review-pr only on opened/reopened, not synchronize, for bot-authored PRs — let the scheduled autofix scan pick up new feedback instead of real-time triggers
中文

发生了什么?

在 bot 创建的 PR(qwen-code-dev-bot)上,autofix 工作流和 review-pr 工作流形成了自我强化的取消循环:

  1. Autofix bot 推送 commit 修复 review 意见
  2. GitHub 在 push 时触发 pull_request_target: synchronize
  3. qwen-code-pr-review.yml 在 synchronize 事件上设置了 cancel-in-progress: true —— 正在运行的 review-pr 被立即杀死
  4. 新的 review-pr 在新 head 上从头开始
  5. Autofix bot 拿到上一轮(已被取消的)review 的部分输出,推送更多修复 → 回到第 2 步

这意味着 review-pr 永远得不到足够的连续时间来跑完一次完整的审查。每次 autofix push 都会重置数小时的审查工作。

具体案例:PR #8830

时间 (UTC) 事件 review-pr 状态
04:27 PR 创建(efb6fee,2 个文件) review-pr 开始
05:10 bot push 38569c9 review-pr 被杀(跑了 43 分钟)
05:29 bot merge main(a1faea1) review-pr 被杀(跑了 19 分钟)
05:49 人类 reviewer 发现 tsc 错误 —
06:20 bot push acb6475(修类型) review-pr 被杀(跑了 51 分钟)
08:43 review-pr 终于产出结果(7 个 findings) 最长窗口:2h23min
09:46 bot push 01f27b1 review-pr 被杀(跑了 63 分钟)
12:02 review-pr 第 2 轮产出 —
12:45 bot push 3300977 review-pr 被杀(跑了 43 分钟)
13:57 bot merge main(0e16199) review-pr 被杀(跑了 ~72 分钟)
现在 — review-pr 仍在 in_progress
  • 7 个 commit,约 9.5 小时内
  • review-pr 被取消并重启了 至少 6 次
  • 最长不中断审查窗口:约 3h26min(06:20→09:46),但 review 花了 2h23min 才产出结果
  • PR 范围:2 个文件 → 3 个包共 15+ 个文件
  • 该 PR 的 concurrency 账本:83 次 API 调用,~8.7M 输入 token,~199K 输出 token

根因

qwen-code-pr-review.yml 第 65 行:

cancel-in-progress: "${{ github.event_name == 'pull_request_target' && (github.event.action == 'synchronize' || github.event.action == 'closed') }}"

每次 autofix push 对 PR 来说都是 synchronize 事件,无条件取消正在运行的 review-pr。

为什么这很重要

  1. 审查不完整 —— review bot 永远无法完成一次完整审查,发现的问题分散在多次运行中
  2. PR 范围膨胀 —— 每次部分审查都能在上一次修复中发现新问题,autofix bot 不断扩展 PR 去处理
  3. 人类跟不上 —— 人类 reviewer 打开 PR 时,bot 已经推了 3-4 轮改动
  4. 巨大的 CI 浪费 —— 每次 review-pr 取消都丢弃了计算/token 工作;仅 PR fix(core): compute stored provider version from built-in template so 'update all' clears the prompt #8830 就消耗了约 8.7M token

建议修复

选项(不互斥):

  1. 不在 autofix bot 的 push 上取消 review-pr —— 当 push 作者是 qwen-code-dev-bot(autofix bot 自己的 push,不是人类的 push 或 base 更新)时跳过 cancel-in-progress
  2. 添加冷却期 —— autofix push 之后,等待 review-pr 完成(或超时)再允许下一轮 autofix
  3. 对 bot 创建的 PR,review-pr 只在 opened/reopened 上运行,不在 synchronize 上运行 —— 让定时 autofix 扫描来获取新反馈,而不是实时触发

Activity

  1. doudouOUC commented on Aug 10, 2026

    @doudouOUC
    Collaborator

    Confirmed against current main — the analysis matches what the workflows actually do, and there are two reinforcing mechanisms (one on each side) worth adding.

    Root cause (verified)

    .github/workflows/qwen-code-pr-review.yml, concurrency block (lines 51–59 on main):

    concurrency:
      group: >-
        ${{ github.event_name == 'pull_request_target' &&
        format('qwen-pr-review-pr-{0}', github.event.pull_request.number) ||
        format('qwen-pr-review-run-{0}', github.run_id) }}
      cancel-in-progress: "${{ github.event_name == 'pull_request_target' && (github.event.action == 'synchronize' || github.event.action == 'closed') }}"

    Every synchronize kills the in-flight review regardless of who pushed — the expression never consults github.event.sender.login.

    Why the 10-minute delay doesn't help here

    delay-automatic-review does debounce opened/synchronize via the qwen-pr-review-delay environment wait timer (currently 10 minutes per the comment in the file), but that only coalesces pushes less than 10 minutes apart. Autofix rounds in the #8830 timeline are ~40–90 minutes apart, so every push sails through the delay gate and cancels a review that needs 1–3 hours to finish a pass.

    The autofix side never waits for the review either

    qwen-autofix.yml line 155 explicitly excludes review-pr from the checks it waits on before pushing:

    NON_BLOCKING_CHECKS: '["review-pr"]'

    So the two workflows have no mutual synchronization at all: autofix pushes as soon as it has actionable (even partial) findings, and each push resets the review. With the */10 cron plus the pull_request_review: submitted trigger, partial findings are picked up within minutes — that's the "goto 2" in the loop description.

    Notes on the suggested fixes

    • Option 1 is directly implementable: cancel-in-progress accepts an expression, and github.event.sender.login is available on synchronize (sender = the pusher), so bot pushes can be excluded. Two caveats: (a) with cancellation disabled for bot pushes, each synchronize still enqueues a fresh run in the PR-scoped group and those runs then execute sequentially — to avoid a queue pile-up you'd likely want to skip the trigger itself for bot pushes (an option-3 variant), not just the cancellation; (b) the bot login is vars.AUTOFIX_BOT_LOGIN || 'qwen-code-dev-bot' in qwen-autofix.yml, so the guard should key off the same variable rather than a hardcoded login.
    • For options 1/3: a review that survives a bot push reviews the head it started on, so its findings lag the branch by one push. Probably acceptable for bot PRs (the next pass catches up), but it means the "review of record" trails the branch while autofix is active.
    • Option 2 is cheap on the autofix side: before pushing in the review phase, check gh run list --workflow qwen-code-pr-review.yml --branch <head> --status in_progress and defer the round if a review is running — the */10 cron retries naturally, so a deferral costs at most one tick. This also attacks the "partial findings → scope explosion" symptom directly, because autofix would respond to a complete pass.

    Net: option 3 for bot-authored PRs (review on opened/reopened and explicit /review; let the scheduled scan pick up the rest) combined with option 2 as the autofix-side guard looks like the smallest change that breaks the loop from both directions.

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

    category/developmentDevelopment experiencepriority/P2Medium - Moderately impactful, noticeable problemscope/github-actionsGitHub Actions integrationstatus/ready-for-humanSpecified but requires human judgment to implement; not suitable for an autonomous agenttype/bugSomething isn't working as expected

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions