Skip to content

feat(autofix): bridge fork-PR reviews into the credentialed review lane - #8676

Merged
wenshao merged 4 commits into
mainfrom
feat/autofix-fork-review-bridge
Aug 7, 2026
Merged

feat(autofix): bridge fork-PR reviews into the credentialed review lane#8676
wenshao merged 4 commits into
mainfrom
feat/autofix-fork-review-bridge

Conversation

@wenshao

@wenshao wenshao commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

What this PR does

Restores real-time autofix pickup for pull requests opened from a fork, using the standard workflow_run bridge.

Two workflows. qwen-autofix-fork-signal.yml runs on pull_request_review, where a fork PR's event can reach it, and records only which PR was reviewed — permissions: {}, no checkout, no repository code, hosted runner rather than the persistent self-hosted pool. qwen-autofix-fork-bridge.yml runs on workflow_run, which GitHub creates on the default branch with the repository's own token, validates the number, and dispatches qwen-autofix.yml for that PR using actions: write — the same lever Fleet Shepherd already pulls. Neither half holds a PAT.

The dispatched run re-derives admission from live API state (open, targeting main, bot-authored or takeover-labelled, and for a fork a live write+ author plus maintainer edits allowed), so the PR number says when to look, never who may be touched.

Why it's needed

A workflow run tied to a pull request whose head lives in a fork is created with Secret source: None, so secrets.CI_DEV_BOT_PAT arrives empty and the autofix review lane cannot authenticate. #8671 stopped that from reddening CI by declining those events in route, but it removed the capability rather than fixing it.

The cost is latency. A fork PR's review now waits for the scheduled scan, and qwen-autofix.yml records the measurement itself: the */10 cron actually lands every 40-70 minutes on this repo. Every takeover-labelled fork PR — the ones a maintainer is actively waiting on — pays that.

Reading the PR with github.token instead would not close the gap: review-address still needs the PAT to push and comment, and it is empty for the whole run. The credential has to come from a different run, which is what workflow_run provides.

Reviewer Test Plan

How to verify

Three properties make it safe to act on a number that arrives from a fork-triggered run. Each was measured rather than assumed, and a reviewer can re-run each command.

A fork cannot edit the signalpull_request_review runs the workflow file from the base branch. Run 31152873061 is a review on PR #8436, whose branch does not contain #8410:

$ git merge-base --is-ancestor d5e47709a3 pr8436 && echo 包含 || echo 不包含
不包含
$ git show pr8436:.github/workflows/qwen-autofix.yml | grep -c read_forced_pr_meta
0
$ gh api repos/QwenLM/qwen-code/actions/jobs/92786326577/logs | grep -c read_forced_pr_meta
2

The run executed a script its own PR branch does not contain, so the file came from base.

The number is bound to the run that produced it — that run's head_sha equals the reviewed PR's head exactly:

$ gh api repos/QwenLM/qwen-code/actions/runs/31152873061 --jq '.head_sha'
b8ac04ef99c37cab53b28d2c80cbfe55f853f557
$ gh pr view 8436 --json headRefOid --jq '.headRefOid'
b8ac04ef99c37cab53b28d2c80cbfe55f853f557

The bridge fetches the named PR and refuses unless its head matches, failing closed on an empty or unreadable head.

The artifact is the only channelworkflow_run.pull_requests is empty for fork PRs, and /commits/{sha}/pulls does not resolve a fork head either:

$ gh api repos/QwenLM/qwen-code/actions/runs/31152873061 --jq '.pull_requests|length'
0
$ gh api repos/QwenLM/qwen-code/commits/b8ac04ef.../pulls    # fork head
[]
$ gh api repos/QwenLM/qwen-code/commits/a8898837.../pulls --jq 'length'   # in-repo head
1

Then run the suite:

npx vitest run --config ./scripts/tests/vitest.config.ts scripts/tests/qwen-autofix-fork-bridge-workflow.test.js

Expected: 4/4 pass. It pins the cross-file contracts (the bridge's workflows: entry equals the signal's name:, the download name equals the upload name, the read path equals the written path, and qwen-autofix.yml really accepts a pr_number dispatch input) and replays the bridge's validate-and-dispatch block under bash against a stub API.

Evidence (Before & After)

N/A — no user-visible or TUI surface. This cannot be exercised end to end before merge either: workflow_run only fires for workflows already present on the default branch. The evidence is the stub-API replay and the mutation results below.

The replayed cases: happy path; forgery (a real open PR whose head differs — every other check passes, only the binding refuses it); an unreadable head; both heads empty (the case a bare != gets wrong); non-numeric, empty and path-shaped artifacts; a closed, retargeted or in-repo PR; download and PR-read failures; and dispatch retry-then-exhaustion.

Mutation-tested — 12 of 12 caught:

mutation caught
drop the head_sha binding
drop the empty-head guard
loosen the PR-number regex
drop the conclusion == 'success' filter
drop the state/base/fork early-outs
dispatch once, no retry
drop the pr_number input
rename the signal workflow
change the artifact name
give the signal permissions
drop the fork-only gate

The empty-head-guard mutation initially survived; that is what added the both-heads-empty case.

Tested on

OS Status
🍏 macOS N/A
🪟 Windows N/A
🐧 Linux

Environment (optional)

Workflow YAML and a vitest suite only; no local runtime involved.

Risk & Scope

  • Main risk or tradeoff: the bridge acts on a PR number that originates in a fork-triggered run. Mitigated by three layers: the signal workflow is read from the base branch so a fork cannot edit it; the number is parsed as bounded digits before becoming a shell word or API path segment; and it is bound to workflow_run.head_sha, so a signal cannot name a PR other than the one whose review produced it. Beyond that the dispatched run re-derives admission from live API state, so the number only chooses timing.
  • Not validated / out of scope: end-to-end behaviour cannot be observed before merge, because workflow_run only fires for workflows already on the default branch. The first real fork-PR review after merge is the live check. The takeover-label lane (pull_request labelled on a fork) is deliberately not bridged — it needs an ack comment, which a pr_number dispatch cannot produce, and route already declines it.
  • Breaking changes / migration notes: none. Two new workflows; nothing existing is modified. Enabling Send secrets to workflows from fork pull requests would also fix the underlying problem and should not be done — review-address checks out and builds fork code in the same run that would then hold the PAT.

Linked Issues

Depends on #8671 (merged). That PR removed the fork-PR review lane because it could never authenticate; this one restores the capability with credentials that actually exist. Merging this alone would have added a working dispatch beside a still-red direct lane, so it is intended to land after #8671 — which it now does.

中文说明

What this PR does

用标准的 workflow_run 桥接,恢复 fork PR 的 autofix 实时接管。

两个 workflow。qwen-autofix-fork-signal.ymlpull_request_review 上运行(fork PR 的事件能触达这里),只记录被评审的是哪个 PR —— permissions: {}、不 checkout、不执行仓库代码、用托管 runner 而非持久化的自托管池。qwen-autofix-fork-bridge.ymlworkflow_run 上运行,GitHub 会把该 run 创建在默认分支上并带有仓库自身的 token;它校验号码后用 actions: write dispatch qwen-autofix.yml——Fleet Shepherd 已经在用同一个手段。两半都不持有 PAT。

被 dispatch 的 run 会从实时 API 状态重新推导准入条件(open、面向 main、bot 创建或带接管标签,fork 还需作者实时 write+ 且允许维护者编辑),所以 PR 号只说明何时去看,绝不决定谁可以被改动。

Why it's needed

绑定在 fork PR head 上的 workflow run 以 Secret source: None 创建,secrets.CI_DEV_BOT_PAT 为空,autofix 评审车道无法认证。#8671 通过在 route 中拒绝这些事件止住了 CI 报红,但那是移除能力,不是修复它。

代价是延迟。fork PR 的评审现在要等定时扫描,而 qwen-autofix.yml 自己记录了实测值:*/10 的 cron 在本仓每 40-70 分钟才真正落一次。每一个带接管标签的 fork PR——正是维护者在等的那些——都要付这个代价。

改用 github.token 读 PR 并不能补上缺口:review-address 仍然需要 PAT 来 push 和发评论,而它在整个 run 里都是空的。凭据必须来自另一个 run,这正是 workflow_run 提供的。

Reviewer Test Plan

How to verify

有三个性质使得「依据一个来自 fork 触发 run 的号码去行动」是安全的。每一条都是实测而非假设,评审者可以逐条复跑。

fork 无法篡改 signal —— pull_request_review 使用 base 分支的 workflow 文件。run 31152873061 是对 PR #8436 的评审,而 #8436 的分支不含 #8410

$ git merge-base --is-ancestor d5e47709a3 pr8436 && echo 包含 || echo 不包含
不包含
$ git show pr8436:.github/workflows/qwen-autofix.yml | grep -c read_forced_pr_meta
0
$ gh api repos/QwenLM/qwen-code/actions/jobs/92786326577/logs | grep -c read_forced_pr_meta
2

该 run 执行了一份它自己 PR 分支里并不存在的脚本,说明文件来自 base。

号码与产生它的 run 绑定 —— 该 run 的 head_sha 与被评审 PR 的 head 完全相等:

$ gh api repos/QwenLM/qwen-code/actions/runs/31152873061 --jq '.head_sha'
b8ac04ef99c37cab53b28d2c80cbfe55f853f557
$ gh pr view 8436 --json headRefOid --jq '.headRefOid'
b8ac04ef99c37cab53b28d2c80cbfe55f853f557

桥接侧取回被指名的 PR,head 不匹配就拒绝;空值或读取失败一律失败关闭。

artifact 是唯一通道 —— fork PR 的 workflow_run.pull_requests 为空,/commits/{sha}/pulls 也解析不出 fork 的 head:

$ gh api repos/QwenLM/qwen-code/actions/runs/31152873061 --jq '.pull_requests|length'
0
$ gh api repos/QwenLM/qwen-code/commits/b8ac04ef.../pulls    # fork head
[]
$ gh api repos/QwenLM/qwen-code/commits/a8898837.../pulls --jq 'length'   # in-repo head
1

然后跑测试套件:

npx vitest run --config ./scripts/tests/vitest.config.ts scripts/tests/qwen-autofix-fork-bridge-workflow.test.js

预期 4/4 通过。它钉住了跨文件契约(桥接的 workflows: 条目等于 signal 的 name:、下载名等于上传名、读取路径等于写入路径,且 qwen-autofix.yml 确实接受 pr_number 这个 dispatch 输入),并用 bash 对着 stub API 真实回放桥接的「校验并 dispatch」代码块。

Evidence (Before & After)

N/A —— 没有用户可见界面或 TUI 变化。合入前也无法端到端跑通:workflow_run 只对已经位于默认分支上的 workflow 生效。证据是下面的 stub API 回放与变异测试结果。

回放覆盖的场景:正常路径;伪造(一个真实存在且 open 的 PR,但 head 不同——其他检查全部通过,只有绑定把它拦下);head 不可读;两侧 head 都为空(裸 != 会判错的那个场景);非数字、空、路径形状的 artifact;PR 已关闭、已改 base、或非 fork;下载与 PR 读取失败;以及 dispatch 重试直至耗尽。

变异测试 —— 12 个全部被捕获:

变异 被捕获
删除 head_sha 绑定
删除空 head 守卫
放松 PR 号正则
删除 conclusion == 'success' 过滤
删除 state/base/fork 早退
只 dispatch 一次、不重试
去掉 pr_number 输入
重命名 signal workflow
改动 artifact 名
给 signal 加权限
删除 fork-only 门

空 head 守卫那个变异最初存活了,正是它促成补上「两侧 head 都为空」这个用例。

Tested on

OS Status
🍏 macOS N/A
🪟 Windows N/A
🐧 Linux

Environment (optional)

只涉及 workflow YAML 与一个 vitest 套件,不需要本地运行时。

Risk & Scope

  • 主要风险 / 权衡: 桥接依据的号码源自一个 fork 触发的 run。由三层缓解:signal workflow 从 base 分支读取,fork 无法编辑;号码在成为 shell 词或 API 路径片段之前,先被解析为有界纯数字;并且它与 workflow_run.head_sha 绑定,signal 无法指向「产生它的那次评审」之外的 PR。在此之上,被 dispatch 的 run 还会从实时 API 状态重新推导准入条件,所以号码只决定时机。
  • 未验证 / 范围之外: 合入前无法观察端到端行为,因为 workflow_run 只对已在默认分支上的 workflow 生效;合入后第一个真实的 fork PR 评审就是实地检验。接管标签车道(fork 上的 pull_request labeled)刻意不做桥接——它需要发出 ack 评论,而 pr_number dispatch 产生不了,且 route 已经明确拒绝了该路径。
  • 破坏性变更 / 迁移说明: 无。新增两个 workflow,不修改任何现有文件。打开 Send secrets to workflows from fork pull requests 同样能修根因,但不应该做——review-address 会在同一个 run 里 checkout 并构建 fork 的代码,而那个 run 届时持有 PAT。

Linked Issues

依赖 #8671(已合入)。那个 PR 移除了 fork PR 的评审车道(它从来无法认证),本 PR 用真实存在的凭据恢复该能力。单独合入本 PR,会在一条仍然报红的直连车道旁边多出一条能用的 dispatch,因此它设计为在 #8671 之后落地——目前已满足。

A workflow run tied to a pull request whose head lives in a fork is
created with `Secret source: None`, so `secrets.CI_DEV_BOT_PAT` is empty
and the autofix review lane cannot authenticate. Those reviews therefore
wait for the scheduled scan, which GitHub throttles hard — the `*/10`
cron lands every 40-70 minutes on this repo.

Reading the PR with `github.token` instead would not help: review-address
still needs the PAT to push and comment, and it is empty for the whole
run. The credential has to come from a different run.

This is the standard `workflow_run` bridge for that.

- `qwen-autofix-fork-signal.yml` runs on `pull_request_review`, where the
  fork PR's event can reach it, and records only which PR was reviewed.
  It is deliberately powerless: `permissions: {}`, no checkout, no
  repository code, and the hosted pool rather than the persistent
  self-hosted one.
- `qwen-autofix-fork-bridge.yml` runs on `workflow_run`, which GitHub
  creates on the default branch with the repository's own token, and
  dispatches `qwen-autofix.yml` for that PR using `actions: write` — the
  same lever Fleet Shepherd already pulls. It holds no PAT.

The dispatched run re-derives admission from live API state, so the PR
number says when to look, never who may be touched. It is bound to
`workflow_run.head_sha` regardless: the signal run carries the reviewed
PR's head SHA, and only that PR has that head.

Measured, not assumed:

- `workflow_run.pull_requests` is empty for fork PRs, and
  `/commits/{sha}/pulls` does not resolve a fork head either (it does
  resolve an in-repo one), so the artifact is the only way to learn the
  number.
- `pull_request_review` runs the workflow file from the BASE branch: run
  31152873061's PR branch predates a main-only change to
  `qwen-autofix.yml` and it still executed the new file. A fork cannot
  edit what the signal writes.
- That run's `head_sha` equals PR #8436's `headRefOid` exactly, which is
  what makes the binding possible.

The bridge's validate-and-dispatch block is replayed under bash against a
stub API: forgery, an unreadable head, both heads empty, non-numeric and
path-shaped artifacts, a closed or retargeted PR, download and read
failures, and dispatch retry then exhaustion.
@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

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

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

@qwen-code-ci-bot qwen-code-ci-bot 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.

@wenshao The content here is unusually thorough — the problem, the design, and the verification are all well documented — but the body skips the PR template entirely, so this is a formatting gate, not a code concern.

All five required headings from pull_request_template.md are missing: ## What this PR does, ## Why it's needed, ## Reviewer Test Plan (with ### How to verify, ### Evidence (Before & After), ### Tested on), ## Risk & Scope, and ## Linked Issues. Your recent merged PRs — including the CI-only ones — all use this template, so this one stands out.

Could you restructure the body under those headings? The existing sections map across cleanly: Summary → What this PR does; the Secret source: None problem and the 40-70 minute cron latency → Why it's needed; Verification → Reviewer Test Plan (Before/After is N/A since workflow_run cannot fire before merge — the stub-API replay and the 12/12 mutation results are the evidence); the safety analysis plus "Deliberately not done" → Risk & Scope. Please put the dependency on #8671 and the intended merge ordering into Linked Issues — that is the piece a merging maintainer most needs to see in the standard place.

Once the body follows the template, re-run me and I'll take it through the full review.

中文说明

@wenshao 这个 PR 的内容非常扎实——问题、设计和验证都写得很清楚——但正文完全没有使用 PR 模板,所以这是一次格式上的拦截,而不是对代码的质疑。

pull_request_template.md 要求的五个标题全部缺失:## What this PR does## Why it's needed## Reviewer Test Plan(含 ### How to verify### Evidence (Before & After)### Tested on)、## Risk & Scope## Linked Issues。你最近合入的 PR——包括纯 CI 类的——都使用了这个模板,这一个因此显得例外。

能否把正文重新组织到这些标题下?现有章节可以直接对应:Summary → What this PR does;Secret source: None 问题和 40-70 分钟的 cron 延迟 → Why it's needed;Verification → Reviewer Test Plan(Before/After 写 N/A,因为 workflow_run 在合入前无法触发——stub API 回放和 12/12 变异测试结果就是证据);安全性分析加上「刻意没有做的事」→ Risk & Scope。请把对 #8671 的依赖以及预期的合入顺序写进 Linked Issues——这是合入时 maintainer 最需要在标准位置看到的信息。

正文符合模板后重新触发我,我会完整走一遍审查流程。

Qwen Code · qwen3.8-max

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Summary

