Skip to content

fix(ci): stop the fallback comment from denying a review it already posted - #9462

Merged
wenshao merged 10 commits into
mainfrom
fix/review-fallback-false-failure
Aug 20, 2026
Merged

fix(ci): stop the fallback comment from denying a review it already posted#9462
wenshao merged 10 commits into
mainfrom
fix/review-fallback-false-failure

Conversation

@wenshao

@wenshao wenshao commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator

What this PR does

Stops both /review fallback-comment sites from announcing a review that the same run had already posted. The review job can fail after the post — the CLI exiting silently, a cleanup step dying — and the fallback body's claim ("The review pipeline failed before a review could be posted") then contradicts the review sitting directly above it, with a retry instruction attached. Before composing a body, each site now asks whether a review this run posted is already on the PR, and stays silent when the answer is yes.

The check is scoped three ways so a stale review can never buy silence on a genuinely dead pipeline: the bot's own account, the head this run reviewed, and a submission at or after this run started. Where that proof is unavailable — no start time, no head, a failed listing — the guard declines to fire and the comment posts, which is the same call the existing head-moved guard makes when its comparison is unavailable. The job-level step also now reads state and headRefOid in one gh pr view (the in-job step already did), which is where its head value comes from.

Why it's needed

Measured on PR #9342, run 32119559927: the review posted at 11:56:34Z; review-pr failed at 12:00:53Z with Transient review failure (Qwen review completed but produced no output.); the fallback comment landed at 12:01:00Z telling the reader the pipeline "failed before a review could be posted … retry with @qwen-code /review" — a fresh ~3-hour review, asked for beside the review that had just landed.

The cost is not only a confusing pair of messages. The autofix takeover loop reads the same feed a human does, and on that PR the red check drove it to merge main and re-run the full CI. A reviewer who trusts the comment spends another review cycle; a reader who trusts the review wonders which of the two to believe. It is the same defect class this review pipeline keeps paying down: prose asserting the opposite of the evidence beside it.

This PR fixes the false claim. It deliberately does not touch the underlying classification — a run that posts its review and then exits without stdout is still a red check — because that decision (does a posted review make the run a success?) deserves its own change; the empty-output classifier cannot currently tell "died" from "posted, then went quiet", and I have no reproduction of the second attempt's silence yet.

Reviewer Test Plan

How to verify

npx vitest run scripts/tests/qwen-pr-review-workflow.test.js — 165 pass. Eight new tests execute the steps' real bash (extracted from the YAML) against a stub gh that applies the step's own --jq filter to review fixtures, because the guard is that filter:

  • {fallback job,in-job step} stays silent when THIS run already posted its review — the incident shape; asserts no comment and the skip line in the step summary.
  • … still posts when no review can be attributed to this run — each near-miss on its own: an earlier run's review at the same head, another account's review, a review of a different head, a PENDING (unsubmitted) one, and none at all.
  • … posts when this run's start time is unavailable and … posts when the reviews lookup itself fails — the fail-open direction, so a lookup failure never reads as "a review exists".

One pre-existing assertion was tightened rather than deleted: expect(r.calls).not.toContain('run view') was the proxy for "no head comparison on comment runs", and the new guard asks that same command for startedAt on every event; it now pins the head lookups (headSha, --json headRefOid) themselves. The stub's state,headRefOid branch also learned the pr_closed scenario its state-only sibling already knew — without that, the job-level step's new combined read always saw OPEN.

Local failures unrelated to this change (verified by re-running the same tests on a pristine tree): repairs a single unwritable directory instead of failing fast in this file, and 5 tests in scripts/tests/qwen-autofix-workflow.test.js. scripts/tests/{qwen-resolve-workflow,review-worktree-cleanup-workflow,serve-ab-workflow}.test.js are green (42 pass).

Evidence (Before & After)

N/A — CI-only change, no user-visible surface. The observable behavior is the presence or absence of a bot comment, which the tests above assert directly.

Tested on

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

Risk & Scope

  • Main risk or tradeoff: the guard trades a small amount of noise for silence in one shape — a run that posted its review and then died is no longer announced. That is the intent, and the run's own red check still says the job failed; nothing about the failure becomes invisible, only the sentence that described it wrongly. The opposite risk — silencing a genuinely dead pipeline — is bounded by scoping the check to the bot's own account, the head this run reviewed, and a submission at or after this run started, with each of those clauses pinned by its own test.
  • Not validated / out of scope: the underlying classification is untouched. A run that posts its review and then exits without stdout is still a red check, and on PR fix(review): clear the deferred-suggestion backlog from #9175's review rounds #9342 that red check is what drove the autofix loop to merge main and re-run CI — so this PR removes the false sentence and the retry instruction, not the wasted re-run. Making a posted review count toward the run's outcome needs the empty-output classifier to tell "died" from "posted, then went quiet", which I have no reproduction for yet (the second attempt's 3-minute silence on that run is unexplained; the suspicion is the incremental anchor's same-sha stop, unproven). Also unvalidated here: real GitHub API behavior — the tests drive the steps' real bash against a stub gh, which is how every other executable test in this file works.
  • Breaking changes / migration notes: none. No workflow inputs, outputs, secrets or permissions change; the only behavior change is one additional skip condition on two comment-posting steps.

Linked Issues

中文说明

这个 PR 做什么:让 /review 的两个兜底评论站点不再宣称「未能发布 review」——而实际上同一次运行早已发布过。review 作业可能在发布之后才失败(CLI 静默退出、清理步骤挂掉),此时兜底正文的断言与其正上方的 review 自相矛盾,还附带重试指引。现在两处在组装正文前先检查:本次运行是否已在该 PR 上发布过 review;是则静默。

检查按三个维度收窄,使陈旧 review 无法为「真正死掉的流水线」买到静默:bot 自己的账号、本次运行所审的 head、以及提交时间不早于本次运行开始。当证据不可得(无开始时间、无 head、查询失败)时守卫不触发、照常发帖——与既有 head-moved 守卫在比较不可得时的选择一致。

为什么需要:实测于 PR #9342(run 32119559927):11:56:34Z review 已发布 → 12:00:53Z 作业失败(Qwen review completed but produced no output.)→ 12:01:00Z 兜底评论称「failed before a review could be posted……retry with @qwen-code /review」,在刚落地的 review 旁边索要一次约 3 小时的重跑。代价不止是自相矛盾的两条消息:autofix takeover 循环与人读同一个信息流,在该 PR 上红检查驱动它合并 main 并重跑了整轮 CI。这与本流水线反复偿还的是同一类缺陷:散文断言与其旁边的证据相反。

本 PR 只修这条虚假断言,刻意不动底层分类(发布后无 stdout 仍是红检查)——「已发布 review 是否应让该次运行判为成功」值得单独一个改动;当前的空输出判定分不清「进程死了」与「发完就没声了」,且我尚无第二次尝试静默的复现。

验证npx vitest run scripts/tests/qwen-pr-review-workflow.test.js —— 165 通过。新增 8 个测试直接执行从 YAML 抽出的真实 bash,用桩 gh 对 review 夹具套用步骤自己的 --jq 过滤器(守卫本身就是那个过滤器):事故形态静默;四种近似情形(同 head 的旧 review、他人账号、不同 head、PENDING)与无 review 时照常发帖;开始时间不可得、reviews 查询失败时同样发帖。一条既有断言被收紧而非删除(not.toContain('run view') 原是「评论型运行不做 head 比较」的代理,新守卫在所有事件上都会用同一命令问 startedAt,故改为直接钉 head 查询)。桩里的 state,headRefOid 分支补上了它 state 兄弟早已有的 pr_closed 场景。本机既有失败(原始树复现,与本改动无关):本文件的 repairs a single unwritable directory,以及 qwen-autofix-workflow.test.js 的 5 条。

风险与范围:主要权衡是这个守卫在一种形态下用少量「沉默」换掉错误陈述——「发布了 review 然后死掉」的运行不再被播报;这正是意图所在,而该运行自己的红色检查仍在说作业失败,失败并未变得不可见,只是那句描述错误的话没有了。反方向的风险(让真正死掉的流水线沉默)被三个维度的收窄限制住,且每个子句都有各自的钉住测试。未验证/超出范围:底层分类未动——发布后无 stdout 仍是红检查;在 #9342 上正是这个红检查驱动 autofix 合并 main 并重跑 CI,所以本 PR 去掉的是那句虚假断言与重试指引,而不是那次浪费的重跑。要让「已发布 review」计入运行结果,需要空输出判定能区分「进程死了」与「发完就没声了」,我尚无复现(该运行第二次尝试的三分钟静默原因不明,怀疑是增量锚点的 same-sha 停轮,未证实)。此外未验证的是真实 GitHub API 行为——测试以桩 gh 驱动步骤的真实 bash,这与该文件中其他可执行测试的做法一致。破坏性变更:无;不涉及 workflow 的输入、输出、secrets 或权限,唯一行为变化是给两个发帖步骤各加一个跳过条件。

关联#9342(本次误报的实测现场)、#9255(引入本 PR 所加固的兜底作业)、以及本测试套件命名所源自的 PR #8894 incident class

…osted

The review job can fail AFTER posting its review — the CLI exiting
silently, a cleanup step dying — and both fallback sites then announce
that review as one that could not be posted, retry instruction attached.
Measured on PR #9342: the review posted at 11:56:34Z, review-pr failed
at 12:00:53Z ("Qwen review completed but produced no output"), and the
comment landed at 12:01:00Z saying the pipeline "failed before a review
could be posted. … retry with @qwen-code /review" — a fresh ~3-hour
review, asked for beside the review that had just landed. The autofix
takeover loop reads the same feed a human does.

Both sites now check, before composing a body, whether a review this run
posted is already on the PR. The check is scoped three ways so a stale
review can never buy silence on a genuinely dead pipeline: the bot's own
account, the head this run reviewed, and a submission at or after this
run started. Where the proof is unavailable — no start time, no head, a
failed listing — the guard declines to fire and the comment posts, the
same call the head-moved guard already makes.

The job-level step now reads state and headRefOid in one `gh pr view`
(the in-job step already did), which is where its head value comes from.

Tests run the steps' real bash over review fixtures, because the guard
IS a filter: silence when this run posted the review, and posting for
each near-miss on its own — an earlier run's review at the same head,
another account's, one of a different head, a PENDING one, none at all,
an unavailable start time, and a failed reviews listing. One existing
assertion tightened: "no `gh run view`" was the proxy for "no head
comparison on comment runs", and the new guard asks that same command
for startedAt on every event, so it now pins the head lookups
themselves. The stub's state,headRefOid branch learned the pr_closed
scenario its state-only sibling already knew.
@qwen-code-ci-bot

