fix(ci): route the autofix convergence-brake handoff through failure.md - #9371
Conversation
The growth brake tells the address-review agent to stop with a handoff but never names the output file, so round 14 on QwenLM#9184 wrote handoff.md — a file owned by run-agent.mjs that the verdict gate does not accept. The round was reported as missing its required outputs even though the defer-to-human was correct (run 32076785809). Name failure.md (the stop file run-agent.mjs wraps into the handoff comment) as the handoff target, forbid agent-written handoff.md, and pin the directive in the workflow contract test.
|
✅ Qwen Triage finished — CI landed green on ✅ Qwen Triage 已完成 —— |
|
Thanks for the PR! Template looks good ✓ Problem: observed, not theoretical — and I verified it independently. The round-14 comment on PR #9184 (run 32076785809) shows exactly the failure described: the growth brake fired, the agent deferred to a human, yet the round still landed as Direction: aligned. This is the autofix loop's own output contract. Routing the brake's handoff through the pre-existing Size: 2 files, +17/−6 (11 skill-text lines + 6 contract-test lines). No core package paths touched — Stage 0 not applicable. Approach: minimal and complete — names the file, states the reason, forbids the runner-owned one, and pins both directives in the existing workflow contract test. Nothing to cut, no drive-by changes. Risk: no elevated risk signals (no high-risk paths touched; skill text and scripts tests only). Moving on to code review. 🔍 中文说明感谢贡献! 模板完整 ✓ 问题:已观测到,不是理论问题——且我已独立核实。PR #9184 第 14 轮(run 32076785809)的评论正是所描述的失败:增长刹车触发、agent 交还给人类,但该轮仍以 方向:对齐。这是 autofix 循环自身的输出契约。让刹车的交接走既有的 规模:2 个文件,+17/−6(11 行 skill 文本 + 6 行契约测试)。未触及 core 包路径——Stage 0 不适用。 方案:最小且完整——点名文件、说明原因、禁写 runner 自有文件,并在既有 workflow 契约测试中钉住两条指令。没有可砍的部分,也没有顺手改动。 风险:无升级风险信号(未触及高风险路径;仅 skill 文本与 scripts 测试)。 进入代码审查 🔍 — Qwen Code · qwen3.8-max Reviewed at |
Code reviewBefore reading the diff, my independent proposal for this problem was exactly what this PR does: name Every mechanism claim checks out against the base tree:
No correctness, security, or convention findings. The diff carries nothing beyond the stated goal. CI evidenceUnattended CI run — the PR's code is neither built nor executed here; the evidence below quotes the PR's own CI checks fetched via the API, once, at review time. The job that actually runs the pinned contract test ( Final CI results for
One row per check name (latest run); skipped checks omitted; failures sort first. / 每个检查名一行(取最新一次运行),省略 skipped,失败项排在最前。 Sandboxed lanes: there is no claim here 中文说明代码审查读 diff 之前,我对这个问题的独立方案与 PR 做法完全一致:在非收敛条目中点名 所有机制性论断都已对照基线树核实: 无正确性、安全或规范问题。diff 没有超出既定目标的内容。 CI 证据无人值守 CI 运行——此处不构建、不执行 PR 代码;下方证据为审查时通过 API 一次性抓取的 PR 自身 CI 检查。真正运行钉住契约测试的 job( 沙盒验证通道:此处没有 — Qwen Code · qwen3.8-max Reviewed at |
|
Confidence: 4/5 — everything statically verifiable checks out (observed problem, verified mechanism, minimal diff, pinning test); the one reservation is inherently unprovable in advance: whether the agent actually follows the new instruction at the next real brake round. Stepping back: this is exactly the kind of fix the gate should wave through. The failure was observed in production (PR #9184 round 14, verified against the actual comment), the fix routes through a stop path that already exists and already works — no new machinery, no gate changes — and the contract test pins the wording so it cannot silently regress. Twenty-three lines across two files with zero drive-by content; my independent proposal matched the PR's approach point for point, and I have nothing simpler to suggest. The only thing no review can give you in advance is the model-compliance proof, and explicit file naming plus the pinning test is the right mitigation for it. Verdict: approve. The unit suite that runs the pinning test is still in flight, so approval is deferred until CI lands green on 中文说明置信度:4/5 —— 一切可静态核实之处均通过(问题已观测、机制已核实、diff 最小、契约测试钉住);唯一保留意见本质上无法预先证明:下一次真实刹车轮次中 agent 是否真的遵循新指令。 退一步看:这正是 gate 应当放行的修复。失败在生产中观测到(PR #9184 第 14 轮,已对照真实评论核实),修复走的是既已存在、既已可用的停止路径——没有新机制、没有 gate 改动——且契约测试钉住措辞,防止悄悄回退。两个文件共 23 行、零顺手改动;我的独立方案与 PR 逐点一致,没有更简路径可提。唯一任何审查都无法预先给出的是模型遵循性证明,而点名文件加点钉住测试正是对它的正确缓解。 结论:批准。运行钉住测试的单测套件仍在进行,因此批准推迟到 CI 在该提交上落绿。 — Qwen Code · qwen3.8-max Reviewed at |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
LGTM, looks ready to ship — CI landed green after the review. ✅
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
No issues found. LGTM! ✅
中文说明
未发现问题。LGTM!✅
— qwen3.8-max via Qwen Code /review (v0.21.13)
The SKILL.md conflict pits this PR's handoff output contract against QwenLM#9371's failure.md stopgap. Resolve it in this PR's favor: the merged run-agent.mjs accepts an agent-written handoff.md as a first-class verdict (exit 0, no spec output) and the merged verify gate classifies it as outcome=handoff (or dirty_handoff over a dirty tree), which is exactly the acceptance QwenLM#9371's failure.md routing worked around. Re-pin QwenLM#9371's contract-test assertions to the handoff.md directive so they lock the new contract instead of the superseded stopgap.
|
Released in v0.21.14. |
What this PR does
When the autofix loop's growth brake decides a PR's diff is not converging, the round feedback tells the agent to stop patching and hand the decision to a maintainer. This change makes that instruction name the exact output file the agent must write its handoff into, and forbids it from writing the wrapper file that the runner-side harness owns. The workflow contract test now pins the instruction so a future edit cannot silently flip it back.
Why it's needed
On PR #9184 round 14 (run 32076785809) the convergence brake fired and the agent did exactly what the feedback asked: no code changes, verified the remaining Critical finding by direct code reading, and wrote a handoff naming the decision, the options (split the PR, redesign, or accept with the tail deferred), and a recommendation. But it wrote that handoff into
handoff.md— a file the runner-side harness generates, not one the round's verdict gate accepts (onlyaddress-summary.mdorno-action.mdas success verdicts, plusfailure.mdas the sole stop verdict). The round was therefore reported as "finished without required output file(s)": a correct defer-to-human burned a round as a failure, and the PR comment carried the generic gate error instead of the agent's handoff analysis.Writing
failure.mdis already the established stop path — the runner wraps it into the workflow's handoff comment and exits zero, and the verification gate treats it as a deliberate abort. This change simply routes the brake's handoff through that existing path end to end.Reviewer Test Plan
How to verify
failure.md, explains that this is the one stop file the round's output contract accepts, and forbids the agent from writinghandoff.mditself (with the reason).failure.md, exits zero, the verification gate reports a deliberate abort, and the handoff comment's "What I found before stopping" section carries the agent's decision analysis instead of the missing-output gate error.Evidence (Before & After)
N/A — agent-behavior policy text and its contract test; no user-visible/TUI change. Before: see the round-14 comment on PR #9184 ("Could not produce a passing fix ... finished without required output file(s)"). After: the same situation routes through the existing
failure.mdhandoff path.Tested on
Environment (optional)
Contract test only:
npx vitest run --config ./scripts/tests/vitest.config.ts scripts/tests/qwen-autofix-workflow.test.js. The 2 unrelated failures in that file (bite check,keeps the green path intact) also fail on the clean base tree in this local environment.Risk & Scope
failure.mdpath itself is pre-existing and already exercised. Posting inlinecomment-replies.jsonreplies on the handoff path remains unposted (unchanged by this PR).Linked Issues
Observed on PR #9184 round 14 (run 32076785809); no issue filed.
中文说明
本 PR 做了什么
当 autofix 循环的增长刹车判定某个 PR 的 diff 不收敛时,该轮的 feedback 会指示 agent 停止打补丁、把决策交还给维护者。本次改动让这条指示明确写出 agent 必须把交接内容写入的具体输出文件,并禁止 agent 去写那个由 runner 侧脚本自己生成的包装文件。workflow 契约测试现在把这条指令钉住,防止未来的修改把它悄悄改回去。
为什么需要
在 PR #9184 第 14 轮(run 32076785809)中,收敛刹车触发,agent 完全按 feedback 要求执行:不改代码、通过直接读码核实了剩余的 Critical finding、并写了一份交接,指明决策点、列出选项(拆分 PR、重新设计、或接受现状并把尾巴延后)以及推荐意见。但它把交接写进了
handoff.md—— 这个文件是 runner 侧脚本生成的,并不在该轮 verdict gate 接受的范围内(gate 只接受address-summary.md或no-action.md作为成功结论,外加failure.md作为唯一的停止结论)。于是该轮被上报为 "finished without required output file(s)":一次正确的 defer-to-human 以失败姿态烧掉了一轮,PR 评论里也只有干巴巴的 gate 报错,而不是 agent 的交接分析。写
failure.md本来就是既有的停止路径 —— runner 会把它包装进 workflow 的交接评论并以零码退出,验证 gate 也将其视为有意中止。本次改动只是让刹车的交接走这条既有路径,端到端打通。审阅者测试计划
如何验证
failure.md,说明这是该轮输出契约接受的唯一停止文件,并禁止 agent 自己写handoff.md(附原因)。failure.md、零码退出,验证 gate 上报有意中止,交接评论的 "What I found before stopping" 部分呈现 agent 的决策分析,而不是 missing-output gate 报错。证据(前后对比)
N/A —— agent 行为策略文本及其契约测试,无用户可见/TUI 变化。Before:见 PR #9184 第 14 轮评论("Could not produce a passing fix ... finished without required output file(s)")。After:同样情形将走既有的
failure.md交接路径。测试环境
运行环境(可选)
仅契约测试:
npx vitest run --config ./scripts/tests/vitest.config.ts scripts/tests/qwen-autofix-workflow.test.js。该文件中 2 个不相关的失败(bite check、keeps the green path intact)在本机干净基线树上同样失败,与本 PR 无关。风险与范围
failure.md路径本身是既有的且已被使用过。交接路径下不发布内联comment-replies.json回复的行为维持不变(本 PR 未改动)。关联 Issue
观察于 PR #9184 第 14 轮(run 32076785809);未建 issue。