From 3f659fcd01b857139e8984eede48cc7b2a3fe958 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Sat, 1 Aug 2026 00:32:12 +0800 Subject: [PATCH 1/2] fix(autofix): extend takeover suggestion window Co-authored-by: Qwen-Coder --- .github/workflows/qwen-autofix.yml | 25 +++++++++++++-------- scripts/tests/qwen-autofix-workflow.test.js | 23 ++++++++++--------- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/.github/workflows/qwen-autofix.yml b/.github/workflows/qwen-autofix.yml index e862c800221..ca597cfaf2d 100644 --- a/.github/workflows/qwen-autofix.yml +++ b/.github/workflows/qwen-autofix.yml @@ -119,6 +119,9 @@ env: # changes, failed checks, and base conflicts may drive code changes; # lower-severity feedback is recorded and left open. CRITICAL_ONLY_AFTER_ROUND: '5' + # Takeover is explicitly delegated work and gets a wider suggestion window + # before the same Critical-only brake engages. + TAKEOVER_CRITICAL_ONLY_AFTER_ROUND: '10' # Per-author tail budget inside Critical-only mode. An account is an # ACCOUNTABILITY unit, not a throttle: a human login can host an automated # reviewer loop with the exact regeneration property the review bot has @@ -2471,10 +2474,10 @@ jobs: | select((.state // "") | IN("CHANGES_REQUESTED", "COMMENTED")) ] | length' \ "${WORKDIR}/rv.json")" # Per AGENTS.md's review policy, Suggestion-level findings are - # actionable during the first five change-producing rounds. The - # scan still selects later feedback so prepare can record and - # watermark its deferral; only the address job filters what may - # drive code changes. + # actionable during the initial change-producing rounds; takeover + # extends that window. The scan still selects later feedback so + # prepare can record and watermark its deferral; only the address + # job filters what may drive code changes. N_COMMENTS="$(jq --arg wm "${EFF_WM}" --arg rb "${REVIEW_BOT}" --arg ab "${AUTOFIX_BOT}" \ --argjson trust "${TRUSTED_ASSOC}" ' [ .[] @@ -3024,8 +3027,12 @@ jobs: STALE='true' echo "⛔ live round ${ROUND} already at MAX_ROUNDS (${MAX_ROUNDS}) — discarding without action or marker" fi + EFFECTIVE_CRITICAL_ONLY_AFTER_ROUND="${CRITICAL_ONLY_AFTER_ROUND}" + if [[ "${LIVE_TAKEOVER}" == "true" ]]; then + EFFECTIVE_CRITICAL_ONLY_AFTER_ROUND="${TAKEOVER_CRITICAL_ONLY_AFTER_ROUND}" + fi CRITICAL_ONLY='false' - if [[ "${ROUND}" -ge "${CRITICAL_ONLY_AFTER_ROUND}" ]]; then + if [[ "${ROUND}" -ge "${EFFECTIVE_CRITICAL_ONLY_AFTER_ROUND}" ]]; then CRITICAL_ONLY='true' fi # Which trusted humans have exhausted their per-window regular @@ -3048,7 +3055,7 @@ jobs: OVER_BUDGET_AUTHORS="$(jq -n \ --arg key "${LIVE_REARM_KEY}" --arg ab "${AUTOFIX_BOT}" --arg rb "${REVIEW_BOT}" \ --argjson trust "${TRUSTED_ASSOC}" \ - --argjson r5 "${CRITICAL_ONLY_AFTER_ROUND}" \ + --argjson critical_after "${EFFECTIVE_CRITICAL_ONLY_AFTER_ROUND}" \ --argjson k "${CRITICAL_ONLY_HUMAN_BATCHES}" \ --slurpfile rv "${WORKDIR}/rv.json" --slurpfile rc "${WORKDIR}/rc.json" --slurpfile ic "${WORKDIR}/ic.json" ' ([ ($ic | add)[] | select((.user.login // "") == $ab) | . as $c | ($c.body // "") @@ -3058,7 +3065,7 @@ jobs: | sort_by(.at)) as $ms | ([ range(0; ($ms | length)) as $i | ($ms[$i] - | select((.acted == "true" and .round > $r5) or (.acted == "false" and .round >= $r5)) + | select((.acted == "true" and .round > $critical_after) or (.acted == "false" and .round >= $critical_after)) | {lo: (if $i == 0 then "" else ($ms[$i - 1].ts) end), hi: .ts}) ]) as $spans | ($rv | add) as $reviews | ($rc | add) as $comments @@ -3101,7 +3108,7 @@ jobs: { echo '## Deferred non-Critical feedback' echo - echo "Critical-only mode is active after ${CRITICAL_ONLY_AFTER_ROUND} change-producing rounds: the automated reviewer's non-Critical suggestions below are deferred and stay open for human follow-up — do not modify code, resolve threads, or reply on their behalf. Maintainer feedback defers only once its author has already had ${CRITICAL_ONLY_HUMAN_BATCHES} regular feedback batches addressed in this window's Critical-only tail — an account can host an automated reviewer loop, so the brake keys on measured regeneration, not identity; authors at their budget, if any, are named below. (A maintainer can lift the mode itself: \`@qwen-code /retry\` starts a fresh counting window.)" + echo "Critical-only mode is active after ${EFFECTIVE_CRITICAL_ONLY_AFTER_ROUND} change-producing rounds: the automated reviewer's non-Critical suggestions below are deferred and stay open for human follow-up — do not modify code, resolve threads, or reply on their behalf. Maintainer feedback defers only once its author has already had ${CRITICAL_ONLY_HUMAN_BATCHES} regular feedback batches addressed in this window's Critical-only tail — an account can host an automated reviewer loop, so the brake keys on measured regeneration, not identity; authors at their budget, if any, are named below. (A maintainer can lift the mode itself: \`@qwen-code /retry\` starts a fresh counting window.)" echo jq -r --arg wm "${WATERMARK}" --arg rb "${REVIEW_BOT}" --arg ab "${AUTOFIX_BOT}" \ --arg pr_url "${PR_URL}" --argjson over "${OVER_BUDGET_AUTHORS}" ' @@ -3156,7 +3163,7 @@ jobs: echo '
' echo '中文说明' echo - echo "完成 ${CRITICAL_ONLY_AFTER_ROUND} 个产生改动的轮次后进入仅处理 Critical 的模式:以上为自动评审的非 Critical 建议,予以延后、保持开放并留待人工跟进——不要为其修改代码、解决线程或代为回复。维护者的反馈仅在其本人于本窗口 Critical-only 阶段已被处理 ${CRITICAL_ONLY_HUMAN_BATCHES} 批常规反馈之后才会被延后——账号可能挂着自动评审循环,因此刹车依据实测的再生频度而非身份;达到预算的作者(如有)在下方点名。(如需解除该模式,评论 \`@qwen-code /retry\` 即可开启新的计数窗口。)" + echo "完成 ${EFFECTIVE_CRITICAL_ONLY_AFTER_ROUND} 个产生改动的轮次后进入仅处理 Critical 的模式:以上为自动评审的非 Critical 建议,予以延后、保持开放并留待人工跟进——不要为其修改代码、解决线程或代为回复。维护者的反馈仅在其本人于本窗口 Critical-only 阶段已被处理 ${CRITICAL_ONLY_HUMAN_BATCHES} 批常规反馈之后才会被延后——账号可能挂着自动评审循环,因此刹车依据实测的再生频度而非身份;达到预算的作者(如有)在下方点名。(如需解除该模式,评论 \`@qwen-code /retry\` 即可开启新的计数窗口。)" echo echo '
' } > "${WORKDIR}/deferred-feedback.md" diff --git a/scripts/tests/qwen-autofix-workflow.test.js b/scripts/tests/qwen-autofix-workflow.test.js index 71d0f1ef518..f1bf7e6f033 100644 --- a/scripts/tests/qwen-autofix-workflow.test.js +++ b/scripts/tests/qwen-autofix-workflow.test.js @@ -3812,28 +3812,31 @@ describe('qwen-autofix workflow', () => { ); }); - it('switches to Critical-only feedback after five change rounds', () => { - // ROUND counts change-producing rounds, so 4 still starts the fifth - // suggestion-capable change while 5 starts the first Critical-only round. + it('gives takeover ten suggestion-capable change rounds', () => { + // ROUND counts change-producing rounds. Standard management enters + // Critical-only mode after 5 changes; explicit takeover enters after 10. expect(workflow).toContain("CRITICAL_ONLY_AFTER_ROUND: '5'"); + expect(workflow).toContain("TAKEOVER_CRITICAL_ONLY_AFTER_ROUND: '10'"); expect(prepareBranchAndFeedbackStep).toContain( - '[[ "${ROUND}" -ge "${CRITICAL_ONLY_AFTER_ROUND}" ]]', + '[[ "${ROUND}" -ge "${EFFECTIVE_CRITICAL_ONLY_AFTER_ROUND}" ]]', ); const modeBlock = prepareBranchAndFeedbackStep.match( - /(CRITICAL_ONLY='false'\n\s+if \[\[ "\$\{ROUND\}" -ge "\$\{CRITICAL_ONLY_AFTER_ROUND\}" \]\]; then\n\s+CRITICAL_ONLY='true'\n\s+fi)/, + /(EFFECTIVE_CRITICAL_ONLY_AFTER_ROUND="\$\{CRITICAL_ONLY_AFTER_ROUND\}"[\s\S]*?CRITICAL_ONLY='false'\n\s+if \[\[ "\$\{ROUND\}" -ge "\$\{EFFECTIVE_CRITICAL_ONLY_AFTER_ROUND\}" \]\]; then\n\s+CRITICAL_ONLY='true'\n\s+fi)/, )?.[1]; expect(modeBlock).toBeTruthy(); - const modeAt = (round) => + const modeAt = (round, takeover) => execFileSync( 'bash', [ '-c', - `ROUND=${round}\nCRITICAL_ONLY_AFTER_ROUND=5\n${modeBlock}\nprintf '%s' "$CRITICAL_ONLY"`, + `ROUND=${round}\nLIVE_TAKEOVER=${takeover}\nCRITICAL_ONLY_AFTER_ROUND=5\nTAKEOVER_CRITICAL_ONLY_AFTER_ROUND=10\n${modeBlock}\nprintf '%s' "$CRITICAL_ONLY"`, ], { encoding: 'utf8' }, ); - expect(modeAt(4)).toBe('false'); - expect(modeAt(5)).toBe('true'); + expect(modeAt(4, false)).toBe('false'); + expect(modeAt(5, false)).toBe('true'); + expect(modeAt(9, true)).toBe('false'); + expect(modeAt(10, true)).toBe('true'); // Once the boundary is crossed, only an explicit Critical inline finding // or a formal changes-requested review is actionable. Suggestion and @@ -4519,7 +4522,7 @@ describe('qwen-autofix workflow', () => { "AUTOFIX_BOT='qwen-code-dev-bot'", "REVIEW_BOT='qwen-code-ci-bot'", `TRUSTED_ASSOC='["OWNER","MEMBER","COLLABORATOR"]'`, - 'CRITICAL_ONLY_AFTER_ROUND=5', + 'EFFECTIVE_CRITICAL_ONLY_AFTER_ROUND=5', 'CRITICAL_ONLY_HUMAN_BATCHES=2', censusBlock.replace(/\n {10}/g, '\n'), 'printf %s "${OVER_BUDGET_AUTHORS}"', From 316ff2d8dc849a03177974cc5a471d838c0a1d18 Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Sat, 1 Aug 2026 00:40:09 +0800 Subject: [PATCH 2/2] fix(autofix): use ten-round suggestion threshold Co-authored-by: Qwen-Coder --- .github/workflows/qwen-autofix.yml | 27 ++++++++------------- scripts/tests/qwen-autofix-workflow.test.js | 26 +++++++++----------- 2 files changed, 22 insertions(+), 31 deletions(-) diff --git a/.github/workflows/qwen-autofix.yml b/.github/workflows/qwen-autofix.yml index ca597cfaf2d..db578bacd9c 100644 --- a/.github/workflows/qwen-autofix.yml +++ b/.github/workflows/qwen-autofix.yml @@ -113,15 +113,12 @@ env: # exists to stop an unproductive LOOP, not to ration ordinary iteration — # a genuinely stuck PR still stops, just later. MAX_ROUNDS: '10' - # Suggestions may improve a young PR, but continuing to implement them after - # five change-producing rounds expands the diff and creates fresh review - # churn. From round 6 onward, only Critical findings, formally requested - # changes, failed checks, and base conflicts may drive code changes; - # lower-severity feedback is recorded and left open. - CRITICAL_ONLY_AFTER_ROUND: '5' - # Takeover is explicitly delegated work and gets a wider suggestion window - # before the same Critical-only brake engages. - TAKEOVER_CRITICAL_ONLY_AFTER_ROUND: '10' + # Suggestions may improve a PR, but continuing to implement them after ten + # change-producing rounds expands the diff and creates fresh review churn. + # From round 11 onward, only Critical findings, formally requested changes, + # failed checks, and base conflicts may drive code changes; lower-severity + # feedback is recorded and left open. + CRITICAL_ONLY_AFTER_ROUND: '10' # Per-author tail budget inside Critical-only mode. An account is an # ACCOUNTABILITY unit, not a throttle: a human login can host an automated # reviewer loop with the exact regeneration property the review bot has @@ -3027,12 +3024,8 @@ jobs: STALE='true' echo "⛔ live round ${ROUND} already at MAX_ROUNDS (${MAX_ROUNDS}) — discarding without action or marker" fi - EFFECTIVE_CRITICAL_ONLY_AFTER_ROUND="${CRITICAL_ONLY_AFTER_ROUND}" - if [[ "${LIVE_TAKEOVER}" == "true" ]]; then - EFFECTIVE_CRITICAL_ONLY_AFTER_ROUND="${TAKEOVER_CRITICAL_ONLY_AFTER_ROUND}" - fi CRITICAL_ONLY='false' - if [[ "${ROUND}" -ge "${EFFECTIVE_CRITICAL_ONLY_AFTER_ROUND}" ]]; then + if [[ "${ROUND}" -ge "${CRITICAL_ONLY_AFTER_ROUND}" ]]; then CRITICAL_ONLY='true' fi # Which trusted humans have exhausted their per-window regular @@ -3055,7 +3048,7 @@ jobs: OVER_BUDGET_AUTHORS="$(jq -n \ --arg key "${LIVE_REARM_KEY}" --arg ab "${AUTOFIX_BOT}" --arg rb "${REVIEW_BOT}" \ --argjson trust "${TRUSTED_ASSOC}" \ - --argjson critical_after "${EFFECTIVE_CRITICAL_ONLY_AFTER_ROUND}" \ + --argjson critical_after "${CRITICAL_ONLY_AFTER_ROUND}" \ --argjson k "${CRITICAL_ONLY_HUMAN_BATCHES}" \ --slurpfile rv "${WORKDIR}/rv.json" --slurpfile rc "${WORKDIR}/rc.json" --slurpfile ic "${WORKDIR}/ic.json" ' ([ ($ic | add)[] | select((.user.login // "") == $ab) | . as $c | ($c.body // "") @@ -3108,7 +3101,7 @@ jobs: { echo '## Deferred non-Critical feedback' echo - echo "Critical-only mode is active after ${EFFECTIVE_CRITICAL_ONLY_AFTER_ROUND} change-producing rounds: the automated reviewer's non-Critical suggestions below are deferred and stay open for human follow-up — do not modify code, resolve threads, or reply on their behalf. Maintainer feedback defers only once its author has already had ${CRITICAL_ONLY_HUMAN_BATCHES} regular feedback batches addressed in this window's Critical-only tail — an account can host an automated reviewer loop, so the brake keys on measured regeneration, not identity; authors at their budget, if any, are named below. (A maintainer can lift the mode itself: \`@qwen-code /retry\` starts a fresh counting window.)" + echo "Critical-only mode is active after ${CRITICAL_ONLY_AFTER_ROUND} change-producing rounds: the automated reviewer's non-Critical suggestions below are deferred and stay open for human follow-up — do not modify code, resolve threads, or reply on their behalf. Maintainer feedback defers only once its author has already had ${CRITICAL_ONLY_HUMAN_BATCHES} regular feedback batches addressed in this window's Critical-only tail — an account can host an automated reviewer loop, so the brake keys on measured regeneration, not identity; authors at their budget, if any, are named below. (A maintainer can lift the mode itself: \`@qwen-code /retry\` starts a fresh counting window.)" echo jq -r --arg wm "${WATERMARK}" --arg rb "${REVIEW_BOT}" --arg ab "${AUTOFIX_BOT}" \ --arg pr_url "${PR_URL}" --argjson over "${OVER_BUDGET_AUTHORS}" ' @@ -3163,7 +3156,7 @@ jobs: echo '
' echo '中文说明' echo - echo "完成 ${EFFECTIVE_CRITICAL_ONLY_AFTER_ROUND} 个产生改动的轮次后进入仅处理 Critical 的模式:以上为自动评审的非 Critical 建议,予以延后、保持开放并留待人工跟进——不要为其修改代码、解决线程或代为回复。维护者的反馈仅在其本人于本窗口 Critical-only 阶段已被处理 ${CRITICAL_ONLY_HUMAN_BATCHES} 批常规反馈之后才会被延后——账号可能挂着自动评审循环,因此刹车依据实测的再生频度而非身份;达到预算的作者(如有)在下方点名。(如需解除该模式,评论 \`@qwen-code /retry\` 即可开启新的计数窗口。)" + echo "完成 ${CRITICAL_ONLY_AFTER_ROUND} 个产生改动的轮次后进入仅处理 Critical 的模式:以上为自动评审的非 Critical 建议,予以延后、保持开放并留待人工跟进——不要为其修改代码、解决线程或代为回复。维护者的反馈仅在其本人于本窗口 Critical-only 阶段已被处理 ${CRITICAL_ONLY_HUMAN_BATCHES} 批常规反馈之后才会被延后——账号可能挂着自动评审循环,因此刹车依据实测的再生频度而非身份;达到预算的作者(如有)在下方点名。(如需解除该模式,评论 \`@qwen-code /retry\` 即可开启新的计数窗口。)" echo echo '
' } > "${WORKDIR}/deferred-feedback.md" diff --git a/scripts/tests/qwen-autofix-workflow.test.js b/scripts/tests/qwen-autofix-workflow.test.js index f1bf7e6f033..c3050958d5a 100644 --- a/scripts/tests/qwen-autofix-workflow.test.js +++ b/scripts/tests/qwen-autofix-workflow.test.js @@ -3812,31 +3812,29 @@ describe('qwen-autofix workflow', () => { ); }); - it('gives takeover ten suggestion-capable change rounds', () => { - // ROUND counts change-producing rounds. Standard management enters - // Critical-only mode after 5 changes; explicit takeover enters after 10. - expect(workflow).toContain("CRITICAL_ONLY_AFTER_ROUND: '5'"); - expect(workflow).toContain("TAKEOVER_CRITICAL_ONLY_AFTER_ROUND: '10'"); + it('switches to Critical-only feedback after ten change rounds', () => { + // ROUND counts change-producing rounds, so 9 still starts the tenth + // suggestion-capable change while 10 starts the first Critical-only round. + expect(workflow).toContain("CRITICAL_ONLY_AFTER_ROUND: '10'"); + expect(workflow).not.toContain('TAKEOVER_CRITICAL_ONLY_AFTER_ROUND'); expect(prepareBranchAndFeedbackStep).toContain( - '[[ "${ROUND}" -ge "${EFFECTIVE_CRITICAL_ONLY_AFTER_ROUND}" ]]', + '[[ "${ROUND}" -ge "${CRITICAL_ONLY_AFTER_ROUND}" ]]', ); const modeBlock = prepareBranchAndFeedbackStep.match( - /(EFFECTIVE_CRITICAL_ONLY_AFTER_ROUND="\$\{CRITICAL_ONLY_AFTER_ROUND\}"[\s\S]*?CRITICAL_ONLY='false'\n\s+if \[\[ "\$\{ROUND\}" -ge "\$\{EFFECTIVE_CRITICAL_ONLY_AFTER_ROUND\}" \]\]; then\n\s+CRITICAL_ONLY='true'\n\s+fi)/, + /(CRITICAL_ONLY='false'\n\s+if \[\[ "\$\{ROUND\}" -ge "\$\{CRITICAL_ONLY_AFTER_ROUND\}" \]\]; then\n\s+CRITICAL_ONLY='true'\n\s+fi)/, )?.[1]; expect(modeBlock).toBeTruthy(); - const modeAt = (round, takeover) => + const modeAt = (round) => execFileSync( 'bash', [ '-c', - `ROUND=${round}\nLIVE_TAKEOVER=${takeover}\nCRITICAL_ONLY_AFTER_ROUND=5\nTAKEOVER_CRITICAL_ONLY_AFTER_ROUND=10\n${modeBlock}\nprintf '%s' "$CRITICAL_ONLY"`, + `ROUND=${round}\nCRITICAL_ONLY_AFTER_ROUND=10\n${modeBlock}\nprintf '%s' "$CRITICAL_ONLY"`, ], { encoding: 'utf8' }, ); - expect(modeAt(4, false)).toBe('false'); - expect(modeAt(5, false)).toBe('true'); - expect(modeAt(9, true)).toBe('false'); - expect(modeAt(10, true)).toBe('true'); + expect(modeAt(9)).toBe('false'); + expect(modeAt(10)).toBe('true'); // Once the boundary is crossed, only an explicit Critical inline finding // or a formal changes-requested review is actionable. Suggestion and @@ -4522,7 +4520,7 @@ describe('qwen-autofix workflow', () => { "AUTOFIX_BOT='qwen-code-dev-bot'", "REVIEW_BOT='qwen-code-ci-bot'", `TRUSTED_ASSOC='["OWNER","MEMBER","COLLABORATOR"]'`, - 'EFFECTIVE_CRITICAL_ONLY_AFTER_ROUND=5', + 'CRITICAL_ONLY_AFTER_ROUND=5', 'CRITICAL_ONLY_HUMAN_BATCHES=2', censusBlock.replace(/\n {10}/g, '\n'), 'printf %s "${OVER_BUDGET_AUTHORS}"',