Skip to content

test(core): rescale the shell-safety CPU budget to the metric it measures - #10735

Merged
yiliang114 merged 3 commits into
QwenLM:mainfrom
TianYuan1024:fix/shell-ast-cpu-budget-unit
Sep 2, 2026
Merged

test(core): rescale the shell-safety CPU budget to the metric it measures#10735
yiliang114 merged 3 commits into
QwenLM:mainfrom
TianYuan1024:fix/shell-ast-cpu-budget-unit

Conversation

@TianYuan1024

Copy link
Copy Markdown
Contributor

What this PR does

Raises maxClassificationCpuMs in packages/core/src/utils/shellAstParser.test.ts from 1000 to 4000, and records in a comment how the number was derived.

Why it's needed

#10648 moved the two budget assertions in that file from wall clock to process.cpuUsage(). That is a change of unit, not just of clock source, but the 1000 literal came along unchanged — so a wall-clock budget is now being applied to a CPU-time measurement.

process.cpuUsage() is process-wide: it sums user + system across every thread in the process for the window, so V8's background GC and JIT compiler threads and the parser runtime's own threads are charged to it alongside the work under test.

Measured directly against the built packages/core/dist on an idle 10-core M-series Mac (Node v22.22.1), running exactly the six adversarial commands from the failing test:

parallel    cpu=344.4ms  wall=110.7ms  ratio=3.11x
parallel    cpu=191.0ms  wall= 83.9ms  ratio=2.28x
sequential  cpu=179.4ms  wall= 82.5ms  ratio=2.17x
sequential  cpu=166.6ms  wall= 78.4ms  ratio=2.13x

The decisive rows are the sequential ones: the 2–3× inflation is not the Promise.all fan-out over six commands — replacing it with an awaited loop still reports 2.1×. It is process-wide accounting of concurrent runtime threads. So the effect of #10648 was to tighten the budget by 2–3× at the same moment the number being measured got noisier.

That left 1000 below the floor of what a healthy run reports:

environment measured CPU ms result
this machine, inside vitest (548-test file) 267.6 pass
GitHub-hosted runner 1232.8 / 1322.3 / 1328.3 / 1340.3 / 1360.8 fail
ECS (ecs-qwen-*) pass

Hosted runners cluster at 1232–1361 ms — 1.23–1.36× the budget, with no overlap with it at all. This is not flake; it is the wrong constant for the metric. Per ci.yml:155-159, in-repo PRs and fork PRs from OWNER/MEMBER/COLLABORATOR authors route to ECS and everything else stays on GitHub-hosted runners, so the failure lands squarely and only on outside-contributor fork PRs — the population least able to diagnose it, and for whom a red Test job reads as "your PR broke something".

Why 4000, and why it does not blunt the guard

4000 ms is ~2.9× the slowest healthy run observed anywhere (1361 ms) and ~15× what this machine reports inside vitest.

These two tests exist to catch catastrophic backtracking on 10 000-repetition adversarial inputs. That class of regression costs orders of magnitude, not a small multiple — it would blow past 1000, 4000, or 40000 alike. Widening from 1.3× under the healthy floor to ~3× above it removes the false positives without weakening what the assertions actually detect.

Alternatives considered

Recorded in #10734 and deliberately not done here, since either is a larger change that deserves its own discussion:

  • Calibrate rather than hardcode — measure a fixed reference workload in the same process and express the budget as a multiple of it, so the assertion measures the code rather than the runner.
  • Assert the invariant, not the duration — pin that cost does not scale superlinearly with input size (10k vs 20k repetitions within a constant factor). Machine-independent, and closer to what the test actually wants to guarantee.

Reverting to wall clock is not proposed: #10648's motivation was sound. Wall clock inflates under contention on shared runners because it counts descheduled time (see #10490, expected 1762 to be less than 1000 on this very test), and CPU time correctly does not. The metric was the right call; only the constant was left behind.

Reviewer Test Plan

How to verify

npx vitest run src/utils/shellAstParser.test.ts   # from packages/core

548 passed locally. To see the numbers for yourself, temporarily log (cpuUsage.user + cpuUsage.system) / 1000 next to each assertion and run with --silent=false: the adversarial-inputs test reports ~270 ms on an idle machine, the nested-substitution test ~4 ms.