Package Lines Statements Functions Branches
CLI 83.57% 83.57% 89.63% 82.69%
Core 87.72% 87.72% 89.3% 86.26%
CLI Package - Full Text Report
-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |   83.57 |    82.69 |   89.63 |   83.57 |                   
 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.33 |    72.97 |   90.03 |   70.33 |                   
  acpAgent.ts      |   70.02 |    72.86 |   90.07 |   70.02 | ...40,11945-11947 
  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,242-243 
 ...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.62 |    72.18 |   64.51 |   89.62 |                   
  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.68 |    66.66 |     100 |   87.68 | ...31,743,759-763 
  sessions.ts      |     100 |      100 |      50 |     100 |                   
  update.ts        |   98.13 |    94.44 |   66.66 |   98.13 | 82-83             
 ...mmands/channel |   88.32 |    87.71 |    90.3 |   88.32 |                   
  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.39 |   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       |      75 |      100 |      50 |      75 | 22-28,59-70       
  pidfile.ts       |   95.55 |       90 |     100 |   95.55 | ...50-251,315-316 
  proxy.ts         |     100 |      100 |     100 |     100 |                   
  reload.ts        |    77.5 |    86.95 |      75 |    77.5 | 72-84,93-97       
  runtime.ts       |   82.43 |    86.44 |     100 |   82.43 | ...87-191,251-253 
  set.ts           |   75.72 |    85.71 |      50 |   75.72 | 65-83,111-116     
  start.ts         |    85.8 |    82.17 |      88 |    85.8 | ...85,591-594,606 
  ...ure-format.ts |   93.65 |    82.45 |     100 |   93.65 | ...42,48-49,74-75 
  status.ts        |   78.57 |    59.25 |   66.66 |   78.57 | ...36-137,150-161 
  stop.ts          |   57.83 |    82.35 |      50 |   57.83 | ...3,74-76,85-111 
 ...nds/extensions |   88.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 |   87.32 |    87.84 |   88.41 |   87.32 |                   
  agent-prompt.ts  |   92.82 |    92.19 |   96.96 |   92.82 | ...2122,2236-2316 
  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 | ...04-505,545-555 
  drive.ts         |   76.07 |    85.71 |   81.81 |   76.07 | ...90-492,497-499 
  extract-step.ts  |   91.36 |    90.62 |   88.88 |   91.36 | ...90-707,714-729 
  fetch-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.66 |    96.55 |     100 |   99.66 | 404               
  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 |    89.9 |    81.81 |   94.11 |    89.9 | ...08-311,404-407 
  script-lint.ts   |   83.67 |    78.41 |   88.88 |   83.67 | ...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 |   97.08 |     94.8 |   97.58 |   97.08 |                   
  agent-briefs.ts  |   98.95 |      100 |      50 |   98.95 | 695-696           
  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.94 |    95.39 |   95.65 |   95.94 | ...14,351,460-477 
  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.19 |    94.93 |     100 |   96.19 | ...90-491,496-499 
  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 |   97.88 |    93.87 |     100 |   97.88 | 260-261,267       
  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 |    89.77 |     100 |     100 | ...16-317,328,430 
  review-footer.ts |     100 |      100 |     100 |     100 |                   
  roster.ts        |     100 |    95.71 |     100 |     100 | 145,163,208       
  shell-quote.ts   |     100 |      100 |     100 |     100 |                   
  stale-bundle.ts  |   98.11 |    94.04 |     100 |   98.11 | 416,457,497-498   
  test-utils.ts    |     100 |      100 |     100 |     100 |                   
  transcripts.ts   |   96.59 |    94.56 |     100 |   96.59 | ...08,297-298,323 
  ...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.66 |    89.35 |   96.02 |   94.66 |                   
  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.87 |     100 |   98.97 | 85                
  mcpApprovals.ts  |   96.55 |    95.55 |     100 |   96.55 | 223-224,229-231   
  mcpJson.ts       |     100 |      100 |     100 |     100 |                   
  mcpServers.ts    |   92.85 |     87.5 |     100 |   92.85 | 46-47             
  ...idersScope.ts |      95 |    94.73 |     100 |      95 | 11-12             
  ...abledTools.ts |     100 |      100 |     100 |     100 |                   
  ...comparison.ts |     100 |      100 |     100 |     100 |                   
  ...n-settings.ts |   99.15 |    93.75 |     100 |   99.15 | 63                
  sandboxConfig.ts |   93.33 |    93.33 |     100 |   93.33 | ...42-147,216-217 
  ...ings-cache.ts |   98.26 |    97.14 |     100 |   98.26 | 201-202           
  settings.ts      |   91.27 |    92.64 |      90 |   91.27 | ...1030,1032-1033 
  ...ingsSchema.ts |     100 |      100 |     100 |     100 |                   
  ...ngsWatcher.ts |   95.54 |    88.34 |     100 |   95.54 | ...28,277-278,293 
  ...d-env-keys.ts |     100 |      100 |     100 |     100 |                   
  ...l-settings.ts |     100 |      100 |     100 |     100 |                   
  ...paths-lite.ts |   89.47 |       88 |     100 |   89.47 | 43-44,53-54,56-57 
  ...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.29 |    83.45 |   90.44 |   87.29 |                   
  ...tp-enabled.ts |     100 |      100 |     100 |     100 |                   
  ...ion-bridge.ts |     100 |      100 |     100 |     100 |                   
  auth.ts          |   93.43 |    92.95 |     100 |   93.43 | ...20-321,324-326 
  ...em-adapter.ts |     100 |      100 |     100 |     100 |                   
  capabilities.ts  |     100 |    98.07 |     100 |     100 | 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 |    94.1 |    86.89 |     100 |    94.1 | ...75-477,484,486 
  ...-selection.ts |     100 |      100 |     100 |     100 |                   
  ...ings-store.ts |    86.2 |    92.35 |   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 
  ...y-pressure.ts |     100 |    96.96 |     100 |     100 | 135               
  ...trics-ring.ts |     100 |      100 |     100 |     100 |                   
  ...s-provider.ts |   68.04 |    52.77 |     100 |   68.04 | ...44-249,282-290 
  daemon-status.ts |   98.57 |     90.8 |     100 |   98.57 | ...1411,1413-1414 
  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.98 |    81.38 |   95.45 |   90.98 | ...32-541,607-608 
  ...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.58 |    79.69 |   75.26 |   83.58 | ...7249,7255-7256 
  ...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.57 |    90.92 |   71.69 |   90.57 | ...2663,2677-2681 
  ...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 | ...20,823,836-838 
  ...l-resolver.ts |   90.32 |    66.66 |     100 |   90.32 | 16,45-46          
  ...ell-static.ts |   92.18 |    88.37 |     100 |   92.18 | ...21-224,267-270 
  ...ace-agents.ts |   66.13 |    70.57 |   92.68 |   66.13 | ...2246,2256-2266 
  ...generation.ts |    95.4 |    82.35 |   66.66 |    95.4 | 55-56,78,92       
  ...-git-state.ts |     100 |    91.93 |    90.9 |     100 | 161,172,202,265   
  ...ace-inputs.ts |     100 |      100 |     100 |     100 |                   
  ...ace-memory.ts |      83 |    74.54 |     100 |      83 | ...30-537,597-604 
  ...ers-status.ts |   98.58 |       79 |     100 |   98.58 | 106,134,174,177   
  ...tion-store.ts |   89.67 |    88.27 |   92.59 |   89.67 | ...91-400,411-414 
  ...e-registry.ts |   93.89 |     87.5 |     100 |   93.89 | ...18-519,525-526 
  ...e-remember.ts |   98.23 |    92.51 |     100 |   98.23 | ...36,340-345,386 
  ...te-runtime.ts |   83.98 |    90.29 |     100 |   83.98 | ...48-156,216-237 
  ...me-storage.ts |     100 |      100 |     100 |     100 |                   
  ...management.ts |   72.63 |    72.72 |      96 |   72.63 | ...88-889,896-900 
  ...lls-status.ts |     100 |    95.45 |     100 |     100 | 152               
  ...reconciler.ts |   91.63 |    84.09 |     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.31 |    79.62 |   95.45 |   85.31 |                   
  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.71 |    83.33 |     100 |   85.71 | 101-108           
  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 | ...4777,4779-4780 
  sse-events.ts    |   86.82 |    85.71 |   94.11 |   86.82 | ...16-927,930,937 
  usage-stats.ts   |     100 |    95.45 |     100 |     100 | 118               
  ...space-auth.ts |   85.55 |    75.64 |     100 |   85.55 | ...21-326,331,345 
  ...el-control.ts |   86.26 |    78.94 |     100 |   86.26 | ...17-318,339-347 
  ...management.ts |   90.92 |    79.69 |     100 |   90.92 | ...81-482,501-502 
  ...d-contacts.ts |     100 |      100 |     100 |     100 |                   
  ...controller.ts |   83.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.11 |   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.59 |     100 |     100 | 34,42,103,159     
  ...branch-ops.ts |     100 |      100 |     100 |     100 |                   
  ...t-deadline.ts |     100 |      100 |     100 |     100 |                   
  ...iter-setup.ts |      65 |    73.33 |   33.33 |      65 | 30-35,38-43,47-48 
  ...st-helpers.ts |   95.11 |    95.19 |     100 |   95.11 | ...65-167,422-427 
  self-origin.ts   |   76.19 |       80 |     100 |   76.19 | 45-54             
  ...e-features.ts |      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.44 |     100 |   99.02 | ...25,639,781-783 
 src/serve/voice   |    92.7 |    91.48 |   97.67 |    92.7 |                   
  ...ice-config.ts |   84.81 |       30 |     100 |   84.81 | 91-100,104-105    
  voice-ws.ts      |   91.58 |    93.44 |      96 |   91.58 | ...68,483,521-523 
  ...oordinator.ts |     100 |    98.21 |     100 |     100 | 176               
 ...kspace-service |   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.48 |    89.31 |      98 |   92.48 |                   
  ...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.77 |     100 |   98.64 | 116,142-143       
  voice-model.ts   |     100 |      100 |     100 |     100 |                   
  voice-service.ts |    90.4 |    87.87 |     100 |    90.4 | ...81,288,353-358 
  ...e-settings.ts |     100 |    95.23 |     100 |     100 | 19                
  ...ranscriber.ts |   91.77 |    87.11 |   97.22 |   91.77 | ...99-901,904-906 
 ...rvices/insight |     100 |      100 |     100 |     100 |                   
  dates.ts         |     100 |      100 |     100 |     100 |                   
 ...ght/generators |   88.91 |    86.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 | 96-99             
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/services/tips |   97.27 |    84.61 |     100 |   97.27 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  tipHistory.ts    |   92.59 |       70 |     100 |   92.59 | ...24,146,153,162 
  tipRegistry.ts   |     100 |      100 |     100 |     100 |                   
  tipScheduler.ts  |     100 |    91.66 |     100 |     100 | 55                
 src/startup       |   88.99 |    83.47 |    90.9 |   88.99 |                   
  ...p-prefetch.ts |   98.09 |    94.23 |    87.5 |   98.09 | 50,209,225-226    
  ...reeStartup.ts |   80.53 |     74.6 |     100 |   80.53 | ...94,403,409-412 
 src/test-utils    |   94.09 |    79.16 |   77.77 |   94.09 |                   
  ci-env.ts        |      88 |     62.5 |     100 |      88 | 22-23,28          
  ...omMatchers.ts |   69.69 |       50 |      50 |   69.69 | 32-35,37-39,45-47 
  ...mised-lock.ts |     100 |      100 |   66.66 |     100 |                   
  ...andContext.ts |     100 |      100 |     100 |     100 |                   
  render.tsx       |     100 |      100 |     100 |     100 |                   
 src/ui            |   72.78 |    75.23 |   65.16 |   72.78 |                   
  App.tsx          |   33.33 |       75 |   33.33 |   33.33 | 32-86             
  AppContainer.tsx |   74.01 |    72.14 |   68.57 |   74.01 | ...4112,4228-4234 
  ...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.57 |    82.92 |   89.15 |   82.57 |                   
  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 |    77.41 |     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 |   69.07 |     72.6 |   84.61 |   69.07 | ...78-611,622-623 
  copyCommand.ts   |    98.7 |    96.29 |     100 |    98.7 | 66-67,172,272,323 
  ...or-command.ts |   85.95 |    80.55 |   88.88 |   85.95 | ...68-274,298-309 
  deleteCommand.ts |     100 |      100 |     100 |     100 |                   
  diffCommand.ts   |     100 |    87.87 |     100 |     100 | ...63,231-232,245 
  ...ryCommand.tsx |   81.64 |    87.67 |    90.9 |   81.64 | ...73-278,325-332 
  docsCommand.ts   |     100 |     90.9 |     100 |     100 | 25                
  doctorCommand.ts |   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 |   94.44 |    90.14 |     100 |   94.44 | ...13-214,241-251 
  learn-command.ts |     100 |      100 |     100 |     100 |                   
  lspCommand.ts    |     100 |    86.95 |     100 |     100 | 31,101-102        
  mcpCommand.ts    |     100 |      100 |     100 |     100 |                   
  memoryCommand.ts |     100 |      100 |     100 |     100 |                   
  modelCommand.ts  |   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.96 |    86.04 |     100 |   90.96 | ...41-146,177-178 
  resumeCommand.ts |     100 |      100 |     100 |     100 |                   
  rewindCommand.ts |   81.25 |      100 |      50 |   81.25 | 20-22             
  ...ngsCommand.ts |     100 |      100 |     100 |     100 |                   
  ...hubCommand.ts |   89.47 |       75 |      80 |   89.47 | 54-59             
  skillsCommand.ts |   78.82 |    81.81 |     100 |   78.82 | 37-52,78,97       
  statsCommand.ts  |   90.65 |    76.73 |     100 |   90.65 | ...30-733,825-832 
  ...ineCommand.ts |     100 |      100 |     100 |     100 |                   
  ...aryCommand.ts |   73.04 |     82.3 |      90 |   73.04 | ...20-547,561-565 
  tasksCommand.ts  |   77.22 |    72.13 |     100 |   77.22 | ...46-150,172-177 
  ...tupCommand.ts |     100 |      100 |     100 |     100 |                   
  themeCommand.ts  |     100 |      100 |     100 |     100 |                   
  toolsCommand.ts  |     100 |      100 |     100 |     100 |                   
  trustCommand.ts  |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...te-command.ts |     100 |    94.11 |     100 |     100 | 74,148            
  vimCommand.ts    |   54.54 |      100 |      50 |   54.54 | 19-29             
  voice-command.ts |   93.57 |       88 |     100 |   93.57 | 35,97-102         
  ...owsCommand.ts |   91.86 |    78.87 |   66.66 |   91.86 | ...60-161,170-175 
 src/ui/components |   71.42 |     78.8 |   79.85 |   71.42 |                   
  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.28 |    66.33 |     100 |   79.28 | ...08,511,514-520 
  ...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 |   95.67 |    87.09 |     100 |   95.67 | ...24-125,275-277 
  ...inalImage.tsx |     100 |    93.93 |     100 |     100 | 75,129            
  ThemeDialog.tsx  |   89.95 |    46.15 |      75 |   89.95 | ...71-173,243-245 
  Tips.tsx         |   93.54 |       75 |     100 |   93.54 | 39-40             
  TodoDisplay.tsx  |     100 |      100 |     100 |     100 |                   
  ...tsDisplay.tsx |     100 |     87.5 |     100 |     100 | 31-32             
  TrustDialog.tsx  |     100 |    83.33 |     100 |     100 | 72-87             
  ...ification.tsx |   36.36 |      100 |       0 |   36.36 | 15-22             
  ...Indicator.tsx |    92.5 |     87.5 |     100 |    92.5 | 50-53             
  ...ackDialog.tsx |       0 |        0 |       0 |       0 | 1-134             
  ...xitDialog.tsx |   80.36 |    43.47 |      60 |   80.36 | ...24-238,248-251 
  ...odeVisuals.ts |   97.22 |    85.71 |     100 |   97.22 | 25                
  ...s-helpers.tsx |   66.25 |    81.25 |      50 |   66.25 | 25-32,46-53,62-72 
 ...nts/agent-view |   55.05 |    69.09 |      50 |   55.05 |                   
  ...atContent.tsx |    9.09 |      100 |       0 |    9.09 | 54-275,281-283    
  ...tChatView.tsx |   21.05 |      100 |       0 |   21.05 | 21-39             
  ...tComposer.tsx |   69.48 |    33.33 |   66.66 |   69.48 | ...51,269,277-279 
  AgentFooter.tsx  |   15.38 |      100 |       0 |   15.38 | 28-65             
  AgentHeader.tsx  |   15.38 |      100 |       0 |   15.38 | 27-64             
  AgentTabBar.tsx  |    87.9 |    63.88 |     100 |    87.9 | ...88,110-118,136 
  ...oryAdapter.ts |     100 |    91.83 |     100 |     100 | 103,109-110,138   
  index.ts         |       0 |        0 |       0 |       0 | 1-12              
 ...mponents/arena |    42.3 |    68.69 |   73.68 |    42.3 |                   
  ArenaCards.tsx   |   73.06 |    71.79 |   85.71 |   73.06 | ...83-185,321-326 
  ...ectDialog.tsx |   83.48 |    69.86 |   88.88 |   83.48 | ...88-392,409-410 
  ...artDialog.tsx |       0 |        0 |       0 |       0 | 1-166             
  ...tusDialog.tsx |       0 |        0 |       0 |       0 | 1-288             
  ...topDialog.tsx |       0 |        0 |       0 |       0 | 1-213             
 ...ackground-view |   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.3 |   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.24 |     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 |   90.11 |    86.69 |   85.43 |   90.11 |                   
  ...ionDialog.tsx |   89.23 |     84.9 |   81.81 |   89.23 | ...75,593,611-613 
  BtwMessage.tsx   |     100 |      100 |     100 |     100 |                   
  ...upDisplay.tsx |     100 |    94.73 |     100 |     100 | ...43,289,402,432 
  ...onMessage.tsx |   92.06 |    82.35 |     100 |   92.06 | 58-60,62,64       
  ...nMessages.tsx |   94.11 |    95.91 |   76.92 |   94.11 | ...47-349,352-355 
  DiffRenderer.tsx |   93.17 |    86.02 |     100 |   93.17 | ...07,235-236,302 
  ...tsDisplay.tsx |   97.08 |    77.77 |     100 |   97.08 | 95,97,106         
  ...usMessage.tsx |   81.73 |     65.9 |      75 |   81.73 | ...10-214,222,245 
  ...tsDisplay.tsx |   95.52 |    88.31 |     100 |   95.52 | ...40,142,175-180 
  ...ssMessage.tsx |    12.5 |      100 |       0 |    12.5 | 18-59             
  ...edMessage.tsx |   21.05 |      100 |       0 |   21.05 | 23-39             
  ...sMessages.tsx |   59.04 |       50 |    37.5 |   59.04 | ...21-126,147-159 
  ...ryMessage.tsx |   13.63 |      100 |       0 |   13.63 | 23-64             
  ...onMessage.tsx |   91.38 |    81.02 |     100 |   91.38 | ...33-635,642-644 
  ...upMessage.tsx |   98.38 |    95.38 |     100 |   98.38 | 188-191,422       
  ToolMessage.tsx  |   92.87 |    86.17 |   93.33 |   92.87 | ...1009,1036-1038 
 ...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 |    70.1 |    72.89 |   61.11 |    70.1 |                   
  ContextUsage.tsx |   71.49 |    64.86 |      80 |   71.49 | ...30-436,473-567 
  DoctorReport.tsx |     9.8 |      100 |       0 |     9.8 | 25-54,57-131      
  ...sionsList.tsx |   88.05 |       75 |     100 |   88.05 | 70-77             
  McpStatus.tsx    |   92.01 |     73.8 |     100 |   92.01 | ...36,175-177,262 
  SkillsList.tsx   |   20.51 |      100 |       0 |   20.51 | 17-20,27-57       
  ToolsList.tsx    |     100 |      100 |     100 |     100 |                   
 src/ui/contexts   |   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      |   85.57 |    82.91 |   88.04 |   85.57 |                   
  ...dProcessor.ts |   85.53 |    85.13 |     100 |   85.53 | ...-970,1017-1018 
  ...ention-ref.ts |   97.72 |       84 |     100 |   97.72 | 65                
  keyToAnsi.ts     |    3.92 |      100 |       0 |    3.92 | 19-77             
  ...esourceRef.ts |     100 |      100 |     100 |     100 |                   
  ...completion.ts |     100 |    95.45 |     100 |     100 | 95                
  ...ention-ref.ts |     100 |      100 |     100 |     100 |                   
  ...dProcessor.ts |   94.62 |    73.58 |     100 |   94.62 | ...87-288,293-294 
  ...dProcessor.ts |   85.65 |    68.16 |   81.81 |   85.65 | ...1455,1476-1480 
  ...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.45 |    83.01 |     100 |   95.45 | ...60-161,285-288 
  ...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 |   85.97 |    81.12 |   76.92 |   85.97 | ...5165-5167,5169 
  ...BranchName.ts |     100 |    94.44 |     100 |     100 | 54                
  ...oryManager.ts |   98.38 |    98.85 |     100 |   98.38 | 141-144           
  ...ooksDialog.ts |    87.5 |      100 |     100 |    87.5 | 19,23             
  ...stListener.ts |     100 |      100 |     100 |     100 |                   
  ...nAuthError.ts |   76.19 |       50 |     100 |   76.19 | 39-40,43-45       
  ...putHistory.ts |   92.59 |    85.71 |     100 |   92.59 | 63-64,72,94-96    
  ...storyStore.ts |     100 |    94.11 |     100 |     100 | 69                
  useKeypress.ts   |     100 |      100 |     100 |     100 |                   
  ...rdProtocol.ts |   36.36 |      100 |       0 |   36.36 | 24-31             
  ...unchEditor.ts |   22.58 |      100 |      50 |   22.58 | 11-32,44-85       
  ...gIndicator.ts |     100 |    96.66 |     100 |     100 | 109               
  useLogger.ts     |      16 |      100 |       0 |      16 | 15-45             
  useMCPHealth.ts  |   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.48 |    88.88 |     100 |   89.48 | ...54-456,489-499 
  ...oryCommand.ts |       0 |        0 |       0 |       0 | 1-7               
  ...umeCommand.ts |   95.26 |    77.14 |     100 |   95.26 | 120-121,223-228   
  ...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 |       70 |     100 |   93.75 | 47-48,72          
  vim.ts           |      74 |    67.56 |   69.23 |      74 | ...1854-1861,1869 
 src/ui/layouts    |    91.2 |    89.47 |     100 |    91.2 |                   
  ...AppLayout.tsx |    90.9 |     87.5 |     100 |    90.9 | 60-62,110-115,151 
  ...AppLayout.tsx |   91.66 |    92.85 |     100 |   91.66 | 75-80             
 src/ui/models     |   80.72 |       80 |   71.42 |   80.72 |                   
  ...ableModels.ts |   80.72 |       80 |   71.42 |   80.72 | ...,61-71,125-127 
 ...noninteractive |     100 |      100 |    6.66 |     100 |                   
  ...eractiveUi.ts |     100 |      100 |    6.66 |     100 |                   
 src/ui/selection  |   86.47 |    79.88 |   96.66 |   86.47 |                   
  screen-buffer.ts |   94.73 |    64.28 |     100 |   94.73 | 51-52             
  ...ion-coords.ts |     100 |      100 |     100 |     100 |                   
  ...ction-span.ts |   92.72 |       90 |     100 |   92.72 | 37-38,67-68       
  ...tion-state.ts |   85.71 |      100 |   88.88 |   85.71 | 51-58             
  ...ction-text.ts |   92.85 |    92.45 |     100 |   92.85 | 30-34,114-115     
  ...selection.tsx |   80.31 |    59.64 |     100 |   80.31 | ...13-314,330-331 
 src/ui/state      |      95 |    81.81 |     100 |      95 |                   
  extensions.ts    |      95 |    81.81 |     100 |      95 | 69-70,89          
 src/ui/themes     |    98.5 |    73.17 |     100 |    98.5 |                   
  ansi-light.ts    |     100 |      100 |     100 |     100 |                   
  ansi.ts          |     100 |      100 |     100 |     100 |                   
  atom-one-dark.ts |     100 |      100 |     100 |     100 |                   
  ayu-light.ts     |     100 |      100 |     100 |     100 |                   
  ayu.ts           |     100 |      100 |     100 |     100 |                   
  color-utils.ts   |   99.23 |    97.05 |     100 |   99.23 | 277-278           
  default-light.ts |     100 |      100 |     100 |     100 |                   
  default.ts       |     100 |      100 |     100 |     100 |                   
  ...inal-theme.ts |   88.59 |    85.96 |     100 |   88.59 | ...57-261,266-270 
  dracula.ts       |     100 |      100 |     100 |     100 |                   
  github-dark.ts   |     100 |      100 |     100 |     100 |                   
  github-light.ts  |     100 |      100 |     100 |     100 |                   
  googlecode.ts    |     100 |      100 |     100 |     100 |                   
  no-color.ts      |     100 |      100 |     100 |     100 |                   
  qwen-dark.ts     |     100 |      100 |     100 |     100 |                   
  qwen-light.ts    |     100 |      100 |     100 |     100 |                   
  ...tic-tokens.ts |     100 |      100 |     100 |     100 |                   
  ...-of-purple.ts |     100 |      100 |     100 |     100 |                   
  theme-manager.ts |   88.68 |    84.52 |     100 |   88.68 | ...83-392,397-398 
  theme.ts         |     100 |    38.02 |     100 |     100 | ...34-449,457-461 
  xcode.ts         |     100 |      100 |     100 |     100 |                   
 src/ui/utils      |   86.94 |    85.14 |   95.61 |   86.94 |                   
  ...Colorizer.tsx |   80.31 |    85.41 |     100 |   80.31 | ...00-201,313-339 
  ...nRenderer.tsx |   79.84 |     75.6 |     100 |   79.84 | ...66,270,328-329 
  ...wnDisplay.tsx |   92.87 |    93.46 |     100 |   92.87 | ...,955,1002-1020 
  ...idDiagram.tsx |   87.79 |    95.34 |     100 |   87.79 | 156-179           
  ...eRenderer.tsx |   92.38 |    81.91 |   95.23 |   92.38 | ...43-746,799-804 
  ...odeDisplay.ts |   94.28 |    85.71 |     100 |   94.28 | 23,40             
  asciiCharts.ts   |    96.7 |     87.5 |     100 |    96.7 | 170-177,278       
  ...dWorkUtils.ts |     100 |      100 |     100 |     100 |                   
  ...boardUtils.ts |   52.52 |    73.25 |   91.66 |   52.52 | ...23,626-635,638 
  commandUtils.ts  |   96.17 |    88.88 |     100 |   96.17 | ...77,179-180,323 
  computeStats.ts  |     100 |      100 |     100 |     100 |                   
  customBanner.ts  |   90.68 |    91.22 |     100 |   90.68 | ...13,324-327,334 
  displayUtils.ts  |   73.84 |    73.91 |     100 |   73.84 | ...34,36-40,42-46 
  formatters.ts    |   94.87 |    98.21 |     100 |   94.87 | 116-119           
  goal-runtime.ts  |   91.17 |    94.73 |     100 |   91.17 | 31-33             
  gradientUtils.ts |     100 |      100 |     100 |     100 |                   
  highlight.ts     |     100 |      100 |     100 |     100 |                   
  ...gap-notice.ts |     100 |      100 |     100 |     100 |                   
  ...oryMapping.ts |     100 |       95 |     100 |     100 | 44,103            
  historyUtils.ts  |   96.03 |     97.1 |     100 |   96.03 | 103-106           
  ...mage-parts.ts |   97.75 |    94.87 |     100 |   97.75 | 82-83             
  inline-math.ts   |   98.48 |    95.23 |     100 |   98.48 | 129-130           
  input-mouse.ts   |     100 |    85.71 |     100 |     100 | 48,93             
  isNarrowWidth.ts |     100 |      100 |     100 |     100 |                   
  ...olDetector.ts |   68.81 |       75 |   66.66 |   68.81 | ...27-132,160-161 
  latexRenderer.ts |   94.95 |     73.8 |     100 |   94.95 | ...76-178,184-187 
  layoutUtils.ts   |     100 |      100 |     100 |     100 |                   
  list-mouse.ts    |     100 |      100 |     100 |     100 |                   
  ...ightLoader.ts |     100 |       95 |     100 |     100 | 81                
  ...nUtilities.ts |   98.72 |    94.36 |     100 |   98.72 | 145-146           
  ...t-position.ts |     100 |     87.5 |     100 |     100 | 85                
  ...geRenderer.ts |   86.51 |    70.16 |   95.12 |   86.51 | ...1286,1326-1332 
  ...alRenderer.ts |   86.69 |     71.9 |     100 |   86.69 | ...1476,1513-1519 
  ...lsBySource.ts |     100 |    95.23 |     100 |     100 | 84                
  mouse.ts         |   92.85 |    74.19 |     100 |   92.85 | ...38,145,149-152 
  osc8.ts          |   90.43 |    78.33 |     100 |   90.43 | ...59,244,248-249 
  ...red-height.ts |   98.38 |    97.14 |     100 |   98.38 | 195-197           
  ...mConstants.ts |     100 |      100 |     100 |     100 |                   
  restoreGoal.ts   |     100 |      100 |     100 |     100 |                   
  ...storyUtils.ts |   80.19 |    77.92 |     100 |   80.19 | ...83-605,736-737 
  ...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 |   90.61 |    83.44 |     100 |   90.61 | ...80,482-484,607 
  ...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      |   81.27 |    79.92 |   81.94 |   81.27 |                   
  ...d-recorder.ts |     6.2 |      100 |       0 |     6.2 | ...33-159,162-163 
  ...o-recorder.ts |   84.61 |    93.33 |   57.14 |   84.61 | ...16-117,131-136 
  ...me-session.ts |   91.09 |     92.1 |     100 |   91.09 | ...99,305,316-319 
  sox-recorder.ts  |    92.7 |    71.87 |     100 |    92.7 | ...34-135,153-154 
  ...ailability.ts |     100 |      100 |     100 |     100 |                   
  ...e-keyterms.ts |     100 |      100 |     100 |     100 |                   
  voice-model.ts   |     100 |      100 |     100 |     100 |                   
  ...e-recorder.ts |   88.29 |    67.74 |   81.81 |   88.29 | ...,98-99,112,115 
  voice-refine.ts  |     100 |    93.33 |     100 |     100 | 92                
  ...ream-retry.ts |   86.79 |       70 |     100 |   86.79 | 16-18,48-49,59-60 
  ...am-session.ts |   88.02 |    66.66 |   84.61 |   88.02 | ...26,343-345,363 
  ...ranscriber.ts |     100 |      100 |     100 |     100 |                   
 src/utils         |    81.5 |       87 |   92.57 |    81.5 |                   
  ...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 |    89.65 |     100 |     100 | 41-43,49          
  ...re-runtime.ts |     100 |      100 |     100 |     100 |                   
  ...ScopeUtils.ts |   97.56 |    88.88 |     100 |   97.56 | 67                
  doctorChecks.ts  |   70.31 |    74.57 |     100 |   70.31 | ...95-301,325-341 
  ...putCapture.ts |   90.65 |    86.31 |     100 |   90.65 | ...73,371,373-374 
  ...arResolver.ts |   97.14 |    96.55 |     100 |   97.14 | 125-126           
  errors.ts        |   97.56 |    94.64 |     100 |   97.56 | 69-70,304-305     
  events.ts        |     100 |      100 |     100 |     100 |                   
  ...on-mention.ts |   88.48 |     82.6 |     100 |   88.48 | ...56-160,164-168 
  gitUtils.ts      |   92.85 |    86.66 |     100 |   92.85 | ...13-116,164-167 
  ...AutoUpdate.ts |    93.1 |       94 |      90 |    93.1 | 103,108,179-190   
  ...tyWarnings.ts |     100 |      100 |     100 |     100 |                   
  ...lationInfo.ts |   97.68 |    94.28 |     100 |   97.68 | ...64,381-382,427 
  jsonc-editor.ts  |   93.18 |    92.72 |     100 |   93.18 | ...80-381,384-385 
  languageUtils.ts |   98.88 |    97.05 |     100 |   98.88 | 184-185           
  load-undici.ts   |     100 |      100 |     100 |     100 |                   
  ...npm-update.ts |   89.31 |    77.33 |     100 |   89.31 | ...87,303-304,344 
  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.72 |    86.26 |    89.3 |   87.72 |                   
 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          |    92.3 |    87.96 |   93.28 |    92.3 |                   
  baseLlmClient.ts |    88.4 |     83.8 |   81.81 |    88.4 | ...59,672,678-680 
  client.ts        |   91.92 |    87.13 |   91.56 |   91.92 | ...3923,4021-4022 
  ...tGenerator.ts |   86.34 |    87.34 |   84.61 |   86.34 | ...96-497,542-548 
  ...lScheduler.ts |   90.05 |    84.72 |   96.19 |   90.05 | ...6225,6253-6269 
  geminiChat.ts    |   94.49 |    89.68 |   95.53 |   94.49 | ...5001,5047-5048 
  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.67 |    93.07 |     100 |   98.67 | ...79,707-708,755 
  ...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.61 |    90.39 |   95.61 |   91.61 |                   
  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      |   95.45 |    91.18 |     100 |   95.45 | ...1300,1308,1407 
  ...ix-caching.ts |   95.23 |    92.85 |     100 |   95.23 | 45-46,69-70       
  ...ureContext.ts |     100 |      100 |     100 |     100 |                   
  ...ingOptions.ts |       0 |        0 |       0 |       0 | 1                 
  ...CallParser.ts |   92.24 |     92.4 |     100 |   92.24 | ...28-529,549-552 
  ...kingParser.ts |     100 |    96.87 |     100 |     100 | 42                
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...rator/provider |   97.19 |    90.44 |   98.36 |   97.19 |                   
  dashscope.ts     |   98.36 |    92.99 |   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.16 |    88.85 |    95.9 |   94.16 |                   
  ...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.43 |    85.93 |     100 |   92.43 | ...80-381,394,449 
  goal-runtime.ts  |   99.02 |    93.49 |     100 |   99.02 | ...86-687,710-711 
  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.71 |    83.62 |   90.47 |   87.71 |                   
  ...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         |     100 |      100 |     100 |     100 |                   
  ...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.62 |   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 |       44 |   84.61 |   74.22 | ...,67-74,106-117 
  ...igResolver.ts |   98.71 |    93.33 |     100 |   98.71 | 166,328,334       
  modelRegistry.ts |     100 |    98.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.73 |    84.59 |    96.9 |   89.73 |                   
  ...ionTrailer.ts |     100 |      100 |     100 |     100 |                   
  ...llRegistry.ts |   97.68 |    85.71 |     100 |   97.68 | ...96,119,490-491 
  ...ionService.ts |   97.51 |    96.15 |     100 |   97.51 | ...,929,1072-1080 
  ...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 |   95.49 |    90.82 |     100 |   95.49 | ...37,346-347,483 
  cronTasksLock.ts |   94.44 |    89.47 |     100 |   94.44 | ...02-103,132-133 
  ...eryService.ts |   96.22 |    93.54 |      90 |   96.22 | 121,155-156,161   
  ...oryService.ts |   88.17 |    79.02 |    92.3 |   88.17 | ...1303,1344-1347 
  fileReadCache.ts |    97.5 |    96.07 |     100 |    97.5 | 349-350,363-364   
  ...temService.ts |    92.8 |    84.68 |   94.11 |    92.8 | ...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 |   94.53 |    89.82 |   96.66 |   94.53 | ...1353-1354,1417 
  ...est-helper.ts |       0 |        0 |       0 |       0 | 1-65              
  ...iter-lease.ts |   83.14 |    74.47 |   97.61 |   83.14 | ...2433,2445-2448 
  sessionRecap.ts  |   67.56 |    43.47 |     100 |   67.56 | ...60,178,180-183 
  ...ionService.ts |   88.95 |    84.18 |   97.14 |   88.95 | ...2450,2526-2546 
  sessionTitle.ts  |   94.19 |    73.21 |     100 |   94.19 | ...43-246,277-278 
  ...ionService.ts |    84.4 |    78.45 |   97.18 |    84.4 | ...2493,2499-2504 
  ...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.95 |     100 |   87.98 | ...38-439,455-456 
 ...icrocompaction |    98.9 |    95.08 |     100 |    98.9 |                   
  microcompact.ts  |    98.9 |    95.08 |     100 |    98.9 | ...40,749,758-759 
 ...s/visionBridge |   98.81 |    92.12 |     100 |   98.81 |                   
  ...capability.ts |     100 |      100 |     100 |     100 |                   
  ...part-utils.ts |     100 |      100 |     100 |     100 |                   
  ...ion-bridge.ts |   98.72 |    82.35 |     100 |   98.72 | 65,71             
  ...-constants.ts |     100 |      100 |     100 |     100 |                   
  ...ge-service.ts |   98.61 |     94.7 |     100 |   98.61 | ...06,666,679-680 
 src/skills        |   89.29 |    85.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.53 |      70 |   74.23 |                   
  event-types.ts   |       0 |        0 |       0 |       0 |                   
  qwen-logger.ts   |   74.23 |    80.35 |   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.11 |     84.9 |   88.42 |   86.11 |                   
  ...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.69 |    77.08 |   81.25 |   85.69 | ...95-911,957-958 
  ...escendants.ts |   36.17 |    64.51 |   55.55 |   36.17 | ...46-310,385-390 
  ...nforcement.ts |   83.21 |    90.69 |     100 |   83.21 | 147-158,207-220   
  read-file.ts     |   95.49 |    88.52 |   86.66 |   95.49 | ...49,464,536-537 
  ...p-resource.ts |   96.85 |      100 |   91.66 |   96.85 | 92-96             
  ...d-artifact.ts |   91.18 |    86.71 |    87.5 |   91.18 | ...26-427,441-453 
  ripGrep.ts       |    94.6 |    87.26 |   95.23 |    94.6 | ...33-734,740-741 
  ...-transport.ts |   71.42 |    55.55 |   71.42 |   71.42 | ...36-137,143-144 
  send-message.ts  |   81.13 |    89.74 |    62.5 |   81.13 | ...80-286,363-371 
  ...n-mcp-view.ts |   93.57 |     92.3 |      90 |   93.57 | 122-130           
  shell.ts         |   78.72 |     84.1 |   91.91 |   78.72 | ...5032,5095-5096 
  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.85 |    89.62 |   96.86 |   92.85 |                   
  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 
  file-identity.ts |     100 |      100 |     100 |     100 |                   
  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.61 |    92.42 |     100 |   93.61 | ...62-563,565-567 
  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.33 |     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 |    57.14 |      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 |   96.74 |    91.04 |     100 |   96.74 | ...69,196,299-301 
  xml.ts           |    97.8 |    87.69 |     100 |    97.8 | 98-99             
  yaml-parser.ts   |   83.87 |    77.27 |     100 |   83.87 | ...31-234,239-240 
 ...ils/filesearch |   83.94 |    80.72 |   94.73 |   83.94 |                   
  crawlCache.ts    |     100 |      100 |     100 |     100 |                   
  crawler.ts       |    82.9 |    76.81 |   95.08 |    82.9 | ...1563,1597-1598 
  fileSearch.ts    |   93.78 |    87.67 |     100 |   93.78 | ...71-272,274-275 
  fzfWorker.ts     |       0 |        0 |       0 |       0 | 1-109             
  ...rkerHandle.ts |   84.05 |    75.43 |   89.47 |   84.05 | ...30-334,340-341 
  ignore.ts        |     100 |    97.36 |     100 |     100 | 187               
  result-cache.ts  |     100 |    93.75 |     100 |     100 | 49                
 ...uest-tokenizer |   69.76 |    75.47 |   85.29 |   69.76 |                   
  ...eTokenizer.ts |   65.72 |    74.02 |    92.3 |   65.72 | ...65-466,479-533 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...tTokenizer.ts |   68.39 |    69.49 |    90.9 |   68.39 | ...24-325,327-328 
  ...ageFormats.ts |   76.92 |      100 |   33.33 |   76.92 | 46-49,56-57       
  textTokenizer.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |       0 |        0 |       0 |       0 | 1                 
