Skip to content

feat(triage): add sandboxed /verify deep-verification lane - #7710

Merged
wenshao merged 21 commits into
mainfrom
feat/triage-verify-lane
Jul 26, 2026
Merged

feat(triage): add sandboxed /verify deep-verification lane#7710
wenshao merged 21 commits into
mainfrom
feat/triage-verify-lane

Conversation

@wenshao

@wenshao wenshao commented Jul 25, 2026

Copy link
Copy Markdown
Collaborator

What this PR does

Adds an on-demand deep-verification lane to the triage workflow: commenting @qwen-code /verify on a PR now runs a maintainer-grade evidence round against the PR's real build — an A/B load-bearing proof against the base side, a vacuity check on new tests, mock-free wire-oracle harnesses, and targeted workspace gates — and publishes the report back to the PR as one upserted comment (live "running" status → final report). The report is explicitly advisory evidence for human reviewers: it is never a review, an approval, or a CI check.

Concretely: two new jobs in qwen-triage.yml (verify executes the PR inside the same isolation contract as the existing /tmux job — container, no GitHub token in the agent env, model key behind a loopback proxy that only allows POST /chat/completions, gated on write permission from both the PR author (whose code runs) and the commenter (who spends a scarce runner slot plus a model budget); publish-verify posts the report from a clean hosted runner that never checks out PR code), plus a new verify-pr skill encoding the methodology and artifact contract, and a Stage 2c update so the static triage agent recommends /verify when a PR's central claim needs behavioral evidence.

Hardening built in from the start: the agent's skill is pinned from the base branch via git archive HEAD^1 so the tree under test can never rewrite its own verifier; PR-committed tmp/*-verify-* directories are deleted after checkout so a PR cannot pre-plant a fake report that the artifact collector would publish; the persistent self-hosted workspace gets the same git exec-vector sweep (config allowlist + hook removal) the triage job already uses; and the agent-written verdict is allowlisted (merge-ready|findings|blocked|inconclusive) before it touches workflow outputs.