To confirm the guard still bites, drop the budget back to a value under the floor (e.g. 200) and watch the adversarial-inputs test go red.

Tested on

OS Status
🍏 macOS
🪟 Windows ⚠️
🐧 Linux ⚠️

prettier --check and eslint clean on the changed file. Windows and Linux rely on CI.

Risk & Scope

Linked Issues

Fixes #10734

中文说明

这个 PR 做了什么

packages/core/src/utils/shellAstParser.test.ts 中的 maxClassificationCpuMs1000 提到 4000,并用注释记录这个数字是怎么定出来的。

为什么需要

#10648 把该文件的两条预算断言从墙钟时间改为 process.cpuUsage()。这不只是换了计时源,而是换了量纲,但 1000 这个字面量原封不动地留了下来——于是一个墙钟预算被用来约束 CPU 时间的测量值。

process.cpuUsage()进程级的:它把窗口期内进程中所有线程的 user + system 累加,因此 V8 的后台 GC 与 JIT 编译线程、解析器运行时自身的线程,都和被测代码一起被计入。

直接针对构建产物 packages/core/dist 实测(空载 10 核 M 系列 Mac,Node v22.22.1,跑的正是失败测试里那六条对抗性命令),数据见上方英文部分。

决定性的是 sequential 两行:2–3 倍的膨胀并非来自对六条命令的 Promise.all 并发——改成串行 await 后依然是 2.1 倍。它来自对并发运行时线程的进程级计费。因此 #10648 的实际效果,是在被测数值变得更嘈杂的同时把预算收紧了 2–3 倍。

这使得 1000 落到了健康运行的地板以下:本机在 vitest 中报 267.6ms(通过),托管 runner 报 1232.8 / 1322.3 / 1328.3 / 1340.3 / 1360.8ms(全部失败),ECS 通过。托管 runner 集中在 1232–1361ms,是预算的 1.23–1.36 倍,与预算区间完全不重叠——这不是抖动,而是这个常量对新口径就是错的。

ci.yml:155-159 的路由,仓库内 PR 与 OWNER/MEMBER/COLLABORATOR 作者的 fork PR 跑 ECS,其余留在托管 runner,所以这个失败只砸在外部贡献者的 fork PR 上——恰恰是最难自行诊断的一群人,而红掉的 Test job 对他们读起来就是"你的 PR 弄坏了什么"。

为什么是 4000,以及为什么不削弱这条防线

4000ms 约为已观测到的最慢健康运行(1361ms)的 2.9 倍,约为本机 vitest 内数值的 15 倍。

这两条测试的存在意义是捕获一万次重复对抗性输入引发的灾难性回溯。那一类回归的代价是数量级级别的,而不是小倍数——它会同样轻易地突破 1000、4000 或 40000。把边界从"低于健康地板 1.3 倍"改成"高于地板约 3 倍",消除了误报,却不改变这些断言真正能检测到的东西。

考虑过但未采用的方案

记录在 #10734,本 PR 刻意不做,因为两者都是更大的改动、值得单独讨论:改为相对标定;以及断言不变量而非时长。

不提议改回墙钟计时#10648 的动机是成立的。墙钟时间在共享 runner 上会因计入被调度出去的时间而在争用下膨胀(见 #10490,同一条测试上的 expected 1762 to be less than 1000),而 CPU 时间正确地不计这部分。口径选对了,只是常量没跟上。

复核测试方案

packages/core 运行 npx vitest run src/utils/shellAstParser.test.ts,本地 548 条全部通过。若想自行看数值,在两条断言旁临时打印 (cpuUsage.user + cpuUsage.system) / 1000 并加 --silent=false 运行:空载机器上对抗性输入那条约 270ms,嵌套替换那条约 4ms。若想确认防线仍然有效,把预算调回地板以下(例如 200),对抗性输入那条会变红。

prettier --checkeslint 在改动文件上均干净。Windows 与 Linux 依赖 CI。

风险与范围

关联 Issue

Fixes #10734

…ures

`process.cpuUsage()` is process-wide: it sums user + system across every
thread for the window, so V8's background GC and JIT threads and the
parser runtime's own threads are charged to it alongside the work under
test. Measured against the built package on an idle machine, that reports
2.1-3.1x the wall time of the same six commands -- 2.1x even when they run
sequentially, so the inflation is the accounting, not the `Promise.all`
fan-out.