-------------------|---------|----------|---------|---------|-------------------

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

@wenshao

wenshao commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator Author

Code review — fork-review bridge (high effort)

The three new fork-bridge workflows add a signal → bridge → workflow_dispatch lane whose gating is weaker than the lane it replaces: the signal admits any open fork PR reviewed by a collaborator or the review bot, dropping route's maintainer-edits/bot-author/takeover admission. That both burns three runs per ordinary contributor review and pushes takeover-labeled PRs into a credentialed path that writes a ⛔ "AutoFix blocked" comment where the direct lane stayed silent. Laundering reviews into workflow_dispatch also defeats qwen-autofix.yml's explicit guard against the #7836 cap-refusal comment spam, and the head-SHA binding conflates freshness with authenticity so an ordinary push between review and bridge produces a red run and a silently dropped review. The rest are concurrency races that can cancel or fail to coalesce runs, a fleet-shepherd dispatch-correlation collision, and three cleanups.

Correctness

1. qwen-autofix-fork-signal.yml:53 — the signal gate drops route's fork admission prefilter (confirmed)

qwen-autofix.yml's direct fork path (lines 375-395) reads labels,maintainerCanModify and refuses to route unless maintainer edits are on and the PR is bot-authored or takeover-labeled. The signal reproduces none of that — it gates only on fork/base/open/reviewer trust. So a takeover-labeled fork PR whose author has since turned maintainer edits off gets signalled, bridged, and forced into review-scan, where forced_admission_reason returns maintainer_edits_disabled and report_forced_takeover_blocked upserts a PAT-authored ⛔ "AutoFix blocked — takeover admission stopped at maintainer_edits_disabled" comment, overwriting the existing ✅ autofix-status comment. Previously that review produced no run and no comment. In the ordinary case — a maintainer reviewing any unrelated external contributor's fork PR — the same missing prefilter spends a signal run, a bridge run and a full dispatched qwen-autofix run per review, all so review-scan can reject the PR as unmanaged_author.

2. qwen-autofix-fork-bridge.yml:116 — bridging as workflow_dispatch revives the #7836 cap-refusal spam (confirmed)

qwen-autofix.yml:2697 posts the <!-- takeover-cap-refused --> comment only when -n FORCED_PR && FORCED_PR == PR && EVENT_NAME == 'workflow_dispatch'. Its own comment explains why the event-name conjunct exists: FORCED_PR is also set for every trusted pull_request_review, and answering each one "spammed 7 refusals on #7836". The bridge turns every trusted fork-PR review into exactly a workflow_dispatch carrying pr_number. A managed fork PR sitting at 10/10 rounds that receives three reviews now gets three separate "⏸️ Dispatch refused" comments (the code notes "No dedup on the dispatch itself") — the exact regression the gate was added to prevent, growing with every further review.

3. qwen-autofix-fork-bridge.yml:98 — the head-SHA binding fails closed on a benign concurrent push (confirmed)

SIGNAL_HEAD_SHA is the head at review time; HEAD_OID is read live by gh pr view one to three minutes later (signal run + workflow_run dispatch latency + bridge job start). On an active fork PR that is precisely when a new commit arrives — the review bot reviews head X at T, an in-flight autofix address round (or the author) pushes Y at T+1min, the bridge reads Y and takes the mismatch branch. Result: exit 1, a red "Qwen Autofix Fork Bridge" run whose error claims the signal "is not bound to the run that produced it", and the review is never bridged. The log is indistinguishable from the forgery the guard exists for, so a benign race reads as a security event.

4. qwen-autofix-fork-bridge.yml:38 — a skipped bridge run can cancel the in-flight real one (plausible)

Concurrency is claimed at run creation, before the job if: is evaluated. Every signal run — including ones gated out as skipped and ones cancelled by the signal's own concurrency — still fires workflow_run: completed, so a bridge run is created for each and enters group qwen-autofix-fork-bridge-<head_sha>. Sequence: the bot reviews fork PR #N at head X; the real bridge run starts (≈30-60s of runner pickup + gh run download + gh pr view). During that window a non-collaborator submits a review on the same PR at the same head; its signal run is skipped, its bridge run is created for head X, cancels the real bridge run, then skips its own job. The dispatch is never issued and the PR waits for the scheduled scan (40-70 min observed). Repeating the review submission holds the autofix loop off a fork PR indefinitely.

5. qwen-autofix-fork-signal.yml:41 — an untrusted review cancels the in-flight trusted signal run (plausible)

concurrency.group is workflow-level and keyed only on the PR number, evaluated before the job's trust gate. A trusted review on fork PR #N starts a signal run; ~20s later an untrusted user submits a review on the same PR. The new run cancels the trusted one (cancelled, no pr-number.txt artifact) and then skips its own job (skipped). The bridge's if: requires conclusion == 'success', so neither run dispatches — the maintainer's review is silently never bridged, which is the exact gap this PR exists to close, with no error anywhere.

6. qwen-autofix-fork-bridge.yml:116 — dispatched runs no longer coalesce on review bursts (plausible)

route's concurrency group (qwen-autofix.yml:266) maps pull_request_review to qwen-autofix-route-pr-{N} with cancel-in-progress: true specifically so "two reviews on the same PR seconds apart route once". workflow_dispatch instead falls through to qwen-autofix-route-{run_id} with cancel-in-progress false ("dispatches are unique per run and are never cancelled"). The bridge's own head_sha concurrency only collapses bridge runs still in flight, and it dispatches within seconds. A review storm on one fork PR head therefore yields three uncancellable full autofix runs that serialize behind the qwen-pr-head-write-{PR} lock, each re-reading the same feedback and delaying the real address round behind two redundant scans.

Cleanups

7. qwen-autofix-fork-bridge.yml:115 — autonomous dispatches break the fleet shepherd's run correlation (plausible)

qwen-fleet-shepherd.yml:210-222 identifies its own liveness dispatch by taking the newest workflow_dispatch run created since T0, justified by "nothing else in this tick has dispatched yet ... so the newest dispatch created since T0 is ours". Before this PR, workflow_dispatch runs of qwen-autofix.yml came only from the shepherd or a human. The bridge now dispatches automatically at arbitrary times; one landing inside the shepherd's ~10s polling window is recorded as PREV_LIVENESS_RUN, so the next tick's SCAN_INFLIGHT attribution (lines 185-191) tracks the wrong run — suppressing a needed liveness dispatch or firing a duplicate scan.

8. qwen-autofix-fork-signal.yml:6 — the header cites a route secretless output that does not exist (confirmed)

Lines 6-9 say the review lane "now skips itself for those PRs (see route's secretless output)", but grep -n secretless .github/workflows/qwen-autofix.yml returns nothing on origin/main or on this branch — the output only arrives with the unmerged #8671. Until that lands the stated premise is false: for a managed fork PR the direct pull_request_review lane still fires and still reds out on the empty PAT, side by side with the new bridge run.

9. qwen-autofix-fork-signal.yml:70 — the artifact channel is redundant with the run head SHA (plausible)

The bridge accepts the artifact's number only after confirming it maps to workflow_run.head_sha — the head SHA is the real authority, the number a hint. Resolving the PR straight from that SHA (gh pr list --state open --base main --json number,headRefOid filtered with jq, one call alongside the gh pr view already paid for) would delete the upload step, the gh run download + mktemp/trap block, the parse, the whole binding comparison, and roughly a third of the 268-line test. That is 482 added lines maintaining a channel whose payload is discarded on disagreement; the only behavioural difference is the already-ambiguous case of two open PRs sharing a head SHA.

10. qwen-autofix-fork-signal.yml:58 — third hardcoded copy of the trusted-reviewer/bot literals (plausible)

qwen-autofix.yml keeps these as TRUSTED_ASSOC and REVIEW_BOT env constants and already duplicates them once in its concurrency expression (line 266); this adds a third copy in a different file. If the automated reviewer identity changes, qwen-autofix.yml picks it up and the signal silently stops firing for fork PRs — the bridge looks healthy while never dispatching, which is the silent decoupling the new test claims to prevent. The test does not catch it either: qwen-autofix-fork-bridge-workflow.test.js:104 asserts the literal 'qwen-code-ci-bot' is present rather than asserting it equals qwen-autofix.yml's REVIEW_BOT.