qwen-code-ci-bot commented Aug 19, 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 Thanks for the PR — the incident write-up (timestamps from #9342, run link, the autofix-loop consequence) is exactly the kind of evidence a reviewer wants. Before this can move to code review, the PR body is missing two required sections from the PR template:

  • ## Risk & Scope — main risk or tradeoff, what is not validated / out of scope, breaking changes. Much of this is already argued in the prose (e.g. the deliberate decision not to touch the failure classification, the fail-open direction of the guard), so filling the section should just be a matter of lifting those sentences into it.
  • ## Linked Issues — no closing keyword is needed here, but the related work (#9342, the #8894 incident class this test suite is named after) belongs in this section rather than only inline in the prose.

Everything else checks out: What / Why / Reviewer Test Plan (How to verify, Evidence, Tested on) and the bilingual summary are all present. Once the two sections are added, re-trigger with @qwen-code /triage and the gate will continue from here.

中文说明

@wenshao 感谢提交——事故描述(#9342 的时间线、run 链接、autofix 循环被误导的后果)正是 reviewer 需要的证据。但在进入代码审查之前,PR 正文缺少模板中的两个必填章节:

  • ## Risk & Scope(风险与范围)——主要风险或权衡、未验证/超出范围的部分、破坏性变更。正文中其实已经论述了大部分内容(例如刻意不动底层失败分类、守卫在证据不可得时选择照常发帖),补这一节基本只是把相关句子挪进来。
  • ## Linked Issues(关联 Issue)——这里不需要自动关闭关键字,但相关工作(#9342、本测试套件命名所来自的 #8894 事故类别)应放在这个章节里,而不仅散落在正文中。

其余部分都完整:What / Why / Reviewer Test Plan(验证方式、证据、测试平台)以及中文总结均已提供。补上这两个章节后使用 @qwen-code /triage 重新触发,审查会从这一步继续。

Qwen Code · qwen3.8-max

@wenshao

wenshao commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /triage

Both sections are added: ## Risk & Scope (the tradeoff, the explicitly out-of-scope failure classification with why it needs its own change, and no breaking changes) and ## Linked Issues (#9342, #9255, and the #8894 incident class). The Chinese summary mirrors both.

两节已补齐:## Risk & Scope(权衡、刻意排除的失败分类及其原因、无破坏性变更)与 ## Linked Issues#9342#9255#8894 事故类别),中文说明同步镜像。

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Sandboxed verification: ⚠️ incomplete — infrastructure failure - workflow run

The verification job did not complete (checkout, runner, or setup error) and produced no report. See the workflow run for details.

中文 — 判定:⚠️ 未完成 · 基础设施故障

验证作业未完成(检出、runner 或初始化错误),未生成报告。详见工作流运行日志。

Qwen Code · sandboxed verification

@github-actions

github-actions Bot commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Summary

Package Lines Statements Functions Branches
CLI 84.94% 84.94% 90.23% 84%
Core 88.18% 88.18% 89.72% 86.73%
CLI Package - Full Text Report
-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |   84.94 |       84 |   90.23 |   84.94 |                   
 src               |   85.83 |    81.72 |   88.13 |   85.83 |                   
  cli.ts           |   95.68 |    84.11 |     100 |   95.68 | ...60-561,565-566 
  gemini.tsx       |    73.4 |    78.04 |   80.76 |    73.4 | ...1338-1342,1469 
  ...ractiveCli.ts |   88.25 |    82.33 |   89.06 |   88.25 | ...3147,3153,3219 
  ...liCommands.ts |   88.93 |    83.21 |      80 |   88.93 | ...97-599,615,721 
  ...ActiveAuth.ts |     100 |     87.5 |     100 |     100 | 66-80             
 ...cp-integration |   72.42 |    75.07 |   91.83 |   72.42 |                   
  acpAgent.ts      |   71.58 |    74.67 |   91.16 |   71.58 | ...44,13049-13051 
  ...k-reporter.ts |     100 |       80 |     100 |     100 | 81,84,119,141     
  authMethods.ts   |      92 |       60 |     100 |      92 | 33-34             
  ...heap-probe.ts |   97.39 |    96.66 |     100 |   97.39 | 243,264-265       
  errorCodes.ts    |     100 |      100 |     100 |     100 |                   
  ...ion-skills.ts |     100 |    88.23 |     100 |     100 | 17,32             
  generation.ts    |    97.1 |    81.25 |     100 |    97.1 | 109,112           
  ...figuration.ts |     100 |      100 |     100 |     100 |                   
  ...DirContext.ts |     100 |      100 |     100 |     100 |                   
 ...ration/service |    97.1 |    95.83 |   93.33 |    97.1 |                   
  filesystem.ts    |    97.1 |    95.83 |   93.33 |    97.1 | ...22-123,246-247 
 ...ration/session |   91.23 |    86.47 |   95.93 |   91.23 |                   
  Session.ts       |    90.6 |    85.16 |   95.38 |    90.6 | ...89,12216-12220 
  ...entTracker.ts |   96.81 |    89.36 |      90 |   96.81 | 137-143,222       
  ...projection.ts |   98.85 |    91.59 |     100 |   98.85 | 234,250,262       
  ...stop-guard.ts |     100 |    98.07 |     100 |     100 | 37,127            
  ...eplay-page.ts |   94.18 |     86.2 |     100 |   94.18 | ...15,319,399,403 
  ...y-replayer.ts |   83.17 |    92.98 |   94.11 |   83.17 | ...24-142,260-262 
  index.ts         |       0 |        0 |       0 |       0 | 1-40              
  ...ssionUtils.ts |   89.76 |    87.32 |     100 |   89.76 | ...54-270,326-328 
  ...oal-update.ts |   98.61 |    97.29 |     100 |   98.61 | 64                
  ...lure-guard.ts |   98.32 |    97.72 |     100 |   98.32 | 294-295,340-341   
  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.62 |    92.69 |   96.96 |   95.62 |                   
  ...ageEmitter.ts |   95.25 |    93.54 |     100 |   95.25 | ...08-115,128-129 
  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 |   98.57 |    94.84 |     100 |   98.57 | 75-76,394-395     
 ...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 |    81.54 |   91.44 |      89 |                   
  attach-lease.ts  |     100 |    96.96 |     100 |     100 | 173               
  ...t-cli-argv.ts |     100 |      100 |     100 |     100 |                   
  ...ged-detach.ts |     100 |     90.9 |     100 |     100 | 40,64             
  protocol.ts      |     100 |      100 |     100 |     100 |                   
  pty-host-env.ts  |     100 |      100 |     100 |     100 |                   
  ...st-process.ts |   87.99 |    77.53 |    94.2 |   87.99 | ...1219,1309-1311 
  pty-host.ts      |   84.51 |     84.9 |   90.47 |   84.51 | ...14-516,531-532 
  ...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.54 |   83.33 |   93.98 | 228-238           
  ...r-sideband.ts |   95.37 |    86.44 |     100 |   95.37 | 203-204,228-233   
 src/commands      |   90.36 |    77.48 |   65.62 |   90.36 |                   
  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.82 |      100 |      50 |   98.82 | 96                
  serve.ts         |   88.95 |    74.52 |     100 |   88.95 | ...74,877-880,892 
  sessions.ts      |     100 |      100 |      50 |     100 |                   
  update.ts        |   98.13 |    94.44 |   66.66 |   98.13 | 82-83             
 ...mmands/channel |   89.08 |    88.57 |   90.64 |   89.08 |                   
  channel-cwd.ts   |     100 |      100 |     100 |     100 |                   
  ...l-registry.ts |   94.88 |    95.49 |      90 |   94.88 | ...20-323,368-371 
  ...entry-path.ts |      75 |       50 |     100 |      75 | 8-9               
  config-utils.ts  |   95.88 |    96.35 |     100 |   95.88 | ...08-213,271-274 
  configure.ts     |    14.7 |      100 |       0 |    14.7 | 18-21,23-84       
  daemon-worker.ts |   93.91 |    85.61 |   94.33 |   93.91 | ...1264,1271-1272 
  loop-runtime.ts  |   91.66 |      100 |      50 |   91.66 | 15,22             
  ...classifier.ts |   98.53 |    96.66 |     100 |   98.53 | 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.85 |    87.91 |   87.09 |   88.85 |                   
  consent.ts       |   72.53 |    90.32 |   42.85 |   72.53 | ...86-142,157-163 
  disable.ts       |     100 |       90 |     100 |     100 | 30                
  enable.ts        |     100 |    91.66 |     100 |     100 | 38                
  install.ts       |   82.95 |    81.57 |      75 |   82.95 | ...96-199,202-211 
  link.ts          |     100 |      100 |     100 |     100 |                   
  list.ts          |     100 |     90.9 |     100 |     100 | 18                
  new.ts           |     100 |      100 |     100 |     100 |                   
  settings.ts      |   99.15 |      100 |   83.33 |   99.15 | 151               
  sources.ts       |   93.42 |    87.09 |   92.85 |   93.42 | ...4-66,96-98,167 
  uninstall.ts     |   74.57 |       40 |   66.66 |   74.57 | 45-47,60-67,70-73 
  update.ts        |   96.71 |    97.05 |     100 |   96.71 | 114-118           
  utils.ts         |   75.63 |    57.14 |     100 |   75.63 | ...30-134,136-140 
 ...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.31 |    84.61 |   83.33 |   90.31 |                   
  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          |   93.15 |    84.84 |      80 |   93.15 | ...78-180,198-199 
  reconnect.ts     |   78.85 |    66.66 |   85.71 |   78.85 | 42-55,169-191     
  remove.ts        |     100 |       80 |     100 |     100 | 21-25             
 ...ommands/review |   90.19 |    89.64 |   90.53 |   90.19 |                   
  agent-prompt.ts  |   94.22 |    92.93 |   97.56 |   94.22 | ...1964,2993-3073 
  base-tree.ts     |   76.16 |    80.76 |   77.77 |   76.16 | ...50-371,373-386 
  capture-local.ts |      70 |     90.9 |      75 |      70 | 112-116,163-194   
  ...k-coverage.ts |   50.71 |       35 |   66.66 |   50.71 | ...40-245,279-289 
  cleanup.ts       |   92.79 |     88.7 |   84.61 |   92.79 | ...43-648,650-651 
  comment-body.ts  |   67.85 |    87.09 |   66.66 |   67.85 | ...30,157,159-164 
  ...ent-status.ts |   93.19 |    84.61 |   83.33 |   93.19 | 302,442,573-593   
  ...ose-review.ts |   96.79 |     93.2 |   98.07 |   96.79 | ...4150-4194,4434 
  cost-ledger.ts   |   94.58 |     94.4 |   81.25 |   94.58 | ...53-654,694-704 
  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-diff.ts    |   73.75 |      100 |   66.66 |   73.75 | 77-97             
  fetch-pr.ts      |   97.06 |    92.45 |      96 |   97.06 | ...1655,1713-1718 
  issue-context.ts |   88.15 |     93.1 |   85.71 |   88.15 | 249-276           
  load-rules.ts    |   26.41 |      100 |   16.66 |   26.41 | ...41-153,155-156 
  match-remote.ts  |   85.55 |     92.3 |   66.66 |   85.55 | 74-79,144-150     
  meta.ts          |   79.43 |    93.75 |   66.66 |   79.43 | 123-128,147-162   
  mock-provider.ts |   95.44 |    90.25 |   89.47 |   95.44 | 145,690-709       
  parse-args.ts    |   99.48 |    95.65 |     100 |   99.48 | 553,824,880       
  plan-diff.ts     |    68.1 |      100 |   66.66 |    68.1 | 162-205           
  pr-context.ts    |   95.44 |    86.15 |     100 |   95.44 | ...1729,1818-1834 
  presubmit.ts     |   90.52 |    88.82 |      90 |   90.52 | ...74-775,861-891 
  ...ish-assets.ts |    81.3 |    82.22 |   85.71 |    81.3 | ...79-483,510-556 
  ...r-findings.ts |   90.74 |    83.75 |     100 |   90.74 | ...17-422,429-430 
  repo-context.ts  |   94.62 |    90.75 |     100 |   94.62 | ...66-467,482-487 
  ...ve-anchors.ts |   78.34 |    89.28 |      75 |   78.34 | ...83-188,200-217 
  run.ts           |   82.66 |    88.54 |   94.11 |   82.66 | ...19,635-689,703 
  save-artifact.ts |   91.92 |    87.77 |   93.75 |   91.92 | ...06-409,502-505 
  script-lint.ts   |   81.27 |    79.38 |   88.88 |   81.27 | ...69-783,785-807 
  submit.ts        |   88.56 |    87.87 |      90 |   88.56 | ...08,850,878-914 
  test-delta.ts    |    86.4 |       92 |      60 |    86.4 | 177-208,471-479   
  test-efficacy.ts |   88.04 |    84.12 |   95.45 |   88.04 | ...2602,2610-2630 
  test-plan.ts     |   91.36 |    91.35 |   89.47 |   91.36 | ...35-836,900-917 
 ...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 |   98.05 |    95.57 |   98.79 |   98.05 |                   
  agent-briefs.ts  |      99 |      100 |      50 |      99 | 757-758           
  ...t-identity.ts |     100 |      100 |     100 |     100 |                   
  anchors.ts       |     100 |    96.42 |     100 |     100 | ...39,175,184,231 
  assets.ts        |     100 |      100 |     100 |     100 |                   
  audit-layers.ts  |   98.67 |    96.15 |     100 |   98.67 | 288-290           
  authorization.ts |   93.36 |    94.39 |     100 |   93.36 | ...14-320,490-491 
  budget.ts        |     100 |    97.97 |     100 |     100 | 887,940           
  build-budget.ts  |     100 |      100 |     100 |     100 |                   
  certification.ts |     100 |      100 |     100 |     100 |                   
  coverage.ts      |   98.71 |    94.77 |     100 |   98.71 | ...1097,1642-1643 
  deadline.ts      |   98.03 |    91.73 |     100 |   98.03 | ...20,752,820,837 
  diff-flags.ts    |     100 |        0 |     100 |     100 | 75                
  diff-plan.ts     |   98.73 |    93.04 |     100 |   98.73 | ...41,264,290-291 
  disk.ts          |     100 |      100 |     100 |     100 |                   
  effort.ts        |     100 |      100 |     100 |     100 |                   
  failing-files.ts |     100 |    93.33 |     100 |     100 | 41                
  gh.ts            |   89.09 |    95.38 |   77.77 |   89.09 | ...29,366-367,394 
  git.ts           |   97.84 |    96.15 |     100 |   97.84 | 207-208           
  heavy.ts         |     100 |      100 |     100 |     100 |                   
  inline-counts.ts |     100 |      100 |     100 |     100 |                   
  ...audit-gate.ts |     100 |     97.5 |     100 |     100 | 135               
  ledger.ts        |     100 |      100 |     100 |     100 |                   
  local-diff.ts    |   84.86 |    90.38 |     100 |   84.86 | ...63-473,475-483 
  ...ry-context.ts |   96.61 |    95.48 |     100 |   96.61 | ...47-450,496-499 
  merge-base.ts    |     100 |      100 |     100 |     100 |                   
  npm-toolchain.ts |   98.23 |    95.29 |     100 |   98.23 | ...,819,1200,1217 
  path-rules.ts    |     100 |      100 |     100 |     100 |                   
  paths.ts         |   90.47 |    78.57 |     100 |   90.47 | 32-33,36-37       
  prompt-record.ts |   98.03 |    94.23 |     100 |   98.03 | 293-294,300       
  receipt.ts       |     100 |      100 |     100 |     100 |                   
  remote-match.ts  |   97.84 |    94.23 |     100 |   97.84 | 85-86             
  report.ts        |   92.85 |    86.66 |     100 |   92.85 | 204-205,207-211   
  ...ry-context.ts |     100 |    98.66 |     100 |     100 | 187               
  resume.ts        |     100 |      100 |     100 |     100 |                   
  retirement.ts    |     100 |    94.36 |     100 |     100 | ...58-559,760,917 
  review-footer.ts |   99.55 |     98.1 |     100 |   99.55 | 548-549           
  ...w-settings.ts |     100 |    94.73 |     100 |     100 | 79                
  roster.ts        |     100 |    95.52 |     100 |     100 | 136,154,199       
  round-model.ts   |     100 |      100 |     100 |     100 |                   
  run-ledger.ts    |    98.2 |    93.87 |     100 |    98.2 | ...23,541,647,670 
  same-file.ts     |     100 |    94.11 |     100 |     100 | 35                
  shell-quote.ts   |     100 |      100 |     100 |     100 |                   
  stale-bundle.ts  |   98.21 |    94.11 |     100 |   98.21 | 433,474,514-515   
  test-utils.ts    |     100 |      100 |     100 |     100 |                   
  toolchain.ts     |     100 |      100 |     100 |     100 |                   
  transcripts.ts   |   98.05 |    95.03 |     100 |   98.05 | ...67,415,684-685 
  ...pace-scope.ts |     100 |    96.96 |     100 |     100 | 186               
  workspaces.ts    |     100 |    96.77 |     100 |     100 | 222,452,499,512   
  worktree.ts      |     100 |      100 |     100 |     100 |                   
 ...w/lib/platform |   76.52 |    80.57 |   78.37 |   76.52 |                   
  aone-client.ts   |   14.28 |      100 |       0 |   14.28 | ...7,82-83,91-127 
  aone.ts          |   80.33 |    78.48 |   81.25 |   80.33 | ...17,481-486,538 
  github.ts        |   96.05 |    75.67 |     100 |   96.05 | 26-29,213-214     
  registry.ts      |     100 |    95.65 |     100 |     100 | 84                
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...mands/sessions |   94.11 |    89.06 |   89.47 |   94.11 |                   
  common.ts        |     100 |      100 |     100 |     100 |                   
  list.ts          |   90.96 |    86.66 |   81.81 |   90.96 | 208-219,221-222   
  ps.ts            |     100 |    94.44 |     100 |     100 | 58                
 src/config        |   94.95 |    89.87 |   96.28 |   94.95 |                   
  ...l-fallback.ts |     100 |      100 |     100 |     100 |                   
  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        |   89.12 |    88.69 |   83.78 |   89.12 | ...2497,2499-2507 
  ...cy-monitor.ts |      90 |    77.27 |     100 |      90 | ...72-73,90-92,98 
  ...ust-policy.ts |   83.02 |    88.88 |     100 |   83.02 | ...02-209,232-240 
  ...heme-names.ts |     100 |      100 |     100 |     100 |                   
  environment.ts   |    96.5 |    93.51 |      95 |    96.5 | ...85-586,640-641 
  ...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.4 |       50 |     100 |    97.4 | 240-243           
  ...ngsAdapter.ts |     100 |    94.11 |     100 |     100 | 64                
  ...ig-watcher.ts |   95.17 |    83.05 |     100 |   95.17 | ...78,200,292-293 
  ...er-secrets.ts |   98.97 |    96.96 |     100 |   98.97 | 85                
  mcpApprovals.ts  |   96.55 |    95.55 |     100 |   96.55 | 223-224,229-231   
  mcpJson.ts       |     100 |      100 |     100 |     100 |                   
  mcpServers.ts    |   92.85 |     87.5 |     100 |   92.85 | 46-47             
  ...idersScope.ts |      95 |    94.73 |     100 |      95 | 11-12             
  ...abledTools.ts |     100 |      100 |     100 |     100 |                   
  ...comparison.ts |     100 |      100 |     100 |     100 |                   
  ...n-settings.ts |   99.15 |    93.75 |     100 |   99.15 | 63                
  sandboxConfig.ts |   93.33 |    93.33 |     100 |   93.33 | ...42-147,216-217 
  session-id.ts    |     100 |      100 |     100 |     100 |                   
  ...ings-cache.ts |   96.52 |    93.93 |     100 |   96.52 | 90-91,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 
  ...precedence.ts |   98.79 |     92.3 |     100 |   98.79 | 62                
  ...tedFolders.ts |   92.53 |    93.47 |     100 |   92.53 | ...36-337,373-384 
 ...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    |   75.08 |    67.64 |   71.42 |   75.08 |                   
  ...tputBridge.ts |   75.33 |    68.18 |   73.68 |   75.33 | ...09-410,418-421 
  ...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          |   86.22 |    81.92 |   89.65 |   86.22 |                   
  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.98 |    77.27 |   84.12 |   80.98 |                   
  session.ts       |   84.97 |    76.31 |   96.07 |   84.97 | ...1048,1057-1067 
  types.ts         |    42.5 |      100 |   33.33 |    42.5 | ...31-632,635-636 
 ...active/control |   75.54 |    89.83 |      80 |   75.54 |                   
  ...rolContext.ts |    6.06 |        0 |       0 |    6.06 | 57-99             
  ...Dispatcher.ts |   91.95 |    92.98 |   88.88 |   91.95 | ...54-372,392,395 
  ...rolService.ts |    6.89 |        0 |       0 |    6.89 | 46-188            
 ...ol/controllers |   45.95 |    69.03 |   55.26 |   45.95 |                   
  ...Controller.ts |    42.4 |      100 |   83.33 |    42.4 | 101-105,140-223   
  ...Controller.ts |       0 |        0 |       0 |       0 | 1-56              
  ...Controller.ts |   55.01 |    67.14 |   58.33 |   55.01 | ...15-624,639-644 
  ...Controller.ts |   49.23 |       60 |      50 |   49.23 | ...07-108,111-121 
  ...Controller.ts |   40.64 |    68.11 |   46.66 |   40.64 | ...72-684,693-722 
 .../control/types |       0 |        0 |       0 |       0 |                   
  serviceAPIs.ts   |       0 |        0 |       0 |       0 | 1                 
 ...Interactive/io |   98.16 |    94.22 |   95.29 |   98.16 |                   
  ...putAdapter.ts |   98.02 |     93.3 |   98.07 |   98.02 | ...1433,1449-1450 
  ...putAdapter.ts |   96.22 |    91.66 |   85.71 |   96.22 | 52-53             
  ...nputReader.ts |     100 |    94.73 |     100 |     100 | 67                
  ...putAdapter.ts |   98.51 |      100 |   90.47 |   98.51 | 90-91,131-132     
  ...projection.ts |     100 |      100 |     100 |     100 |                   
  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         |   88.18 |    84.74 |   90.81 |   88.18 |                   
  ...tp-enabled.ts |     100 |      100 |     100 |     100 |                   
  ...ion-bridge.ts |     100 |      100 |     100 |     100 |                   
  auth.ts          |   93.99 |    91.58 |     100 |   93.99 | ...29-430,433-435 
  ...em-adapter.ts |     100 |      100 |     100 |     100 |                   
  capabilities.ts  |     100 |    98.07 |     100 |     100 | 703               
  ...cp-command.ts |     100 |      100 |     100 |     100 |                   
  ...horization.ts |   92.79 |    93.54 |    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 |   89.64 |    94.11 |   96.29 |   89.64 | ...57-269,521-524 
  ...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 
  ...horization.ts |     100 |      100 |     100 |     100 |                   
  ...tartup-ipc.ts |   97.72 |    96.66 |     100 |   97.72 | 88-89             
  ...supervisor.ts |   92.54 |    84.53 |   97.14 |   92.54 | ...1489,1543-1547 
  ...e-grouping.ts |     100 |    94.28 |     100 |     100 | 71,137            
  core-runtime.ts  |     100 |      100 |     100 |     100 |                   
  ...ub-session.ts |    90.9 |     78.6 |   94.73 |    90.9 | ...1001,1022-1027 
  ...tree-guard.ts |   92.89 |    87.55 |     100 |   92.89 | ...2766,2836-2840 
  daemon-logger.ts |   82.82 |    78.68 |   92.04 |   82.82 | ...1775,1802-1808 
  ...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.69 |    91.94 |     100 |   98.69 | ...1590,1592-1593 
  debug-mode.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 |    87.09 |     100 |   92.06 | ...72,287-293,316 
  ...h-settings.ts |   94.94 |    90.41 |     100 |   94.94 | ...30,708,724,734 
  fast-path.ts     |   90.99 |    81.38 |   95.45 |   90.99 | ...33-542,608-609 
  ...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-149             
  ...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.68 |    88.29 |     100 |   92.68 | ...89-291,303-305 
  ...qwen-serve.ts |   83.99 |     80.9 |    75.9 |   83.99 | ...7923,7941-7945 
  ...tup-errors.ts |     100 |      100 |     100 |     100 |                   
  ...-keepalive.ts |   94.27 |    88.18 |     100 |   94.27 | ...34,538-539,578 
  ...-lifecycle.ts |     100 |      100 |     100 |     100 |                   
  ...-lifecycle.ts |   89.16 |    90.29 |   86.95 |   89.16 | ...24-325,330-334 
  server.ts        |   91.15 |     90.6 |   72.03 |   91.15 | ...2969,2999-3000 
  ...-admission.ts |   98.24 |    94.73 |     100 |   98.24 | 79-80,303-304     
  ...on-helpers.ts |     100 |      100 |     100 |     100 |                   
  ...-redaction.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.72 |    77.93 |     100 |   93.72 | ...51,854,867-869 
  ...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 |   94.98 |     90.5 |     100 |   94.98 | ...67-568,575-576 
  ...e-remember.ts |   98.23 |    92.56 |     100 |   98.23 | ...36,340-345,386 
  ...te-runtime.ts |    89.4 |    90.47 |     100 |    89.4 | ...89-190,258-279 
  ...me-storage.ts |     100 |      100 |     100 |     100 |                   
  ...visibility.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 |   79.65 |    79.91 |   94.09 |   79.65 |                   
  ...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 |   93.03 |    84.13 |   98.52 |   93.03 | ...1624,1671-1682 
  dispatch.ts      |   74.18 |    76.45 |   91.52 |   74.18 | ...5383,5440-5446 
  index.ts         |   82.68 |    79.74 |   91.22 |   82.68 | ...2424,2510-2511 
  json-rpc.ts      |     100 |    96.96 |     100 |     100 | 92                
  ...ach-budget.ts |     100 |      100 |     100 |     100 |                   
  safe-ws-send.ts  |   52.94 |    71.42 |     100 |   52.94 | 33-42,47-55       
  sse-stream.ts    |   98.26 |    88.75 |     100 |   98.26 | 87-88,117         
  ...ort-stream.ts |       0 |        0 |       0 |       0 | 1                 
  ws-stream.ts     |   94.06 |    89.09 |     100 |   94.06 | 50,55,134,138-141 
 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             
 .../conversations |   90.53 |    87.16 |   95.23 |   90.53 |                   
  ...e-activity.ts |     100 |      100 |     100 |     100 |                   
  ...ime-errors.ts |     100 |      100 |     100 |     100 |                   
  ...me-manager.ts |     100 |      100 |     100 |     100 |                   
  ...-ownership.ts |   87.33 |    83.33 |   88.46 |   87.33 | ...57-558,601-602 
  ...-workspace.ts |   88.26 |    82.53 |     100 |   88.26 | ...33-234,246-247 
  ...ion-source.ts |     100 |      100 |     100 |     100 |                   
 src/serve/fs      |   87.77 |    82.32 |     100 |   87.77 |                   
  audit.ts         |     100 |    96.29 |     100 |     100 | 211               
  errors.ts        |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...x-registry.ts |     100 |      100 |     100 |     100 |                   
  paths.ts         |   77.64 |    74.01 |     100 |   77.64 | ...65,594-598,611 
  policy.ts        |   90.52 |    89.18 |     100 |   90.52 | 172-180           
  text-cursor.ts   |   88.23 |       90 |     100 |   88.23 | 74-77,92-95       
  ...ile-system.ts |   88.02 |    81.83 |     100 |   88.02 | ...3027,3037-3038 
 src/serve/live    |   78.12 |    70.29 |   90.13 |   78.12 |                   
  ...en-context.ts |   95.74 |    81.25 |     100 |   95.74 | ...0,66-67,99-100 
  discovery.ts     |   85.89 |    81.91 |    90.9 |   85.89 | ...73-579,592-593 
  ...structions.ts |     100 |      100 |     100 |     100 |                   
  ...oordinator.ts |   82.67 |    76.63 |   97.01 |   82.67 | ...1319,1351-1353 
  ...-installer.ts |    64.3 |    82.35 |   80.76 |    64.3 | ...45-446,460-472 
  ...oordinator.ts |   76.69 |    67.47 |   85.71 |   76.69 | ...1884,1975-1976 
  ...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.68 |    62.11 |   93.33 |   86.68 | ...1176,1200-1207 
  ...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.85 |    77.39 |     100 |   94.85 | ...18,327-330,350 
  types.ts         |     100 |      100 |     100 |     100 |                   
 .../local-control |   82.89 |    86.13 |      90 |   82.89 |                   
  credentials.ts   |   96.42 |    95.45 |     100 |   96.42 | 109-110           
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...interfaces.ts |   43.58 |       75 |   42.85 |   43.58 | ...09-117,130-142 
  ...r-identity.ts |     100 |    85.71 |     100 |     100 | 61                
  service.ts       |    93.4 |       90 |     100 |    93.4 | ...20-222,313-315 
 src/serve/routes  |   85.72 |    80.61 |   94.85 |   85.72 |                   
  a2ui-action.ts   |   96.84 |     88.5 |    87.5 |   96.84 | ...70-272,309-311 
  capabilities.ts  |   98.73 |    96.15 |     100 |   98.73 | 82                
  ...nel-notify.ts |   79.16 |    85.18 |     100 |   79.16 | ...03-104,120-126 
  ...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 | 143               
  health.ts        |   99.09 |    91.17 |     100 |   99.09 | 147               
  live-setup.ts    |   33.33 |     37.5 |      50 |   33.33 | ...18-123,130-135 
  live.ts          |   84.61 |    76.47 |     100 |   84.61 | ...04,106-111,131 
  permission.ts    |     100 |     92.3 |     100 |     100 | 50,98             
  ...uled-tasks.ts |   87.53 |    84.26 |   93.33 |   87.53 | ...1389,1432-1433 
  ...on-runtime.ts |   91.42 |       90 |     100 |   91.42 | 56-64             
  session.ts       |    85.9 |    81.46 |   91.34 |    85.9 | ...6359,6361-6362 
  sse-events.ts    |   86.85 |    85.64 |   94.11 |   86.85 | ...18-929,932,939 
  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.35 |    78.94 |     100 |   90.35 | ...52-553,576-577 
  ...d-contacts.ts |   83.62 |    94.59 |     100 |   83.62 | 123,125-142       
  ...controller.ts |   83.33 |    80.47 |      90 |   83.33 | ...1056,1061,1068 
  ...extensions.ts |    88.8 |    77.83 |   93.84 |    88.8 | ...2329,2374-2375 
  ...-file-read.ts |      91 |    80.91 |     100 |      91 | ...20-621,624-625 
  ...file-write.ts |   89.72 |    79.35 |     100 |   89.72 | ...05,719-726,807 
  ...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 
  ...al-control.ts |   74.17 |    69.23 |     100 |   74.17 | ...18,220-226,231 
  ...management.ts |   87.47 |       85 |     100 |   87.47 | ...1733,1743-1748 
  ...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 |    76.9 |    87.15 |     100 |    76.9 | ...29-354,360-394 
  ...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 |   76.92 |     67.1 |      80 |   76.92 | ...38-343,351-352 
  ...pace-voice.ts |   91.33 |    81.02 |     100 |   91.33 | ...70-673,676-678 
 src/serve/server  |   92.38 |    89.78 |   97.15 |   92.38 |                   
  access-log.ts    |   98.73 |    97.26 |     100 |   98.73 | 119,196           
  ...-timestamp.ts |     100 |      100 |     100 |     100 |                   
  ...er-helpers.ts |   63.82 |    78.15 |   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 |   86.92 |     73.6 |     100 |   86.92 | ...68,785,848-857 
  fs-factory.ts    |     100 |    95.52 |     100 |     100 | 77,144,200        
  ...branch-ops.ts |     100 |      100 |     100 |     100 |                   
  ...list-cache.ts |   99.01 |    95.52 |     100 |   99.01 | 184-185           
  ...t-deadline.ts |     100 |      100 |     100 |     100 |                   
  ...iter-setup.ts |      65 |       80 |   33.33 |      65 | 30-35,38-43,47-48 
  ...st-helpers.ts |   95.13 |    95.14 |     100 |   95.13 | ...66-168,423-428 
  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.74 |     86.4 |   97.36 |   89.74 | ...82,909,937-938 
  ...ion-export.ts |     100 |    94.73 |     100 |     100 | 64                
  session-list.ts  |   97.15 |    93.95 |     100 |   97.15 | ...1012,1211-1215 
  ...ry-context.ts |    87.5 |       50 |     100 |    87.5 | 49-50             
  telemetry.ts     |   99.04 |    97.26 |     100 |   99.04 | ...92,861,940-942 
 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 |    90.9 |    87.96 |    91.3 |    90.9 |                   
  index.ts         |   90.41 |    87.29 |      90 |   90.41 | ...1505-1509,1512 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/services      |   92.69 |    89.52 |   98.06 |   92.69 |                   
  ...mandLoader.ts |     100 |    88.88 |     100 |     100 | 106-120           
  ...killLoader.ts |   97.19 |    85.29 |     100 |   97.19 | 142,153-154       
  ...andService.ts |   98.73 |      100 |     100 |   98.73 | 107               
  ...mandLoader.ts |   87.09 |    83.07 |     100 |   87.09 | ...35-340,345-350 
  ...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 |   92.14 |    92.42 |     100 |   92.14 | ...91-296,329-330 
  ...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.8 |   96.15 |   88.91 |                   
  DataProcessor.ts |   88.28 |    86.77 |   94.73 |   88.28 | ...1362,1366-1373 
  ...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            |   74.57 |    75.47 |   68.47 |   74.57 |                   
  App.tsx          |   33.33 |       75 |   33.33 |   33.33 | 32-86             
  AppContainer.tsx |   76.06 |       72 |   69.44 |   76.06 | ...4292,4408-4414 
  ...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        |   63.63 |      100 |   41.17 |   63.63 | ...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 |   71.42 |     74.5 |    62.5 |   71.42 | ...10,337,404-409 
  ...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.76 |    66.66 |   51.06 |   58.76 |                   
  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.83 |       75 |     100 |   94.83 | ...33-234,253-259 
  ...rSetupFlow.ts |   43.18 |    33.33 |      50 |   43.18 | ...78-399,416-459 
 src/ui/commands   |    84.1 |    83.79 |   90.02 |    84.1 |                   
  aboutCommand.ts  |     100 |      100 |     100 |     100 |                   
  ...or-command.ts |     100 |    95.65 |     100 |     100 | 104,182           
  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 | ...28-129,137-146 
  ...essCommand.ts |   68.22 |    54.05 |      75 |   68.22 | ...97-198,212-215 
  ...astCommand.ts |   84.27 |       75 |     100 |   84.27 | ...,91-97,125-130 
  ...ig-command.ts |   93.12 |    88.42 |     100 |   93.12 | ...07-315,321-323 
  ...extCommand.ts |   75.05 |    74.39 |   84.61 |   75.05 | ...95-628,639-640 
  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 |   90.56 |    87.83 |    90.9 |   90.56 | ...75-280,327-334 
  docsCommand.ts   |     100 |     90.9 |     100 |     100 | 25                
  doctorCommand.ts |   70.16 |    84.61 |      95 |   70.16 | ...29-679,682-816 
  dreamCommand.ts  |   85.45 |    88.88 |     100 |   85.45 | 58-65             
  editorCommand.ts |     100 |      100 |     100 |     100 |                   
  ...rt-command.ts |   80.48 |       75 |     100 |   80.48 | 49-54,69-72,93-98 
  effort-utils.ts  |     100 |      100 |     100 |     100 |                   
  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   |     100 |    96.49 |     100 |     100 | 139,192           
  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  |   85.02 |    82.53 |     100 |   85.02 | ...1089,1123-1128 
  ...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.6 |       90 |     100 |    89.6 | ...72-176,212-219 
  ...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 |   93.06 |       85 |   66.66 |   93.06 | ...78-183,282-287 
 src/ui/components |   72.79 |    79.77 |   77.58 |   72.79 |                   
  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 | ...-76,88,143,157 
  ...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 |   11.28 |      100 |       0 |   11.28 | 71-598            
  DiffDialog.tsx   |    53.5 |     37.5 |   69.23 |    53.5 | ...32-737,747-760 
  ...ngsDialog.tsx |    8.44 |      100 |       0 |    8.44 | 37-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       |   81.27 |    69.23 |      50 |   81.27 | ...06,245,267-272 
  ...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.69 |    67.61 |     100 |   79.69 | ...17,520,523-529 
  ...ngeDialog.tsx |     100 |      100 |     100 |     100 |                   
  InputPrompt.tsx  |   84.26 |    82.94 |      80 |   84.26 | ...2215,2236,2332 
  ...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.58 |    95.06 |   46.15 |   95.58 | ...79,482-486,489 
  MemoryDialog.tsx |   86.59 |    80.15 |     100 |   86.59 | ...34-435,485,553 
  ...geDisplay.tsx |       0 |        0 |       0 |       0 | 1-41              
  ModelDialog.tsx  |   85.22 |    74.08 |     100 |   85.22 | ...1041,1097,1099 
  ...tsDisplay.tsx |     100 |    97.22 |     100 |     100 | 270               
  ...fications.tsx |   16.66 |      100 |       0 |   16.66 | 14-56             
  ...onsDialog.tsx |    2.13 |      100 |       0 |    2.13 | 62-133,148-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 |    8.57 |      100 |       0 |    8.57 | 24-55,58-134      
  ...geDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...ngDisplay.tsx |   21.42 |      100 |       0 |   21.42 | 13-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 |      28 |      100 |       0 |      28 | 18-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.9 |    86.88 |     100 |    93.9 | ...20,282,302-304 
  ...yTodoList.tsx |   96.36 |    88.23 |     100 |   96.36 | 138-141           
  ...nsDisplay.tsx |   95.62 |    87.09 |     100 |   95.62 | ...24-125,273-275 
  ...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 |    7.84 |      100 |       0 |    7.84 | 24-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 |   58.69 |    70.24 |    62.5 |   58.69 |                   
  ...atContent.tsx |    9.09 |      100 |       0 |    9.09 | 54-275,281-283    
  ...tChatView.tsx |     100 |    81.81 |     100 |     100 | 82                
  ...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 |   45.51 |    70.53 |   60.86 |   45.51 |                   
  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 |    9.77 |      100 |       0 |    9.77 | 27-166            
  ...tusDialog.tsx |    5.63 |      100 |       0 |    5.63 | 33-75,80-288      
  ...topDialog.tsx |    6.17 |      100 |       0 |    6.17 | 33-213            
 ...ackground-view |   85.34 |    84.91 |   92.98 |   85.34 |                   
  ...sksDialog.tsx |   81.87 |    82.77 |   85.71 |   81.87 | ...1853,1965-1971 
  ...TasksPill.tsx |   78.84 |    94.28 |     100 |   78.84 | 64,109-129        
  ...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.7 |    52.38 |   20.83 |    50.7 |                   
  ...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.24 |      100 |       0 |    9.24 | 40-67,70-163      
 ...mponents/hooks |   87.11 |    81.37 |   91.89 |   87.11 |                   
  ...rListBody.tsx |   95.29 |    85.18 |     100 |   95.29 | 95-98             
  ...etailStep.tsx |   75.32 |    71.42 |      60 |   75.32 | ...56-169,173-186 
  ...etailStep.tsx |     100 |      100 |     100 |     100 |                   
  ...rListStep.tsx |     100 |      100 |     100 |     100 |                   
  ...entHeader.tsx |     100 |    85.71 |     100 |     100 | 47                
  ...rListStep.tsx |     100 |      100 |     100 |     100 |                   
  ...etailStep.tsx |     100 |      100 |     100 |     100 |                   
  ...abledStep.tsx |     100 |      100 |     100 |     100 |                   
  ...sListStep.tsx |     100 |      100 |     100 |     100 |                   
  ...entDialog.tsx |   72.29 |    70.49 |     100 |   72.29 | ...51,563-568,572 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-13              
  ...erGrouping.ts |     100 |      100 |     100 |     100 |                   
  sourceLabels.ts  |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...components/mcp |   40.91 |    63.44 |   70.58 |   40.91 |                   
  ...ealthPill.tsx |     100 |      100 |     100 |     100 |                   
  ...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.35 |    86.92 |   85.71 |   90.35 |                   
  ...orMessage.tsx |     100 |      100 |     100 |     100 |                   
  ...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.87 |    82.63 |     100 |   91.87 | ...49-651,658-660 
  ...upMessage.tsx |   98.38 |    95.38 |     100 |   98.38 | 188-191,422       
  ToolMessage.tsx  |   93.06 |    86.32 |   93.75 |   93.06 | ...1037,1082-1084 
 ...ponents/shared |   86.29 |     82.4 |   94.17 |   86.29 |                   
  ...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.95 |      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 |     100 |      100 |     100 |     100 |                   
  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 |   91.49 |    86.66 |   83.33 |   91.49 | ...18-846,859,959 
  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 |    3.96 |      100 |       0 |    3.96 |                   
  ...gerDialog.tsx |    3.96 |      100 |       0 |    3.96 | 79-137,140-681    
 ...ents/subagents |   30.87 |        0 |       0 |   30.87 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-11              
  reducers.tsx     |    12.1 |      100 |       0 |    12.1 | 33-190            
  types.ts         |     100 |      100 |     100 |     100 |                   
  utils.ts         |   10.95 |      100 |       0 |   10.95 | ...1,56-57,60-102 
 ...bagents/create |    9.13 |      100 |       0 |    9.13 |                   
  ...ionWizard.tsx |    7.28 |      100 |       0 |    7.28 | 34-299            
  ...rSelector.tsx |   14.75 |      100 |       0 |   14.75 | 26-85             
  ...onSummary.tsx |    4.26 |      100 |       0 |    4.26 | 27-331            
  ...tionInput.tsx |    8.63 |      100 |       0 |    8.63 | 23-177            
  ...dSelector.tsx |   33.33 |      100 |       0 |   33.33 | 20-21,26-27,36-63 
  ...nSelector.tsx |    37.5 |      100 |       0 |    37.5 | 20-21,26-27,36-58 
  ...EntryStep.tsx |   12.76 |      100 |       0 |   12.76 | 34-78             
  ToolSelector.tsx |    4.16 |      100 |       0 |    4.16 | 31-253            
 ...bagents/manage |    21.6 |    59.52 |   27.27 |    21.6 |                   
  ...ctionStep.tsx |   10.25 |      100 |       0 |   10.25 | 21-103            
  ...eleteStep.tsx |   20.93 |      100 |       0 |   20.93 | 23-62             
  ...tEditStep.tsx |   25.53 |      100 |       0 |   25.53 | ...2,37-38,51-124 
  ...ctionStep.tsx |   35.61 |    59.52 |     100 |   35.61 | ...21-433,438-440 
  ...iewerStep.tsx |   13.72 |      100 |       0 |   13.72 | 18-73             
  ...gerDialog.tsx |    6.74 |      100 |       0 |    6.74 | 35-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   |   86.01 |    81.54 |   86.48 |   86.01 |                   
  ...ewContext.tsx |   87.56 |       80 |      75 |   87.56 | ...37-240,246-256 
  AppContext.tsx   |      80 |       50 |     100 |      80 | 19-20             
  ...ewContext.tsx |   93.83 |    68.51 |   42.85 |   93.83 | ...44,281-285,317 
  ...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 |    79.56 |    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    |   93.33 |    85.71 |   66.66 |   93.33 |                   
  ...ngsManager.ts |   93.33 |    85.71 |   66.66 |   93.33 | 49,63-64          
 src/ui/hooks      |   85.95 |    83.88 |   87.81 |   85.95 |                   
  ...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 |   86.79 |    71.86 |   83.33 |   86.79 | ...1529,1558-1562 
  ...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 |      42 |       75 |     100 |      42 | 42-44,53-59,62-87 
  ...odeCommand.ts |   58.82 |      100 |     100 |   58.82 | 28,33-48          
  ...enaCommand.ts |      85 |      100 |     100 |      85 | 23-24,29          
  ...aInProcess.ts |   27.92 |       80 |      25 |   27.92 | ...69-170,173-175 
  ...Completion.ts |   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.89 |    77.55 |     100 |   94.89 | 164-168,257,263   
  ...chedScroll.ts |     100 |      100 |     100 |     100 |                   
  ...ketedPaste.ts |    23.8 |      100 |       0 |    23.8 | 19-37             
  ...nchCommand.ts |   95.53 |    83.01 |     100 |   95.53 | ...64-165,289-292 
  ...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   |   11.62 |      100 |       0 |   11.62 | 44-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 |   87.31 |    84.02 |   78.26 |   87.31 | ...5757-5759,5761 
  ...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  |   10.52 |      100 |       0 |   10.52 | 36-75             
  ...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 |   85.29 |    80.28 |    92.3 |   85.29 | ...36,351-361,441 
  useQwenAuth.ts   |     100 |      100 |     100 |     100 |                   
  ...lScheduler.ts |   89.13 |     86.9 |     100 |   89.13 | ...61-463,496-506 
  ...oryCommand.ts |       0 |        0 |       0 |       0 | 1-7               
  ...umeCommand.ts |    95.4 |    77.77 |     100 |    95.4 | 133-134,236-241   
  ...ompletion.tsx |   90.67 |    83.33 |     100 |   90.67 | ...02,105,138-141 
  ...ectionList.ts |   97.12 |    96.19 |     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.32 |    93.93 |     100 |   97.32 | ...18-422,518-525 
  ...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 |    79.2 |    35.29 |     100 |    79.2 | ...15-116,120-121 
  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.25 |    89.47 |     100 |   91.25 |                   
  ...AppLayout.tsx |   90.99 |     87.5 |     100 |   90.99 | 61-63,111-116,152 
  ...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  |   93.56 |    86.13 |     100 |   93.56 |                   
  screen-buffer.ts |   94.73 |    64.28 |     100 |   94.73 | 51-52             
  ...ion-coords.ts |     100 |      100 |     100 |     100 |                   
  ...ction-span.ts |   93.81 |     92.1 |     100 |   93.81 | ...1,45-46,99-100 
  ...tion-state.ts |     100 |      100 |     100 |     100 |                   
  ...ction-text.ts |   93.85 |    93.44 |     100 |   93.85 | 30-34,130-131     
  ...selection.tsx |   91.88 |    78.57 |     100 |   91.88 | ...16-417,446-447 
 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      |   87.72 |    85.81 |   96.06 |   87.72 |                   
  ...Colorizer.tsx |   80.31 |    85.41 |     100 |   80.31 | ...00-201,313-339 
  ...nRenderer.tsx |   80.07 |     75.6 |     100 |   80.07 | ...70,274,332-333 
  ...wnDisplay.tsx |   92.87 |     93.5 |     100 |   92.87 | ...,955,1002-1020 
  ...idDiagram.tsx |   87.79 |    95.34 |     100 |   87.79 | 156-179           
  ...eRenderer.tsx |   93.63 |    81.77 |   95.23 |   93.63 | ...47-750,803-808 
  ...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.9 |    74.15 |    92.3 |    52.9 | ...29,632-641,644 
  commandUtils.ts  |   98.61 |    93.22 |     100 |   98.61 | 189,217-218,424   
  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.42 |       95 |     100 |   91.42 | 32-34             
  gradientUtils.ts |     100 |      100 |     100 |     100 |                   
  highlight.ts     |     100 |      100 |     100 |     100 |                   
  ...gap-notice.ts |     100 |      100 |     100 |     100 |                   
  ...oryMapping.ts |     100 |    95.65 |     100 |     100 | 45,151            
  historyUtils.ts  |   96.07 |    97.14 |     100 |   96.07 | 104-107           
  ...mage-parts.ts |   97.75 |    94.59 |     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          |   91.33 |    79.03 |     100 |   91.33 | ...73,273,277-278 
  ...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 |   83.24 |    80.12 |     100 |   83.24 | ...02-624,755-756 
  ...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 |   95.19 |      100 |   88.88 |   95.19 | 121-126           
  ...nal-buffer.ts |     100 |      100 |     100 |     100 |                   
  ...e-renderer.ts |   90.61 |    83.44 |     100 |   90.61 | ...80,482-484,607 
  ...ize-reflow.ts |     100 |     92.3 |     100 |     100 | 57,62,209,217,347 
  ...wOptimizer.ts |     100 |    94.11 |     100 |     100 | 33,76             
  terminalSetup.ts |    4.37 |      100 |       0 |    4.37 | 44-393            
  textUtils.ts     |   98.71 |    95.72 |     100 |   98.71 | 292-293,478-479   
  ...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       
  windowTitle.ts   |   96.55 |    94.73 |     100 |   96.55 | 56-57             
  ...ow-keyword.ts |     100 |      100 |     100 |     100 |                   
 ...i/utils/export |   75.03 |     60.1 |   94.59 |   75.03 |                   
  collect.ts       |   71.27 |    65.81 |      96 |   71.27 | ...90-633,655-656 
  index.ts         |     100 |      100 |     100 |     100 |                   
  normalize.ts     |   80.42 |    51.35 |     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.64 |   81.94 |   81.27 |                   
  ...d-recorder.ts |     6.2 |        0 |       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         |   82.94 |    87.85 |   92.97 |   82.94 |                   
  ...p-profiler.ts |   98.39 |    92.59 |     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 |      100 |     100 |     100 |                   
  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 
  findings.ts      |   96.01 |    92.08 |     100 |   96.01 | ...1227,1236-1237 
  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 
  ...projection.ts |   95.27 |    95.58 |     100 |   95.27 | 140-145           
  jsonc-editor.ts  |   93.18 |    92.66 |     100 |   93.18 | ...80-381,384-385 
  languageUtils.ts |   98.88 |    97.01 |     100 |   98.88 | 184-185           
  load-undici.ts   |     100 |      100 |     100 |     100 |                   
  ...npm-update.ts |   86.64 |    77.02 |     100 |   86.64 | ...03-304,335-345 
  math.ts          |       0 |        0 |       0 |       0 | 1-15              
  ...er-mention.ts |     100 |    66.66 |     100 |     100 | 14,30,44-46       
  ...iagnostics.ts |   94.57 |    83.01 |   88.88 |   94.57 | ...05,311,315-317 
  ...serMessage.ts |     100 |      100 |     100 |     100 |                   
  ...onfigUtils.ts |   94.25 |    91.17 |     100 |   94.25 | ...30,436,439-443 
  ...iveHelpers.ts |   95.14 |    91.79 |     100 |   95.14 | ...54-455,553,566 
  osc.ts           |   97.18 |      100 |    87.5 |   97.18 | 182-183           
  package.ts       |   88.88 |    85.71 |     100 |   88.88 | 31-32             
  paths.ts         |     100 |      100 |     100 |     100 |                   
  ...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.52 |    57.35 |   76.92 |   45.52 | ...1040,1052-1075 
  ...xImageName.ts |     100 |    77.77 |     100 |     100 | 10,18             
  sandboxMounts.ts |     100 |      100 |     100 |     100 |                   
  ...-path-argv.ts |     100 |      100 |     100 |     100 |                   
  sessionPaths.ts  |   90.84 |    90.56 |     100 |   90.84 | ...81-182,185-186 
  settingsUtils.ts |   79.62 |     88.8 |   85.18 |   79.62 | ...47-565,572-580 
  shell-args.ts    |     100 |      100 |     100 |     100 |                   
  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.09 |    90.27 |     100 |   95.09 | ...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                
  ...iagnostics.ts |    95.8 |     87.5 |   93.75 |    95.8 | ...03,277-278,289 
  ...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 |                   
  ...WithBackup.ts |   65.04 |    77.77 |     100 |   65.04 | 97,112,133-172    
 ...s/housekeeping |   93.51 |    90.95 |   96.96 |   93.51 |                   
  cleanup.ts       |   92.59 |    93.75 |     100 |   92.59 | ...02-205,209-211 
  ...eractionAt.ts |     100 |      100 |     100 |     100 |                   
  scheduler.ts     |      93 |    88.34 |      95 |      93 | ...57-359,411-415 
  throttledOnce.ts |   95.95 |    93.93 |     100 |   95.95 | 77-78,153-154     
-------------------|---------|----------|---------|---------|-------------------
Core Package - Full Text Report
-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |   88.18 |    86.73 |   89.72 |   88.18 |                   
 src               |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/__mocks__/fs  |       0 |        0 |       0 |       0 |                   
  promises.ts      |       0 |        0 |       0 |       0 | 1-48              
 src/agents        |   89.63 |    83.96 |   94.11 |   89.63 |                   
  ...transcript.ts |   88.49 |    84.09 |     100 |   88.49 | ...32,640,646-650 
  ...ent-resume.ts |   85.59 |    77.75 |   83.33 |   85.59 | ...1794-1798,1801 
  ...ound-tasks.ts |   94.63 |    90.13 |   96.38 |   94.63 | ...1773,1793-1796 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...ent-result.ts |    96.8 |    92.68 |     100 |    96.8 | 106,129-131       
  ...n-registry.ts |   94.86 |    87.26 |    98.3 |   94.86 | ...1463,1477-1479 
  ...w-snapshot.ts |   75.73 |    72.22 |    87.5 |   75.73 | ...21,445,452-454 
  worktree-pin.ts  |     100 |    88.23 |     100 |     100 | 78,99             
 src/agents/arena  |   76.94 |    68.22 |   78.94 |   76.94 |                   
  ...gentClient.ts |   79.47 |    88.88 |   81.81 |   79.47 | ...68-183,189-204 
  ArenaManager.ts  |   75.89 |     65.2 |   78.57 |   75.89 | ...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 |   91.36 |    86.54 |   90.25 |   91.36 |                   
  agent-context.ts |     100 |      100 |     100 |     100 |                   
  agent-core.ts    |   84.54 |    76.42 |   77.58 |   84.54 | ...2365,2411-2413 
  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.38 |      100 |    92.3 |   98.38 | 85-86             
  ...low-budget.ts |     100 |      100 |     100 |     100 |                   
  ...-scheduler.ts |   97.43 |    96.36 |     100 |   97.43 | 128-130           
  ...ow-journal.ts |   92.78 |    78.12 |     100 |   92.78 | ...49-150,192-194 
  ...chestrator.ts |   93.87 |    90.44 |    91.3 |   93.87 | ...2216,2309-2312 
  ...ow-prompts.ts |     100 |      100 |     100 |     100 |                   
  ...low-runner.ts |   95.47 |    83.47 |   94.44 |   95.47 | ...44,312,332-335 
  ...ow-sandbox.ts |   96.88 |    91.16 |     100 |   96.88 | ...1768,1774-1775 
  ...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.97 |    84.56 |    89.2 |   82.97 |                   
  TeamManager.ts   |   74.33 |    81.09 |    80.7 |   74.33 | ...1707,1730-1731 
  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.29 |       83 |     100 |   89.29 | ...1000,1044-1045 
  team-events.ts   |   60.52 |      100 |      50 |   60.52 | ...40-144,151-155 
  teamHelpers.ts   |   91.71 |    94.54 |      95 |   91.71 | ...18-319,355-365 
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...eam/test-utils |   95.06 |    95.16 |   98.21 |   95.06 |                   
  ...on-harness.ts |   96.49 |       85 |     100 |   96.49 | 128-129,141-142   
  fake-agent.ts    |     100 |    96.77 |     100 |     100 | 158,167           
  fake-backend.ts  |   86.46 |    97.61 |   95.83 |   86.46 | 124-146           
 src/config        |   84.33 |     86.9 |   75.67 |   84.33 |                   
  approval-mode.ts |     100 |      100 |     100 |     100 |                   
  ...xtDefaults.ts |     100 |      100 |     100 |     100 |                   
  config.ts        |   83.65 |    86.63 |   74.19 |   83.65 | ...8910,8914-8915 
  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.46 |    88.23 |   93.05 |   92.46 |                   
  baseLlmClient.ts |    88.4 |     83.8 |   81.81 |    88.4 | ...59,672,678-680 
  client.ts        |   92.58 |    88.04 |   91.01 |   92.58 | ...4310,4408-4409 
  ...tGenerator.ts |   86.34 |    87.34 |   84.61 |   86.34 | ...96-497,542-548 
  ...lScheduler.ts |   89.77 |     84.7 |   94.73 |   89.77 | ...6429,6457-6473 
  geminiChat.ts    |   94.91 |     90.1 |   95.72 |   94.91 | ...5208,5256-5257 
  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 |   94.89 |    88.54 |     100 |   94.89 | ...51-252,297-298 
  prompts.ts       |   93.64 |    91.42 |   83.33 |   93.64 | ...1209,1412-1413 
  ...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 |    91.89 |     100 |     100 | 87,122-139        
  ...reparation.ts |     100 |      100 |     100 |     100 |                   
  ...tion-guard.ts |   90.38 |    94.73 |     100 |   90.38 | 83-87             
  ...allIdUtils.ts |   98.81 |    91.22 |     100 |   98.81 | 43,52             
  ...okTriggers.ts |   99.45 |    92.43 |     100 |   99.45 | 182,193           
  ...terruption.ts |     100 |     92.3 |     100 |     100 | 86,104            
  turn.ts          |   99.19 |    94.48 |     100 |   99.19 | 698-699,768       
  ...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 | ...1436,1465,1476 
  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 |   96.12 |     91.3 |    90.9 |   96.12 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...tGenerator.ts |   96.06 |    90.75 |   90.47 |   96.06 | ...1309-1310,1338 
  ...tDetection.ts |     100 |      100 |     100 |     100 |                   
 ...ntentGenerator |    91.9 |    90.54 |   95.76 |    91.9 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  converter.ts     |    91.3 |    89.49 |   96.87 |    91.3 | ...1942,2111-2126 
  errorHandler.ts  |     100 |      100 |     100 |     100 |                   
  index.ts         |   68.25 |    82.35 |      50 |   68.25 | 44-53,74-78,90-94 
  ...tGenerator.ts |    66.4 |    70.58 |   88.88 |    66.4 | ...51-157,168-169 
  pipeline.ts      |   95.27 |     90.9 |     100 |   95.27 | ...1434,1442,1541 
  ...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.39 |    92.28 |    98.5 |   97.39 |                   
  dashscope.ts     |   98.36 |    95.08 |   96.42 |   98.36 | ...08-709,851-852 
  deepseek.ts      |   94.91 |    89.36 |     100 |   94.91 | ...31-132,145-146 
  default.ts       |   99.18 |    97.05 |     100 |   99.18 | 208               
  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     |   88.46 |    85.59 |   93.19 |   88.46 |                   
  ...ive-safety.ts |     100 |      100 |     100 |     100 |                   
  ...-converter.ts |   80.55 |    73.66 |     100 |   80.55 | ...1133,1179-1180 
  corruptFile.ts   |     100 |       50 |     100 |     100 | 40-45             
  ...-converter.ts |     100 |      100 |     100 |     100 |                   
  ...redentials.ts |   95.33 |    89.47 |     100 |   95.33 | ...21-122,173-175 
  ...me-refresh.ts |     100 |      100 |     100 |     100 |                   
  ...sion-store.ts |   92.82 |    89.08 |    98.3 |   92.82 | ...1641-1647,1691 
  ...ionManager.ts |   84.45 |    83.47 |      83 |   84.45 | ...3126,3164-3165 
  ...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 |    85.71 |   85.71 |    75.9 | ...98,202,214-248 
  github.ts        |   91.61 |     84.5 |     100 |   91.61 | ...1027-1028,1038 
  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       
  ...-converter.ts |   94.89 |    90.41 |     100 |   94.89 | ...50-151,222-224 
  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 |    84.21 |     100 |   88.95 | ...32-235,238-241 
  ...extraction.ts |   85.77 |       81 |   89.47 |   85.77 | ...02-205,260-261 
 ...ent-plugins-v1 |   84.94 |    79.51 |     100 |   84.94 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  manifest.ts      |   81.87 |    84.48 |     100 |   81.87 | ...55-156,161-174 
  mcp.ts           |   84.98 |    79.56 |     100 |   84.98 | ...88-389,419-420 
  paths.ts         |     100 |    94.44 |     100 |     100 | 59                
  skills.ts        |   82.31 |    63.88 |     100 |   82.31 | ...38-141,150-151 
 src/followup      |   84.58 |    81.04 |   86.84 |   84.58 |                   
  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   |   75.98 |    67.22 |   58.33 |   75.98 | ...42-743,750-751 
  ...onToolGate.ts |   97.97 |     87.5 |     100 |   97.97 | 105,110           
  ...nGenerator.ts |   86.27 |    87.65 |     100 |   86.27 | ...42-247,359-361 
 src/generated     |       0 |        0 |       0 |       0 |                   
  git-commit.ts    |       0 |        0 |       0 |       0 | 1-10              
 src/goals         |   92.96 |    89.05 |   94.34 |   92.96 |                   
  ...eGoalStore.ts |   87.61 |    88.88 |   86.66 |   87.61 | ...85-188,196-204 
  ...t-verifier.ts |   96.27 |     90.9 |     100 |   96.27 | ...20,143-146,163 
  ...checkpoint.ts |   81.48 |    76.19 |     100 |   81.48 | ...02-105,115-118 
  goal-evidence.ts |   88.34 |    87.06 |    97.5 |   88.34 | ...1162,1185-1188 
  ...projection.ts |   66.66 |    72.97 |   33.33 |   66.66 | ...87,190,194-196 
  ...ersistence.ts |   87.29 |    85.71 |    87.5 |   87.29 | ...53-154,185-190 
  goal-protocol.ts |   96.87 |    95.65 |     100 |   96.87 | 200-201           
  goal-reducer.ts  |      95 |    92.34 |   97.05 |      95 | ...43,520,538-539 
  goal-runtime.ts  |   96.89 |    89.93 |   95.74 |   96.89 | ...1315-1316,1437 
  goal-tools.ts    |   98.38 |    94.05 |   95.45 |   98.38 | ...98-199,300-301 
  ...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-28              
  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.07 |    86.35 |   88.54 |   88.07 |                   
  ...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.09 |   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.48 |   89.28 |   82.12 |                   
  ...en-storage.ts |     100 |      100 |     100 |     100 |                   
  ...en-storage.ts |   87.08 |    87.71 |   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        |   88.08 |     84.5 |   90.62 |   88.08 |                   
  ...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       |   92.41 |    79.41 |     100 |   92.41 | 56-61,100,119-122 
  ...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.99 |    82.69 |   86.36 |   86.99 | ...69,389,396-402 
  memoryAge.ts     |   90.47 |    83.33 |     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 |    86.79 |     100 |   97.26 | ...10-218,222,225 
  recall.ts        |   86.86 |    86.36 |   92.85 |   86.86 | ...33-538,571-582 
  refresh.ts       |   93.58 |    89.58 |     100 |   93.58 | ...75-176,183-184 
  ...ceSelector.ts |    93.2 |    85.71 |     100 |    93.2 | ...45-146,148-149 
  remember.ts      |   98.89 |    90.19 |     100 |   98.89 | 50,70             
  scan.ts          |   93.75 |       80 |     100 |   93.75 | ...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 |    85.71 |     100 |     100 | 27                
  ...cret-guard.ts |     100 |      100 |     100 |     100 |                   
  ...emory-sync.ts |   94.24 |    82.85 |     100 |   94.24 | ...34-236,246-247 
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...ontextFile.ts |   81.21 |     79.1 |   81.81 |   81.21 | ...63-277,291-296 
 src/mocks         |       0 |        0 |       0 |       0 |                   
  msw.ts           |       0 |        0 |       0 |       0 | 1-9               
 src/models        |   92.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.79 |    91.16 |   71.07 |   83.79 |                   
  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.63 |    88.88 |      80 |   86.63 | ...1111,1217-1221 
  rule-parser.ts   |   94.49 |    92.72 |     100 |   94.49 | ...1447,1481-1483 
  ...-semantics.ts |   70.44 |    91.09 |   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.6 |   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 |    74.04 |   78.26 |   75.85 | ...73-474,502-503 
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...viders/presets |   97.85 |    91.66 |   63.63 |   97.85 |                   
  ...oding-plan.ts |   87.34 |      100 |       0 |   87.34 | 81-83,86-88,90-93 
  ...a-standard.ts |     100 |      100 |     100 |     100 |                   
  ...token-plan.ts |     100 |      100 |     100 |     100 |                   
  ...m-provider.ts |   97.05 |    81.25 |      75 |   97.05 | 118-119           
  deepseek.ts      |     100 |      100 |     100 |     100 |                   
  grok.ts          |     100 |      100 |     100 |     100 |                   
  idealab.ts       |     100 |      100 |     100 |     100 |                   
  minimax.ts       |     100 |      100 |     100 |     100 |                   
  modelscope.ts    |     100 |      100 |     100 |     100 |                   
  openrouter.ts    |     100 |      100 |     100 |     100 |                   
  requesty.ts      |     100 |      100 |     100 |     100 |                   
  zai.ts           |     100 |      100 |     100 |     100 |                   
 src/qwen          |   85.41 |    78.76 |   95.89 |   85.41 |                   
  ...tGenerator.ts |   98.64 |    98.18 |     100 |   98.64 | 105-106           
  qwenOAuth2.ts    |   82.79 |    73.75 |   90.62 |   82.79 | ...1205-1221,1251 
  ...kenManager.ts |   85.36 |    76.61 |     100 |   85.36 | ...52-757,778-783 
 src/resources     |     100 |      100 |     100 |     100 |                   
  ...e-registry.ts |     100 |      100 |     100 |     100 |                   
 src/services      |   90.43 |    86.08 |    96.8 |   90.43 |                   
  ...ionTrailer.ts |     100 |      100 |     100 |     100 |                   
  ...llRegistry.ts |   98.48 |    87.28 |     100 |   98.48 | 81-82,105,474-475 
  branch-points.ts |     100 |    95.23 |     100 |     100 | ...20,211,224,327 
  ...ionService.ts |    97.7 |    96.44 |     100 |    97.7 | ...1069,1212-1220 
  ...ingService.ts |   91.36 |    86.98 |   93.25 |   91.36 | ...2685,2700-2701 
  ...ttribution.ts |   91.73 |    87.71 |      90 |   91.73 | ...80-685,826-827 
  ...utSlimming.ts |    97.2 |    94.23 |     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 | ...53,479-486,531 
  ...ratedFiles.ts |      96 |    88.23 |     100 |      96 | 119-120,146-147   
  gitInit.ts       |     100 |      100 |     100 |     100 |                   
  ...reeService.ts |   74.75 |    70.76 |   96.07 |   74.75 | ...2296,2325-2326 
  ...on-service.ts |   87.38 |       72 |     100 |   87.38 | ...01-305,343-344 
  ...references.ts |   98.57 |    91.42 |     100 |   98.57 | 156-157,217-218   
  ...ionService.ts |   98.21 |    97.25 |     100 |   98.21 | ...81-682,729-730 
  ...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.22 |    90.99 |     100 |   97.22 | ...55-456,609-610 
  ...ttachments.ts |   97.74 |     90.9 |     100 |   97.74 | 298-308,646       
  ...pi-history.ts |   98.94 |    88.88 |     100 |   98.94 | 43                
  ...ersistence.ts |   91.66 |    80.58 |     100 |   91.66 | ...1060-1061,1089 
  ...tory-state.ts |     100 |    95.23 |     100 |     100 | 31                
  ...on-service.ts |   94.49 |    92.26 |   97.14 |   94.49 | ...98-600,656-664 
  ...ce-service.ts |    98.5 |    94.11 |    90.9 |    98.5 | 64-65             
  ...n-registry.ts |   98.73 |    96.29 |     100 |   98.73 | 584,638-639,692   
  ...ken-counts.ts |     100 |       96 |     100 |     100 | 58                
  ...ipt-reader.ts |   93.71 |    91.05 |   97.77 |   93.71 | ...2755-2756,2833 
  ...turn-state.ts |   94.11 |     90.9 |   91.66 |   94.11 | 108-112,129-130   
  ...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 |   89.31 |    85.89 |   96.05 |   89.31 | ...2643,2657-2677 
  sessionTitle.ts  |   95.75 |    77.41 |     100 |   95.75 | ...53-256,287-288 
  ...ionService.ts |   84.43 |    78.45 |   97.18 |   84.43 | ...2496,2502-2507 
  ...pInhibitor.ts |   97.42 |    92.77 |     100 |   97.42 | ...30,169,369-370 
  ...Estimation.ts |     100 |    94.11 |     100 |     100 | 118               
  ...ageService.ts |   97.76 |    91.59 |   93.75 |   97.76 | ...61-262,366,567 
  ...ite-origin.ts |     100 |    93.33 |     100 |     100 | 32                
  ...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 |   88.36 |     87.7 |     100 |   88.36 | ...48-449,465-466 
 ...icrocompaction |   98.91 |    95.08 |     100 |   98.91 |                   
  microcompact.ts  |   98.91 |    95.08 |     100 |   98.91 | ...60,769,778-779 
 ...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.92 |   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.69 |     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.03 |     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     |   82.53 |    84.79 |   85.86 |   82.53 |                   
  ...ty-tracker.ts |     100 |      100 |     100 |     100 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...on-metrics.ts |   99.08 |    80.95 |     100 |   99.08 | 185,199           
  ...on-tracing.ts |   80.71 |    81.91 |   79.16 |   80.71 | ...92,499-501,517 
  ...attributes.ts |   96.98 |    91.37 |     100 |   96.98 | ...47-348,366-367 
  ...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.12 |    96.03 |      95 |   99.12 | 150,379-380       
  ...t.circular.ts |       0 |        0 |       0 |       0 | 1-128             
  loggers.ts       |   60.73 |    78.01 |   66.66 |   60.73 | ...1507,1524-1544 
  metrics.ts       |   80.37 |    82.35 |   80.95 |   80.37 | ...1150,1153-1164 
  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      |   93.95 |    86.32 |      75 |   93.95 | ...41,491-492,508 
  sdk.ts           |    82.7 |     90.9 |   66.66 |    82.7 | ...00-204,242-264 
  ...on-context.ts |     100 |      100 |     100 |     100 |                   
  ...ion-events.ts |     100 |      100 |     100 |     100 |                   
  ...on-tracing.ts |   91.17 |    88.72 |    97.5 |   91.17 | ...1920,1949-1952 
  ...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         |   83.09 |     95.1 |   86.36 |   83.09 | ...1467,1471-1478 
  uiTelemetry.ts   |   97.18 |    93.93 |      88 |   97.18 | ...70,314,461-462 
 ...ry/qwen-logger |   74.23 |     80.7 |      70 |   74.23 |                   
  event-types.ts   |       0 |        0 |       0 |       0 |                   
  qwen-logger.ts   |   74.23 |    80.53 |   69.49 |   74.23 | ...1122,1160-1161 
 src/test-utils    |   96.38 |    98.61 |   83.33 |   96.38 |                   
  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.24 |    84.97 |      89 |   86.24 |                   
  ...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.76 |    86.77 |   81.25 |   82.76 | ...45-746,865-915 
  ...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.11 |    82.35 |   83.33 |   94.11 | 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 |   82.13 |    80.47 |   85.71 |   82.13 | ...3234,3236-3237 
  mcp-client.ts    |   80.03 |    86.58 |   89.47 |   80.03 | ...2272,2276-2279 
  ...ry-timeout.ts |     100 |      100 |     100 |     100 |                   
  mcp-errors.ts    |     100 |      100 |     100 |     100 |                   
  ...pool-entry.ts |   79.21 |    85.71 |   81.57 |   79.21 | ...1341,1349-1350 
  ...ool-events.ts |       8 |      100 |       0 |       8 | 132-158           
  mcp-pool-key.ts  |   97.46 |    93.93 |     100 |   97.46 | 176-177           
  ...ce-content.ts |   96.55 |    91.17 |     100 |   96.55 | 80-82             
  mcp-retry.ts     |   97.67 |    95.65 |     100 |   97.67 | 131-132           
  ...ion-config.ts |     100 |      100 |     100 |     100 |                   
  mcp-status.ts    |     100 |      100 |     100 |     100 |                   
  mcp-tool.ts      |   98.35 |    93.71 |     100 |   98.35 | ...-990,1045-1046 
  ...sport-pool.ts |   83.98 |     80.3 |   88.46 |   83.98 | ...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.82 |    83.09 |   88.46 |   91.82 | ...99,612,810-815 
  notebook-edit.ts |   85.71 |    77.08 |   81.25 |   85.71 | ...96-912,958-959 
  ...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 |    87.1 |    81.04 |   93.93 |    87.1 | ...78-879,903-904 
  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 |   94.07 |    91.89 |    90.9 |   94.07 | 131-139           
  shell.ts         |   78.96 |    84.29 |      93 |   78.96 | ...5036,5111-5112 
  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     |   80.43 |    86.36 |   83.33 |   80.43 | ...67,121,125-132 
  task-stop.ts     |   93.14 |    96.15 |   85.71 |   93.14 | 39-40,54-64       
  task-update.ts   |   82.87 |    86.41 |    92.3 |   82.87 | ...54-564,588-599 
  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 | ...76-577,593-599 
  ...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.58 |    83.57 |      80 |   90.58 | ...1025,1083-1086 
  write-file.ts    |      87 |    85.48 |   88.88 |      87 | ...26-829,866-901 
  zoom-image.ts    |   95.76 |    93.75 |      90 |   95.76 | 54-59,203-204     
 src/tools/agent   |   86.97 |    87.71 |   88.49 |   86.97 |                   
  agent.ts         |   85.56 |    86.65 |   86.02 |   85.56 | ...4274,4308-4318 
  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.9 |    85.18 |   77.77 |    86.9 |                   
  workflow.ts      |    86.9 |    85.18 |   77.77 |    86.9 | ...08,553,555-556 
 src/utils         |   93.14 |    89.85 |   96.83 |   93.14 |                   
  LruCache.ts      |     100 |      100 |     100 |     100 |                   
  ...Controller.ts |     100 |      100 |     100 |     100 |                   
  ...ssageQueue.ts |     100 |      100 |     100 |     100 |                   
  ...cFileWrite.ts |      95 |     92.7 |     100 |      95 | ...49-550,657-661 
  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 |                   
  ...igResolver.ts |     100 |      100 |     100 |     100 |                   
  ...engthError.ts |   91.06 |    89.47 |     100 |   91.06 | ...46-147,154-155 
  ...n-branches.ts |   95.89 |    94.11 |      95 |   95.89 | ...99-500,512-525 
  ...tion-chain.ts |     100 |      100 |     100 |     100 |                   
  cronDisplay.ts   |     100 |    97.61 |     100 |     100 | 46                
  cronParser.ts    |   95.34 |    93.33 |     100 |   95.34 | 41-42,47-48,70-71 
  debugLogger.ts   |   96.66 |    96.61 |   88.88 |   96.66 | 192-196           
  editHelper.ts    |   93.63 |     83.9 |     100 |   93.63 | ...27-428,462-463 
  editor.ts        |   97.65 |    95.45 |     100 |   97.65 | ...35-336,338-339 
  encoding.ts      |     100 |      100 |     100 |     100 |                   
  env.ts           |     100 |      100 |     100 |     100 |                   
  ...arResolver.ts |   94.28 |    88.88 |     100 |   94.28 | 28-29,125-126     
  ...entContext.ts |   96.63 |    90.13 |   96.66 |   96.63 | ...42,444-445,512 
  errorParsing.ts  |     100 |      100 |     100 |     100 |                   
  ...rReporting.ts |   95.65 |    93.33 |     100 |   95.65 | 37-38             
  errors.ts        |   88.92 |    93.58 |   66.66 |   88.92 | ...92,394,410-411 
  fetch.ts         |   90.68 |    82.51 |     100 |   90.68 | ...72,483-484,503 
  file-identity.ts |     100 |      100 |     100 |     100 |                   
  fileUtils.ts     |   95.05 |    92.71 |   96.15 |   95.05 | ...1988,1996-1997 
  forkedAgent.ts   |   92.98 |    83.78 |   94.44 |   92.98 | ...77,685,690-697 
  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 
  ...fig-safety.ts |   97.01 |       80 |     100 |   97.01 | 53-54             
  git-ignore.ts    |     100 |      100 |     100 |     100 |                   
  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.83 |    82.35 |    87.5 |   78.83 | ...22-123,164-215 
  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.08 |    93.33 |     100 |   95.08 | ...62-166,234-238 
  ...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.41 |    93.54 |     100 |   95.41 | ...27-328,370-373 
  ...-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 |   93.42 |    90.72 |     100 |   93.42 | ...11,370,592-595 
  ...tProcessor.ts |   94.01 |    89.88 |     100 |   94.01 | ...47-353,445-446 
  ...Inspectors.ts |     100 |      100 |     100 |     100 |                   
  modelId.ts       |   98.96 |    98.18 |     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         |   90.88 |    90.66 |     100 |   90.88 | ...28-629,631-633 
  pdf.ts           |   92.17 |    85.81 |     100 |   92.17 | ...64-565,606-611 
  ...s-liveness.ts |     100 |    93.47 |     100 |     100 | 62,72,108         
  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.08 |     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.71 |   96.29 |   84.87 | ...71,696,725-734 
  ...odelPrefix.ts |     100 |      100 |     100 |     100 |                   
  runtimeStatus.ts |   97.77 |    91.48 |     100 |   97.77 | 172-173           
  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 |       90 |     100 |     100 | 95                
  ...orageUtils.ts |   96.21 |    85.21 |     100 |   96.21 | ...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.26 |    88.58 |     100 |   86.26 | ...2295,2302-2306 
  ...lAstParser.ts |    98.3 |    91.59 |     100 |    98.3 | ...1340-1342,1352 
  ...ContextEnv.ts |     100 |    94.73 |     100 |     100 | 76,111            
  ...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             
  ...repeat-key.ts |     100 |      100 |     100 |     100 |                   
  ...name-utils.ts |     100 |      100 |     100 |     100 |                   
  ...-finalizer.ts |    98.1 |     92.3 |   93.33 |    98.1 | ...34-235,237-241 
  ...iagnostics.ts |   99.06 |     97.7 |   91.66 |   99.06 | 132-133,204       
  ...-retention.ts |     100 |    95.83 |     100 |     100 | 116               
  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.39 |     100 |   96.13 | ...34-339,341-346 
  ...pt-records.ts |   87.58 |    86.13 |     100 |   87.58 | ...79-483,513-528 
  truncation.ts    |   90.61 |    90.51 |     100 |   90.61 | ...53-461,498-504 
  windowsPath.ts   |   89.47 |    79.31 |     100 |   89.47 | ...57-58,62,90-91 
  ...ifact-path.ts |   94.11 |    92.85 |     100 |   94.11 | 32-33             
  ...aceContext.ts |   95.39 |    89.47 |     100 |   95.39 | ...16-317,321-322 
  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 |   71.04 |    75.92 |   91.17 |   71.04 |                   
  ...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 |     100 |      100 |     100 |     100 |                   
  textTokenizer.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |       0 |        0 |       0 |       0 | 1                 
-------------------|---------|----------|---------|---------|-------------------

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

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Re-run against f9333d06 (nine commits since the last gate pass, via the review rounds and the takeover loop) — the gate stands on every point.

  • Template ✓ — all required sections present; the Chinese summary mirrors them.
  • Problem — observed, measured, linked: the fix(review): clear the deferred-suggestion backlog from #9175's review rounds #9342 timeline (review posted 11:56:34Z → job failed 12:00:53Z → contradicting fallback comment 12:01:00Z), the run link, and the concrete consequence — the autofix loop read the false comment and merged main + re-ran CI. That is the evidence bar, cleared.
  • Direction — aligned. The pipeline's own output asserting the opposite of the evidence beside it is the defect class this repo keeps paying down. The fix is scoped to the two comment-posting sites and deliberately leaves the failure classifier alone — the right cut, and the PR says why.
  • Size — not applicable: no core paths (one workflow YAML + its test file). The executable change is ~30 lines of bash across two sites; the rest is rationale comments and tests.
  • Approach — scope is right. The final /review round on this head reports no blockers, with the remaining Suggestions explicitly deferred to a follow-up per the standing round-5+ rule; nothing in the diff beyond the stated goal.
  • Risk — no high-risk path matches; no elevated risk signals.

Moving on to code review. 🔍

中文说明

针对 f9333d06 重跑(距上次 gate 通过已有九个提交,来自评审各轮与接管循环)——各关卡依然全部通过。

  • 模板 ✓ —— 各节齐全,中文说明与之对应。
  • 问题 —— 已观测、已度量、已关联:fix(review): clear the deferred-suggestion backlog from #9175's review rounds #9342 的时间线(11:56:34Z review 已发布 → 12:00:53Z 作业失败 → 12:01:00Z 自相矛盾的兜底评论)、run 链接、以及具体后果——autofix 循环读了这条错误评论并合并 main、重跑 CI。证据门槛已达标。
  • 方向 —— 对齐。流水线自身输出与其旁边的证据相反,正是本仓库反复偿还的缺陷类别。修复限定在两个发帖站点,刻意不动失败分类器——这个切分是对的,PR 中也说明了原因。
  • 规模 —— 不适用:未触及核心路径(一个 workflow YAML 加其测试文件)。可执行改动为两个站点共约 30 行 bash;其余为说明性注释与测试。
  • 方案 —— 范围合理。该 head 上的最后一轮 /review 报告无阻塞项,剩余 Suggestions 按第 5 轮后的惯例显式延期至后续跟进;diff 中没有超出既定目标的内容。
  • 风险 —— 未命中高风险路径;无升级风险信号。

进入代码审查 🔍

Qwen Code · qwen3.8-max

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

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Code review — no blockers. My independent take before reading the diff: attribute "did this run already post a review?" via the reviews API, scoped to the bot's own account and a submission window opening at the run's start, fail-open whenever the evidence is unavailable. The PR matches that baseline and improves on it in the one place my proposal was naive: the bot account is shared — release finalize, triage finalize, and the triage skill all approve under it — so matching any in-window bot review would let a foreign LGTM buy silence for a genuinely dead run. The guard instead matches positively on what only this pipeline's composed reviews carry (the via Qwen Code /review footer or the qwen-review-ledger marker), and exclusion-by-name is provably unfinished here: round 3 found a third approval body the shipped list missed.

What I verified against f9333d06:

  • Both sites reach the guard with a provably non-empty bot_login — the in-job step's dedup branch exits 0 before it otherwise, the fallback job's retry loop exits 1. FALLBACK_MARKER is workflow-level env, so both sites see it.
  • The marker premise holds in the composer — the ledger marker rides the body the posting path actually sends (compose-review.ts appends it where submit reads it; it withholds only when the plan names no PR, which this pipeline never does), and the three known foreign approval bodies in the repo match the test's FOREIGN_APPROVAL_BODIES exactly — none carries either marker.
  • The jq filter's edges behave — a PENDING review (null submitted_at) fails >= under jq's type ordering, ISO-8601 Z timestamps compare correctly as strings, and --paginate covers heavily-reviewed PRs like this one. Each edge is pinned by its own test, and the tests run the steps' real bash through the steps' own filter — the guard is that filter, so nothing is re-implemented.
  • Each anchor decision has a discriminating testcreatedAt over startedAt (the stub answers the two with different values; a failed-job re-run keeps the run id but moves startedAt), and time over head (a review on any head inside the window silences; carries no cross-job head wiring pins that the deleted round-2 wiring stays deleted).
  • The tightened assertion is scoped correctly — it pins the head lookups themselves (headSha, --json headRefOid) so the guard's gh run view --json createdAt can't read as a head comparison.
  • One non-blocking note: two description details lag the final code — the body still says the job-level step reads state and headRefOid in one call (round-2 shape; round 3 reverted it to state-only) and quotes 165 tests (the suite at head runs 174, per CI). The code is right; the prose is stale.

Test evidence — the PR's own CI, read via the API (per policy this review never executes PR code). On f9333d06 everything landed green: 15 checks success, 42 skipped (review-pipeline orchestration for the three bot-triggered runs on this commit), 0 failures, 0 pending. The Test (ubuntu-latest, Node 22.x) job log shows the touched suite actually executing — ✓ scripts/tests/qwen-pr-review-workflow.test.js (174 tests) 2899ms — so a green suite that never ran the change is ruled out.

CI on the reviewed commit:

Check Conclusion
Qwen Code CI / Test (ubuntu-latest, Node 22.x) ✅ success
Qwen Code CI / Secret scan (TruffleHog) ✅ success
Qwen Code CI / Dependency CVE audit ✅ success
Qwen Code CI / Desktop Shell (ubuntu-22.04) ✅ success
Qwen Code CI / Desktop Shell (windows-2022) ✅ success
Qwen Code CI / web-shell E2E Smoke (ubuntu-latest, Node 22.x) ✅ success
Qwen Code CI / Post Coverage Comment ✅ success
Security Checks ✅ success
42 orchestration checks (review pipeline × 3 runs) ⏭️ skipped

Not verified here: live GitHub API behavior — the guard's gh run view --json createdAt and reviews-listing calls against real responses. The suite pins the filter against realistic fixtures through real jq, which is as far as offline evidence reaches. The sandboxed run that can settle the remainder is already in flight — verify run 32423632774; its report will post to this thread.

Real-scenario (tmux): N/A — CI-only change with no user-visible surface. The observable behavior (the fallback comment appearing or not) is asserted directly by the suite above.

中文说明

代码审查——无阻塞项。 读 diff 前的独立方案:通过 reviews API 判定「本次运行是否已发布过 review」,范围限定为 bot 自身账号、以运行开始为起点的提交窗口,证据不可得时放行(照发)。PR 与该基线一致,并在我的方案天真之处做了改进:bot 账号是共享的——release finalize、triage finalize、triage skill 都以它发 approval——因此匹配窗口内任意 bot review 会让外来 LGTM 为真正死掉的运行买到静默。守卫改为正向匹配只有本流水线组成的 review 才携带的东西(via Qwen Code /review 落款或 qwen-review-ledger 标记);按名字排除在此被证明无法穷尽:第 3 轮就发现了线上列表遗漏的第三种 approval 正文。

针对 f9333d06 核实的内容:

  • 两个站点到达守卫时 bot_login 均 provably 非空 —— job 内步骤的 dedup 分支否则先行 exit 0,兜底作业的重试循环失败则 exit 1。FALLBACK_MARKER 是 workflow 级 env,两站点都可见。
  • 标记前提在 composer 中成立 —— ledger 标记挂在发布路径真正发送的正文上(compose-review.tssubmit 读取处附加;仅当 plan 未指明 PR 时才不发,而本流水线永远指明),仓库中三个已知的外来 approval 正文与测试的 FOREIGN_APPROVAL_BODIES 完全一致,均不含任一标记。
  • jq 过滤器的边界行为正确 —— PENDING review(submitted_at 为 null)在 jq 类型序下不满足 >=;ISO-8601 Z 时间戳按字符串比较正确;--paginate 覆盖如本 PR 般评审密集的场景。每个边界各有专属测试钉住,且测试执行的是步骤的真实 bash、走的是步骤自己的过滤器——守卫本身就是那个过滤器,没有任何重新实现。
  • 每个锚点决定都有判别性测试 —— 用 createdAt 而非 startedAt(桩以不同值应答两者;失败 job 重跑保留 run id 但移动 startedAt);按时间而非 head(窗口内任意 head 上的 review 都触发静默;carries no cross-job head wiring 钉住第 2 轮被删除的接线不会复活)。
  • 收紧后的断言范围正确 —— 直接钉 head 查询本身(headSha--json headRefOid),使守卫的 gh run view --json createdAt 不会被误读为 head 比较。
  • 一条非阻塞提示:描述有两处落后于最终代码——正文仍写 job 级步骤一次调用读取 stateheadRefOid(第 2 轮形态;第 3 轮已改回只读 state),并引用 165 个测试(按 CI,head 上的套件为 174 个)。代码是对的,行文过时。

测试证据——来自 PR 自己的 CI,经 API 读取(按规约本审查不执行 PR 代码)。f9333d06 全绿落地:15 项 success、42 项 skipped(该提交上三次 bot 触发运行的评审流水线编排任务)、0 失败、0 pending。Test (ubuntu-latest, Node 22.x) 的 job 日志显示被改动的套件真实执行——✓ scripts/tests/qwen-pr-review-workflow.test.js (174 tests) 2899ms——排除了「套件全绿但从未运行该改动」的可能。CI 表格见上方标记区域(由 finalize 工作流在 CI 落定后就地更新)。此处未验证:真实 GitHub API 行为——守卫的两次 API 调用对真实响应的表现。套件通过真实 jq 以贴近真实的夹具钉住了过滤器,离线证据到此为止。能补上其余部分的沙箱运行已在进行中(verify run 32423632774),报告将发布到本线程。

真实场景(tmux):N/A——纯 CI 改动,无用户可见面。可观测行为(兜底评论出现与否)由上述套件直接断言。

Qwen Code · qwen3.8-max

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

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Confidence: 4/5 — a minimal, well-evidenced fix that matches the approach I'd have proposed independently and improves on it where my proposal was naive; the one reservation is the live-API behavior no offline test can cover, which is inherent to the change (and has a verify run in flight) rather than doubt about it.

Stepping back: this is the incident class this pipeline keeps paying down — prose asserting the opposite of the evidence beside it — and the PR measured its incident precisely (timestamps, run link, the autofix-loop consequence) instead of asserting it abstractly. Ten review rounds plus three takeover rounds is a long road, but the convergence is real: the final round on this head found nothing, the leftover Suggestions are explicitly deferred to a follow-up, and every load-bearing decision in the shipped design — attribute by time, not head; anchor on createdAt, not startedAt; match positively on composed-review markers instead of an exclusion list; fail open wherever evidence is unavailable — has a discriminating test that fails if that decision is reverted. The redesign went subtractive where it mattered: round 3 deleted the unstable head clause and its cross-job wiring rather than patching them a third time. If I were maintaining this in six months, the comment blocks would tell me exactly why each clause exists and which test punishes removing it.

Actions taken in this pass, transparently:

  • Approved, pinned to the reviewed commit through the reviews API (so a force-push between check and act can't inherit the approval).
  • Dismissed the bot's own five stale CHANGES_REQUESTED reviews — the stage-1a template gate and the round reviews on a062d6deb9b9c96. Every finding they raised is resolved per this thread and superseded by the final no-blocker review on this head; GitHub does not auto-dismiss request-changes on push, so left alone they would block the merge indefinitely.
  • For the maintainers: main requires two approvals, and @doudouOUC's earlier approval was dismissed by the autofix pushes — a human re-approval is still needed. The sandboxed verify run 32423632774 is still in flight; its report will land in this thread.
中文说明

置信度:4/5 —— 一个最小且证据充分的修复,与我独立提出的方案一致,并在我的方案天真之处做了改进;唯一的保留是任何离线测试都无法覆盖的真实 API 行为——这是改动本身的属性(且已有 verify 运行在途),而非对它的怀疑。

退后一步看:这正是本流水线反复偿还的事故类别——散文断言与其旁边的证据相反——而本 PR 精确度量了它的事故(时间戳、run 链接、autofix 循环后果),而非抽象断言。十轮评审加三轮接管是一段长路,但收敛是真实的:该 head 上的最后一轮未发现任何问题,遗留的 Suggestions 已显式延期至后续跟进,且最终设计中每个承重决定——按时间而非 head 归因;锚定 createdAt 而非 startedAt;正向匹配组成型 review 的标记而非排除列表;证据不可得时一律放行——都有判别性测试,一旦回退该决定即失败。重构在关键处做减法:第 3 轮删除了不稳定的 head 子句及其跨 job 接线,而不是第三次打补丁。若六个月后由我维护,这些注释块恰好说明每个子句为何存在、哪个测试惩罚删除它。

本次执行的操作,透明列出:

  • 已批准,通过 reviews API 钉在所审提交上(check 与 act 之间的 force-push 无法继承该批准)。
  • 驳回了 bot 自己的五条陈旧 CHANGES_REQUESTED 评审 —— stage-1a 模板关卡与 a062d6deb9b9c96 上的各轮评审。它们提出的每条发现均已按本线程解决,并被该 head 上最终的无阻塞评审取代;GitHub 不会在 push 时自动驳回 request-changes,若放任不管将无限期阻塞合并。
  • 对维护者:main 需要两个批准,@doudouOUC 较早的批准已被 autofix 的 push 驳回——仍需人类重新批准。沙箱 verify 运行(32423632774)仍在进行,报告将发布到本线程。

Qwen Code · qwen3.8-max

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

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Triage re-run completed without a new review.

The bot already has a review of its own on a062d6d829a0160216a041c4dc8dc80e26d3eb9e, which still stands.

机器人在 a062d6d829a0160216a041c4dc8dc80e26d3eb9e 上已有自己的评审,且仍然有效。

The stage comments above were updated with the latest result. View workflow run.

上方各阶段评论已更新为最新结果。查看工作流运行

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Partially reviewed — gaps disclosed.

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

Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/qwen-code-pr-review.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

中文说明

仅完成部分审查,审查缺口已披露。

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

未检查(工具限制,非阻断):the executable-script lint — .github/workflows/qwen-code-pr-review.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

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

Comment on lines +1767 to +1768
run_started="$(gh run view "${GITHUB_RUN_ID:?}" --repo "$GITHUB_REPOSITORY" --json startedAt --jq '.startedAt' 2>/dev/null)" || run_started=""
if [ -n "$run_started" ] && [ -n "$current_head" ]; 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.

[Critical] The time anchor of this guard resets on job re-runs. gh run view --json startedAt returns the LATEST attempt's start, not the run's first start — and re-runs keep the same run id (the dedup comment just above relies on exactly that). So when attempt 1 of this run posts its review and the job fails after the post (the incident shape this PR fixes, measured on PR 9342), a re-run re-anchors startedAt to attempt 2's start: attempt 1's review no longer satisfies select(.submitted_at >= "$run_started"), and if attempt 2 then fails before posting, this step posts 'The review pipeline failed before a review could be posted … retry with @qwen-code /review' directly beneath the review attempt 1 already posted — the exact contradiction this PR exists to eliminate. Measured against this repo's own data:

gh api repos/QwenLM/qwen-code/actions/runs/32219268680
→ created_at 2026-08-19T05:23:57Z, run_attempt 2, run_started_at 2026-08-19T05:51:26Z
attempt-1 jobs created 05:23:57–05:24:10Z; attempt-2 jobs created from 05:51:27Z
re-run 32218596441: created_at 05:13:04Z → run_started_at 05:22:05Z (same reset)

Run-level startedAt equals the re-executed attempt's start while createdAt stays attempt-stable. Note the new stale fixture pins exactly this shape as the intended posting behavior from attempt 2's re-anchored window. Anchor on an attempt-stable timestamp instead — --json createdAt --jq '.createdAt' — at both sites: a review submitted after the run was created still cannot belong to an earlier run, so the stale-review-from-earlier-run protection is preserved. The test stub's *startedAt* dispatch pattern needs a matching update (with RUN_STARTED fixture values re-derived from createdAt).

Suggested change
run_started="$(gh run view "${GITHUB_RUN_ID:?}" --repo "$GITHUB_REPOSITORY" --json startedAt --jq '.startedAt' 2>/dev/null)" || run_started=""
if [ -n "$run_started" ] && [ -n "$current_head" ]; then
run_started="$(gh run view "${GITHUB_RUN_ID:?}" --repo "$GITHUB_REPOSITORY" --json createdAt --jq '.createdAt' 2>/dev/null)" || run_started=""
if [ -n "$run_started" ] && [ -n "$current_head" ]; then
中文说明

【Critical】 该守卫的时间锚点在作业重跑(re-run)时会被重置。gh run view --json startedAt 返回的是最新一次 attempt 的开始时间,而不是整个 run 最初的开始时间——而重跑保持同一个 run id(上方的 dedup 注释正是依赖这一点)。因此,当本次运行的 attempt 1 已发布 review、作业在发布之后才失败(本 PR 要修的正是这种形态,实测于 PR 9342),重跑会把 startedAt 重新锚定到 attempt 2 的开始时间:attempt 1 的 review 不再满足 select(.submitted_at >= "$run_started");若 attempt 2 又是在发布前失败,这一步就会在 attempt 1 已发布的 review 正下方发出「The review pipeline failed before a review could be posted … retry with @qwen-code /review」——这正是本 PR 要消除的自相矛盾。已在本仓库数据上实测:

gh api repos/QwenLM/qwen-code/actions/runs/32219268680
→ created_at 2026-08-19T05:23:57Z, run_attempt 2, run_started_at 2026-08-19T05:51:26Z
attempt-1 jobs created 05:23:57–05:24:10Z; attempt-2 jobs created from 05:51:27Z
re-run 32218596441: created_at 05:13:04Z → run_started_at 05:22:05Z(同样的重置)

run 级 startedAt 等于重跑 attempt 的开始时间,而 createdAt 在各 attempt 间保持不变。另请注意:新增的 stale 夹具从 attempt 2 的重锚窗口看,恰好把这种形态钉成了「应当照常发帖」。建议改为锚定 attempt 稳定的时间戳——两处站点均改用 --json createdAt --jq '.createdAt':review 只要在 run 创建之后提交就不可能属于更早的 run,因此「更早 run 的陈旧 review 不能买到静默」这一保护仍然成立。测试桩里的 *startedAt* 分发模式需要同步更新(RUN_STARTED 夹具值也需改为按 createdAt 取值)。

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

Comment on lines +1979 to +1980
run_started="$(gh run view "${GITHUB_RUN_ID:?}" --repo "$GITHUB_REPOSITORY" --json startedAt --jq '.startedAt' 2>/dev/null)" || run_started=""
if [ -n "$run_started" ] && [ -n "$pr_head" ]; 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.

[Critical] Same defect as the in-job copy: the time anchor resets on job re-runs. gh run view --json startedAt returns the LATEST attempt's start, not the run's first start, and re-runs keep the same run id. When attempt 1 of this run posts its review and fails after the post, a re-run re-anchors startedAt to attempt 2's start; attempt 1's review then fails select(.submitted_at >= "$run_started"), and if attempt 2 fails before posting, this job posts 'The review pipeline failed before a review could be posted … retry with @qwen-code /review' directly beneath the review attempt 1 already posted. Measured against this repo's own data: re-run 32219268680 has attempt-1 jobs created 05:23:57–05:24:10Z but run-level run_started_at reads 05:51:26Z (the re-executed attempt's start, 05:51:27Z); re-run 32218596441 shows the same reset (05:13:04Z → 05:22:05Z), while createdAt stays attempt-stable. Anchor on --json createdAt --jq '.createdAt' instead, at both sites: a review submitted after the run was created still cannot belong to an earlier run, so the stale-review protection is preserved. The test stub's *startedAt* dispatch pattern needs a matching update.

Suggested change
run_started="$(gh run view "${GITHUB_RUN_ID:?}" --repo "$GITHUB_REPOSITORY" --json startedAt --jq '.startedAt' 2>/dev/null)" || run_started=""
if [ -n "$run_started" ] && [ -n "$pr_head" ]; then
run_started="$(gh run view "${GITHUB_RUN_ID:?}" --repo "$GITHUB_REPOSITORY" --json createdAt --jq '.createdAt' 2>/dev/null)" || run_started=""
if [ -n "$run_started" ] && [ -n "$pr_head" ]; then
中文说明

【Critical】 与 in-job 那份副本相同的缺陷:时间锚点在作业重跑时会被重置。gh run view --json startedAt 返回的是最新一次 attempt 的开始时间而非 run 最初的开始时间,且重跑保持同一个 run id。当本次运行的 attempt 1 已发布 review、作业在发布之后失败时,重跑会把 startedAt 重新锚定到 attempt 2 的开始时间;于是 attempt 1 的 review 不再满足 select(.submitted_at >= "$run_started");若 attempt 2 在发布前失败,这个作业就会在 attempt 1 已发布的 review 正下方发出「The review pipeline failed before a review could be posted … retry with @qwen-code /review」。已在本仓库数据上实测:re-run 32219268680 的 attempt-1 作业创建于 05:23:57–05:24:10Z,但 run 级 run_started_at 读数为 05:51:26Z(即重跑 attempt 的开始时间 05:51:27Z);re-run 32218596441 显示同样的重置(05:13:04Z → 05:22:05Z),而 createdAt 在各 attempt 间保持不变。建议两处站点均改为锚定 --json createdAt --jq '.createdAt':review 只要在 run 创建之后提交就不可能属于更早的 run,陈旧 review 的防护仍然成立。测试桩里的 *startedAt* 分发模式需要同步更新。

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

run_started="$(gh run view "${GITHUB_RUN_ID:?}" --repo "$GITHUB_REPOSITORY" --json startedAt --jq '.startedAt' 2>/dev/null)" || run_started=""
if [ -n "$run_started" ] && [ -n "$current_head" ]; then
posted_reviews="$(gh api "repos/${GITHUB_REPOSITORY}/pulls/${PR_NUMBER}/reviews" --paginate \
--jq ".[] | select(.user.login == \"$bot_login\") | select(.commit_id == \"$current_head\") | select(.submitted_at >= \"$run_started\") | .id" 2>/dev/null)" || posted_reviews=""

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] Both lookups this guard relies on swallow every failure (2>/dev/null, || var="") and write nothing anywhere, so a failed guard degrades to the exact bug this PR fixes with zero trace. A transient API 5xx or secondary rate limit hitting gh run view or the reviews listing empties run_started/posted_reviews, the guard declines to fire, and the contradictory fallback comment posts — and the oncall investigating the recurrence finds no log line distinguishing 'the guard ran, nothing matched' from 'the lookup died'. Every adjacent lookup in these same steps announces its failures ('Fallback comment dedup lookup failed; deferring…', '::error::could not verify PR…'). Emit a ::warning:: and/or a step-summary line such as 'Already-posted guard unavailable (lookup failed); proceeding to post' before continuing, at both sites — no behavior change.

中文说明

【Suggestion】 该守卫依赖的两处查询都把失败完全吞掉(2>/dev/null|| var=""),且不留任何痕迹,因此守卫失效时会悄无声息地退化成本 PR 要修的那个 bug。一次瞬时的 API 5xx 或次级限流命中 gh run view 或 reviews 列表查询时,run_started/posted_reviews 变为空,守卫拒绝触发,自相矛盾的兜底评论照常发出——而事后排查的 oncall 找不到任何日志能区分「守卫执行了但没有匹配」与「查询本身挂了」。同一批步骤里所有相邻查询都会宣告自己的失败('Fallback comment dedup lookup failed; deferring…'、'::error::could not verify PR…')。建议在两处站点查询失败时先发一条 ::warning:: 和/或 step-summary(如 'Already-posted guard unavailable (lookup failed); proceeding to post')再继续——不改变任何行为。

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

run_started="$(gh run view "${GITHUB_RUN_ID:?}" --repo "$GITHUB_REPOSITORY" --json startedAt --jq '.startedAt' 2>/dev/null)" || run_started=""
if [ -n "$run_started" ] && [ -n "$pr_head" ]; then
posted_reviews="$(gh api "repos/${GITHUB_REPOSITORY}/pulls/${PR_NUMBER}/reviews" --paginate \
--jq ".[] | select(.user.login == \"$bot_login\") | select(.commit_id == \"$pr_head\") | select(.submitted_at >= \"$run_started\") | .id" 2>/dev/null)" || posted_reviews=""

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] Same silent-failure gap as the in-job copy: both lookups swallow every failure (2>/dev/null, || var="") with no trace, so a transient API failure here degrades to the exact bug this PR fixes, with nothing in the logs distinguishing 'no matching review' from 'lookup died' — while every adjacent lookup in this step announces its failures ('::error::fallback comment dedup lookup failed after retries', '::error::could not verify PR…'). Emit a ::warning:: and/or a step-summary line on lookup failure before continuing — no behavior change.

