Skip to content

fix(review): prove the diff was read, build every agent's prompt, and compute the verdict - #6892

Merged
wenshao merged 13 commits into
mainfrom
fix/review-coverage-both-topologies
Jul 15, 2026
Merged

fix(review): prove the diff was read, build every agent's prompt, and compute the verdict#6892
wenshao merged 13 commits into
mainfrom
fix/review-coverage-both-topologies

Conversation

@wenshao

@wenshao wenshao commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator

What this PR does

/review now proves it read the diff, builds every agent's prompt in code, and computes its own verdict. Seven defects were found across six rounds of dogfooding against real pull requests of this repo, each one measured against the harness's own per-agent transcripts — what each agent was actually launched with, and what it actually did — rather than against what the run said about itself.

The verdict a small pull request got was a lie. Coverage was attributed by one question: did an agent whose launch prompt says chunk N of M make a successful tool call? No Step 3A prompt ever says that — there, every dimension agent walks the whole diff. Run against a real 3A review whose twelve agents each opened the diff, walked both chunks and filed findings, check-coverage returned Coverage: 0/2 chunk(s) reviewed. 16 agent(s) ran; 16 did work followed by ERROR: 2 chunk(s) were not reviewed. Nobody read those lines. Both sentences cannot be true. compose-review runs the same computation on the way to the verdict, so that review was capped away from Approve and told, in the body it would have posted to the pull request, that nobody had read it. Step 3A is the topology most pull requests get; the only reason it never blew up is that check-coverage lived inside Step 3B and was never reached from 3A — two bugs cancelling. Coverage is now the intersection of two things the harness wrote down: the lines each agent was pointed at, and the fact that it opened the diff. Topology-blind.

Half the fan-out was still being launched blind. agent-prompt built the territory agents' prompts and left the rest to prose. All three whole-diff agents of a real 3B run — cross-file tracer, test-coverage matrix, build & test — got a prompt naming no diff file at all. The test-coverage matrix was told to "Read the diff chunks" and given no path to read them from; it read the post-change source instead, which on a deletion shows it nothing.

Agent 0 was never launched, and nothing could tell. Every check in the skill asks a question of an agent that ran. An agent that does not run leaves no transcript to ask, so an omission is invisible precisely because it is an omission. check-coverage now derives a roster from the plan — which the caller does not write — and names every required agent that never ran, with the exact agent-prompt call that builds it.

The prompt was rewritten on the way to the agent, and then it grew too big to carry at all. One run invoked agent-prompt correctly for all five chunks and then paraphrased what it printed — keeping the read_file line (so every other check passed it) and dropping the rule against reciting a stock sentence, the half-read warning, and the project's review rules. The next, with the briefs welded into the launch prompt, delivered 2 893 characters of a 4 652-character prompt, then read the check's exit-3, concluded "the agents clearly did their job", skipped compose-review, and filed an Approve it had written itself. A 17-chunk Step 3B review would have asked the orchestrator to paste 87 546 characters in one response. So the brief now goes where the diff already goes — on disk, read by the agent — and the launch prompt drops to ~500-800 characters. Whether the agent read its brief is a tool call the harness recorded, not a hope.

The verdict was the model's to write. compose-review computed the event and body, and the skill then told the orchestrator to "copy event/body verbatim into the review JSON" — a transcription, into a document the model writes, of a decision the CLI had already made. submit composes now. It takes the findings and derives everything that follows, including how many blockers there are, by counting the **[Critical]** / **[Suggestion]** prefixes of the comments actually attached rather than believing a number typed beside them. A payload carrying event/body is refused.

SKILL.md drops 171 → 154 KB, and three things had never reached an agent at all. The briefs were duplicated between the skill and the code; the skill now keeps what each agent is for and drops what it is sent. Removing the prose surfaced that the Exclusion Criteria (the largest precision control in the review) had never been delivered to any agent — the skill states them at the end of the document and tells the orchestrator to apply them, and the agents do not read the document. Nor had the anchor rules (resolve-anchors was downstream of a snippet nobody had told the agents how to produce), nor the severity calibration that SEVERITY's own comment says is needed.

Path-scoped rules: .github/workflows. The dimensions are domain-blind by design, which holds until a file's failure modes are not guessable from reading it. A workflow is YAML, so it reads as configuration, and the reviewer who treats it as configuration misses every one of its attack classes — including a pull_request_target job that checks out the contributor's head, which is the difference between a CI file and a remote code execution with the repository's write token. This repo runs qwen-autofix.yml, which posts to pull requests. A checklist is now appended to the brief of every code-reviewing agent whose territory actually contains a matching file.

Why it's needed

The line running through every defect is the one this skill has now re-learned seven times: a rule stated in prose is a rule that will eventually not be followed, and the fix is to move it into code that can say no. The skill had already applied that to the review target, the posting gate, the verdict composition and the coverage report — and left it unapplied in the four places that turned out to matter most: the agents' prompts, the roster of who must exist, the terminal verdict, and the rules the agents were never actually sent.

Concretely, before this PR: a Step 3A review could not reach Approve and would have published a false claim; the only agents covering cross-file tracing, cross-chunk removed-behaviour and the test matrix had never opened the diff; issue fidelity could be skipped silently; and a run that skipped compose-review could print — and post — a verdict of its own.

Two of the fixes were themselves caught by dogfooding and fixed in this PR, which is the point of the method:

  • The delivery check was crying wolf. It was a substring test, and on a Step 3B review it failed all nine agents — for two entirely legitimate differences: the orchestrator had inserted the one-sentence summary of the change that the skill explicitly tells it to add, and had reflowed a hard-wrapped sentence onto one line. A gate that fires on a correct run is a gate that gets talked around, and this PR contains the transcript of a model doing exactly that. The rule is now the one the skill states: you may add; you may not remove, alter, or reorder.
  • An invariant agent was handed the whole chunk plan. It owns one heavily-rewritten file. Coverage is computed from the ranges in the launch prompt, so an invariant agent was being credited with reading every chunk in the review — one of them could have masked twenty missing chunk agents.

Reviewer Test Plan

How to verify

Nothing here is verified by a review saying it went well. Each run below was checked afterwards by reading the harness's per-agent transcripts (<projectDir>/subagents/<sessionId>/agent-*.jsonl, written at launch and not retconnable) and asking, per agent: is the prompt it was launched with byte-for-byte the one the CLI built, and did it open what it was pointed at?

To reproduce any of them:

npm run build && npm run bundle
# put the repo build on PATH so the skill's own `qwen review …` calls resolve to it
qwen --yolo            # then: /review <pr-number>

Unit tests for the whole surface:

npx vitest run --root packages/cli src/commands/review     # 557 passed
npx vitest run --root packages/core src/skills/bundled-skills
npx tsc --noEmit -p packages/cli/tsconfig.json

Evidence (Before & After)

The live bug, replayed against a real Step 3A review's transcripts (twelve agents that each opened the diff, walked both chunks and filed findings):

BEFORE   Coverage: 0/2 chunk(s) reviewed. 16 agent(s) ran; 16 did work
         ERROR: 2 chunk(s) were not reviewed — 1, 2. Nobody read those lines.   exit 3

AFTER    Coverage: 2/2 chunk(s) reviewed. 17 agent(s) ran; 17 did work          exit 0

The prompt-rewrite check, replayed against the Step 3B run that paraphrased its prompts — all five chunk agents named, which nothing in the run could see before, because a paraphrase keeps the diff path:

ERROR: 5 agent(s) were not launched with the prompt this CLI built for them —
       chunk 1 … chunk 5 — launched with a prompt that is not the one the CLI built.

The roster, replayed against the run that never launched issue fidelity:

ERROR: 9 required agent(s) never ran — Agent 0: Issue fidelity & root-cause ownership
       — no prompt was built for it (`agent-prompt --role 0` never ran); …

The carrying problem, on a real 17-chunk PR: 17 chunk launch prompts × ~5 149 chars = 87 546 characters in one response → 14 789 after the briefs moved to disk.

End-to-end runs, all verified from the transcripts:

Run Topology Result
/review 6847 3A, 12 roles 12/12 delivered intact, 12/12 opened their brief, 3–19 successful tool calls each — Agent 0 among them. Step 3D: 1/1 chunks, 12/12 did work.
/review 6766 3B, 5 chunks + 4 roles 9/9 intact, 9/9 opened their brief. Step 3D: 5/5 chunks, every list empty, exit 0.
/review 6457 3B, 21 chunks + a heavy file → 29 agents 29/29 intact, 29/29 opened their brief. Step 3D: 21/21 chunks, 30/30 did work, no errors. Invariant agent A found a real cross-line defect no chunk agent can see: retries exhausted → return, but the 60-second reconnect timer is armed unconditionally forty lines away, so it logs "giving up" every minute and never retries.
/review --effort high (local) on a foreign project with a planted vulnerability 3A, local roster Scored against a held-out answer key: pull_request_target + PR-head checkout ✅ Critical (with the postinstall attack chain); ${{ pull_request.title }} into run:Critical (plus a $GITHUB_OUTPUT injection I had not planted); unpinned third-party action ✅ Suggestion; actions/checkout@v4 correctly not reported; a planted falsy-value bug ✅ Critical with an exact repro. Zero false positives; no noise on the non-workflow file.
/review 6788 3A, verdict path Called compose-review, was told Verdict: Comment, and showed the user "Comment — downgraded from Approve (CI failing: route)" — the presubmit downgrade applied by code, on a run that did not post.

The posting gate, at the wire:

# a payload with a hand-written verdict
$ qwen review submit … --review forged.json --user-authorized --dry-run
Error: the payload carries `event`/`body`. Those are computed here … they are not inputs.

# the same findings, no verdict
$ qwen review submit … --review honest.json --user-authorized --dry-run
{ "wouldPost": true, "event": "COMMENT" }        # not APPROVE — an unreviewed dimension capped it

Tested on

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

Environment (optional)

Repo build (npm run build && npm run bundle) driven through a real TUI in tmux, model qwen3.7-max. All dogfood runs against live pull requests of this repository; the foreign-project run against a throwaway git repo outside the tree.

Risk & Scope

  • Main risk or tradeoff: the agents' briefs move from SKILL.md into packages/cli/src/commands/review/lib/agent-briefs.ts, so a change to what an agent is told is now a code change, not a prose edit. That is the intent — the prose did not survive the trip — but it does mean the skill and the code must not drift back apart. The skill now states which one is authoritative.
  • Not validated / out of scope: --comment posting has not been driven against a live pull request. It is covered by unit tests and a dry run (above), and submit now composes the verdict itself, but the end-to-end write path is unexercised. Also out of scope: the Step 4 verification agents and Step 5 reverse-audit agents still get orchestrator-written prompts and are not in the roster.
  • Breaking changes / migration notes: the submit payload changes shape — {commit_id, comments, state}, with no event/body, and a payload carrying them is refused rather than silently overruled. SKILL.md is updated in the same commit; nothing outside this skill calls it.
  • Unrelated CI failure (resolved): the first CI run on this PR failed at Install dependencies on a duplicate import in packages/web-shell that was present on main and broke npm ci for every open pull request. Fixed on main by fix(web-shell): remove duplicate useWebShellPortalRoot import in ChatEditor #6890 and merged into this branch; the failure was never this branch's.

Linked Issues

None.

中文说明

这个 PR 做了什么

/review 能证明自己读过 diff用代码生成每一个 agent 的 prompt自己算出裁决。在本仓库的真实 PR 上做了六轮 dogfood,找出七个缺陷——每一个都是拿 harness 自己记录的 subagent transcript(每个 agent 实际被什么 prompt 启动、实际做了什么)测出来的,而不是听这次 run 自述。

小 PR 拿到的裁决是假的。 coverage 只认 launch prompt 里的 chunk N of M 来归属,而 Step 3A 从来没有 agent 的 prompt 会说这句(那条路上每个维度 agent 都走整个 diff)。拿一次真实的 3A review(12 个 agent 全读了 diff、走完两个 chunk、产出真 finding)去跑闸门,它输出 Coverage: 0/2 chunk(s) reviewed. 16 agent(s) ran; 16 did work,紧接着 ERROR: 2 chunk(s) were not reviewed. Nobody read those lines. 两句话不可能同时为真。而 compose-review 在通往裁决的路上跑的是同一段计算——所以那次完美的 review 被封顶、拿不到 Approve,并且在它准备发到 PR 上的正文里写着「没人读过」。3A 是绝大多数 PR 走的拓扑;它至今没爆的唯一原因是 check-coverage 埋在 Step 3B 里、3A 根本够不到它——两个 bug 互相掩护。现在 coverage 取的是 harness 写下的两件事的交集:agent 被指到的行,以及它真的打开过 diff。与拓扑无关。

扇出的另一半仍然是瞎的。 agent-prompt 只焊死了 territory agent 的 prompt,其余交给散文。一次真实 3B run 的三个 whole-diff agent——cross-file tracer、test-coverage matrix、build & test——prompt 里一个 diff 路径都没有。test-matrix 被要求「Read the diff chunks」却没给它路径,于是它跑去读了改后源码——而删除的行在改后文件里根本不存在。

Agent 0 压根没启动,而且没人看得见。 skill 里每一个检查问的都是「跑过的 agent 怎么样」。没跑的 agent 不留 transcript,所以遗漏因为是遗漏所以不可见。现在 check-coverageplan 推出 roster(调用方写不了 plan),点名每一个该跑没跑的 agent,并附上生成它的确切命令。

prompt 在送达途中被改写,然后大到根本搬不动。 一次 run 正确调用了 agent-prompt(5 个 chunk 全调了),然后把输出改写了——保留了 read_file 那行(于是所有其他检查都放行),删掉了「不要照念现成句子」、删掉了半读警告、把项目 rules 换成自己写的三句话。下一次,brief 被焊进 launch prompt 后,它只交付了 4652 字符里的 2893 字符,然后读到闸门的 exit-3,自我说服「the agents clearly did their job」,跳过 compose-review,自己写了个 Approve。一个 17-chunk 的 3B review 会要求编排器在一个 response 里粘贴 87,546 字符——这种事不会发生。所以 brief 去了 diff 早就去的地方:磁盘上,由 agent 自己读;launch prompt 降到 ~500–800 字符。而「agent 到底读没读 brief」从一句但愿,变成 transcript 里一次可查的工具调用。

裁决曾经是模型自己写的。 compose-review 早就在算 event 和 body 了,然后 skill 让编排器「把 event/body 逐字抄进 review JSON」——把 CLI 已经做出的决定,转抄进一份模型自己写的文档现在 submit 自己 compose。 它只收 findings,其余全部现算——包括有几个 blocker:从实际挂上去的 comment 的 **[Critical]** / **[Suggestion]** 前缀数出来,而不是相信旁边写的那个数字。payload 里还带 event/body直接拒绝

SKILL.md 从 171KB 降到 154KB——而且发现三样东西从来没送到过 agent 手里。 brief 在 skill 和代码里各有一份;skill 现在只留「这个 agent 是干嘛的」,删掉「发给它的是什么」。删的过程逼出了:Exclusion Criteria 从未到达任何 agent(整个 review 最大的精度控制——skill 在文末写着它、叫编排器去 apply,而 agent 根本不读那份文档);anchor 规则也没有(resolve-anchors 一直在消费没人教过怎么产出的片段);severity 校准也没有(SEVERITY 常量的注释自己写着需要它)。

按路径生效的规则:.github/workflows 维度是刻意「不认领域」的——直到某个文件的失效模式光看它本身猜不出来。workflow 是 YAML,读起来像配置;把它当配置读的人,会漏掉它的每一个攻击面——包括 pull_request_target 去 checkout 贡献者的 head,那是「一个 CI 文件」和「拿着仓库写权限的远程代码执行」之间的区别。本仓库自己就跑着 qwen-autofix.yml,会往 PR 发东西。 现在这份清单只会附加给territory 里真的有该文件的 code-reviewing agent。

为什么需要

贯穿每一个缺陷的是同一条、这个 skill 已经重新学会七次的教训:凡是用散文写下的规则,最终都会被无视;解法是把它变成能说「不」的代码。 skill 早就把这条用在了 review 目标、发布闸门、裁决合成和覆盖率报告上——唯独漏了最要紧的四处:agent 自己的 prompt、「该有谁」这份名单、终端里的裁决,以及那些从来没真正发给 agent 的规则。

这个 PR 里有两个修复是 dogfood 抓出我自己写的 bug,这正是这套方法的意义:

  • 交付检查在误伤正确的 run。 它是连续子串比对,在一次 3B review 上把全部 9 个 agent 判成改写——而两处差异都完全合法:编排器插入了SKILL 明确要求它加的那句变更摘要,以及把一个硬换行的句子拉直成一行。一个在正确的 run 上也会响的闸门,就是一个会被绕过的闸门——这个 PR 里就有模型这么干的 transcript。规则现在改成 skill 真正说的那条:可以加,不可以删、改、重排。
  • invariant agent 被塞了整个 chunk plan。 它只管一个被大幅重写的文件。而 coverage 是从 launch prompt 里的区间算的——所以一个 invariant agent 会被记成「读完了整个 review 的所有 chunk」,一个能掩盖二十个缺席的 chunk agent

审查者验证计划

这里没有一件事是靠「这次 review 说自己跑得很好」来验证的。下面每一次 run 都是事后去读 harness 的 per-agent transcript<projectDir>/subagents/<sessionId>/agent-*.jsonl,启动那一刻写下、无法事后追改),逐个 agent 地问:它被启动时拿到的 prompt,是不是 CLI 构建的那份、一字不差?它有没有打开它被指向的东西?

复现任何一次:

npm run build && npm run bundle
# 把仓库构建放到 PATH 上,让 skill 内部的 `qwen review …` 调用解析到它
qwen --yolo            # 然后:/review <pr-number>

单元测试:

npx vitest run --root packages/cli src/commands/review     # 557 通过
npx tsc --noEmit -p packages/cli/tsconfig.json

那个实伤,拿真实 3A review 的 transcript 回放(12 个 agent 各自打开了 diff、走完两个 chunk、产出了真 finding):

修复前   Coverage: 0/2 chunk(s) reviewed. 16 agent(s) ran; 16 did work
        ERROR: 2 chunk(s) were not reviewed — 1, 2. Nobody read those lines.   exit 3

修复后   Coverage: 2/2 chunk(s) reviewed. 17 agent(s) ran; 17 did work          exit 0

改写检测,拿那次真的改写了 prompt 的 3B run 回放——5 个 chunk agent 全部被点名(改写保留了 diff 路径,所以这在以前对整个 run 都是隐形的)。

roster,拿那次没启动 Agent 0 的 run 回放——ERROR: 9 required agent(s) never ran — Agent 0: Issue fidelity …

搬运问题,在一个真实的 17-chunk PR 上:17 × ~5,149 = 87,546 字符 → brief 落盘后 14,789

端到端 run(全部由 transcript 验证):

Run 拓扑 结果
/review 6847 3A,12 个角色 12/12 逐字交付、12/12 打开了 brief,每个 3–19 次成功工具调用——Agent 0 在列。Step 3D:1/1 chunk,12/12 did work。
/review 6766 3B,5 chunk + 4 角色 9/9 逐字、9/9 打开 brief。Step 3D:5/5 chunk,所有列表为空,exit 0。
/review 6457 3B,21 chunk + heavy 文件 → 29 个 agent 29/29 逐字、29/29 打开 brief。Step 3D:21/21 chunk,30/30 did work,零错误。invariant agent A 抓到一个任何 chunk agent 都看不见的跨行缺陷:重试耗尽后 return 了,但 60 秒的重连定时器在四十行外无条件被排上——于是它每分钟打印一次「giving up」,却永不重试。
/review --effort high(本地)跑在一个外部项目上,里面种了已知漏洞 3A,local roster 对着一份 held-out 答案 key 打分:pull_request_target + checkout PR head ✅ Critical(连 postinstall 攻击链都对);${{ pull_request.title }} 注入 run:Critical(还多抓到一个我没种的 $GITHUB_OUTPUT 注入);未 pin 的第三方 action ✅ Suggestion;actions/checkout@v4 正确地没报;种下的 falsy 逻辑 bug ✅ Critical,带精确复现。零假阳性;非 workflow 文件上没有噪音。
/review 6788 3A,裁决路径 调用了 compose-review,拿到 Verdict: Comment,给用户显示 "Comment — downgraded from Approve (CI failing: route)"——presubmit 降级由代码施加,且该次 run 未发布。

发布闸门,在出网前:

# 带手写裁决的 payload
$ qwen review submit … --review forged.json --user-authorized --dry-run
Error: the payload carries `event`/`body`. Those are computed here … they are not inputs.

# 同样的 findings,不带裁决
$ qwen review submit … --review honest.json --user-authorized --dry-run
{ "wouldPost": true, "event": "COMMENT" }        # 不是 APPROVE——一个未审维度把它封顶了

风险与范围

  • 主要风险/权衡: agent 的 brief 从 SKILL.md 挪进了 packages/cli/src/commands/review/lib/agent-briefs.ts,所以「改变一个 agent 被告知什么」现在是改代码、不是改散文。这正是意图(散文没能活着送到),但也意味着 skill 和代码不能再漂回两份。skill 里已经写明哪一份是权威。
  • 未验证 / 范围外: --comment 真发布没有在活的 PR 上跑过。它有单元测试和 dry-run 覆盖(见上),submit 现在也自己算裁决,但端到端的写路径未被驱动过。同样在范围外:Step 4 的验证 agent 和 Step 5 的 reverse-audit agent 仍然拿编排器手写的 prompt,且不在 roster 里。
  • 破坏性变更 / 迁移: submit 的 payload 换了形状——{commit_id, comments, state}没有 event/body,带了就直接拒绝(而不是静默覆盖)。SKILL.md 在同一个 commit 里同步更新;这个 skill 之外没有别的东西调用它。
  • 与本 PR 无关的 CI 失败(已解决): 本 PR 的第一轮 CI 挂在 Install dependencies,原因是 packages/web-shell 里一个重复 import——它在 main 上就存在,会让每一个开着的 PR 的 npm ci 失败。main 已由 fix(web-shell): remove duplicate useWebShellPortalRoot import in ChatEditor #6890 修复并合入本分支;这个失败自始至终与本分支无关。

关联 issue

无。

wenshao added 6 commits July 14, 2026 20:48
…survived the trip

Three defects, all measured against the harness's own transcripts of real /review
runs against QwenLM/qwen-code PRs #6766 (Step 3B) and #6579 (Step 3A).

1. Step 3A reviews were told nobody had read them.

   Coverage was attributed by one question: did an agent whose launch prompt says
   `chunk N of M` make a successful tool call? No Step 3A prompt says that — there
   every dimension agent walks the whole diff — so no chunk was ever attributed to
   anyone. Run against a real 3A review whose twelve agents each opened the diff,
   walked both chunks and filed findings, check-coverage returned

     Coverage: 0/2 chunk(s) reviewed. 16 agent(s) ran; 16 did work
     ERROR: 2 chunk(s) were not reviewed — 1, 2. Nobody read those lines.

   in one breath. compose-review runs the same computation on the way to the
   verdict, so a flawless small-PR review was capped away from Approve and the
   body it would have POSTED to the pull request said nobody had read it. Step 3A
   is the topology most pull requests get. The only reason it never blew up is
   that check-coverage lived inside Step 3B and was never reached from 3A — two
   bugs cancelling.

   Coverage is now the intersection of two things the harness wrote down: the
   lines each agent was pointed at (its launch prompt) and the fact that it opened
   the diff (a successful tool call naming the diff file). Topology-blind. It also
   no longer credits a chunk to an agent on the strength of any successful call —
   a glob for test files was enough.

2. The whole-diff agents were still launched blind.

   agent-prompt built the territory agents' prompts and left the other half of the
   fan-out to prose. All three whole-diff agents of the 3B run — cross-file tracer,
   test-coverage matrix, build & test — got a prompt naming no diff file at all.
   The test-coverage matrix was told to "Read the diff chunks" and given no path to
   read them from; it read the post-change source instead, which on a deletion
   shows it nothing. These agents own the classes a chunk agent is structurally
   blind to, and the gate could not see it: it only asked that question of agents
   whose prompt said `chunk N of M`.

   `agent-prompt --whole-diff` now builds their diff-reading block too.