Four further candidates were refuted during verification and are not listed: a claimed runner-pool switch under workflow_dispatch, a claimed total loss of per-PR collapsing (the signal's per-PR concurrency preserves it), a claim that workflow_run.head_sha is the base commit for review events (measured false against the live API), and the gh run download vs. actions/download-artifact divergence.

@wenshao

wenshao commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /review

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor
_Qwen Code review request accepted. Review is queued in [workflow run](https://github.com/QwenLM/qwen-code/actions/runs/31160501077)._

@wenshao

wenshao commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /takeover

@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 7, 2026
@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 commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

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

中文说明

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

…dged dispatches

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
@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 轮)。改动内容与我反驳保留之处如下:

AutoFix review round — summary

One commit: 46319d4a7 — all ten code findings from the high-effort review are fixed; the PR-body template finding needs one maintainer action this flow cannot perform (details below).

Code review findings (@wenshao) — all fixed

# Finding Fix
1 Signal gate drops route's fork admission prefilter The signal if: now mirrors route's fork path exactly: maintainer_can_modify == true AND (bot-authored OR takeover-labeled), with the bot login read from vars.AUTOFIX_BOT_LOGIN the same way qwen-autofix.yml does. The bridge additionally re-checks all of it against LIVE API state before dispatching, so consent withdrawn between review and bridge costs one API read, not a dispatched run (and no ⛔ blocked comment on edits-off takeover PRs).
2 workflow_dispatch bridging revives the #7836 cap-refusal spam New source dispatch input; the bridge passes source=fork-bridge. The loud cap-refusal guard now also requires DISPATCH_SOURCE != 'fork-bridge' — bridged reviews are review submissions in dispatch clothing and stay covered by the once-per-window pause notice, exactly as the guard's own comment says review events should.
3 Head-SHA binding reds out on a benign concurrent push Subsumed by #9 — the binding no longer exists. A push between review and bridge simply leaves no eligible PR at the reviewed head: green no-op with an explanatory log line, scheduled scan as backstop. The race can no longer read as a security event.
4 A skipped bridge run can cancel the in-flight real one The bridge concurrency group now includes github.event.workflow_run.conclusion, so skipped/cancelled signal runs land in their own groups and can never cancel a success-signal bridge run.
5 An untrusted review cancels the in-flight trusted signal run Signal concurrency is now trust-keyed, mirroring route's idiom: trusted reviews share a per-PR group (coalescing bursts); everything else gets a run-unique group that cancels nothing.
6 Dispatched runs no longer coalesce on review bursts Route gains a qwen-autofix-forkbridge-pr-{N} group (with cancellation) taken only by workflow_dispatch runs carrying source=fork-bridge and a pr_number. Human and shepherd dispatches keep their run-unique never-cancelled groups; review storms on a fork PR now coalesce exactly like review events.
7 Autonomous dispatches break the fleet shepherd's run correlation The shepherd's post-dispatch correlation now counts candidates created since T0: exactly one → attributed as before; more than one (the bridge raced it) → records run=none — the same documented fallback as a never-appearing run (a duplicate scan, never starvation) — instead of tracking a run it does not own.
8 Header cites route's secretless output, which only arrives with unmerged #8671 Rewritten: the signal header now states that merging REQUIRES #8671 first, that until then a managed fork PR's review fires both lanes with the direct one still red-ing out on the empty PAT, and that the merge ordering belongs in the PR body.
9 The artifact channel is redundant with the run head SHA Removed entirely: no upload step, no gh run download, no parse, no binding comparison. The bridge resolves the PR by asking which open fork PR currently carries workflow_run.head_sha (gh pr list --state open --base main, one call), re-applies the admission filters to that live state, and dispatches each match (the two-PRs-one-head ambiguity is answered by dispatching both; admission is re-derived per PR downstream). Forgery is structurally impossible — the head SHA comes from GitHub's own payload — and the file's only writes remain the same single-PR dispatches.
10 Third hardcoded copy of the trusted-reviewer/bot literals The bot-author check now uses the vars.AUTOFIX_BOT_LOGIN expression (no literal); the remaining unavoidable copies (REVIEW_BOT, TRUSTED_ASSOC, TAKEOVER_LABEL, SKIP_LABEL, the bot fallback) are pinned to qwen-autofix.yml's env by equality assertions in the workflow test — every occurrence in both the gate and the concurrency group is extracted and compared, so an identity change there fails the test instead of silently decoupling the signal.

All fixes carry regression tests: the stub-API replay now exercises the head-SHA resolution (happy path, benign push, each withdrawn consent, skip-wins, shared head, enumeration failure, dispatch retry/exhaustion), the cap-refusal and shepherd correlation guards are extracted VERBATIM and replayed under bash, and the concurrency/input wiring is pinned cross-file. The two pre-existing workflow suites were updated where they pinned the exact lines this round changed.

PR body template (@qwen-code-ci-bot, CHANGES_REQUESTED) — needs a maintainer edit

This one is not a code defect and this flow cannot fix it: address-review mode has no PR-body edit hook and holds no GitHub credentials, so gh pr edit --body has to come from a maintainer (or a credentialed flow). A paste-ready template-conformant body is provided below. It reflects the design AS REVISED this round, so it supersedes the original body rather than just re-heading it — please skim the Risk & Scope and Verification sections against the original text before saving. Once the body is updated, re-running the automated reviewer should clear the formatting gate.

Proposed PR body (paste-ready)

What this PR does

Fork PRs cannot receive repository secrets on their own review events (Secret source: None), so the credentialed autofix review lane cannot answer a review on a fork PR until the next scheduled scan. This PR closes that gap with the standard two-half workflow_run bridge: a credential-free signal workflow (permissions: {}, no checkout, hosted pool) that completes success exactly for the reviews the direct lane cannot serve, and a base-context bridge that resolves the reviewed PR from the signal run's head SHA, re-checks admission against live API state, and issues a single-PR workflow_dispatch of qwen-autofix.yml with the run's own actions: write token. The dispatch re-derives all admission, so the bridge only decides WHEN the scan happens, never who may be touched. Reviewing this PR also surfaced ten defects in the first revision (admission prefilter, cap-refusal spam, concurrency races, shepherd run correlation, a redundant artifact channel); all are fixed in the second commit with regression tests.

Why it's needed

A fork PR's review event carries no secrets, so the review lane cannot authenticate and reddens out after three failed API calls; the only other pickup is the scheduled scan, whose */10 cron is throttled to 40-70 minutes in practice on this repo. Maintainer reviews on takeover fork PRs therefore sat unanswered for up to an hour. The bridge answers them within seconds, in the base context where the PAT and actions: write exist, without giving the fork-triggered half anything worth stealing.

Reviewer Test Plan

How to verify

  • workflow_run cannot fire before merge, so live Before/After evidence is N/A; the behavior is verified by replay instead.
  • The bridge script is extracted verbatim from the workflow YAML and replayed against a stub gh API: happy path, benign concurrent push, every withdrawn-consent case, skip-label priority, two PRs sharing one head, unreadable enumeration, and dispatch retry/exhaustion. Run: npx vitest run --config ./scripts/tests/vitest.config.ts scripts/tests/qwen-autofix-fork-bridge-workflow.test.js.
  • The cap-refusal and shepherd-correlation guards are extracted verbatim and replayed under bash to prove the fork-bridge exclusion and the ambiguous-window fallback. Run the same command for qwen-autofix-workflow.test.js and qwen-fleet-shepherd-workflow.test.js.
  • Confirm in-repo PR reviews are unaffected: the signal gate requires head.repo.full_name != github.repository, and human/shepherd dispatches keep their never-cancelled run-unique concurrency groups.

Evidence (Before & After)

N/A — non-user-visible workflow change; workflow_run cannot be exercised before merge. The stub-API replay suite (all scenarios green) and the mutation-tested assertions in the three workflow suites are the evidence.

Tested on

OS Status
🍏 macOS ⚠️ not tested
🪟 Windows ⚠️ not tested
🐧 Linux ✅ tested

Environment (optional)

Node 22, vitest via scripts/tests/vitest.config.ts; the workflows themselves run on GitHub-hosted ubuntu-latest runners.

Risk & Scope

  • Main risk or tradeoff: the bridge adds an autonomous dispatcher to qwen-autofix.yml, so route concurrency, the cap-refusal guard, and the fleet shepherd's run correlation were extended to recognize source=fork-bridge dispatches; each extension is pinned by a behavioral test. The fork-triggered half holds no token permissions, no secrets, and no checkout.
  • Not validated / out of scope: live workflow_run behavior before merge (impossible by construction); the direct lane still reds out on fork reviews until fix(autofix): skip the PAT-backed jobs when the run has no secrets #8671 merges (stated in the signal header). Deliberately not done: giving the bridge any PAT or checkout, dispatching without the per-PR admission re-check, or folding bridge dispatches into human/shepherd concurrency groups.
  • Breaking changes / migration notes: none; new workflow_dispatch input source is optional and routing-only.

Linked Issues

中文说明

这个 PR 做了什么

Fork PR 自己的 review 事件拿不到仓库 secrets(Secret source: None),因此带凭证的 autofix review 通道无法响应 fork PR 上的 review,只能等下一次定时扫描。本 PR 用标准的两段式 workflow_run 桥接补上这个缺口:一个无凭证的 signal workflow(permissions: {}、无 checkout、hosted 运行池),仅在直接通道无法处理的 review 上以 success 完成;以及一个 base-context bridge,从 signal 运行的 head SHA 解析出被 review 的 PR,按实时 API 状态复核准入,然后用运行自身的 actions: write token 对 qwen-autofix.yml 发起单 PR 的 workflow_dispatch。dispatch 会重新推导全部准入条件,所以桥接只决定"何时"扫描,绝不决定"谁"可以被操作。Review 本 PR 的过程中还暴露了第一版的十个缺陷(准入预过滤、cap 拒绝刷屏、并发竞争、shepherd 运行关联、冗余的 artifact 通道),全部在第二个 commit 中修复并附回归测试。

为什么需要

Fork PR 的 review 事件不带 secrets,review 通道无法认证,三次 API 调用失败后变红;唯一的兜底是定时扫描,而本仓库的 */10 cron 实际被限流到 40-70 分钟。因此 takeover fork PR 上的 maintainer review 最长要等一小时才有响应。桥接在 base context(PAT 和 actions: write 存在的地方)数秒内响应,同时不给 fork 可触发的那一半留下任何可窃取的东西。

Reviewer 测试计划

如何验证

  • workflow_run 在合入前无法触发,所以线上的前后对比为 N/A;行为通过回放方式验证。
  • bridge 脚本从 workflow YAML 中原样提取,并用 stub gh API 回放:正常路径、良性并发 push、各种撤回同意的情形、skip 标签优先、两个 PR 共享同一 head、枚举不可读、dispatch 重试/耗尽。运行:npx vitest run --config ./scripts/tests/vitest.config.ts scripts/tests/qwen-autofix-fork-bridge-workflow.test.js
  • cap 拒绝与 shepherd 关联守卫同样原样提取并在 bash 下回放,证明 fork-bridge 排除与歧义窗口兜底。对 qwen-autofix-workflow.test.jsqwen-fleet-shepherd-workflow.test.js 运行同样的命令。
  • 确认 in-repo PR 的 review 不受影响:signal 门要求 head.repo.full_name != github.repository,人工/shepherd dispatch 保持其永不取消的 run-unique 并发组。

证据(前后对比)

N/A —— 非用户可见的 workflow 变更;workflow_run 在合入前无法演练。证据为 stub API 回放套件(全部场景通过)以及三个 workflow 套件中经变异测试的断言。

测试环境

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

环境(可选)

Node 22,vitest 通过 scripts/tests/vitest.config.ts 运行;workflow 本身运行在 GitHub-hosted ubuntu-latest runner 上。

风险与范围

  • 主要风险或权衡:桥接为 qwen-autofix.yml 增加了一个自动 dispatcher,因此 route 并发、cap 拒绝守卫、fleet shepherd 的运行关联都扩展为识别 source=fork-bridge dispatch;每处扩展都有行为测试钉住。fork 可触发的那一半不持有任何 token 权限、secrets 或 checkout。
  • 未验证 / 不在范围内:合入前的线上 workflow_run 行为(构造上不可能);在 fix(autofix): skip the PAT-backed jobs when the run has no secrets #8671 合入前,直接通道仍会在 fork review 上变红(已在 signal 头部注释说明)。刻意没有做的事:给 bridge 任何 PAT 或 checkout、跳过按 PR 的准入复核就 dispatch、把 bridge dispatch 并入人工/shepherd 的并发组。
  • 破坏性变更 / 迁移说明:无;新增的 workflow_dispatch 输入 source 为可选,仅用于路由。

关联 Issue

Verification

Commands actually run this round (all on the final tree, commit 46319d4a7):

  • npm run build — passed (exit 0)
  • npm run typecheck — passed (exit 0)
  • npm run lint — passed (exit 0; re-run after prettier formatting)
  • npx vitest run --config ./scripts/tests/vitest.config.ts scripts/tests/qwen-autofix-fork-bridge-workflow.test.js scripts/tests/qwen-autofix-workflow.test.js scripts/tests/qwen-fleet-shepherd-workflow.test.js — 3 files, 142 passed, 0 failed
  • npm run test:scripts (full scripts suite) — 49 files, 986 passed, 14 skipped, 0 failed (the initial install-script.test.js failure was a missing packages/audio-capture/dist — it passes once npm run build has run and is unrelated to this change)
  • YAML parse validation of all four changed workflows (yaml library) — passed
  • npx prettier --check on the changed test files — passed
  • Not available on this runner: yamllint / actionlint binaries (the repo's scripts/lint.js wrappers exit vacuously without them); the changed YAML was instead audited by hand against .yamllint.yml rules and existing file style. CI will run the real linters.
  • Integration tests after npm run bundle: not applicable — no CLI/package source changed, only workflow YAML and workflow tests.
中文说明

AutoFix review 轮次 —— 总结

一个 commit:46319d4a7 —— 高强度 review 中的十个代码发现全部修复;PR 正文模板的发现需要一个本流程无法执行、需 maintainer 操作的动作(详见下文)。

代码 review 发现(@wenshao)—— 全部修复

# 发现 修复
1 signal 门丢掉了 route 的 fork 准入预过滤 signal 的 if: 现在与 route 的 fork 路径完全一致:maintainer_can_modify == true 且(bot 作者 或 带 takeover 标签),bot 登录名与 qwen-autofix.yml 相同,从 vars.AUTOFIX_BOT_LOGIN 读取。bridge 在 dispatch 前还会按实时 API 状态复核全部条件,因此 review 与 bridge 之间撤回同意只花费一次 API 读取,而不是一次 dispatched 运行(edits 关闭的 takeover PR 也不会再收到 ⛔ blocked 评论)。
2 workflow_dispatch 桥接复活了 #7836 的 cap 拒绝刷屏 新增 source dispatch 输入;bridge 传 source=fork-bridge。高声 cap 拒绝守卫现在额外要求 DISPATCH_SOURCE != 'fork-bridge' —— 桥接过来的 review 是穿了 dispatch 外衣的 review 提交,与守卫自身注释对 review 事件的要求一致,继续由每窗口一次的暂停通知覆盖。
3 head SHA 绑定在良性并发 push 上变红 #9 吞并 —— 绑定已不存在。review 与 bridge 之间的 push 只会让被 review 的 head 上不再有合格的 PR:绿色无操作并附解释日志,定时扫描兜底。该竞态不会再被读成安全事件。
4 被跳过的 bridge 运行可能取消正在运行的真实 bridge bridge 的并发组现在包含 github.event.workflow_run.conclusion,skipped/cancelled 的 signal 运行落入各自的组,永远无法取消 success signal 的 bridge 运行。
5 不可信 review 会取消正在运行的可信 signal signal 并发现在按信任度分组,沿用 route 的惯用模式:可信评审共享按 PR 的组(合并突发);其余一律 run-unique 组,不取消任何东西。
6 dispatched 运行在 review 突发时不再合并 route 新增 qwen-autofix-forkbridge-pr-{N} 组(带取消),仅由携带 source=fork-bridgepr_numberworkflow_dispatch 运行进入。人工与 shepherd dispatch 保持其 run-unique 永不取消组;fork PR 上的 review 风暴现在像 review 事件一样合并。
7 自动 dispatch 打破 fleet shepherd 的运行关联 shepherd 的 dispatch 后关联现在统计 T0 之后创建的候选:恰好一个 → 照旧认领;多于一(bridge 与其竞速)→ 记录 run=none —— 与"运行始终未出现"相同的文档化兜底(一次被吸收的重复扫描,绝不绝食)—— 而不是去跟踪一个不属于它的运行。
8 头部注释引用了 route 的 secretless 输出,而它只来自未合入的 #8671 已重写:signal 头部现在声明合入本 PR 必须先有 #8671,在此之前 managed fork PR 的 review 会同时触发两条通道、直接通道仍因空 PAT 变红,且合入顺序应写入 PR 正文。
9 artifact 通道相对于运行 head SHA 是冗余的 整体移除:不再有 upload 步骤、gh run download、解析与绑定比较。bridge 通过询问"当前哪个 open fork PR 携带 workflow_run.head_sha"来解析 PR(gh pr list --state open --base main,一次调用),对该实时状态重新套用准入过滤,并对每个匹配发起 dispatch(两个 PR 共享一个 head 的歧义通过都 dispatch 来回答;准入在下游按 PR 重新推导)。伪造在结构上不可能 —— head SHA 来自 GitHub 自己的 payload —— 文件唯一的写操作仍是同样的单 PR dispatch。
10 可信评审/bot 字面量的第三份硬编码拷贝 bot 作者检查现在使用 vars.AUTOFIX_BOT_LOGIN 表达式(无字面量);其余无法避免的拷贝(REVIEW_BOTTRUSTED_ASSOCTAKEOVER_LABELSKIP_LABEL、bot 兜底名)由 workflow 测试中的相等断言钉到 qwen-autofix.yml 的 env —— 门与并发组中的每一处出现都被提取并比较,因此那边改动身份会让测试失败,而不是让 signal 悄悄失联。

所有修复都带回归测试:stub API 回放现在演练 head SHA 解析(正常路径、良性 push、各种撤回同意、skip 优先、共享 head、枚举失败、dispatch 重试/耗尽),cap 拒绝与 shepherd 关联守卫被原样提取并在 bash 下回放,并发/输入接线被跨文件钉住。两个既有 workflow 套件中钉住本轮所改行的断言也已同步更新。

PR 正文模板(@qwen-code-ci-bot,CHANGES_REQUESTED)—— 需要 maintainer 编辑

这一项不是代码缺陷,且本流程无法修复:address-review 模式没有编辑 PR 正文的钩子,也不持有任何 GitHub 凭证,因此 gh pr edit --body 必须由 maintainer(或某个持凭证的流程)执行。下方提供了一份可直接粘贴的、符合模板的正文。它反映的是本轮修订之后的设计,因此是对原正文的整体替换而非仅仅重排标题 —— 保存前请对照原文核对 Risk & Scope 与 Verification 两节。正文更新后重新运行自动 reviewer 即可通过格式关卡。

(可粘贴的 PR 正文草案见上方英文部分的折叠块;草案自带按仓库惯例的中文翻译折叠块。)

验证

本轮实际运行的命令(均在最终代码树、commit 46319d4a7 上):

  • npm run build —— 通过(exit 0)
  • npm run typecheck —— 通过(exit 0)
  • npm run lint —— 通过(exit 0;prettier 格式化后重跑)
  • npx vitest run --config ./scripts/tests/vitest.config.ts scripts/tests/qwen-autofix-fork-bridge-workflow.test.js scripts/tests/qwen-autofix-workflow.test.js scripts/tests/qwen-fleet-shepherd-workflow.test.js —— 3 个文件,142 通过,0 失败
  • npm run test:scripts(完整 scripts 套件)—— 49 个文件,986 通过,14 跳过,0 失败(最初 install-script.test.js 的失败源于缺少 packages/audio-capture/dist —— 运行过 npm run build 后即通过,与本改动无关)
  • 四个改动 workflow 的 YAML 解析校验(yaml 库)—— 通过
  • 对改动测试文件的 npx prettier --check —— 通过
  • 本 runner 上不可用:yamllint / actionlint 二进制(仓库的 scripts/lint.js 包装器在缺少它们时空转退出);改动的 YAML 已按 .yamllint.yml 规则与既有文件风格人工审计。CI 会运行真正的 linter。
  • npm run bundle 之后的集成测试:不适用 —— 没有改动 CLI/包源码,只改了 workflow YAML 与 workflow 测试。

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

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

⚠️ Downgraded from Request changes to Comment: self-PR; CI still running. Reviewed. Suggestions are inline. Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/qwen-autofix-fork-bridge.yml: actionlint embedded-shell source mapping is not yet supported — not linted; the executable-script lint — .github/workflows/qwen-autofix-fork-signal.yml: actionlint embedded-shell source mapping is not yet supported — not linted; the executable-script lint — .github/workflows/qwen-autofix.yml: actionlint embedded-shell source mapping is not yet supported — not linted; the executable-script lint — .github/workflows/qwen-fleet-shepherd.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

中文说明

⚠️ 已从请求修改降级为评论:self-PR; CI still running。 已审查。 建议见行内评论。 未检查(工具限制,非阻断):the executable-script lint — .github/workflows/qwen-autofix-fork-bridge.yml: actionlint embedded-shell source mapping is not yet supported — not linted; the executable-script lint — .github/workflows/qwen-autofix-fork-signal.yml: actionlint embedded-shell source mapping is not yet supported — not linted; the executable-script lint — .github/workflows/qwen-autofix.yml: actionlint embedded-shell source mapping is not yet supported — not linted; the executable-script lint — .github/workflows/qwen-fleet-shepherd.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

— gpt-5.6-sol via Qwen Code /review (v0.21.7)

Comment on lines +232 to +234
if [[ "${COUNT}" == "1" ]]; then
LIVENESS_RUN_OUT="$(jq -r '.[0].databaseId // "" | tostring' <<< "${CANDIDATES}")"
break

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

[Critical] R1-1: The first singleton visible after DISPATCH_T0 is not necessarily the shepherd run. GitHub may expose a concurrent fork-bridge dispatch before the shepherd's own run; this branch records the foreign ID and stops polling. On the next tick, a long-running foreign scan is treated as liveness work and can suppress the watchdog even if the real liveness scan has completed or failed. Correlate the dispatch with an explicit unique value, or at minimum wait through a stabilization window instead of accepting the first singleton.

中文说明

问题: DISPATCH_T0 之后最先可见的单个候选不一定是 shepherd 自己的 run。GitHub 可能先暴露并发的 fork-bridge dispatch、稍后才暴露 shepherd 自己的 run;这里会记录外部 run ID 并立即停止轮询。下一 tick 会把长时间运行的外部 scan 当作 liveness 工作,从而在真正的 liveness scan 已完成或失败时仍抑制 watchdog。应使用显式唯一值关联 dispatch,或至少等待稳定窗口,而不是接受首次 singleton。

— gpt-5.6-sol via Qwen Code /review (v0.21.7)

Comment on lines +114 to +117
# Two open fork PRs sharing one head SHA is already ambiguous — the
# review could have targeted either — so every match is dispatched;
# admission is re-derived per PR downstream.
for PR in $(jq -r '.[]' <<< "${MATCHES}"); do

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

[Critical] R1-2: A head SHA authenticates the revision, not which PR generated the review. If managed fork PR A and PR B share a commit, a review submitted only on A dispatches both. B's downstream scan then reads B's own pending reviews/comments and may post or push even though this event never targeted B; live admission proves B is manageable, not that the review belonged to B. Preserve a GitHub-owned PR binding, or fail closed when multiple PRs match.

中文说明

问题: head SHA 只能证明代码版本,不能证明是哪一个 PR 产生了 review。如果两个 managed fork PR 共享同一提交,只对 PR A 提交 review 也会同时 dispatch A 和 B。B 的下游 scan 随后会读取 B 自己待处理的 review/comment,并可能发评论或推送;实时准入只能证明 B 可被管理,不能证明本次事件指向 B。应保留 GitHub 所有的 PR 身份绑定;若多个 PR 匹配则失败关闭。

— gpt-5.6-sol via Qwen Code /review (v0.21.7)

Comment on lines +86 to +89
source:
description: 'Dispatch-origin marker (fork-bridge = the fork-review bridge); routing metadata only, never changes what may be touched'
required: false
type: 'string'

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

[Critical] R1-3: source=fork-bridge changes trusted concurrency and cap-refusal semantics, but it is an unrestricted public workflow_dispatch input. A maintainer can manually supply this value, causing explicit human dispatches to cancel/coalesce per PR and suppress the refusal response even though the bridge did not originate them. Use a structurally distinct trusted entry point such as workflow_call, or verify bridge provenance independently before honoring this marker.

中文说明

问题: source=fork-bridge 会改变并发与 cap-refusal 语义,但它只是一个不受限制的公开 workflow_dispatch 输入。maintainer 手动填入该值后,明确的人工作业会按 PR 相互取消/合并,并抑制拒绝回复,即使它并非由 bridge 发起。应使用结构上独立的可信入口(如 workflow_call),或在采用该标记前独立验证 bridge 来源。

— gpt-5.6-sol via Qwen Code /review (v0.21.7)

Comment on lines +78 to +79
&& (contains(fromJSON('["OWNER", "MEMBER", "COLLABORATOR"]'), github.event.review.author_association)
|| github.event.review.user.login == 'qwen-code-ci-bot') }}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

[Critical] R1-4: MEMBER and COLLABORATOR association do not guarantee live repository write permission. A read/triage collaborator can pass this signal gate and launch the secret-bearing lane, while the direct pull_request_review route explicitly rejects the same reviewer unless the live permission is write|maintain|admin. Preserve the reviewer identity and perform the same live permission check in the privileged bridge, retaining the review-bot exception.

中文说明

问题: MEMBERCOLLABORATOR association 并不保证当前拥有仓库 write 权限。只有 read/triage 权限的 collaborator 可以通过 signal 门并启动持有 secrets 的通道,而直接 pull_request_review route 会明确要求实时权限为 write|maintain|admin。应保留 reviewer 身份,并在有权限的 bridge 中执行相同的实时权限检查,同时保留 review bot 例外。

— gpt-5.6-sol via Qwen Code /review (v0.21.7)

Comment on lines +240 to +242
const refusedGuard = autofixText.match(
/(if \[\[ -n "\$\{FORCED_PR\}" && "\$\{FORCED_PR\}" == "\$\{PR\}" && "\$\{EVENT_NAME\}" == 'workflow_dispatch' && "\$\{DISPATCH_SOURCE\}" != 'fork-bridge' \]\]; then)/,
)?.[1];

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

[Suggestion] R1-5: This suite extracts and behaviorally replays the complete cap-refusal guard that qwen-autofix-workflow.test.js already owns. A legitimate guard edit now requires updating two regex extractors and equivalent subprocess assertions, so one canonical test change can create a redundant failure here without adding independent coverage. Keep the behavioral replay in the autofix workflow suite and retain only bridge-specific cross-file source wiring assertions here.

中文说明

建议: 该套件完整提取并行为回放了 qwen-autofix-workflow.test.js 已经负责的 cap-refusal guard。一次合理的 guard 修改现在要同步维护两份正则提取器和等价 subprocess 断言;只更新 canonical 测试会在这里产生没有独立覆盖价值的重复失败。建议把行为回放留在 autofix workflow 套件,本文件仅保留 bridge 特有的跨文件 source 接线断言。

— gpt-5.6-sol via Qwen Code /review (v0.21.7)

Comment on lines +75 to +77
&& github.event.pull_request.maintainer_can_modify == true
&& (github.event.pull_request.user.login == (vars.AUTOFIX_BOT_LOGIN || 'qwen-code-dev-bot')
|| contains(toJSON(github.event.pull_request.labels.*.name), '"autofix/takeover"'))

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

[Suggestion] R1-6: The signal omits the autofix/skip veto that the bridge applies later. A trusted review on an otherwise managed fork PR carrying the skip label still creates both workflow runs and performs the open-PR enumeration before being discarded, repeating known-useless work on every review. Add the skip-label exclusion to this gate and pin the copied label against qwen-autofix.yml in the cross-workflow test.

中文说明

建议: signal 没有包含 bridge 稍后才执行的 autofix/skip 否决。带 skip 标签的 managed fork PR 收到可信 review 后,仍会创建 signal 和 bridge 两个 workflow run,并执行 open-PR 枚举,最后才被丢弃;每次 review 都会重复这段已知无用工作。建议在这里加入 skip-label 排除,并在跨 workflow 测试中把该标签钉到 qwen-autofix.yml

— gpt-5.6-sol via Qwen Code /review (v0.21.7)

@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 linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/qwen-autofix-fork-bridge.yml: actionlint embedded-shell source mapping is not yet supported — not linted; the executable-script lint — .github/workflows/qwen-autofix-fork-signal.yml: actionlint embedded-shell source mapping is not yet supported — not linted; the executable-script lint — .github/workflows/qwen-autofix.yml: actionlint embedded-shell source mapping is not yet supported — not linted; the executable-script lint — .github/workflows/qwen-fleet-shepherd.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

[Critical] Still-standing blocker from the existing inline thread at .github/workflows/qwen-fleet-shepherd.yml:232-235 (comment 3735552469, prior review round): the singleton-candidate attribution can credit a foreign fork-bridge dispatch when the shepherd's own run is list-lagged — the mechanism is present in the code at HEAD and the new comment overclaims it. Re-checked this round against the code: not fixed. (This review's independent trace: the impact is bounded and self-heals when the foreign run completes — the LIVENESS_OUT watermark advances independently of run attribution, and a completed run drops out of SCAN_INFLIGHT — and the hole predates this diff in shape; this review rates the same mechanism a low-confidence Suggestion, but the defect as filed is present in the code, so the blocker stands.) 仍存在的阻塞:shepherd 关联循环在自身 run 延迟出现时可能把外部 fork-bridge dispatch 记为己有,该机制在 HEAD 代码中存在且新注释表述过度;本轮复核未修复。(本 review 的独立追踪:影响有界且在外部 run 结束时自愈——LIVENESS_OUT 水位与归因无关、已完成 run 不再计入 SCAN_INFLIGHT——且该漏洞形态早于本 diff;本 review 将同一机制评为低置信 Suggestion,但所报缺陷确在代码中,阻塞成立。)

中文说明

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

[Critical] Still-standing blocker from the existing inline thread at .github/workflows/qwen-fleet-shepherd.yml:232-235 (comment 3735552469, prior review round): the singleton-candidate attribution can credit a foreign fork-bridge dispatch when the shepherd's own run is list-lagged — the mechanism is present in the code at HEAD and the new comment overclaims it. Re-checked this round against the code: not fixed. (This review's independent trace: the impact is bounded and self-heals when the foreign run completes — the LIVENESS_OUT watermark advances independently of run attribution, and a completed run drops out of SCAN_INFLIGHT — and the hole predates this diff in shape; this review rates the same mechanism a low-confidence Suggestion, but the defect as filed is present in the code, so the blocker stands.) 仍存在的阻塞:shepherd 关联循环在自身 run 延迟出现时可能把外部 fork-bridge dispatch 记为己有,该机制在 HEAD 代码中存在且新注释表述过度;本轮复核未修复。(本 review 的独立追踪:影响有界且在外部 run 结束时自愈——LIVENESS_OUT 水位与归因无关、已完成 run 不再计入 SCAN_INFLIGHT——且该漏洞形态早于本 diff;本 review 将同一机制评为低置信 Suggestion,但所报缺陷确在代码中,阻塞成立。)

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

