perf(autofix): build the review CLI bundle once per scan and fan it out to legs - #8548
Conversation
…ut to legs Each review-address leg repeated the same trusted-base build: measured 3.5-5 minutes of npm ci + build + bundle per leg (~25 runner-minutes on one 6-leg scan) before the agent could start. A build-cli job now compiles the bundle once per scan, uploads the repo-root dist/ as an artifact, and the legs download it; their checkout is pinned to the compiled SHA so a mid-run base push can never pair a leg's bundle with different sources. The legs keep npm ci (the agent and the verify gate still need node_modules against the PR branch), and the issue phase is untouched — it runs only when no review targets exist, so gating the build on do_issue too would rebuild on every quiet scheduled tick.
|
Thanks for the PR! Re-run on the new head ( Template looks good ✓ Problem: observed, not theoretical — run 30912069124 shows each of the 6 review-address legs spending 204–307s rebuilding the same trusted-base bundle before the agent can start (~25 runner-minutes of identical work per scan). For a perf/CI change the timing measurement is the reproduction, and it's provided. Direction: aligned. This is internal CI efficiency with a clear latency win for autofix feedback, and it explicitly does not change what gets verified. No CHANGELOG signal applies (CI-only change). Size: no core paths touched — the autofix workflow is 148 production lines (+139/−9) and the two contract-test files are 138 test lines (+131/−7). Below every threshold; no advisory. Approach: the scope still feels right. Build once, fan out a run-scoped artifact — that's the minimal mechanism here, and the obvious alternative (an Risk: no Stage 1e high-risk path matches. The workflow is security-adjacent (the address legs carry secrets), so the shared artifact's trust chain got the detailed look at the code-review stage — Moving on to code review. 🔍 中文说明感谢贡献!这是针对新 head( 模板完整 ✓ 问题:已观测而非理论——run 30912069124 显示 6 条 review-address leg 每条都要花 204–307 秒重复构建同一个 trusted-base bundle(每次 scan 约 25 runner-分钟的相同工作)。对 perf/CI 类改动,耗时测量本身就是复现,且已提供。 方向:对齐。这是纯内部 CI 效率优化,能明显降低 autofix 反馈延迟,且明确不改变被验证的内容。CHANGELOG 无对应信号(CI-only 改动)。 规模:未触及核心路径——autofix 工作流 148 行生产逻辑(+139/−9),两个契约测试文件 138 行测试(+131/−7)。低于所有阈值,无需大 PR 提示。 方案:范围依然合理。构建一次并通过 run 级 artifact 分发是这里的最小机制;显而易见的替代方案(按 base SHA 键控的 风险:Stage 1e 高风险路径无命中。该工作流与安全相关(address leg 携带 secrets),因此共享 artifact 的信任链在代码审查阶段做了重点核查—— 进入代码审查 🔍 — Qwen Code · qwen3.8-max Reviewed at |
Code reviewRe-run after two new commits since the last pass: a merge of current main, and the fix round addressing the four inline suggestions from the automated review. The core design I reviewed before stands, and the delta holds up:
No blockers, no convention violations. Testing evidenceUnattended CI run — PR code is never executed here; the evidence is the PR's own CI on the reviewed commit, fetched via the API. Two checks need explaining.
One row per check name (latest run); skipped checks omitted; failures sort first. / 每个检查名一行(取最新一次运行),省略 skipped,失败项排在最前。 Not verified (and can't be, pre-merge): a real multi-leg fan-out with review targets — cross-job artifact transfer and matrix fan-out only happen on a live scheduled scan. The design bounds that risk: a failed 中文说明代码审查自上次审查后新增两个 commit:合入当前 main,以及处理自动评审四条 inline 建议的修复轮次。此前审查的核心设计保持不变,增量部分也经得起检验:
无阻塞问题,无约定违规。 测试证据无人值守 CI 运行——此处不执行 PR 代码;证据为被审 commit 上 PR 自身的 CI(经 API 获取)。 两个检查需要解释。 CI 结果摘要:除 未验证(merge 前也无法验证):带真实 review 目标的多 leg 扇出——跨 job artifact 传输与矩阵扇出只有实际定时 scan 才会发生。设计上已限制该风险: — Qwen Code · qwen3.8-max Reviewed at |
|
Confidence: 4/5 — clean across every stage; the one reservation remains the piece nobody can check pre-merge (a live multi-leg fan-out with real targets), and the design bounds it fail-closed. The fix round since the last review did the work properly — all four inline findings answered with real pins rather than minimal text edits: the loud fail-closed SHA guard now runs before the leg's checkout, the Verdict: approve. CI has settled on this commit — the one red check is the automated review timing out on its 180-minute budget (pre-existing bot infra, twice now on this PR), and the unit suite carrying the contract tests is green — so no deferred approval this round. 中文说明置信度:4/5 —— 各阶段审查均干净;唯一的保留仍是 merge 前谁都无法验证的部分(带真实目标的多 leg 实际扇出),而设计上已用 fail-closed 收口。 上次审查之后的修复轮次做得扎实——四条 inline 意见全部用真正的契约固定来回应,而不是最小化的文字修改:大声的 fail-closed SHA 校验现在先于 leg 的 checkout 执行; 结论:批准。CI 已在该 commit 上稳定——唯一的红色检查是自动评审用满 180 分钟预算超时(既有机器人基础设施问题,本 PR 上已出现两次),承载契约测试的单元测试套件为绿——因此本轮无需延迟批准。 — Qwen Code · qwen3.8-max Reviewed at |
|
@qwen-code /takeover |
|
🤝 Takeover engaged: the autofix loop now manages this PR — it will address new review feedback and resolve base conflicts until the label is removed or the round cap is reached. This is a fork PR, so the first round comes from the next scheduled scan (usually within minutes). Remove the 中文说明🤝 已接管:autofix 循环现在管理此 PR —— 将持续处理新的评审反馈与 base 冲突,直到移除标签或达到轮次上限。本 PR 来自 fork,首轮处理将由下一次定时扫描执行(通常几分钟内)。移除 |
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 review timed out. Qwen review timed out after 10800 seconds (of the 180-minute budget). For large PRs, retry with a longer timeout by commenting: |
|
🔀 Base updated: red check(s) [review-pr] pass on current main — merged current main via update-branch; CI will re-run. 中文说明🔀 已更新 base:红色检查 [review-pr] 在当前 main 上通过 —— 已通过 update-branch 合入当前 main,CI 将重新运行。 |
|
🤖 Reviewed the latest feedback — no changes needed. Why, point by point: · 已审阅最新反馈——无需改动。逐点说明原因如下: Autofix review round: no action neededNo actionable feedback arrived in this round for PR #8548 (branch Feedback triage (items newer than the last evaluation at 2026-08-04T18:53:11Z):
Outcome: no code changes and no commit this round. The working tree remains at 中文说明Autofix 评审轮次:无需处理本轮 PR #8548(分支 反馈分类(上次评估 2026-08-04T18:53:11Z 之后的新条目):
结果: 本轮未做代码变更,未创建提交。工作树保持在 Base-conflict check · 基分支冲突检查: no conflict with main. · 与 main 无冲突。 🧠 Handled by Qwen Code · model/模型 |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Reviewed — no blockers. Suggestions are inline. Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/qwen-autofix.yml: actionlint embedded-shell source mapping is not yet supported — not linted.
中文说明
已审查——无阻断问题。 建议见行内评论。 未检查(工具限制,非阻断):the executable-script lint — .github/workflows/qwen-autofix.yml: actionlint embedded-shell source mapping is not yet supported — not linted。
— qwen3.8-max via Qwen Code /review (v0.21.5)
| expect(buildCliJob).toContain( | ||
| "base_sha: '${{ steps.meta.outputs.base_sha }}'", | ||
| ); |
There was a problem hiding this comment.
[Suggestion] The new fan-out test pins each side of the SHA chain but not the link itself: nothing asserts the step writing base_sha actually carries id: 'meta' — which is what makes steps.meta.outputs.base_sha resolve. Probed empirically: renaming id: 'meta' → id: 'meta2' survives the full suite (126/126). At runtime a nonexistent step id resolves to '', so needs.build-cli.outputs.base_sha becomes empty and every leg checks out ref: '' — falling back to the event-default ref, which on pull_request_review triggers is the PR merge ref, the exact checkout the SECURITY comment in the workflow exists to prevent.
Failure scenario: a future rename of the step id ships with a green suite → every leg silently checks out the PR merge ref in a secret-bearing run.
| expect(buildCliJob).toContain( | |
| "base_sha: '${{ steps.meta.outputs.base_sha }}'", | |
| ); | |
| expect(buildCliJob).toContain( | |
| "base_sha: '${{ steps.meta.outputs.base_sha }}'", | |
| ); | |
| expect(stepOf(buildCliJob, 'Upload CLI bundle')).toContain("id: 'meta'"); |
中文说明
新增的 fan-out 测试固定了 SHA 链的两端,但没有固定链本身:没有任何断言保证写出 base_sha 的步骤携带 id: 'meta'——而正是它让 steps.meta.outputs.base_sha 能够解析。经实测:将 id: 'meta' 改名为 id: 'meta2' 后整套测试仍然通过(126/126)。运行时,不存在的 step id 会静默解析为 '',于是 needs.build-cli.outputs.base_sha 变为空,每条 leg 以 ref: '' checkout——回退到事件默认 ref,在 pull_request_review 触发器下即 PR 合并 ref,正是 workflow 中 SECURITY 注释要防止的 checkout。
失败场景:未来某次 step id 改名会在测试全绿的情况下上线 → 每条 leg 在携带密钥的运行中静默 checkout PR 合并 ref。
— qwen3.8-max via Qwen Code /review (v0.21.5)
| expect(stepOf(addressJob, 'Download CLI bundle')).toContain( | ||
| "name: 'qwen-autofix-cli-dist'", | ||
| ); |
There was a problem hiding this comment.
[Suggestion] Same pattern on the artifact side of this contract: the restore step's ${RUNNER_TEMP}/cli-dist/qwen-cli-dist.tar.gz is asserted, but the Download step's path: '${{ runner.temp }}/cli-dist' input is never asserted — so the download-directory/extract-path agreement is untested. Probed empirically: changing the download path: to cli-dist2 survives the full suite (126/126), after which every leg dies at tar -xzf ("No such file or directory").
Failure scenario: a future rename of the download directory ships green → every review-address leg fails at the restore step, re-adding as a hard failure exactly the per-leg latency this PR removes.
| expect(stepOf(addressJob, 'Download CLI bundle')).toContain( | |
| "name: 'qwen-autofix-cli-dist'", | |
| ); | |
| expect(stepOf(addressJob, 'Download CLI bundle')).toContain( | |
| "name: 'qwen-autofix-cli-dist'", | |
| ); | |
| expect(stepOf(addressJob, 'Download CLI bundle')).toContain( | |
| "path: '${{ runner.temp }}/cli-dist'", | |
| ); |
中文说明
同一契约的 artifact 端存在相同问题:restore 步骤的 ${RUNNER_TEMP}/cli-dist/qwen-cli-dist.tar.gz 有断言,但 Download 步骤的 path: '${{ runner.temp }}/cli-dist' 输入从未被断言——下载目录与解压路径的一致性未被测试。经实测:将下载 path: 改为 cli-dist2 后整套测试仍然通过(126/126),随后每条 leg 都会在 tar -xzf 处失败("No such file or directory")。
失败场景:未来某次下载目录改名会在测试全绿的情况下上线 → 每条 review-address leg 在还原步骤失败,把本 PR 消除的逐 leg 延迟以硬失败的形式重新引入。
— qwen3.8-max via Qwen Code /review (v0.21.5)
| - name: 'Install dependencies and build' | ||
| env: | ||
| QWEN_SKIP_PREPARE: '1' |
There was a problem hiding this comment.
[Suggestion] This diff adds a third copy of the npm-ci retry + build + bundle recipe and a third byte-identical qwen shim heredoc, leaving the build procedure triplicated across issue-autofix, build-cli, and review-address — all three sites are touched by this change. Cross-site agreement on node-version: '22.x', the GITHUB_PATH wiring, chmod, and the --version smoke is pinned by no test.
Failure scenario: a partial recipe edit (Node version bump applied to two of the three jobs, npm flag, backoff tweak) passes the whole suite and silently diverges build-cli's bundle from what the legs' shims point at — the exact class of mismatch this PR's SHA-pinning was written to prevent, reintroduced at the recipe level.
Suggested fix: extract the shared install/build/bundle + shim-staging block into a composite action (e.g. .github/actions/prepare-qwen-cli) invoked by all three jobs; at minimum add cross-reference comments at each copy and extend the contract tests to pin node-version and the GITHUB_PATH wiring across all three sites.
中文说明
本 diff 新增了第三份 npm-ci 重试 + build + bundle 配方和第三份逐字节相同的 qwen shim heredoc,使构建配方在 issue-autofix、build-cli、review-address 三处重复——三处都在本次改动中被触及。三处之间 node-version: '22.x'、GITHUB_PATH 接线、chmod 和 --version 冒烟的一致性没有任何测试固定。
失败场景:一次局部的配方修改(对三个 job 中的两个升级 Node 版本、npm 参数、退避调整)会通过整套测试,并悄悄让 build-cli 的 bundle 与各 leg 的 shim 指向产生偏差——正是本 PR 的 SHA 固定要防止的那类不匹配,在配方层面被重新引入。
建议修复:把共享的安装/构建/打包 + shim 部署代码块提取为复合 action(如 .github/actions/prepare-qwen-cli)供三个 job 调用;至少在每个副本处加交叉引用注释,并扩展契约测试以固定三处的 node-version 与 GITHUB_PATH 接线。
— qwen3.8-max via Qwen Code /review (v0.21.5)
| with: | ||
| ref: '${{ github.event.repository.default_branch }}' | ||
| ref: '${{ needs.build-cli.outputs.base_sha }}' |
There was a problem hiding this comment.
[Suggestion] This ref pin degrades fail-open: if needs.build-cli.outputs.base_sha ever resolves empty, actions/checkout silently falls back to the event-default ref — on pull_request_review triggers that is refs/pull/N/merge, the contributor-controlled tree the adjacent SECURITY comment says this pin exists to prevent. Verified against the pinned action's source (input-helper.ts: empty ref falls through to github.context.ref), and no guard validates the SHA before checkout. The current wiring is sound (hence Suggestion, not Critical), but this diff converted an always-present context pin into a cross-job output reference that can resolve empty, and the test suite is proven not a backstop — renaming id: 'meta' survives 126/126.
Failure scenario: a future rename of the step id or a typo in the output name → ref: '' → every leg silently checks out the PR merge ref → PR-influenced .github/scripts/* and run-agent.mjs are staged as the "trusted" copies and PR-influenced npm lifecycle scripts run at npm ci time, in the job carrying CI_DEV_BOT_PAT and the model key.
Suggested fix — a fail-loud validation step before this checkout (a job-level if: is inadequate: it only skips, silently stalling the fleet; skip ≠ fail-closed):
- name: 'Validate bundle SHA'
env:
BASE_SHA: '${{ needs.build-cli.outputs.base_sha }}'
run: |-
if [[ ! "${BASE_SHA}" =~ ^[0-9a-f]{40}$ ]]; then
echo "::error::build-cli published no usable base_sha ('${BASE_SHA:-<empty>}') — refusing to fall back to the event-default ref."
exit 1
fi中文说明
此 ref 固定以 fail-open 方式退化:一旦 needs.build-cli.outputs.base_sha 解析为空,actions/checkout 会静默回退到事件默认 ref——在 pull_request_review 触发器下即 refs/pull/N/merge,也就是相邻 SECURITY 注释声明本固定要防止的贡献者可控代码树。已对照固定版本的 action 源码核实(input-helper.ts:空 ref 会落到 github.context.ref),且 checkout 前没有任何校验该 SHA 的保护。当前接线是健全的(因此是 Suggestion 而非 Critical),但本 diff 把一个永远存在的上下文固定转换成了可能解析为空的跨 job 输出引用,而测试套件已被证明不是兜底——将 id: 'meta' 改名后 126/126 测试仍全绿。
失败场景:未来某次 step id 改名或输出名拼写错误 → ref: '' → 每条 leg 静默 checkout PR 合并 ref → PR 可控的 .github/scripts/* 与 run-agent.mjs 被当作 "trusted" 副本部署,PR 可控的 npm 生命周期脚本在 npm ci 时运行,而该 job 携带 CI_DEV_BOT_PAT 与模型密钥。
建议修复——在此 checkout 之前增加一个 fail-loud 校验步骤(job 级 if: 不够:它只会 skip,使整个队列静默停摆;skip ≠ fail-closed),代码见上。
— qwen3.8-max via Qwen Code /review (v0.21.5)
…ontracts (QwenLM#8548) Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
|
🤖 Addressed the latest review feedback (round 1/100). What changed, and what I pushed back on: · 已处理最新评审反馈(第 1/100 轮)。改动内容与我反驳保留之处如下: Autofix review round summary — PR #8548Commit: All four inline findings addressed and resolved in code. No base conflict ( Findings
Verification
中文说明Autofix 审查轮次总结 — PR #8548提交: 四条行内发现全部处理并在代码中解决。无 base 冲突( 发现
验证
Base-conflict check · 基分支冲突检查: no conflict with main. · 与 main 无冲突。 Re-review when you have a moment. After round 100 this bot stops and leaves the PR for a human. · 有空请复审;第 100 轮后本 bot 停止并将 PR 交给人工。 🧠 Handled by Qwen Code · model/模型 |
|
Qwen Code review timed out. Qwen review timed out after 10800 seconds (of the 180-minute budget). For large PRs, retry with a longer timeout by commenting: |
yiliang114
left a comment
There was a problem hiding this comment.
LGTM, no blockers — the security pinning is genuinely careful (empty/malformed base_sha fails loud BEFORE checkout, closing the empty-ref->PR-merge-ref hole; default_branch is repo metadata not PR-controlled; the artifact can only be uploaded by the PR-free build-cli job). Contract tests pin the SHA link, validate-before-checkout order, both artifact paths, and the 3-way recipe lockstep. Non-blocking follow-ups: (1) P2 — build-cli is now a single point of failure: npm ci has 3-attempt retry but 'npm run build'/'bundle' don't, so one transient build failure kills the whole scan (previously legs built independently). Add retry or a leg self-build fallback. (2) P3 — this optimizes runner-minutes/cost, not wall-clock: legs serialize behind build-cli and still run their own npm ci, so per-PR latency may rise ~2-3min. Fine if the goal is cost/queue, just be clear which perf it buys.
|
@qwen-code /triage |
|
Sandboxed verification: ❌ not passed — findings reported (agent verdict) - workflow run Ran the PR in an isolated, token-free container: A/B against the base build, mock-free harness assertions, targeted gates. Advisory evidence for human reviewers — not a review, an approval, or a CI check. Scripted assertions: 114 passed · 3 failed · 117 total 中文 — 判定:❌ 不通过 · 报告了发现(agent 判定)沙箱验证在隔离、无凭证的容器中执行了该 PR 的代码(与 base 构建 A/B 对照、无 mock harness 断言、定向门禁)。仅作为评审证据,不构成评审、批准或 CI 检查。 脚本断言:114 通过 · 3 失败 · 117 总计 Verification reportVerification report — PR #8548Verdict: 中文摘要
Central claim and A/BCentral claim: the review phase compiles the trusted-base CLI bundle once per scan in a new
Captures: The security model holds as described: bundle compiled from the default branch with Corrections
FindingsF1 — Suggestion (security-adjacent coverage gap): Measured fix (scratch fixture, not committed): a 3-case lockstep test asserting Minimal suggested fix (for the author)for (const jobName of ['issue-autofix', 'build-cli', 'review-address']) {
it(`${jobName} checkout disables persist-credentials`, () => {
const job = workflow.jobs[jobName];
const checkout = (job?.steps ?? []).find((s) =>
String(s?.uses ?? '').startsWith('actions/checkout@'),
);
expect(checkout).toBeTruthy();
expect(checkout.with['persist-credentials']).toBe(false);
});
}Measured: head 3/3 green; M9 → F2 — Nit (benign coverage gap): F3 — Nit (informational): SC2312 on the new Not covered
MethodologyEnvironment: Evidence imagesHarness scripts and raw logs are in the workflow run artifacts (7-day retention). — Qwen Code · sandboxed verification |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
LGTM, looks ready to ship. ✅
|
Released in v0.21.6. |
* fix(autofix): ship core dist in the review CLI bundle The review fan-out (QwenLM#8548) dropped the per-leg build: legs restore the shared bundle's repo-root dist/ and rely on the verify gate's full build for branch verification. But the gate's settings-schema and i18n checks run BEFORE any build, on every path including no-action, and their tsx-transpiled cli sources import '@qwen-code/qwen-code-core', which resolves through the workspace symlink to packages/core/dist/index.js. With no build on the leg, the generator crashes with ERR_MODULE_NOT_FOUND and the gate misreports a deterministic "settings schema is stale" rejection (run 31031063525 on PR 8600), then burns an 18-minute repair agent round on an environment problem no agent can fix. Ship packages/core/dist (+~8.5MB gzipped) alongside the root dist/ in the fan-out artifact and assert its entry point on restore. This restores exactly the pre-fan-out state: legs used to build the trusted base themselves before the branch checkout, so the gate always ran against base-built core dist. The workflow contract tests pin the new tar command and the restore-side assertion. * fix(autofix): rebuild branch-touched core dist before the schema gate Review feedback on the core-dist bundle fix: - Rebuild packages/core from branch sources in the review verify gate when the branch diff touches core's sources, so the pre-build settings-schema check never compares the branch's committed schema against a base-built dist (changed runtime constants) or crashes the generator (changed exports). Lives in the shared gate script so both the initial and the repair gate are covered. - Narrow the bundle/restore comments and their test mirror to the settings-schema generator: the i18n check resolves core to sources via the packages/cli tsconfig paths map and needs no dist (verified empirically). - Anchor the tar contract pin at end-of-line so additive path drift fails the suite instead of passing on a substring match.




What this PR does
The autofix review phase fans out one
review-addressleg per PR, and every leg used to repeat the exact same trusted-base build —npm ci+npm run build+npm run bundle— before the agent could start. This PR adds abuild-clijob that compiles the CLI bundle once per scan, uploads the repo-rootdist/as a run-scoped artifact, and has each leg download and restore it instead of building. Each leg's checkout is pinned to the SHA the bundle was compiled from, so a mid-run base push can never pair a leg's bundle with different sources than its checkout.The legs still run
npm ci(the agent and the verification gate neednode_modulesagainst the PR branch), and the verification gate still rebuilds from branch sources — nothing about what gets verified changes. The issue phase is untouched: it runs only when no review targets exist, so gating the build ondo_issueas well would have rebuilt on every quiet scheduled tick.Why it's needed
Measured on run 30912069124 (6 legs): "Install dependencies and build" took 204-307 seconds per leg, ~25 runner-minutes per scan of identical repeated work, and on some legs more wall time than the agent round itself. After this change each leg pays only
npm ci(warm-cached) plus a ~23 MB artifact download (~10-20s), so the agent starts minutes earlier per leg and feedback latency drops correspondingly.Reviewer Test Plan
How to verify
review-scan(unchanged) →build-cli(gated onhas_targets == 'true', so an idle tick builds nothing) →review-address(needsnow includesbuild-cli, checkout ref pinned toneeds.build-cli.outputs.base_sha).test -f dist/cli.jsguard and the existingqwen --versionsmoke.persist-credentials: false), the artifact is run-scoped (same-run download only, 1-day retention), and PR-branch code never participates in the build.npx vitest run --config ./scripts/tests/vitest.config.ts scripts/tests/qwen-autofix-workflow.test.js scripts/tests/package-scripts.test.js scripts/tests/qwen-resolve-workflow.test.js— 155 tests pass.Evidence (Before & After)
N/A (CI-only change; no user-visible behavior). Before: each leg's "Install dependencies and build" step 204-307s (run 30912069124). After: legs download the shared artifact; the build happens once in
build-cli.Tested on
Environment (optional)
Unit-level verification only: workflow contract tests, yamllint, actionlint (no new findings vs base), prettier, eslint, and a local tar round-trip of
dist/(node dist/cli.js --versionruns from the restored archive).Risk & Scope
build-clifails, all legs skip without writing markers — fail-closed, and the next scan re-emits the targets, so a transient build failure costs one tick (~10 min) of latency, never a stranded PR.Linked Issues
N/A — follow-up to the resource-usage discussion of run 30912069124.
中文说明
本 PR 的内容
autofix 的 review 阶段会为每个 PR 扇出一条
review-addressleg,而此前每条 leg 在 agent 启动前都要重复一次完全相同的 trusted-base 构建——npm ci+npm run build+npm run bundle。本 PR 新增一个build-clijob:每次 scan 只编译一次 CLI bundle,将仓库根目录的dist/作为 run 级 artifact 上传,各 leg 改为下载并还原它,不再各自构建。每条 leg 的 checkout 固定为 bundle 编译时对应的 SHA,因此即使运行期间 base 分支有新的推送,也不可能出现 leg 的 bundle 与其 checkout 源码不一致的情况。各 leg 仍会运行
npm ci(agent 和验证门禁需要针对 PR 分支的node_modules),验证门禁也仍然从分支源码重新构建——被验证的内容没有任何变化。issue 阶段不受影响:它只在没有 review 目标时运行,如果构建 job 同时挂在do_issue上,反而会在每个空闲的定时 tick 都白跑一次构建。为什么需要
以 run 30912069124(6 条 leg)实测:每条 leg 的 "Install dependencies and build" 耗时 204-307 秒,一次 scan 约 25 分钟的 runner 时间在做完全相同的重复构建,有些 leg 的构建耗时甚至超过 agent 轮次本身。改动后每条 leg 只需
npm ci(有缓存)加上约 23 MB 的 artifact 下载(约 10-20 秒),agent 启动提前数分钟,反馈延迟相应降低。审查者测试计划
如何验证
review-scan(不变)→build-cli(由has_targets == 'true'门控,空闲 tick 不构建)→review-address(needs新增build-cli,checkout ref 固定为needs.build-cli.outputs.base_sha)。test -f dist/cli.js兜底和原有的qwen --version冒烟。persist-credentials: false)编译,artifact 仅限同一次 run 内下载(保留 1 天),PR 分支代码不参与构建过程。npx vitest run --config ./scripts/tests/vitest.config.ts scripts/tests/qwen-autofix-workflow.test.js scripts/tests/package-scripts.test.js scripts/tests/qwen-resolve-workflow.test.js—— 155 个测试通过。证据(前后对比)
N/A(仅 CI 改动,无用户可见行为)。改动前:每条 leg 的 "Install dependencies and build" 204-307 秒(run 30912069124)。改动后:leg 下载共享 artifact,构建只在
build-cli发生一次。测试平台
macOS ✅;Windows / Linux N/A。
环境(可选)
仅单元级验证:workflow 契约测试、yamllint、actionlint(与基线相比无新增 finding)、prettier、eslint,以及本地对
dist/的 tar 往返验证(从还原的归档中node dist/cli.js --version可正常运行)。风险与范围
build-cli失败,所有 leg 会跳过且不写 marker——失败关闭(fail-closed),下一轮 scan 会重新选出这些目标,因此一次瞬时构建失败只损失一个 tick(约 10 分钟)的延迟,绝不会让 PR 搁浅。关联 Issue
N/A —— 源自 run 30912069124 的资源消耗讨论。