3. The prompt the CLI built was rewritten on the way to the agent.

   The 3B run invoked agent-prompt correctly for all five chunks and then
   paraphrased what it printed: the delivered prompt dropped the rule against
   reciting a stock sentence, dropped the half-read warning, replaced the project's
   review rules with a three-sentence summary of its own, and invented an
   instruction that was never in the original. Nothing could see it, because a
   paraphrase keeps the diff path. So agent-prompt records what it emitted, at a
   path derived from the plan that the caller is never given; check-coverage reads
   it back against the launch prompt the harness recorded. Replayed against that
   run's real transcripts, all five chunk agents are now named.

Verified end to end: a fresh /review of #6829 (3A) calls `agent-prompt
--whole-diff`, passes it verbatim, and Step 3D reports 2/2 chunks reviewed,
12 agents, 12 did work — a gate that path could not reach before, and could not
have passed if it had.
Two more failures, both measured against the harness's own transcripts of real
/review runs.

1. Agent 0 was never launched, and nothing could tell.

   The skill says issue fidelity runs on every PR review. Dogfooded on #6766, it
   did not run — and every check passed, because every check asks a question of an
   agent that RAN. An agent that does not run leaves no transcript to ask. An
   omission is invisible precisely because it is an omission.

   So `check-coverage` now derives a roster from the plan — which the caller does
   not write — and names every required agent that never ran, with the exact
   `agent-prompt` call that builds it. The plan already knew everything the roster
   turns on: the topology, whether the diff deletes anything, which files were
   rewritten heavily enough to need invariant agents, whether there is a worktree
   to build in and a pull request to check an issue against.

   `agent-prompt --role <role>` builds all of them: 0, 1a, 1b, 1c, 2, 3, 4, 5,
   6a/6b/6c, 7, the test matrix, and the three invariant agents per heavy file.
   The briefs move out of SKILL.md and into code, because a brief the orchestrator
   retypes is a brief that drifts.

2. A 4 652-character prompt is not a thing an orchestrator will paste twelve times.

   With the briefs welded into the launch prompt, the first dogfood delivered
   **2 893** characters of one: it kept the head, added a preamble of its own, and
   cut nineteen hundred characters out of the middle. The delivery check caught it
   — and the run then read the check's exit-3, concluded "the agents clearly did
   their job", skipped `compose-review`, and filed an **Approve it had written
   itself**. A gate that always fails is a gate that gets talked around.

   So the brief goes where the diff already goes: on disk, read by the agent that
   needs it. The launch prompt drops to ~500-800 characters — it names the role,
   points at the brief file, and lists the diff reads — and whether the agent
   actually read its brief stops being a hope and becomes a tool call the harness
   wrote down (`unreadBriefs`).

Verified end to end. A fresh /review of #6847 built all twelve role prompts, and
against the harness's transcripts: 12 of 12 delivered **byte-for-byte verbatim**,
12 of 12 **opened their brief**, 3-19 successful tool calls each — Agent 0 among
them. Step 3D: `1/1 chunks reviewed, 12/12 agents did work`, no errors.
`compose-review` has computed the event and the body since the C/S table stopped
being prose. The skill then told the orchestrator to "copy event/body verbatim
into the review JSON" — a transcription, into a document the model writes, of a
decision the CLI had already made. That is the exact anti-pattern `submit`'s own
header repudiates, and it left two ways for a run to author its own verdict:

  - **The terminal.** Step 6's verdict was composed by the model, from prose
    rules. Dogfooded, a run read the coverage check's refusal, concluded that
    "the agents clearly did their job", never called `compose-review` at all, and
    printed `Review complete — Approve` on a review whose gate had just refused.

  - **The wire.** `submit` took `{event, body}` as fields. Nothing stopped a run
    that had skipped the computation from posting the conclusion it preferred.

So `submit` composes. It takes the findings — the inline comments and the states
Step 6 established — and derives everything that follows, including how many
blockers there are: `criticalsInline` and `suggestionsInline` are counted off the
`**[Critical]**` / `**[Suggestion]**` prefixes of the comments actually attached,
not accepted as numbers beside them. (A number beside a list is a number that can
disagree with the list, and one did: the breaching run posted a body reading
"Suggestions are inline" next to an empty `comments` array and a summary claiming
`0 Suggestion inline`.) A payload carrying `event`/`body` is refused rather than
silently overruled — the caller was trying to author a verdict.

Two body checks are deleted, not weakened: a body that promises inline comments it
does not carry, and a body whose footer is preceded by a literal `\n`. Both were
checks on a string the caller built. The caller no longer builds it.

`compose-review` now prints the verdict line itself, and Step 6 prints that. There
is one place a verdict exists; skipping the command does not get you a different
one, it gets you none.

Verified: a payload with `event: APPROVE` and an unreviewed dimension is refused
at the wire; the same findings without a verdict compose to `COMMENT`. A fresh
/review of #6788 called `compose-review`, was told `Verdict: Comment`, and showed
the user "Comment — downgraded from Approve (CI failing: route)" — the presubmit
downgrade applied by code, on a run that did not post.
…ng wolf

Dogfooding the Step 3B path — the one topology none of this had been run against
— found two defects, and the second is the more important of the two.

1. Eighty-seven kilobytes of chunk prompts, in one response.

   The briefs moved onto disk for the dimension agents and not for the territory
   agents. Measured on PR #6606 (5 511 diff lines, 17 chunks): 17 chunk launch
   prompts of ~5 149 characters each — **87 546 characters** the orchestrator was
   expected to paste unedited. At a twelfth of that load it had already cut
   nineteen hundred characters out of a single prompt.

   Chunk agents get the same split: the brief on disk, and a launch prompt that
   carries only what cannot live anywhere else — `chunk N of M`, which attributes
   the territory, and the `offset`/`limit`, which are the lines coverage proves
   were delivered. 87 546 → 14 789 characters. And `check-coverage` now asks the
   territory agents the same question it asks the others: did you open your brief?

2. The delivery check failed a correct run — all nine agents of it.

   It was a substring test: the built prompt had to appear in the launch prompt,
   contiguously. That is a stricter claim than the skill makes, and both of the
   differences it fired on were legitimate. The orchestrator had inserted **the
   one-sentence summary of the change that the skill explicitly tells it to add**,
   which breaks contiguity by construction — and it had reflowed a hard-wrapped
   sentence onto one line, which changes not one character of meaning.

   This is the failure this skill keeps re-learning, and this time it was ours: a
   gate that fires on a correct run is a gate that gets talked around, and there is
   a dogfood transcript of a model doing exactly that. The rule the check enforces
   is now the rule the skill states — **you may add; you may not remove, alter, or
   reorder** — over whitespace-collapsed lines, in order.

Verified against the harness's transcripts of a real Step 3B review of #6766: nine
agents (five chunks, issue fidelity, cross-file tracer, test matrix, build & test),
9/9 delivered intact, 9/9 opened their brief, 6-22 successful tool calls each.
`check-coverage`: 5/5 chunks, every list empty, exit 0.
…, where they were never reaching the agents

Two changes, and the second found a hole the first would not have.

1. Rules that attach to a path, not to a dimension.

   The nine dimensions are domain-blind by design — "find security bugs" is a lens,
   not a syllabus — and that holds until a file's failure modes are not guessable
   from reading it. A GitHub Actions workflow is the clearest case: it is YAML, so it
   reads as configuration, and the reviewer who treats it as configuration misses
   every one of its attack classes. Nothing in this review knew to ask whether a
   `pull_request_target` job checks out the contributor's head — which is the
   difference between a CI file and a remote code execution with the repository's
   write token. This repo runs `qwen-autofix.yml`, which posts to pull requests.

   `agent-prompt` now appends a checklist for such a file to the brief of every
   code-reviewing agent **whose territory actually contains one**. Scoped, because a
   rule that fires on every review is a rule that gets skimmed. `/review` runs on
   other people's repositories, so the calibration matters as much as the content:
   the blockers are the six that are unambiguously wrong; the two that shade into
   taste (SHA-pinning, `permissions:`) are Suggestions, exempt the conventions almost
   everyone keeps, and are scoped to lines the diff touches. No style rules — a
   linter owns those, and the Exclusion Criteria already forbid them.

2. The briefs move out of SKILL.md — and three things turned out never to have
   reached an agent at all.

   The briefs have been built in code since the roster landed, and SKILL.md still
   carried 38 KB of the same prose. Duplication is drift, and a 178 KB skill is
   ~45 000 tokens in the orchestrator's context on every review — which is itself a
   cause of the failure this whole line of work has been chasing. The skill now keeps
   what each agent is *for* (a table) and drops what it is *sent* (the command's copy
   is the one that arrives).

   Doing that surfaced what the code briefs were missing, because the deleted prose
   had to go somewhere:

   - **The Exclusion Criteria had never reached an agent.** The skill states them at
     the end of the document and tells the orchestrator to "apply" them. The agents
     do not read the document. The single largest precision control in this review
     has been governing nobody, in every run, since it was written.
   - **Nor had the anchor rules.** Agents were asked for a snippet and never told
     what makes one resolvable: prefer added lines, a removed line cannot be anchored
     at all, a bare `}` matches everywhere. `resolve-anchors` was downstream of a
     snippet nobody had given the rules to produce.
   - **Nor the severity calibration.** `SEVERITY`'s own comment warns that a chunk
     agent owns test coverage with nothing to calibrate it and will file "zero test
     coverage" as Critical — and then did not include the calibration.

   All three are in the briefs now. And two degradations the orchestrator used to be
   told to add by hand — and can no longer add, because it does not write these
   prompts — are applied by the builder: in cross-repo lightweight mode there is no
   tree, so 1b and 1c report at `Confidence: low` rather than asserting a
   re-establishment is missing. A false Critical blocks a merge.

   Step 3C (the medium-effort inline pass) now *loads* the briefs it needs rather
   than carrying them: same text as the high-effort agents get, read when that level
   actually runs instead of sitting in every review's context.

SKILL.md: 171 178 → 153 656 bytes.
…ker's blast radius be part of the blocker

Two corrections, both from dogfooding the paths that had never been run.

1. An invariant agent was being handed the whole chunk plan.

   It owns one heavily-rewritten file. Its brief says so, and gives it that file's
   own slice of the diff. Its *launch prompt* listed every chunk in the review —
   on PR #6457, all twenty-one reads of a 6 149-line diff, for an agent whose job
   is one file.

   The wasted reading is the smaller half. Coverage is computed from the ranges in
   the launch prompt, so an invariant agent was being credited with having read
   **every chunk in the review**. One of them could have masked twenty missing chunk
   agents. It now gets exactly its file's `diffRange`, and nothing else.

2. `permissions: write-all` on a job that runs untrusted code is not a Suggestion.

   The path rule said it was. Dogfooded against a planted vulnerability, the security
   agent read that and escalated anyway: "grants maximum token scope to a job that
   processes untrusted contributor code, amplifying the RCE above". It was right and
   the flat rule was too coarse. A broad token on a privileged job is not a separate
   recommendation — it is how far the blocker reaches, and it belongs in that finding,
   at Critical. On an ordinary job it stays a Suggestion.

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

The substance here is excellent — seven real defects found and verified through dogfooding, with transcripts. But the PR body is missing all the required template headings, which makes it harder for the review pipeline and future readers to navigate:

  • ## What this PR does
  • ## Why it's needed
  • ## Reviewer Test Plan (with ### How to verify, ### Evidence (Before & After), ### Tested on)
  • ## Risk & Scope
  • ## Linked Issues

Could you add the template structure? The narrative content is great — it just needs to fit under the right headings so reviewers can find the test plan, evidence, and risk assessment without reading the whole body.

Template: .github/pull_request_template.md

中文说明

内容非常好——通过 dogfooding 发现并验证了七个真实缺陷,附有 transcript。但 PR body 缺少所有必需的模板标题,不便于审查流程和后续读者导航:

  • ## What this PR does
  • ## Why it's needed
  • ## Reviewer Test Plan(含 ### How to verify### Evidence (Before & After)### Tested on
  • ## Risk & Scope
  • ## Linked Issues

请补充模板结构。叙述内容很好——只需放到对应的标题下,方便审查者快速找到测试计划、证据和风险评估。

Qwen Code · qwen3.7-max

@wenshao
wenshao requested a review from Copilot July 14, 2026 13:24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions

github-actions Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Summary

Package Lines Statements Functions Branches
CLI 81.52% 81.52% 87.32% 81.85%
Core 86.36% 86.36% 87.84% 85.47%
CLI Package - Full Text Report
-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |   81.52 |    81.85 |   87.32 |   81.52 |                   
 src               |   80.35 |    78.39 |   84.41 |   80.35 |                   
  cli.ts           |   94.31 |    82.35 |     100 |   94.31 | ...67-468,478-479 
  gemini.tsx       |   71.24 |    75.95 |      80 |   71.24 | ...1047-1051,1172 
  ...ractiveCli.ts |    77.4 |    75.54 |      75 |    77.4 | ...2054-2056,2093 
  ...liCommands.ts |   88.34 |    83.87 |      90 |   88.34 | ...63,480,514,635 
  ...ActiveAuth.ts |     100 |     87.5 |     100 |     100 | 66-80             
 ...cp-integration |   63.11 |    68.31 |   85.43 |   63.11 |                   
  acpAgent.ts      |   62.86 |    68.13 |   85.35 |   62.86 | ...8872-8874,8890 
  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             
  ...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 |   88.68 |    81.52 |   93.01 |   88.68 |                   
  Session.ts       |   88.78 |    80.55 |    92.7 |   88.78 | ...6227,6254-6258 
  ...entTracker.ts |   91.53 |    89.47 |   88.88 |   91.53 | ...32,196,270-279 
  ...eplay-page.ts |   98.31 |    88.33 |     100 |   98.31 | 68,89,164         
  ...y-replayer.ts |   82.33 |    86.25 |   93.33 |   82.33 | ...24-425,448-449 
  index.ts         |       0 |        0 |       0 |       0 | 1-40              
  ...ssionUtils.ts |      85 |    84.84 |     100 |      85 | ...49-165,221-223 
  tasksSnapshot.ts |   94.21 |     87.5 |     100 |   94.21 | 65-71             
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...ssion/emitters |   96.89 |    95.47 |   96.96 |   96.89 |                   
  ...ageEmitter.ts |   95.91 |    98.14 |     100 |   95.91 | 49-56             
  PlanEmitter.ts   |     100 |      100 |     100 |     100 |                   
  base-emitter.ts  |     100 |    83.33 |     100 |     100 | 23,27             
  index.ts         |       0 |        0 |       0 |       0 | 1-10              
  ...ll-emitter.ts |   98.53 |    95.28 |     100 |   98.53 | 333-334,435,443   
 ...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.71 |    73.52 |   64.51 |   88.71 |                   
  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.67 |      100 |      50 |   97.67 | 54                
  serve.ts         |   86.42 |    67.64 |     100 |   86.42 | ...00-603,617-621 
  sessions.ts      |     100 |      100 |      50 |     100 |                   
  update.ts        |   98.11 |    94.44 |   66.66 |   98.11 | 81-82             
 ...mmands/channel |   82.29 |    86.84 |    83.2 |   82.29 |                   
  channel-cwd.ts   |     100 |      100 |     100 |     100 |                   
  ...l-registry.ts |    6.52 |      100 |       0 |    6.52 | 6-33,36-54        
  ...entry-path.ts |      75 |       50 |     100 |      75 | 8-9               
  config-utils.ts  |   95.85 |    96.29 |     100 |   95.85 | ...08-213,271-274 
  configure.ts     |    14.7 |      100 |       0 |    14.7 | 18-21,23-84       
  daemon-worker.ts |   95.89 |    87.95 |   96.87 |   95.89 | ...06-807,811-812 
  ...classifier.ts |   97.59 |    92.85 |     100 |   97.59 | 47-48             
  pairing.ts       |   26.31 |      100 |       0 |   26.31 | ...30,40-50,52-65 
  pidfile.ts       |   95.55 |       90 |     100 |   95.55 | ...50-251,315-316 
  proxy.ts         |     100 |      100 |     100 |     100 |                   
  reload.ts        |   72.97 |    80.95 |      75 |   72.97 | 64-76,85-91       
  runtime.ts       |   78.24 |    86.95 |     100 |   78.24 | ...55-159,189-191 
  set.ts           |   69.56 |    83.33 |      50 |   69.56 | 57-75,103-110,123 
  start.ts         |   75.21 |    75.28 |   66.66 |   75.21 | ...38,544-547,559 
  status.ts        |   77.68 |    57.14 |   66.66 |   77.68 | ...26-127,140-151 
  stop.ts          |   57.83 |    82.35 |      50 |   57.83 | ...3,74-76,85-111 
 ...nds/extensions |   88.82 |    87.82 |   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 |     90.9 |     100 |     100 | 18                
  new.ts           |     100 |      100 |     100 |     100 |                   
  settings.ts      |   99.15 |      100 |   83.33 |   99.15 | 151               
  sources.ts       |   93.42 |    87.09 |   92.85 |   93.42 | ...4-66,96-98,167 
  uninstall.ts     |   74.57 |       40 |   66.66 |   74.57 | 45-47,60-67,70-73 
  update.ts        |   96.71 |    97.05 |     100 |   96.71 | 114-118           
  utils.ts         |      75 |    55.55 |     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.15 |    84.39 |   83.33 |   90.15 |                   
  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.73 |    66.66 |   85.71 |   78.73 | 42-55,168-190     
  remove.ts        |     100 |       80 |     100 |     100 | 21-25             
 ...ommands/review |   74.46 |     85.4 |   75.21 |   74.46 |                   
  agent-prompt.ts  |    89.3 |    88.14 |   92.85 |    89.3 | ...91-794,947-984 
  capture-local.ts |   72.16 |     90.9 |      75 |   72.16 | 101-105,152-174   
  ...k-coverage.ts |   10.43 |      100 |       0 |   10.43 | ...04-214,216-217 
  cleanup.ts       |   17.72 |      100 |       0 |   17.72 | ...27-132,134-135 
  ...ose-review.ts |   92.52 |    93.43 |   88.88 |   92.52 | ...69,280,524-532 
  fetch-pr.ts      |   25.44 |      100 |    12.5 |   25.44 | ...15-304,345-347 
  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     |   73.43 |      100 |   66.66 |   73.43 | 95-111            
  pr-context.ts    |   84.02 |    76.37 |   91.66 |   84.02 | ...22-903,932-934 
  presubmit.ts     |    73.2 |    78.57 |   83.33 |    73.2 | ...12-313,365-395 
  ...ve-anchors.ts |   77.02 |    88.46 |      75 |   77.02 | ...70-175,187-204 
  submit.ts        |   74.44 |    81.33 |      80 |   74.44 | ...42-578,580-581 
  test-efficacy.ts |   81.81 |    72.34 |   93.33 |   81.81 | ...26-627,635-655 
 ...nds/review/lib |   93.51 |       92 |   90.29 |   93.51 |                   
  agent-briefs.ts  |   97.97 |      100 |       0 |   97.97 | 373-374           
  anchors.ts       |     100 |    94.79 |     100 |     100 | ...33,169,178,225 
  coverage.ts      |   95.65 |    91.91 |     100 |   95.65 | ...02,229,247,256 
  diff-flags.ts    |     100 |        0 |     100 |     100 | 63                
  diff-plan.ts     |    98.7 |    92.65 |     100 |    98.7 | ...21,244,270-271 
  gh.ts            |   52.87 |      100 |      30 |   52.87 | ...81-182,190-197 
  git.ts           |   97.64 |    95.65 |     100 |   97.64 | 180-181           
  heavy.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         |   84.61 |       80 |   66.66 |   84.61 | 42-43,76-77       
  prompt-record.ts |   93.97 |    85.18 |     100 |   93.97 | ...05,128-129,133 
  report.ts        |   92.13 |    86.66 |     100 |   92.13 | 170-171,173-177   
  roster.ts        |     100 |    85.36 |     100 |     100 | ...98,103,117,154 
  transcripts.ts   |   96.27 |    93.18 |     100 |   96.27 | ...83,269-270,294 
 ...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.25 |    87.77 |   95.34 |   94.25 |                   
  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 
  config.ts        |   87.63 |    86.32 |   84.37 |   87.63 | ...2304,2306-2314 
  ...heme-names.ts |     100 |      100 |     100 |     100 |                   
  environment.ts   |   94.18 |     89.4 |   94.73 |   94.18 | ...22-626,642-643 
  ...le-watcher.ts |   90.76 |    83.33 |   95.83 |   90.76 | ...23-325,370,409 
  ...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.1 |       50 |     100 |    97.1 | 214-217           
  ...ngsAdapter.ts |     100 |    94.11 |     100 |     100 | 64                
  ...ig-watcher.ts |   95.17 |    83.05 |     100 |   95.17 | ...78,200,292-293 
  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.6 |    91.84 |   89.65 |    90.6 | ...61,963,965-966 
  ...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 |                   
  ...paths-lite.ts |   89.47 |       88 |     100 |   89.47 | 43-44,53-54,56-57 
  ...tedFolders.ts |   93.78 |    94.78 |     100 |   93.78 | ...43-344,380-391 
 ...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.61 |    70.31 |   66.66 |   71.61 |                   
  ...tputBridge.ts |   71.76 |    70.96 |   68.42 |   71.76 | ...05-406,414-417 
  ...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          |    86.9 |    80.45 |    93.1 |    86.9 |                   
  index.ts         |   73.45 |    77.77 |      90 |   73.45 | ...70-271,294-299 
  languages.ts     |   96.92 |    86.66 |     100 |   96.92 | 134-135,167,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 |   79.44 |    75.82 |   81.35 |   79.44 |                   
  session.ts       |   83.56 |    74.71 |   93.61 |   83.56 | ...4-985,994-1004 
  types.ts         |    42.5 |      100 |   33.33 |    42.5 | ...23-624,627-628 
 ...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.26 |     58.4 |   47.22 |   39.26 |                   
  ...Controller.ts |   39.49 |      100 |      80 |   39.49 | 88-92,127-210     
  ...Controller.ts |       0 |        0 |       0 |       0 | 1-56              
  ...Controller.ts |   46.62 |    52.94 |   54.54 |   46.62 | ...24-633,648-653 
  ...Controller.ts |   14.06 |      100 |       0 |   14.06 | ...82-117,130-133 
  ...Controller.ts |    37.8 |       60 |   46.66 |    37.8 | ...40-652,661-690 
 .../control/types |       0 |        0 |       0 |       0 |                   
  serviceAPIs.ts   |       0 |        0 |       0 |       0 | 1                 
 ...Interactive/io |   97.49 |    93.84 |   95.23 |   97.49 |                   
  ...putAdapter.ts |   97.13 |    92.89 |   98.07 |   97.13 | ...1314,1409-1410 
  ...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 | 83-84,124-125     
  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         |   88.45 |    84.94 |   89.86 |   88.45 |                   
  ...tp-enabled.ts |     100 |      100 |     100 |     100 |                   
  ...ion-bridge.ts |     100 |      100 |     100 |     100 |                   
  auth.ts          |    93.4 |    92.95 |     100 |    93.4 | ...16-317,320-322 
  ...em-adapter.ts |     100 |      100 |     100 |     100 |                   
  capabilities.ts  |     100 |    97.56 |     100 |     100 | 554               
  ...cp-command.ts |     100 |      100 |     100 |     100 |                   
  ...-selection.ts |     100 |      100 |     100 |     100 |                   
  ...ebhook-ipc.ts |    98.5 |    86.66 |     100 |    98.5 | 47                
  ...worker-env.ts |     100 |      100 |     100 |     100 |                   
  ...rker-group.ts |   91.56 |    85.79 |     100 |   91.56 | ...44-648,654-658 
  ...er-manager.ts |   92.85 |    86.66 |   94.11 |   92.85 | ...28,447,458-460 
  ...supervisor.ts |   96.99 |    88.23 |   96.42 |   96.99 | ...-945,1053-1057 
  ...e-grouping.ts |     100 |    94.11 |     100 |     100 | 69,132            
  ...ub-session.ts |   92.04 |    77.77 |     100 |   92.04 | ...36-445,470,508 
  daemon-logger.ts |   98.31 |    88.73 |   96.55 |   98.31 | 119-120,205       
  ...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.19 |       89 |     100 |   98.19 | ...-998,1000-1001 
  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.39 |    88.75 |     100 |   94.39 | ...22,700,716,726 
  fast-path.ts     |   91.28 |    81.98 |   95.45 |   91.28 | ...64-473,539-540 
  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                
  ...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 |   84.53 |    80.45 |   71.94 |   84.53 | ...5360,5365-5366 
  ...tup-errors.ts |     100 |      100 |     100 |     100 |                   
  ...-keepalive.ts |   95.91 |    90.72 |     100 |   95.91 | ...26,486-488,524 
  ...-lifecycle.ts |     100 |      100 |     100 |     100 |                   
  server.ts        |   95.21 |     92.5 |   77.77 |   95.21 | ...1702,1722-1725 
  ...on-helpers.ts |     100 |      100 |     100 |     100 |                   
  ...t-event-id.ts |     100 |    91.66 |     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 |                   
  ...l-resolver.ts |   90.32 |    66.66 |     100 |   90.32 | 16,45-46          
  ...ell-static.ts |   91.07 |     86.2 |     100 |   91.07 | ...79-182,216-219 
  ...ace-agents.ts |   57.15 |    67.61 |   86.66 |   57.15 | ...1821,1831-1841 
  ...-git-state.ts |     100 |    95.65 |    87.5 |     100 | 77                
  ...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 |   82.19 |    75.28 |     100 |   82.19 | ...82-489,549-556 
  ...ers-status.ts |   97.32 |    81.19 |     100 |   97.32 | ...61,164,297-303 
  ...tion-store.ts |    85.6 |    85.98 |   90.47 |    85.6 | ...82-291,302-305 
  ...e-registry.ts |   91.26 |    90.69 |     100 |   91.26 | ...91-292,298-299 
  ...ber-errors.ts |     100 |    95.32 |     100 |     100 | 53,93-94,172,192  
  ...e-remember.ts |   97.94 |    94.33 |     100 |   97.94 | ...00,304-309,350 
  ...te-runtime.ts |   93.14 |    87.71 |     100 |   93.14 | ...-88,92,145-150 
  ...ls-mapping.ts |     100 |      100 |     100 |     100 |                   
  ...lls-status.ts |     100 |    94.44 |     100 |     100 | 102               
 ...serve/acp-http |   75.53 |    78.31 |   93.71 |   75.53 |                   
  ...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.19 |    88.55 |     100 |   98.19 | 1015,1037-1048    
  dispatch.ts      |    68.8 |    74.89 |     100 |    68.8 | ...4404,4452-4458 
  index.ts         |   81.78 |    78.37 |   89.36 |   81.78 | ...2159,2190-2192 
  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.88 |   84.61 |   93.96 | ...57-159,161-163 
  ...ort-stream.ts |       0 |        0 |       0 |       0 | 1                 
  ws-stream.ts     |   91.86 |    78.78 |     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.68 |    80.06 |     100 |   85.68 |                   
  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.19 |     78.6 |     100 |   85.19 | ...2094,2104-2105 
 src/serve/routes  |   85.96 |    79.37 |   95.65 |   85.96 |                   
  a2ui-action.ts   |   99.49 |    94.52 |    87.5 |   99.49 | 250               
  capabilities.ts  |     100 |      100 |     100 |     100 |                   
  ...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            
  health-demo.ts   |    92.3 |    83.33 |     100 |    92.3 | 55-59             
  permission.ts    |     100 |     92.3 |     100 |     100 | 50,98             
  ...uled-tasks.ts |   84.12 |    83.18 |     100 |   84.12 | ...50-858,975-976 
  ...on-runtime.ts |     100 |    86.66 |     100 |     100 | 39,75             
  session.ts       |   89.05 |    83.94 |   96.15 |   89.05 | ...2984,2986-2987 
  sse-events.ts    |   86.25 |     88.6 |   77.77 |   86.25 | ...81,387,404-407 
  usage-stats.ts   |     100 |    95.65 |     100 |     100 | 116               
  ...space-auth.ts |    83.7 |       75 |     100 |    83.7 | ...23,328,340-344 
  ...el-control.ts |    82.9 |    81.92 |     100 |    82.9 | ...01-202,223-231 
  ...controller.ts |   81.71 |    77.09 |   89.65 |   81.71 | ...73,975,981,984 
  ...extensions.ts |   87.44 |    72.76 |   95.74 |   87.44 | ...1788,1830-1831 
  ...-file-read.ts |   92.32 |       80 |     100 |   92.32 | ...94-595,598-599 
  ...file-write.ts |   84.44 |    64.13 |     100 |   84.44 | ...73-275,355-357 
  workspace-git.ts |     100 |      100 |     100 |     100 |                   
  ...-lifecycle.ts |   96.85 |       75 |     100 |   96.85 | 130-131,161-162   
  ...management.ts |    86.5 |    83.87 |     100 |    86.5 | ...05,909,929-934 
  ...cp-control.ts |   69.87 |     61.9 |     100 |   69.87 | ...46-452,461-462 
  ...ace-models.ts |   95.87 |    92.42 |     100 |   95.87 | 38-39,136-141     
  ...ermissions.ts |   74.66 |    69.23 |     100 |   74.66 | ...25-233,254-271 
  ...e-settings.ts |   66.08 |    60.93 |     100 |   66.08 | ...21-426,435-445 
  ...tup-github.ts |   77.52 |    70.27 |   84.21 |   77.52 | ...87,309,352-353 
  ...ace-skills.ts |   94.44 |    92.59 |     100 |   94.44 | 41-46             
  ...ace-status.ts |   75.33 |    61.97 |     100 |   75.33 | ...34-335,359-360 
  ...pace-tools.ts |   74.82 |    69.23 |     100 |   74.82 | ...41-146,175-176 
  ...pace-trust.ts |   76.08 |       50 |   66.66 |   76.08 | ...01-206,214-215 
  ...pace-voice.ts |   91.45 |    82.35 |     100 |   91.45 | ...21-624,627-629 
 src/serve/server  |   88.89 |     88.6 |   94.33 |   88.89 |                   
  access-log.ts    |   97.72 |    95.45 |     100 |   97.72 | 51                
  ...er-helpers.ts |   63.82 |    77.96 |   81.81 |   63.82 | ...16,330,332-347 
  ...w-registry.ts |    98.8 |    86.95 |     100 |    98.8 | 107               
  ...r-handlers.ts |   97.14 |    71.42 |     100 |   97.14 | 16                
  ...r-response.ts |    83.6 |    75.79 |     100 |    83.6 | ...19,641,704-713 
  fs-factory.ts    |     100 |    92.59 |     100 |     100 | 33,41,100,156     
  ...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 |   94.82 |    95.04 |     100 |   94.82 | ...32-134,389-394 
  self-origin.ts   |   76.19 |       80 |     100 |   76.19 | 45-54             
  ...e-features.ts |   93.85 |       92 |     100 |   93.85 | 146-152           
  ...on-archive.ts |   89.13 |    89.58 |    87.5 |   89.13 | ...17-422,494-504 
  ...ion-export.ts |     100 |    83.33 |     100 |     100 | 60,84             
  session-list.ts  |   94.44 |     91.3 |     100 |   94.44 | ...48-563,565-571 
  telemetry.ts     |   97.28 |    96.73 |     100 |   97.28 | ...93-295,397-399 
 src/serve/voice   |   85.15 |     93.1 |   90.47 |   85.15 |                   
  ...ice-config.ts |   96.77 |       30 |     100 |   96.77 | 85-86             
  voice-ws.ts      |   77.97 |    96.39 |   83.33 |   77.97 | ...55,470,508-510 
  ...oordinator.ts |     100 |    98.11 |     100 |     100 | 171               
 ...kspace-service |   94.05 |    81.65 |   97.14 |   94.05 |                   
  index.ts         |   93.75 |    81.08 |   96.66 |   93.75 | ...1053-1057,1060 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/services      |   92.17 |    88.36 |   97.65 |   92.17 |                   
  ...mandLoader.ts |     100 |    88.88 |     100 |     100 | 103-116           
  ...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.17 |    83.82 |   83.33 |   77.17 | ...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             
  ...low-loader.ts |     100 |    96.15 |     100 |     100 | 88                
  setup-github.ts  |    90.5 |    81.81 |     100 |    90.5 | ...35-436,443-444 
  ...-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.71 |     100 |   98.64 | 116,142-143       
  voice-model.ts   |     100 |      100 |     100 |     100 |                   
  voice-service.ts |   88.14 |    87.69 |     100 |   88.14 | ...80,287,352-357 
  ...e-settings.ts |     100 |    95.23 |     100 |     100 | 19                
  ...ranscriber.ts |   90.46 |    82.11 |      96 |   90.46 | ...66-668,671-673 
 ...ght/generators |   88.86 |    85.78 |   96.29 |   88.86 |                   
  DataProcessor.ts |   88.23 |    85.71 |      95 |   88.23 | ...1348,1352-1359 
  ...tGenerator.ts |   98.21 |    85.71 |     100 |   98.21 | 46                
  ...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.08 |    82.52 |      90 |   88.08 |                   
  ...p-prefetch.ts |   98.75 |       95 |   85.71 |   98.75 | 44,168            
  ...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            |   70.43 |     72.6 |   65.38 |   70.43 |                   
  App.tsx          |   33.33 |       75 |   33.33 |   33.33 | 32-86             
  AppContainer.tsx |   71.46 |       69 |   61.53 |   71.46 | ...3954,3958-3962 
  ...tionNudge.tsx |    9.58 |      100 |       0 |    9.58 | 24-94             
  ...ackDialog.tsx |   29.23 |      100 |       0 |   29.23 | 25-75             
  ...tionNudge.tsx |    7.69 |      100 |       0 |    7.69 | 25-103            
  colors.ts        |      60 |      100 |   35.29 |      60 | ...52,54-55,60-61 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  keyMatchers.ts   |   95.91 |    97.14 |     100 |   95.91 | 25-26             
  ...tic-colors.ts |     100 |      100 |     100 |     100 |                   
  ...ractiveUI.tsx |   64.39 |    48.38 |      80 |   64.39 | ...29,244,268-273 
  ...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.45 |    66.18 |   51.06 |   58.45 |                   
  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.03 |    70.73 |   57.69 |   60.03 | ...87,791,800,803 
  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   |   80.47 |    82.89 |   88.77 |   80.47 |                   
  aboutCommand.ts  |     100 |      100 |     100 |     100 |                   
  agentsCommand.ts |   83.78 |      100 |      60 |   83.78 | 30-32,42-44       
  ...odeCommand.ts |   89.47 |    81.25 |     100 |   89.47 | 92-93,95-100      
  arenaCommand.ts  |   62.81 |    58.73 |   65.21 |   62.81 | ...90-595,680-688 
  authCommand.ts   |     100 |      100 |     100 |     100 |                   
  branchCommand.ts |     100 |      100 |     100 |     100 |                   
  btwCommand.ts    |   94.32 |    77.41 |     100 |   94.32 | 35-36,114-119     
  bugCommand.ts    |     100 |    77.77 |     100 |     100 | 27,61             
  cdCommand.ts     |    92.1 |     84.9 |     100 |    92.1 | ...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 |   67.46 |    69.69 |   84.61 |   67.46 | ...53-586,597-598 
  copyCommand.ts   |   98.49 |    95.78 |     100 |   98.49 | ...80,280,321,327 
  deleteCommand.ts |     100 |      100 |     100 |     100 |                   
  diffCommand.ts   |     100 |     87.5 |     100 |     100 | ...61,224-225,238 
  ...ryCommand.tsx |   81.43 |     88.4 |    90.9 |   81.43 | ...59-264,311-318 
  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 | ...78-181,193-196 
  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   |   84.33 |    72.72 |     100 |   84.33 | 68,82-87,89-94    
  ...ghtCommand.ts |   77.87 |    71.42 |     100 |   77.87 | ...44-245,250-272 
  ...ageCommand.ts |   93.18 |    85.48 |     100 |   93.18 | ...69,189,198-208 
  lspCommand.ts    |     100 |    86.95 |     100 |     100 | 31,101-102        
  mcpCommand.ts    |     100 |      100 |     100 |     100 |                   
  memoryCommand.ts |     100 |      100 |     100 |     100 |                   
  modelCommand.ts  |    81.1 |     89.5 |   88.23 |    81.1 | ...80-793,827-832 
  ...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.6 |    77.95 |     100 |    90.6 | ...91-694,785-792 
  ...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 |    92.59 |     100 |     100 | 69,118            
  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 |   68.57 |     78.5 |   74.71 |   68.57 |                   
  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 |    86.66 |     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 | 18                
  ...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-596             
  DiffDialog.tsx   |   31.17 |    19.51 |   30.76 |   31.17 | ...07-712,722-735 
  ...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       |    77.6 |    61.11 |     100 |    77.6 | ...17-222,240-244 
  ...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.32 |       90 |     100 |   98.32 | ...24,381,447-448 
  ...emDisplay.tsx |   74.35 |    62.19 |      75 |   74.35 | ...72,475,478-484 
  ...ngeDialog.tsx |     100 |      100 |     100 |     100 |                   
  InputPrompt.tsx  |   82.17 |    79.92 |      80 |   82.17 | ...2141,2167,2227 
  ...Shortcuts.tsx |   20.87 |      100 |       0 |   20.87 | ...6,49-51,67-125 
  ...Indicator.tsx |   98.18 |    97.82 |     100 |   98.18 | 161-162           
  ...firmation.tsx |   91.42 |      100 |      50 |   91.42 | 26-31             
  MainContent.tsx  |   98.18 |    94.64 |   66.66 |   98.18 | 90,168-172,474    
  MemoryDialog.tsx |   86.59 |    80.15 |     100 |   86.59 | ...34-435,485,553 
  ...geDisplay.tsx |       0 |        0 |       0 |       0 | 1-41              
  ModelDialog.tsx  |   86.41 |       73 |     100 |   86.41 | ...74,876,881-897 
  ...tsDisplay.tsx |     100 |    97.22 |     100 |     100 | 270               
  ...fications.tsx |       0 |        0 |       0 |       0 | 1-58              
  ...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 |    84.21 |     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.27 |    73.89 |   69.23 |   71.27 | ...1240,1246-1247 
  ...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.78 |    87.67 |     100 |   97.78 | ...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 |    5.46 |      100 |       0 |    5.46 | 24-215            
  ...ineDialog.tsx |    93.5 |    85.18 |     100 |    93.5 | ...05,267,287-289 
  ...yTodoList.tsx |   96.33 |    88.23 |     100 |   96.33 | 137-140           
  ...nsDisplay.tsx |    92.9 |       85 |     100 |    92.9 | ...04,207,234-236 
  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 |    81.81 |     100 |     100 | 71-86             
  ...ification.tsx |       0 |        0 |       0 |       0 | 1-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.38 |    68.69 |   73.68 |   42.38 |                   
  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-164             
  ...tusDialog.tsx |       0 |        0 |       0 |       0 | 1-288             
  ...topDialog.tsx |       0 |        0 |       0 |       0 | 1-213             
 ...ackground-view |   82.06 |    81.23 |   90.74 |   82.06 |                   
  ...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 | 256               
  ...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.86 |    68.14 |   70.83 |   71.86 |                   
  DiscoverTab.tsx  |   68.22 |    67.66 |   55.55 |   68.22 | ...93,656-660,664 
  InstalledTab.tsx |   75.45 |    67.28 |   83.33 |   75.45 | ...76,781-782,819 
  SourcesTab.tsx   |   71.52 |    70.47 |   77.77 |   71.52 | ...27,546,618-630 
 ...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.9 |    73.51 |   57.14 |    53.9 |                   
  ...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.46 |    81.25 |     100 |   88.46 | ...63,169,174-179 
  ...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 |   87.87 |    84.51 |   81.31 |   87.87 |                   
  ...ionDialog.tsx |   86.88 |    81.25 |      80 |   86.88 | ...21,539,557-559 
  BtwMessage.tsx   |     100 |      100 |     100 |     100 |                   
  ...upDisplay.tsx |     100 |     88.7 |     100 |     100 | ...36,246,294,300 
  ...onMessage.tsx |   91.93 |    82.35 |     100 |   91.93 | 57-59,61,63       
  ...nMessages.tsx |   92.16 |    92.68 |   91.66 |   92.16 | ...82-286,304-310 
  DiffRenderer.tsx |   93.19 |    86.17 |     100 |   93.19 | ...09,237-238,304 
  ...tsDisplay.tsx |   97.82 |    77.27 |     100 |   97.82 | 87,89             
  ...usMessage.tsx |   76.31 |     42.1 |   66.66 |   76.31 | ...99,101,124,155 
  ...tsDisplay.tsx |    95.5 |    88.31 |     100 |    95.5 | ...39,141,174-179 
  ...ssMessage.tsx |    12.5 |      100 |       0 |    12.5 | 18-59             
  ...edMessage.tsx |   16.66 |      100 |       0 |   16.66 | 22-38             
  ...sMessages.tsx |   58.65 |       50 |    37.5 |   58.65 | ...20-125,146-158 
  ...ryMessage.tsx |   14.28 |      100 |       0 |   14.28 | 23-62             
  ...onMessage.tsx |   82.31 |    74.02 |   33.33 |   82.31 | ...69-471,478-480 
  ...upMessage.tsx |    98.3 |    95.23 |     100 |    98.3 | 182-185,412       
  ToolMessage.tsx  |   92.09 |    84.57 |   93.33 |   92.09 | ...16-921,948-950 
 ...ponents/shared |   85.62 |    81.93 |   94.89 |   85.62 |                   
  ...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  |   83.01 |    86.25 |   88.88 |   83.01 | ...12-513,618-619 
  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 |    82.7 |    84.84 |     100 |    82.7 | 46-64,71-74       
  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.57 |    85.11 |      90 |   88.57 | ...15,745-773,875 
  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-678             
 ...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.04 |    53.19 |    37.5 |   14.04 |                   
  ...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.42 |    59.52 |     100 |   35.42 | ...20-432,437-439 
  ...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   |   82.17 |    79.32 |   84.37 |   82.17 |                   
  ...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 |   83.18 |     83.4 |     100 |   83.18 | ...1289,1297-1299 
  ...owContext.tsx |   91.07 |    81.81 |     100 |   91.07 | 47-48,60-62       
  ...deContext.tsx |     100 |      100 |      50 |     100 |                   
  ...onContext.tsx |   78.68 |    73.77 |   91.66 |   78.68 | ...86-389,398-401 
  ...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 | 147-148           
  ...teContext.tsx |   86.66 |       50 |     100 |   86.66 | 233-234           
  ...deContext.tsx |      80 |     87.5 |      75 |      80 | ...11-112,118-120 
 src/ui/daemon     |   88.27 |    73.27 |   95.45 |   88.27 |                   
  ...ui-adapter.ts |   88.27 |    73.27 |   95.45 |   88.27 | ...66,784-785,871 
 src/ui/editors    |       0 |        0 |       0 |       0 |                   
  ...ngsManager.ts |       0 |        0 |       0 |       0 | 1-67              
 src/ui/hooks      |   83.75 |    81.86 |   88.38 |   83.75 |                   
  ...dProcessor.ts |   81.49 |    80.95 |     100 |   81.49 | ...33-734,740-745 
  ...ention-ref.ts |   97.67 |       84 |     100 |   97.67 | 63                
  keyToAnsi.ts     |    3.92 |      100 |       0 |    3.92 | 19-77             
  ...esourceRef.ts |     100 |      100 |     100 |     100 |                   
  ...dProcessor.ts |   94.62 |    73.58 |     100 |   94.62 | ...86-287,292-293 
  ...dProcessor.ts |   85.14 |    66.27 |   81.81 |   85.14 | ...1400,1421-1425 
  ...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 
  ...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 |      42 |       75 |     100 |      42 | 42-44,53-59,62-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 |   89.83 |    88.97 |     100 |   89.83 | ...49-456,496-505 
  ...ifications.ts |   86.91 |    96.29 |     100 |   86.91 | 116-130           
  ...tIndicator.ts |   88.28 |    81.08 |     100 |   88.28 | ...66,175,179-187 
  ...waySummary.ts |   96.22 |    69.69 |     100 |   96.22 | 125-127,169       
  ...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.4 |       80 |     100 |    94.4 | ...36,210,273-276 
  ...ompletion.tsx |   96.75 |    81.81 |     100 |   96.75 | ...78-279,289-290 
  ...dMigration.ts |    92.1 |    88.88 |     100 |    92.1 | 42-44             
  useCompletion.ts |   94.11 |    89.65 |     100 |   94.11 | ...32-133,137-138 
  ...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 |      100 |     100 |     100 |                   
  ...ggestions.tsx |   96.47 |    78.94 |     100 |   96.47 | 121,155-156       
  ...miniStream.ts |    83.4 |    80.26 |   95.65 |    83.4 | ...3603,3688-3696 
  ...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 |       0 |        0 |       0 |       0 | 1-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 |      100 |     100 |     100 |                   
  ...delCommand.ts |     100 |    92.85 |     100 |     100 | 48                
  ...ouseEvents.ts |   94.31 |     97.5 |   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 |   86.95 |    77.41 |   91.66 |   86.95 | ...70,311-323,371 
  useQwenAuth.ts   |     100 |      100 |     100 |     100 |                   
  ...lScheduler.ts |   89.47 |    92.45 |     100 |   89.47 | ...77-280,395-405 
  ...oryCommand.ts |       0 |        0 |       0 |       0 | 1-7               
  ...tleRepaint.ts |     100 |      100 |     100 |     100 |                   
  ...umeCommand.ts |   94.33 |    72.72 |     100 |   94.33 | ...18,173,214-219 
  ...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 |       0 |        0 |       0 |       0 | 1-73              
  ...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 |   76.19 |      100 |      50 |   76.19 | 21-25             
  ...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 |      100 |     100 |     100 |                   
  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 |    72.72 |     100 |   93.75 | 47-48,72          
  vim.ts           |      74 |    67.56 |   69.23 |      74 | ...1854-1861,1869 
 src/ui/layouts    |    90.9 |    90.62 |     100 |    90.9 |                   
  ...AppLayout.tsx |   90.72 |       90 |     100 |   90.72 | 57-59,101-106     
  ...AppLayout.tsx |   91.17 |    91.66 |     100 |   91.17 | 70-75             
 src/ui/models     |   80.24 |    79.16 |   71.42 |   80.24 |                   
  ...ableModels.ts |   80.24 |    79.16 |   71.42 |   80.24 | ...,61-71,123-125 
 ...noninteractive |     100 |      100 |    6.66 |     100 |                   
  ...eractiveUi.ts |     100 |      100 |    6.66 |     100 |                   
 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      |    84.9 |    84.09 |   93.71 |    84.9 |                   
  ...Colorizer.tsx |   80.42 |    85.41 |     100 |   80.42 | ...00-201,298-324 
  ...nRenderer.tsx |   68.83 |    70.14 |      50 |   68.83 | ...52-254,274-293 
  ...wnDisplay.tsx |   92.55 |    93.33 |     100 |   92.55 | ...56,896,943-961 
  ...idDiagram.tsx |   87.79 |    95.34 |     100 |   87.79 | 156-179           
  ...eRenderer.tsx |   92.68 |    82.35 |   95.23 |   92.68 | ...34-737,790-795 
  ...odeDisplay.ts |   94.28 |    85.71 |     100 |   94.28 | 23,40             
  asciiCharts.ts   |   96.77 |    87.62 |     100 |   96.77 | 173-180,281       
  ...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  |   90.38 |    73.91 |     100 |   90.38 | 23,25,29,31,33    
  formatters.ts    |    95.4 |    98.41 |     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  |    95.4 |    95.08 |     100 |    95.4 | 96-99             
  input-mouse.ts   |     100 |    85.71 |     100 |     100 | 48,93             
  isNarrowWidth.ts |     100 |      100 |     100 |     100 |                   
  ...olDetector.ts |    8.23 |      100 |       0 |    8.23 | ...31-132,135-136 
  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 |   95.72 |    94.23 |     100 |   95.72 | 90-92,137-138     
  ...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          |   94.84 |    88.74 |     100 |   94.84 | ...57,442,446-447 
  ...red-height.ts |   96.85 |    95.31 |     100 |   96.85 | 71-73,201-203     
  ...mConstants.ts |     100 |      100 |     100 |     100 |                   
  restoreGoal.ts   |   99.02 |    97.56 |     100 |   99.02 | 106               
  ...storyUtils.ts |   71.02 |    78.86 |   93.75 |   71.02 | ...03-525,655-656 
  ...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 
  ...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     |   94.27 |    90.82 |   94.11 |   94.27 | ...89-290,450-451 
  ...background.ts |     100 |      100 |     100 |     100 |                   
  todoSnapshot.ts  |   89.33 |    93.47 |     100 |   89.33 | ...,66-78,180-181 
  ...isplay-map.ts |     100 |      100 |     100 |     100 |                   
  updateCheck.ts   |     100 |       80 |     100 |     100 | 37-49,120         
  ...ow-keyword.ts |     100 |      100 |     100 |     100 |                   
 ...i/utils/export |   74.23 |    56.52 |   94.59 |   74.23 |                   
  collect.ts       |   71.21 |    63.71 |      96 |   71.21 | ...88-631,653-654 
  index.ts         |     100 |      100 |     100 |     100 |                   
  normalize.ts     |   78.57 |    44.92 |     100 |   78.57 | ...40-345,357-359 
  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         |    76.1 |    88.24 |   89.69 |    76.1 |                   
  acpModelUtils.ts |   95.49 |    94.23 |     100 |   95.49 | 44,68-69,73-74    
  apiPreconnect.ts |   96.72 |    97.05 |     100 |   96.72 | 165-168           
  ...ol-call-id.ts |    92.3 |    83.33 |     100 |    92.3 | 26-27             
  ...ng-failure.ts |     100 |       95 |     100 |     100 | 72                
  checks.ts        |   33.33 |      100 |       0 |   33.33 | 23-28             
  cleanup.ts       |   82.53 |    93.33 |      80 |   82.53 | 74,105-115        
  commands.ts      |   96.96 |    97.95 |     100 |   96.96 | 123-125           
  commentJson.ts   |   90.51 |     92.1 |     100 |   90.51 | 67-76,116         
  ...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          
  ...ScopeUtils.ts |   97.56 |    88.88 |     100 |   97.56 | 67                
  doctorChecks.ts  |   70.31 |    74.57 |     100 |   70.31 | ...95-301,325-341 
  ...putCapture.ts |   90.65 |    86.31 |     100 |   90.65 | ...72,370,372-373 
  ...arResolver.ts |   97.14 |    96.55 |     100 |   97.14 | 125-126           
  errors.ts        |   90.85 |    96.36 |    92.3 |   90.85 | 69-70,298-310     
  events.ts        |     100 |      100 |     100 |     100 |                   
  ...on-mention.ts |   88.48 |     82.6 |     100 |   88.48 | ...56-160,164-168 
  gitUtils.ts      |    92.7 |    84.09 |     100 |    92.7 | ...07-110,158-161 
  ...AutoUpdate.ts |   92.89 |    94.59 |   88.88 |   92.89 | 148-159           
  ...tyWarnings.ts |     100 |      100 |     100 |     100 |                   
  ...lationInfo.ts |   97.45 |       94 |     100 |   97.45 | ...17,334-335,380 
  languageUtils.ts |   98.47 |    97.72 |     100 |   98.47 | 153-154           
  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.19 |    90.97 |     100 |   94.19 | ...28,434,437-441 
  ...iveHelpers.ts |   95.33 |    92.08 |     100 |   95.33 | ...51-452,550,563 
  osc.ts           |    97.5 |      100 |   88.88 |    97.5 | 195-196           
  package.ts       |   88.88 |    85.71 |     100 |   88.88 | 31-32             
  processUtils.ts  |     100 |      100 |     100 |     100 |                   
  readStdin.ts     |   93.67 |    94.11 |   85.71 |   93.67 | 79-83             
  relaunch.ts      |   93.22 |    81.25 |     100 |   93.22 | 65-67,80          
  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       |   11.46 |    23.52 |   16.66 |   11.46 | ...5-763,770-1047 
  ...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.37 |    88.75 |      90 |   82.37 | ...20-738,745-753 
  spawnWrapper.ts  |     100 |      100 |     100 |     100 |                   
  ...ate-verify.ts |     100 |      100 |     100 |     100 |                   
  ...one-update.ts |   40.22 |    77.44 |   62.16 |   40.22 | ...1181,1184-1203 
  ...upProfiler.ts |   98.47 |    94.66 |     100 |   98.47 | 132-133,308       
  ...upWarnings.ts |     100 |      100 |     100 |     100 |                   
  stdioHelpers.ts  |     100 |       60 |     100 |     100 | 23,32             
  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 |   94.11 |    83.33 |     100 |   94.11 | 13                
  ...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          |   86.36 |    85.47 |   87.84 |   86.36 |                   
 src               |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/__mocks__/fs  |       0 |        0 |       0 |       0 |                   
  promises.ts      |       0 |        0 |       0 |       0 | 1-48              
 src/agents        |   90.37 |    83.44 |   95.36 |   90.37 |                   
  ...transcript.ts |    92.6 |     87.5 |     100 |    92.6 | ...46,365-366,497 
  ...ent-resume.ts |   83.52 |    72.79 |   79.41 |   83.52 | ...1284-1288,1291 
  ...ound-tasks.ts |   96.53 |     90.4 |     100 |   96.53 | ...1359,1379-1382 
  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.25 |     67.5 |   78.94 |   76.25 |                   
  ...gentClient.ts |   79.47 |    88.88 |   81.81 |   79.47 | ...68-183,189-204 
  ArenaManager.ts  |   75.01 |    64.22 |   78.57 |   75.01 | ...1874,1880-1881 
  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 |   77.89 |    84.85 |   76.28 |   77.89 |                   
  ITermBackend.ts  |   97.97 |    93.93 |     100 |   97.97 | ...78-180,255,307 
  ...essBackend.ts |   90.17 |    84.12 |   93.33 |   90.17 | ...71,673,675-676 
  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 |   88.49 |    85.84 |   83.54 |   88.49 |                   
  agent-context.ts |     100 |      100 |     100 |     100 |                   
  agent-core.ts    |   79.97 |    76.22 |      68 |   79.97 | ...2030,2057-2104 
  agent-events.ts  |     100 |      100 |     100 |     100 |                   
  ...t-headless.ts |   87.93 |    79.06 |   63.63 |   87.93 | ...00-401,404-405 
  ...nteractive.ts |   81.01 |    82.35 |   76.66 |   81.01 | ...33,535-538,541 
  ...statistics.ts |   98.19 |    82.35 |     100 |   98.19 | 127,151,192,225   
  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.86 |    84.09 |    87.4 |   81.86 |                   
  TeamManager.ts   |    72.1 |     79.6 |   78.84 |    72.1 | ...1628,1651-1652 
  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 | ...37-141,148-152 
  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.53 |    86.35 |    71.9 |   83.53 |                   
  approval-mode.ts |     100 |      100 |     100 |     100 |                   
  ...xtDefaults.ts |     100 |      100 |     100 |     100 |                   
  config.ts        |   82.54 |    85.92 |   69.41 |   82.54 | ...6766,6770-6771 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  models.ts        |     100 |      100 |     100 |     100 |                   
  storage.ts       |   94.63 |    91.86 |   89.58 |   94.63 | ...15-416,419-420 
 ...nfirmation-bus |   98.29 |    97.14 |     100 |   98.29 |                   
  message-bus.ts   |   98.14 |    97.05 |     100 |   98.14 | 42-43             
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/core          |   90.83 |    85.97 |   92.89 |   90.83 |                   
  baseLlmClient.ts |   87.19 |    79.68 |      80 |   87.19 | ...18,631,685-687 
  client.ts        |   89.97 |    84.15 |   91.04 |   89.97 | ...2919,3015-3016 
  ...tGenerator.ts |   88.07 |       75 |     100 |   88.07 | ...89-393,401-405 
  ...lScheduler.ts |   89.72 |    84.34 |   95.65 |   89.72 | ...4845,4873-4884 
  geminiChat.ts    |   91.13 |    87.51 |   95.55 |   91.13 | ...3895,3937-3938 
  geminiRequest.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 |   92.59 |       75 |      50 |   92.59 | 41-42             
  ...on-helpers.ts |   87.61 |    76.92 |     100 |   87.61 | ...00-201,215-224 
  ...issionFlow.ts |   98.79 |       96 |     100 |   98.79 | 97                
  prompts.ts       |   88.93 |    87.87 |   72.72 |   88.93 | ...-918,1121-1122 
  ...ing-effort.ts |     100 |      100 |     100 |     100 |                   
  ...n-recovery.ts |   95.13 |       80 |     100 |   95.13 | ...06-107,142-144 
  ...t-profiler.ts |   96.82 |     80.3 |   88.23 |   96.82 | ...08,115-116,121 
  ...port-retry.ts |     100 |      100 |     100 |     100 |                   
  tokenLimits.ts   |     100 |     92.1 |     100 |     100 | 87,122-123        
  ...allIdUtils.ts |   98.23 |     92.1 |     100 |   98.23 | 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 | ...93,621-622,668 
 ...ntentGenerator |   95.75 |       85 |      95 |   95.75 |                   
  ...tGenerator.ts |   97.04 |    85.21 |   94.11 |   97.04 | ...1223,1251-1253 
  converter.ts     |   95.37 |    84.82 |     100 |   95.37 | ...7,843,998-1000 
  index.ts         |       0 |        0 |       0 |       0 | 1-21              
  usage.ts         |     100 |      100 |     100 |     100 |                   
 ...ntentGenerator |   89.93 |    71.83 |   93.33 |   89.93 |                   
  ...tGenerator.ts |    88.3 |    71.21 |   92.85 |    88.3 | ...19-325,343-344 
  index.ts         |     100 |       80 |     100 |     100 | 50                
 ...ntentGenerator |   94.61 |    84.69 |    92.1 |   94.61 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...tGenerator.ts |   94.51 |    83.39 |   91.66 |   94.51 | ...1113-1114,1142 
  ...tDetection.ts |     100 |      100 |     100 |     100 |                   
 ...ntentGenerator |   90.37 |    87.54 |   94.62 |   90.37 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  converter.ts     |   89.32 |    85.36 |   96.29 |   89.32 | ...1646,1815-1830 
  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.34 |    88.83 |     100 |   96.34 | ...20-921,929,997 
  ...ureContext.ts |     100 |      100 |     100 |     100 |                   
  ...ingOptions.ts |       0 |        0 |       0 |       0 | 1                 
  ...CallParser.ts |   92.22 |    90.67 |     100 |   92.22 | ...05-406,443-444 
  ...kingParser.ts |     100 |    96.87 |     100 |     100 | 42                
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...rator/provider |   96.47 |    89.51 |   96.49 |   96.47 |                   
  dashscope.ts     |   97.43 |    91.72 |   94.73 |   97.43 | ...70-371,513-514 
  deepseek.ts      |   94.91 |    89.36 |     100 |   94.91 | ...31-132,145-146 
  default.ts       |    97.5 |    96.55 |   88.88 |    97.5 | 123-124,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.05 |    82.91 |   92.19 |   86.05 |                   
  ...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.69 |    85.18 |   97.82 |   90.69 | ...1189-1195,1239 
  ...ionManager.ts |   80.55 |    77.97 |   80.23 |   80.55 | ...2576,2598-2599 
  ...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.35 |    82.13 |     100 |   88.35 | ...42,932-933,943 
  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.83 |    78.48 |    90.9 |   77.83 |                   
  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.48 |    55.69 |   71.42 |   65.48 | ...75-576,583-584 
  ...onToolGate.ts |     100 |    96.55 |     100 |     100 | 96                
  ...nGenerator.ts |   72.03 |    81.15 |   83.33 |   72.03 | ...68-219,331-333 
 src/generated     |       0 |        0 |       0 |       0 |                   
  git-commit.ts    |       0 |        0 |       0 |       0 | 1-10              
 src/goals         |   92.14 |    86.66 |   95.12 |   92.14 |                   
  ...eGoalStore.ts |   87.61 |    89.28 |   86.66 |   87.61 | ...85-188,196-204 
  goalHook.ts      |   96.59 |    92.72 |     100 |   96.59 | 99-104,205-206    
  goalJudge.ts     |   90.07 |     81.7 |     100 |   90.07 | ...35-336,379-380 
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/hooks         |   87.49 |    86.14 |   88.69 |   87.49 |                   
  ...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.42 |    72.04 |   66.66 |   62.42 | ...64-765,774-775 
  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 |   96.37 |     90.9 |      90 |   96.37 | 342-350,424-425   
  ...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 |    86.74 |     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.09 |   88.88 |   94.24 | ...42-543,628-632 
  urlValidator.ts  |     100 |      100 |     100 |     100 |                   
 src/ide           |   76.87 |    84.98 |   79.03 |   76.87 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  detect-ide.ts    |     100 |      100 |     100 |     100 |                   
  ide-client.ts    |   68.92 |    84.57 |   68.29 |   68.92 | ...1057,1086-1094 
  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.39 |    77.81 |   78.33 |   82.39 |                   
  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.52 |    58.06 |     100 |   79.52 | ...33-940,947-949 
  ...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        |   85.79 |    80.96 |    88.5 |   85.79 |                   
  ...nel-memory.ts |    88.7 |    80.95 |      90 |    88.7 | ...00-204,209-212 
  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 
  manager.ts       |   78.44 |    82.29 |   77.77 |   78.44 | ...1482,1495-1497 
  ...ent-config.ts |   81.98 |    79.72 |   82.35 |   81.98 | ...25,244,251-257 
  memoryAge.ts     |   90.47 |       80 |     100 |   90.47 | 50-51             
  paths.ts         |   94.61 |    95.77 |     100 |   94.61 | ...16-317,338-339 
  ...ing-skills.ts |     100 |       72 |     100 |     100 | 31-35,73-78,97    
  prompt.ts        |   96.96 |    85.96 |     100 |   96.96 | ...22,225,560-561 
  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         |   93.33 |    81.25 |     100 |   93.33 | ...,94-95,119-120 
  ...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 |   79.38 |    78.33 |   81.81 |   79.38 | ...58-272,286-291 
 src/mocks         |       0 |        0 |       0 |       0 |                   
  msw.ts           |       0 |        0 |       0 |       0 | 1-9               
 src/models        |   91.25 |    88.35 |   89.74 |   91.25 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...tor-config.ts |   90.55 |    91.42 |     100 |   90.55 | 146,152,155-164   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...nfigErrors.ts |   74.22 |       44 |   84.61 |   74.22 | ...,67-74,106-117 
  ...igResolver.ts |   98.71 |    93.33 |     100 |   98.71 | 166,328,334       
  modelRegistry.ts |     100 |    98.91 |     100 |     100 | 177               
  modelsConfig.ts  |   88.07 |    86.78 |   85.36 |   88.07 | ...1358,1387-1388 
  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.03 |    91.25 |   69.95 |   83.03 |                   
  autoMode.ts      |   97.78 |    94.08 |     100 |   97.78 | ...42,570-577,686 
  ...transcript.ts |      98 |       84 |     100 |      98 | 200-201           
  classifier.ts    |      94 |    94.44 |     100 |      94 | 158-165,385-389   
  ...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 |   85.13 |    89.24 |      80 |   85.13 | ...1035,1141-1145 
  rule-parser.ts   |   94.36 |    92.63 |     100 |   94.36 | ...1211,1245-1247 
  ...-semantics.ts |   70.36 |    91.07 |   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/plan-gate     |   76.16 |    91.42 |      80 |   76.16 |                   
  ...viewAgents.ts |   52.28 |    88.46 |   66.66 |   52.28 | ...24-220,242-243 
  ...provalGate.ts |   92.47 |    92.85 |   85.71 |   92.47 | ...86-187,268-274 
  state.ts         |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 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     |   81.91 |    76.58 |   78.12 |   81.91 |                   
  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 |    72.6 |       70 |   73.91 |    72.6 | ...94-495,502-511 
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...viders/presets |   97.67 |    89.28 |   55.55 |   97.67 |                   
  ...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.3 |     78.8 |   95.89 |    85.3 |                   
  ...tGenerator.ts |   98.64 |    98.18 |     100 |   98.64 | 105-106           
  qwenOAuth2.ts    |   82.55 |    73.71 |   90.62 |   82.55 | ...1183-1199,1229 
  ...kenManager.ts |   85.36 |    76.61 |     100 |   85.36 | ...52-757,778-783 
 src/resources     |     100 |      100 |     100 |     100 |                   
  ...e-registry.ts |     100 |      100 |     100 |     100 |                   
 src/services      |   90.47 |    85.28 |   96.62 |   90.47 |                   
  ...ionTrailer.ts |     100 |      100 |     100 |     100 |                   
  ...llRegistry.ts |   97.35 |    85.21 |     100 |   97.35 | ...94,117,417-418 
  ...ionService.ts |   96.71 |    95.79 |     100 |   96.71 | ...83,699,832-840 
  ...ingService.ts |   91.63 |    85.77 |      90 |   91.63 | ...1633,1648-1649 
  ...ttribution.ts |   91.73 |    87.71 |      90 |   91.73 | ...80-685,826-827 
  ...utSlimming.ts |   99.54 |    96.42 |     100 |   99.54 | 98                
  cronScheduler.ts |    96.2 |     91.8 |     100 |    96.2 | ...1228,1627-1628 
  cronTasksFile.ts |   95.71 |    91.01 |     100 |   95.71 | ...93,318-319,437 
  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.07 |    85.93 |    90.9 |   92.07 | ...09,211,323-330 
  ...ratedFiles.ts |      96 |    88.23 |     100 |      96 | 119-120,146-147   
  gitInit.ts       |     100 |      100 |     100 |     100 |                   
  ...reeService.ts |   74.05 |       69 |   95.74 |   74.05 | ...2170,2198-2199 
  ...references.ts |   98.39 |    88.88 |     100 |   98.39 | 154-155,215-216   
  ...ionService.ts |   98.09 |    97.17 |     100 |   98.09 | ...00-601,648-649 
  ...ticsDumper.ts |   98.37 |    95.23 |     100 |   98.37 | 185-186           
  ...ureMonitor.ts |   95.82 |    90.52 |   97.05 |   95.82 | ...60,861,875-877 
  ...orRegistry.ts |   97.27 |    91.22 |     100 |   97.27 | ...50-451,606-607 
  ...ttachments.ts |   97.74 |     90.8 |     100 |   97.74 | 298-308,646       
  ...ersistence.ts |   91.01 |    78.68 |     100 |   91.01 | ...6,971-972,1000 
  ...on-service.ts |   94.49 |    92.26 |   97.14 |   94.49 | ...98-600,656-664 
  ...ipt-reader.ts |   92.81 |    83.61 |   97.95 |   92.81 | ...74-876,979-984 
  sessionRecap.ts  |   67.56 |    43.47 |     100 |   67.56 | ...60,178,180-183 
  ...ionService.ts |   87.75 |    80.98 |   95.31 |   87.75 | ...2246,2316-2336 
  sessionTitle.ts  |   94.19 |    73.21 |     100 |   94.19 | ...43-246,277-278 
  ...ionService.ts |   84.03 |    78.09 |   96.96 |   84.03 | ...2406,2412-2417 
  ...pInhibitor.ts |   97.42 |    92.77 |     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 |   92.07 |    84.69 |     100 |   92.07 | ...47-450,502-503 
  ...reeCleanup.ts |   14.56 |      100 |   33.33 |   14.56 | 58-185            
  ...ionService.ts |   87.98 |    86.95 |     100 |   87.98 | ...38-439,455-456 
 ...icrocompaction |   99.41 |    96.06 |     100 |   99.41 |                   
  microcompact.ts  |   99.41 |    96.06 |     100 |   99.41 | 242-243,675       
 ...s/visionBridge |   96.64 |    94.17 |   94.11 |   96.64 |                   
  ...capability.ts |     100 |      100 |     100 |     100 |                   
  ...part-utils.ts |     100 |      100 |     100 |     100 |                   
  ...-constants.ts |     100 |      100 |     100 |     100 |                   
  ...ge-service.ts |   95.49 |     91.3 |      90 |   95.49 | ...12,430,443-444 
 src/skills        |   88.22 |    87.05 |   90.16 |   88.22 |                   
  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.44 |    82.16 |   82.35 |   83.44 | ...1202,1209-1213 
  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.28 |    87.17 |   96.42 |   87.28 |                   
  ...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.48 |    82.81 |   94.59 |   83.48 | ...1480,1557-1558 
  types.ts         |     100 |      100 |     100 |     100 |                   
  validation.ts    |   92.46 |    95.18 |     100 |   92.46 | 47-52,63-68,71-76 
 src/telemetry     |   79.95 |    87.42 |   82.18 |   79.95 |                   
  ...ty-tracker.ts |     100 |      100 |     100 |     100 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...on-metrics.ts |   99.06 |    80.48 |     100 |   99.06 | 183,197           
  ...on-tracing.ts |   74.55 |    73.21 |   70.58 |   74.55 | ...95,354-356,372 
  ...attributes.ts |   97.47 |    93.15 |     100 |   97.47 | 39-44             
  ...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 
  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       |   53.44 |    71.57 |      62 |   53.44 | ...1326,1343-1363 
  metrics.ts       |   76.07 |    78.57 |   78.94 |   76.07 | ...1021,1024-1035 
  ...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       
  sdk.ts           |   86.75 |     88.4 |   66.66 |   86.75 | ...17-621,659-681 
  ...on-context.ts |     100 |      100 |     100 |     100 |                   
  ...on-tracing.ts |   90.06 |    88.25 |   96.55 |   90.06 | ...1541,1572-1575 
  ...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         |   81.31 |    86.15 |      85 |   81.31 | ...1301,1305-1312 
  uiTelemetry.ts   |   93.07 |    92.85 |   83.33 |   93.07 | ...62,290,410-411 
 ...ry/qwen-logger |   73.22 |    82.24 |   68.96 |   73.22 |                   
  event-types.ts   |       0 |        0 |       0 |       0 |                   
  qwen-logger.ts   |   73.22 |    82.07 |   68.42 |   73.22 | ...1079,1117-1118 
 src/test-utils    |   93.85 |    98.14 |   77.77 |   93.85 |                   
  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.3 |      100 |   74.19 |    92.3 | ...54,218-219,232 
  ...aceContext.ts |     100 |      100 |     100 |     100 |                   
 src/tools         |   84.25 |    83.54 |    87.7 |   84.25 |                   
  ...erQuestion.ts |   90.74 |    82.43 |    92.3 |   90.74 | ...23-424,431-432 
  ...-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 |   84.89 |    81.81 |   85.71 |   84.89 | ...27-132,165-179 
  exit-worktree.ts |   83.29 |    83.65 |   94.44 |   83.29 | ...14-515,537-538 
  exitPlanMode.ts  |    81.7 |    73.41 |     100 |    81.7 | ...28-531,561-564 
  glob.ts          |   94.42 |    88.23 |   93.33 |   94.42 | ...19-220,368,371 
  grep.ts          |   83.09 |    86.66 |   80.95 |   83.09 | ...60-661,711-712 
  ...adTracking.ts |     100 |      100 |     100 |     100 |                   
  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.54 |    78.86 |    85.1 |   81.54 | ...3182,3184-3185 
  mcp-client.ts    |   78.48 |    83.66 |   88.46 |   78.48 | ...2140,2144-2147 
  ...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      |   91.66 |    89.74 |   96.77 |   91.66 | ...20-721,771-772 
  ...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.72 |    84.28 |   88.46 |   91.72 | ...92,605,803-808 
  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 |    89.74 |     100 |   82.57 | 174-185,234-247   
  read-file.ts     |   94.86 |    90.62 |   81.81 |   94.86 | ...06,309,392-393 
  ...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.87 |     88.4 |   94.73 |   95.87 | ...56-657,663-664 
  ...-transport.ts |   71.42 |    55.55 |   71.42 |   71.42 | ...36-137,143-144 
  send-message.ts  |    82.3 |    89.65 |    62.5 |    82.3 | ...37-243,326-334 
  ...n-mcp-view.ts |   93.57 |     92.3 |      90 |   93.57 | 122-130           
  shell.ts         |   77.46 |    82.06 |   91.48 |   77.46 | ...4833,4896-4897 
  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     |   89.27 |    82.05 |   92.85 |   89.27 | ...50-555,577-578 
  tool-error.ts    |     100 |      100 |     100 |     100 |                   
  tool-names.ts    |     100 |      100 |     100 |     100 |                   
  tool-registry.ts |   76.78 |    74.59 |   82.22 |   76.78 | ...96-897,905-906 
  tool-search.ts   |   96.19 |    89.72 |   93.33 |   96.19 | ...09,259-264,426 
  tools.ts         |   93.97 |     90.9 |   95.23 |   93.97 | ...36-537,553-559 
  web-fetch.ts     |   90.12 |    85.71 |   92.85 |   90.12 | ...11-312,326-327 
  write-file.ts    |   84.28 |    82.79 |   84.61 |   84.28 | ...87-690,727-762 
 src/tools/agent   |   84.44 |    84.79 |   86.31 |   84.44 |                   
  agent.ts         |   84.49 |    84.88 |    86.2 |   84.49 | ...3695,3717-3727 
  fork-subagent.ts |   83.14 |       80 |    87.5 |   83.14 | 83-101,133-134    
 ...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         |   91.48 |    89.22 |   95.81 |   91.48 |                   
  LruCache.ts      |     100 |      100 |     100 |     100 |                   
  ...Controller.ts |     100 |      100 |     100 |     100 |                   
  ...ssageQueue.ts |     100 |      100 |     100 |     100 |                   
  ...cFileWrite.ts |   94.76 |    93.26 |     100 |   94.76 | ...30-531,634-638 
  bareMode.ts      |   81.81 |      100 |      50 |   81.81 | 18-19             
  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 
  ...tion-chain.ts |     100 |    96.15 |     100 |     100 | 91                
  cronDisplay.ts   |     100 |    91.66 |     100 |     100 | 15,43,57          
  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 | ...28-429,463-464 
  editor.ts        |   97.65 |    95.45 |     100 |   97.65 | ...35-336,338-339 
  env.ts           |     100 |      100 |     100 |     100 |                   
  ...arResolver.ts |   94.28 |    88.88 |     100 |   94.28 | 28-29,125-126     
  ...entContext.ts |   96.55 |       88 |   96.77 |   96.55 | ...74,476-477,544 
  errorParsing.ts  |    97.7 |    97.05 |     100 |    97.7 | 72-73             
  ...rReporting.ts |   95.65 |    93.33 |     100 |   95.65 | 37-38             
  errors.ts        |   81.73 |    90.55 |   57.89 |   81.73 | ...08-324,328-334 
  fetch.ts         |   72.45 |    81.81 |   71.42 |   72.45 | ...31,142-143,162 
  fileUtils.ts     |   94.44 |    90.65 |   96.15 |   94.44 | ...1596,1621-1622 
  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,330-335 
  getPty.ts        |   31.57 |       50 |     100 |   31.57 | 26-38             
  gitDiff.ts       |   92.36 |    80.09 |     100 |   92.36 | ...55-856,928-929 
  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 |    88.88 |   83.33 |      75 | ...,78-79,103-154 
  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 |                   
  jsonl-utils.ts   |   95.27 |    92.85 |     100 |   95.27 | ...16-317,356-359 
  ...-detection.ts |     100 |      100 |     100 |     100 |                   
  ...iagnostics.ts |    96.4 |     94.2 |     100 |    96.4 | ...66,293-294,376 
  ...yDiscovery.ts |    92.4 |    89.01 |     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.14 |     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 
  partUtils.ts     |     100 |    98.61 |     100 |     100 | 206               
  pathReader.ts    |   97.77 |       90 |     100 |   97.77 | 93,121            
  paths.ts         |   93.72 |    92.59 |     100 |   93.72 | ...47-448,450-452 
  pdf.ts           |   92.59 |    86.76 |     100 |   92.59 | ...54-555,596-601 
  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.42 |     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 |    91.83 |     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  |   50.94 |    85.71 |      70 |   50.94 | ...54-255,268-346 
  ...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 |   83.09 |    86.77 |   95.45 |   83.09 | ...70,595,624-633 
  ...odelPrefix.ts |     100 |      100 |     100 |     100 |                   
  runtimeStatus.ts |    97.5 |    89.74 |     100 |    97.5 | 162-163           
  safe-mode.ts     |     100 |      100 |     100 |     100 |                   
  safeJsonParse.ts |   74.07 |    83.33 |     100 |   74.07 | 40-46             
  ...nStringify.ts |     100 |      100 |     100 |     100 |                   
  ...aConverter.ts |   91.13 |    89.47 |     100 |   91.13 | ...41-42,96,98-99 
  ...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.96 |     100 |   95.98 | ...70,386,466,485 
  ...-pager-env.ts |     100 |      100 |     100 |     100 |                   
  shell-utils.ts   |   85.76 |     88.2 |     100 |   85.76 | ...2179,2186-2190 
  ...lAstParser.ts |   96.39 |    88.06 |     100 |   96.39 | ...1071-1073,1083 
  ...ContextEnv.ts |     100 |      100 |     100 |     100 |                   
  ...nlyChecker.ts |   95.08 |    91.75 |     100 |   95.08 | ...15-316,324-325 
  sideQuery.ts     |   86.82 |     86.2 |     100 |   86.82 | ...81-187,189-195 
  ...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          
  ...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             
  tool-utils.ts    |    95.2 |    93.61 |     100 |    95.2 | ...58-159,162-163 
  ...ultCleanup.ts |   54.62 |       64 |      75 |   54.62 | ...03-105,108-134 
  ...Compaction.ts |   95.68 |    95.32 |     100 |   95.68 | ...29-334,533-534 
  truncation.ts    |   75.55 |    86.17 |   71.42 |   75.55 | ...44-449,453-477 
  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.01 |     74.5 |   84.37 |   69.01 |                   
  ...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.

@wenshao

wenshao commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator Author

CI: the two failures are flakes, not this branch

`Test (ubuntu-latest, Node 22.x)` failed on two tests, and both are timeouts in files this branch does not touch:

Test Failure
`packages/cli/src/serve/workspace-registration-store.test.ts` → persists, deduplicates, and removes workspace paths `Error: Test timed out in 5000ms`
`packages/core/src/extension/github.test.ts` → should cancel while extracting a tar archive `Error: Timed out waiting for extracted data at /tmp/gemini-test-…/extracted/large.bin`

Both pass locally on this branch:

$ npx vitest run --root packages/cli src/serve/workspace-registration-store.test.ts
  Test Files  1 passed (1)     Tests  15 passed | 1 skipped (16)

$ npx vitest run --root packages/core src/extension/github.test.ts
  Test Files  1 passed (1)     Tests  86 passed (86)

This branch touches only packages/cli/src/commands/review/ and packages/core/src/skills/bundled/review/ — zero files under serve/ or extension/. And main's own CI has failed on 3 of its last 6 runs.

Failed jobs re-run.

中文说明

Test (ubuntu-latest, Node 22.x) 挂了两个测试,都是超时,且都在本分支一行未碰的文件里serve/workspace-registration-store.test.tsTest timed out in 5000ms)和 extension/github.test.tsTimed out waiting for extracted data)。两者在本分支上本地都通过(15 passed / 86 passed)。本分支只改了 packages/cli/src/commands/review/packages/core/src/skills/bundled/review/serve/extension/ 下零改动;而 main 自己最近 6 次 CI 里有 3 次是红的。已重跑失败的 job。

@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 the diff; see the terminal output.

— qwen3.7-max via Qwen Code /review

Comment on lines 311 to 312
if (payload.state === undefined) {
problems.push(

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] structuralProblems does not reject state: null — Concrete cost: a payload with "state": null passes the === undefined guard (null is not undefined). compose then collapses it to {} via ?? ({} as ComposeReviewInput), producing a confusing error downstream instead of the intended "state is missing" message.

Suggested change
if (payload.state === undefined) {
problems.push(
if (payload.state == null) {
problems.push(

Loose equality (== null) catches both undefined and null.

— qwen3.7-max via Qwen Code /review

Comment thread packages/cli/src/commands/review/lib/prompt-record.ts
Comment thread packages/cli/src/commands/review/lib/coverage.ts
Comment on lines +144 to +145
/** Drop the record. Called by `cleanup`, which owns the rest of the temp files. */
export function removePromptRecord(planPath: string): void {

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] removePromptRecord is exported with a doc comment saying "Called by cleanup" but cleanup.ts never imports or calls it. Cleanup happens via cleanup.ts's prefix-based rmSync sweep. Either have cleanup.ts call this function (making the comment true and cleanup more precise), or correct the doc comment to describe the actual cleanup mechanism.

— qwen3.7-max via Qwen Code /review

'',
'```bash',
`qwen review test-efficacy ${opts.planPath} \\`,
` --worktree ${typeof wt === 'string' ? wt : '<worktree>'} \\`,

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] worktreePath may be relative (e.g., .qwen/tmp/review-pr-6892), but the test-efficacy command embeds it as the --worktree argument. Since the agent's cwd is already the worktree, the relative path would resolve to <worktree>/.qwen/tmp/review-pr-6892 (nonexistent). Use resolve(wt) (already imported from node:path) to produce an absolute path, or emit --worktree ..