Comment on lines +6 to +8
# `qwen-autofix.yml` cannot authenticate. Merging this bridge REQUIRES #8671
# first: that PR adds route's `secretless` output so the direct
# `pull_request_review` lane skips fork PRs instead of failing three API calls

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 header documents #8671 as adding route's secretless output — a mechanism #8671 never shipped. #8671 is already merged (63a99c2): it declines fork pull_request_review events inline in route's decide script and adds an empty-PAT fail-fast guard at the top of review-scan, and its commit message records the route-output design as the rejected alternative (grep -c secretless on origin/main's qwen-autofix.yml → 0). Compounding it, the new test pins the wrong word — expect(signalText).toContain('secretless') — so anyone correcting this comment fails the test.

Failure scenario: a future oncall verifying the bridge's premise greps for secretless, finds nothing, and either doubts a premise that is actually sound or resurrects a "missing" output that was deliberately rejected; the real mechanism stays undocumented and the test actively enforces the drift. Behaviorally the premise holds (the direct lane no longer reds), so this is documentation drift, not a functional defect.

Suggested fix: rewrite these lines to state what #8671 actually did (route declines fork reviews inline; review-scan fails fast on an empty PAT), drop the now-stale "Until #8671 lands" merge-ordering prose since it has landed, and replace the secretless assertion with one pinning the real mechanism.

中文说明

[Suggestion] 头部注释把 #8671 描述为给 route 增加 secretless 输出——而 #8671 从未交付这个机制。#8671 已经合入(63a99c2c11):它在 route 的 decide 脚本中内联拒绝 fork 的 pull_request_review 事件,并在 review-scan 顶部增加空 PAT 快速失败守卫,其 commit message 明确记录了 route 输出方案是被否决的替代方案(对 origin/main 的 qwen-autofix.yml 执行 grep -c secretless → 0)。更糟的是,新测试把错误的词钉住了——expect(signalText).toContain('secretless')——任何人修正这段注释都会导致测试失败。

失败场景:未来某个 oncall 验证 bridge 前提时 grep secretless,一无所获,要么怀疑一个其实成立的前提,要么复活一个被刻意否决的「缺失」输出;真实机制始终没有文档,而测试在主动固化这种漂移。行为上前提成立(直接通道不再变红),所以这是文档漂移,不是功能缺陷。

建议修复:重写这几行,写明 #8671 实际做了什么(route 内联拒绝 fork review;review-scan 对空 PAT 快速失败),删掉已经过时的「在 #8671 落地前」合入顺序措辞(它已落地),并把 secretless 断言换成钉住真实机制的断言。

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

Comment on lines +1859 to +1861
expect(routeJob).toContain(
"cancel-in-progress: |-\n ${{ github.event_name != 'workflow_dispatch' }}",
"format('qwen-autofix-forkbridge-pr-{0}', inputs.pr_number)",
);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] Route's concurrency group is pinned only by order-blind toContain substrings, so branch order in the || chain is unpinned. One of 4 instances of the same pattern in this review: workflow-expression connectives/branch order asserted only as substrings, with connective/order mutants proven to keep the whole suite green.

Failure scenario: proven mutation — moving the (github.event_name == 'workflow_dispatch' && inputs.source == 'fork-bridge' && ...) disjunct after the always-truthy format('qwen-autofix-route-{0}', github.run_id) fallback keeps both test files fully green. In that state the forkbridge branch never evaluates, every fork-bridge dispatch gets a run-unique group that cancels nothing, and a burst of reviews on one fork PR serializes N full autofix scans behind the per-PR lock — the exact regression this diff's own comment says it prevents.

Suggested fix: pin the order — e.g. assert the forkbridge format index precedes the run-id fallback's, or pin the whole group string with toBe.

中文说明

[Suggestion] route 的并发组只用顺序无关的 toContain 子串钉住,因此 || 链中的分支顺序未被钉住。这是本 review 中同一模式的 4 处之一:workflow 表达式的连接词/分支顺序只以子串断言,连接词/顺序类变异已被证实能让整个套件保持绿色。

失败场景:已证实的变异——把 (github.event_name == 'workflow_dispatch' && inputs.source == 'fork-bridge' && ...) 分支移到永真的 format('qwen-autofix-route-{0}', github.run_id) 兜底之后——两个测试文件仍然全绿。此时 forkbridge 分支永远不会被求值,每个 fork-bridge dispatch 落入一个不取消任何东西的 run-unique 组,一个 fork PR 上的 review 突发会在 per-PR 锁后串行化 N 次完整 autofix 扫描——正是本 diff 注释声称要防止的回归。

建议修复:钉住顺序——例如断言 forkbridge format 的下标先于 run-id 兜底,或用 toBe 钉住整个组字符串。

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

Comment on lines +130 to +131
expect(gate).toContain(`vars.AUTOFIX_BOT_LOGIN || '${BOT_FALLBACK}'`);
expect(gate).toContain(`'"${TAKEOVER_LABEL}"'`);

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 signal gate's Boolean composition is pinned only as condition substrings; the || between the bot-authored and takeover-labeled disjuncts is untested. One of 4 connective/order pinning gaps in this review, each proven by mutation.

Failure scenario: proven mutation — flipping that || to && in qwen-autofix-fork-signal.yml keeps all tests green. Under that mutant a human-authored fork PR carrying autofix/takeover is never signalled, so real-time pickup for takeover PRs — which the bridge-side behavioral replay (takeover scenario) explicitly proves the downstream half would serve — silently disappears, and only the scheduled-scan backstop remains. The two halves of the bridge disagree about takeover PRs and no test notices.

Suggested fix: pin the complete gate with expect(signalJob.if).toBe('<full expected gate>') — it is small and stable; one exact-string pin kills this whole mutation class (and covers the trust-clause connective tracked in the sibling thread).

中文说明

[Suggestion] signal 门的布尔组合只以条件子串钉住;bot 创建与 takeover 标签两个分支之间的 || 未被测试。这是本 review 中 4 处连接词/顺序钉住缺口之一,均经变异证实。

失败场景:已证实的变异——把 qwen-autofix-fork-signal.yml 中该 || 翻转为 &&——所有测试保持绿色。在该变异下,一个带 autofix/takeover 标签、人类创建的 fork PR 永远不会被 signal,于是 takeover PR 的实时接管——bridge 侧行为回放(takeover 场景)明确证明下游一半本可以服务它——悄悄消失,只剩定时扫描兜底。桥接的两半对 takeover PR 的判断不一致,而没有任何测试察觉。

建议修复:用 expect(signalJob.if).toBe('<完整期望的门表达式>') 钉住整个门——它小而稳定;一个精确字符串钉住即可消灭整类变异(同时覆盖姊妹线程中信任子句的连接词)。

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

Comment on lines +135 to +136
expect(gate).toContain('github.event.review.author_association');
expect(gate).toContain(`github.event.review.user.login == '${REVIEW_BOT}'`);

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 trust clause's || (trusted-association OR review-bot login) in the job gate is unpinned: the tests constrain only the literals on each side (the identity-pinning test only counts/values them). One of 4 connective/order pinning gaps in this review, each proven by mutation.

Failure scenario: proven mutations — flipping this || to && makes trust require BOTH an in-list association AND the review-bot login — false for every human maintainer and for a bot whose association is not OWNER/MEMBER/COLLABORATOR; every trusted review then fails the gate and fork-PR reviews silently degrade to the throttled cron backstop while all tests stay green. Flipping the && joining the managed clause to the trust clause to || also escapes, letting any trusted review on any PR pass the gate.

Suggested fix: pin the clause shape verbatim (the full two-line trust clause) — the same verbatim standard this PR applies to the bash guards — or fold it into an exact-string pin of the whole gate.

中文说明

[Suggestion] job 门中信任子句的 ||(可信成员身份或 review-bot 登录名)未被钉住:测试只约束两侧的字面量(身份钉住测试也只统计其数量/取值)。这是本 review 中 4 处连接词/顺序钉住缺口之一,均经变异证实。

失败场景:已证实的变异——把该 || 翻转为 && 后,信任条件要求同时满足列表内成员身份与 review-bot 登录名——对每一位人类 maintainer、以及成员身份不在 OWNER/MEMBER/COLLABORATOR 列表内的 bot 都为假;所有可信 review 都无法过门,fork PR 的 review 悄悄退化为被限流的 cron 兜底,而所有测试保持绿色。把连接 managed 子句与信任子句的 && 翻转为 || 同样存活,会使任何 PR 上的任何可信 review 都通过门。

建议修复:逐字钉住该子句的完整两行形态——与本 PR 对 bash 守卫采用的逐字标准一致——或并入对整个门的精确字符串钉住。

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

Comment on lines +194 to +196
expect(signalGroup).toContain(
"format('qwen-autofix-fork-signal-pr-{0}', github.event.pull_request.number)",
);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] The conditional glue separating trusted (per-PR) from untrusted (run-unique) signal concurrency groups is unpinned — this test asserts only that both format(...) literals are present, not the &&/|| structure routing reviews between them. One of 4 connective/order pinning gaps in this review, each proven by mutation.

Failure scenario: proven mutation — changing the && before the per-PR format to || keeps the entire scripts suite green. Under it a trusted review's expression evaluates to boolean true, so every trusted review on every PR shares one concurrency group literally named true with cancel-in-progress: true: a maintainer's review on PR B cancels the queued or in-flight trusted signal for PR A, which never completes success, the bridge never resolves it, and that review is silently dropped to the cron backstop — the cross-PR version of the failure the comment above the group says the trust split exists to prevent. The test named 'isolates gated-out runs so they cannot cancel the real ones' should catch this and does not.

Suggested fix: pin the resolved group structure — assert signalGroup equals the full expression string (as the bridge group is pinned with toBe), or assert structurally that the per-PR format is the &&-branch and the run-unique format the ||-fallback.

中文说明

[Suggestion] 区分可信(按 PR)与不可信(run-unique)signal 并发组的条件粘合未被钉住——本测试只断言两个 format(...) 字面量都存在,没有断言在两者之间路由 review 的 &&/|| 结构。这是本 review 中 4 处连接词/顺序钉住缺口之一,均经变异证实。

失败场景:已证实的变异——把按 PR 的 format 之前的 && 改为 ||——整个 scripts 套件保持绿色。在该变异下,可信 review 的表达式求值为布尔 true,于是每个 PR 上的每个可信 review 共享一个字面名为 true、带 cancel-in-progress: true 的并发组:maintainer 在 PR B 上的 review 会取消 PR A 排队中或运行中的可信 signal,后者永远无法以 success 完成,bridge 永远不会解析它,该 review 被悄悄丢给 cron 兜底——正是组上方注释说信任分流要防止的失败的跨 PR 版本。名为 'isolates gated-out runs so they cannot cancel the real ones' 的测试本应捕获它却没有。

建议修复:钉住解析后的组结构——断言 signalGroup 等于完整表达式字符串(如同 bridge 组用 toBe 钉住那样),或结构性断言按 PR 的 format 位于 && 分支、run-unique 的 format 位于 || 兜底。

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

Comment on lines +33 to +35
pull_request_review:
types:
- 'submitted'

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 bridge side of the trigger contract is pinned (bridge.on.workflow_run.workflows equals the signal's name:, types equals ['completed']), but the signal side — that the trigger is pull_request_review with type submitted — is asserted nowhere. One of 4 unpinned wiring-contract instances in this review, each proven by mutation.

Failure scenario: proven mutation — changing types: ['submitted'] to types: ['dismissed'] keeps all 142 tests green. In production, submitted reviews never fire the signal, so the bridge never runs and fork-PR review pickup silently dies (the rare dismissal-triggered signals resolve stale heads and no-op green); renaming or dropping the event decouples it from the bridge's workflows: match the same way. Both files stay individually valid YAML — the exact silent-decoupling class the first test in this suite enumerates.

Suggested fix: expect(signal.on.pull_request_review.types).toEqual(['submitted']) (optionally also expect(Object.keys(signal.on)).toEqual(['pull_request_review'])).

中文说明

[Suggestion] 触发契约的 bridge 一侧已被钉住(bridge.on.workflow_run.workflows 等于 signal 的 name:types 等于 ['completed']),但 signal 一侧——触发器是 pull_request_review 且类型为 submitted——没有任何断言。这是本 review 中 4 处未钉住的接线契约之一,均经变异证实。

失败场景:已证实的变异——把 types: ['submitted'] 改为 types: ['dismissed']——全部 142 个测试保持绿色。生产中 submitted 的 review 永远不会触发 signal,bridge 永远不运行,fork PR 的 review 接管悄悄死亡(罕见的 dismissal 触发 signal 只会解析到过期 head 并绿色无操作);重命名或删除该事件会以同样方式断开它与 bridge workflows: 的匹配。两个文件各自仍是合法 YAML——正是本套件第一个测试列举的那种静默失联。

建议修复:expect(signal.on.pull_request_review.types).toEqual(['submitted'])(可选地再加 expect(Object.keys(signal.on)).toEqual(['pull_request_review']))。

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

Comment on lines +345 to +346
// Nothing at all → the polling loop exhausts and records nothing.
expect(runCorrelation([])).toBe('');

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] All four correlation-replay scenarios use a static gh stub, so the retry-until-appears semantics of the 5×2s polling loop are untested. One of 2 instances of the same pattern in this review: the replay stubs are state/flag-insensitive, so loop/parameter mutants escape (both proven by mutation).

Failure scenario: proven mutation — changing the loop guard in qwen-fleet-shepherd.yml from -gt 1 to -ne 1 (COUNT==0 breaks after the first empty poll — one poll instead of five) keeps every test green, because with a static stub no scenario can tell single-poll from five-poll. In production a freshly dispatched run can take more than 2s to become visible via gh run list; with the mutant the shepherd records run=none on every such tick, turning the documented rare fallback (duplicate scan) into the normal case and permanently degrading liveness tracking.

Suggested fix: add a stateful stub scenario — first gh run list call returns [], second returns one candidate: the original attributes the run id, the mutant returns ''.

中文说明

[Suggestion] 全部四个关联回放场景都使用静态 gh stub,因此 5×2s 轮询循环「重试直到出现」的语义未被测试。这是本 review 中同一模式的 2 处之一:回放 stub 对状态/标志不敏感,循环/参数类变异因此存活(均已变异证实)。

失败场景:已证实的变异——把 qwen-fleet-shepherd.yml 中循环守卫从 -gt 1 改为 -ne 1(COUNT==0 时在第一次空轮询后即 break——一次轮询取代五次)——所有测试保持绿色,因为静态 stub 下没有任何场景能区分单次轮询与五次轮询。生产中新 dispatch 的运行可能要超过 2s 才在 gh run list 中可见;在该变异下 shepherd 每个这样的 tick 都记录 run=none,把文档中的罕见兜底(重复扫描)变成常态,永久退化存活跟踪。

建议修复:增加一个有状态的 stub 场景——第一次 gh run list 返回 [],第二次返回一个候选:原实现会归因该 run id,变异实现返回 ''

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

Comment on lines +95 to +96
if ! PR_LIST="$(gh pr list --repo "${REPO}" --state open --base main \
--limit 1000 --json number,author,labels,headRefOid,isCrossRepository,maintainerCanModify 2> /dev/null)"; then

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 --limit 1000 enumeration parameter — load-bearing for this workflow's core "resolve the PR from the head SHA" function — is invisible to the entire test suite: the replay's gh stub ignores flags and no assertion mentions the limit. One of 2 replay-stub-insensitivity instances in this review (both proven by mutation). Distinct from the separate low-confidence note about 1000 itself being a cap: this is about the parameter being unpinned.

Failure scenario: proven mutation — --limit 1000--limit 1 keeps all 991 tests in the scripts suite green. Under it the bridge sees only the single newest open PR, so every signal whose reviewed PR is not literally the newest open PR against main resolves to the "no eligible fork PR carries head" green no-op — indistinguishable in logs and status from a healthy race — silently degrading every such fork-PR review to the cron backstop. A future cost-cutting --limit 100, or a refactor dropping the flag to gh's default 30, would ship equally green.

Suggested fix: honor --limit in the replay stub (truncate the stub's pr list output to the requested limit; add a case where the target PR sits just outside a small window), or pin the flag textually.

中文说明

[Suggestion] --limit 1000 枚举参数——本 workflow 核心功能「从 head SHA 解析 PR」的承重参数——对整个测试套件不可见:回放的 gh stub 忽略所有标志,也没有任何断言提到该 limit。这是本 review 中回放 stub 不敏感模式的 2 处之一(均已变异证实)。与另一条低置信度意见(1000 本身是上限)不同:此处的问题是参数未被钉住。

失败场景:已证实的变异——--limit 1000--limit 1——scripts 套件全部 991 个测试保持绿色。在该变异下 bridge 只能看到最新的一个 open PR,凡被 review 的 PR 不是恰好最新者,signal 都落入「no eligible fork PR carries head」的绿色无操作——日志与状态上与健康竞态无法区分——悄悄把这类 fork PR 的 review 全部退化为 cron 兜底。未来省成本的 --limit 100、或重构丢掉该标志回落到 gh 默认 30,都会同样绿灯地合入。

建议修复:让回放 stub 尊重 --limit(按请求的 limit 截断 stub 的 pr list 输出;补一个目标 PR 恰好在小窗口之外的用例),或在文本上钉住该标志。

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

Comment on lines +36 to +39
permissions:
actions: 'write'
contents: 'read'
pull-requests: 'read'

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 bridge declares contents: 'read' although no step reads repository contents — the single step runs only gh pr list (needs pull-requests: 'read'), gh workflow run (needs actions: 'write') and a local GITHUB_STEP_SUMMARY write; there is no checkout, no git operation and no contents-API call anywhere in the file. Additionally the test pins the signal's permission set exhaustively (expect(signal.permissions).toEqual({})) while pinning the bridge's only partially (bridge.permissions.actions), so this unused scope and any future scope creep land without tripping the test that exists to police this invariant.

Failure scenario: the privileged half of a fork-triggered chain ships a token scope it never uses — against the PR's own least-privilege narrative — and a future contents: 'write' or pull-requests: 'write' addition passes the very test created to police the invariant, widening the blast radius of the run a pwn-request would target. (An unused read scope is hygiene, not a live hole — the bridge executes no untrusted code — the concrete cost is the unpinned minimum.)

Suggested change
permissions:
actions: 'write'
contents: 'read'
pull-requests: 'read'
permissions:
actions: 'write'
pull-requests: 'read'

and pin the exact set in the test: expect(bridge.permissions).toEqual({ actions: 'write', 'pull-requests': 'read' }).

中文说明

[Suggestion] bridge 声明了 contents: 'read',但没有任何步骤读取仓库内容——唯一步骤只运行 gh pr list(需要 pull-requests: 'read')、gh workflow run(需要 actions: 'write')和本地写 GITHUB_STEP_SUMMARY;整个文件没有 checkout、没有 git 操作、没有任何 contents API 调用。此外测试对 signal 的权限集做了穷尽钉住(expect(signal.permissions).toEqual({})),对 bridge 却只钉了一部分(bridge.permissions.actions),因此这个未使用的权限以及未来任何权限扩张,都不会触发那个为守护此不变量而存在的测试。

失败场景:fork 触发链条中持权的一半携带了一个它从不使用的 token 权限——与本 PR 自己的最小权限叙事相悖——未来若加上 contents: 'write'pull-requests: 'write' 也能通过那个专为守护该不变量而建的测试,扩大 pwn-request 目标运行的爆炸半径。(未使用的 read 权限是卫生问题而非现实漏洞——bridge 不执行任何不可信代码——具体成本是「最小权限」未被钉住。)

并在测试中钉住精确集合:expect(bridge.permissions).toEqual({ actions: 'write', 'pull-requests': 'read' })

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

Comment on lines +47 to +50
// Does the file actually READ a secret, as opposed to naming one in prose?
// Both workflows explain themselves by referring to `secrets.CI_DEV_BOT_PAT`,
// so only an expression counts.
const readsASecret = (text) => /\$\{\{[^}]*\bsecrets\./.test(text);

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 readsASecret detector that enforces the bridge's central invariant — no secret read alongside actions: write, the combination that makes a pwn-request worth attempting — is defeated by any expression containing a } before secrets.: [^}]* cannot cross the brace.

Failure scenario: proven by probe against this commit — inserting LEAKED: "${{ format('{0}', secrets.CI_DEV_BOT_PAT) }}" (or ${{ fromJSON('{"a":1}').a == secrets.CI_DEV_BOT_PAT }} — both valid, evaluated expressions) into the bridge leaves readsASecret(bridgeText) false and the invariant test green, while a plain ${{ secrets.X }} is still caught. A future edit giving the base-context, actions: write bridge a real secret read hidden behind any brace-bearing expression then ships silently — the exact regression this test exists to catch.

Suggested fix: scan each ${{ … }} expression with a scanner that skips single-quoted string literals (with '' escapes) before locating the closing }}, then test the body for \bsecrets\. — verified to detect both payloads while keeping the prose comments and both current files clean. A parsed-YAML walk needs the same expression-aware check: the bridge's own run: prose matches a bare /secrets\./ scan.

中文说明

[Suggestion] 守护 bridge 核心不变量的 readsASecret 检测器——actions: write 旁不得读取 secret,该组合正是让 pwn-request 值得尝试的条件——会被任何在 secrets. 之前含有 } 的表达式击败:[^}]* 无法跨越花括号。

失败场景:已在本 commit 上探测证实——向 bridge 插入 LEAKED: "${{ format('{0}', secrets.CI_DEV_BOT_PAT) }}"(或 ${{ fromJSON('{"a":1}').a == secrets.CI_DEV_BOT_PAT }}——两者都是合法且会被求值的表达式),readsASecret(bridgeText) 仍返回 false、不变量测试保持绿色,而裸 ${{ secrets.X }} 仍会被捕获。未来若有人给这个 base-context、持 actions: write 的 bridge 加上藏在任何带花括号表达式背后的真实 secret 读取,它将静默合入——正是本测试要捕获的那种回归。

建议修复:逐个扫描 ${{ … }} 表达式,先用能跳过单引号字符串字面量(含 '' 转义)的扫描器定位收尾的 }},再对表达式主体测试 \bsecrets\.——已验证可检出上述两种载荷,同时保持散文注释与当前两个文件不误报。若走解析 YAML 的路线也需要同样的表达式感知检查:bridge 自己的 run: 散文会让裸 /secrets\./ 扫描误报。

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

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

What I found before stopping:
Qwen failed during address-review: status 125.

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

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


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

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

AutoFix review round — PR #8676