When the assertions moved from wall clock to CPU time the 1000 ms literal
came along unchanged, which left the budget below the floor of what a
healthy run reports: ~270 ms in vitest on an idle machine, but 1232-1361 ms
on GitHub-hosted runners, where it now fails deterministically. Per
ci.yml's routing that lane is exactly where outside-contributor fork PRs
land, so the failure reads to them as "your PR broke something".

Rescale to 4000 ms and record how the number was derived. These tests
guard against catastrophic backtracking on 10k-repetition adversarial
inputs, which costs orders of magnitude rather than a small multiple, so
the headroom does not blunt them.

Fixes QwenLM#10734
@github-actions github-actions Bot added the review/self-reported The linked issue was opened by the PR author (self-reported) label Sep 1, 2026
@qwen-code-ci-bot

qwen-code-ci-bot commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

⚠️ Deferred approval withheld — 1 PR CI workflow run(s) on 92ef15d did not finish green; see the updated table in the Stage 2 comment. Re-run @qwen-code /triage after fixes. finalize run

⚠️ 延迟审批已搁置 —— 92ef15d 有 1 个 PR CI workflow 未以绿色完成,详见 Stage 2 评论中已更新的表格。修复后可重新运行 @qwen-code /triage查看 finalize 运行

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Thanks for the PR!