— qwen3.7-max via Qwen Code /review

writeStdoutLine(
JSON.stringify(
{ posted: false, wouldPost: true, target, event: payload.event },
{ posted: false, wouldPost: true, target, event },

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] Dry-run JSON omits cappedBy — Concrete cost: a user running --dry-run to preview what would be posted sees "event": "COMMENT" with no explanation of why the verdict was capped from APPROVE. The non-dry-run path (line 523) already includes cappedBy; add it here too.

Suggested change
{ posted: false, wouldPost: true, target, event },
{ posted: false, wouldPost: true, target, event, cappedBy },

— qwen3.7-max via Qwen Code /review

…equest

The repository's own `/review` bot reviewed #6892 — this change reviewing the code
that changes it — and filed six Suggestions. Every one of them is real, and two are
fail-open holes in the gates this pull request exists to build. They are fixed here,
each with a test.

- **`submit` accepted `state: null`.** `=== undefined` is not `== null`, so the
  structural check passed it; `compose`'s `?? {}` then collapsed it to an empty state
  and would have posted a review whose footer named no model and whose caps came from
  nowhere.

- **`wasDeliveredVerbatim` was vacuously true for an empty `built` prompt.** A
  zero-byte record is what a partial write leaves behind — and `recordPrompt` swallows
  its write errors by design, so this is reachable. `readRecordedPrompts` stores it as
  `''`, not `undefined`, so the "no prompt was built" guard did not catch it, and the
  loop's body never executed. The roster would have credited a required role to
  whichever transcript it looked at first. It now fails closed.

- **A chunk read across two pages got no credit.** The check asked for a *single*
  range containing the chunk, and reads of 1-200 and 201-400 are two — so it
  contradicted the paging instruction the same review had just given, on exactly the
  oversized chunks where paging is not optional. Ranges are coalesced first.

- **Agent 7 was handed relative paths it could not resolve.** `worktreePath` and the
  plan path are repo-relative in the report, and Agent 7's working directory *is* the
  worktree — so `--worktree .qwen/tmp/review-pr-6457` resolved to
  `<worktree>/.qwen/tmp/review-pr-6457`, which does not exist. This was already
  visible and nobody had read it: in the 29-agent dogfood run, Agent 7 spent its time
  running `find … -name "*6457*fetch*"`, hunting for a plan it had been handed a path
  to. Absolute now.

- **`removePromptRecord` was dead code with a comment claiming a caller it did not
  have.** `cleanup.ts` sweeps the prompt directory by prefix instead. Deleted.

- **`--dry-run` omitted `cappedBy`.** The point of a dry run is to see what would be
  posted; `"event": "COMMENT"` with no reason leaves the reader to guess why the
  Approve went away.
@wenshao
wenshao requested a review from Copilot July 14, 2026 15:59

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@wenshao

wenshao commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator Author

All six findings fixed — and this is the result the PR was arguing for

The repository's own /review reviewed this pull request. All six of its Suggestions are real, and two of them are fail-open holes in the very gates this change exists to build. Fixed in 1e69e522a, each with a test.

# Finding Verdict
1 structuralProblems does not reject state: null Real. === undefined is not == null. compose's ?? {} then collapsed it to an empty state, and the review would have posted with a footer naming no model and caps coming from nowhere.
2 wasDeliveredVerbatim is true for an empty built prompt Real, and a fail-open in a gate. A zero-byte record is what a partial write leaves behind — and recordPrompt swallows its write errors by design, so this is reachable. readRecordedPrompts stores it as ``, not undefined, so the "no prompt was built" guard misses it and the loop body never runs. The roster would have credited a required role to whichever transcript it looked at first. Now fails closed.
3 Chunk coverage needs a single range to contain the chunk Real. Reads of 1-200 and 201-400 are two ranges — so the check contradicted the paging instruction the same review had just given, on exactly the oversized chunks where paging is not optional. Ranges are coalesced first.
4 removePromptRecord is dead code whose comment claims a caller it does not have Real. cleanup.ts sweeps the directory by prefix instead. Deleted.
5 Agent 7 gets a relative --worktree it cannot resolve Real — and I have the transcript of it failing. worktreePath is repo-relative and Agent 7's cwd is the worktree, so --worktree .qwen/tmp/review-pr-6457 resolves to <worktree>/.qwen/tmp/review-pr-6457. In the 29-agent dogfood run, Agent 7 spent its time running find … -name "*6457*fetch*" — hunting for a plan it had been handed a path to. I watched that happen and did not read it. The reviewer did. Absolute now.
6 --dry-run omits cappedBy Real. The point of a dry run is seeing what would be posted; "event": "COMMENT" with no reason leaves the reader to guess why the Approve went away.

Zero false positives. Two of the six are defects in the gates themselves, and #5 is a bug whose live failure was in a transcript I had already looked at.

That is the argument of this pull request, run against the pull request: the review's value is not in what it says about itself — it is in what its agents actually read.

562 tests in commands/review, green.

中文说明

仓库自己的 /review 审了这个 PR——这个 skill 在审改它自己的代码六条 Suggestion 全是真的,其中两条是这个 PR 正要建立的那些闸门里的 fail-open 漏洞。已在 1e69e522a 全部修复,每条都有测试钉住。

  1. state: null 绕过 === undefined —— 真。compose?? {} 会把它塌成空 state,然后带着「footer 里没有模型名、封顶来源不明」的评审发出去。
  2. builtwasDeliveredVerbatim 恒真 —— 真,而且是闸门的 fail-open。零字节记录正是部分写入留下的东西,而 recordPrompt 按设计吞掉写错误,所以这条路可达。readRecordedPrompts 把它存成 `` 而不是 undefined,于是「没有构建过 prompt」的守卫漏掉它,循环体一次都不执行——roster 会把一个必需角色记到它第一眼看到的那个 transcript 头上。现在 fail-closed。
  3. 分页读的 chunk 拿不到 credit —— 真。1-200 和 201-400 是两个区间,于是这个检查跟同一次 review 刚刚下达的分页指令自相矛盾,而且恰恰是在「分页不是可选项」的超大 chunk 上。现在先合并区间。
  4. removePromptRecord 是死代码,注释还声称有个并不存在的调用方 —— 真。已删除。
  5. Agent 7 拿到解析不了的相对 --worktree —— 真,而且我手里就有它失败的 transcript。29-agent 那轮里,Agent 7 在满世界跑 find … -name "*6457*fetch*"——找一个「明明把路径给了它」的 plan。那一幕我看见了,但没读懂。审查器读懂了。
  6. --dry-run 漏了 cappedBy —— 真。

零假阳性。六条里两条是闸门自身的缺陷,第 5 条的失败现场就躺在我早已看过的一份 transcript 里。

这正是本 PR 的论点,作用在本 PR 身上:一次 review 的价值不在它如何自述,而在它的 agent 究竟读了什么。

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

[Critical] SKILL.md Step 7 contradiction: unchanged main-path JSON examples still show event/body fields (lines ~786-815), but submit.ts now refuses payloads carrying those fields. An orchestrator following the unchanged instructions would build a payload that submit rejects. The new no-findings path (line ~905) correctly states the new contract, but the main-path examples were not updated.

— qwen3.7-max via Qwen Code /review

Comment thread packages/cli/src/commands/review/agent-prompt.ts Outdated
Comment thread packages/cli/src/commands/review/lib/transcripts.ts
Comment thread packages/cli/src/commands/review/lib/transcripts.ts
Comment on lines +400 to +401
const brief = briefPath(planPath, req.key);
const opened = agent.successfulCallArgs.some((a) => a.includes(brief));

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] unreadBriefs check does not verify the brief file exists on disk before reporting — Concrete cost: if writeBrief silently fails (e.g., inode exhaustion) but recordPrompt succeeds, the coverage report says the agent "never opened its brief" when the brief was never written. Consider adding existsSync(brief) check or a separate missingBriefFiles category.