中文说明

【Suggestion】 与 in-job 副本相同的静默失败缺口:两处查询都把失败完全吞掉(2>/dev/null|| var="")且不留痕迹,因此这里一次瞬时的 API 失败就会退化成本 PR 要修的那个 bug,日志中没有任何东西能区分「没有匹配的 review」与「查询挂了」——而本步骤里所有相邻查询都会宣告自己的失败('::error::fallback comment dedup lookup failed after retries'、'::error::could not verify PR…')。建议查询失败时先发一条 ::warning:: 和/或 step-summary 再继续——不改变任何行为。

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

' *state,headRefOid*)',
' [ "${SCENARIO:-}" = "state_fail" ] && exit 1',
' printf "OPEN\\t%s\\n" "${PR_HEAD:-}"; exit 0 ;;',
' state=OPEN; [ "${SCENARIO:-}" = "pr_closed" ] && state=MERGED',

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 migration leaves the stub's *state*) branch unreachable. The fallback job's standalone gh pr view --json state call was that branch's only consumer, and the new --json state,headRefOid form matches the earlier *state,headRefOid*) branch in case order. I parsed the workflow and enumerated every gh call in both extracted step scripts: zero standalone --json state queries remain, so nothing can reach *state*) — its state_fail/pr_closed handling now exists in two branches, and this diff itself demonstrates the trap: pr_closed had to be migrated into the live branch because the dead one no longer sees the call. A future edit adding a scenario to the dead branch would be silently a no-op, and a reader cannot tell which branch is authoritative. Delete the dead *state*) branch (the three lines right after the *headRefOid*) branch).

