Skip to content

feat(review): carry the round ledger in the posted review body - #8255

Merged
wenshao merged 92 commits into
mainfrom
feat/review-persistent-ledger
Aug 1, 2026
Merged

feat(review): carry the round ledger in the posted review body#8255
wenshao merged 92 commits into
mainfrom
feat/review-persistent-ledger

Conversation

@wenshao

@wenshao wenshao commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator

What this PR does

Stacked on #8225 (→ #8218#8215). Makes the round ledger survive across environments by carrying its authoritative copy in the posted review body, and lets the default (medium) effort read it:

  • compose-review embeds a machine-readable marker — an HTML comment, invisible on the PR page — carrying this round's findings (round-scoped ids, severity, location, one-line title) into the body it composes. The round number comes from a CLI-written side file (+1 over the previous recovered round), never from the model.
  • pr-context recovers the reviewing account's latest marker from the PR's reviews, renders it as a "Previous /review round (machine ledger)" work-list section in the context file, and writes it beside it as qwen-review-pr-<n>-prev-ledger.json for compose-review's round counter. Own-account only; fail-quiet on any malformation; the marker is stripped from the full-body rendering so the JSON never reaches a model as prose.
  • SKILL Step 6's previous-round ruling now runs at medium too (recovery costs nothing — the reviews were already fetched); the local cache is demoted to fallback for rounds that never posted. Medium still writes no cache and posts nothing.

Why it's needed

The ledger shipped in #8218 as a local cache file, and its first multi-round live use exposed the flaw: four model-comparison rounds re-reviewed the same two PRs and every round opened from scratch — medium never reads the cache, and from CI or another machine there is no cache at all. The human workflow this imitates opens round 2 with "M1 is fixed" precisely because the previous report lives on the PR. Now the machine copy lives there too: the boundaries are own-account/latest-only (another user's marker is data about their tooling), data-not-authority (every recovered entry is owed a Step 6 ruling against the code — a tampered marker costs wasted rulings, never a wrong verdict), and caps on size (50 findings × 80-char titles, -- never survives into the comment payload).

Reviewer Test Plan

How to verify

  • Run cd packages/cli && npx vitest run src/commands/review src/commands/review.test.ts; expect all 45 files and 1217 tests to pass, including the new lib/ledger.test.ts and the latestOwnLedger / renderLedgerSection / buildLedger suites.
  • Round-trip by hand: serializeLedger → paste into a body → parseLedger returns the same ledger; any malformation (bad JSON, wrong version, non-integer round, misshapen entries) contributes nothing and never throws.
  • Confirm the boundaries: a marker posted by a different login is ignored; the newest own-account marker wins; a body containing -- inside titles/paths still forms a valid HTML comment (the serializer rewrites -- to ).
  • Read the Step 6 and Step 8 wording changes and the DESIGN.md section for the source-priority contract (PR marker > local cache) and the medium-reads/high-writes split.

Evidence (Before & After)

The motivating measurement is this branch's own history: four live model-comparison rounds on PRs #8219/#8224 (all medium effort) each opened from scratch despite three earlier rounds' findings being known — the cache was never read at medium and would not have existed off-machine. Non-UI change: N/A.

Tested on

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

Environment (optional)

Unit suites only.

Risk & Scope

  • Main risk or tradeoff: the marker is a new machine-readable surface on posted reviews. It is bounded — own-account/latest-only on read, size-capped on write, fail-quiet on parse, and advisory by contract (every entry is re-ruled against code) — so the worst a forged or stale marker buys is a few wasted rulings.
  • Not validated / out of scope: no live posted round has round-tripped the marker end to end yet (posting requires --comment, which these dogfood rounds deliberately withheld); the next posted review is the natural canary.
  • Breaking changes / migration notes: none. Bodies gain an invisible trailing comment; older caches keep working as the fallback they now are.

Linked Issues

Stacked on #8225#8218#8215 (retarget down the stack as they land).

中文说明

本 PR 做了什么

叠在 #8225(→ #8218#8215)之上。让轮次台账跨环境存续:权威副本改为随发布的 review 正文携带,并让缺省档(medium)读取它:

  • compose-review 在其组装的正文中嵌入机器可读 marker——HTML 注释,PR 页面上不可见——携带本轮 findings(轮次作用域 id、严重度、位置、单行标题)。轮次编号来自 CLI 写出的 side 文件(上一轮恢复值 +1),绝不来自模型。
  • pr-context 从 PR 的 reviews 中恢复本账号最新的 marker,在 context 文件中渲染为 "Previous /review round (machine ledger)" 工作清单章节,并在旁边写出 qwen-review-pr-<n>-prev-ledger.jsoncompose-review 的轮次计数使用。仅限本账号;任何畸形输入静默失败;全文渲染时剥离 marker,JSON 不会作为散文喂给模型。
  • SKILL Step 6 的前轮裁定现在 medium 档也执行(恢复零成本——reviews 本就已拉取);本地缓存降级为未发布轮次的回退。medium 仍不写缓存、不发布。

为什么需要

台账在 #8218 中以本地缓存文件面世,首次多轮实测立刻暴露缺陷:四轮模型对比复审同样两个 PR,每轮都从零开始——medium 从不读缓存,而在 CI 或另一台机器上根本没有缓存。它模仿的人工流程之所以能以 "M1 已修复" 开场,正因为上一轮报告就在 PR 上。现在机器副本也在那里:边界为仅本账号/仅最新(他人的 marker 是关于他们工具的数据)、数据而非权威(每条恢复条目都欠 Step 6 一次对照代码的裁定——被篡改的 marker 代价是几次白费的裁定,绝不是错误结论)、以及尺寸上限(50 条 × 80 字符标题,-- 不会进入注释载荷)。

Reviewer 测试计划

验证方式

  • 运行 cd packages/cli && npx vitest run src/commands/review src/commands/review.test.ts;预期 45 个文件、1217 项测试全部通过,含新增的 lib/ledger.test.tslatestOwnLedger / renderLedgerSection / buildLedger 套件。
  • 手工往返:serializeLedger → 粘入正文 → parseLedger 返回同一台账;任何畸形(坏 JSON、版本不符、非整数轮次、条目形状错误)都不产出且不抛异常。
  • 确认边界:他人 login 发布的 marker 被忽略;本账号最新 marker 胜出;标题/路径含 -- 时正文仍是合法 HTML 注释(序列化器把 -- 改写为 )。
  • 阅读 Step 6 与 Step 8 的措辞变更及 DESIGN.md 新章节:来源优先级契约(PR marker > 本地缓存)与 medium 读/high 写的划分。

前后对比证据

动机测量即本分支自身的历史:对 #8219/#8224 的四轮真实模型对比(均为 medium 档),每轮都在前几轮 findings 已知的情况下从零开场——medium 不读缓存,且离开本机缓存根本不存在。非 UI 变更:N/A。

测试平台

OS 状态
🍏 macOS ⚠️
🪟 Windows ⚠️
🐧 Linux

环境(可选)

仅单元测试。

风险与范围

  • 主要风险或取舍:marker 是发布 review 上新增的机器可读表面。它有边界——读取侧仅本账号/仅最新、写入侧尺寸受限、解析静默失败、契约上仅为参考(每条都需对照代码重新裁定)——因此伪造或过期 marker 的最坏代价是几次白费的裁定。
  • 未验证 / 范围外:尚无已发布轮次端到端跑通 marker 往返(发布需要 --comment,而这几轮 dogfood 刻意未发布);下一次发布的 review 是天然的金丝雀。
  • 破坏性变更 / 迁移说明:无。正文末尾多一段不可见注释;旧缓存作为回退继续工作。

关联 Issue

叠在 #8225#8218#8215 之上(随下层合并依次 retarget)。

wenshao and others added 12 commits July 31, 2026 17:02
… A/B, per-hunk probes

- qwen review test-plan: rule on the PR Test Plan's checkable claims (paths,
  npm scripts, test counts) against the reviewed tree; contradictions and
  differing counts are disclosed via compose-review, never capping.
- qwen review base-tree: build the merge base in a sibling worktree so the
  verifier can A/B a comparative claim instead of reading it; swept by cleanup.
- test-efficacy: third probe kind — reverse-apply one hunk at a time and
  re-run the affected tests, attributing a still-green suite to the specific
  change nothing gates; shares the mutants' budget window, runs last.
… summaries

Both measured on a live /review of #8176 with the built CLI:

- test-plan's observedTestCounts strips SGR sequences before matching; a
  color-enabled pipe interleaves them BETWEEN tokens, and the count claim
  fell to 'unchecked' with the summary right there in the report.
- build-test's trimOutput rescues runner summary lines from the omitted
  middle (like module-resolution errors): a failing suite's tail is all
  failure details and npm epilogue, which pushed the one-line summary out
  of the kept text entirely.