— qwen3.7-max via Qwen Code /review

Comment on lines +160 to +162
if (report.missingChunks.length > 0) {
writeStderrLine(
'NOTE: a chunk counts as read when an agent was pointed at its lines AND ' +

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] Redundant NOTE + ERROR output for the same missingChunks condition — Concrete cost: when chunks are missing, the user gets a NOTE explaining why chunks might be missing followed by an ERROR listing which ones. Consider merging the NOTE's context into the ERROR message at line 185.

— qwen3.7-max via Qwen Code /review

Comment thread packages/cli/src/commands/review/lib/roster.ts Outdated
Comment thread packages/cli/src/commands/review/agent-prompt.test.ts Outdated
The reviewer caught a real contradiction it filed as Critical: submit.ts now
refuses a payload carrying `event`/`body` (those are computed from `state` and
the attached comments), but Step 7's main-path 'Build the review JSON' examples
still showed `"event": "REQUEST_CHANGES"` / `"body"` and routed the verdict
through a copy-it-verbatim step. An orchestrator following the unchanged
instructions would have built exactly the payload submit rejects.

The correct `{commit_id, comments, state}` shape existed lower in the section (the
no-findings branch), added when submit took over composition — but the main-path
examples and the compose-review-then-transcribe bullets above them were never
reconciled. They are now: one payload shape, no verdict in it, `state` handed to
submit, and the inline counts derived from the comments rather than supplied.

Found by the repository's own /review on #6892.
@wenshao
wenshao requested a review from Copilot July 14, 2026 23:11

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@wenshao

wenshao commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator Author

The Critical is real — fixed in a43ca7ef6

Confirmed and fixed. The submit change (verdict is computed from state, never carried) landed in the code, and the no-findings branch of Step 7 was updated to the {commit_id, comments, state} shape — but the main-path "Build the review JSON" examples (lines ~785-820) were never reconciled: they still showed "event": "REQUEST_CHANGES" / "body" and routed the verdict through a "call compose-review, then copy event/body verbatim into the JSON" step. An orchestrator following those would have built precisely the payload submit now refuses.

Reconciled to one shape:

  • the payload is { commit_id, comments, state } — no event, no body;
  • state is handed to submit, which composes the verdict from it (the same computation Step 6 already printed for the terminal);
  • the inline counts are derived from the attached comments, not supplied — a state carrying criticalsInline/suggestionsInline is refused;
  • the duplicate no-findings example collapsed to prose that points back at the one shape.

bundled-skills integration test green; dist SKILL rebuilt.

This is the seventh time in this PR that the answer to a review finding was "a rule stated in one place and contradicted in another" — and the review reads the whole document, so it caught the half I had left behind. That is the argument of the change, again, on the change.

中文说明

这条 Critical 是真的,已在 a43ca7ef6 修复。 submit 改成从 state 现算 verdict(不再接受 payload 里的 event/body)之后,Step 7 的无 findings 分支更新成了 {commit_id, comments, state} 形状——但主路径的「Build the review JSON」示例(约 785-820 行)没同步:仍然写着 "event": "REQUEST_CHANGES" / "body",还让人「调 compose-review,再把 event/body 逐字抄进 JSON」。照着走的 orchestrator 会构造出正是 submit 现在会拒绝的 payload。

已统一成一种形状:payload 只有 { commit_id, comments, state };state 交给 submit 现算 verdict(与 Step 6 打印给终端的是同一次计算);inline 计数从挂上的 comment 数出来、不接受传入;重复的无-findings 示例收敛成一句指回主形状的散文。

bundled-skills 集成测试通过,dist 已重建。

这已经是本 PR 里第七次「一条规则在一处声明、在另一处自相矛盾」——而审查器读的是整份文档,于是它抓到了我落下的那一半。这又一次正是这个改动本身的论点,作用在这个改动上。

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

— qwen3.7-max via Qwen Code /review

It reads the harness's own per-agent transcripts: a record you do not author, are not given the path to, and cannot revise. It reports three failures, and they are not the same:
**This step runs on both topologies.** It used to live inside Step 3B and be reachable only from there, and it modelled coverage as "an agent whose prompt says `chunk N of M` made a tool call" — which no Step 3A agent's prompt ever says. Run against a real 3A review whose twelve agents each opened the diff, walked both chunks and filed findings, it reported `0/2 chunk(s) reviewed … Nobody read those lines` in the same breath as `16 agent(s) ran; 16 did work`. `compose-review` runs the same computation on the way to the verdict, so that review was capped away from Approve and the body it would have posted to the pull request said nobody had read it. Both sentences cannot be true. Coverage is now the intersection of two things the harness wrote down: the lines each agent was **pointed at** (its launch prompt) and the fact that it **opened the diff** (a successful tool call naming the diff file).

It reads the harness's own per-agent transcripts: a record you do not author, are not given the path to, and cannot revise. It reports six failures, and they are not the same:

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] Count mismatch: the text says "six failures" but seven bullet points follow (Agents that never ran, never opened brief, launched blind, not launched with CLI-built prompt, pointed at diff but never opened it, made no tool call, chunks nobody reviewed). check-coverage.ts reports eight distinct categories (blindAgents, rewrittenPrompts, missingRoles, unreadBriefs, unopenedAgents, idleAgents, uncoverableChunks, missingChunks). An orchestrator trusting the count "six" would silently drop one failure class.