Addressed all four Critical findings and all fifteen Suggestions from @wenshao and @qwen-code-ci-bot in one commit (fix(autofix): harden the fork-review bridge per review feedback (#8676)). No base-conflict work (--conflict false). The wenshao review body's "not linted" notes are an actionlint tool limitation on embedded shells, explicitly non-blocking — no action available.

Critical findings

R1-1 / rc:3735552469 — shepherd can attribute a foreign dispatch (also the ci-bot's still-standing blocker on the same thread). Fixed with the reviewer's accepted alternative — a stabilization window instead of first-singleton acceptance. The attribution loop now records run=none on ANY poll seeing two or more candidates, and accepts a singleton only after it is the sole candidate across two consecutive polls; a foreign dispatch visible before the shepherd's own run flips the window to ambiguous on the next poll instead of being attributed. Added a STATEFUL gh stub to the shepherd suite (a static stub cannot distinguish single-poll from five-poll): delayed-appearance still attributes, and the filed race (foreign singleton first, both on the next poll) records run=none. Residual case (foreign singleton alone for the entire 10s window) is documented in the code as the bounded, self-healing fallback: a duplicate scan, never starvation.

R1-2 / rc:3735552476 — head SHA authenticates the revision, not the PR. The signal now encodes the reviewed PR number AND the reviewer login in its run-name (fork-signal: PR <N> reviewed by <login>), which GitHub surfaces on the workflow_run event as display_title — a GitHub-owned binding supplied by the base-branch signal file, which a fork cannot forge. The bridge parses it (unparseable → red, out-of-contract), dispatches ONLY the bound PR (two fork PRs sharing a head no longer dispatch both), and keeps workflow_run.head_sha as the freshness gate (push-between-review-and-bridge still no-ops green). The head-enumeration (gh pr list --limit 1000) is replaced by a single live gh pr view of the bound PR with all admission predicates re-applied (state OPEN, baseRefName main, cross-repo, maintainer edits, bot-authored-or-takeover, skip-wins) — which also removes the unpinned --limit parameter flagged in rc:3735664152.

R1-3 / rc:3735552482 — source=fork-bridge is a public input changing trusted semantics. The marker no longer changes concurrency AT ALL: route's forkbridge per-PR group and its cancel-in-progress exception are removed, and every dispatch (fork-bridge included) is back in a run-unique never-cancelled group — fork-review bursts already coalesce upstream (signal per PR with cancel-in-progress; bridge per conclusion+head), so the removed branch was economy, not correctness. The one remaining behavioral effect — staying quiet at the round cap — is now honored only after positive provenance verification in review-scan: a recent SUCCESSFUL qwen-autofix-fork-bridge.yml run whose title names the exact PR (the bridge propagates the signal title into its own run title; both files are base-branch, not fork-forgeable). Unverified markers are answered like explicit dispatches. The provenance jq program and the refusal guard are both replayed behaviorally in the autofix-workflow suite (exact-PR match, no prefix collision, success-only, recency, empty list). A future workflow_call entry point would be the structural next step if per-PR coalescing is ever wanted back; it was too large and risky for this round.

R1-4 / rc:3735552489 — MEMBER/COLLABORATOR does not guarantee live write permission. The bridge now re-checks the reviewer LIVE before dispatching: repos/{repo}/collaborators/{reviewer}/permission must return admin|maintain|write (the exact call route makes for the same event), with route's review-bot exception mirrored via a new pinned REVIEW_BOT env. Below-write or unreadable permission → green no-op (the direct lane declined the same review; cron remains the backstop). This is why the bridge keeps contents: 'read' — it is now genuinely used (see rc:3735664159 below).

Suggestions

  • R1-5 / rc:3735552496 — removed the duplicated cap-refusal behavioral replay from the fork-bridge suite; the canonical replay lives once in qwen-autofix-workflow.test.js (now extended with the provenance semantics), and the fork-bridge suite keeps only bridge-specific source wiring assertions.
  • R1-6 / rc:3735552500 — added the autofix/skip veto to the signal gate (skip-labeled reviews no longer burn signal+bridge runs and a PR read), and pinned the copied label to qwen-autofix.yml's SKIP_LABEL via the verbatim gate pin built from the shared constant.
  • rc:3735664113 — rewrote the signal header to state what fix(autofix): skip the PAT-backed jobs when the run has no secrets #8671 actually did (route declines fork reviews inline; review-scan fails fast on an empty PAT; commit 63a99c2), dropped the stale "REQUIRES fix(autofix): skip the PAT-backed jobs when the run has no secrets #8671 / Until fix(autofix): skip the PAT-backed jobs when the run has no secrets #8671 lands / merge ordering" prose, and replaced the test's secretless pin with assertions on the real mechanism plus not.toContain('secretless').
  • rc:3735664117 — superseded by the R1-3 removal: the forkbridge disjunct no longer exists, and the suite now pins its ABSENCE (not.toContain('forkbridge'), not.toContain("inputs.source == 'fork-bridge'")) plus the reverted exact cancel-in-progress expression, so a re-added branch fails the tests.
  • rc:3735664120, rc:3735664124, rc:3735664132 — the whole signal gate is now pinned VERBATIM with toBe (built from the pinned TRUSTED_ASSOC/REVIEW_BOT/label constants), covering the gate's connectives, the trust-clause ||, and the github.repository scope guard; the bridge job gate (with its scope guard) is pinned verbatim too. One exact-string pin kills the proven connective/order mutant class.
  • rc:3735664130 — the signal concurrency group is pinned verbatim with toBe (same standard as the bridge group), so the trusted/untrusted routing glue cannot flip silently.
  • rc:3735664137 — the dispatch contract now pins source and pr_number input type: 'string' and required: false (GitHub rejects the bridge's string field against a boolean input; shepherd/manual dispatches omit both).
  • rc:3735664138 — pinned bridgeJob.env.SIGNAL_HEAD_SHA exactly to ${{ github.event.workflow_run.head_sha }} (a head_branch rebind resolves nothing forever, byte-identical to a healthy race); the new SIGNAL_TITLE binding is pinned the same way.
  • rc:3735664145 — pinned the signal side of the trigger contract: on keys equal exactly ['pull_request_review'] and types equals ['submitted'].
  • rc:3735664149 — added the stateful-stub scenarios described under R1-1; they catch both the -ne 1 single-poll mutant and the first-singleton-acceptance defect.
  • rc:3735664152 — resolved by the R1-2 redesign: PR resolution is a direct gh pr view of the bound PR; there is no enumeration window or --limit parameter left to pin, and the new resolution contract (command, JSON fields, predicates) is pinned and behaviorally replayed.
  • rc:3735664159 — the bridge's permission set is now pinned EXACTLY (toEqual({ actions: 'write', contents: 'read', 'pull-requests': 'read' })) so any future scope creep trips the policing test. Deviation from the suggested block: contents: 'read' is retained because the R1-4 live reviewer-permission check reads the collaborators API — the same call route makes under contents: read — so the scope is no longer unused.
  • rc:3735664172readsASecret is now expression-aware: it scans each ${{ … }} expression with a pass that skips single-quoted string literals (with '' escapes) before locating the closing }}, then tests the body for \bsecrets\.. Both proven defeat payloads (format('{0}', secrets.X) and the fromJSON object literal) are caught, prose stays clean, and the detector's own behavior is pinned by direct unit assertions in the suite.

Verification

Commands actually run on the final tree (commit 31bac88012):

  • npm run build — passed (exit 0)
  • npm run typecheck — passed (exit 0)
  • npm run lint — passed (exit 0)
  • npx prettier --check on the three changed test files — clean
  • npm run test:scripts — passed: 49/49 test files, 996 passed / 14 skipped (includes the three workflow contract suites below)
  • Focused vitest, three changed suites — 143/143 passed:
    • scripts/tests/qwen-autofix-fork-bridge-workflow.test.js — 9 passed
    • scripts/tests/qwen-fleet-shepherd-workflow.test.js — 13 passed
    • scripts/tests/qwen-autofix-workflow.test.js — 121 passed
  • Not run (not applicable): focused package Vitest runs (no packages/** files touched); integration tests after npm run bundle (the changed behavior is GitHub Actions workflows plus their contract tests, not exercised through the bundled CLI or integration harness); npm run generate:settings-schema (no settings source touched).
  • Note: scripts/tests/install-script.test.js failed once mid-round with ENOENT … packages/audio-capture/dist before the package was built; it passes after npm run build and is unrelated to this change.
中文说明

AutoFix 评审轮次 — PR #8676

在一次提交(fix(autofix): harden the fork-review bridge per review feedback (#8676))中处理了 @wenshao@qwen-code-ci-bot 的全部 4 个 Critical 发现和 15 个 Suggestion。无 base 冲突工作(--conflict false)。wenshao review 正文中的 "not linted" 备注是 actionlint 对内嵌 shell 的工具限制,明确非阻断——无可执行动作。

Critical 发现

R1-1 / rc:3735552469 — shepherd 可能把外部 dispatch 记为己有(也是 ci-bot 在同一线程上的仍存在阻塞)。 采用评审人接受的替代方案修复——用稳定窗口取代"接受首个 singleton"。关联循环现在在任一次轮询看到两个及以上候选时记录 run=none,且只有当某个 singleton 连续两次轮询都是唯一候选时才接受;在 shepherd 自身 run 出现之前先可见的外部 dispatch,会在下一次轮询把窗口翻转为 ambiguous,而不是被归因。在 shepherd 测试套件中新增了有状态的 gh stub(静态 stub 无法区分单次轮询与五次轮询):延迟出现仍能归因;所报竞态(先是外部 singleton、下一次轮询出现两者)记录 run=none。残余情形(外部 singleton 在整个 10 秒窗口内始终唯一)在代码中记录为有界且自愈的兜底:一次重复扫描,绝不饥饿。

R1-2 / rc:3735552476 — head SHA 只能证明代码版本,不能证明是哪一个 PR。 signal 现在把被评审的 PR 编号与评审人登录名编码进自己的 run-namefork-signal: PR <N> reviewed by <login>),GitHub 会在 workflow_run 事件上以 display_title 呈现——这是由 base 分支的 signal 文件提供的、GitHub 所有的绑定,fork 无法伪造。bridge 解析它(无法解析 → 变红,视为契约断裂),只 dispatch 绑定的那一个 PR(两个共享 head 的 fork PR 不再同时被 dispatch),并继续以 workflow_run.head_sha 作为新鲜度闸门(review 与 bridge 之间有 push 落地时仍是绿色无操作)。head 枚举(gh pr list --limit 1000)被替换为对绑定 PR 的单次实时 gh pr view,并重新套用全部准入谓词(state OPENbaseRefName main、跨仓库、允许 maintainer 编辑、bot 作者或带 takeover 标签、skip 优先)——同时也移除了 rc:3735664152 指出的未钉住 --limit 参数。

R1-3 / rc:3735552482 — source=fork-bridge 是一个改变可信语义的公开输入。 该标记不再改变任何并发语义:route 的 forkbridge per-PR 组及其 cancel-in-progress 例外已被移除,所有 dispatch(含 fork-bridge)回到 run-unique、永不取消的组——fork review 突发本来就在上游合并(signal 按 PR、cancel-in-progress;bridge 按 conclusion+head),被移除的分支只是节省而非正确性。该标记唯一保留的行为效果——在轮次上限处保持安静——现在只有在 review-scan 完成来源证实后才生效:最近存在一个 SUCCESSFUL 的 qwen-autofix-fork-bridge.yml 运行,且其标题点名了确切的 PR(bridge 把 signal 标题传播进自己的运行标题;两个文件都在 base 分支,fork 无法伪造)。未通过验证的标记按显式 dispatch 对待并回复拒绝。provenance jq 程序与拒绝守卫都在 autofix-workflow 套件中做了行为回放(确切 PR 匹配、无前缀冲突、仅 success、时效性、空列表)。若将来想恢复 per-PR 合并,结构性的下一步是 workflow_call 入口;对本轮而言改动面过大、风险过高。

R1-4 / rc:3735552489 — MEMBER/COLLABORATOR 并不保证当前拥有 write 权限。 bridge 现在在 dispatch 前对评审人做实时复查:repos/{repo}/collaborators/{reviewer}/permission 必须返回 admin|maintain|write(与 route 对同一事件所做的调用完全一致),并镜像 route 的 review-bot 例外(新增被钉住的 REVIEW_BOT env)。权限低于 write 或读取失败 → 绿色无操作(直接通道对同一条 review 也会拒绝;cron 仍是兜底)。这也是 bridge 保留 contents: 'read' 的原因——它现在被真实使用(见下方 rc:3735664159)。

Suggestion

  • R1-5 / rc:3735552496 — 从 fork-bridge 套件中移除了重复的 cap-refusal 行为回放;canonical 回放只在 qwen-autofix-workflow.test.js 中存在一份(已扩展为 provenance 语义),fork-bridge 套件只保留 bridge 特有的 source 接线断言。
  • R1-6 / rc:3735552500 — 在 signal 门加入了 autofix/skip 否决(带 skip 标签的 PR 收到 review 不再白烧 signal+bridge 运行和一次 PR 读取),并通过"从共享常量构造的逐字门钉住"把该标签钉到 qwen-autofix.ymlSKIP_LABEL
  • rc:3735664113 — 重写 signal 头部,写明 fix(autofix): skip the PAT-backed jobs when the run has no secrets #8671 实际做了什么(route 内联拒绝 fork review;review-scan 对空 PAT 快速失败;commit 63a99c2),删掉过时的 "REQUIRES fix(autofix): skip the PAT-backed jobs when the run has no secrets #8671 / Until fix(autofix): skip the PAT-backed jobs when the run has no secrets #8671 lands / merge ordering" 措辞,并把测试中的 secretless 钉住替换为对真实机制的断言加 not.toContain('secretless')
  • rc:3735664117 — 被 R1-3 的移除取代:forkbridge 分支已不存在,套件现在钉住它的缺席(not.toContain('forkbridge')not.toContain("inputs.source == 'fork-bridge'"))以及还原后的精确 cancel-in-progress 表达式,任何重新加回的分支都会让测试失败。
  • rc:3735664120、rc:3735664124、rc:3735664132 — 整个 signal 门现在用 toBe 逐字钉住(由钉住的 TRUSTED_ASSOC/REVIEW_BOT/标签常量构造),覆盖门的连接词、信任子句的 || 以及 github.repository 作用域守卫;bridge 作业门(含其作用域守卫)也逐字钉住。一个精确字符串钉住即可消灭已被证实的连接词/顺序变异类。
  • rc:3735664130 — signal 并发组用 toBe 逐字钉住(与 bridge 组同一标准),可信/不可信的分流粘合不会再被静默翻转。
  • rc:3735664137 — dispatch 契约现在钉住 sourcepr_number 输入的 type: 'string'required: false(GitHub 会拒绝把 bridge 的字符串字段对到 boolean 输入;shepherd/人工 dispatch 不传这两个输入)。
  • rc:3735664138 — 精确钉住 bridgeJob.env.SIGNAL_HEAD_SHA${{ github.event.workflow_run.head_sha }}(改绑 head_branch 会永远解析不到任何东西,且与健康竞态逐字节无法区分);新的 SIGNAL_TITLE 绑定同样被精确钉住。
  • rc:3735664145 — 钉住触发契约的 signal 一侧:on 的键恰为 ['pull_request_review']types 恰为 ['submitted']
  • rc:3735664149 — 新增 R1-1 所述的有状态 stub 场景;它们同时捕获 -ne 1 单次轮询变异与"接受首个 singleton"缺陷。
  • rc:3735664152 — 由 R1-2 的重构解决:PR 解析改为对绑定 PR 的直接 gh pr view;不再有枚举窗口或 --limit 参数可钉,新的解析契约(命令、JSON 字段、谓词)已被钉住并做行为回放。
  • rc:3735664159 — bridge 的权限集合现在被精确钉住(toEqual({ actions: 'write', contents: 'read', 'pull-requests': 'read' })),未来任何权限扩张都会触发守护测试。与建议块的偏差:保留 contents: 'read',因为 R1-4 的评审人实时权限检查要读 collaborators API——与 route 在 contents: read 下做的是同一个调用——该权限不再是未使用的。
  • rc:3735664172readsASecret 现在是表达式感知的:逐个扫描 ${{ … }} 表达式,先用跳过单引号字符串字面量(含 '' 转义)的扫描器定位收尾 }},再对主体测试 \bsecrets\.。两个已被证实的绕过载荷(format('{0}', secrets.X)fromJSON 对象字面量)均被捕获,散文注释保持干净,且检测器自身的行为在套件中被直接单测钉住。

验证

在最终树(commit 31bac88012)上实际执行的命令:

  • npm run build — 通过(exit 0)
  • npm run typecheck — 通过(exit 0)
  • npm run lint — 通过(exit 0)
  • npx prettier --check(三个改动的测试文件)— 干净
  • npm run test:scripts — 通过:49/49 个测试文件,996 通过 / 14 跳过(含下方三个 workflow 契约套件)
  • 聚焦 vitest,三个改动套件 — 143/143 通过:
    • scripts/tests/qwen-autofix-fork-bridge-workflow.test.js — 9 通过
    • scripts/tests/qwen-fleet-shepherd-workflow.test.js — 13 通过
    • scripts/tests/qwen-autofix-workflow.test.js — 121 通过
  • 未运行(不适用):包内聚焦 Vitest(未改动任何 packages/** 文件);npm run bundle 后的集成测试(改动的行为是 GitHub Actions workflow 及其契约测试,不经由 bundled CLI 或集成测试框架执行);npm run generate:settings-schema(未改动任何 settings 源)。
  • 说明:scripts/tests/install-script.test.js 曾在轮次中途以 ENOENT … packages/audio-capture/dist 失败一次,原因是该包尚未构建;npm run build 之后通过,与本改动无关。

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

@wenshao

wenshao commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /triage

@qwen-code-ci-bot

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

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

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

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

Verification report

PR #8676 verification — feat(autofix): bridge fork-PR reviews into the credentialed review lane

Verdict: merge-ready — 217/217 scripted assertions passed, 0 unexpected failures. Verified head: 31bac8801242a6ca32efdf06eea83fc720dd4479 (merge 198d31aab4, base tip 9e1b1eb49e).

中文摘要
  • 结论: merge-ready。217/217 条脚本化断言全部通过,0 条意外失败。中心论断(桥接把 fork PR 评审安全地转成带凭据车道的 dispatch)经 A/B + 变异矩阵证明各守卫均承重:删除 head_sha 绑定后伪造信号会被 dispatch,删除 reviewer 实时权限复查后低于 write 的评审者会被 dispatch,HEAD 构建对全部 26 个对抗用例(伪造、注入形状、路径形号码、越权评审者、撤回同意、重试语义)均按预期处置。
  • A/B 结论: 桥接块 HEAD 26/26 如预期;四个单点变异各自翻转其判别用例(见下表与 01-bridge-ab-head-vs-mutations.png)。shepherd 归因 A/B:BASE 在"外部 dispatch 先可见"的竞态下会把外部 run id 记成自己的,HEAD 记 run=none(文档化的回退:重复扫描,永不饥饿)。round-cap 静默路径 11/11:只有 GitHub 记录中真实成功且标题点名同一 PR 的 fork-bridge run 才能买到静默,手工伪造 source=fork-bridge 一律大声回应。
  • Findings(均不阻塞): ① PR 正文仍描述已被最终提交移除的 artifact 通道设计("artifact 是唯一通道"、"4/4 pass"、"空 head 守卫"变异),与代码不符,建议更新正文(见 Corrections);② headRefOid == $sha 在两侧同时为空时恒真(生产不可达,两者均由 GitHub 填充),正文"空 head 失败关闭"的表述对该角不成立;③ 桥接并发组以 conclusion+head_sha 为键,两个共享同一 head 的 fork PR 会互相取消在途桥接,先到的评审退回定时扫描兜底;④ shepherd 残余:外部单例持续且自身 dispatch 10 秒内不出现时会被记为"自己的"(文档化回退保持)。
  • 未覆盖: 合入前无法端到端(workflow_run 只对默认分支上的 workflow 触发);display_title 在新 signal workflow 上的传播仅有文档与作者对同类 run 的实测佐证;yamllint 容器内无 pip 无法运行(actionlint 已探针证明存活并覆盖 YAML 结构);浅克隆下 4 个提交仅 1 个可达,逐提交归因不可行,验证的是聚合 diff;cron 40–70 分钟延迟为作者实测,本环境无网络复核。

Scope

Central claim: the workflow_run bridge turns fork-PR review signals into credentialed autofix dispatches safely — a legitimate signal dispatches exactly the bound, eligible PR; forged, malformed, unauthorized, and stale signals are refused without dispatch (digit-locked parse, live reviewer write+ re-check, head-SHA freshness gate, live eligibility re-derivation).

Secondary claims: (1) source=fork-bridge is routing metadata only — round-cap silence is honored solely on GitHub-records provenance verification; manual dispatches asserting the marker are answered loud. (2) The shepherd's liveness attribution never attributes a foreign bridge dispatch on a guess — ambiguous windows record run=none (documented fallback: duplicate scan, never starvation).

Central claim: A/B and mutation matrix

Base cell (structural): at HEAD^1 neither workflow exists, qwen-autofix.yml has no source input and no DISPATCH_SOURCE, and route declines fork pull_request_review green (#8671 present at base) — so on base a fork review can never reach the credentialed lane in real time. Witness: 01-bridge-ab-head-vs-mutations.png.

build forgery (head moved) below-write reviewer path-shaped PR flaky dispatch result
base (HEAD^1) n/a — no bridge; fork review never dispatches n/a n/a n/a capability absent
HEAD refused (green no-op) refused (green no-op) red at parse, no dispatch retries, then dispatches 26/26 as expected
mut: drop head binding dispatched refused red retries guard load-bearing
mut: drop reviewer re-check refused dispatched red retries guard load-bearing
mut: loosen PR regex refused refused parses; red at quoted-gh boundary retries parse gate flipped; safety rides quoting
mut: single dispatch refused refused red red after 1 attempt retry loop load-bearing

Independent replay matrix at HEAD (harness/bridge-replay.mjs, raw log 01-bridge-head.txt): 26/26 — including $(…)/backtick reviewers (no side-effect file created), a newline-in-reviewer title (declined green, real-gh path semantics), a 300-digit PR number (red, fail-closed), all six consent-withdrawal shapes (green no-ops), unreadable PR (red), and dispatch retry/exhaustion (2 then 3 attempts).

Secondary claim 1 (harness/capsilence-replay.mjs, 02-capsilence-provenance-matrix.png): 11/11 — silence only for a verified recent successful bridge run naming the exact PR; spoofed marker, other-PR run, prefix collisions in both directions (7836 vs 78366), stale run, failed run, and API failure are all loud; a review event is unaffected by the marker.

Secondary claim 2 (harness/shepherd-replay.mjs, 03-shepherd-attribution-base-vs-head.png): HEAD 7/7, BASE 3/3. In the foreign-first race BASE attributes the foreign run id (900002) while HEAD records ''; a persistent foreign singleton is still attributed by HEAD after the two-poll stabilization window — the documented residual, whose downstream effect stays "duplicate scan, never starvation".

Targeted gates (witness 04-vitest-three-suites-green.png): the three workflow suites pass 143/143 at HEAD; vacuity triad in a scratch worktree: unmutated 9/9 green, drop -f source=fork-bridge → 2 red, drop the head-binding select → 2 red. bash -n clean on all four extracted run blocks; shellcheck (repo exclusions + env-provided categories) clean on all four; actionlint probe-proven live (planted broken expression caught, exit 1) and clean on all four workflows with the repo's flags; eslint clean on the three changed test files; prettier clean on the new files.

Corrections

The PR body's Reviewer Test Plan and "measured" bullets describe the artifact-channel design that the final commit removed; the code is the intended design (the suite pins the artifact channel's absence: "a resurrected one would reintroduce a binding that read a benign concurrent push as a forgery"). Specifically, at the verified head:

  1. "The artifact is the only channel" is false — the binding rides the signal's run-name, surfaced as workflow_run.display_title; signalText contains no upload-artifact, the bridge contains no gh run download (both pinned by the suite).
  2. "Expected: 4/4 pass" for the fork-bridge suite is stale — the file has 9 tests (143 across the three suites).
  3. "Drop the empty-head guard ✅" and the "both heads empty" replay case describe a guard/case that no longer exist; the effective binding is select(.headRefOid == $sha) (see Finding 2).

These are description-accuracy items, not code defects — labeled as corrections to the body, not requests to change the code.

Findings (non-blocking)

  1. Both-heads-empty is vacuously openselect(.headRefOid == $sha) admits '' == '', so a signal with an empty head_sha plus a PR view returning an empty headRefOid would dispatch. Unreachable in production: GitHub always populates workflow_run.head_sha, and gh pr view always returns headRefOid for an existing PR; the harness documents the behavior (both-heads-empty case dispatches). The body's "fails closed on an empty or unreadable head" holds for empty-vs-set, not both-empty. Repro: node tmp/…/harness/bridge-replay.mjs --only both-heads-empty.
  2. Cross-PR cancellation on a shared head — the bridge concurrency group is qwen-autofix-fork-bridge-${conclusion}-${head_sha}; two open fork PRs sharing one head commit share the group, so the later signal cancels the earlier in-flight bridge and that PR falls back to the scheduled scan (40–70 min on this repo). The comment's "two reviews on the same commit want one scan" reasoning is per-PR; across PRs it silently drops one real-time pickup. Backstop exists; economy-vs-pickup tradeoff worth a line in the body.
  3. Shepherd residual attribution — if a foreign dispatch is the sole candidate across all five polls (our run never appears within ~10 s), the foreign id is recorded as ours. Documented in the code comment; downstream effect remains duplicate-scan-never-starvation because the mis-attributed run is itself a full scan. Proven by shepherd-replay.mjs case head-persistent-foreign-attributed.

Not covered

  • Live E2E of the workflow_run chain — impossible pre-merge (workflow_run fires only for workflows already on the default branch); the author acknowledges this; the first real fork-PR review after merge is the live check.
  • display_title propagation for the new signal workflow — platform semantics verified only via GitHub docs plus the author's measured analogous pull_request_review run (31152873061, whose head_sha equaled the reviewed PR's head). If GitHub ever truncates or reformats run-names in display_title, the bridge fails red on parse (fail-closed), so the residual failure mode is "bridge silent + scheduled scan", not unsafe dispatch.
  • yamllint — the container image ships no pip, so the pinned yamllint could not be installed; actionlint (probe-proven live) covers YAML structure and expressions instead. bash -n/shellcheck on extracted blocks ran as above.
  • Per-commit attribution — depth-2 checkout: the metadata lists 4 commits but only 1 is locally reachable (git rev-list HEAD^1..HEAD^2 returns 1 at the shallow boundary); the aggregate HEAD^1..HEAD diff was verified instead.
  • The "cron lands every 40–70 min" motivation — author-measured; no network here to re-derive.
  • Repo-wide lint:ci/full test suite not re-run (the PR's own CI covers them); targeted gates above are the evidence cited.

Methodology

Environment: the CI verify container (node:22-bookworm, no GitHub token), merge-ref checkout (HEAD = merge, HEAD^1 = base 9e1b1eb49e, HEAD^2 = head 31bac88012). Harnesses (harness/*.mjs) extract each changed run: block verbatim from the parsed workflow YAML and execute it under bash -eo pipefail (the production shell) with a PATH-stubbed gh encoding real-CLI semantics (non-numeric PR selectors fail; collaborator paths with newlines or extra segments 404) and the real jq; every expectation is a scripted comparison. Mutation arms apply one documented single-hunk change to the extracted text and assert the discriminating case flips. Raw logs: 01-*.txt, 02-capsilence.txt, 03-shepherd-*.txt; images: evidence/*.png via scripts/verify-capture.mjs. Honesty note: the first shepherd harness run failed on both arms due to a missing trailing newline in my stub's response file (harness bug, fixed and re-run) — an A/A-style self-check before trusting either arm. Assertion counts: vitest 143 + bridge 26 + mutations 6 + capsilence 11 + shepherd 10 + vacuity 3 + bash -n 4 + shellcheck 4 + actionlint 2 + structural 6 + eslint 1 + prettier 1 = 217.

Evidence images

01-bridge-ab-head-vs-mutations

02-capsilence-provenance-matrix

03-shepherd-attribution-base-vs-head

04-vitest-three-suites-green

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.

Reviewed — no blockers. Suggestions are inline. Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/qwen-autofix-fork-bridge.yml: actionlint embedded-shell source mapping is not yet supported — not linted; the executable-script lint — .github/workflows/qwen-autofix-fork-signal.yml: actionlint embedded-shell source mapping is not yet supported — not linted; the executable-script lint — .github/workflows/qwen-autofix.yml: actionlint embedded-shell source mapping is not yet supported — not linted; the executable-script lint — .github/workflows/qwen-fleet-shepherd.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

中文说明

已审查——无阻断问题。 建议见行内评论。 未检查(工具限制,非阻断):the executable-script lint — .github/workflows/qwen-autofix-fork-bridge.yml: actionlint embedded-shell source mapping is not yet supported — not linted; the executable-script lint — .github/workflows/qwen-autofix-fork-signal.yml: actionlint embedded-shell source mapping is not yet supported — not linted; the executable-script lint — .github/workflows/qwen-autofix.yml: actionlint embedded-shell source mapping is not yet supported — not linted; the executable-script lint — .github/workflows/qwen-fleet-shepherd.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

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

Comment on lines +70 to +71
# conjuncts MIRROR route's fork admission (qwen-autofix.yml's
# pull_request_review path): maintainer edits on, and the PR bot-authored

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] Stale comment pointer: these conjuncts are said to "MIRROR route's fork admission (qwen-autofix.yml's pull_request_review path)", but since #8671 that path no longer admits fork PRs — it declines them inline ("fork review noted … the next scheduled scan engages", qwen-autofix.yml ~line 404). The criteria actually mirrored live in review-scan's fork admission (scheduled-scan candidate filter ~2228-2250 and forced_admission_reason ~2010). — Failure scenario: a maintainer verifying the mirror claim (or "fixing" the gate to match the cited code) opens route's pull_request_review branch, finds only a fork refusal, and may reconcile the gate with it — silently killing real-time fork-review pickup; no test pins the comment's pointer.

Suggested change
# conjuncts MIRROR route's fork admission (qwen-autofix.yml's
# pull_request_review path): maintainer edits on, and the PR bot-authored
# conjuncts MIRROR review-scan's fork admission (qwen-autofix.yml's
# candidate filter + forced_admission_reason): maintainer edits on, and the PR bot-authored
中文说明

问题: 注释指针过期:这里说这些条件「MIRROR route's fork admission (qwen-autofix.yml's pull_request_review path)」,但自 #8671 之后该路径已不再接纳 fork PR——它在行内直接拒绝("fork review noted … the next scheduled scan engages",qwen-autofix.yml 约第 404 行)。实际被镜像的标准位于 review-scan 的 fork 准入逻辑(定时扫描候选过滤 ~2228-2250 与 forced_admission_reason ~2010)。

失败场景: maintainer 核对这一镜像声明(或按注释所指的代码去「修正」门控)时,打开 route 的 pull_request_review 分支只会看到对 fork 的拒绝,可能据此把门控改成与拒绝一致——从而悄无声息地杀死实时接管;没有任何测试钉住这个注释指针。

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

Comment on lines +125 to +126
if [[ "${SIGNAL_REVIEWER}" != "${REVIEW_BOT}" ]]; then
REVIEWER_PERM="$(gh api "repos/${REPO}/collaborators/${SIGNAL_REVIEWER}/permission" --jq '.permission // ""' 2> /dev/null || echo '')"

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] A failed reviewer-permission API lookup is indistinguishable from, and logged as, a genuine "below write" decision — asserting a verdict the code never obtained. Both siblings making this same call treat failure differently: route logs ::warning::Permission API call failed (qwen-autofix.yml ~420), and review-scan's read_live_permission (~1982) retries and distinguishes definitive none/404 from transient failures. — Failure scenario: a transient 5xx / secondary rate limit on the collaborators endpoint during a GitHub API brownout → every fork review silently loses real-time pickup (the whole point of this PR) while the log positively asserts a reviewer-permission cause ("permission='none' is below write"), sending oncall to inspect ACLs instead of API health; the run stays green, so nothing pages.

Suggested fix (failing closed is right — only the log and the distinction need fixing):

if [[ "${SIGNAL_REVIEWER}" != "${REVIEW_BOT}" ]]; then
  if ! REVIEWER_PERM="$(gh api "repos/${REPO}/collaborators/${SIGNAL_REVIEWER}/permission" --jq '.permission // ""' 2> /dev/null)"; then
    echo "::warning::reviewer permission lookup failed for '${SIGNAL_REVIEWER}' — failing closed, the scheduled scan remains the backstop"
    exit 0
  fi
  case "${REVIEWER_PERM}" in
    ...
中文说明

问题: reviewer 权限 API 查询失败时,与「确实低于 write」无法区分,且日志按后者输出——断言了一个代码从未获得的结论。两处做同样调用的兄弟代码处理方式不同:route 会记录 ::warning::Permission API call failed(qwen-autofix.yml ~420),review-scan 的 read_live_permission(~1982)会重试并区分「确定的 none/404」与瞬时故障。

失败场景: GitHub API 抖动期间 collaborators 端点出现瞬时 5xx / 二级限流 → 每个 fork review 都会静默失去实时接管(这正是本 PR 要恢复的能力),而日志却斩钉截铁地归因于 reviewer 权限("permission='none' is below write"),把 oncall 引去排查 ACL 而非 API 健康度;run 仍是绿色,不会有任何告警。

建议修复: 失败关闭的方向是对的——只需修日志与区分:单独捕获查询退出码,失败时输出独立的 ::warning:: 后失败关闭(route 的模式),或重试 2-3 次并以诚实的「permission lookup failed」收尾。

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

if [[ "${SIGNAL_REVIEWER}" != "${REVIEW_BOT}" ]]; then
REVIEWER_PERM="$(gh api "repos/${REPO}/collaborators/${SIGNAL_REVIEWER}/permission" --jq '.permission // ""' 2> /dev/null || echo '')"
case "${REVIEWER_PERM}" in
admin|maintain|write) : ;;

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 admin and maintain accept branches of this case are never exercised — the replay harness only supplies write (happy path) and triage/read/empty/lookup-failure (decline paths). — Failure scenario: verified empirically — mutating the pattern to write) : ;; leaves all 9 fork-bridge tests green. In production, an org owner or maintainer reviewing a fork PR (live permission admin/maintain) would then be silently declined with the factually wrong "below write" message, losing real-time pickup and degrading to the cron backstop with no test red. The harness already supports the discriminating inputs.

Suggested fix (in scripts/tests/qwen-autofix-fork-bridge-workflow.test.js): add { reviewerPermission: 'admin' } and { reviewerPermission: 'maintain' } replay cases asserting status 0 + pr_number=8436 in the recorded calls.

中文说明

问题: 该 case 的 adminmaintain 接受分支从未被测试执行——回放 harness 只提供 write(正常路径)和 triage/read/空值/查询失败(拒绝路径)。

失败场景: 已实测验证——把模式变异为 write) : ;;,全部 9 个 fork-bridge 测试依旧通过。生产中,org owner 或 maintainer 对 fork PR 提交 review(实时权限为 admin/maintain)时会被静默拒绝,并附带与事实不符的「below write」消息,失去实时接管、退化到 cron 兜底,而没有任何测试变红。harness 本就支持这两个区分性输入。

建议修复:(在 scripts/tests/qwen-autofix-fork-bridge-workflow.test.js 中)新增 { reviewerPermission: 'admin' }{ reviewerPermission: 'maintain' } 回放用例,断言 status 0 且录制调用中含 pr_number=8436

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

Comment on lines +2738 to +2739
FORK_BRIDGE_VERIFIED=false
if [[ "${DISPATCH_SOURCE}" == 'fork-bridge' ]]; then

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 only code path that ever sets FORK_BRIDGE_VERIFIED=true — this condition, the provenance success branch, and the '360 minutes ago' window — is never executed by any test: the guard replay injects FORK_BRIDGE_VERIFIED directly from the test env, and the jq replay passes cutoff in, so the glue is pinned by substrings only. — Failure scenario: three one-line mutants empirically survive with all 130 tests in the two affected suites green — ==!= on the line below; FORK_BRIDGE_VERIFIED=true=false; and shrinking '360 minutes ago'. Each makes genuine fork-bridge dispatches on round-capped fork PRs post the loud refusal comment — resurrecting the exact #7836 refusal-spam regression this PR exists to eliminate. This is the same connective-flip mutant class the suite's own comments say it exists to catch.

Suggested fix (in scripts/tests/qwen-autofix-workflow.test.js): extract this if [[ "${DISPATCH_SOURCE}" == 'fork-bridge' ]]; then ... fi block verbatim (the suite's existing pattern) and replay it under bash with a PATH-stubbed gh run list and a stubbed/fixed date; assert FORK_BRIDGE_VERIFIED ends true for a matching bridge run, false for DISPATCH_SOURCE='', and false + warning for an unmatched/failed lookup; pin the '360 minutes ago' literal.

中文说明

问题: 唯一会把 FORK_BRIDGE_VERIFIED=true 的代码路径——此条件、溯源成功分支以及 '360 minutes ago' 窗口——从未被任何测试执行:守卫回放直接从测试环境注入 FORK_BRIDGE_VERIFIED,jq 回放则由测试传入 cutoff,所以这段胶水逻辑只被字符串级钉住。

失败场景: 三个单行变异均实测存活,且两个相关套件的 130 个测试全部保持绿色——下一行的 ==!=FORK_BRIDGE_VERIFIED=true=false;缩短 '360 minutes ago'。每一个都会让真实 fork-bridge dispatch 在已达上限的 fork PR 上发出响亮拒绝评论——复活本 PR 要消除的 #7836 拒绝刷屏回归。这正是套件自身注释声称要捕捉的连接词翻转类变异。

建议修复:(在 scripts/tests/qwen-autofix-workflow.test.js 中)按套件既有模式逐字抽出该 if [[ "${DISPATCH_SOURCE}" == 'fork-bridge' ]]; then ... fi 块,在 bash 下用 PATH stub 的 gh run list 与固定/stub 的 date 回放;断言匹配 bridge run 时 FORK_BRIDGE_VERIFIEDtrueDISPATCH_SOURCE='' 时为 false,未匹配/查询失败时为 false 且带 warning;同时钉住 '360 minutes ago' 字面量。

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

FORK_BRIDGE_VERIFIED=false
if [[ "${DISPATCH_SOURCE}" == 'fork-bridge' ]]; then
BRIDGE_CUTOFF="$(date -u -d '360 minutes ago' +%Y-%m-%dT%H:%M:%SZ)"
if BRIDGE_RUNS="$(gh run list --repo "${REPO}" --workflow qwen-autofix-fork-bridge.yml --limit 20 --json conclusion,createdAt,displayTitle 2> /dev/null)" \

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] The provenance horizon is the page, not the window: gh run list --limit 20 has no status filter, so skipped/queued/failed bridge runs consume slots in the newest-20, and the 360-minute cutoff filters only after the page is fetched. — Failure scenario: any GitHub account can submit ~20 COMMENTED reviews on throwaway fork PRs; each fires a signal that gates itself out as skipped, and every skipped signal still fires workflow_run: completed (documented in the bridge's own concurrency comment), creating skipped bridge runs that fill the page. A maintainer then reviews a round-capped managed fork PR, the bridge legitimately dispatches, but the scan finds no successful bridge run in the page → FORK_BRIDGE_VERIFIED=false → one loud "Dispatch refused" comment per review on the capped fork PR — the exact #7836 spam pattern this gate exists to prevent, triggerable with zero repository permissions. Organic variant: route backlog queues the dispatch for hours while 20+ bridge runs churn the page.

Suggested change
if BRIDGE_RUNS="$(gh run list --repo "${REPO}" --workflow qwen-autofix-fork-bridge.yml --limit 20 --json conclusion,createdAt,displayTitle 2> /dev/null)" \
if BRIDGE_RUNS="$(gh run list --repo "${REPO}" --workflow qwen-autofix-fork-bridge.yml --status success --limit 100 --json conclusion,createdAt,displayTitle 2> /dev/null)" \

(raise the page so the window binds; --status success also stops non-success runs from consuming slots — they never pass the jq filter anyway)

中文说明

问题: 溯源检查的视野是这一页 20 条,而不是 360 分钟窗口:gh run list --limit 20 没有状态过滤,skipped/queued/failed 的 bridge run 也会占据最新 20 条的名额,而 360 分钟截止线要在取回这一页之后才参与过滤。

失败场景: 任意 GitHub 账号都可以在一次性 fork PR 上提交约 20 条 COMMENTED review;每条都会触发一个自我门控为 skipped 的 signal,而 skipped 的 signal 同样会触发 workflow_run: completed(bridge 自己的并发注释已说明),由此产生的 skipped bridge run 会占满页面。随后 maintainer 对一个已达轮次上限的 managed fork PR 提交 review,bridge 正常 dispatch,但扫描在页面里找不到成功的 bridge run → FORK_BRIDGE_VERIFIED=false → 该 PR 上每次 review 都收到一条响亮的「Dispatch refused」评论——正是本门控要防止的 #7836 刷屏模式,且触发者无需任何仓库权限。非对抗变体:route 积压把 dispatch 排队数小时,期间 20+ 个 bridge run 刷新了页面。

建议修复: 提高页大小让窗口成为约束(如 --limit 100),并加 --status success 使非成功 run 不再占用名额——它们本来就过不了 jq 过滤。

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

FORK_BRIDGE_VERIFIED=false
if [[ "${DISPATCH_SOURCE}" == 'fork-bridge' ]]; then
BRIDGE_CUTOFF="$(date -u -d '360 minutes ago' +%Y-%m-%dT%H:%M:%SZ)"
if BRIDGE_RUNS="$(gh run list --repo "${REPO}" --workflow qwen-autofix-fork-bridge.yml --limit 20 --json conclusion,createdAt,displayTitle 2> /dev/null)" \

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] The --workflow qwen-autofix-fork-bridge.yml filename reference here is pinned by no test to the bridge file's actual path. If the bridge workflow is renamed, the fork-bridge suite fails only until its bridgePath constant is updated; afterwards all its assertions derive from the file at the new path and pass, and the literal pin in qwen-autofix-workflow.test.js matches stale-to-stale — the suite is green while this YAML reference stays wrong. — Failure scenario: in production gh run list --workflow qwen-autofix-fork-bridge.yml then 404s (verified live — the identical call shape returns HTTP 404 today, since the bridge is not merged yet: exactly the post-rename state) → the substitution dies in 2> /dev/nullFORK_BRIDGE_VERIFIED is forever false → the refusal-spam regression on capped fork PRs returns, discoverable only via the per-run ::warning::. Distinct from the run-title-prefix pin: this is the workflow-identity reference, with a file rename as the trigger.

Suggested fix (in scripts/tests/qwen-autofix-fork-bridge-workflow.test.js, which already loads autofixText):

expect(autofixText).toContain('--workflow ' + bridgePath.split('/').pop());
中文说明

问题: 此处的 --workflow qwen-autofix-fork-bridge.yml 文件名引用没有任何测试把它钉到 bridge 文件的真实路径。若 bridge workflow 被重命名,fork-bridge 套件只会先在其 bridgePath 常量处失败;常量更新后,所有断言都从新路径的文件推导并通过,而 qwen-autofix-workflow.test.js 里的字面量钉住项也只是陈旧对陈旧——套件全绿,YAML 里的引用却已错误。

失败场景: 生产中 gh run list --workflow qwen-autofix-fork-bridge.yml 将返回 404(已实测——同样的调用形态今天就返回 HTTP 404,因为 bridge 尚未合入:恰与重命名后的状态一致)→ 命令替换在 2> /dev/null 中消亡 → FORK_BRIDGE_VERIFIED 永远为 false → 上限 fork PR 上的拒绝刷屏回归重现,唯一线索是每次运行的 ::warning::。与 run-title 前缀的钉住项不同:这是 workflow 身份引用,触发条件是文件重命名。

建议修复:(在已加载 autofixTextscripts/tests/qwen-autofix-fork-bridge-workflow.test.js 中)由真实路径推导该引用并断言。

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

&& jq -e --arg pr "${PR}" --arg cutoff "${BRIDGE_CUTOFF}" '
[ .[]
| select(.conclusion == "success" and ((.createdAt // "") >= $cutoff))
| select((.displayTitle // "") | startswith("fork-bridge: fork-signal: PR \($pr) reviewed by ")) ]

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] This scan-side copy of the composed run-title prefix is the only one no test ties back to the two run-name: fields it derives from: qwen-autofix-workflow.test.js reads only qwen-autofix.yml/ci.yml/release.yml, and the fork-bridge test — which does hold autofixText — contains no assertion on the scan prefix. — Failure scenario: verified empirically — a coordinated reviewed byreviewed-by edit across the signal run-name:, the bridge TITLE_RE and all six fork-bridge-test pins leaves 130/130 tests green, while the stale scan prefix never matches a real bridge title again: FORK_BRIDGE_VERIFIED stays false for every fork-bridge dispatch and the cap gate answers each one loudly — reintroducing the #7836 refusal spam, silently, with only a provenance unverified warning. The bridge-side copy (TITLE_RE) fails loud (red bridge runs) under the same edit; the scan leg is the silent one.

Suggested fix (in scripts/tests/qwen-autofix-fork-bridge-workflow.test.js): derive the expected prefix from the pinned SIGNAL_RUN_NAME/BRIDGE_RUN_NAME static parts and assert it appears in the review-scan script — replacing one hardcoded copy with a cross-file check.

中文说明

问题: 这个由两个 run-name: 字段组合而成的 run-title 前缀,扫描端的这一份是唯一没有被任何测试回溯到其来源字段的拷贝:qwen-autofix-workflow.test.js 只读取 qwen-autofix.yml/ci.yml/release.yml,而持有 autofixText 的 fork-bridge 测试里没有任何针对扫描端前缀的断言。

失败场景: 已实测验证——把 signal 的 run-name:、bridge 的 TITLE_RE 以及 fork-bridge 测试的六处钉住项协同地从 reviewed by 改为 reviewed-by,130/130 个测试全绿,而陈旧的扫描端前缀从此再也匹配不到真实的 bridge 标题:所有 fork-bridge dispatch 的 FORK_BRIDGE_VERIFIED 恒为 false,上限门控对每一次都响亮回应——重新引入 #7836 拒绝刷屏,且是静默的,只有一条 provenance unverified warning。同样编辑下 bridge 端的拷贝(TITLE_RE)会响亮失败(bridge run 变红);扫描端这条腿才是沉默的那条。

建议修复:(在 scripts/tests/qwen-autofix-fork-bridge-workflow.test.js 中)由钉住的 SIGNAL_RUN_NAME/BRIDGE_RUN_NAME 静态部分推导期望前缀,并断言其出现在 review-scan 脚本中——把一份硬编码拷贝替换为跨文件检查。

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

Comment on lines +246 to +247
if [[ -n "${SEEN_ID}" && "${SEEN_ID}" == "${PREV_SEEN:-}" ]]; then
ATTRIBUTED="${SEEN_ID}"

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 loop's keep-polling semantics — an ambiguity arriving AFTER a two-poll stabilization still clears the attribution — are pinned by no test; the stateful stub sequences are only [empty, singleton] and [foreign-singleton, pair]. — Failure scenario: verified empirically — appending ; break after ATTRIBUTED="${SEEN_ID}" (a plausible "optimization") survives the whole suite. With polls [foreign-singleton, foreign-singleton, pair] (the bridge's dispatch lands just after stabilization), the mutant attributes the foreign run — the guess-attribution this diff's own comment forbids ("never attribute a guess") — while the original records run=none; no existing test distinguishes them.

Suggested fix (in scripts/tests/qwen-fleet-shepherd-workflow.test.js): add one stateful sequence [singleton(900002), singleton(900002), pair(900002, 900001)] expecting ''.

中文说明

问题: 该循环「持续轮询」的语义——两次轮询稳定之后才出现的歧义仍会清空归因——没有任何测试钉住;stateful stub 序列只有 [empty, singleton][foreign-singleton, pair]

失败场景: 已实测验证——在 ATTRIBUTED="${SEEN_ID}" 后追加 ; break(一个看似合理的「优化」)即可通过整个套件。当轮询序列为 [foreign-singleton, foreign-singleton, pair](bridge 的 dispatch 恰在稳定后出现)时,变异体会把外部 run 归为己有——正是本 diff 注释所禁止的猜测式归因("never attribute a guess")——而原始实现记录 run=none;现有测试无法区分两者。

建议修复:(在 scripts/tests/qwen-fleet-shepherd-workflow.test.js 中)新增一条 stateful 序列 [singleton(900002), singleton(900002), pair(900002, 900001)],期望结果为 ''

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

Comment on lines +119 to +121
expect(bridgeScript).toContain('gh workflow run qwen-autofix.yml');
expect(bridgeScript).toContain('-f pr_number=');
expect(bridgeScript).toContain('-f source=fork-bridge');

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 element of the bridge's dispatch call is pinned cross-file here — except the target ref. --ref main (.github/workflows/qwen-autofix-fork-bridge.yml:161) selects which copy of qwen-autofix.yml executes; the replay's stub gh accepts any ref. — Failure scenario: verified empirically — mutating --ref main--ref release leaves all 9 tests green. If the ref drifts, the dispatch either fails after three retries (bridge permanently red) or executes the scan lane from the wrong branch's workflow file — silent behavioral drift of the secret-bearing lane with no CI signal.

Suggested change
expect(bridgeScript).toContain('gh workflow run qwen-autofix.yml');
expect(bridgeScript).toContain('-f pr_number=');
expect(bridgeScript).toContain('-f source=fork-bridge');
expect(bridgeScript).toContain('gh workflow run qwen-autofix.yml');
expect(bridgeScript).toContain('-f pr_number=');
expect(bridgeScript).toContain('-f source=fork-bridge');
expect(bridgeScript).toContain('--ref main');
中文说明

问题: bridge 的 dispatch 调用在此被跨文件钉住了每一个要素——唯独缺了目标 ref。--ref main(.github/workflows/qwen-autofix-fork-bridge.yml:161)决定执行哪一份 qwen-autofix.yml;回放用的 stub gh 接受任意 ref。

失败场景: 已实测验证——把 --ref main 变异为 --ref release,全部 9 个测试依旧通过。若 ref 发生漂移,dispatch 要么在三次重试后失败(bridge 永久变红),要么用错误分支的 workflow 文件执行扫描车道——持有 secrets 的车道发生静默行为漂移,而 CI 毫无信号。

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

Comment on lines +290 to +291
const replay = (ghScript) => {
const dir = mkdtempSync(join(tmpdir(), 'shepherd-corr-'));

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] This PR adds two more copies of the PATH-stubbed-gh replay harness that already exists in this very file — three copies of the same skeleton now live in two test files: runBusyWalk (this file, :405, pre-existing), replay (:290, added here) and runBridge (qwen-autofix-fork-bridge-workflow.test.js:394, added here). All repeat mkdtemp → write gh stub → chmodSync 0o755 → bash with PATH prefix → rmSync in finally, and they drifted on day one: runBusyWalk omits the set -eo pipefail + sleep() stub prologue the new copies include (the production shape per GHA's bash -eo pipefail default), and runBridge uses spawnSync while the other two use execFileSync. — Concrete cost: any future fix to stub/cleanup semantics — or the next replay test, which will copy a fourth time — must be made in 3+ places independently, and a harness fix applied to one copy leaves the others simulating a different shell. scripts/tests/workflow-helpers.js already exists and is imported by sibling suites.

Suggested fix: extract the shared skeleton there, e.g. replayWithStubbedGh({ ghScript, script, env, prologue }) returning stdout/status, and have all three call sites use it.

中文说明

问题: 本 PR 又新增了两份 PATH stub gh 回放 harness 的拷贝——同一骨架现在共有三份、分布在两个测试文件里:runBusyWalk(本文件 :405,原有)、replay(:290,本次新增)、runBridge(qwen-autofix-fork-bridge-workflow.test.js:394,本次新增)。三者都重复 mkdtemp → 写 gh stub → chmodSync 0o755 → 带 PATH 前缀运行 bash → finallyrmSync,且第一天就已漂移:runBusyWalk 缺少新拷贝都带的 set -eo pipefail + sleep() stub 前导(按 GHA 默认 bash -eo pipefail 这才是生产形态),runBridgespawnSync 而另两个用 execFileSync

具体代价: 未来任何对 stub/清理语义的修复——或下一个回放测试(会复制出第四份)——都必须在 3+ 处独立完成;只修一份,其余拷贝就在模拟另一种 shell。scripts/tests/workflow-helpers.js 已经存在,且已被兄弟套件引用。

建议修复: 把共享骨架抽到那里,例如 replayWithStubbedGh({ ghScript, script, env, prologue }) 返回 stdout/status,三处调用点统一使用。

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

@wenshao

wenshao commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /triage

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Re-run after the template gate — the body now carries every required heading ✓

Problem: an observed capability loss, not theoretical hardening. #8671 (merged) made the direct lane decline fork-PR review events because those runs arrive with Secret source: None and cannot authenticate — route's own comments on main document it. Since then, takeover-labelled fork PRs only get picked up by the scheduled scan, whose */10 cron lands every 40–70 minutes on this repo — measured, not assumed.

Direction: aligned. This restores real-time pickup for exactly the PRs a maintainer is actively waiting on (bot-authored or takeover-labelled forks), without reopening the red-CI failure mode #8671 closed.

Size: no core-package paths — ~369 production lines of workflow YAML across 4 files, ~795 lines of tests across 3 files. Below every advisory threshold.

Approach: the canonical workflow_run bridge, split correctly: a zero-permission signal half that a fork-triggered run can reach, and a base-context bridge half that holds actions: write but no PAT. One observation at the description level: the body still describes an earlier artifact-channel revision in places ("The artifact is the only channel", "Expected: 4/4 pass", a "change the artifact name" mutation) while the code moved to a run-name binding and the suite now has 9 tests — worth syncing the body, noted again below, not blocking.

Risk: no high-risk-path matches. It is credential plumbing, but the design keeps the secretless half genuinely secretless (pinned by a brace-aware test) and every hop re-derives admission from live API state.

Moving on to code review. 🔍

中文说明

模板拦截后的 re-run——正文现在包含了所有必需的标题 ✓

问题:已观测到的能力缺失,不是理论性加固。#8671(已合入)让直连车道拒绝 fork PR 的评审事件,因为这类 run 拿不到仓库 secrets(Secret source: None),无法认证——main 上 route 自己的注释记录了这一点。此后 takeover 标记的 fork PR 只能靠定时扫描拾取,而本仓库的 */10 cron 实际落地间隔是 40–70 分钟——是实测值,不是假设。

方向:对齐。它恢复的正是维护者正在主动等待的那类 PR(bot 作者或带 takeover 标签的 fork PR)的实时拾取,同时没有重新打开 #8671 关闭的红 CI 失败模式。

规模:不涉及 core 包路径——4 个文件约 369 行生产 workflow YAML,3 个测试文件约 795 行。低于所有提示阈值。

方案:标准的 workflow_run 桥接,且拆分正确:fork 触发的 run 能够到的零权限 signal 半边,加上持有 actions: write 但不持 PAT 的 base 上下文 bridge 半边。描述层面有一个观察:正文部分位置仍在描述较早的 artifact 通道设计("artifact 是唯一通道"、"Expected: 4/4 pass"、"改动 artifact 名"变异),而代码已改为 run-name 绑定,测试套件也已有 9 个用例——建议同步正文,下面会再提,不构成阻断。

风险:未命中高风险路径。这确实是凭据管道,但设计让无 secret 的半边真正无 secret(由一个能识别花括号的测试钉死),且每一跳都从实时 API 状态重新推导准入。

进入代码审查 🔍

Qwen Code · qwen3.8-max

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

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Code review

Independent baseline first: for "fork-PR review events carry no secrets, so the credentialed lane cannot authenticate", the canonical answer is exactly a workflow_run bridge — a powerless signal on the fork-triggered event plus a base-context dispatcher. The PR matches that baseline and is more careful than it in the details: the binding channel is the signal's run-name rather than an artifact (no upload/download race against head moves), admission is re-derived live at every hop, and the failure modes are loud-red for broken contracts, green no-ops for stale state, with the cron scan as backstop throughout.

The security trace holds up:

  • A fork cannot edit the gate or forge the binding. Fork-triggered pull_request_review runs execute the workflow file from the base branch — the PR's run-31152873061 evidence checks out (fix(triage): finalize the status comment on cancellation too #8436 is a fork PR whose branch predates the executed script), and main's own route comment confirms the file-vs-credentials split. The run-name is supplied by that base file from event data (numeric PR, GitHub-controlled login).
  • The secretless half is genuinely secretless. permissions: {}, no checkout, hosted runner, and a brace-aware expression scanner pins that neither new file reads a secret. Live smoke on this very PR: run 31194346199 fired the signal on each of this PR's reviews and self-gated to skipped (in-repo, not a fork) — the gate works as shipped.
  • The bridge trusts nothing it cannot re-verify. It re-checks the reviewer's LIVE write permission (association alone is not enough), re-reads the bound PR, requires head-equality plus the full admission set, and dispatches exactly one number. Unparseable title, unreadable PR, exhausted retries → red; withdrawn consent or a moved head → green no-op.
  • The public source input buys no privilege. It grants no concurrency rights (pinned OUT of route's group key) and its one behavioral effect — staying quiet at the round cap — is honored only after verifying provenance against a real, recent, successful fork-bridge run naming the exact PR (prefix-collision-safe; a manual dispatch cannot fabricate the run list).
  • The shepherd fix matches the filed defect. Ambiguous window (2+ candidates) → run=none; a singleton is attributed only after surviving two consecutive polls. A residual race remains in theory — a foreign singleton stable while the shepherd's own run stays list-invisible for both polls would be misattributed — but the impact is the documented bounded one (self-heals when the foreign run completes; failure mode is a duplicate scan, never starvation or a security boundary), and the loop is replayed behaviorally with stateful stubs.

Two nits, neither blocking:

  1. The body lags the code. The design pivoted from an artifact channel to the run-name binding, but the body still says "The artifact is the only channel", "the download name equals the upload name", "Expected: 4/4 pass" (the suite now has 9 tests), and lists a "change the artifact name" mutation. Worth syncing so the next reader's verification commands match what shipped.
  2. The mutation table and replayed-case list in the body are otherwise solid evidence of the methodology — the empty-head case genuinely earned its guard.
sequenceDiagram
    participant P1 as Trusted reviewer
    participant P2 as Fork Signal
    participant P3 as Fork Bridge
    participant P4 as Autofix scan
    P1->>P2: submits a review on a fork PR
    Note over P2: base-branch file, permissions empty, run-name carries the PR binding
    P2->>P3: workflow_run completed
    Note over P3: re-checks reviewer write permission and live PR admission
    P3->>P4: workflow_dispatch with pr_number and source marker
    Note over P4: re-derives admission again from live API state
Loading
Files changed (7 of 7)
File What changed
.github/workflows/qwen-autofix-fork-signal.yml New powerless signal half — fires on a trusted review of an eligible fork PR, completes success so the bridge fires, run-name carries the PR and reviewer
.github/workflows/qwen-autofix-fork-bridge.yml New base-context bridge — parses the run-name binding, re-checks the reviewer live, re-reads live PR admission, dispatches one PR number with retries
.github/workflows/qwen-autofix.yml Adds the optional source dispatch input and the provenance-verified silence at the round cap
.github/workflows/qwen-fleet-shepherd.yml Attribution hardening — ambiguous window records run none, singleton must survive two consecutive polls
scripts/tests/qwen-autofix-fork-bridge-workflow.test.js New 9-test suite — cross-file contract pins plus a stub-API bash replay of the bridge
scripts/tests/qwen-autofix-workflow.test.js Pins the provenance jq program and the refusal guard behaviorally
scripts/tests/qwen-fleet-shepherd-workflow.test.js Replays the attribution loop verbatim with static and stateful stubs

Testing evidence — the PR's own CI

Check Conclusion
Qwen Code CI · Test (ubuntu-latest, Node 22.x) ✅ success
Qwen Code CI · Desktop Shell (ubuntu-22.04) ✅ success
Qwen Code CI · web-shell E2E Smoke (ubuntu-latest, Node 22.x) ✅ success
Qwen Code CI · Classify PR ✅ success
Qwen Code CI · Test (macos-latest / windows-latest) ⏭️ skipped — merge-queue only by design
Qwen Code CI · Integration Tests (CLI, No Sandbox) ⏭️ skipped — merge-queue only by design

All 114 check-runs on the reviewed commit completed: 0 failures, 0 pending. The macOS/Windows and integration skips are the repo's standing design (ci.yml gates them on merge_group), not caused by this PR. The ubuntu test job ran the new suites — from the job log: scripts/tests/qwen-autofix-fork-bridge-workflow.test.js (9 tests) 278ms with the scripts suite green overall (8 files / 79 tests passed).

What no CI can settle pre-merge, stated plainly: workflow_run only fires for workflows already on the default branch, so the live end-to-end bridge cannot be observed by anyone until after merge — the PR says so itself, and the first real fork-PR review afterwards is the field test, with the scheduled scan as backstop. A sandboxed /verify or /tmux lane cannot close that gap either (there is no user-visible surface, and no lane can trigger the production plumbing); the separately-triggered verification run from the earlier /triage comment is still in flight but can only re-exercise the pinned replay harnesses CI already ran. Not verified: live post-merge fork-review pickup — by nature, not by omission.

中文说明

代码审查

先给出独立基线:对于「fork PR 的评审事件没有 secrets,持凭据的车道无法认证」这个问题,标准解法正是 workflow_run 桥接——fork 触发事件上的无权限 signal,加 base 上下文的 dispatcher。本 PR 与该基线一致,且在细节上更谨慎:绑定通道用 signal 的 run-name 而非 artifact(避免上传/下载与 head 移动的竞态),每一跳都实时重新推导准入,失败模式上——契约破裂响亮报红、状态过期绿色 no-op、全程以定时扫描兜底。

安全推演成立:fork 无法编辑 gate 或伪造绑定(fork 触发的评审 run 执行 base 分支的 workflow 文件——PR 引用的 run 31152873061 证据经核实成立,main 上 route 的注释也印证了文件与凭据的分离);无 secret 的半边真正无 secret(permissions: {}、无 checkout、托管 runner,且有能识别花括号内嵌表达式的扫描器钉死两个新文件都不读 secret)——本 PR 自身的评审还触发了 run 31194346199 的实时冒烟:signal fired 后因「非 fork」自我 gate 为 skipped;bridge 不信任任何无法实时复核的东西(实时复查 reviewer 写权限、重读目标 PR、要求 head 相等与完整准入集,只 dispatch 一个号码);公开的 source 输入换不来任何特权(不进 route 的并发分组,其唯一行为效果——轮次上限时保持安静——只在核实到真实、近期、成功且点名同一 PR 的 fork-bridge run 后才生效);shepherd 修复与所报缺陷对应(歧义窗口记 run=none,singleton 需连续两次轮询存活)——理论上仍有一个残余竞态(外部 singleton 稳定、而 shepherd 自己的 run 两次轮询都不可见时会被错误归属),但影响是文档化的有界自愈(失败模式是重复扫描,不是饥饿或安全边界),且该循环已用带状态 stub 行为化回放。

两个不阻断的小问题:正文落后于代码(设计已从 artifact 通道转为 run-name 绑定,正文仍有 artifact 表述与「4/4 pass」,套件现为 9 个测试),建议同步;正文的变异表与回放用例清单本身是很好的方法论证据。

测试证据

被审 commit 上 114 个 check-run 全部完成:0 失败、0 待定。macOS/Windows 与集成测试的跳过是仓库既有设计(merge_group 才跑),与本 PR 无关。ubuntu 测试 job 的日志显示新套件已运行并通过(qwen-autofix-fork-bridge-workflow.test.js (9 tests) 278ms,scripts 套件整体 8 文件 79 用例全绿)。合入前任何 CI 都无法验证的是端到端实时桥接——workflow_run 只对默认分支上已有的 workflow 生效,PR 自己也这么说;合入后第一个真实 fork 评审就是实地检验,定时扫描兜底。沙箱 /verify/tmux 车道也关不了这个缺口(无用户可见面,任何车道都无法触发生产管道)。未验证项:合入后的实时 fork 评审拾取——性质使然,而非疏漏。

Qwen Code · qwen3.8-max

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

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Confidence: 4/5 — clean across every stage; the one real nit is that the PR body still narrates the earlier artifact-channel revision instead of the run-name binding that shipped.

Stepping back: my independent proposal for this problem was the same workflow_run bridge, and this PR exceeds it — the run-name binding is simpler than an artifact channel and immune to the head-move race, every hop re-derives admission from live state, and the test suite pins cross-file contracts and replays the actual bash under a stub API rather than asserting substrings. The motivation is an observed loss (verified: #8671 is merged and route's decline is on main), the latency it restores was measured, and the two drive-on edits (the source input, the shepherd attribution fix) are direct consequences of the new dispatch source, not scope creep.

The questions I sat with: does the residual shepherd race bother me? In theory a foreign dispatch stable across two polls while the shepherd's own run stays list-invisible gets misattributed — but the failure mode is a duplicate scan that self-heals, never starvation or a security boundary, and it is replayed behaviorally. Does the pre-merge unobservability bother me? It is inherent to workflow_run, the design fails closed at every seam, and the cron backstop covers the gap. Neither rises above a nit. The body staleness is the only thing I'd ask the author to fix, and it can land whenever — it doesn't hold the code.

Approving, pinned to the reviewed commit. The stale CHANGES_REQUESTED states on this PR are my own earlier template gate (the body is fixed) and a round-1 review finding that the current head resolves — this approval supersedes both.

中文说明

置信度:4/5 —— 各阶段都干净;唯一实质性的瑕疵是 PR 正文仍在描述较早的 artifact 通道设计,而不是实际落地的 run-name 绑定。

退一步看:我对这个问题的独立方案同样是 workflow_run 桥接,而本 PR 做得更多——run-name 绑定比 artifact 通道更简单、天然免疫 head 移动竞态,每一跳都从实时状态重新推导准入,测试套件钉住跨文件契约并在 stub API 下回放真实 bash,而不是断言子串。动机是已观测到的能力缺失(已核实:#8671 已合入,route 的拒绝逻辑在 main 上),要恢复的延迟有实测数据,两处附带修改(source 输入、shepherd 归属修复)都是新 dispatch 来源的直接后果,不是范围蔓延。

我反复掂量的问题:shepherd 的残余竞态是否构成顾虑?理论上存在「外部 dispatch 连续两次轮询稳定、而 shepherd 自己的 run 始终不可见」被错误归属的可能——但失败模式是可自愈的重复扫描,不是饥饿或安全边界,且已有行为化回放。合入前不可观测是否构成顾虑?这是 workflow_run 的固有属性,设计在每个接缝上都 fail closed,定时扫描兜底。两者都只是小问题。正文滞后是唯一希望作者修的点,随时可以补,不扣代码。

批准,锚定在被审 commit。本 PR 上残留的 CHANGES_REQUESTED 状态分别是我早前的模板拦截(正文已修复)和第一轮 review 的发现(当前 head 已解决)——本次批准取代两者。

Qwen Code · qwen3.8-max

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

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM, looks ready to ship. ✅

@wenshao
wenshao enabled auto-merge August 7, 2026 16:10

@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 P0/P1/P2 — an unusually well-hardened privilege-boundary bridge; findings are P3 defense-in-depth only. Security verified with evidence: (1) no escalation — the bridge's only write is dispatching qwen-autofix.yml with one re-validated pr_number, and review-scan's forced-fork admission requires the fork AUTHOR to hold live admin/maintain/write, so a malicious fork author can never get their code touched and anyone who can trigger this already has equivalent power (manual dispatch exists); (2) signal authenticity rides the signal run's run-name, which GitHub evaluates from the base-branch workflow file (a fork can't edit/forge it), parsed with an anchored regex + live permission re-check + live PR re-read, with no artifact channel (tests pin upload/download out); (3) fork code running with secrets is the pre-existing review-address lane's documented limit (docker sandbox, live write+ authors only), not broadened here, and the two new workflows are clean (minimal permissions, zero checkout, zero secrets expressions, brace-aware scanner pin); (4) concurrency handled (trust-split signal groups, conclusion+head keying, route refuses public source buying shared-group/cancel rights, per-PR head-write lock). P3s: REVIEW_BOT exemption from the live write re-check (document the dependency); assert workflow_run.event=='pull_request_review' in the bridge if:; include display_title in the concurrency group for per-PR isolation; raise --limit 20 provenance window for bursts; distinguish lookup-failure from low-permission in the log.

@wenshao
wenshao added this pull request to the merge queue Aug 7, 2026
Merged via the queue into main with commit 20b9504 Aug 7, 2026
148 checks passed
@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Sandboxed verification: ⚠️ not run — skipped - workflow run

Skipped because the PR is not open for verification (state=MERGED, draft=false).

中文 — 判定:⚠️ 未运行 · 已跳过

跳过原因:the PR is not open for verification (state=MERGED, draft=false)。

Qwen Code · sandboxed verification

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Released in v0.21.8.

pull Bot pushed a commit to Stars1233/qwen-code that referenced this pull request Aug 22, 2026
…wenLM#9469)

* fix(ci): gate the fork signal on fields the review payload delivers

`qwen-autofix-fork-signal.yml` gated on
`github.event.pull_request.maintainer_can_modify == true`. That field does
not exist in a `pull_request_review` payload: the event carries the SIMPLE
pull-request object, and `maintainer_can_modify` — like `mergeable`,
`additions`, and `changed_files` — ships only on the full object the
`pull_request` event sends. The expression evaluated to null on every
delivery, `null == true` is false, and the job's `if` could never hold.

Measured on the repository: across the 300 runs between the bridge shipping
(QwenLM#8676, 2026-08-07) and this change, 290 skipped, 7 cancelled, 1
action_required, and 0 success. Not one signal ever reached its step, so the
bridge behind it has never fired either — every fork-PR review has been
served by the scheduled scan alone, which is exactly the throttled backstop
this bridge exists to get ahead of.

The consent check is not lost, and does not move: the bridge already re-reads
it live (`gh pr view --json maintainerCanModify`, then
`select(… .maintainerCanModify == true)`), and that read was always the
authoritative one — consent can be withdrawn between the review and the
dispatch, so a payload copy could only ever have been a stale early-out. The
signal job cannot make that call itself: it holds `permissions: {}`, no
secrets and no checkout, deliberately, because it runs on a fork-triggered
event.

What the removal does cost is one signal + bridge run and one PR read for a
takeover-labeled fork PR whose author has turned maintainer edits off, where
the gate previously intended to spend nothing. Ordinary contributor fork PRs
are unaffected — the bot-authored-or-takeover-labeled conjunct still excludes
them.

Also adds a regression test asserting the gate references no full-object-only
field. A gate like this fails silently: the job's entire body is one echo, so
"never opens" and "no fork review happened to qualify" look identical from
outside, which is why this went twelve days unnoticed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* test(ci): match the full-object-only guard on a word boundary (R1-1)

The guard asserted the signal gate references no full-object-only field via
bare substring containment, but four deny-list entries are strict prefixes of
fields the simple pull-request object DOES deliver: `merged` in `merged_at`,
`commits` in `commits_url`, `comments` in `comments_url`, `review_comments` in
`review_comments_url`. A future edit adding a legal conjunct such as
`github.event.pull_request.merged_at == null` would turn the suite red with a
message blaming a full-object-only field — pushing the author to drop the
conjunct or weaken the guard itself.

Anchor each check on a word boundary, and add a test that pins the matcher's
discrimination on all four prefix pairs so the substring form cannot come back
unnoticed.

* test(ci): see full-object fields through the index operator (R2-1)

The full-object-only guard matched `pull_request.<field>` literally, so it
only saw the `.` property de-reference. GitHub Actions reaches the same
property through the documented `[ ]` index operator, on any segment of the
path, and `github.event.pull_request['maintainer_can_modify'] == true`
evaluates exactly as the dot form did: the field is absent from the simple
`pull_request_review` payload, `null == true` is false, and the gate never
opens. The guard stayed green through it — a silent replay of the incident
this PR fixes, invisible to the test written to catch it.

Rewrite the index form to the dot form before matching rather than
enumerating spellings, so one matcher covers every combination of the two at
any depth. The word-boundary anchor from R1-1 is unchanged, so the four
delivered fields the deny-list names prefix (`merged_at`, `commits_url`,
`comments_url`, `review_comments_url`) still pass in every spelling.

A `fromJSON(toJSON(github.event.pull_request))` round-trip still evades this;
no textual guard catches that one, and the comment says so.

Mutation-verified, each mutant reddening the tests that pin it:

| mutant | result |
|---|---|
| normalization removed (identity) | 2 failed — bracket and mixed spellings go unseen |
| word boundary dropped | 1 failed — `merged_at` rejected as `merged` |

`npx vitest run --config ./scripts/tests/vitest.config.ts
scripts/tests/qwen-autofix-fork-bridge-workflow.test.js` -> 12 passed (12).
eslint and prettier clean.

* test(ci): pin the fork-signal guard's bracket-whitespace tolerance

R3-1: `asDotAccess` rewrites `pull_request['field']` to the dot form before
matching, and its regex deliberately tolerates whitespace inside the index
(`\[\s*…\s*\]`) because GitHub Actions accepts
`github.event.pull_request[ 'maintainer_can_modify' ]` as a legal expression.
No spelling in `referenceSpellings` carried that whitespace, so the tolerance
was unpinned: deleting both `\s*` left all 12 tests green, and a later gate
edit written in the spaced form would have reached the same absent field and
restored the always-false gate this PR fixes.

Add the spaced-bracket spelling, which both index-operator tests consume.

Mutation-verified: with the two `\s*` deleted from `asDotAccess`, this file
now fails 2 tests ("rejects a full-object field without rejecting the fields
it prefixes" and "sees a full-object field through the index operator");
before this commit the same mutation left 12 passed.

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.

4 participants