中文说明

【Suggestion】 这次迁移让桩里的 *state*) 分支变得不可达。兜底作业原先独立的 gh pr view --json state 调用是该分支唯一的消费者,而新的 --json state,headRefOid 形式按 case 顺序会先命中前面的 *state,headRefOid*) 分支。我解析了 workflow 并枚举两个被抽取步骤脚本里的所有 gh 调用:独立的 --json state 查询已经为零,没有任何调用能到达 *state*)——它的 state_fail/pr_closed 处理现在存在于两个分支里,而本 diff 恰好演示了这个陷阱:pr_closed 不得不迁到活分支,因为死分支已经看不到该调用了。未来若有人往死分支里加场景,会悄无声息地变成空操作,读者也无法判断哪个分支才是权威的。建议删除死掉的 *state*) 分支(紧跟在 *headRefOid*) 分支之后的三行)。

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

// review-pr failed 12:00:53Z, the comment landed 12:01:00Z asking for a
// fresh ~3-hour review; the autofix takeover loop reads the same feed a
// human does. The guard is a FILTER (author scope, head, submission
// time), so these run the step's real bash over review fixtures.

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] These tests run the extracted in-job script verbatim, but bash chokes on MAX_TIMEOUT_MINUTES="${{ vars.QWEN_REVIEW_MAX_TIMEOUT_MINUTES }}" (workflow line 1776): the assignment is skipped with a bad substitution error and MAX_TIMEOUT_MINUTES stays unset, so for that line the tests do not actually run 'the step's real bash' as this comment claims. Measured: the full suite prints exactly 8 bash: line 52: …: bad substitution lines — this diff's new tests add 7 of them (the eighth new test exits at the guard before reaching the line; the fallback-job block contains no ${{ }}). Every suite run now normalizes eight lines of bash error output mixed with any real failure's diagnostics, and any future in-job test of the FAILURE_KIND=timeout body — the only branch that reads this variable — evaluates [ "$TIMEOUT_MINUTES" -lt "$MAX_TIMEOUT_MINUTES" ] with the variable unset, errors, and falls into the wrong branch, so a timeout-variant test would pass or fail for the wrong reason. Substitute the expression before executing, e.g. in runFallbackStep: (useInJobStep ? inJobStep.run : step.run).replaceAll('${{ vars.QWEN_REVIEW_MAX_TIMEOUT_MINUTES }}', '<repo default>') — using the repo's real default so future timeout-variant tests are meaningful. Verified: the fix flips 8 errors → 0 with the suite still green.

中文说明

【Suggestion】 这些测试原样执行抽取出的 in-job 脚本,但 bash 会在 MAX_TIMEOUT_MINUTES="${{ vars.QWEN_REVIEW_MAX_TIMEOUT_MINUTES }}"(workflow 第 1776 行)上报 bad substitution 错误并跳过该赋值,MAX_TIMEOUT_MINUTES 保持未设置——因此对这一行而言,测试并未像此注释所宣称的那样运行「步骤的真实 bash」。实测:完整套件恰好打印 8 行 bash: line 52: …: bad substitution——本 diff 的新测试贡献了其中 7 行(第 8 个新测试在到达该行前就已在守卫处退出;兜底作业的代码块不含任何 ${{ }})。现在每次运行套件都会把 8 行 bash 错误输出当作常态混入 stderr,与真实失败的诊断信息混在一起;而未来任何针对 FAILURE_KIND=timeout 分支(唯一读取该变量的分支)的 in-job 测试,都会在变量未设置的情况下执行 [ "$TIMEOUT_MINUTES" -lt "$MAX_TIMEOUT_MINUTES" ],报错后落入错误分支——timeout 变体测试会因为错误的原因通过或失败。建议在执行前先替换该表达式,例如在 runFallbackStep 中:(useInJobStep ? inJobStep.run : step.run).replaceAll('${{ vars.QWEN_REVIEW_MAX_TIMEOUT_MINUTES }}', '<repo default>')——用仓库的真实默认值,让未来的 timeout 变体测试有意义。已验证:该修复把 8 个错误降为 0,套件仍然全绿。

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

…ay when it cannot run

Round 1's two blockers, both re-verified against this repo's own run data.

The time anchor reset on job re-runs. `gh run view --json startedAt`
returns the LATEST attempt's start while the run id stays the same — the
dedup above relies on that stability — so a re-run pushed attempt 1's
review outside "this run": runs 32219268680 (created 05:23:57Z,
startedAt 05:51:26Z) and 32218596441 (05:13:04Z → 05:22:05Z) both show
the ~9-28 minute shift. Attempt 1 posts its review, the job fails after
the post, someone re-runs it, attempt 2 fails before posting — and the
guard, anchored on attempt 2's start, lets the contradictory comment
through. Exactly the shape this PR exists to stop, on the path most
likely to reach it. Both sites now anchor on `createdAt`, which is
attempt-stable; a review submitted after the run was created still
cannot belong to an earlier run, so the stale-review protection is
unchanged.

The guard also swallowed its own lookup failures. A transient failure
in either call emptied the value, the guard declined, and the false
comment posted with nothing in the log separating "the guard ran,
nothing matched" from "the lookup died" — while every sibling lookup in
these steps announces its failures. Both unavailable paths now emit a
`::warning::` and a step-summary line before posting. No behavior
change: posting was, and remains, the fail-open direction.

Tests: a re-run fixture per site, where the stub answers `createdAt` and
`startedAt` with DIFFERENT values and attempt 1's review sits between
them — reverting either site to `startedAt` fails exactly these two; and
a per-site assertion that both unavailable paths announce themselves.

Also from round 1, both verified before taking: the stub's standalone
`*state*)` branch is dead (no `--json state` call remains in either
extracted step) and is removed, so its scenarios cannot be edited into a
no-op; and the harness now substitutes `${{ vars.* }}` before running
the in-job script, which bash rejected as a bad substitution — the
assignment was skipped, `MAX_TIMEOUT_MINUTES` stayed unset, and eight
error lines rode every suite run, so "the step's real bash" was not
quite true for that line.
@wenshao

wenshao commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator Author

All six findings from round 1 are taken in f4a9053 — nothing deferred.

The two blockers were right, and I re-derived the evidence before changing anything. gh api repos/QwenLM/qwen-code/actions/runs/32219268680created_at 05:23:57Z, run_started_at 05:51:26Z, run_attempt 2; run 32218596441 shows the same reset (05:13:04Z → 05:22:05Z). So a re-run of a failed job — the path most likely to reach this guard — pushed attempt 1's review outside the window and let the contradictory comment through. Both sites now anchor on createdAt, and the pin is discriminating rather than incidental: the stub answers createdAt and startedAt with different values and the fixture review sits between them, so reverting either site to startedAt fails exactly the two new re-run tests (mutation-verified in both directions).

The silent-failure Suggestion is the same defect class this PR is about, so it was not a nit: both unavailable paths now emit ::warning::already-posted guard unavailable (…) plus a step-summary line before posting, with a per-site test asserting both. Behavior is unchanged — posting was and remains the fail-open direction.

The two test-hygiene Suggestions were verified before taking. I enumerated every gh … --json call in both extracted step scripts: no standalone --json state remains, so the *state*) branch really was unreachable — removed, rather than left as a place a future scenario could be edited into a no-op. And the harness now substitutes ${{ vars.QWEN_REVIEW_MAX_TIMEOUT_MINUTES }} before running the in-job script; bash rejected the raw expression as a bad substitution, which skipped the assignment, left the variable unset, and put eight error lines in every suite run — so the comment's claim that these tests run "the step's real bash" was not quite true for that one line. It is now.

Suite: 169 pass in this file (the one failure, repairs a single unwritable directory, reproduces on a pristine tree here and is unrelated); qwen-resolve-workflow and review-worktree-cleanup-workflow green; prettier and eslint clean.

中文说明

第 1 轮六条全部采纳(f4a9053472),无延后。

两条阻断项属实,我在动手前独立复核了证据gh api …/actions/runs/32219268680created_at 05:23:57Zrun_started_at 05:51:26Zrun_attempt 232218596441 同样漂移(05:13:04Z → 05:22:05Z)。因此「重跑失败作业」——最可能触达该守卫的路径——会把第 1 次尝试发布的 review 推出时间窗,放行自相矛盾的评论。两处改锚 createdAt,且钉住是有判别力的:桩对 createdAtstartedAt 返回不同值、夹具 review 落在两者之间,故任一处回退到 startedAt 都恰好让两条新增的重跑测试变红(已双向变异验证)。

「静默失败」那条与本 PR 要修的是同一类缺陷,因此不算小节:两条不可用路径现在都会先输出 ::warning::already-posted guard unavailable (…) 与 step-summary 行再发帖,并各有测试断言。行为不变——发帖依旧是 fail-open 方向。

两条测试卫生项也先核后改:我枚举了两个抽出脚本里所有 gh … --json 调用,确认已无独立 --json state,故 *state*) 分支确为死代码——删除,而不是留一个未来可能被无声改成 no-op 的地方。harness 现在在运行 in-job 脚本前替换 ${{ vars.QWEN_REVIEW_MAX_TIMEOUT_MINUTES }}:bash 会把原始表达式判为 bad substitution,跳过赋值、变量为空,并在每次跑套件时留下八行错误——所以「跑的是步骤真实 bash」这句话对那一行原本并不成立,现在成立了。

测试:本文件 169 通过(唯一失败 repairs a single unwritable directory 在原始树同样复现,与本改动无关);qwen-resolve-workflowreview-worktree-cleanup-workflow 全绿;prettier 与 eslint 干净。

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