Suggested change
It reads the harness's own per-agent transcripts: a record you do not author, are not given the path to, and cannot revise. It reports six failures, and they are not the same:
It reads the harness's own per-agent transcripts: a record you do not author, are not given the path to, and cannot revise. It reports eight failures, and they are not the same:

— qwen3.7-max via Qwen Code /review

Comment thread packages/cli/src/commands/review/compose-review.ts
Comment thread packages/cli/src/commands/review/submit.ts
The repository's /review passed #6892 (no blockers) and filed three Suggestions.
All three are real; two are contradictions this PR itself introduced.

- **verdictLine printed a dangling colon.** When a would-be Approve was taken away
  by a presubmit downgrade ALONE — no cap state, `cappedBy` empty, `downgraded`
  true — the code joined the empty array and produced 'an Approve was NOT
  available:  — downgraded by a presubmit check', a colon over nothing. It now
  collects the reasons (a cap and a downgrade are both reasons, either can be the
  only one) and prints the clause only when there is a reason to. The function had
  no test; it has six now, including this case.

- **Step 3D said 'six failures' and listed seven, while check-coverage reports
  eight.** The count drifted as failure classes were added, and the uncoverable-chunk
  class had no bullet at all. Now 'eight', with the missing bullet written.

- **`submit --review` help still advertised `event` / `body`** as payload fields,
  which the same command now refuses. Updated to `commit_id / comments / state`.

Found by the repository's own /review on #6892 — the third pass, the one that
turned CHANGES_REQUESTED into no-blockers.
@wenshao
wenshao requested a review from Copilot July 15, 2026 00:53

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@wenshao

wenshao commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator Author

Third pass: no blockers, three Suggestions — all real, fixed in c2cb5b618

The review passed (Reviewed — no blockers) — the stale-event/body Critical from pass two is gone. It filed three Suggestions, and two of them are contradictions this PR introduced:

# Finding Verdict
1 verdictLine has no test; a downgrade-only path could print a dangling colon Real, and reproducible. When a would-be Approve is taken away by a presubmit downgrade alone — no cap state, cappedBy empty, downgraded true — the old code joined the empty array: an Approve was NOT available: — downgraded by a presubmit check, a colon over nothing. The reviewer had the mechanism slightly off (it framed it as cappedBy empty + downgrade, which is exactly the trigger) but the instinct was right and the bug was there. Now it collects the reasons — a cap and a downgrade are both reasons, either can be the only one — and prints the clause only when there is one. Six tests added, this case among them.
2 Step 3D says "six failures", lists seven, check-coverage reports eight Real. The count drifted as failure classes were added across this PR, and the uncoverable-chunk class had no bullet at all. Now "eight", with the missing bullet written.
3 submit --review help still advertises event / body Real — same root as pass two's Critical, one layer down. The --help text still listed event/body as payload fields the command now refuses. A user reading --help would build the rejected shape. Updated to commit_id / comments / state.