The second commit folds in patterns from recent hand-run verification rounds (#7632 round 2, #7656): re-running /verify is a follow-up round — the resolve step snapshots the previous report before overwriting it, and the skill re-checks each prior finding at the new head (fixed/stands/superseded); harnesses prefer configuration seams (a baseUrl, an env var) over module interception with the fake peer encoding the upstream's real semantics; multi-commit PRs get per-commit load-bearing tables; workflow/CI PRs get embedded-script replay against real data, the repo's own lint gates, and day-one trigger cost math from real event history; blockers enumerate their blast radius and carry a collapsed minimal suggested fix.

The third commit adds image evidence, borrowing the layout and hosting conventions from image-bearing PRs and rounds (#7265, #7471, #7686 round 2): the agent may save evidence/*.png (kebab-case filenames that double as claim-binding captions; before/after pairs preferred), and publish-verify hosts them on the pr-assets branch under verify/pr<N>-<run>-<attempt>/ and renders them below the escaped report. Untrusted-payload discipline throughout: strict filename allowlist, 8-image / 2 MB caps, racing-push retry, and any hosting failure degrades to a text-only comment. It also encodes the quantified-verification rules from #7686 round 2: follow-up rounds lead with a previous-finding status table and re-measure instead of diffing the old report; size/perf claims get measured-metric Δ tables with every residual delta accounted for; unreachable branches get the configuration that reaches them constructed; defensive guards get their accept path verified against real production artifacts, not just mocked rejects.

Why it's needed

The triage agent is static-analysis-only by design — its environment carries a write PAT, so it must never execute PR code, and its test evidence is limited to reading the PR's own CI. The only behavioral lane today, /tmux, is scoped to TUI surfaces and text captures. Maintainers currently produce deep verification rounds (A/B against base, wire oracles, load-bearing proofs — e.g. the round-3 verification on #7586) entirely by hand. This PR makes that style of evidence available on demand in CI, with the isolation guarantees the hand-run version doesn't need to think about, and without widening the existing approval surface: the verify check-runs ride the issue_comment event, which the finalize workflow's event == "pull_request" universe structurally excludes from both the CI table and the deferred-approval gate.

Reviewer Test Plan

How to verify

Static/replay verification (all reproducible locally):

  • node scripts/lint.js --actionlint and yamllint with the repo config pass; the only shellcheck classes actionlint reports (SC2016/SC2129) are in the lint script's explicit ignore set and pre-exist in the cloned tmux blocks.
  • All 13 run: blocks belonging to this lane (authorize, verify, publish-verify), extracted from the YAML, pass bash -n and shellcheck -S warning; the embedded loopback-proxy JS passes node --check. The independent Linux replication extended this to all 29 blocks in the workflow.
  • The publish-verify script was executed (not just read) across all six terminal branches — cancelled, infra-failure, skipped, n/a, prepare-fail, report — with a stubbed gh; the rendered bodies are correct and report content containing </code></pre></details>, @everyone, and <img onerror=…> stays fully entity-escaped inside the <details><pre><code> block.
  • The verdict allowlist rejects junk/injection strings (PWNED @everyone, findings; rm -rf / → discarded); the assertions jq coerces non-numeric JSON ({"pass":"<script>"}) to zeros; the docs-only decision grep was replayed against mixed/docs-only/empty file lists with GNU grep semantics.

Live end-to-end run (local replica of the CI job, faithful to every contract knob — merge-ref worktree of #7547 at depth-2 parents, .qwen pinned from this branch, QWEN_VERIFY_CONTEXT metadata snapshot, credential-less gh, isolated QWEN_HOME): the agent (qwen3.8-max-preview) completed in 25 turns / 3.5 minutes API time, produced every artifact in the contract, and returned verdict merge-ready with 318/318 assertions. The numbers were then audited adversarially: 318 = 304 real vitest tests (23+68+213 across three targeted gate files, log-verified) + 13 A/B assertions + 1 vacuity check; re-running the agent's own ab-harness.mjs reproduced 13/13; reverting the PR's fix and re-running that same harness went exactly 7/13 (the 3 PR-side and 3 flip assertions failed), and restoring returned 13/13 — proving the A/B senses the fix rather than comparing a file to itself. The agent made zero gh invocations. Feeding the real artifacts through the actual publish-verify script rendered the exact 4.7 KB comment CI would post.

Evidence (Before & After)

Agent's A/B harness, rerun by hand at head and under mutation (fix reverted, then restored):

=== A/B SUMMARY: 13 passed, 0 failed, 13 total ===   # head, as the agent reported
=== A/B SUMMARY: 7 passed, 6 failed, 13 total ===    # fix reverted → harness goes red
=== A/B SUMMARY: 13 passed, 0 failed, 13 total ===   # fix restored

Publish rendering of the real run's artifacts (headline of the comment CI would post):

**Sandboxed verification: merge-ready (agent verdict)** - [workflow run](…)
Scripted assertions: 318 passed · 0 failed · 318 total

Tested on

OS Status
🍏 macOS
🪟 Windows N/A
🐧 Linux ✅ static/replay · ⚠️ live run

Linux detail: the static and replay layer (YAML parse, 36/36 workflow tests, all 29 extracted run: blocks through bash -n, both proxy heredocs through node --check, and the verdict-allowlist replay) was independently replicated on Linux at c25afbd8 with zero failures. What stays untested there is the live path — the jobs running on a real Actions runner with the runner secrets — which nothing before merge can cover.

Environment (optional)

macOS 15 / Node 22 / qwen CLI 0.20.1; agent model qwen3.8-max-preview (DashScope); verification worktree built with a real npm ci + npm run build from the PR lockfile.

Risk & Scope

  • Main risk or tradeoff: the workflow jobs themselves have not yet executed on a live Actions runner (Linux row above: the static/replay layer is independently replicated there, the live path is not) — the lane is opt-in comment-triggered, per-PR concurrency-isolated, and every failure mode (skip, docs-only, install/build failure, infra error, cancel) publishes an explicit comment instead of silence, so a bad first run is visible and contained. The loopback-proxy/agent machinery is duplicated from the tmux job rather than extracted; a shared-steps refactor is a deliberate follow-up to keep this change additive.
  • Not validated / out of scope: live ECS/container execution; screenshot publishing to pr-assets (v1 ships text + run artifacts); the adjacent pre-existing gap that the tmux job's *-tmux-* artifact collection can likewise be spoofed by PR-committed directories — same attack class fixed here for verify, left for a separate PR on the tmux side.
  • Breaking changes / migration notes: none; purely additive (new comment command, new skill, one new recommendation sentence in the triage skill).

Linked Issues

The methodology this encodes is the hand-run deep-verification style used on recent PRs (e.g. the round-3 verification comment on #7586). No issues closed.

中文说明

本 PR 做了什么

为 triage workflow 增加一条按需触发的深度验证车道:在 PR 上评论 @qwen-code /verify,即可对该 PR 的真实构建执行一轮维护者级别的证据验证——与 base 侧的 A/B load-bearing 对照、新增测试的空测检查、无 mock 的 wire-oracle harness、以及受影响 workspace 的定向门禁——并把报告以单条评论("运行中"状态 → 最终报告原位升级)发回 PR。报告明确定位为供人类评审者参考的证据:它永远不是 review、不是批准、也不是 CI 检查。

具体实现:qwen-triage.yml 新增两个 job(verify 在与现有 /tmux 完全相同的隔离契约下执行 PR 代码——容器、agent 环境无任何 GitHub token、模型 key 藏在只放行 POST /chat/completions 的 loopback 代理后、要求 PR 作者(其代码被执行)评论者(其消耗稀缺 runner 与模型预算)双方都具有写权限;publish-verify 在干净的 hosted runner 上发布报告,绝不 checkout PR 代码),加上一个新的 verify-pr skill 固化方法论与产物契约,以及 Stage 2c 的更新,使静态 triage agent 在 PR 的核心声明需要行为证据时主动推荐 /verify

内置的安全加固:agent 的 skill 通过 git archive HEAD^1 从 base 分支 pin 取,被测代码树无法改写自己的验证器;checkout 后立即删除 PR 预埋的 tmp/*-verify-* 目录,杜绝伪造报告被产物收集器发布;持久 self-hosted workspace 沿用 triage job 的 git exec-vector 清扫(config 白名单 + hook 清除);agent 写出的 verdict 经白名单(merge-ready|findings|blocked|inconclusive)过滤后才进入 workflow 输出。

第二个提交把近期手工验证轮次(#7632 第 2 轮、#7656)的模式固化进车道:重复触发 /verify 即为后续轮次——resolve 步骤在覆盖前快照上一份报告,skill 在新 head 上逐项复核既往发现(已修复/仍存在/已被取代);harness 优先使用配置级 seam(baseUrl、环境变量)而非模块拦截,且伪造对端需编码上游的真实语义;多 commit PR 逐 commit 出 load-bearing 表;workflow/CI 类 PR 用真实数据回放内嵌脚本、跑仓库自身 lint 门禁、并用真实事件历史做上线首日成本测算;阻断级发现需枚举影响面并附保持原提交意图的最小修复建议(折叠展示)。

第三个提交增加图片证据能力,借鉴带图 PR 与验证轮次(#7265#7471#7686 第 2 轮)的版式与托管惯例:agent 可产出 evidence/*.png(kebab-case 文件名即绑定断言的图注;优先 before/after 成对),publish-verify 将其托管到 pr-assets 分支 verify/pr<N>-<run>-<attempt>/ 目录并在转义报告下方渲染。全程按不可信载荷处理:严格文件名白名单、8 张 / 单张 2 MB 上限、竞争推送重试、托管失败一律降级为纯文本评论。同时固化 #7686 第 2 轮的量化验证规则:后续轮次以既往发现状态表开篇并重新测量(而非对比旧报告);体积/性能类声明用带 Δ 列的实测指标表且残差必须解释;默认配置下不可达的分支要构造出能触达它的配置;防御性 guard 的接受路径要用真实生产产物验证,而非只测被 mock 的拒绝路径。

为什么需要

triage agent 在设计上只做静态分析——其环境携带写权限 PAT,绝不能执行 PR 代码,测试证据只能来自读取 PR 自己的 CI。目前唯一的行为验证车道 /tmux 仅覆盖 TUI 表面和文本捕获。维护者现在完全靠手工产出深度验证轮次(对 base 的 A/B、wire oracle、load-bearing 证明——例如 #7586 上的第 3 轮验证)。本 PR 把这种证据风格变成 CI 里按需可得的能力,自带手工验证无需操心的隔离保证,并且不扩大现有审批面:verify 的 check-run 挂在 issue_comment 事件上,finalize workflow 的 event == "pull_request" 过滤在结构上将其排除在 CI 表格与延迟审批门禁之外。

评审验证方案

如何验证

静态/回放验证(均可本地复现):node scripts/lint.js --actionlint 与仓库配置的 yamllint 通过;从 YAML 抽出的、属于本车道的全部 13 个 run: 块(authorize、verify、publish-verify)通过 bash -nshellcheck -S warning(第三方 Linux 复现进一步覆盖了整个 workflow 的 29 个块);内嵌 loopback 代理 JS 通过 node --checkpublish-verify 脚本用 stub gh 在全部六种终态分支上真实执行过,含 </code></pre></details>@everyone<img onerror=…> 的报告内容在 <details><pre><code> 中保持完全实体转义;verdict 白名单拒绝注入串;assertions jq 把非数字 JSON 强制为 0;docs-only 判定 grep 用 GNU grep 语义在混合/纯文档/空文件列表上回放。

真实端到端运行(本地忠实复刻 CI job 的全部契约:#7547 的 merge-ref worktree、depth-2 父提交、.qwen 从本分支 pin、QWEN_VERIFY_CONTEXT 元数据快照、无凭证 gh、隔离 QWEN_HOME):agent(qwen3.8-max-preview)25 turns / API 3.5 分钟完成,产物契约全部满足,verdict merge-ready,318/318 断言。随后对数字做了对抗式审计:318 = 304 个真实 vitest 测试(23+68+213,日志核对)+ 13 个 A/B 断言 + 1 个空测检查;亲手复跑 agent 的 ab-harness.mjs 得到 13/13;回退 PR 修复后复跑同一 harness 精确变为 7/13(恰为 3 个 PR 侧断言 + 3 个 flip 断言失败),恢复后回到 13/13——证明 A/B 真实感知修复而非同文件自比。agent 全程 0 次 gh 调用。把真实产物喂给真正的 publish-verify 脚本,渲染出 CI 将要发布的 4.7 KB 评论。

证据(Before & After)

见英文部分的 harness 复跑与变异测试输出,以及发布渲染的评论头部。

测试平台

macOS ✅;Windows N/A;Linux:静态与回放层 ✅——YAML 解析、36/36 workflow 测试、29 个抽取的 run: 块过 bash -n、两处代理 heredoc 过 node --check、verdict 白名单回放,均已由第三方在 c25afbd8独立复现且零失败;实际运行层仍 ⚠️(workflow 尚未在真实 Actions runner 上带 secret 执行,这部分在合并前无法由任何复现覆盖)。

环境

macOS 15 / Node 22 / qwen CLI 0.20.1;agent 模型 qwen3.8-max-preview(DashScope);验证 worktree 用 PR lockfile 真实 npm ci + npm run build 构建。

风险与范围

  • 主要风险/权衡:workflow job 本身尚未在真实 Actions runner 上跑过(上表 Linux 行:静态/回放层已被第三方独立复现,实际运行层尚未)——该车道为评论触发的 opt-in、按 PR 并发隔离,且所有失败模式(skip、纯文档、安装/构建失败、infra 错误、取消)都会发布显式评论而非沉默,首次运行即使出问题也可见且可控。loopback 代理/agent 机制从 tmux job 复制而未抽取公共步骤——为保持本次改动纯增量,共享步骤重构留作后续。
  • 未验证/范围外:真实 ECS/容器执行;截图发布到 pr-assets(v1 只有文本 + run artifacts);相邻的既有缺口——tmux job 的 *-tmux-* 产物收集同样可被 PR 预埋目录伪造(与本 PR 为 verify 修复的是同一攻击类),留待 tmux 侧单独 PR。
  • 破坏性变更/迁移说明:无;纯增量(新评论命令、新 skill、triage skill 一句推荐语)。

关联 Issue

本 PR 固化的方法论即近期 PR 上手工执行的深度验证风格(如 #7586 的第 3 轮验证评论)。不关闭任何 issue。

@qwen-code /verify on a PR now runs a local-verification-style evidence
round in the isolated /tmux sandbox contract (container, token-free agent
env, loopback model proxy, author-write gate) and publishes the report via
a separate PR-code-free job:

- new verify job: merge-ref checkout at depth 2 (base tip + PR head for
  A/B), skills pinned from base so the tree under test can never rewrite
  its own verifier, PR-planted tmp/*-verify-* artifacts dropped, git
  exec-vector sweep for the persistent workspace, agent verdict
  allowlisted before it reaches workflow outputs
- new publish-verify job: upserts one marker comment (running status ->
  final report), HTML-escapes the untrusted report, reports skip/na/
  prepare-fail/infra outcomes explicitly since /verify is always an
  explicit request
- new verify-pr skill: A/B load-bearing proof, vacuity check on new
  tests, mock-free wire-oracle harnesses, targeted gates, fixed report/
  verdict/assertions artifact contract, counts-are-sacred rules
- triage skill Stage 2c now names /verify (not just /tmux) as the trigger
  to recommend when a PR's central claim needs behavioral evidence

The verify check-runs ride the issue_comment event, which the finalize
workflow's event == "pull_request" universe structurally excludes, so
they cannot pollute the CI table or the deferred-approval gate.
@qwen-code-ci-bot

qwen-code-ci-bot commented Jul 25, 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

qwen-code-ci-bot commented Jul 25, 2026

Copy link
Copy Markdown
Collaborator

Thanks for the PR!

Template looks good ✓

Problem: this is a feature addition, not a bug fix — the "problem" is an observed workflow gap. Maintainers currently produce deep verification rounds (A/B against base, wire oracles, load-bearing proofs) entirely by hand (referenced #7586 round 3, #7632, #7656, #7686). The triage agent is static-only by design (its env carries a write PAT), and the only behavioral lane today (/tmux) is scoped to TUI surfaces. The gap is real and well-evidenced by the hand-run rounds this PR encodes.

Direction: aligned. This is CI/triage infrastructure — squarely within the project's scope. It's purely additive (new comment command, new skill, one recommendation sentence in the triage skill). Doesn't touch auth, sandbox, model selection, telemetry, release, or public contract. The verify check-runs ride the issue_comment event, which the finalize workflow's event == "pull_request" filter structurally excludes from the CI table and deferred-approval gate — so no widening of the approval surface.

Size: no core paths touched (packages/core/src/** etc.). Production logic: ~2,091 lines (workflow YAML 1,685 + skill 386 + pr-workflow.md 20). Test: 1,638 lines. The 1,000+ large-PR advisory applies — this is a substantial change, but the scope is proportionate: two new CI jobs with extensive security hardening (it executes untrusted PR code), a methodology skill, and comprehensive tests. Not blocking.

Approach: the scope feels right for what it's doing. The security hardening is extensive but justified — case-insensitive command matching, ephemeral proxy port with nonce + bearer auth, re-pinning the verifier after PR lifecycle scripts, symlink-safe cleanup, HEAD movement detection, verdict allowlisting, HTML escaping with size capping. The duplication with the tmux job's loopback-proxy machinery is acknowledged as a deliberate follow-up to keep this additive — reasonable. The three commits fold in patterns from hand-run rounds (follow-up rounds, image evidence, quantified verification rules), each earning its place.

Moving on to code review. 🔍

中文说明

感谢贡献!

模板完整 ✓

问题:这是一个功能新增,而非 bug 修复——"问题"是一个已观测到的工作流缺口。维护者目前完全靠手工产出深度验证轮次(对 base 的 A/B、wire oracle、load-bearing 证明——引用了 #7586 第 3 轮、#7632#7656#7686)。triage agent 在设计上只做静态分析(其环境携带写权限 PAT),目前唯一的行为验证车道 /tmux 仅覆盖 TUI 表面。缺口真实存在,本 PR 编码的手工验证轮次即是证据。

方向:对齐。这是 CI/triage 基础设施——完全在项目范围内。纯增量改动(新评论命令、新 skill、triage skill 中一句推荐语)。不触及 auth、sandbox、模型选择、遥测、发布或公共契约。verify 的 check-run 挂在 issue_comment 事件上,finalize workflow 的 event == "pull_request" 过滤在结构上将其排除在 CI 表格与延迟审批门禁之外——不扩大审批面。

规模:未触及核心路径。生产逻辑约 2,091 行(workflow YAML 1,685 + skill 386 + pr-workflow.md 20),测试 1,638 行。触发 1,000+ 大 PR 建议——改动量大,但范围与目标相称:两个新 CI job 带大量安全加固(执行不可信 PR 代码)、一个方法论 skill、以及全面的测试。不阻断。

方案:范围与目标相称。安全加固广泛但有正当理由——大小写不敏感的命令匹配、临时端口代理 + nonce + bearer 认证、PR 生命周期脚本后重新 pin 验证器、符号链接安全的清理、HEAD 移动检测、verdict 白名单、HTML 转义与尺寸上限。与 tmux job 的 loopback-proxy 机制的重复被明确标注为后续重构——合理。三个提交分别固化了手工验证轮次的模式(后续轮次、图片证据、量化验证规则),各有其价值。

进入代码审查 🔍

Qwen Code · qwen3.8-max-preview

Reviewed at 218aa08c3d7e933bfe7a58888efe356b23a29b0b · re-run with @qwen-code /triage

@qwen-code-ci-bot

qwen-code-ci-bot commented Jul 25, 2026

Copy link
Copy Markdown
Collaborator

Code review

Independent proposal: for a sandboxed deep-verification lane, I would add two jobs to qwen-triage.yml — one that executes the PR in a container with no GitHub token (model key behind a loopback proxy), and one that publishes the report from a clean hosted runner. Gate on both the PR author (whose code runs) and the commenter (who spends budget). Pin the verifier skill from the base branch so the PR can't rewrite its own verifier. Add a skill file encoding the methodology, and tests that execute the embedded shell scripts with a stubbed gh.

Comparison: the PR matches and substantially exceeds this baseline. The security hardening goes well beyond what I would have proposed in a first pass — ephemeral proxy port with nonce identity + bearer auth, re-pinning the verifier after PR lifecycle scripts run (not just before checkout), killing leftover build processes before agent start, symlink-safe cleanup paths, worktree-scoped git config neutralization, HEAD movement detection between authorization and execution, verdict allowlisting, HTML escaping applied before size capping. Each of these addresses a concrete attack vector the PR documents in comments. The test suite (1,638 lines) executes the shell scripts rather than substring-matching them — the authorize gate is replayed with a stubbed gh across multiple principal combinations, the docs-only classifier handles a 60k-entry file list, the publish script's escaping is exercised with hostile content, and the image hosting path runs end-to-end against a bare git remote.

No critical blockers found. No AGENTS.md violations. The duplication with the tmux job's loopback-proxy machinery is acknowledged as a deliberate follow-up — reasonable for an additive change. Comments throughout explain why (the attack vector, the race condition, the failure mode), not what.

Files changed (4 of 4)
File What changed
.github/workflows/qwen-triage.yml Two new jobs (verify, publish-verify) plus authorize-job extensions for /verify gating, acknowledgement, and denial explanations
.qwen/skills/verify-pr/SKILL.md New skill encoding the deep-verification methodology — A/B load-bearing proof, vacuity checks, wire-oracle harnesses, targeted gates, artifact contract
.qwen/skills/triage/references/pr-workflow.md Stage 2c updated to recommend /verify alongside /tmux when a PR's central claim needs behavioral evidence, with write-access caveats
scripts/tests/qwen-triage-workflow.test.js 1,638 lines of new tests — executes embedded shell scripts with stubbed gh, covers authorize gate, case-insensitive matching, docs-only classifier, publish escaping, image hosting, upsert logic

CI test evidence

All checks completed on the reviewed commit — no failures, no pending runs.

Check Conclusion
Test (ubuntu-latest, Node 22.x) ✅ success
web-shell E2E Smoke (ubuntu-latest, Node 22.x) ✅ success
Post Coverage Comment (ubuntu-latest, 22.x) ✅ success
review-pr ✅ success
Classify PR ✅ success
authorize ✅ success
label ✅ success
Remind on force-push ✅ success
route ✅ success
remove-suspicious-attachments ✅ success
Test (macos-latest, Node 22.x) ⏭️ skipped
Test (windows-latest, Node 22.x) ⏭️ skipped
Integration Tests (CLI, No Sandbox) ⏭️ skipped

macOS/Windows tests and integration tests are skipped — expected for a workflow/skill/test-only change that doesn't touch the CLI runtime.

Real-scenario testing

N/A — this PR changes CI workflow YAML, a skill file, and workflow tests. There is no user-visible CLI behavior change; the /verify command is a CI comment trigger, not a CLI feature.

中文说明

代码审查

独立方案: 对于沙箱深度验证车道,我会在 qwen-triage.yml 中新增两个 job——一个在无 GitHub token 的容器中执行 PR(模型 key 藏在 loopback 代理后),一个在干净的 hosted runner 上发布报告。对 PR 作者(其代码被执行)和评论者(其消耗预算)双方做权限门禁。从 base 分支 pin 验证器 skill,使 PR 无法改写自己的验证器。新增一个方法论 skill 文件,以及用 stub gh 执行内嵌 shell 脚本的测试。

对比: PR 与独立方案吻合,并大幅超出。安全加固远超首次提案——临时端口代理 + nonce 身份 + bearer 认证、PR 生命周期脚本后重新 pin 验证器、agent 启动前杀死残留构建进程、符号链接安全的清理路径、worktree 级 git config 中和、授权与执行间的 HEAD 移动检测、verdict 白名单、HTML 转义在尺寸上限之前应用。每一项都针对 PR 注释中记录的具体攻击向量。测试套件(1,638 行)执行 shell 脚本而非子串匹配——authorize 门禁用 stub gh 在多种 principal 组合下回放,docs-only 分类器处理 60k 条目文件列表,发布脚本的转义用恶意内容验证,图片托管路径对 bare git remote 做端到端测试。

未发现关键阻断项。无 AGENTS.md 违规。与 tmux job 的 loopback-proxy 机制的重复被明确标注为后续重构——对增量改动合理。注释全程解释"为什么"(攻击向量、竞态条件、故障模式),而非"做什么"。

CI 测试证据

所有检查在受审提交上已完成——无失败、无待处理运行。macOS/Windows 测试和集成测试被跳过——对仅改动 workflow/skill/测试的 PR 属预期行为。

真实场景测试

不适用——本 PR 改动 CI workflow YAML、skill 文件和 workflow 测试。无用户可见的 CLI 行为变更;/verify 是 CI 评论触发器,不是 CLI 功能。

Qwen Code · qwen3.8-max-preview

Reviewed at 218aa08c3d7e933bfe7a58888efe356b23a29b0b · re-run with @qwen-code /triage

…hods

Fold two more hand-verification patterns into the verify lane:

- round continuity: the resolve step snapshots the previous verify report
  (if any) into the agent context before the status upsert overwrites it,
  and the skill re-checks each prior finding at the new head
  (fixed/stands/superseded), scoping new probes to the delta
- harness quality: prefer configuration seams over module interception,
  encode the upstream's real semantics in the fake peer, add decoy targets
- artifact-matched methods: per-commit load-bearing tables for multi-commit
  PRs; workflow/CI PRs get embedded-script replay against real data, repo
  lint gates, and day-one trigger cost math from real event history; every
  new config knob must trace to an observable effect, and default-path
  dispatch combinations get probed
- findings quality: blockers enumerate blast radius, demonstrate the
  sharpest consequence end-to-end when budget allows, and carry a collapsed
  minimal suggested fix preserving the original commit's intent
@qwen-code-ci-bot

qwen-code-ci-bot commented Jul 25, 2026

Copy link
Copy Markdown
Collaborator

Confidence: 4/5 — solid, well-hardened implementation; the live CI path hasn't run yet but every failure mode publishes an explicit comment, so a bad first run is visible and contained.

This PR does one thing — makes maintainer-grade deep verification available on demand in CI — and does it thoroughly. The security model is the standout: it treats every boundary as hostile (PR lifecycle scripts, PR-committed artifact dirs, the agent's own verdict file, the report content, evidence images) and defends each with a specific, documented mechanism rather than a blanket "sandbox" hand-wave. The test suite executes the embedded shell scripts rather than pattern-matching them, which is the right discipline for workflow code where the shell IS the product.

The independent proposal I wrote before reading the diff covered the same two-job split and base-pinning, but the PR's hardening goes significantly deeper — ephemeral proxy port with nonce + bearer, re-pinning after lifecycle scripts, symlink-safe cleanup, HEAD movement detection. Each addresses a concrete attack I didn't think of, and the comments say so.

Non-blocking nits: the loopback-proxy duplication with the tmux job will want a shared-steps refactor (acknowledged as a follow-up), and the live Actions runner path is untested by definition until merge — but the lane is opt-in, per-PR concurrency-isolated, and every failure mode (skip, docs-only, install/build failure, infra error, cancel) publishes an explicit comment instead of silence.

Approving. ✅

中文说明

置信度:4/5 —— 实现扎实、加固到位;实际 CI 路径尚未运行过,但每种故障模式都会发布明确评论,因此首次运行出问题也是可见且可控的。

本 PR 只做一件事——让维护者级深度验证在 CI 中按需可得——而且做得彻底。安全模型是亮点:它将每条边界都视为敌对的(PR 生命周期脚本、PR 预埋的产物目录、agent 自身的 verdict 文件、报告内容、证据图片),并用具体的、有文档记录的机制逐一防御,而非笼统地一句"沙箱"带过。测试套件执行内嵌 shell 脚本而非模式匹配——对于 shell 即产品的 workflow 代码,这是正确的纪律。

独立方案覆盖了相同的两 job 拆分和 base pinning,但 PR 的加固显著更深——临时端口代理 + nonce + bearer、生命周期脚本后重新 pin、符号链接安全的清理、HEAD 移动检测。每一项都针对我没想到的具体攻击,且注释说明了原因。

非阻断建议:与 tmux job 的 loopback-proxy 重复后续需要共享步骤重构(已标注为后续),实际 Actions runner 路径在合并前按定义无法测试——但车道是按需触发、按 PR 并发隔离的,且每种故障模式都发布明确评论而非沉默。

批准。✅

Qwen Code · qwen3.8-max-preview

Reviewed at 218aa08c3d7e933bfe7a58888efe356b23a29b0b · re-run with @qwen-code /triage

@github-actions

github-actions Bot commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Summary

Package Lines Statements Functions Branches
CLI 83.05% 83.05% 89.08% 82.31%
Core 87.11% 87.11% 88.69% 85.94%
CLI Package - Full Text Report
-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |   83.05 |    82.31 |   89.08 |   83.05 |                   
 src               |   84.12 |    80.67 |   88.88 |   84.12 |                   
  cli.ts           |   94.54 |    84.07 |     100 |   94.54 | ...86-487,497-498 
  gemini.tsx       |   73.89 |    76.49 |    82.6 |   73.89 | ...1183-1187,1308 
  ...ractiveCli.ts |   85.02 |    80.82 |   86.84 |   85.02 | ...2363,2369,2421 
  ...liCommands.ts |   88.34 |     83.6 |      90 |   88.34 | ...63,480,514,635 
  ...ActiveAuth.ts |     100 |     87.5 |     100 |     100 | 66-80             
 ...cp-integration |   68.37 |    71.09 |   88.97 |   68.37 |                   
  acpAgent.ts      |   67.99 |    70.91 |   88.98 |   67.99 | ...31,10736-10738 
  authMethods.ts   |      92 |       60 |     100 |      92 | 33-34             
  errorCodes.ts    |       0 |        0 |       0 |       0 | 1-22              
  ...ion-skills.ts |     100 |    88.23 |     100 |     100 | 17,32             
  generation.ts    |    97.1 |    81.25 |     100 |    97.1 | 109,112           
  ...DirContext.ts |     100 |      100 |     100 |     100 |                   
 ...ration/service |   97.04 |    95.71 |   93.33 |   97.04 |                   
  filesystem.ts    |   97.04 |    95.71 |   93.33 |   97.04 | ...21-122,238-239 
 ...ration/session |   91.65 |    85.67 |   95.97 |   91.65 |                   
  Session.ts       |   91.23 |    84.45 |   95.23 |   91.23 | ...8482,8509-8513 
  ...entTracker.ts |   91.87 |    89.18 |   88.88 |   91.87 | ...33,197,280-289 
  ...stop-guard.ts |     100 |    97.08 |     100 |     100 | 37,127,247        
  ...eplay-page.ts |   92.27 |    88.09 |     100 |   92.27 | ...83,108-118,121 
  ...y-replayer.ts |    98.5 |    95.38 |     100 |    98.5 | 229-231           
  index.ts         |       0 |        0 |       0 |       0 | 1-40              
  ...ssionUtils.ts |   89.76 |    86.76 |     100 |   89.76 | ...54-270,326-328 
  tasksSnapshot.ts |   94.26 |     87.5 |     100 |   94.26 | 65-71             
  ...on-tracker.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...ssion/emitters |   95.68 |     93.7 |   96.66 |   95.68 |                   
  ...ageEmitter.ts |   95.34 |    94.11 |     100 |   95.34 | 52-59             
  PlanEmitter.ts   |     100 |    83.33 |     100 |     100 | 59                
  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.17 |    97.43 |     100 |   99.17 | 352-353           
 ...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/commands      |   88.97 |    73.18 |   64.51 |   88.97 |                   
  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        |   97.87 |      100 |      50 |   97.87 | 58                
  serve.ts         |   86.85 |     67.3 |     100 |   86.85 | ...32-635,649-653 
  sessions.ts      |     100 |      100 |      50 |     100 |                   
  update.ts        |   98.13 |    94.44 |   66.66 |   98.13 | 82-83             
 ...mmands/channel |   86.92 |    87.05 |   90.44 |   86.92 |                   
  channel-cwd.ts   |     100 |      100 |     100 |     100 |                   
  ...l-registry.ts |   79.66 |    84.61 |      80 |   79.66 | 36-39,48-51,62-65 
  ...entry-path.ts |      75 |       50 |     100 |      75 | 8-9               
  config-utils.ts  |   95.87 |    96.35 |     100 |   95.87 | ...08-213,271-274 
  configure.ts     |    14.7 |      100 |       0 |    14.7 | 18-21,23-84       
  daemon-worker.ts |    94.2 |    85.09 |   97.82 |    94.2 | ...1155,1162-1163 
  loop-runtime.ts  |   91.66 |      100 |      50 |   91.66 | 15,22             
  ...classifier.ts |   98.49 |    96.51 |     100 |   98.49 | 115-116,161       
  ...tact-store.ts |   93.51 |    87.65 |     100 |   93.51 | ...71,288-289,337 
  pairing.ts       |   72.85 |      100 |      50 |   72.85 | 22-28,57-68       
  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       |   81.42 |    87.71 |     100 |   81.42 | ...70-174,234-236 
  set.ts           |   75.72 |    85.71 |      50 |   75.72 | 65-83,111-116     
  start.ts         |   75.05 |    73.17 |   76.92 |   75.05 | ...31,537-540,552 
  ...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.82 |    87.64 |   87.09 |   88.82 |                   
  consent.ts       |   72.53 |       90 |   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 |     87.5 |     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 |    53.84 |     100 |      75 | ...27-131,133-137 
 ...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.17 |    84.39 |   83.33 |   90.17 |                   
  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          |   92.59 |    83.87 |      80 |   92.59 | ...62-164,180-181 
  reconnect.ts     |   78.85 |    66.66 |   85.71 |   78.85 | 42-55,169-191     
  remove.ts        |     100 |       80 |     100 |     100 | 21-25             
 ...ommands/review |   84.43 |    86.64 |   83.78 |   84.43 |                   
  agent-prompt.ts  |   90.88 |    92.78 |      96 |   90.88 | ...1256,1726-1795 
  capture-local.ts |   72.16 |     90.9 |      75 |   72.16 | 101-105,152-174   
  ...k-coverage.ts |   48.38 |    14.28 |   66.66 |   48.38 | ...21-226,239-249 
  cleanup.ts       |   87.36 |    82.35 |   83.33 |   87.36 | ...77-482,484-485 
  ...ent-status.ts |   93.03 |    83.87 |   83.33 |   93.03 | 291,531-551       
  ...ose-review.ts |   95.42 |    92.13 |   91.66 |   95.42 | ...1099,1127-1143 
  fetch-pr.ts      |   73.26 |    53.57 |      50 |   73.26 | ...93,327,396-401 
  load-rules.ts    |   26.41 |      100 |   16.66 |   26.41 | ...41-153,155-156 
  parse-args.ts    |   99.25 |       96 |     100 |   99.25 | 341,413           
  plan-diff.ts     |    67.9 |      100 |   66.66 |    67.9 | 121-148           
  pr-context.ts    |   84.44 |    79.38 |   91.66 |   84.44 | ...29-910,939-941 
  presubmit.ts     |   83.75 |    92.72 |   88.88 |   83.75 | ...77-578,655-685 
  ...ve-anchors.ts |   77.02 |    88.46 |      75 |   77.02 | ...70-175,187-204 
  submit.ts        |   76.67 |    82.05 |   81.81 |   76.67 | ...99-635,637-638 
  test-efficacy.ts |   80.68 |    69.41 |    92.3 |   80.68 | ...93-594,602-622 
 ...nds/review/lib |   95.49 |    92.87 |   94.16 |   95.49 |                   
  agent-briefs.ts  |   98.68 |      100 |       0 |   98.68 | 493-494           
  anchors.ts       |     100 |    94.79 |     100 |     100 | ...33,169,178,225 
  coverage.ts      |   95.37 |    94.08 |   95.45 |   95.37 | ...98,335,429-446 
  diff-flags.ts    |     100 |        0 |     100 |     100 | 63                
  diff-plan.ts     |   98.73 |    93.01 |     100 |   98.73 | ...41,264,290-291 
  gh.ts            |   84.09 |     87.5 |   64.28 |   84.09 | ...20,257-258,285 
  git.ts           |   97.64 |    95.65 |     100 |   97.64 | 180-181           
  heavy.ts         |     100 |      100 |     100 |     100 |                   
  inline-counts.ts |     100 |      100 |     100 |     100 |                   
  local-diff.ts    |    84.4 |    88.46 |     100 |    84.4 | ...63-473,475-483 
  merge-base.ts    |     100 |      100 |     100 |     100 |                   
  path-rules.ts    |     100 |      100 |     100 |     100 |                   
  paths.ts         |    92.3 |    83.33 |   83.33 |    92.3 | 76-77             
  prompt-record.ts |   94.73 |    88.23 |     100 |   94.73 | ...28,151-152,156 
  receipt.ts       |     100 |      100 |     100 |     100 |                   
  report.ts        |   94.38 |    93.75 |     100 |   94.38 | 173-177           
  roster.ts        |     100 |    92.85 |     100 |     100 | 104,118,163       
  shell-quote.ts   |     100 |      100 |     100 |     100 |                   
  transcripts.ts   |   96.27 |    93.18 |     100 |   96.27 | ...83,269-270,294 
  workspaces.ts    |   97.76 |     91.3 |     100 |   97.76 | 186-187,212-213   
 ...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.14 |     88.7 |    95.9 |   94.14 |                   
  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        |   88.26 |    88.14 |   84.84 |   88.26 | ...2363,2365-2373 
  ...cy-monitor.ts |   88.75 |    76.19 |     100 |   88.75 | ...3,90-92,98,101 
  ...ust-policy.ts |   83.04 |    88.28 |     100 |   83.04 | ...39,253,352-353 
  ...heme-names.ts |     100 |      100 |     100 |     100 |                   
  environment.ts   |   94.33 |    89.61 |   94.73 |   94.33 | ...35-639,655-656 
  ...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.74 |     100 |     100 | 47,160,220        
  keyBindings.ts   |   97.38 |       50 |     100 |   97.38 | 234-237           
  ...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.65 |     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 |   61.64 |    71.87 |   66.66 |   61.64 | ...54-68,73,77-89 
  ...ings-cache.ts |   96.52 |    93.93 |     100 |   96.52 | 90-91,201-202     
  settings.ts      |   90.74 |    92.02 |   89.65 |   90.74 | ...72,974,976-977 
  ...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 
  ...tedFolders.ts |    93.4 |     94.4 |     100 |    93.4 | ...93-394,430-441 
 ...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    |    71.8 |    70.31 |   66.66 |    71.8 |                   
  ...tputBridge.ts |   71.95 |    70.96 |   68.42 |   71.95 | ...08-409,417-420 
  ...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/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 |    76.31 |   81.35 |      80 |                   
  session.ts       |   84.08 |    75.27 |   93.61 |   84.08 | ...1007,1016-1026 
  types.ts         |    42.5 |      100 |   33.33 |    42.5 | ...24-625,628-629 
 ...active/control |   76.11 |    89.09 |      80 |   76.11 |                   
  ...rolContext.ts |    6.45 |        0 |       0 |    6.45 | 56-95             
  ...Dispatcher.ts |   91.79 |    92.45 |   88.88 |   91.79 | ...49-367,387,390 
  ...rolService.ts |     7.4 |        0 |       0 |     7.4 | 46-185            
 ...ol/controllers |   39.78 |    63.24 |   47.22 |   39.78 |                   
  ...Controller.ts |   39.49 |      100 |      80 |   39.49 | 88-92,127-210     
  ...Controller.ts |       0 |        0 |       0 |       0 | 1-56              
  ...Controller.ts |   49.11 |    62.96 |   54.54 |   49.11 | ...63-568,570-575 
  ...Controller.ts |   14.06 |      100 |       0 |   14.06 | ...82-117,130-133 
  ...Controller.ts |   37.92 |    60.71 |   46.66 |   37.92 | ...41-653,662-691 
 .../control/types |       0 |        0 |       0 |       0 |                   
  serviceAPIs.ts   |       0 |        0 |       0 |       0 | 1                 
 ...Interactive/io |   98.14 |     94.4 |   95.23 |   98.14 |                   
  ...putAdapter.ts |   98.09 |    93.65 |   98.07 |   98.09 | ...1319,1422-1423 
  ...putAdapter.ts |      96 |    91.66 |   85.71 |      96 | 51-52             
  ...nputReader.ts |     100 |    94.73 |     100 |     100 | 67                
  ...putAdapter.ts |   98.38 |      100 |   90.47 |   98.38 | 84-85,125-126     
  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/serve         |   87.47 |    83.48 |      91 |   87.47 |                   
  ...tp-enabled.ts |     100 |      100 |     100 |     100 |                   
  ...ion-bridge.ts |     100 |      100 |     100 |     100 |                   
  auth.ts          |    93.4 |    92.95 |     100 |    93.4 | ...19-320,323-325 
  ...em-adapter.ts |     100 |      100 |     100 |     100 |                   
  capabilities.ts  |     100 |    97.87 |     100 |     100 | 628               
  ...cp-command.ts |     100 |      100 |     100 |     100 |                   
  ...horization.ts |   92.79 |    93.33 |    87.5 |   92.79 | 75-80,135-136     
  ...livery-ipc.ts |     100 |     90.9 |     100 |     100 | 94,106,134        
  ...l-delivery.ts |     100 |      100 |     100 |     100 |                   
  ...nt-service.ts |   93.65 |    86.02 |     100 |   93.65 | ...52-454,461,463 
  ...-selection.ts |     100 |      100 |     100 |     100 |                   
  ...ings-store.ts |   85.85 |    91.78 |   95.83 |   85.85 | ...94-206,366-369 
  ...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 |   91.42 |    86.72 |     100 |   91.42 | ...26,732-736,748 
  ...er-manager.ts |   89.39 |    83.88 |   93.33 |   89.39 | ...98,711,722-724 
  ...tartup-ipc.ts |   97.72 |    96.66 |     100 |   97.72 | 88-89             
  ...supervisor.ts |   96.49 |    86.37 |   96.72 |   96.49 | ...1253,1307-1311 
  ...e-grouping.ts |     100 |    94.11 |     100 |     100 | 69,132            
  core-runtime.ts  |     100 |      100 |     100 |     100 |                   
  ...ub-session.ts |   92.04 |    77.77 |     100 |   92.04 | ...36-445,470,508 
  daemon-logger.ts |    82.2 |    77.26 |   91.76 |    82.2 | ...1720,1747-1753 
  ...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.37 |    90.06 |     100 |   98.37 | ...1041,1043-1044 
  debug-mode.ts    |     100 |      100 |     100 |     100 |                   
  demo.ts          |     100 |      100 |     100 |     100 |                   
  env-snapshot.ts  |    91.3 |       80 |     100 |    91.3 | ...24-127,205-212 
  ...-scheduler.ts |   87.34 |    83.87 |     100 |   87.34 | 33-36,48-50,79-81 
  ...-path-argv.ts |     100 |      100 |     100 |     100 |                   
  ...h-settings.ts |   94.41 |    88.75 |     100 |   94.41 | ...24,702,718,728 
  fast-path.ts     |   90.33 |    80.23 |   95.45 |   90.33 | ...83-492,558-559 
  ...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-143             
  ...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 | ...27-128,139-140 
  ...iders-edit.ts |     100 |    82.14 |     100 |     100 | 58-60,65,81       
  ...sion-audit.ts |     100 |      100 |   93.33 |     100 |                   
  rate-limit.ts    |   92.77 |    88.42 |     100 |   92.77 | ...93-295,307-309 
  ...qwen-serve.ts |   82.37 |    79.09 |   73.76 |   82.37 | ...6603,6608-6609 
  ...tup-errors.ts |     100 |      100 |     100 |     100 |                   
  ...-keepalive.ts |   95.04 |    88.77 |     100 |   95.04 | ...07,511-512,552 
  ...-lifecycle.ts |     100 |      100 |     100 |     100 |                   
  server.ts        |   93.93 |    93.52 |      75 |   93.93 | ...2044,2065-2069 
  ...on-helpers.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 |                   
  ...erver-name.ts |     100 |      100 |     100 |     100 |                   
  ...ion-limits.ts |     100 |      100 |     100 |     100 |                   
  ...t-sessions.ts |   93.34 |    76.57 |     100 |   93.34 | ...17,820,833-835 
  ...l-resolver.ts |   90.32 |    66.66 |     100 |   90.32 | 16,45-46          
  ...ell-static.ts |   91.07 |    86.66 |     100 |   91.07 | ...79-182,216-219 
  ...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 |                   
  ...-constants.ts |     100 |      100 |     100 |     100 |                   
  ...-summaries.ts |   86.66 |       50 |     100 |   86.66 | 11,19             
  ...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 | ...17-518,524-525 
  ...ber-errors.ts |     100 |    95.32 |     100 |     100 | 53,93-94,172,192  
  ...e-remember.ts |   98.14 |    88.92 |     100 |   98.14 | ...31,335-340,381 
  ...te-runtime.ts |   82.62 |    88.88 |     100 |   82.62 | ...48-156,216-237 
  ...management.ts |   72.63 |    72.72 |      96 |   72.63 | ...88-889,896-900 
  ...ls-mapping.ts |     100 |      100 |     100 |     100 |                   
  ...lls-status.ts |     100 |    92.85 |     100 |     100 | 127               
  ...reconciler.ts |    91.6 |     83.9 |     100 |    91.6 | ...70-272,305-306 
 ...serve/acp-http |    76.7 |    77.99 |   93.04 |    76.7 |                   
  ...r-registry.ts |     100 |    95.45 |     100 |     100 | 191               
  client-mcp-ws.ts |   54.85 |    58.62 |   72.72 |   54.85 | ...99-300,304-305 
  ...n-registry.ts |    98.2 |    88.62 |     100 |    98.2 | 1015,1041-1052    
  dispatch.ts      |   71.11 |    73.69 |   95.23 |   71.11 | ...4685,4733-4739 
  index.ts         |   81.78 |    79.64 |   90.56 |   81.78 | ...2273,2343-2344 
  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 |   85.73 |    73.17 |    97.5 |   85.73 |                   
  ...r-emulator.ts |   88.57 |    63.63 |     100 |   88.57 | ...72-175,194-195 
  ...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 |       0 |        0 |       0 |       0 |                   
  ...mcp-smoke.mjs |       0 |        0 |       0 |       0 | 1-119             
  ...cceptance.mjs |       0 |        0 |       0 |       0 | 1-473             
  real-tab.mjs     |       0 |        0 |       0 |       0 | 1-218             
 src/serve/fs      |   85.64 |    78.41 |     100 |   85.64 |                   
  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 |     73.6 |     100 |   77.64 | ...65,594-598,611 
  policy.ts        |   90.32 |    89.18 |     100 |   90.32 | 142-150           
  ...ile-system.ts |   85.14 |    76.25 |     100 |   85.14 | ...2073,2083-2084 
 src/serve/routes  |   86.13 |    79.88 |   95.52 |   86.13 |                   
  a2ui-action.ts   |   96.84 |     88.5 |    87.5 |   96.84 | ...70-272,309-311 
  capabilities.ts  |     100 |      100 |     100 |     100 |                   
  ...nel-notify.ts |   85.22 |       88 |     100 |   85.22 | ...,83-87,103-104 
  ...l-webhooks.ts |   93.56 |    84.09 |     100 |   93.56 | ...42,292,332,334 
  daemon-status.ts |   85.45 |    83.33 |     100 |   85.45 | 98-105            
  goals.ts         |   98.92 |     90.9 |     100 |   98.92 | 146               
  health-demo.ts   |   94.73 |     86.2 |     100 |   94.73 | 62-66,154         
  permission.ts    |     100 |     92.3 |     100 |     100 | 50,98             
  ...uled-tasks.ts |   86.78 |     81.9 |   95.65 |   86.78 | ...1195,1238-1239 
  ...on-runtime.ts |     100 |    90.47 |     100 |     100 | 58,94             
  session.ts       |   86.27 |    81.47 |      95 |   86.27 | ...4295,4297-4298 
  sse-events.ts    |   84.45 |     87.5 |   77.77 |   84.45 | ...36,453-456,485 
  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 |   89.29 |    75.72 |     100 |   89.29 | ...91-392,411-412 
  ...d-contacts.ts |     100 |      100 |     100 |     100 |                   
  ...controller.ts |   83.41 |    78.89 |      90 |   83.41 | ...1024,1030,1033 
  ...extensions.ts |    87.2 |    72.76 |   94.11 |    87.2 | ...1822,1867-1868 
  ...-file-read.ts |   92.34 |    80.31 |     100 |   92.34 | ...96-597,600-601 
  ...file-write.ts |   84.44 |    64.51 |     100 |   84.44 | ...73-275,355-357 
  ...e-git-diff.ts |   97.32 |    90.56 |     100 |   97.32 | 161-162,189-191   
  ...ce-git-log.ts |     100 |    92.68 |     100 |     100 | 52,77,183         
  workspace-git.ts |   77.08 |    89.65 |     100 |   77.08 | 97-118            
  ...github-prs.ts |      97 |    91.66 |     100 |      97 | 133-135           
  ...-lifecycle.ts |   95.23 |    75.75 |     100 |   95.23 | ...50-151,186-187 
  ...management.ts |   87.81 |    85.11 |     100 |   87.81 | ...1491,1511-1516 
  ...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 |   74.81 |    70.31 |     100 |   74.81 | ...47-658,664-665 
  ...tup-github.ts |   77.97 |    70.58 |   84.21 |   77.97 | ...46-352,397-398 
  ...ace-skills.ts |   69.87 |    78.12 |     100 |   69.87 | ...59-284,290-324 
  ...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.42 |    64.78 |      80 |   78.42 | ...31-336,344-345 
  ...pace-voice.ts |   91.33 |    80.92 |     100 |   91.33 | ...70-673,676-678 
 src/serve/server  |   90.77 |    89.51 |   95.27 |   90.77 |                   
  access-log.ts    |   98.68 |     97.1 |     100 |   98.68 | 115,186           
  ...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 |   85.45 |    76.57 |     100 |   85.45 | ...93,710,773-782 
  fs-factory.ts    |     100 |    92.72 |     100 |     100 | 34,42,103,159     
  ...branch-ops.ts |     100 |      100 |     100 |     100 |                   
  ...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.11 |    95.14 |     100 |   95.11 | ...65-167,422-427 
  self-origin.ts   |   76.19 |       80 |     100 |   76.19 | 45-54             
  ...e-features.ts |   94.81 |    90.32 |     100 |   94.81 | 175-181           
  ...on-archive.ts |   89.61 |    90.56 |   88.23 |   89.61 | ...36-441,513-523 
  ...ion-export.ts |     100 |    94.44 |     100 |     100 | 64                
  session-list.ts  |   93.55 |    91.01 |     100 |   93.55 | ...79,681-687,827 
  telemetry.ts     |   99.01 |    97.44 |     100 |   99.01 | ...13,627,769-771 
 src/serve/voice   |   83.35 |    92.22 |   90.47 |   83.35 |                   
  ...ice-config.ts |   84.61 |       30 |     100 |   84.61 | 90-99,103-104     
  voice-ws.ts      |   77.16 |    94.73 |   83.33 |   77.16 | ...68,483,521-523 
  ...oordinator.ts |     100 |    98.21 |     100 |     100 | 176               
 ...kspace-service |    89.4 |    85.59 |      90 |    89.4 |                   
  index.ts         |   88.94 |    85.16 |   88.57 |   88.94 | ...1211-1215,1218 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/services      |   92.17 |    88.31 |   97.82 |   92.17 |                   
  ...mandLoader.ts |     100 |    88.88 |     100 |     100 | 104-117           
  ...killLoader.ts |   97.14 |    87.87 |     100 |   97.14 | 140,151-152       
  ...andService.ts |   98.73 |      100 |     100 |   98.73 | 107               
  ...mandLoader.ts |   86.83 |    83.87 |     100 |   86.83 | ...30-335,340-345 
  ...omptLoader.ts |   77.36 |    85.52 |   83.33 |   77.36 | ...43,168,210-211 
  ...mandLoader.ts |   97.36 |    92.68 |     100 |   97.36 | 153,160-161       
  ...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 |    93.75 |     100 |   96.66 | 34-35             
  ...tree-lease.ts |   88.29 |    86.11 |     100 |   88.29 | ...91-196,229-230 
  ...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.54 |    90.47 |    87.5 |   93.54 | 201-203,217-223   
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...e-keyterms.ts |   98.64 |    95.83 |     100 |   98.64 | 116,142-143       
  voice-model.ts   |     100 |      100 |     100 |     100 |                   
  voice-service.ts |   90.37 |    87.87 |     100 |   90.37 | ...80,287,352-357 
  ...e-settings.ts |     100 |    95.23 |     100 |     100 | 19                
  ...ranscriber.ts |   90.46 |    82.19 |      96 |   90.46 | ...66-668,671-673 
 ...rvices/insight |     100 |      100 |     100 |     100 |                   
  dates.ts         |     100 |      100 |     100 |     100 |                   
 ...ght/generators |   88.91 |    86.29 |   96.15 |   88.91 |                   
  DataProcessor.ts |   88.28 |    86.24 |   94.73 |   88.28 | ...1352,1356-1363 
  ...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 | 95-98             
  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.04 |    83.33 |      80 |   94.04 |                   
  ...omMatchers.ts |   69.69 |       50 |      50 |   69.69 | 32-35,37-39,45-47 
  ...andContext.ts |     100 |      100 |     100 |     100 |                   
  render.tsx       |     100 |      100 |     100 |     100 |                   
 src/ui            |   71.09 |    72.95 |   66.66 |   71.09 |                   
  App.tsx          |   33.33 |       75 |   33.33 |   33.33 | 32-86             
  AppContainer.tsx |   72.22 |    69.85 |   66.66 |   72.22 | ...4022,4026-4030 
  ...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.22 |     100 |   95.91 | 25-26             
  ...tic-colors.ts |     100 |      100 |     100 |     100 |                   
  ...ractiveUI.tsx |   62.73 |    47.22 |   66.66 |   62.73 | ...95-296,313-318 
  ...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.53 |    66.18 |   51.06 |   58.53 |                   
  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.6 |    73.52 |     100 |    94.6 | ...21-222,241-247 
  ...rSetupFlow.ts |   43.18 |    33.33 |      50 |   43.18 | ...78-399,416-459 
 src/ui/commands   |    81.4 |       83 |    89.4 |    81.4 |                   
  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.46 |    83.63 |     100 |   92.46 | ...4-69,94-99,178 
  clearCommand.ts  |    80.9 |    70.83 |     100 |    80.9 | ...24-125,133-142 
  ...essCommand.ts |   67.95 |    55.88 |      75 |   67.95 | ...86-187,201-204 
  ...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 |   68.28 |    70.14 |   84.61 |   68.28 | ...66-599,610-611 
  copyCommand.ts   |   98.46 |    95.78 |     100 |   98.46 | ...72,272,313,319 
  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 |   65.37 |    81.88 |   94.11 |   65.37 | ...85-535,538-672 
  dreamCommand.ts  |   85.45 |    88.88 |     100 |   85.45 | 58-65             
  editorCommand.ts |     100 |      100 |     100 |     100 |                   
  ...rt-command.ts |   82.97 |    78.57 |     100 |   82.97 | 47-52,67-70,91-96 
  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   |   91.13 |    83.72 |      90 |   91.13 | ...81-184,196-199 
  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 |   93.45 |    89.06 |     100 |   93.45 | ...68-169,196-206 
  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  |   86.27 |    83.01 |     100 |   86.27 | ...22-935,969-974 
  ...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.06 |    88.37 |     100 |   89.06 | ...72-176,202-209 
  ...oreCommand.ts |    90.9 |    86.04 |     100 |    90.9 | ...41-146,176-177 
  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 |    6.43 |      100 |      50 |    6.43 | 31-330            
  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 |   91.82 |    78.87 |   66.66 |   91.82 | ...59-160,169-174 
 src/ui/components |   70.54 |    78.07 |   76.29 |   70.54 |                   
  AboutBox.tsx     |     100 |      100 |     100 |     100 |                   
  ...ateScreen.tsx |   97.29 |     87.5 |   66.66 |   97.29 | 49                
  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 |   86.72 |       88 |     100 |   86.72 | ...00-302,355-359 
  Composer.tsx     |   94.49 |    66.66 |     100 |   94.49 | ...-72,84,139,153 
  ...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-597             
  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       |   75.11 |     61.4 |      50 |   75.11 | ...48-253,271-275 
  ...ngSpinner.tsx |   68.42 |    85.71 |      50 |   68.42 | 35-52,73,80-81    
  GoalPill.tsx     |   83.33 |    76.92 |     100 |   83.33 | 24-30             
  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 |   78.45 |    64.28 |     100 |   78.45 | ...98,501,504-510 
  ...ngeDialog.tsx |     100 |      100 |     100 |     100 |                   
  InputPrompt.tsx  |   82.49 |    80.33 |      80 |   82.49 | ...2178,2204,2278 
  ...Shortcuts.tsx |   20.65 |      100 |       0 |   20.65 | ...7,50-52,68-126 
  ...Indicator.tsx |   98.18 |    97.82 |     100 |   98.18 | 161-162           
  ...firmation.tsx |   91.42 |      100 |      50 |   91.42 | 26-31             
  MainContent.tsx  |   95.82 |    92.53 |      50 |   95.82 | ...97,440-444,447 
  MemoryDialog.tsx |   86.59 |    80.15 |     100 |   86.59 | ...34-435,485,553 
  ...geDisplay.tsx |       0 |        0 |       0 |       0 | 1-41              
  ModelDialog.tsx  |   83.41 |    71.65 |     100 |   83.41 | ...69,971,976-992 
  ...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 |   72.56 |       80 |      40 |   72.56 | ...06-109,114-117 
  ...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.5 |    85.18 |     100 |    93.5 | ...05,267,287-289 
  ...yTodoList.tsx |   96.36 |    88.23 |     100 |   96.36 | 138-141           
  ...nsDisplay.tsx |   92.97 |    83.87 |     100 |   92.97 | ...43,246,273-275 
  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             
  ...criptView.tsx |   98.27 |    84.21 |     100 |   98.27 | 45,53             
  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 |   53.72 |    70.87 |   42.85 |   53.72 |                   
  ...atContent.tsx |    9.09 |      100 |       0 |    9.09 | 54-275,281-283    
  ...tChatView.tsx |   21.05 |      100 |       0 |   21.05 | 21-39             
  ...tComposer.tsx |   64.78 |    29.41 |   33.33 |   64.78 | ...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 |    82.2 |    81.36 |    90.9 |    82.2 |                   
  ...sksDialog.tsx |   77.53 |     76.9 |   80.76 |   77.53 | ...1781,1803-1809 
  ...TasksPill.tsx |   67.03 |     86.2 |     100 |   67.03 | ...02-122,130-138 
  ...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.14 |   70.83 |   71.92 |                   
  DiscoverTab.tsx  |   68.22 |    67.66 |   55.55 |   68.22 | ...93,656-660,664 
  InstalledTab.tsx |   75.49 |    67.28 |   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.97 |    52.38 |   20.83 |   50.97 |                   
  ...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.56 |      100 |       0 |    9.56 | 40-67,70-158      
 ...mponents/hooks |   86.99 |    81.37 |   91.89 |   86.99 |                   
  ...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.04 |    61.53 |   70.58 |   40.04 |                   
  ...ealthPill.tsx |   68.42 |    85.71 |     100 |   68.42 | 40-46             
  ...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 |   89.85 |       86 |   86.86 |   89.85 |                   
  ...ionDialog.tsx |   89.23 |    84.27 |   81.81 |   89.23 | ...75,593,611-613 
  BtwMessage.tsx   |     100 |      100 |     100 |     100 |                   
  ...upDisplay.tsx |     100 |    94.79 |     100 |     100 | 37,41,43,289,365  
  ...onMessage.tsx |   92.06 |    82.35 |     100 |   92.06 | 58-60,62,64       
  ...nMessages.tsx |   96.71 |    97.77 |   91.66 |   96.71 | 223-233           
  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 |   76.52 |     42.1 |   66.66 |   76.52 | ...00,102,125,156 
  ...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 |   89.75 |     79.1 |     100 |   89.75 | ...33-635,642-644 
  ...upMessage.tsx |   98.32 |    95.16 |     100 |   98.32 | 184-187,414       
  ToolMessage.tsx  |   92.43 |    84.84 |   93.33 |   92.43 | ...56-961,988-990 
 ...ponents/shared |   85.73 |    82.05 |   94.05 |   85.73 |                   
  ...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 |   72.72 |      100 |     100 |   72.72 | 31-33             
  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 |   88.51 |    85.11 |   81.81 |   88.51 | ...51-779,792,887 
  text-buffer.ts   |   85.94 |    81.73 |   97.91 |   85.94 | ...2651,2749-2750 
  ...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 |   69.81 |    72.64 |   61.11 |   69.81 |                   
  ContextUsage.tsx |   70.88 |    63.88 |      80 |   70.88 | ...20-426,463-557 
  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   |   83.59 |    81.27 |   86.11 |   83.59 |                   
  ...ewContext.tsx |   64.83 |    88.88 |      50 |   64.83 | ...16-219,225-235 
  AppContext.tsx   |      80 |       50 |     100 |      80 | 19-20             
  ...ewContext.tsx |   92.45 |    62.79 |      50 |   92.45 | ...69-270,272-276 
  ...igContext.tsx |   81.81 |       50 |     100 |   81.81 | 15-16             
  ...ssContext.tsx |    85.1 |    84.53 |     100 |    85.1 | ...1583-1585,1591 
  ...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 | 151-152           
  ...teContext.tsx |   86.66 |       50 |     100 |   86.66 | 234-235           
  ...deContext.tsx |      80 |     87.5 |      75 |      80 | ...11-112,118-120 
 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      |   84.91 |     82.4 |   89.57 |   84.91 |                   
  ...dProcessor.ts |      84 |    84.12 |     100 |      84 | ...41-873,920-921 
  ...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 | ...86-287,292-293 
  ...dProcessor.ts |   85.21 |     66.4 |   81.81 |   85.21 | ...1407,1428-1432 
  ...rt-command.ts |     100 |      100 |     100 |     100 |                   
  ...sced-flush.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.08 |     100 |   88.28 | ...66,175,179-187 
  ...waySummary.ts |   96.26 |       75 |     100 |   96.26 | 126-128,170       
  ...ndTaskView.ts |   94.73 |    76.59 |     100 |   94.73 | 162-166,255,261   
  ...chedScroll.ts |     100 |      100 |     100 |     100 |                   
  ...ketedPaste.ts |    23.8 |      100 |       0 |    23.8 | 19-37             
  ...nchCommand.ts |   94.85 |    80.76 |     100 |   94.85 | ...54,229,292-295 
  ...ompletion.tsx |   96.81 |    81.81 |     100 |   96.81 | ...90-291,301-302 
  ...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 |   78.53 |    88.57 |     100 |   78.53 | ...96-104,112-113 
  ...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.7 |     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 |   85.51 |    81.02 |   96.15 |   85.51 | ...3891,4053-4061 
  ...BranchName.ts |     100 |    91.66 |     100 |     100 | 30                
  ...oryManager.ts |   98.01 |    98.36 |     100 |   98.01 | 139-142           
  ...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 |    9.67 |      100 |       0 |    9.67 | 11-32,39-90       
  ...gIndicator.ts |     100 |    96.66 |     100 |     100 | 109               
  useLogger.ts     |      16 |      100 |       0 |      16 | 15-45             
  useMCPHealth.ts  |   63.15 |       80 |      50 |   63.15 | 42-52,64-67       
  ...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 |    96.77 |     100 |     100 | 75                
  ...delCommand.ts |     100 |       95 |     100 |     100 | 53                
  ...ouseEvents.ts |   94.31 |    97.43 |   83.33 |   94.31 | 76-80             
  ...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 |    87.4 |    78.78 |     100 |    87.4 | ...71,321-333,381 
  useQwenAuth.ts   |     100 |      100 |     100 |     100 |                   
  ...lScheduler.ts |   91.16 |     90.9 |     100 |   91.16 | ...35-338,453-463 
  ...oryCommand.ts |       0 |        0 |       0 |       0 | 1-7               
  ...tleRepaint.ts |     100 |      100 |     100 |     100 |                   
  ...umeCommand.ts |   94.67 |    74.28 |     100 |   94.67 | ...19,174,233-238 
  ...ompletion.tsx |   90.67 |    83.33 |     100 |   90.67 | ...02,105,138-141 
  ...ectionList.ts |   97.12 |    96.22 |     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.13 |    93.33 |     100 |   97.13 | ...78-382,478-485 
  ...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 |   53.06 |       50 |   66.66 |   53.06 | ...53,61-68,79-85 
  ...rminalSize.ts |     100 |      100 |     100 |     100 |                   
  ...emeCommand.ts |   67.01 |    29.41 |     100 |   67.01 | ...10-111,115-116 
  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.2 |    89.47 |     100 |    91.2 |                   
  ...AppLayout.tsx |    90.9 |     87.5 |     100 |    90.9 | 60-62,110-115,151 
  ...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  |   86.47 |    79.88 |   96.66 |   86.47 |                   
  screen-buffer.ts |   94.73 |    64.28 |     100 |   94.73 | 51-52             
  ...ion-coords.ts |     100 |      100 |     100 |     100 |                   
  ...ction-span.ts |   92.72 |       90 |     100 |   92.72 | 37-38,67-68       
  ...tion-state.ts |   85.71 |      100 |   88.88 |   85.71 | 51-58             
  ...ction-text.ts |   92.85 |    92.45 |     100 |   92.85 | 30-34,114-115     
  ...selection.tsx |   80.31 |    59.64 |     100 |   80.31 | ...13-314,330-331 
 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      |   86.13 |     84.8 |   94.88 |   86.13 |                   
  ...Colorizer.tsx |   80.31 |    85.41 |     100 |   80.31 | ...00-201,313-339 
  ...nRenderer.tsx |    82.6 |    74.32 |     100 |    82.6 | ...53,278,300-301 
  ...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 |   92.67 |    82.35 |   95.23 |   92.67 | ...35-738,791-796 
  ...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.52 |    73.25 |   91.66 |   52.52 | ...23,626-635,638 
  commandUtils.ts  |    96.1 |    88.77 |     100 |    96.1 | ...73,175-176,320 
  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    |    95.4 |    98.38 |     100 |    95.4 | 123-126           
  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 |    97.05 |     100 |      96 | 102-105           
  inline-math.ts   |     100 |      100 |     100 |     100 |                   
  input-mouse.ts   |     100 |    85.71 |     100 |     100 | 48,93             
  isNarrowWidth.ts |     100 |      100 |     100 |     100 |                   
  ...olDetector.ts |   69.47 |       75 |   66.66 |   69.47 | ...24-129,157-158 
  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.59 |     100 |   98.72 | 145-146           
  ...t-position.ts |     100 |     87.5 |     100 |     100 | 85                
  ...geRenderer.ts |   86.23 |    69.06 |   95.12 |   86.23 | ...1284,1324-1330 
  ...alRenderer.ts |   86.69 |     71.9 |     100 |   86.69 | ...1476,1513-1519 
  ...lsBySource.ts |     100 |    95.23 |     100 |     100 | 84                
  mouse.ts         |   92.85 |    73.77 |     100 |   92.85 | ...38,145,149-152 
  osc8.ts          |   90.43 |    78.33 |     100 |   90.43 | ...59,244,248-249 
  ...red-height.ts |   98.38 |     97.1 |     100 |   98.38 | 195-197           
  ...mConstants.ts |     100 |      100 |     100 |     100 |                   
  restoreGoal.ts   |     100 |      100 |     100 |     100 |                   
  ...storyUtils.ts |   71.08 |    79.03 |   93.75 |   71.08 | ...03-525,656-657 
  ...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 |   94.94 |      100 |   88.88 |   94.94 | 112-117           
  ...wOptimizer.ts |     100 |    96.77 |     100 |     100 | 69                
  terminalSetup.ts |    4.37 |      100 |       0 |    4.37 | 44-393            
  textUtils.ts     |   95.97 |    93.22 |   94.44 |   95.97 | ...21-322,482-483 
  ...background.ts |     100 |      100 |     100 |     100 |                   
  todoSnapshot.ts  |   89.65 |       92 |     100 |   89.65 | ...83-184,217-218 
  ...isplay-map.ts |     100 |      100 |     100 |     100 |                   
  updateCheck.ts   |     100 |    92.75 |     100 |     100 | 227-239,331       
  ...ow-keyword.ts |     100 |      100 |     100 |     100 |                   
 ...i/utils/export |   75.03 |    59.89 |   94.59 |   75.03 |                   
  collect.ts       |   71.27 |    65.81 |      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      |   80.94 |    72.69 |   80.55 |   80.94 |                   
  ...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 |   89.72 |    65.33 |   93.75 |   89.72 | ...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 |    68.42 |     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         |   80.91 |    86.87 |    92.3 |   80.91 |                   
  ...p-profiler.ts |   98.39 |    90.56 |     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 |       95 |     100 |     100 | 72                
  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      |   96.96 |    97.95 |     100 |   96.96 | 123-125           
  commentJson.ts   |   91.37 |    94.87 |     100 |   91.37 | 67-76             
  ...Calculator.ts |     100 |      100 |     100 |     100 |                   
  cpuProfiler.ts   |   70.73 |    73.23 |   88.88 |   70.73 | ...27,430-431,438 
  deepMerge.ts     |     100 |       90 |     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.17 |     100 |   90.65 | ...72,370,372-373 
  ...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 | ...59,376-377,422 
  languageUtils.ts |   98.88 |    97.05 |     100 |   98.88 | 184-185           
  load-undici.ts   |     100 |      100 |     100 |     100 |                   
  ...npm-update.ts |   86.32 |    76.05 |     100 |   86.32 | ...02-303,331-341 
  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 |   74.38 |    69.56 |     100 |   74.38 | ...92-103,105-116 
  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.67 |    56.93 |   76.92 |   45.67 | ...1034,1046-1069 
  ...xImageName.ts |     100 |    77.77 |     100 |     100 | 10,18             
  sandboxMounts.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 |     87.5 |     100 |     100 | 23                
  systemInfo.ts    |   95.12 |    90.27 |     100 |   95.12 | ...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       
  ...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 |                   
  windowTitle.ts   |   95.45 |    93.33 |     100 |   95.45 | 54-55             
  ...WithBackup.ts |   65.04 |    77.77 |     100 |   65.04 | 97,112,133-172    
 ...s/housekeeping |   91.63 |    91.02 |      95 |   91.63 |                   
  cleanup.ts       |   95.77 |    95.83 |     100 |   95.77 | 70-72             
  ...eractionAt.ts |     100 |      100 |     100 |     100 |                   
  scheduler.ts     |   91.91 |    90.47 |    87.5 |   91.91 | 58-62,73,131-135  
  throttledOnce.ts |   86.66 |     86.2 |     100 |   86.66 | ...99,105,137-138 
-------------------|---------|----------|---------|---------|-------------------
Core Package - Full Text Report
-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |   87.11 |    85.94 |   88.69 |   87.11 |                   
 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        |   89.96 |    83.92 |   94.02 |   89.96 |                   
  ...transcript.ts |   88.09 |    85.71 |     100 |   88.09 | ...97,605,611-615 
  ...ent-resume.ts |   84.53 |    76.01 |   78.26 |   84.53 | ...1674-1678,1681 
  ...ound-tasks.ts |   96.14 |     90.1 |   98.76 |   96.14 | ...1728,1748-1751 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...ent-result.ts |    96.8 |    92.68 |     100 |    96.8 | 106,129-131       
  ...n-registry.ts |   95.65 |    89.28 |     100 |   95.65 | ...12-413,485-489 
  ...w-snapshot.ts |   91.86 |       75 |     100 |   91.86 | ...54,178,185-187 
 src/agents/arena  |   76.32 |    67.71 |   78.94 |   76.32 |                   
  ...gentClient.ts |   79.47 |    88.88 |   81.81 |   79.47 | ...68-183,189-204 
  ArenaManager.ts  |   75.11 |    64.51 |   78.57 |   75.11 | ...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.02 |    85.19 |   76.28 |   78.02 |                   
  ITermBackend.ts  |   97.97 |    93.93 |     100 |   97.97 | ...78-180,255,307 
  ...essBackend.ts |    90.8 |    85.24 |   93.33 |    90.8 | ...64,666,668-669 
  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 |   90.19 |    85.26 |   87.28 |   90.19 |                   
  agent-context.ts |     100 |      100 |     100 |     100 |                   
  agent-core.ts    |   84.13 |    73.18 |   76.47 |   84.13 | ...2138,2184-2186 
  agent-events.ts  |     100 |      100 |     100 |     100 |                   
  ...t-headless.ts |   93.49 |    88.09 |   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.95 |     100 |   98.29 | 141,165,206,239   
  agent-types.ts   |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...ool-policy.ts |   98.34 |      100 |    92.3 |   98.34 | 81-82             
  ...low-budget.ts |     100 |      100 |     100 |     100 |                   
  ...ow-journal.ts |   91.76 |    75.86 |     100 |   91.76 | ...38-139,179-181 
  ...chestrator.ts |   91.79 |    87.79 |   82.35 |   91.79 | ...1774,1823-1826 
  ...ow-prompts.ts |     100 |      100 |     100 |     100 |                   
  ...ow-sandbox.ts |   96.87 |    94.51 |     100 |   96.87 | ...24-325,330-331 
  ...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   |   81.81 |    83.99 |    87.5 |   81.81 |                   
  TeamManager.ts   |   72.02 |    79.41 |   79.24 |   72.02 | ...1632,1655-1656 
  identity.ts      |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...sionBridge.ts |     100 |      100 |     100 |     100 |                   
  mailbox.ts       |   94.76 |    86.36 |   92.85 |   94.76 | 86-87,348-354     
  ...ptAddendum.ts |     100 |      100 |     100 |     100 |                   
  tasks.ts         |   88.85 |    82.56 |   96.29 |   88.85 | ...-990,1034-1035 
  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.26 |   98.21 |   94.39 |                   
  ...on-harness.ts |   96.49 |    84.21 |     100 |   96.49 | 128-129,141-142   
  fake-agent.ts    |   98.49 |    95.08 |     100 |   98.49 | 201-203           
  fake-backend.ts  |   86.46 |    97.61 |   95.83 |   86.46 | 124-146           
 src/config        |   83.52 |     86.5 |   72.88 |   83.52 |                   
  approval-mode.ts |     100 |      100 |     100 |     100 |                   
  ...xtDefaults.ts |     100 |      100 |     100 |     100 |                   
  config.ts        |   82.66 |    86.12 |   70.79 |   82.66 | ...7395,7399-7400 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  models.ts        |     100 |      100 |     100 |     100 |                   
  storage.ts       |   94.11 |    91.95 |      88 |   94.11 | ...25-426,429-430 
 ...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          |    91.5 |    88.02 |    92.7 |    91.5 |                   
  baseLlmClient.ts |   88.28 |    82.48 |   81.81 |   88.28 | ...47,660,666-668 
  client.ts        |    91.2 |    87.09 |   90.41 |    91.2 | ...3243,3339-3340 
  ...tGenerator.ts |   85.81 |     85.5 |   80.95 |   85.81 | ...25-426,471-477 
  ...lScheduler.ts |   89.79 |     86.1 |   95.83 |   89.79 | ...5296,5324-5335 
  geminiChat.ts    |   91.88 |    89.29 |   95.69 |   91.88 | ...4079,4127-4128 
  geminiRequest.ts |     100 |      100 |     100 |     100 |                   
  genai-compat.ts  |     100 |      100 |     100 |     100 |                   
  ...MediaLimit.ts |     100 |    95.83 |     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.33 |    83.33 |      50 |   93.33 | 46-47             
  ...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 |   95.19 |    89.47 |     100 |   95.19 | ...44-245,290-291 
  prompts.ts       |   93.57 |    91.42 |   83.33 |   93.57 | ...1186,1389-1390 
  ...ing-effort.ts |     100 |      100 |     100 |     100 |                   
  ...n-recovery.ts |   95.13 |       80 |     100 |   95.13 | ...06-107,142-144 
  ...t-profiler.ts |   96.89 |    80.88 |   88.23 |   96.89 | ...10,117-118,123 
  ...port-retry.ts |     100 |      100 |     100 |     100 |                   
  tokenLimits.ts   |     100 |     92.1 |     100 |     100 | 87,122-123        
  ...reparation.ts |     100 |      100 |     100 |     100 |                   
  ...allIdUtils.ts |   98.41 |    93.02 |     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          |   98.49 |    91.17 |     100 |   98.49 | ...94,622-623,669 
 ...ntentGenerator |   96.18 |    87.11 |   95.38 |   96.18 |                   
  ...tGenerator.ts |   97.09 |    86.94 |   94.44 |   97.09 | ...1322,1351,1362 
  converter.ts     |   96.04 |    87.15 |     100 |   96.04 | ...,931,1086-1088 
  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 |   95.21 |    86.46 |    92.3 |   95.21 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...tGenerator.ts |   95.12 |     85.4 |   91.89 |   95.12 | ...1169-1170,1198 
  ...tDetection.ts |     100 |      100 |     100 |     100 |                   
 ...ntentGenerator |   91.65 |    90.23 |   95.23 |   91.65 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  converter.ts     |   91.15 |    89.32 |   96.87 |   91.15 | ...1914,2083-2098 
  errorHandler.ts  |     100 |      100 |     100 |     100 |                   
  index.ts         |   60.31 |       75 |      50 |   60.31 | ...71,74-78,90-94 
  ...tGenerator.ts |    66.4 |    70.58 |   88.88 |    66.4 | ...51-157,168-169 
  pipeline.ts      |   96.63 |    90.94 |     100 |   96.63 | ...1100,1108,1203 
  ...ureContext.ts |     100 |      100 |     100 |     100 |                   
  ...ingOptions.ts |       0 |        0 |       0 |       0 | 1                 
  ...CallParser.ts |    92.2 |     92.4 |     100 |    92.2 | ...15-516,536-539 
  ...kingParser.ts |     100 |    96.87 |     100 |     100 | 42                
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...rator/provider |   96.73 |    89.76 |   98.27 |   96.73 |                   
  dashscope.ts     |   97.48 |    91.91 |      95 |   97.48 | ...85-386,528-529 
  deepseek.ts      |   94.91 |    89.36 |     100 |   94.91 | ...31-132,145-146 
  default.ts       |   99.16 |    96.96 |     100 |   99.16 | 198               
  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     |   86.12 |    83.09 |   92.19 |   86.12 |                   
  ...ive-safety.ts |     100 |      100 |     100 |     100 |                   
  ...-converter.ts |   78.32 |    71.83 |     100 |   78.32 | ...1122,1168-1169 
  corruptFile.ts   |     100 |       50 |     100 |     100 | 40-45             
  ...-converter.ts |   80.39 |     87.5 |     100 |   80.39 | 50-59             
  ...me-refresh.ts |     100 |      100 |     100 |     100 |                   
  ...sion-store.ts |   90.82 |    86.11 |   97.82 |   90.82 | ...1215-1221,1265 
  ...ionManager.ts |   80.59 |    78.06 |   80.23 |   80.59 | ...2577,2599-2600 
  ...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 |    84.61 |   85.71 |    75.9 | ...98,202,214-248 
  github.ts        |   88.58 |    82.13 |     100 |   88.58 | ...62,952-953,963 
  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       
  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 |    83.78 |     100 |   88.95 | ...32-235,238-241 
  ...extraction.ts |   85.77 |    80.61 |   89.47 |   85.77 | ...02-205,260-261 
 src/followup      |   77.38 |    79.84 |    90.9 |   77.38 |                   
  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   |   65.26 |    62.63 |   71.42 |   65.26 | ...17-618,625-626 
  ...onToolGate.ts |     100 |    96.55 |     100 |     100 | 97                
  ...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         |   93.15 |    86.93 |   95.91 |   93.15 |                   
  ...eGoalStore.ts |   87.61 |    88.88 |   86.66 |   87.61 | ...85-188,196-204 
  goal-evidence.ts |   87.01 |    84.26 |   95.65 |   87.01 | ...86-587,610-613 
  ...projection.ts |   89.41 |    72.22 |   66.66 |   89.41 | ...28,131,135-137 
  ...ersistence.ts |   83.96 |       76 |      80 |   83.96 | ...0,93-94,97-106 
  goal-protocol.ts |     100 |      100 |     100 |     100 |                   
  goal-reducer.ts  |   91.24 |    81.14 |     100 |   91.24 | ...68,381,432-436 
  goal-runtime.ts  |   98.71 |    92.69 |     100 |   98.71 | ...38-639,662-663 
  goal-verifier.ts |   91.72 |    89.47 |     100 |   91.72 | ...63-166,179-181 
  goal-wire.ts     |       0 |        0 |       0 |       0 | 1-27              
  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         |   87.41 |    85.73 |   88.38 |   87.41 |                   
  ...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.43 |     83.5 |   94.59 |   95.43 | ...1010-1011,1021 
  hookPlanner.ts   |    87.5 |    85.36 |   86.66 |    87.5 | ...21-225,232-243 
  hookRegistry.ts  |   92.53 |    85.43 |     100 |   92.53 | ...39,458,462,466 
  hookRunner.ts    |   62.48 |    72.04 |   66.66 |   62.48 | ...67-768,777-778 
  hookSystem.ts    |    87.5 |      100 |   70.21 |    87.5 | ...43-744,750-751 
  ...HookRunner.ts |   75.51 |     61.9 |      80 |   75.51 | ...05-406,424-425 
  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     |   77.22 |    85.36 |     100 |   77.22 | ...57,261-267,273 
  stopHookCap.ts   |     100 |      100 |     100 |     100 |                   
  trustedHooks.ts  |      90 |    52.63 |     100 |      90 | ...53,66-67,97-98 
  types.ts         |   94.24 |    96.12 |   88.88 |   94.24 | ...42-543,628-632 
  urlValidator.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.17 |    82.76 |   90.29 |   87.17 |                   
  ...y-document.ts |   89.52 |    84.61 |     100 |   89.52 | ...24-325,329-330 
  ...nel-memory.ts |   97.11 |    95.72 |   96.29 |   97.11 | ...85-287,361-362 
  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 |    81.81 |     100 |     100 | 126,136           
  entries.ts       |   75.59 |    84.84 |   83.33 |   75.59 | ...56-157,172-180 
  extract.ts       |   91.48 |    75.75 |     100 |   91.48 | ...99,118-121,189 
  ...entPlanner.ts |   91.51 |    76.19 |     100 |   91.51 | ...04,113-116,290 
  ...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 |   82.27 |    77.92 |   83.33 |   82.27 | ...66,285,292-298 
  memoryAge.ts     |   90.47 |       80 |     100 |   90.47 | 50-51             
  paths.ts         |   94.73 |    95.94 |     100 |   94.73 | ...35-336,357-358 
  ...ing-skills.ts |     100 |       72 |     100 |     100 | 31-35,73-78,97    
  prompt.ts        |   97.26 |    87.03 |     100 |   97.26 | ...10-218,222,225 
  recall.ts        |   82.06 |       75 |    90.9 |   82.06 | ...59-364,395-406 
  refresh.ts       |   89.85 |    82.92 |     100 |   89.85 | ...54-155,162-163 
  ...ceSelector.ts |    93.1 |    81.81 |     100 |    93.1 | ...25,127-128,136 
  remember.ts      |   98.89 |    89.79 |     100 |   98.89 | 50,70             
  scan.ts          |   93.12 |    77.41 |     100 |   93.12 | ...08-109,154,157 
  ...et-scanner.ts |     100 |      100 |     100 |     100 |                   
  ...entPlanner.ts |   71.68 |    65.51 |   68.75 |   71.68 | ...90-394,397,403 
  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.54 |    88.91 |   91.13 |   92.54 |                   
  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,260           
  modelsConfig.ts  |   89.36 |    86.77 |   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.54 |       91 |   70.71 |   83.54 |                   
  autoMode.ts      |   97.64 |    93.13 |     100 |   97.64 | ...78-585,631,708 
  ...transcript.ts |      98 |    84.61 |     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.53 |    89.57 |      80 |   86.53 | ...1095,1201-1205 
  rule-parser.ts   |   94.14 |    91.89 |     100 |   94.14 | ...1335,1369-1371 
  ...-semantics.ts |   70.36 |    91.02 |   46.66 |   70.36 | ...2237,2300-2303 
  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.5 |   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 |    73.84 |   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 | 82-84,87-89,91-94 
  ...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      |   89.53 |    84.84 |   96.29 |   89.53 |                   
  ...ionTrailer.ts |     100 |      100 |     100 |     100 |                   
  ...llRegistry.ts |   97.66 |    85.71 |     100 |   97.66 | ...95,118,487-488 
  ...ionService.ts |   96.71 |    95.79 |     100 |   96.71 | ...83,699,832-840 
  ...ingService.ts |   87.48 |    81.45 |   89.83 |   87.48 | ...1840,1867-1868 
  ...ttribution.ts |   91.73 |    87.71 |      90 |   91.73 | ...80-685,826-827 
  ...utSlimming.ts |    97.2 |    94.05 |     100 |    97.2 | ...39-340,378-381 
  cronScheduler.ts |   94.12 |    90.45 |      98 |   94.12 | ...1323,1726-1727 
  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 |     100 |      100 |     100 |     100 |                   
  ...temService.ts |   92.22 |    86.11 |   91.66 |   92.22 | ...80-281,349-356 
  ...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.76 |     100 |   98.39 | 154-155,215-216   
  ...ionService.ts |   98.22 |    97.32 |     100 |   98.22 | ...63-664,711-712 
  ...ticsDumper.ts |   98.37 |    95.23 |     100 |   98.37 | 185-186           
  ...ureMonitor.ts |   95.82 |    90.47 |   97.05 |   95.82 | ...60,861,875-877 
  ...orRegistry.ts |   97.27 |    91.22 |     100 |   97.27 | ...50-451,606-607 
  ...ttachments.ts |   97.74 |     90.8 |     100 |   97.74 | 298-308,646       
  ...ersistence.ts |   90.95 |    78.75 |     100 |   90.95 | ...78,963-964,992 
  ...on-service.ts |   94.49 |    92.26 |   97.14 |   94.49 | ...98-600,656-664 
  ...ce-service.ts |   98.38 |    93.75 |   88.88 |   98.38 | 63-64             
  ...ipt-reader.ts |   94.49 |    89.16 |   97.95 |   94.49 | ...1038,1049-1050 
  ...est-helper.ts |       0 |        0 |       0 |       0 | 1-65              
  ...iter-lease.ts |   76.81 |    73.71 |    92.1 |   76.81 | ...15-816,820-827 
  sessionRecap.ts  |   67.56 |    43.47 |     100 |   67.56 | ...60,178,180-183 
  ...ionService.ts |   88.73 |     83.5 |    97.1 |   88.73 | ...2401,2471-2491 
  sessionTitle.ts  |   94.19 |    73.21 |     100 |   94.19 | ...43-246,277-278 
  ...ionService.ts |   84.35 |    78.37 |   97.14 |   84.35 | ...2472,2478-2483 
  ...pInhibitor.ts |   97.42 |    92.68 |     100 |   97.42 | ...30,169,369-370 
  ...Estimation.ts |     100 |    86.66 |     100 |     100 | 96-97             
  ...ageService.ts |   97.76 |    91.59 |   93.75 |   97.76 | ...61-262,366,567 
  ...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 |   87.98 |    86.95 |     100 |   87.98 | ...38-439,455-456 
 ...icrocompaction |   99.41 |    96.03 |     100 |   99.41 |                   
  microcompact.ts  |   99.41 |    96.03 |     100 |   99.41 | 244-245,677       
 ...s/visionBridge |    98.6 |    94.11 |     100 |    98.6 |                   
  ...capability.ts |     100 |      100 |     100 |     100 |                   
  ...part-utils.ts |     100 |      100 |     100 |     100 |                   
  ...-constants.ts |     100 |      100 |     100 |     100 |                   
  ...ge-service.ts |   98.32 |    92.64 |     100 |   98.32 | ...23,647,660-661 
 src/skills        |   88.37 |    87.22 |   90.16 |   88.37 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...activation.ts |     100 |    93.33 |     100 |     100 | 93,112            
  skill-load.ts    |   94.84 |     87.5 |     100 |   94.84 | ...03,223,235-237 
  skill-manager.ts |   83.78 |    82.63 |   82.35 |   83.78 | ...1218,1225-1229 
  skill-paths.ts   |   89.65 |    86.95 |     100 |   89.65 | ...11-112,117-118 
  symlinkScope.ts  |     100 |      100 |     100 |     100 |                   
  types.ts         |   97.91 |       98 |     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.53 |    88.63 |   96.42 |   87.53 |                   
  ...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 |   83.96 |    85.11 |   94.59 |   83.96 | ...1517,1594-1595 
  types.ts         |     100 |      100 |     100 |     100 |                   
  validation.ts    |   92.46 |    95.18 |     100 |   92.46 | 47-52,63-68,71-76 
 src/telemetry     |   80.69 |    83.54 |   84.29 |   80.69 |                   
  ...ty-tracker.ts |     100 |      100 |     100 |     100 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...on-metrics.ts |   99.07 |    80.95 |     100 |   99.07 | 183,197           
  ...on-tracing.ts |   76.31 |    74.62 |   73.68 |   76.31 | ...80,387-389,405 
  ...attributes.ts |   95.15 |    87.27 |     100 |   95.15 | ...97-198,216-217 
  ...ag-metrics.ts |     100 |    77.77 |     100 |     100 | 21,40             
  ...t-loop-lag.ts |     100 |    90.47 |     100 |     100 | 49,76             
  ...-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.09 |    95.61 |      95 |   99.09 | 141,365-366       
  ...t.circular.ts |       0 |        0 |       0 |       0 | 1-128             
  loggers.ts       |   55.35 |    71.56 |   63.46 |   55.35 | ...1350,1367-1387 
  metrics.ts       |   78.44 |    79.62 |   79.66 |   78.44 | ...1079,1082-1093 
  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      |   91.06 |    87.15 |   68.75 |   91.06 | ...32,478-479,495 
  sdk.ts           |   79.22 |    89.18 |   63.63 |   79.22 | ...57-161,199-221 
  ...on-context.ts |     100 |      100 |     100 |     100 |                   
  ...on-tracing.ts |   90.38 |    89.22 |   96.66 |   90.38 | ...1611,1642-1645 
  ...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         |   82.05 |    94.48 |   85.71 |   82.05 | ...1332,1336-1343 
  uiTelemetry.ts   |   97.18 |    93.93 |      88 |   97.18 | ...70,314,461-462 
 ...ry/qwen-logger |   73.62 |    81.25 |   69.49 |   73.62 |                   
  event-types.ts   |       0 |        0 |       0 |       0 |                   
  qwen-logger.ts   |   73.62 |    81.08 |   68.96 |   73.62 | ...1095,1133-1134 
 src/test-utils    |      94 |    98.24 |   78.94 |      94 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  ...st-helpers.ts |   94.11 |       90 |     100 |   94.11 | 69-70             
  index.ts         |     100 |      100 |     100 |     100 |                   
  mock-tool.ts     |   92.57 |      100 |   75.75 |   92.57 | ...63,227-228,241 
  ...aceContext.ts |     100 |      100 |     100 |     100 |                   
 src/tools         |   85.56 |    84.51 |   88.07 |   85.56 |                   
  ...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 |                   
  edit.ts          |    82.7 |    86.77 |   81.25 |    82.7 | ...43-744,863-913 
  ...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  |   94.94 |    85.29 |     100 |   94.94 | ...09-313,332,366 
  glob.ts          |   96.33 |     88.5 |     100 |   96.33 | ...24-225,373,376 
  grep.ts          |   83.21 |    86.66 |   80.95 |   83.21 | ...65-666,716-717 
  ...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.24 |    92.85 |     100 |   99.24 | 44                
  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 |   81.63 |       79 |   85.41 |   81.63 | ...3221,3223-3224 
  mcp-client.ts    |   79.83 |    85.09 |   89.47 |   79.83 | ...2233,2237-2240 
  ...ry-timeout.ts |     100 |      100 |     100 |     100 |                   
  mcp-errors.ts    |     100 |      100 |     100 |     100 |                   
  ...pool-entry.ts |   77.56 |    84.11 |   77.14 |   77.56 | ...1291,1299-1300 
  ...ool-events.ts |       8 |      100 |       0 |       8 | 132-158           
  mcp-pool-key.ts  |   97.46 |    93.93 |     100 |   97.46 | 175-176           
  ...ce-content.ts |   96.55 |    91.17 |     100 |   96.55 | 80-82             
  mcp-retry.ts     |   97.67 |    95.65 |     100 |   97.67 | 131-132           
  mcp-status.ts    |     100 |      100 |     100 |     100 |                   
  mcp-tool.ts      |   95.43 |    93.89 |     100 |   95.43 | ...79-780,830-831 
  ...sport-pool.ts |   83.49 |    80.15 |   84.61 |   83.49 | ...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.74 |    84.28 |   88.46 |   91.74 | ...93,606,804-809 
  notebook-edit.ts |   85.55 |    77.39 |   81.25 |   85.55 | ...86-902,948-949 
  ...escendants.ts |   36.17 |    64.51 |   55.55 |   36.17 | ...46-310,385-390 
  ...nforcement.ts |   82.57 |    90.24 |     100 |   82.57 | 174-185,234-247   
  read-file.ts     |   95.65 |    88.88 |   86.66 |   95.65 | ...80,495,567-568 
  ...p-resource.ts |   96.85 |      100 |   91.66 |   96.85 | 92-96             
  ...d-artifact.ts |    90.9 |    86.71 |    87.5 |    90.9 | ...13-414,428-440 
  ripGrep.ts       |    95.9 |     88.4 |   94.73 |    95.9 | ...61-662,668-669 
  ...-transport.ts |   71.42 |    55.55 |   71.42 |   71.42 | ...36-137,143-144 
  send-message.ts  |    81.2 |    89.74 |    62.5 |    81.2 | ...80-286,369-377 
  ...n-mcp-view.ts |   93.57 |     92.3 |      90 |   93.57 | 122-130           
  shell.ts         |   78.68 |    83.81 |   91.83 |   78.68 | ...4979,5042-5043 
  skill-utils.ts   |     100 |      100 |     100 |     100 |                   
  skill.ts         |   91.06 |    93.33 |   89.47 |   91.06 | ...71,475,520-542 
  ...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     |   73.38 |    77.77 |   83.33 |   73.38 | ...02,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     |   93.92 |    83.13 |   92.85 |   93.92 | ...86-391,413-414 
  tool-error.ts    |     100 |      100 |     100 |     100 |                   
  tool-names.ts    |     100 |      100 |     100 |     100 |                   
  tool-registry.ts |   78.06 |    78.83 |   82.22 |   78.06 | ...37-938,946-947 
  tool-search.ts   |   96.19 |    89.72 |   93.33 |   96.19 | ...09,259-264,426 
  tools.ts         |   92.74 |    91.52 |    91.3 |   92.74 | ...63-564,580-586 
  ...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.53 |    83.57 |      80 |   90.53 | ...1007,1065-1068 
  write-file.ts    |   85.66 |    85.04 |   85.71 |   85.66 | ...53-756,793-828 
 src/tools/agent   |   85.09 |    85.09 |   86.66 |   85.09 |                   
  agent.ts         |   84.92 |    84.84 |   86.17 |   84.92 | ...4092,4114-4124 
  fork-subagent.ts |   88.32 |       90 |    90.9 |   88.32 | ...05-123,200-201 
 ...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 |   87.46 |    79.41 |   85.71 |   87.46 |                   
  workflow.ts      |   87.46 |    79.41 |   85.71 |   87.46 | ...51-652,664-667 
 src/utils         |   92.63 |    89.56 |   96.76 |   92.63 |                   
  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 |                   
  ...ncyLimiter.ts |   94.64 |    95.23 |     100 |   94.64 | 64-66             
  ...igResolver.ts |     100 |      100 |     100 |     100 |                   
  ...engthError.ts |   91.11 |    89.47 |     100 |   91.11 | ...46-147,154-155 
  ...n-branches.ts |   95.81 |    93.95 |      95 |   95.81 | ...91-492,504-517 
  ...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.06 |   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        |   82.23 |     92.9 |    61.9 |   82.23 | ...56-372,376-382 
  fetch.ts         |   90.68 |    82.51 |     100 |   90.68 | ...72,483-484,503 
  fileUtils.ts     |    95.3 |    92.06 |   96.15 |    95.3 | ...1773,1798-1799 
  forkedAgent.ts   |   92.45 |    82.35 |   93.75 |   92.45 | ...34,642,647-654 
  formatters.ts    |   81.81 |       75 |     100 |   81.81 | 15-16             
  ...eUtilities.ts |    92.4 |    86.95 |     100 |    92.4 | ...52-158,168-169 
  ...rStructure.ts |   94.36 |    94.28 |     100 |   94.36 | ...17-120,331-336 
  getPty.ts        |   31.57 |       50 |     100 |   31.57 | 26-38             
  gitDiff.ts       |   95.12 |    81.03 |     100 |   95.12 | ...1073,1390-1391 
  gitDirect.ts     |   98.46 |    90.17 |     100 |   98.46 | 148,268,352       
  ...noreParser.ts |   94.59 |    92.59 |     100 |   94.59 | ...05-106,140-141 
  gitUtils.ts      |      75 |    89.47 |   83.33 |      75 | ...,78-79,103-154 
  github-prs.ts    |    99.3 |    90.62 |     100 |    99.3 | 204               
  iconvHelper.ts   |     100 |      100 |     100 |     100 |                   
  ...rePatterns.ts |     100 |      100 |     100 |     100 |                   
  ...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.27 |     93.1 |     100 |   95.27 | ...16-317,359-362 
  ...-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 |   93.77 |    89.15 |     100 |   93.77 | ...13-319,406-407 
  ...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.61 |     100 |     100 | 206               
  pathReader.ts    |   97.77 |       90 |     100 |   97.77 | 93,121            
  paths.ts         |   93.95 |    92.79 |     100 |   93.95 | ...78-479,481-483 
  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 |   59.15 |    76.92 |     100 |   59.15 | ...5,89-90,96-101 
  ...noreParser.ts |   92.63 |    91.37 |     100 |   92.63 | ...72-173,192-193 
  rateLimit.ts     |   93.75 |    89.62 |     100 |   93.75 | ...13,218-219,262 
  ...text-range.ts |   97.73 |    93.24 |     100 |   97.73 | 85-86,107,262-263 
  readManyFiles.ts |   96.29 |     87.5 |     100 |   96.29 | 225,275,286-290   
  retry.ts         |   95.93 |    92.23 |     100 |   95.93 | ...33,524-525,543 
  retryContext.ts  |     100 |      100 |     100 |     100 |                   
  ...sification.ts |   97.65 |    96.96 |     100 |   97.65 | ...00,250-251,277 
  retryPolicy.ts   |   97.72 |    90.56 |     100 |   97.72 | 130-131           
  ripgrepUtils.ts  |   80.47 |     82.6 |    90.9 |   80.47 | ...75-380,384-387 
  ...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.61 |   96.29 |   84.87 | ...71,696,725-734 
  ...odelPrefix.ts |     100 |      100 |     100 |     100 |                   
  runtimeStatus.ts |    97.5 |       90 |     100 |    97.5 | 162-163           
  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 |   94.77 |     94.2 |     100 |   94.77 | ...42,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.72 |    92.12 |     100 |   91.72 | ...36-539,615-616 
  ...nIdContext.ts |     100 |      100 |     100 |     100 |                   
  ...orageUtils.ts |   95.98 |     83.8 |     100 |   95.98 | ...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.05 |    88.59 |     100 |   86.05 | ...2251,2258-2262 
  ...lAstParser.ts |   98.16 |    91.91 |     100 |   98.16 | ...1244-1246,1256 
  ...ContextEnv.ts |     100 |    90.47 |     100 |     100 | 46-48             
  ...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.82 |     100 |   97.66 | 165-166,168-172   
  tool-utils.ts    |    95.2 |    93.61 |     100 |    95.2 | ...58-159,162-163 
  ...ultCleanup.ts |   54.62 |    30.76 |      75 |   54.62 | ...03-105,108-134 
  ...Compaction.ts |   96.11 |    96.33 |     100 |   96.11 | ...22-327,329-334 
  ...pt-records.ts |   85.78 |    83.63 |     100 |   85.78 | ...84-388,418-433 
  truncation.ts    |   90.44 |    89.09 |     100 |   90.44 | ...18-426,463-469 
  windowsPath.ts   |   89.47 |    79.31 |     100 |   89.47 | ...57-58,62,90-91 
  ...aceContext.ts |   95.81 |    89.39 |     100 |   95.81 | ...74-275,299-301 
  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.68 |    80.38 |   94.69 |   83.68 |                   
  crawlCache.ts    |     100 |      100 |     100 |     100 |                   
  crawler.ts       |   82.47 |    76.22 |      95 |   82.47 | ...1525,1559-1560 
  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.

…rules

Borrow the image-evidence and quantified-verification patterns from
hand-run rounds (#7265, #7471, #7686 r2 and the pr-assets convention):

- publish-verify now hosts agent-produced evidence/*.png on the pr-assets
  branch (verify/pr<N>-<run>-<attempt>/) and appends them below the
  escaped report. Untrusted-payload discipline: strict filename allowlist,
  8-image / 2 MB caps enforced in the find predicates, racing-push retry,
  and every failure degrades to a text-only comment. VERIFY_ASSETS_REMOTE
  is a test seam; the block was dry-run against a local bare remote
  covering hosting, hostile filenames, oversize files, dotfiles, missing
  branch, and no-image runs
- skill: evidence images are named as kebab-case captions binding image to
  claim, before/after pairs over lone after-shots; follow-up rounds lead
  with a previous-finding status table (fixed/stands/superseded/declined,
  with adjudication) and re-measure instead of diffing the old report;
  size/perf claims get measured-metric Δ tables with residual deltas
  accounted for; unreachable branches get the configuration that reaches
  them constructed; defensive guards get their accept path checked against
  real production artifacts, not just mocked rejects

@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. 1 Suggestion-level finding(s) could not be anchored to a changed line and were dropped; nothing further to act on here. Not reviewed: reverse audit — an auditor ran and opened its brief, but no agent was launched with the prompt the CLI built — the launch was written by hand, and what the agent was actually asked is not what this skill certifies.

— qwen3.7-max via Qwen Code /review

Comment thread .qwen/skills/verify-pr/SKILL.md Outdated
Comment thread .github/workflows/qwen-triage.yml
Comment thread .qwen/skills/verify-pr/SKILL.md
- skill: local invocation resolves --repo and passes it to every gh call
- skill: call out the dependency confound when the base A/B side reuses
  the PR-installed node_modules and the PR touches package.json/lockfile
- workflow: document the pin step's bootstrap logic — issue_comment jobs
  run the default branch's YAML, so base always carries the verify-pr
  skill by the time this job exists
@wenshao

wenshao commented Jul 25, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /triage

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Triage re-run completed without a new review.

The stage comments above were updated with the latest result. View workflow 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.

LGTM, looks ready to ship — CI landed green after the review. ✅

@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! ✅

中文说明

未发现问题。LGTM!✅

— qwen3.7-max via Qwen Code /review

@wenshao

wenshao commented Jul 25, 2026

Copy link
Copy Markdown
Collaborator Author

Review: feat(triage): add sandboxed /verify deep-verification lane

Overview

Adds an on-demand @qwen-code /verify lane to qwen-triage.yml: a verify job that executes the PR's real build in a container on the ECS pool (token-free agent env, loopback model proxy, author-write gate), and a publish-verify job on a clean hosted runner that upserts the report back to the PR. Plus a new verify-pr skill encoding the methodology/artifact contract and a one-paragraph Stage 2c update so triage recommends the trigger.

The isolation design is the strongest part: .qwen pinned from HEAD^1 so the tree under test can't rewrite its own verifier, depth-2 checkout giving the token-free agent a local base side for A/B, the git exec-vector sweep the tmux job lacks, verdict allowlisting before $GITHUB_OUTPUT, and every terminal state publishing an explicit comment. Escaping discipline in publish-verify is correct — I re-checked emit_block against </code></pre></details>, @everyone and <img onerror> payloads and they stay inert.

I independently replicated the PR's static claims (they hold):

  • actionlint with the repo's exact flag set (scripts/lint.js:97) → clean on the head file.
  • All 9 new run: blocks extracted from verify + publish-verifybash -n clean, shellcheck -S warning clean with the repo's ignore set.

Below are the things I'd want addressed. Nothing here is a correctness blocker for the happy path; items 1–4 are the ones I'd fix before merge.


1. Any GitHub user can trigger a 45-minute self-hosted job + a full model budget — Medium/High

.github/workflows/qwen-triage.yml:115 resolves the principal for /verify to $ISSUE_AUTHOR only. The commenter is never checked. On a public repo that means any authenticated account — a brand-new drive-by — can comment @qwen-code /verify on any open PR authored by a write-holder and consume:

  • up to 45 min on the shared ecs-qwen pool (:1417), cancel-in-progress: false,
  • a full npm ci + npm run build + 25 min of agent time + the model spend behind REVIEW_OPENAI_API_KEY.

Concurrency is keyed per-PR, so N open maintainer PRs → N queued jobs. /tmux has the same property, but its cost profile is a fraction of this one, so inheriting the gate verbatim changes the abuse economics materially.

The author gate is right for whose code runs; it just isn't a gate on who may spend the budget. Suggest requiring both: author has write (code-execution gate, unchanged) and commenter is a collaborator/write (spend gate). That's a few lines in the existing perm step and doesn't touch the /tmux semantics if you scope it to /verify.

2. The escaped report can exceed GitHub's comment limit → no comment at all — Medium

:2233 caps the report block at 50,000 raw bytes, then emit_block HTML-escapes it. Escaping is expansive (<→4×, &→5×), and the check runs before expansion. GitHub's issue-comment cap is 65,536 characters; gh api -F body=@… returns 422, set -euo pipefail kills the step, and nothing is posted — leaving the "🔬 Sandboxed verification is running" comment on the PR permanently while the run is long dead.

Measured, not theoretical:

$ head -c 50000 report-code.md | sed -e 's/&/\&amp;/g' -e 's/</\&lt;/g' -e 's/>/\&gt;/g' | wc -c
70253      # 50,000 raw bytes of TS-generics-heavy lines → 70,253 chars > 65,536

Overflow starts at roughly 10.4 % </> density (extra = 3·(#< + #>) + 4·#&, need > 15,536), before the ~1.2 KB of fixed framing and the evidence section. A report quoting JSX, TS generics, XML/HTML wire payloads, or a diff of this very workflow gets there. publish-tmux uses 20 KB + 30 KB and shares the mechanism, but the single 50 KB block here is the most exposed instance.

Fix is one line — escape first, then truncate, so the cap is a cap on what actually ships:

content="$(html_escape < "$file" | head -c "$max")"   # and drop $max to ~45000

3. -size -2M is really a 1 MiB cap, and over-cap images vanish silently — Medium

:2082 uses find … -size -2M. find rounds size up to the unit, so -2M matches only files whose rounded size is < 2 MiB — i.e. ≤ 1,048,576 bytes. Verified:

1048576 b.png   → matched
1048577 c.png   → NOT matched
1500000 d.png   → NOT matched

So the "8 images, 2 MB each" contract in SKILL.md, the workflow comment at :2071, and the PR body all overstate the real limit by 2×. A Playwright full-page capture routinely lands between 1 and 2 MB and would be dropped.

Worse than the off-by-one: the drop is completely silent. No ::warning::, no note in the comment — meanwhile report.md prose still references 01-bundle-ab-base-vs-head.png by name (the skill mandates exactly that), so the reader sees a caption pointing at nothing. Same for the head -8 truncation.

Suggest -size -2049k (or -2M documented honestly as 1 MiB), plus counting found vs hosted and appending _N image(s) exceeded the size/count cap — see run artifacts._ to the evidence section whenever they differ.

4. The planted-artifact fix covers pre-commit but not run-time — Medium

The tmp/*-verify-* sweep at :1626 closes the pre-committed-directory variant, and that's a good catch. But the same forgery is still reachable during the run:

  • :1905 chowns $RUNNER_TEMP/verify-results to node before the agent starts, and PR code executes as node. A test or build script can drop verify-results/report.md directly.
  • :2189-2190 select with find verify-results -name 'report.md' … | head -1 — unordered readdir, and a top-level plant sorts ahead of the real verify-results/pr<n>-verify-<ts>/report.md in typical traversal.
  • verdict.txt is likewise read from a workspace path (:1965) that is chowned to the agent user at :1639.

Given the author already holds write, this isn't an escalation so much as a truth-in-labelling issue: a PR under verification can author its own "merge-ready" headline, and the comment block at :1617-1624 reads as if the sweep closed that. Two cheap improvements:

find verify-results -mindepth 2 -path '*-verify-*/report.md' | sort | head -1

(the -mindepth 2 -path pin plus sort for determinism, same for assertions.json), and a sentence in that comment saying the sweep hardens the pre-commit vector while run-time output is inherently agent-authored and only ever advisory.

5. npm install -g runs against the previous PR's .npmrc — Low/Medium

:1557 carries the comment "Install before checkout so PR-controlled .npmrc cannot affect npm." On a persistent self-hosted workspace that reasoning inverts: at that point the workspace still holds the previous run's checked-out PR tree — actions/checkout (:1592) hasn't run yet, and Clean stale agent state (:1572) only sweeps git config/hooks/tmp. run steps default to cwd = $GITHUB_WORKSPACE, and npm reads the project .npmrc from cwd even for -g.

--registry=… overrides the registry, but not script-shell, ignore-scripts, cafile, prefix, or //…/:_authToken — and this install runs as root. Same pattern exists at :811 in the tmux job.

One-line fix that removes the whole question: run the global install from outside the workspace.

( cd "${RUNNER_TEMP:-/tmp}" && npm install -g --registry=https://registry.npmjs.org '@qwen-code/qwen-code@latest' )

6. skip / n-a / cancelled bodies overwrite a previous real report — Low/Medium

All six terminal branches upsert on the same <!-- qwen-triage:verify --> marker. So: PR gets a full verification round → later marked draft, or picks up a conflict, or someone re-triggers on a docs-only follow-up → the prior evidence comment is replaced by "Sandboxed verification: not run". The resolve step deliberately snapshots the previous report for the agent's follow-up round; it'd be a shame to lose it from the PR itself. Consider posting skip/na/cancelled as a new comment (they're transient states), or preserving the prior report in a collapsed <details> below the skip notice.

7. Smaller items

  • git pull --rebase misses the identity its siblings carry (:2116). Every other git call in that block passes -c user.name -c user.email; the rebase retry doesn't, and rebase needs a committer ident. Where the runner's ident can't be auto-detected, the racing-push retry aborts and degrades to text-only — i.e. the retry never fires in exactly the case it exists for. Cleanest fix is to set it once after clone (git -C "$clone_dir" config user.name …) and drop the four repeated -c pairs.
  • No feedback when the ECS pool is unavailable. The 👀 reaction and the "running" status comment both live inside the verify job (:1424ff), which needs the scarce self-hosted runner. If the pool is saturated or MAINTAINER_ECS_RUNNER_DISABLED is set — which :1417 hardcodes past, unlike :79/:202 — the user gets total silence, publish-verify never runs, and the job sits queued. That's the one hole in the PR's "an explicit request never gets silence" goal; acking from the hosted authorize side would close it.
  • Duplicate-filename collision. Two artifact dirs each containing evidence/01-foo.png sanitize to the same safe name: the second cp overwrites the first, hosted counts 2, and the render loop emits the same image twice. Prefix with the index, or de-dup.
  • No PNG validation + unbounded pr-assets growth. Bytes are attacker-supplied and only the extension is checked. raw.githubusercontent.com's CSP/sandbox headers make this low-risk, but a head -c 8 | cmp against the PNG magic is nearly free, and the branch accumulates 8 MB/run forever with no retention story.
  • head -c can split a UTF-8 char at the 50 KB cut, and the skill mandates a 中文摘要 section. On GNU tr the invalid bytes pass through and gh renders one U+FFFD (cosmetic; BSD tr would error instead). iconv -c -f UTF-8 -t UTF-8 after the cut makes it exact.
  • Double chown -R $GITHUB_WORKSPACE:1639 (pre-npm ci) then :1905 (post-npm ci, so ~50k+ node_modules files). The second one is mostly redundant work on the critical path.
  • SKILL.md worktree guidance is inaccurate. It says to keep worktrees under tmp/ "so the workflow's cleanup finds them", but every cleanup globs *-verify-*tmp/base-tree matches none of them and survives until the next checkout's git clean. Either name the worktree to match the glob or have the cleanup handle git worktree list output.
  • Worth confirming: verify and tmux use disjoint concurrency groups, so /tmux and /verify on the same PR can run simultaneously. That's fine if the ECS pool gives each runner its own _work, but the tmux job's own comment ("would share the same self-hosted runner workspace") suggests otherwise — if that premise holds, a shared {workflow}-sandbox-{pr} group prefix is safer.

Test coverage

There is no automated coverage for either job — expected for workflow YAML, and the PR compensates with a genuinely thorough manual round (six-branch stubbed-gh replay, injection-escaping proof, verdict-allowlist and assertions-jq replay, plus a full local E2E of the agent against #7547 with an audited 318/318 and a 13→7→13 mutation A/B). That's the right evidence for this artifact type. The honest ⚠️ on Linux stands: the jobs themselves have never run on a real Actions runner, and items 2, 3 and 5 above are exactly the class of thing that only shows up there — all three degrade visibly rather than silently corrupting, which matches the PR's stated containment argument.

Verdict

Approach and isolation model are sound, and the skill is the most valuable artifact here — it encodes real methodology rather than platitudes. I'd fix 1 (spend gate), 2 (escape-then-truncate) and 3 (image cap + silent drop) before merging, since 2 and 3 both produce a wrong or missing published comment on the first real run. 4–7 are follow-up-able.

中文说明

整体设计(容器隔离、.qwen 从 base pin 取、depth-2 本地 A/B、git exec-vector 清扫、verdict 白名单、六种终态均发评论)是这个 PR 最扎实的部分;转义纪律我复核过,</details>@everyone<img onerror> 均保持惰性。仓库 lint 声明我独立复现通过:repo 精确参数的 actionlint 干净,9 个新 run:bash -n + shellcheck -S warning 全绿。

建议合并前处理的三项:

  1. 任何 GitHub 用户都能触发 45 分钟自建 runner 作业 + 全额模型预算:115)。principal 只取 PR 作者,评论者完全不校验。公开仓库上任意路人账号即可在任一 write 用户的开放 PR 上评论 /verify,按 PR 并发排队消耗 ECS 池与模型额度。/tmux 虽同样如此,但成本量级差一个数量级。建议对 /verify 同时要求「作者有 write(代码执行门禁)」+「评论者是 collaborator(花费门禁)」。
  2. 转义后的报告可能超出 GitHub 65,536 字符评论上限:2233)。50,000 字节上限是在转义之前判定的,而 <→4 倍、&→5 倍。实测:50,000 字节的 TS 泛型密集内容转义后 70,253 字符,超限 → gh api 422 → set -e 杀掉步骤 → 一条评论都发不出,PR 上永远停在"运行中"。约 10.4% 的尖括号密度即触发。改法一行:先转义再 head -c,上限降到 ~45000。
  3. -size -2M 实际是 1 MiB 上限,且超限图片静默丢弃:2082)。find 向上取整,实测 1048577 字节即不匹配,与 SKILL/注释/PR 描述宣称的 2 MB 差一倍;Playwright 整页截图常在 1–2 MB。更关键的是丢弃无任何提示,而 report.md 仍按文件名引用该图,读者会看到指向空的图注。建议改 -size -2049k,并在 found != hosted 时在证据区追加一行说明。

其余(可后续处理):4 预埋产物防护只覆盖「提交时预埋」,运行期仍可伪造(verify-results 在 agent 运行前已 chown 给 node,且 find … | head -1 无序)——建议 -mindepth 2 -path '*-verify-*/report.md' | sort | head -1 并在注释中说明该产物本质是 agent 自述、仅作参考;5 npm install -g 的 cwd 仍是持久 workspace 中上一次运行留下的 PR 树,其 .npmrc 对这次 root 全局安装生效(--registry 覆盖不了 script-shell 等),改为在 $RUNNER_TEMP 下执行即可;6 skip/n-a/cancelled 会按 marker 覆盖掉此前真实的验证报告;7 若干小项:retry 里的 git pull --rebase 缺少同伴命令都带的身份配置、ECS 池不可用时零反馈(👀 与状态评论都在稀缺作业内部,且 :1417 绕过了 MAINTAINER_ECS_RUNNER_DISABLED)、同名图片覆盖后重复渲染、PNG 未校验魔数且 pr-assets 无限增长、head -c 可能截断多字节字符、重复 chown -R、SKILL 中"worktree 放 tmp/ 以便 cleanup 找到"与 *-verify-* glob 不符。

结论:方向与隔离模型成立,skill 本身价值最高。建议先修 1/2/3(后两项会直接导致首次真实运行发出错误或发不出评论),4–7 可作为后续。

@wenshao wenshao left a comment

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.

Reviewed. Suggestions are inline.

中文说明

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

— qwen3.8-max-preview via Qwen Code /review

Comment thread .github/workflows/qwen-triage.yml Outdated
Comment thread .github/workflows/qwen-triage.yml
Comment thread .qwen/skills/verify-pr/SKILL.md Outdated
…g per review

Address review round 5078770575 items 1-3 plus the cheap follow-ups:

- authorize: /verify now requires write from BOTH the PR author (whose
  code runs) and the commenter (who spends a scarce runner slot + model
  budget) — a drive-by account can no longer burn 45 minutes of ecs-qwen
  on someone else's PR; duplicates check once; /tmux and /triage gates
  unchanged. Replayed 8 principal scenarios against a stubbed gh
- authorize acks /verify with the eyes reaction from the always-hosted
  job, so a queued/saturated sandbox pool no longer means total silence
- publish: emit_block escapes FIRST and caps the escaped size (45 KB for
  the report) — a raw-side cap let dense <>& content inflate past
  GitHub's 65,536-char comment limit, 422 the post, and strand the
  running status with no report at all; iconv -c keeps a UTF-8 sequence
  split by the byte cut (likely, given the mandated 中文 summary) from
  shipping broken; replayed: 50 KB dense report -> 45,873-byte body
- publish: image cap is byte-exact (-size -2097153c; find's -2M rounds
  sizes UP to MiB, silently making the documented 2 MB cap 1 MiB), bytes
  must carry the PNG magic (extension is attacker-choosable), duplicate
  sanitized names dedupe instead of overwriting + double-rendering, and
  dropped images are reported in the comment instead of vanishing
- publish: weak terminal notices (cancelled/infra/skipped/n-a) only
  replace this run's own running status; a previous round's real report
  survives as the marker comment and the notice posts fresh
- publish: report.md/assertions.json lookups pin the artifact-dir shape
  and sort (bare find -name order is filesystem-dependent); the verify
  job's verdict.txt lookup sorts likewise
- verify: global npm install runs from RUNNER_TEMP (the persistent
  workspace still holds the PREVIOUS run's tree, whose .npmrc would
  apply to a root install); both cleanup passes remove leftover tmp/
  worktrees (git worktree prune alone only drops metadata); the run step
  no longer re-chowns 50k node_modules files; pr-assets clone sets its
  committer identity once so the racing-push rebase retry can commit
- skill: worktree guidance now tells the agent to remove its base tree
  itself, with the workflow sweep as backstop only
@wenshao

wenshao commented Jul 25, 2026

Copy link
Copy Markdown
Collaborator Author

Response to the review round (comment) — all three pre-merge items fixed in 1db0136cd

Every fix below was replayed locally before pushing (stubbed gh, local bare pr-assets remote, extracted run-blocks through bash -n + shellcheck -S warning, repo-exact actionlint/yamllint).

# Finding Resolution
1 Any GitHub user can trigger a 45-min self-hosted job + model budget Fixed. /verify now requires write from both the PR author and the commenter; duplicates check once; any API error or non-write denies. Replayed 8 principal scenarios (drive-by deny, both-write allow, author-without-write deny, self-comment dedupe, 404 fail-closed, /tmux+/triage unchanged) — 8/8.
2 Escaped report can exceed the 65,536 comment cap → 422 → no comment Fixed. emit_block escapes first, then caps the escaped size (report cap 45,000; 400 KB input bound on the escape itself); iconv -c drops a UTF-8 sequence split by the byte cut. Replayed: the 50 KB dense <>& report that previously assembled to >65k now produces a 45,873-byte body with a truncation note, valid UTF-8; a 中文-heavy report cut at the cap decodes clean.
3 -size -2M is a 1 MiB cap; over-cap images vanish silently Fixed. Byte-exact -size -2097153c (verified: exactly-2-MiB accepted, +1 byte rejected); bytes must carry the PNG magic (extension is attacker-choosable); duplicate sanitized names dedupe instead of overwrite-and-render-twice; dropped images are now counted in the comment ("N additional image(s) did not pass the hosting checks…") instead of vanishing.
4 Run-time forgery: unordered find -name report.md Hardened. report.md/assertions.json/verdict.txt lookups pin the *-verify-*/ dir shape, add -mindepth 2, and sort. Full run-time forgery by a steered agent remains inherently in-scope of the agent's own powers — the report is advisory and labeled as such; noted as a residual, not closable by lookup discipline alone.
5 npm install -g under the previous PR's .npmrc Fixed for the verify lane: the global install runs from RUNNER_TEMP. The identical pattern in the tmux job is pre-existing and left for the follow-up PR.
6 skip/n-a/cancelled overwrite a previous real report Fixed. Weak terminal notices only PATCH the marker comment when it is this run's own "running" status; over a previous round's real report they post fresh. Replayed all three arms of the matrix.
7a rebase retry lacks committer identity Fixed — identity set once on the clone; the per-command -c pairs are gone.
7b Total silence when the ECS pool is saturated Improved — the 👀 ack moved to the always-hosted authorize job, so an accepted request is acknowledged even while the sandbox job queues. The runs-on fallback question (hardcoded ECS vs MAINTAINER_ECS_RUNNER_DISABLED) is deferred: it mirrors the tmux job's deliberate ECS-only choice and deserves its own decision.
7c Duplicate-filename collision Fixed (dedupe, see #3).
7d No PNG validation / unbounded pr-assets growth Magic check fixed (see #3). Retention policy for pr-assets is a repo-level decision (the hand-run rounds have the same growth) — deferred to the follow-up.
7e UTF-8 split at the cut Fixed (see #2).
7f Double chown -R $GITHUB_WORKSPACE Fixed — the run step now chowns only the two RUNNER_TEMP dirs.
7g Worktree guidance inaccurate Fixed — the skill now has the agent git worktree remove its own base tree, and both workflow cleanup passes sweep leftover tmp/ worktrees via git worktree list --porcelain (prune alone only drops metadata).
7h Disjoint verify/tmux concurrency groups Confirmed safe, no change: a self-hosted runner instance executes one job at a time and each instance owns its own _work directory, so /tmux and /verify running concurrently land on different instances with separate workspaces. The tmux comment's "same workspace" concern applies to two runs of the same job family on the same instance over time, which each lane's own per-PR group already serializes.

Deferred to the follow-up PR (tmux-side siblings, as the review suggested): tmux's *-tmux-* planted-artifact sweep, its raw-side emit_block caps, its .npmrc-exposed global install, and the pr-assets retention story.

中文说明

针对本轮 review 的处理(修复提交 1db0136cd,推送前全部经本地回放验证):

  • 1(任意账号可触发 45 分钟 self-hosted job)已修/verify 现要求 PR 作者与评论者双方均具写权限,重复主体只查一次,API 错误或权限不足一律拒绝;8 个场景回放全过(路人拒绝、双写放行、作者无写拒绝、自评去重、404 fail-closed、/tmux/triage 行为不变)。
  • 2(转义后报告超 65,536 上限 → 422 → 无评论)已修emit_block 先转义再按转义后大小截断(报告上限 45,000),iconv -c 处理被字节切割劈开的 UTF-8 序列;50 KB 高密度 <>& 报告现在产出 45,873 字节评论体 + 截断注記,中文重载报告切割后解码无损。
  • 3(-2M 实为 1 MiB 上限、超限图片静默消失)已修:字节级精确 -size -2097153c(实测恰 2 MiB 收、+1 字节拒);字节必须带 PNG magic;重名去重;被丢弃图片在评论中显式计数。
  • 4 查找已钉死目录形态并排序;被劫持 agent 的运行时伪造属其固有能力范围,报告本身即标注为参考性证据。
  • 5 verify 侧全局安装已移至 RUNNER_TEMP 执行;tmux 同款问题留后续 PR。
  • 6(弱终态覆盖旧报告)已修:cancelled/infra/skipped/n-a 只替换本轮的"运行中"状态;旧报告存活,弱通知另发新评论;三臂矩阵回放通过。
  • 7 系列:rebase 身份、👀 移至 hosted authorize、重名碰撞、PNG magic、UTF-8 切割、双重 chown、worktree 指引与清扫均已修;verify/tmux 并发组经分析确认安全(单 runner 实例同时只跑一个 job,各实例 _work 独立);ECS runs-on 回退与 pr-assets 保留策略留待后续决策。

后续 PR 待办(review 建议的 tmux 侧同款问题):*-tmux-* 预埋产物清扫、emit_block 原始侧上限、.npmrc 暴露的全局安装、pr-assets 保留策略。

Comment thread .github/workflows/qwen-triage.yml
Comment thread .qwen/skills/verify-pr/SKILL.md Outdated
Comment thread .github/workflows/qwen-triage.yml
@wenshao

wenshao commented Jul 25, 2026

Copy link
Copy Markdown
Collaborator Author

Review — feat(triage): add sandboxed /verify deep-verification lane (round 2, head 1db0136cd)

Overview

Adds a comment-triggered deep-verification lane: verify (self-hosted, containerized, token-free agent behind a loopback model proxy) executes the PR's real build and runs the new verify-pr skill; publish-verify (hosted, no PR checkout, write PAT) upserts the report back as one comment. The isolation contract is a faithful clone of /tmux with three deliberate upgrades — fetch-depth: 2 for a local A/B base, .qwen pinned from HEAD^1 so the tree under test can't rewrite its own verifier, and an allowlisted agent verdict. The round-1 fixes all landed and hold up: dual author+commenter gate, escape-then-cap emit_block, byte-exact -size -2097153c, PNG-magic + name dedupe, npm -g from RUNNER_TEMP, weak-body upsert guard, 👀 moved to the hosted authorize job.

Verified locally (not just read)

  • Repo-exact actionlint (-shellcheck= -pyflakes= -ignore SC2002/SC2016/SC2129 … from scripts/lint.js) on the head workflow → clean (only the expected "reusable workflow not found" from my isolated copy).
  • All 11 run: blocks of authorize/verify/publish-verify, extracted with PyYAML → bash -n clean, shellcheck -S warning clean under the repo's ignore set.
  • Mergeability retry loop ([ "$mergeable" != "UNKNOWN" ] && break as the last command under set -euo pipefail) → replayed: does not trip errexit, so the UNKNOWN-after-retries branch is reachable as intended. ✅
  • emit_block escape-then-cap → replayed with a 250 KB report at max=45000. The truncation pipeline does die of SIGPIPE (141) under pipefail, but esc="$(A)" || esc="$(B)" is accidentally self-healing: A already assigned the 45 000-byte partial capture, so B re-truncates the short value and exits 0. Step survives, body = 45 130 B. ✅ (I chased this specifically because a set -e death there would resurrect exactly the stranded-"running"-comment bug round 1 fixed.)

Findings

1. (High) A runtime-planted tmp/*-verify-* dir beats the agent's real one — and sort makes the win deterministic

The planted-artifact sweep runs in Pin agent inputs from base (:1657), i.e. before Install and build PR app (:1669). That step runs npm ci and npm run build, both of which execute PR-controlled code — this repo's root package.json already wires postinstall: patch-package, prepare: node scripts/prepare.js, build: node scripts/build.js, and a PR can edit any of them. Anything they create under tmp/*-verify-* is still there when the collector runs at :1987.

All three selections then take the lexicographically first match:

  • :2008 VERDICT_FILE="$(find tmp … -path '*-verify-*/verdict.txt' | sort | head -1)"
  • :2278 REPORT="$(find verify-results … -path '*-verify-*/report.md' | sort | head -1)"
  • :2279 ASSERTIONS_FILE=… | sort | head -1

So a dir named tmp/0000-verify-x/ deterministically outranks the skill's tmp/pr<n>-verify-<ts>/. Replayed with the exact commands from the head revision (planted 0000-verify-planted alongside a real pr7710-verify-20260725-101010):

--- verify job verdict selection ---
picked: tmp/0000-verify-planted/verdict.txt -> merge-ready
--- publish-verify selection ---
report picked: verify-results/0000-verify-planted/report.md
# FABRICATED REPORT
All good, ship it.
assertions picked: verify-results/0000-verify-planted/assertions.json
{"pass":999,"fail":0,"total":999}

Result: the bot posts "Sandboxed verification: merge-ready (agent verdict) · 999 passed · 0 failed · 999 total" with attacker-authored prose, while the agent's real blocked report is discarded. The escaping and the "advisory, not a review" framing bound the blast radius to fabricated content — no HTML injection, no approval — but a forged bot attestation is precisely the attack this PR already hardens against for the pre-commit variant, so the gap is worth closing on the same commit. Note the round-1 sort fix (added for determinism) is what upgrades this from "nondeterministic race" to "guaranteed attacker win".

Suggested minimal fix

Re-sweep immediately before launching the agent, at the top of Run verification agent (:1716), after install/build has run:

# Install/build executed PR code; re-sweep so nothing it planted can be
# collected as the agent's report.
find tmp -maxdepth 2 -type d -name '*-verify-*' -exec rm -rf {} + 2>/dev/null || true

Fuller closure (also covers code the agent executes): let the workflow own the path instead of globbing for it — export QWEN_VERIFY_ARTIFACT_DIR="$RUNNER_TEMP/verify-out/pr${PR_NUMBER}-verify-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" into the agent env, have the skill write there, and collect exactly that path. A dir under $RUNNER_TEMP is outside the tree that build scripts roam, and the run-scoped name isn't guessable from a committed script.

2. (Medium) /verify on an outside contributor's PR is completely silent

The dual gate requires the PR author to hold write. For a fork PR from a non-collaborator — the majority case on this repo — a maintainer's @qwen-code /verify produces:

  • no 👀: the ack step (:173) is gated on steps.perm.outputs.should_run == 'true';
  • no run: verify.if requires needs.authorize.outputs.should_run == 'true';
  • no comment: publish-verify.if is always() && needs.verify.result != 'skipped' (:2055), and a job whose if is false reports skipped.

issue_comment runs don't surface on the PR's checks tab either, so the only trace is a step-summary line in a run nobody links to. This contradicts the PR's own stated principle — "/verify is always an explicit request, so silence would read as a lost run" — and it fires on the exact PRs where deep verification is most valuable. /tmux has the same shape, but /tmux never promised a receipt.

Suggested fix (keeps the gate, avoids opening a spam vector): have the perm step emit a deny_reason output plus a commenter_ok flag, and add a hosted step that posts a one-liner only when the commenter themself has write — e.g. "/verify needs write access for both the requester and the PR author (@author has read); the sandbox executes the author's code." Everything needed is already computed in that loop.

3. (Low, hardening — shared with the pre-existing /tmux collector) symlinks in the collected artifact tree

find tmp … -exec cp -r {} "$RUNNER_TEMP/verify-results/" (:1987, and :1179 for tmux) copies a directory that node fully controls, and the cp itself runs as root — the same process boundary that separates the agent from /proc/<proxy-pid>/environ, where REVIEW_OPENAI_API_KEY lives for the proxy's lifetime. GNU cp -R on bookworm does not dereference symlinks found during traversal, so this is not exploitable as written; but attacker-created symlinks do land in the upload directory, and actions/upload-artifact resolves symlinks when zipping — on a public repo those artifacts are world-downloadable. One line after the copy removes the whole question:

find "$RUNNER_TEMP/verify-results" -type l -delete 2>/dev/null || true

Nits

  • Free text after /verify is accepted and dropped. startsWith(body, '@qwen-code /verify ') triggers the lane, but the prompt is fixed (/verify-pr N --repo R), so @qwen-code /verify focus on the SSE retry path silently verifies whatever the skill picks. Same as /tmux today, so consistent — but worth either forwarding it as an explicitly-untrusted "requested focus" line or saying in the skill/docs that the suffix is ignored.
  • verify hardcodes runs-on: ['self-hosted', …, 'ecs-qwen'] (:1450) instead of the vars.MAINTAINER_ECS_RUNNER_DISABLED fallback that authorize/triage honor. Matches tmux-testing, and moving 👀 to the hosted job softens it, but with the pool off the requester gets 👀 and then nothing until the queue expires. Worth a comment noting it's intentional.
  • emit_block latent empty-render: in the truncation branch, if iconv were absent the first || arm captures nothing and the fallback re-truncates the now-empty esc, emitting an empty <pre><code> plus "...truncated". Unreachable on ubuntu-latest (glibc), so latent only.
  • pr-assets growth: every image-bearing run adds a permanent verify/pr<N>-<run>-<attempt>/ dir with no retention story. Bounded by the write-gate, but the branch only grows.

Verdict

The security architecture is sound and the round-1 fixes are real — I re-derived the two I was most suspicious of (SIGPIPE in the new cap path, errexit in the retry loop) and both hold. #1 is the one I'd want fixed before merge: it's a two-line change, it's the same threat class the PR already invested in, and shipping it means the lane's first published report can be forged by any PR that edits a build script. #2 is a UX gap that will be hit within days of merge. Everything else is optional.

中文说明

结论

整体架构可靠,第一轮的修复均已落地并经复核(我特意重跑了两处最可疑的:新的「先转义后截断」路径的 SIGPIPE 行为,以及 mergeability 重试循环里 [ … ] && break 是否触发 set -e——两者都没问题)。

本地实测(非仅阅读)

  • 仓库同款 actionlint 通过;authorize/verify/publish-verify 的全部 11 个 run: 块经 PyYAML 抽出后 bash -nshellcheck -S warning 全绿。
  • 重试循环 fall-through 到 UNKNOWN 分支可达 ✅。
  • emit_block:250 KB 报告 + max=45000 实测,截断管道确实因 SIGPIPE 返回 141,但 esc="$(A)" || esc="$(B)" 恰好自愈(A 已把 45000 字节部分输出赋给 esc,B 再截短即成功),步骤存活,body 45 130 字节 ✅。

发现

  1. (高)运行期预埋的 tmp/*-verify-* 目录会击败 agent 的真实产物,且 sort 让攻击者稳赢。 预埋清扫在 Pin agent inputs from base:1657)执行,而其后的 npm ci / npm run build:1669)会运行 PR 可控代码(本仓库根 package.json 已有 postinstall/prepare/build 脚本)。三处选取(:2008:2278:2279)都是 sort | head -1,因此 tmp/0000-verify-x/ 必然排在 tmp/pr<n>-verify-<ts>/ 之前。用 head 版本的原命令实测:伪造的 merge-ready + 999/999 + 假 report.md 全部被选中,真实的 blocked 报告被丢弃。转义与「仅供参考」的定位限制了危害范围(无 HTML 注入、不构成批准),但伪造 bot 背书正是本 PR 已为「预提交」变体加固的同一攻击类。最小修复:在 Run verification agent:1716)开头再清扫一次;更彻底的做法是由 workflow 指定 QWEN_VERIFY_ARTIFACT_DIR$RUNNER_TEMP 下含 run id 的路径)并只收集该路径。

  2. (中)对外部贡献者的 PR 执行 /verify 完全无声。 双方写权限门要求 PR 作者有写权限;fork PR 的作者通常没有,于是:无 👀(:173 要求 should_run == 'true')、job 被 skip、publish-verify:2055needs.verify.result != 'skipped')同样被 skip,且 issue_comment 的 run 不出现在 PR 检查列表 —— 与本 PR 自己的原则「显式请求绝不应得到沉默」相悖,且恰好命中最需要深度验证的那类 PR。建议:perm 步骤输出 deny_reasoncommenter_ok,仅当评论者本人有写权限时由 hosted 步骤回一句说明(避免被滥用刷评论)。

  3. (低,加固;与既有 /tmux 收集器共有) cp -r:1987)以 root 身份复制 node 完全可控的目录,而 root 正是能读到 /proc/<proxy-pid>/environ(其中有 REVIEW_OPENAI_API_KEY)的一侧。bookworm 的 GNU cp -R 默认不解引用,所以当前不可利用;但符号链接仍会进入上传目录,而 actions/upload-artifact 打包时会解引用,公开仓库的产物任何人可下载。复制后加一行 find "$RUNNER_TEMP/verify-results" -type l -delete 即可。

次要项

/verify 后的自由文本被接受但丢弃(与 /tmux 一致);verifyruns-on 硬编码绕过 MAINTAINER_ECS_RUNNER_DISABLED 回退(与 tmux job 一致);emit_blockiconv 缺失时会静默渲染空块(ubuntu-latest 上不可达);pr-assets 分支只增不减,缺少留存策略。

建议

#1 建议合并前修复(两行改动,且属于本 PR 已投入加固的同一威胁类:若不修,该车道发布的第一份报告就可能被任何改动构建脚本的 PR 伪造);#2 合并后数日内必然遇到;其余可选。


Reviewed at 1db0136cdd5ed2b0231dc8302c6648c818026d7b. Local evidence: repo-exact actionlint, 11 extracted run: blocks under bash -n + shellcheck -S warning, and replays of the artifact-selection, errexit-retry, and emit_block truncation paths.

…erify

Address review round 2 (comment 5079157987) and the CHANGES_REQUESTED
round on the verify lane:

- run step re-sweeps tmp/*-verify-* AFTER npm ci/build and before the
  agent starts: the pin step's sweep runs before PR lifecycle scripts
  (postinstall etc.), which could re-plant a fake artifact dir whose
  zeroed timestamp deterministically wins the sorted collector. From the
  sweep on, only the agent writes those dirs; a steered agent forging its
  own artifacts remains the documented advisory-report residual
- RUNNER_TEMP verify-results/verify-context are rm'd before mkdir: the
  pool is persistent and runner temp hygiene is runner-managed — a stale
  report or previous-report.md from ANOTHER PR must never ride along
- symlinks are stripped from verify-results before upload:
  actions/upload-artifact dereferences them, so a node-planted link would
  exfiltrate whatever it points at into the artifact
- a trusted commenter invoking /verify on a PR whose author lacks write
  now gets an explanation comment from the hosted authorize job instead
  of total silence (the commenter is checked first; drive-by accounts and
  API errors still get nothing); job timeout 45->60 so a slow install can
  never let the JOB limit kill the agent past its own graceful 25m budget
- stale tmp/base-tree (skill's canonical scratch worktree) is removed by
  name at job start — a plain dir isn't git-registered, so the worktree
  sweep alone misses it and the next worktree add would fail
- scripts/tests/qwen-triage-workflow.test.js gains a verify-lane describe
  block: an 8-arm stub-gh replay of the dual principal gate (drive-by
  deny, author-without-write deny + explain flag, self-comment dedupe,
  404 fail-closed, /tmux and /triage unchanged) plus guards for the
  post-prepare sweep placement, the symlink strip, and the RUNNER_TEMP
  resets — the replay found this commit's sweep edit had silently not
  applied, which is exactly the regression class it exists to catch
@wenshao

wenshao commented Jul 25, 2026

Copy link
Copy Markdown
Collaborator Author

Response to review round 2 (comment) — all three findings fixed in 844469dbc

Finding Resolution
High — runtime-planted artifact deterministically wins the collector (lifecycle scripts run after the pin sweep; 00000000 sorts ahead of real timestamps) The run step now re-sweeps tmp/*-verify-* after npm ci/npm run build and immediately before the agent launches — from that point only the agent writes those dirs, so the sorted selectors can no longer meet a plant. sort stays for determinism. The alternative (workflow-owned artifact dir under $RUNNER_TEMP) was considered and set aside: verify-results is node-writable during the agent phase anyway, so it offers the same trust envelope as a swept workspace dir at more plumbing. Residual: a steered agent forging its own artifacts — inherent to its power envelope, which is why the report is advisory and never a review. Placement is regression-tested (sweep must precede start_openai_proxy).
Medium — /verify on an untrusted-author PR is totally silent The gate now checks the commenter first; when the author check is what fails, the hosted authorize job posts a bilingual explanation ("author lacks write; the sandbox executes the author's code; use /triage instead"). Drive-by commenters and API-error denials stay silent — nothing is owed there, and it avoids handing an unauthenticated account a comment-trigger oracle. Covered by the replay test (explain flag asserted on exactly the trusted-commenter/untrusted-author arm).
Low — upload-artifact dereferences node-planted symlinks find "$RUNNER_TEMP/verify-results" -type l -delete runs between collection and upload; guarded by test.

Also from this round's overlap with the CHANGES_REQUESTED pass: $RUNNER_TEMP/verify-{results,context} are flushed before reuse (stale-run leakage on the persistent pool), job timeout 45→60 so the agent's graceful 25m budget survives slow installs, and the authorize principal routing got the 8-arm stub-gh replay test — which promptly caught an edit in this very commit that had silently failed to apply.

中文说明

第 2 轮三项发现已全部在 844469dbc 修复:

  • High(生命周期脚本可在 pin 清扫后重新预埋伪造产物目录,00000000 时间戳在排序下必胜):run 步骤在 npm ci/build 之后、agent 启动之前二次清扫 tmp/*-verify-*,此后只有 agent 会写这些目录;sort 保留用于确定性。评估过"workflow 专属 $RUNNER_TEMP 产物目录"方案后搁置——agent 阶段该目录同样是 node 可写的,信任包络相同而管线更复杂。残余风险(被劫持的 agent 自伪造产物)属其固有能力范围,报告因此定位为参考证据而非评审。清扫位置有回归测试。
  • Medium(作者无写权限时 /verify 完全静默):门禁改为先查评论者;当失败方是作者时,由常驻 hosted 的 authorize job 发布双语说明(作者缺写权限、沙箱执行作者代码、请改用 /triage)。路人评论者与 API 错误仍保持静默。回放测试断言 explain 标志只在"可信评论者 + 不可信作者"场景出现。
  • Low(upload-artifact 解引用 symlink):收集与上传之间删除全部符号链接,配测试。

另与 CHANGES_REQUESTED 轮重叠的修复:$RUNNER_TEMP 两目录复用前冲洗、job 超时 45→60、8 场景 stub-gh 回放测试守卫双主体门禁(该测试当场抓到本提交中一处未生效的编辑)。

@wenshao wenshao left a comment

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.

⚠️ Downgraded from Request changes to Comment: self-PR. Reviewed. Suggestions are inline. Not reviewed: reverse audit — five-round hard cap reached before two consecutive dry rounds.

— Codex GPT-5 via Qwen Code /review

Comment thread .github/workflows/qwen-triage.yml
Comment thread .qwen/skills/verify-pr/SKILL.md Outdated
Comment thread .github/workflows/qwen-triage.yml Outdated
Comment thread .github/workflows/qwen-triage.yml Outdated
Comment thread .github/workflows/qwen-triage.yml Outdated
Comment thread .github/workflows/qwen-triage.yml
Comment thread .github/workflows/qwen-triage.yml Outdated
Comment thread .github/workflows/qwen-triage.yml
Comment thread .github/workflows/qwen-triage.yml
Comment thread .github/workflows/qwen-triage.yml Outdated

@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 reviewed: coverage — no plan was given, so this run cannot show that any of the diff was read.

— qwen3.7-max via Qwen Code /review

Comment thread scripts/tests/qwen-triage-workflow.test.js

@wenshao wenshao left a comment

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.

⚠️ Downgraded from Request changes to Comment: self-PR. Reviewed. Suggestions are inline.

中文说明

⚠️ 已从请求修改降级为评论:self-PR。 已审查。 建议见行内评论。

— qwen3.8-max-preview via Qwen Code /review

Comment thread .github/workflows/qwen-triage.yml
Comment thread .github/workflows/qwen-triage.yml
Comment thread .github/workflows/qwen-triage.yml Outdated
Comment thread .github/workflows/qwen-triage.yml
… in /verify

Address the Codex /review round (19 findings) and the bot's follow-up.
Each fix was replayed locally; the proxy fix has a decisive A/B.

Gate and routing:
- the shell command match is case-insensitive: GitHub Actions expression
  comparisons ignore case, so `@QWEN-CODE /VERIFY` reached the step and
  fell through to the commenter-only branch — running the PR author's
  code with the author never checked
- the verify ack and denial notice require github.event.issue.pull_request:
  /verify on a plain issue was acknowledged but could never report
- publish-verify joins the verify job's per-PR concurrency group, and a
  failed PATCH falls back to posting fresh instead of going silent

Untrusted-input paths:
- the model proxy binds an EPHEMERAL port, reports it through a
  root-owned file, and its health check must echo a per-run nonce with
  the recorded PID alive. A/B with a squatter on 8787: the old code's
  proxy dies EADDRINUSE yet still reports enabled and points qwen at the
  squatter; the new code comes up unaffected on an ephemeral port
- worktree-scoped git config is deleted before hooksPath is resolved:
  `extensions.worktreeConfig` is allowlisted and .git/config.worktree is
  invisible to `git config --local`, so a prior run could set
  core.hooksPath=/ and make the hook sweep's recursive delete walk / as
  root (verified locally). The sweep now also refuses any hooks path
  outside the repository's git dir
- marker-comment lookups accept only bot-owned comments that START with
  the marker: any user can paste the marker and divert the bot into
  PATCHing a stranger's comment
- the upload staging dir is re-flushed after npm lifecycle scripts

Honest verdicts:
- the docs-only classifier no longer uses a pipeline (grep -q made the
  writer take SIGPIPE, so under pipefail a long file list with an early
  code file classified a code PR as docs-only and skipped verification),
  and executable markdown/YAML (.qwen, .github/workflows, scripts) is
  classified as behavioral before the extension rule
- tee's status is checked alongside qwen's: a full results volume made a
  truncated evidence stream publish as pass
- 137 is split by elapsed budget into watchdog timeout vs crash/OOM
- the agent's verdict is honored only for VERDICT=pass with a report and
  zero failed assertions; otherwise the process outcome headlines and
  the scope paragraph says the run did not complete
- verdict.txt is read through a bounded prefix (SIGPIPE under pipefail)

Skill contract corrections: per-commit tables only when the commits are
reachable at depth 2 (else aggregate + Not covered); internal workspace
symlinks must have their realpaths asserted before a base control is
trusted; repo lint gates and event-history cost math are qualified to
what the token-free container can actually run; --repo is never inferred
from `origin` (a fork holds a different PR under the same number).

Tests: 9 new guards, all mutation-verified (reverting each fix turns one
red), including an executable escaping/size-cap/UTF-8 test for the
publisher's own emit_block and a fix to the earlier command-file test,
which matched the tmux job's identically named step.
@wenshao

wenshao commented Jul 25, 2026

Copy link
Copy Markdown
Collaborator Author

Response to the Codex review round + bot follow-up — all 22 threads addressed in b92ebfc3c

Every inline thread has a per-item reply. Summary of what changed, and the two findings that turned out to be exploitable exactly as written:

Proven exploitable, now fixed with an A/B:

  • Fixed proxy port 8787. With a squatter listening (which PR lifecycle code can arrange, since it runs first), the control arm's real proxy dies EADDRINUSEand still reports openai_proxy=enabled (http://127.0.0.1:8787/v1), pointing the agent at the squatter's chat completions. The agent would then have authored its own "verification". Now: ephemeral port, published through a root-owned file, readiness requiring PID liveness + a per-run nonce echoed by /__health. New arm comes up on :53693 unaffected.
  • extensions.worktreeConfigcore.hooksPath=/. Reproduced locally: the key is invisible to git config --local --name-only --list, the extension itself is on the keep-list, and git rev-parse --git-path hooks duly returns / — pointing the hook sweep's recursive delete at the filesystem root as root. Now the worktree config file is deleted and the extension unset before hooksPath is resolved, and any hooks path that does not canonicalize under the repo's git dir is warned about, never swept.

Also fixed: case-insensitive command matching in the shell gate (GHA expressions ignore case, so @QWEN-CODE /VERIFY was reaching the commenter-only branch and running the author's code unchecked); docs-only classifier SIGPIPE (reproduced: 60k-entry list with an early code file → n/a) plus executable markdown/YAML classified as behavioral; tee status checked alongside qwen's; 137 split by elapsed budget into watchdog-timeout vs crash; agent verdict honored only for a clean, evidenced run, with a partial-run scope paragraph otherwise; marker comments matched by bot ownership + prefix with a post-fresh fallback; run-start status no longer overwrites a previous report; publish-verify in the verify job's per-PR concurrency group; PR-only guards on the ack and denial steps; bounded verdict read; unguarded evidence find; upload staging re-flushed after lifecycle scripts.

Skill contract corrections: per-commit tables only when the commits are reachable at depth 2; internal workspace symlink realpaths asserted before a base control is trusted; lint gates and event-history cost math qualified to what a token-free container can actually run; --repo never inferred from origin.

Deferred (recorded, not silently dropped): the head-controller-vs-opener TOCTOU (same shape /tmux has carried since it shipped; a real fix pins the head SHA through the job), and the tmux-side siblings — *-tmux-* planted artifacts, raw-side emit_block caps, the .npmrc-exposed global install, its own fixed-port proxy, and pr-assets retention.

Tests: 9 new guards, every one mutation-verified — reverting each fix turns exactly one test red — including an executable escaping/size-cap/UTF-8 test for the publisher's own emit_block, and a fix to the earlier command-file test, which had been matching the tmux job's identically named step (the same helper shadowing the review flagged). 27/27 pass; prettier, eslint, repo-exact actionlint and yamllint clean.

中文说明

Codex 轮 + bot 后续共 22 条线程已全部在 b92ebfc3c 处理,逐条均有行内回复。其中两条经复现确属可利用:

  • 固定代理端口 8787:PR 生命周期脚本先于代理运行,可先行占位。对照实验显示旧代码代理 EADDRINUSE 死亡却仍报告 enabled 并把 agent 指向占位进程——等于让攻击者撰写"验证结果"。现改为临时端口 + root 专属端口文件 + PID 存活 + 每轮 nonce 三重就绪判定,新代码在同场景下于 :53693 正常启动。
  • extensions.worktreeConfigcore.hooksPath=/:已本地复现——该键对 git config --local 不可见、扩展本身在保留白名单内、rev-parse --git-path hooks 确返回 /,使 hook 清扫的递归删除以 root 身份指向文件系统根。现在先删 worktree 配置文件并 unset 扩展再解析 hooks,且拒绝清扫无法规范化到仓库 git 目录内的路径。

其余已修:shell 门禁大小写不敏感(GHA 表达式忽略大小写,@QWEN-CODE /VERIFY 此前落入仅查评论者分支)、docs-only 判定的 SIGPIPE(已复现)与可执行文档判定、tee 状态检查、137 按耗时区分看门狗与崩溃、agent verdict 仅在干净且有证据的运行中采信(否则输出"未完成"表述)、标记评论按 bot 归属与前缀匹配且 PATCH 失败回退新发、起跑状态不再覆盖旧报告、publish-verify 并入按 PR 并发组、👀 与拒绝说明的 PR 限定、verdict 限长读取、evidence find 守卫、生命周期脚本后二次清空上传暂存目录。

Skill 契约修正:逐 commit 表格仅在 depth 2 可达时给出;base 对照需断言内部 workspace 依赖 realpath;lint 门禁与事件历史成本测算按无凭证容器实际能力限定;--repo 不再从 origin 推断。

明确顺延(非静默忽略):head 控制者与 opener 不一致的 TOCTOU(与 /tmux 同源,需将 head SHA 贯穿 job);tmux 侧同款问题(预埋产物、emit_block 原始侧上限、.npmrc 全局安装、其自身固定端口代理、pr-assets 保留策略)。

测试:新增 9 条守卫,全部经变异验证(逐一回退修复各使一条测试变红),含发布侧 emit_block 的可执行转义/限长/UTF-8 测试;并修正了上一轮那条实际匹配到 tmux 同名步骤的测试。27/27 通过,prettier、eslint、仓库同款 actionlint 与 yamllint 全绿。

@wenshao wenshao left a comment

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.

⚠️ Downgraded from Request changes to Comment: self-PR; CI failing: route. Reviewed. Suggestions are inline. Not reviewed: reverse audit — five-round hard cap reached before two consecutive dry rounds. Not reviewed: build-and-test — CI full-profile checks were skipped after route failed; Agent 7 selected no build/test command for the non-workspace files (the targeted workflow test was run separately: 27 passed).

— Codex GPT-5 via Qwen Code /review

Comment thread .github/workflows/qwen-triage.yml
Comment thread .qwen/skills/verify-pr/SKILL.md Outdated
Comment thread .qwen/skills/verify-pr/SKILL.md Outdated
Comment thread .github/workflows/qwen-triage.yml
Comment thread .github/workflows/qwen-triage.yml
Comment thread .qwen/skills/verify-pr/SKILL.md
Comment thread .github/workflows/qwen-triage.yml Outdated
Comment thread .github/workflows/qwen-triage.yml
Comment thread .github/workflows/qwen-triage.yml Outdated
Comment thread scripts/tests/qwen-triage-workflow.test.js

@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. Not reviewed: Invariant agent A: state, timers, collections — .github/workflows/qwen-triage.yml, Invariant agent B: counters, return values, error taxonomies — .github/workflows/qwen-triage.yml, Invariant agent C: config fields, early returns — .github/workflows/qwen-triage.yml — its prompt was built, but no agent on record was launched with it.

— qwen3.7-max via Qwen Code /review

@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 — no blockers. 2 Suggestion-level finding(s) could not be anchored to a changed line and were dropped; nothing further to act on here.

中文说明

已审查——无阻断问题。 2 条建议级发现无法锚定到改动行,已丢弃;此处无需进一步处理。

— qwen3.7-max via Qwen Code /review

…egressions

Fold techniques from the re-verification on #7709 that the skill had no
equivalent for:

- the mutation matrix must report the mutations that changed NOTHING, not
  only the ones that failed. Each survivor gets classified as an ordinary
  coverage gap or as dead code — a guard whose deletion leaves every test
  green is one of those two, and the difference is what the author needs.
  Survivors mirroring a pre-existing gap are labelled as such, and the set
  is framed as completeness reporting rather than merge conditions
- the sharper case that report demonstrates: a test that passes for the
  WRONG REASON. If deleting the new guard leaves its own new test green,
  that test is pinned by an earlier early-return, not by the change, and
  asserts nothing about it. Name what actually pins it
- and do not generalize from one dead guard to its siblings: the same
  report shows a clause that is unreachable on one path while being the
  only protection on another. Check each, report the contrast
- observability regressions: when a change suppresses output, follow the
  value before calling the suppression correct. A bare catch on the path
  plus a field with no readers anywhere in the repo means the cause is now
  unobservable even in devtools — a real loss that no behavioural
  assertion can see
- report structure gains a Corrections section: when an earlier round or
  bot comment described the code inaccurately, state the correct fact with
  evidence and label it as a correction to the description, not a request
  to change code. A wrong description left standing costs the next reader
  more than the original finding did

@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 — no blockers. 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.

中文说明

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

— qwen3.7-max via Qwen Code /review

PR_NUMBER: '${{ needs.tmux-testing.outputs.pr_number }}'
# Same reason as publish-verify: a tmux job cancelled while
# pending never evaluates its outputs.
PR_NUMBER: '${{ needs.tmux-testing.outputs.pr_number || github.event.issue.number }}'

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 tmux PR_NUMBER fallback (needs.tmux-testing.outputs.pr_number || github.event.issue.number) has no test asserting its presence, while the identical pattern in publish-verify is covered by the 'still identifies the PR when verify was cancelled before it started' test. — Failure scenario: a refactor removes the || github.event.issue.number fallback. When the tmux job is cancelled while pending, PR_NUMBER resolves to empty, the null guard fires (exit 0), and the result comment silently does not post.

Suggested change
PR_NUMBER: '${{ needs.tmux-testing.outputs.pr_number || github.event.issue.number }}'
PR_NUMBER: '${{ needs.tmux-testing.outputs.pr_number || github.event.issue.number }}' # tested: see publish-verify equivalent
中文说明

[Suggestion] tmux 的 PR_NUMBER 回退值(needs.tmux-testing.outputs.pr_number || github.event.issue.number)缺少断言其存在的测试,而 publish-verify 中完全相同的模式已被 'still identifies the PR when verify was cancelled before it started' 测试覆盖。— 失败场景:重构删除 || github.event.issue.number 回退。当 tmux 任务在等待中被取消时,PR_NUMBER 解析为空,空值守卫触发(exit 0),结果评论不会发布。

— qwen3.7-max via Qwen Code /review

@yiliang114 yiliang114 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Re-approve

The PR has gone through 19 commits of extensive security hardening since my initial review:

  • Close runtime-plant and stale-RUNNER_TEMP channels
  • Close proxy-hijack, gate-bypass, and false-verdict paths
  • Re-establish trust boundary after PR code runs
  • Repair PIPESTATUS read and six forgeable controls
  • Answer dropped /verify requests and prove proxy rejects
  • Resolve hooks hermetically and mirror symlink guards at job end
  • Fix silent drop and survivor accounting

The security posture has significantly improved. The earlier P1 (SKILL.md GFM rendering) and P2s have been addressed through iterative hardening. Production-ready.

@wenshao

wenshao commented Jul 26, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /triage

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM, looks ready to ship. ✅

@wenshao
wenshao added this pull request to the merge queue Jul 26, 2026
Merged via the queue into main with commit 883094d Jul 26, 2026
70 checks passed

@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 exact head 218aa08c3d7e933bfe7a58888efe356b23a29b0b. Requesting changes for three new Critical findings inline. The existing unresolved model-proxy credential-boundary Critical also still stands at this head.

Verification performed: exact pinned actions/checkout and actions/upload-artifact source inspection; safe temporary-directory reproductions for external core.worktree clean/reset and post-sweep symlink replanting; downstream tracing through Qwen's real shell environment sanitization; 59/59 targeted workflow tests; actionlint; yamllint. The green suite does not exercise these trust boundaries.

This PR has already exceeded roughly five review rounds, so I am intentionally not adding new Suggestion-level scope.

rm -f "$(git rev-parse --git-path config.worktree 2>/dev/null || echo /nonexistent)" 2>/dev/null || true
git config --local --unset-all extensions.worktreeConfig 2>/dev/null || true
git config --local --name-only --list 2>/dev/null \
| { grep -ivE '^(core\.(repositoryformatversion|bare|filemode|symlinks|ignorecase|precomposeunicode|logallrefupdates|worktree|hidedotfiles|protecthfs|protectntfs)|remote\.|branch\.|extensions\.|gc\.|pack\.|fetch\.|index\.|safe\.|submodule\.[^.]+\.(url|active|branch))' || 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.

[Critical] Preserve no attacker-controlled core.worktree before the root checkout. The previous run recursively chowns the workspace, including .git/config, to node, so PR code can persist core.worktree=/__w/_temp (or another mounted path). This allowlist explicitly keeps that key. On the next run, the pinned actions/checkout defaults clean=true; for an existing repository it runs git clean -ffdx and then git reset --hard HEAD, and Git applies both to the configured worktree rather than GITHUB_WORKSPACE.

A safe isolated replay with an external temporary worktree produced Would remove outside-untracked, and the actual clean deleted that file; reset likewise overwrote a tracked file in the external target. This crosses the repository boundary and lets one verification run make the next root-owned checkout delete or overwrite persistent runner paths. Unset core.worktree before any worktree-sensitive Git command (and preferably require git rev-parse --show-toplevel to resolve exactly to GITHUB_WORKSPACE) instead of preserving it here.

中文说明

[严重] 上一次运行可写 .git/config,能够植入指向 workspace 外部的 core.worktree;本白名单又保留该值。下一次 root 权限的 actions/checkout 会在该外部路径执行 git clean -ffdxgit reset --hard。临时目录回放已确认外部文件会被删除/覆盖。应在任何 worktree 相关 Git 操作前清除该键,并校验真实顶层目录就是 GITHUB_WORKSPACE

esac
STAGE_DIR="$(mktemp -d)"
git archive "$BASE_OID" -- .qwen | tar -x -C "$STAGE_DIR"
rm -rf .qwen

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] Keep the PR-side .qwen tree available as the subject under test. The resolver deliberately classifies .qwen/** as behavioral code that this lane exists to verify, but both pin passes replace the entire directory with HEAD^1. The skill simultaneously promises the agent that the working tree is the merge ref. For a future PR that changes another skill or project setting, normal filesystem reads and the head side of an A/B therefore see the base file; a .qwen-only PR can be compared base-vs-base and receive false clean evidence.

This is separate from correctly pinning verify-pr itself. Keep that verifier in a non-shadowable trusted location, while preserving (or separately staging and explicitly documenting) the PR's .qwen content for inspection and execution. Add an end-to-end fixture where a non-verifier .qwen file differs between base and head and prove the head cell observes the changed content.

中文说明

[严重] 解析器把 .qwen/** 视为本车道要验证的可执行行为,但这里把整个 .qwen 替换成 base,且 skill 又声称 working tree 就是 merge ref。未来修改其他 skill/配置的 PR 会在 head 侧实际读取 base 文件,甚至形成 base-vs-base 的伪绿证据。应只把 verifier 放到不可覆盖的可信位置,同时保留或单独暂存 PR 侧 .qwen 作为被测对象,并增加真实 A/B 回归用例。

# cp -r copies symlinks as symlinks (no deref), but
# actions/upload-artifact FOLLOWS them — a node-planted link would
# exfiltrate whatever it points at into the artifact. Drop links.
find "$RUNNER_TEMP/verify-results" -type l -delete 2>/dev/null || 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.

[Critical] Stop agent descendants before treating this one-time symlink sweep as an upload boundary. The pre-agent pkill only removes lifecycle descendants. Qwen then runs in YOLO mode as node, and a tool/test can launch a detached child that closes its stdio and survives the Qwen pipeline. verify-results was chowned to node; such a child can wait for this find ... -delete to remove a marker symlink and immediately replant a top-level link before the next upload-artifact step.

The exact pinned upload action sets followSymbolicLinks: true and uses fs.stat, so its root-running process dereferences the replanted link. A safe watcher replay deterministically restored a link after the sweep. That reopens root-readable file exfiltration into the artifact and leaves the final root cleanup racing a live PR-controlled process—the same reason the earlier lifecycle one-shot sweep was not sufficient. After Qwen exits, kill/fail closed on every remaining node process, then stage into a fresh root-owned, non-node-writable upload directory before stripping links and uploading.

中文说明

[严重] agent 以 node + YOLO 运行,可启动脱离会话的后台子进程;而上传目录仍归 node 所有。该子进程可等待本次一次性 symlink 删除完成后重新植入链接。固定版本的 upload-artifact 明确跟随符号链接,并以 root 读取目标,从而重新打开 artifact 越权读取与末尾 root 清理竞态。应在 agent 结束后再次终止并确认无 node 进程,再把产物冻结到 root 所有、node 不可写的新目录。

wenshao added a commit to wenshao/qwen-code that referenced this pull request Jul 27, 2026
…LM#7753)

* feat(triage): add sandboxed /verify deep-verification lane

@qwen-code /verify on a PR now runs a local-verification-style evidence
round in the isolated /tmux sandbox contract (container, token-free agent
env, loopback model proxy, author-write gate) and publishes the report via
a separate PR-code-free job:

- new verify job: merge-ref checkout at depth 2 (base tip + PR head for
  A/B), skills pinned from base so the tree under test can never rewrite
  its own verifier, PR-planted tmp/*-verify-* artifacts dropped, git
  exec-vector sweep for the persistent workspace, agent verdict
  allowlisted before it reaches workflow outputs
- new publish-verify job: upserts one marker comment (running status ->
  final report), HTML-escapes the untrusted report, reports skip/na/
  prepare-fail/infra outcomes explicitly since /verify is always an
  explicit request
- new verify-pr skill: A/B load-bearing proof, vacuity check on new
  tests, mock-free wire-oracle harnesses, targeted gates, fixed report/
  verdict/assertions artifact contract, counts-are-sacred rules
- triage skill Stage 2c now names /verify (not just /tmux) as the trigger
  to recommend when a PR's central claim needs behavioral evidence

The verify check-runs ride the issue_comment event, which the finalize
workflow's event == "pull_request" universe structurally excludes, so
they cannot pollute the CI table or the deferred-approval gate.

* feat(triage): teach /verify round continuity and artifact-matched methods

Fold two more hand-verification patterns into the verify lane:

- round continuity: the resolve step snapshots the previous verify report
  (if any) into the agent context before the status upsert overwrites it,
  and the skill re-checks each prior finding at the new head
  (fixed/stands/superseded), scoping new probes to the delta
- harness quality: prefer configuration seams over module interception,
  encode the upstream's real semantics in the fake peer, add decoy targets
- artifact-matched methods: per-commit load-bearing tables for multi-commit
  PRs; workflow/CI PRs get embedded-script replay against real data, repo
  lint gates, and day-one trigger cost math from real event history; every
  new config knob must trace to an observable effect, and default-path
  dispatch combinations get probed
- findings quality: blockers enumerate blast radius, demonstrate the
  sharpest consequence end-to-end when budget allows, and carry a collapsed
  minimal suggested fix preserving the original commit's intent

* feat(triage): host /verify evidence images and encode quantified-A/B rules

Borrow the image-evidence and quantified-verification patterns from
hand-run rounds (QwenLM#7265, QwenLM#7471, QwenLM#7686 r2 and the pr-assets convention):

- publish-verify now hosts agent-produced evidence/*.png on the pr-assets
  branch (verify/pr<N>-<run>-<attempt>/) and appends them below the
  escaped report. Untrusted-payload discipline: strict filename allowlist,
  8-image / 2 MB caps enforced in the find predicates, racing-push retry,
  and every failure degrades to a text-only comment. VERIFY_ASSETS_REMOTE
  is a test seam; the block was dry-run against a local bare remote
  covering hosting, hostile filenames, oversize files, dotfiles, missing
  branch, and no-image runs
- skill: evidence images are named as kebab-case captions binding image to
  claim, before/after pairs over lone after-shots; follow-up rounds lead
  with a previous-finding status table (fixed/stands/superseded/declined,
  with adjudication) and re-measure instead of diffing the old report;
  size/perf claims get measured-metric Δ tables with residual deltas
  accounted for; unreachable branches get the configuration that reaches
  them constructed; defensive guards get their accept path checked against
  real production artifacts, not just mocked rejects

* fix(triage): address /review suggestions on the verify lane

- skill: local invocation resolves --repo and passes it to every gh call
- skill: call out the dependency confound when the base A/B side reuses
  the PR-installed node_modules and the PR touches package.json/lockfile
- workflow: document the pin step's bootstrap logic — issue_comment jobs
  run the default branch's YAML, so base always carries the verify-pr
  skill by the time this job exists

* fix(triage): harden /verify gate, comment budget, and evidence hosting per review

Address review round 5078770575 items 1-3 plus the cheap follow-ups:

- authorize: /verify now requires write from BOTH the PR author (whose
  code runs) and the commenter (who spends a scarce runner slot + model
  budget) — a drive-by account can no longer burn 45 minutes of ecs-qwen
  on someone else's PR; duplicates check once; /tmux and /triage gates
  unchanged. Replayed 8 principal scenarios against a stubbed gh
- authorize acks /verify with the eyes reaction from the always-hosted
  job, so a queued/saturated sandbox pool no longer means total silence
- publish: emit_block escapes FIRST and caps the escaped size (45 KB for
  the report) — a raw-side cap let dense <>& content inflate past
  GitHub's 65,536-char comment limit, 422 the post, and strand the
  running status with no report at all; iconv -c keeps a UTF-8 sequence
  split by the byte cut (likely, given the mandated 中文 summary) from
  shipping broken; replayed: 50 KB dense report -> 45,873-byte body
- publish: image cap is byte-exact (-size -2097153c; find's -2M rounds
  sizes UP to MiB, silently making the documented 2 MB cap 1 MiB), bytes
  must carry the PNG magic (extension is attacker-choosable), duplicate
  sanitized names dedupe instead of overwriting + double-rendering, and
  dropped images are reported in the comment instead of vanishing
- publish: weak terminal notices (cancelled/infra/skipped/n-a) only
  replace this run's own running status; a previous round's real report
  survives as the marker comment and the notice posts fresh
- publish: report.md/assertions.json lookups pin the artifact-dir shape
  and sort (bare find -name order is filesystem-dependent); the verify
  job's verdict.txt lookup sorts likewise
- verify: global npm install runs from RUNNER_TEMP (the persistent
  workspace still holds the PREVIOUS run's tree, whose .npmrc would
  apply to a root install); both cleanup passes remove leftover tmp/
  worktrees (git worktree prune alone only drops metadata); the run step
  no longer re-chowns 50k node_modules files; pr-assets clone sets its
  committer identity once so the racing-push rebase retry can commit
- skill: worktree guidance now tells the agent to remove its base tree
  itself, with the workflow sweep as backstop only

* fix(triage): close runtime-plant and stale-RUNNER_TEMP channels in /verify

Address review round 2 (comment 5079157987) and the CHANGES_REQUESTED
round on the verify lane:

- run step re-sweeps tmp/*-verify-* AFTER npm ci/build and before the
  agent starts: the pin step's sweep runs before PR lifecycle scripts
  (postinstall etc.), which could re-plant a fake artifact dir whose
  zeroed timestamp deterministically wins the sorted collector. From the
  sweep on, only the agent writes those dirs; a steered agent forging its
  own artifacts remains the documented advisory-report residual
- RUNNER_TEMP verify-results/verify-context are rm'd before mkdir: the
  pool is persistent and runner temp hygiene is runner-managed — a stale
  report or previous-report.md from ANOTHER PR must never ride along
- symlinks are stripped from verify-results before upload:
  actions/upload-artifact dereferences them, so a node-planted link would
  exfiltrate whatever it points at into the artifact
- a trusted commenter invoking /verify on a PR whose author lacks write
  now gets an explanation comment from the hosted authorize job instead
  of total silence (the commenter is checked first; drive-by accounts and
  API errors still get nothing); job timeout 45->60 so a slow install can
  never let the JOB limit kill the agent past its own graceful 25m budget
- stale tmp/base-tree (skill's canonical scratch worktree) is removed by
  name at job start — a plain dir isn't git-registered, so the worktree
  sweep alone misses it and the next worktree add would fail
- scripts/tests/qwen-triage-workflow.test.js gains a verify-lane describe
  block: an 8-arm stub-gh replay of the dual principal gate (drive-by
  deny, author-without-write deny + explain flag, self-comment dedupe,
  404 fail-closed, /tmux and /triage unchanged) plus guards for the
  post-prepare sweep placement, the symlink strip, and the RUNNER_TEMP
  resets — the replay found this commit's sweep edit had silently not
  applied, which is exactly the regression class it exists to catch

* fix(triage): close proxy-hijack, gate-bypass, and false-verdict paths in /verify

Address the Codex /review round (19 findings) and the bot's follow-up.
Each fix was replayed locally; the proxy fix has a decisive A/B.

Gate and routing:
- the shell command match is case-insensitive: GitHub Actions expression
  comparisons ignore case, so `@QWEN-CODE /VERIFY` reached the step and
  fell through to the commenter-only branch — running the PR author's
  code with the author never checked
- the verify ack and denial notice require github.event.issue.pull_request:
  /verify on a plain issue was acknowledged but could never report
- publish-verify joins the verify job's per-PR concurrency group, and a
  failed PATCH falls back to posting fresh instead of going silent

Untrusted-input paths:
- the model proxy binds an EPHEMERAL port, reports it through a
  root-owned file, and its health check must echo a per-run nonce with
  the recorded PID alive. A/B with a squatter on 8787: the old code's
  proxy dies EADDRINUSE yet still reports enabled and points qwen at the
  squatter; the new code comes up unaffected on an ephemeral port
- worktree-scoped git config is deleted before hooksPath is resolved:
  `extensions.worktreeConfig` is allowlisted and .git/config.worktree is
  invisible to `git config --local`, so a prior run could set
  core.hooksPath=/ and make the hook sweep's recursive delete walk / as
  root (verified locally). The sweep now also refuses any hooks path
  outside the repository's git dir
- marker-comment lookups accept only bot-owned comments that START with
  the marker: any user can paste the marker and divert the bot into
  PATCHing a stranger's comment
- the upload staging dir is re-flushed after npm lifecycle scripts

Honest verdicts:
- the docs-only classifier no longer uses a pipeline (grep -q made the
  writer take SIGPIPE, so under pipefail a long file list with an early
  code file classified a code PR as docs-only and skipped verification),
  and executable markdown/YAML (.qwen, .github/workflows, scripts) is
  classified as behavioral before the extension rule
- tee's status is checked alongside qwen's: a full results volume made a
  truncated evidence stream publish as pass
- 137 is split by elapsed budget into watchdog timeout vs crash/OOM
- the agent's verdict is honored only for VERDICT=pass with a report and
  zero failed assertions; otherwise the process outcome headlines and
  the scope paragraph says the run did not complete
- verdict.txt is read through a bounded prefix (SIGPIPE under pipefail)

Skill contract corrections: per-commit tables only when the commits are
reachable at depth 2 (else aggregate + Not covered); internal workspace
symlinks must have their realpaths asserted before a base control is
trusted; repo lint gates and event-history cost math are qualified to
what the token-free container can actually run; --repo is never inferred
from `origin` (a fork holds a different PR under the same number).

Tests: 9 new guards, all mutation-verified (reverting each fix turns one
red), including an executable escaping/size-cap/UTF-8 test for the
publisher's own emit_block and a fix to the earlier command-file test,
which matched the tmux job's identically named step.

* fix(triage): re-establish the /verify trust boundary after PR code runs

Third review round (31 findings). The unifying defect: everything the
lane pinned or swept happened BEFORE npm ci/build executed PR-authored
lifecycle scripts as node, so each control could be undone afterwards.

Trust boundary, rebuilt in order before the agent starts:
- kill every process owned by the build user and fail the step if any
  survives — a detached postinstall child could otherwise wait out each
  one-shot sweep and re-plant afterwards
- re-pin .qwen from the base commit again, now root-owned and read-only:
  the prepare step chowns the workspace to node, so a lifecycle script
  could rewrite the very skill that defines /verify-pr
- give the agent a fresh HOME/QWEN_HOME: qwen loads user-scope file
  commands from $HOME/.qwen, and /home/node belongs to the build user,
  so a planted commands/verify-pr.toml could shadow the pinned skill
- the model proxy now requires a per-run bearer token, closing the
  blind-localhost-scan path to an unauthenticated signer for the real
  model credential (a command the agent itself launches still inherits
  it — documented residual, not closed)

Authorization and lifecycle:
- re-verify the PR author's write permission at execution time and pin
  the authorized head OID; refuse if the checked-out HEAD^2 differs, so
  a push during the runner wait cannot smuggle in unreviewed code
- validate each principal separately: an empty author vanished in word
  splitting and left only the commenter checked
- honor MAINTAINER_ECS_RUNNER_DISABLED with an explicit notice instead
  of queueing forever against a disabled pool
- status comments carry a machine state marker; inferring 'running' from
  prose let a report quoting that sentence be overwritten
- previous-report.md snapshots the newest substantive report, never a
  weak/cancelled notice, so prior findings survive into the next round
- bot-identity lookup failures fail closed instead of widening the
  ownership filter to every user's comments
- publish-verify uses a per-run concurrency group: a per-PR group holds
  only one pending job, so a second /verify could cancel a completed
  run's pending publisher

Correctness:
- install/build failures are classified: signals, ENOSPC, registry and
  network errors are infra-error, not a PR verdict
- watchdog classification measures the child's own elapsed time, not
  shell-global $SECONDS which includes proxy setup
- assertions.json must be three non-negative integers with a positive
  total and total == pass + fail before it counts as evidence
- the proxy keeps its upstream deadline armed until the body ends and
  aborts upstream when the client disconnects
- cleanups remove .qwen/tmp itself: PR code can make it a symlink, and
  globbing below it deleted the target's contents as root (verified)
- emit_block materializes the escaped text and truncates on a character
  boundary via node — iconv -c passes an incomplete trailing sequence
  through on BSD (measured), which the new test caught

Skill: local mode requires the same isolation CI provides and must not
assume HEAD^1/HEAD^2 on a plain head checkout; shallow boundaries make
rev-list counts unreliable for per-commit claims; never run
scripts/lint.js with no arguments (it runs prettier --write and rewrites
the tree under the harnesses); a vacuity check must fail the intended
assertion, not the import. pr-workflow.md now says both sandboxed lanes
need the author to have write, so triage stops recommending a
guaranteed denial on external PRs.

Tests: 9 more guards, all mutation-verified, including executable
replays of the docs-only classifier (SIGPIPE + executable-markdown
cases), the uppercase-command gate, the empty-principal deny, and the
untrusted-image hosting path against a bare pr-assets remote.

* test(triage): pass the classifier fixture through a file, not argv

The new docs-only classifier replay passed on macOS and failed on CI
with `Cannot read properties of undefined (reading 'trim')`: its
60,001-entry fixture is ~889 KB and was passed as a single argv element.
Linux caps one argument at MAX_ARG_STRLEN (128 KB), so the spawn failed
with E2BIG and stdout was undefined; macOS has no per-argument limit and
only a ~1 MB total, so the same call succeeded locally (verified both).

Write the list to a temp file and pass the path. The harness now also
asserts the spawn succeeded, so a future spawn failure reports itself
instead of surfacing as a TypeError on undefined output.

* fix(triage): make the /verify report match what the run actually produced

Three publisher findings, all introduced by my own previous round:

- an artifact download failure (the step is continue-on-error) let the
  full-report path run with no results: the headline read 'completed' and
  the scope paragraph claimed the A/B, the harnesses and the gates had
  run when nothing had been delivered. The download outcome is now an
  input, and its failure gets its own body saying the results could not
  be retrieved
- the prepare-failure branch ignored the verdict the prepare step had
  just computed, so an install killed by a registry outage or OOM
  (classified infra-error) still told the author 'this is treated as a
  PR failure verdict rather than an infrastructure failure' — the exact
  opposite. It now branches on the verdict, and an infra-classified
  prepare failure is a weak body that cannot overwrite a real report
- weak notices were being snapshotted as the follow-up round's
  previous-report.md: they lack the running marker, so 'newest
  non-running comment' selected them. Bodies that carry findings now
  mark themselves (qwen-triage:verify-substantive) and the snapshot
  selects on that marker. A/B on the real jq: report A then cancelled B
  now snapshots A (101), the old filter picked B (102)

Tests: 4 more guards, all mutation-verified — the publisher is rendered
for each outcome with a stubbed gh and the assertions read the body it
would post, and the snapshot test runs the workflow's own jq program
verbatim against a paginate-shaped fixture.

* fix(triage): stop PR build output from masquerading as an infra failure

Two review findings plus a test-helper hazard:

- classify_failure grepped the prepare log for bare words like ENOSPC
  and ETIMEDOUT, but that log is written by PR-controlled code: a
  genuine build failure that merely prints 'expected ETIMEDOUT to equal
  ok' would be published as an infrastructure incident, telling the
  author to re-run something that fails identically. The patterns are
  now anchored to lines only npm's reporter or the kernel emits
  ('npm ERR! code E…', 'npm ERR! network …', kernel OOM, bare 'Killed');
  a signal exit still needs no log evidence. Replayed 10 cells: four
  PR-authored logs quoting infra words stay 'fail', five real
  diagnostics and one signal exit are 'infra-error'
- the two execution-time controls added last round — re-verifying the
  author's permission after the runner wait, and refusing a head that
  moved since authorization — had no tests. Both are now executed:
  the re-auth snippet against a stubbed permission API (write proceeds
  and pins head_oid; read skips with a publishable reason), and the pin
  step against a real git repo with a real merge commit (matching head
  proceeds, moved head exits non-zero)
- add a stepIn(job, step) test helper. Several step names exist in both
  the tmux and verify jobs, and the unscoped step() returns the first
  match, so a verify-lane assertion silently tests the tmux copy — that
  has now bitten this suite three times, including in this commit.

* docs(triage): teach verify-pr test-only PRs, differential oracles, gate liveness

Fold techniques from the round-2 verification on QwenLM#7620 (an ANSI parser
PR) that the skill had no equivalent for:

- test-only PRs get their own method: a mutation A/B across TEST FILES
  (same mutants of the unmodified production file, only the test file
  swapped), reporting killed/total on both sides, requiring that no
  mutant regressed from killed to survived, checking that the killing
  assertion is the one the commit claims to have strengthened, and
  adjudicating every survivor as coverage gap or defect with independent
  evidence rather than by inspection
- when the code emulates a known implementation, that implementation is
  the oracle: feed identical input to both and report disagreement
  counts per side, lift reference tables verbatim out of the shipped
  dependency, and build the corpus from bytes captured off a real
  producer alongside synthesized sweeps
- prove a gate is live before citing it: plant a violation the linter
  must catch, confirm it is reported, remove it — a linter that matched
  no files exits 0 exactly like one that passed
- attribute pre-existing failures by byte-identical failing file AND
  test names on both sides, with deltas, not just totals
- when the base is far behind, verify the merge: trial-merge into
  current main, confirm it is conflict-free, and re-run the affected
  suite on the merged tree
- round continuity gains its one legitimate shortcut: a production file
  proven byte-identical (sha256 quoted at both heads) carries prior
  evidence forward by construction

* style(triage): reflow verify-pr skill to prettier's markdown wrapping

The previous commit's added paragraphs were hand-wrapped and prettier
--check flagged the file; the repo runs prettier over all of it.

* test(triage): cover the disabled-runner-pool notice

The kill-switch path had no test: a refactor could drop the notice and
leave a /verify request acknowledged with 👀 but permanently unanswered,
since the verify job refuses to start and publish-verify skips with it.

Fold the step into the existing PR-guard loop (now scoped through
stepIn, so it cannot match a same-named step in another job) and assert
the parts that make the answer useful — the kill-switch and permission
conditions, both languages, the alternative it points at, and the verify
job's own exclusion of the disabled pool. All three mutations turn it
red: removing the step, dropping its PR guard, or letting the verify job
queue against the disabled pool.

* fix(triage): repair a step-killing PIPESTATUS read and six forgeable controls

Sixth review round, 12 findings. Several are regressions from my own two
previous rounds; the first would have broken every single run.

- `AGENT_STATUS=${PIPESTATUS[0]}` is itself a command and resets
  PIPESTATUS, so the next line's ${PIPESTATUS[1]} was unset and `set -u`
  aborted the step immediately after the agent finished — before artifact
  collection, the verdict, or anything else. Verified by replaying the
  exact structure: 'PIPESTATUS[1]: unbound variable'. Both elements are
  now snapshotted in one command
- concurrency predicates were broader than the job conditions they guard,
  and GitHub evaluates concurrency BEFORE the job `if`: a /verify comment
  entered the triage job's shared per-PR group (where it could displace a
  pending /triage and then skip), and a /verify queued while the runner
  kill switch was on did the same to a real verification. Both predicates
  now match their job's runnable set exactly
- an outward-resolving .git/hooks entry was only warned about and left in
  place, so the next root-owned git command would run it. It is now
  unlinked without traversing its target, a root-owned hooks directory is
  restored, and core.hooksPath is unset
- the second .qwen pin re-derived HEAD^1 from git metadata after the
  workspace, including .git, had been handed to the build user. The base
  OID is now recorded while .git is still root-owned and the re-pin
  archives that content-addressed OID
- classify_failure took both of its inputs from PR-controlled sources: a
  lifecycle script can exit with a signal status and can print any line
  the log patterns matched, turning its own deterministic breakage into
  'infrastructure, please re-run' — which hid the failure and preserved a
  stale report. No infra verdict is derivable there, so the prepare step
  reports `fail` and lets the embedded log speak for itself
- cleanups descended through PR-writable parents: `.qwen` itself can be a
  symlink, and the worktree sweep trusted git metadata with only a lexical
  prefix check. Symlinks are unlinked without traversal and worktree paths
  must canonicalize inside the workspace. Replayed all three escapes
- skipped and docs-only outcomes upload no artifact, so the new
  download-failure branch pre-empted them and made their real reason
  unreachable; they are answered first now
- a run that crashed before writing report.md still claimed the
  substantive marker, letting a headline overwrite the previous round's
  evidence. The marker now requires a report

Skill: the byte-identical shortcut needs the whole input closure, not one
file hash; the credential-free local path cannot call `gh` at all (fetch
the metadata outside and mount it read-only); and the A/B base is
`baseRefOid` in local mode, not `HEAD^1`.

Tests: 7 new guards plus 4 updated to the new shapes, all
mutation-verified (50/50).

* fix(triage): answer dropped /verify requests and prove the proxy rejects

Maintainer review (yiliang114), 7 items:

- a third /verify while two runs are in flight is dropped by the
  concurrency group with no job and therefore no comment. The hosted
  authorize job now counts this workflow's other in-flight runs and says
  so; an API hiccup leaves the request alone rather than denying it
- the proxy's bearer check had no executable test. It now starts the real
  proxy against a real upstream and issues real requests: no header and
  a wrong token are 401, this run's token is 200, and a route other than
  /chat/completions is 403 — with the health endpoint echoing the nonce
- the 502 path forwarded the raw upstream error, which can name resolved
  hosts and TLS detail to PR code. It logs server-side and returns a
  generic failure
- publish-verify inherited the 360-minute default; it downloads one
  artifact and posts one comment, so it is bounded at 10
- removing the log classifier last round left the comment block it
  replaced, which still said failures are classified from the exit status
  and the log. Deleted
- that removal also left every install failure reported as the PR's
  fault, including a registry outage. There is exactly one signal here PR
  code cannot write — asking the registry ourselves, as root, with the
  container's resolver — so an install failure is downgraded to
  infra-error only when that probe fails. It proves reachability now
  rather than at failure time, so it can only ever downgrade, never
  confirm; a build failure has no equivalent and stays the tree's problem
- the skill's local-invocation warning ran into the preceding sentence,
  which GFM renders as one paragraph

Tests: 5 new guards, all mutation-verified (55/55).

* fix(triage): resolve hooks hermetically and mirror symlink guards at job end

Maintainer review round (doudouOUC), 6 findings. Two were Critical and
both reproduced:

- the hooks sweep resolved its path with the ambient git config in play.
  With a global core.hooksPath set — which the reviewer has and I do not,
  which is why my earlier replay showed a false pass — `git rev-parse
  --git-path hooks` returns that global path, the in-git-dir guard reads
  'outside', and a planted `.git/hooks` symlink survives untouched. A/B:
  old code leaves the symlink under a global hooksPath, new code removes
  it in both environments and never touches the link target. Resolution
  now runs with GIT_CONFIG_GLOBAL and GIT_CONFIG_SYSTEM pointed at
  /dev/null
- the END-of-job cleanup still used the bare `rm -rf .qwen/tmp` that the
  start-of-job cleaner was hardened against two rounds ago. The agent
  executes PR code between the two, so the end is no safer than the
  start: it now unlinks symlinks without descending and canonicalizes
  worktree paths inside the workspace before deleting

Plus four suggestions, all valid:

- the saturation notice counted this workflow's in-flight runs across
  every PR while the concurrency group is per-PR, so a run on another PR
  would trigger a warning about a queue that does not exist. It now
  matches on the PR title (the only per-PR handle an issue_comment run
  record carries) and stays silent when that cannot be resolved
- the skill recommended `require.resolve` for the workspace-realpath
  check; these packages are ESM-only with import-only exports, so it
  throws ERR_PACKAGE_PATH_NOT_EXPORTED and reads like a missing module.
  Verified, and replaced with `readlink -f node_modules/@qwen-code/...`
- the symlink-escape test inherited the developer's git config, which is
  what hid the first finding. It now runs with global/system config
  neutralized AND repeats the case with a global core.hooksPath planted
- the publisher's build-phase arm was never rendered by any test (every
  case used 'install'), so a typo in that command name would have
  shipped. Now covered, along with an unrecognized phase

Mutation-verified 4/4. The hooks guard needed a discriminating assertion:
git's own `*.sample` files must survive the sweep, because the
outward-path fallback removes the whole directory and would otherwise
satisfy a bare 'planted hook is gone' check.

* fix(triage): count only /verify runs for saturation, and test the PATCH arm

Bot review round, 2 suggestions, both valid:

- the saturation notice matched runs by PR title, which narrowed to this
  PR but not to /verify. /triage and /tmux live in their own concurrency
  groups, so two of those in flight would warn about a verify queue that
  is actually empty. It now also requires the run to have a job named
  'verify' — the run record carries no command, but its job list does.
  Replayed: two non-verify runs stay silent, two verify runs warn
- every publish fixture returned an empty comments listing, so the PATCH
  arm was never executed: a broken PATCH would have stranded the running
  status comment and posted a duplicate below it, with the suite green.
  The publisher now runs against a stubbed listing and the test asserts
  which verb went to which comment id — bot-owned live status is PATCHed
  in place, an absent comment posts fresh, and a marker comment owned by
  someone else is left alone and posted around

Mutation-verified 3/3: counting every command, never PATCHing, and
accepting foreign-owned markers each turn one test red.

Two stub bugs found while writing these, both mine and both silent:
${*#pattern} applies per positional parameter rather than to the joined
string (yielding a wrong run id), and the paginate fixture needs one
array per page, not an array of pages.

* fix(triage): fix the real silent drop and drop the step built on a wrong premise

Review round 4. The blocker was mine twice over: the saturation notice I
added last round had GitHub's concurrency semantics backwards, and the
silent drop it claimed to cover was somewhere else entirely.

- GitHub cancels the OLDER pending run in a group and admits the new one
  (confirmed against the workflow-syntax reference). My step told the
  person who had just typed /verify that their request might be dropped,
  when theirs is the one that runs — and said nothing to the person whose
  queued run actually died. This PR already had it right in
  publish-verify's own comment, so the file contradicted itself and the
  user-facing copy followed the wrong half. The step is removed rather
  than reworded: with the fix below there is nothing left for it to warn
  about, and it cost 2+N API calls on every /verify.
- the actual drop: a verify job cancelled while still PENDING never
  reaches a runner, so its outputs block — where the
  "|| github.event.issue.number" fallback lived — is never evaluated.
  publish-verify then read an empty PR_NUMBER, hit its own guard and
  exited 0, making the cancelled branch unreachable in exactly the
  scenario that produces cancellations. The fallback now lives where the
  value is read. Reproduced both arms by executing the real step: with a
  number the cancelled notice posts, with an empty one it only warns.
- same one-line class in publish-tmux, fixed alongside.

Two copy defects from the classifier removal, both mis-attribution
pointed the other way:

- the infra-error body still named a signal/OOM kill and a full disk,
  none of which the current prepare step can produce — infra-error now
  requires npm ci to fail AND the registry probe to fail. It names that
  condition only, and offers a re-run instead of asserting it is the fix.
- the code comment above it still described the deleted classifier.

Also fixes the indentation break an earlier scripted edit left in the
publish body builder, and replaces the saturation test with one that
executes the cancelled path. Mutation-verified 2/2; the copy needed its
own guard, since reverting the wording alone left every test green.

* docs(triage): teach verify-pr survivor accounting and observability regressions

Fold techniques from the re-verification on QwenLM#7709 that the skill had no
equivalent for:

- the mutation matrix must report the mutations that changed NOTHING, not
  only the ones that failed. Each survivor gets classified as an ordinary
  coverage gap or as dead code — a guard whose deletion leaves every test
  green is one of those two, and the difference is what the author needs.
  Survivors mirroring a pre-existing gap are labelled as such, and the set
  is framed as completeness reporting rather than merge conditions
- the sharper case that report demonstrates: a test that passes for the
  WRONG REASON. If deleting the new guard leaves its own new test green,
  that test is pinned by an earlier early-return, not by the change, and
  asserts nothing about it. Name what actually pins it
- and do not generalize from one dead guard to its siblings: the same
  report shows a clause that is unreachable on one path while being the
  only protection on another. Check each, report the contrast
- observability regressions: when a change suppresses output, follow the
  value before calling the suppression correct. A bare catch on the path
  plus a field with no readers anywhere in the repo means the cause is now
  unobservable even in devtools — a real loss that no behavioural
  assertion can see
- report structure gains a Corrections section: when an earlier round or
  bot comment described the code inaccurately, state the correct fact with
  evidence and label it as a correction to the description, not a request
  to change code. A wrong description left standing costs the next reader
  more than the original finding did

* fix(triage): carry the /verify lane's hardening across to /tmux

The /tmux job executes the same untrusted PR code, as the same user, on the
same persistent self-hosted pool as the /verify lane that QwenLM#7710 hardened.
Five of those controls had no equivalent here. Each was found on the verify
side by reproducing an attack or a failure, not by reading the code, so the
same evidence applies unchanged.

- the model proxy bound a FIXED port (8787). PR lifecycle scripts run before
  it, so a detached child can squat that port: the real proxy then dies with
  EADDRINUSE while the health probe succeeds against the squatter, and the
  agent takes its chat completions. Now an ephemeral port published through
  a root-owned file, a per-run nonce the health endpoint must echo, and a
  liveness check on the PID we started. Replayed with 8787 occupied: the
  proxy comes up on an OS-chosen port and answers with the nonce.
- nothing swept planted artifact directories. npm ci/build run the PR's
  lifecycle scripts, which can create tmp/<name>-tmux-<ts>/ holding a
  report.md and a transcript; the collector globs *-tmux-* and the publisher
  takes the first match, so a planted directory could supply the comment's
  contents. Swept after the last PR-controlled process and before the agent.
- the global npm install ran with the workspace as cwd, where the PREVIOUS
  run's checked-out tree still sits. npm reads a cwd .npmrc, and a
  --registry flag does not override script-shell or hooks, so that config
  reached a root-privileged install. It now runs from RUNNER_TEMP.
- the end-of-job cleanup globbed below .qwen/tmp. PR code ran in this
  workspace, so either .qwen or .qwen/tmp can be a symlink out of the tree —
  verified on the verify lane, where the glob deleted the link target's
  contents as root. Symlinks are unlinked without descending.
- emit_block capped the raw log then escaped it. Escaping inflates every
  & < > by 4-5 bytes, so dense content can push the assembled body past
  GitHub's 65,536-character comment limit, 422 the post, and leave no
  comment at all. It now escapes first, caps the escaped bytes, and
  truncates on a character boundary via node — BSD iconv -c passes an
  incomplete trailing UTF-8 sequence through unchanged.

Tests: a tmux-lane-parity suite, all six mutations verified (restoring the
fixed port, dropping the sweep, moving the install back, dropping the
symlink guard, reverting to a raw-side cap, and dropping the
character-boundary truncation each turn one test red; a no-op control
correctly changes nothing). One pre-existing assertion updated: it pinned
emit_block's old inline-capture shape, and the guarantee it protects —
a render failure is caught — is asserted in the new form.

Also adds the regression guard for the publish-tmux PR_NUMBER fallback that
landed in QwenLM#7710 without one: a job cancelled while pending never evaluates
its outputs, so without the fallback the result comment silently does not
post.

* fix(triage): address review — symlink guard, artifact strip, bearer auth (QwenLM#7753)

* fix(triage): address R2 review — proxy parity, bearer wire tests, process kill (QwenLM#7753)

* fix(triage): address R3 review — publisher parity, dedup ownership, cap budget tests (QwenLM#7753)

* fix(triage): address R4 review — drop redundant tmux-lane .mjs guards (QwenLM#7753)

* fix(triage): address R5 review — tmp symlink sweep guard, proxy timer clear (QwenLM#7753)

* fix(triage): address R6 review — hoist proxy timer out of try, dead-upstream 502 tests (QwenLM#7753)

* fix(triage): address R7 review — make proxy watchdog idle, end stalled response (QwenLM#7753)

---------

Co-authored-by: wenshao <wenshao@example.com>
Co-authored-by: qwen-code-dev-bot <qwen-code-dev-bot@users.noreply.github.com>
Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com>
@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Released in v0.21.1.

@yiliang114

yiliang114 commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

This is just the CI bot confirming that PR #7710 (feat(triage): add sandboxed /verify deep-verification lane) has been released in v0.21.1. No code changes or reply needed — purely informational.

Acknowledged. ✅


✅ completed

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.

5 participants