Partially reviewed — gaps disclosed. Suggestions are inline.

Not reviewed: build-and-test — Test (macos-latest, Node 22.x) was skipped in CI (merge_group-gated) and its suite ran locally on Linux only.

Not explored to full depth (tool budget reached): "agent 2": none — no check was cut short.; "agent 4": none — no check was cut short..

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

Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/qwen-code-pr-review.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

Deferred under the convergence posture (round 2, not a blocker) — recorded, not requested in this round:

  • scripts/tests/qwen-pr-review-workflow.test.js:3459 — [review] new test comment says the guard asks gh run view for startedAt, but the guard queries createdAt
  • scripts/tests/qwen-pr-review-workflow.test.js:3285 — [review] reviews stub runs the host's jq; on a jq-less host the silence tests go red and the 'still posts' filter cases pass vacuously
  • scripts/tests/qwen-pr-review-workflow.test.js:3285 — [review] --paginate is unpinned; deleting it from the guard survives the suite while production reads only page 1
  • scripts/tests/qwen-pr-review-workflow.test.js:3281 — [review] gh api stub dispatches on the repos/ prefix alone; endpoint drift escapes the suite
中文说明

仅完成部分审查,审查缺口已披露。 建议见行内评论。

未审查:build-and-test — Test (macos-latest, Node 22.x) was skipped in CI (merge_group-gated) and its suite ran locally on Linux only。

未探索到全部深度(达到工具调用预算):"agent 2"none — no check was cut short."agent 4"none — no check was cut short.

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

未检查(工具限制,非阻断):the executable-script lint — .github/workflows/qwen-code-pr-review.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

收敛姿态下延后(第 2 轮,非阻断)——已记录,本轮不要求修改:共 4 条(原文未翻译,列表见上方英文部分)。

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

Comment on lines +1763 to +1766
# head this run reviewed, and a submission at or after this run
# started, so a stale review from an earlier run cannot silence a
# genuinely dead one; an unavailable start time or head declines to
# fire and posts.

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 opening paragraph of this guard comment still describes the round-1 startedAt anchor — "a submission at or after this run started", "an unavailable start time" — but the code below queries createdAt, and the very next paragraph says "The anchor is the run's CREATION, never its start" (the runtime warning likewise announces "no run creation time"). A maintainer editing this guard gets two contradictory anchors from the same block; trusting the first paragraph, they would conclude job re-runs break the guard — precisely the round-1 defect this revision removed. Suggest replacing "started" with "was created" and "start time" with "creation time" in the opening paragraph, here and in the fallback-comment job's twin.

Suggested change
# head this run reviewed, and a submission at or after this run
# started, so a stale review from an earlier run cannot silence a
# genuinely dead one; an unavailable start time or head declines to
# fire and posts.
# head this run reviewed, and a submission at or after this run
# was created, so a stale review from an earlier run cannot silence a
# genuinely dead one; an unavailable creation time or head declines to
# fire and posts.
中文说明

【Suggestion】 该守卫注释的首段仍在描述第一轮的 startedAt 锚点——「a submission at or after this run started」「an unavailable start time」——但其下方代码查询的是 createdAt,紧邻的下一段也写明「The anchor is the run's CREATION, never its start」(运行时警告同样提示「no run creation time」)。维护者编辑这段守卫时会从同一个注释块里得到两个互相矛盾的锚点;若相信首段,就会认为作业重跑会破坏守卫——而这正是本轮修订所移除的第一轮缺陷。建议将首段的「started」改为「was created」、「start time」改为「creation time」,此处与 fallback-comment 作业中的孪生副本同步修改。

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

Comment on lines +1995 to +1997
# reviewed, and a submission at or after this run started. When the
# start time or the head is unavailable the guard declines to fire —
# posting wins over silence, the same call the head-moved guard

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] Same stale-anchor wording as the in-job twin: this opening sentence says "a submission at or after this run started" and "when the start time or the head is unavailable", while the next paragraph states "The anchor is the run's CREATION, never its start" and the code queries createdAt. The same 10-line block gives a maintainer two contradictory anchors for the condition that decides re-run behavior. Suggest "at or after this run was created" / "creation time" here as well.

Suggested change
# reviewed, and a submission at or after this run started. When the
# start time or the head is unavailable the guard declines to fire —
# posting wins over silence, the same call the head-moved guard
# reviewed, and a submission at or after this run was created. When the
# creation time or the head is unavailable the guard declines to fire —
# posting wins over silence, the same call the head-moved guard
中文说明

【Suggestion】 与 in-job 那份副本相同的陈旧锚点措辞:首句写「a submission at or after this run started」「when the start time or the head is unavailable」,而下一段写明「The anchor is the run's CREATION, never its start」,代码查询的也是 createdAt。同一个 10 行注释块为决定重跑行为的条件给出了两个互相矛盾的锚点。此处同样建议改为「at or after this run was created」/「creation time」。

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

Comment on lines +1792 to +1795
elif [ -n "$posted_reviews" ]; then
echo "Skipping fallback comment: this run already posted a review on ${current_head}." >> "$GITHUB_STEP_SUMMARY"
exit 0
fi

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 skip message claims "this run already posted a review", but the guard's window (bot account + head + submitted_at >= createdAt) also matches a SIBLING run's review — reviews carry no run id, so the guard cannot distinguish this run's post from another run's, and the workflow's own concurrency comment acknowledges overlapping same-head runs ("an occasional duplicate review"). The suppression itself is correct — posting the fallback body would contradict the review sitting above it; only the attribution is wrong: an oncall investigating a silent dead run reads in this step's summary that THIS run posted when it never did. Suggest rewording to what the guard actually proved, here and in the fallback-comment job's twin.

Suggested change
elif [ -n "$posted_reviews" ]; then
echo "Skipping fallback comment: this run already posted a review on ${current_head}." >> "$GITHUB_STEP_SUMMARY"
exit 0
fi
elif [ -n "$posted_reviews" ]; then
echo "Skipping fallback comment: a bot review already exists on ${current_head} submitted at or after this run was created." >> "$GITHUB_STEP_SUMMARY"
exit 0
fi
中文说明

【Suggestion】 这条跳过消息声称「this run already posted a review」,但守卫的窗口(bot 账号 + head + submitted_at >= createdAt)同样会匹配兄弟运行发布的 review——review 上不携带 run id,守卫无法区分本次运行的发布与另一次运行的发布,而本 workflow 自己的并发注释也承认同 head 运行会重叠(「an occasional duplicate review」)。静默本身是正确的——此时再发兜底正文会与上方的 review 自相矛盾;只是归属错了:值班排查一次静默的死运行,会在这一步的 summary 里读到「本次运行已发布过 review」,而它从未发布。建议把措辞改为守卫实际证明的事实,此处与 fallback-comment 作业中的孪生副本同步修改。

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

Comment on lines +2020 to +2021
elif ! posted_reviews="$(gh api "repos/${GITHUB_REPOSITORY}/pulls/${PR_NUMBER}/reviews" --paginate \
--jq ".[] | select(.user.login == \"$bot_login\") | select(.commit_id == \"$pr_head\") | select(.submitted_at >= \"$run_created\") | .id" 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] In this job the guard compares review commit_id against pr_head fetched fresh at fallback time, not the head this run reviewed. On every event except pull_request_target — where the head-moved guard above deliberately does not run — a push landing after the review was posted makes select(.commit_id == "$pr_head") match nothing, and the contradictory comment posts anyway. Executed through this repo's own harness (the step's real bash against a stub gh):

arm1 (fresh head == reviewed head):        guard fires, posted '' — summary "already posted a review"
arm2 (push landed, pr_head=B, review on A): posted "<!-- qwen-review-fallback --> … failed before a review could be posted … retry with `@qwen-code /review`"

— the exact #9342 shape this guard exists to stop, re-opened for the non-PRT trigger + post + push + fail-after-post interleaving. The in-job twin is immune (its unconditional EXPECTED_HEAD_SHA check exits first), but this job has no record of the reviewed head — review-pr declares no job outputs. Suggest exposing expected_head_sha as a review-pr job output (job outputs survive job failure; empty only when the review step never ran, i.e. nothing was posted) and preferring it over the fresh head in the filter when non-empty — or correcting the comment's "the head this run reviewed" claim and documenting the residual.

中文说明

【Suggestion】 在这个作业里,守卫把 review 的 commit_id兜底时刻新取的 pr_head 比较,而不是本次运行实际所审的 head。在除 pull_request_target 之外的所有事件上——上方的 head-moved 守卫在这些事件上刻意不运行——review 发布之后若有 push 落地,select(.commit_id == "$pr_head") 就什么都匹配不到,自相矛盾的评论照样发出。已用本仓库自己的测试装置执行验证(步骤的真实 bash + 桩 gh``):arm1(新 head == 所审 head)守卫触发、保持静默;arm2(push 落地,pr_head=B 而 review 的 commit_id=A)步骤发出了「failed before a review could be posted … retry with @qwen-code /review」——正是本守卫要消除的 #9342 形态,在「非 PRT 触发 + 已发布 + push + 发布后失败」这一子交错下被重新打开。in-job 那份副本不受影响(其无条件的 EXPECTED_HEAD_SHA 检查先行退出),但本作业无所审 head 的任何记录——review-pr没有声明任何 job outputs。建议把expected_head_sha暴露为review-pr` 的 job output(job output 在作业失败后仍然存在;仅当 review 步骤从未运行——即从未发布——时才为空),并在过滤器中非空时优先于新取的 head;或者修正注释里「the head this run reviewed」的说法并明确记录这一残留窗口。

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

Comment on lines +3265 to +3267
' *createdAt*)',
' [ "${SCENARIO:-}" = "runstart_fail" ] && exit 1',
' printf "%s" "${RUN_CREATED:-}"; exit 0 ;;',

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 stub's case "$*" branches match substrings in order, so any gh run view query whose arguments contain createdAt — including a combined --json createdAt,startedAt --jq '.startedAt' — is answered from this *createdAt*) branch with RUN_CREATED, and the *startedAt*) discriminator below is unreachable for it. Mutation-tested against the suite: switching both guard sites to --json createdAt,startedAt --jq '.startedAt' leaves survives a job re-run green (the stub's $* contains createdAt, so the guard is handed RUN_CREATED 09:08:38Z and MID_RERUN 10:00:00Z compares ≥ it), while in production run_created would hold the re-executed attempt's start — the round-1 regression. The wholesale startedAt swap IS killed by the suite, so only this partial variant escapes; note the combined-field idiom is established in this very diff (--json state,headRefOid), which makes the shape a plausible future edit. Suggest answering run view the way the stub already answers the reviews lookup — run the caller's real --jq over a JSON object holding both fields ({"createdAt": "$RUN_CREATED", "startedAt": "$RUN_STARTED_ATTEMPT"}), so any query shape is answered per-field and the partial mutant is killed.

中文说明

【Suggestion】 桩里的 case "$*" 分支按顺序做子串匹配,因此任何参数中含 createdAtgh run view 查询——包括组合式 --json createdAt,startedAt --jq '.startedAt'——都会命中这个 *createdAt*) 分支并得到 RUN_CREATED,下方的 *startedAt*) 判别分支对它永不可达。已对套件做变异实测:把两处守卫改成 --json createdAt,startedAt --jq '.startedAt'survives a job re-run 仍然通过(桩的 $*createdAt,守卫拿到 RUN_CREATED 09:08:38Z,MID_RERUN 10:00:00Z 比较 ≥ 成立),而生产中 run_created 将持有重跑 attempt 的开始时间——即第一轮回归。整串换成 startedAt 的变异能被套件杀死,只有这种部分变体漏网;注意组合字段写法在本 diff 中已有先例(--json state,headRefOid),这一形态是合理的未来编辑。建议让 run view 采用桩应答 reviews 查询的同一方式——对同时持有两个字段的 JSON 对象({"createdAt": "$RUN_CREATED", "startedAt": "$RUN_STARTED_ATTEMPT"})执行调用方自己的 --jq,使任何查询形态都按字段应答,从而杀死该部分变体。

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

Comment on lines +2024 to +2027
elif [ -n "$posted_reviews" ]; then
echo "Skipping fallback comment: this run already posted a review on ${pr_head}." >> "$GITHUB_STEP_SUMMARY"
exit 0
fi

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] Same attribution wording as the in-job twin: "this run already posted a review" — but the guard's window also matches a sibling run's review (reviews carry no run id), so this step summary can tell the oncall that THIS run posted when the review actually came from an overlapping run. The suppression behavior stays correct; reword the message to what the guard proved.

Suggested change
elif [ -n "$posted_reviews" ]; then
echo "Skipping fallback comment: this run already posted a review on ${pr_head}." >> "$GITHUB_STEP_SUMMARY"
exit 0
fi
elif [ -n "$posted_reviews" ]; then
echo "Skipping fallback comment: a bot review already exists on ${pr_head} submitted at or after this run was created." >> "$GITHUB_STEP_SUMMARY"
exit 0
fi
中文说明

【Suggestion】 与 in-job 那份副本相同的归属措辞:「this run already posted a review」——但守卫的窗口同样会匹配兄弟运行的 review(review 不携带 run id),因此这条 step summary 可能告诉值班「本次运行已发布过 review」,而那条 review 实际来自一次重叠的运行。静默行为本身正确;只需把消息改为守卫实际证明的事实。

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

…rd proved

Round 2's six, all taken.

The fallback JOB compared review commit ids against the PR's head at
fallback time, not the head the run reviewed. On every trigger but
pull_request_target the head-moved guard above deliberately does not
run, so a push landing between the post and this step leaves that value
pointing at bytes no review ever covered: the match fails and the
contradictory comment posts anyway — the #9342 shape, re-opened for the
trigger + post + push + fail-after-post interleaving. `review-pr` now
publishes the head its review step recorded as a job output, and the
guard reads it, falling back to the fresh head only when the job died
before that step (a run that posted nothing either). The in-job twin
needs none of this — its unconditional head-moved check exits first —
and that asymmetry is now pinned per site rather than left to be
rediscovered.

Both skip messages claimed "this run already posted a review". Reviews
carry no run id, so the window (bot account + head + submitted at or
after this run was created) also matches an overlapping sibling run's
review, which this workflow's own concurrency note says can happen. The
suppression is right either way — a review IS sitting above the comment
— but the oncall reading the summary was told something the guard never
proved; both now say what it did.

The guard's opening paragraphs still described the round-1 `startedAt`
anchor while the code (and the paragraph below it, and the runtime
warning) said creation. A maintainer reading top-down got the anchor
that re-runs break — the defect round 1 removed.

Test stub: `gh run view` now answers by running the caller's own --jq
over an object carrying both timestamps, instead of a `case` on "$*"
that matched substrings in order. A combined
`--json createdAt,startedAt --jq '.startedAt'` was answered from the
createdAt branch, leaving the re-run pin green for a guard reading the
attempt-scoped field — the exact regression it exists to catch.
@wenshao

wenshao commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator Author

Round 2's six are all taken in 12dc118 — nothing deferred.

The reviewed-head finding is the one that mattered, and its probe was right. The fallback job had no record of what this run reviewed, so it compared against the PR's head at fallback time; with the head-moved guard deliberately inert on non-pull_request_target triggers, a push between the post and this step made the match fail and the contradictory comment post — the #9342 shape re-opened through a different door. review-pr now publishes its recorded head as a job output and the guard reads it, falling back to the fresh head only when the job died before the review step (a run that posted nothing either). Mutation-verified: reverting to the fresh head fails exactly the new test. The in-job twin genuinely is immune — its unconditional head-moved check exits first — and that asymmetry is now pinned per site, so nobody has to re-derive why only one of the two needs the output.

The attribution wording was a fair catch on my own prose. Reviews carry no run id, so the window also matches an overlapping sibling run's review — the suppression stays correct (a review IS sitting above the comment), but the summary told the oncall something the guard never proved. Both messages now say what it did prove. Same for the two opening paragraphs still describing the round-1 startedAt anchor: read top-down, the block handed a maintainer the anchor that re-runs break.

The stub finding is the sharpest of the four hygiene ones, because it attacks the pin rather than the code: a case on "$*" answered a combined --json createdAt,startedAt --jq '.startedAt' from the createdAt branch, so a guard reading the attempt-scoped field would have kept the re-run test green. The stub now runs the caller's own --jq over an object carrying both timestamps — the same technique it already used for the reviews lookup — which is the shape that cannot drift.

Suite: 171 pass in this file (the one failure, repairs a single unwritable directory, reproduces on a pristine tree here); qwen-resolve-workflow and review-worktree-cleanup-workflow green; prettier and eslint clean.

中文说明

第 2 轮六条全部采纳(12dc11827f),无延后。

「审查时的 head」那条最关键,其探针结论正确:兜底作业没有本轮实际审查了哪个 head 的记录,只能拿兜底时刻的 PR head 比对;而在非 pull_request_target 触发下 head-moved 门本就不启用,于是「发帖后、本步骤前」的一次推送会让匹配落空、自相矛盾的评论照发——#9342 的形态换了扇门重新打开。现在 review-pr 把它记录的 head 作为 job 输出发布,守卫读它;仅当作业在 review 步骤之前就死掉(那种运行也没发过 review)才回退到新 head。已变异验证:改回读新 head 恰好让新测试变红。in-job 那侧确实免疫(其无条件 head-moved 检查更早退出),该不对称现在按站点各自钉住,无需他人重新推导为何只有一侧需要这个输出。

措辞归因那条是对我自己散文的公正指正:review 不携带 run id,所以该时间窗同样会匹配并发同胞运行发布的 review——抑制行为依然正确(评论上方确实有一份 review),但 summary 告诉 oncall 的是守卫从未证明的事。两处消息现在只陈述已证明的内容。两段仍在描述第 1 轮 startedAt 锚点的开头注释同理:自上而下读,这个代码块会把「重跑会破坏的那个锚点」交给维护者。

桩那条是四条卫生项里最锋利的,因为它攻击的是钉本身:对 "$*"case 会把 --json createdAt,startedAt --jq '.startedAt'createdAt 分支应答,于是「读取按尝试计时字段」的守卫仍能让重跑测试保持绿色。桩现在用调用方自己的 --jq 跑在同时携带两个时间戳的对象上——与它对 reviews 查询早已采用的技术一致,这种形状不会漂移。

测试:本文件 171 通过(唯一失败在原始树同样复现);qwen-resolve-workflowreview-worktree-cleanup-workflow 全绿;prettier 与 eslint 干净。

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

1 Suggestion-level finding(s) this review confirmed are already reported on this PR and are not repeated:

Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/qwen-code-pr-review.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

Deferred under the convergence posture (round 3, not a blocker) — recorded, not requested in this round:

  • .github/workflows/qwen-code-pr-review.yml:1793 — [review] the already-posted guard is duplicated verbatim across the two fallback sites — deferred (code-age rule: anchored code unchanged since round 2)
  • scripts/tests/qwen-pr-review-workflow.test.js:3462 — [review] test comment says the guard queries startedAt but it queries createdAt — round 2 deferred the same finding; code unchanged
  • .github/workflows/qwen-code-pr-review.yml:2019 — [review] guard lookups are single-shot while the sibling dedup loop retries 3× — deferred (code-age rule: anchored code unchanged since round 2)
中文说明

本轮确认的 1 条建议级发现已在 PR 上报告过,不再重复发布(列表见上方英文部分)。

未检查(工具限制,非阻断):the executable-script lint — .github/workflows/qwen-code-pr-review.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

收敛姿态下延后(第 3 轮,非阻断)——已记录,本轮不要求修改:共 3 条(原文未翻译,列表见上方英文部分)。

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

# harness, that interleaving reproduces the #9342 shape exactly.
# The job output is empty only when review-pr died before its review
# step ran, which is also a run that posted nothing.
guard_head="${REVIEWED_HEAD_SHA:-$pr_head}"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Critical] The already-posted guard attributes a review to this run through the head the LAST attempt reviewed, so after a "Re-run failed jobs" the run's own attempt-1 review becomes invisible to the guard — and the fallback posts the contradictory "failed before a review could be posted … retry" comment directly beneath the review the same run already posted. Two demonstrated entrances: (1) attempt 1 posts its review on head H1 and the job fails after the post; the re-run keeps the run id; attempt 2 dies before the review step writes expected_head_sha (the runner-health fail-fast this workflow exists for, a checkout failure, or the step's own fail "Failed to determine state") — the re-executed job recomputes the output from attempt 2's empty step state, so REVIEWED_HEAD_SHA is '' and guard_head falls back to the (possibly moved) pr_head; (2) a push lands and attempt 2's review step re-runs, writing expected_head_sha=H2 (the new head), before the CLI dies — the same miss with the output populated. In both, .commit_id == <last-attempt head> misses attempt 1's review on H1 even though its submitted_at passes the attempt-stable createdAt window, and the in-job twin has the same hole via an empty EXPECTED_HEAD_SHA skipping its head-moved check. Probe against the steps' real bash (stub gh, the step's own --jq), with an attempt-1 bot review on H1 submitted after run creation and the head moved to H2:

fallback job (REVIEWED_HEAD_SHA=''): posted "<!-- qwen-review-fallback -->… failed before a review could be posted"
control (head unmoved):              posted '' — "a bot review already exists on H1OLDSHA"
populated arm (head = H2):           posted=YES in both twins
with the commit_id clause dropped:   posted=no — "Skipping fallback comment: a bot review already exists"

The re-run premise is measured on this repo (run 32219268680: a previously-succeeded dependent job was re-executed by "Re-run failed jobs"). The createdAt anchor closed the time axis of the round-1 blockers; the head axis still breaks, and the comment blocks at lines 415-420 and 2029-2034 state the false inference ("a run that never got that far never posted a review either" — attempt 2 dying early does not mean the RUN posted nothing). Attribute reviews to the RUN instead of one attempt's head — e.g. drop the select(.commit_id == …) clause from both filters (the bot-account clause plus submitted_at >= run_created already scopes a review to this run), or collect the reviewed heads of all attempts — and correct those two comment blocks.

中文说明

【Critical】 该守卫通过「最后一次 attempt 所审的 head」把 review 归属到本 run,因此「Re-run failed jobs」之后,本 run 自己 attempt 1 发布的 review 会从守卫视野中消失——兜底评论会在同一 run 刚刚发布的 review 正下方发出自相矛盾的「failed before a review could be posted … retry」。两条已证实的入口:(1) attempt 1 在 head H1 上发布 review 后作业才失败;重跑保持同一 run id;attempt 2 在 review 步骤写入 expected_head_sha 之前死掉(本 workflow 专门防御的 runner-health fail-fast、checkout 失败、或步骤自身的 fail "Failed to determine state")——重跑的作业从 attempt 2 的空步骤状态重新计算 output,REVIEWED_HEAD_SHA''guard_head 回落到(可能已移动的)pr_head;(2) 一个 push 落地后 attempt 2 的 review 步骤重跑、写入 expected_head_sha=H2(新 head),随后 CLI 死掉——output 有值但同样错过。两种形态下 .commit_id == <最后 attempt 的 head> 都匹配不到 attempt 1 在 H1 上的 review(尽管其 submitted_at 通过了 attempt 稳定的 createdAt 窗口);in-job 的孪生守卫同样有洞:EXPECTED_HEAD_SHA 为空时其 head-moved 检查被跳过。以步骤的真实 bash(桩 gh、步骤自己的 --jq)做的探针,attempt-1 bot review 在 H1、提交于 run 创建之后、head 已移至 H2:

fallback job(REVIEWED_HEAD_SHA=''):posted "<!-- qwen-review-fallback -->… failed before a review could be posted"
对照(head 未移动):               posted '' — "a bot review already exists on H1OLDSHA"
output 有值分支(head = H2):       两个孪生站点均 posted=YES
去掉 commit_id 子句后:              posted=no — "Skipping fallback comment: a bot review already exists"

重跑前提已在本仓库实测(run 32219268680:一个先前已成功的依赖作业被「Re-run failed jobs」重新执行)。createdAt 锚点关闭了第 1 轮两个 blocker 的时间轴;head 轴仍然会断,且 415-420 与 2029-2034 两处注释陈述了错误推断(「走不到那一步的 run 也不可能发过 review」——attempt 2 早死并不意味着该 RUN 没发过)。建议把 review 归属到 RUN 而不是某一个 attempt 的 head——例如从两处过滤器中去掉 select(.commit_id == …) 子句(bot 账号子句加 submitted_at >= run_created 已足以把 review 限定到本 run),或收集所有 attempt 审过的 head——并同步更正上述两处注释。

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

Comment on lines +2039 to +2040
elif ! posted_reviews="$(gh api "repos/${GITHUB_REPOSITORY}/pulls/${PR_NUMBER}/reviews" --paginate \
--jq ".[] | select(.user.login == \"$bot_login\") | select(.commit_id == \"$guard_head\") | select(.submitted_at >= \"$run_created\") | .id" 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] Both guard comment blocks assert "a review submitted after the run was created still cannot belong to an earlier run", but this workflow's per-run concurrency groups deliberately allow two concurrent runs reviewing the same head (the concurrency comment itself accepts "an occasional duplicate review"). An earlier-created overlapping run's review — bot author, same commit_id, submitted after this run's createdAt — therefore satisfies this run's guard and silences its fallback: lifecycle run A created T0 reviews head X; a maintainer @qwen-code /review comment creates run B at T1 (per-run group — neither run disturbs the other); A submits at T2 > T1; B dies before posting → B's guard matches A's review on all three clauses and exits silent, so the failure of the explicitly-requested run is never announced. The harm is bounded — a fresh bot review of the same head is on the PR, so the suppressed comment would itself have contradicted it — but these comment blocks are the guard's only documentation and are written as load-bearing reasoning (measured run ids and timestamps); a future edit trusting "cannot belong to an earlier run" builds on a guarantee the concurrency model disproves. State the actual guarantee instead: a match proves this head is covered by a bot review submitted while this run was alive, and under per-run concurrency an earlier-created overlapping run's review can also match — accepted because silence then coincides with an existing review of the same head. If this silence ever becomes harmful, the class-closing fix is to embed the run URL/ID in the review body and match on it, exactly like the marker+RUN_URL dedup above.

中文说明

【Suggestion】 两处守卫注释都断言「在 run 创建之后提交的 review 仍不可能属于更早的 run」,但本 workflow 的 per-run 并发组刻意允许两个并发运行审同一个 head(并发注释自己也接受「偶尔的重复 review」)。因此一个创建更早、时间重叠的 run 的 review——bot 账号、相同 commit_id、提交于本 run 的 createdAt 之后——可以满足本 run 的守卫并让其兜底静默:生命周期 run A 于 T0 创建并审 head X;维护者评论触发的 run B 于 T1 创建(per-run 组——互不干扰);A 于 T2 > T1 提交;B 在发帖前死掉 → B 的守卫三个子句全部匹配 A 的 review 并静默退出,被显式请求的那次运行的失败无人播报。危害有界——PR 上已有同 head 的新鲜 bot review,被压掉的评论本身就会与之矛盾——但这两处注释是该守卫唯一的文档,且以承重推理的口吻写成(附实测 run id 与时间戳);未来若有人信任「不可能属于更早的 run」,就会在一个被并发模型证伪的保证上做建设。建议改为陈述真实保证:匹配只证明该 head 已被一份在本 run 存活期间提交的 bot review 覆盖,且在 per-run 并发下一个创建更早的重叠 run 的 review 也可能匹配——之所以接受,是因为此时静默与同 head 已有 review 并存。若这种静默将来有害,彻底关闭此类的做法是把 run URL/ID 嵌入 review 正文并按它匹配,与上方 marker+RUN_URL 的 dedup 一致。

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

GH_TOKEN: '${{ secrets.CI_BOT_PAT }}'
PR_NUMBER: '${{ github.event.pull_request.number || github.event.issue.number || github.event.inputs.pr_number }}'
RUN_URL: '${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}'
REVIEWED_HEAD_SHA: "${{ needs.review-pr.outputs.expected_head_sha || '' }}"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] The new cross-job wiring chain — the review-pr job output expected_head_sha feeding this env var — is pinned by no test: the behaviour tests inject REVIEWED_HEAD_SHA directly into the step's environment (bypassing this YAML env: block), and nothing asserts doc.jobs['review-pr'].outputs.expected_head_sha either. Probe: with both wiring hunks (the outputs: declaration and this env line) deleted, the suite still passes 172/172 — blind to the chain in both directions — while the same suite pins same-shaped wiring elsewhere (inJobStep.env.GH_TOKEN, step.env.RUN_URL, job.needs). A future edit that renames or drops either side of the chain ships green while REVIEWED_HEAD_SHA is permanently empty in production; the guard then falls back to pr_head, and on the common issue_comment trigger — where the head-moved guard deliberately does not run — the review-post → push → fail-after-post interleaving matches nothing and re-ships the exact #9342 contradiction this PR closes. A structural pin beside the existing ones would close it:

expect(doc.jobs['review-pr'].outputs?.expected_head_sha).toBe(
  '${{ steps.review.outputs.expected_head_sha }}',
);
expect(step.env.REVIEWED_HEAD_SHA).toBe(
  "${{ needs.review-pr.outputs.expected_head_sha || '' }}",
);
中文说明

【Suggestion】 新的跨作业接线链——review-pr 作业 output expected_head_sha 馈入此环境变量——没有任何测试钉住:行为测试把 REVIEWED_HEAD_SHA 直接注入步骤环境(绕过了这段 YAML env:),也没有任何断言检查 doc.jobs['review-pr'].outputs.expected_head_sha。探针:删掉两处接线 hunk(outputs: 声明与本 env 行)后套件仍 172/172 全绿——对该链两个方向都失明——而同一套件在别处钉住了同形态的接线(inJobStep.env.GH_TOKENstep.env.RUN_URLjob.needs)。未来若有编辑重命名或删掉链条任一侧,测试全绿的同时生产环境里 REVIEWED_HEAD_SHA 恒为空;守卫回落至 pr_head,而在常见的 issue_comment 触发下(head-moved 守卫刻意不运行),「发布 review → push → 发布后失败」的交错将匹配不到任何 review,从而重新放出本 PR 要关闭的 #9342 式自相矛盾。建议在既有接线断言旁补一个结构性钉住(见上方代码块)。

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

… run attribute

Round 3's blocker, and the second time the head clause re-opened the
contradiction this PR exists to close. Two entrances this round, both
after a "Re-run failed jobs": attempt 2 dies before the review step
writes its head, so the guard falls back to a head attempt 1 never
reviewed; or a push lands and attempt 2 records the NEW head — in both,
attempt 1's own review no longer matches `.commit_id`, and the fallback
posts "failed before a review could be posted … retry" beneath the
review the same run had posted.

Rather than patch the head lookup a third time, the head clause is
gone. What the guard proves is now narrower and stable: a bot review of
this PR was submitted while this run was alive — bot account plus the
attempt-stable `createdAt` window. That closes both entrances at once
and takes the round-2 cross-job wiring with it (review-pr's
`expected_head_sha` output and the env line that read it), so there is
no untested chain left whose silent breakage would restore the
fresh-head comparison. The job-level step no longer needs the PR head
either and reverts to its state-only query; the test stub's
state-only branch, removed in round 1 as dead, has a caller again.