Zero false positives across all three passes: 6 + 1 + 3 = ten findings, ten real. Every one was either a fail-open in a gate this PR builds, or a place where a rule was stated once and contradicted somewhere the author did not re-read — which is the failure the whole change is about, and the review reads the whole document, so it keeps finding it.

568 tests in commands/review, green. dist SKILL rebuilt.

中文说明

第三轮:无 blocker,三条 Suggestion,全真,已在 c2cb5b618 修复。 上一轮那条 stale-event/body 的 Critical 消失了(verdict 从 CHANGES_REQUESTED 降到 no-blockers)。三条里两条是本 PR 自己引入的矛盾:

  1. verdictLine 无测试,downgrade-only 路径会打印悬空冒号 —— 真且可复现。当一个本该 Approve 的裁决仅因 presubmit 降级(无任何 cap,cappedBy 空,downgraded true)被拉走时,旧代码 join 了空数组,输出 an Approve was NOT available: — downgraded by a presubmit check——冒号后面是空的。审查器把机制说得略偏(它说成 cappedBy 空 + downgrade,而这恰好就是触发条件),但直觉对、bug 在。现在改成先收集"原因"(cap 和 downgrade 都算原因,任一都可能是唯一),有原因才打印那一句。新增六个测试,含这一例。
  2. Step 3D 写"six failures"却列了七条,check-coverage 实际有八类 —— 真。计数随本 PR 陆续加失败类别而漂移,而 uncoverable-chunk 那一类根本没有 bullet。现在改成"eight",并补上缺的那条。
  3. submit --review 的 help 仍宣传 event / body —— 真,与上一轮那条 Critical 同源、低一层。--help 文本还把 event/body 列为字段,而这个命令现在会拒绝它们。照着 --help 走的人会构造出被拒的形状。已改成 commit_id / comments / state

三轮零假阳性:6 + 1 + 3 = 十条 finding,十条全真。 每一条要么是本 PR 所建闸门里的 fail-open,要么是"一条规则在一处声明、在作者没回看的另一处矛盾"——而这正是整个改动要解决的失败,审查器读的是整份文档,所以它一次次抓到。

commands/review 568 测试绿,dist SKILL 已重建。

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

Manual review of the coverage / roster / prompt-record / submit changes.