Template: Complete ✓ — every required section is present, and the description carries measured before/after data inline. (The Evidence (Before & After) subsection isn't a standalone heading, but for a test-only change it would read N/A and the numbers are inline instead — fine.)

Problem: Observed and deterministic, not theoretical. #10734 cites five Test (ubuntu-latest) jobs on GitHub-hosted runners measuring 1232.8–1360.8 ms of CPU time against the 1000 ms budget — every run red, with no overlap with the budget at all. I verified the root cause against main (1804683): #10648 switched both budget assertions in shellAstParser.test.ts from wall clock to process-wide process.cpuUsage() but kept the wall-clock literal. That is a unit bug, not a flake.

Direction: In scope. This is a deterministic CI red, and the ci.yml runner routing confirms it lands only on outside-contributor fork PRs (this PR's author has read access → GitHub-hosted runner). Making the CI signal honest for first-time contributors is clearly worth fixing.

Size: Touches packages/core/src/, but the file is a test: 0 production lines, 16 test lines (15+1), 0 generated/schema. No threshold applies.

Approach: Minimal, and the right call. Rescale the literal to the metric it now measures, document the derivation, and explicitly defer the two larger alternatives (calibration, invariant-based assertion) to #10734. 4000 ms is ~2.9× the slowest observed healthy run (1361 ms); these guards catch order-of-magnitude regressions, so the headroom does not blunt them.

Risk: No elevated risk signals — the changed file is a .test.ts (excluded from the revert-correlated path list), and the PR touches only the timing budget, not the shell-safety classification logic it guards.

Moving on to code review. 🔍

中文说明

感谢贡献!

模板:完整 ✓——所有必需小节齐全,描述中直接内联了 before/after 实测数据。(Evidence (Before & After) 未作为独立小节出现,但对纯测试改动它本就应为 N/A,且数据已内联,可以接受。)

问题:已观测到且是确定性的,不是理论问题。#10734 引用了五个托管 runner 上的 Test (ubuntu-latest) job,CPU 时间实测 1232.8–1360.8ms,全部超过 1000ms 预算,与预算区间完全不重叠。已对照 main(1804683)核实根因:#10648 把两条预算断言从墙钟改为进程级 process.cpuUsage(),却原样保留了墙钟字面量。这是量纲错误,不是抖动。

方向:在使命范围内。这是一个确定性 CI 红,且经 ci.yml runner 路由确认只砸在外部贡献者的 fork PR 上(本 PR 作者为 read 权限 → 托管 runner)。为首次贡献者修复 CI 信号的可信度,值得做。

规模:触及 packages/core/src/,但文件是测试:生产代码 0 行、测试 16 行(15+1)、生成/schema 0 行。不适用任何阈值。

方案:最小且正确。把字面量重标定到它现在度量的量纲,记录推导过程,并把两个更大的替代方案(相对标定、断言不变量)明确留给 #10734。4000ms 约为最慢健康运行(1361ms)的 2.9 倍;这些防线针对的是数量级回归,余量不会钝化它们。

风险:无升级风险信号——改动文件是 .test.ts(不在 revert 相关路径列表内),且只动计时预算,不碰它守护的 shell 安全分类逻辑。

进入代码审查 🔍

Qwen Code · qwen3.8-max

Reviewed at 92ef15da86100f41e1f0376e524435bae0566929 · re-run with @qwen-code /triage

@qwen-code-ci-bot

qwen-code-ci-bot commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Code review

Independent baseline first: given "#10648 changed the metric from wall clock to process-wide CPU time but kept the 1000 literal, and hosted runners measure 1232–1361 ms", the minimal fix is to rescale the constant comfortably above the slowest observed run and document the derivation — leaving recalibration or invariant-based assertions for a follow-up. That is exactly what this PR does, so there is no simpler path it missed.

The diff is one constant (1000 → 4000) plus an accurate derivation comment: process-wide accounting charges V8's GC/JIT threads, hence the 2.1–3.1× inflation, and the sequential control run shows it is the accounting rather than the Promise.all fan-out. Both assertion sites (adversarial inputs, nested substitutions) share the constant, so one change covers both; grep confirms the constant is referenced nowhere else. No scope creep, no product-code change, conventions fine. No blockers.

CI evidence

CI on the reviewed commit is still running, and one caveat matters: I verified on main (1804683) that packages/web-shell/client/components/ChatEditor.test.tsx carries a duplicate language = 'en', destructuring binding (lines 422/425) — a hard syntax error that fails the whole Test job at transform time. #10729 fixes it but is still open, so this PR's Test job is expected to be red for reasons unrelated to this change until that lands and this branch rebases.

Two facts frame the signal:

The oracle for the fix is this PR's own hosted-runner Test job once the unrelated transform error is out of the way. A sandboxed /verify run cannot stand in for it: fast environments pass this assertion even at 1000 (per #10734, ECS runners do), so only a hosted-runner CI run exercises the failing regime.

Final CI results for 92ef15d (auto-updated by the triage finalize job after CI completed):

Check Conclusion
Test (ubuntu-latest, Node 22.x) ❌ failure
Classify PR ✅ success
Dependency CVE audit ✅ success
Desktop Shell (ubuntu-22.04) ✅ success
Desktop Shell (windows-2022) ✅ success
Integration Tests (no-AK, No Sandbox) ✅ success
Secret scan (TruffleHog) ✅ success
web-shell E2E Smoke (ubuntu-latest, Node 22.x) ✅ success

One row per check name (latest run); skipped checks omitted; failures sort first. / 每个检查名一行(取最新一次运行),省略 skipped,失败项排在最前。

Real-scenario testing

N/A — test-only change with nothing user-visible. Per the static-review rule the PR's code is never executed; test evidence comes from the PR's own CI above.

中文说明

代码审查:先写独立方案——已知"#10648 把度量从墙钟改为进程级 CPU 时间、却保留了 1000 字面量,托管 runner 实测 1232–1361ms",最小修法就是把常量重标定到最慢观测值之上并记录推导,标定/不变量方案留作后续。本 PR 正是这么做的,没有遗漏更简路径。

diff 就是一个常量(1000 → 4000)加一段准确的推导注释:进程级计费把 V8 的 GC/JIT 线程也算了进去,故有 2.1–3.1 倍膨胀;sequential 对照表明膨胀来自计费口径而非 Promise.all 并发。两处断言(对抗性输入、嵌套替换)共用该常量,一处改动覆盖两处;grep 确认该常量别处无引用。无范围蔓延、无产品代码改动、符合约定。无阻塞项。

CI 证据:被审提交的 CI 仍在运行,且有一个重要前提:已在 main(1804683)上核实 ChatEditor.test.tsx 存在重复的 language = 'en', 解构绑定(422/425 行)——硬语法错误,会在 transform 阶段使整个 Test job 失败。修复它的 #10729 仍未合入,因此在其合入并 rebase 之前,本 PR 的 Test job 预计会因无关原因变红。

两个事实框定了信号:本提交的 Test (ubuntu-latest) job 正运行在托管 runner 上(已核对 job 的 runner 标签与 ci.yml 对 read 权限 fork 作者的路由)——正是 #10734 中全部五次失败所在的 runner 类别;macOS/Windows Test job 为 skipped,按设计它们只对 merge queue/定时/手动触发运行,不对 PR 运行。失败证据是真实 CI 而非作者口述:#10734 逐一列出了五个托管 runner job 的编号,issue 的 triage 已核对 job 99900653054 的日志,其中正是第二处断言报出 expected 1340.262 to be less than 1000

修复的 oracle 是本 PR 自己的托管 runner Test job(待无关 transform 错误清除后)。沙箱 /verify 无法替代:快环境在 1000 预算下也能通过(#10734 中 ECS runner 即如此),只有托管 runner 的 CI 才处于失败区间。

真实场景测试:N/A——纯测试改动,无用户可见行为。按静态审查规则不执行 PR 代码,测试证据来自上述 PR 自身 CI。

Qwen Code · qwen3.8-max

Reviewed at 92ef15da86100f41e1f0376e524435bae0566929 · re-run with @qwen-code /triage

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Confidence: 5/5 — textbook small fix: a measured bug with public CI evidence, the minimum possible diff, and a derivation comment that saves the next reader the archaeology.

Stepping back: the independent proposal I wrote before reading the diff — rescale the constant above the slowest observed run, document how it was chosen, defer the fancier alternatives — is exactly what landed. Every line in the diff is needed for the stated goal: one constant and the comment explaining it. This solves a real problem that lands disproportionately on first-time contributors, whose fork PRs run on GitHub-hosted runners where the wall-clock literal made Test deterministically red regardless of their change — the most expensive place this bug could live. The fix is the smallest correct one: reverting to wall clock was rightly rejected (it would reintroduce the contention inflation from #10490), and calibration / invariant rewrites are rightly deferred to #10734. If I maintain this in six months, the comment tells me exactly why 4000.

Two process notes, neither a reflection on the code: this PR's Test job is expected red regardless of this change until #10729 lands (the duplicate destructuring binding on main is verified), so it will need a rebase then; and CI on the reviewed commit is still running, so approval is deferred until it lands green on 92ef15da86100f41e1f0376e524435bae0566929.

中文说明

置信度:5/5——教科书式的小修复:问题有实测数据与公开 CI 证据,diff 取最小可能,推导注释让后来者不必再做考古。

退一步看:我在读 diff 之前写下的独立方案——把常量重标定到最慢观测值之上、记录取值依据、把更复杂的替代方案延后——与本 PR 完全一致。diff 中每一行都是目标所必需:一个常量加一段解释它的注释。这个问题真实存在,且不成比例地砸在首次贡献者头上——他们的 fork PR 跑在托管 runner 上,墙钟字面量让 Test 无论改动如何都确定性变红——这是该 bug 最昂贵的位置。修复是最小的正确修法:改回墙钟被正确拒绝(会重新引入 #10490 的争用膨胀),相对标定/不变量重写被正确地留给 #10734。六个月后维护这段代码时,注释会说明 4000 的来历。

两点流程说明,均与代码质量无关:在 #10729 合入之前,本 PR 的 Test job 预计会因无关原因变红(main 上的重复解构绑定已核实),届时需要 rebase;被审提交的 CI 仍在运行,因此批准推迟到其在 92ef15da86100f41e1f0376e524435bae0566929 上变绿之后。

Qwen Code · qwen3.8-max

Reviewed at 92ef15da86100f41e1f0376e524435bae0566929 · re-run with @qwen-code /triage

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Downgraded from Approve to Comment: CI failing: Test (ubuntu-latest, Node 22.x). Partially reviewed — gaps disclosed.

Not reviewed: reverse audit — stopped before round 1 by the review time budget.

Test Plan (not a blocker): src/utils/shellAstParser.test.tsno such file or directory; 548 passed — this review observed 22978, 1898, 27712, 256, 1753, 504, 5468, 94 passed.

中文说明

⚠️ 已从批准降级为评论:CI failing: Test (ubuntu-latest, Node 22.x)。 仅完成部分审查,审查缺口已披露。

未审查:反向审计——评审时间预算不足,未能开始第 1 轮。

Test Plan(非阻断):src/utils/shellAstParser.test.tsno such file or directory; 548 passed — this review observed 22978, 1898, 27712, 256, 1753, 504, 5468, 94 passed

— qwen3.8-max via Qwen Code /review (v0.22.3)

@qqqys

qqqys commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Verification report at head 92ef15da (periodic review round; static review + local execution, no Critical found).

What this is: one constant — maxClassificationCpuMs 1000 → 4000 in packages/core/src/utils/shellAstParser.test.ts — plus a comment documenting why: process.cpuUsage() is process-wide (all V8/parser threads charged to the window), so the old wall-clock-carried budget sat below the healthy floor on CI runners (measured 1232–1361 ms there vs ~270 ms idle-local).

Static check — the budget still bites: both call sites assert (user+system)/1000 < maxClassificationCpuMs upper bounds around Promise.all fan-outs of adversarial 10k-repetition inputs, with the classification results themselves pinned by unchanged resolves.toEqual([...]) assertions. A catastrophic-backtracking regression costs orders of magnitude more than 4 s, so the widened ceiling does not blunt the guard; assertion direction and functional expectations unchanged.

Local execution at head (scratch tree, Node 24.18.1, full shellAstParser.test.ts): 548/548 pass; the adversarial-budget test measured ~644 ms wall here.

Mutation check (assertion liveness): with the constant set to 100 ms in a scratch copy, classifies adversarial rule inputs within the CPU budget fails (676 ms > 100 ms) while the nested-substitution sibling still passes (24 ms) — the budget assertion is live, not decorative; restored to green afterward.

CI at head: the PR's target suite is green in the Test(ubuntu) run (shellAstParser.test.ts (548 tests) 1639ms ✓, adversarial-budget case 810 ms). The lane's overall failure is the known pre-existing main break — packages/web-shell/client/components/ChatEditor.test.tsx:425: The symbol "language" has already been declared (transform error; fix is open in #10729) — unrelated to this diff, which touches no web-shell file.

Not approving: no ci-bot/maintainer APPROVED on record at 92ef15da (ci-bot's latest review state is COMMENTED) — leaving that to the bot's re-review / maintainer. Once an approval lands and the Test lane re-runs green (post-#10729), this looks mergeable.

中文

位于 92ef15da 的验证报告(静态评审 + 本地执行,未发现 Critical)。改动仅一处常量:shell 安全分类 CPU 预算 1000→4000ms,并补充了 process.cpuUsage 进程级计费导致旧预算低于 CI 健康下限的说明。两个断言仍是上界断言,分类结果断言未变;本地全套 548/548 通过(对抗用例实测约 644ms);变异检查(预算压到 100ms)确认对抗用例会失败——断言仍然有效。CI 上该文件已绿,当前 Test lane 的红色是 main 上已有的 ChatEditor 重复声明问题(#10729 修复中),与本 PR 无关。因 head 上尚无 ci-bot/维护者 APPROVED,本次不批准;待批准到位且 Test lane 复跑转绿后即可合并。

qqqys periodic review round · verified at 92ef15da

@qwen-code-ci-bot qwen-code-ci-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Downgraded from Approve to Comment: CI still running. Partially reviewed — gaps disclosed.

Not reviewed: reverse audit — stopped before round 1 by the review time budget.

Test Plan (not a blocker): src/utils/shellAstParser.test.tsno such file or directory; 548 passed — this review observed 22988, 1898, 27821, 256, 1755, 504, 5628, 94 passed.

中文说明

⚠️ 已从批准降级为评论:CI still running。 仅完成部分审查,审查缺口已披露。

未审查:反向审计——评审时间预算不足,未能开始第 1 轮。

Test Plan(非阻断):src/utils/shellAstParser.test.tsno such file or directory; 548 passed — this review observed 22988, 1898, 27821, 256, 1755, 504, 5628, 94 passed

— qwen3.8-max via Qwen Code /review (v0.22.3)

@TianYuan1024

Copy link
Copy Markdown
Contributor Author

CI's green now, hosted runner included. @yiliang114 @wenshao @chiga0 mind giving this a look when you have a sec? Test-only, one constant — process.cpuUsage() stays, just rescaling the literal to match
the unit. Details in #10734.

@yiliang114 yiliang114 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review passed.

The rescale is justified and well-documented: process.cpuUsage() is process-wide (user+system across all threads, so V8 GC/JIT and the parser runtime's own threads are charged alongside the work under test), and the measured 2.1–3.1x inflation over wall time — 2.1x even when the commands run sequentially — shows the old 1000 was a wall-clock number carried over unchanged when the metric changed, sitting below the floor of a healthy run (1232–1361 ms on GitHub-hosted runners). 4000 restores headroom without blunting the guard: these tests exist to catch catastrophic backtracking on 10k-repetition adversarial inputs, which costs orders of magnitude rather than a small multiple. CI green on this head.

@qwen-code-dev-bot qwen-code-dev-bot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed at head 1a1711de.

  • Correct diagnosis, minimally fixed: #10648 migrated the budget assertion from wall-clock to process.cpuUsage(), which is process-wide (user+system across V8 GC/JIT and runtime threads), so the old 1000 was a wall-clock number applied to a 2–3x-inflated CPU metric — the author's sequential-vs-parallel measurements show the inflation is the accounting, not the Promise.all fan-out, so GH-hosted healthy runs (1232–1361ms) were already past the old ceiling.
  • Raising the ceiling to 4000ms keeps the guard's purpose intact: it defends against catastrophic backtracking on adversarial inputs, which costs orders of magnitude more than the added headroom, and the wall-clock cost stays well under vitest's timeout. Comment documents the derivation; no production code touched.
  • No open threads, CI has no failures; per the channel convention the call is on the review itself.

@yiliang114
yiliang114 added this pull request to the merge queue Sep 2, 2026
Merged via the queue into QwenLM:main with commit ec15ba6 Sep 2, 2026
99 checks passed
@chiga0

chiga0 commented Sep 2, 2026

Copy link
Copy Markdown
Collaborator

Post-merge review — merged at 1a1711debc99bb1c4427b9376c3425648d8d73cc.

Tier: Scan — test-only, one constant + comment, no production code.

Scope: packages/core/src/utils/shellAstParser.test.ts only. NOT reviewed: unrelated test infrastructure (no diff), CI configuration files (no diff).


No blocking findings.
Approval blockers: none.

What I checked:

  1. Stated rationale vs. actual PR history. The PR claims test(ci): stabilize shared-runner budgets and cron interactive checks #10648 changed the metric from wall-clock to process.cpuUsage() without updating the constant. Confirmed: test(ci): stabilize shared-runner budgets and cron interactive checks #10648's own body reads "Shell safety performance guards now measure process CPU time instead of elapsed wall-clock time… The same one-second budget and classification assertions remain in place." The diagnosis is correct.

  2. Test validity (class 5) — does widening to 4000 ms make the guard vacuous? The two assertions cover adversarial inputs at 10,000 repetitions. Catastrophic backtracking at that scale would be O(n²) or worse — that is seconds to tens of seconds, not a small multiple of 4000 ms. The budget is still a tight upper bound on catastrophic failure; only the false-positive floor moved. The guard is intact.

  3. Comment accuracy. The added comment correctly describes: (a) process.cpuUsage() is process-wide summing user+system; (b) the 2.1–3.1x inflation ratio; (c) that sequential execution still shows 2.1x, ruling out Promise.all fan-out as the cause; (d) the old constant's origin as a wall-clock carryover; (e) the adversarial-input nature of these tests.

  4. Both assertions share the constant — a single update covers both, no drift risk.

Not run: rung 1 or higher (no working tree available; classified as not required — test-only change, no new algorithm, no production behavior changed).


Cross-check against existing reviews: yiliang114 (APPROVED) and qwen-code-dev-bot (APPROVED) both confirmed the same analysis independently. qqqys's verification comment (static + local execution) found no critical issues. No reviewer found anything this review did not also cover; no missed finding.

Reviewed with AI assistance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review/self-reported The linked issue was opened by the PR author (self-reported)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ci: the 1000 ms CPU budget in shellAstParser.test.ts is a wall-clock number applied to a CPU-time metric — deterministic red on GitHub-hosted runners

6 participants