The comment blocks now state the guarantee the concurrency model
actually supports. They claimed a review inside the window "cannot
belong to an earlier run", but per-run concurrency groups deliberately
allow overlapping runs on the same head, so an earlier-created run's
review can match and this run's failure then goes unannounced. That is
accepted, and said plainly: the silence coincides with a bot review a
reader can see — the very state that makes the comment's claim false —
while the bot-author and creation-time clauses still rule out silence
with no review at all.

Tests: the moved-head case flips from "posts" to "silences" and is
pinned per site (a review on ANY head inside the window silences);
re-introducing a head clause fails exactly that test; and a structural
pin asserts the wiring is absent rather than merely unused.
@wenshao

wenshao commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator Author

Round 3's blocker is fixed in a1380d0, and it deserved a design change rather than a third patch.

The head clause was the defect, twice. Round 2 caught it comparing against a head a push had moved; round 3 caught it comparing against a head a re-run recomputed — both entrances ending in the same contradictory comment beneath the review the same run had posted. The head is simply not a stable attribute of a run: pushes move it, re-runs recompute it, and a job that died before its review step never recorded it at all. So the clause is gone. What the guard proves is now narrower and stable — a bot review of this PR was submitted while this run was alive — which closes both of your entrances at once.

That also deletes the round-2 cross-job wiring (review-pr's expected_head_sha output and the env line reading it), which answers your third finding better than a test would have: there is no chain left to drift, and a structural pin now asserts its absence rather than its shape. The job-level step reverts to its state-only PR query, so the stub branch I removed in round 1 as dead has a caller again.

The concurrency finding is right and I stated the real guarantee instead of the convenient one. Per-run groups deliberately allow overlapping runs on the same head, so an earlier-created run's review can fall inside this run's window and silence its fallback. Both comment blocks now say so, with the reason it is accepted: the silence coincides with a bot review a reader can see — precisely the state that makes this comment's claim false — while the bot-author and creation-time clauses still rule out silence with no review at all. If that ever becomes harmful, your run-URL-in-the-body idea is the class-closing fix, and it belongs in the composer, not here.

Mutation-verified: re-introducing any head clause fails the new attribute-by-time test at both sites. Suite: 171 pass in this file (the one failure, repairs a single unwritable directory, reproduces on a pristine tree here); siblings green; prettier and eslint clean.

中文说明

第 3 轮的阻断项已在 a1380d0 修复——它值得一次设计调整,而不是第三个补丁。

head 子句本身才是缺陷,而且这是第二次。 第 2 轮抓到它比对的是被推送移动过的 head;第 3 轮抓到它比对的是被重跑重新计算的 head——两条入口通向同一个结果:在同一次运行已发布的 review 下方贴出自相矛盾的评论。head 根本不是运行的稳定属性:推送会移动它、重跑会重算它、在 review 步骤之前就死掉的作业压根没记录过它。所以该子句被移除。守卫现在证明的事更窄也更稳定——本 PR 上有一份 bot review 在本次运行存活期间提交——这一次性关掉了你给出的两条入口。

这同时删掉了第 2 轮引入的跨 job 接线(review-prexpected_head_sha 输出与读取它的 env 行),这比补一个测试更好地回应了你的第三条发现:不再有可漂移的链路,且新增结构钉断言它的不存在而非它的形状。job 级步骤回到只查 state 的形态,于是我在第 1 轮当作死代码删掉的桩分支重新有了调用方。

并发那条说得对,我把真实保证写了进去,而不是那个方便的说法。 per-run 并发组本就允许同 head 的重叠运行,因此更早创建的运行发布的 review 可能落入本次运行的时间窗并使其兜底静默。两处注释现在都如实写明,并给出接受它的理由:此时的静默与「读者能看到的一份 bot review」同时成立——而那正是使本评论断言为假的状态;同时 bot 账号与创建时间两个子句仍然排除「完全没有 review 的静默」。若将来这种静默造成危害,你提出的「在 review 正文内嵌 run URL」是彻底关闭该类问题的修法,那属于 composer,不属于这里。

已变异验证:在任一站点重新引入 head 子句都会让新的「按时间归因」测试失败。测试:本文件 171 通过(唯一失败在原始树同样复现);姊妹套件全绿;prettier 与 eslint 干净。

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Qwen Code review did not complete successfully. A transient error is retried automatically; if you are seeing this, retry with @qwen-code /review. See workflow logs.

@doudouOUC doudouOUC left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Re-check: 3 blockers resolved

All three Critical blockers from prior rounds are confirmed fixed at HEAD a1380d019f:

  1. startedAtcreatedAt (comments 3811217387, 3811217401) — Both the fallback-comment job and the in-job step now query --json createdAt --jq '.createdAt' instead of startedAt. The createdAt field is attempt-stable across re-runs, while startedAt moves to the re-executed attempt's start. Verified on the actual workflow lines 1797 and 2032.

  2. Head-independent attribution (comment 3813388372) — The select(.commit_id == ...) clause has been dropped from both guard filters. The guard now attributes by TIME (bot account + submitted_at >= run_created), not by head. The workflow comments explicitly state "It is deliberately NOT keyed on the reviewed head."

  3. Test coverage — 8 new tests cover both sites (fallback job + in-job step): the incident shape, each near-miss (stale/foreign/pending/none), re-run stability, fail-open paths, and the absence of commit_id in both sites. 90 tests pass (2 failures are environment-specific: jq not available on Windows, and a pre-existing repairs a single unwritable directory failure noted by the author).

No new findings. The remaining open inline comments are Suggestions about wording and edge cases already discussed in prior rounds.

中文说明

重新检查:3 个阻断问题均已解决

本轮审查确认此前三轮的所有 3 个 Critical 级别阻断问题已在 HEAD a1380d019f 修复:

  1. startedAt 改为 createdAt(评论 3811217387、3811217401)——兜底作业和 in-job 步骤现在均查询 --json createdAt --jq '.createdAt' 而非 startedAtcreatedAt 字段在各次重跑之间保持稳定,而 startedAt 会随重跑 attempt 的开始时间而漂移。已在 workflow 第 1797 和 2032 行验证。

  2. 按时间而非 head 归属(评论 3813388372)——两处守卫过滤器中的 select(.commit_id == ...) 子句已被移除。守卫现在按时间(bot 账号 + submitted_at >= run_created)而非 head 来归属 review。workflow 注释明确说明"故意不锁定审过的 head"。

  3. 测试覆盖——新增 8 个测试覆盖两个站点(兜底作业 + in-job 步骤):事故形态、四种近似情形(陈旧/他人账号/PENDING/无 review)、重跑稳定性、故障开放路径、以及两处均无 commit_id。90 条测试通过(2 条失败为环境问题:当前 Windows 系统无 jq,以及作者已标注的既有 repairs a single unwritable directory 失败)。

无新发现。剩余的未结行内评论均为建议级,涉及措辞和边缘情况,已在之前轮次中讨论过。

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

…d of failing them

The stub answers the guard's reviews and run-view lookups by running the
caller's own `--jq` filter — that filter IS the thing under test — so
those cases need jq on PATH. A reviewer running the suite on Windows
without jq saw them as failures of the guard rather than as untested,
which is the wrong signal in the wrong direction.

Probed once per run and skipped honestly. Measured with a jq that exits
127: the file goes from 31 failures to 26 failures plus 13 skips — the
26 are the retry-loop cases, which have parsed the review log with jq
since long before this change and are equally untestable without it.
GitHub's windows-latest image ships jq, so CI coverage is unchanged
either way; what changes is what a jq-less machine reports.
@wenshao

wenshao commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator Author

Thanks for the re-check — and for the Windows datapoint, which was the one actionable thing in it. Fixed in 35bcbca.

The jq failure was a wrong signal, not a broken guard. The stub answers the reviews and run-view lookups by running the caller's own --jq filter, because that filter is what these tests exist to pin — so without jq they cannot run, and failing them reports the guard as broken instead of untested. They now probe for jq once and skip. Measured with a jq that exits 127: the file goes from 31 failures to 26 failures plus 13 skips, and those 26 are the retry-loop cases, which have parsed the review log with jq since long before this PR. GitHub's windows-latest image ships jq, so CI coverage is unchanged; what changes is what a jq-less machine reports.

One incident worth flagging, unrelated to the code but visible on this PR. A <!-- qwen-review-fallback --> comment landed at 14:35:50Z reading **Qwen Code review did not complete successfully.** A transient error is retried automatically … See [workflow logs](). It cannot have come from a workflow run: the body shape is the in-job step's (${FAILURE_REASON} interpolated, here empty — hence the double space), production always populates both FAILURE_REASON and RUN_URL, and this PR's only review-pr job was still inside its Run review step at that moment, with the fallback step not yet reached. The likely source is a probe executing the step's real bash with a live authenticated gh on PATH and PR_NUMBER pointing at this PR — the same technique these reviews describe using. Worth hardening on the probe side: a stub that shadows gh and refuses anything outside its allowlist, rather than one that assumes the un-stubbed path is never taken. (Its [workflow logs]() also carries no actions/runs/<id>, so the fallback dedup cannot match it and a later genuine fallback would post a second comment.)

中文说明

感谢复核——其中唯一可执行的一点是 Windows 数据点,已在 35bcbca 修复。

jq 失败是错误信号,而非守卫损坏。 桩是用调用方自己的 --jq 过滤器来应答 reviews 与 run-view 查询的,因为该过滤器正是这些测试要钉住的对象;没有 jq 就无法运行,此时"失败"把守卫报成损坏而不是未测。现在改为探测一次 jq 并诚实跳过。以退出码 127 的假 jq 实测:该文件从 31 条失败变为 26 条失败 + 13 条跳过,而那 26 条是重试环路用例——它们早在本 PR 之前就用 jq 解析 review 日志。GitHub 的 windows-latest 镜像自带 jq,因此 CI 覆盖不变;变化的只是无 jq 机器上的报告。

另有一起与代码无关、但出现在本 PR 上的事件值得点出。 14:35:50Z 出现一条 <!-- qwen-review-fallback --> 评论,正文为 **Qwen Code review did not complete successfully.** A transient error is retried automatically … See [workflow logs]().。它不可能来自工作流运行:正文形态属于 in-job 步骤(插值了 ${FAILURE_REASON},此处为空——故有双空格),而生产环境中 FAILURE_REASONRUN_URL 始终有值;且当时本 PR 唯一的 review-pr 作业仍停在 Run review 步骤内,兜底步骤尚未执行。可能的来源是:某个探针以真实且已认证的 gh 执行了该步骤的真实 bash,且 PR_NUMBER 指向本 PR——正是这些审查所描述的技术。建议在探针侧加固:桩应当遮蔽 gh 并拒绝白名单之外的一切调用,而不是假设未打桩的路径不会被走到。(该评论的 [workflow logs]() 也不含 actions/runs/<id>,兜底去重无法匹配它,将来真实兜底会重复发帖。)

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

Partially reviewed — gaps disclosed. Suggestions are inline.

1 Suggestion-level finding(s) this review confirmed are already reported on this PR and are not repeated:

  • R4-2 test comment lists a head clause the shipped filter does not have (describe-level header) — dropped as overlap: same line as existing comment 3811217427 at scripts/tests/qwen-pr-review-workflow.test.js:3524

Not reviewed: build-and-test — Test (macos-latest, Node 22.x) was skipped in CI (merge_group-gated) and its suite ran locally on Linux only.

Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/qwen-code-pr-review.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

Deferred under the convergence posture (round 4, not a blocker) — recorded, not requested in this round:

  • scripts/tests/qwen-pr-review-workflow.test.js:3482 — [review] assertion comment says the guard asks for startedAt but it queries createdAt — rounds 2 and 3 deferred the same finding; code unchanged
  • scripts/tests/qwen-pr-review-workflow.test.js:3300 — [probe] endpoint drift in the guard is an unobservable mutation — deferred (code-age rule: anchored code unchanged since round 3)
  • scripts/tests/qwen-pr-review-workflow.test.js:3300 — [probe] the guard's --paginate flag is pinned by no assertion — deferred (code-age rule: anchored code unchanged since round 3)
中文说明

仅完成部分审查,审查缺口已披露。 建议见行内评论。

本轮确认的 1 条建议级发现已在 PR 上报告过,不再重复发布(列表见上方英文部分)。

未审查:build-and-test — Test (macos-latest, Node 22.x) was skipped in CI (merge_group-gated) and its suite ran locally on Linux only。

未检查(工具限制,非阻断):the executable-script lint — .github/workflows/qwen-code-pr-review.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

收敛姿态下延后(第 4 轮,非阻断)——已记录,本轮不要求修改:共 3 条(原文未翻译,列表见上方英文部分)。

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

Comment on lines +2039 to +2047
# The head this run REVIEWED, not the PR's head at fallback time: on
# every trigger but pull_request_target the head-moved guard above
# deliberately does not run, so a push landing between the post and
# this step leaves `pr_head` pointing at bytes no review ever
# covered — the reviewed head's review then matches nothing and the
# contradictory comment posts anyway. Executed through this file's
# harness, that interleaving reproduces the #9342 shape exactly.
# The job output is empty only when review-pr died before its review
# step ran, which is also a run that posted nothing.

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] Leftover paragraph from the abandoned head-keyed revision. It describes pr_head, "the reviewed head's review", and a review-pr "job output" — none of which exist: the shipped filter has no head clause, pr_head appears nowhere else in this workflow, and review-pr declares no outputs: (the new carries no cross-job head wiring to drift test pins both absences). It sits directly below the paragraph stating the guard is "deliberately NOT keyed on the reviewed head", contradicting it, and the in-job sibling carries no such paragraph. A maintainer debugging the next #9342-class contradiction reads this and either hunts for deleted wiring or "restores" head keying — re-opening the exact regression that test pins shut. Delete the paragraph; the shipped guard is fully explained by the preceding paragraphs.

Suggested change
# The head this run REVIEWED, not the PR's head at fallback time: on
# every trigger but pull_request_target the head-moved guard above
# deliberately does not run, so a push landing between the post and
# this step leaves `pr_head` pointing at bytes no review ever
# covered — the reviewed head's review then matches nothing and the
# contradictory comment posts anyway. Executed through this file's
# harness, that interleaving reproduces the #9342 shape exactly.
# The job output is empty only when review-pr died before its review
# step ran, which is also a run that posted nothing.

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

Comment on lines +3297 to +3299
// The reviews lookup runs the step's REAL --jq filter over the
// fixture: the guard under test IS that filter (author scope, head,
// submission time), so a stub that pre-applied it would pin nothing.

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 comment lists a head clause the shipped filter deliberately does not have — the filter is author scope + submission time only, and the attributes by TIME, not by head test exists precisely to pin that head is NOT a clause. It became wrong when the head clause was dropped. A maintainer making the test match the comment re-introduces head keying — the failure mode that test catches. Drop head, from the parenthetical.

Suggested change
// The reviews lookup runs the step's REAL --jq filter over the
// fixture: the guard under test IS that filter (author scope, head,
// submission time), so a stub that pre-applied it would pin nothing.
// The reviews lookup runs the step's REAL --jq filter over the
// fixture: the guard under test IS that filter (author scope,
// submission time), so a stub that pre-applied it would pin nothing.

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

REVIEWS_JSON: reviews,
RUN_CREATED: runCreated,
RUN_STARTED_ATTEMPT: runStartedAttempt,
REVIEWED_HEAD_SHA: reviewedHead,

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 harness injects REVIEWED_HEAD_SHA: reviewedHead, here and declares reviewedHead = '' at line 3247, but nothing reads REVIEWED_HEAD_SHA — neither step's run block references it (zero occurrences in the workflow), which the new carries no cross-job head wiring to drift test pins. The wiring became dead when the head mechanism was dropped. It advertises harness support for reviewed-head scenarios the guard deliberately does not consume; a future author passing reviewedHead: 'X' sees silently no effect and may misdiagnose the guard as head-aware. Remove the reviewedHead = '' parameter (line 3247) and this REVIEWED_HEAD_SHA: reviewedHead, entry.

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

Comment on lines +1786 to +1796
# The anchor is the run's CREATION, never its start. Re-running a
# failed job keeps the run id — the dedup above relies on exactly
# that — but moves run-level `startedAt` to the re-executed attempt:
# measured on this repo's runs 32219268680 (created 05:23:57Z,
# startedAt 05:51:26Z) and 32218596441 (05:13:04Z → 05:22:05Z).
# Anchoring there would push attempt 1's review outside "this run"
# on every re-run, so a re-run that fails before posting would
# contradict the review attempt 1 had posted — the very shape this
# guard exists to stop. `createdAt` is attempt-stable, and a review
# submitted after the run was created still cannot belong to an
# earlier run.

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 in-job block now states the createdAt-not-startedAt rationale twice: the "The window is anchored on createdAt, not startedAt …" passage about ten lines above and this paragraph, both citing the same two measured runs (32219268680, 32218596441). The fallback-comment job's block states it once. This round's comment rewrite added the first passage and cleaned the fallback block but left this second copy behind. A future correction must now be made in two places, and the two copies already phrase the claim differently — a one-sided edit leaves them silently disagreeing about the anchor. Delete this paragraph, keeping the first statement so the in-job block matches the fallback block's single-copy shape.

Suggested change
# The anchor is the run's CREATION, never its start. Re-running a
# failed job keeps the run id — the dedup above relies on exactly
# that — but moves run-level `startedAt` to the re-executed attempt:
# measured on this repo's runs 32219268680 (created 05:23:57Z,
# startedAt 05:51:26Z) and 32218596441 (05:13:04Z → 05:22:05Z).
# Anchoring there would push attempt 1's review outside "this run"
# on every re-run, so a re-run that fails before posting would
# contradict the review attempt 1 had posted — the very shape this
# guard exists to stop. `createdAt` is attempt-stable, and a review
# submitted after the run was created still cannot belong to an
# earlier run.

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

Round 5's four, all leftovers of the round-3 design change rather than
new behavior.

The job-level block still explained why it compared against the head
this run reviewed — naming `pr_head`, "the reviewed head's review" and a
`review-pr` job output, none of which survive: the shipped filter is
author scope plus the creation-time window, and the wiring was deleted
with the head clause. A maintainer reading it would look for a
comparison that is not there. The in-job block stated the
createdAt-not-startedAt rationale twice, once with the measured run ids
and once without; the measured one stays.

Same in the tests: the stub's comment listed a head clause the filter
deliberately does not have (`attributes by TIME, not by head` is the
test that pins its absence), and the harness still declared and injected
`reviewedHead`/`REVIEWED_HEAD_SHA`, which nothing reads since the wiring
went — a knob that looks live and cannot be.
@wenshao

wenshao commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator Author

Round 5's four are taken in 7619a82. All four were leftovers of the round-3 design change, and the round is a fair audit of it: when a clause is removed, its rationale and its test knobs do not remove themselves.

  • The job-level block still explained a comparison against the reviewed head, naming pr_head, "the reviewed head's review" and a review-pr job output — none of which survive the head clause's removal. Deleted rather than reworded; the remaining paragraph already says why the head is deliberately not a key.
  • The in-job block stated the createdAt-not-startedAt rationale twice. The one with the measured run ids stays.
  • The stub's comment listed a head clause the shipped filter does not have — corrected, and it now names the test that pins the absence (attributes by TIME, not by head).
  • The harness still declared and injected reviewedHead/REVIEWED_HEAD_SHA, which nothing has read since the wiring was deleted. A knob that looks live and cannot be is worse than no knob; gone.

No behavior change in this commit — comments and one dead test option. Suite unchanged: 171 pass in this file (plus the known local repairs a single unwritable directory failure), siblings green, prettier and eslint clean.

中文说明

第 5 轮四条已在 7619a82 处理。四条都是第 3 轮设计改动的残留,而这一轮正是对它的公正审计:子句被移除时,它的理由和它的测试旋钮不会自己消失。

  • job 级代码块仍在解释「与被审 head 比较」,提到 pr_head、「被审 head 的那份 review」以及 review-pr 的 job 输出——在 head 子句移除后这些都不复存在。选择删除而非改写:余下那段已经说明了为何刻意不以 head 为键。
  • in-job 代码块把 createdAt 而非 startedAt 的理由讲了两遍,保留带实测 run id 的那一份。
  • 桩的注释列出了实际过滤器并不具备的 head 子句——已订正,并点名钉住其不存在的测试(attributes by TIME, not by head)。
  • harness 仍声明并注入 reviewedHead/REVIEWED_HEAD_SHA,而自接线删除后无人读取。看起来活着却不可能生效的旋钮比没有旋钮更糟,已删除。

本提交无行为变更(注释 + 一个死的测试选项)。测试不变:本文件 171 通过(外加已知本机 repairs a single unwritable directory 失败),姊妹套件全绿,prettier 与 eslint 干净。

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed. Suggestions are inline.

1 Suggestion-level finding(s) this review confirmed are already reported on this PR and are not repeated:

Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/qwen-code-pr-review.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

Deferred under the convergence posture (round 5, not a blocker) — recorded, not requested in this round:

  • scripts/tests/qwen-pr-review-workflow.test.js:3482 — [review] Comment says the guard queries startedAt but it queries createdAt — rounds 2, 3 and 4 deferred the same finding; code unchanged
  • scripts/tests/qwen-pr-review-workflow.test.js:3247 — [review] Harness option expectedHead is declared and read but set by no caller (dead switch) — code unchanged since round 4
中文说明

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

本轮确认的 1 条建议级发现已在 PR 上报告过,不再重复发布(列表见上方英文部分)。

未检查(工具限制,非阻断):the executable-script lint — .github/workflows/qwen-code-pr-review.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

收敛姿态下延后(第 5 轮,非阻断)——已记录,本轮不要求修改:共 2 条(原文未翻译,列表见上方英文部分)。

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

Comment on lines +1786 to +1790
# The anchor is the run's CREATION, never its start. Re-running a
# failed job keeps the run id — the dedup above relies on exactly
# that — but moves run-level `startedAt` to the re-executed attempt:
# measured on this repo's runs 32219268680 (created 05:23:57Z,
# startedAt 05:51:26Z) and 32218596441 (05:13:04Z → 05:22:05Z).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] R4-4: Round 4 flagged that this block states the createdAt-not-startedAt rationale twice; the fix in 7619a82 deleted a different third paragraph ("Anchoring there would push attempt 1's review outside this run…"), leaving the flagged pair in place. The "What a match proves" paragraph above (~lines 1772-1778) already says the window is anchored on createdAt, not startedAt — citing the same two measured runs 32219268680 and 32218596441 — and this trailing paragraph restates it with slightly different wording ("the dedup above relies on that" vs "relies on exactly that"). The fallback-comment job's twin block states the rationale once. A future correction to the anchor rationale must now edit both copies, and a one-sided edit leaves this single block internally disagreeing about which timestamp the window anchors on. Delete this trailing paragraph so the in-job block matches the fallback block's single-copy shape.

Suggested change
# The anchor is the run's CREATION, never its start. Re-running a
# failed job keeps the run id — the dedup above relies on exactly
# that — but moves run-level `startedAt` to the re-executed attempt:
# measured on this repo's runs 32219268680 (created 05:23:57Z,
# startedAt 05:51:26Z) and 32218596441 (05:13:04Z → 05:22:05Z).
中文说明

【Suggestion】 R4-4:第 4 轮曾指出本代码块把 createdAt 而非 startedAt 的理由讲了两遍;7619a82cad 的修复删除的是另一段("Anchoring there would push attempt 1's review outside this run…"),被指出的那一对仍然都在。上方 "What a match proves" 段(约 1772-1778 行)已说明窗口锚定在 createdAt 而非 startedAt——并引用了同样的两个实测 run 32219268680 与 32218596441——而这段结尾段落又用略有不同的措辞复述了一遍("the dedup above relies on that" 对 "relies on exactly that")。fallback-comment job 的孪生代码块只陈述了一次该理由。将来若要修正锚点理由,必须同时改两处;单边修改会让这一个注释块内部对「窗口锚定在哪个时间戳」自相矛盾。删除这段结尾段落,使 in-job 块与 fallback 块的单份陈述形态一致。

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

@wenshao

wenshao commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator Author

Round 6 reports no blocker.

R4-4 is a fair catch — the round-5 edit removed a neighbouring paragraph rather than the duplicated rationale, so the repetition it flagged is still there. It is comment text with no behavioral effect, and this stack's standing rule takes only Criticals past round 5, so it is recorded and deferred rather than spent as another round. Same for the re-reported 2>/dev/null stderr note, which the guard already answers with its ::warning:: plus step-summary line on both unavailable paths.

中文说明

第 6 轮无阻断项。

R4-4 指出得对——第 5 轮的编辑删掉的是相邻段落,而非被点名的重复理由段,因此该重复仍在。它是注释文本、无行为影响;本栈现行规则是第 5 轮之后只采纳 Critical,故记录延后,而不是再消耗一轮。重报的 2>/dev/null 一条同理:守卫已在两条不可用路径上以 ::warning:: 加 step-summary 行作答。

@wenshao

wenshao commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /takeover

@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 轮)。改动内容与我反驳保留之处如下:

Round summary

This round closed the one still-actionable inline finding (R4-4, re-reported in round 5) plus the last surviving items of the reviewer's deferred lists — all leftovers of the round-3 design change (attribute by time, drop the head clause). The batch is subtractive: net −6 lines, comments and one dead test knob only, no behavior change. Commit: 39a93c7395.

Implemented this round

  1. rc:3815780639 and rc:3815300053 — R4-4, duplicated anchor rationale. Verified against current code: the in-job guard block stated the createdAt-not-startedAt rationale twice — the "What a match proves" paragraph and a trailing paragraph ("The anchor is the run's CREATION, never its start…"), both citing the same two measured runs (32219268680, 32218596441). The round-5 commit had deleted a different, third paragraph, leaving the flagged pair in place. Deleted the trailing paragraph (5 lines); the in-job block now matches the fallback block's single-copy shape, keeping the paragraph that carries the measured runs.
  2. Reviewer deferred list (rounds 2–5) — stale startedAt in a test comment. Verified: the comment above the "no run view" pin said the already-posted guard asks gh run view for startedAt on every event, but the guard queries createdAt (workflow lines 1786, 2021). Corrected the word.
  3. Review round 5 body (dropped as overlap) — stale head clause in the describe-level header. Verified: the header still described the guard as a filter over "(author scope, head, submission time)", but the shipped filter has no head clause — the attributes by TIME, not by head test exists precisely to pin that. Corrected to "(author scope and submission time)", matching the stub's comment wording.
  4. Reviewer deferred list (rounds 4–5) — dead expectedHead harness option. Verified by grep: declared in runFallbackStep's options, read once (EXPECTED_HEAD_SHA: expectedHead), set by no caller. This PR introduced the knob — pre-PR the harness hardcoded EXPECTED_HEAD_SHA: '' — so removal restores the original shape. Removed the option and restored the hardcoded ''.

Re-verified as already resolved in prior commits (no change needed)

  • rc:3811217387, rc:3811217401 (Critical — startedAt resets on re-runs): both guard sites query --json createdAt --jq '.createdAt' (lines 1786, 2021). Fixed in f4a90534.
  • rc:3811217409, rc:3811217413 (silent lookup failure): both unavailable paths emit ::warning::already-posted guard unavailable (…) plus a step-summary line before posting (lines 1794–1795, 1798–1799 and 2029–2030, 2033–2034); behavior stays fail-open. Fixed in f4a90534.
  • rc:3811217422 (dead *state*) stub branch): the branch is live again — the round-3 design reverted the fallback job to a state-only PR query, and the branch carries the state_fail/pr_closed scenarios with a "Live again" comment.
  • rc:3811217427 (${{ vars… }} bad substitution): the harness substitutes the expression with the repo default (180) before running the step's real bash.
  • rc:3812251467, rc:3812251486 (stale startedAt-anchor wording in the opening paragraphs): both blocks now describe the run's creation, consistent with the queried field. Fixed in 12dc1182.
  • rc:3812251492, rc:3812251528 (skip-message attribution): both sites now say what the guard proved — "a bot review of this PR was submitted after this run was created". Fixed in 12dc1182.
  • rc:3812251505, rc:3813388372 (head-keyed attribution, Critical): the filter has no commit_id clause at either site; attribution is bot account + submitted_at >= createdAt only. Fixed in a1380d01 and independently re-verified by @doudouOUC at that commit (rv:4973372476).
  • rc:3812251519 (stub substring dispatch): the stub answers run view by running the caller's own --jq over an object carrying both createdAt and startedAt, so the partial combined-field mutant is killed. Fixed in 12dc1182.
  • rc:3813388377 (concurrency guarantee wording): both comment blocks state the real guarantee, including the accepted overlapping-run silence. Fixed in a1380d01.
  • rc:3813388379 (cross-job wiring unpinned): superseded — the wiring was deleted in a1380d01 and the "carries no cross-job head wiring to drift" test pins the absence of job outputs, REVIEWED_HEAD_SHA, and commit_id == at both sites.
  • rc:3815300031 (leftover head-keyed paragraph in the fallback block): deleted in 7619a82c; grep confirms pr_head appears nowhere in the workflow, and the structural test pins the absent outputs.
  • rc:3815300043 (stub comment listed a head clause): corrected in 7619a82c; it now names the test that pins the absence.
  • rc:3815300048 (dead reviewedHead/REVIEWED_HEAD_SHA knob): removed in 7619a82c; the absence is pinned.

Declined / deferred / escalated

None.

Conflict

--conflict false — no merge performed.

Verification

  • npx vitest run scripts/tests/qwen-pr-review-workflow.test.js --config ./scripts/tests/vitest.config.ts — 172 passed (1 file)
  • npm run lint — passed
  • npm run typecheck — passed
  • npm run build — passed
  • npx prettier --check scripts/tests/qwen-pr-review-workflow.test.js — clean
中文说明

本轮总结

本轮关闭了唯一仍处于可处理状态的行内发现(R4-4,第 5 轮重新上报),以及审查者延后列表中最后的遗留项——它们都是第 3 轮设计变更(按时间归因、移除 head 子句)的残留。本批改动是收敛性的:净 −6 行,仅涉及注释与一个死掉的测试旋钮,无行为变更。提交:39a93c7395