All measured in the review (#8215 review comment):

- test-plan: linear-time bold-heading scan (the old pattern backtracked
  catastrophically on an unclosed ** line an untrusted PR body controls);
  a flag preceding the npm script yields no claim instead of a false
  'no package defines this script'.
- test-efficacy: a hunk probe's restore recreates the parent directory a
  reverse-applied 'new file' hunk removed (the ENOENT from finally lost
  the verdict and marked every remaining hunk inconclusive); hunks get
  their own skippedForBaseline instead of mislabeling a red baseline as
  a budget skip; splitDiffIntoHunks re-captures the file header at every
  diff --git boundary; a hunk-survived finding notes when it restates an
  inert file-level revert at hunk granularity.
- base-tree: idempotent fast path keyed on a build marker + HEAD check —
  concurrent verifier shards reuse one built tree instead of sweeping it
  out from under each other mid-A/B (a fabricated base-side difference
  with a deterministic source tag was the worst case); cost wording is
  now 'an install and a build' everywhere it was 'one extra build'.
…line (#8215)

A per-hunk probe reported `survived` whenever the green baseline probes still
passed with the hunk reverted. When the hunk's own collocated test dropped out
of the baseline (a probe-tree import error collects nothing), the remaining
green probes prove only that THEY do not cover the hunk, so the verdict is now
`inconclusive` — the same dropped-test asymmetry the mutants already hold.

Also scope the hunk-survived cross-reference note to the hunk's own collocated
test, and let test-plan match a workspace-scoped run of the plan's bare command
instead of falling through to the manifest on an exact-string miss.
…his branch

The two blocking findings, reproduced on this PR's own Test Plan:

- test-plan files no false contradicted notes: npm rulings move from a
  four-verb denylist to an allowlist (the run form + npm's script aliases —
  the ~fifty other builtins each used to become 'no package defines this
  script'); a slash token is claimed as a repo path only with evidence (an
  extension or ./ prefix), never when it is a flag's value (--repo
  owner/repo) or under the review's own temp root; HEADING_LINE_RE drops
  the same quadratic shape its bold sibling was rewritten to remove.
- base-tree gets a real mutual-exclusion lock around sweep+add+build
  (mkdirSync test-and-set; the loser returns busy instead of deleting the
  tree the winner is mid-install in), and a failed build writes a settled
  marker so later shards stop re-paying the install to relearn
  'unavailable'.

Also: Agent 7's brief now names hunk-survived and the hunks.* counters
(it is the report's only consumer, and the finding class was invisible);
hunk findings anchor at the first ADDED line instead of up to three
context lines above the change.
… round ledger, richer mutants, doc parity

Shaped by a live round-2 maintainer re-verification (#7818):

- qwen review test-delta: rerun the PR side's failed test commands on the
  built merge base and diff the failing FILE SETS — netNew is the PR's own
  failure by measurement (whatever files the diff touches), shared is
  pre-existing by measurement. Counts are never compared: a flaky suite
  fails different test names between runs of the same tree. An unfinished
  base rerun attributes nothing.
- Round ledger: the incremental review cache persists confirmed findings
  under round-scoped ids (R1-2); a high-effort re-review rules on each
  (fixed / still stands / cannot tell) and opens its report with the table,
  the way a human round-2 comment opens with 'M1 is fixed'.
- Three replacement mutation operators in test-efficacy: drop '?? fallback',
  force a comparison-bearing guard condition to 'true', drop a '+ CONST'
  term. Each survivor maps to one crisp untested-protection sentence.
  A line whose raw text and literal-blanked code view disagree yields no
  candidate — an edit index computed across the two views once spliced
  'iftrue 0)' into a guard, and a mangled mutant reads as inconclusive
  while quietly spending a cap slot.
- Quality brief: documentation-parity lens — a new user-facing surface whose
  siblings are documented is a Suggestion naming the sibling precedent; no
  documented sibling, no finding.
…rification lenses

Shaped by a live sanitizer-PR verification (#8147):

- Render-adjudication capability (opt-in): with QWEN_REVIEW_SCRATCH_REPO
  set, the verifier may post a minimal payload to that user-designated repo
  and rule on GitHub's own rendered HTML — the measured case being an
  @ -> &#64; defusal every local reading called sound while GitHub's real
  renderer registered the mention and fired the notification. Absent the
  setting, rendering claims honestly cap at low confidence / cannot tell.
  Step 7's write ban names the carve-out explicitly.
- qwen review extract-step: lift one workflow step's run: script verbatim
  into an executable, with env (as comments, never half-substituted
  exports), every ${{ }} site listed unevaluated, and a heuristic invoked-
  command list as the stubbing starting point. With base-tree, both arms of
  a by-hand workflow A/B become two invocations. yaml declared as a cli
  dependency (previously resolved only via hoisting).
- Three brief lenses: a borrowed protection idiom missing what made it work
  at home (the code ancestor did the protecting; only the entity was
  copied); a second parser for an authoritatively-parsed format is a
  divergence hunt; tests that pin the mechanism instead of the effect, and
  oracles that mirror the implementation's own model.
From round 6 of the live sanitizer verification (#8147):
the fix closed the fence-shaped entrance into a raw-HTML block, and the
code-span entrance beside it — same divergence, adjacent syntax — stayed
open. A re-check that tests only the reported input rules 'fixed' over a
hole one backtick away.

Both fixed-verdict sites in SKILL Step 6 (the open-Criticals re-check and
the round ledger) now require enumerating a divergence-class defect's
sibling entrances before ruling fixed; a still-open sibling is a NEW
finding, never a reason to withhold the original's fixed — the two
rulings stay separate so the second hole cannot ship unreviewed.
…7/8005

- Threshold-boundary scan: when a fix is a ratio/length guard, hold the
  issue's own variables fixed and binary-search the boundary where the
  behaviour flips; put the number next to what the issue reports. Live
  case: a prose-ratio guard covered the edit/write_file half of its issue
  and silently declined the run_shell_command half (~473-char boundary).
- Delimiter self-injection named as the first parser-differential probe:
  a no-escaping extractor fed its own close tag truncates silently.
- Shared-gate state enumeration: a deliberate-design defence extends only
  to the states it argues — an input-hold argued for 'active' silently
  froze three idle states sharing the same gate. The sibling-entrance
  rule, applied to a state machine instead of a syntax.
The ledger shipped as a local cache file and its first multi-round live
use exposed the flaw: four model-comparison rounds re-reviewed the same
two PRs and every round opened from scratch — medium never reads the
cache, and from CI or another clone there is no cache at all. The one
artifact every environment can see, the posted review, carried nothing
machine-readable.

- compose-review embeds an HTML-comment marker (invisible on GitHub)
  carrying this round's findings and round number; the round comes from
  the side file pr-context recovered, +1 — never from the model.
- pr-context recovers the reviewing account's latest marker, renders it
  as a 'Previous /review round (machine ledger)' work-list section, and
  writes it beside the context file for compose-review's round counter.
  Own-account only, latest round wins, fail-quiet on any malformation —
  the marker is data the next round rules on, never authority it obeys.
- Step 6's previous-round ruling now runs at medium too (recovery is
  free; medium still writes no cache and posts nothing); the local cache
  is demoted to fallback for rounds that never posted.
@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

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

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

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Re-running the gate on the current head.

  • Template — complete ✓ (motivation, why-it's-needed, reviewer test plan with how-to-verify + evidence, risk & scope, linked issues, bilingual fold).
  • Problem — observed, not theoretical. The PR cites a concrete failure from the maintainer's own dogfood: four model-comparison rounds re-reviewed the same two PRs and every round opened from scratch, because medium never reads the local cache and from CI or another clone there is no cache at all. That is a real, measured defect in the review pipeline, not a "could theoretically happen" hypothesis.
  • Direction — aligned. This is the /review skill's own infrastructure, and carrying the authoritative round ledger in the posted review body — the one artifact every environment can see — is exactly the right primitive. It is the maintainer's own review-tooling stack (feat(review): Test Plan claim check, base-tree A/B harness, per-hunk probes #8215feat(review): measured failure attribution, round ledger, richer mutants, doc parity #8218feat(review): render adjudication, workflow step extraction, three verification lenses #8225 → this).
  • Size — production code lives entirely in packages/cli/src/commands/review/ (not a Stage 0 core path). The only packages/core/src/** files touched are two skill docs (DESIGN.md +12, SKILL.md +3/−3). Production .ts ≈ 534 lines, tests ≈ 869, docs ≈ 18 — under the 1000-line advisory. Author is a maintainer and this is a feat, so no core size gate applies.
  • Approach — the scope feels right. My independent read of "make the ledger survive across environments" lands on the same solution: embed a machine-readable copy in the posted body, recover it own-account-only next round, demote the cache to fallback. The capping/escaping machinery (size caps, -- HTML-comment escape, markdown-table injection hardening) is proportionate to a writable trust boundary, not gold-plating. No drive-by changes spotted.
  • Risk — no elevated risk signals: none of the changed files match the high-risk revert-correlated paths.

Moving on to code review. 🔍

中文说明

在当前 head 上重跑 gate。

  • 模板 —— 完整 ✓(动机、为什么需要、含验证方式与证据的 Reviewer 测试计划、风险与范围、关联 issue、双语折叠)。
  • 问题 —— 已观测,非理论。PR 引用了维护者自身 dogfood 中的具体失败:四轮模型对比复审同样两个 PR,每轮都从零开始——因为 medium 从不读本地缓存,而在 CI 或另一台机器上根本没有缓存。这是 review 流水线中真实、可测量的缺陷,不是"理论上可能发生"的假设。
  • 方向 —— 对齐。这是 /review skill 自身的基础设施,把权威的轮次台账放进发布的 review 正文——每个环境都能看到的唯一产物——正是正确的原语。属于维护者自己的 review 工具栈(feat(review): Test Plan claim check, base-tree A/B harness, per-hunk probes #8215feat(review): measured failure attribution, round ledger, richer mutants, doc parity #8218feat(review): render adjudication, workflow step extraction, three verification lenses #8225 → 本 PR)。
  • 规模 —— 生产代码全部位于 packages/cli/src/commands/review/(非 Stage 0 核心路径)。唯一触及 packages/core/src/** 的是两个 skill 文档DESIGN.md +12、SKILL.md +3/−3)。生产 .ts 约 534 行、测试约 869、文档约 18——低于 1000 行大 PR 建议线。作者是维护者且为 feat 类型,不触发核心规模门禁。
  • 方案 —— 范围合理。我对"让台账跨环境存续"的独立判断落在同一方案:在发布正文中嵌入机器可读副本,下一轮仅本账号恢复,缓存降级为回退。上限/转义机制(尺寸上限、-- HTML 注释转义、markdown 表格注入加固)与一个可写信任边界相称,并非过度设计。未发现顺手改动。
  • 风险 —— 无升级风险信号:改动文件均未命中与 revert 相关的高风险路径。

进入代码审查 🔍

Qwen Code · qwen3.8-max-preview

Reviewed at 24c6d3e22203334dce063761384679912b6cea9e · re-run with @qwen-code /triage

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Code review

No blockers, no convention violations. This is unusually well-built. My independent proposal for "make the round ledger survive across environments" was exactly what landed — embed a machine-readable copy in the posted body, recover it own-account-only next round — so I spent the review trying to break the safety model rather than rethink the approach. What I verified:

  • Trust boundary on parse. The marker rides in a review body — a surface other accounts can write — and parseLedger is fail-quiet: wrong version, non-integer round, misshapen findings, truncated JSON, or a forged sibling all contribute nothing and never throw. Caps bind on read too, so a hand-edited marker can't exceed what the serializer would have written. The ledger.test.ts suite treats this as an untrusted-input boundary and covers it thoroughly.
  • HTML-comment safety, lossless. -- would close the comment early and spill the tail onto the PR page, so the serializer escapes it at the JSON layer (---\u002d), which parses back to a literal --. The earlier em-dash rewrite was comment-safe but lied about a finding quoting --comment; the current escape re-locates the claim verbatim. Verified the escape can't create a fresh -- at a replacement boundary.
  • No forged state. The ledger's contents come from the comments actually posted, never from the caller's state JSON — draftedComments is stripped at both boundaries (compose-review's handler and submit's destructure), the same seam as env/prBodyFetcher. The round number comes from a CLI-written side file (+1 over the recovered round), never from the model. submit.test.ts has an explicit "forged state is ignored" test.
  • Markdown-table injection. renderLedgerSection escapes backslash before pipe (the order matters — \\| must not become a live separator), collapses newlines, and replaces backticks inside the location code span. The tests count live cell separators to prove no forged row.
  • Reuse discipline. One severity predicate for the whole package — severityOf from inline-counts.ts (the same one the verdict count uses), avoiding a whitespace divergence that would have silently dropped a counted Critical from the ledger and shifted every id after it. I confirmed severityOf and currentUser both exist in the base, so the imports resolve.
  • The actual bug this fixes. The marker is appended inside composeReview — the pure function submit posts — not in the CLI handler. Appending it in the handler (the first cut) left the feature inert end to end: the marker reached only the on-disk JSON, which nothing in the posting path reads. Both compose-review.test.ts and submit.test.ts assert on the body that reaches GitHub, not the composed file.
  • Id carry-forward. A still-standing finding keeps its original id (CARRIED_ID_RE reads it back off the re-report), and idFor guarantees no id is issued twice however the comments are worded — so R1-2 names the same claim in every round, which is the whole payoff.

The capping machinery (per-field caps + an 8 KiB whole-marker cap + a dropped field) looks like a lot for a footnote, but it's justified against measurement (n=66 posted bodies, max 3,925 chars; 50 full-width findings would serialize to ~17 KB — four times more invisible payload than visible review) and dropped exists so a truncated list can never read as complete. Proportionate, not speculative.

The cross-round round-trip the feature introduces:

sequenceDiagram
    participant P1 as compose-review
    participant P2 as GitHub PR reviews
    participant P3 as pr-context
    participant P4 as prev-ledger side file
    P1->>P4: read previous round number
    P1->>P1: buildLedger from posted comments
    P1->>P2: post review body with ledger marker
    P3->>P2: fetch reviews next round
    P3->>P3: latestOwnLedger own-account only
    P3->>P4: write recovered ledger
    P3->>P3: render previous-round work list
Loading

Test evidence (this commit's own CI)

The load-bearing unit suite is green on the reviewed commit; windows/macos/integration jobs are skipped (matrix-conditional), not failed. The remaining in-flight check-runs (review-pr, PR Asset Branch Cleanup) are bot orchestration, not this PR's CI.

Check Conclusion
Qwen Code CI (workflow) ✅ success
Test (ubuntu-latest, Node 22.x) ✅ success
web-shell E2E Smoke (ubuntu-latest, Node 22.x) ✅ success
Post Coverage Comment (ubuntu-latest, 22.x) ✅ success
Classify PR / label / authorize ✅ success
Test (windows-latest, Node 22.x) ⏭️ skipped
Test (macos-latest, Node 22.x) ⏭️ skipped
Integration Tests (CLI, No Sandbox) ⏭️ skipped

The round-trip behaviour itself is pinned by unit tests that drive the real composeReview and runSubmit paths (serialize → embed in the posted body → recover → render), so this is not a case where a green suite passes with the change removed. The one thing not yet exercised is a live posted round on a real PR (posting needs --comment, which the dogfood rounds withheld) — the author names the next posted review as the canary, which is the right place for it; that is a deployment fact rather than a behaviour the diff asserts but the tests don't pin, so no sandboxed lane applies here.

中文说明

代码审查

无阻塞项,无规范违反。这个 PR 构建得异常扎实。我对"让轮次台账跨环境存续"的独立方案与最终落地完全一致——在发布正文嵌入机器可读副本、下一轮仅本账号恢复——所以我把审查花在尝试击穿安全模型,而非重新审视方案。已验证:

  • 解析侧信任边界。 marker 寄身于 review 正文——其他账号可写的表面——parseLedger 静默失败:版本不符、非整数轮次、畸形 findings、截断 JSON、伪造兄弟条目都不产出且不抛异常。上限在读取侧同样生效,手工编辑的 marker 无法超出序列化器会写出的范围。ledger.test.ts 把它当作不可信输入边界,覆盖充分。
  • HTML 注释安全且无损。 -- 会提前关闭注释并把尾部溅到 PR 页面,序列化器在 JSON 层转义(---\u002d),解析回字面 --。早先的 em-dash 改写虽注释安全但会对引用 --comment 的 finding 撒谎;当前转义可逐字重新定位。已验证转义不会在替换边界产生新的 --
  • 无伪造 state。 台账内容来自实际发布的评论,绝不来自调用方 state JSON——draftedComments 在两个边界(compose-review handler 与 submit 解构)都被剥离,与 env/prBodyFetcher 同一道缝隙。轮次编号来自 CLI 写出的 side 文件(恢复轮次 +1),绝不来自模型。submit.test.ts 有显式的"伪造 state 被忽略"测试。
  • markdown 表格注入。 renderLedgerSection 先转义反斜杠转义竖线(顺序关键——\\| 不能变成活分隔符),折叠换行,并替换位置 code span 内的反引号。测试通过统计活单元格分隔符证明无伪造行。
  • 复用纪律。 全包一个严重度谓词——inline-counts.tsseverityOf(与 verdict 计数所用相同),避免了一处空白分歧导致已计数的 Critical 静默缺席台账、并使其后所有 id 错位。已确认 severityOfcurrentUser 均存在于基线,import 可解析。
  • 本 PR 真正修的 bug。 marker 在 composeReview 内部追加——即 submit 发布的纯函数——而非 CLI handler。在 handler 追加(第一版)会让功能端到端失效:marker 只到达磁盘 JSON,而发布路径什么都不读。compose-review.test.tssubmit.test.ts 都对到达 GitHub 的 body 断言,而非对组装出的文件。
  • id 前移。 仍然成立的 finding 保留原 id(CARRIED_ID_RE 从重新报告中读回),idFor 保证无论评论如何措辞都不会重复发号——于是 R1-2 在每一轮都指代同一 claim,这正是全部收益所在。

上限机制(字段级上限 + 8 KiB 整体 marker 上限 + dropped 字段)对一个脚注看似很多,但有测量支撑(n=66 个发布正文,最大 3,925 字符;50 条满宽 findings 序列化约 17 KB——四倍于可见 review 的不可见载荷),且 dropped 的存在使截断列表永远无法被读作完整。相称,而非投机。

测试证据(本 commit 自身 CI)

承载性的单元测试套件在被审 commit 上为绿;windows/macos/integration 作业为跳过(矩阵条件),非失败。其余在跑 check-run(review-prPR Asset Branch Cleanup)是 bot 编排,非本 PR 的 CI。轮次往返行为本身由驱动真实 composeReviewrunSubmit 路径的单元测试钉住,因此不属于"移除改动套件仍绿"的情形。唯一尚未演练的是在真实 PR 上实际发布一轮(发布需 --comment,dogfood 轮刻意未发布)——作者以下一次发布的 review 作为金丝雀,位置正确;那是部署事实,而非 diff 声称但测试未钉住的行为,故此处不适用沙箱通道。

Qwen Code · qwen3.8-max-preview

Reviewed at 24c6d3e22203334dce063761384679912b6cea9e · re-run with @qwen-code /triage

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Confidence: 5/5 — clean across every stage; would merge without hesitation.

Stepping back: my independent proposal for this problem was the same primitive the PR ships — carry the authoritative ledger in the posted review body, recover it own-account-only next round, demote the cache to fallback — so there was no simpler path I felt the author missed. The security model is the part that could have been hand-waved and wasn't: the marker is treated as data to re-rule, never authority to obey; parsing is fail-quiet against a writable surface; the round number and the ledger contents both come from CLI-controlled inputs, never the model or the caller's state JSON; and the HTML-comment and markdown-table injection paths are escaped and tested. Every change in the diff is load-bearing — I looked for scope creep or a drive-by refactor and didn't find one. The capping machinery is the one thing that could read as over-built, and it isn't: it's justified against a measured body-size distribution and dropped closes a real "truncated list reads as complete" hole.

The unit suite is green on the reviewed commit and, importantly, it pins the change — the assertions run through the real composeReview/runSubmit posting path, so this isn't a suite that would pass with the feature removed. The only untested surface is a live posted round, which the author has already named as the next-posted-review canary; that's the right place for it and isn't something the diff claims but the tests fail to back.

If I'm maintaining this in six months I'd thank the author — the tests each document the exact failure they prevent, which is how this code stays maintainable. Approving, pinned to the reviewed commit. ✅

中文说明

置信度:5/5 —— 每个阶段都干净,毫不犹豫地合并。

退一步看:我对这个问题的独立方案与 PR 交付的原语相同——把权威台账放进发布的 review 正文、下一轮仅本账号恢复、缓存降级为回退——因此没有感到作者遗漏更简路径。安全模型是本可敷衍却没有敷衍的部分:marker 被当作待重新裁定的数据,绝非待服从的权威;对可写表面的解析静默失败;轮次编号与台账内容都来自 CLI 控制的输入,绝不来自模型或调用方 state JSON;HTML 注释与 markdown 表格注入路径都被转义且有测试。diff 中每处改动都承重——我找过 scope creep 或顺手重构,没有发现。上限机制是唯一可能显得过度构建的部分,而它并非如此:有针对实测正文尺寸分布的依据,且 dropped 堵住了一个真实的"截断列表被读作完整"漏洞。

单元测试套件在被审 commit 上为绿,且关键的是它钉住了改动——断言走真实的 composeReview/runSubmit 发布路径,因此这不是一个移除功能仍会通过的套件。唯一未测的表面是实际发布的一轮,作者已以下一次发布的 review 作为金丝雀;位置正确,也不是 diff 声称而测试未支撑的东西。

若六个月后由我维护,我会感谢作者——每个测试都记录了它所阻止的确切失败,这正是这段代码保持可维护的方式。批准,钉在被审 commit 上。✅

Qwen Code · qwen3.8-max-preview

Reviewed at 24c6d3e22203334dce063761384679912b6cea9e · 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. ✅

Qwen Code added 2 commits July 31, 2026 19:18
…est-plan false positives, hunk-probe ranges (#8215)

- base-tree: only stamp a base tree available when runBuildTest actually
  compiled something (ok AND npm toolchain AND a non-empty build). An
  `unsupported` handoff or an empty npm scope returns ok:true having built
  nothing; marking that tree available let an A/B read the absence of a build
  as a behavioural difference.
- cleanup: sweep the stale base-tree build lock a killed builder leaves behind.
- test-plan: read the root manifest's scripts directly so a root-only script
  survives when the root defines no build/test; bail on the inline --root=./dir
  rebasing form; stop treating a positional after an inline --flag=value as the
  flag's value; prefer a failed scoped run when ruling a bare command; anchor
  the npm script alias to a full token so `yarn test:unit` is not truncated.
- test-efficacy: exclude `\ No newline at end of file` from the startLine offset
  count; compute the mutant-overlap range from the header's new-side span so it
  no longer overshoots into a closely following hunk.
Qwen Code Bot and others added 3 commits July 31, 2026 23:51
@wenshao

wenshao commented Aug 1, 2026

Copy link
Copy Markdown
Collaborator Author

Overview

Moves the round ledger's authoritative copy from a local cache file into the posted review body, as an invisible HTML-comment marker:

  • lib/ledger.ts (new) — serializeLedger / parseLedger / stripLedgerMarker, with caps (50 findings × 80-char titles) and -- neutralisation so the payload can't close its own comment.
  • compose-reviewbuildLedger turns the drafted inline comments + body Criticals into round-scoped ids and appends the marker to the composed body.
  • pr-context — recovers the reviewing account's latest marker, renders it as a work-list section, and writes it beside the context file as qwen-review-pr-<n>-prev-ledger.json for the round counter.
  • SKILL Step 6 now runs the previous-round ruling at medium too; the cache is demoted to fallback.

The design is well argued and the parse half is genuinely well built — treated as an untrusted-input boundary, fail-quiet on every malformation, own-account-and-latest-only, size-capped, stripped before any body reaches a model as prose. The -- invisibility test (expect(s.slice(4, -3)).not.toContain('--')) is a nice touch, and the DESIGN.md rationale earns its place.

But the write half does not reach the PR. Details below.


🔴 Critical — the marker never reaches the posted body; the feature is inert end to end

compose-review appends the marker in its CLI handler, after the pure function returns:

// compose-review.ts:1637  (inside composeReviewCommand, which starts at :1555)
const result = composeReview({ ...parsed, ...countInlineFindings(drafted) });
...
result.body = `${result.body}\n\n${serializeLedger(ledger)}`;   // :1678

But composeReviewCommand posts nothing. Per SKILL Step 7, qwen review submit is the only write path in this skill, and it derives the body itself — from the pure composeReview() at compose-review.ts:242, which this PR does not touch:

// submit.ts:299 — unchanged by this PR
const r = composeReview({ ...rest, criticalsInline, suggestionsInline });
return { event: r.event, body: r.body, cappedBy: r.cappedBy };   // no marker

And submit explicitly refuses a caller-supplied body, so the marker-bearing composed.json can never be handed to it:

// submit.ts:316
if (payload.event !== undefined || payload.body !== undefined) {
  problems.push('the payload carries `event`/`body`. Those are computed here…');
}

git grep ledger -- packages/cli/src/commands/review/ returns zero hits in submit.ts. So:

  • every posted review body goes out without a marker;
  • latestOwnLedger therefore always returns null, the side file is never written, buildLedger always emits round 1;
  • the whole read half, the new pr-context section, and the SKILL/DESIGN "PR marker > local cache" contract are dead on the only path that matters.

This is exactly where the PR body's "no live posted round has round-tripped the marker end to end yet" is hiding. Posting once with --comment would have caught it immediately.

There is a second, independent consequence worth naming: after this change the body in composed.json and the body submit posts differ. This codebase spends a lot of design effort (inline-counts.ts's header, submit's refusal of event/body, "one counting function, fed by the comments array both callers already hold") on making sure two places can never disagree about the same computed artifact — and this reintroduces exactly that split for the body itself.

Suggested fix — put the embed where both callers reach it. composeReview() only receives counts, not comment bodies, so the natural shape is a shared helper in lib/ledger.ts rather than pushing it into the pure function:

// lib/ledger.ts
export function withLedgerMarker(
  body: string,
  planPath: string | undefined,
  drafted: DraftedComment[],
  bodyCriticals: string[],
): string { /* the block currently at compose-review.ts:1640-1684 */ }

then call it from both composeReviewCommand.handler and submit.ts's compose() — both already hold planPath (via state) and the comments array. A test asserting the body submit builds contains qwen-review-ledger would lock this down; today nothing covers the compose→submit→post seam.


🟡 Suggestions

1. buildLedger restates the severity predicate that severityOf() is the single source of — and they already disagree.

lib/inline-counts.ts is unusually explicit that this must not happen:

"The ONE statement of the predicate. The counter and the unmarked-scan each restated it at first, and drift between restatements is exactly the bug-class this file's header describes; every caller classifies through here so the two can never disagree about what 'marked' means."

severityOf classifies on body.trimStart(); buildLedger uses raw body.startsWith('**[Critical]**') and a regex anchored at ^ with no trim. Concretely, for body = ' **[Critical]** double free':

  • readDraftedComments's unmarked gate passes it (it calls severityOf),
  • countInlineFindings counts it as a Critical, so it drives the verdict,
  • buildLedger hits if (!sev) continue and silently drops it — the ledger omits a Critical the review posted, and the next round never re-rules it.

compose-review.ts already imports CRITICAL_PREFIX / SUGGESTION_PREFIX (lines 49-50) and uses them at :197 and :1546, so the literals here are also a straight duplication. Suggest classifying through severityOf and deriving the title from the trimmed body.

Worth noting the if (!sev) continue branch is otherwise unreachable from the CLI — readDraftedComments throws on unmarked comments before buildLedger runs — so the only thing that branch can actually do today is swallow this divergence.

2. Stripping after the worth-showing filter defeats the canonical-LGTM filter for every review this pipeline posts.

// pr-context.ts — filter sees the raw body…
const meaningfulReviews = reviews.filter((r) => isReviewWorthShowing(r.body))
// …but rendering strips
parts.push(quoteBlock(fullBody(stripLedgerMarker(r.body ?? ''), r.id, ctx)));

CANONICAL_LGTM_RE is anchored to end-of-body on purpose (its comment explains why). Once every own-account review carries a trailing marker, that anchor never matches again, so every auto-emitted No issues found. LGTM! ✅ _— … via Qwen Code /review_ starts rendering in full under "Review summaries" — one extra block per round, in a file Step 1 already warns routinely exceeds the 25 000-char read threshold. Strip once, up front, and feed the stripped body to both the filter and the renderer.

(Same call site, minor: stripLedgerMarker removes only the first marker, and .trim()s only when one was found — harmless today, slightly surprising later.)

3. renderLedgerSection doesn't escape |, and it's building a markdown table.

`| ${f.id} | … | \`${f.file}${}\` | ${f.title} |`

A perfectly ordinary finding title — "`a || b` short-circuits" — breaks the row for the model that has to read it. f.title.replace(/\|/g, '\\|') on both title and file costs nothing. (Newlines are already impossible via split('\n')[0].)

4. latestOwnLedger tie-break keeps the oldest on equal timestamps.

if (!best || at > best.at) best = { at, ledger };

GitHub returns reviews in ascending submitted_at, so with strict > two reviews submitted in the same second (or several with submitted_at absent, all collapsing to '') resolve to the first one seen — the opposite of the documented "latest wins". >= matches both the doc comment and the API's ordering.

5. Round counter can silently reset to 1, reusing ids.

pr-context writes the side file only when it recovers a ledger, and never removes a stale one. If currentUser() throws (the try/catch at pr-context.ts:930 swallows it — plausible on a rate limit or a keyring hiccup) and Step 9 cleanup has already removed the previous side file (it matches the .qwen/tmp/qwen-review-{target}-* glob), the next posted round emits R1-* ids that collide with a genuine round 1's. Cosmetic while only the latest marker is read, but the ids are documented as "stable across re-reports", and a Step 6 ruling addressed to R1-2 becomes ambiguous. Worth a sentence in the DESIGN.md boundaries list at minimum.


Things that are right

  • Parse boundary treated as untrusted input, with a test enumerating malformations and asserting nothing throws and nothing is contributed — the correct posture for a surface another account can write.
  • -- neutralisation plus the invisibility assertion; the slice-then-replace ordering is correct, and no adjacency across JSON field boundaries can reintroduce --.
  • Caps documented against GitHub's actual 65 536-char body limit.
  • Own-account gating, with the reasoning ("another user's marker is data about their tooling") written down rather than assumed.
  • Marker stripped before any body is rendered as model-facing prose.
  • DESIGN.md section states the boundaries as boundaries, including the data-not-authority contract that keeps a forged marker cheap.

Verdict

Critical #1 blocks: as written, nothing this PR posts is recoverable, so neither half of the round trip runs in production. It's a small fix (share the embed between the two callers) plus one test across the compose→submit seam — and one live --comment round to confirm the marker actually lands.

中文说明

概述

把轮次台账的权威副本从本地缓存文件搬到发布的 review 正文里,以不可见的 HTML 注释 marker 承载。解析侧做得相当扎实:按不可信输入边界处理、任何畸形都静默失败、仅本账号+仅最新、尺寸受限、喂给模型前先剥离。-- 中和及其不可见性断言是个好设计,DESIGN.md 的论证也站得住。

写入侧到不了 PR

🔴 阻断问题:marker 永远进不了发布的正文

compose-review 是在 CLI handler 里、纯函数返回之后才追加 marker 的(compose-review.ts:1678,位于 :1555 起的 composeReviewCommand 内)。而按 SKILL Step 7,qwen review submit 是本 skill 唯一的写入路径,它自己从未被本 PR 改动的纯函数 composeReview():242)算出正文:

// submit.ts:299
const r = composeReview({ ...rest, criticalsInline, suggestionsInline });
return { event: r.event, body: r.body, cappedBy: r.cappedBy };   // 没有 marker

而且 submit 明确拒绝调用方自带 bodysubmit.ts:316),所以带 marker 的 composed.json 根本无法交给它。git grep ledgersubmit.ts 中零命中。

结果:所有发布的 review 都不带 marker → latestOwnLedger 恒为 null → side 文件从不写出 → buildLedger 永远输出 round 1 → 读取侧、pr-context 新章节、以及 SKILL/DESIGN 的 “PR marker > 本地缓存” 契约,在唯一要紧的路径上全是死代码。

PR 描述里那句“尚无已发布轮次端到端跑通 marker 往返”正是它藏身之处——只要带 --comment 发布一次就会暴露。

还有一个独立的后果:改动之后 composed.json 的正文与 submit 发布的正文不一致。这个代码库花了大量设计(inline-counts.ts 的文件头、submitevent/body 的拒绝)来保证同一个计算产物不会有两个会分歧的来源,而这里恰好为正文本身重新引入了这种分裂。

建议修法:把嵌入逻辑抽成 lib/ledger.ts 里的共享 helper withLedgerMarker(body, planPath, drafted, bodyCriticals),由 composeReviewCommand.handlersubmit.tscompose() 同时调用——两者都已持有 planPath(经 state)和 comments 数组。再补一个断言 submit 所构造正文含 qwen-review-ledger 的测试;目前 compose→submit→post 这一接缝完全没有覆盖。

🟡 建议

  1. buildLedger 重述了 severityOf() 独占的判定逻辑,且两者已经不一致。 inline-counts.ts 的注释明确写着“判定谓词的唯一表述……每个调用方都经由此处分类,两者才不可能对‘什么算已标记’产生分歧”。severityOftrimStart() 再判定,buildLedger 直接 startsWith。对 ' **[Critical]** double free'readDraftedComments 放行、countInlineFindings 计入 Critical 并参与裁决,而 buildLedgerif (!sev) continue 静默丢弃——台账漏掉一条本轮发布的 Critical,下一轮永远不会再裁定它。而且 compose-review.ts 第 49-50 行已经导入了 CRITICAL_PREFIX/SUGGESTION_PREFIX,这里的字面量属于纯重复。建议改走 severityOf

  2. 先过滤后剥离,使 canonical-LGTM 过滤对本流水线发布的每一条 review 都失效。 isReviewWorthShowing(r.body) 看的是原始正文,渲染时才 stripLedgerMarkerCANONICAL_LGTM_RE刻意锚定到正文末尾的(其注释解释了原因)。一旦每条本账号 review 都带上尾部 marker,该锚点再不匹配,于是每条自动发出的 No issues found. LGTM! ✅ 都会完整渲染进 “Review summaries”——每轮多一段,而这个文件 Step 1 已警告经常超过 25 000 字符阈值。应在最前面剥离一次,过滤与渲染共用剥离后的正文。

  3. renderLedgerSection 未转义 |,而它在拼 markdown 表格。 一个很普通的标题(如 "`a || b` short-circuits")就会把行拼坏,而读它的正是模型。对 titlefile 各做一次 replace(/\|/g, '\\|') 即可。

  4. latestOwnLedger 的并列取值取的是最旧的一条。 at > best.at 严格大于:GitHub 按 submitted_at 升序返回,同秒提交(或多条缺失 submitted_at、一并塌缩为 '')时会保留先遇到的那条,与文档注释所说的“最新胜出”相反。用 >=

  5. 轮次计数可能静默重置为 1 并复用 id。 pr-context 仅在恢复到台账时才写 side 文件,且从不清除陈旧副本。若 currentUser() 抛错(pr-context.ts:930try/catch 会吞掉,限流或 keyring 抖动时都可能),而 Step 9 清理已删掉上一份 side 文件(它匹配 .qwen/tmp/qwen-review-{target}-* 通配),下一轮发布就会产出与真正 round 1 冲突的 R1-* id。在只读最新 marker 的前提下多属观感问题,但 id 被文档描述为“跨复报稳定”,且一条写给 R1-2 的 Step 6 裁定会变得有歧义。至少值得在 DESIGN.md 的边界清单里补一句。

结论

Critical #1 阻断:照现状,本 PR 发布出去的东西没有任何可恢复内容,往返的两半在生产路径上都不会运行。修起来不大——把嵌入逻辑在两个调用方之间共享,加一个跨 compose→submit 接缝的测试,再带 --comment 实跑一轮确认 marker 真的落地。

wenshao added 3 commits August 1, 2026 13:29
…verification

# Conflicts:
#	packages/cli/src/commands/review/test-efficacy.integration.test.ts
…r seam

Merging main brought #8050's Windows-portability refactor, which resolves
the probe runner through vitest/package.json's bin — a node_modules/.bin
fake is dead weight it never reads. The 8215-only collocated-dropout test
still installed the old .bin fake, so the REAL vitest ran its fixtures,
price.test.ts genuinely passed, and the hunk scored survived. The test now
overrides the fake package's vitest.mjs like every post-refactor test.
The per-field caps leave the total unbounded: fifty findings at full
width serialize to just under 17,000 characters. The module's own
paragraph calls the marker "a footnote, never a payload" and reasons
about GitHub's 65,536-character body limit, so the total is the number
that claim is about and nothing was computing it.

Set the budget from measurement rather than from the limit. Across every
review this pipeline has posted on its own stack (n=66) the body runs a
median of 721 characters, p90 2,178, max 3,925 - the limit has ~61 KiB
of headroom, and an over-long marker was never going to fail a post. The
real cost is proportion: 17,000 characters of invisible payload on a
3,925-character review is four times more marker than review. 8 KiB
holds fifty findings at realistic widths without dropping any, and the
truncation path is reached only by a ledger no round has produced.

What it drops travels with it. A `dropped` count is the difference
between a list the next round reads as complete and one that says it is
not - the same distinction this module already draws everywhere else.
@wenshao
wenshao requested a review from Copilot August 1, 2026 15:30

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.

yiliang114
yiliang114 previously approved these changes Aug 1, 2026

@yiliang114 yiliang114 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM. The ledger-as-HTML-comment design is well-bounded and the fail-quiet parse is the right contract for an untrusted-input surface.

Two non-blocking notes:

  1. buildLedger passes through negative line values (typeof c.line === 'number' includes -1). Harmless since it's re-location metadata only, but a c.line > 0 guard would keep the ledger's shape honest — a negative line number is never a real location.

  2. ledgerMarkerFor re-reads and re-parses the plan file that composeReviewBody already consumed. Not a correctness issue (the function is called once per review), but threading the prNumber through from the already-parsed plan would remove the redundant I/O and the second try/catch surface.

Neither blocks — the serialization round-trip is lossless, the size caps bind both halves, and the carried-id logic is thoroughly tested.

The size cap added in the previous commit can drop entries, and the
rendered section still opened with "**Every entry below is owed a
this-round ruling**" and said nothing about what was missing. The
`dropped` count existed and reached the only place a reader sees the
list as nothing at all — which is the failure it was added to prevent,
committed one step after adding the field. It now says the list is
partial, how many are missing, and that absence is not evidence a
finding was fixed.

Second, the table escaping escaped `|` but not `\`. `\|` in a title
became `\\|`, which markdown reads as an escaped backslash followed by a
LIVE separator: the forged row the escaping exists to prevent, produced
by the escaping. Backslash first now, and the test counts separators the
way markdown does rather than by pattern, because a lookbehind counter
is fooled by exactly the input under test.

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.

A comment that is nothing but its severity marker produced a ledger
entry with an empty title. That does not merely degrade the entry, it
jams the review: the next round is told every ledger entry is owed a
this-round ruling, has no claim text to rule on, answers `cannot tell`,
and `cannot-tell-existing-critical` is one of the cap reasons. Nothing
between rounds changes, so the cap comes back every round.

Dropping the entry would hide a Critical that really was posted, so it
keeps its place and gets the one handle there is - the location it was
filed at, or "the review body" for a body-level one. The field's stated
job is "enough for the next round to re-locate the claim", and that is
what a text-less finding still has.

Found by probing `buildLedger` with ten malformed comment shapes; the
other nine - carried ids, id collisions, two comments carrying the same
id, `R2D2` not being an id, a leading newline before the marker - all
behaved correctly and needed no change.
@wenshao
wenshao requested a review from Copilot August 1, 2026 15:45

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.

Found by running the three previous fixes together on one round: 51
findings in, 24 kept, and the marker said 26 were missing.
`LEDGER_MAX_FINDINGS` truncates before the byte cap ever runs, and
measuring `dropped` against the already-sliced list left the count cap's
share silent - so the field added two commits ago to stop a truncated
list reading as complete was itself under-reporting the truncation.

Measured against what came IN now, and pinned across all four
combinations: count cap alone, byte cap alone, both, and neither. Kept
plus dropped equals given, in every one.
@wenshao
wenshao requested a review from Copilot August 1, 2026 15:50

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 requested a review from Copilot August 1, 2026 15:55

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 Aug 1, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Summary

Package Lines Statements Functions Branches
CLI 83.44% 83.44% 89.33% 82.68%
Core 87.59% 87.59% 89.21% 86.21%
CLI Package - Full Text Report
-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |   83.44 |    82.68 |   89.33 |   83.44 |                   
 src               |   84.36 |    81.54 |   88.29 |   84.36 |                   
  cli.ts           |   95.64 |     83.8 |     100 |   95.64 | ...52-553,557-558 
  gemini.tsx       |   72.21 |    76.81 |   80.76 |   72.21 | ...1253-1257,1378 
  ...ractiveCli.ts |   86.46 |    82.39 |    87.5 |   86.46 | ...2492,2498,2553 
  ...liCommands.ts |   88.09 |    84.37 |      90 |   88.09 | ...81,498,532,654 
  ...ActiveAuth.ts |     100 |     87.5 |     100 |     100 | 66-80             
 ...cp-integration |   69.97 |    72.73 |   89.81 |   69.97 |                   
  acpAgent.ts      |   69.64 |     72.6 |   89.84 |   69.64 | ...65,11370-11372 
  authMethods.ts   |      92 |       60 |     100 |      92 | 33-34             
  errorCodes.ts    |       0 |        0 |       0 |       0 | 1-22              
  ...ion-skills.ts |     100 |    88.23 |     100 |     100 | 17,32             
  generation.ts    |    97.1 |    81.25 |     100 |    97.1 | 109,112           
  ...DirContext.ts |     100 |      100 |     100 |     100 |                   
 ...ration/service |   97.04 |    95.71 |   93.33 |   97.04 |                   
  filesystem.ts    |   97.04 |    95.71 |   93.33 |   97.04 | ...21-122,238-239 
 ...ration/session |   91.65 |    86.59 |   96.24 |   91.65 |                   
  Session.ts       |   91.25 |    85.47 |   95.67 |   91.25 | ...9412,9439-9443 
  ...entTracker.ts |   91.87 |    89.47 |      90 |   91.87 | ...43,207,286-295 
  ...stop-guard.ts |     100 |    98.07 |     100 |     100 | 37,127            
  ...eplay-page.ts |    93.1 |    90.72 |     100 |    93.1 | 71,82-85,111-121  
  ...y-replayer.ts |   98.53 |    95.52 |     100 |   98.53 | 238-240           
  index.ts         |       0 |        0 |       0 |       0 | 1-40              
  ...ssionUtils.ts |   89.76 |    87.32 |     100 |   89.76 | ...54-270,326-328 
  tasksSnapshot.ts |    94.3 |     87.5 |     100 |    94.3 | 65-71             
  ...on-tracker.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...ssion/emitters |   95.79 |    93.43 |   96.66 |   95.79 |                   
  ...ageEmitter.ts |   95.34 |    94.11 |     100 |   95.34 | 52-59             
  PlanEmitter.ts   |     100 |       90 |     100 |     100 | 66                
  base-emitter.ts  |   78.26 |       75 |     100 |   78.26 | 23-24,26-28       
  index.ts         |       0 |        0 |       0 |       0 | 1-10              
  ...ll-emitter.ts |   99.18 |    96.42 |     100 |   99.18 | 355-356           
 ...ession/rewrite |    91.8 |    89.13 |   94.44 |    91.8 |                   
  LlmRewriter.ts   |    82.4 |     86.2 |     100 |    82.4 | ...,88-89,166-170 
  ...Middleware.ts |   96.96 |    88.09 |     100 |   96.96 | 144,152-154       
  TurnBuffer.ts    |     100 |      100 |     100 |     100 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 src/agent-view    |   89.03 |    81.37 |   89.09 |   89.03 |                   
  ...t-cli-argv.ts |     100 |      100 |     100 |     100 |                   
  protocol.ts      |     100 |      100 |     100 |     100 |                   
  ...sor-client.ts |   80.38 |    72.54 |   76.66 |   80.38 | ...22-626,652-656 
  ...or-process.ts |   96.61 |    89.47 |   84.61 |   96.61 | 129-130,150-151   
  ...sor-runner.ts |    84.9 |     75.6 |      85 |    84.9 | ...44,468,471-481 
  ...sor-server.ts |   85.71 |    83.06 |   95.45 |   85.71 | ...67-468,471-488 
  ...isor-store.ts |   97.73 |    81.16 |     100 |   97.73 | ...92,594,607,643 
  ...nal-bridge.ts |   93.98 |     91.3 |   83.33 |   93.98 | 228-238           
 src/commands      |   89.25 |    73.75 |   64.51 |   89.25 |                   
  auth.ts          |     100 |    83.33 |     100 |     100 | 11,14             
  channel.ts       |   55.55 |      100 |       0 |   55.55 | 18-22,30-40       
  extensions.tsx   |   96.77 |      100 |      50 |   96.77 | 39                
  hooks.tsx        |   66.66 |      100 |       0 |   66.66 | 20-24             
  mcp.ts           |   95.45 |      100 |      50 |   95.45 | 31                
  review.ts        |    98.3 |      100 |      50 |    98.3 | 70                
  serve.ts         |    87.1 |    68.22 |     100 |    87.1 | ...46-649,663-667 
  sessions.ts      |     100 |      100 |      50 |     100 |                   
  update.ts        |   98.13 |    94.44 |   66.66 |   98.13 | 82-83             
 ...mmands/channel |   88.29 |    87.65 |    90.3 |   88.29 |                   
  channel-cwd.ts   |     100 |      100 |     100 |     100 |                   
  ...l-registry.ts |      80 |    84.61 |      80 |      80 | 37-40,49-52,63-66 
  ...entry-path.ts |      75 |       50 |     100 |      75 | 8-9               
  config-utils.ts  |   95.87 |    96.35 |     100 |   95.87 | ...08-213,271-274 
  configure.ts     |    14.7 |      100 |       0 |    14.7 | 18-21,23-84       
  daemon-worker.ts |   93.89 |    85.39 |   94.11 |   93.89 | ...1209,1216-1217 
  loop-runtime.ts  |   91.66 |      100 |      50 |   91.66 | 15,22             
  ...classifier.ts |   98.49 |    96.51 |     100 |   98.49 | 115-116,161       
  ...tact-store.ts |   93.51 |    87.65 |     100 |   93.51 | ...71,288-289,337 
  pairing.ts       |   72.85 |      100 |      50 |   72.85 | 22-28,57-68       
  pidfile.ts       |   95.55 |       90 |     100 |   95.55 | ...50-251,315-316 
  proxy.ts         |     100 |      100 |     100 |     100 |                   
  reload.ts        |    77.5 |    86.95 |      75 |    77.5 | 72-84,93-97       
  runtime.ts       |   82.43 |    86.44 |     100 |   82.43 | ...87-191,251-253 
  set.ts           |   75.72 |    85.71 |      50 |   75.72 | 65-83,111-116     
  start.ts         |    85.8 |    82.17 |      88 |    85.8 | ...85,591-594,606 
  ...ure-format.ts |   93.65 |    82.45 |     100 |   93.65 | ...42,48-49,74-75 
  status.ts        |   78.57 |    59.25 |   66.66 |   78.57 | ...36-137,150-161 
  stop.ts          |   57.83 |    82.35 |      50 |   57.83 | ...3,74-76,85-111 
 ...nds/extensions |   88.82 |    87.64 |   87.09 |   88.82 |                   
  consent.ts       |   72.53 |       90 |   42.85 |   72.53 | ...86-142,157-163 
  disable.ts       |     100 |       90 |     100 |     100 | 30                
  enable.ts        |     100 |    91.66 |     100 |     100 | 38                
  install.ts       |   82.95 |    81.57 |      75 |   82.95 | ...96-199,202-211 
  link.ts          |     100 |      100 |     100 |     100 |                   
  list.ts          |     100 |     87.5 |     100 |     100 | 18                
  new.ts           |     100 |      100 |     100 |     100 |                   
  settings.ts      |   99.15 |      100 |   83.33 |   99.15 | 151               
  sources.ts       |   93.42 |    87.09 |   92.85 |   93.42 | ...4-66,96-98,167 
  uninstall.ts     |   74.57 |       40 |   66.66 |   74.57 | 45-47,60-67,70-73 
  update.ts        |   96.71 |    97.05 |     100 |   96.71 | 114-118           
  utils.ts         |      75 |    53.84 |     100 |      75 | ...27-131,133-137 
 ...les/mcp-server |       0 |        0 |       0 |       0 |                   
  example.ts       |       0 |        0 |       0 |       0 | 1-60              
 ...amples/starter |       0 |        0 |       0 |       0 |                   
  example.ts       |       0 |        0 |       0 |       0 | 1-64              
 src/commands/mcp  |   90.17 |    84.39 |   83.33 |   90.17 |                   
  add.ts           |    99.3 |    96.07 |     100 |    99.3 | 154-155           
  approve.ts       |   76.19 |     87.5 |   66.66 |   76.19 | ...,89-99,114-124 
  list.ts          |   92.59 |    83.87 |      80 |   92.59 | ...62-164,180-181 
  reconnect.ts     |   78.85 |    66.66 |   85.71 |   78.85 | 42-55,169-191     
  remove.ts        |     100 |       80 |     100 |     100 | 21-25             
 ...ommands/review |   85.79 |     86.9 |   86.76 |   85.79 |                   
  agent-prompt.ts  |   90.88 |    92.78 |      96 |   90.88 | ...1273,1743-1812 
  base-tree.ts     |   74.87 |    79.16 |   77.77 |   74.87 | ...29-350,352-365 
  capture-local.ts |   68.57 |     90.9 |      75 |   68.57 | 107-111,158-189   
  ...k-coverage.ts |   48.38 |    14.28 |   66.66 |   48.38 | ...21-226,239-249 
  cleanup.ts       |   89.12 |    82.22 |   83.33 |   89.12 | ...00-505,507-508 
  ...ent-status.ts |   93.03 |    83.87 |   83.33 |   93.03 | 291,531-551       
  ...ose-review.ts |   95.77 |    91.19 |   95.65 |   95.77 | ...1615,1643-1665 
  extract-step.ts  |   91.26 |    90.44 |   88.88 |   91.26 | ...76-693,700-715 
  fetch-pr.ts      |   74.02 |    53.57 |      50 |   74.02 | ...98,332,402-407 
  load-rules.ts    |   26.41 |      100 |   16.66 |   26.41 | ...41-153,155-156 
  parse-args.ts    |   99.27 |       96 |     100 |   99.27 | 345,417           
  plan-diff.ts     |   64.04 |      100 |   66.66 |   64.04 | 127-163           
  pr-context.ts    |   81.77 |    80.86 |   92.85 |   81.77 | ...1043,1072-1074 
  presubmit.ts     |   83.75 |    92.72 |   88.88 |   83.75 | ...77-578,655-685 
  ...ve-anchors.ts |   77.02 |    88.46 |      75 |   77.02 | ...70-175,187-204 
  run.ts           |   81.14 |    86.17 |    90.9 |   81.14 | ...13,429-477,490 
  script-lint.ts   |   83.67 |    78.41 |   88.88 |   83.67 | ...59-773,775-797 
  submit.ts        |   77.59 |    82.05 |   81.81 |   77.59 | ...20-656,658-659 
  test-delta.ts    |   86.91 |     92.5 |      75 |   86.91 | 187-218,444-452   
  test-efficacy.ts |   88.18 |    83.11 |      95 |   88.18 | ...2167,2175-2195 
  test-plan.ts     |   90.34 |    92.12 |   88.88 |   90.34 | ...19-720,784-801 
 ...nds/review/lib |   96.01 |    93.58 |   95.94 |   96.01 |                   
  agent-briefs.ts  |   98.68 |      100 |       0 |   98.68 | 561-562           
  anchors.ts       |     100 |    94.79 |     100 |     100 | ...33,169,178,225 
  coverage.ts      |   95.47 |    94.28 |   95.45 |   95.47 | ...98,335,433-450 
  diff-flags.ts    |     100 |        0 |     100 |     100 | 63                
  diff-plan.ts     |   98.73 |    93.01 |     100 |   98.73 | ...41,264,290-291 
  effort.ts        |     100 |      100 |     100 |     100 |                   
  gh.ts            |    85.6 |    88.37 |   71.42 |    85.6 | ...20,257-258,285 
  git.ts           |   97.64 |    95.65 |     100 |   97.64 | 180-181           
  heavy.ts         |     100 |      100 |     100 |     100 |                   
  inline-counts.ts |     100 |      100 |     100 |     100 |                   
  ledger.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         |     100 |     87.5 |     100 |     100 | 84                
  prompt-record.ts |   94.73 |    88.23 |     100 |   94.73 | ...28,151-152,156 
  receipt.ts       |     100 |      100 |     100 |     100 |                   
  report.ts        |   94.38 |    93.75 |     100 |   94.38 | 173-177           
  roster.ts        |     100 |    94.23 |     100 |     100 | 143,161,206       
  shell-quote.ts   |     100 |      100 |     100 |     100 |                   
  test-utils.ts    |     100 |      100 |     100 |     100 |                   
  transcripts.ts   |   96.27 |    93.18 |     100 |   96.27 | ...83,269-270,294 
  workspaces.ts    |   98.88 |    92.39 |     100 |   98.88 | 212-213           
  worktree.ts      |     100 |      100 |     100 |     100 |                   
 ...mands/sessions |   91.56 |    86.95 |   83.33 |   91.56 |                   
  common.ts        |     100 |      100 |     100 |     100 |                   
  list.ts          |   90.96 |    86.66 |   81.81 |   90.96 | 208-219,221-222   
 src/config        |   94.35 |    88.93 |   95.63 |   94.35 |                   
  auth.ts          |   89.35 |    83.56 |     100 |   89.35 | ...97-298,314-315 
  ...eMcpImport.ts |   87.91 |    81.52 |     100 |   87.91 | ...63-371,453-454 
  compile-cache.ts |     100 |      100 |     100 |     100 |                   
  config.ts        |   88.91 |    88.72 |   83.78 |   88.91 | ...2445,2447-2455 
  ...cy-monitor.ts |   88.75 |    76.19 |     100 |   88.75 | ...3,90-92,98,101 
  ...ust-policy.ts |   83.04 |    88.28 |     100 |   83.04 | ...39,253,352-353 
  ...heme-names.ts |     100 |      100 |     100 |     100 |                   
  environment.ts   |   94.33 |    89.61 |   94.73 |   94.33 | ...35-639,655-656 
  ...le-watcher.ts |   90.86 |    83.65 |   95.83 |   90.86 | ...23-325,370,418 
  ...resh-state.ts |   90.57 |    97.29 |   93.75 |   90.57 | 137-142,146-152   
  ...ime-reload.ts |     100 |    69.69 |     100 |     100 | ...12-113,122-123 
  hot-reload.ts    |     100 |    89.13 |     100 |     100 | 47,172-178,238    
  keyBindings.ts   |   97.43 |       50 |     100 |   97.43 | 236-239           
  ...ngsAdapter.ts |     100 |    94.11 |     100 |     100 | 64                
  ...ig-watcher.ts |   95.17 |    83.05 |     100 |   95.17 | ...78,200,292-293 
  ...er-secrets.ts |   98.97 |    96.87 |     100 |   98.97 | 85                
  mcpApprovals.ts  |   96.55 |    95.55 |     100 |   96.55 | 223-224,229-231   
  mcpJson.ts       |     100 |      100 |     100 |     100 |                   
  mcpServers.ts    |   92.85 |     87.5 |     100 |   92.85 | 46-47             
  ...idersScope.ts |      95 |    94.73 |     100 |      95 | 11-12             
  ...abledTools.ts |     100 |      100 |     100 |     100 |                   
  ...comparison.ts |     100 |      100 |     100 |     100 |                   
  ...n-settings.ts |   99.15 |    93.75 |     100 |   99.15 | 63                
  sandboxConfig.ts |   61.64 |    71.87 |   66.66 |   61.64 | ...54-68,73,77-89 
  ...ings-cache.ts |   98.26 |    97.14 |     100 |   98.26 | 201-202           
  settings.ts      |   90.99 |     92.3 |      90 |   90.99 | ...1006,1008-1009 
  ...ingsSchema.ts |     100 |      100 |     100 |     100 |                   
  ...ngsWatcher.ts |   95.54 |    88.34 |     100 |   95.54 | ...28,277-278,293 
  ...d-env-keys.ts |     100 |      100 |     100 |     100 |                   
  ...l-settings.ts |     100 |      100 |     100 |     100 |                   
  ...paths-lite.ts |   89.47 |       88 |     100 |   89.47 | 43-44,53-54,56-57 
  ...tedFolders.ts |   93.35 |    94.11 |     100 |   93.35 | ...90-391,427-438 
 ...nfig/migration |   95.23 |    77.77 |   83.33 |   95.23 |                   
  index.ts         |   95.65 |     87.5 |     100 |   95.65 | 117-118           
  scheduler.ts     |   96.55 |    77.77 |     100 |   96.55 | 19-20             
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...ation/versions |   94.91 |      100 |     100 |   94.91 |                   
  ...-v2-shared.ts |     100 |      100 |     100 |     100 |                   
  v1-to-v2.ts      |   81.75 |      100 |     100 |   81.75 | ...28-229,231-247 
  v2-to-v3.ts      |     100 |      100 |     100 |     100 |                   
  v3-to-v4.ts      |     100 |      100 |     100 |     100 |                   
  v5-to-v4.ts      |      96 |      100 |     100 |      96 | 94-95,99          
 src/core          |     100 |      100 |     100 |     100 |                   
  auth.ts          |     100 |      100 |     100 |     100 |                   
  initializer.ts   |     100 |      100 |     100 |     100 |                   
  theme.ts         |     100 |      100 |     100 |     100 |                   
 src/dualOutput    |    71.8 |    70.31 |   66.66 |    71.8 |                   
  ...tputBridge.ts |   71.95 |    70.96 |   68.42 |   71.95 | ...08-409,417-420 
  ...utContext.tsx |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-8               
 src/export        |       0 |        0 |       0 |       0 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-7               
 src/generated     |     100 |      100 |     100 |     100 |                   
  git-commit.ts    |     100 |      100 |     100 |     100 |                   
 src/hooks         |     100 |      100 |     100 |     100 |                   
  ...elete-hook.ts |     100 |      100 |     100 |     100 |                   
 src/i18n          |   85.98 |    81.92 |   89.65 |   85.98 |                   
  index.ts         |   73.45 |    77.77 |      90 |   73.45 | ...70-271,294-299 
  languages.ts     |   93.07 |     92.3 |   85.71 |   93.07 | ...35,164-169,184 
  ...nslateKeys.ts |     100 |      100 |     100 |     100 |                   
  ...lationDict.ts |   93.33 |    66.66 |     100 |   93.33 | 15                
 src/i18n/locales  |     100 |      100 |     100 |     100 |                   
  ca.js            |     100 |      100 |     100 |     100 |                   
  de.js            |     100 |      100 |     100 |     100 |                   
  en.js            |     100 |      100 |     100 |     100 |                   
  fr.js            |     100 |      100 |     100 |     100 |                   
  ja.js            |     100 |      100 |     100 |     100 |                   
  pt.js            |     100 |      100 |     100 |     100 |                   
  ru.js            |     100 |      100 |     100 |     100 |                   
  zh-TW.js         |     100 |      100 |     100 |     100 |                   
  zh.js            |     100 |      100 |     100 |     100 |                   
 ...nonInteractive |      80 |    76.31 |   81.35 |      80 |                   
  session.ts       |   84.08 |    75.27 |   93.61 |   84.08 | ...1007,1016-1026 
  types.ts         |    42.5 |      100 |   33.33 |    42.5 | ...24-625,628-629 
 ...active/control |   75.63 |    89.09 |      80 |   75.63 |                   
  ...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 |    6.89 |        0 |       0 |    6.89 | 46-188            
 ...ol/controllers |   42.27 |    64.66 |   48.64 |   42.27 |                   
  ...Controller.ts |   39.49 |      100 |      80 |   39.49 | 88-92,127-210     
  ...Controller.ts |       0 |        0 |       0 |       0 | 1-56              
  ...Controller.ts |   53.96 |    65.71 |   58.33 |   53.96 | ...37-642,644-649 
  ...Controller.ts |   14.06 |      100 |       0 |   14.06 | ...82-117,130-133 
  ...Controller.ts |   37.92 |    60.71 |   46.66 |   37.92 | ...41-653,662-691 
 .../control/types |       0 |        0 |       0 |       0 |                   
  serviceAPIs.ts   |       0 |        0 |       0 |       0 | 1                 
 ...Interactive/io |   98.07 |    94.07 |   95.23 |   98.07 |                   
  ...putAdapter.ts |   97.98 |    93.23 |   98.07 |   97.98 | ...1415,1431-1432 
  ...putAdapter.ts |      96 |    91.66 |   85.71 |      96 | 51-52             
  ...nputReader.ts |     100 |    94.73 |     100 |     100 | 67                
  ...putAdapter.ts |   98.38 |      100 |   90.47 |   98.38 | 84-85,125-126     
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/patches       |       0 |        0 |       0 |       0 |                   
  is-in-ci.ts      |       0 |        0 |       0 |       0 | 1-17              
 src/remoteInput   |   87.31 |    75.32 |   88.23 |   87.31 |                   
  ...utContext.tsx |     100 |      100 |     100 |     100 |                   
  ...putWatcher.ts |   88.01 |       76 |   93.33 |   88.01 | ...49-350,361-364 
  index.ts         |       0 |        0 |       0 |       0 | 1-8               
 src/runtime       |   99.61 |    95.04 |     100 |   99.61 |                   
  ...livery-ipc.ts |     100 |     90.9 |     100 |     100 | 94,106,134        
  ...l-delivery.ts |     100 |      100 |     100 |     100 |                   
  cpu-percent.ts   |     100 |      100 |     100 |     100 |                   
  ...erver-name.ts |     100 |      100 |     100 |     100 |                   
  ...-constants.ts |     100 |      100 |     100 |     100 |                   
  ...-summaries.ts |   86.66 |       50 |     100 |   86.66 | 11,19             
  ...ber-errors.ts |     100 |    95.32 |     100 |     100 | 53,93-94,172,192  
  ...ls-mapping.ts |     100 |      100 |     100 |     100 |                   
 src/serve         |   87.07 |    83.28 |   90.81 |   87.07 |                   
  ...tp-enabled.ts |     100 |      100 |     100 |     100 |                   
  ...ion-bridge.ts |     100 |      100 |     100 |     100 |                   
  auth.ts          |    93.4 |    92.95 |     100 |    93.4 | ...19-320,323-325 
  ...em-adapter.ts |     100 |      100 |     100 |     100 |                   
  capabilities.ts  |     100 |    97.95 |     100 |     100 | 650               
  ...cp-command.ts |     100 |      100 |     100 |     100 |                   
  ...horization.ts |   92.79 |    93.33 |    87.5 |   92.79 | 75-80,135-136     
  ...op-mcp-ipc.ts |   81.06 |    73.68 |   94.11 |   81.06 | ...37-242,267,289 
  ...nt-service.ts |   93.89 |    86.61 |     100 |   93.89 | ...66-468,475,477 
  ...-selection.ts |     100 |      100 |     100 |     100 |                   
  ...ings-store.ts |   85.85 |    91.78 |   95.83 |   85.85 | ...94-206,366-369 
  ...ebhook-ipc.ts |    98.5 |    86.66 |     100 |    98.5 | 47                
  ...iagnostics.ts |     100 |      100 |     100 |     100 |                   
  ...worker-env.ts |     100 |      100 |     100 |     100 |                   
  ...rker-group.ts |   87.27 |     85.2 |     100 |   87.27 | ...10,816-820,838 
  ...er-manager.ts |   89.39 |    83.88 |   93.33 |   89.39 | ...98,711,722-724 
  ...tartup-ipc.ts |   97.72 |    96.66 |     100 |   97.72 | 88-89             
  ...supervisor.ts |   92.41 |    84.44 |    97.1 |   92.41 | ...1460,1514-1518 
  ...e-grouping.ts |     100 |    94.11 |     100 |     100 | 69,132            
  core-runtime.ts  |     100 |      100 |     100 |     100 |                   
  ...ub-session.ts |   92.04 |    77.77 |     100 |   92.04 | ...36-445,470,508 
  daemon-logger.ts |    82.2 |    77.26 |   91.76 |    82.2 | ...1720,1747-1753 
  ...trics-ring.ts |     100 |      100 |     100 |     100 |                   
  ...s-provider.ts |   68.04 |    52.77 |     100 |   68.04 | ...44-249,282-290 
  daemon-status.ts |   98.37 |    90.06 |     100 |   98.37 | ...1041,1043-1044 
  debug-mode.ts    |     100 |      100 |     100 |     100 |                   
  demo.ts          |     100 |      100 |     100 |     100 |                   
  env-snapshot.ts  |   93.37 |    85.18 |     100 |   93.37 | 114-117,195-202   
  ...-scheduler.ts |   87.34 |    83.87 |     100 |   87.34 | 33-36,48-50,79-81 
  ...-path-argv.ts |     100 |      100 |     100 |     100 |                   
  ...h-settings.ts |   94.41 |    88.75 |     100 |   94.41 | ...24,702,718,728 
  fast-path.ts     |   90.49 |     80.7 |   95.45 |   90.49 | ...92-501,567-568 
  ...ration-sse.ts |   42.55 |    33.33 |     100 |   42.55 | 23-24,30,33-56    
  health-query.ts  |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-143             
  ...e-observer.ts |   89.89 |    83.24 |      96 |   89.89 | ...11-512,541-543 
  ...back-binds.ts |     100 |    88.88 |     100 |     100 | 32                
  ...-workspace.ts |    90.9 |    85.71 |     100 |    90.9 | ...27-128,139-140 
  ...iders-edit.ts |     100 |    82.14 |     100 |     100 | 58-60,65,81       
  ...ory-picker.ts |     100 |    86.95 |     100 |     100 | 36,66,92          
  ...sion-audit.ts |     100 |      100 |   93.33 |     100 |                   
  rate-limit.ts    |   92.77 |    88.42 |     100 |   92.77 | ...93-295,307-309 
  ...qwen-serve.ts |   82.69 |    79.33 |   74.06 |   82.69 | ...6745,6750-6751 
  ...tup-errors.ts |     100 |      100 |     100 |     100 |                   
  ...-keepalive.ts |   94.19 |    88.57 |     100 |   94.19 | ...26,530-531,571 
  ...-lifecycle.ts |     100 |      100 |     100 |     100 |                   
  server.ts        |   93.57 |    93.29 |   74.02 |   93.57 | ...2148,2169-2173 
  ...on-helpers.ts |     100 |      100 |     100 |     100 |                   
  ...t-event-id.ts |     100 |    95.23 |     100 |     100 | 12                
  ...-admission.ts |   98.71 |    89.65 |     100 |   98.71 | 68                
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...ion-limits.ts |     100 |      100 |     100 |     100 |                   
  ...t-sessions.ts |    93.3 |    76.83 |     100 |    93.3 | ...13,816,829-831 
  ...l-resolver.ts |   90.32 |    66.66 |     100 |   90.32 | 16,45-46          
  ...ell-static.ts |   91.07 |    86.66 |     100 |   91.07 | ...79-182,216-219 
  ...ace-agents.ts |   66.13 |    70.57 |   92.68 |   66.13 | ...2246,2256-2266 
  ...generation.ts |    95.4 |    82.35 |   66.66 |    95.4 | 55-56,78,92       
  ...-git-state.ts |     100 |    91.93 |    90.9 |     100 | 161,172,202,265   
  ...ace-inputs.ts |     100 |      100 |     100 |     100 |                   
  ...ace-memory.ts |      83 |    74.54 |     100 |      83 | ...30-537,597-604 
  ...ers-status.ts |   98.58 |       79 |     100 |   98.58 | 106,134,174,177   
  ...tion-store.ts |   89.67 |    88.27 |   92.59 |   89.67 | ...91-400,411-414 
  ...e-registry.ts |   93.89 |     87.5 |     100 |   93.89 | ...18-519,525-526 
  ...e-remember.ts |   98.23 |    92.51 |     100 |   98.23 | ...36,340-345,386 
  ...te-runtime.ts |   83.98 |    90.29 |     100 |   83.98 | ...48-156,216-237 
  ...me-storage.ts |     100 |      100 |     100 |     100 |                   
  ...management.ts |   72.63 |    72.72 |      96 |   72.63 | ...88-889,896-900 
  ...lls-status.ts |     100 |    95.45 |     100 |     100 | 152               
  ...reconciler.ts |    91.6 |     83.9 |     100 |    91.6 | ...70-272,305-306 
 ...serve/acp-http |   77.04 |    78.33 |   93.26 |   77.04 |                   
  ...r-registry.ts |   96.92 |    94.87 |     100 |   96.92 | 184-187           
  client-mcp-ws.ts |   54.85 |    58.62 |   72.72 |   54.85 | ...99-300,304-305 
  ...n-registry.ts |    98.2 |    88.62 |     100 |    98.2 | 1015,1041-1052    
  dispatch.ts      |   71.44 |    73.89 |   95.34 |   71.44 | ...4733,4781-4787 
  index.ts         |   81.93 |    79.92 |    90.9 |   81.93 | ...2291,2375-2376 
  json-rpc.ts      |     100 |    96.96 |     100 |     100 | 92                
  safe-ws-send.ts  |   52.94 |    71.42 |     100 |   52.94 | 33-42,47-55       
  sse-stream.ts    |   93.96 |    88.57 |   84.61 |   93.96 | ...57-159,161-163 
  ...ort-stream.ts |       0 |        0 |       0 |       0 | 1                 
  ws-stream.ts     |   91.86 |       80 |     100 |   91.86 | 45,50,96,100-103  
 src/serve/auth    |   86.86 |     79.7 |   93.87 |   86.86 |                   
  device-flow.ts   |   96.35 |    80.57 |   97.61 |   96.35 | ...1358,1453,1519 
  ...w-provider.ts |   44.24 |    74.07 |   71.42 |   44.24 | ...23-284,297,301 
 ...rve/cdp-tunnel |   85.73 |    73.17 |    97.5 |   85.73 |                   
  ...r-emulator.ts |   88.57 |    63.63 |     100 |   88.57 | ...72-175,194-195 
  ...verse-link.ts |      88 |    76.19 |     100 |      88 | ...28-329,420-423 
  ...l-registry.ts |     100 |      100 |     100 |     100 |                   
  cdp-ws.ts        |   76.28 |    61.29 |    87.5 |   76.28 | ...13-217,223-228 
 ...nel/acceptance |       0 |        0 |       0 |       0 |                   
  ...mcp-smoke.mjs |       0 |        0 |       0 |       0 | 1-119             
  ...cceptance.mjs |       0 |        0 |       0 |       0 | 1-473             
  real-tab.mjs     |       0 |        0 |       0 |       0 | 1-218             
 src/serve/fs      |    86.4 |    80.74 |     100 |    86.4 |                   
  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.8 |     100 |   77.64 | ...65,594-598,611 
  policy.ts        |   90.42 |    89.18 |     100 |   90.42 | 161-169           
  text-cursor.ts   |   88.23 |       90 |     100 |   88.23 | 74-77,92-95       
  ...ile-system.ts |   86.17 |    79.55 |     100 |   86.17 | ...2506,2516-2517 
 src/serve/routes  |   85.54 |    79.53 |   95.47 |   85.54 |                   
  a2ui-action.ts   |   96.84 |     88.5 |    87.5 |   96.84 | ...70-272,309-311 
  capabilities.ts  |     100 |      100 |     100 |     100 |                   
  ...nel-notify.ts |   85.22 |       88 |     100 |   85.22 | ...,83-87,103-104 
  ...l-webhooks.ts |   93.56 |    84.09 |     100 |   93.56 | ...42,292,332,334 
  daemon-status.ts |   85.45 |    83.33 |     100 |   85.45 | 98-105            
  goals.ts         |   98.92 |     90.9 |     100 |   98.92 | 146               
  health-demo.ts   |   94.73 |     86.2 |     100 |   94.73 | 62-66,154         
  permission.ts    |     100 |     92.3 |     100 |     100 | 50,98             
  ...uled-tasks.ts |   87.12 |    82.73 |   92.59 |   87.12 | ...1263,1306-1307 
  ...on-runtime.ts |     100 |    90.47 |     100 |     100 | 58,94             
  session.ts       |   85.17 |    81.72 |   95.16 |   85.17 | ...4633,4635-4636 
  sse-events.ts    |   84.45 |     87.5 |   77.77 |   84.45 | ...36,453-456,485 
  usage-stats.ts   |     100 |    95.45 |     100 |     100 | 118               
  ...space-auth.ts |   85.55 |    75.64 |     100 |   85.55 | ...21-326,331,345 
  ...el-control.ts |   86.26 |    78.94 |     100 |   86.26 | ...17-318,339-347 
  ...management.ts |   90.19 |    77.68 |     100 |   90.19 | ...47-448,467-468 
  ...d-contacts.ts |     100 |      100 |     100 |     100 |                   
  ...controller.ts |   83.09 |       79 |      90 |   83.09 | ...1032,1038,1041 
  ...extensions.ts |   87.23 |    72.76 |   94.11 |   87.23 | ...1826,1871-1872 
  ...-file-read.ts |      91 |    80.91 |     100 |      91 | ...20-621,624-625 
  ...file-write.ts |   84.44 |    64.51 |     100 |   84.44 | ...73-275,355-357 
  ...t-branches.ts |   75.43 |    66.66 |     100 |   75.43 | ...13-618,627-634 
  ...e-git-diff.ts |   97.32 |    90.56 |     100 |   97.32 | 161-162,189-191   
  ...ce-git-log.ts |     100 |    93.18 |     100 |     100 | 52,77,188         
  workspace-git.ts |   77.08 |    89.65 |     100 |   77.08 | 97-118            
  ...github-prs.ts |   88.26 |    63.46 |     100 |   88.26 | ...38-239,264-265 
  ...-lifecycle.ts |   95.23 |    75.75 |     100 |   95.23 | ...50-151,186-187 
  ...management.ts |   88.22 |    85.29 |     100 |   88.22 | ...1546,1566-1571 
  ...cp-control.ts |    73.2 |    67.54 |   85.71 |    73.2 | ...27-633,644-645 
  ...ace-models.ts |   95.53 |    89.74 |     100 |   95.53 | ...52-157,296-297 
  ...ermissions.ts |    77.9 |    72.41 |     100 |    77.9 | ...69-277,298-316 
  ...e-settings.ts |    74.9 |    70.31 |     100 |    74.9 | ...49-660,666-667 
  ...tup-github.ts |   77.97 |    70.58 |   84.21 |   77.97 | ...46-352,397-398 
  ...ace-skills.ts |   69.87 |    78.12 |     100 |   69.87 | ...59-284,290-324 
  ...ace-status.ts |   82.94 |     74.5 |     100 |   82.94 | ...84-486,490-491 
  ...pace-tools.ts |   75.94 |    69.69 |   66.66 |   75.94 | ...59-164,193-194 
  ...pace-trust.ts |   78.42 |    64.78 |      80 |   78.42 | ...31-336,344-345 
  ...pace-voice.ts |   91.33 |    80.92 |     100 |   91.33 | ...70-673,676-678 
 src/serve/server  |   90.71 |    89.17 |   96.55 |   90.71 |                   
  access-log.ts    |   98.68 |     97.1 |     100 |   98.68 | 115,186           
  ...er-helpers.ts |   63.82 |    77.96 |   81.81 |   63.82 | ...16,330,332-347 
  ...w-registry.ts |    98.8 |    81.81 |     100 |    98.8 | 107               
  ...r-handlers.ts |   97.29 |       75 |     100 |   97.29 | 17                
  ...r-response.ts |   85.66 |    76.83 |     100 |   85.66 | ...02,719,782-791 
  fs-factory.ts    |     100 |    92.59 |     100 |     100 | 34,42,103,159     
  ...branch-ops.ts |     100 |      100 |     100 |     100 |                   
  ...t-deadline.ts |     100 |      100 |     100 |     100 |                   
  ...iter-setup.ts |      65 |    73.33 |   33.33 |      65 | 30-35,38-43,47-48 
  ...st-helpers.ts |   95.11 |    95.19 |     100 |   95.11 | ...65-167,422-427 
  self-origin.ts   |   76.19 |       80 |     100 |   76.19 | 45-54             
  ...e-features.ts |   94.81 |    90.32 |     100 |   94.81 | 175-181           
  ...on-archive.ts |   89.55 |    87.78 |   97.14 |   89.55 | ...32-836,888-889 
  ...ion-export.ts |     100 |    94.44 |     100 |     100 | 64                
  session-list.ts  |   93.55 |    91.01 |     100 |   93.55 | ...79,681-687,827 
  telemetry.ts     |   99.02 |    97.44 |     100 |   99.02 | ...25,639,781-783 
 src/serve/voice   |   83.35 |    92.22 |   90.47 |   83.35 |                   
  ...ice-config.ts |   84.61 |       30 |     100 |   84.61 | 90-99,103-104     
  voice-ws.ts      |   77.16 |    94.73 |   83.33 |   77.16 | ...68,483,521-523 
  ...oordinator.ts |     100 |    98.21 |     100 |     100 | 176               
 ...kspace-service |   89.11 |    86.15 |   90.69 |   89.11 |                   
  index.ts         |   88.66 |    85.77 |   89.47 |   88.66 | ...1286-1290,1293 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/services      |   92.31 |    88.44 |   97.84 |   92.31 |                   
  ...mandLoader.ts |     100 |    88.88 |     100 |     100 | 105-118           
  ...killLoader.ts |   97.19 |    85.29 |     100 |   97.19 | 142,153-154       
  ...andService.ts |   98.73 |      100 |     100 |   98.73 | 107               
  ...mandLoader.ts |   86.83 |    83.87 |     100 |   86.83 | ...30-335,340-345 
  ...omptLoader.ts |   79.55 |    88.29 |   83.33 |   79.55 | ...48,178,245-246 
  ...mandLoader.ts |   97.77 |    92.15 |     100 |   97.77 | 176,183-184       
  ...nd-factory.ts |   91.42 |    91.66 |     100 |   91.42 | 128,137-144       
  ...ation-tool.ts |     100 |    95.45 |     100 |     100 | 125               
  ...ndMetadata.ts |   98.23 |    96.72 |     100 |   98.23 | 83,87             
  commandUtils.ts  |      96 |     90.9 |     100 |      96 | 48                
  ...and-parser.ts |   90.69 |    85.71 |     100 |   90.69 | 63-66             
  ...ionService.ts |     100 |      100 |     100 |     100 |                   
  prompt-stash.ts  |   96.66 |    92.85 |     100 |   96.66 | 34-35             
  ...tree-lease.ts |   88.29 |    86.48 |     100 |   88.29 | ...91-196,229-230 
  ...low-loader.ts |     100 |    96.15 |     100 |     100 | 88                
  setup-github.ts  |    90.8 |    80.95 |     100 |    90.8 | ...49-450,457-458 
  ...-args-file.ts |   93.93 |    91.66 |    87.5 |   93.93 | 208-210,224-230   
  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 |   90.37 |    87.87 |     100 |   90.37 | ...80,287,352-357 
  ...e-settings.ts |     100 |    95.23 |     100 |     100 | 19                
  ...ranscriber.ts |   90.46 |    82.19 |      96 |   90.46 | ...66-668,671-673 
 ...rvices/insight |     100 |      100 |     100 |     100 |                   
  dates.ts         |     100 |      100 |     100 |     100 |                   
 ...ght/generators |   88.91 |    86.29 |   96.15 |   88.91 |                   
  DataProcessor.ts |   88.28 |    86.24 |   94.73 |   88.28 | ...1352,1356-1363 
  ...tGenerator.ts |   98.24 |    85.71 |     100 |   98.24 | 47                
  ...teRenderer.ts |     100 |      100 |     100 |     100 |                   
 .../insight/types |       0 |       50 |      50 |       0 |                   
  ...sightTypes.ts |       0 |        0 |       0 |       0 |                   
  ...sightTypes.ts |       0 |        0 |       0 |       0 | 1                 
 ...mpt-processors |   97.27 |    94.04 |     100 |   97.27 |                   
  ...tProcessor.ts |     100 |      100 |     100 |     100 |                   
  ...eProcessor.ts |   94.52 |    84.21 |     100 |   94.52 | 46-47,93-94       
  ...tionParser.ts |     100 |      100 |     100 |     100 |                   
  ...lProcessor.ts |   97.41 |    95.65 |     100 |   97.41 | 95-98             
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/services/tips |   97.27 |    84.61 |     100 |   97.27 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  tipHistory.ts    |   92.59 |       70 |     100 |   92.59 | ...24,146,153,162 
  tipRegistry.ts   |     100 |      100 |     100 |     100 |                   
  tipScheduler.ts  |     100 |    91.66 |     100 |     100 | 55                
 src/startup       |   88.99 |    83.47 |    90.9 |   88.99 |                   
  ...p-prefetch.ts |   98.09 |    94.23 |    87.5 |   98.09 | 50,209,225-226    
  ...reeStartup.ts |   80.53 |     74.6 |     100 |   80.53 | ...94,403,409-412 
 src/test-utils    |   93.26 |       75 |   83.33 |   93.26 |                   
  ci-env.ts        |      88 |     62.5 |     100 |      88 | 22-23,28          
  ...omMatchers.ts |   69.69 |       50 |      50 |   69.69 | 32-35,37-39,45-47 
  ...andContext.ts |     100 |      100 |     100 |     100 |                   
  render.tsx       |     100 |      100 |     100 |     100 |                   
 src/ui            |    72.7 |     75.2 |    65.9 |    72.7 |                   
  App.tsx          |   33.33 |       75 |   33.33 |   33.33 | 32-86             
  AppContainer.tsx |   73.91 |    72.08 |   70.58 |   73.91 | ...4096,4212-4218 
  ...tionNudge.tsx |    9.58 |      100 |       0 |    9.58 | 24-94             
  ...ackDialog.tsx |    30.3 |      100 |       0 |    30.3 | 26-76             
  ...tionNudge.tsx |    7.69 |      100 |       0 |    7.69 | 25-103            
  colors.ts        |      60 |      100 |   35.29 |      60 | ...52,54-55,60-61 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  keyMatchers.ts   |   95.91 |    97.14 |     100 |   95.91 | 25-26             
  ...tic-colors.ts |     100 |      100 |     100 |     100 |                   
  ...ractiveUI.tsx |   68.12 |    64.86 |   33.33 |   68.12 | ...98,321,341-346 
  ...inePresets.ts |   96.27 |    83.87 |     100 |   96.27 | ...97,402,410-412 
  textConstants.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/ui/auth       |   58.53 |    66.18 |   51.06 |   58.53 |                   
  AuthDialog.tsx   |   59.01 |     42.1 |   16.66 |   59.01 | ...25,332-354,358 
  ...nProgress.tsx |       0 |        0 |       0 |       0 | 1-64              
  ...etupSteps.tsx |   60.21 |    70.73 |   57.69 |   60.21 | ...90,794,803,806 
  useAuth.ts       |    94.6 |    73.52 |     100 |    94.6 | ...21-222,241-247 
  ...rSetupFlow.ts |   43.18 |    33.33 |      50 |   43.18 | ...78-399,416-459 
 src/ui/commands   |   81.27 |    82.88 |   88.88 |   81.27 |                   
  aboutCommand.ts  |     100 |      100 |     100 |     100 |                   
  agentsCommand.ts |   83.78 |      100 |      60 |   83.78 | 30-32,42-44       
  ...odeCommand.ts |    93.1 |    95.23 |     100 |    93.1 | 77-82             
  arenaCommand.ts  |   63.89 |    65.71 |   65.21 |   63.89 | ...01-606,691-699 
  authCommand.ts   |     100 |      100 |     100 |     100 |                   
  branchCommand.ts |     100 |      100 |     100 |     100 |                   
  btwCommand.ts    |   94.32 |    81.25 |     100 |   94.32 | 35-36,114-119     
  bugCommand.ts    |     100 |    77.77 |     100 |     100 | 27,61             
  cdCommand.ts     |    92.3 |    82.75 |     100 |    92.3 | ...,94-99,178,187 
  clearCommand.ts  |    80.9 |    70.83 |     100 |    80.9 | ...24-125,133-142 
  ...essCommand.ts |   68.06 |    54.05 |      75 |   68.06 | ...96-197,211-214 
  ...astCommand.ts |   84.17 |       75 |     100 |   84.17 | ...,91-97,125-130 
  ...ig-command.ts |   93.12 |    88.42 |     100 |   93.12 | ...07-315,321-323 
  ...extCommand.ts |   68.28 |    70.14 |   84.61 |   68.28 | ...66-599,610-611 
  copyCommand.ts   |    98.7 |    96.29 |     100 |    98.7 | 66-67,172,272,323 
  ...or-command.ts |   85.95 |    80.55 |   88.88 |   85.95 | ...68-274,298-309 
  deleteCommand.ts |     100 |      100 |     100 |     100 |                   
  diffCommand.ts   |     100 |    87.87 |     100 |     100 | ...63,231-232,245 
  ...ryCommand.tsx |   81.64 |    87.67 |    90.9 |   81.64 | ...73-278,325-332 
  docsCommand.ts   |     100 |     90.9 |     100 |     100 | 25                
  doctorCommand.ts |   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   |   79.86 |    85.71 |   66.66 |   79.86 | ...63-168,277-280 
  helpCommand.ts   |     100 |      100 |     100 |     100 |                   
  ...oryCommand.ts |     100 |      100 |     100 |     100 |                   
  hooksCommand.ts  |   81.13 |    65.71 |   85.71 |   81.13 | ...,86-93,131-132 
  ideCommand.ts    |   60.75 |    64.28 |   41.17 |   60.75 | ...05-306,310-324 
  ...figCommand.ts |   52.83 |    81.25 |      70 |   52.83 | ...74-319,321-330 
  initCommand.ts   |   91.86 |       80 |     100 |   91.86 | 48,83-88          
  ...ghtCommand.ts |   77.87 |    71.42 |     100 |   77.87 | ...44-245,250-272 
  ...ageCommand.ts |   93.45 |    89.06 |     100 |   93.45 | ...68-169,196-206 
  learn-command.ts |     100 |      100 |     100 |     100 |                   
  lspCommand.ts    |     100 |    86.95 |     100 |     100 | 31,101-102        
  mcpCommand.ts    |     100 |      100 |     100 |     100 |                   
  memoryCommand.ts |     100 |      100 |     100 |     100 |                   
  modelCommand.ts  |   84.78 |    82.47 |     100 |   84.78 | ...1071,1105-1110 
  ...onsCommand.ts |     100 |      100 |     100 |     100 |                   
  planCommand.ts   |   78.82 |    76.92 |     100 |   78.82 | 30-35,51-56,68-73 
  quitCommand.ts   |     100 |      100 |     100 |     100 |                   
  recapCommand.ts  |   21.81 |      100 |      50 |   21.81 | 24-73             
  ...ns-command.ts |   98.83 |    81.81 |     100 |   98.83 | 100               
  ...berCommand.ts |     100 |     87.5 |     100 |     100 | 46                
  renameCommand.ts |   89.06 |    88.37 |     100 |   89.06 | ...72-176,202-209 
  ...oreCommand.ts |    90.9 |    86.04 |     100 |    90.9 | ...41-146,176-177 
  resumeCommand.ts |     100 |      100 |     100 |     100 |                   
  rewindCommand.ts |   81.25 |      100 |      50 |   81.25 | 20-22             
  ...ngsCommand.ts |     100 |      100 |     100 |     100 |                   
  ...hubCommand.ts |   89.47 |       75 |      80 |   89.47 | 54-59             
  skillsCommand.ts |   78.82 |    81.81 |     100 |   78.82 | 37-52,78,97       
  statsCommand.ts  |   90.65 |    76.73 |     100 |   90.65 | ...30-733,825-832 
  ...ineCommand.ts |     100 |      100 |     100 |     100 |                   
  ...aryCommand.ts |    6.43 |      100 |      50 |    6.43 | 31-330            
  tasksCommand.ts  |   77.22 |    72.13 |     100 |   77.22 | ...46-150,172-177 
  ...tupCommand.ts |     100 |      100 |     100 |     100 |                   
  themeCommand.ts  |     100 |      100 |     100 |     100 |                   
  toolsCommand.ts  |     100 |      100 |     100 |     100 |                   
  trustCommand.ts  |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...te-command.ts |     100 |    94.11 |     100 |     100 | 74,148            
  vimCommand.ts    |   54.54 |      100 |      50 |   54.54 | 19-29             
  voice-command.ts |   93.57 |       88 |     100 |   93.57 | 35,97-102         
  ...owsCommand.ts |   91.86 |    78.87 |   66.66 |   91.86 | ...60-161,170-175 
 src/ui/components |   71.12 |    78.59 |   78.81 |   71.12 |                   
  AboutBox.tsx     |     100 |      100 |     100 |     100 |                   
  AnsiOutput.tsx   |   65.57 |      100 |      50 |   65.57 | 69-90             
  ApiKeyInput.tsx  |       0 |        0 |       0 |       0 | 1-97              
  AppHeader.tsx    |    88.7 |       75 |     100 |    88.7 | 36,38-43,45       
  ...odeDialog.tsx |   87.24 |    72.22 |   33.33 |   87.24 | ...85,233-238,245 
  AsciiArt.ts      |     100 |      100 |     100 |     100 |                   
  ...Indicator.tsx |   95.65 |    66.66 |     100 |   95.65 | 27,52             
  ...TextInput.tsx |   88.65 |    90.41 |     100 |   88.65 | ...84-286,300-302 
  Composer.tsx     |   94.49 |    66.66 |     100 |   94.49 | ...-72,84,139,153 
  ...entPrompt.tsx |     100 |      100 |     100 |     100 |                   
  ...ryDisplay.tsx |   75.89 |    62.06 |     100 |   75.89 | ...,88,93-108,113 
  ...geDisplay.tsx |   68.42 |    57.14 |     100 |   68.42 | 16-17,31-32,42-50 
  CronPill.tsx     |     100 |    93.75 |     100 |     100 | 19                
  ...ification.tsx |      84 |       60 |     100 |      84 | 23-24,40-42       
  ...gProfiler.tsx |       0 |        0 |       0 |       0 | 1-36              
  ...ogManager.tsx |       0 |        0 |       0 |       0 | 1-598             
  DiffDialog.tsx   |    53.5 |     37.5 |   69.23 |    53.5 | ...32-737,747-760 
  ...ngsDialog.tsx |       0 |        0 |       0 |       0 | 1-195             
  EffortDialog.tsx |   97.36 |      100 |     100 |   97.36 | 55-56             
  ExitWarning.tsx  |     100 |      100 |     100 |     100 |                   
  ...hProgress.tsx |    87.8 |    33.33 |     100 |    87.8 | 28-31,56          
  ...ustDialog.tsx |     100 |      100 |     100 |     100 |                   
  Footer.tsx       |   74.09 |     61.4 |      50 |   74.09 | ...55-260,278-282 
  ...ngSpinner.tsx |   68.42 |    85.71 |      50 |   68.42 | 35-52,73,80-81    
  GoalPill.tsx     |   93.51 |    81.81 |     100 |   93.51 | 37-38,106-109,123 
  Header.tsx       |   98.65 |    94.73 |     100 |   98.65 | 173,175           
  Help.tsx         |   98.33 |       90 |     100 |   98.33 | ...25,382,448-449 
  ...emDisplay.tsx |   79.06 |    66.33 |     100 |   79.06 | ...04,507,510-516 
  ...ngeDialog.tsx |     100 |      100 |     100 |     100 |                   
  InputPrompt.tsx  |    83.1 |    81.95 |      80 |    83.1 | ...2199,2225,2299 
  ...Shortcuts.tsx |     100 |       88 |     100 |     100 | 98,119            
  ...Indicator.tsx |   98.18 |    97.82 |     100 |   98.18 | 161-162           
  ...firmation.tsx |   91.42 |      100 |      50 |   91.42 | 26-31             
  MainContent.tsx  |    95.9 |    92.53 |      50 |    95.9 | ...99,445-449,452 
  MemoryDialog.tsx |   86.59 |    80.15 |     100 |   86.59 | ...34-435,485,553 
  ...geDisplay.tsx |       0 |        0 |       0 |       0 | 1-41              
  ModelDialog.tsx  |   81.95 |    71.27 |     100 |   81.95 | ...1045,1050-1066 
  ...tsDisplay.tsx |     100 |    97.22 |     100 |     100 | 270               
  ...fications.tsx |       0 |        0 |       0 |       0 | 1-56              
  ...onsDialog.tsx |       0 |        0 |       0 |       0 | 1-1004            
  ...ryDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...icePrompt.tsx |   92.64 |    85.71 |     100 |   92.64 | 102-106,134-139   
  PrepareLabel.tsx |   91.66 |    77.27 |     100 |   91.66 | 73-75,77-79,110   
  ...atePrompt.tsx |       0 |        0 |       0 |       0 | 1-134             
  ...geDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...ngDisplay.tsx |       0 |        0 |       0 |       0 | 1-39              
  ...hProgress.tsx |   85.25 |    88.46 |     100 |   85.25 | 121-147           
  ...dSelector.tsx |   92.79 |    82.65 |     100 |   92.79 | ...19-323,354-370 
  ...ionPicker.tsx |   83.66 |    72.13 |     100 |   83.66 | ...96,402,444-466 
  ...onPreview.tsx |   93.58 |    83.78 |     100 |   93.58 | ...,70-71,195-197 
  ...ryDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...putPrompt.tsx |   72.56 |       80 |      40 |   72.56 | ...06-109,114-117 
  ...tedDialog.tsx |     100 |      100 |     100 |     100 |                   
  ...ngsDialog.tsx |   71.49 |    73.89 |   69.23 |   71.49 | ...1244,1250-1251 
  ...ionDialog.tsx |    92.3 |    96.15 |   33.33 |    92.3 | 60-63,68-75,164   
  ...putPrompt.tsx |    15.9 |      100 |       0 |    15.9 | 20-63             
  ...Indicator.tsx |   57.14 |      100 |       0 |   57.14 | 12-15             
  ...MoreLines.tsx |       0 |        0 |       0 |       0 | 1-40              
  ...iewDialog.tsx |   97.77 |    87.67 |     100 |   97.77 | ...97,305-307,324 
  ...tsDisplay.tsx |   95.86 |       75 |     100 |   95.86 | 67-71             
  ...ionPicker.tsx |       0 |        0 |       0 |       0 | 1-172             
  ...tivityTab.tsx |    3.94 |      100 |       0 |    3.94 | 27-275            
  StatsDialog.tsx  |    8.64 |      100 |       0 |    8.64 | ...76-111,130-322 
  StatsDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...ciencyTab.tsx |    78.9 |    56.52 |     100 |    78.9 | ...26,213,262-288 
  ...atmapView.tsx |    8.98 |      100 |       0 |    8.98 | 20-107            
  ...essionTab.tsx |      80 |    66.66 |     100 |      80 | ...70-277,283-300 
  ...ineDialog.tsx |    93.5 |    85.18 |     100 |    93.5 | ...05,267,287-289 
  ...yTodoList.tsx |   96.36 |    88.23 |     100 |   96.36 | 138-141           
  ...nsDisplay.tsx |   92.97 |    83.87 |     100 |   92.97 | ...45,248,275-277 
  ...inalImage.tsx |     100 |     90.9 |     100 |     100 | 75,93             
  ThemeDialog.tsx  |   89.95 |    46.15 |      75 |   89.95 | ...71-173,243-245 
  Tips.tsx         |   93.54 |       75 |     100 |   93.54 | 39-40             
  TodoDisplay.tsx  |     100 |      100 |     100 |     100 |                   
  ...tsDisplay.tsx |     100 |     87.5 |     100 |     100 | 31-32             
  TrustDialog.tsx  |     100 |    83.33 |     100 |     100 | 72-87             
  ...ification.tsx |   36.36 |      100 |       0 |   36.36 | 15-22             
  ...Indicator.tsx |    92.5 |     87.5 |     100 |    92.5 | 50-53             
  ...ackDialog.tsx |       0 |        0 |       0 |       0 | 1-134             
  ...xitDialog.tsx |   80.36 |    43.47 |      60 |   80.36 | ...24-238,248-251 
  ...odeVisuals.ts |   97.22 |    85.71 |     100 |   97.22 | 25                
  ...s-helpers.tsx |   66.25 |    81.25 |      50 |   66.25 | 25-32,46-53,62-72 
 ...nts/agent-view |   55.05 |    69.09 |      50 |   55.05 |                   
  ...atContent.tsx |    9.09 |      100 |       0 |    9.09 | 54-275,281-283    
  ...tChatView.tsx |   21.05 |      100 |       0 |   21.05 | 21-39             
  ...tComposer.tsx |   69.48 |    33.33 |   66.66 |   69.48 | ...51,269,277-279 
  AgentFooter.tsx  |   15.38 |      100 |       0 |   15.38 | 28-65             
  AgentHeader.tsx  |   15.38 |      100 |       0 |   15.38 | 27-64             
  AgentTabBar.tsx  |    87.9 |    63.88 |     100 |    87.9 | ...88,110-118,136 
  ...oryAdapter.ts |     100 |    91.83 |     100 |     100 | 103,109-110,138   
  index.ts         |       0 |        0 |       0 |       0 | 1-12              
 ...mponents/arena |    42.3 |    68.69 |   73.68 |    42.3 |                   
  ArenaCards.tsx   |   73.06 |    71.79 |   85.71 |   73.06 | ...83-185,321-326 
  ...ectDialog.tsx |   83.48 |    69.86 |   88.88 |   83.48 | ...88-392,409-410 
  ...artDialog.tsx |       0 |        0 |       0 |       0 | 1-166             
  ...tusDialog.tsx |       0 |        0 |       0 |       0 | 1-288             
  ...topDialog.tsx |       0 |        0 |       0 |       0 | 1-213             
 ...ackground-view |   82.95 |    81.71 |   92.72 |   82.95 |                   
  ...sksDialog.tsx |   78.73 |    77.65 |   84.61 |   78.73 | ...1809,1833-1839 
  ...TasksPill.tsx |   67.74 |    86.66 |     100 |   67.74 | ...04-124,132-140 
  ...gentPanel.tsx |   97.08 |    86.31 |     100 |   97.08 | 132,442-446,520   
  agent-forest.ts  |    99.2 |    93.93 |     100 |    99.2 | 258               
  ...Visibility.ts |     100 |      100 |     100 |     100 |                   
  ...e-overlay.tsx |    88.2 |    76.47 |     100 |    88.2 | ...36-138,140-142 
 ...nts/extensions |   84.32 |    76.78 |   83.33 |   84.32 |                   
  ...gerDialog.tsx |   82.15 |    76.08 |     100 |   82.15 | ...91-198,258,260 
  TabBar.tsx       |   97.29 |    88.88 |     100 |   97.29 | 33                
  index.ts         |       0 |        0 |       0 |       0 | 1-12              
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...tensions/steps |   46.26 |       85 |   58.82 |   46.26 |                   
  ...ctionStep.tsx |   95.12 |    92.85 |   85.71 |   95.12 | 84-86,89          
  ...etailStep.tsx |       0 |        0 |       0 |       0 | 1-145             
  ...nListStep.tsx |   75.26 |    88.37 |   66.66 |   75.26 | ...53,174,203-209 
  ...electStep.tsx |       0 |        0 |       0 |       0 | 1-83              
  ...nfirmStep.tsx |   16.32 |      100 |       0 |   16.32 | 28-74             
  index.ts         |       0 |        0 |       0 |       0 | 1-11              
 ...xtensions/tabs |   71.92 |    68.21 |   70.83 |   71.92 |                   
  DiscoverTab.tsx  |   68.22 |    67.66 |   55.55 |   68.22 | ...93,656-660,664 
  InstalledTab.tsx |   75.49 |    67.44 |   83.33 |   75.49 | ...77,782-783,820 
  SourcesTab.tsx   |   71.67 |    70.47 |   77.77 |   71.67 | ...28,547,621-633 
 ...tensions/views |   50.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 |   87.11 |    81.37 |   91.89 |   87.11 |                   
  ...rListBody.tsx |   95.29 |    85.18 |     100 |   95.29 | 95-98             
  ...etailStep.tsx |   75.32 |    71.42 |      60 |   75.32 | ...56-169,173-186 
  ...etailStep.tsx |     100 |      100 |     100 |     100 |                   
  ...rListStep.tsx |     100 |      100 |     100 |     100 |                   
  ...entHeader.tsx |     100 |    85.71 |     100 |     100 | 47                
  ...rListStep.tsx |     100 |      100 |     100 |     100 |                   
  ...etailStep.tsx |     100 |      100 |     100 |     100 |                   
  ...abledStep.tsx |     100 |      100 |     100 |     100 |                   
  ...sListStep.tsx |     100 |      100 |     100 |     100 |                   
  ...entDialog.tsx |   72.29 |    70.49 |     100 |   72.29 | ...51,563-568,572 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-13              
  ...erGrouping.ts |     100 |      100 |     100 |     100 |                   
  sourceLabels.ts  |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...components/mcp |   40.04 |    61.53 |   70.58 |   40.04 |                   
  ...ealthPill.tsx |   68.42 |    85.71 |     100 |   68.42 | 40-46             
  ...entDialog.tsx |   32.09 |    26.19 |      40 |   32.09 | ...12,914,927-933 
  ...valDialog.tsx |   15.06 |      100 |       0 |   15.06 | 40-109            
  constants.ts     |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-35              
  types.ts         |     100 |      100 |     100 |     100 |                   
  utils.ts         |      97 |       95 |     100 |      97 | 24,113-114        
 ...ents/mcp/steps |   53.94 |    73.51 |   57.14 |   53.94 |                   
  ...icateStep.tsx |    5.65 |      100 |       0 |    5.65 | 40-66,69-308      
  ...electStep.tsx |   10.95 |      100 |       0 |   10.95 | 16-88             
  ...etailStep.tsx |     100 |      100 |     100 |     100 |                   
  ...eListStep.tsx |   99.09 |    97.36 |     100 |   99.09 | 71                
  ...etailStep.tsx |   62.83 |       60 |   33.33 |   62.83 | ...87-296,307-332 
  ...rListStep.tsx |   88.53 |    81.25 |     100 |   88.53 | ...64,170,175-180 
  ...etailStep.tsx |    10.3 |      100 |       0 |    10.3 | ...1,67-79,82-140 
  ToolListStep.tsx |   69.29 |       50 |     100 |   69.29 | ...23,126,135-144 
 ...nents/messages |   89.93 |    86.42 |   85.29 |   89.93 |                   
  ...ionDialog.tsx |   89.23 |     84.9 |   81.81 |   89.23 | ...75,593,611-613 
  BtwMessage.tsx   |     100 |      100 |     100 |     100 |                   
  ...upDisplay.tsx |     100 |    94.73 |     100 |     100 | ...43,289,402,432 
  ...onMessage.tsx |   92.06 |    82.35 |     100 |   92.06 | 58-60,62,64       
  ...nMessages.tsx |   93.46 |      100 |   76.92 |   93.46 | ...90-292,295-298 
  DiffRenderer.tsx |   93.17 |    86.02 |     100 |   93.17 | ...07,235-236,302 
  ...tsDisplay.tsx |   97.08 |    77.77 |     100 |   97.08 | 95,97,106         
  ...usMessage.tsx |   81.73 |     65.9 |      75 |   81.73 | ...10-214,222,245 
  ...tsDisplay.tsx |   95.52 |    88.31 |     100 |   95.52 | ...40,142,175-180 
  ...ssMessage.tsx |    12.5 |      100 |       0 |    12.5 | 18-59             
  ...edMessage.tsx |   21.05 |      100 |       0 |   21.05 | 23-39             
  ...sMessages.tsx |   59.04 |       50 |    37.5 |   59.04 | ...21-126,147-159 
  ...ryMessage.tsx |   13.63 |      100 |       0 |   13.63 | 23-64             
  ...onMessage.tsx |   91.38 |    81.02 |     100 |   91.38 | ...33-635,642-644 
  ...upMessage.tsx |   98.32 |    95.16 |     100 |   98.32 | 184-187,414       
  ToolMessage.tsx  |   92.62 |    85.29 |   93.33 |   92.62 | ...-982,1009-1011 
 ...ponents/shared |   85.79 |    81.94 |   94.11 |   85.79 |                   
  ...ctionList.tsx |     100 |      100 |      75 |     100 |                   
  ...tonSelect.tsx |     100 |      100 |     100 |     100 |                   
  EnumSelector.tsx |     100 |    96.42 |     100 |     100 | 58                
  ...rBoundary.tsx |     100 |      100 |     100 |     100 |                   
  MaxSizedBox.tsx  |   84.71 |    86.86 |      90 |   84.71 | ...67-568,685-686 
  MultiSelect.tsx  |   93.58 |       75 |     100 |   93.58 | ...43,199-201,211 
  ...tonSelect.tsx |     100 |      100 |     100 |     100 |                   
  ...ontroller.tsx |     100 |    83.33 |     100 |     100 | 73,93-95          
  ...eSelector.tsx |     100 |       60 |     100 |     100 | 40-45             
  ...lableList.tsx |   81.48 |    84.84 |     100 |   81.48 | 46-66,73-76       
  StaticRender.tsx |   72.72 |      100 |     100 |   72.72 | 31-33             
  TextInput.tsx    |    80.8 |    67.24 |      80 |    80.8 | ...36-240,252-258 
  ...ontroller.tsx |     100 |    81.81 |     100 |     100 | 59-62             
  ...apsedTime.tsx |     100 |      100 |     100 |     100 |                   
  ...Indicator.tsx |     100 |      100 |     100 |     100 |                   
  ...lizedList.tsx |   88.51 |    83.75 |   81.81 |   88.51 | ...51-779,792,887 
  text-buffer.ts   |   85.98 |    81.81 |   97.91 |   85.98 | ...2664,2762-2763 
  ...er-actions.ts |   73.93 |    67.22 |     100 |   73.93 | ...32-733,934-936 
 ...ponents/skills |       0 |        0 |       0 |       0 |                   
  ...gerDialog.tsx |       0 |        0 |       0 |       0 | 1-681             
 ...ents/subagents |       0 |        0 |       0 |       0 |                   
  constants.ts     |       0 |        0 |       0 |       0 | 1-71              
  index.ts         |       0 |        0 |       0 |       0 | 1-11              
  reducers.tsx     |       0 |        0 |       0 |       0 | 1-190             
  types.ts         |       0 |        0 |       0 |       0 | 1-125             
  utils.ts         |       0 |        0 |       0 |       0 | 1-102             
 ...bagents/create |       0 |        0 |       0 |       0 |                   
  ...ionWizard.tsx |       0 |        0 |       0 |       0 | 1-299             
  ...rSelector.tsx |       0 |        0 |       0 |       0 | 1-85              
  ...onSummary.tsx |       0 |        0 |       0 |       0 | 1-331             
  ...tionInput.tsx |       0 |        0 |       0 |       0 | 1-177             
  ...dSelector.tsx |       0 |        0 |       0 |       0 | 1-63              
  ...nSelector.tsx |       0 |        0 |       0 |       0 | 1-58              
  ...EntryStep.tsx |       0 |        0 |       0 |       0 | 1-78              
  ToolSelector.tsx |       0 |        0 |       0 |       0 | 1-253             
 ...bagents/manage |   14.14 |    53.19 |    37.5 |   14.14 |                   
  ...ctionStep.tsx |       0 |        0 |       0 |       0 | 1-103             
  ...eleteStep.tsx |       0 |        0 |       0 |       0 | 1-62              
  ...tEditStep.tsx |       0 |        0 |       0 |       0 | 1-124             
  ...ctionStep.tsx |   35.61 |    59.52 |     100 |   35.61 | ...21-433,438-440 
  ...iewerStep.tsx |       0 |        0 |       0 |       0 | 1-73              
  ...gerDialog.tsx |       0 |        0 |       0 |       0 | 1-341             
 ...mponents/views |   69.81 |    72.64 |   61.11 |   69.81 |                   
  ContextUsage.tsx |   70.88 |    63.88 |      80 |   70.88 | ...20-426,463-557 
  DoctorReport.tsx |     9.8 |      100 |       0 |     9.8 | 25-54,57-131      
  ...sionsList.tsx |   88.05 |       75 |     100 |   88.05 | 70-77             
  McpStatus.tsx    |   92.01 |     73.8 |     100 |   92.01 | ...36,175-177,262 
  SkillsList.tsx   |   20.51 |      100 |       0 |   20.51 | 17-20,27-57       
  ToolsList.tsx    |     100 |      100 |     100 |     100 |                   
 src/ui/contexts   |   83.96 |    81.62 |    86.3 |   83.96 |                   
  ...ewContext.tsx |   64.83 |    88.88 |      50 |   64.83 | ...16-219,225-235 
  AppContext.tsx   |      80 |       50 |     100 |      80 | 19-20             
  ...ewContext.tsx |   92.45 |    62.79 |      50 |   92.45 | ...69-270,272-276 
  ...igContext.tsx |   81.81 |       50 |     100 |   81.81 | 15-16             
  ...ssContext.tsx |   85.65 |    84.85 |     100 |   85.65 | ...1612-1614,1620 
  ...owContext.tsx |   91.07 |    81.81 |     100 |   91.07 | 47-48,60-62       
  ...deContext.tsx |     100 |      100 |      50 |     100 |                   
  ...onContext.tsx |   80.77 |       80 |    92.3 |   80.77 | ...31-434,443-446 
  ...gsContext.tsx |     100 |      100 |     100 |     100 |                   
  ...usContext.tsx |     100 |      100 |     100 |     100 |                   
  ...ngContext.tsx |   71.42 |       50 |     100 |   71.42 | 17-20             
  ...utContext.tsx |   85.71 |      100 |   66.66 |   85.71 | 13-14             
  ...edContext.tsx |     100 |      100 |      50 |     100 |                   
  ...nsContext.tsx |   88.88 |       50 |     100 |   88.88 | 156-157           
  ...teContext.tsx |   86.66 |       50 |     100 |   86.66 | 235-236           
  ...deContext.tsx |      80 |     87.5 |      75 |      80 | ...11-112,118-120 
  ...rtContext.tsx |     100 |      100 |     100 |     100 |                   
 src/ui/daemon     |   88.35 |    73.51 |   95.45 |   88.35 |                   
  ...ui-adapter.ts |   88.35 |    73.51 |   95.45 |   88.35 | ...74,792-793,879 
 src/ui/editors    |       0 |        0 |       0 |       0 |                   
  ...ngsManager.ts |       0 |        0 |       0 |       0 | 1-67              
 src/ui/hooks      |   84.86 |    82.59 |   87.75 |   84.86 |                   
  ...dProcessor.ts |   85.53 |    85.13 |     100 |   85.53 | ...-970,1017-1018 
  ...ention-ref.ts |   97.72 |       84 |     100 |   97.72 | 65                
  keyToAnsi.ts     |    3.92 |      100 |       0 |    3.92 | 19-77             
  ...esourceRef.ts |     100 |      100 |     100 |     100 |                   
  ...completion.ts |     100 |    95.45 |     100 |     100 | 95                
  ...ention-ref.ts |     100 |      100 |     100 |     100 |                   
  ...dProcessor.ts |   94.62 |    73.58 |     100 |   94.62 | ...86-287,292-293 
  ...dProcessor.ts |   85.63 |    68.16 |   81.81 |   85.63 | ...1452,1473-1477 
  ...rt-command.ts |     100 |      100 |     100 |     100 |                   
  ...sced-flush.ts |     100 |      100 |     100 |     100 |                   
  ...ng-enabled.ts |     100 |      100 |     100 |     100 |                   
  ...oice-input.ts |   92.36 |    81.95 |   66.66 |   92.36 | ...00,502-503,658 
  ...ke-repaint.ts |     100 |      100 |     100 |     100 |                   
  ...amingState.ts |   12.22 |      100 |       0 |   12.22 | 54-157            
  ...agerDialog.ts |   88.23 |      100 |     100 |   88.23 | 20,24             
  ...dScrollbar.ts |     100 |      100 |     100 |     100 |                   
  ...ationFrame.ts |      52 |    63.63 |     100 |      52 | ...59,67-70,76-87 
  ...odeCommand.ts |   58.82 |      100 |     100 |   58.82 | 28,33-48          
  ...enaCommand.ts |      85 |      100 |     100 |      85 | 23-24,29          
  ...aInProcess.ts |   27.92 |       80 |      25 |   27.92 | ...69-170,173-175 
  ...Completion.ts |   86.44 |    88.48 |     100 |   86.44 | ...14-515,525-541 
  ...ifications.ts |   87.82 |    96.77 |     100 |   87.82 | 138-152           
  ...tIndicator.ts |   88.28 |    81.57 |     100 |   88.28 | ...66,175,179-187 
  ...waySummary.ts |   96.26 |       75 |     100 |   96.26 | 126-128,170       
  ...ndTaskView.ts |   94.81 |    76.59 |     100 |   94.81 | 162-166,255,261   
  ...chedScroll.ts |     100 |      100 |     100 |     100 |                   
  ...ketedPaste.ts |    23.8 |      100 |       0 |    23.8 | 19-37             
  ...nchCommand.ts |   95.23 |    82.69 |     100 |   95.23 | ...53-154,277-280 
  ...ompletion.tsx |   97.09 |    87.09 |     100 |   97.09 | ...23-324,334-335 
  ...dMigration.ts |    92.1 |    88.88 |     100 |    92.1 | 42-44             
  useCompletion.ts |   96.29 |    90.56 |     100 |   96.29 | ...17-218,222-223 
  ...nitMessage.ts |     100 |      100 |     100 |     100 |                   
  ...extualTips.ts |   78.26 |       50 |     100 |   78.26 | ...2,75-79,96-104 
  ...eteCommand.ts |   89.52 |    90.69 |     100 |   89.52 | ...98-106,114-115 
  ...ialogClose.ts |   36.11 |       10 |     100 |   36.11 | ...89-195,202-207 
  useDiffData.ts   |       0 |        0 |       0 |       0 | 1-87              
  ...oublePress.ts |   53.12 |       75 |     100 |   53.12 | 33-35,41-54       
  ...orSettings.ts |     100 |      100 |     100 |     100 |                   
  ...Completion.ts |   99.12 |    97.67 |     100 |   99.12 | 182-183           
  ...ionUpdates.ts |   93.72 |    92.98 |     100 |   93.72 | ...87-291,314-320 
  ...agerDialog.ts |   88.88 |      100 |     100 |   88.88 | 21,25             
  ...backDialog.ts |    63.9 |    76.47 |   66.66 |    63.9 | ...66-168,190-191 
  useFocus.ts      |     100 |      100 |     100 |     100 |                   
  ...olderTrust.ts |     100 |    93.33 |     100 |     100 | 62                
  ...ggestions.tsx |   96.47 |    78.94 |     100 |   96.47 | 121,155-156       
  ...miniStream.ts |   83.08 |    80.25 |   74.35 |   83.08 | ...4907-4909,4911 
  ...BranchName.ts |     100 |    94.44 |     100 |     100 | 54                
  ...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 |   22.58 |      100 |      50 |   22.58 | 11-32,44-85       
  ...gIndicator.ts |     100 |    96.66 |     100 |     100 | 109               
  useLogger.ts     |      16 |      100 |       0 |      16 | 15-45             
  useMCPHealth.ts  |   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 |     97.4 |     100 |     100 | 175,262           
  ...delCommand.ts |     100 |       96 |     100 |     100 | 61                
  ...ouseEvents.ts |   94.89 |       95 |   83.33 |   94.89 | 78-82             
  ...raseCycler.ts |   84.74 |    76.47 |     100 |   84.74 | ...49,52-53,69-71 
  ...rredEditor.ts |   58.33 |    22.22 |     100 |   58.33 | 23-27,29-33       
  ...derUpdates.ts |    87.4 |    78.78 |     100 |    87.4 | ...71,321-333,381 
  useQwenAuth.ts   |     100 |      100 |     100 |     100 |                   
  ...lScheduler.ts |   88.95 |    86.95 |     100 |   88.95 | ...37-439,471-481 
  ...oryCommand.ts |       0 |        0 |       0 |       0 | 1-7               
  ...umeCommand.ts |   95.18 |    76.47 |     100 |   95.18 | 118-119,220-225   
  ...ompletion.tsx |   90.67 |    83.33 |     100 |   90.67 | ...02,105,138-141 
  ...ectionList.ts |   97.12 |    96.22 |     100 |   97.12 | ...92-193,247-250 
  ...sionPicker.ts |   92.87 |    90.35 |     100 |   92.87 | ...99-501,503-505 
  ...earchInput.ts |     100 |    97.29 |     100 |     100 | 82                
  ...ngsCommand.ts |   18.75 |      100 |       0 |   18.75 | 10-25             
  ...ellHistory.ts |   93.28 |    80.95 |     100 |   93.28 | ...96,153-154,164 
  ...oryCommand.ts |   85.48 |    58.33 |     100 |   85.48 | 22-28,40,71       
  ...agerDialog.ts |   88.23 |      100 |     100 |   88.23 | 20,24             
  ...Completion.ts |   82.85 |    85.13 |   94.73 |   82.85 | ...78-680,688-724 
  ...tateAndRef.ts |     100 |      100 |     100 |     100 |                   
  ...tatsDialog.ts |     100 |      100 |     100 |     100 |                   
  useStatusLine.ts |   97.13 |    93.33 |     100 |   97.13 | ...78-382,478-485 
  ...eateDialog.ts |   88.23 |      100 |     100 |   88.23 | 14,18             
  ...mInProcess.ts |   27.35 |       80 |      25 |   27.35 | ...82-183,186-188 
  ...tification.ts |     100 |     87.5 |     100 |     100 | 50                
  ...alProgress.ts |   67.34 |    58.82 |   66.66 |   67.34 | 52-53,61-68,79-85 
  ...rminalSize.ts |     100 |      100 |     100 |     100 |                   
  ...emeCommand.ts |   67.01 |    29.41 |     100 |   67.01 | ...10-111,115-116 
  useTimer.ts      |   97.59 |    94.73 |     100 |   97.59 | 17-18             
  ...lMigration.ts |       0 |        0 |       0 |       0 |                   
  ...rustModify.ts |     100 |    90.47 |     100 |     100 | 112,134           
  useTurnDiffs.ts  |   95.12 |    78.57 |     100 |   95.12 | 133-134,156-157   
  ...elcomeBack.ts |   87.36 |     90.9 |     100 |   87.36 | ...,94-96,114-115 
  ...reeSession.ts |   93.75 |       70 |     100 |   93.75 | 47-48,72          
  vim.ts           |      74 |    67.56 |   69.23 |      74 | ...1854-1861,1869 
 src/ui/layouts    |    91.2 |    89.47 |     100 |    91.2 |                   
  ...AppLayout.tsx |    90.9 |     87.5 |     100 |    90.9 | 60-62,110-115,151 
  ...AppLayout.tsx |   91.66 |    92.85 |     100 |   91.66 | 75-80             
 src/ui/models     |   80.72 |       80 |   71.42 |   80.72 |                   
  ...ableModels.ts |   80.72 |       80 |   71.42 |   80.72 | ...,61-71,125-127 
 ...noninteractive |     100 |      100 |    6.66 |     100 |                   
  ...eractiveUi.ts |     100 |      100 |    6.66 |     100 |                   
 src/ui/selection  |   86.47 |    79.88 |   96.66 |   86.47 |                   
  screen-buffer.ts |   94.73 |    64.28 |     100 |   94.73 | 51-52             
  ...ion-coords.ts |     100 |      100 |     100 |     100 |                   
  ...ction-span.ts |   92.72 |       90 |     100 |   92.72 | 37-38,67-68       
  ...tion-state.ts |   85.71 |      100 |   88.88 |   85.71 | 51-58             
  ...ction-text.ts |   92.85 |    92.45 |     100 |   92.85 | 30-34,114-115     
  ...selection.tsx |   80.31 |    59.64 |     100 |   80.31 | ...13-314,330-331 
 src/ui/state      |      95 |    81.81 |     100 |      95 |                   
  extensions.ts    |      95 |    81.81 |     100 |      95 | 69-70,89          
 src/ui/themes     |    98.5 |    73.17 |     100 |    98.5 |                   
  ansi-light.ts    |     100 |      100 |     100 |     100 |                   
  ansi.ts          |     100 |      100 |     100 |     100 |                   
  atom-one-dark.ts |     100 |      100 |     100 |     100 |                   
  ayu-light.ts     |     100 |      100 |     100 |     100 |                   
  ayu.ts           |     100 |      100 |     100 |     100 |                   
  color-utils.ts   |   99.23 |    97.05 |     100 |   99.23 | 277-278           
  default-light.ts |     100 |      100 |     100 |     100 |                   
  default.ts       |     100 |      100 |     100 |     100 |                   
  ...inal-theme.ts |   88.59 |    85.96 |     100 |   88.59 | ...57-261,266-270 
  dracula.ts       |     100 |      100 |     100 |     100 |                   
  github-dark.ts   |     100 |      100 |     100 |     100 |                   
  github-light.ts  |     100 |      100 |     100 |     100 |                   
  googlecode.ts    |     100 |      100 |     100 |     100 |                   
  no-color.ts      |     100 |      100 |     100 |     100 |                   
  qwen-dark.ts     |     100 |      100 |     100 |     100 |                   
  qwen-light.ts    |     100 |      100 |     100 |     100 |                   
  ...tic-tokens.ts |     100 |      100 |     100 |     100 |                   
  ...-of-purple.ts |     100 |      100 |     100 |     100 |                   
  theme-manager.ts |   88.68 |    84.52 |     100 |   88.68 | ...83-392,397-398 
  theme.ts         |     100 |    38.02 |     100 |     100 | ...34-449,457-461 
  xcode.ts         |     100 |      100 |     100 |     100 |                   
 src/ui/utils      |   86.74 |    84.96 |   95.48 |   86.74 |                   
  ...Colorizer.tsx |   80.31 |    85.41 |     100 |   80.31 | ...00-201,313-339 
  ...nRenderer.tsx |   79.84 |     75.6 |     100 |   79.84 | ...66,270,328-329 
  ...wnDisplay.tsx |   92.87 |    93.46 |     100 |   92.87 | ...,955,1002-1020 
  ...idDiagram.tsx |   87.79 |    95.34 |     100 |   87.79 | 156-179           
  ...eRenderer.tsx |   92.38 |    81.91 |   95.23 |   92.38 | ...43-746,799-804 
  ...odeDisplay.ts |   94.28 |    85.71 |     100 |   94.28 | 23,40             
  asciiCharts.ts   |    96.7 |     87.5 |     100 |    96.7 | 170-177,278       
  ...dWorkUtils.ts |     100 |      100 |     100 |     100 |                   
  ...boardUtils.ts |   52.52 |    73.25 |   91.66 |   52.52 | ...23,626-635,638 
  commandUtils.ts  |   96.17 |    88.88 |     100 |   96.17 | ...77,179-180,323 
  computeStats.ts  |     100 |      100 |     100 |     100 |                   
  customBanner.ts  |   90.68 |    91.22 |     100 |   90.68 | ...13,324-327,334 
  displayUtils.ts  |   73.84 |    73.91 |     100 |   73.84 | ...34,36-40,42-46 
  formatters.ts    |   94.87 |    98.21 |     100 |   94.87 | 116-119           
  goal-runtime.ts  |   91.17 |    94.73 |     100 |   91.17 | 31-33             
  gradientUtils.ts |     100 |      100 |     100 |     100 |                   
  highlight.ts     |     100 |      100 |     100 |     100 |                   
  ...gap-notice.ts |     100 |      100 |     100 |     100 |                   
  ...oryMapping.ts |     100 |       95 |     100 |     100 | 44,103            
  historyUtils.ts  |   96.03 |     97.1 |     100 |   96.03 | 103-106           
  inline-math.ts   |   98.48 |    95.23 |     100 |   98.48 | 129-130           
  input-mouse.ts   |     100 |    85.71 |     100 |     100 | 48,93             
  isNarrowWidth.ts |     100 |      100 |     100 |     100 |                   
  ...olDetector.ts |   68.81 |       75 |   66.66 |   68.81 | ...27-132,160-161 
  latexRenderer.ts |   94.95 |     73.8 |     100 |   94.95 | ...76-178,184-187 
  layoutUtils.ts   |     100 |      100 |     100 |     100 |                   
  list-mouse.ts    |     100 |      100 |     100 |     100 |                   
  ...ightLoader.ts |     100 |       95 |     100 |     100 | 81                
  ...nUtilities.ts |   98.72 |    94.36 |     100 |   98.72 | 145-146           
  ...t-position.ts |     100 |     87.5 |     100 |     100 | 85                
  ...geRenderer.ts |   86.51 |    70.16 |   95.12 |   86.51 | ...1286,1326-1332 
  ...alRenderer.ts |   86.69 |     71.9 |     100 |   86.69 | ...1476,1513-1519 
  ...lsBySource.ts |     100 |    95.23 |     100 |     100 | 84                
  mouse.ts         |   92.85 |    74.19 |     100 |   92.85 | ...38,145,149-152 
  osc8.ts          |   90.43 |    78.33 |     100 |   90.43 | ...59,244,248-249 
  ...red-height.ts |   98.38 |     97.1 |     100 |   98.38 | 195-197           
  ...mConstants.ts |     100 |      100 |     100 |     100 |                   
  restoreGoal.ts   |     100 |      100 |     100 |     100 |                   
  ...storyUtils.ts |   79.42 |    78.08 |     100 |   79.42 | ...50-572,703-704 
  ...ickerUtils.ts |     100 |      100 |     100 |     100 |                   
  ...evel-label.ts |   77.77 |    66.66 |     100 |   77.77 | 18,22-24          
  ...are-cursor.ts |   89.47 |    85.71 |     100 |   89.47 | 39-44             
  ...ataService.ts |   93.17 |     79.1 |     100 |   93.17 | ...14,227,254-256 
  suggestions.ts   |     100 |      100 |     100 |     100 |                   
  ...izedOutput.ts |   94.94 |      100 |   88.88 |   94.94 | 112-117           
  ...nal-buffer.ts |     100 |      100 |     100 |     100 |                   
  ...e-renderer.ts |   89.19 |    79.54 |     100 |   89.19 | ...14,316-318,434 
  ...wOptimizer.ts |     100 |    96.77 |     100 |     100 | 69                
  terminalSetup.ts |    4.37 |      100 |       0 |    4.37 | 44-393            
  textUtils.ts     |   97.94 |    95.45 |   94.11 |   97.94 | ...82-283,443-444 
  ...background.ts |     100 |      100 |     100 |     100 |                   
  todoSnapshot.ts  |   90.42 |    92.85 |     100 |   90.42 | ...06-207,240-241 
  ...isplay-map.ts |     100 |      100 |     100 |     100 |                   
  updateCheck.ts   |     100 |    92.75 |     100 |     100 | 227-239,331       
  ...ow-keyword.ts |     100 |      100 |     100 |     100 |                   
 ...i/utils/export |   75.03 |    59.89 |   94.59 |   75.03 |                   
  collect.ts       |   71.27 |    65.81 |      96 |   71.27 | ...90-633,655-656 
  index.ts         |     100 |      100 |     100 |     100 |                   
  normalize.ts     |   80.42 |    50.68 |     100 |   80.42 | ...59-364,376-378 
  types.ts         |       0 |        0 |       0 |       0 | 1                 
  utils.ts         |     100 |      100 |     100 |     100 |                   
 ...ort/formatters |   52.92 |    47.22 |   71.42 |   52.92 |                   
  html.ts          |   84.61 |       50 |     100 |   84.61 | ...53,57-58,62-63 
  json.ts          |     100 |      100 |     100 |     100 |                   
  jsonl.ts         |   82.45 |     37.5 |     100 |   82.45 | ...48,50-51,65-66 
  markdown.ts      |   36.32 |    47.05 |      50 |   36.32 | ...16-219,233-295 
 src/ui/voice      |   80.94 |    72.69 |   80.55 |   80.94 |                   
  ...d-recorder.ts |     6.2 |      100 |       0 |     6.2 | ...33-159,162-163 
  ...o-recorder.ts |   84.61 |    93.33 |   57.14 |   84.61 | ...16-117,131-136 
  ...me-session.ts |   89.72 |    65.33 |   93.75 |   89.72 | ...99,305,316-319 
  sox-recorder.ts  |    92.7 |    71.87 |     100 |    92.7 | ...34-135,153-154 
  ...ailability.ts |     100 |      100 |     100 |     100 |                   
  ...e-keyterms.ts |     100 |      100 |     100 |     100 |                   
  voice-model.ts   |     100 |      100 |     100 |     100 |                   
  ...e-recorder.ts |   88.29 |    67.74 |   81.81 |   88.29 | ...,98-99,112,115 
  voice-refine.ts  |     100 |    93.33 |     100 |     100 | 92                
  ...ream-retry.ts |   86.79 |    68.42 |     100 |   86.79 | 16-18,48-49,59-60 
  ...am-session.ts |   88.02 |    66.66 |   84.61 |   88.02 | ...26,343-345,363 
  ...ranscriber.ts |     100 |      100 |     100 |     100 |                   
 src/utils         |   81.37 |    86.98 |   92.54 |   81.37 |                   
  ...p-profiler.ts |   98.39 |    90.56 |     100 |   98.39 | 141,185,235       
  acpModelUtils.ts |   97.36 |    95.19 |     100 |   97.36 | ...09-210,214-215 
  apiPreconnect.ts |   96.74 |    94.59 |     100 |   96.74 | 167-170           
  ...ol-call-id.ts |   84.61 |       60 |     100 |   84.61 | 26-27,37-38       
  ...ng-failure.ts |     100 |       95 |     100 |     100 | 72                
  checks.ts        |   33.33 |      100 |       0 |   33.33 | 23-28             
  ...-api-error.ts |     100 |    96.42 |     100 |     100 | 14                
  cleanup.ts       |   84.05 |    94.11 |      80 |   84.05 | 80,111-121        
  commands.ts      |   97.45 |    96.66 |     100 |   97.45 | 153-155           
  ...Calculator.ts |     100 |      100 |     100 |     100 |                   
  cpuProfiler.ts   |   70.73 |    73.23 |   88.88 |   70.73 | ...27,430-431,438 
  deepMerge.ts     |     100 |       90 |     100 |     100 | 41-43,49          
  ...re-runtime.ts |     100 |      100 |     100 |     100 |                   
  ...ScopeUtils.ts |   97.56 |    88.88 |     100 |   97.56 | 67                
  doctorChecks.ts  |   70.31 |    74.57 |     100 |   70.31 | ...95-301,325-341 
  ...putCapture.ts |   90.65 |    86.31 |     100 |   90.65 | ...73,371,373-374 
  ...arResolver.ts |   97.14 |    96.55 |     100 |   97.14 | 125-126           
  errors.ts        |   97.56 |    94.64 |     100 |   97.56 | 69-70,304-305     
  events.ts        |     100 |      100 |     100 |     100 |                   
  ...on-mention.ts |   88.48 |     82.6 |     100 |   88.48 | ...56-160,164-168 
  gitUtils.ts      |   92.85 |    86.66 |     100 |   92.85 | ...13-116,164-167 
  ...AutoUpdate.ts |    93.1 |       94 |      90 |    93.1 | 103,108,179-190   
  ...tyWarnings.ts |     100 |      100 |     100 |     100 |                   
  ...lationInfo.ts |   97.68 |    94.28 |     100 |   97.68 | ...64,381-382,427 
  jsonc-editor.ts  |   93.18 |    92.72 |     100 |   93.18 | ...80-381,384-385 
  languageUtils.ts |   98.88 |    97.05 |     100 |   98.88 | 184-185           
  load-undici.ts   |     100 |      100 |     100 |     100 |                   
  ...npm-update.ts |   86.32 |    76.05 |     100 |   86.32 | ...02-303,331-341 
  math.ts          |       0 |        0 |       0 |       0 | 1-15              
  ...er-mention.ts |     100 |    66.66 |     100 |     100 | 14,30,44-46       
  ...iagnostics.ts |   94.57 |    83.01 |   88.88 |   94.57 | ...05,311,315-317 
  ...serMessage.ts |     100 |      100 |     100 |     100 |                   
  ...onfigUtils.ts |   94.25 |    91.17 |     100 |   94.25 | ...30,436,439-443 
  ...iveHelpers.ts |   95.13 |    91.79 |     100 |   95.13 | ...53-454,552,565 
  osc.ts           |   97.18 |      100 |    87.5 |   97.18 | 182-183           
  package.ts       |   88.88 |    85.71 |     100 |   88.88 | 31-32             
  ...uggestions.ts |   84.29 |    70.83 |     100 |   84.29 | 70-76,92-103      
  processUtils.ts  |    92.3 |       80 |     100 |    92.3 | 45-46             
  readStdin.ts     |   93.67 |    94.11 |   85.71 |   93.67 | 79-83             
  relaunch.ts      |   95.87 |    89.28 |     100 |   95.87 | 103-105,131       
  resolvePath.ts   |     100 |      100 |     100 |     100 |                   
  runBudget.ts     |   99.35 |    96.77 |     100 |   99.35 | 119               
  sandbox-path.ts  |     100 |      100 |     100 |     100 |                   
  sandbox.ts       |   45.67 |    56.93 |   76.92 |   45.67 | ...1034,1046-1069 
  ...xImageName.ts |     100 |    77.77 |     100 |     100 | 10,18             
  sandboxMounts.ts |     100 |      100 |     100 |     100 |                   
  sessionPaths.ts  |   90.84 |    90.56 |     100 |   90.84 | ...81-182,185-186 
  settingsUtils.ts |   82.35 |    89.57 |      90 |   82.35 | ...25-743,750-758 
  spawnWrapper.ts  |     100 |      100 |     100 |     100 |                   
  ...ate-verify.ts |     100 |      100 |     100 |     100 |                   
  ...one-update.ts |   39.81 |    77.44 |   62.16 |   39.81 | ...1193,1196-1215 
  ...upProfiler.ts |   98.47 |    94.66 |     100 |   98.47 | 132-133,308       
  ...upWarnings.ts |     100 |      100 |     100 |     100 |                   
  stdioHelpers.ts  |     100 |     87.5 |     100 |     100 | 23                
  systemInfo.ts    |   95.12 |    90.27 |     100 |   95.12 | ...54-255,260-264 
  ...InfoFields.ts |    87.5 |    65.85 |     100 |    87.5 | ...24-125,146-147 
  ...alSequence.ts |     100 |    97.61 |     100 |     100 | 60                
  ...iffPreview.ts |   76.47 |       25 |     100 |   76.47 | 13,17,23-24       
  ...on-handler.ts |    73.8 |       75 |     100 |    73.8 | 17-18,25-26,67-73 
  ...e-relaunch.ts |   89.61 |    86.66 |      50 |   89.61 | 56-61,83-84       
  ...entEmitter.ts |     100 |      100 |     100 |     100 |                   
  ...ansionHook.ts |     100 |      100 |     100 |     100 |                   
  ...upWarnings.ts |   87.75 |       75 |     100 |   87.75 | 47-48,53-54,57-58 
  version.ts       |     100 |    66.66 |     100 |     100 | 11                
  ...ingHandler.ts |     100 |      100 |     100 |     100 |                   
  windowTitle.ts   |   95.45 |    93.33 |     100 |   95.45 | 54-55             
  ...WithBackup.ts |   65.04 |    77.77 |     100 |   65.04 | 97,112,133-172    
 ...s/housekeeping |   91.63 |    91.02 |      95 |   91.63 |                   
  cleanup.ts       |   95.77 |    95.83 |     100 |   95.77 | 70-72             
  ...eractionAt.ts |     100 |      100 |     100 |     100 |                   
  scheduler.ts     |   91.91 |    90.47 |    87.5 |   91.91 | 58-62,73,131-135  
  throttledOnce.ts |   86.66 |     86.2 |     100 |   86.66 | ...99,105,137-138 
-------------------|---------|----------|---------|---------|-------------------
Core Package - Full Text Report
-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |   87.59 |    86.21 |   89.21 |   87.59 |                   
 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.46 |    84.13 |   95.65 |   90.46 |                   
  ...transcript.ts |   87.63 |    83.52 |     100 |   87.63 | ...80,588,594-598 
  ...ent-resume.ts |   85.59 |    77.55 |   83.33 |   85.59 | ...1793-1797,1800 
  ...ound-tasks.ts |   96.15 |    90.13 |   98.76 |   96.15 | ...1732,1752-1755 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...ent-result.ts |    96.8 |    92.68 |     100 |    96.8 | 106,129-131       
  ...n-registry.ts |    93.3 |    86.11 |     100 |    93.3 | ...85-991,996-998 
  ...w-snapshot.ts |   91.86 |    75.75 |     100 |   91.86 | ...54,178,185-187 
 src/agents/arena  |   76.32 |    67.71 |   78.94 |   76.32 |                   
  ...gentClient.ts |   79.47 |    88.88 |   81.81 |   79.47 | ...68-183,189-204 
  ArenaManager.ts  |   75.11 |    64.51 |   78.57 |   75.11 | ...1887,1893-1894 
  arena-events.ts  |   64.44 |      100 |      50 |   64.44 | ...71-175,178-183 
  diff-summary.ts  |    87.5 |    72.34 |     100 |    87.5 | ...32-133,137-138 
  index.ts         |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...gents/backends |   78.09 |    85.23 |   76.28 |   78.09 |                   
  ITermBackend.ts  |   97.97 |    93.93 |     100 |   97.97 | ...78-180,255,307 
  ...essBackend.ts |    90.9 |    85.36 |   93.33 |    90.9 | ...70,672,674-675 
  TmuxBackend.ts   |    90.7 |    76.55 |   97.36 |    90.7 | ...87,697,743-747 
  detect.ts        |   31.25 |      100 |       0 |   31.25 | 34-88             
  index.ts         |     100 |      100 |     100 |     100 |                   
  iterm-it2.ts     |     100 |     92.1 |     100 |     100 | 37-38,106         
  tmux-commands.ts |    6.64 |      100 |    3.03 |    6.64 | ...93-363,386-503 
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...agents/runtime |   90.55 |    86.13 |   87.64 |   90.55 |                   
  agent-context.ts |     100 |      100 |     100 |     100 |                   
  agent-core.ts    |   85.07 |    76.73 |   77.77 |   85.07 | ...2291,2337-2339 
  agent-events.ts  |     100 |      100 |     100 |     100 |                   
  ...t-headless.ts |   93.49 |    89.41 |   83.33 |   93.49 | ...96-497,500-501 
  ...nteractive.ts |   81.01 |    82.35 |   76.66 |   81.01 | ...33,535-538,541 
  ...statistics.ts |   98.29 |    82.55 |     100 |   98.29 | 141,165,206,239   
  agent-types.ts   |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...ool-policy.ts |   98.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.86 |    88.71 |   82.35 |   91.86 | ...1782,1831-1834 
  ...ow-prompts.ts |     100 |      100 |     100 |     100 |                   
  ...low-runner.ts |    94.3 |    87.17 |   91.66 |    94.3 | ...74,222,242-245 
  ...ow-sandbox.ts |   96.87 |    94.64 |     100 |   96.87 | ...24-325,330-331 
  ...flow-saved.ts |   96.51 |    94.36 |     100 |   96.51 | 134-135,234-237   
  ...flow-stall.ts |    97.9 |    83.33 |     100 |    97.9 | 138-139,236       
 src/agents/tasks  |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/agents/team   |   81.81 |    83.99 |    87.5 |   81.81 |                   
  TeamManager.ts   |   72.02 |    79.41 |   79.24 |   72.02 | ...1632,1655-1656 
  identity.ts      |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...sionBridge.ts |     100 |      100 |     100 |     100 |                   
  mailbox.ts       |   94.76 |    86.36 |   92.85 |   94.76 | 86-87,348-354     
  ...ptAddendum.ts |     100 |      100 |     100 |     100 |                   
  tasks.ts         |   88.85 |    82.56 |   96.29 |   88.85 | ...-990,1034-1035 
  team-events.ts   |   60.52 |      100 |      50 |   60.52 | ...40-144,151-155 
  teamHelpers.ts   |   92.02 |    94.91 |   95.23 |   92.02 | ...31-332,368-378 
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...eam/test-utils |   94.39 |    94.26 |   98.21 |   94.39 |                   
  ...on-harness.ts |   96.49 |    84.21 |     100 |   96.49 | 128-129,141-142   
  fake-agent.ts    |   98.49 |    95.08 |     100 |   98.49 | 201-203           
  fake-backend.ts  |   86.46 |    97.61 |   95.83 |   86.46 | 124-146           
 src/config        |   84.96 |    87.06 |   75.48 |   84.96 |                   
  approval-mode.ts |     100 |      100 |     100 |     100 |                   
  ...xtDefaults.ts |     100 |      100 |     100 |     100 |                   
  config.ts        |   84.27 |    86.78 |   73.91 |   84.27 | ...8316,8320-8321 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  models.ts        |     100 |      100 |     100 |     100 |                   
  storage.ts       |   94.39 |    91.57 |   88.23 |   94.39 | ...45-446,449-450 
 ...nfirmation-bus |   98.27 |    97.14 |     100 |   98.27 |                   
  message-bus.ts   |   98.14 |    97.05 |     100 |   98.14 | 42-43             
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/core          |   91.97 |    88.26 |   93.21 |   91.97 |                   
  baseLlmClient.ts |   88.28 |    82.48 |   81.81 |   88.28 | ...47,660,666-668 
  client.ts        |   91.92 |    87.39 |   91.56 |   91.92 | ...3915,4009-4010 
  ...tGenerator.ts |   86.34 |    87.34 |   84.61 |   86.34 | ...81-482,527-533 
  ...lScheduler.ts |   90.11 |       86 |      96 |   90.11 | ...5647,5675-5686 
  geminiChat.ts    |   92.56 |    89.36 |      96 |   92.56 | ...4504,4552-4553 
  geminiRequest.ts |     100 |      100 |     100 |     100 |                   
  genai-compat.ts  |     100 |      100 |     100 |     100 |                   
  ...MediaLimit.ts |     100 |       96 |     100 |     100 | 96                
  ...htProtocol.ts |    9.09 |      100 |       0 |    9.09 | ...9,62-66,69-110 
  ...ream-error.ts |     100 |      100 |     100 |     100 |                   
  logger.ts        |   87.41 |    87.02 |     100 |   87.41 | ...64-568,614-628 
  ...lay-buffer.ts |     100 |      100 |     100 |     100 |                   
  ...dispatcher.ts |     100 |      100 |     100 |     100 |                   
  ...tyDefaults.ts |     100 |      100 |     100 |     100 |                   
  ...olExecutor.ts |   93.54 |    83.33 |      50 |   93.54 | 49-50             
  ...on-helpers.ts |   93.49 |    78.57 |     100 |   93.49 | ...10-211,228-229 
  ...issionFlow.ts |   98.97 |    96.96 |     100 |   98.97 | 107               
  ...try-policy.ts |     100 |      100 |     100 |     100 |                   
  ...ell-policy.ts |   95.19 |    89.47 |     100 |   95.19 | ...44-245,290-291 
  prompts.ts       |   93.57 |    91.42 |   83.33 |   93.57 | ...1188,1391-1392 
  ...ing-effort.ts |     100 |      100 |     100 |     100 |                   
  ...n-recovery.ts |   95.13 |       80 |     100 |   95.13 | ...06-107,142-144 
  ...t-profiler.ts |    97.9 |    81.15 |   88.23 |    97.9 | 117,124-125,130   
  ...port-retry.ts |     100 |      100 |     100 |     100 |                   
  tokenLimits.ts   |     100 |     92.1 |     100 |     100 | 87,122-139        
  ...reparation.ts |     100 |      100 |     100 |     100 |                   
  ...tion-guard.ts |     100 |      100 |     100 |     100 |                   
  ...allIdUtils.ts |   98.41 |    93.47 |     100 |   98.41 | 36,45             
  ...okTriggers.ts |   99.45 |    92.43 |     100 |   99.45 | 182,193           
  ...terruption.ts |     100 |     92.3 |     100 |     100 | 86,104            
  turn.ts          |   98.52 |    91.66 |     100 |   98.52 | ...17,645-646,693 
  ...l-fallback.ts |     100 |      100 |     100 |     100 |                   
 ...ntentGenerator |   96.32 |    88.02 |    96.1 |   96.32 |                   
  ...tGenerator.ts |   97.23 |    86.48 |   94.73 |   97.23 | ...1423,1452,1463 
  converter.ts     |   96.19 |    89.25 |     100 |   96.19 | ...1329,1550-1552 
  index.ts         |       0 |        0 |       0 |       0 | 1-21              
  usage.ts         |     100 |      100 |     100 |     100 |                   
 ...ntentGenerator |   88.78 |    72.36 |   89.47 |   88.78 |                   
  ...tGenerator.ts |   87.18 |    71.83 |   88.88 |   87.18 | ...58-364,382-383 
  index.ts         |     100 |       80 |     100 |     100 | 50                
 ...ntentGenerator |    95.6 |    88.74 |    92.3 |    95.6 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...tGenerator.ts |   95.52 |    87.88 |   91.89 |   95.52 | ...1195-1196,1224 
  ...tDetection.ts |     100 |      100 |     100 |     100 |                   
 ...ntentGenerator |   91.65 |    90.23 |   95.23 |   91.65 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  converter.ts     |   91.15 |    89.32 |   96.87 |   91.15 | ...1914,2083-2098 
  errorHandler.ts  |     100 |      100 |     100 |     100 |                   
  index.ts         |   60.31 |       75 |      50 |   60.31 | ...71,74-78,90-94 
  ...tGenerator.ts |    66.4 |    70.58 |   88.88 |    66.4 | ...51-157,168-169 
  pipeline.ts      |   96.63 |    90.94 |     100 |   96.63 | ...1100,1108,1203 
  ...ureContext.ts |     100 |      100 |     100 |     100 |                   
  ...ingOptions.ts |       0 |        0 |       0 |       0 | 1                 
  ...CallParser.ts |   92.24 |     92.4 |     100 |   92.24 | ...28-529,549-552 
  ...kingParser.ts |     100 |    96.87 |     100 |     100 | 42                
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...rator/provider |   96.73 |    89.76 |   98.27 |   96.73 |                   
  dashscope.ts     |   97.48 |    91.91 |      95 |   97.48 | ...85-386,528-529 
  deepseek.ts      |   94.91 |    89.36 |     100 |   94.91 | ...31-132,145-146 
  default.ts       |   99.16 |    96.96 |     100 |   99.16 | 198               
  index.ts         |     100 |      100 |     100 |     100 |                   
  mimo.ts          |   94.11 |    66.66 |     100 |   94.11 | 29,52-53          
  minimax.ts       |     100 |      100 |     100 |     100 |                   
  mistral.ts       |   96.07 |    73.33 |     100 |   96.07 | 32-33             
  modelscope.ts    |     100 |      100 |     100 |     100 |                   
  types.ts         |       0 |        0 |       0 |       0 |                   
  utils.ts         |     100 |      100 |     100 |     100 |                   
  zai.ts           |   92.13 |    82.14 |     100 |   92.13 | ...,39-40,135-137 
 src/extension     |    86.2 |    83.25 |   92.33 |    86.2 |                   
  ...ive-safety.ts |     100 |      100 |     100 |     100 |                   
  ...-converter.ts |   78.32 |    71.83 |     100 |   78.32 | ...1122,1168-1169 
  corruptFile.ts   |     100 |       50 |     100 |     100 | 40-45             
  ...-converter.ts |   80.39 |     87.5 |     100 |   80.39 | 50-59             
  ...me-refresh.ts |     100 |      100 |     100 |     100 |                   
  ...sion-store.ts |   90.82 |    86.38 |   97.82 |   90.82 | ...1215-1221,1265 
  ...ionManager.ts |   81.06 |    78.78 |   81.52 |   81.06 | ...2705,2727-2728 
  ...references.ts |     100 |     90.9 |     100 |     100 | ...05,129,197,200 
  ...onSettings.ts |    92.3 |     94.4 |     100 |    92.3 | ...98-501,570-571 
  ...-converter.ts |    75.9 |    84.61 |   85.71 |    75.9 | ...98,202,214-248 
  github.ts        |   88.58 |    82.13 |     100 |   88.58 | ...62,952-953,963 
  http-client.ts   |   84.61 |       80 |     100 |   84.61 | 20-21             
  i18n.ts          |   78.26 |       96 |      50 |   78.26 | 104-110,116-123   
  index.ts         |     100 |      100 |     100 |     100 |                   
  marketplace.ts   |   88.39 |    83.11 |     100 |   88.39 | ...08,494,507-508 
  ...ork-policy.ts |   89.72 |       90 |     100 |   89.72 | ...36,148-154,156 
  npm.ts           |   89.02 |    81.81 |     100 |   89.02 | ...86-688,695-700 
  override.ts      |   94.11 |    93.33 |     100 |   94.11 | 63-64,81-82       
  redaction.ts     |     100 |      100 |     100 |     100 |                   
  settings.ts      |   66.26 |      100 |      50 |   66.26 | 81-107,141-146    
  ...ceRegistry.ts |   94.01 |    83.14 |     100 |   94.01 | ...38-344,365-366 
  storage.ts       |     100 |      100 |     100 |     100 |                   
  ...ableSchema.ts |     100 |      100 |     100 |     100 |                   
  variables.ts     |   88.95 |    83.78 |     100 |   88.95 | ...32-235,238-241 
  ...extraction.ts |   85.77 |    80.61 |   89.47 |   85.77 | ...02-205,260-261 
 src/followup      |   79.86 |    80.36 |    90.9 |   79.86 |                   
  followupState.ts |   98.44 |    95.74 |     100 |   98.44 | 236-237           
  index.ts         |     100 |      100 |     100 |     100 |                   
  overlayFs.ts     |   96.29 |    88.88 |     100 |   96.29 | 78,108,122        
  speculation.ts   |   71.45 |    66.01 |   71.42 |   71.45 | ...49-650,657-658 
  ...onToolGate.ts |     100 |    96.55 |     100 |     100 | 97                
  ...nGenerator.ts |   72.03 |    81.15 |   83.33 |   72.03 | ...68-219,331-333 
 src/generated     |       0 |        0 |       0 |       0 |                   
  git-commit.ts    |       0 |        0 |       0 |       0 | 1-10              
 src/goals         |   94.23 |    88.89 |   95.93 |   94.23 |                   
  ...eGoalStore.ts |   87.61 |    88.88 |   86.66 |   87.61 | ...85-188,196-204 
  goal-evidence.ts |   87.59 |     85.1 |   95.65 |   87.59 | ...12-613,636-639 
  ...projection.ts |   89.41 |    72.22 |   66.66 |   89.41 | ...28,131,135-137 
  ...ersistence.ts |   87.73 |    84.84 |      80 |   87.73 | ...-94,97,101-106 
  goal-protocol.ts |    91.3 |       90 |     100 |    91.3 | 107-108           
  goal-reducer.ts  |   92.28 |    85.48 |     100 |   92.28 | ...74-375,388,443 
  goal-runtime.ts  |   99.05 |     93.6 |     100 |   99.05 | ...17-718,741-742 
  goal-tools.ts    |   98.32 |    93.18 |   95.23 |   98.32 | ...46-147,254-255 
  ...rn-context.ts |     100 |      100 |     100 |     100 |                   
  goal-verifier.ts |   92.46 |    92.85 |     100 |   92.46 | ...69-172,185-187 
  goal-wire.ts     |       0 |        0 |       0 |       0 | 1-27              
  goalHook.ts      |   96.91 |    92.42 |     100 |   96.91 | 115-120,221-222   
  goalJudge.ts     |   95.84 |    87.09 |     100 |   95.84 | ...55-356,448-449 
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/hooks         |   88.11 |    86.38 |   88.62 |   88.11 |                   
  ...okRegistry.ts |   86.48 |    77.08 |     100 |   86.48 | ...41-344,362-369 
  ...bortSignal.ts |     100 |      100 |     100 |     100 |                   
  context-usage.ts |     100 |      100 |     100 |     100 |                   
  ...terpolator.ts |   96.66 |    93.33 |     100 |   96.66 | 66-67             
  ...HookRunner.ts |   96.68 |    87.23 |     100 |   96.68 | 110-112,231-233   
  ...Aggregator.ts |   96.57 |    91.48 |     100 |   96.57 | ...20-321,402,404 
  ...entHandler.ts |   95.57 |    84.76 |   94.73 |   95.57 | ...1040-1041,1051 
  hookPlanner.ts   |   87.55 |    85.54 |   86.66 |   87.55 | ...22-226,233-244 
  hookRegistry.ts  |   92.53 |    85.43 |     100 |   92.53 | ...39,458,462,466 
  hookRunner.ts    |   62.65 |    72.34 |   66.66 |   62.65 | ...70-771,780-781 
  hookSystem.ts    |   87.64 |     98.5 |   70.83 |   87.64 | ...58-759,765-766 
  ...HookRunner.ts |   79.06 |    66.66 |      80 |   79.06 | ...33-434,452-456 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...edCallback.ts |     100 |      100 |     100 |     100 |                   
  ...HookRunner.ts |   94.19 |    84.37 |   81.81 |   94.19 | ...76-384,458-459 
  ...SkillHooks.ts |   78.75 |       75 |   66.66 |   78.75 | 62-66,137-152     
  ...oksManager.ts |   94.87 |    88.88 |     100 |   94.87 | ...84,325,327-329 
  ssrfGuard.ts     |   86.45 |    89.13 |     100 |   86.45 | ...85,289-295,301 
  stopHookCap.ts   |     100 |      100 |     100 |     100 |                   
  trustedHooks.ts  |      90 |    52.63 |     100 |      90 | ...53,66-67,97-98 
  types.ts         |   94.25 |    96.12 |   88.88 |   94.25 | ...46-547,632-636 
  urlValidator.ts  |     100 |      100 |     100 |     100 |                   
  ...it-context.ts |     100 |      100 |     100 |     100 |                   
 src/ide           |   76.98 |    85.03 |   79.03 |   76.98 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  detect-ide.ts    |     100 |      100 |     100 |     100 |                   
  ide-client.ts    |   69.16 |    84.65 |   68.29 |   69.16 | ...1068,1097-1105 
  ide-installer.ts |   89.06 |    79.31 |     100 |   89.06 | ...36,143-147,160 
  ideContext.ts    |     100 |      100 |     100 |     100 |                   
  process-utils.ts |   84.84 |    71.79 |     100 |   84.84 | ...37,151,193-194 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/lsp           |   58.96 |    70.57 |   66.14 |   58.96 |                   
  ...nfigLoader.ts |   80.55 |       72 |   95.45 |   80.55 | ...02-504,508-514 
  ...ionFactory.ts |   42.81 |    73.07 |      50 |   42.81 | ...76-427,433-450 
  ...Normalizer.ts |   23.09 |    13.72 |   30.43 |   23.09 | ...04-905,909-924 
  ...verManager.ts |   75.73 |     80.1 |   79.66 |   75.73 | ...1346,1352-1382 
  ...eLspClient.ts |   32.78 |       80 |   16.66 |   32.78 | ...89-293,299-300 
  ...LspService.ts |      60 |    73.36 |   78.26 |      60 | ...1575,1635-1645 
  configHash.ts    |     100 |      100 |     100 |     100 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/mcp           |    82.3 |    77.81 |   78.33 |    82.3 |                   
  configHash.ts    |     100 |      100 |     100 |     100 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...h-provider.ts |   86.95 |      100 |   33.33 |   86.95 | ...,93,97,101-102 
  ...h-provider.ts |   79.31 |    58.06 |     100 |   79.31 | ...26-933,940-942 
  ...en-storage.ts |   98.78 |    97.95 |     100 |   98.78 | 106-107           
  oauth-utils.ts   |   73.61 |    85.48 |    92.3 |   73.61 | ...46-366,392-421 
  ...n-provider.ts |   89.83 |       96 |   45.45 |   89.83 | ...43,147,151-152 
 .../token-storage |   82.12 |    88.19 |   89.28 |   82.12 |                   
  ...en-storage.ts |     100 |      100 |     100 |     100 |                   
  ...en-storage.ts |   87.08 |    87.03 |   95.23 |   87.08 | ...00-201,214-215 
  ...en-storage.ts |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...en-storage.ts |   68.14 |    82.35 |   64.28 |   68.14 | ...81-295,298-314 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/memory        |   87.58 |    83.46 |    90.5 |   87.58 |                   
  ...y-document.ts |   89.52 |    84.61 |     100 |   89.52 | ...24-325,329-330 
  ...nel-memory.ts |   97.11 |    95.72 |   96.29 |   97.11 | ...85-287,361-362 
  const.ts         |   94.28 |     92.3 |     100 |   94.28 | 66-67             
  dream.ts         |    64.6 |    72.22 |      50 |    64.6 | ...04-109,124-165 
  ...entPlanner.ts |     100 |    81.81 |     100 |     100 | 136,146           
  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.59 |    76.19 |     100 |   91.59 | ...05,114-117,293 
  ...ionPlanner.ts |       0 |        0 |       0 |       0 | 1                 
  forget.ts        |   81.83 |       75 |   83.33 |   81.83 | ...51,474,478-507 
  indexer.ts       |   94.14 |       84 |     100 |   94.14 | ...32-233,334,337 
  ...kill-agent.ts |   97.94 |    89.36 |     100 |   97.94 | 82-83,179-180     
  manager.ts       |    78.4 |    82.29 |   77.77 |    78.4 | ...1482,1495-1497 
  ...ent-config.ts |   86.95 |    82.52 |   86.36 |   86.95 | ...68,388,395-401 
  memoryAge.ts     |   90.47 |       80 |     100 |   90.47 | 50-51             
  paths.ts         |   95.29 |    96.59 |     100 |   95.29 | ...80-381,402-403 
  ...ing-skills.ts |     100 |       72 |     100 |     100 | 31-35,73-78,97    
  prompt.ts        |   97.26 |    87.03 |     100 |   97.26 | ...10-218,222,225 
  recall.ts        |   82.06 |       75 |    90.9 |   82.06 | ...59-364,395-406 
  refresh.ts       |   89.85 |    82.92 |     100 |   89.85 | ...54-155,162-163 
  ...ceSelector.ts |    93.1 |    81.81 |     100 |    93.1 | ...25,127-128,136 
  remember.ts      |   98.89 |    89.79 |     100 |   98.89 | 50,70             
  scan.ts          |   93.12 |    77.41 |     100 |   93.12 | ...08-109,154,157 
  scopes.ts        |     100 |      100 |     100 |     100 |                   
  ...et-scanner.ts |     100 |      100 |     100 |     100 |                   
  ...entPlanner.ts |   77.03 |    73.41 |   72.22 |   77.03 | ...47-451,454,460 
  status.ts        |   10.52 |      100 |       0 |   10.52 | 41-98             
  store.ts         |   92.92 |     82.6 |     100 |   92.92 | ...16-117,147-148 
  ...git-status.ts |     100 |     87.5 |     100 |     100 | 30                
  ...cret-guard.ts |     100 |      100 |     100 |     100 |                   
  ...emory-sync.ts |   94.24 |    82.85 |     100 |   94.24 | ...34-236,246-247 
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...ontextFile.ts |   81.21 |    81.53 |   81.81 |   81.21 | ...63-277,291-296 
 src/mocks         |       0 |        0 |       0 |       0 |                   
  msw.ts           |       0 |        0 |       0 |       0 | 1-9               
 src/models        |   92.55 |    88.97 |   91.13 |   92.55 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...tor-config.ts |   97.77 |    91.83 |     100 |   97.77 | 155,161,171       
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...nfigErrors.ts |   74.22 |    47.82 |   84.61 |   74.22 | ...,67-74,106-117 
  ...igResolver.ts |   98.71 |    93.33 |     100 |   98.71 | 166,328,334       
  modelRegistry.ts |     100 |    98.11 |     100 |     100 | 177,261           
  modelsConfig.ts  |   89.36 |    86.93 |   88.09 |   89.36 | ...1404,1433-1434 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/output        |     100 |      100 |     100 |     100 |                   
  ...-formatter.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/permissions   |   83.77 |    91.27 |   71.07 |   83.77 |                   
  autoMode.ts      |   97.66 |    93.13 |     100 |   97.66 | ...82-589,635,712 
  ...transcript.ts |      98 |    84.61 |     100 |      98 | 200-201           
  classifier.ts    |      94 |    94.54 |     100 |      94 | 158-165,389-393   
  ...erousRules.ts |     100 |    89.36 |     100 |     100 | 110,133,147,175   
  ...alTracking.ts |     100 |      100 |     100 |     100 |                   
  ...e-commands.ts |   86.77 |     73.8 |     100 |   86.77 | 131-141,210-214   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...on-manager.ts |   86.54 |    89.63 |      80 |   86.54 | ...1096,1202-1206 
  rule-parser.ts   |   94.49 |    92.72 |     100 |   94.49 | ...1447,1481-1483 
  ...-semantics.ts |   70.44 |    91.07 |   46.66 |   70.44 | ...2237,2311-2314 
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...sifier-prompts |   99.04 |    95.23 |     100 |   99.04 |                   
  system-prompt.ts |   99.04 |    95.23 |     100 |   99.04 | 220               
 src/prompts       |   83.63 |      100 |    87.5 |   83.63 |                   
  mcp-prompts.ts   |   18.18 |      100 |       0 |   18.18 | 11-19             
  ...t-registry.ts |     100 |      100 |     100 |     100 |                   
 src/providers     |   83.71 |     78.5 |   81.25 |   83.71 |                   
  all-providers.ts |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  install.ts       |   93.11 |     84.5 |     100 |   93.11 | ...56-257,330-331 
  ...der-config.ts |   75.85 |    73.84 |   78.26 |   75.85 | ...73-474,502-503 
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...viders/presets |   97.82 |    91.66 |   63.63 |   97.82 |                   
  ...oding-plan.ts |   87.34 |      100 |       0 |   87.34 | 82-84,87-89,91-94 
  ...a-standard.ts |     100 |      100 |     100 |     100 |                   
  ...token-plan.ts |     100 |      100 |     100 |     100 |                   
  ...m-provider.ts |   97.05 |    81.25 |      75 |   97.05 | 118-119           
  deepseek.ts      |     100 |      100 |     100 |     100 |                   
  grok.ts          |     100 |      100 |     100 |     100 |                   
  idealab.ts       |     100 |      100 |     100 |     100 |                   
  minimax.ts       |     100 |      100 |     100 |     100 |                   
  modelscope.ts    |     100 |      100 |     100 |     100 |                   
  openrouter.ts    |     100 |      100 |     100 |     100 |                   
  requesty.ts      |     100 |      100 |     100 |     100 |                   
  zai.ts           |     100 |      100 |     100 |     100 |                   
 src/qwen          |   85.41 |    78.52 |   95.89 |   85.41 |                   
  ...tGenerator.ts |   98.64 |    98.18 |     100 |   98.64 | 105-106           
  qwenOAuth2.ts    |   82.79 |    73.29 |   90.62 |   82.79 | ...1205-1221,1251 
  ...kenManager.ts |   85.36 |    76.61 |     100 |   85.36 | ...52-757,778-783 
 src/resources     |     100 |      100 |     100 |     100 |                   
  ...e-registry.ts |     100 |      100 |     100 |     100 |                   
 src/services      |   89.49 |    84.29 |   96.93 |   89.49 |                   
  ...ionTrailer.ts |     100 |      100 |     100 |     100 |                   
  ...llRegistry.ts |   97.68 |    85.71 |     100 |   97.68 | ...96,119,490-491 
  ...ionService.ts |   96.72 |    95.38 |     100 |   96.72 | ...30,746,879-887 
  ...ingService.ts |   90.91 |    84.21 |   95.45 |   90.91 | ...2058,2085-2086 
  ...ttribution.ts |   91.73 |    87.71 |      90 |   91.73 | ...80-685,826-827 
  ...utSlimming.ts |    97.2 |    94.05 |     100 |    97.2 | ...39-340,378-381 
  cronScheduler.ts |   94.17 |    90.45 |      98 |   94.17 | ...1333,1736-1737 
  cronTasksFile.ts |   96.31 |    91.81 |     100 |   96.31 | ...11,336-337,483 
  cronTasksLock.ts |   94.44 |    89.47 |     100 |   94.44 | ...02-103,132-133 
  ...eryService.ts |   96.22 |    93.54 |      90 |   96.22 | 121,155-156,161   
  ...oryService.ts |   88.17 |    79.02 |    92.3 |   88.17 | ...1303,1344-1347 
  fileReadCache.ts |     100 |      100 |     100 |     100 |                   
  ...temService.ts |    92.8 |    84.68 |   94.11 |    92.8 | ...41,467-474,519 
  ...ratedFiles.ts |      96 |    88.23 |     100 |      96 | 119-120,146-147   
  gitInit.ts       |     100 |      100 |     100 |     100 |                   
  ...reeService.ts |    73.7 |    68.49 |   95.83 |    73.7 | ...2196,2225-2226 
  ...on-service.ts |   87.38 |       72 |     100 |   87.38 | ...01-305,343-344 
  ...references.ts |   98.39 |    88.76 |     100 |   98.39 | 154-155,215-216   
  ...ionService.ts |   98.22 |    97.34 |     100 |   98.22 | ...75-676,723-724 
  ...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.3 |    91.22 |     100 |    97.3 | ...53-454,611-612 
  ...ttachments.ts |   97.74 |     90.8 |     100 |   97.74 | 298-308,646       
  ...ersistence.ts |   90.95 |    78.75 |     100 |   90.95 | ...78,963-964,992 
  ...on-service.ts |   94.49 |    92.26 |   97.14 |   94.49 | ...98-600,656-664 
  ...ce-service.ts |   98.38 |    93.75 |   88.88 |   98.38 | 63-64             
  ...ipt-reader.ts |   94.52 |    89.21 |   98.03 |   94.52 | ...1111-1112,1176 
  ...est-helper.ts |       0 |        0 |       0 |       0 | 1-65              
  ...iter-lease.ts |    82.1 |     73.7 |    97.5 |    82.1 | ...2364,2376-2379 
  sessionRecap.ts  |   67.56 |    43.47 |     100 |   67.56 | ...60,178,180-183 
  ...ionService.ts |   88.94 |    83.69 |   97.14 |   88.94 | ...2450,2520-2540 
  sessionTitle.ts  |   94.19 |    73.21 |     100 |   94.19 | ...43-246,277-278 
  ...ionService.ts |   84.35 |    78.37 |   97.14 |   84.35 | ...2472,2478-2483 
  ...pInhibitor.ts |   97.42 |    92.77 |     100 |   97.42 | ...30,169,369-370 
  ...Estimation.ts |     100 |    88.23 |     100 |     100 | 118-119           
  ...ageService.ts |   97.76 |    91.59 |   93.75 |   97.76 | ...61-262,366,567 
  ...UseSummary.ts |   94.63 |    88.46 |     100 |   94.63 | ...62-164,214-215 
  ...rd-service.ts |     100 |    88.37 |     100 |     100 | ...29,145-146,241 
  ...oryService.ts |   90.72 |    84.07 |     100 |   90.72 | ...06-509,561-562 
  ...reeCleanup.ts |   14.42 |      100 |   33.33 |   14.42 | 58-186            
  ...ionService.ts |   87.98 |    86.84 |     100 |   87.98 | ...38-439,455-456 
 ...icrocompaction |   99.41 |    96.55 |     100 |   99.41 |                   
  microcompact.ts  |   99.41 |    96.55 |     100 |   99.41 | 244-245,677       
 ...s/visionBridge |   98.81 |    92.12 |     100 |   98.81 |                   
  ...capability.ts |     100 |      100 |     100 |     100 |                   
  ...part-utils.ts |     100 |      100 |     100 |     100 |                   
  ...ion-bridge.ts |   98.72 |    82.35 |     100 |   98.72 | 65,71             
  ...-constants.ts |     100 |      100 |     100 |     100 |                   
  ...ge-service.ts |   98.61 |     94.7 |     100 |   98.61 | ...06,666,679-680 
 src/skills        |   89.21 |    85.66 |   93.54 |   89.21 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...activation.ts |     100 |    93.33 |     100 |     100 | 93,112            
  skill-curator.ts |   89.52 |    80.95 |     100 |   89.52 | ...95-896,898-901 
  skill-load.ts    |   94.84 |     87.5 |     100 |   94.84 | ...03,223,235-237 
  skill-manager.ts |   84.82 |    85.29 |   83.33 |   84.82 | ...1243,1250-1254 
  skill-paths.ts   |   90.42 |     87.5 |     100 |   90.42 | ...19-120,125-126 
  symlinkScope.ts  |     100 |      100 |     100 |     100 |                   
  types.ts         |   97.91 |       98 |     100 |   97.91 | 277-278           
 ...ataviz/scripts |   80.06 |    95.23 |   88.23 |   80.06 |                   
  ...te_palette.js |   80.06 |    95.23 |   88.23 |   80.06 | 261-296,306-328   
 ...s/bundled/loop |   97.48 |    95.77 |     100 |   97.48 |                   
  ...omous-loop.ts |     100 |      100 |     100 |     100 |                   
  ...-task-file.ts |   94.85 |     92.4 |     100 |   94.85 | ...56,367,375-376 
  ...k-resolver.ts |     100 |      100 |     100 |     100 |                   
 src/subagents     |   87.72 |    89.01 |   96.55 |   87.72 |                   
  ...ter-schema.ts |     100 |    98.07 |     100 |     100 | 99                
  ...tin-agents.ts |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...nt-manager.ts |   84.48 |    85.91 |   94.87 |   84.48 | ...1582,1659-1660 
  types.ts         |     100 |      100 |     100 |     100 |                   
  validation.ts    |   92.46 |    95.18 |     100 |   92.46 | 47-52,63-68,71-76 
 src/telemetry     |   81.15 |    83.96 |   84.57 |   81.15 |                   
  ...ty-tracker.ts |     100 |      100 |     100 |     100 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...on-metrics.ts |   99.07 |    80.95 |     100 |   99.07 | 183,197           
  ...on-tracing.ts |   76.31 |    74.62 |   73.68 |   76.31 | ...80,387-389,405 
  ...attributes.ts |   95.15 |    87.27 |     100 |   95.15 | ...97-198,216-217 
  ...ag-metrics.ts |     100 |    77.77 |     100 |     100 | 21,40             
  ...t-loop-lag.ts |   96.85 |    85.71 |     100 |   96.85 | 170-173           
  ...-exporters.ts |   65.78 |    83.33 |   55.55 |   65.78 | ...04-105,108-109 
  ...ai-content.ts |    74.5 |    66.41 |   91.66 |    74.5 | ...1480,1493-1502 
  ...i-provider.ts |     100 |       99 |     100 |     100 | 99                
  ...ai-request.ts |   87.52 |    92.79 |   83.78 |   87.52 | ...55-561,564-570 
  gen-ai-usage.ts  |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...t.circular.ts |       0 |        0 |       0 |       0 | 1-111             
  ...-processor.ts |   99.09 |    95.61 |      95 |   99.09 | 141,365-366       
  ...t.circular.ts |       0 |        0 |       0 |       0 | 1-128             
  loggers.ts       |   56.85 |    74.35 |   64.81 |   56.85 | ...1397,1414-1434 
  metrics.ts       |   79.63 |    81.98 |   79.66 |   79.63 | ...1082,1085-1096 
  otlp-urls.ts     |     100 |      100 |     100 |     100 |                   
  ...attributes.ts |     100 |      100 |     100 |     100 |                   
  ...ime-config.ts |       0 |        0 |       0 |       0 | 1                 
  sanitize.ts      |      80 |    83.33 |     100 |      80 | 35-36,41-42       
  ...rters-grpc.ts |     100 |      100 |     100 |     100 |                   
  ...rters-http.ts |     100 |      100 |     100 |     100 |                   
  sdk-impl.ts      |   91.06 |    87.15 |   68.75 |   91.06 | ...32,478-479,495 
  sdk.ts           |   79.22 |    89.18 |   63.63 |   79.22 | ...57-161,199-221 
  ...on-context.ts |     100 |      100 |     100 |     100 |                   
  ...on-tracing.ts |   90.83 |    90.05 |   96.77 |   90.83 | ...1667,1698-1701 
  ...etry-utils.ts |     100 |      100 |     100 |     100 |                   
  ...l-decision.ts |     100 |      100 |     100 |     100 |                   
  trace-context.ts |     100 |      100 |     100 |     100 |                   
  ...e-id-utils.ts |     100 |      100 |     100 |     100 |                   
  tracer.ts        |   98.56 |    88.63 |     100 |   98.56 | 52,101            
  types.ts         |   82.35 |    94.61 |   86.04 |   82.35 | ...1361,1365-1372 
  uiTelemetry.ts   |   97.18 |    93.93 |      88 |   97.18 | ...70,314,461-462 
 ...ry/qwen-logger |   74.17 |    80.53 |      70 |   74.17 |                   
  event-types.ts   |       0 |        0 |       0 |       0 |                   
  qwen-logger.ts   |   74.17 |    80.35 |   69.49 |   74.17 | ...1120,1158-1159 
 src/test-utils    |      94 |    98.24 |   78.94 |      94 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  ...st-helpers.ts |   94.11 |       90 |     100 |   94.11 | 69-70             
  index.ts         |     100 |      100 |     100 |     100 |                   
  mock-tool.ts     |   92.57 |      100 |   75.75 |   92.57 | ...63,227-228,241 
  ...aceContext.ts |     100 |      100 |     100 |     100 |                   
 src/tools         |   86.01 |    84.81 |   88.36 |   86.01 |                   
  ...erQuestion.ts |   89.71 |    80.76 |   91.66 |   89.71 | ...66-367,374-375 
  ...-registrar.ts |    77.7 |    66.66 |   66.66 |    77.7 | ...72-277,292-294 
  ...ub-session.ts |   89.67 |     91.3 |   81.81 |   89.67 | ...03-304,315-322 
  cron-create.ts   |   90.64 |    92.85 |   72.72 |   90.64 | ...,73-74,223-231 
  cron-delete.ts   |   97.56 |      100 |   83.33 |   97.56 | 31-32             
  cron-list.ts     |   98.23 |    95.34 |    87.5 |   98.23 | 57-58             
  diffOptions.ts   |     100 |      100 |     100 |     100 |                   
  display-image.ts |   87.42 |    84.84 |   88.88 |   87.42 | ...29-134,194-195 
  edit.ts          |    82.7 |    86.77 |   81.25 |    82.7 | ...43-744,863-913 
  ...r-worktree.ts |   83.14 |    67.56 |    87.5 |   83.14 | ...84-187,278-279 
  enterPlanMode.ts |      85 |     82.6 |    87.5 |      85 | ...28-133,161-175 
  exit-worktree.ts |   83.29 |    83.65 |   94.44 |   83.29 | ...14-515,537-538 
  exitPlanMode.ts  |      95 |    85.29 |     100 |      95 | ...21-325,344,378 
  ...permission.ts |     100 |      100 |     100 |     100 |                   
  glob.ts          |   96.33 |     88.5 |     100 |   96.33 | ...24-225,373,376 
  grep.ts          |   90.73 |    86.61 |   85.71 |   90.73 | ...76-677,727-728 
  ...adTracking.ts |     100 |      100 |     100 |     100 |                   
  image-gen.ts     |   91.66 |    77.41 |    90.9 |   91.66 | ...13-214,221-222 
  list-agents.ts   |   94.02 |    82.35 |   83.33 |   94.02 | 31-32,47-48       
  loop-wakeup.ts   |   99.27 |    92.85 |     100 |   99.27 | 45                
  ls.ts            |   96.74 |    90.27 |     100 |   96.74 | 176-181,212,216   
  lsp.ts           |   72.71 |     59.5 |   90.32 |   72.71 | ...1212,1214-1215 
  ...nt-manager.ts |   81.49 |     80.1 |   85.71 |   81.49 | ...3217,3219-3220 
  mcp-client.ts    |   79.87 |    85.58 |   89.47 |   79.87 | ...2259,2263-2266 
  ...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 |        0 |       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      |    97.2 |    93.47 |     100 |    97.2 | ...00-801,856-857 
  ...sport-pool.ts |   83.49 |    80.15 |   84.61 |   83.49 | ...1409,1416-1420 
  ...ace-budget.ts |   87.27 |     82.6 |     100 |   87.27 | ...00-305,340-345 
  memory-config.ts |     100 |      100 |     100 |     100 |                   
  ...iable-tool.ts |     100 |    84.61 |     100 |     100 | 101,108           
  monitor.ts       |   91.74 |    84.28 |   88.46 |   91.74 | ...93,606,804-809 
  notebook-edit.ts |   85.55 |    77.39 |   81.25 |   85.55 | ...86-902,948-949 
  ...escendants.ts |   36.17 |    64.51 |   55.55 |   36.17 | ...46-310,385-390 
  ...nforcement.ts |   82.57 |    90.24 |     100 |   82.57 | 174-185,234-247   
  read-file.ts     |   95.49 |    88.52 |   86.66 |   95.49 | ...49,464,536-537 
  ...p-resource.ts |   96.85 |      100 |   91.66 |   96.85 | 92-96             
  ...d-artifact.ts |   91.18 |    86.71 |    87.5 |   91.18 | ...26-427,441-453 
  ripGrep.ts       |    94.6 |    87.26 |   95.23 |    94.6 | ...33-734,740-741 
  ...-transport.ts |   71.42 |    55.55 |   71.42 |   71.42 | ...36-137,143-144 
  send-message.ts  |   81.13 |    89.74 |    62.5 |   81.13 | ...80-286,363-371 
  ...n-mcp-view.ts |   93.57 |     92.3 |      90 |   93.57 | 122-130           
  shell.ts         |   78.67 |    84.04 |   91.91 |   78.67 | ...5019,5082-5083 
  skill-utils.ts   |     100 |      100 |     100 |     100 |                   
  skill.ts         |   91.39 |    92.55 |      90 |   91.39 | ...84,488,534-556 
  ...eticOutput.ts |   95.12 |      100 |      80 |   95.12 | 87-88             
  task-create.ts   |    94.4 |    93.33 |   81.81 |    94.4 | 45-49,63-64,95    
  task-list.ts     |   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     |   95.12 |    87.94 |   93.33 |   95.12 | ...22-526,539-544 
  tool-error.ts    |     100 |      100 |     100 |     100 |                   
  tool-names.ts    |     100 |      100 |     100 |     100 |                   
  tool-registry.ts |   78.57 |    79.59 |    82.6 |   78.57 | ...89-990,998-999 
  tool-search.ts   |   96.19 |    89.72 |   93.33 |   96.19 | ...09,259-264,426 
  tools.ts         |   93.11 |    92.53 |   91.66 |   93.11 | ...69-570,586-592 
  ...reapproved.ts |   99.27 |    94.11 |     100 |   99.27 | 170               
  web-fetch.ts     |   96.05 |    90.54 |   96.77 |   96.05 | ...85-786,800-801 
  web-search.ts    |   90.53 |    83.57 |      80 |   90.53 | ...1007,1065-1068 
  write-file.ts    |    86.7 |    84.92 |   88.88 |    86.7 | ...24-827,864-899 
  zoom-image.ts    |   95.76 |    93.75 |      90 |   95.76 | 54-59,203-204     
 src/tools/agent   |    86.9 |    87.48 |   88.69 |    86.9 |                   
  agent.ts         |   85.52 |     86.4 |   86.31 |   85.52 | ...4315,4337-4347 
  fork-profile.ts  |   93.65 |       90 |     100 |   93.65 | ...33-134,171-174 
  fork-subagent.ts |   98.67 |     94.8 |     100 |   98.67 | 101-102,173       
 ...tools/artifact |   95.78 |    92.51 |   88.63 |   95.78 |                   
  artifact-tool.ts |   91.46 |    88.46 |   71.42 |   91.46 | ...13-314,322-325 
  ...-publisher.ts |     100 |    85.71 |     100 |     100 | 32                
  ...-publisher.ts |   96.74 |    97.72 |    87.5 |   96.74 | 29-30,156-157     
  html.ts          |     100 |    96.77 |     100 |     100 | 122               
  ...-publisher.ts |     100 |       80 |     100 |     100 | 30                
  oss-publisher.ts |    98.1 |    91.48 |     100 |    98.1 | 43-45             
  publisher.ts     |     100 |      100 |     100 |     100 |                   
 ...s/computer-use |   90.21 |    82.17 |   78.08 |   90.21 |                   
  bootstrap.ts     |   59.42 |    80.95 |   41.66 |   59.42 | ...35-339,341-345 
  client.ts        |   80.11 |       90 |   77.77 |   80.11 | ...97,242-243,274 
  constants.ts     |     100 |    94.73 |     100 |     100 | 129,256           
  downloader.ts    |   65.29 |    52.77 |   58.33 |   65.29 | ...99-300,316-355 
  index.ts         |     100 |      100 |     100 |     100 |                   
  install-state.ts |   94.44 |    72.72 |     100 |   94.44 | 44-45             
  ...n-detector.ts |     100 |     87.5 |     100 |     100 | 50                
  schemas.ts       |     100 |      100 |     100 |     100 |                   
  tool.ts          |    96.3 |    85.71 |     100 |    96.3 | 75-76,184,252-258 
 ...tools/workflow |   86.24 |    84.81 |      75 |   86.24 |                   
  workflow.ts      |   86.24 |    84.81 |      75 |   86.24 | ...61,506,508-509 
 src/utils         |   92.84 |    89.61 |   96.84 |   92.84 |                   
  LruCache.ts      |     100 |      100 |     100 |     100 |                   
  ...Controller.ts |     100 |      100 |     100 |     100 |                   
  ...ssageQueue.ts |     100 |      100 |     100 |     100 |                   
  ...cFileWrite.ts |   94.94 |    92.47 |     100 |   94.94 | ...43-544,651-655 
  bareMode.ts      |   81.81 |      100 |      50 |   81.81 | 18-19             
  ...ry-content.ts |   98.45 |    95.45 |     100 |   98.45 | 132-133,159-160   
  browser.ts       |   86.84 |    78.94 |     100 |   86.84 | 34,36-37,65-66    
  btwUtils.ts      |   13.95 |      100 |       0 |   13.95 | 17-31,34-55       
  bundlePaths.ts   |     100 |      100 |     100 |     100 |                   
  ...on-context.ts |     100 |      100 |     100 |     100 |                   
  ...ncyLimiter.ts |   94.64 |    95.23 |     100 |   94.64 | 64-66             
  ...igResolver.ts |     100 |      100 |     100 |     100 |                   
  ...engthError.ts |   91.06 |    89.47 |     100 |   91.06 | ...46-147,154-155 
  ...n-branches.ts |   95.81 |    93.95 |      95 |   95.81 | ...91-492,504-517 
  ...tion-chain.ts |     100 |      100 |     100 |     100 |                   
  cronDisplay.ts   |     100 |    97.61 |     100 |     100 | 46                
  cronParser.ts    |   95.34 |    93.33 |     100 |   95.34 | 41-42,47-48,70-71 
  debugLogger.ts   |   96.66 |    96.61 |   88.88 |   96.66 | 192-196           
  editHelper.ts    |   93.63 |     83.9 |     100 |   93.63 | ...27-428,462-463 
  editor.ts        |   97.65 |    95.45 |     100 |   97.65 | ...35-336,338-339 
  encoding.ts      |     100 |      100 |     100 |     100 |                   
  env.ts           |     100 |      100 |     100 |     100 |                   
  ...arResolver.ts |   94.28 |    88.88 |     100 |   94.28 | 28-29,125-126     
  ...entContext.ts |   96.63 |    90.13 |   96.66 |   96.63 | ...42,444-445,512 
  errorParsing.ts  |     100 |      100 |     100 |     100 |                   
  ...rReporting.ts |   95.65 |    93.33 |     100 |   95.65 | 37-38             
  errors.ts        |   82.62 |    94.32 |    61.9 |   82.62 | ...62-378,382-388 
  fetch.ts         |   90.68 |    82.51 |     100 |   90.68 | ...72,483-484,503 
  fileUtils.ts     |   94.87 |    92.95 |   96.15 |   94.87 | ...1907,1915-1916 
  forkedAgent.ts   |   92.45 |    82.35 |   93.75 |   92.45 | ...34,642,647-654 
  formatters.ts    |     100 |      100 |     100 |     100 |                   
  ...eUtilities.ts |    92.4 |    86.95 |     100 |    92.4 | ...52-158,168-169 
  ...rStructure.ts |   94.39 |    94.28 |     100 |   94.39 | ...29-132,343-348 
  getPty.ts        |   31.57 |       50 |     100 |   31.57 | 26-38             
  git-branches.ts  |    91.6 |    84.21 |    92.3 |    91.6 | ...90,405-410,570 
  gitDiff.ts       |   95.19 |    81.36 |     100 |   95.19 | ...1073,1419-1420 
  gitDirect.ts     |   98.84 |    94.28 |     100 |   98.84 | 234,318           
  ...noreParser.ts |   94.48 |    93.22 |     100 |   94.48 | ...23-124,158-159 
  gitUtils.ts      |   78.02 |    81.25 |   85.71 |   78.02 | ...22-123,147-198 
  github-prs.ts    |   95.74 |    82.27 |     100 |   95.74 | 216,314-322       
  iconvHelper.ts   |     100 |      100 |     100 |     100 |                   
  ...rePatterns.ts |     100 |      100 |     100 |     100 |                   
  image-view.ts    |   95.12 |    93.33 |     100 |   95.12 | ...68-172,240-244 
  ...ionManager.ts |     100 |     90.9 |     100 |     100 | 27                
  ...lPromptIds.ts |     100 |      100 |     100 |     100 |                   
  ...on-context.ts |     100 |      100 |     100 |     100 |                   
  jsonl-utils.ts   |   95.27 |    93.25 |     100 |   95.27 | ...16-317,359-362 
  ...-detection.ts |     100 |      100 |     100 |     100 |                   
  ...iconv-lite.ts |     100 |      100 |     100 |     100 |                   
  ...simple-git.ts |   96.77 |    91.66 |     100 |   96.77 | 38                
  ...m-headless.ts |      96 |    88.88 |     100 |      96 | 34                
  ...iagnostics.ts |    96.4 |     94.2 |     100 |    96.4 | ...66,293-294,376 
  ...yDiscovery.ts |    92.4 |    89.13 |     100 |    92.4 | ...28,331,522-525 
  ...tProcessor.ts |   94.01 |       90 |     100 |   94.01 | ...47-353,445-446 
  ...Inspectors.ts |     100 |      100 |     100 |     100 |                   
  modelId.ts       |   98.96 |    98.21 |     100 |   98.96 | 153               
  ...kerChecker.ts |    90.9 |    91.66 |     100 |    90.9 | 73-79             
  notebook.ts      |   94.57 |    89.91 |   95.83 |   94.57 | ...21,333,385-387 
  openaiLogger.ts  |   91.66 |    89.74 |     100 |   91.66 | ...26-228,251-256 
  osc8.ts          |   54.26 |    64.86 |   83.33 |   54.26 | ...72-195,197-257 
  partUtils.ts     |     100 |    98.64 |     100 |     100 | 211               
  pathReader.ts    |     100 |      100 |     100 |     100 |                   
  paths.ts         |   93.99 |    92.85 |     100 |   93.99 | ...88-489,491-493 
  pdf.ts           |   92.17 |    85.81 |     100 |   92.17 | ...64-565,606-611 
  projectPath.ts   |     100 |      100 |     100 |     100 |                   
  projectRoot.ts   |   71.73 |    78.57 |     100 |   71.73 | 54-66             
  ...ectSummary.ts |   89.62 |    72.41 |     100 |   89.62 | ...40-145,196-199 
  ...tIdContext.ts |     100 |      100 |     100 |     100 |                   
  proxyUtils.ts    |     100 |      100 |     100 |     100 |                   
  ...rDetection.ts |   71.15 |       86 |     100 |   71.15 | ...-90,96-101,147 
  ...noreParser.ts |   92.63 |    91.66 |     100 |   92.63 | ...77-178,197-198 
  rateLimit.ts     |   93.75 |    89.62 |     100 |   93.75 | ...13,218-219,262 
  ...text-range.ts |    96.9 |    86.85 |     100 |    96.9 | ...59-660,735-736 
  readManyFiles.ts |   95.75 |    80.86 |     100 |   95.75 | ...05,558,568-572 
  retry.ts         |   96.09 |    92.52 |     100 |   96.09 | ...67,558-559,577 
  retryContext.ts  |     100 |      100 |     100 |     100 |                   
  ...sification.ts |   97.63 |    97.02 |     100 |   97.63 | ...17,251-252,278 
  retryPolicy.ts   |   97.72 |    90.56 |     100 |   97.72 | 130-131           
  ripgrepUtils.ts  |   90.04 |    93.43 |   95.45 |   90.04 | ...55-565,598-599 
  ...sDiscovery.ts |   97.46 |    93.05 |     100 |   97.46 | ...04,182-183,202 
  ...iagnostics.ts |   83.08 |     67.5 |   92.59 |   83.08 | ...23,543-544,550 
  ...tchOptions.ts |   84.87 |    86.61 |   96.29 |   84.87 | ...71,696,725-734 
  ...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 |     100 |      100 |     100 |     100 |                   
  ...nStringify.ts |     100 |      100 |     100 |     100 |                   
  ...-child-env.ts |     100 |      100 |     100 |     100 |                   
  ...aConverter.ts |   98.03 |    97.75 |     100 |   98.03 | 100,102-103       
  ...aValidator.ts |   92.09 |    83.65 |   90.47 |   92.09 | ...60,882-883,896 
  ...r-launcher.ts |   96.35 |    93.97 |   85.71 |   96.35 | ...35-336,347-348 
  sedEditParser.ts |   91.78 |    92.18 |     100 |   91.78 | ...66-569,645-646 
  ...nIdContext.ts |     100 |      100 |     100 |     100 |                   
  ...orageUtils.ts |   95.98 |    83.96 |     100 |   95.98 | ...70,386,466,485 
  ...-pager-env.ts |     100 |      100 |     100 |     100 |                   
  ...fety-rules.ts |     100 |     89.7 |     100 |     100 | ...01,304,309-311 
  shell-utils.ts   |   86.07 |    88.36 |     100 |   86.07 | ...2269,2276-2280 
  ...lAstParser.ts |   98.16 |    91.91 |     100 |   98.16 | ...1244-1246,1256 
  ...ContextEnv.ts |     100 |       92 |     100 |     100 | 50-52             
  ...nlyChecker.ts |   96.33 |    96.57 |     100 |   96.33 | ...83-284,292-293 
  sideQuery.ts     |   86.82 |    86.66 |     100 |   86.82 | ...79-185,187-193 
  ...pEventSink.ts |     100 |       80 |     100 |     100 | 61                
  ...tGenerator.ts |     100 |      100 |     100 |     100 |                   
  ...ameContext.ts |     100 |      100 |     100 |     100 |                   
  symlink.ts       |   77.77 |       50 |     100 |   77.77 | 44,54-59          
  ...e-encoding.ts |   85.96 |    76.47 |     100 |   85.96 | 58-61,64-65,78-79 
  ...emEncoding.ts |   96.36 |    91.17 |     100 |   96.36 | 59-60,124-125     
  terminalSafe.ts  |     100 |      100 |     100 |     100 |                   
  ...Serializer.ts |   98.72 |       90 |     100 |   98.72 | 42-43,134,201-203 
  testUtils.ts     |   53.33 |      100 |   33.33 |   53.33 | ...53,59-64,70-72 
  ...-constants.ts |     100 |      100 |     100 |     100 |                   
  textUtils.ts     |      65 |      100 |      75 |      65 | 56-75             
  thoughtUtils.ts  |     100 |    95.65 |     100 |     100 | 99                
  ...-converter.ts |   95.23 |    85.71 |     100 |   95.23 | 36-37             
  ...name-utils.ts |     100 |      100 |     100 |     100 |                   
  ...-finalizer.ts |   97.66 |     90.9 |     100 |   97.66 | 165-166,168-172   
  tool-utils.ts    |    95.2 |    93.61 |     100 |    95.2 | ...58-159,162-163 
  ...ultCleanup.ts |   54.62 |       64 |      75 |   54.62 | ...03-105,108-134 
  ...Compaction.ts |   96.13 |    96.42 |     100 |   96.13 | ...34-339,341-346 
  ...pt-records.ts |   85.85 |    83.78 |     100 |   85.85 | ...90-394,424-439 
  truncation.ts    |   90.56 |    90.43 |     100 |   90.56 | ...35-443,480-486 
  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.94 |    80.72 |   94.73 |   83.94 |                   
  crawlCache.ts    |     100 |      100 |     100 |     100 |                   
  crawler.ts       |    82.9 |    76.81 |   95.08 |    82.9 | ...1563,1597-1598 
  fileSearch.ts    |   93.78 |    87.67 |     100 |   93.78 | ...71-272,274-275 
  fzfWorker.ts     |       0 |        0 |       0 |       0 | 1-109             
  ...rkerHandle.ts |   84.05 |    75.43 |   89.47 |   84.05 | ...30-334,340-341 
  ignore.ts        |     100 |    97.36 |     100 |     100 | 187               
  result-cache.ts  |     100 |    93.75 |     100 |     100 | 49                
 ...uest-tokenizer |   69.76 |    75.47 |   85.29 |   69.76 |                   
  ...eTokenizer.ts |   65.72 |    74.02 |    92.3 |   65.72 | ...65-466,479-533 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...tTokenizer.ts |   68.39 |    69.49 |    90.9 |   68.39 | ...24-325,327-328 
  ...ageFormats.ts |   76.92 |      100 |   33.33 |   76.92 | 46-49,56-57       
  textTokenizer.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |       0 |        0 |       0 |       0 | 1                 
-------------------|---------|----------|---------|---------|-------------------

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

@wenshao

wenshao commented Aug 1, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /triage

@yiliang114 yiliang114 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM on re-review. The four Copilot findings are all fixed correctly:

  • Table cell escaping: backslash-first ordering is right (pipe-first would produce \\| → escaped backslash + live separator). The liveSeparators test is a good oracle.
  • Side-file write: mkdirSync + try/catch preserves best-effort semantics.
  • parseLedger last-marker: lastIndexOf is the correct choice for edited/quote-carrying bodies.
  • Doc comment reattached.

Also verified: stripLedgerMarker is applied at every model-facing render site (worth-showing filter, fullBody quoteBlock, meaningful count) — no path leaks the JSON blob as prose.

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Sandboxed verification: ✅ passed — merge-ready (agent verdict) - workflow run

Ran the PR in an isolated, token-free container: A/B against the base build, mock-free harness assertions, targeted gates. Advisory evidence for human reviewers — not a review, an approval, or a CI check.

Scripted assertions: 68 passed · 0 failed · 68 total

中文 — 判定:✅ 通过 · 可合入(agent 判定)

沙箱验证在隔离、无凭证的容器中执行了该 PR 的代码(与 base 构建 A/B 对照、无 mock harness 断言、定向门禁)。仅作为评审证据,不构成评审、批准或 CI 检查

脚本断言:68 通过 · 0 失败 · 68 总计

Verification report

/verify-pr 8255 — deep verification

Verdict: merge-ready — 68/68 scripted harness assertions passed, 0 failed; targeted gate green (47 files, 1403 passed | 3 skipped); central claim proven load-bearing by A/B. No blocking findings; two informational corrections to the PR description.

  • Verified head: 24c6d3e22203334dce063761384679912b6cea9e (git rev-parse HEAD^2)
  • Base (control): dbb034935193ce980585503a74b5f06ef27db5e0 (HEAD^1)
  • Merge commit under test: 4bda57d1c7e97c6ef9507f98302c17e9524551af
  • PR: feat(review): carry the round ledger in the posted review body #8255 "feat(review): carry the round ledger in the posted review body" (author @​wenshao)
中文摘要

结论:merge-ready 68/68 脚本化断言通过、0 失败;定向门禁全绿(47 文件,1403 通过 | 3 跳过);中心主张经 A/B 证明为承重。无阻塞性发现;仅对 PR 描述有两处信息性更正。

  • A/B 结论:同一输入下,HEAD 的 composeReview 在返回正文末尾嵌入台账 marker(round 1、两条 finding、id R1-1/R1-2;轮次按 side 文件 +1,4→5;本地复审不带 marker),BASE(HEAD^1)正文以普通 footer 收尾、无 marker,且 buildLedger 在 base 不存在。改动承重,见 01-ab-compose-head-vs-base.png
  • 改动面(mock-free 线oracle)ledger.ts 37/37(往返无损、畸形输入全部静默返回 null 且不抛异常、四组上限组合 kept+dropped==given、-- 无损转义、剥离每个 marker、O(n) 无 ReDoS、标题内伪造 marker 被转义中和);pr-context.ts 22/22(仅本账号/最新/同秒按 id 决胜、表格注入消毒——含「反斜杠先于竖线」具名修复——经正控校验的 oracle 证实无法伪造行/列)。见 02/03
  • 空转检验:对两个承重 hunk 各做单点突变——回退 HEAD^2 的 dropped 计数修复 → expected 50 to be 51(1 红);删除 -- 转义 → not to contain '--'(2 红);还原后 12/12 绿。测试非空转、门禁是活的。见 04-mutation-matrix.png
  • findings:无阻塞。两处描述更正(见下)。残余风险(台账标题作为「仅供参考」工作清单进入模型上下文)被「仅本账号读取 + 每条须对照代码重裁 + 解析静默失败 + 尺寸上限」界定;无法在无真实模型轮的情况下行为性证明模型遵守「仅供参考」契约。
  • 未覆盖:逐 commit 归因(浅克隆 depth 2,92 个 commit 不可逐个到达,仅验证 HEAD^1..HEAD 聚合 diff);真实「发布→拉取」往返(沙箱无 GitHub token,PR 自身亦声明范围外);GitHub 对 HTML 注释的实际渲染;模型侧行为。base 控制构建在与本 PR 无关的模块(测试文件缺 @testing-library/react、生成的 git-commit.js@lydell/node-pty 类型)上有类型错误但仍产出了 JS——已验证 base 产物确为 base(0 处 marker 引用 vs head 的 4 处)、可正常导入运行,A/B 成立;core 仅文档变更,workspace 软链不构成混淆。

Central claim + A/B

Central claim: the /review round ledger is carried in the posted review body as an invisible HTML-comment marker — compose-review embeds it, pr-context recovers the reviewing account's latest copy on the next round — so the ledger survives across environments (CI, another machine) where the local cache file does not exist.

The A/B drives the real compiled composeReview (the pure function submit posts the return of) with an identical input on both arms:

cell build oracle result
HEAD packages/cli/dist/.../compose-review.js body carries marker; parses to round 1; both findings; ids R1-1,R1-2 ✅ marker present
HEAD same round counted off recovered side file (+1): 4 → 5
HEAD control same, no planPath a local review carries no marker ✅ no marker
BASE (HEAD^1) tmp/base-tree/.../compose-review.js identical input → body carries no marker ✅ no marker (ends _— m via Qwen Code /review…_)
BASE same buildLedger export ✅ absent (typeof undefined)

Witness: 01-ab-compose-head-vs-base.png. The base artifact was verified genuinely base before use (0 marker references vs head's 4; buildLedger not exported; base source has zero ledger references). The change is load-bearing: 9/9 A/B assertions pass.

Changed-surface harnesses (mock-free, compiled dist)

02-ledger-harness-head.pngledger.ts, 37/37:

  • round-trip through a posted body is lossless;
  • 11 malformations (bad JSON, wrong version, round 0 / 1.5 / negative / missing, findings-not-array, unterminated) each return null, none throw; shape-invalid entries dropped, valid siblings kept;
  • caps + dropped across all four combinations — count-cap-only (51→kept 50/dropped 1), byte-cap-only (50→24/26), both (51→24/27), neither (3→3/0): kept + dropped == given in every one, marker always ≤ 8192 B. The both cell (27, not 26) is exactly the HEAD^2 fix;
  • -- is comment-safe (no raw -- in payload) and lossless — a title quoting --comment returns verbatim, never an em dash; siblings ---, -->, a---b, --x-- all lossless;
  • parseLedger reads the LAST marker; stripLedgerMarker removes EVERY marker and leaves an unterminated one intact;
  • sibling sweep: a forged marker embedded inside a finding title does not surface a forged finding — the -- escape neutralises the embedded &lt;!\-\-/ --> delimiters, so lastIndexOf(OPEN) still lands on the real marker (the escape defeats marker-forgery, not just comment-breakage);
  • scaling ladder: parseLedger is O(n) — 2 M chars in 0.4 ms (no marker) / 0.8 ms (buried marker); no ReDoS (parse path is indexOf/lastIndexOf + JSON.parse, the only regex runs over the serializer's own output).

03-pr-context-harness-head.pngpr-context.ts, 22/22:

  • latestOwnLedger: own-account only (a foreign login's newer/higher marker is ignored), latest submitted_at wins over array order and id, a submitted_at tie breaks on the higher review id in both array orders, null on no-login / no-marker / malformed, no throw on undefined fields;
  • renderLedgerSection: PARTIAL line appears iff dropped>0; table-injection oracle (positive-controlled: a clean row = 6 live cells, an unescaped-pipe forge = 7) — pipe/newline/CRLF/backslash-pipe/double-backslash-pipe in titles and pipe/backtick in file paths all stay at 6 cells (no forged row or column); a backtick in a path is neutralised to ' and stays inside its code span (exactly the 2 wrapping backticks survive). The backslash-before-pipe ordering — the named fix — holds.

Vacuity / gate liveness

04-mutation-matrix.pnglib/ledger.test.ts (12 tests):

state result signal
unmutated (HEAD) 12/12 green — (positive control)
mutant A: dropped measured against capped.length (reverts HEAD^2) 11/12, 1 red expected 50 to be 51
mutant B: comment-safe -- escape removed 10/12, 2 red expected … not to contain '--'
restored (HEAD) 12/12 green tree clean (0 uncommitted)

Both load-bearing hunks are pinned by behavioural assertions (expected-vs-actual, not import/compile errors); 2/2 mutants killed. Targeted gate (05-targeted-gate.png): the PR's own command npx vitest run src/commands/review src/commands/review.test.ts → 47 files passed, 1403 passed | 3 skipped (1406), including ledger.test.ts 12/12, compose-review.test.ts 151, pr-context.test.ts 65, submit.test.ts 42.

Corrections (to the PR description, not code-change requests)

  1. The -- mechanism is described stale. The PR body (EN "How to verify" and 中文「验证方式」) says a body containing -- stays valid because "the serializer rewrites -- to ". The shipped serializer does not rewrite to an em dash — it escapes ---\u002d at the JSON layer, which parses back to a literal - and therefore round-trips losslessly: a title the `--comment` gate misreads ---- as a flag returns verbatim (harness check "title is NOT mutated to an em dash" passed; 02-ledger-harness-head.png). The PR's own test escapes \--` LOSSLESSLYdocuments the em-dash as the *rejected first cut* that "lies". The code is strictly better than the description (lossless re-location of the claim); only the prose lags. Suggested wording: "the serializer escapes--` so none survives into the comment, losslessly (the title round-trips verbatim)."

  2. The test count is stale. The body says "expect all 45 files and 1217 tests to pass". The merged tree runs 47 files / 1406 tests (1403 passed | 3 skipped), all green — the count moved because the stack merged up (the base tip gained review tests, e.g. feat(review): borrow recall, a fix loop, and a size-derived budget from Claude /review #8315). The "all pass" claim holds; only the numbers drifted.

Findings

No blocking findings. Two informational notes:

  • (informational) Prompt-injection surface is bounded, not zero. Recovered ledger titles reach the model as an advisory work-list table. A compromised own-account review could carry hostile instruction text in a title. This is bounded by four verified properties: own-account-only read (foreign-login marker ignored — 03), fail-quiet parse, size caps (50 × 80-char titles, 8 KiB marker), and the advisory contract (SKILL Step 6 owes every entry a re-ruling against the code; a forged entry buys wasted rulings, not a wrong verdict). I could not behaviourally prove the model honours the advisory contract without a live model round (out of scope). The PR names this contract explicitly. Note the strongest mitigation is structural: a PR author cannot inject a trusted marker — latestOwnLedger reads only reviews whose user.login equals the reviewing account, so markers in the PR body or in others' reviews are data, never authority.
  • (informational, mitigated by design) parseLedger returns null for both "no marker" and "malformed marker". This single sentinel could let a transient malformation reset the round counter to 1 — except pr-context deliberately never clears a stale side file on a failed recovery ("keeping the stale copy only ever advances the count"), and compose-review reads the round off that side file. So the ambiguity cannot move the id space backwards. Verified in code; the design matches the hazard.

Not covered

  • Per-commit attribution. Shallow merge-ref checkout (depth 2): only the merge commit, HEAD^1, HEAD^2 exist locally. git rev-list --count HEAD^1..HEAD^2 returns an unreliable 1 at the shallow boundary; the 92 commits in the metadata snapshot are not individually reachable. Verified the aggregate HEAD^1..HEAD diff only.
  • Live posted round-trip. No GitHub token in this sandbox (and gh requires auth even for public reads), so no actual post→fetch cycle. I proved the wire shape end to end through the real compiled functions (serialize → embed in body → parse → render → side-file → round+1), but not a real GitHub post. The PR names this itself: "no live posted round has round-tripped the marker end to end yet … the next posted review is the natural canary."
  • GitHub's rendering of the marker as invisible-on-the-page (standard markdown HTML-comment semantics; the -- escape keeps the comment well-formed) — not tested against live GitHub.
  • submit.ts wire request body. Exercised by the gate (42 tests, including "takes its contents from the comments posted, not from state") and it posts the pure composeReview return that the A/B proved carries the marker; I did not build an independent loopback oracle for the submit→GitHub request.
  • Model-side behaviour of the rendered ledger section (does the model actually re-rule each entry) — requires a live model round.
  • Base-control build confound (transparency). The base worktree's tsc --build reported type errors, all in modules unrelated to this PR that a bare worktree lacks (test files needing @testing-library/react, the generated git-commit.js, @lydell/node-pty types); tsc still emitted JS. The head build (the unit under test) built fully in CI. I confirmed the emitted base compose-review.js is genuinely base (0 marker refs, no buildLedger) and imports/runs cleanly, so the A/B is sound. Core's only changes are DESIGN.md/SKILL.md (docs), so the node_modules/@qwen-code/qwen-code-core symlink resolving to the head core dist loads JS byte-identical to base core — verified, not a confound.

Methodology

Ran in the CI verify container (node:22-bookworm, Node v22.23.2) on the merge-ref checkout (HEAD 4bda57d, base HEAD^1 = dbb0349, verified head HEAD^2 = 24c6d3e). Harnesses in harness/ import the compiled dist modules directly (mock-free) and drive them as an untrusted-input boundary; every check is a scripted assertion that can fail (raw outputs in logs/). For the A/B, a scratch worktree at HEAD^1 (tmp/base-tree) was compiled for packages/cli (via node ../../scripts/build_package.js with node_modules/.bin on PATH); core is docs-only-changed so the workspace symlink is not a confound (realpath verified). Vacuity used literal string mutations (harness/mutate.mjs) with a git checkout trap guaranteeing a clean tree (confirmed 0 uncommitted changes after every run). Evidence images were rendered with scripts/verify-capture.mjs. assertions.json counts only the three harnesses' scripted assertions (68); the targeted gate (vitest, 1403 passed | 3 skipped) and the mutation matrix (2/2 killed) are reported separately so intended base-cell/mutant reds are never miscounted as unexpected failures.

Evidence images

01-ab-compose-head-vs-base

02-ledger-harness-head

03-pr-context-harness-head

04-mutation-matrix

05-targeted-gate

Harness scripts and raw logs are in the workflow run artifacts (7-day retention).

Qwen Code · sandboxed verification

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

LGTM✅

@doudouOUC doudouOUC left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed at 24c6d3e. Confirmed first that #8225/#8218/#8215 are all merged and are ancestors of this head, so 1be199ae..24c6d3e is exactly this PR's delta and the stack does not inflate the range.

The --> containment I verified by execution, not by reading. serializeLedger neutralises with JSON.stringify(payload).replace(/--/g, '-\\u002d'), which is subtle enough to be worth probing: I imported the real module and drove 48 adversarial cases — --, ---, ----, -->, --->, a-->b, " -->", a pre-escaped \u002d\u002d, a--b--c--d, a nested fake marker, and a 50-char prefix ending in -->, each injected into title, file, and id in turn. Result: no --> and no bare -- survived into any payload, every case round-tripped losslessly through parseLedger, and every case was removed by stripLedgerMarker. The odd-dash case is the one that would break a naive implementation (----\u002d-, no adjacent dashes) and it holds. So the marker cannot terminate its own comment and spill JSON onto the PR page.

Own-account enforcement is anchored to the authenticated identity, not a spoofable field. latestOwnLedger skips on r.user?.login !== login, and the login it is given comes from currentUser()gh('api', 'user', '--jq', '.login') — the token's own account, not a display name and not anything from the PR payload. Recovery also scans reviews only, so a crafted marker in an inline comment or reply carries no authority: it cannot inflate the round counter, cannot reach the side file, and cannot forge a work-list. Latest-marker selection is submitted_at with the review id as tiebreak, so array order and a same-second re-submit both resolve deterministically.

Round-counter integrity holds. The number is prevRound + 1 where prevRound comes only from qwen-review-pr-<n>-prev-ledger.json, and the model cannot reach it — submit's compose explicitly destructures draftedComments out of the caller-supplied state and refills it from payload.comments, so the ledger describes what is actually being posted. A forged state.draftedComments is dropped, and there is a test for exactly that. The missing/corrupt side-file fallback restarts at 1, and pr-context deliberately does not clear a stale side file on a recovery failure, which keeps the drift in the safe direction (the count can only advance, never collide with an already-used id space).

One factual note rather than a finding, since I checked it and it does not bite: two sites render bodies into the context file without stripLedgerMarkerpr-context.ts:607 and :881, both snippetWithRef(...) over review-thread roots and replies. That is correct as written, because the marker is appended only to the review body (compose-review.ts:262, { ...result, body: \${result.body}\n\n${marker}` }`) and never to an inline comment, so our own tooling cannot leak there. The only way a marker appears at those two sites is a third party typing one into an inline comment, where it renders as visible JSON inside an already-untrusted quoted snippet and carries no authority. Worth knowing if inline comments ever start carrying markers; nothing to change now.

The rendered work-list is also escape-hardened where it matters: cell() escapes backslash before pipe (the ordering that makes \\| an actual escape rather than a literal backslash plus a live separator) and flattens newlines, code() additionally replaces backticks so a crafted path cannot close its code span — with tests asserting the live-separator count stays at 5 across a | b, back\| slash, and a trailing backslash.

Ran the four touched test files locally at this HEAD: 270/270. (Note for reproduction: the default coverage provider hits EPERM on the sandboxed temp dir here — --coverage.enabled=false is needed locally; unrelated to this PR.) CI green apart from review-pr still running. No findings.

@wenshao
wenshao added this pull request to the merge queue Aug 1, 2026
Merged via the queue into main with commit 05260af Aug 1, 2026
62 of 63 checks passed

@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 deleted the feat/review-persistent-ledger branch August 1, 2026 16:50
pchaganti pushed a commit to pchaganti/qx-qwen-code that referenced this pull request Aug 1, 2026
…rol, seven lenses (QwenLM#8261)

* feat(review): borrowed-verification trio — test-plan check, base-tree A/B, per-hunk probes

- qwen review test-plan: rule on the PR Test Plan's checkable claims (paths,
  npm scripts, test counts) against the reviewed tree; contradictions and
  differing counts are disclosed via compose-review, never capping.
- qwen review base-tree: build the merge base in a sibling worktree so the
  verifier can A/B a comparative claim instead of reading it; swept by cleanup.
- test-efficacy: third probe kind — reverse-apply one hunk at a time and
  re-run the affected tests, attributing a still-green suite to the specific
  change nothing gates; shares the mutants' budget window, runs last.

* fix(review): survive real runner output — ANSI-laced and trimmed-away summaries

Both measured on a live /review of QwenLM/qwen-code#8176 with the built CLI:

- test-plan's observedTestCounts strips SGR sequences before matching; a
  color-enabled pipe interleaves them BETWEEN tokens, and the count claim
  fell to 'unchecked' with the summary right there in the report.
- build-test's trimOutput rescues runner summary lines from the omitted
  middle (like module-resolution errors): a failing suite's tail is all
  failure details and npm epilogue, which pushed the one-line summary out
  of the kept text entirely.

* fix(review): address the eight findings from live review of this branch

All measured in the review (QwenLM/qwen-code#8215 review comment):

- test-plan: linear-time bold-heading scan (the old pattern backtracked
  catastrophically on an unclosed ** line an untrusted PR body controls);
  a flag preceding the npm script yields no claim instead of a false
  'no package defines this script'.
- test-efficacy: a hunk probe's restore recreates the parent directory a
  reverse-applied 'new file' hunk removed (the ENOENT from finally lost
  the verdict and marked every remaining hunk inconclusive); hunks get
  their own skippedForBaseline instead of mislabeling a red baseline as
  a budget skip; splitDiffIntoHunks re-captures the file header at every
  diff --git boundary; a hunk-survived finding notes when it restates an
  inert file-level revert at hunk granularity.
- base-tree: idempotent fast path keyed on a build marker + HEAD check —
  concurrent verifier shards reuse one built tree instead of sweeping it
  out from under each other mid-A/B (a fabricated base-side difference
  with a deterministic source tag was the worst case); cost wording is
  now 'an install and a build' everywhere it was 'one extra build'.

* fix(cli): never score a hunk survived when its own test left the baseline (#8215)

A per-hunk probe reported `survived` whenever the green baseline probes still
passed with the hunk reverted. When the hunk's own collocated test dropped out
of the baseline (a probe-tree import error collects nothing), the remaining
green probes prove only that THEY do not cover the hunk, so the verdict is now
`inconclusive` — the same dropped-test asymmetry the mutants already hold.

Also scope the hunk-survived cross-reference note to the hunk's own collocated
test, and let test-plan match a workspace-scoped run of the plan's bare command
instead of falling through to the manifest on an exact-string miss.

* fix(review): silence-bias hardening from four live review rounds of this branch

The two blocking findings, reproduced on this PR's own Test Plan:

- test-plan files no false contradicted notes: npm rulings move from a
  four-verb denylist to an allowlist (the run form + npm's script aliases —
  the ~fifty other builtins each used to become 'no package defines this
  script'); a slash token is claimed as a repo path only with evidence (an
  extension or ./ prefix), never when it is a flag's value (--repo
  owner/repo) or under the review's own temp root; HEADING_LINE_RE drops
  the same quadratic shape its bold sibling was rewritten to remove.
- base-tree gets a real mutual-exclusion lock around sweep+add+build
  (mkdirSync test-and-set; the loser returns busy instead of deleting the
  tree the winner is mid-install in), and a failed build writes a settled
  marker so later shards stop re-paying the install to relearn
  'unavailable'.

Also: Agent 7's brief now names hunk-survived and the hunks.* counters
(it is the report's only consumer, and the finding class was invisible);
hunk findings anchor at the first ADDED line instead of up to three
context lines above the change.

* feat(review): four round-2 borrowings — measured failure attribution, round ledger, richer mutants, doc parity

Shaped by a live round-2 maintainer re-verification (QwenLM/qwen-code#7818):

- qwen review test-delta: rerun the PR side's failed test commands on the
  built merge base and diff the failing FILE SETS — netNew is the PR's own
  failure by measurement (whatever files the diff touches), shared is
  pre-existing by measurement. Counts are never compared: a flaky suite
  fails different test names between runs of the same tree. An unfinished
  base rerun attributes nothing.
- Round ledger: the incremental review cache persists confirmed findings
  under round-scoped ids (R1-2); a high-effort re-review rules on each
  (fixed / still stands / cannot tell) and opens its report with the table,
  the way a human round-2 comment opens with 'M1 is fixed'.
- Three replacement mutation operators in test-efficacy: drop '?? fallback',
  force a comparison-bearing guard condition to 'true', drop a '+ CONST'
  term. Each survivor maps to one crisp untested-protection sentence.
  A line whose raw text and literal-blanked code view disagree yields no
  candidate — an edit index computed across the two views once spliced
  'iftrue 0)' into a guard, and a mangled mutant reads as inconclusive
  while quietly spending a cap slot.
- Quality brief: documentation-parity lens — a new user-facing surface whose
  siblings are documented is a Suggestion naming the sibling precedent; no
  documented sibling, no finding.

* feat(review): render adjudication, workflow step extraction, three verification lenses

Shaped by a live sanitizer-PR verification (QwenLM/qwen-code#8147):

- Render-adjudication capability (opt-in): with QWEN_REVIEW_SCRATCH_REPO
  set, the verifier may post a minimal payload to that user-designated repo
  and rule on GitHub's own rendered HTML — the measured case being an
  @ -> &#64; defusal every local reading called sound while GitHub's real
  renderer registered the mention and fired the notification. Absent the
  setting, rendering claims honestly cap at low confidence / cannot tell.
  Step 7's write ban names the carve-out explicitly.
- qwen review extract-step: lift one workflow step's run: script verbatim
  into an executable, with env (as comments, never half-substituted
  exports), every ${{ }} site listed unevaluated, and a heuristic invoked-
  command list as the stubbing starting point. With base-tree, both arms of
  a by-hand workflow A/B become two invocations. yaml declared as a cli
  dependency (previously resolved only via hoisting).
- Three brief lenses: a borrowed protection idiom missing what made it work
  at home (the code ancestor did the protecting; only the entity was
  copied); a second parser for an authoritatively-parsed format is a
  divergence hunt; tests that pin the mechanism instead of the effect, and
  oracles that mirror the implementation's own model.

* feat(review): sibling-entrance discipline for the fixed verdict

From round 6 of the live sanitizer verification (QwenLM/qwen-code#8147):
the fix closed the fence-shaped entrance into a raw-HTML block, and the
code-span entrance beside it — same divergence, adjacent syntax — stayed
open. A re-check that tests only the reported input rules 'fixed' over a
hole one backtick away.

Both fixed-verdict sites in SKILL Step 6 (the open-Criticals re-check and
the round ledger) now require enumerating a divergence-class defect's
sibling entrances before ruling fixed; a still-open sibling is a NEW
finding, never a reason to withhold the original's fixed — the two
rulings stay separate so the second hole cannot ship unreviewed.

* feat(review): three measured-verification lenses from live rounds 8037/8005

- Threshold-boundary scan: when a fix is a ratio/length guard, hold the
  issue's own variables fixed and binary-search the boundary where the
  behaviour flips; put the number next to what the issue reports. Live
  case: a prose-ratio guard covered the edit/write_file half of its issue
  and silently declined the run_shell_command half (~473-char boundary).
- Delimiter self-injection named as the first parser-differential probe:
  a no-escaping extractor fed its own close tag truncates silently.
- Shared-gate state enumeration: a deliberate-design defence extends only
  to the states it argues — an input-hold argued for 'active' silently
  froze three idle states sharing the same gate. The sibling-entrance
  rule, applied to a state machine instead of a syntax.

* feat(review): carry the round ledger in the posted review body

The ledger shipped as a local cache file and its first multi-round live
use exposed the flaw: four model-comparison rounds re-reviewed the same
two PRs and every round opened from scratch — medium never reads the
cache, and from CI or another clone there is no cache at all. The one
artifact every environment can see, the posted review, carried nothing
machine-readable.

- compose-review embeds an HTML-comment marker (invisible on GitHub)
  carrying this round's findings and round number; the round comes from
  the side file pr-context recovered, +1 — never from the model.
- pr-context recovers the reviewing account's latest marker, renders it
  as a 'Previous /review round (machine ledger)' work-list section, and
  writes it beside the context file for compose-review's round counter.
  Own-account only, latest round wins, fail-quiet on any malformation —
  the marker is data the next round rules on, never authority it obeys.
- Step 6's previous-round ruling now runs at medium too (recovery is
  free; medium still writes no cache and posts nothing); the local cache
  is demoted to fallback for rounds that never posted.

* fix(review): address review feedback — false-positive hardening, binary diff guard, error convention (#8215)

* fix(review): address review feedback — base-tree availability gate, test-plan false positives, hunk-probe ranges (#8215)

- base-tree: only stamp a base tree available when runBuildTest actually
  compiled something (ok AND npm toolchain AND a non-empty build). An
  `unsupported` handoff or an empty npm scope returns ok:true having built
  nothing; marking that tree available let an A/B read the absence of a build
  as a behavioural difference.
- cleanup: sweep the stale base-tree build lock a killed builder leaves behind.
- test-plan: read the root manifest's scripts directly so a root-only script
  survives when the root defines no build/test; bail on the inline --root=./dir
  rebasing form; stop treating a positional after an inline --flag=value as the
  flag's value; prefer a failed scoped run when ruling a bare command; anchor
  the npm script alias to a full token so `yarn test:unit` is not truncated.
- test-efficacy: exclude `\ No newline at end of file` from the startLine offset
  count; compute the mutant-overlap range from the header's new-side span so it
  no longer overshoots into a closely following hunk.

* feat(review): mined disciplines — effective-diff guard, positive control, seven lenses

From a full sweep of 108 maintainer verification comments (2026-07-31):

- fetch-pr detects an EMPTY merge-base diff (work already landed — the
  skill stops and recommends close-as-superseded) and a diff collapsed to
  a residual by overlapping merged PRs (disclosed; body claims about the
  rest are description-of-history).
- test-efficacy runs a POSITIVE CONTROL before spending the mutant window:
  an injected always-failing test must turn the runner red, or every
  would-be survivor is re-classed inconclusive — a dead runner cannot
  kill, and its survivors were the false gap-reports measured live.
- Brief lenses: tested-fix + contamination statement; race verdicts as
  rates with load amplification (lower idle rate without structural
  change is luck); triangulate-and-label for unreachable authorities;
  arm-identity and comparator negative-control for A/B; deleted code's
  incidental effects; self-defeating fallbacks (trigger set within
  cannot-succeed set); reachability adjudication (fix vs scaffolding);
  flipped-assertion audit; shape-vs-provenance authorization probing.

* fix(review): four fixes from the stack's own round-2 reviews

- test-delta (Critical, #8218 review): a base rerun that fails with ZERO
  parseable failing files (install/toolchain failure) no longer reads as
  'base green' — it attributes nothing, like a timeout, instead of
  promoting every PR-side failure to net-new.
- extract-step (Critical, #8225 review): every line of a multi-line env
  value is comment-prefixed — an unprefixed block-scalar second line sat
  in the emitted script as an executable line.
- extract-step: expressionsOf no longer misses expressions containing
  their own brace (format('{0}')).
- cleanup (#8215 review): sweeps an orphaned base-tree build lock, which
  otherwise wedges the A/B for that PR permanently.

* fix(review): close the remaining round-2 findings across the stack

- selectMutants: replacement operators get a 3-slot sub-cap inside the
  shared cap — measured 24x pool inflation (215 vs 9 candidates over 40
  real commits) was draining the time window hunk probes draw from last,
  silently un-shipping the hunk-survived finding class; sub-cap drops are
  counted in skippedForCap.
- test-delta: whole-command budget (540s, mirroring test-efficacy) so
  three failed commands cannot blow the 600s tool ceiling and lose the
  report; run() regains build-test's three deliberate properties (stdin
  ignored, error.code/SIGTERM timeout detection, trimmed output).
- test-plan: pasted unified diffs inside Evidence blocks shed no path
  claims (+++ b/<path> once ruled contradicted on a correct body);
  gitignored paths rule unchecked — absent at the reviewed commit by
  construction, the .qwen/ reasoning generalized.
- agent-prompt: the Agent 7 efficacy block now enumerates all FOUR
  finding kinds including hunk-survived, the hunks.* skip counters, and
  harnessValidated — the brief and the block in the same prompt no longer
  present two different complete sets (the sibling-enumeration lesson,
  applied to our own prompt).

* fix(review): address review feedback — diff-header false positives, stale prompt enumeration, added-file hunk probes (#8215)

* fix(review): close the round-3 findings on the stack

#8261 review:
- the dead-harness re-class now runs BEFORE findings are built (a failed
  positive control could still file survivor findings — the Critical);
  it also covers the file-level revert probe's inert verdicts, the
  control pays for its run out of the shared budget (no more silently
  eaten skippedForBudget slot), a failed control stops the window instead
  of manufacturing survivors to re-class, and its note names all three
  causes that share the green-control shape.
- emptyDiff no longer fires on a FAILED diff capture (close-as-superseded
  off an infrastructure error would close a live PR); countDiffChangedLines
  counts --x/++x body lines.

#8215 review:
- the cd target itself is no longer claimed as a path (a bare dir carries
  no evidence; only the file tokens it resolves are);
- 'Test Files N passed' is a FILE count — variable-length lookbehind
  keeps it out of the test-count claims;
- base-tree's handler gains the pipeline's catch-and-exit-1 convention;
- probeCreateFailureDetail folded into the shared
  worktreeCreateFailureDetail.

* fix(review): address review feedback — cd-base exclusion, Test Files count guard, base-tree error handling, probe delegation (#8215)

* fix(review): port the collocated-dropout test to the post-#8050 runner seam

Merging main brought #8050's Windows-portability refactor, which resolves
the probe runner through vitest/package.json's bin — a node_modules/.bin
fake is dead weight it never reads. The 8215-only collocated-dropout test
still installed the old .bin fake, so the REAL vitest ran its fixtures,
price.test.ts genuinely passed, and the hunk scored survived. The test now
overrides the fake package's vitest.mjs like every post-refactor test.

* fix(review): close the round-4 findings from both stack reviews

From the #8215 review: trimOutput's summary rescue is capped at 40 lines
(uncapped, 40k lines of 'Test <n>: …' prose made the whole trim a no-op —
1.6MB in, 1.6MB out); a spaceless # line is prose per the ATX rule GitHub
applies (a pasted #!/bin/bash outside a fence once ended the Test Plan
mid-body), with the bare-#-run crash on the closing scan guarded; a
base-tree build lock older than 30 minutes is a corpse and is swept
rather than reporting busy for the rest of the review.

From the #8261 review: a pasted diff's BODY lines shed no path claims
(-packages/old/gone.ts matched PATH_RE and ruled a false contradicted —
the syntax-line filter alone was vacuous against the real failure mode);
a gitignored file that nonetheless EXISTS rules reproduces (the ignore
guard only ever downgrades a would-be contradiction); test-delta's note
now explains each unattributed command (timeout vs toolchain failure)
instead of leaving the reader to infer why it is in neither list.

* fix(review): bound the summary rescue, apply the ATX heading rule, sweep stale build locks

The three 8215-layer findings from the latest review, fixed at this
layer (they were first patched further up the stack, where the reviewer
of THIS PR cannot see them):

- trimOutput's summary rescue is capped at 40 lines — uncapped, 40k
  lines of 'Test <n>: …' prose voided the trim entirely (measured 1.6MB
  in, 1.6MB out) and the bounded-output contract is the whole point.
- A '#' with no following whitespace is prose, not a heading (the ATX
  rule GitHub applies): '#8176', '#tag', an unfenced '#!/bin/bash' no
  longer end the Test Plan section mid-body; the bare-#-run crash on
  the closing scan is guarded.
- A base-tree build lock older than 30 minutes is a corpse left by a
  killed builder — swept and rebuilt instead of reporting busy for the
  rest of the review.

* fix(review): EEXIST-only lock busy, bun test alias, chained cd bail, fence backreference

Four live findings from the latest inline review round (the rest of the
round was already fixed upstream by the takeover bot - verified by
probing head behavior rather than re-reading the threads):

- base-tree's lock catch distinguishes EEXIST (a concurrent builder,
  busy) from EPERM/EROFS/ENOSPC (this run's own failure, reported as
  such, not as a busy that will never clear).
- "bun test" is bun's built-in runner, not a package-script alias: it
  runs whether or not any manifest defines test, so ruling it against
  the scripts table filed a false contradicted.
- A chained cd matches the leading-cd shape but the single-hop resolver
  joined file tokens against the FIRST directory; it now bails like the
  exotic-cd case.
- codeSpans' fence regex closes on its own marker via backreference; a
  tilde fence line inside a backtick block ended the span early and
  lines after it were lost to extraction.

* fix(review): make the ledger marker actually reach the posted body

Three Criticals from the #8255 review, all real:

- The marker was appended in the CLI handler, AFTER composeReview()
  returned, so it only ever reached the composed JSON on disk. submit
  posts what the PURE function returns, so no posted review carried a
  marker, latestOwnLedger always returned null, and the whole feature
  was inert end to end. The append now lives inside composeReview, fed
  by a draftedComments seam that both CLI boundaries fill from the same
  array they count (and both strip from a model-written state JSON).
  Three end-to-end tests now assert on the body composeReview returns.
- pr-context's side-file write preceded the mkdir that creates its
  directory and was unguarded: an ENOENT failed the whole command over
  a best-effort carry-forward. mkdir first, write guarded.
- CANONICAL_LGTM_RE is anchored, so a trailing marker made every no-op
  round "worth showing" and prior rounds started rendering in full. The
  marker is now stripped before the filter and the count walk, not only
  before rendering.

Plus the three thread findings: ledger cells are escaped before landing
in the context table (a title with a pipe could forge rows), parseLedger
takes the LAST marker and type-checks/normalises what it recovers, and
the stray verdict doc comment is reattached to verdictLine.

* fix(review): close the ten open findings on this PR

- guard-true tested for a comparison anywhere after `if (`, including the
  then-body, so `if (ready) emit(a !== b);` admitted a mutant on the
  comparison-less condition the gate exists to exclude. It now tests the
  condition span only.
- The `survived` detail said "when it changes" for legacy DELETION
  mutants too; it now matches the operator.
- test-delta's `unparsed` required both sides to parse zero files, so a
  PR-side failure whose FAIL lines the trim scattered was silently
  dropped whenever the base rerun happened to parse. netNew/shared come
  from the PR side, so the PR side alone decides.
- failingFilesOf now matches Windows path shapes (backslashes, C:) - a
  missed parse is an unattributed failure, not a loud error.
- The replacement branch of runOneMutant (write-file -> run-probe ->
  classify) had no end-to-end test; one now drives a coalesce operator
  through the real handler and asserts the mutated line, the verdict,
  the operator-specific wording, and that the shared tree is untouched.
- Two tests were vacuous with respect to what they promised: the
  baseline-dir test never asserted the cwd (its helper swallowed the
  argument - fixed at the helper), and the one-candidate-per-line test
  used an input that never triggered the replacement path, so the
  `continue` under test was not load-bearing.
- Reattached the orphaned selectMutants JSDoc; reworded the SKILL line.

* fix(review): the test helper's cwd parameter is required, not optional

CI's `tsc --build` failed on test-delta.test.ts: the exec seam always
passes a cwd, but the helper's signature marked it optional, so pushing
it into a string[] was `string | undefined`.

Missed locally because vitest runs through esbuild, which strips types
without checking them - the suite was green while the build was red. The
gate to run before pushing a type-level change is `npx tsc --build`, not
the test suite.

* fix(review): a base rerun that could not RUN attributes nothing

Two Criticals from the latest review, both reachable on the brief's own
happy path:

- baseUnusable covered only timeouts. Every other way the base side can
  fail to run - an unbuilt base tree, a missing install, a workspace the
  PR ADDED (npm test --workspace cannot resolve on base), an ENOBUFS
  truncation - exits non-zero with zero FAIL lines, which this code read
  as a green base. Every PR-side failure then became netNew: the
  strongest evidence the command emits, manufactured from a base that
  never ran a test. It now attributes nothing and says why.
- Timeout detection was the weaker substring form the sibling explicitly
  rejects; an external SIGTERM (container stop, cancelled job) set
  neither an ETIMEDOUT message nor an exit code and fed straight into
  the above. build-test now exports spawnTimedOut and test-delta asks
  the same question rather than re-deriving it.

Also: the base output is trimmed (it precedes the verdict fields in the
report the agent reads, so an untrimmed megabyte truncates exactly what
the command produces); the guard-true gate no longer reads an arrow
function's => as a comparison (every predicate guard was a candidate -
the if (ready) noise the gate exists to exclude); the term-drop message
no longer calls a string concatenation a reserve term; the unparsed note
describes its own PR-side-only condition; and the ledger's Step 6/Step 8
now agree that a still-standing finding keeps its id.

* fix(review): extract-step resolves all three env/defaults levels, and comments every env line

Two silent-wrongness defects in a command whose whole value is fidelity.

`env:`, `shell:` and `working-directory:` are three-level settings on GitHub —
workflow, job, step, nearest wins — and only the step level appears in the
step's own text. Reading step-level alone reproduced by machine the exact
transcription error this command exists to remove: measured, a step under a
job-level `NODE_ENV: production` and a workflow-level `GLOBAL_FLAG` extracted
with `env: { LOCAL: '1' }` and `workingDirectory: undefined`, so the emitted
script ran with both unset and nothing said so. Not a contrived shape: this
repo carries workflow-level `env:` in 7 workflows, job-level `env:` in 10, and
job-level `defaults.run` in qwen-triage.yml — the workflow the command's own
test plan names. The three levels now merge with the runner's precedence, and
`envSources` records which level each key came from, so an inherited value is
visible rather than indistinguishable from the step's own.

The env block was commented per ENTRY, not per LINE. A YAML block scalar
(qwen-autofix.yml's `SETTINGS_JSON: |-`) reaches the header as a multi-line
string, so its continuation lines landed in command position — and under the
`set -e` the header itself emits, the extracted step died in its own preamble
before its `run:` body ran. Every line is commented now.

Tests pin the effect, not the mechanism: `executableLines()` asserts nothing
but the `run:` body ever reaches command position, plus a `bash -n` parse
check. Verified to flip — all five new assertions fail against the pre-fix
implementation (`{ LOCAL: '1' }`, `undefined` working directory, three
executable lines instead of one, and a real `bash -n` syntax error).

* fix(review): compare failing files by a normalised, project-keyed identity

Critical: the two sides run in DIFFERENT roots (the PR worktree and the
base tree), and netNew/shared compared the parsed paths verbatim - so an
absolute-path runner turned every pre-existing failure into a fabricated
Critical, with the authority of a measurement behind it. Paths are now
normalised against each run's own root (and backslashes to /, so a
Windows path compares with its POSIX-printed twin), which is why
test-delta gained --pr-worktree.

The identity also keeps the vitest project token: dropping it collapsed
same-named test files across workspaces, so a PR-caused failure in one
package could read as pre-existing because another package has a file by
the same name - the worse failure direction.

Also from the same review, all of them reachable on the brief's own path:

- The base rerun now inherits build-test's stdio: ['ignore','pipe','pipe']
  ("a build that asks a question is a build that hangs until the
  deadline") and its trimOutput, which matters because entries[].base
  precedes the verdict fields in the report the agent reads.
- The brief gates on base-tree's `available`, not just its `path`: a tree
  that was created but did not build populates path too, and measuring
  against it turns an infrastructure failure into Criticals.
- A programmatic caller omitting `timeout` no longer sends NaN into
  spawnSync.
- MutantCandidate is a discriminated union, so an operator without its
  replacement line - which would delete a line while reporting "with its
  ?? fallback dropped" - is unrepresentable.
- The comparison class no longer requires a trailing space (if (a<b) is
  the same guard, just unformatted) and matches a brace-less else if.
- DeltaEntry.unparsed's doc now describes the PR-side-only condition it
  actually implements.

* fix(review): restore the whole-command budget, keep generics out of guard-true

Round-1 findings from a fresh review of this PR:

- test-delta had no aggregate deadline: --timeout is PER command and
  defaults to 300s, so three failed commands is 900s against Agent 7's
  600s ceiling - killed with NO report at all, discarding the base-tree
  install and build just paid for. TOTAL_BUDGET_MS mirrors the one
  test-efficacy reserves; commands it cannot fit are disclosed.
- guard-true matched generic calls: `if (isRecord<string>(v))` produced a
  mutant, and a type-guard predicate is exactly the `if (ready)` shape
  whose survivors the gate calls noise. The trailing \s is required, not
  an accidental asymmetry with [!=]== - telling `a<b` from `fn<T>(x)`
  needs a parser, and the gate is silence-biased by design.
- --pr-worktree had no contract test, and its failure mode is the worst
  here: arriving undefined, root stripping silently stops and every
  pre-existing failure becomes a fabricated netNew. The new test feeds
  parseSync's output straight into runTestDelta and asserts an
  attribution only reachable when both roots were stripped (verified
  red against the snake_case field shape that shipped once already).
- Merged the two consecutive doc comments on prWorktree.

* fix(review): a budget-shortened deadline is not the same fact as a slow rerun

Round-2 finding on the budget just restored: `Math.min(perCommandMs,
remaining)` can hand a rerun far less than --timeout, and if it dies
there the note said only "timed out - infrastructure, not evidence".
True, but it sends the reader hunting a hang that is really an exhausted
budget - and unlike a real timeout, a rerun with budget to spare would
still measure it. The note now names those commands separately and says
so. Verified red against removing the tracking line.

* fix(review): brace-tolerant stub list, pipefail fidelity, and extract-step in the briefs

Round-3 findings on this PR, fixed.

`expressionsOf` matched `[^}]*`, so any expression containing a brace —
`format('refs/pull/{0}/head', …)`, `fromJSON('{"a":1}')` — was not mis-listed
but DROPPED. A stub list reads as "these are all the values to supply", so a
silent omission is a value that never gets stubbed. It now scans forward to the
closing `}}`, and reports nothing for an unterminated site rather than
swallowing the rest of the text.

Declaring `shell: bash` is not the runner's default `bash`. The default is
`bash -e {0}`; a declared `bash` (at any level) is
`bash --noprofile --norc -eo pipefail {0}`, and a pipeline whose middle stage
fails aborts under one and not the other. The header now carries `set -eo
pipefail` or `set -e` accordingly — 163 of this repo's 434 `run:` steps are
under a declared bash and were getting the weaker one. A `shell:` value is also
a command template (`perl {0}`), so only its first word goes in the shebang and
the whole template is recorded beside it.

`extract-step` was registered on the CLI and mentioned in DESIGN.md, and
nowhere in SKILL.md or the agent briefs — the runtime prompts. The capability
was unreachable by the agents it was written for. The verifier's brief now
carries it next to the A/B paragraph it composes with, and Step 4 summarises it.

Also: env ordered nearest-first (measured on qwen-autofix.yml:route:0, merge
order put 20 inherited entries ahead of the step's own 26 in a 49-line header);
a valueless `FOO:` renders as the empty string, not `"null"`, and a non-scalar
as JSON rather than `[object Object]`; a missing file no longer reports as a
parse failure; DESIGN.md's lens count matches its list.

The test oracle is rebuilt around the property instead of a filter: the file is
the header plus the body verbatim, and every line before the body is a comment
or a directive the test names. The old helper dropped `set -e` unconditionally,
so it could not tell the header's from one the body legitimately contains — and
would have gone green on a header that leaked exactly that line. 434 real `run:`
steps swept: 0 non-verbatim bodies, 0 live header lines, 0 missed expression
sites, 0 out-of-order env, 0 `bash -n` failures.

* fix(review): restore the replacement sub-cap, stranded on a downstream branch

Round-3 finding, and the third instance of one class: an 8218-layer fix
committed on the 8261 branch, four PRs above the code it belongs to.

Measured over 40 real commits, the replacement operators produce ~24x
the deletion pool (215 vs 9 candidates; guard-true drives it). Every
mutant run drains the same window hunk probes draw from LAST, so
uncapped, most diffs with any replacement candidates leave hunk probing
zero runs - the hunk-survived finding class silently stops firing and
nothing says so. Three slots, and what the sub-cap drops is counted in
skippedForCap rather than lost.

Also swept the other direction: diffed every review file against its
8261 copy to confirm nothing else 8218-layer is stranded up there. The
remaining divergence is 8261's own (the positive control, its lenses).

* fix(review): one severity predicate, carried ids, and a lossless marker

Round-1 review of the ledger marker, six findings.

Two contradicted contracts this package already states elsewhere:

- `buildLedger` restated the severity predicate as a bare `startsWith`
  while `severityOf` — what `countInlineFindings` and the unmarked-comment
  gate both use — trims first. A Critical whose body opened with a newline
  was counted, was posted, blocked the merge, and was silently absent from
  the ledger, shifting the id of every finding after it. It classifies
  through `severityOf` now, and strips the marker with the shared prefixes
  instead of a second copy of the literals.

- Ids were assigned by array position every round, so the report saying
  `R1-2 still stands` shipped beside a marker recording that claim as
  `R3-4` — and `LedgerFinding.id` documented itself "stable across
  re-reports". Step 6 now mandates writing the original id into the
  re-report (`**[Critical]** R1-2: …`), `buildLedger` reads it back, and a
  duplicate or absent id falls back to the next free id of this round.

Four smaller ones:

- `stripLedgerMarker` removed only the FIRST marker while `parseLedger`
  reads the LAST, so a body holding two leaked the trusted marker into
  model-facing prose and un-filtered the canonical LGTM it was appended to.
- The `--` guard rewrote data to an em dash: a finding about `--comment`
  reached the next round as `—comment`. It escapes at the JSON layer now,
  which is comment-safe and lossless.
- `file` was capped on read (200) but not on write; the cap is one
  constant binding both halves.
- `submit`'s path — the one GitHub's payload is built from — had no test
  that the marker reaches the posted body.

Plus: tie-break `latestOwnLedger` on review id when `submitted_at` ties,
neutralise a backtick in the location code span, skip the `currentUser()`
round-trip when the PR has no reviews, and say why a stale side file is
deliberately left in place.

* docs(review): complete the "delta cannot rule" enumeration in both places

Round-4 finding. The brief and SKILL.md each listed three cases where
test-delta attributes nothing - unparsed, timed-out base, no merge base -
but the code has five: the later rounds of this PR added "a base rerun
that failed without naming any failing file" (it did not measure the
base) and "a command the whole-command budget could not fit". Two
enumerations of the same set with different membership, in the two
places an agent reads.

That is the sibling-enumeration lesson this skill teaches, applied to
its own prose for the second time: the fix is not just adding the
missing members but saying that the report names each case with its own
reason rather than folding them into one.

* fix(review): the invokes list was mostly prose, not commands

Round-4 finding on this PR. `invokes` is documented as a heuristic starting
point, and imprecision is fine — but measured over this repo's 434 real `run:`
steps it was reporting 435 distinct "commands", 267 of them appearing exactly
once, with a worst case of 63 entries made up of words like `CI`, `Evidence`,
`PR` and `and`. A list that size, mostly prose, is not a starting point.

Three causes, each measured:

- A `${{ … }}` expression is not shell, and it routinely contains `||`.
  Splitting on that as a pipeline separator reported both operands as commands
  (`matrix.arch`, `github.event.inputs.version`). Expressions are now masked to
  an opaque token before the split; one sitting in command position contributes
  nothing, which is honest — what it expands to is unknown here by design.
- A heredoc body is input to a command, not a list of them. Its lines were
  scanned as commands, terminator included. 12 steps in this repo carry one.
- The `name=value` skip stepped over the prefix and took the NEXT word as the
  command — but for a quoted value with spaces that word is inside the value:
  `EVIDENCE_SECTION=$'### Evidence images'` reported `Evidence`. Quoted spans
  are now blanked out, with the quote carried across lines so a multi-line
  string's continuation lines are data too. Command substitutions are read
  first, so `body="$(sanitize < "$REPORT")"` still reports `sanitize`.

A `#` preceded by whitespace ends the live part of a line, so an apostrophe in
a trailing comment cannot open a span and eat the rest of the script.

Measured after: 435 distinct commands to 187, singletons 267 to 104, worst case
63 to 27 — and the worst case is now real commands (`awk cat chmod curl git jq
mktemp pkill tar tee timeout`) plus the script's own shell functions. Also
added the builtins a stub could not intercept anyway (`eval`, `exec`, `source`,
`unset`, `command`, …) to the keyword set.

434 steps re-swept: 0 non-verbatim bodies, 0 live header lines, 0 missed
expression sites, 0 out-of-order env, 0 `bash -n` failures.

* docs(review): the rationale named only one of the ways base goes unmeasured

Third and last copy of the enumeration the previous commit fixed. The
bullet's headline already generalised - "base attributes nothing it did
not finish" - but its body named only the timeout, so a reader learning
the contract from the rationale would conclude timeouts are the only
unusable case. Name the set, and say why the report keeps the reasons
apart: "we could not measure" and "we measured nothing" are different
facts to the author, and only one of them is about their PR.

* fix(review): a quoted `<<EOF` is not a heredoc, and a continued line is one command

Round-5 findings, both in the previous commit's own scanner.

A heredoc opener was matched over the whole line, so one inside a string
started heredoc mode: `echo "write <<EOF for a heredoc"` made every later line
wait for a terminator that never arrives. The failure is not a missing entry
but a missing REST — measured, a three-line script returned `[]` instead of
`[curl, jq]`, empty and entirely plausible. Opener detection moved inside the
quote walk, where it only fires outside quotes; the quoted forms (`<<'EOF'`)
are consumed by the match, so their quotes never open a span either.

A backslash-continued command was scanned as several lines, which puts the next
ARGUMENT in command position — this is where `apt-get install -y \` /
`  libx11-dev` reported the package as an invoked command. Continuations are
now joined into one logical line before scanning.

Measured after: 187 distinct commands to 185, and the singleton tail is now
dominated by real ones — PowerShell cmdlets, macOS tooling, and the scripts'
own shell functions. 434 real steps re-swept: 0 non-verbatim bodies, 0 live
header lines, 0 missed expression sites, 0 out-of-order env, 0 `bash -n`
failures.

* fix(review): case labels, a second heredoc, and an expression in command position

Round-6 findings, from running the scanner against adversarial shapes rather
than reading it again. Two are UNDER-reports, which is the worse direction: a
command missing from the list is a stub the verifier never writes, so the
extraction reaches the real network.

- A `case` pattern label stopped the scan on its own line: `blocked) gh api x`
  reported nothing, losing `gh`. The label is now stepped over like a `name=`
  prefix.
- Only the first heredoc opener on a line was tracked, so `cat <<A <<B` left
  the second body and its terminator read as commands (`B`, `y`). Openers are
  queued and consumed in order.
- Masking an expression to a QUOTED token let the quote-stripper delete it
  entirely, so `${{ steps.x.outputs.cmd }} arg` reported `arg` as the command.
  The token now survives stripping and cannot match a command word, so an
  expression in command position contributes nothing.

Ten further adversarial shapes were already correct and are pinned as
regression guards: nested `$( )` in quotes, subshells, function definitions,
indented heredoc terminators, backticks, bare redirects, adjacent and empty
`${{ }}` sites, and a JSON literal inside an expression. Verified to flip —
exactly the three above fail against the previous commit, the other ten pass.

434 real steps re-swept: 0 non-verbatim bodies, 0 live header lines, 0 missed
expression sites, 0 out-of-order env, 0 `bash -n` failures.

* fix(review): annotate the continuation accumulator so tsc can type it

`invokedCommandsOf`'s backslash-continuation loop failed to compile with
TS7022: the narrowed type of `pending` at the join line is the union of
the loop-entry value and the back edge, and the back edge is computed
from the join itself. The declaration's own annotation does not break
that cycle - control-flow narrowing runs after it - so the checker gives
up and calls the result `any`.

Caught only on a forced rebuild. `tsc --build` had been reporting this
tree clean off a stale .tsbuildinfo, which is the same shape of gap that
put a type error into CI last week: the test runner strips types, so the
suite stayed green either way. Gate with --force.

* fix(review): a file-count label stops counting at the end of its line

`Test Files  45 passed` filing its 45 as a differing TEST count was
fixed once, with a lookbehind on the bare-count pattern. That only ever
rejected the all-green shape. The moment any file fails, the runner
prints `Test Files  1 failed | 44 passed (45)`, the label is no longer
adjacent to the number, and 44 comes through as a test count - so the
note reads "claimed 44, observed 1323" on exactly the runs whose summary
someone would paste. Adjacency was the wrong invariant; the line is.

Masking from the label to end-of-line is distance-independent and picks
up jest's `Test Suites: 1 failed, 44 passed, 45 total` at no cost. The
label keeps its `Test` word on purpose: a first cut matched a bare
`files` and blanked the line in "expect all four files and 471 tests to
pass", silencing a real claim. An existing test caught that, which is
the argument for the rule being as narrow as it is - anything that
suppresses claims is worth exactly its narrowness.

Also drops the now-dead lookbehind, which a reviewer had separately (and
wrongly) called a JS syntax error; variable-length lookbehind is legal
in V8, and the module parsed fine. It goes because the line rule
subsumes it, not because it was broken.

* fix(review): address round-1 review of the mined-disciplines batch

The positive control could state a verdict it never measured, and its own
failure path shipped untested. Ten findings from the review of #8261:

- `runControlMutant` returns `boolean | null`. An unreadable probe file
  injected no test and ran nothing, but returned `false` — which the caller
  reads as "the injected always-failing test stayed green", re-classes every
  survivor with that sentence, and discards the whole mutant/hunk window over
  an I/O error. `null` is the file's own third-outcome rule; the window stays
  spendable and the note says the harness was not validated.
- `mutants.skippedForControl` / `hunks.skippedForControl`. A control that came
  back red stopped the run with candidates unprobed while every `skipped*`
  counter read 0 — the silent cap the brief teaching agents to read those
  counters rules out. Their own reason, not the budget's.
- Cover the control's failure half: a dead-runner integration case (survivors
  re-classed, revert probe's `inert` re-classed, findings empty, nothing
  spent) and a could-not-set-up case pinning that `null` does NOT discard the
  window. Both branches, and the re-class block, were previously unreachable
  by any test.
- `rulePath`: one existence check, not two. The second was unreachable behind
  the first and its note — "exists at the reviewed commit (the diff does not
  change it)" — silently retired, collapsing tracked state and this run's
  build output onto one sentence. The ignore status now picks the wording.
- `expressionsOf`: forbid the body from crossing another `${{`. A malformed
  site above a real one swallowed it into the blob, so
  `${{ github.event.comment.body }}` stopped being enumerated as an injection
  site — the one direction this helper must not fail in.
- `countDiffChangedLines`: count by hunk position, not prefix shape. A deleted
  line whose content starts `--` arrives as `--- …` (markdown rules, YAML
  markers, SQL comments), and every dropped line pushes the ratio toward a
  false `collapsedFromUpstream`.
- `emptyDiff` is gated on `baseFetchFailed` too. A stale local base ref that
  already contains the head commits diffs to empty, and the skill acts on that
  by recommending close-as-superseded.
- `test-delta`: price the budget slot against the command's own measured
  duration instead of a flat 5s floor, which admitted commands that could only
  time out and then disclosed them as "infrastructure, not evidence".
  `skippedForBudget` becomes a structured field; `now` becomes a seam so the
  test stops reassigning the global `Date.now`.
- Drop `probeCreateFailureDetail` (no production caller after the swap to
  `worktreeCreateFailureDetail`) and the duplicated base-lock sweep in
  `cleanup.ts`, ten lines above the identical pre-existing one.
- `--` before the path in `check-ignore`, and the comment says plainly that no
  `-`-leading claim survives extraction today.

* fix(review): parse the base rerun before its output is trimmed

`trimOutput` rescues module errors and runner summaries out of the
omitted middle, not the per-file FAIL lines this command reads. A base
suite whose failure section overruns the tail budget therefore lost
failing files into the gap - and a SHORT base set is the dangerous
direction, because netNew is the PR side minus the base side. Every file
the trim hid came back as a Critical attributed to this PR by
"measurement". Parse the raw text, report the bounded one.

The PR side cannot be fixed here: it is read out of build-test's stored
output, trimmed before this command existed. That loss runs the other
way - it understates `shared`, never invents a netNew - so the entry
carries `prTruncated` and the note says the list may be partial. A
silence-biased gap is still a gap the author should hear about.

Also names both selection caps in the mutant-skip diagnostic. The count
accumulates replacement sub-cap drops, and with 2 deletions and 6
replacements the total is exactly MAX_MUTANTS: the main cap never fires,
yet 3 are dropped, and the message sent the reader looking for a pool of
11 candidates that never existed.

* test(review): pin the `sh` set-line to exactly what the runner uses

A reviewer asked for `expect(script).not.toContain('set -e')` on a
`shell: sh` step. The opposite is correct - GitHub runs that step as
`sh -e {0}` - but the thread was right that nothing pinned it either
way. Assert both halves: `set -e` is present, `pipefail` is not. Dropping
the line makes an extracted `sh` step run past a failure the runner
stops on; adding pipefail claims a bash feature `sh` does not have.

* fix(review): rerun only the command shapes build-test emits

This command reads a report off disk and then executes the strings in it
with `shell: true`, in the base worktree. Nothing else in the pipeline
re-executes a value it read back from a file, so nothing else has to
care where that value came from - this does, and the provenance is worse
than it looks: the command is `npm test --workspace="<dir>"`, the
workspace token is a directory, and a directory is a name a pull request
chooses. `packages/x";curl …|sh;"` is a legal path in git and on Linux
and it round-trips through the report into a shell.

Restricting to the emitter's own grammar costs nothing real, since that
grammar is the two shapes build-test produces. A command outside it is
skipped and disclosed, the same treatment everything else this command
cannot do already gets, so a future shape degrades to "judge it by the
diff" rather than to arbitrary execution.

* test(review): pin the empty-diff and collapse detectors

Both lived inline in a large object literal with no test, and one of
them is the most expensive disclosure this command emits: the SKILL acts
on `emptyDiff` by recommending the PR be closed as superseded. Dropping
the 200-line floor, flipping the 4x comparison, or losing either
empty-diff guard turned nothing red.

Extracted as two pure predicates and pinned at the boundaries, including
the two guards that are not about the diff at all - a capture that threw
leaves diffText empty, and a merge base resolved from a stale local ref
can already contain the head commits. Either would have closed a live PR
on an infrastructure error.

Checked by mutation rather than by reading: all four edits above now
fail exactly one assertion each.

* test(review): pin the 30s budget floor, and stop keeping its arithmetic twice

Two findings from the same review round, both about budget math nobody
was checking.

The 30s floor separates "skipped, judge it by the diff" from "started,
timed out, disclosed as infrastructure". Every existing budget test left
it non-binding - two sit hundreds of seconds from the boundary and the
third is capped by the per-command deadline - so regressing it to the
old 5s turned nothing red. Verified by doing exactly that: 26 green
before the new test, one red after. A one-second command admitted into a
twenty-second window comes back labelled `budgetClamped`, which is the
mislabelling the priced floor exists to prevent.

The other is the same duplication lesson this skill keeps arriving at,
in its own tests: one test carried the per-run budget arithmetic in a
block comment AND at the `now:` argument, and when the per-run figure
changed only one copy moved. The block also predated the positive
control, so it omitted a whole suite run. Deleted the copy rather than
correcting it - two agreeing copies today are two disagreeing copies
later.

* fix(review): the working directory is a setting the extraction was losing

Two findings, both of them this file failing its own stated argument.

The stub list dropped it. `expressions` covered the script and the env
and nothing else, so a `working-directory: ${{ github.workspace }}/x`
produced an empty list and a summary line reading "0 ${{ }} site(s) to
stub" - and `expressionsOf`'s own comment says why that is the failure
this list cannot afford: the caller reads it as "these are all the
values to supply". Widened to every setting the command carries, the
`shell:` template included.

The emitted script never mentioned it. The env block is commented into
the header precisely so a reader of the script alone can see it; the
working directory changes what the script does just as much and was in
the metadata only. The argument for reading all three levels, written in
this file, is that a step run "in the wrong directory, and nothing says
so" is the transcription error the command exists to remove - which is
exactly what the header did. It is a comment rather than a `cd` for the
same reason env is comments, not exports: the value may hold `${{ … }}`
and this command substitutes nothing.

Both pinned, and both checked by deleting the fix: each mutation fails
exactly one of the two new tests.

* fix(review): $(( )) is arithmetic, and a heredoc's form decides where it ends

Three fixes and one deliberate non-fix, all measured against this repo's
own 434 `run:` steps rather than argued.

`$(( ))` was read as a command substitution, so `N=$((N + 1))` reported
`N` as a command to stub. It was the single largest source of junk in
the list: 196 distinct "commands" across the corpus, 165 without it.

A plain `<<WORD` heredoc ends only on a line that is exactly WORD; the
loose match ended it on an indented `EOF` inside the body and then read
the body as commands, which is how `rm` got reported for a script that
never runs it. `<<-` stays looser than bash (any leading whitespace, not
just tabs) because looser can only end a body early, and this file's
priority is that an under-report is the worse direction.

`[^()]*` matched only the innermost `$( )`, so `X=$(gh api $(u))` lost
`gh` - a missed stub, and the extraction reaches the network. Depth
counted now, and the assignment-prefix skip no longer steps over an
unclosed `X=$(gh` into reading `api` as the command.

The non-fix is recorded where the next reader will hit it: the quote
walk is flat while shell quoting nests, and over ~300 lines the drift
reports fragments of jq source as commands. Inserting a separator where
a blanked span was removes nine of those, but it splits `a"X"b`, which
is one word to the shell, and the minimal reproducer for the difference
is 296 lines - nothing short enough to pin it. A scanner nobody can pin
costs more than the junk it removes.

* fix(review): refuse an ambiguous step name, and report errors like the siblings

Two findings, both about a message the caller never gets.

A job may legally hold two steps with the same name. The selector took
the first and said nothing, which is the failure this file's own header
names - "picks the same-named step from the wrong job" - and it is worst
in the use the command exists for: A/B extraction runs it once per tree,
so a PR that adds or reorders a duplicate leaves the two sides comparing
different steps while reporting on one. Refused out loud now, naming the
indices; the index is always available and never ambiguous.

The handler also let every throw propagate, so five carefully separated
messages - cannot read vs cannot parse vs no job vs no step vs no `run:`
- all arrived as "An unexpected critical error occurred" under a stack
trace. `base-tree` and `test-plan` in the same directory already catch,
write the message, and set exit 1. Matched. The separation between "the
path is wrong" and "the YAML is wrong" only pays if the caller sees it.

* docs(review): the brief's list of limits was one short

"Two limits worth knowing before you spend the step" became three when
the selector started refusing an ambiguous step name, and the count went
stale in the same commit that made it wrong. This is the enumeration
drift the skill teaches, in the text that teaches it.

The added entry says what to do rather than only what happens: pass the
index, which is what an A/B wants regardless — the two trees have to
select the same step, and a name that moved between them is exactly how
they stop doing that.

* chore(review): drop a scratch probe file that reached the branch

`packages/cli/inert.mjs` was a throwaway harness for sweeping the repo's
own workflows; its cleanup ran with a relative path from the wrong
directory and it got committed by the next `git add -A`.

It failed CI and not the local hook because the two lint different sets:
lint-staged filters to `*.{js,jsx,ts,tsx}`, which does not include
`.mjs`, while CI's flat config picks the file up regardless of `--ext`.
Verified with CI's own command this time, not the hook's.

* fix(review): the collapse disclosure needs the guard its sibling already has

Three findings from the round on this branch, all accepted.

`isEmptyDiff` refuses to rule when the merge base came from a possibly
stale local ref, because such a base can already contain the head
commits and diff to empty. The PARTIAL form of that cause lands on
`isCollapsedFromUpstream` instead - a stale ref holding most of the head
commits shrinks the recomputed diff past the 4x ratio - and the flag
then tells Agent 0 to read the body as description-of-history when the
body may be perfectly current and the real cause is a fetch failure. Two
predicates over the same evidence, one guarded and one not. Guarded now,
and pinned: removing the guard fails exactly one test.

The pre-set of `mutantsSkippedForBudget`/`hunksSkippedForBudget` in the
no-budget-for-control branch was dead in every path and worse than dead
in one: both loops run with `harnessValidated` still null, re-check the
same budget, and set their own counters - and the hunk loop's figure
excludes the collocated-probe inconclusives it pushes first, which the
pre-set did not. Dropped, with the reason where the assignment was.

`runControlMutant`'s bound is now stated in its doc: it validates ONE
file, so a collector that silently drops a different probe file passes
the control while that file's survivors stand. The per-file baseline
gate bounds what is left. A `true` there is read as covering the run, so
what it does not cover belongs next to it.

* fix(review): bound the whole ledger marker, not just each of its fields

The per-field caps leave the total unbounded: fifty findings at full
width serialize to just under 17,000 characters. The module's own
paragraph calls the marker "a footnote, never a payload" and reasons
about GitHub's 65,536-character body limit, so the total is the number
that claim is about and nothing was computing it.

Set the budget from measurement rather than from the limit. Across every
review this pipeline has posted on its own stack (n=66) the body runs a
median of 721 characters, p90 2,178, max 3,925 - the limit has ~61 KiB
of headroom, and an over-long marker was never going to fail a post. The
real cost is proportion: 17,000 characters of invisible payload on a
3,925-character review is four times more marker than review. 8 KiB
holds fifty findings at realistic widths without dropping any, and the
truncation path is reached only by a ledger no round has produced.

What it drops travels with it. A `dropped` count is the difference
between a list the next round reads as complete and one that says it is
not - the same distinction this module already draws everywhere else.

* fix(review): a partial ledger must not render as a complete one

The size cap added in the previous commit can drop entries, and the
rendered section still opened with "**Every entry below is owed a
this-round ruling**" and said nothing about what was missing. The
`dropped` count existed and reached the only place a reader sees the
list as nothing at all — which is the failure it was added to prevent,
committed one step after adding the field. It now says the list is
partial, how many are missing, and that absence is not evidence a
finding was fixed.

Second, the table escaping escaped `|` but not `\`. `\|` in a title
became `\\|`, which markdown reads as an escaped backslash followed by a
LIVE separator: the forged row the escaping exists to prevent, produced
by the escaping. Backslash first now, and the test counts separators the
way markdown does rather than by pattern, because a lookbehind counter
is fooled by exactly the input under test.

* fix(review): an empty ledger title is a cap the next round cannot lift

A comment that is nothing but its severity marker produced a ledger
entry with an empty title. That does not merely degrade the entry, it
jams the review: the next round is told every ledger entry is owed a
this-round ruling, has no claim text to rule on, answers `cannot tell`,
and `cannot-tell-existing-critical` is one of the cap reasons. Nothing
between rounds changes, so the cap comes back every round.

Dropping the entry would hide a Critical that really was posted, so it
keeps its place and gets the one handle there is - the location it was
filed at, or "the review body" for a body-level one. The field's stated
job is "enough for the next round to re-locate the claim", and that is
what a text-less finding still has.

Found by probing `buildLedger` with ten malformed comment shapes; the
other nine - carried ids, id collisions, two comments carrying the same
id, `R2D2` not being an id, a leading newline before the marker - all
behaved correctly and needed no change.

* fix(review): count both caps as dropped, not just the byte one

Found by running the three previous fixes together on one round: 51
findings in, 24 kept, and the marker said 26 were missing.
`LEDGER_MAX_FINDINGS` truncates before the byte cap ever runs, and
measuring `dropped` against the already-sliced list left the count cap's
share silent - so the field added two commits ago to stop a truncated
list reading as complete was itself under-reporting the truncation.

Measured against what came IN now, and pinned across all four
combinations: count cap alone, byte cap alone, both, and neither. Kept
plus dropped equals given, in every one.

* fix(review): the ignore check was the one git spawn without a deadline

`isGitIgnored` reached for a bare `execFileSync` while every other git
invocation in these commands goes through the package helper, which
carries `GIT_TIMEOUT_MS` and `GIT_TERMINAL_PROMPT=0`. That constant's own
comment is the argument: "a hang must still end". This one ran against a
worktree the review does not control and could not.

No behavioural delta for any input that does not hang - all 80 test-plan
tests pass unchanged - so it ships without a new test rather than with a
mocked-spawn assertion that would pin the call shape instead of the
behaviour.

* docs(review): a control killed mid-run did not "never run at all"

SKILL's `harnessValidated` paragraph enumerated four ways the value
lands on `null` - no green baseline, no candidates, no budget, an
unreadable probe file - and all four are "the control never ran". There
is a fifth: `runControlMutant` throws when its deadline kills the run or
the runner cannot be spawned, the outer catch swallows it, and the value
stays `null` rather than becoming a fabricated `false`. That is the path
a slow machine takes.

The ruling is unchanged - neither validated nor refuted, a survivor
stands but unconfirmed - so this is about what the terminal says, not
what it decides. An agent quoting "the control never ran at all" for a
control that ran and was killed states something untrue about the run,
and the enumeration is what it quotes from.

---------

Co-authored-by: qwen-code-dev-bot <qwen-code-dev@service.alibaba.com>
Co-authored-by: Qwen Code <qwen-code@users.noreply.github.com>
Co-authored-by: Qwen Code Bot <qwen-code-bot@users.noreply.github.com>
Co-authored-by: Qwen Code Autofix <qwen-code-autofix@users.noreply.github.com>
@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Released in v0.21.3.

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

⚠️ Downgraded from Approve to Comment: CI failing: review-pr. Reviewed.

— qwen3.7-max via Qwen Code /review

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.

6 participants