fix(ci): keep contended ECS E2E shards above the flat 60-minute ceiling (#10591) - #10597
fix(ci): keep contended ECS E2E shards above the flat 60-minute ceiling (#10591)#10597qwen-code-dev-bot wants to merge 4 commits into
Conversation
…ng (#10591) The post-merge E2E run 33345905817 on cd5d5af failed before any test result was reported: the per-commit issue body from main-ci-failure-issue.yml means no failed job log carried a vitest FAIL line, and the run's ~63-minute wall clock lines up with the flat timeout-minutes: 60 killing a shard still working on a contended shared ECS host. ci.yml's pool lanes already got extended, ECS-scoped ceilings for the same contention (#10552), and #10567 capped each E2E shard to one vitest fork on the pool; the Linux E2E job was the last shared-pool lane still on the pre-contention bound. Extend the ceiling to 90 on the ECS routing only — the same condition runs-on uses — so hosted fallbacks (forks and the kill-switch) keep the pre-contention 60 and a genuine hang there does not burn the extra 30 minutes. A lane-contract test evaluates the real timeout expression for both routings, the way ci-platform-lanes.test.js does, so a regression to an unconditional ceiling fails there instead of reading as a passing constant.
E2E Report — fix(ci): keep contended ECS E2E shards above the flat 60-minute ceiling (#10591)ProblemIssue #10591 tracks the post-merge Diagnosis (repository evidence — no GitHub credentials available to read the run logs)
Change
The exact failure step inside the job cannot be proven without the run logs; the extended, ECS-scoped ceiling is the repository's established remedy for this lane under contention, and fast-failure mechanisms (docker preflight Mutation probes (guard witnessed by the round's own tests)
Workflow size ratchet
Verification
中文说明E2E 报告 — fix(ci): 让争用中的 ECS E2E 分片不再受固定 60 分钟上限卡死(#10591)问题Issue #10591 跟踪的是提交 诊断(基于仓库内证据——没有 GitHub 凭据,无法读取运行日志)
变更
没有运行日志就无法证明任务内部具体失败在哪一步;提高并按 ECS 限定的上限是仓库对该通道在争用下的既定补救手段,而快速失败机制(docker 预检 变异探针(本回合提交的测试即为守卫的见证)
工作流体积棘轮
验证
🧠 Handled by Qwen Code · model/模型 |
|
|
|
Thanks for the PR! Template looks good ✓ Problem: observed, not theoretical. Post-merge E2E run 33345905817 on Direction: aligned. This is the same contention remedy already accepted for the sibling pool lanes (#10552 raised the ci.yml pool ceilings to 90, #10567 capped E2E forks on the pool) — this PR just closes the one lane that was still on the old flat bound. CHANGELOG has no direct reference, but CI reliability is squarely in scope and the 90-minute value matches what ci.yml's pool lanes already run. Size: not applicable — Approach: the scope feels right and it's done the minimal way. The timeout expression reuses the exact boolean the job's Risk: no elevated risk signals — neither changed file matches the revert-correlated paths. Moving on to code review. 🔍 中文说明感谢贡献! 模板完整 ✓ 问题:是已观测到的问题,不是理论担忧。 方向:对齐。这与兄弟资源池通道已经接受的争用补救手段一致(#10552 把 ci.yml 资源池上限提到 90,#10567 限制了资源池上 E2E 的 fork 数)——本 PR 只是补上仍停留在旧固定上限上的那一条通道。CHANGELOG 没有直接引用,但 CI 可靠性完全在范围内,且 90 分钟的取值与 ci.yml 资源池通道现行值一致。 规模:不适用——仅 方案:范围合理,且做法已经是最小化。timeout 表达式复用了该任务 风险:无升级风险信号——两个改动文件都不命中与回滚相关的高风险路径。 进入代码审查 🔍 — Qwen Code · qwen3.8-max Reviewed at |
|
Code review Before reading the diff I'd have done exactly this: raise Two things I verified closely, both clean:
No correctness bugs, no convention violations, no scope creep — every line is needed for the stated goal. Nothing blocking. Testing This is a CI workflow change with nothing user-visible, so real-scenario (tmux) testing is Final CI results for
One row per check name (latest run); skipped checks omitted; failures sort first. / 每个检查名一行(取最新一次运行),省略 skipped,失败项排在最前。 No check has failed at the time of writing; the Linux unit job (which runs the new contract test) and the no-AK integration lane are still running. One honest caveat: the deterministic half of the claim — "the expression evaluates to 90 on the pool and 60 on every hosted fallback, and stays that way" — is pinned by the contract test above. The other half — "90 minutes is enough headroom under real pool contention" — is an environmental tuning question that only future post-merge runs can answer, and no sandboxed lane can reproduce shared-host contention; the PR itself says as much, and 90 is the same value the sibling ci.yml pool lanes already run. So I'm not flagging a 中文说明代码审查 在看 diff 之前我的独立方案就是这样:只在资源池路由上提高 我重点核了两处,都干净:
没有正确性 bug、没有规范违反、没有范围蔓延——每一行都是目标所必需的。无阻塞项。 测试 这是用户不可见的 CI 工作流变更,因此真实场景(tmux)测试为 (CI 表格见上方标记区域,由 finalize 工作流在 CI 结束后原地更新。) 撰写时没有任何检查失败;Linux 单元任务(运行新契约测试)与无 AK 集成通道仍在运行。一个诚实的说明:该改动的确定性部分——"表达式在资源池上求值为 90、在所有托管回退上为 60,并保持如此"——已由契约测试钉住。另一半——"90 分钟在真实资源池争用下是否足够"——是只有未来合并后运行才能回答的环境调参问题,任何沙箱通道都无法复现共享主机争用;PR 本身也这么说了,而且 90 与兄弟 ci.yml 资源池通道现行值一致。因此这里不点名 — Qwen Code · qwen3.8-max Reviewed at |
|
Confidence: 5/5 — an observed, API-confirmed timeout failure fixed the same way its sibling lanes already were, scoped to the pool routing and pinned by a test that fails on regression. Stepping back: this is exactly the kind of change I want to see. The problem is real — I confirmed run 33345905817's docker shard was cancelled at ~62 minutes, past the flat 60-minute ceiling, before it could report a single test result. The fix is the minimal version of itself: one conditional Verdict: approve. The Linux unit job and the no-AK integration lane are still running on this commit, though, so approval is deferred until CI lands green on 中文说明置信度:5/5 —— 一次已观测到、并经 API 确认的超时失败,用其兄弟通道已经采用的方式修复,严格限定在资源池路由内,并由一个"退化即失败"的测试钉住。 退一步看:这正是我希望看到的改动。问题是真实的——我确认运行 33345905817 的 docker 分片在约 62 分钟(超过固定 60 分钟上限)时被取消,且尚未报告任何测试结果。修复本身就是最小形态:一个复用 结论:批准。 但该提交上的 Linux 单元任务与无 AK 集成通道仍在运行,因此批准将推迟到 CI 在该提交上全绿之后。 — Qwen Code · qwen3.8-max Reviewed at |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/e2e.yml: actionlint embedded-shell source mapping is not yet supported — not linted.
中文说明
未检查(工具限制,非阻断):the executable-script lint — .github/workflows/e2e.yml: actionlint embedded-shell source mapping is not yet supported — not linted。
— qwen3.8-max via Qwen Code /review (v0.22.3)
| # at the old flat 60 on a contended shared host before its log reported | ||
| # any test result. Hosted fallbacks keep the pre-contention ceiling so | ||
| # a genuine hang there does not burn the extra 30 minutes. | ||
| timeout-minutes: "${{ fromJSON((github.repository == 'QwenLM/qwen-code' && vars.MAINTAINER_ECS_RUNNER_DISABLED != 'true') && '90' || '60') }}" |
There was a problem hiding this comment.
[Critical] R1-1: [fails-closed] [regression] This change turns e2e-test-linux's timeout-minutes from the number 60 into this expression string, but the existing lane-contract test .github/scripts/ci-runner-routing.test.mjs:552 still pins assert.equal(job['timeout-minutes'], 60) for this exact job and is never updated by this PR. That file imports node:assert/strict (so assert.equal is strictEqual), which means the assertion now fails unconditionally in every routing state. The file is listed in HELPER_TESTS (.github/workflows/ci.yml:82) and executed via node --test by both helper steps — "GitHub CI helper checks" (ci.yml:436) and "Run .github/scripts helper tests" (ci.yml:586); this PR classifies into the full profile, so the required Test (ubuntu-latest, Node 22.x) check goes red on this PR's own CI run.
Witness:
$ node --test .github/scripts/ci-runner-routing.test.mjs (at HEAD 64a703c)
# tests 23
# pass 22
# fail 1
not ok 5 - carries the pool hygiene and capability steps in order
operator: strictEqual
expected: 60
actual: "${{ fromJSON((github.repository == 'QwenLM/qwen-code' && vars.MAINTAINER_ECS_RUNNER_DISABLED != 'true') && '90' || '60') }}"
at: .github/scripts/ci-runner-routing.test.mjs:552
A/B on the contested assertion: BASE (pre-change e2e.yml) passes with value=60; the PR arm fails with the expression string.
Update .github/scripts/ci-runner-routing.test.mjs:552 in this same PR: replace the bare 60 pin with an evaluation of the new routing-scoped expression — the same substitute-then-evaluate technique this PR adds in scripts/tests/e2e-workflow.test.js — asserting 90 on the pool routing and 60 on both hosted fallbacks (fork and kill-switch), and fix the adjacent stale comment ("Pin the ci.yml pool precedent"), which now contradicts ci.yml's actual pool precedent of 90.
The updated pin must keep the two ceilings mirrored from .github/workflows/ci.yml:219 (90 on ecs-qwen routing, 60 hosted) and agree with the routing condition the timeout mirrors (runs-on at .github/workflows/e2e.yml:47). The updated assertion itself must go red if timeout-minutes regresses to an unconditional value (a flat 60 or flat 90 without the routing condition) — please remove the routing condition from the assertion and run that subtest to prove it.
中文说明
本改动把 e2e-test-linux 的 timeout-minutes 从数字 60 改成了这个表达式字符串,但既有的通道契约测试 .github/scripts/ci-runner-routing.test.mjs:552 仍然对同一个任务钉死 assert.equal(job['timeout-minutes'], 60),且本 PR 没有更新它。该文件导入 node:assert/strict(因此 assert.equal 即 strictEqual),所以这条断言现在在任何路由状态下都会无条件失败。该文件位于 HELPER_TESTS(.github/workflows/ci.yml:82)中,由两个助手测试步骤通过 node --test 执行——"GitHub CI helper checks"(ci.yml:436)与 "Run .github/scripts helper tests"(ci.yml:586);本 PR 会被分类为 full profile,因此本 PR 自己的 CI 运行中必需的 Test (ubuntu-latest, Node 22.x) 检查会变红。
见证(在 HEAD 64a703c 上执行):node --test .github/scripts/ci-runner-routing.test.mjs → 23 个测试,22 通过,1 失败——失败子测试为 "carries the pool hygiene and capability steps in order",operator: strictEqual,expected: 60,actual 为新的表达式字符串。对该断言做 A/B:BASE(改动前的 e2e.yml)通过(值为 60),PR 侧失败。
请在同一个 PR 中更新 .github/scripts/ci-runner-routing.test.mjs:552:把裸的 60 钉子替换为对新的路由限定表达式求值——复用本 PR 在 scripts/tests/e2e-workflow.test.js 中新增的"先替换再求值"手法——断言资源池路由为 90、两种托管回退(fork 与紧急开关)均为 60,并修正旁边那条已过时的注释("Pin the ci.yml pool precedent"),它现在与 ci.yml 实际的资源池上限 90 相矛盾。
更新后的钉子必须保持与 .github/workflows/ci.yml:219 一致的两个上限(ecs-qwen 路由 90,托管 60),并与 timeout 所镜像的路由条件(.github/workflows/e2e.yml:47 的 runs-on)保持一致。更新后的断言本身必须在 timeout-minutes 退化为无条件值(不带路由条件的裸 60 或裸 90)时变红——请从断言中去掉路由条件并运行该子测试来证明这一点。
— qwen3.8-max via Qwen Code /review (v0.22.3)
There was a problem hiding this comment.
Verified real at the current head: node --test --test-concurrency=1 .github/scripts/ci-runner-routing.test.mjs fails at line 552 (strictEqual expected 60, actual is the new routing-scoped expression string) — 23 tests, 22 pass, 1 fail. The full HELPER_TESTS set confirms this is the sole cause of the red required Test (ubuntu-latest, Node 22.x) check: 500 tests, exactly this one failure.
This round nevertheless does NOT implement the pin update: .github/scripts/ is outside this PR's footprint (the PR touches only .github/workflows/e2e.yml and scripts/tests/e2e-workflow.test.js), and the round-3 attempt at exactly this pin update was rejected by the autofix gate and reverted for that reason. Repeating the rejected change would fail the gate again, and there is no in-footprint change that can turn the check green while the pin still reads 60. This needs a maintainer decision on where the pin update lands:
- Allow this PR to expand into
.github/scripts/, so a next round updates the pin here (substitute-then-evaluate: 90 on the pool routing, 60 on both hosted fallbacks, mirroring theruns-oncondition; plus the stale "Pin the ci.yml pool precedent" comment); or - A maintainer lands the pin update separately (direct commit, or a small standalone PR merged first), and this PR rebases onto it; or
- Revert this PR's timeout change entirely (not recommended — it abandons the Main CI failed: E2E Tests on cd5d5af2fbd7 #10591 fix).
Leaving this thread open until a maintainer chooses.
中文说明
已在当前 head 上确认为真实问题:node --test --test-concurrency=1 .github/scripts/ci-runner-routing.test.mjs 在第 552 行失败(strictEqual 期望 60,实际为新的路由限定表达式字符串)——23 个测试,22 通过,1 失败。完整 HELPER_TESTS 集合确认这是必需的 Test (ubuntu-latest, Node 22.x) 检查变红的唯一原因:共 500 个测试,仅此一处失败。
但本轮不实施该断言更新:.github/scripts/ 在本 PR 的 footprint 之外(本 PR 只改动 .github/workflows/e2e.yml 和 scripts/tests/e2e-workflow.test.js),且第 3 轮对同一断言的更新尝试已被 autofix gate 以该理由拒绝并回滚。重复被拒绝的改动只会再次被 gate 拒绝,而在断言仍钉死 60 的情况下,footprint 内没有任何改动能让该检查变绿。需要维护者决定断言更新落在哪里:
- 允许本 PR 扩展到
.github/scripts/,下一轮即可在此更新断言(先替换再求值:资源池路由 90、两种托管回退均为 60,与runs-on条件保持一致;同时修正过时的 "Pin the ci.yml pool precedent" 注释);或 - 由维护者单独落地断言更新(直接提交,或先合并一个小的独立 PR),之后本 PR 重新变基;或
- 整体回退本 PR 的 timeout 改动(不建议——等于放弃 Main CI failed: E2E Tests on cd5d5af2fbd7 #10591 的修复)。
在维护者作出选择之前,本线程保持打开。
| // Run 33345905817 (issue #10591) expired at the old flat 60-minute | ||
| // ceiling on a contended shared ECS host before its log reported any | ||
| // test result. The extended ceiling is | ||
| // scoped to the pool routing — the same condition `runs-on` uses: |
There was a problem hiding this comment.
[Suggestion] R1-2: The new lane-contract test evaluates only the timeout-minutes expression and never reads runs-on, so the timeout↔routing equivalence this comment claims ("the same condition runs-on uses") is documented but unpinned. e2e.yml carries the routing predicate as two hand-written copies (runs-on at e2e.yml:47 and timeout-minutes at e2e.yml:54), unlike ci.yml where both fields derive from one source of truth (needs.classify_pr.outputs.ubuntu_runner). A future edit to the runs-on condition (adding a kill-switch term or widening pool eligibility) that forgets timeout-minutes leaves every test in this suite green: runs newly routed onto the contended ECS pool keep the 60-minute ceiling and silently re-create issue #10591 (a shard expires before its log reports any test result), or drift the other way and hosted runs get 90 minutes, burning the extra 30 the diff's comment explicitly exists to prevent.
Witness:
Mutation probe: flip != 'true' -> == 'true' on runs-on ONLY (timeout expression untouched)
PR suite on mutated tree: 11/11 passed (green through a complete inversion of routing semantics)
equivalence probe (assert timeout == 90 iff runs-on resolves to ecs-qwen): 2 failed | 1 passed
poolRouted=false but timeout=90
poolRouted=true but timeout=60 <- the exact #10591 re-creation
flip check on pristine tree: 3 passed
In the same describe block, evaluate the runs-on expression with the same substitution sweep and assert agreement per scenario instead of asserting each half against test-chosen constants — e.g. assert timeoutMinutesOn(s) === 90 iff the evaluated runs-on expression resolves to the ["self-hosted", "linux", "x64", "ecs-qwen"] branch — so the two expressions answer to one oracle. Note that runs-on at .github/workflows/e2e.yml:47 is a single-quoted YAML scalar with doubled quotes, so after YAML parse the embedded literals carry single quotes; the check must compare the two evaluated results, not a third hand-copied condition. The new equivalence assertion must go red when != 'true' is flipped to == 'true' on only the runs-on expression — today's suite stays green under that mutation; please add it and prove it.
中文说明
新增的通道契约测试只对 timeout-minutes 表达式求值,从不读取 runs-on,因此这条注释所声称的 timeout↔路由等价关系("与 runs-on 使用相同的条件")只是写在注释里,并没有被测试钉住。e2e.yml 中的路由谓词以两份手写副本存在(runs-on 在 e2e.yml:47,timeout-minutes 在 e2e.yml:54),而不像 ci.yml 那样两个字段都从 needs.classify_pr.outputs.ubuntu_runner 这一唯一事实源派生。如果未来某次编辑修改了 runs-on 条件(新增紧急开关项或放宽资源池准入)却忘了 timeout-minutes,本套件的所有测试仍会全绿:新路由到争用 ECS 资源池的运行会继续使用 60 分钟上限,悄悄复现 issue #10591(分片在报告任何测试结果之前过期);反向漂移则会让托管运行获得 90 分钟,白白烧掉本 diff 注释明确要避免的额外 30 分钟。
见证:变异探针——只对 runs-on 表达式把 != 'true' 翻转为 == 'true'(timeout 表达式不动),本 PR 的套件在变异树上 11/11 全绿(路由语义被完全反转后依然通过);而等价性探针(断言 timeout == 90 当且仅当 runs-on 解析到 ecs-qwen 分支)在同一变异树上 2 失败 | 1 通过,包括 "poolRouted=false but timeout=90" 与 "poolRouted=true but timeout=60"(即 #10591 的复现形态);在纯净树上做翻转校验:3 通过。
请在同一个 describe 块中,用相同的替换扫描对 runs-on 表达式求值,并按场景断言两者一致,而不是各自对着测试选定的常量断言——例如断言 timeoutMinutesOn(s) === 90 当且仅当求值后的 runs-on 表达式解析到 ["self-hosted", "linux", "x64", "ecs-qwen"] 分支——让两个表达式对同一个裁决者负责。注意:.github/workflows/e2e.yml:47 的 runs-on 是内含双写引号的单引号 YAML 标量,YAML 解析后其中的字面量带单引号;检查应比较两个求值结果,而不是第三份手抄的条件。新的等价断言必须满足:只把 runs-on 表达式中的 != 'true' 翻转为 == 'true' 时变红——当前套件在该变异下保持全绿,请加上断言并运行证明。
— qwen3.8-max via Qwen Code /review (v0.22.3)
|
🔀 Base updated: red check(s) [web-shell E2E Smoke (ubuntu-latest, Node 22.x)] pass on current main — merged current main via update-branch; CI will re-run. 中文说明🔀 已更新 base:红色检查 [web-shell E2E Smoke (ubuntu-latest, Node 22.x)] 在当前 main 上通过 —— 已通过 update-branch 合入当前 main,CI 将重新运行。 |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/e2e.yml: actionlint embedded-shell source mapping is not yet supported — not linted.
Deferred under the convergence posture (round 2, not a blocker) — recorded, not requested in this round:
scripts/tests/e2e-workflow.test.js:110 — [probe] timeoutMinutesOn duplicates the ci-platform-lanes.test.js substitute-then-evaluate skeleton (extract into workflow-helpers.js)
中文说明
未检查(工具限制,非阻断):the executable-script lint — .github/workflows/e2e.yml: actionlint embedded-shell source mapping is not yet supported — not linted。
收敛姿态下延后(第 2 轮,非阻断)——已记录,本轮不要求修改:共 1 条(原文未翻译,列表见上方英文部分)。
— qwen3.8-max via Qwen Code /review (v0.22.3)
| # at the old flat 60 on a contended shared host before its log reported | ||
| # any test result. Hosted fallbacks keep the pre-contention ceiling so | ||
| # a genuine hang there does not burn the extra 30 minutes. | ||
| timeout-minutes: "${{ fromJSON((github.repository == 'QwenLM/qwen-code' && vars.MAINTAINER_ECS_RUNNER_DISABLED != 'true') && '90' || '60') }}" |
There was a problem hiding this comment.
[Critical] R1-1: [fails-closed] [regression] This change turns e2e-test-linux's timeout-minutes from the number 60 into this expression string, but the existing lane-contract test .github/scripts/ci-runner-routing.test.mjs:552 still pins assert.equal(job['timeout-minutes'], 60) for this exact job and is never updated by this PR. That file imports node:assert/strict (so assert.equal is strictEqual), which means the assertion now fails unconditionally in every routing state. The file is listed in HELPER_TESTS (.github/workflows/ci.yml:82) and executed via node --test by both helper steps — "GitHub CI helper checks" (ci.yml:436) and "Run .github/scripts helper tests" (ci.yml:586); this PR classifies into the full profile, so the required Test (ubuntu-latest, Node 22.x) check goes red on this PR's own CI run.
Re-checked at f2b2a2f7 (this round's reviewed commit): the stale pin is untouched and the failure still fires.
Witness:
$ node --test .github/scripts/ci-runner-routing.test.mjs (at HEAD f2b2a2f7)
# tests 23
# pass 22
# fail 1
not ok 5 - carries the pool hygiene and capability steps in order
operator: strictEqual
expected: 60
actual: "${{ fromJSON((github.repository == 'QwenLM/qwen-code' && vars.MAINTAINER_ECS_RUNNER_DISABLED != 'true') && '90' || '60') }}"
at: .github/scripts/ci-runner-routing.test.mjs:552
A/B on the contested assertion: BASE (pre-change e2e.yml) passes with value=60; the PR arm fails with the expression string.
Update .github/scripts/ci-runner-routing.test.mjs:552 in this same PR: replace the bare 60 pin with an evaluation of the new routing-scoped expression — the same substitute-then-evaluate technique this PR adds in scripts/tests/e2e-workflow.test.js — asserting 90 on the pool routing and 60 on both hosted fallbacks (fork and kill-switch), and fix the adjacent stale comment ("Pin the ci.yml pool precedent"), which now contradicts ci.yml's actual pool precedent of 90.
The updated pin must keep the two ceilings mirrored from .github/workflows/ci.yml:219 (90 on ecs-qwen routing, 60 hosted) and agree with the routing condition the timeout mirrors (runs-on at .github/workflows/e2e.yml:47). The updated assertion itself must go red if timeout-minutes regresses to an unconditional value (a flat 60 or flat 90 without the routing condition) — please remove the routing condition from the assertion and run that subtest to prove it.
中文说明
本改动把 e2e-test-linux 的 timeout-minutes 从数字 60 改成了这个表达式字符串,但既有的通道契约测试 .github/scripts/ci-runner-routing.test.mjs:552 仍然对同一个任务钉死 assert.equal(job['timeout-minutes'], 60),且本 PR 没有更新它。该文件导入 node:assert/strict(因此 assert.equal 即 strictEqual),所以这条断言现在在任何路由状态下都会无条件失败。该文件位于 HELPER_TESTS(.github/workflows/ci.yml:82)中,由两个助手测试步骤通过 node --test 执行——"GitHub CI helper checks"(ci.yml:436)与 "Run .github/scripts helper tests"(ci.yml:586);本 PR 会被分类为 full profile,因此本 PR 自己的 CI 运行中必需的 Test (ubuntu-latest, Node 22.x) 检查会变红。
已在本轮审阅的提交 f2b2a2f7 上复核:该过时的断言原样存在,失败仍然触发。
见证(在 HEAD f2b2a2f 上执行):node --test .github/scripts/ci-runner-routing.test.mjs → 23 个测试,22 通过,1 失败——失败子测试为 "carries the pool hygiene and capability steps in order",operator: strictEqual,expected: 60,actual 为新的表达式字符串。对该断言做 A/B:BASE(改动前的 e2e.yml)通过(值为 60),PR 侧失败。
请在同一个 PR 中更新 .github/scripts/ci-runner-routing.test.mjs:552:把裸的 60 钉子替换为对新的路由限定表达式求值——复用本 PR 在 scripts/tests/e2e-workflow.test.js 中新增的"先替换再求值"手法——断言资源池路由为 90、两种托管回退(fork 与紧急开关)均为 60,并修正旁边那条已过时的注释("Pin the ci.yml pool precedent"),它现在与 ci.yml 实际的资源池上限 90 相矛盾。
更新后的钉子必须保持与 .github/workflows/ci.yml:219 一致的两个上限(ecs-qwen 路由 90,托管 60),并与 timeout 所镜像的路由条件(.github/workflows/e2e.yml:47 的 runs-on)保持一致。更新后的断言本身必须在 timeout-minutes 退化为无条件值(不带路由条件的裸 60 或裸 90)时变红——请从断言中去掉路由条件并运行该子测试来证明这一点。
— qwen3.8-max via Qwen Code /review (v0.22.3)
There was a problem hiding this comment.
Verified real at the current head: node --test --test-concurrency=1 .github/scripts/ci-runner-routing.test.mjs fails at line 552 (strictEqual expected 60, actual is the new routing-scoped expression string) — 23 tests, 22 pass, 1 fail. The full HELPER_TESTS set confirms this is the sole cause of the red required Test (ubuntu-latest, Node 22.x) check: 500 tests, exactly this one failure.
This round nevertheless does NOT implement the pin update: .github/scripts/ is outside this PR's footprint (the PR touches only .github/workflows/e2e.yml and scripts/tests/e2e-workflow.test.js), and the round-3 attempt at exactly this pin update was rejected by the autofix gate and reverted for that reason. Repeating the rejected change would fail the gate again, and there is no in-footprint change that can turn the check green while the pin still reads 60. This needs a maintainer decision on where the pin update lands:
- Allow this PR to expand into
.github/scripts/, so a next round updates the pin here (substitute-then-evaluate: 90 on the pool routing, 60 on both hosted fallbacks, mirroring theruns-oncondition; plus the stale "Pin the ci.yml pool precedent" comment); or - A maintainer lands the pin update separately (direct commit, or a small standalone PR merged first), and this PR rebases onto it; or
- Revert this PR's timeout change entirely (not recommended — it abandons the Main CI failed: E2E Tests on cd5d5af2fbd7 #10591 fix).
Leaving this thread open until a maintainer chooses.
中文说明
已在当前 head 上确认为真实问题:node --test --test-concurrency=1 .github/scripts/ci-runner-routing.test.mjs 在第 552 行失败(strictEqual 期望 60,实际为新的路由限定表达式字符串)——23 个测试,22 通过,1 失败。完整 HELPER_TESTS 集合确认这是必需的 Test (ubuntu-latest, Node 22.x) 检查变红的唯一原因:共 500 个测试,仅此一处失败。
但本轮不实施该断言更新:.github/scripts/ 在本 PR 的 footprint 之外(本 PR 只改动 .github/workflows/e2e.yml 和 scripts/tests/e2e-workflow.test.js),且第 3 轮对同一断言的更新尝试已被 autofix gate 以该理由拒绝并回滚。重复被拒绝的改动只会再次被 gate 拒绝,而在断言仍钉死 60 的情况下,footprint 内没有任何改动能让该检查变绿。需要维护者决定断言更新落在哪里:
- 允许本 PR 扩展到
.github/scripts/,下一轮即可在此更新断言(先替换再求值:资源池路由 90、两种托管回退均为 60,与runs-on条件保持一致;同时修正过时的 "Pin the ci.yml pool precedent" 注释);或 - 由维护者单独落地断言更新(直接提交,或先合并一个小的独立 PR),之后本 PR 重新变基;或
- 整体回退本 PR 的 timeout 改动(不建议——等于放弃 Main CI failed: E2E Tests on cd5d5af2fbd7 #10591 的修复)。
在维护者作出选择之前,本线程保持打开。
| // Run 33345905817 (issue #10591) expired at the old flat 60-minute | ||
| // ceiling on a contended shared ECS host before its log reported any | ||
| // test result. The extended ceiling is | ||
| // scoped to the pool routing — the same condition `runs-on` uses: |
There was a problem hiding this comment.
[Suggestion] R1-2: The new lane-contract test evaluates only the timeout-minutes expression and never reads runs-on, so the timeout↔routing equivalence this comment claims ("the same condition runs-on uses") is documented but unpinned. e2e.yml carries the routing predicate as two hand-written copies (runs-on at e2e.yml:47 and timeout-minutes at e2e.yml:54), unlike ci.yml where both fields derive from one source of truth (needs.classify_pr.outputs.ubuntu_runner). A future edit to the runs-on condition (adding a kill-switch term or widening pool eligibility) that forgets timeout-minutes leaves every test in this suite green: runs newly routed onto the contended ECS pool keep the 60-minute ceiling and silently re-create issue #10591 (a shard expires before its log reports any test result), or drift the other way and hosted runs get 90 minutes, burning the extra 30 the diff's comment explicitly exists to prevent.
Re-checked at f2b2a2f7 (this round's reviewed commit): the equivalence is still unpinned.
Witness:
Mutation probe: flip != 'true' -> == 'true' on runs-on ONLY (timeout expression untouched)
PR suite on mutated tree: 11/11 passed (green through a complete inversion of routing semantics)
equivalence probe (assert timeout == 90 iff runs-on resolves to ecs-qwen): 2 failed | 1 passed
poolRouted=false but timeout=90
poolRouted=true but timeout=60 <- the exact #10591 re-creation
flip check on pristine tree: 3 passed
In the same describe block, evaluate the runs-on expression with the same substitution sweep and assert agreement per scenario instead of asserting each half against test-chosen constants — e.g. assert timeoutMinutesOn(s) === 90 iff the evaluated runs-on expression resolves to the ["self-hosted", "linux", "x64", "ecs-qwen"] branch — so the two expressions answer to one oracle. Note that runs-on at .github/workflows/e2e.yml:47 is a single-quoted YAML scalar with doubled quotes, so after YAML parse the embedded literals carry single quotes; the check must compare the two evaluated results, not a third hand-copied condition. The new equivalence assertion must go red when != 'true' is flipped to == 'true' on only the runs-on expression — today's suite stays green under that mutation; please add it and prove it.
中文说明
新增的通道契约测试只对 timeout-minutes 表达式求值,从不读取 runs-on,因此这条注释所声称的 timeout↔路由等价关系("与 runs-on 使用相同的条件")只是写在注释里,并没有被测试钉住。e2e.yml 中的路由谓词以两份手写副本存在(runs-on 在 e2e.yml:47,timeout-minutes 在 e2e.yml:54),而不像 ci.yml 那样两个字段都从 needs.classify_pr.outputs.ubuntu_runner 这一唯一事实源派生。如果未来某次编辑修改了 runs-on 条件(新增紧急开关项或放宽资源池准入)却忘了 timeout-minutes,本套件的所有测试仍会全绿:新路由到争用 ECS 资源池的运行会继续使用 60 分钟上限,悄悄复现 issue #10591(分片在报告任何测试结果之前过期);反向漂移则会让托管运行获得 90 分钟,白白烧掉本 diff 注释明确要避免的额外 30 分钟。
已在本轮审阅的提交 f2b2a2f7 上复核:该等价关系仍未被测试钉住。
见证:变异探针——只对 runs-on 表达式把 != 'true' 翻转为 == 'true'(timeout 表达式不动),本 PR 的套件在变异树上 11/11 全绿(路由语义被完全反转后依然通过);而等价性探针(断言 timeout == 90 当且仅当 runs-on 解析到 ecs-qwen 分支)在同一变异树上 2 失败 | 1 通过,包括 "poolRouted=false but timeout=90" 与 "poolRouted=true but timeout=60"(即 #10591 的复现形态);在纯净树上做翻转校验:3 通过。
请在同一个 describe 块中,用相同的替换扫描对 runs-on 表达式求值,并按场景断言两者一致,而不是各自对着测试选定的常量断言——例如断言 timeoutMinutesOn(s) === 90 当且仅当求值后的 runs-on 表达式解析到 ["self-hosted", "linux", "x64", "ecs-qwen"] 分支——让两个表达式对同一个裁决者负责。注意:.github/workflows/e2e.yml:47 的 runs-on 是内含双写引号的单引号 YAML 标量,YAML 解析后其中的字面量带单引号;检查应比较两个求值结果,而不是第三份手抄的条件。新的等价断言必须满足:只把 runs-on 表达式中的 != 'true' 翻转为 == 'true' 时变红——当前套件在该变异下保持全绿,请加上断言并运行证明。
— qwen3.8-max via Qwen Code /review (v0.22.3)
|
🤖 AutoFix updated a stale base — the fix did not pass verification, but this PR was behind Address-review summary — PR #10597 (issue #10591), round 4 (same-run verification repair)Commits this round: Deterministic rejection repairThe round-3 commit was rejected with: "This round modified CI/verification machinery in area(s) the PR itself never touched: ci-scripts Action taken: Feedback triage[rc:3891763181] / [rc:3892039740] — R1-1 [Critical], e2e.yml:54 — ESCALATED to a maintainer (not implemented)The finding is real and re-reproduced on the restored tree this round: Why it was not pushed: Note: the base has since been auto-updated; the verdict below predates that update, and the next round's re-measurement may charge the round. build failed on the agent-committed fix 中文说明🤖 AutoFix 更新了一个过期的 base —— 修复未通过验证,但本 PR 落后于 验证门的拒绝原因与日志证据见上方英文部分(gate-rejection 不翻译)。 Run log: https://github.com/QwenLM/qwen-code/actions/runs/33365133425 🧠 Handled by Qwen Code · model/模型 |
qwen-code-ci-bot
left a comment
There was a problem hiding this comment.
1 Suggestion-level finding(s) this review confirmed are already reported on this PR and are not repeated:
- R1-2 timeout↔runs-on mirror unpinned in tests — already reported (comment 3892039748)
Not explored to full depth (tool budget reached): "agent 1a": none — the only check I could not run is the vitest suite itself (no node_modules in the review worktree or parent checkout), which I substituted with the ver…; "agent 3c": none — but note the vitest suite could not be run end-to-end (no node_modules in the review worktree); the Critical was instead verified by reading the exact …; "agent 3b": none — the vitest suite could not be executed in this tree (no node_modules ), but the helper's computation was verified directly, and no check was cut short b….
Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/e2e.yml: actionlint embedded-shell source mapping is not yet supported — not linted.
Deferred under the convergence posture (round 3, not a blocker) — recorded, not requested in this round:
scripts/tests/e2e-workflow.test.js:110 — [review] D3-1 timeoutMinutesOn duplicates the substitute-then-evaluate skeleton (4th copy; guards drifted)
中文说明
本轮确认的 1 条建议级发现已在 PR 上报告过,不再重复发布(列表见上方英文部分)。
未探索到全部深度(达到工具调用预算):"agent 1a":none — the only check I could not run is the vitest suite itself (no node_modules in the review worktree or parent checkout), which I substituted with the ver…;"agent 3c":none — but note the vitest suite could not be run end-to-end (no node_modules in the review worktree); the Critical was instead verified by reading the exact …;"agent 3b":none — the vitest suite could not be executed in this tree (no node_modules ), but the helper's computation was verified directly, and no check was cut short b…。
未检查(工具限制,非阻断):the executable-script lint — .github/workflows/e2e.yml: actionlint embedded-shell source mapping is not yet supported — not linted。
收敛姿态下延后(第 3 轮,非阻断)——已记录,本轮不要求修改:共 1 条(原文未翻译,列表见上方英文部分)。
— qwen3.8-max via Qwen Code /review (v0.22.3)
| # at the old flat 60 on a contended shared host before its log reported | ||
| # any test result. Hosted fallbacks keep the pre-contention ceiling so | ||
| # a genuine hang there does not burn the extra 30 minutes. | ||
| timeout-minutes: "${{ fromJSON((github.repository == 'QwenLM/qwen-code' && vars.MAINTAINER_ECS_RUNNER_DISABLED != 'true') && '90' || '60') }}" |
There was a problem hiding this comment.
[Critical] R1-1: [fails-closed] [regression] This change turns e2e-test-linux's timeout-minutes from the number 60 into this expression string, but the existing lane-contract test .github/scripts/ci-runner-routing.test.mjs:552 still pins assert.equal(job['timeout-minutes'], 60) for this exact job and is never updated by this PR. That file imports node:assert/strict (so assert.equal is strictEqual), which means the assertion now fails unconditionally in every routing state. The file is listed in HELPER_TESTS (.github/workflows/ci.yml:82) and executed via node --test by both helper steps — "GitHub CI helper checks" (ci.yml:436) and "Run .github/scripts helper tests" (ci.yml:586); this PR classifies into the full profile, so the required Test (ubuntu-latest, Node 22.x) check goes red on this PR's own CI run and on every run after merge until the pin is updated.
Re-checked at 77eb9c1 (this round's reviewed commit): the stale pin is untouched and the failure still fires.
Witness:
$ node --test --test-concurrency=1 .github/scripts/ci-runner-routing.test.mjs (at HEAD 77eb9c1)
# tests 23
# pass 22
# fail 1
not ok 5 - carries the pool hygiene and capability steps in order
operator: strictEqual
expected: 60
actual: "${{ fromJSON((github.repository == 'QwenLM/qwen-code' && vars.MAINTAINER_ECS_RUNNER_DISABLED != 'true') && '90' || '60') }}"
at: .github/scripts/ci-runner-routing.test.mjs:552
A/B on the contested assertion: BASE (pre-change e2e.yml, git show HEAD^2) carries the numeric 60 that satisfies the pin; the PR arm fails with the expression string.
Update .github/scripts/ci-runner-routing.test.mjs:552 in this same PR: replace the bare 60 pin with an evaluation of the new routing-scoped expression — the same substitute-then-evaluate technique this PR adds in scripts/tests/e2e-workflow.test.js — asserting 90 on the pool routing and 60 on both hosted fallbacks (fork and kill-switch), and fix the adjacent stale comment ("Pin the ci.yml pool precedent"), which now contradicts ci.yml's actual pool precedent of 90. Note: the round-3 autofix attempt at exactly this fix was rejected by the autofix gate because .github/scripts/ is outside this PR's footprint, and the change was reverted — if that gate still applies to this PR, this update needs a maintainer decision on where the pin change lands.
The replacement must respect the strict-assert import at .github/scripts/ci-runner-routing.test.mjs:17 (node:assert/strict, so compare like-typed values), must keep the pin as a node:test/node:assert assertion (ci.yml:579-583 notes vitest does not collect node:test files), and must keep the two ceilings mirrored from .github/workflows/ci.yml:219 (90 on ecs-qwen routing, 60 hosted), agreeing with the routing condition the timeout mirrors (runs-on at .github/workflows/e2e.yml:47). The updated assertion itself must go red if timeout-minutes regresses to an unconditional value (a flat 60 or flat 90 without the routing condition) — please remove the routing condition from the assertion and run that subtest to prove it.
中文说明
本改动把 e2e-test-linux 的 timeout-minutes 从数字 60 改成了这个表达式字符串,但既有的通道契约测试 .github/scripts/ci-runner-routing.test.mjs:552 仍然对同一个任务钉死 assert.equal(job['timeout-minutes'], 60),且本 PR 没有更新它。该文件导入 node:assert/strict(因此 assert.equal 即 strictEqual),所以这条断言现在在任何路由状态下都会无条件失败。该文件位于 HELPER_TESTS(.github/workflows/ci.yml:82)中,由两个助手测试步骤通过 node --test 执行——"GitHub CI helper checks"(ci.yml:436)与 "Run .github/scripts helper tests"(ci.yml:586);本 PR 会被分类为 full profile,因此本 PR 自己的 CI 运行中必需的 Test (ubuntu-latest, Node 22.x) 检查会变红,且在更新该断言之前,合并后的每次运行也会变红。
已在 77eb9c1(本轮审阅的提交)上复核:该过时的断言原样存在,失败仍然触发。
见证(在 HEAD 77eb9c1 上执行):node --test --test-concurrency=1 .github/scripts/ci-runner-routing.test.mjs → 23 个测试,22 通过,1 失败——失败子测试为 "carries the pool hygiene and capability steps in order",operator: strictEqual,expected: 60,actual 为新的表达式字符串。对该断言做 A/B:BASE(改动前的 e2e.yml,git show HEAD^2)是能满足该断言的数字 60;PR 侧因表达式字符串而失败。
请在同一个 PR 中更新 .github/scripts/ci-runner-routing.test.mjs:552:把裸的 60 钉子替换为对新的路由限定表达式求值——复用本 PR 在 scripts/tests/e2e-workflow.test.js 中新增的"先替换再求值"手法——断言资源池路由为 90、两种托管回退(fork 与紧急开关)均为 60,并修正旁边那条已过时的注释("Pin the ci.yml pool precedent"),它现在与 ci.yml 实际的资源池上限 90 相矛盾。注意:第 3 轮 autofix 曾尝试过完全相同的修复,但因 .github/scripts/ 超出本 PR 的改动范围而被 autofix 门拒绝并回退——如果该限制对本 PR 仍然生效,这次更新需要维护者决定断言改动落在哪里。
替换时必须尊重 .github/scripts/ci-runner-routing.test.mjs:17 的 strict 断言导入(node:assert/strict,即比较同类型值);断言必须保持为 node:test/node:assert 形式(ci.yml:579-583 注明 vitest 不会收集 node:test 文件);并保持与 .github/workflows/ci.yml:219 一致的两个上限(ecs-qwen 路由 90,托管 60),与 timeout 所镜像的路由条件(.github/workflows/e2e.yml:47 的 runs-on)保持一致。更新后的断言本身必须在 timeout-minutes 退化为无条件值(不带路由条件的裸 60 或裸 90)时变红——请从断言中去掉路由条件并运行该子测试来证明这一点。
— qwen3.8-max via Qwen Code /review (v0.22.3)
There was a problem hiding this comment.
Verified real at the current head: node --test --test-concurrency=1 .github/scripts/ci-runner-routing.test.mjs fails at line 552 (strictEqual expected 60, actual is the new routing-scoped expression string) — 23 tests, 22 pass, 1 fail. The full HELPER_TESTS set confirms this is the sole cause of the red required Test (ubuntu-latest, Node 22.x) check: 500 tests, exactly this one failure.
This round nevertheless does NOT implement the pin update: .github/scripts/ is outside this PR's footprint (the PR touches only .github/workflows/e2e.yml and scripts/tests/e2e-workflow.test.js), and the round-3 attempt at exactly this pin update was rejected by the autofix gate and reverted for that reason, as this comment itself notes. Repeating the rejected change would fail the gate again, and there is no in-footprint change that can turn the check green while the pin still reads 60. This needs a maintainer decision on where the pin update lands:
- Allow this PR to expand into
.github/scripts/, so a next round updates the pin here (substitute-then-evaluate: 90 on the pool routing, 60 on both hosted fallbacks, mirroring theruns-oncondition; plus the stale "Pin the ci.yml pool precedent" comment); or - A maintainer lands the pin update separately (direct commit, or a small standalone PR merged first), and this PR rebases onto it; or
- Revert this PR's timeout change entirely (not recommended — it abandons the Main CI failed: E2E Tests on cd5d5af2fbd7 #10591 fix).
Leaving this thread open until a maintainer chooses.
中文说明
已在当前 head 上确认为真实问题:node --test --test-concurrency=1 .github/scripts/ci-runner-routing.test.mjs 在第 552 行失败(strictEqual 期望 60,实际为新的路由限定表达式字符串)——23 个测试,22 通过,1 失败。完整 HELPER_TESTS 集合确认这是必需的 Test (ubuntu-latest, Node 22.x) 检查变红的唯一原因:共 500 个测试,仅此一处失败。
但本轮不实施该断言更新:.github/scripts/ 在本 PR 的 footprint 之外(本 PR 只改动 .github/workflows/e2e.yml 和 scripts/tests/e2e-workflow.test.js),且正如本评论所述,第 3 轮对同一断言的更新尝试已被 autofix gate 以该理由拒绝并回滚。重复被拒绝的改动只会再次被 gate 拒绝,而在断言仍钉死 60 的情况下,footprint 内没有任何改动能让该检查变绿。需要维护者决定断言更新落在哪里:
- 允许本 PR 扩展到
.github/scripts/,下一轮即可在此更新断言(先替换再求值:资源池路由 90、两种托管回退均为 60,与runs-on条件保持一致;同时修正过时的 "Pin the ci.yml pool precedent" 注释);或 - 由维护者单独落地断言更新(直接提交,或先合并一个小的独立 PR),之后本 PR 重新变基;或
- 整体回退本 PR 的 timeout 改动(不建议——等于放弃 Main CI failed: E2E Tests on cd5d5af2fbd7 #10591 的修复)。
在维护者作出选择之前,本线程保持打开。
|
🔀 Base updated: red check(s) [Test (ubuntu-latest, Node 22.x), web-shell E2E Smoke (ubuntu-latest, Node 22.x), Post Coverage Comment (ubuntu-latest, 22.x)] pass on current main — merged current main via update-branch; CI will re-run. 中文说明🔀 已更新 base:红色检查 [Test (ubuntu-latest, Node 22.x), web-shell E2E Smoke (ubuntu-latest, Node 22.x), Post Coverage Comment (ubuntu-latest, 22.x)] 在当前 main 上通过 —— 已通过 update-branch 合入当前 main,CI 将重新运行。 |
|
🤖 Addressed the latest review feedback (round 2/10). What changed, and what I pushed back on: · 已处理最新评审反馈(第 2/10 轮)。改动内容与我反驳保留之处如下: Autofix review round — PR #10597 (issue #10591)Feedback dispositionsImplemented
Escalated to maintainer (not implemented)
No action
Changes this round
Mutation probes (witness verification)
Failed-check notes
Verification
中文说明Autofix 审阅轮次 — PR #10597(issue #10591)反馈处置已实施
升级给维护者(未实施)
无需处理
本轮改动
变异探针(见证验证)
失败检查说明
验证
🦷 Gate advisory — this round resolves a Critical/Request-changes finding with test-only changes (machine-measured): the bite check cannot verify a test-side fix, so the resolution rests on the round summary alone. · 本轮以纯测试改动解决 Critical/Request-changes 反馈(门自动测量):bite 检查无法验证测试侧修复,该解决仅以轮次摘要为凭。 Base-conflict check · 基分支冲突检查: no conflict with main. · 与 main 无冲突。
Re-review when you have a moment. After round 10 this bot stops and leaves the PR for a human. · 有空请复审;第 10 轮后本 bot 停止并将 PR 交给人工。 🧠 Handled by Qwen Code · model/模型 |
What this PR does
Extends the Linux E2E job's ceiling on the shared ECS runner pool from 60 to 90 minutes, scoped exactly to the pool routing: the same repository and kill-switch condition that decides whether a shard runs on the
ecs-qwenpool or falls back to a hosted runner. Hosted fallbacks keep the pre-contention 60-minute bound. A lane-contract test in the scripts test suite evaluates the real timeout expression for both routings — the substitute-then-evaluate technique the platform-lane tests already use — so a regression to an unconditional ceiling fails in CI instead of reading as a passing constant.Why it's needed
The post-merge E2E run 33345905817 on
cd5d5af2fbfailed before any test result was reported and was tracked as issue #10591. The issue body is the failure tracker's per-commit template, which it only uses when the failed jobs' logs carry no vitest FAIL lines — a job that died before tests reported. The run's wall clock (~63 minutes from push to filed issue) lines up with the flat 60-minute job ceiling expiring on a contended shared host, plus finalization and tracker latency.The shared ECS pool has a documented history of stretching CI lanes past their pre-contention budgets: #10552 extended the main CI and Serve A/B ceilings (scoped to the pool) and serialized the Java SDK lane behind a host lock, and #10567 capped each E2E shard to one vitest fork on the pool — the test phase only. The Linux E2E job was the last shared-pool lane still on the old flat bound, so its install/build/bundle/sandbox-build phases under overlapping runs could still expire the whole shard before any test reported. This closes that gap the same way the sibling lanes were fixed.
Reviewer Test Plan
How to verify
runs-on, so the ceiling can never disagree with where the job runs (pool → 90, hosted fallback → 60).npx vitest run --config ./scripts/tests/vitest.config.ts scripts/tests/e2e-workflow.test.js— the two new assertions evaluate the real expression for the pool routing (expects 90) and for both hosted fallbacks, fork and kill-switch (expect 60).60and the pool assertion fails; set both branches to'90'and the hosted assertion fails (both probes were run during development and restored).main: under host contention, shards that previously expired at 60 minutes without reporting any test result should now complete; genuinely wedged shards still fail at 90 instead of GitHub's 360-minute default.Evidence (Before & After)
N/A (CI workflow change, not user-visible). Before: run 33345905817 failed before any test result was reported and the tracker filed per-commit issue #10591. After: the ECS-routed shards carry the contention budget their sibling pool lanes already have, pinned by a failing-on-regression contract test.
Tested on
Environment (optional)
Verification ran on a shared ECS runner host:
npm run build,npm run typecheck,npm run lint,node scripts/lint.js --actionlint,npx prettier --checkon the touched files, focused vitest on the workflow contract test with mutation probes, and a fullnpm run test:scriptspass (four unrelated load-flakes re-run green in isolation; details in the E2E report). yamllint could not run locally (no pip); the new line matches the double-quoted-with-inner-single-quotes style already present and CI-green in the same file, which the yamllint config explicitly allows.Risk & Scope
Linked Issues
Fixes #10591
中文说明
本 PR 做了什么
将 Linux E2E 任务在共享 ECS runner 资源池上的上限从 60 分钟提高到 90 分钟,并且严格限定在资源池路由上:使用与"任务跑在
ecs-qwen池还是回退到托管 runner"完全相同的仓库名 + 紧急开关条件。托管回退路径保留争用前的 60 分钟上限。脚本测试套件中新增了一个通道契约测试,对两种路由分别求值真实的 timeout 表达式——沿用平台通道测试已在使用的"先替换再求值"手法——这样将来如果退化成无条件的固定上限,会在 CI 中直接失败,而不是看起来像个通过的常量。为什么需要
cd5d5af2fb上的合并后 E2E 运行 33345905817 在报告任何测试结果之前就失败了,被跟踪为 issue #10591。该 issue 正文是失败跟踪器的"按提交跟踪"模板,只有当失败任务的日志中没有任何 vitest FAIL 行时才会使用——即任务在测试产出结果之前就死掉了。该运行的墙上时钟(从推送到建 issue 约 63 分钟)与固定 60 分钟任务上限在争用的共享主机上到期、再加上收尾和跟踪器延迟相吻合。共享 ECS 资源池有把 CI 通道撑到超过争用前预算的既有记录:#10552 提高了主 CI 与 Serve A/B 的上限(限定在资源池内),并用主机锁把 Java SDK 通道串行化;#10567 把每个 E2E 分片在资源池上的 vitest fork 数限制为 1——但只覆盖测试阶段。Linux E2E 任务是唯一仍停留在旧的固定上限上的共享池通道,因此在重叠运行之下,其安装/构建/打包/沙箱镜像构建阶段仍可能让整个分片在任何测试产出结果之前超时。本 PR 用与兄弟通道相同的方式补上了这个缺口。
审阅者测试计划
如何验证
runs-on完全相同的路由条件,因此上限永远不会与任务实际运行的位置不一致(资源池 → 90,托管回退 → 60)。npx vitest run --config ./scripts/tests/vitest.config.ts scripts/tests/e2e-workflow.test.js—— 两个新断言分别对资源池路由求值真实表达式(期望 90),以及对 fork 和紧急开关两种托管回退求值(期望 60)。60,资源池断言会失败;把两个分支都改成'90',托管断言会失败(开发过程中两个探针都实际运行过并已恢复)。main上的合并后 E2E 运行:在主机争用下,过去在 60 分钟未报告任何测试结果就超时的分片现在应当能够完成;真正卡死的分片仍会在 90 分钟失败,而不是 GitHub 默认的 360 分钟。证据(前后对比)
N/A(CI 工作流变更,用户不可见)。变更前:运行 33345905817 在报告任何测试结果之前失败,跟踪器按提交建立了 issue #10591。变更后:ECS 路由的分片获得了其兄弟资源池通道早已拥有的争用预算,并由一个"退化即失败"的契约测试钉住。
测试平台
环境(可选)
验证在一台共享 ECS runner 主机上进行:
npm run build、npm run typecheck、npm run lint、node scripts/lint.js --actionlint、对改动文件运行npx prettier --check、对工作流契约测试做带变异探针的聚焦 vitest,以及一次完整的npm run test:scripts(4 个与本次变更无关的负载性 flake 单独重跑后全绿,详见 E2E 报告)。yamllint 在本地无法运行(没有 pip);新行与同文件中已经存在且 CI 全绿的"双引号内含单引号"写法完全一致,yamllint 配置明确允许该形态。风险与范围
关联 Issue
Fixes #10591