本轮实施

  1. rc:3815780639rc:3815300053 —— R4-4,重复的锚点理由段。 已对当前代码核实:in-job 守卫代码块把 createdAt 而非 startedAt 的理由讲了两遍——「What a match proves」段与结尾段(「The anchor is the run's CREATION, never its start…」),且都引用同样的两个实测 run(32219268680、32218596441)。第 5 轮的提交删掉的是另一段(第三段),被指出的这一对仍然都在。已删除结尾段(5 行);in-job 块现在与 fallback 块的单份陈述形态一致,保留携带实测 run 编号的那一段。
  2. 审查者延后列表(第 2–5 轮)——测试注释中的陈旧 startedAt 已核实:「no run view」钉住断言上方的注释称已发布守卫在每个事件下都向 gh run view 查询 startedAt,而守卫实际查询的是 createdAt(workflow 第 1786、2021 行)。已订正该词。
  3. 第 5 轮审查正文(被作为重叠丢弃)——describe 级头部注释中的陈旧 head 子句。 已核实:该头部注释仍把守卫描述为对「(author scope, head, submission time)」的过滤,但实际过滤器没有 head 子句——attributes by TIME, not by head 测试正是为钉住这一点而存在。已订正为「(author scope and submission time)」,与桩注释的措辞一致。
  4. 审查者延后列表(第 4–5 轮)——死掉的 expectedHead 测试旋钮。 已通过 grep 核实:在 runFallbackStep 的选项中声明、被读取一次(EXPECTED_HEAD_SHA: expectedHead)、但没有任何调用方设置它。该旋钮是本 PR 引入的——PR 之前测试装置硬编码 EXPECTED_HEAD_SHA: ''——因此移除即恢复原状。已删除该选项并恢复硬编码的 ''

已复核确认先前提交已解决(无需改动)

  • rc:3811217387rc:3811217401(Critical——startedAt 在重跑时漂移):两处守卫站点均查询 --json createdAt --jq '.createdAt'(第 1786、2021 行)。已在 f4a90534 修复。
  • rc:3811217409rc:3811217413(查询静默失败):两条不可用路径在发帖前都会输出 ::warning::already-posted guard unavailable (…) 与 step-summary 行(第 1794–1795、1798–1799 行与第 2029–2030、2033–2034 行);行为保持故障开放。已在 f4a90534 修复。
  • rc:3811217422(死掉的 *state*) 桩分支):该分支已复活——第 3 轮设计把兜底作业还原为只查 state,该分支承载 state_fail/pr_closed 场景并附有「Live again」注释。
  • rc:3811217427${{ vars… }} 坏替换):测试装置在执行步骤的真实 bash 之前,已用仓库默认值(180)替换该表达式。
  • rc:3812251467rc:3812251486(开头段落中陈旧的 startedAt 锚点措辞):两个代码块现在都描述 run 的创建时间,与所查询的字段一致。已在 12dc1182 修复。
  • rc:3812251492rc:3812251528(跳过消息的归属措辞):两处现在都只陈述守卫实际证明的事——「a bot review of this PR was submitted after this run was created」。已在 12dc1182 修复。
  • rc:3812251505rc:3813388372(按 head 归因,Critical):两处过滤器均无 commit_id 子句;归因仅凭 bot 账号 + submitted_at >= createdAt。已在 a1380d01 修复,并由 @doudouOUC 在该提交上独立复核确认(rv:4973372476)。
  • rc:3812251519(桩的子串分发):桩现在用调用方自己的 --jq 跑在同时携带 createdAtstartedAt 的对象上应答 run view,部分组合字段变异可被杀死。已在 12dc1182 修复。
  • rc:3813388377(并发保证措辞):两个注释块都陈述了真实保证,包括被接受的「重叠运行静默」。已在 a1380d01 修复。
  • rc:3813388379(跨作业接线无测试钉住):已被更彻底地解决——接线已在 a1380d01 删除,「carries no cross-job head wiring to drift」测试钉住 job outputs、REVIEWED_HEAD_SHA 与两处 commit_id == 的不存在。
  • rc:3815300031(fallback 块中残留的 head-keyed 段落):已在 7619a82c 删除;grep 确认 pr_head 在整个 workflow 中无处出现,结构性测试钉住 outputs 的不存在。
  • rc:3815300043(桩注释列出了 head 子句):已在 7619a82c 订正;现在点名了钉住该不存在的测试。
  • rc:3815300048(死掉的 reviewedHead/REVIEWED_HEAD_SHA 旋钮):已在 7619a82c 删除;其不存在已被钉住。

拒绝 / 延后 / 升级

无。

冲突

--conflict false —— 未执行合并。

验证

  • npx vitest run scripts/tests/qwen-pr-review-workflow.test.js --config ./scripts/tests/vitest.config.ts —— 172 通过(1 个文件)
  • npm run lint —— 通过
  • npm run typecheck —— 通过
  • npm run build —— 通过
  • npx prettier --check scripts/tests/qwen-pr-review-workflow.test.js —— 干净

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

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


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

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/qwen-code-pr-review.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

Deferred under the convergence posture (round 7, not a blocker) — recorded, not requested in this round:

  • .github/workflows/qwen-code-pr-review.yml:1766 — [review] the already-posted guard is duplicated verbatim across the two fallback sites; extraction would need a checkout added to the fallback job (also deferred in rounds 2, 3 and 6)
中文说明

未检查(工具限制,非阻断):the executable-script lint — .github/workflows/qwen-code-pr-review.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

收敛姿态下延后(第 7 轮,非阻断)——已记录,本轮不要求修改:共 1 条(原文未翻译,列表见上方英文部分)。

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

Comment on lines +1796 to +1797
elif ! posted_reviews="$(gh api "repos/${GITHUB_REPOSITORY}/pulls/${PR_NUMBER}/reviews" --paginate \
--jq ".[] | select(.user.login == \"$bot_login\") | select(.submitted_at >= \"$run_created\") | .id" 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.

[Critical] The already-posted guard's window (bot account + submitted_at >= run createdAt) matches ANY review posted by the bot account — but this account posts other kinds of reviews too. finalize-release.yml:252-260 unconditionally approves release PRs as CI_BOT_PAT directly, and qwen-triage-finalize.yml:458 posts a deferred APPROVE under QWEN_CODE_BOT_TOKEN || CI_BOT_PAT (the same account whenever QWEN_CODE_BOT_TOKEN is unset). When such an approval lands inside the window, the guard exits 0 and the fallback stays silent for a genuinely dead review run — exactly the "silence with NO review at all" state the guard's comment claims the author + creation-time clauses rule out: the review pipeline's review is still absent, the claim "failed before a review could be posted" remains true, the retry instruction remains needed, and the visible LGTM approval now actively masks the dead pipeline.

Concrete shape, probed against this step's real bash: every release PR triggers a review run (release PRs are same-repo branches authored by github-actions[bot]; precheck-pr is fork-only and authorize unconditionally admits non-review_requested pull_request_target events), finalize-release's second-bot approval is submitted at or after the review run's creation, and if review-pr then fails before posting, the guard matches the approval and skips. The triage leg is the same shape whenever QWEN_CODE_BOT_TOKEN is unset — its green gate counts only event == "pull_request" runs (qwen-triage-finalize.yml:160,184), structurally excluding the review run's pull_request_target run, so its approval can land while the review run is alive. The accepted-trade-off paragraph argues only about an overlapping run's review of THIS workflow; it does not argue this sibling state, so the defense does not transfer.

witness: probe on the extracted real step bash (stub gh applying the step's own --jq filter):
  ARM bot-approve-in-window: exit=0 posted=no — "Skipping fallback comment: a bot review of this PR was submitted after this run was created."
  controls: different author → posted=yes; same account out-of-window → posted=yes
  fixed copy (foreign approvals excluded): release-approve posted=yes, triage-approve posted=yes,
  while the pipeline's own in-window review still posts=no

Key the guard on evidence only this pipeline's review carries instead of the account-wide window — the robust option is having the review step record the id of the review it posted and checking that evidence here; alternatively exclude the known foreign approval bodies from the match. The identical copy in the fallback-comment job (lines 2031-2032) needs the same treatment.

中文说明

【Critical】 已发布守卫的窗口(bot 账号 + submitted_at >= run createdAt)会匹配该 bot 账号发布的任何 review——但该账号还会发布其他种类的 review。finalize-release.yml:252-260 直接以 CI_BOT_PAT 无条件批准 release PR;qwen-triage-finalize.yml:458QWEN_CODE_BOT_TOKEN || CI_BOT_PAT 发布延迟 APPROVE(当 QWEN_CODE_BOT_TOKEN 未配置时即同一账号)。当这类批准落在窗口内时,守卫 exit 0、兜底保持静默——而 review 流水线其实已经死了。这正是守卫注释声称 author + creation-time 子句已排除的「完全没有任何 review 的静默」状态:本流水线的 review 并未发布,「failed before a review could be posted」的断言仍然为真,重试指引仍然需要,而可见的 LGTM 批准反而把死掉的流水线掩盖了。

具体形态(已对步骤的真实 bash 做探针验证):每个 release PR 都会触发一次 review run(release PR 是 github-actions[bot] 创建的同仓库分支;precheck-pr 仅针对 fork,authorize 无条件放行非 review_requestedpull_request_target 事件);finalize-release 的第二 bot 批准提交于该 review run 创建之后;若 review-pr 在发布前失败,守卫就会匹配到该批准并跳过发帖。triage 分支在 QWEN_CODE_BOT_TOKEN 未配置时同形——其绿灯门槛只统计 event == "pull_request" 的 run(qwen-triage-finalize.yml:160,184),在结构上排除了 review run 的 pull_request_target run,因此其批准可以在 review run 存活期间落地。注释中「可接受的折衷」一段只论证了本 workflow 的重叠 run 的 review,未论证这种同账号的外来批准,因此该辩护不能迁移过来。

探针证据(抽出步骤真实 bash,桩 gh 套用步骤自己的 --jq 过滤器):ARM bot-approve-in-window:exit=0 posted=no —— "Skipping fallback comment: a bot review of this PR was submitted after this run was created.";对照:不同作者 → posted=yes,同账号但窗口外 → posted=yes;修正副本(排除外来批准):release-approve posted=yes、triage-approve posted=yes,而本流水线自己窗口内的 review 仍然 posted=no。

建议把守卫锚定到只有本流水线 review 才携带的证据上,而不是账号级窗口——最稳健的做法是让 review 步骤记录其发布的 review id,这里检查该证据;或者从匹配中排除已知的外来批准正文。fallback-comment 作业中的同款副本(2031-2032 行)需要同步处理。

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

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

Autofix round summary — PR #9462

Feedback points and dispositions

[rc:3820618375] Critical — already-posted guard matches foreign same-account approvals → Resolved in code

The claim: the guard's window (bot account + submitted_at >= run createdAt) matches ANY review the bot account posts, but finalize-release.yml (second release approval, same CI_BOT_PAT) and qwen-triage-finalize.yml (deferred APPROVE, QWEN_CODE_BOT_TOKEN || CI_BOT_PAT) also post approvals under that account. When one lands inside the window, the guard exits 0 and the fallback stays silent for a genuinely dead review run — masked by a visible LGTM.

Reproduced before changing anything: the claim is checkable and was probed. Two new tests run the step's real bash with a stub gh applying the step's own --jq filter, and both FAILED against the pre-fix workflow (expected '' not to be '' — the guard skipped posting). The account-sharing premises were verified in the sibling workflows: finalize-release.yml approves under CI_BOT_PAT with body "Automated second approval for the release version bump.", and qwen-triage-finalize.yml posts the deferred APPROVE ("LGTM, looks ready to ship — CI landed green after the review. ✅") under QWEN_CODE_BOT_TOKEN || CI_BOT_PAT.

Fix: the guard's --jq filter now excludes those two known foreign approval bodies by exact match, in both copies (the in-job fallback step and the fallback-comment job). Exact match — not substring — so this pipeline's own report body can never be swallowed by an exclusion; reviews with a null/missing body still match as before. This implements the finding's "exclude the known foreign approval bodies" alternative; the "record the posted review id" option was not taken because the review is posted inside the CLI, so capturing the id would require CLI changes plus cross-job output wiring — outside this PR's footprint.

Both guard comment blocks now document the exclusion and name the sibling workflows, and the existing "stays silent" test gives the pipeline's own review a realistic report body so the exclusions cannot silently swallow it.

Post-fix evidence: the new tests pass; a direct jq probe over the extracted real filter confirmed the finding's witness shape (foreign approvals excluded; the pipeline's own in-window review still matches — alone AND mixed with foreign approvals; stale/different-author controls unchanged); both guard copies verified byte-identical.

[rv:4981569331] CHANGES_REQUESTED review — Declined (nothing requested this round)

The review's items are explicitly marked "Not linted (tool limitation, not a blocker)" and "recorded, not requested in this round" (the duplicated-guard extraction, already deferred in rounds 2, 3 and 6). No checkable defect claim to reproduce; nothing to implement this round. Recorded here so the deferral stays visible.

Changes

  • .github/workflows/qwen-code-pr-review.yml — both copies of the already-posted guard: two select(.body != …) clauses excluding the known foreign approval bodies; a comment paragraph naming the sibling workflows that post them.
  • scripts/tests/qwen-pr-review-workflow.test.jsreviewFixture gains an optional body field; new per-site test "still posts when the only in-window reviews are foreign approvals"; the "stays silent" test now uses a realistic report body.

Conflict

None (--conflict false; origin/main not merged).

Verification

  • npx vitest run --config ./scripts/tests/vitest.config.ts scripts/tests/qwen-pr-review-workflow.test.js -t "foreign approvals" (pre-fix) — 2 failed (reproduction of the finding)
  • npx vitest run --config ./scripts/tests/vitest.config.ts scripts/tests/qwen-pr-review-workflow.test.js — 174 passed
  • jq probe on the extracted real guard filter (7 witness cases incl. mixed fixture) — all passed
  • YAML parse check (js-yaml) — OK (8 jobs)
  • npx prettier --check on both changed files — clean
  • npm run build — passed
  • npm run typecheck — passed
  • npm run lint — passed
  • pre-commit hook (lint-staged) — passed
  • npm run generate:settings-schema — not applicable (no settings source changed)
  • Bundled-CLI/integration tests — not applicable (the changed behavior is exercised by the workflow test harness itself)
中文说明

Autofix 轮次总结 — PR #9462

反馈点及处置

[rc:3820618375] Critical — already-posted 守卫会匹配同账号的外来批准 → 已在代码中解决

该观点认为:守卫的窗口(bot 账号 + submitted_at >= run createdAt)会匹配该 bot 账号发布的任何 review,但 finalize-release.yml(第二个 release 批准,使用同一 CI_BOT_PAT)和 qwen-triage-finalize.yml(延迟 APPROVE,使用 QWEN_CODE_BOT_TOKEN || CI_BOT_PAT)也会以该账号发布批准。当这类批准落在窗口内时,守卫 exit 0,兜底评论对一条真正已死的 review run 保持静默——并被一条可见的 LGTM 所掩盖。

修改前先复现:该缺陷可检验,且已做探针验证。两个新测试用桩 gh(套用步骤自己的 --jq 过滤器)运行步骤的真实 bash,在修复前的 workflow 上均失败expected '' not to be '' —— 守卫跳过了发帖)。同账号的前提已在兄弟 workflow 中核实:finalize-release.ymlCI_BOT_PAT 批准,正文为 "Automated second approval for the release version bump.";qwen-triage-finalize.ymlQWEN_CODE_BOT_TOKEN || CI_BOT_PAT 发布延迟 APPROVE("LGTM, looks ready to ship — CI landed green after the review. ✅")。

修复:守卫的 --jq 过滤器现在以精确匹配排除这两个已知的外来批准正文,两处副本(job 内兜底步骤与 fallback-comment 作业)同步处理。采用精确匹配而非子串匹配,确保本流水线自己的报告正文永远不会被排除条款误伤;body 为 null/缺失的 review 仍按原逻辑匹配。这里实现了该发现给出的「排除已知外来批准正文」备选方案;未采用「记录已发布 review 的 id」方案,因为 review 是在 CLI 内部发布的,捕获该 id 需要 CLI 改动加跨作业输出接线——超出本 PR 的范围。

两处守卫的注释块均已记录该排除条款并点名相关兄弟 workflow;既有的 "stays silent" 测试现在为本流水线自己的 review 赋予真实的报告正文,防止排除条款悄悄把它吞掉。

修复后证据:新测试通过;对抽出的真实过滤器直接做 jq 探针,确认了该发现的见证形态(外来批准被排除;本流水线自己窗口内的 review 仍然匹配——单独存在以及与外来批准混合存在时均如此;stale/不同作者的对照不变);两处守卫副本经核验逐字节一致。

[rv:4981569331] CHANGES_REQUESTED review — 拒绝(本轮无请求事项)

该 review 的条目均明确标注 "Not linted (tool limitation, not a blocker)" 以及 "recorded, not requested in this round"(重复守卫的抽取,已在第 2、3、6 轮延后)。没有可检验的缺陷断言可供复现;本轮无可实施事项。记录于此以保持延后事项的可见性。

变更

  • .github/workflows/qwen-code-pr-review.yml —— already-posted 守卫的两处副本:新增两个 select(.body != …) 子句排除已知外来批准正文;新增一段注释点名发布这些批准的兄弟 workflow。
  • scripts/tests/qwen-pr-review-workflow.test.js —— reviewFixture 增加可选 body 字段;新增逐站点的测试 "still posts when the only in-window reviews are foreign approvals";"stays silent" 测试改用真实的报告正文。

冲突

无(--conflict false;未合并 origin/main)。