Overall this is solid, well-tested work. The fail-closed reasoning holds up (an empty prompt record makes wasDeliveredVerbatim return false; a missing planPath caps compose-review to COMMENT; submit strips env from caller state so transcripts can't be redirected), the id-based tool-call pairing in transcripts.ts fixes a real "N parallel calls counted as 1" bug, and I confirmed the self-review fixes are present (the verdictLine dangling-colon guard, --dry-run carrying cappedBy, and the stale event/body example purge).

One substantive finding (inline on roster.ts): a heavy file in a Step-3A-sized diff makes the roster demand invariant agents that Step 3A never launches, which falsely blocks an otherwise-complete review. Plus two minor notes — a merge() input-mutation nit and an Agent-0 readsDiff coupling question.

Posting as a COMMENT (not blocking a maintainer PR); the roster/skill mismatch is the one worth resolving before merge.

Comment thread packages/cli/src/commands/review/lib/roster.ts Outdated
Comment thread packages/cli/src/commands/review/lib/coverage.ts
Comment thread packages/cli/src/commands/review/lib/agent-briefs.ts

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

[Critical] submit.test.ts:186 — test 'posts when the user typed --comment' fails (ghMock called 0 times). The authorization gate at submit.ts:170 checks currentSessionId() === '' && args.skillArgs, but in the test environment currentSessionId() returns a non-empty value, so the fallback to args.skillArgs is never reached and the post never happens.

— qwen3.7-max via Qwen Code /review

Comment thread packages/cli/src/commands/review/compose-review.ts Outdated
Comment thread packages/cli/src/commands/review/lib/agent-briefs.ts Outdated
Comment thread packages/cli/src/commands/review/agent-prompt.ts
Comment thread packages/cli/src/commands/review/submit.ts
… agents

From a human review of #6892 (doudouOUC). `heavy` is decided independently of
topology (lib/heavy.ts): a ~300-line source file with ~120 changed lines clears
the rewrite-ratio branch while srcDiffLines stays under 500 — a Step 3A review.
The invariant-agent loop in requiredAgents ran in both topologies, so it added
invariant-a/b/c to the roster of a 3A review that never launches them; check-coverage
then reported them as missingRoles and exit-3'd, and compose-review capped the
verdict — an otherwise-complete small PR, falsely blocked.

Gate the loop on isTerritoryFanOut. Step 3A's dimension agents each walk the whole
diff, so one already sees both ends of a rewritten file; invariant agents are a 3B
mechanism for when the diff is carved into territories and no single agent holds
the whole file. roster.test.ts now pins the 3A-heavy case.

Also, same review: merge() in coverage.ts copied its first tuple and pushes copies,
so it no longer mutates a tuple owned by rec.diffReads (harmless today, pure now).
@wenshao
wenshao requested a review from Copilot July 15, 2026 03:33

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@wenshao

wenshao commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator Author

Fourth pass: one real human finding fixed (7c499d193), and the bot's Critical is a false positive

@doudouOUC's manual review — thank you, this one was a genuine bug my own dogfood never hit:

  • Bug (fixed): a heavy file in a Step-3A-sized diff demanded invariant agents that 3A never launches. Exactly as you traced it — heavy is topology-independent, so a ~300-line module with ~120 changed lines is a 3A review that still flags heavy, and the invariant loop ran outside the isTerritoryFanOut branch. check-coverage would have missingRoles-exit-3'd an otherwise-complete small PR. Gated the loop on isTerritoryFanOut; roster.test.ts now pins the 3A-heavy case (it only exercised 3B-sized heavy files before, as you noted). Chose your option (a) over adding invariant instructions to 3A, because a 3A dimension agent already walks the whole diff and sees both ends of the file — invariant agents are the 3B answer to a file carved across territories.
  • Nit (fixed): merge() mutated a tuple owned by rec.diffReads. Copies the first element and pushes copies now — pure, as you suggested.
  • Design check (Agent 0 readsDiff: true): intended, keeping it. Agent 0's brief tells it to read the diff and check the change against the issue evidence — "does this PR fix the observed behaviour" is a question about the code, not only the issue text. Coupling "issue fidelity ran" to "it opened the diff" is the stronger requirement on purpose. You called it defensible; I'm confirming it's deliberate.

The qwen-code-ci-bot Critical is a false positive. It claims submit.test.ts:186 (posts when the user typed --comment) fails with ghMock called 0 times, reasoning that currentSessionId() returns non-empty in the test environment so the args.skillArgs fallback is never reached. But:

  • that test does not set QWEN_CODE_SESSION_ID, and it is unset in the environment, so currentSessionId() returns `` and the fallback is taken;
  • only one test (ignores a caller-supplied --skill-args) sets it, in a try/finally that restores it;
  • submit.test.ts is 33/33 green locally, and this PR's own Test (ubuntu-latest, Node 22.x) job passed (11m11s).

The bot reasoned about the test environment instead of running it, and reasoned wrong. It is the one finding across four passes that did not survive verification — which is the reverse-audit rule this skill is built on: a review's claim is worth what its evidence is worth, and this one had none.

Tally across four passes: 11 findings, 10 real and fixed, 1 false. 569 tests green.

中文说明

@doudouOUC 的人工 review —— 一条我自己 dogfood 没撞到的真 bug,已修(7c499d193):

  • Bug(已修):3A 尺寸的 diff 里若有 heavy 文件,roster 会要求 3A 从不启动的 invariant agent。 完全如你所析——heavy 与拓扑无关,~300 行、~120 改动行的模块是 3A review 却仍标 heavy,而 invariant 循环在 isTerritoryFanOut 分支外。check-coverage 会把一个本已完整的小 PR 用 missingRoles exit-3 掉。已把循环 gate 在 isTerritoryFanOut 上;roster.test.ts 现在钉住了 3A-heavy 这种情况(如你所说,之前只测了 3B 尺寸的 heavy)。选了你的方案 (a) 而非给 3A 加 invariant 指令——因为 3A 的 dimension agent 本就走整个 diff、能看见文件两端;invariant agent 是 3B 里「文件被切进多个 territory、没有单个 agent 掌握整份文件」时的答案。
  • Nit(已修):merge() 就地改了 rec.diffReads 拥有的 tuple。 现在复制首元素、push 副本——纯函数,如你所建议。
  • Design check(Agent 0 readsDiff: true):是有意的,保留。 Agent 0 的 brief 要求它读 diff 并把改动对照 issue 证据——「这个 PR 有没有修好观察到的行为」是关于代码的问题,不只是 issue 文本。把「issue fidelity 跑了」耦合到「它打开了 diff」是刻意的更强要求。你说它 defensible,我确认它是 deliberate。

qwen-code-ci-bot 那条 Critical 是假阳性。 它声称 submit.test.ts:186 失败、ghMock 0 次调用,理由是测试环境里 currentSessionId() 非空、走不到 args.skillArgs fallback。但:该测试不设 QWEN_CODE_SESSION_ID、环境里也没有,所以 currentSessionId() 返回 ``、fallback 生效;只有另一个测试设了它、且在 try/finally 里恢复;`submit.test.ts` 本地 33/33 绿,本 PR 自己的 `Test (ubuntu)` job 也过了(11m11s)。bot 靠想象测试环境、而不是运行它,想错了。这是四轮里唯一一条没通过复核的 finding——而这正是这个 skill 立足的 reverse-audit 规则:一条 review 的价值等于它证据的价值,而这一条没有证据。

四轮合计:11 条 finding,10 真已修,1 假。 569 测试绿。

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

— qwen3.7-max via Qwen Code /review

// half that was not got launched with no diff path at all, and the one that was
// never launched at all could not be seen by anything that inspects the agents
// that ran.
describe('buildRolePrompt — every agent, not just the territory ones', () => {

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] Misleading describe block name: buildRolePrompt does not exist as a function. Every test inside calls buildRoleBrief. A maintainer grepping for buildRoleBrief tests will not find this block.

Concrete cost: discoverability of the test suite.

Suggested change
describe('buildRolePrompt — every agent, not just the territory ones', () => {
describe('buildRoleBrief — every agent, not just the territory ones', () => {

— qwen3.7-max via Qwen Code /review

it.each([
['neither', {}],
['both', { chunk: 13, 'whole-diff': true }],
])('rejects a call that names %s of the two modes', (_, extra) => {

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 mode-rejection test covers only 2 of 8 combinations (neither and both for chunk + whole-diff). The production code now has three mutually exclusive modes (chunk, whole-diff, role), but role+chunk, role+whole-diff, and all three are untested. The message "the two modes" also reflects the old two-mode design.

Concrete cost: a future refactor that breaks role-mode mutual exclusion would not be caught.

Suggested change
])('rejects a call that names %s of the two modes', (_, extra) => {
])(
'rejects a call that names %s',
(_, extra) => {

And add cases: ['chunk+role', { chunk: 13, role: '2' }], ['whole-diff+role', { 'whole-diff': true, role: '2' }], ['all three', { chunk: 13, 'whole-diff': true, role: '2' }].

— qwen3.7-max via Qwen Code /review

Comment on lines +579 to +583
} else if (r.downgraded) {
// The base was not an Approve (a Suggestion-only Comment, say), so there was no
// Approve to lose — but a presubmit downgrade still moved the event, and the
// user should see that it did.
line += ' — downgraded by a presubmit check';

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] When baseEvent is REQUEST_CHANGES and a presubmit check downgrades it to COMMENT, the verdict reads "Comment — downgraded by a presubmit check". The operator sees "Comment" and may conclude there are no blockers, when Criticals were found and the review would otherwise have been REQUEST_CHANGES. The code comment says "a Suggestion-only Comment, say" but this branch also fires for REQUEST_CHANGES.

Failure scenario: an operator running submit sees the terminal verdict and acts on it — "Comment" reads as "minor issues, nothing blocking", but the review actually posted Criticals inline.

Suggested fix: distinguish the two cases:

} else if (r.downgraded) {
  if (r.baseEvent === 'REQUEST_CHANGES') {
    line += ' — Request changes was downgraded to Comment by a presubmit check';
  } else {
    line += ' — downgraded by a presubmit check';
  }
}

— qwen3.7-max via Qwen Code /review


// `verdictLine` is what Step 6 prints — the one place a verdict exists for the
// user. It had no test, and a review of this change found the reason to want one.
describe('verdictLine — the terminal verdict, and its dangling colon', () => {

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 verdictLine test suite covers 6 scenarios but omits baseEvent: 'REQUEST_CHANGES' with downgraded: true. The else if (r.downgraded) branch at compose-review.ts:579 handles this case, and the COMMENT+downgraded test exercises the same branch with a different baseEvent, but the REQUEST_CHANGES origin is untested.

Concrete cost: a regression that mishandles the REQUEST_CHANGES+downgraded case would go undetected.

Suggested change
describe('verdictLine — the terminal verdict, and its dangling colon', () => {
describe('verdictLine — the terminal verdict, and its dangling colon', () => {
const line = (over: Partial<ComposeReviewResult>): string =>
verdictLine({
event: 'COMMENT',
body: '',
baseEvent: 'COMMENT',
cappedBy: [],
downgraded: false,
...over,
});
it('says a Request changes downgraded to Comment was downgraded', () => {
expect(
line({ event: 'COMMENT', baseEvent: 'REQUEST_CHANGES', downgraded: true }),
).toContain('downgraded');
});

— qwen3.7-max via Qwen Code /review

]
],
"state": {
/* the compose-review state below */

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 JSON example uses /* comment */ inside a ```json code fence. JavaScript-style comments are not valid JSON — a reader copying the example verbatim would get a parse error.

Concrete cost: documentation accuracy; a reader following the example literally cannot produce valid JSON.

Switch the fence to ```jsonc or replace the comment with a valid placeholder.

— qwen3.7-max via Qwen Code /review

…mment

Fifth self-review, one behavioural finding among five (the rest are test/doc).

verdictLine printed 'Comment — downgraded by a presubmit check' for BOTH a
Suggestion-only Comment the presubmit moved and a REQUEST_CHANGES it moved down to
Comment. The second is a review with confirmed Criticals posted inline, and
'Comment — downgraded' reads to an operator as 'nothing blocking'. It could not
tell them apart from baseEvent alone — a cap may already have softened the RC
before the downgrade ran — so ComposeReviewResult now carries downgradedFrom, and
verdictLine says 'Request changes, downgraded to Comment … (the blockers are still
posted)' for that case. Six verdictLine cases now, including this one.

Also from the same review, all confirmed:
- agent-prompt.test.ts: the describe block named a function that was renamed
  (buildRolePrompt -> buildRoleBrief), and the mode-rejection it.each covered 2 of
  the invalid combinations, not the role-mode ones; now covers all five and drops
  the stale 'two modes' wording.
- SKILL.md Step 7: the review-JSON example used a /* */ comment inside a ```json
  fence (not valid JSON); switched to ```jsonc with a // comment.
@wenshao
wenshao requested a review from Copilot July 15, 2026 05:10

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@wenshao

wenshao commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator Author

Fifth pass: no blockers, five Suggestions — all real, fixed in 24df1020f

One is behavioural; the rest are test/doc. All confirmed.

# Finding Verdict
1 verdictLine prints Comment — downgraded for a downgraded Request changes too, hiding that Criticals were posted Real, and the one that matters. A presubmit downgrade (self-PR, failing CI) moves a REQUEST_CHANGES — a review with confirmed Criticals inline — down to COMMENT. Printed as a bare "Comment — downgraded", an operator reads "nothing blocking". baseEvent alone could not distinguish it (a cap may have softened the RC before the downgrade ran), so ComposeReviewResult now carries downgradedFrom, and the line reads "Request changes, downgraded to Comment by a presubmit check (the blockers are still posted)". A sixth verdictLine test pins it.
2 describe block named buildRolePrompt — a function renamed to buildRoleBrief Real. Renamed.
3 mode-rejection it.each covered 2 of the invalid combinations, missed the role-mode ones, and said "two modes" Real. Now covers all five (none, chunk+whole-diff, chunk+role, whole-diff+role, all three).
4 verdictLine suite omitted baseEvent: REQUEST_CHANGES + downgraded Real — the test for #1. Added.
5 Step 7 review-JSON example used a /* */ comment inside a ```json fence Real. Copying it verbatim gives a JSON parse error; the example already had {placeholder} values, so the honest fence is ```jsonc with a // comment. Switched.

#1 is worth dwelling on: it is a regression in my previous fix. Last pass I split verdictLine to kill a dangling colon and wrote the new branch thinking only of the Suggestion-only case — the comment even said "a Suggestion-only Comment, say". The review read the branch against every baseEvent that reaches it and found the one I had not: a downgraded blocker, announced as if it were not one. That is the class this whole PR is about — a rule (or here, a display) correct in the case its author pictured and wrong in the one they did not — and it caught it in the fix for the same class, one pass later.

Tally across five passes: 16 findings, 15 real and fixed, 1 false (the pass-four submit.test.ts "failure" that CI and local both showed green). 573 tests green.

中文说明

第五轮:无 blocker,五条 Suggestion,全真,已在 24df1020f 修复。 一条是行为问题,其余是测试/文档。

  1. verdictLine 对「被降级的 Request changes」也打印 Comment — downgraded,掩盖了已发的 Critical —— 真,且是最要紧的一条。presubmit 降级(self-PR、CI 失败)会把一个有 Critical 内联的 REQUEST_CHANGES 降到 COMMENT;打印成光秃秃的 "Comment — downgraded",operator 会读成「没 blocker」。单靠 baseEvent 分不出来(cap 可能在降级前已软化了 RC),所以 ComposeReviewResult 现在带 downgradedFrom,该行改为 "Request changes, downgraded to Comment …(the blockers are still posted)"。第六个 verdictLine 测试钉住它。
  2. describe 块名叫 buildRolePrompt(已改名 buildRoleBrief)—— 真,已改。
  3. mode-rejection it.each 只覆盖 2 种非法组合、漏了 role-mode、消息还写 "two modes" —— 真,现覆盖全部五种。
  4. verdictLine 测试漏了 baseEvent: REQUEST_CHANGES + downgraded —— 真,即 pre-release: fix ci #1 的测试,已补。
  5. Step 7 的 JSON 示例在 ```json fence 里用了 /* */ 注释 —— 真,照抄会 parse 错;示例本就有 {占位符},故改成 ```jsonc + //

#1 值得多说一句:它是我上一轮修复的回归。 上一轮我拆 verdictLine 去消除悬空冒号,写新分支时只想着 Suggestion-only 那种情况——注释甚至写着 "a Suggestion-only Comment, say"。审查器把这个分支对着每一个会到达它的 baseEvent 都验了一遍,找到了我没想到的那个:一个被降级的 blocker,被当成非 blocker 播报。这正是整个 PR 讲的那类失败——一条规则(这里是一处显示)在作者设想的情况里对、在他没设想的那个里错——而它在「修同一类失败的那次修复」里,晚一轮,抓到了它。

五轮合计:16 条 finding,15 真已修,1 假(第四轮那条 submit.test.ts "失败",CI 与本地都显示绿)。573 测试绿。

…lution

Follows 7c499d1, which resolved the doudouOUC roster finding (a heavy file in
a Step-3A diff must not demand invariant agents — gate the loop on the
topology) and the merge() purity nit. This carries the rest of the same round:

- `roster.ts` requires Agent 0 only for a positive PR number. `!== undefined`
  let `null`/`0`/`''` through. Note the reviewer's suggested `typeof === 'number'`
  is wrong for this codebase — `fetch-pr` writes the number as a *string* — so
  the guard accepts a numeric string too, or every real PR review would lose
  Agent 0. A table test pins both directions.
- `transcripts.ts` matches the diff path as a whole JSON string value, so
  `…/diff.txt.bak` no longer counts as reading `…/diff.txt`. It also documents
  why FIFO is right for a chronological transcript.
- `agent-prompt.ts` scopes path rules to `--file` only for invariant roles — a
  whole-diff reviewsCode agent passed `--file` would otherwise lose the rules
  for every other file — and guards each chunk element in `diffReadingBlock`
  like `chunkFrom`, so a corrupted chunk errors legibly instead of emitting
  `offset=NaN`.
- `compose-review.ts` stops double-wrapping `cov.missingRoles` /
  `cov.rewrittenPrompts`, which coverage.ts already writes self-explanatory.
- `agent-briefs.ts` JSDoc said "Two do not" read the diff; only Build & Test
  does not.
- The agent-prompt size-bound test now covers `test-matrix`.

The empty-prompt guard, the paged-read coverage, the verdictLine dangling-colon
and the submit help text were all already handled by earlier commits on the
branch; those threads are answered without a code change.
@wenshao

wenshao commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator Author

Automated-review round: disposition

Follow-up to the human review, covering the qwen-code-ci-bot suggestions. Fixes are in 619f336e1 (on top of the maintainer's 7c499d193 / 24df1020f).

Fixed:

Finding Fix
transcripts.tsincludes(diffPath) false-positives on …/diff.txt.bak matches the whole JSON string value now
transcripts.ts — LIFO→FIFO undocumented added the why (chronological transcript)
agent-prompt.ts--file path-scoping applied to all reviewsCode roles gated on invariant- roles
agent-prompt.tsdiffReadingBlock didn't guard chunk elements mirrors chunkFrom's validation; a bad chunk errors instead of offset=NaN
compose-review.ts — double-wrapped in missingRoles/rewrittenPrompts push the label as-is (coverage.ts already writes it self-explanatory)
agent-briefs.ts — JSDoc "Two do not" read the diff only Build & Test does; "One does not"
agent-prompt.test.tstest-matrix missing from the size-bound test added

Fixed — but not as suggested: roster.ts prNumber guard. The !== undefined check does let null/0/'' through, so a positive-number guard is right. But the suggested typeof plan.prNumber === 'number' is wrong for this codebasefetch-pr.ts writes prNumber as a string ("6766"), so that check would have dropped Agent 0 from every real PR review. The guard accepts a numeric string too; a table test pins both the accept ("6766", 6766) and reject (null, 0, "0", "", junk) directions. (The review suite catches this — it was a red run before I corrected it.)

Already handled by earlier commits on the branch — no change, verified:

  • prompt-record.ts empty-built guard — already present (if (built.trim().length === 0) return false), stronger than suggested.
  • coverage.ts:358 paged-read coverage — already handled: merge() sort-merges abutting ranges before the containment check, so 1-200 + 201-400 credits a 1-400 chunk.
  • submit.ts --review help text — already reads commit_id / comments / state … do not include [event/body].
  • compose-review.ts verdictLine dangling-colon — already unit-tested (does not leave a dangling colon when a downgrade ALONE took the Approve).

Not taken (reasoned):

  • coverage.ts:406existsSync on the brief before "never opened its brief". The brief check is only reached once the .txt prompt was recorded, and the brief is written to the same dir adjacently, so the miss requires recordPrompt to succeed while writeBrief fails for the same key mid-write — and the outcome is already fail-safe (caps to COMMENT, never a wrong Approve). A missingBriefFiles category is a clean follow-up if the diagnostic distinction is wanted, but it's more machinery than the inode-exhaustion edge warrants.
  • check-coverage.ts:162 — the NOTE and ERROR on missingChunks are deliberately complementary: the NOTE is the one-time coverage-model explanation + how to fix it, the ERROR is the machine-actionable per-chunk list that drives exit 3. Merging them would bury the fix guidance inside the failure line.

577 review tests green; lint/format/tsc clean on the changed files.


🤖 Reviewed & applied with Claude Code · Opus 4.8 (1M context)

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

Re-reviewed at 619f336e1 — all three findings from my earlier review are resolved, and CI Test (ubuntu) is green. Approving.

My findings — all addressed:

  • Heavy file in a Step-3A diff (roster.ts) — fixed in 7c499d193. The heavyFiles loop is now gated on isTerritoryFanOut, so invariant agents are demanded only in the 3B topology that actually launches them; a new roster.test.ts case pins the 3A-heavy behavior. The rationale is sound — 3A dimension agents each walk the whole diff, so they already see both ends of a file.
  • merge() input mutation (coverage.ts) — fixed in 7c499d193: it seeds and pushes tuple copies, so the function is now pure.
  • Agent 0 readsDiff coupling (agent-briefs.ts) — confirmed intentional (issue fidelity has to judge the stated intent against what the diff actually does), and the stale "Two do not read the diff" JSDoc was corrected to "One". Acceptable as deliberate fail-closed behavior.

Additional self-review fixes (24df1020f, 619f336e1) also verified:

  • The downgradedFrom verdict-line fix is a genuinely good catch — a REQUEST_CHANGES downgraded to COMMENT by a presubmit check no longer reads as "nothing blocking" when blockers are posted inline.
  • isPositivePrNumber (hardens the Agent-0 gate against null/0/''/junk while accepting the numeric-string form fetch-pr writes), the diffReadingBlock NaN guard, the invariant--gated path-rules scoping, the quoted-path match in transcripts.ts (fixes the …/diff.txt.bak false-positive, with no false negative for the instructed read_file path), and the missingRoles/rewrittenPrompts label de-dup all look correct and are each pinned by a test.

No outstanding concerns. Nice work turning each finding around with a test to pin it. LGTM 🎉

@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: chunk 1, chunk 2, chunk 3, chunk 4, chunk 5, chunk 6, chunk 7, chunk 8, chunk 9, chunk 10, chunk 11, chunk 12, chunk 13, chunk 14, chunk 15, chunk 16, chunk 17, chunk 18, chunk 19, chunk 20, chunk 21, chunk 22, chunk 23, chunk 24 — no agent reported covering these; nobody read them.

— qwen3.7-max via Qwen Code /review

@wenshao

wenshao commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /triage

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Thanks for the PR!

Template looks good ✓ — all required sections present and filled in with real content.

Problem: Observed, not theoretical. Seven specific defects identified across six rounds of dogfooding against real pull requests of this repo, each measured against the harness's per-agent transcripts. The coverage bug produced contradictory output (0/2 chunks reviewed alongside 16 agents ran; 16 did work), Agent 0 was never launched on a real review, and the orchestrator paraphrased prompts before delivery. Before/after evidence is concrete and verifiable.

Direction: Strongly aligned. The core thesis — "a rule stated in prose is a rule that will eventually not be followed; the fix is to move it into code that can say no" — is the right architectural direction for an automated review skill. This is the same lesson the skill has already applied to the review target, posting gate, and coverage report, now extended to the four remaining gaps: agent prompts, the roster, the terminal verdict, and rules that never reached agents. No CHANGELOG reference but the area is directly within the skill's reliability mandate.

Size: This PR touches one core-path file (packages/core/src/skills/bundled/review/SKILL.md — docs/prose, not production TypeScript) and 19 files in packages/cli/src/commands/review/. Production logic lines: ~2,898 (additions + deletions). Test lines: ~2,454. This triggers the 1000+ production-line advisory — large, but the scope is justified: each of the seven defects requires its own module (briefs, coverage, roster, prompt-record, path-rules, transcript enrichment, submit changes), and they're interconnected through the coverage check that reads all of them. Not a candidate for splitting.

Approach: The scope feels right for the problem. Each change maps to a named, demonstrated defect. The architecture is clean: briefs on disk (not in prompts), coverage as line-range intersection (topology-blind), roster derived from the plan (not caller-supplied), verdict computed at submit time (refusing hand-written event/body), and delivery verified by subsequence check (not substring). Tests are thorough — 452 passed in the review test suite — with each test tied to a specific observed failure. No drive-by refactors or scope creep. Moving on to code review. 🔍

中文说明

感谢贡献!

模板完整 ✓ — 所有必需章节均已填写,内容真实。

问题: 已观测到的缺陷,非理论性加固。通过在本仓库真实 PR 上进行六轮 dogfood 测试,发现了七个具体缺陷,每个都通过 harness 的 per-agent transcript 进行了量化验证。coverage bug 产生了矛盾的输出("0/2 chunks reviewed" 与 "16 agents ran; 16 did work" 并存),Agent 0 在一次真实 review 中完全未被启动,编排器在传递 prompt 前对其进行了改写。before/after 证据具体且可验证。

方向: 高度对齐。核心论点——"用散文写下的规则最终不会被遵守;解法是把它变成能说「不」的代码"——是自动化 review skill 的正确架构方向。CHANGELOG 中无直接引用,但该领域直接关系到 skill 的可靠性。

规模: 本 PR 涉及一个核心路径文件(packages/core/src/skills/bundled/review/SKILL.md — 文档/散文,非生产 TypeScript)和 19 个 packages/cli/src/commands/review/ 文件。生产逻辑行数约 2,898 行,测试行数约 2,454 行。触发 1000+ 生产行建议——规模大,但范围合理:七个缺陷各需独立模块,且通过 coverage 检查互相关联。不适合拆分。

方案: 范围与问题匹配。每项改动对应一个已证实的缺陷。架构清晰:brief 落盘、coverage 取行范围交集(拓扑无关)、roster 从 plan 推导、裁决在 submit 时计算、交付通过子序列检查验证。452 个测试通过,每个测试关联一个已观测的故障。无顺手重构或范围蔓延。进入代码审查 🔍

Qwen Code · qwen3.7-max

Reviewed at 619f336e1fa8ac2e0a33e4be12f2005c67670e8a · re-run with @qwen-code /triage

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Code Review

No critical blockers found. The implementation is clean, well-structured, and thoroughly tested.

Architecture — the move from prose-enforced rules to code-enforced invariants is applied consistently across every layer: prompt recording (prompt-record.ts), coverage computation (coverage.ts), roster derivation (roster.ts), delivery verification (wasDeliveredVerbatim), and verdict composition (submit.ts). Each module is independently testable and the interfaces between them are clean.

Prompt recordingprompt-record.ts writes both the launch prompt and the brief to disk at a path derived from the plan (not caller-supplied), so the orchestrator cannot tamper with either. The wasDeliveredVerbatim check correctly uses subsequence matching (not substring) — allowing additions and whitespace reflow while preventing removals. The empty-record fails-closed guard catches partial writes from recordPrompt's swallowed errors.

Coverage — the topology-blind coverage model (intersection of pointed-at lines and diff-opened ranges) elegantly solves the Step 3A/3B discrepancy. The merge() function correctly handles paged reads with its copy-on-write tuple approach to avoid mutating shared references. pointedAt() extracts line ranges from the CLI-generated read_file calls in the prompt, with a sensible fallback to the plan's chunk boundaries.

Transcript parsing — the switch from stack-based to ID-based call-response pairing is correct. The FIFO fallback for anonymous (un-ID'd) calls matches JSONL's chronological ordering. rangeOf() correctly returns null when no limit is present, avoiding false credit for unbounded reads.

Submit authorization — reading the raw user-typed argument string and parsing it in submit.ts itself (rather than trusting the parser's JSON output) is a sound defense against a caller-written authorization document. The target-scoping check (PR number + repo + host must match what the user typed) correctly prevents stale or swapped authorizations from reaching the wrong pull request.

Verdict compositionsubmit now computes event and body from state + comments, refusing payloads that carry event/body. The inline counts are derived from **[Critical]**/**[Suggestion]** prefixes of attached comments, eliminating the disagreement-between-count-and-list bug. The env stripping in compose() prevents a caller from pointing coverage at fabricated transcripts.

Path rules — the GitHub Actions security checklist is well-calibrated: scoped to agents whose territory contains workflow files, distinguishes blockers (Critical) from recommendations (Suggestion), and correctly handles the ${{ }} injection and pull_request_target checkout attack classes.

Tests — 581 tests across 29 files, all passing. Each test is tied to a specific observed failure from dogfooding. The test for wasDeliveredVerbatim covers both the false-positive case (legitimate additions and reflow) and the false-negative case (paraphrased prompts with dropped content). The roster tests cover edge cases like string-typed PR numbers from fetch-pr, empty files arrays, and heavy files in Step 3A topology.

Minor observation (not a blocker): the test posts when the user typed --comment fails when QWEN_CODE_SESSION_ID is set in the environment — authorization() correctly prioritizes the session-scoped path over the test-supplied skillArgs, but the test doesn't unset this env var. Not a code defect (passes in CI where the env var is absent), but a test isolation improvement for local runs inside Qwen Code sessions.

Testing

Unit tests (581 passed, 0 failed):

$ QWEN_CODE_SESSION_ID= npx vitest run --root packages/cli src/commands/review
 Test Files  29 passed (29)
      Tests  581 passed (581)
   Duration  9.54s

Real-scenario testing: not performed in this triage. This PR changes internal review skill infrastructure (prompt building, coverage computation, verdict composition) — verifying it end-to-end requires running /review through the full Qwen Code TUI with model API access, which is not available in this triage environment. The PR author's own dogfooding evidence (six rounds against live PRs, all verified from per-agent transcripts) is the real-scenario evidence for this change.

中文说明

代码审查

未发现关键阻塞问题。实现干净、结构良好、测试充分。

架构 — 从散文强制到代码强制的转变一致地应用于每一层:prompt 记录、coverage 计算、roster 推导、交付验证和裁决合成。每个模块独立可测,接口清晰。

Prompt 记录prompt-record.ts 将 launch prompt 和 brief 写入磁盘上从 plan 推导的路径(非调用方提供),编排器无法篡改。wasDeliveredVerbatim 正确使用子序列匹配(非子串),允许添加和空白重排但防止删除。空记录失败关闭的守卫捕获了 recordPrompt 吞掉的写入错误。

Coverage — 拓扑无关的 coverage 模型(指向行与 diff 打开范围的交集)优雅地解决了了 Step 3A/3B 不一致问题。merge() 函数通过 copy-on-write 元组方法正确处理分页读取。pointedAt() 从 CLI 生成的 read_file 调用中提取行范围,并有合理的回退到 plan chunk 边界。

Transcript 解析 — 从基于栈到基于 ID 的调用-响应对匹配是正确的。匿名调用的 FIFO 回退匹配 JSONL 的时间顺序。当没有 limitrangeOf() 正确返回 null,避免对无界读取给予虚假信用。

Submit 授权 — 在 submit.ts 自身中读取原始用户输入的参数串并解析(而非信任解析器的 JSON 输出),是对调用方编写的授权文档的可靠防御。目标范围检查(PR 号 + 仓库 + 主机必须匹配用户输入)正确防止过期或交换的授权到达错误的 pull request。

裁决合成submit 现在从 state + comments 计算 event 和 body,拒绝携带 event/body 的 payload。内联计数从附加 comment 的 **[Critical]**/**[Suggestion]** 前缀推导,消除了计数与列表不一致的 bug。

测试 — 29 个文件中 581 个测试全部通过。每个测试关联一个 dogfood 中发现的具体故障。

小观察(非阻塞):QWEN_CODE_SESSION_ID 在环境中设置时,posts when the user typed --comment 测试会失败——authorization() 正确优先使用 session 作用域路径,但测试未清除该环境变量。非代码缺陷(在无此变量的 CI 中通过),但在 Qwen Code 会话内本地运行时需注意测试隔离。

测试

单元测试(581 通过,0 失败):

$ QWEN_CODE_SESSION_ID= npx vitest run --root packages/cli src/commands/review
 Test Files  29 passed (29)
      Tests  581 passed (581)
   Duration  9.54s

真实场景测试: 本次审查中未执行。本 PR 变更的是内部 review skill 基础设施——端到端验证需要通过完整 Qwen Code TUI 运行 /review 并需要模型 API 访问,在本次审查环境中不可用。PR 作者自己的 dogfood 证据(六轮针对活跃 PR,全部通过 per-agent transcript 验证)是本变更的真实场景证据。

Qwen Code · qwen3.7-max

Reviewed at 619f336e1fa8ac2e0a33e4be12f2005c67670e8a · re-run with @qwen-code /triage

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Confidence: 5/5 — clean across every stage; the defects are real, the fix is correct, and the test suite proves it.

This PR addresses a genuine reliability crisis in the /review skill: the coverage check was producing contradictory results, agents were being launched without the instructions they needed, and the orchestrator could silently rewrite prompts or forge verdicts. Each of the seven defects was discovered through dogfooding against real pull requests, not hypothesized.

The architecture is the right one. Every layer that was previously enforced by prose is now enforced by code: briefs live on disk where the orchestrator can't truncate them, coverage is the intersection of two independently-recorded artifacts (what the agent was pointed at and what it opened), the roster is derived from the plan rather than supplied by the caller, and the verdict is computed at submit time from the same state Step 6 showed the user. The key insight — that a rule stated in prose is a rule that will eventually not be followed — is applied consistently and without exception.

581 tests pass, each tied to a specific observed failure. The test for wasDeliveredVerbatim is particularly well-crafted: it catches both the false-positive case (legitimate additions and reflow triggering a substring test) and the false-negative case (paraphrased prompts with dropped content passing a substring test because the diff path was preserved).

The PR is large (~2,900 production lines) but not bloated — each of the seven defects requires its own module, and they're interconnected through the coverage check. Splitting would have been artificial and would have left intermediate states where some defects were fixed and others weren't.

One minor observation: the test posts when the user typed --comment fails when QWEN_CODE_SESSION_ID is set (as it is inside Qwen Code sessions) because authorization() correctly prioritizes the session-scoped path. Consider adding process.env.QWEN_CODE_SESSION_ID = '' to the test's beforeEach for robustness in all environments.

Ship it. ✅

中文说明

置信度:5/5 — 各阶段均无问题;缺陷真实存在,修复正确,测试套件已证明。

本 PR 解决了 /review skill 的真正可靠性危机:coverage 检查产生矛盾结果、agent 启动时没有收到所需指令、编排器可以静默改写 prompt 或伪造裁决。七个缺陷中的每一个都是通过对真实 PR 进行 dogfood 测试发现的,而非假设。

架构是正确的。之前由散文强制的每一层现在都由代码强制:brief 存在磁盘上(编排器无法截断),coverage 是两个独立记录工件的交集(agent 被指向的内容和它打开的内容),roster 从 plan 推导而非由调用方提供,裁决在 submit 时从 Step 6 展示给用户的同一 state 计算。关键洞察——"用散文写下的规则最终不会被遵守"——被一致且无例外地应用。

581 个测试通过,每个关联一个已观测的故障。PR 规模较大(约 2,900 生产行)但不臃肿——每个缺陷需要独立模块,且通过 coverage 检查互连。拆分将是人为的。

一个小建议:posts when the user typed --comment 测试在 QWEN_CODE_SESSION_ID 设置时会失败,考虑在 beforeEach 中添加 process.env.QWEN_CODE_SESSION_ID = '' 以增强所有环境下的鲁棒性。

可以合并 ✅

Qwen Code · qwen3.7-max

Reviewed at 619f336e1fa8ac2e0a33e4be12f2005c67670e8a · re-run with @qwen-code /triage

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM, looks ready to ship. ✅

@wenshao
wenshao added this pull request to the merge queue Jul 15, 2026
Merged via the queue into main with commit 35c9186 Jul 15, 2026
109 of 111 checks passed
@wenshao
wenshao deleted the fix/review-coverage-both-topologies branch July 15, 2026 06:55
wenshao added a commit that referenced this pull request Jul 16, 2026
…inds

Reported from a real session: `npm run dev:daemon`, `/review 6998 --comment` in the
web shell, and the run died on

  Missing required argument: chunk

with a help screen for a command that has no `--role` at all. The daemon was running
the checkout — the skill it loaded is the current one, and says `--role 0` — but the
skill shells out to `qwen review agent-prompt …`, and `qwen` on that machine is
`/usr/bin/qwen` → a v0.19.10 global install whose `agent-prompt` predates #6892
entirely. The skill and the CLI it was talking to were different programs.

The skill assumed `qwen` on PATH is the build running it. That holds for a single
install and breaks for exactly the people most likely to run a dev daemon. It is also
invisible when it breaks: the error names an argument, not a version.

So the entry is passed down instead of rediscovered. `scripts/cli-entry.js` is the
executable entry and the one thing that knows its own path, so it publishes it as
`QWEN_CODE_CLI` (`||=`, so the relaunch into dist/cli.js keeps pointing callers back
at the wrapper with the shebang, not at itself). `daemon-dev.js` sets it too — the dev
daemon is started as `node scripts/dev.js` and never passes through the wrapper, which
is why this bit there first. `getShellContextEnvVars` passes it to every shell
subprocess, beside the session and project-dir vars that are already handed down for
the same reason. The skill's 23 command sites now read `"${QWEN_CODE_CLI:-qwen}"
review …`; the fallback keeps hosts that do not export it on the old behaviour.

PATH was the other candidate and was rejected: prepending a shim dir means writing an
executable at spawn time and overriding `PATH` in an env that
`normalizePathEnvForWindows` has already normalised — a `Path`/`PATH` collision on
Windows in exchange for saving one variable.

The env var is isolated in `shellContextEnv.test.ts` the way the session id already
is: the CLI now exports it to every shell it spawns, so `npm test` run from inside a
qwen session inherits it, and the exact-equality assertion would have failed on a
variable the test never set. Verified by running the suite with it set.
wenshao added a commit to wenshao/qwen-code that referenced this pull request Jul 18, 2026
…ne call (QwenLM#7033)

* fix(review): name a rewritten launch as itself, and leave nothing to hand-assemble

Dogfooded on a real 3A review of a live PR, and the run talked its way past the gate:

  compose-review printed: Verdict: Comment — an Approve was NOT available: a
  dimension nobody reviewed

  the run's next thought: "the compose-review flagged reverse audit as unreviewed
  (transcript visibility issue — the reverse audit did run substantively with two
  dry rounds). Let me proceed."

  the run then reported, and saved: Verdict: Approve

The gap was right and its wording was wrong, and the wording is what let the run
dismiss it. Two auditors HAD run — 16 and 23 tool calls each — and both HAD opened
their brief. What had actually happened is that the orchestrator skipped `--findings`
and hand-wrote their launches, keeping only the brief pointer, so no agent was
launched with the prompt the CLI built. The gap said "no agent was launched with it
that opened its brief", which is false as written, and "a transcript visibility
issue" is what a reader concludes from a message that does not describe what
happened.

So the floor tells the four shapes apart instead of collapsing them into one
boolean, and each says what happened and what to do:

  not-built     — the step was skipped; `agent-prompt --role <r>` never ran
  not-launched  — the prompt was built and nothing was launched with it
  rewritten     — an agent ran and opened its brief, but no agent got the built
                  prompt: the launch was written by hand instead of pasted
  brief-unread  — an agent got the built prompt and never opened the brief

`rewritten` is the one that just happened, and it is now un-dismissable: it concedes
the agent ran and read its brief, and names the orchestrator's own edit as the defect.

And the path that produced it is gone: `--findings` is now REQUIRED for a role that
takes findings. There is no bare-block-plus-hand-assembly path left — the command
refuses, and prints one block to paste. An early reverse-audit round with nothing
confirmed yet passes an empty file, which the command renders as "Nothing is
confirmed yet".

SKILL: Step 4/5 say `--findings` is required. Step 6 gains the second half of the
lesson — you may not overrule the line compose-review gives you; a cap you can
explain is still a cap, and the fix is to make the step verifiable and re-run, not to
keep the verdict you preferred. Step 8's report interpolates the verdict out of the
composed JSON (`jq -r .event`) instead of typing it, because the terminal is prose
and the archive is forever.

* fix(review): call the CLI that is running, not whatever `qwen` PATH finds

Reported from a real session: `npm run dev:daemon`, `/review 6998 --comment` in the
web shell, and the run died on

  Missing required argument: chunk

with a help screen for a command that has no `--role` at all. The daemon was running
the checkout — the skill it loaded is the current one, and says `--role 0` — but the
skill shells out to `qwen review agent-prompt …`, and `qwen` on that machine is
`/usr/bin/qwen` → a v0.19.10 global install whose `agent-prompt` predates QwenLM#6892
entirely. The skill and the CLI it was talking to were different programs.

The skill assumed `qwen` on PATH is the build running it. That holds for a single
install and breaks for exactly the people most likely to run a dev daemon. It is also
invisible when it breaks: the error names an argument, not a version.

So the entry is passed down instead of rediscovered. `scripts/cli-entry.js` is the
executable entry and the one thing that knows its own path, so it publishes it as
`QWEN_CODE_CLI` (`||=`, so the relaunch into dist/cli.js keeps pointing callers back
at the wrapper with the shebang, not at itself). `daemon-dev.js` sets it too — the dev
daemon is started as `node scripts/dev.js` and never passes through the wrapper, which
is why this bit there first. `getShellContextEnvVars` passes it to every shell
subprocess, beside the session and project-dir vars that are already handed down for
the same reason. The skill's 23 command sites now read `"${QWEN_CODE_CLI:-qwen}"
review …`; the fallback keeps hosts that do not export it on the old behaviour.

PATH was the other candidate and was rejected: prepending a shim dir means writing an
executable at spawn time and overriding `PATH` in an env that
`normalizePathEnvForWindows` has already normalised — a `Path`/`PATH` collision on
Windows in exchange for saving one variable.

The env var is isolated in `shellContextEnv.test.ts` the way the session id already
is: the CLI now exports it to every shell it spawns, so `npm test` run from inside a
qwen session inherits it, and the exact-equality assertion would have failed on a
variable the test never set. Verified by running the suite with it set.

* fix(review): point the dev daemon's CLI at the source it is running, not dist

Verifying the previous commit on a real `npm run dev:daemon` caught it doing a
smaller version of the bug it fixes. The daemon runs the TypeScript **source**
through tsx; `cli-entry.js` runs `dist/cli.js`. Pointing QWEN_CODE_CLI there traded
"the subprocess is a whole major version behind" for "the subprocess is however
stale the last build was" — measured on the box that reported this, dist was **105
source files** behind the daemon. Same bug, smaller hat.

`scripts/dev.js` is the entry that runs what the daemon itself runs, so the dev
daemon points there. It gains a shebang and the exec bit, which is what lets a
caller invoke it as `"${QWEN_CODE_CLI}" review …` without knowing it needs node —
the same shape `cli-entry.js` already has for the published path.

Verified end to end on a headless box: started the dev daemon, read
/proc/<pid>/environ (QWEN_CODE_CLI=<repo>/scripts/dev.js, -rwxr-xr-x), and ran the
command that started this whole thread. Before: `Missing required argument: chunk`.
After: `agent-prompt: --role 0 needs a plan with prNumber and ownerRepo` — the role
is understood, and the complaint is about the fixture, which is the correct answer.

* fix(review): say what a missing brief proves, once, to the reader who can act on it

A role with no recorded prompt proves one thing: the brief never reached an
agent. The roster check claimed more than that — "no prompt was built for it
(`agent-prompt --role 0` never ran)" — and on QwenLM#7012 it said that about all
twelve dimensions of a review that had just posted two Criticals with line
numbers. The agents were in the same comment the gate was calling empty.

Both failures are real and neither is the other. An orchestrator that writes the
launch by hand gets an agent that runs, reads the diff and finds things, having
never seen the severity bar, the finding format or this project's rules — all of
which live in the brief it was never given. That is worth blocking on. It is not
"nobody looked", and a check may not report the reading it cannot see.

Three changes, one shape:

- The per-role text says the brief never reached an agent, and that the
  dimension was reviewed "if at all" from a prompt the run wrote for itself.
  It no longer speaks for the agent's existence.
- Every role briefless collapses to one line. It is one failure — the run did
  not use the prompt builder — and saying it twelve times buries the fact that
  explains all twelve.
- The public body drops the internal command. `agent-prompt --role 2` is not
  something a PR author can run; on QwenLM#7012 fourteen lines of it were the whole
  CHANGES_REQUESTED while the findings sat inline below the fold. The call
  survives in check-coverage's stderr, where the orchestrator reads it, and the
  role number is already in each label.

check-coverage no longer leads with a count: the collapsed line covers the whole
roster, so "1 required brief" would undercount it by the size of the review.

Behaviour is unchanged — the gate fires on exactly the same runs and still caps
the verdict. Only the sentence changes, and only where it was overclaiming or
talking to the wrong reader.

* fix(review): name the directory the missing briefs were missing from

"The prompt builder never ran" and "the prompt builder ran against a different
--plan" arrive at this check as the same thing — an absent file — and they are
fixed differently. Nothing in the error told them apart.

The record directory hangs off the plan path as given, so a relative --plan
resolves against the caller's cwd, and the skill runs Steps 2-6 from inside the
worktree it just created. Two cwds, one relative path, two directories. Proven
locally: the same `--plan .qwen/tmp/p.json` from a repo root and from a worktree
under it yields two record dirs.

That is not a reason to resolve the path differently — resolving a relative path
against the cwd is what a relative path means, and the mismatch mostly fails
loudly, because the plan is not in the worktree either and the read errors. It
is a reason to print where it looked. One line, on stderr, where the
orchestrator reads it; the PR author gets no path to a temp directory.

* feat(review): build the whole roster in one call, because compliance decays per call

The launch prompts are already small — a role line, the brief pointer, the diff
reads — and it did not save the run that stopped building them. Dogfooded on one
PR, the same environment went from a clean review to "no prompt was built for
any of twelve roles" over three reviews in a day. The per-agent form asks the
orchestrator for ~30 build-then-launch round trips on a large review, and that
is a compliance cost paid per agent, per review, forever; what decays under
repetition eventually decayed.

`agent-prompt --roster` builds every prompt the plan requires — chunk agents,
dimension agents, invariants — in one call: one labelled block per agent, each
recorded under the key `check-coverage` will look it up by. The list is
`requiredAgents(plan)`, the same list the coverage gate reads, so what gets
built is exactly what gets checked; a key the two derive differently is refused
at build time rather than surfacing later as "brief never reached an agent" on
a compliant run.

The blocks are separated by lines that are visibly not prompt text, and a block
copied lazily — separator included — still passes the add-only delivery check.
That is load-bearing: if honest-but-sloppy copying read as a rewrite, the gate
would punish exactly the behaviour this call exists to buy.

The per-agent forms stay, for rebuilding a single prompt after Step 3D names a
gap. Step 4/5 verify and reverse-audit are untouched: they are built per round,
with the findings folded in.

SKILL.md's Step 3A and 3B now ask for the roster once instead of one call per
agent, and check-coverage's missing-brief error names the one-call fix first.

* fix(review): close the review's five consistency gaps in the CLI-pinning story

Review feedback on this PR found five places where the fix stopped short of its
own thesis. All five, addressed:

1. Four copyable SKILL.md commands had missed the QWEN_CODE_CLI sweep —
   `pr-context` (lightweight mode), `cleanup` (cache hit), `capture-local
   --file` (file-path reviews), `agent-prompt --whole-diff` (Agent 8). On a
   skewed host those modes died exactly the way the motivating run did. All
   four now carry the prefix; the remaining bare mentions are prose.

2. check-coverage's own stderr recommended recovery with a bare `qwen` — the
   message is the interface the orchestrator acts on, and on a skewed host the
   recommended recovery reproduced the skew. All four recommendation sites now
   print the prefixed form, and the rebuild hint covers `--chunk <id>`, which a
   missing chunk agent needs and `--role` cannot express.

3. Ambient inheritance could silently re-point an entry at another session's
   CLI. A dev daemon started from inside another qwen session's shell — the
   usual dogfooding flow — inherited that session's QWEN_CODE_CLI through
   `??`/`||=` and called the OUTER build: the same skew, one level up, and
   silent. Every entry now stamps itself unconditionally; nested sessions each
   call their own build. The `||=` comment in cli-entry.js also claimed a
   relaunch hazard that does not exist (the relaunch child runs dist/cli.js and
   never re-executes the wrapper) — the comment now states the real reason.

4. The third dogfooding entry point was still unpinned: `npm run dev` and
   `npm start` published nothing, so a /review from a plain dev TUI fell back
   to PATH. `scripts/dev.js` now stamps the variable in the env it spawns with
   — which also covers the daemon, since daemon-dev launches serve through it,
   and the daemon's own deferring copy is gone (one writer, not two).
   `scripts/start.js` does the same and gains the shebang and exec bit that
   make it callable as the entry it now names.

5. `"${VAR:-fallback}"` is POSIX parameter expansion, which cmd.exe passes
   through literally and PowerShell rejects. The skill was already POSIX-bound
   (Step 0 pipes through `tee`); the requirement is now total, and SKILL.md
   says so where the variable is introduced: on Windows, run the review from
   git-bash.

The unconditional stamp is pinned by a test that inherits a foreign
QWEN_CODE_CLI and asserts the spawned child gets this checkout's dev.js;
flipping the assignment back to `??` turns exactly that test red.

* fix(review): finish the two-register split, and pin the last unpinned entry

Round-2 review feedback: five more places where this PR's own rules were not
yet applied to itself.

The Agent 7 brief handed its subagent a bare `qwen`. Its two fenced command
blocks (`build-test`, `test-efficacy`) are the one call site where a SUBAGENT
shells out to the review CLI — reachable by neither the SKILL.md sweep nor the
stderr hints. Its shell gets QWEN_CODE_CLI exactly as the orchestrator's does,
so the standard prefix works verbatim; without it, an old PATH global likely
lacks these subcommands entirely, wedging the agent between its mandate (no
hand-run builds) and a command that does not exist. A test now rejects any
line-initial bare `qwen review` in that brief.

The Step 4/5 gap texts and the blind-agent line carried remediation commands
into the posted body — the register §4 stripped from missingRoles, surviving
in the sibling paths, and partly ADDED by this PR (the rewritten texts). Each
gap is now two sentences for two readers: `gap` (author-facing, no internal
commands, rendered under `Not reviewed:`) and `fix` (orchestrator-facing,
printed by compose-review to stderr as `FIX:` lines, carried on the result as
`remediation`). The four-shape precision is intact — it moved channels, not
content — and tests pin both directions: the body may not contain
`agent-prompt`/`--findings`, and the remediation must.

Pinning start.js exposed a stdout contamination: check-build-status.js printed
"Checking build status..." to stdout ahead of every child, and start.js is now
an entry whose stdout callers consume — `review parse-args --stdin | tee`
would write a plan file whose first line is not JSON. The checker's status
lines go to stderr with its warnings; `./scripts/start.js --version` now emits
the version alone.

Also from review: the all-briefless hint no longer points at role labels the
collapsed line does not carry, and start.js's stamp gets the same test dev.js
has — inherit a foreign QWEN_CODE_CLI, assert the spawned child gets this
checkout's entry.

* fix(review): isolate the env var this PR exports, and give every gap its FIX

Two findings from the bot review of the previous commit.

The shellContextEnv suite isolated QWEN_CODE_SESSION_ID and QWEN_CODE_CLI but
not QWEN_CODE_PROJECT_DIR — the third variable the CLI exports to every shell,
and the one this suite's own per-session tests assign without cleanup.
Reproduced: run the suite with it set, as any `npm test` from inside a qwen
session does, and exactly the two `.toEqual()` exact-match tests fail on a key
the test never set. Same isolation, same shape, and it retires the in-file
leak too.

The remediation channel covered blind agents and the Step 4/5 gaps and stopped
there: missing briefs, rewritten launches, unread briefs and never-opened
diffs still reached the body with no FIX line beside them. A body disclosure
with no repair command is how QwenLM#7012's orchestrator got to "the agents clearly
did their job" — the whole reason the channel exists. Each category now pushes
one remediation line (missing briefs point at `--roster`; the relaunch-shaped
ones say relaunch with the same printed prompt), and a test pins the pair for
a roster gap: the body says "brief never reached an agent" with no command in
it, and the remediation names the roster call.

* fix(review): retire the last two overclaims the round-3 review found

Two sentences, same class, both this branch's own thesis applied to itself.

A chunk agent that ran on a hand-written prompt while its chunk was never
built landed in the body as "no prompt was built for it (`agent-prompt` never
ran for this chunk)" — an internal command on the author-facing surface, one
line per chunk on a 3B replay of the QwenLM#7012 shape. The label now says what
happened in the author's register (ran on a prompt the run wrote itself; the
brief never reached it); the rebuild command already rides the
rewritten-launches remediation line on stderr.

And the Step 4/5 `not-built` texts still said "no auditor ran" / "no verifier
ran" — the one residual of the overclaim this branch exists to retire.
`not-built` is decided before the transcripts are consulted: a run that
skipped the builder and hand-wrote the launch leaves no brief on disk whose
open could be looked for, so such an auditor is invisible to the check, and
"no auditor ran" claims sight it does not have. Both texts now use the roster
wording: what a missing record proves (no agent was launched with a prompt
this skill builds), then what it costs ("ran, if at all, without the method
its brief carries"). The Delivery docstring records why.

Tests pin the new sentences positively and negatively; the register pin
(no `agent-prompt`/`--chunk` in a body label) guards the first one.

* test(review): make the every-gap-has-a-FIX claim true, and pin the partial stderr shape

Round-5 review caught a test whose title outran its body: "every coverage gap
… has a FIX" exercised only the missing-roles path, so dropping the
remediation push for unread briefs — or rewritten launches, or never-opened
diffs — failed nothing. That is the exact disclosure-without-repair state the
channel exists to prevent, asserted by a test that could not see it.

The title now claims what the test covers, and a sibling test covers the rest:
one plan, three defects — a chunk agent on a hand-written prompt, one that
never opened its brief, one that never opened the diff — asserting each
category's FIX line and that none of the three drags a command into the body.
Between the blind-agent test, the missing-roles test and this one, every
category that discloses is now asserted to repair; mutation-checked by
deleting each push in turn, one red test each.

Also from the review: the missing-briefs stderr had handler coverage only for
the all-briefless collapse. The partial shape — one role missing, the rest
briefed — reached stderr through no test, so a formatting regression there
(a broken join, a lost --roster hint, a garbled Looked-in path) would ship
unseen. A second handler test pins it: the per-role detail, the rebuild
hints, and the record-dir line, with the collapse text asserted absent.

* fix(review): close the round-5 findings — entry contracts, gap reach, repair loops

A GPT-5 review pass filed twenty-eight findings against this branch. Nineteen
were real and are fixed here; two were refuted with evidence (the scripts test
suite IS in CI: `test:ci` runs `npm run test:scripts`); the rest are recorded
follow-ups of documented floor designs.

Entry contracts. The standalone package launches through a shim that carries
the bundled Node and announces itself via QWEN_CODE_LAUNCHER_PATH — stamping
cli-entry.js there handed subprocesses a `#!/usr/bin/env node` script on hosts
that may have no system Node; the shim is now preferred, with a test. The
variable also predates this branch with a second meaning: desktop tooling sets
it to a vendored dist/cli.js — a module path, no shebang — which a POSIX shell
would run as a shell script; getShellContextEnvVars now drops a shebang-less
script (and only a script: a native binary needs none), restoring the bare
`qwen` fallback for those hosts. And both dev launchers read a signal-killed
child (`code === null`) as exit 0 — a killed gate command reported green; both
now re-raise the signal, with close(null, 'SIGKILL') regressions. The
production entry's stamp gets the test only the dev entries had.

Gap reach. `not-launched` said the pass "did not run" — but a hand-written
launch that never opened the brief lands in that shape too, so it now uses the
certification language the other shapes got. The roster check judged only the
FIRST transcript matching a built prompt, so a failed attempt masked the
compliant relaunch that the remediation itself prescribes — all matches are
consulted now. An agent flagged rewritten is no longer also flagged unopened
(contradictory repairs for one agent), and the all-briefless collapse no
longer coexists with one "none was built" line per chunk transcript.

Repair loops. Every rebuild command the run prints is now executable as
written — plan, selector, and `--rules` included, because a rebuild without
the rules file writes a rules-free brief that every delivery check still
passes; the verify variant stops inviting the empty findings file that is only
legitimate for a reverse-audit round. check-coverage prints exact selectors
beside the human labels. Idle agents and unread chunks get FIX lines too, and
a handler test pins the boundary: every FIX on stderr, before the verdict,
never in the JSON. SKILL.md Step 6 now says what FIX lines are for: one
bounded repair round, recompose, then the cap stands.

Roster integrity. The output is self-checking against the 30 000-character
shell truncation the skill itself documents — numbered blocks, an
end-of-roster line, and SKILL.md redirects it to a file read back paged. A
PR-controlled filename can no longer forge a block boundary: control
characters flatten to spaces in the label and the launch prompt, and a test
pins the separator count.

The jq interpolation in the report template is gone — the verdict line is
copied from Step 6's output, not recomputed by a binary the host may not have.
The findings read-error no longer advises omitting a flag another guard
requires.

* fix(review): filter by overwriting, not omitting — the spread carries what the record drops

The shebang filter fixed the wrong layer. It omitted QWEN_CODE_CLI from the
record getShellContextEnvVars returns — but every spawn site composes the
child env as `{...process.env, ...vars}`, so a key omitted from the additive
record arrives anyway, inherited through the spread. On exactly the hosts the
filter was written for (desktop tooling setting the variable to a shebang-less
vendored dist/cli.js), the value leaked through and every
`"${QWEN_CODE_CLI:-qwen}"` in the skill died on exit 126 — where before this
branch those hosts ran bare `qwen` and worked.

The fix is the pattern this same function already documents for the
agent/prompt IDs: write an EMPTY string, which overwrites the inherited value
through the spread, and which the consumer's `:-` expansion treats exactly
like unset. The test comment that justified omission — "an empty string would
shadow the fallback" — was true only of the colon-less `${VAR-qwen}` form and
is corrected where it stood, so the reasoning that produced the bug does not
outlive it.

The tests now assert on the channel the bug lived in: composing
`{...process.env, ...getShellContextEnvVars()}` and reading the child env —
for the shebang-less case, the unreadable-path case, and the pass-through
case. Reverting the overwrite to an omission turns exactly the two filter
tests red. Verified end-to-end: with the desktop shape in the parent env, a
child shell resolves `"${QWEN_CODE_CLI:-qwen}"` to the PATH `qwen` again.

Also from the same review: the two adjacent `missingReceipts` blocks in
compose-review are one block now (disclosure and repair cannot drift apart),
and the `Exact selectors:` line says a rebuild of an already-built role is
idempotent, so the over-prescription cannot make an operator hesitate.

* fix(review): reunite roleLabel with the doc comment the selectorOf insertion orphaned

The insertion left roleLabel's one-line JSDoc stranded above selectorOf,
stacked on top of the new function's own — a maintainer chasing a wrong-label
bug would have edited the rebuild-flags function. Each doc sits on its
function again.

* fix(review): close the round-9 findings — convergence, injectivity, and the claims a record can carry

Fourteen findings from a GPT-5 review of the previous head; twelve fixed here,
one was already fixed in the commit the review missed, one re-recorded as the
standing roster-design follow-up.

Repair loops now converge. Coverage accumulated every historical failed
transcript, so the relaunch its own FIX line prescribes ADDED a transcript
while the failed one kept its flag — ok stayed false, the same FIX printed
forever. A failed attempt is now superseded by a compliant attempt at the same
target (same chunk served verbatim with the diff opened; same built prompt
delivered to an agent that opened its brief), and a rewritten agent is not
also told to relaunch the prompt that was the defect.

One transcript, one credit. Pasting the whole roster output to a single agent
produced one transcript that verbatim-contains every block, matched every
requirement independently, and certified an N-agent fan-out with one reader
(reproduced upstream: roster 8, agents 1, ok true). Requirements now claim
distinct transcripts; the paste-all run fails with a sentence that names the
mistake.

Records claim only what they prove. "Its brief never reached an agent" said
more than a missing record can see (the builder may have run against another
--plan spelling); it now reads "no record shows its brief reaching an agent".
The rewritten texts claimed the brief's method never arrived — but that shape
is DETECTED by the brief being opened; they now state exactly that, and that
the launch was not the built one. A zero-byte record (a torn write) no longer
counts as built anywhere: one predicate serves the collapse, the roster loop
and the chunk lookup.

Entries the shell can actually run. The shebang filter now also requires the
execute bit (a 0644 script passes the header check and dies on EACCES), and
cli-entry consumes QWEN_CODE_LAUNCHER_PATH at stamp time — the serve/mcp fast
path never reached the branch that deleted it, so a standalone daemon leaked
the outer shim into every child, where a different checkout would republish it
as its own entry.

Inputs a PR cannot weaponize, commands an operator can run. The invariant
brief interpolated the raw PR-controlled filename into the file the agent is
told is the whole of its instructions — display sinks now flatten control
characters and the functional read argument is JSON-quoted. Agent 7 no longer
receives the review rules its own workflow forbids it (SKILL.md: deterministic
commands, not code review). The verifier refuses an empty findings file — a
vacuous pass that cleared the delivery floor while ruling on nothing — while
the early reverse-audit round keeps it. FIX lines carry the run's real plan
path instead of a `<plan>` placeholder that pastes as a shell redirection, the
roster truncation hint names --file and --rules, and composed.json persists
the exact verdictLine so the archived report copies rather than reconstructs
it — event and cappedBy alone cannot express a presubmit downgrade.

Every new behaviour is pinned: convergence, paste-all refusal, and the
zero-byte collapse are mutation-checked (disabling each turns exactly its test
red); the exec-bit, brief-injection, launcher-consumption and verdictLine
contracts each carry a direct test. 1 236 tests across the affected suites.

* fix(review): close the three paths the round-11 review found still open

The Step 4/5 FIX lines still carried a literal `--plan <plan>`. Round 9
substituted the real path into compose-review's own remediation strings and
check-coverage's hints, and left the one builder both Step 4/5 gaps flow
through — `rebuildFix` — untouched: its output reached stderr through
verificationGaps with the placeholder intact, and a literal `<plan>` pasted
into a POSIX shell parses as input redirection, so the one repair round Step 6
prescribes could never run there. The push sites now substitute the plan path
verificationGaps was handed, and the test that pins the fix text asserts no
literal `<plan>` survives anywhere in the remediation.

A lightweight cross-repo review can now be REQUIRED to run Agent 0. plan-diff
takes `--pr <n> --repo <owner/repo>` — passed only after pr-context succeeds,
so the pair's presence doubles as the context-availability signal — and
writes the identity into the plan; the roster requires role 0 wherever the
full identity is present, not only in worktree mode (fetch-pr always writes
both fields, so PR-worktree behavior is unchanged). Half an identity is
refused: a roster demanding an agent nobody can brief would wedge the run.
SKILL.md's lightweight capture block carries the flags and the
when-not-to-pass-them rule.

And the path-inertness boundary is one function with a wider net: `inertPath`
now flattens every control character (a terminal escape in a filename must
not reach a terminal), the separator glyph, and the backtick — which could
close the Markdown code span the path is rendered inside and let the tail of
a PR-controlled filename run as markup in the brief the agent treats as
authoritative. The roster label and launch-prompt sites that had their own
narrower regexes now share it. The injection test's hostile filename gained a
backtick and an ESC sequence, and asserts the rendered heading carries
exactly the span's own backtick pair and no control bytes, while the
JSON-quoted functional read argument still round-trips the raw path.

Each fix is mutation-checked: reverting the substitution, re-gating the
roster on worktree mode, and narrowing inertPath each turn exactly one test
red.

* fix(review): bind the receipt to what was delivered, and match what actually assigns

Three review-integrity holes from the round-12 review, each with a
reproduction, each fixed at the layer the reproduction named.

The verify receipt could be satisfied by a partial delivery. The record was
deliberately the findings-free launch block, so one key could serve every
shard by the add-only rule — and that same rule let a caller build with a real
findings file, launch the agent with only the recorded tail, and clear the
gate while no verifier ever saw a finding. The record is now the EXACT printed
prompt, findings folded in, keyed per findings-content digest
(`verify--<sha>`, `reverse-audit--chunk-N--<sha>`); the delivery side collects
the whole key family with the documented floor of one. Tail-only delivery
matches nothing; each shard verifies against its own list; shard records no
longer share a key, so none clobbers another.

The injective roster matching was greedy, and greedy rejects valid
assignments. With transcript T1 containing blocks A+B and T2 containing only
A, first-come claiming took T1 for A and reported B missing — a compliant
repair permanently capped by transcript filename order. The claim set is now a
maximum bipartite matching (Kuhn's augmenting paths), seeded on the edges
where the transcript also opened the requirement's brief and extended over all
verbatim edges, so a requirement reports missing only when no injective
completion exists at all.

A rules-free rebuild could silently strip the brief. The launch prompt only
points at the brief, so rebuilding a rules-bearing role without --rules left
the recorded launch byte-identical while the project rules vanished from the
one file the agent treats as authoritative — every delivery check kept
passing. writeBrief now refuses the downgrade at the single choke point both
build paths pass through, with the escape hatch named (delete the record dir
to start over deliberately).

All three are mutation-checked: regressing the record to findings-free, the
matching to greedy, or disabling the downgrade guard each turns its own test
red. 704 review tests green.

* docs(review): let the docs and comments claim only what the new record design does

The round-13 review caught the drift this branch's own thesis forbids: two
SKILL.md sentences still described the findings-free record the previous
commit retired — an orchestrator reasoning from them would conclude a
findings-less delivery still matches, precisely the bypass that commit closed.
Both now state the new contract: the record is the exact printed block, keyed
per findings digest, and a launch that drops the list matches no record.

And the matching comment claimed more than Kuhn guarantees: phase-2
augmentation can displace an opened match onto an unopened edge to enlarge the
matching, so an unread flag describes the assignment, not an impossibility.
The comment now says so, and why cardinality is the right thing to maximize.

* docs(review): finish retiring the findings-free record from every sentence that described it

Round 15 found the three survivors round 13 missed — all in code, not
SKILL.md: the findingsSection docstring (all three of its clauses false since
the digest-key commit), the findings field doc ('Printed, not recorded'), and
the --findings --help text, which told an operator the exact opposite of what
the command now does. Each now states the new contract: the findings are part
of the recorded prompt, keyed per digest, and a launch that drops them matches
no record.

Also from the same review: the plan-path substitution uses a function
replacer, so a path containing $& or $` cannot be misrendered as a
replacement pattern. Practically unreachable for .qwen/tmp paths; closed
because it costs four characters.

* docs(review): the actually-last sentence describing the findings-free record

Round 16 counted one survivor of the sweep the previous commit's title
claimed complete: the acceptsFindings jsdoc in agent-briefs.ts, present-tense,
whose '(see runAgentPrompt)' pointed at a function whose own comment says the
opposite. It now states the digest-key contract like its siblings, and a
whole-tree grep for present-tense descriptions of the retired design comes
back empty.

* test(review): pin the idle and missing-chunk FIX lines to the remediation channel

Round-18 review: the two remediation pushes added for the every-gap-has-a-FIX
rule had no test of their own — deleting either failed nothing, leaving a body
disclosure whose repair could silently vanish, the exact state the channel
exists to prevent. The idle-plan test now asserts the relaunch FIX; the
blind-plan test, whose chunks nobody reads, now asserts the chunks-nobody-read
FIX beside the blind one. Both mutation-checked: deleting each push turns
exactly one test red.

* fix(review): quote the plan path in every printed repair, and test the executable shebang-less shape

Round-21 review, three items. The plan path is now single-quoted at all seven
sites that print it into a repair command — a workspace path containing a
space split the copy-pasted FIX at the space, exactly the operator moment the
lines exist for; the earlier uniformity deferral ends here, uniformly.
PlanDiffResult declares prNumber/ownerRepo so a refactor away from the
conditional spread cannot silently drop the fields the roster's Agent-0
requirement reads. And the filter gains the test its primary target deserved:
an EXECUTABLE shebang-less .js (the desktop vendored bundle shape) is rejected
by the header read itself — the existing 0644 fixture never reached that
branch, so a regression in the byte read would have passed every test.

* fix(review): shell-quote the plan path properly — an apostrophe is not rarer than a space

Round-22 review: the bare '…' wrap from the previous commit closed at an
embedded apostrophe, so ~/Documents/John's Projects broke where it had worked
unquoted — one breakage class traded for another instead of both closed. A
shared shellQuotePath (the same '\'' dance as utils/standalone-update.ts)
now serves all six repair-printing sites, and a test drives verificationGaps
from a plan under an apostrophe directory, asserting the escaped form and
rejecting the naive wrap.

* fix(review): quote the --file selector, un-dead the spawn guard, test the half-identity

Round-24/25 reviews, four small items. selectorOf now shell-quotes the --file
path — the same copy-paste contract the --plan quoting just earned, on the one
selector that carries a path. RULES_MARKER moves above writeBrief's JSDoc,
which it had been silently stealing. The check-build-status test's reject
guard was dead (execFile always delivers string stdout, so an ENOENT resolved
and the empty-stdout assertion passed on a script that never ran) — it now
rejects on spawn-level errors, which carry string codes, while non-zero exits
still resolve. And the roster's ownerRepo guard gets the independent test it
never had: a plan with prNumber but no ownerRepo requires no Agent 0, since
the brief builder cannot serve half an identity.
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.

4 participants