验证

  • npx vitest run --config ./scripts/tests/vitest.config.ts scripts/tests/qwen-pr-review-workflow.test.js -t "foreign approvals"(修复前)—— 2 个失败(复现该发现)
  • npx vitest run --config ./scripts/tests/vitest.config.ts scripts/tests/qwen-pr-review-workflow.test.js —— 174 通过
  • 对抽出的真实守卫过滤器做 jq 探针(7 个见证用例,含混合 fixture)—— 全部通过
  • YAML 解析检查(js-yaml)—— 通过(8 个作业)
  • npx prettier --check 两个变更文件 —— 通过
  • npm run build —— 通过
  • npm run typecheck —— 通过
  • npm run lint —— 通过
  • pre-commit 钩子(lint-staged)—— 通过
  • npm run generate:settings-schema —— 不适用(未改动 settings 源)
  • 打包 CLI/集成测试 —— 不适用(变更行为由 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 commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator Author

Verified the round-2 fix and found the exclusion list already incomplete — reporting rather than pushing, since the takeover loop owns the branch.

A third foreign approval body exists, posted under the same account, and it is not excluded. .qwen/skills/triage/references/pr-workflow.md:84 and :701 instruct the triage agent to post -f event=APPROVE -f body='LGTM, looks ready to ship. ✅' directly through the API. That is a different string from the finalize workflow's LGTM, looks ready to ship — CI landed green after the review. ✅, so the shipped select(.body != …) pair does not catch it. It is not hypothetical: on PR #9342 that exact body appears twice as a review by qwen-code-ci-bot, once as the APPROVED review at 2026-08-19T00:10:21Z. Land a review run that dies in the same window and the guard silences the fallback for a genuinely dead pipeline — the finding's own failure shape, through a third door.

The structural point is that the list cannot be finished by enumeration. Three sources are already known (two workflows plus a skill reference), one of them is not even a workflow file, and any of the three can be reworded without anyone thinking about this filter — and every such drift fails in the dangerous direction: a masked dead pipeline, not a noisy comment.

Suggested direction: match on evidence only this pipeline's review carries, rather than excluding what it does not. Every body compose-review posts ends with the — _<model> via Qwen Code /review (v…)_ attribution, and PR-plan bodies additionally carry the <!-- qwen-review-ledger marker; the foreign approvals carry neither (checked against every bot review on #9342 and #9462: the ones without the attribution are exactly the triage/release approvals). An allowlist also fails in the safe direction — if the attribution ever changes, the guard stops firing and the comment posts, which is the pre-PR status quo rather than a masked failure. Worth confirming before adopting: that every composed body — including an APPROVE with no findings — carries at least one of the two.

中文说明

已核验第 2 轮的修复,并发现排除清单本身就不完整——因分支由 takeover 循环管理,我只报告不推送。

存在第三种同账号外来批准正文,且未被排除。 .qwen/skills/triage/references/pr-workflow.md:84:701 指示 triage agent 直接通过 API 发 -f event=APPROVE -f body='LGTM, looks ready to ship. ✅'。它与 finalize 工作流那句 LGTM, looks ready to ship — CI landed green after the review. ✅ 是不同字符串,因此已合入的 select(.body != …) 两条抓不到它。这并非假设:在 PR #9342 上该正文作为 qwen-code-ci-bot 的 review 出现过两次,其中 2026-08-19T00:10:21Z 那条是 APPROVED。只要有一次 review run 在同一时间窗内死掉,守卫就会为真正死掉的流水线保持静默——正是该发现描述的失败形态,从第三扇门进来。

结构性问题在于:这份清单无法靠枚举收尾。 目前已知三个来源(两个工作流 + 一个 skill 参考文档),其中一个甚至不是工作流文件;三者中任何一处改写措辞都不会有人想到这个过滤器,而每一次漂移都朝危险方向失败——被掩盖的死流水线,而不是一条吵闹的评论。

建议方向:匹配只有本流水线 review 才携带的证据,而不是排除它不携带的东西。 compose-review 发布的每份正文都以 — _<model> via Qwen Code /review (v…)_ 署名结尾,PR 计划的正文还额外携带 <!-- qwen-review-ledger 标记;外来批准两者皆无(已对 #9342#9462 上的全部 bot review 核对:没有署名的恰好都是 triage/release 批准)。白名单同样朝安全方向失败——若署名将来变化,守卫不再触发、评论照发,那只是回到本 PR 之前的状态,而非被掩盖的失败。采纳前值得确认一点:每一份合成正文(包括零发现的 APPROVE)都至少携带两者之一。

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

Partially reviewed — gaps disclosed.

Not reviewed: build-and-test — Test (macos-latest, Node 22.x) was skipped in CI (merge_group-gated) and its suite ran locally on Linux only.

Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/qwen-code-pr-review.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

Deferred under the convergence posture (round 8, not a blocker) — recorded, not requested in this round:

  • scripts/tests/qwen-pr-review-workflow.test.js:3548 — [review] test hardcodes FOREIGN_APPROVAL_BODIES instead of deriving them from the producer workflows
  • .github/workflows/qwen-code-pr-review.yml:1806 — [review] the already-posted guard is duplicated verbatim across the two fallback sites, embedding exclusion literals the file's convention says to define once (workflow-level env: next to FAL…
  • .github/workflows/qwen-code-pr-review.yml:1806 — [review] the exclusion literals are exact-string copies of producer-owned bodies (finalize-release.yml, qwen-triage-finalize.yml) with no back-reference on either producer side
中文说明

仅完成部分审查,审查缺口已披露。

未审查:build-and-test — Test (macos-latest, Node 22.x) was skipped in CI (merge_group-gated) and its suite ran locally on Linux only。

未检查(工具限制,非阻断):the executable-script lint — .github/workflows/qwen-code-pr-review.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

收敛姿态下延后(第 8 轮,非阻断)——已记录,本轮不要求修改:共 3 条(原文未翻译,列表见上方英文部分)。

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

echo "::warning::already-posted guard unavailable (no run creation time); posting the fallback comment"
echo "Already-posted guard unavailable (run creation time missing); proceeding to post." >> "$GITHUB_STEP_SUMMARY"
elif ! posted_reviews="$(gh api "repos/${GITHUB_REPOSITORY}/pulls/${PR_NUMBER}/reviews" --paginate \
--jq ".[] | select(.user.login == \"$bot_login\") | select(.submitted_at >= \"$run_created\") | select(.body != \"Automated second approval for the release version bump.\") | select(.body != \"LGTM, looks ready to ship — CI landed green after the review. ✅\") | .id" 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.

[Critical] R7-1: the foreign-approval exclusion list is still incomplete — a third same-account approval body, LGTM, looks ready to ship. ✅, matches the guard window and silences the fallback for a genuinely dead run. .qwen/skills/triage/references/pr-workflow.md (lines 82-84 and 699-701) instructs the triage agent to approve with exactly that body via gh api .../reviews -f event=APPROVE, under QWEN_CODE_BOT_TOKEN || CI_BOT_PAT — the same account this guard resolves whenever that secret is unset. The two select(.body != ...) clauses exclude only the release-second-approval and triage-finalize bodies, so the triage approval passes the author and window clauses. This is not hypothetical: PR #9342 carries that exact body twice from qwen-code-ci-bot, once as the APPROVED review at 2026-08-19T00:10:21Z. A review run created before such an approval that then dies before posting its own review is silenced by it — the failure shape this PR exists to stop, through a third door. The identical copy at line 2050 has the same hole.

The entrance space is unbounded — three producers are already known (two workflows plus a skill reference doc an LLM executes), and the live reviews on PR #9342 also carry a fourth freeform variant ("LGTM, looks ready to ship — five rounds converged…") that any exclusion list, including one extended with the third body, would miss. Prefer matching on evidence only this pipeline's review carries — every composed review body ends with the via Qwen Code /review (v…) attribution, while the foreign approvals carry none — over enumerating bodies it does not carry. That fails in the safe direction: if the attribution ever changes, the guard stops firing and the comment posts (the pre-PR status quo, not a masked failure). Verify every composed body, including a zero-findings APPROVE, carries the attribution before adopting; if exclusions stay for now, at minimum add the third body at both sites and extend the test's FOREIGN_APPROVAL_BODIES.

witness — probe on the steps' real bash (stub gh applying the step's own --jq):
SHIPPED: site=fallback job body="LGTM, looks ready to ship. ✅" → status=0 posted=NO
         site=in-job step  body="LGTM, looks ready to ship. ✅" → status=0 posted=NO
         ("Skipping fallback comment: a bot review of this PR was submitted after this run was created.")
+ third exclusion clause: both sites → posted=YES
live: gh api repos/QwenLM/qwen-code/pulls/9342/reviews
      → review 4967239026 APPROVED 2026-08-19T00:10:21Z user=qwen-code-ci-bot
        body="LGTM, looks ready to ship. ✅"
中文说明

【Critical】 R7-1:外来批准正文的排除清单仍不完整——第三个同账号批准正文 LGTM, looks ready to ship. ✅ 会匹配守卫窗口,使兜底评论在真正死掉的流水线面前保持静默。.qwen/skills/triage/references/pr-workflow.md(第 82-84 行与第 699-701 行)指示 triage agent 通过 gh api .../reviews -f event=APPROVE 以该正文发布批准,所用令牌为 QWEN_CODE_BOT_TOKEN || CI_BOT_PAT——当该 secret 未配置时即本守卫所解析的同一账号。现有两条 select(.body != ...) 只排除了 release 第二批准与 triage-finalize 的正文,因此该 triage 批准能通过作者与时间窗两个子句。这并非假设:PR #9342 上就有 qwen-code-ci-bot 以该正文发布的两条 review,其中一条是 2026-08-19T00:10:21Z 的 APPROVED。若一次 review run 在该批准落地之前创建、又在发布自己的 review 之前死掉,就会被它静音——正是本 PR 要消除的失败形态,从第三扇门进来。第 2050 行的同款副本有同样的洞。

入口空间是无界的——目前已知三个来源(两个工作流 + 一个由 LLM 执行的 skill 参考文档),且 PR #9342 的实际 review 数据中还有第四种自由措辞变体("LGTM, looks ready to ship — five rounds converged…"),任何排除清单(包括补上第三个正文的清单)都会漏掉它。建议改为匹配只有本流水线 review 才携带的证据——每份合成的 review 正文都以 via Qwen Code /review (v…) 署名结尾,而外来批准两者皆无——而不是枚举它不携带的正文。该方向朝安全侧失败:若署名将来变化,守卫不再触发、评论照发(回到本 PR 之前的状态,而不是掩盖死流水线)。采纳前请确认每一份合成正文(包括零发现的 APPROVE)都携带该署名;若暂保留排除清单,至少在两处站点补上第三个正文,并同步扩充测试中的 FOREIGN_APPROVAL_BODIES

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

The foreign-approval exclusion list shipped incomplete: the triage skill's
commit-pinned APPROVE body also posts under the same account, matches the
guard's author and window clauses, and silenced the fallback for a
genuinely dead run — the failure shape this guard exists to stop. The
producer set is open, so no exclusion list can be finished; every miss
fails in the dangerous direction.

Match positively instead: a review silences the fallback only if its body
carries what only this pipeline's composed reviews carry — the
"via Qwen Code /review" attribution footer or the invisible
qwen-review-ledger marker. Every composed body carries at least one (a
zero-findings APPROVE included); no foreign approval carries either. A
marker that ever changes shape stops the guard firing and the comment
posts — the pre-guard status quo, not a masked dead run.
@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 轮)。改动内容与我反驳保留之处如下:

Round summary — PR #9462 (already-posted guard, round 9)

One Critical finding, one carrying review, one maintainer report — all three name the same defect. Fixed at the root; nothing else was actionable this round.

Feedback points and dispositions

[rc:3821576772] Critical R7-1 — the foreign-approval exclusion list is incomplete; LGTM, looks ready to ship. ✅ silences the fallback → Fixed (implemented the finding's preferred direction).

Reproduced before changing anything: ran the shipped --jq filter (jq 1.6) over a review fixture carrying that exact body from qwen-code-ci-bot, submitted in-window — the filter matched (emitted the review id), so the guard would skip the fallback for a genuinely dead run. The body is real: .qwen/skills/triage/references/pr-workflow.md instructs the triage agent to post it via gh api .../reviews -f event=APPROVE under the bot token, at two sites in that doc.

The fix is the one the finding and the maintainer comment both recommend: stop enumerating what the pipeline's reviews are NOT, match on what only they ARE. Both guard sites now keep only reviews whose body carries the via Qwen Code /review attribution footer or the invisible qwen-review-ledger marker. Verified the precondition the finding asked for — every composed body carries at least one of the two, a zero-findings APPROVE included: the footer rides every composed body when attribution is on (compose-review appends it on every render leg, trim included), and the ledger marker rides every PR-named review regardless of attribution or trimming (composeReview appends it after the body budget settles). No foreign approval carries either. The failure direction is now safe: if the markers ever change shape, the guard stops firing and the comment posts — the pre-PR status quo, not a masked dead pipeline.

Changes:

  • .github/workflows/qwen-code-pr-review.yml — both guard sites (in-job step and fallback-comment job): replaced the two select(.body != …) exclusion clauses with select((.body // "") | contains("via Qwen Code /review") or contains("qwen-review-ledger")); rewrote the trailing rationale paragraph to name the open producer set and the positive-match direction.
  • scripts/tests/qwen-pr-review-workflow.test.js — added the third foreign body to FOREIGN_APPROVAL_BODIES (the regression pin); added COMPOSED_REVIEW_BODIES covering all three marker shapes (both, ledger-only/attribution-off, footer-only/pre-ledger) and drove the silence tests through all of them at both sites; gave the clause-isolation cases composed bodies so the author/window clauses — not missing markers — decide their outcomes.

Pre-round gate evidence: with the pre-round workflow restored temporarily, exactly the two new foreign-approval tests fail (one per site); with the fix, all pass.

[rv:4982729106] CHANGES_REQUESTED review — "Partially reviewed — gaps disclosed" → Its finding (R7-1) is the Critical above; disclosures acknowledged.

The review's carried finding is R7-1, fixed as above. Its two disclosures are noted and unchanged here: the macOS test matrix leg is merge_group-gated and this runner is Linux (the jq-gated tests probe for jq and skip honestly where absent), and actionlint's embedded-shell source mapping is unsupported (tool limitation — the real-bash test harness is this file's executable coverage). The three items the review deferred under the convergence posture (test deriving FOREIGN_APPROVAL_BODIES from producers; the guard duplicated across the two sites; producer-side back-references) were explicitly "recorded, not requested in this round" and were left untouched. Note the interaction: this round's fix removes the exclusion literals the third deferred item names, so that item no longer applies as written; the other two still stand.

[ic:5355135806] Maintainer report (@wenshao) — same defect plus the structural direction → Fixed along that direction.

The report's structural point — the list cannot be finished by enumeration, and every drift fails toward masking a dead pipeline — is exactly what the fix implements. Its suggested evidence pair (footer or ledger marker) was verified against the compose path before adoption, as the report asked.

Conflict: none (--conflict false; no merge performed).

Verification

Commands actually run this round, in order:

  • Reproduction probe: shipped --jq filter over a fixture with body LGTM, looks ready to ship. ✅ (jq 1.6) — matched (emitted the review id): defect reproduced
  • New-filter probe over six fixture shapes (third foreign body, footer+ledger, footer-only, ledger-only, null body, two known foreign bodies) — all six behaved as required
  • npm run buildpassed (exit 0)
  • npm run typecheckpassed (exit 0)
  • npm run lintpassed (exit 0)
  • npx vitest run --config ./scripts/tests/vitest.config.ts scripts/tests/qwen-pr-review-workflow.test.js174 passed (174)
  • Pre-round gate check: same vitest run against the pre-round workflow — 2 failed (the two new foreign-approval tests, one per site) | 172 passed, confirming the new tests fail before the fix; fix restored afterward and re-verified green
  • npx prettier --check on the two changed files — passed (after one whitespace fix, re-ran the focused vitest suite: 174 passed)

Not run (not applicable): npm run generate:settings-schema (no settings source touched); bundle + integration tests (the changed behavior lives in workflow bash, exercised by the real-bash test harness above). Environment-unavailable legs, as disclosed by the review: the macOS test matrix and actionlint's embedded-shell lint — the workflow's CI remains the final gate for those.

中文说明

本轮总结 — PR #9462(already-posted 守卫,第 9 轮)

一条 Critical 发现、一份携带该发现的 review、一条维护者报告——三者指向同一个缺陷。已从根因修复;本轮没有其他需要处理的内容。

反馈点与处置

[rc:3821576772] Critical R7-1 — 外来批准正文排除清单不完整,LGTM, looks ready to ship. ✅ 会使兜底评论静默 → 已修复(采纳了该发现推荐的方向)。

修改前先复现:用 jq 1.6 将已合入的 --jq 过滤器作用于一条携带该正文、来自 qwen-code-ci-bot、提交时间落在窗口内的 review fixture——过滤器命中(输出了 review id),即守卫会为一条真正死掉的流水线跳过兜底评论。该正文真实存在:.qwen/skills/triage/references/pr-workflow.md 在两处指示 triage agent 通过 gh api .../reviews -f event=APPROVE 以 bot 令牌发布它。

修复方式正是该发现与维护者评论共同推荐的方向:不再枚举本流水线 review「不是什么」,改为匹配「只有它才是什么」。两处守卫站点现在只保留正文携带 via Qwen Code /review 署名或不可见 qwen-review-ledger 标记的 review。已按该发现的要求核验前提——每一份合成正文都至少携带两者之一,包括零发现的 APPROVE:署名在 attribution 开启时随每一份合成正文发布(compose-review 在每个渲染分支、包括裁剪路径都会追加它),而 ledger 标记无论 attribution 或裁剪与否都随每一份指定了 PR 的 review 发布(composeReview 在正文预算落定后追加)。外来批准两者皆无。失败方向现在是安全的:若标记将来变形,守卫不再触发、评论照发——回到本 PR 之前的状态,而不是被掩盖的死流水线。

改动:

  • .github/workflows/qwen-code-pr-review.yml — 两处守卫站点(in-job step 与 fallback-comment job):将两条 select(.body != …) 排除子句替换为 select((.body // "") | contains("via Qwen Code /review") or contains("qwen-review-ledger"));重写结尾的 rationale 段落,点明开放的来源集合与正向匹配方向。
  • scripts/tests/qwen-pr-review-workflow.test.js — 向 FOREIGN_APPROVAL_BODIES 添加第三个外来正文(回归钉);新增 COMPOSED_REVIEW_BODIES,覆盖全部三种标记形态(双标记、仅 ledger/attribution 关闭、仅署名/ledger 引入前),并让两处站点的静默测试逐一通过它们;为子句隔离用例配齐合成正文,使作者/时间窗子句——而非缺失的标记——决定其结果。

前轮门禁证据:临时还原本轮之前的 workflow 后,恰好是两条新的外来批准测试失败(每站点一条);应用修复后全部通过。

[rv:4982729106] CHANGES_REQUESTED review —— "Partially reviewed — gaps disclosed" → 其发现(R7-1)即上述 Critical;已确认其披露项。

该 review 携带的发现即 R7-1,已按上文修复。其两项披露在此记录、不做改动:macOS 测试矩阵腿受 merge_group 门控且本 runner 为 Linux(依赖 jq 的测试会探测 jq,缺失时如实跳过);actionlint 的 embedded-shell source mapping 尚不支持(工具限制——真实 bash 测试骨架即该文件的执行覆盖)。review 在收敛姿态下延后的三项(测试从 producer 推导 FOREIGN_APPROVAL_BODIES、守卫在两站点逐字重复、producer 侧反向引用)明确为「已记录、本轮不要求修改」,未触碰。交互说明:本轮修复移除了第三项延后内容所指的排除字面量,该项按原文已不再适用;其余两项仍然成立。

[ic:5355135806] 维护者报告(@wenshao)—— 同一缺陷及结构性方向 → 按该方向修复。

报告的结构性观点——清单无法靠枚举收尾、且每一次漂移都朝掩盖死流水线的方向失败——正是本次修复所实现的。其建议的证据对(署名或 ledger 标记)在采纳前已按报告要求对合成路径完成核验。

冲突: 无(--conflict false;未执行 merge)。

验证

本轮实际执行的命令,按顺序:

  • 复现探针:已合入的 --jq 过滤器作用于正文为 LGTM, looks ready to ship. ✅ 的 fixture(jq 1.6)—— 命中(输出 review id):缺陷复现
  • 新过滤器探针,覆盖六种 fixture 形态(第三个外来正文、署名+ledger、仅署名、仅 ledger、null 正文、两个已知外来正文)—— 六种行为全部符合要求
  • npm run build通过(exit 0)
  • npm run typecheck通过(exit 0)
  • npm run lint通过(exit 0)
  • npx vitest run --config ./scripts/tests/vitest.config.ts scripts/tests/qwen-pr-review-workflow.test.js174 通过(174)
  • 前轮门禁检查:同一 vitest 在本轮之前的 workflow 上运行 — 2 失败(两条新的外来批准测试,每站点一条)| 172 通过,确认新测试在修复前失败;随后恢复修复并再次确认全绿
  • 对两个改动文件执行 npx prettier --check通过(修正一处空白后重跑聚焦 vitest:174 通过)

未执行(不适用):npm run generate:settings-schema(未触碰 settings 源);bundle + 集成测试(改动行为位于 workflow bash 中,由上述真实 bash 测试骨架覆盖)。环境不可用的部分,与 review 披露一致:macOS 测试矩阵与 actionlint 的 embedded-shell lint——workflow 的 CI 仍是这些项的最终门禁。

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

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


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

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed — no blockers.

3 Suggestion-level finding(s) this review confirmed are already reported on this PR and are not repeated:

  • D9-1 already-posted guard duplicated verbatim across the two fallback sites — already recorded in the rounds 2, 3, 6, 7 and 8 deferral lists
  • D9-2 the guard's --paginate flag is pinned by no assertion — already recorded in the rounds 2, 4 and 6 deferral lists
  • D9-4 guard skip path does not record which review IDs bought the silence — already recorded in the round 6 deferral list

Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/qwen-code-pr-review.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

Deferred under the convergence posture (round 9, not a blocker) — recorded, not requested in this round:

  • .github/workflows/qwen-code-pr-review.yml:1811 — [review] marker literals are unpinned copies of the CLI composer constants
  • scripts/tests/qwen-pr-review-workflow.test.js:3299 — [probe] stub serves the reviews fixture to any repos/* endpoint; the guard's URL is unpinned
中文说明

已审查——无阻断问题。

本轮确认的 3 条建议级发现已在 PR 上报告过,不再重复发布(列表见上方英文部分)。

未检查(工具限制,非阻断):the executable-script lint — .github/workflows/qwen-code-pr-review.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

收敛姿态下延后(第 9 轮,非阻断)——已记录,本轮不要求修改:共 2 条(原文未翻译,列表见上方英文部分)。

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

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

No action taken this round — the only new feedback is the automated reviewer's COMMENTED review ("Reviewed — no blockers"), and it requests nothing:

  • The 3 Suggestion-level findings it lists (D9-1 guard duplicated across the two fallback sites, D9-2 --paginate unpinned by an assertion, D9-4 skip path not recording the matching review IDs) are confirmed by that review as already reported on this PR and not repeated; they remain recorded in the earlier rounds' deferral lists and are tracked in the deferred-findings queue for the follow-up issue.
  • The 2 items deferred under the convergence posture (unpinned [review] marker literals at qwen-code-pr-review.yml:1811; unpinned stub URL at qwen-pr-review-workflow.test.js:3299) are explicitly "recorded, not requested in this round" and likewise stay in the follow-up queue.
  • The executable-script lint note is a disclosed tool limitation, not a blocker.

No inline comments, no issue-level feedback, no failed or still-red checks were present this round (all CI checks are SUCCESS or SKIPPED). This is round 9; per the repo's review policy, Suggestion-level items past the early rounds stay deferred to follow-ups rather than growing a converging PR. No code changes were made and nothing was committed.

中文说明

本轮未采取任何操作——唯一的新反馈是自动评审器发布的 COMMENTED 评审("已审查——无阻断问题"),其中没有提出任何修改要求:

  • 该评审列出的 3 条建议级发现(D9-1 守卫在两个 fallback 位置之间逐字重复、D9-2 --paginate 标志没有任何断言约束、D9-4 跳过路径未记录匹配的评审 ID)已被该评审确认早已在本 PR 上报告过且不再重复发布;它们仍记录在早前各轮次的延后清单中,并已纳入延后发现队列,留待后续跟进 issue 处理。
  • 收敛姿态下延后的 2 条(qwen-code-pr-review.yml:1811 处未固定的 [review] 标记字面量;qwen-pr-review-workflow.test.js:3299 处未固定的 stub URL)被明确标注为"已记录,本轮不要求修改",同样保留在后续跟进队列中。
  • 可执行脚本 lint 一项属于已披露的工具限制,并非阻断问题。

本轮没有行内评论、没有 issue 级反馈、也没有失败或持续飘红的检查(所有 CI 检查均为 SUCCESS 或 SKIPPED)。当前已是第 9 轮评审;按照本仓库的评审政策,超出早期轮次的建议级事项应保持延后、交由后续跟进处理,而不是让一个正在收敛的 PR 继续膨胀。本轮未修改任何代码,也未提交任何内容。

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


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

Reviewed.

3 Suggestion-level finding(s) this review confirmed are already reported on this PR and are not repeated:

  • D9-1 already-posted guard duplicated verbatim across the two fallback sites — already recorded in the rounds 2, 3, 6, 7, 8 and 9 deferral/duplicate lists
  • D10-1 the guard's marker literals are unpinned hand-copies of the CLI composer constants (FOOTER_MARKER / qwen-review-ledger prefix) — already recorded in the round 9 deferral list
  • D9-2 the guard's --paginate flag is pinned by no assertion (mutation probe: deleting it keeps the suite green) — already recorded in the rounds 2, 4, 6 and 9 deferral/duplicate lists

Not linted (tool limitation, not a blocker): the executable-script lint — .github/workflows/qwen-code-pr-review.yml: actionlint embedded-shell source mapping is not yet supported — not linted.

中文说明

已审查。

本轮确认的 3 条建议级发现已在 PR 上报告过,不再重复发布(列表见上方英文部分)。

未检查(工具限制,非阻断):the executable-script lint — .github/workflows/qwen-code-pr-review.yml: actionlint embedded-shell source mapping is not yet supported — not linted。

— glm-5.3 via Qwen Code /review (v0.21.11)

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

No action taken this round — the only new feedback is the automated reviewer's round-10 COMMENTED review ("Reviewed."), which posted zero findings and requests nothing:

  • The 3 Suggestion-level findings it lists (D9-1 the already-posted guard duplicated verbatim across the two fallback sites; D10-1 the guard's marker literals are unpinned hand-copies of the CLI composer constants; D9-2 the guard's --paginate flag is pinned by no assertion) are confirmed by that review as already reported on this PR and not repeated. All three were re-verified against the current code this round and still describe it accurately: the two guard blocks remain textually identical across both sites; contains("via Qwen Code /review") / contains("qwen-review-ledger") in the filter are hand-copies of FOOTER_MARKER (review-footer.ts) and the ledger OPEN prefix (ledger.ts) with no test tying them together; and no assertion in the test file mentions paginate. They are real, verified findings — and they remain recorded in the earlier rounds' deferral lists and tracked in the deferred-findings queue for the follow-up issue, so nothing is lost at merge. They stay out of this PR deliberately, not by oversight.
  • The executable-script lint note on .github/workflows/qwen-code-pr-review.yml is a disclosed tool limitation (actionlint embedded-shell source mapping is not yet supported), not a blocker — the real-bash test harness in scripts/tests/qwen-pr-review-workflow.test.js is this file's executable coverage.
  • No inline comments, no issue-level feedback, no failed or still-red checks were present this round (all 58 checks are SUCCESS or SKIPPED).

This is review round 10; the last two reviews both reported no blockers, and per the repo's review policy Suggestion-level items past the early rounds stay deferred to follow-ups rather than growing a converging PR. No code changes were made and nothing was committed.

中文说明

本轮未采取任何操作——唯一的新反馈是自动评审器第 10 轮发布的 COMMENTED 评审("Reviewed."),该评审未发布任何新发现,也没有提出任何修改要求:

  • 该评审列出的 3 条建议级发现(D9-1:already-posted 守卫在两个 fallback 站点之间逐字重复;D10-1:守卫的标记字面量是 CLI 合成器常量的未固定手工拷贝;D9-2:守卫的 --paginate 标志没有任何断言约束)已被该评审确认早已在本 PR 上报告过且不再重复发布。本轮已对照当前代码逐一复核,三者仍然准确:两处守卫代码块在两个站点之间依旧逐字相同;过滤器中的 contains("via Qwen Code /review") / contains("qwen-review-ledger")FOOTER_MARKER(review-footer.ts)与 ledger OPEN 前缀(ledger.ts)的手工拷贝,且没有任何测试将二者关联;测试文件中也确实没有任何断言提及 paginate。它们是真实且已核实的发现——但它们仍记录在早前各轮次的延后清单中,并已纳入延后发现队列、留待后续跟进 issue 处理,因此在合并时不会丢失。它们被排除在本 PR 之外是有意为之,而非疏漏。
  • 关于 .github/workflows/qwen-code-pr-review.yml 的可执行脚本 lint 提示属于已披露的工具限制(actionlint 的 embedded-shell source mapping 尚不支持),并非阻断问题——scripts/tests/qwen-pr-review-workflow.test.js 中的真实 bash 测试骨架即该文件的执行覆盖。
  • 本轮没有行内评论、没有 issue 级反馈、也没有失败或持续飘红的检查(全部 58 项检查均为 SUCCESS 或 SKIPPED)。

当前已是第 10 轮评审;最近两轮评审均报告无阻断问题,按照本仓库的评审政策,超出早期轮次的建议级事项应保持延后、交由后续跟进处理,而不是让一个正在收敛的 PR 继续膨胀。本轮未修改任何代码,也未提交任何内容。

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


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

@wenshao

wenshao commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /triage

@qwen-code-ci-bot

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

Flakiness gate: ✅ 1 changed test file(s) x 5 identical rounds, no divergence

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

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

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

抖动门:✅ 1 changed test file(s) x 5 identical rounds, no divergence

Verification report

PR #9462 deep verification — fix(ci): stop the fallback comment from denying a review it already posted

Verdict: merge-ready — 84/84 scripted assertions passed, 0 unexpected failures. Verified head f9333d0620df865a8e2c8cb858885bd931d2b1ca (merge-ref HEAD^2; base tip 099a71c9). The central claim is load-bearing: an independent A/B harness driving the steps' real bash flips 10/10 incident-shaped cells from "posts the contradictory comment" (base) to "stays silent with a truthful skip line" (head), while every near-miss and both unavailable paths keep posting on head. The PR's own suite is green at head (174/174) and a 10-mutant matrix kills every mutant on exactly its predicted tests, zero survivors.

中文摘要
  • 结论merge-ready。84 条脚本化断言全部通过,0 意外失败。
  • A/B 结论:独立 harness 以桩 gh(对夹具套用步骤自己的 --jq 过滤器)驱动两个兜底站点的真实 bash。事故形态(本次运行已发布 review)在 base 上一律发出自相矛盾的评论、在 head 上一律静默并写 skip 行(10/10 翻转);陈旧 review、他人账号、同账号外来 LGTM、PENDING、无 review 五种近似情形在 head 上照常发帖;createdAt 不可得与 reviews 列表失败两条 fail-open 路径照常发帖且带 ::warning:: + step-summary 通告。
  • 测试钉住:10 个变异体(整块回退、删 author/时间窗/marker 子句、createdAt→startedAt、fail-open 反转、删通告、重引入 head 子句、dedup 锚点破坏)全部被且仅被预测的测试杀死;fail-open 方向实际被 11 个测试钉住(含 7 个旧测试)。无 jq 环境下 25 个失败与 base 逐名一致(预存),15 个 guard 用例诚实 skip。
  • Findings:无阻塞项。仅描述性偏差:PR 正文若干数字/说明停留在早期轮次(165→174 通过、8→16 新测试实例、42→55 兄弟套件、job 级合并读取说明),最终代码自洽且被测试钉住。
  • 未覆盖:真实 GitHub API 形状(无 token,createdAt/submitted_at 同形假设,失败方向受 fail-open 限制);yamllint 无法安装(容器无 pip3,YAML 有效性由 actionlint 与 yaml 解析器双重证明);逐 commit 归因(depth-2,仅聚合 diff)。

Central claim + A/B

Central claim: when this run already posted its composed review, both fallback sites stay silent instead of claiming "the review could not be posted", attributed by bot account + submission-at-or-after-run-creation + composed-review marker; and every shape that must NOT buy silence still posts.

Harness: ab-harness.mjs extracts both run: blocks verbatim (YAML parser) from base (HEAD^1) and head YAML, substitutes ${{ vars.* }} as Actions would, and drives them through an independent stub gh that runs each call's own --jq filter over JSON fixtures with real jq — the filter is the unit under test. Timestamps model the #9342 incident plus the measured re-run drift (created 09:08:38Z, attempt-2 startedAt 11:30:00Z, review 11:56:34Z). 64/64 checks passed (ab-run3.log), captured in 01-ab-base-vs-head-guard.png:

scenario (review fixture) base (no guard) head (guard)
incident: bot, footer+ledger, after creation POST, body carries the false claim SILENT + "a bot review of this PR was submitted" in summary
attribution off (ledger marker only) POST SILENT
pre-ledger bundle (footer only) POST SILENT
re-run window (between createdAt and startedAt) POST SILENT
moved head (review on OLDSHA, PR at NEWSHA) POST SILENT
stale review (before this run was created) POST POST
foreign account (marker, in window) POST POST
foreign approval (bot LGTM, no marker) POST POST
PENDING review (submitted_at null) POST POST
no reviews at all POST POST
run creation time unavailable POST POST + ::warning::already-posted guard + summary line
reviews listing fails POST POST + ::warning::already-posted guard + summary line

(identical at both sites — fallback-comment job and in-job step — 24 cells + skip-line/warning/false-claim checks = 64 assertions). The base incident cell is the control oracle: it ships "Qwen Code review did not complete successfully … retry with @qwen-code /review" beside a review the fixture says was posted; head replaces that with silence.

Marker invariant (why the positive match is sound): compose-review.ts appends the ledger marker to every PR-review body it returns (only local, PR-less reviews get none, and those are never posted); the attribution footer rides when review.attribution is on, so at least one marker rides every posted composed body. The one escape (a mid-compose plan-file corruption makes ledgerMarkerFor catch → null while attribution is off) fails open — the comment posts, i.e. the pre-guard status quo, not a masked dead run. The foreign same-account producers (finalize-release.yml ×2, qwen-triage-finalize.yml, triage skill pr-workflow.md ×2) all post fixed bodies containing neither marker and no PR-derived text, so nothing attacker-writable can mint a silencing body today.

Reviewer Test Plan walk

plan step result
npx vitest run scripts/tests/qwen-pr-review-workflow.test.js — "165 pass" runs green; actual count at the final tree is 174 passed (174) (the 165 figure predates later rounds adding tests)
"Eight new tests execute the steps' real bash" 16 new test instances exist (7 per site × 2 sites + 2 shared); all pass; they do execute the real bash
{site} stays silent when THIS run already posted its review present, passes; M0/M1..M3 prove it non-vacuous
… still posts when no review can be attributed to this run (stale/foreign-account/PENDING/none) present, passes; each case pinned by M1/M2
… posts when this run's start time is unavailable present under the renamed title "…creation time is unavailable"; passes; pinned by M5
… posts when the reviews lookup itself fails present, passes; pinned by M5/M6
pre-existing assertion tightened (not.toContain('run view') → head lookups) verified in diff and live: the guard calls gh run view … createdAt on every event; M4/M7 pin the lookups' semantics
"Local failures unrelated to this change" (repairs a single unwritable directory, 5 autofix) do not reproduce in this container: the full file is 174/174 green here, and qwen-autofix-workflow.test.js is 192/192 (with one unhandled vitest-worker RPC timeout — infrastructure noise, not a test failure). Environment-dependent, not a PR regression
sibling suites "green (42 pass)" green; actual count 55 passed

Corrections

  • The body says "The job-level step also now reads state and headRefOid in one gh pr view … which is where its head value comes from", and its stub note explains the state,headRefOid branch as serving "the job-level step's new combined read". At the shipped head this is stale: round 3 removed the head clause entirely and reverted the fallback-comment job to a state-only query (--json state --jq '.state', line 1997); only the in-job step keeps the combined read (line 1725). The final test file's own comment ("Live again: the fallback job reverted to a state-only query …") matches the code. The description's round-1 wiring no longer exists — correctly, since the guard no longer keys on the head.

Findings

No blocking findings. Informational only:

  1. Stale description counts (severity: nit). "165 pass" → 174; "eight new tests" → 16 instances; sibling suites "42" → 55; the combined-read/stub notes above. All are description drift across the PR's ten rounds; the shipped code and tests are internally consistent and every behavioral claim I tested holds.

  2. Fail-open is pinned more broadly than the PR states (positive). M5 (silence-on-unavailable) was killed by 11 tests, not the 2 new ones: seven pre-existing tests run without a runCreated fixture, so their stub answers createdAt with '' and the shipped guard fail-OPENs there — turning that into silence voids their posts too. The fail-open direction is therefore defended by the old suite as well.

Mutation matrix (vacuity + coverage)

Control (unmutated head in scratch worktree): 174 passed, 0 failed. Every mutant killed exactly its predicted test set (exact-set equality; mutation-matrix.mjs, captured in 02-mutation-matrix-all-killed.png):

mutant killed by (predicted = observed)
M0 revert guard (both sites) 7 (both "stays silent", both "survives a re-run", both "says so in the log", "attributes by TIME") — failures are behavioral (expected '&lt;!\-\- qwen-review-fallback …' to be '')
M1 drop author clause 2 ("still posts … not attributed" ×2, foreign case)
M2 drop time-window clause 2 (same test, stale/pending cases)
M3 drop marker clause 2 ("still posts … foreign approvals" ×2)
M4 createdAt→startedAt 2 ("survives a job re-run" ×2)
M5 exit silent when creation time unavailable 11 (4 predicted + 7 pre-existing fail-open pins)
M6a drop ::warning (creation-time branch) 2 ("says so in the log" ×2)
M6b drop ::warning (reviews-failed branch) 2 ("says so in the log" ×2)
M7 re-add head clause (in-job only) 2 ("attributes by TIME", "carries no cross-job head wiring")
M8 break dedup anchor (control outside the guard) 2 (both dedup tests)

Zero survivors; the reverted run fails the intended behavioral assertion (M0 quotes expected-vs-actual posted body), and M8 proves the runner catches regressions outside the new tests.

Targeted gates

  • head suite: 174 passed (174); base suite: 158 passed (158) → +16 tests, +0 failures.
  • jq-less regime (jq exits 127): base 25 failed/133 passed, head 25 failed/134 passed/15 skipped; the 25 failing names are byte-identical on both arms (pre-existing retry-loop cases, equally untestable without jq), 0 head-only, 0 base-only; the 15 skips are exactly the jq-driven guard cases (03-nojq-attribution-clean.png).
  • jq filter semantics against real jq: 8/8 (04-jq-semantics-boundary.png) — >= keeps the boundary, drops 1s-before, drops null submitted_at (PENDING), null body doesn't crash, footer/ledger match, foreign LGTM doesn't.
  • Lint: bash -n clean on all four extracted scripts (base+head × 2 sites); shellcheck --shell=bash clean on all four (live control caught a planted violation); actionlint clean on the changed workflow (live control caught a planted undefined-variable); ESLint clean on the changed test file (live control caught a planted unused var). yamllint could not be installed (no pip3 in this container) — see Not covered.

Not covered

  • Real GitHub API shapes: no token in this sandbox, so gh run view --json createdAt and REST submitted_at formats were not observed live. The guard's lexicographic >= is valid only while both stay fixed-format YYYY-MM-DDTHH:MM:SSZ — the same comparison pattern this workflow family already uses (qwen-triage.yml .submitted_at >= $since). If a format ever drifted, the failure direction is bounded: an unavailable/failed listing posts (fail-open), and a silently-wrong comparison degrades to the pre-guard status quo (comment posts) rather than masking a dead run.
  • yamllint gate not run (no pip3 in container); YAML structural validity is nonetheless proven by two independent parsers (actionlint and the yaml package used by the harness and the suite).
  • Per-commit attribution: depth-2 checkout holds only the merge commit, base tip, and PR head (snapshot lists 10 commits, 1 reachable). The aggregate HEAD^1..HEAD diff was verified; per-commit attribution is out of reach.
  • End-to-end GitHub posting (a real comment on a real PR) — by design the harness stubs gh; the PR's own scope statement agrees.
  • The author-claimed local failures (unwritable-dir test, 5 autofix tests) do not reproduce here; I did not chase the author's environment.

Methodology

Environment: node:22-bookworm CI container, merge-ref checkout (HEAD merge commit, HEAD^1 base tip, HEAD^2 PR head), npm ci+npm run build pre-run. ab-harness.mjs and mutation-matrix.mjs (scratch git worktree at HEAD with root node_modules symlinked, removed after) drive the steps' real bash extracted verbatim from base/head YAML through an independent stub gh that applies each call's own --jq to JSON fixtures with real jq; nojq-attribution.mjs and jq-semantics.mjs are the remaining scripted checks. Raw logs (ab-run*.log, mut-*.json, base-*.json, head-nojq.json, matrix-run.log) and harness sources live beside this report; evidence images in evidence/.

Flakiness gate log

rounds=5 files=1 skipped=0
file scripts/tests/qwen-pr-review-workflow.test.js: (cd .) npx --no-install vitest run --config ./scripts/tests/vitest.config.ts ./scripts/tests/qwen-pr-review-workflow.test.js


per-file results (P=pass F=fail I=infra-exit, one letter per run):
  scripts/tests/qwen-pr-review-workflow.test.js: PPPPP

verdict: pass
summary: 1 changed test file(s) x 5 identical rounds, no divergence

--- per-invocation detail (full copy in the artifact) ---
round 1 · scripts/tests/qwen-pr-review-workflow.test.js: P (exit 0)
round 2 · scripts/tests/qwen-pr-review-workflow.test.js: P (exit 0)
round 3 · scripts/tests/qwen-pr-review-workflow.test.js: P (exit 0)
round 4 · scripts/tests/qwen-pr-review-workflow.test.js: P (exit 0)
round 5 · scripts/tests/qwen-pr-review-workflow.test.js: P (exit 0)

Evidence images

01-ab-base-vs-head-guard

02-mutation-matrix-all-killed

03-nojq-attribution-clean

04-jq-semantics-boundary

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

Qwen Code · sandboxed verification

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM, looks ready to ship. ✅

@qwen-code-ci-bot
qwen-code-ci-bot dismissed stale reviews from themself August 20, 2026 22:35

Superseded: the stage-1a template gate this review enforced now passes (Risk & Scope and Linked Issues were added); triage re-run re-gated the PR at f9333d0.

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

🤖 Reviewed the latest feedback — no changes needed. Why, point by point:

No action taken this round — there is no actionable feedback newer than the last evaluation (2026-08-20T16:57:29Z):

  • The automated reviewer posted an APPROVED review ("LGTM, looks ready to ship. ✅") carrying zero findings; it requests nothing.
  • No new inline review comments and no new carrying reviews.
  • The only new issue-level items are a /triage trigger command and the resulting "Sandboxed verification is running" status post — both are workflow triggers/status reports, not feedback on the code.
  • No failed or still-red checks.

The PR stays as-is at f9333d0620 (fix/review-fallback-false-failure), awaiting the sandboxed verification result.

中文说明

🤖 已审阅最新反馈——无需改动。逐点说明原因如下:

本轮未做任何改动——自上次评估(2026-08-20T16:57:29Z)之后没有可操作的反馈:

  • 自动评审器提交了一个 APPROVED 评审("LGTM,看起来可以合入了 ✅"),未携带任何发现项;它没有提出任何请求。
  • 没有新的行内评审意见,也没有新的承载评审。
  • 唯一新增的议题级条目是一条 /triage 触发命令,以及随后的"沙箱验证正在运行"状态帖——两者都是工作流触发命令/状态报告,而非针对代码的反馈。
  • 没有失败或持续红色的检查项。

PR 保持在 f9333d0620(fix/review-fallback-false-failure)不变,等待沙箱验证结果。

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


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

@wenshao
wenshao enabled auto-merge August 20, 2026 23:45

@doudouOUC doudouOUC left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed at HEAD f9333d0. Approving — no new issues found.

The 22 open bot threads are all superseded by later commits (the bot posts them but they were never resolved by hand); I checked each remaining Critical against the code as it stands:

Both recent Criticals — fixed by this diff. The foreign-approval concern (release/triage APPROVEs from the same bot account buying silence, incl. the R7-1 LGTM, looks ready to ship. ✅ triage body) is resolved by dropping body-enumeration for a positive match on what only this pipeline's reviews carry: contains("via Qwen Code /review") or contains("qwen-review-ledger"). I ran the shipped filter against a fixture covering every shape — a composed body with the footer, the ledger marker, both, and neither; a foreign LGTM; a release approval; a wrong-author, a stale (pre-createdAt), and a PENDING (submitted_at: null) review. Only the three composed bodies matched; every foreign/stale/pending case fell through to posting. null >= "…" is false in jq, so PENDING is correctly excluded, and the |-piped contains(a) or contains(b) binds as intended (both test .body).

Other open threads — addressed. Skip-message wording now reads "a bot review of this PR was submitted after this run was created" (no longer over-claims "this run posted"); the dead *state*) stub branch is live again since the fallback job reverted to a state-only query; the ${{ vars.QWEN_REVIEW_MAX_TIMEOUT_MINUTES }} bad substitution is fixed by substituting before bash runs; both failure paths now emit ::warning:: + a step-summary line (no more silent degrade); the head-keyed leftovers and duplicated anchor rationale were removed.

Design is sound and fails safe. Scoped to the bot account + a submission >= createdAt (stable across job re-runs, unlike startedAt), deliberately not keyed on the moving head. Every unavailable input (no creation time, listing failure) declines to fire and posts — the pre-guard status quo, never a masked dead run.

CI green (qwen-pr-review-workflow.test.js 165 pass via Test ubuntu-latest).

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

Copy link
Copy Markdown
Collaborator

Released in v0.22.0.

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