Skip to content

perf(review): retire dry chunks and pipeline verification in the reverse audit - #8498

Merged
wenshao merged 5 commits into
mainfrom
feat/review-ra-retirement
Aug 5, 2026
Merged

perf(review): retire dry chunks and pipeline verification in the reverse audit#8498
wenshao merged 5 commits into
mainfrom
feat/review-ra-retirement

Conversation

@wenshao

@wenshao wenshao commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

Summary

Stacked on #8468 (the reverse-audit budget gate) — merge that first; this PR's diff then shrinks to its own two commits.

Two independent measurements say the reverse-audit loop is where large-PR reviews spend most of their time: a +1699-line CI review ran the loop to the 5-round cap and was killed at 240 minutes mid-verification (#8368), and a +974-line local benchmark completed in 144 minutes with 95 of them (66%) in the loop — 5 rounds × 6 chunks. The round-by-chunk yield grid of that benchmark:

chunk:    1    2    3    4    5    6
round 1:  S    ·    ·    ·    ·    ·      S = one Suggestion, · = dry
round 2:  S    S    ·    S    ·    ·
round 3:  S    S    ·    ·    S    ·
round 4:  S    S    ·    S    ·    ·
round 5:  ·    ·    ·    ·    ·    ·      (ended by the 5-round cap)

Chunks 3 and 6 were dry all five rounds — a third of the loop's auditors re-certifying converged territory — while the findings all came from the hot chunks. And every round waited serially for its verification before the next began.

The design intent — converge within one run, so misses do not leak into another full review cycle — is preserved by both changes; what they remove is redundancy, not depth.

Change 1: per-chunk retirement with cold rotation (CLI-enforced)

From round 3, agent-prompt --all-chunks reads the harness transcripts (the same evidence check-coverage trusts) and retires a chunk whose own last two audits were substantively dry — the receipt named what it examined AND the transcript shows the diff was opened; a whiff or a missing transcript keeps a chunk hot (fail toward auditing). A retired chunk is cold-checked on alternating rounds and returns to every-round auditing the moment a cold check yields. Rounds 1-2 always audit every chunk. Hot chunks get no less auditing than today; a late find in a retired chunk arrives one round later instead of never. (One bounded residual: a chunk retired late enough that its next cold check falls past the 5-round cap — e.g. retired after round 4 — is last audited at its retirement round; that tail is capped by the same hard limit that already ends the loop, and the chunk still holds the two-dry certificate the loop used to end on.) When every chunk holds the two-dry certificate and none is due, the builder prints CONVERGED and exits 5 — a clean convergence: no unreviewedDimensions entry, the per-chunk certificates being collectively the same evidence the global two-dry-rounds rule demanded. The budget gate (exit 4) runs first and is unchanged; single --chunk rebuilds bypass scheduling entirely; any classification error falls back to the full fan-out.

Change 2: verification pipelines with the next round (SKILL)

Round k's verifiers and round k+1's auditors now launch in one response. The cumulative list exists so auditors do not re-report what is filed — an unverified entry serves that purpose exactly as well as a confirmed one, so the 5-8 minutes per round spent waiting for verdicts bought nothing. The orderings that matter stay: the last round's verification completes before Step 6, nothing unverified reaches the report or the PR, and an entry the verifier rejects leaves the list at the next merge.

Projected on the benchmark: the 95-minute loop drops to roughly 55 minutes (retirement −20% of auditors on that grid; pipelining −5-8 min/round), with detection semantics intact.

Test plan

9 new scheduling tests (rounds 1-2 full; round-3 skip with named note; cold-check parity; yield-returns-to-hot; whiff stays hot; all-retired → exit 5 with no records and no stamp; cold-check-only round still stamps; --chunk bypass; transcripts-unavailable fallback; budget-gate-before-retirement pin). Full src/commands/review: 1710 passed, 0 failed; eslint/prettier clean. Coverage interplay verified: skipped chunk-rounds write no records, and the Step 4/5 delivery floor is satisfied by rounds 1-2's records.

中文说明

概述

叠在 #8468 之上——请先合并那个,本 PR 的 diff 随之缩为自己的两个提交。

两次独立测量都表明反审循环是大 PR 评审的最大时间去向:+1699 行的 CI 评审跑满 5 轮上限、在第 240 分钟被杀于验证中途(#8368);+974 行的本地基准 144 分钟完整跑完,其中 95 分钟(66%)在循环里——5 轮 × 6 chunk。逐轮×逐 chunk 产出网格见上(S=1 条 Suggestion,·=干净):chunk 3、6 五轮全干净——三分之一的 auditor 在反复认证早已收敛的领地;所有发现都来自热区。且每轮都串行等完验证才开下一轮。

设计初衷——在单次运行内收敛、避免漏检泄漏到下一整轮评审——两处改动都完整保留;砍掉的是冗余,不是深度。

变更 1:按 chunk 退休 + 冷轮换(CLI 强制)

第 3 轮起,agent-prompt --all-chunks 读取 harness transcripts(与 check-coverage 同源的证据),退休自身最近两次审计均"实质干净"的 chunk——回执点名检查对象 transcript 显示确实打开过 diff;whiff 或缺 transcript 一律保持热区(失败方向=多审计)。退休 chunk 隔轮冷抽查,一旦出货立即回到每轮必审。第 1、2 轮永远全量。热区得到的审计不少于现状;退休区的晚期发现最多晚一轮到达,不会丢失。(一个有界残余:退休得足够晚、下次冷抽查落在 5 轮上限之外的 chunk——例如第 4 轮后退休——其最后一次审计即退休轮;这条尾巴被本就终结循环的硬上限所限,且该 chunk 仍持有循环过去赖以终止的"连续两轮干净"证书。)全部 chunk 持有"连续两轮干净"证书且本轮无人到期时,builder 打印 CONVERGED 并以 5 退出——干净收敛:不欠 unreviewedDimensions 条目,按 chunk 的证书合起来正是全局两干净轮规则所要求的同一份证据。预算闸(exit 4)先行且不变;单 --chunk 重建完全绕过调度;分类异常回退全量扇出。

变更 2:验证与下一轮流水线化(SKILL)

第 k 轮的 verifier 与第 k+1 轮的 auditor 在同一个响应中发射。累计清单的作用是让 auditor 不重复报告——未验证条目与已确认条目在这个用途上等效,过去每轮 5~8 分钟的串行等待买不来任何东西。有意义的顺序保留:末轮验证在 Step 6 前完成,未验证内容绝不进报告或 PR,被 verifier 否决的条目在下次合并时移出清单。

按基准折算:95 分钟循环预计降至约 55 分钟(退休 −20% auditor;流水线每轮 −5~8 分钟),检测语义不变。

测试计划

9 个新调度用例(1-2 轮全量;第 3 轮跳过并点名;冷抽查奇偶;出货回热;whiff 保持热;全退休 → exit 5 且零记录零 stamp;纯冷查轮照常 stamp;--chunk 绕过;transcripts 不可用回退;预算闸先于退休)。全 src/commands/review:1710 通过 0 失败;eslint/prettier 干净。覆盖率交互已核验:被跳过的 chunk-轮不写记录,Step 4/5 投递下限由 1-2 轮的记录满足。

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

🔄 Qwen Triage is runningwatch live progress. Stage results will post in this thread as they complete.

🔄 Qwen Triage 正在运行 —— 查看实时进度。各阶段结果完成后会更新在本线程。

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Re-run over the two commits landed since the last pass (c11df3b8 test-guard split, then 80d4d939 — the autofix round that closed the 23:17 review ledger). Gate re-checked against the new head; nothing below changes verdict.

  • Template: same shape as before — headings deviate from the repo template (Summary / Change 1 / Change 2 / Test plan), but the body covers everything it asks for plus a full Chinese translation. Same structure as fix(review): stop the reverse-audit loop while there is still time to report #8468, so still not gating on it.
  • Problem: still observed and quantified, not theoretical — the feat(auth): add Kimi and Xiaomi MiMo providers #8368 CI review killed at the 5-round cap mid-verification (independently verifiable in Actions), and the round-by-chunk yield grid showing a third of the loop's auditors re-walking converged chunks. The new commits don't change the problem statement; they harden the classifier against the review's probes.
  • Direction: still aligned — the deliberate second step of the fix(review): stop the reverse-audit loop while there is still time to report #8468 work on the repo's own review infrastructure: the budget gate decides when the loop must end, this PR makes the loop cheaper so more of it fits inside the budget. CHANGELOG: no direct reference, but the area is the repo's own tooling.
  • Size: 863 production lines (agent-prompt.ts +240/−43, new retirement.ts +469, prompt-record.ts +51/−9, agent-briefs.ts +10/−1, deadline.ts +22/−18 comment-only) vs 1369 test lines vs 15 lines of SKILL.md docs. That is over the 500-line awareness threshold; the two-tier gate's awareness flag is a visibility note here, not an escalation — the author is a repo admin and the change carries three probe-backed review rounds from that maintainer. The core-path touch is the 15-line SKILL.md prose plus the cross-package span. Note fix(review): stop the reverse-audit loop while there is still time to report #8468 has merged since the last pass — the diff is now this PR's own 8 files, and the stack caveat is gone.
  • Approach: scope remains right. The fail-toward-auditing bias survived the hardening round — every new guard's degradation direction is "audit more", never fewer auditors. No drive-by changes: the deadline.ts delta is comment-only, keeping the reserve arithmetic's documentation honest under the pipelined loop.
  • Risk: no elevated risk signals — none of the changed files match the high-risk paths from the revert-history analysis.

Moving on to code review of the delta. 🔍

中文说明

针对上次评审后落地的两个提交(c11df3b8 测试守卫拆分、80d4d939——关闭 23:17 评审清单的 autofix 轮次)重跑门禁,基于新 head 复查;以下各项不改变结论。

  • 模板:与之前相同——标题与仓库模板不一致(Summary / Change 1 / Change 2 / Test plan),但正文覆盖模板要求的全部内容并附完整中文翻译。与 fix(review): stop the reverse-audit loop while there is still time to report #8468 结构一致,仍不因此拦截。
  • 问题:仍是已观测且已量化的——feat(auth): add Kimi and Xiaomi MiMo providers #8368 的 CI 评审在 5 轮上限处被杀于验证中途(可在 Actions 中独立核实),"轮 × chunk"产出网格显示三分之一的 auditor 在反复重走已收敛的 chunk。新提交不改变问题陈述,只是按评审探针加固分类器。
  • 方向:仍然对齐——fix(review): stop the reverse-audit loop while there is still time to report #8468 工作在仓库自身评审基建上的刻意第二步:预算闸决定循环必须何时结束,本 PR 让循环更便宜、使更多轮次装进预算。CHANGELOG 无直接引用,但该领域是仓库自身工具。
  • 规模:863 行生产代码(agent-prompt.ts +240/−43、新增 retirement.ts +469、prompt-record.ts +51/−9、agent-briefs.ts +10/−1、deadline.ts +22/−18 纯注释),测试 1369 行,SKILL.md 文档 15 行。超过 500 行关注阈值;两级门禁的关注提示在此只是可见性说明而非升级——作者是仓库管理员,且本变更带有该维护者三轮带探针的评审。核心路径触及为 15 行 SKILL.md 文案与跨包范围。注意 fix(review): stop the reverse-audit loop while there is still time to report #8468 已在上次评审后合并——diff 现在就是本 PR 自己的 8 个文件,堆叠说明不再需要。
  • 方案:范围仍然合理。失败偏向多审计的倾向在加固轮后完整保留——每个新守卫的退化方向都是"多审计"。无夹带改动:deadline.ts 的变化纯为注释,让储备时长的文档在流水线化循环下保持诚实。
  • 风险:无升级风险信号——变更文件均未命中 revert 历史分析中的高风险路径。

进入代码审查 🔍

Qwen Code · qwen3.8-max

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

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Code review — the 23:17 ledger is closed at this head

Independent baseline first: given "retire dry chunks, pipeline verification", I would have done exactly what this PR does — derive per-chunk state from the artifacts the delivery checks already trust (the CLI's own prompt records + the harness transcripts, never orchestrator-writable), fail every classification error toward auditing, order convergence ahead of the budget gate so a clean exit never wears a truncation disclosure, and keep --chunk repairs of admitted rounds ungated while routing an unadmitted round's per-chunk builds through the same gate. The delta matches that baseline and exceeds it in rigor in the places review poked.

Every one of the 15 findings in the CHANGES_REQUESTED review (1 Critical, 14 Suggestions) is closed at this head, each with a test carrying the original probe's shape — I checked each ledger entry against the diff, not just the commit message:

  • R1-1 (Critical, separator class): the receipt separator now admits [::] in both widths beside the dash forms, and a U+FF1A receipt that read unknown on the unfixed class is pinned dry ("a Chinese receipt separated by a full-width colon is dry").
  • R1-4 / R1-5 (dry bar range-blind; receipt parroted from the brief): classifyReturn now requires the read to overlap the chunk's baked territory (openedTheTerritory), and substantiveClause refuses a clause echoing the brief's own REVERSE_AUDIT_EXAMPLE_RECEIPT — both pinned by tests, with the brief's example exported from agent-briefs.ts so parser and prompt cannot drift.
  • R1-11 (named-object shortcuts satisfiable by prose): the shortcuts now require an enclosed code span, a real path (second slash or dotted extension — and/or rejected), 4+ CJK ideographs, or a 20-char clause; stray backticks and "all good." stay unknown. Pinned.
  • R1-12 / R1-13 (quotation vs filing; tag removal keyed to merges): a **File:** line already present in the agent's own launch prompt is a quotation, not a filing (pinned for both a bare line and a whole entry); SKILL.md's merge now runs unconditionally before every round build and before Step 6, with the [unverified] tag removed on confirm / entry removed on reject.
  • R1-2 / R1-7 / R1-8 / R1-9 / R1-10 / R1-14 / R1-15 and R1-3 / R1-6: the record mtime fence (dead-attempt records on CI retry), transcripts-unavailable degradation on BOTH admission paths, stamp-keyed exemption with a half-built round refused, cold-check recovery for an uncertified build, admission-leaves-no-marker, the history-less chunk staying due, the same-round multi-record merge in both digest orders, convergence-before-budget under deadline pressure, and a surviving-tag escalation path in SKILL.md — each has its test or its SKILL paragraph.

My own pass beyond the ledger: the new exit-5 blast radius is contained — no workflow script or CLI module shells out to agent-prompt; the SKILL-driven orchestrator is its only consumer, and SKILL.md and the command description both document 5 as a clean termination. The --chunk asymmetry (stamped round = ungated repair, unstamped = full gate sequence) is deliberate and both sides are probed. The one corner I chased — a malformed plan reaching the --chunk convergence check without requireAuditableChunks — is unreachable in practice: a chunk with dry history was auditable when that history was written, and the plan is immutable after capture. deadline.ts is comment-only. The wasDeliveredVerbatim split into deliveredVerbatim + flattenPrompt preserves the contract for the coverage callers and amortizes flattening on the scheduler's O(records × transcripts) walk.

Nothing blocking found. The author's "1710 passed in src/commands/review" is their claim; the evidence below is the PR's own CI.

Testing — the PR's own CI on the reviewed commit

The macOS/Windows unit legs and the no-sandbox integration leg are skipped, not failed — identical to the merged #8468's head, so this is the normal pattern for this branch, not a regression signal. The primary suite ran green.

Check Conclusion
Qwen Code CI (workflow run) ✅ success
Test (ubuntu-latest, Node 22.x) ✅ success
Test (macos-latest, Node 22.x) ⏭️ skipped
Test (windows-latest, Node 22.x) ⏭️ skipped
Integration Tests (CLI, No Sandbox) ⏭️ skipped
web-shell E2E Smoke (ubuntu-latest, Node 22.x) ✅ success
Desktop Shell (ubuntu-22.04) ✅ success

Sandboxed verification would settle the one claim reading alone cannot: that the classifier hardening at this head keeps the A/B behavior the previous round substantiated at 0cf3170b (full-width-colon receipts, parrot refusal, territory-overlap bar) — that round is already in flight as part of this triage run (run 30967503093); its report lands as a separate comment. The 95→55-minute wall-clock projection itself is arithmetic over measured round costs, not a measurement — its first real test is the next budgeted large-PR CI review.

中文说明

代码审查 —— 23:17 的评审清单在本 head 上全部关闭

先说独立基线:给定"退休干净 chunk、流水线化验证"这个目标,我会做的与这个 PR 完全一致——从交付检查本就信任的两份工件(CLI 自己的 prompt 记录 + harness transcripts,绝不读编排者可写的东西)推导每个 chunk 的状态,一切分类错误都失败向多审计,收敛检查排在预算闸之前使干净退出永不披上截断披露,--chunk 修复已准入轮次不过闸、而未准入轮次的逐 chunk 构建走同一套闸。本 diff 与这个基线一致,并在评审戳过的地方更严。

CHANGES_REQUESTED 评审中全部 15 条发现(1 条 Critical、14 条 Suggestion)都在本 head 上关闭,且每条都有携带原探针形状的测试——我是逐条对照 diff 核验的,不是只看提交说明:R1-1(Critical,分隔符类)现在同时接受半角/全角冒号,U+FF1A 回执有测试钉死;R1-4/R1-5(干判定无视行范围、回执照抄简报样例)现在要求读取与 chunk 烘焙领地重叠、并拒绝回声简报自带样例的子句;R1-11(命名对象捷径可被散文满足)现在要求成对代码 span、真实路径、4 个以上汉字或 20 字符子句;R1-12/R1-13(引用 vs 申报、标签移除依赖合并)以"文件行已在自身启动提示中即为引用"区分,SKILL 的合并在每轮构建前与 Step 6 前无条件执行;其余各条(记录 mtime 围栏、两条准入路径的 transcripts 不可用退化、以 stamp 为键的豁免、冷抽查未认证回热、准入不留 marker、无历史 chunk 保持到期、同轮多记录合并在两种 digest 顺序下、截止压力下收敛先于预算、SKILL 中残留 tag 的升级路径)各有其测试或文案。

我在清单之外的核查:新 exit-5 的影响面收敛——没有任何工作流脚本或 CLI 模块直接调用 agent-prompt,SKILL 驱动的编排者是唯一消费者,SKILL.md 与命令描述都已把 5 记为干净终止。--chunk 的不对称(已盖章轮=无闸修复,未盖章=完整闸序列)是刻意的,两侧都有探针。我追过的一个角落——畸形 plan 绕过 requireAuditableChunks 到达 --chunk 收敛检查——实际不可达:有干净历史的 chunk 在历史写入时必然可审计,而 plan 捕获后不可变。deadline.ts 纯注释。wasDeliveredVerbatim 拆分为 deliveredVerbatim + flattenPrompt 保持了 coverage 调用方的契约,并为调度器的 O(记录 × transcript) 走查摊平了展平开销。

未发现阻塞项。作者"src/commands/review 1710 通过"是其自述;下面的证据来自 PR 自己的 CI。

测试 —— 已评审提交上的 CI

macOS/Windows 单测与无沙箱集成为 skipped 而非失败——与已合并的 #8468 的 head 完全一致,属于该分支的常规模式,不是回归信号。主套件全绿(见上表:ubuntu 单测、web-shell E2E、Desktop Shell 均 success)。

沙箱验证将落定纯阅读无法落定的一项主张:本 head 上的分类器加固是否保持上一轮在 0cf3170b 上 A/B 证实的行为(全角冒号回执、拒绝回声、领地重叠线)——该轮已作为本次 triage 运行的一部分在执行(run 30967503093),报告会以单独评论发布。95→55 分钟的墙钟折算本身是按实测轮成本的算术而非测量,第一次真实检验是下一次带预算的大 PR CI 评审。

Qwen Code · qwen3.8-max

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

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Confidence: 4/5 — every finding from three probe-backed review rounds is closed at the head, each pinned by a test carrying the original probe's shape, and CI is green on the reviewed commit; the remaining fifth is what reading alone cannot settle — the wall-clock arithmetic, one SKILL seam still held partly by orchestrator compliance, and a verification round on this exact head still in flight.

Stepping back over the whole arc: the previous pass approved the mechanism early; the review rounds since found two genuine Criticals and a cluster of real holes in the classifier, and this head closes them the way I would have closed each — and in a couple of places better than my baseline (the record fence deliberately keeps the coverage callers unfenced, with the obligation/history distinction spelled out; the three admission paths share one gate helper so they cannot drift). The fail-toward-auditing bias — the whole personality of this subsystem — survived every fix: each new guard's degradation direction is "audit more". The tests are the probes, not new prose about them, and my own walk beyond the ledger (exit-5 blast radius, the --chunk asymmetry, the malformed-plan corner) came back clean.

Named reservations, none blocking: the pipelined last-round ordering is now mechanical where it can be — the [unverified] tag makes Step 6's confirmed-only read structural and gives a surviving tag an explicit escalation path — but compliance at that one SKILL seam is still assumed. The 95→55-minute projection is arithmetic over measured round costs; its first real test is the next budgeted large-PR CI review. And the sandboxed verification round for this head is in flight — the mechanism itself was A/B substantiated at the earlier head, so this round is confirming the hardening, not the idea.

One state note for whoever merges: the standing CHANGES_REQUESTED review is the /review run's against c11df3b8, two commits back — every finding in its ledger is verifiably closed at this head (checked one by one in the Stage 2 comment). The engaged autofix loop owns that review's lifecycle, so I have not touched it; a fresh re-review or dismissal will clear it.

Approving, pinned to the reviewed commit.

中文说明

信心:4/5 —— 三轮带探针评审的每一条发现都在本 head 上关闭,每条都有携带原探针形状的测试钉死,已评审提交上的 CI 全绿;剩下的五分之一是纯阅读无法落定的部分——墙钟折算、一处仍部分依赖编排者合规的 SKILL 接缝,以及针对本 head 的验证轮仍在执行中。

退一步看整条弧线:上一轮较早地批准了机制本身;其后的评审轮找出两个真正的 Critical 和分类器上一批真实的洞,而本 head 按我会采用的方式逐条关闭——有几处比我的基线更好(记录围栏刻意让 coverage 调用方保持无围栏并写明"义务/历史"之别;三条准入路径共用一个闸 helper,不会漂移)。整个子系统的性格——失败偏向多审计——在每次修复后完整保留:每个新守卫的退化方向都是"多审计"。测试就是那些探针本身,不是关于它们的新散文;我在清单之外的核查(exit-5 影响面、--chunk 不对称、畸形 plan 角落)也全部干净。

点名保留意见,均不阻塞:流水线化后的末轮顺序在能结构化的地方已经结构化——[unverified] 标签让 Step 6 的"只读已确认"成为结构性读取,残留标签有明确的升级路径——但那一处 SKILL 接缝仍假设编排者合规。95→55 分钟的折算是按实测轮成本的算术,第一次真实检验是下一次带预算的大 PR CI 评审。针对本 head 的沙箱验证轮正在执行——机制本身已在更早的 head 上 A/B 证实,本轮是确认加固,不是确认想法。

给合并者的状态说明:当前挂着的 CHANGES_REQUESTED 是 /review 流程针对两个提交之前的 c11df3b8 的评审——其清单中的每条发现都已在本 head 上逐条核验关闭(见 Stage 2 评论)。接手中的 autofix 循环拥有该评审的生命周期,我未触碰它;一次新的复审或 dismiss 会将其清除。

批准,锚定在已评审的提交上。

Qwen Code · qwen3.8-max

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

@wenshao

wenshao commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator Author

Review: perf(review): retire dry chunks and pipeline verification in the reverse audit

Reviewed the full stacked diff (#8468's budget gate + this PR's two commits): deadline.ts, retirement.ts, the agent-prompt wiring, compose-review, the workflow deadline export, and the SKILL edits.

Overall: the direction is right and the engineering is careful. Retirement is enforced in the CLI rather than asked for in prose; the schedule is derived from the two artifacts the orchestrator cannot author (its own prompt records × the harness transcripts); every classification path fails toward auditing; readTranscripts' plan-mtime fence is inherited correctly, so a stale-session collision degrades to a full fan-out. The budget-stop marker being read by compose-review directly — rather than depending on the orchestrator to relay a sentence — is the right shape for a verdict cap. Nine scheduling tests drive the real handler round by round instead of unit-testing the scheduler in isolation, which is what makes them worth having.

I found two issues I'd want fixed before merge, and four smaller ones. Both Criticals are reproduced with probes below, run against the PR head in a clean worktree. I did not run the full src/commands/review suite — I ran the two files this diff touches: deadline.test.ts (15) + agent-prompt.test.ts (166), 181 passed, 0 failed.


🔴 Critical 1 — the budget state survives into the CI in-job retry, and poisons it

budget-rounds.json and budget-stop.json live in promptRecordDir(planPath), which is derived from the plan path only. Unlike readTranscripts(since, …) — which retirement.ts:173 correctly fences on the plan's mtime — neither file is fenced by anything, and nothing clears the record dir on a fresh capture (promptRecordDir has exactly three non-test callers: check-coverage, prompt-record, deadline; none deletes).

The .qwen/tmp sweep that would have cleaned it is Step 9 — which by construction does not run when an attempt dies early. And the workflow retries in the same job, same workspace, same plan path:

run_review_once "$attempt_timeout"      # attempt 1 → OUTCOME=retryable, no Step 9
...
run_review_once "$attempt_timeout"      # attempt 2 → same .qwen/tmp

Two consequences, both reproduced:

(a) A stale marker caps a healthy retry's verdict with a false disclosure. compose-review.ts:350 reads the marker unconditionally, so attempt 2 — which may have run every round comfortably — discloses reverse audit — stopped before round 3 by the review time budget and has an otherwise-Approve capped at COMMENT.

(b) stampRound's dedupe-by-round means attempt 2 is never stamped at all, so every attempt-2 estimate is measured from an attempt-1 wall-clock timestamp:

[B] attempt-2 round-1 estimate (s): 660        # measured from attempt 1's round-4 stamp
[B] attempt-2 round-2 estimate (s): 2160       # true round cost ~1500
[B] refused? { remainingSeconds: 3240, reserveSeconds: 1185, expectedRoundSeconds: 2160 }
probe (240-min budget; attempt 1 admits rounds 1-4 then drops its connection at T+160; attempt 2 starts at T+161)
stampRound(plan, 1, T0 + 30 * MIN); stampRound(plan, 2, T0 + 70 * MIN);
stampRound(plan, 3, T0 + 110 * MIN); stampRound(plan, 4, T0 + 150 * MIN);
const A2 = T0 + 161 * MIN, attemptTimeout = 79 * 60;
const env = { [DEADLINE_ENV]: String(A2 / 1000 + attemptTimeout),
              [RESERVE_ENV]: String(Math.floor(attemptTimeout / 4)) };  // as the workflow computes
expect(reverseAuditBudgetExhausted(env, expectedRoundSeconds(plan, 1, A2), A2)).toBeNull();
stampRound(plan, 1, A2);
expect(readRoundStamps(plan)).toHaveLength(4);   // attempt 2's admission silently dropped
const A2R2 = A2 + 25 * MIN;                      // 54 min of budget left, round costs ~25
expect(reverseAuditBudgetExhausted(env, expectedRoundSeconds(plan, 2, A2R2), A2R2)).not.toBeNull();

So a transient API error on a large PR can leave the retry with no reverse audit at all plus a disclosure blaming a time budget it never hit — precisely inverting what this gate is for. The same thing happens locally on a re-review of a target whose previous run was interrupted before Step 9.

Suggested fix: give both files the same fence the transcripts already have — stamp planMtimeMs into each and discard on mismatch (a couple of lines in readRoundStamps / readBudgetStop), or have the capture step clear promptRecordDir. The fence is the cheaper option since it stays local to deadline.ts.


🔴 Critical 2 — one transcript can retire every chunk

retirement.ts:194 credits every record whose prompt appears in a transcript:

transcripts.filter((t) => wasDeliveredVerbatim(t.launchPrompt, prompt)).map(classifyReturn)

There is no injectivity constraint — and wasDeliveredVerbatim is a "you may add, you may not remove" test, so a launch prompt that is all N blocks concatenated matches all N records. verificationGaps guards exactly this, in a comment that says why:

// Injective: one transcript may satisfy ONE roster requirement. Without this, pasting the whole roster output to a single agent yields one transcript that…

Reproduced against the real scheduler — two agents, each handed a whole round's output, retire six chunk-rounds:

[C] schedule at round 3: {"due":[],"coldChecks":[],"skipped":[
  {"chunkId":13,"dryRounds":[1,2],"nextColdCheck":4},
  {"chunkId":14,"dryRounds":[1,2],"nextColdCheck":4},
  {"chunkId":15,"dryRounds":[1,2],"nextColdCheck":4}],"converged":true}

That is exit 5 / CONVERGED, whose stderr text asserts "This is a clean convergence, not a gap: no unreviewedDimensions entry is owed" — on evidence from a launch shape this codebase elsewhere refuses to credit, and verificationGaps' floor-of-one still passes because the one agent did read a brief. Nothing downstream catches it.

This is a shortcut the orchestrator has demonstrably taken before (it is why the injectivity rule exists), not a hypothetical. Given the module's own stated threat model — "evidence authored by the subject is not evidence", "fail toward auditing" — retirement should apply the same greedy one-transcript-one-record assignment verificationGaps uses.


🟡 Suggestion 1 — CONVERGED can only fire when every chunk's last dry round shares a parity

converged requires every retired chunk to be not due, i.e. (round - lastDry) odd for all of them (retirement.ts:225-236). Two chunks whose last dry rounds differ in parity can therefore never both be skipped in the same round:

chunk A (dry 1,2 → lastDry=2) chunk B (yielded r1, dry 2,3 → lastDry=3)
round 4 cold check (due) skipped
round 5 skipped cold check (due)

So on any diff where one chunk yields in round 1 or 2 — the common case on a large PR, and the exact case the PR's own yield grid shows — the loop never takes the clean-convergence exit and always runs to the 5-round cap. Combined with the SKILL edit that re-scopes the two-dry-rounds rule to 3A only ("the 3A criterion — one auditor, so round-dry and territory-dry are the same thing"), the 3B path is left with no early exit at all except exit 4/the cap, and reports "hard cap" rather than "converged" on a run that had in fact converged.

The rounds are cheaper, so this is not a perf regression — but it does mean the advertised exit-5 path will rarely fire in practice. Anchoring the parity on a single per-round basis (e.g. round % 2 against a fixed epoch, or "due if it was skipped last round") would let staggered chunks re-align.

🟡 Suggestion 2 — pipelining lets a rejected finding suppress one round of rediscovery

The cumulative list now carries unverified entries, and the auditor brief tells each agent not to re-report what is on it. If round k files a false positive at x.ts:20, round k+1's auditor is told that spot is covered; the verifier then rejects it and it leaves the list at the next merge — but round k+1 is already gone. Under the old ordering a rejected entry never entered the list at all.

The window is one round in one location and the cap still bounds the loop, so I don't think this blocks the change — but "with detection semantics intact" in the PR body overstates it, and the SKILL bullet would be more honest if it named the trade (an entry a verifier later rejects will have suppressed one round of rediscovery in its neighbourhood).

🟡 Suggestion 3 — the budget gate also refuses a single-chunk repair rebuild

agent-prompt.ts:1690 gates on role === 'reverse-audit' without distinguishing "admit a new round" from "rebuild one chunk of a round already admitted". So a --chunk <id> --round k repair after a truncated read gets exit 4 and writes a marker reading stopped before round k — even though round k ran. Two effects: the truncated delivery can't be repaired (that chunk's auditor is never launched, and nothing writes an unreviewedDimensions entry for it), and the disclosure is factually wrong about which round stopped. Retirement already exempts the --chunk path as "a repair is not scheduling" (nice test, by the way) — the same reasoning applies to the budget gate.

Also: for a rebuild of round k, expectedRoundSeconds deliberately reaches past round k's own stamp to round k-1's, so the "estimate" includes all of round k's elapsed time — systematically inflated exactly on the path most likely to be refused.

🟡 Suggestion 4 — the header's truncation self-check no longer describes the output

agent-prompt.ts:1526 still tells the reader "the output ends with an end-of-round line — if either is missing, the output was truncated in transit", but with a retirement the retirement: note is now appended after it. The literal test still works ("if either is missing"), but the sentence is the thing that has to survive a compression, and it now describes a shape the builder no longer emits. Worth a clause: …ends with an end-of-round line (followed by the retirement note, when there is one).


Smaller notes

  • --all-chunks with no --round: stampRound(planPath, undefined) skips the dedupe (round !== undefined && …) and appends a {round: null} stamp on every invocation, and expectedRoundSeconds(plan, undefined) then reads the most recent one. Harmless as long as the SKILL always passes --round, but it is a fail-closed corner in a module that is otherwise uniformly fail-open.
  • DRY_RECEIPT_RE = /No (new )?(issues|findings|gap)/i won't match a substantive receipt phrased "Nothing further to report — re-walked…". That fails toward auditing, so it's safe; just noting the heuristic is narrower than the brief's contract implies.
  • Workflow: with attempt_timeout as low as 30s (the loop's floor before fail), the 600s reserve floor means the audit loop is skipped outright. The comment says that's intended ("degrades to skipping the audit loop, correctly") — agreed, worth keeping the comment.
  • The 3600DEFAULT_RESERVE_SECONDS "keep the two in sync" pairing is a comment-only invariant across a YAML file and a TS file. Nothing will catch a drift. Low stakes (both are fallbacks), but a # see deadline.ts on the TS side too would at least make it bidirectional.

Test coverage

Strong where it exists — driving agentPromptCommand.handler round by round with harness-shaped transcripts is much better than unit-testing scheduleReverseAuditRound directly, and the negative assertions (no records, no stamp, exit 4 outranks exit 5) are the right ones. Gaps:

  • No test for a schedule with mixed parity across chunks (Suggestion 1) — the scenario the yield grid in the PR description actually shows.
  • No test for a second run against the same plan path (Critical 1). The retirement path is safe there by inheritance from the transcript fence; deadline.ts is not, and nothing covers it.
  • No test for one transcript matching several records (Critical 2).
  • .github/workflows/qwen-code-pr-review.yml's new shell arithmetic (floor/cap, per-attempt recompute) has no coverage; the existing extract-the-run-step harness pattern would cover it cheaply.

Security / performance

No new attack surface: no path comes from the model (both deadline.ts and retirement.ts derive from planPath / the CLI-exported env, consistent with the rest of the module), no new network or shell. readTranscripts is now called once more per --all-chunks round from round 3 — an O(transcripts) parse of a directory that is already read at Step 3D and Step 6, so negligible against a round that costs tens of minutes. The projected saving looks plausible to me on the grid shown; the pipelining half is the more reliable of the two, since it doesn't depend on chunks going cold.

中文说明

总评

方向正确,工程质量高:退休调度由 CLI 强制而非 prose 要求;调度依据是 orchestrator 无法伪造的两份证物(自身的 prompt 记录 × harness transcripts);所有分类路径都朝"多审计"失败;readTranscripts 的 plan-mtime 围栏被正确继承。budget-stop marker 由 compose-review 直接读取、而不依赖 orchestrator 转述,是 verdict cap 的正确形状。9 个调度用例逐轮驱动真实 handler,而非孤立单测 scheduler,这是它们真正有价值的原因。

本地复现:未跑全量 src/commands/review,只跑了本 diff 触及的两个文件 deadline.test.ts(15)+ agent-prompt.test.ts(166),181 passed / 0 failed。两个 Critical 均在干净 worktree 上以探针复现。

🔴 Critical 1:预算状态会带入 CI 同 job 的重试并污染它

budget-rounds.json / budget-stop.json 放在 promptRecordDir(planPath),仅由 plan 路径推导。与 retirement.ts:173 正确使用 plan mtime 围栏的 readTranscripts 不同,这两个文件没有任何围栏,且新一次 capture 不会清理记录目录(promptRecordDir 的三个非测试调用方都不删除)。本该清理的 Step 9 恰恰在 attempt 提前死亡时不会执行,而 workflow 的重试就在同一个 job、同一个 workspace、同一个 plan 路径上。

后果两条,均已复现:

(a) 陈旧 marker 让健康的 attempt 2 被误封顶——compose-review.ts:350 无条件读取,attempt 2 即使完整跑完所有轮次,也会披露 reverse audit — stopped before round 3 by the review time budget 并把 Approve 压到 COMMENT

(b) stampRound 按 round 去重,导致 attempt 2 根本无法打戳,于是每个估算都是从 attempt 1 的墙钟时间量出来的:round-2 估算 2160s(真实约 1500s)→ 在还剩 54 分钟、本轮只要 25 分钟时被拒。

即:大 PR 上一次瞬时 API 错误,可能让重试完全没有反审,还附带一条它从未触发过的时间预算披露——恰好把这道闸的意图反转。本地对一个上次被中断(未走 Step 9)的目标重新 review 同理。

建议:给这两个文件加上 transcripts 已有的同一道围栏(把 planMtimeMs 写进去、不匹配即丢弃,readRoundStamps / readBudgetStop 各几行),或让 capture 步骤清理 promptRecordDir。前者更省,改动不出 deadline.ts

🔴 Critical 2:一份 transcript 可以让所有 chunk 退休

retirement.ts:194 会把每一条 prompt 出现在该 transcript 里的记录都算上,且 wasDeliveredVerbatim 是"可加不可删"的判定——所以一个把 N 个 block 拼接起来的 launch prompt 同时匹配 N 条记录。verificationGaps 正是防这一手的,注释写得很清楚:"Injective: one transcript may satisfy ONE roster requirement…"

对真实 scheduler 复现:两个 agent(每轮一个,拿到整轮输出)让 6 个 chunk-round 全部退休,round 3 直接 converged: trueexit 5 / CONVERGED,而那段 stderr 明确宣称"这是干净收敛,不欠 unreviewedDimensions"。verificationGaps 的 floor-of-one 也照样通过(那一个 agent 确实读了 brief),下游无人能拦。

这是 orchestrator 被观测到真做过的偷懒(injectivity 规则就是因此存在),不是假想。按本模块自述的威胁模型,退休判定应当采用与 verificationGaps 相同的"一份 transcript 只能满足一条记录"的贪心分配。

🟡 建议 1:CONVERGED 只在所有 chunk 的末次干净轮同奇偶时才可能触发

converged 要求所有退休 chunk 本轮都不到期,即所有 chunk 的 (round - lastDry) 同为奇数。两个 lastDry 奇偶不同的 chunk 因此永远无法在同一轮同时被跳过(A: dry 1,2;B: r1 出货、dry 2,3 → 第 4 轮 A 冷查 B 跳过,第 5 轮 A 跳过 B 冷查)。于是只要有一个 chunk 在第 1、2 轮出货(大 PR 的常态,也正是 PR 描述里那张网格的形状),循环就永远走不到干净收敛出口,只能撞 5 轮上限并报告"硬上限"而非"已收敛"。

轮次本身变小了,所以不是性能回退;但配合 SKILL 把两干净轮规则改写为仅限 3A,3B 路径实际上除 exit 4 与硬上限外再无提前出口。把奇偶锚定改成全局(如 round % 2 配固定纪元,或"上一轮被跳过则本轮到期")可让错位的 chunk 重新对齐。

🟡 建议 2:流水线化会让被否决的发现压制一轮复查

累计清单现在带未验证条目,而 auditor brief 要求不重复报告清单内容。若第 k 轮报了一条 x.ts:20 的误报,第 k+1 轮的 auditor 被告知该处已覆盖;verifier 随后否决、下次合并时移出——但第 k+1 轮已经过去了。旧顺序下被否决条目根本不会进入清单。

窗口只有一轮一处,上限仍然兜底,我不认为这该挡住改动;但 PR 描述里"检测语义不变"说过头了,SKILL 那条 bullet 若能点名这个代价会更诚实。

🟡 建议 3:预算闸同样会拒绝单 chunk 的修复重建

agent-prompt.ts:1690 只按 role === 'reverse-audit' 判断,不区分"准入新一轮"与"重建已准入轮次的某个 chunk"。于是截断后的 --chunk <id> --round k 修复会得到 exit 4,并写下一条 stopped before round k 的 marker——而第 k 轮其实跑过了。两个后果:截断的投递无法修复(该 chunk 的 auditor 永不发射,也没有任何 unreviewedDimensions 条目),且披露文本关于"哪一轮停止"是错的。退休逻辑已经把 --chunk 路径豁免为"修复不是调度"(那个用例写得很好),同样的理由适用于预算闸。

另外:重建第 k 轮时 expectedRoundSeconds 会刻意越过第 k 轮自己的戳去读第 k-1 轮的,于是"估算"包含了第 k 轮已耗时间——恰好在最可能被拒的路径上系统性偏高。

🟡 建议 4:表头的截断自检已经不描述实际输出

agent-prompt.ts:1526 仍写着"输出 end-of-round 行结尾",但有退休时 retirement: 注记被追加在其后。字面判据("若缺失")仍成立,但这句话是要挺过压缩的那句,现在描述的形状 builder 已不再产出。建议补一个从句。

其他小点

  • --all-chunks 不带 --round 时,stampRound(planPath, undefined) 跳过去重、每次调用追加一个 {round: null} 戳,expectedRoundSeconds(plan, undefined) 随后读到最近那个。只要 SKILL 始终传 --round 就无害,但这是一个整体 fail-open 的模块里唯一 fail-closed 的角落。
  • DRY_RECEIPT_RE 匹配不到"Nothing further to report — re-walked…"这类实质回执。朝多审计失败,安全;只是比 brief 契约更窄。
  • workflow:attempt_timeout 低至 30s 时,600s 保留下限会直接跳过整个反审循环——注释说这是预期行为,同意,值得保留这段注释。
  • 3600DEFAULT_RESERVE_SECONDS 的"保持同步"是一条跨 YAML/TS 的纯注释不变量,无人能捕获漂移。风险低(两者都是兜底),但 TS 侧也加一句反向指引会更好。

测试覆盖

已有部分很扎实——用 harness 形状的 transcript 逐轮驱动真实 handler,远好于直接单测 scheduleReverseAuditRound;负向断言(无记录、无戳、exit 4 优先于 exit 5)选得对。缺口:

  • 无 chunk 间奇偶错位的调度用例(建议 1)——正是 PR 描述那张网格的形状。
  • 同一 plan 路径第二次运行的用例(Critical 1)。退休路径靠继承 transcript 围栏是安全的,deadline.ts 不是,且无人覆盖。
  • 一份 transcript 匹配多条记录的用例(Critical 2)。
  • workflow 新增的 shell 算术(下限/上限、按 attempt 重算)无覆盖;现有的"抽出 run 步骤跑 fixture"手法可以低成本补上。

安全 / 性能

无新攻击面:没有任何路径来自模型(deadline.tsretirement.ts 都从 planPath / CLI 导出的环境变量推导,与模块其余部分一致),无新增网络或 shell。第 3 轮起每个 --all-chunks 轮多一次 readTranscripts——对一个已在 Step 3D 与 Step 6 读过的目录做 O(transcripts) 解析,相对于数十分钟的一轮可忽略。按所示网格折算的收益看起来可信;流水线那一半更可靠,因为它不依赖 chunk 变冷。

@wenshao

wenshao commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /takeover

@github-actions

github-actions Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Summary

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

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

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

中文说明

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

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

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

Copy link
Copy Markdown
Collaborator

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

中文说明

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

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

Address-review summary — PR #8498 (round after @wenshao's review)

All feedback points from the review are addressed below. Both Criticals are
fixed with reproductions pinned as tests; all four Suggestions are implemented;
of the smaller notes, two are fixed, one is declined with evidence, and one
needed no change. One test-coverage gap is deferred with reason.

Critical 1 — budget state survives into the CI in-job retry (FIXED)

Both on-disk budget states — budget-rounds.json (admission stamps) and
budget-stop.json (the refusal marker) — are now fenced by the plan's mtime,
the same fence readTranscripts already applies to the harness's transcripts.
Every stamp and the marker carry the planMtimeMs they were written under;
readRoundStamps and readBudgetStop discard anything written under another
mtime. A fresh capture (fetch-pr / plan-diff / capture-local) rewrites
the plan at the same path and therefore moves the fence, so:

  • (a) a stale marker from a dead attempt 1 can no longer cap a healthy attempt
    2's verdict with a false stopped before round k by the review time budget
    disclosure — compose-review reads it as absent;
  • (b) attempt 2's stamps are no longer deduped away by attempt 1's, so every
    attempt-2 estimate measures from attempt-2 admissions again.

The fence was chosen over clearing promptRecordDir on capture (the
reviewer's cheaper option): it stays local to deadline.ts, needs no new
caller wiring, and degrades like everything else in the module — an unreadable
plan fails open to the constant estimate, and a missing marker fails open to
no cap, while stale state always reads as empty.

Tests: deadline.test.ts — a new the plan-mtime fence suite covers a second
run against the same plan path for both files (stamps discarded, marker
discarded, retry estimates measure from its own stamps), deterministic under
any clock granularity via a backdated plan.

Critical 2 — one transcript can retire every chunk (FIXED)

scheduleReverseAuditRound now credits transcripts injectively: one
transcript certifies at most ONE record — the unique record it matches — and
an ambiguous match certifies none. wasDeliveredVerbatim allows additions, so
a launch that concatenates several blocks matches every one of them; crediting
each match let one dry receipt retire every chunk (exit 5 / CONVERGED on
evidence the roster check refuses by name). The new rule mirrors
verificationGaps' injectivity for the roster; ambiguous evidence fails
toward auditing, consistent with the module's stated threat model.
Legitimate relaunches are untouched — the round number and each chunk's
territory are baked into the prompt, so an honest launch matches exactly one
record, its own (a same-round rebuild with identical material overwrites the
same key, so it never produces a second matching record either).

Test: agent-prompt.test.tsa shortcut launch matching every record retires nothing: rounds 1-2 built with no transcripts, then two transcripts
launched with all six records concatenated; round 3 must fan out to all three
chunks with no retirement note and no exit 5.

Suggestion 1 — staggered parities make CONVERGED unreachable (FIXED)

Cold checks now land on ONE global parity — the even rounds — instead of each
chunk's own certificate parity. Per-chunk anchors never re-align (a chunk dry
in 2,3 beside one dry in 1,2 cold-checks on opposite rounds forever), so the
all-retired exit 5 could never fire on the staggered large-PR shape and the
loop always reported "hard cap" on a run that had converged in fact. A
certificate completing on an odd last-dry round simply takes its first cold
check one round sooner; after that every retired chunk skips and cold-checks
together. The nextColdCheck arithmetic is restated in the rule's own parity
so the certificate cannot drift from the schedule. The reviewer's mixed-parity
test gap is covered: staggered certificates re-align — mixed parities still converge drives chunks with even and odd certificate parities through the
real handler and asserts the round-4 re-alignment (all cold checks together)
and the round-5 CONVERGED/exit 5.

Suggestion 2 — pipelining suppresses one round of rediscovery for a later-rejected entry (ADDRESSED)

The SKILL's merge bullet now names the trade explicitly: "an entry a verifier
later rejects will have suppressed one round of rediscovery in its
neighbourhood — the window is one round in one location, and the 5-round cap
still bounds the loop." The PR body's "with detection semantics intact"
phrasing is not a file this round can edit; the SKILL text (the part the next
run actually reads) is corrected.

Suggestion 3 — the budget gate refuses single-chunk repair rebuilds (FIXED)

agent-prompt's budget gate now exempts --chunk calls: a repair rebuilds
one auditor of a round ALREADY admitted, whose cost was counted at admission.
Refusing it left the truncation unrepairable — the auditor never launched,
nothing writing the unreviewedDimensions entry for it — under a disclosure
naming the wrong round. This is the same reasoning retirement's existing
--chunk exemption uses ("a repair is not scheduling"). A repair also stamps
nothing, so a rebuild's clock can never measure as the round's cost — this
also dissolves the second half of the finding (the expectedRoundSeconds
inflation on the repair path), since the estimate is simply never computed
there. Test added in the budget-gate suite: an exhausted deadline refuses a
new round (exit 4, unchanged) but builds a --chunk repair with no stamp.

Suggestion 4 — header truncation self-check no longer describes the output (FIXED)

The --all-chunks header now reads: the output ends with an end-of-round line
— followed by the retirement note, when there is one — and names the two
anchors explicitly ("if either the numbering or the end-of-round line is
missing, the output was truncated in transit").

Smaller notes

  • --all-chunks with no --round (fixed): stampRound now dedupes
    unlabeled builds exactly like labelled ones — one round-less stamp, so a
    rebuild cannot refresh the clock the next estimate reads (the fail-closed
    corner the reviewer named). Test added.
  • DRY_RECEIPT_RE narrower than the brief's contract (declined): the
    reviewer's own analysis concludes it "fails toward auditing, so it's safe".
    Widening it would credit more returns as dry — the one direction this module
    treats as dangerous — while the current narrowness only costs an extra
    audit of a territory whose receipt did not match the phrase. No change.
  • Workflow reserve-floor comment (no change): reviewer agrees the
    behaviour is intended and the comment should stay; it stays.
  • 3600DEFAULT_RESERVE_SECONDS sync invariant (fixed): the TS side
    now carries the reverse pointer ("The review workflow caps its scaled
    reserve at this same number … keep the two in sync"), making the invariant
    bidirectional.

Deferred

  • Workflow shell-arithmetic coverage (extract-the-run-step harness): the
    reviewer noted the new floor/cap/per-attempt arithmetic has no coverage and
    the existing harness pattern could cover it cheaply. Building that fixture
    means stubbing the entire ~250-line review step (gh, timeout, date,
    the stream-json log handling) — a larger test-infrastructure addition than
    this round's scope beside two Critical fixes. The arithmetic itself is six
    lines of POSIX shell that every CI review run exercises live. Deferred to a
    follow-up rather than silently dropped.

Failed checks note

All checks listed as failed for this PR are CANCELLED (no failure logs —
cancelled runs, consistent with being superseded). There is nothing to
diagnose in code this round; the next push re-runs them.

Verification

  • npx vitest run src/commands/review/lib/deadline.test.ts (packages/cli) — 18 passed
  • npx vitest run src/commands/review/agent-prompt.test.ts (packages/cli) — 169 passed
  • npx vitest run src/commands/review/compose-review.test.ts src/commands/review/check-coverage.test.ts src/commands/review/lib/prompt-record.test.ts src/commands/review/lib/transcripts.test.ts (packages/cli) — 239 passed
  • npx vitest run src/commands/review (packages/cli, full review suite) — 1713 passed, 4 skipped, 0 failed
  • npm run typecheck — passed
  • npm run lint — passed
  • npm run build — passed (compiled output verified to contain the fence, the injective credit, and the gate exemption)
  • Prettier applied to all changed files
中文说明

处理审查意见总结 — PR #8498@wenshao 评审后的一轮)

评审中的每一条意见都在下面逐条处理。两个 Critical 均已修复,并以可复现的测试钉死;四条 Suggestion 全部实现;其他小点中两条已修、一条带证据拒绝、一条无需改动。一项测试覆盖缺口带理由推迟。

Critical 1 — 预算状态带入 CI 同 job 重试(已修复)

两份磁盘预算状态 —— budget-rounds.json(准入戳)与 budget-stop.json(拒绝 marker)—— 现在都以 plan 的 mtime 为围栏,与 readTranscripts 已经给 harness transcripts 加的围栏完全一致。每个戳与 marker 都带上写入时的 planMtimeMsreadRoundStampsreadBudgetStop 丢弃任何写在其它 mtime 下的状态。新一次 capture(fetch-pr / plan-diff / capture-local)会在同一路径重写 plan,从而移动围栏,于是:

  • (a) 死掉的 attempt 1 留下的陈旧 marker 不再能用一条虚假的 stopped before round k by the review time budget 披露给健康的 attempt 2 封顶 —— compose-review 读到的是"不存在";
  • (b) attempt 2 的戳不再被 attempt 1 的戳去重掉,每个 attempt 2 的估算重新从 attempt 2 自己的准入时间量出。

选择围栏而非在 capture 时清空 promptRecordDir(评审者给出的更省的选项):改动不出 deadline.ts,不需要新的调用方接线,且降级行为与模块其余部分一致 —— plan 不可读时估算 fail-open 回退到常数,marker 缺失时 fail-open 不封顶,而陈旧状态永远读作空。

测试:deadline.test.ts 新增 the plan-mtime fence 套件,覆盖同一 plan 路径的第二次运行(戳被丢弃、marker 被丢弃、重试的估算从自己的戳量出);通过回写 plan 的日期保证在任何时钟粒度下都确定性地移动 mtime。

Critical 2 — 一份 transcript 可以让所有 chunk 退休(已修复)

scheduleReverseAuditRound 现在以单射方式记账 transcript:一份 transcript 至多认证一条记录 —— 它唯一匹配的那条 —— 歧义匹配一律不认证。wasDeliveredVerbatim 允许"只加不删",所以把多个 block 拼接起来的 launch 会匹配其中每一条;逐条记账会让一份干回执退休掉整轮的所有 chunk(以 roster 检查点名的那种证据拿到 exit 5 / CONVERGED)。新规则与 verificationGaps 对 roster 的单射性一致;歧义证据朝"多审计"失败,与本模块自述的威胁模型一致。合法的重新启动不受影响 —— 轮次号与每个 chunk 的领地都焊在 prompt 里,诚实的 launch 恰好匹配一条记录(同轮同料的重建覆盖同一个 key,也不会产生第二条可匹配记录)。

测试:agent-prompt.test.tsa shortcut launch matching every record retires nothing:第 1、2 轮只写记录、无 transcript,随后写入两份以全部六条记录拼接启动的 transcript;第 3 轮必须对全部三个 chunk 完整扇出,无 retirement 注记、无 exit 5。

建议 1 — 奇偶错位让 CONVERGED 永远不可达(已修复)

冷查现在落在同一个全局奇偶上 —— 偶数轮 —— 而不再是每个 chunk 自己证书的奇偶。各自的锚永远无法重新对齐(一个 dry 于 2、3 轮的 chunk 与一个 dry 于 1、2 轮的 chunk 会在相反的轮次永远轮流冷查),于是在错位的大 PR 形状上 all-retired 的 exit 5 永远无法触发,循环只会撞上限、对一次事实上已收敛的运行报告"硬上限"。证书在奇数 last-dry 轮完成的 chunk 只是第一次冷查提前一轮到来;此后每个退休 chunk 一起跳过、一起冷查。nextColdCheck 的算术改用规则自身的奇偶表述,证书无法与调度漂移。评审者指出的奇偶错位测试缺口已补:staggered certificates re-align — mixed parities still converge 用真实 handler 驱动偶/奇证书奇偶并存的 chunk,断言第 4 轮重新对齐(全部一起冷查)与第 5 轮 CONVERGED / exit 5。

建议 2 — 流水线化会让被否决条目压制一轮复查(已处理)

SKILL 的合并 bullet 现在点名这个代价:"an entry a verifier later rejects will have suppressed one round of rediscovery in its neighbourhood — the window is one round in one location, and the 5-round cap still bounds the loop。"PR 描述里"检测语义不变"的措辞不是本轮可编辑的文件;SKILL 文本(下一次运行真正会读的部分)已更正。

建议 3 — 预算闸拒绝单 chunk 的修复重建(已修复)

agent-prompt 的预算闸现在豁免 --chunk 调用:修复重建的是已准入轮次里的一个 auditor,该轮的成本在准入时已计入。拒绝修复会让截断无法修复 —— auditor 永不发射、也没有任何东西为它写 unreviewedDimensions 条目 —— 且披露文本点错轮次。这与 retirement 已有的 --chunk 豁免同理("修复不是调度")。修复也不打戳,重建的时钟永远不会被量作该轮成本 —— 这同时消解了该意见的后半(修复路径上 expectedRoundSeconds 的系统性偏高),因为该路径根本不再计算估算。预算闸套件新增测试:耗尽的 deadline 仍拒绝新轮(exit 4,不变),但会构建 --chunk 修复且不打戳。

建议 4 — 表头截断自检已不描述实际输出(已修复)

--all-chunks 表头现在写作:输出以 end-of-round 行结尾 —— 有退休时其后跟 retirement 注记 —— 并显式点名两个锚点("if either the numbering or the end-of-round line is missing, the output was truncated in transit")。

其他小点

  • --all-chunks 不带 --round(已修): stampRound 现在对无轮次构建做与有轮次相同的去重 —— 只打一个无轮次戳,重建无法刷新下次估算读取的时钟(即评审者点名的那个 fail-closed 角落)。测试已补。
  • DRY_RECEIPT_RE 比 brief 契约更窄(拒绝): 评审者自己的分析即结论:"朝多审计失败,安全"。放宽它等于把更多回执记为 dry —— 恰是本模块视为危险的方向 —— 而当前的窄只会让一个措辞不合的领地多被审计一次。不改。
  • workflow 保留下限注释(无需改动): 评审者认同该行为是预期的、注释应保留;注释保留。
  • 3600DEFAULT_RESERVE_SECONDS 同步不变量(已修): TS 一侧补上反向指引("The review workflow caps its scaled reserve at this same number … keep the two in sync"),让这条不变量双向可见。

推迟项

  • workflow shell 算术的覆盖(extract-the-run-step 手法): 评审者指出新增的下限/上限/按 attempt 重算没有覆盖,现有 harness 模式可以低成本补上。但该 fixture 需要 stub 整个约 250 行的 review 步骤(ghtimeoutdate、stream-json 日志处理)—— 在与两个 Critical 修复同一轮里,这是一个超范围的测试基建添加。该算术本身是六行 POSIX shell,每次 CI review 运行都会真实跑到。推迟到后续单独处理,不做静默丢弃。

关于失败检查

本 PR 列出的失败检查全部是 CANCELLED(没有失败日志 —— 是被取消的运行,与被更新的运行取代的情形一致)。本轮代码层面无可诊断项;下一次推送会重跑它们。

验证

  • npx vitest run src/commands/review/lib/deadline.test.ts(packages/cli)— 18 通过
  • npx vitest run src/commands/review/agent-prompt.test.ts(packages/cli)— 169 通过
  • npx vitest run src/commands/review/compose-review.test.ts src/commands/review/check-coverage.test.ts src/commands/review/lib/prompt-record.test.ts src/commands/review/lib/transcripts.test.ts(packages/cli)— 239 通过
  • npx vitest run src/commands/review(packages/cli,review 全套件)— 1713 通过、4 跳过、0 失败
  • npm run typecheck — 通过
  • npm run lint — 通过
  • npm run build — 通过(并已核对编译产物包含围栏、单射记账与闸门豁免)
  • 所有改动文件已跑 Prettier

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 4, 2026

Copy link
Copy Markdown
Collaborator Author

Review — perf(review): retire dry chunks and pipeline verification in the reverse audit

Scope reviewed: the full PR diff (10 files, +1706/−19), i.e. both #8468's budget gate and this PR's own two commits, since they ship stacked.

Overview

Three mechanisms, all aimed at the reverse-audit loop's wall clock:

  1. Budget gate (lib/deadline.ts, workflow, from fix(review): stop the reverse-audit loop while there is still time to report #8468) — a soft deadline exported by CI; the round builder refuses a round that no longer fits round + tail, exits 4, and writes a budget-stop.json marker that compose-review reads directly so the verdict cap does not depend on the orchestrator relaying a sentence.
  2. Per-chunk retirement (lib/retirement.ts) — from round 3, a chunk whose last two audits were substantive dry receipts is cold-checked on alternating rounds; all-retired-and-none-due exits 5 (CONVERGED).
  3. Pipelining (SKILL.md) — round k's verifiers launch alongside round k+1's auditors; the cumulative list now carries reported-but-unverified findings.

The design discipline is the strongest thing here: every path in retirement.ts fails toward auditing, the evidence is the CLI's own records × the harness's transcripts (never anything the orchestrator wrote), both budget files are fenced by the plan mtime so a CI retry is not capped by the dead attempt's state, and the disclosure is synthesized deterministically rather than relayed. The tests drive the real handler and write harness-shaped JSONL rather than mocking the readers. That's the right bar for this subsystem.

One correctness problem, and it lands on the invariant the module exists to protect.


🔴 Critical — the anti-shortcut guard is inverted; one concatenated launch retires every chunk

packages/cli/src/commands/review/lib/retirement.ts (the outcomesByRecord map):

const outcomesByRecord = records.map((rec) => {
  const matches = transcripts.filter((t) =>
    wasDeliveredVerbatim(t.launchPrompt, rec.prompt),
  );
  return matches.length === 1 ? matches.map(classifyReturn) : [];
});

The comment above it states the intended rule exactly right:

So one transcript certifies at most ONE record: the unique record it matches.

But the code counts transcripts per record, not records per transcript. It never asks how many records a given transcript matches. The two are not the same guard, and the difference is the whole attack:

  • One agent launched with the round's blocks concatenated (the natural shortcut shape — one launch, one transcript): for each of the N records, matches.length === 1. Every chunk is credited with that single agent's return.
  • Two such transcripts: matches.length === 2 for every record, so nothing is credited.

The test 'a shortcut launch matching every record retires nothing' writes two identical concatenated transcripts, which is why it passes — it is exercising the accidental behaviour, not the documented rule. Verified the multiplicity directly against wasDeliveredVerbatim's real algorithm:

per-record matches with ONE concatenated transcript:  [ 1, 1, 1 ]
per-record matches with TWO concatenated transcripts: [ 2, 2, 2 ]

Failure scenario. Orchestrator hands the whole --all-chunks output of round 1 to a single agent (documented as a real, recurring failure mode in this very skill — "a real run that sampled each build with | head -5 … hand-reconstructed all ten launches"), that agent reads the diff and returns a substantive No issues found — … receipt over the substance floor. Same for round 2. At round 3 every chunk holds two "dry" certificates, converged is true, the builder exits 5 with CONVERGED — a clean convergence, explicitly documented as owing no unreviewedDimensions entry. The loop ends after two rounds on the evidence of two agents, and nothing downstream can see it: verificationGaps' reverse-audit floor is "at least one auditor", which those rounds satisfy.

That is precisely the invariant SKILL.md cites PR #6457 for — "a single lazy agent must not be able to end the loop" — and the premise this module opens with: "a schedule the subject of the checks could edit is a schedule that retires whatever chunk is inconvenient to audit."

Fix — build the reverse index and drop transcripts that certify more than one record. This also repairs the honest-relaunch case (see below):

const matchesByRecord = records.map((rec) =>
  transcripts.filter((t) => wasDeliveredVerbatim(t.launchPrompt, rec.prompt)),
);
// How many records each transcript matches. A launch that verbatim-contains
// several built prompts names no territory specifically — it certifies none.
const recordsPer = new Map<AgentRecord, number>();
for (const ms of matchesByRecord) {
  for (const t of ms) recordsPer.set(t, (recordsPer.get(t) ?? 0) + 1);
}
const outcomesByRecord = matchesByRecord.map((ms) =>
  ms.filter((t) => recordsPer.get(t) === 1).map(classifyReturn),
);

And change the test to write one concatenated transcript (keep the two-transcript case as a separate assertion — it should also retire nothing, for a different reason).

🟡 Suggestion — the guard as written also discards legitimate relaunches, contradicting mergeOutcomes

mergeOutcomes' docstring promises the multi-transcript case is handled: "A round can legitimately have several of both — a same-round rebuild with corrected rules is a second record; a relaunch is a second transcript — and the merge fails toward auditing." But SKILL.md mandates relaunching a whiffing auditor once within the round, with the same block verbatim → two transcripts for one record → matches.length === 2[] → that (chunk, round) classifies unknown → the chunk can never retire off a round it whiffed-then-recovered in. Conservative, so not a correctness bug, but it means mergeOutcomes is dead code for its stated purpose. The reverse-index fix above resolves both at once.

🟡 Suggestion — the round-1 estimate is a flat 1800s, so short budgets skip Step 5 entirely

DEFAULT_ROUND_SECONDS = 1800 is applied regardless of 3A/3B, chunk count or diff size, and the required headroom is reserve + round. With the workflow's floor of reserve = 600:

  • /review --timeout=30attempt_timeout = 1800, required = 600 + 1800 = 2400 > 1800round 1 is refused on every review, on a 40-line PR as readily as a 4000-line one. The whole reverse audit is skipped, a stopped before round 1 by the review time budget disclosure is written, and an otherwise-Approve verdict is permanently capped at Comment.
  • The same applies to attempt 2 of a retry, which inherits only the remaining budget (RETRY_MIN_SECONDS = 600 allows a retry with ~11 minutes left).

The comment calls this "a tiny explicit budget degrades to skipping the audit loop, correctly" — that's defensible for a genuinely tiny budget, but 30 minutes is not tiny for a small PR, and the gate has no way to know which it is. Consider scaling the round-1 fallback: 3A (single auditor) vs 3B, or by chunk count, or expressing it as a fraction of the budget rather than an absolute. A cheap version: min(DEFAULT_ROUND_SECONDS, remaining / 3) for round 1 only.

🟡 Suggestion — budget-first ordering turns a clean convergence into a false truncation disclosure

The gate runs in runAgentPrompt before runAllChunks computes the schedule, pinned by 'the budget gate outranks retirement: a refused round is exit 4, not 5'. When both would fire, the run reports "stopped before round k by the review time budget", writes the marker, and caps an otherwise-Approve at Comment — even though retirement would have said CONVERGED, which owes no disclosure and no cap. Round 3+ under a tight budget on a converged diff is not an exotic combination.

Evaluating the schedule first for the --all-chunks round-3+ path costs one transcript directory scan (already fail-open) and would let a genuinely-converged run report the truth. If the ordering is kept deliberately, it'd be worth saying why in the comment — the current comment justifies "budget first" only as "a refused round is refused regardless of what retirement would have scheduled", which is true but doesn't address the disclosure being wrong.

🟡 Suggestion — pipelining widens an unchecked hole

The "last round's verification must complete before Step 6" ordering is now the only thing keeping unverified findings out of the posted body, and it is prose-only. verificationGaps' verify floor is "at least one verify agent ran" — earlier rounds' verifiers satisfy it, so an orchestrator that pipelines and then skips the last round's verification passes every deterministic check. The serial shape made that mistake structurally awkward; the pipelined one makes it a plausible slip. Worth considering whether the round number can be keyed into the verify record so the floor can require a verify record at round == max(reverse-audit round).

🔵 Minor

  • agent-prompt.ts: if (!args.allChunks && !hasChunk) stampRound(...)!hasChunk is already guaranteed by the enclosing if (role === 'reverse-audit' && !hasChunk).
  • compose-review.ts: the dedupe key is u.includes('review time budget') — a loose substring on a generic phrase. u.includes(stop.entry) or a stable marker token would be tighter and would not swallow an unrelated caller entry that happens to contain those three words.
  • retirement.ts: nextColdCheck: round + (round % 2) only ever executes on the odd branch, so it is always round + 1. The parity-flavoured spelling reads as if it generalizes; a plain round + 1 with the existing comment is clearer.
  • retirement.ts has no unit test file — every assertion goes through agent-prompt.test.ts. classifyReturn's thresholds (DRY_MIN_CHARS = 120, DRY_RECEIPT_RE), mergeOutcomes and the parity/stagger rules have no direct tests. A lib/retirement.test.ts driving scheduleReverseAuditRound over synthetic histories would be cheaper than the transcript-writing harness and is the kind of test that would have caught the guard direction above.
  • Perf: scheduleReverseAuditRound calls readTranscripts on every round-3+ --all-chunks build, which parses every subagent JSONL in the session. On a large review that is tens of MB re-parsed per round. Almost certainly noise next to a round, but it is a new per-round cost in a PR about per-round cost.
  • Sync risk: the 3600 cap lives in both deadline.ts and the workflow YAML, kept in sync by a comment in each. A gating script or a test asserting the YAML literal would make the drift visible.
  • Savings shape: retirement only skips on odd rounds (3 and 5 under the 5-round cap); even rounds always cold-check every retired chunk, so the fan-out is unchanged there. Consistent with the −20% claim, but worth one sentence in SKILL.md so a reader doesn't expect a shrunken round 4.
  • docs/users/features/code-review.md documents the soft deadline but not the CONVERGED / exit-5 contract. Internal to agent-prompt, so arguably out of scope for user docs, but the added paragraph already discusses builder behaviour.

What's good

  • Fail-open is applied uniformly and tested on each path: malformed deadline, malformed reserve, past deadline, missing transcripts, whiffed receipt, missing receipt, unreadable plan.
  • The plan-mtime fence on both budget-rounds.json and budget-stop.json is the right mechanism and the reasoning ("nothing clears the record dir; the retry runs at the same path") is spelled out and tested in both directions.
  • Deterministic disclosure via the marker instead of trusting the orchestrator to carry a sentence is exactly consistent with this subsystem's "evidence authored by the subject is not evidence" principle.
  • expectedRoundSeconds reaching past a same-round stamp so a rebuild can't report a round as cheap, and stampRound's dedupe including the unlabeled case, are both subtle and both tested.
  • The --chunk exemption is coherent across the gate and retirement, with the same justification in both places.

Verdict

The budget gate and the deadline module look ready. Retirement should not merge until the injectivity guard is fixed — as written, the mechanism it advertises as its defence against the loop-ending shortcut does not implement that defence for the single-transcript case, which is the shape the shortcut actually takes. The fix is small and the existing test just needs its transcript count changed from two to one to become a real regression test.

中文摘要

结论:预算闸(#8468 部分)可以走;退休机制建议先修一个真实绕过再合。

  • 🔴 retirement.ts 的注入性守卫方向反了。 注释写的是"一条 transcript 至多认证一条 record",代码算的却是"一条 record 被几条 transcript 匹配"。结果:一个 agent 拿整轮拼接的 blocks 启动(正是这个 skill 反复记录过的真实偷懒形态),每条 record 恰好匹配到 1 条 transcript,全部 chunk 被认证为 dry;第 3 轮直接 CONVERGED 退出 5——按设计这是"干净收敛,不欠 disclosure"。两轮、两个 agent 就把循环结束了,正是 SKILL 引 feat(qqbot): group message handling and cron-msg-experimental #6457 立的"单个偷懒 agent 不得终止循环"这条不变量。测试之所以通过,是因为它写了两条相同的拼接 transcript(匹配数=2 才被丢弃)。已用真实 wasDeliveredVerbatim 算法实测确认:1 条 → [1,1,1],2 条 → [2,2,2]。修法见正文的反向索引写法;测试把 transcript 数从 2 改成 1 即成为真回归用例。
  • 🟡 同一个守卫也会误杀 SKILL 强制要求的"whiff 后同轮重启"(一条 record 两条 transcript → 丢弃),这让 mergeOutcomes 的文档承诺变成死代码。上面的修法一并解决。
  • 🟡 round 1 的估算是固定 1800s,不随 3A/3B 或 chunk 数缩放:/review --timeout=30 会让任何 PR(包括 40 行的)在第 1 轮就被拒,整个反审跳过、verdict 永久封顶 Comment。建议按路径/chunk 数或剩余预算比例缩放。
  • 🟡 预算闸排在退休之前:当本该 CONVERGED(干净、不欠条目)时,却写出"被时间预算截断"的 disclosure 并封顶 verdict。建议 round≥3 的 --all-chunks 先算 schedule。
  • 🟡 流水线化后,"末轮验证必须先于 Step 6"只剩散文约束——verificationGaps 的 verify 下限是"至少跑过一个",前几轮就能满足,跳过末轮验证过不了任何确定性检查。
  • 🔵 其余:!hasChunk 冗余判断、compose-review 用宽松子串去重、nextColdCheck 的奇偶写法恒等于 round+1retirement.ts 无独立单测、每轮重解析全部 transcripts 的开销、3600 常量两处手工同步、退休只在奇数轮省 auditor(偶数轮照旧全量)建议在 SKILL 里点明。

做得好的地方:所有路径一致地"失败朝向多审计"且逐条有测试;两个预算文件用 plan mtime 围栏隔离重试;disclosure 由 marker 确定性合成而非依赖 orchestrator 转述;expectedRoundSeconds 跳过同轮 stamp 的处理很细致。

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

Review feedback addressed — PR #8498

Feedback source: @wenshao's issue-level review comment (2026-08-04). No inline
comments this round; all dispositions are recorded here. No base-conflict
resolution was requested (--conflict false); origin/main was already
merged into the branch.

🔴 Critical — the anti-shortcut guard was inverted (retirement.ts)

Fixed. The guard counted transcripts per record (matches.length === 1),
while the invariant it exists to protect is records per transcript. Reproduced
before fixing: with ONE concatenated launch per round (the shortcut's real
shape — one agent handed the whole round's blocks), every record sees a unique
match, all chunks are credited the same dry receipt, and --all-chunks exits 5
CONVERGED after two rounds on the evidence of two agents. The fix inverts the
relation: a reverse index counts how many records each transcript matches, and
a transcript matching several records certifies none. Honest launches are
unaffected (each matches exactly one record), and the mandated whiff relaunch —
several honest transcripts for one record — now merges through mergeOutcomes
as its docstring always promised. The shortcut test now writes ONE concatenated
transcript (the attack shape); the two-transcript case is kept as a second
assertion. Also added lib/retirement.test.ts, a direct unit suite for the
scheduler (classifier floors, the merge, the guard direction, parity/stagger,
mtime fence) — the level at which a wrongly-wired guard fails loudly.

🟡 Suggestions

  1. The guard also discarded legitimate relaunches — fixed by the same
    inversion: two honest transcripts for one record each certify it, and
    mergeOutcomes is live for its stated purpose again. Covered by the new
    unit suite (whiff-then-relaunch retires; a yield in any matching transcript
    still outranks the merge).
  2. Round-1 estimate is a flat 1800s, so small budgets skip Step 5 entirely
    — fixed with the reviewer's cheap version: round 1's estimate is capped at
    a third of the remaining budget (roundAdmissionEstimate in deadline.ts).
    The gate still demands the reserve on top, so a budget the reserve alone no
    longer fits still refuses, and later rounds stay unscaled (they measure
    their predecessor). /review --timeout=30 now admits round 1 instead of
    skipping the audit loop on every PR.
  3. Budget-first ordering wrote a false truncation disclosure over a clean
    convergence
    — fixed: for --all-chunks rounds the budget gate now runs
    in the round builder, AFTER the convergence check. A converged audit exits
    5 with no marker, no disclosure and no cap; a round that is still due is
    refused exactly as before (exit 4, marker, nothing built or recorded). The
    previously pinned ordering test is replaced by the pair that pins the new
    truth in both directions.
  4. Pipelining widens the unchecked verify gap — DEFERRED to a follow-up.
    Verify record keys already carry --round-<k>, so what is missing is the
    floor's semantics, not the keying: requiring "a verify record at the max
    reverse-audit round" false-positives when the last round is dry (no new
    findings → no verifier is built, and records alone cannot tell a skipped
    verification from a dry round). Choosing that evidence shape is a design
    decision for the coverage machinery, beyond this round's scope; the prose
    ordering ("the last round's verification must complete before Step 6")
    stays the mitigation until then.

🔵 Minor

  1. Redundant !hasChunk — removed by the gate restructuring (the
    single-build gate block is now !hasChunk && !args.allChunks, and the
    stamp inside it is unconditional).
  2. Loose review time budget dedupe substring in compose-review — now
    dedupes against the marker's EXACT entry; a new test pins that an unrelated
    dimension merely mentioning the phrase is kept.
  3. nextColdCheck: round + (round % 2) — now round + 1; the branch only
    runs on odd rounds, and the comment says so.
  4. No unit test file for retirement.ts — added (lib/retirement.test.ts,
    13 tests driving scheduleReverseAuditRound over synthetic histories).
  5. Perf: readTranscripts re-parses every round-3+ build — DECLINED: the
    reviewer's own read is "almost certainly noise next to a round"; caching
    would add invalidation state to a module whose design is "the history IS
    the state". Not worth the diff growth.
  6. The 3600 cap lives in two places — added a deadline.test.ts case that
    reads the review workflow and asserts its reserve cap literal equals
    DEFAULT_RESERVE_SECONDS, so a one-sided change fails loudly.
  7. Savings shape (odd rounds only) — SKILL.md's retirement bullet now says
    the savings land on odd rounds; even rounds cold-check every retired chunk
    together, so round 4's fan-out is unchanged.
  8. code-review.md does not document CONVERGED / exit 5 — DEFERRED: the
    added paragraph documents the soft-deadline env vars, and convergence is
    not deadline behaviour (it fires on ungated local runs too). The exit-code
    contract lives in agent-prompt's own --help (0/4/5) and the loop
    contract in SKILL.md; folding it into the deadline paragraph would widen
    that paragraph's scope.

Failed checks

  • Test (ubuntu-latest, Node 22.x) — no CI logs were reachable from this
    runner (no GitHub credentials), so the exact failing step could not be
    read. Instead the full unit suite (npm run test:ci's component suites)
    was reproduced locally in a CI-equivalent environment (fresh HOME, no
    ambient QWEN_* vars): every workspace is green except five release-
    packaging tests that need the zip binary, which this container does not
    ship and cannot install (no root) — GitHub's ubuntu runners ship it. See
    Verification for the exact residual output. The workflow's own CI re-run
    after this push remains the final gate.
  • review-pr — the automated review job that produced this feedback; it
    re-runs on the new head after this push.

Verification

  • npm run build — passed
  • npm run typecheck — passed
  • npm run lint — passed (0 errors, 0 warnings)
  • npx prettier --check on every changed file — passed
  • Reproduction first: patched the existing shortcut test to ONE concatenated
    transcript on the UNFIXED code — exit 5 CONVERGED confirmed, exactly the
    reported hole; the same test on the fixed code builds all three auditors.
  • npx vitest run src/commands/review/ (packages/cli review suite) —
    53 files, 1732 passed / 4 skipped
  • Full workspace suites, CI-equivalent environment:
    • packages/cli — 749 files, 17158 passed / 25 skipped, 0 failed
    • packages/core — 567 files passed / 1 skipped
    • packages/sdk-typescript — 31 files passed
    • packages/vscode-ide-companion — 51 files passed
    • packages/web-shell — 166 files passed; packages/webui — 32 files passed
    • packages/channels/* (10 packages) — all passed (19/10/3/2/2/7/1/1/5/8 files)
    • integrations/external-context — 8 files, 97 tests passed
    • packages/acp-bridge — 23 files passed; packages/audio-capture — 1 file
      passed; packages/chrome-extension — 7 files passed / 1 skipped
  • Root npm run test:scripts — 44/45 files passed; the one failing file is
    scripts/tests/install-script.test.js, 5 tests, every failure
    Error: spawnSync zip ENOENT (release-packaging tests shelling out to the
    zip binary, absent from this container; unrelated to this PR's changes —
    CI's ubuntu runners ship zip).
  • Settings sources untouched — npm run generate:settings-schema not needed.
  • Integration tests not required: the changed behaviour is exercised directly
    by the unit suites through the real handlers, not only via the bundled CLI.
中文说明

已处理的审查反馈 — PR #8498

反馈来源:@wenshao 的 issue 级审查评论(2026-08-04)。本轮没有行内评论,所有处置记录在此。未要求解决 base 冲突(--conflict false);origin/main 已合并进本分支。

🔴 Critical — 反捷径守卫方向反了(retirement.ts)

已修复。 守卫统计的是每条 record 被几条 transcript 匹配matches.length === 1),而它要保护的不变量是每条 transcript 匹配几条 record。修复前已复现:一条拼接启动(捷径的真实形态——一个 agent 拿到整轮拼接的 blocks)时,每条 record 恰好匹配到唯一一条 transcript,全部 chunk 被记上同一张 dry 收据,两轮之后 --all-chunks 以 5 号退出码 CONVERGED——仅凭两个 agent 的证据。修复把关系反过来:用反向索引统计每条 transcript 匹配的 record 数,匹配多条 record 的 transcript 不认证任何一条。诚实启动不受影响(各自恰好匹配一条 record,即自己的),SKILL 强制的 whiff 重启——同一条 record 的多条诚实 transcript——现在也能按 mergeOutcomes 文档承诺的那样正常合并。捷径测试改为写入一条拼接 transcript(攻击形态);两条 transcript 的情形保留为第二条断言。另新增 lib/retirement.test.ts:调度器的直接单测套件(分类器门槛、合并、守卫方向、奇偶/错峰、mtime 围栏)——守卫方向接反会在这个层级直接失败。

🟡 建议

  1. 守卫同时误杀了合法重启 —— 由同一次反向修复一并解决:同一条 record 的两条诚实 transcript 各自认证该 record,mergeOutcomes 重新按其文档工作。新单测覆盖(whiff 后重启可退休;任一匹配 transcript 中的 yield 仍压过合并)。
  2. round 1 估算固定 1800s,小预算会整个跳过 Step 5 —— 采用评论者的廉价版本修复:round 1 的估算封顶为剩余预算的三分之一(deadline.tsroundAdmissionEstimate)。闸门仍要求其上叠加预留金,因此预留金都放不下的预算仍会拒绝;后续轮次不做缩放(它们以前一轮的实测成本为估算)。/review --timeout=30 现在会放行 round 1,而不是在任何 PR 上都跳过审计循环。
  3. 预算优先的排序会在干净收敛上写出虚假截断披露 —— 已修复:--all-chunks 轮的预算闸门移入 round builder,在收敛检查之后运行。收敛的审计以 5 号退出码结束,不写 marker、不欠披露、不封顶;仍到期的轮次照旧被拒(4 号退出码、marker、不构建不记录)。原先钉死旧排序的测试替换为双向钉住新事实的一对测试。
  4. 流水线化扩大了未验证 findings 的缺口 —— 顺延到后续 PR。verify 的 record key 已带 --round-<k>,缺的不是 keying 而是下限的语义:要求"最大反审轮次处存在 verify record"会在末轮为 dry 时误报(无新发现 → 不会构建 verifier,仅凭 records 无法区分"跳过了验证"与"末轮无发现")。选择该证据形态是覆盖机制的设计决策,超出本轮范围;在此之前以散文约束("末轮验证必须先于 Step 6")作为缓解。

🔵 小项

  1. 冗余的 !hasChunk —— 闸门重构顺带移除(单构建闸门块现为 !hasChunk && !args.allChunks,其内的 stamp 无条件执行)。
  2. compose-review 中宽松子串 review time budget 去重 —— 现按 marker 的精确条目去重;新增测试钉住"仅提到该短语的无关维度条目会被保留"。
  3. nextColdCheck: round + (round % 2) —— 改为 round + 1;该分支只在奇数轮执行,注释已说明。
  4. retirement.ts 没有独立单测文件 —— 已新增(lib/retirement.test.ts,13 个用例,用合成历史驱动 scheduleReverseAuditRound)。
  5. 性能:readTranscripts 每轮 round-3+ 构建都重新解析 —— 不采纳:评论者自己的判断是"相对一轮的开销几乎是噪音";加缓存会给一个"历史即状态"的模块引入失效状态,不值得扩大 diff。
  6. 3600 上限散落两处 —— deadline.test.ts 新增用例:读取 review workflow,断言其预留金上限字面量等于 DEFAULT_RESERVE_SECONDS,单边改动会立刻失败。
  7. 节省形态(仅奇数轮) —— SKILL.md 退休条目现写明:节省落在奇数轮;偶数轮所有退休 chunk 一起做冷检,round 4 的扇出不变。
  8. code-review.md 未记录 CONVERGED / exit 5 —— 顺延:新增段落记录的是软截止环境变量,而收敛不是截止行为(无截止的本地运行同样会触发)。退出码契约在 agent-prompt 自己的 --help(0/4/5)中,循环契约在 SKILL.md 中;把它塞进截止段落会扩大该段范围。

失败检查

  • Test (ubuntu-latest, Node 22.x) —— 本 runner 无法获取 CI 日志(没有 GitHub 凭据),读不到确切的失败步骤。改为在 CI 等效环境(全新 HOME、无环境残留的 QWEN_* 变量)本地复现完整单测套件(npm run test:ci 的各组成套件):除 5 个需要 zip 二进制的发布打包测试外全部绿——本容器没有 zip 也无法安装(非 root),而 GitHub 的 ubuntu runner 自带。确切残留输出见"验证"。本次推送后 workflow 自身的 CI 重跑仍是最终闸门。
  • review-pr —— 即产生本反馈的自动审查任务;本次推送后会在新 head 上重跑。

验证

  • npm run build — 通过
  • npm run typecheck — 通过
  • npm run lint — 通过(0 错误 0 警告)
  • npx prettier --check(所有改动文件)— 通过
  • 先复现:在未修复代码上把捷径测试改为一条拼接 transcript —— 确认 5 号退出码 CONVERGED,与报告的漏洞一致;修复后同一测试构建全部三个 auditor。
  • npx vitest run src/commands/review/(packages/cli review 套件)— 53 个文件,1732 通过 / 4 跳过
  • 各 workspace 完整套件(CI 等效环境):
    • packages/cli — 749 个文件,17158 通过 / 25 跳过,0 失败
    • packages/core — 567 个文件通过 / 1 跳过
    • packages/sdk-typescript — 31 个文件通过
    • packages/vscode-ide-companion — 51 个文件通过
    • packages/web-shell — 166 个文件通过;packages/webui — 32 个文件通过
    • packages/channels/*(10 个包)— 全部通过(19/10/3/2/2/7/1/1/5/8 个文件)
    • integrations/external-context — 8 个文件,97 个测试通过
    • packages/acp-bridge — 23 个文件通过;packages/audio-capture — 1 个文件通过;packages/chrome-extension — 7 个文件通过 / 1 跳过
  • 根目录 npm run test:scripts — 44/45 个文件通过;唯一失败的文件是 scripts/tests/install-script.test.js(5 个用例,全部为 Error: spawnSync zip ENOENT:发布打包测试调用 zip 二进制,本容器缺失;与本 PR 改动无关——CI 的 ubuntu runner 自带 zip)。
  • 未改动 settings 源 —— 无需 npm run generate:settings-schema
  • 无需集成测试:改动的行为由单测套件通过真实 handler 直接覆盖,并非只能经 bundled CLI 触发。

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

⚠️ The branch received new commits while this round ran; they were merged into this push, but this round's verification predates that merge — re-check anything that landed mid-run. · 本轮运行期间分支收到了新的提交;本次推送已将其合并,但本轮验证在合并之前完成——请复查运行期间落地的改动。

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 4, 2026

Copy link
Copy Markdown
Collaborator Author

Review

Reviewed the two commits this PR owns on top of #8468 (7f03044 retirement, fc25e27 pipelining, plus the 51f0baf / d0ef34b follow-ups). Ran the suite and four targeted probes against the PR head in an isolated worktree.

Verified locally

  • packages/cli/src/commands/review54 files, 1741 passed, 0 failed.
  • Coverage interplay holds as claimed: coverage.ts:1249's reverse-audit floor is "at least one reverse-audit* record", satisfied by rounds 1-2; a skipped chunk-round writes no record, so verificationGaps has no agent to expect. Nothing downstream consumes agent-prompt's exit code programmatically (only SKILL.md references the command), so exit 5 is safe to add.

What works well

  • Everything in retirement.ts fails toward auditing, and the tests pin each direction individually (whiff, no-transcript, no diff read, yield-outranks-merge). A bug here degrades to today's behaviour, which is the right failure mode for a scheduler.
  • The injectivity guard being records-per-transcript rather than transcripts-per-record is the correct direction and the comment explains why better than most code does — one agent handed the whole round is the shortcut that would otherwise retire everything.
  • Global even-round parity over per-chunk anchors: without it staggered certificates never re-align and CONVERGED is unreachable. Good catch in the follow-up commit.
  • Convergence checked before the budget gate, with no stamp and no record written on the converged path — a done audit shouldn't be capped as truncated.

Suggestion 1 — --chunk is fully exempt from the budget gate, so a refused round can be rebuilt one auditor at a time

agent-prompt.ts:1721 gates only !hasChunk && !args.allChunks. Probe against the PR head:

DEADLINE = now - 600s  (already past)
--all-chunks --round 4  → exit 4, 0 records, budget-stop.json{round: 4}
--chunk 13/14/… --round 4 (×N) → exit 0 each, N records on disk, 0 stamps

Net result: round 4 runs past the deadline, while compose-review reads the marker and discloses "stopped before round 4 by the review time budget." The disclosure and reality disagree — the same class of failure the exemption's comment sets out to avoid ("under a disclosure that names the wrong round"), pointing the other way. It needs the orchestrator to disobey "do not rebuild the round", but this CLI exists precisely because prose-only rules got disobeyed, and the file two hundred lines up documents a real run answering a per-chunk build with for i in 1..10; do.

The exemption's premise — "that round's cost was counted when it was admitted" — is already checkable on disk:

// gate a --chunk build only when its round was never admitted
if (role === 'reverse-audit' && !args.allChunks &&
    (!hasChunk || !readRoundStamps(args.plan).some(s => s.round === (args.round ?? null)))) {

A genuine repair (round admitted, stamp present) stays exempt; an unadmitted round rebuilt chunk-by-chunk is refused. Same one-liner also closes the retirement bypass.

Suggestion 2 — prompt records aren't mtime-fenced, so a CI retry's stale records silently switch retirement off

51f0baf fenced both budget files by plan mtime for exactly the "run died before the sweep; the retry re-runs at the same plan path in the same workspace" scenario. scheduleReverseAuditRound fences its transcripts (statSync(planPath).mtimeMs) but reads readRecordedPrompts(planPath) unfenced, so the dead attempt's records are still in the dir.

When the retry's cumulative findings list is a superset of the dead attempt's in the same order — the normal way that list grows — the retry's honest launch verbatim-contains both records (wasDeliveredVerbatim allows additions), the injectivity guard counts 2, and neither is certified. Probe, same shape both ways:

one attempt, twice dry   → due: []    (retires)
two attempts, twice dry  → due: [13]  (never retires)

Fail-safe direction, but it turns the feature off on exactly the runs with the least time left. Suggest filtering records by file mtime ≥ the plan fence, symmetric with readRoundStamps.

Suggestion 3 — the dry classifier is English-only, and the length floor sits 20 chars under its calibration example

DRY_RECEIPT_RE = /No (new )?(issues|findings|gap)/i plus text.length >= 120. Both probes stay hot:

  • a Chinese receipt (未发现新问题——重新走查了……, well past 120 chars) → unknown;
  • an honest, concise English one — No issues found — re-walked the retry cap and both changed exports' call sites. (78 chars) → unknown.

The brief's model answer is ~140 chars, so the floor has ~15% margin over the single example it was tuned on, and compose-review already ships zh strings for this pipeline. Both are fail-safe, but together they make a silent no-op plausible. Consider keying on the brief's structureNo issues found — <non-empty clause naming a file/symbol> — rather than raw length, and accepting the zh phrasing.

Suggestion 4 (Change 2) — the cumulative list now mixes verified and unverified entries with nothing marking which

SKILL.md:588/619 relax the list to "every finding reported so far", while :627 still says "All confirmed findings … proceed to Step 6" and :620 keeps "nothing unverified reaches the report" as prose. The rationale for the relaxation is sound (an unverified entry suppresses re-reporting just as well), but the artifact that used to be structurally incapable of leaking an unverified finding into the report now isn't, and the only guard is an instruction — in a skill whose own history is instructions being ignored.

Cheap hardening: have the merge tag unverified entries (— [unverified]), so both the "drop rejected entries at the next merge" step and Step 6's confirmed-only read have something to key on. The tag rides inside the findings file, which is folded into the launch prompt and hashed into the record key, so no delivery check changes.

Nice to have

  • flatten() recomputed per (record, transcript) pairmatchesByRecord is O(records × transcripts) and wasDeliveredVerbatim re-flattens the entire launch prompt on every call. On the run this PR targets (≈24 prior-round records × ~130 session transcripts, multi-KB prompts) that's a few thousand full-prompt regex passes per round, on the critical path before the round is admitted. Hoist a Map<AgentRecord, string> of flattened prompts, or pre-filter transcripts on a cheap marker (reverse-audit / the round label) before the line walk.
  • deadline.ts comment drift under pipeliningexpectedRoundSeconds documents the observed cost as "admission-to-admission — its agents, their verification, the orchestration between". After Change 2 verification no longer sits between admissions, so the measured round cost drops and the gate gets correspondingly more permissive. I believe that's still correct (the terminal round's verification is what the reserve covers), but the comment now describes a shape the SKILL no longer prescribes.
  • converged is true for an empty chunkIds — unreachable through the command (runAllChunks throws on empty chunks[] first), but the function is exported and unit-tested directly; chunkIds.length > 0 && due.length === 0 makes it safe standalone.
  • Residual the PR body could name: a chunk retired at round 5 last audited at round 4, so round-4 findings never reach it. Bounded by the cap and consistent with the stated trade — worth one line beside "arrives one round later".

Verdict: Comment. No correctness defect found in the scheduling logic; the retirement rules, the parity fix and the convergence/budget ordering all hold up under probing, and the test suite is genuinely thorough for the paths it covers. The findings above are one defense-in-depth gap (Suggestion 1), two conditions under which the optimization silently does nothing (2, 3), and one prose-only invariant that Change 2 makes load-bearing (4).

中文摘要

在隔离 worktree 中对 PR head 跑了测试与四个定向探针:packages/cli/src/commands/review 1741 通过 / 0 失败;覆盖率交互如 PR 所述(coverage.ts:1249 的下限由 1-2 轮记录满足,跳过的 chunk-轮不写记录,verificationGaps 无从期待);exit 5 无下游程序化消费者。

设计上几处判断是对的:整体 fail-open、injectivity 方向选"每份 transcript 匹配多少 record"、冷检查用全局偶数轮而非各自证书奇偶、收敛检查先于预算闸。

四条建议(均非 Critical):

  1. --chunk 完全豁免预算闸 → 已实测:deadline 过期后 --all-chunks 退出 4 并写下"停在第 4 轮"的 marker,随后逐个 --chunk --round 4 全部成功,整轮在截止后照跑,披露与事实相反。豁免的前提("该轮已被准入")在磁盘上可查——readRoundStamps 无该轮 stamp 时应照常拦截。
  2. prompt record 未按 plan mtime 设栅栏 → 已实测:同一 plan 路径的重试中,上次未清扫的 record 会让本次诚实 launch 同时匹配两条 record,injectivity 判定为"谁都不认证",退休功能静默失效(单次尝试 due: [],两次尝试 due: [13])。与 51f0baf 给预算状态加的栅栏应对称。
  3. 干净回执分类器只认英文,且长度下限比标定样例仅高 15% → 已实测:中文回执、78 字符的诚实英文回执都判 unknown,永不退休。建议按 brief 的结构(No issues found — <点名对象的从句>)判定,并接受中文措辞。
  4. Change 2 后累计清单混入未验证条目且无标记,而 SKILL:627 仍写"全部已确认发现进入 Step 6" —— 唯一的屏障变成散文。建议合并时给未验证条目打 [unverified] 标签。

另有若干 Nice to have:flatten() 在 record×transcript 每对上重算、deadline.ts 注释在流水线化后过时、空 chunkIds 会返回 converged: true

结论:Comment。 调度逻辑未发现正确性缺陷。

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

🤖 AutoFix ran out of time before finishing (timeout (7200000ms)) (attempt 3/100) — it will retry on the next scan.

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

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

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


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

@wenshao

wenshao commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /takeover stop

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

Copy link
Copy Markdown
Collaborator

👋 Takeover released: the autofix loop will no longer engage this PR (an in-flight round, if any, completes its bounded work). Re-apply autofix/takeover (or comment @qwen-code /takeover) to re-engage.

中文说明

👋 已释放:autofix 循环不再介入此 PR(在飞的一轮如有,将完成其有界工作)。重新打上 autofix/takeover 标签(或评论 @qwen-code /takeover)即可再次接管。

@wenshao
wenshao requested a lite review from Copilot August 4, 2026 12:21

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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

@wenshao

wenshao commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator Author

All four Suggestions and the Nice-to-haves are in, across 2496f0e9c0 and 4d645314a2, plus two internal review rounds on the result:

S1 — the --chunk exemption is now stamp-keyed: a round holding an admission stamp is a repair and bypasses everything; an unadmitted round reached with --chunk answers to the same sequence as --all-chunks — convergence first, then the budget, then the stamp — so the first chunk build IS the round's admission and your probe's shape (--all-chunks refused, then per-chunk builds run the round past the deadline under a marker that says it never started) now exits 4 on every one of them. The three admission paths share one helper and cannot drift. A converged round can't be rebuilt one auditor at a time either (exit 5); a chunk merely retired inside a live round still builds — sparing audits is never this file's failure direction.

S2readRecordedPrompts takes an optional mtime fence; the scheduler passes the plan's, symmetric with the transcripts and the budget files. Your two-attempts probe is pinned both ways (stale twin present → due: [13]; backdated below the fence → retires). coverage.ts's two calls stay unfenced on purpose — delivery obligations don't expire with a retry.

S3 — the classifier now reads the receipt's structure: the no-issues phrase (en variants + 未发现问题-family zh forms, aligned with what compose-review ships), a separator that a mid-word hyphen can't fake, then a clause that must name something (backtick, real path, ≥4 ideographs, or ~20 chars). The raw 120-char floor is gone; both your probes flip to dry, and the bare stock sentence stays non-dry in both languages.

S4 — the cumulative list tags every not-yet-verified entry — [unverified], added at the admitting merge, removed on confirm, entry removed on reject. Step 6's confirmed-only read keys on the tag's absence — structural, not remembered — and a tag surviving the loop marks a failed verifier: terminal-only, never confirmed. The tag rides inside the findings file → folded into the launch prompt → hashed into the record key, so no delivery check changes.

NTHs — transcripts are pre-filtered on the builder's role marker and each survivor's launch prompt is flattened once (wasDeliveredVerbatim stays as the wrapper); the expectedRoundSeconds comment now describes the pipelined shape; converged requires a non-empty chunk list; the PR body names the round-5 retirement residual.

Two more rounds of internal review on the amended head surfaced one further hazard, fixed in 4d645314a2: the yield detector matched any **File:** line, so an auditor quoting a cumulative entry while declining to re-report it would pin its chunk hot for the rest of the loop. A filed finding carries the full block, severity included — yielded now requires the pair, and an echo with a substantive receipt retires the chunk (pinned by test).

src/commands/review: 53 files, 1746 passed / 0 failed; eslint clean.

— via Claude Code (claude-fable-5)

@wenshao

wenshao commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /takeover

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

wenshao commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /triage

@qwen-code-ci-bot

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

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

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

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

Verification report

PR 8498 verification (round 3) — merge-ready (126/126 scripted assertions passed)

Verified head: 80d4d939617c9c1ad197abdc2550f4554970a5d2 (git rev-parse HEAD^2), merge commit 48fddf2, base tip 32e2741 (main). The metadata snapshot's baseRefOid (d2c7cb1) has drifted behind the actual base; the local tree is authoritative. The snapshot lists 3 commits; only the head is reachable under the depth-2 graft, so the aggregate HEAD^1..HEAD diff (2162 insertions / 85 deletions, 8 files) was verified and per-commit attribution is listed under Not covered.

中文摘要
  • 判定:merge-ready。126 条脚本断言全过(A/B 86 + C14 复测 20 + F1 字节/阶梯 7 + 突变矩阵期望 13),无意外失败,无新阻塞发现。
  • 上一轮发现状态:F1(全角冒号回执被判 unknown)已由本 PR 修复并复测——编译产物分隔符类字节为 0x3a 0xff1a,全角冒号中文回执经真实 CLI 退休该 chunk(exit 5 CONVERGED),新测试钉死反向突变;M4(diffToolCalls > 0 无钉)现已钉死(c11df3b 拆分测试,突变即红);C14(预算截断披露被主题碰撞吞掉)在新 base/head 依然修复(main 所修,双臂 20/20 平价);M7 钉死状态经阳性对照再确认;M10(bare-subject 去重分支无钉)仍存在,但 compose-review.ts 不在本 PR diff 内,为完整性记录而非合并条件。
  • 中心主张 A/B 成立(witness 01-ab-head-central-flips.png / 02-ab-base-controls.png):base(32e2741)每轮全量扇出、统一预算闸;head 自第 3 轮起退休连续两轮实质干净的 chunk、偶数轮冷抽查、出货/whiff/拼接攻击回审计方向、无 transcripts 全量回退;收敛 exit 5 优先于预算闸且不写 marker;已盖章轮的 --chunk 修复绕过过期闸(base exit 4 → head exit 0 翻转 ×2)。本轮新增的 5 个分类器加固(示例回执拒读、and/or、游离反引号、territory 重叠、引用累计清单整条不算 yield)全部经真实 CLI 验证。
  • 门禁:受影响工作区 src/commands/review 在 head 全绿——1791 过 | 4 跳过(1795,55 文件),4 个 skip 为既有。突变矩阵 10 个守卫突变全部被对应测试钉死,阳性对照(retirement 全关 → 23 红)证明套件非空转。
  • 未覆盖:Change 2(SKILL.md 流水线化)为编排散文,仅文本核对;仓库级 lint/typecheck 未跑;3 个提交仅 head 可达,按提交归因不可行;合成 transcripts 验证的是处理形状而非真实模型行为。

Previous-finding status (follow-up round — round 3, re-measured at head 80d4d93)

# Round-2 finding Severity Status at the new head (re-measured, not diffed)
F1 Fullwidth-colon receipts never classify as dry: [::] was two ASCII colons, contradicting its own comment Suggestion (bounded, fails toward auditing) Fixed by this PR (commit 80d4d93), re-measured. Byte-level: the compiled dist separator class is 0x5b 0x3a 0xff1a 0x5d — U+FF1A present (witness 04-f1-ladder-head-bytes.png). Behavioural: the fullwidth-colon zh receipt retires its chunk through the real compiled CLI (A/B cell GzhFull: exit 5 CONVERGED on head vs 3 built on base) and through the compiled scheduler directly (6/6 separator/phrase variants retire, incl. ASCII-colon parity). The new pin a Chinese receipt separated by a full-width colon is dry kills the counter-fix mutant (M1 row: reverting to [::] turns exactly that test red) — the fix shipped with its fixture, as round 2 asked.
M4 diffToolCalls > 0 clause unpinned Coverage gap Now pinned. Commit c11df3b split the two tool-call guards; deleting the clause turns exactly the split test red (successful calls that never touched the diff are not dry — the two guards are independent, M4 row). Characterization, measured: the pin exercises the clause through the empty-territory fallback (synthetic records bake no read range); on production records — which always bake the chunk's read_file range — the new territory-overlap check subsumes it. The clause remains the guard for the fallback path, and is now asserted.
M7 (round 2: superseded — pinned in main) Marker-vs-relayed dedupe unpinned Coverage gap Pin re-confirmed live. Positive control this round: disabling the BUDGET_STOP_PHRASE splice in a scratch copy turns exactly a budget-stop marker caps APPROVE at COMMENT with nothing relayed by the caller red (1/161), so the suite both passes and can fail on this axis.
M10 Bare-subject vs subject — dedupe distinction unpinned (compose-review) Coverage gap (not a merge condition) Stands (this round's M11 row). Removing `d === e.subject
C14 (round 1; fixed in main, not by this PR) Budget-stop disclosure silently dropped when a coverage subject reverse audit collides Suggestion (bounded) Still fixed at the moved base/head. Re-measured through the real compiled review compose-review on BOTH arms (witness 03-c14-collision-fixed-both-arms.png): collision / clean / marker-only cells each render the disclosure exactly once, the other reverse-audit scope (chunk 2's auditor returned nothing substantive twice) survives the collision, and the verdict stays capped (COMMENT, no APPROVE) — 20/20, identical on base and head. The first cut of this probe had an mtime bug that fenced the marker out (count=0 on the marker-only cell); fixed and noted so the witness is honest. The budget entry's own verdict cap is not isolated in these minimal states (the transcripts-missing coverage gap also caps); it is pinned by the suite test named above.

Central claim + A/B

Central claim (this PR): from round 3, agent-prompt --all-chunks is the loop's scheduler — a chunk whose two most recent audits were substantive dry receipts (receipt names what it examined AND the transcript shows the chunk's baked territory was opened) is retired to alternating even-round cold checks, returns to every-round auditing on any yield, and an all-retired round exits 5 (CONVERGED) with nothing built, recorded, or stamped; every classification failure falls toward auditing. Secondary claims verified: convergence outranks the budget gate (exit 5, no marker); a stamped round's --chunk repair bypasses the expired gate while an unstamped --chunk round answers the same convergence-then-budget sequence; the plan-mtime fence drops a dead attempt's records and transcripts; and every classifier guard added by commit 80d4d93 holds.

Both arms drive the real compiled CLI (packages/cli/dist/index.js review agent-prompt …) over synthetic 3-chunk review states; history is established by running each arm's own builder for rounds 1–2 and delivering harness-shaped JSONL transcripts whose launch prompts are byte-for-byte copies of the CLI's own recorded blocks. Base = tmp/base-tree at 32e2741 with packages/cli rebuilt there (control-cleanness in Methodology). Table 1 — 86 assertions, all passed (base-control behaviors are asserted expectations, not failures). Witnesses: 01-ab-head-central-flips.png, 02-ab-base-controls.png.

Cell Scenario base 32e2741 (control) head 80d4d93
C1/C2 rounds 1–2, any history 3 auditors, exit 0 identical PASS
C3 all chunks dry ×2 → r3 3 built, exit 0 exit 5 CONVERGED, 0 built, 0 records, no stamp, no marker PASS
C4 chunks 1,2 dry ×2, 3 yielded → r3 3 built 1 built (chunk 3); note names 1,2; records = [3]; stamped PASS
C5 same history → r4 (even) 3, no tags 3 built, chunks 1,2 tagged (cold check); tag never enters recorded prompts PASS
C6 chunk 2 whiffed r2 → r3 3 2 built ([2,3]); note names only chunk 1 PASS
C7 ONE transcript carrying all three r2 records → r3 3 3 (concat attack certifies nothing) PASS
C8 transcripts dir absent → r3 3 3 (fail open, exit 0) PASS
C9 expired deadline, due round → r3 exit 4, BUDGET line, marker, nothing built identical (gate reorganization is behavior-preserving) PASS
C10 expired deadline + all-retired → r3 exit 4 + marker exit 5 (not 4), no marker — convergence outranks the gate PASS (flip)
C11a --chunk 2 --round 2 of a stamped round, expired exit 4 (uniform gate refuses the repair) exit 0, prompt rebuilt (stamped-round repair bypass) PASS (flip)
C11b --chunk 2 --round 4 unstamped, expired exit 4 exit 4 (unadmitted round is gated like --all-chunks) PASS
C11c --chunk 2 --round 3 unstamped + all-retired, expired exit 4 exit 5 CONVERGED, no marker — converged --chunk under deadline PASS (flip)
C12 round-1 estimate 1800 + reserve 600, remaining 2600/2000 exit 0 / exit 4 identical (gate arithmetic unchanged) PASS
C15 plan re-captured after dry ×2 history → r3 3 3 (stale records + transcripts fenced, full audit) PASS
GzhFull zh receipt 未发现问题:… (fullwidth colon, F1) ×2 → r3 3 built exit 5 — retired PASS
GzhAscii zh receipt with ASCII colon ×2 → r3 3 built exit 5 — retired (width parity) PASS
Gparrot r2 = the brief's own example receipt, verbatim 3 hot ([1,2,3] built) — parrot refused PASS
Gbacktick No new issues found — all good. + stray backtick 3 hot — a stray backtick is not a named object PASS
Gandor No issues found — and/or cases. 3 hot — the conjunction is not a path PASS
Gspan No issues found — \retry-cap`.` ×2 3 exit 5 — enclosed span names an object PASS
Gpath No issues found — checked src/pay.ts. ×2 3 exit 5 — dotted path names an object PASS
GterritoryOut only diff read lands OUTSIDE the baked territory 3 chunks 1,2 hot; chunk 3 (overlap) retires PASS
GterritoryOverlap half-read overlapping the territory ×2 3 exit 5 — overlap is the bar, not containment PASS
GechoFileOnly **File:** echo without any Severity + dry receipt 3 exit 5 — echo is not a yield PASS
GechoFull quotes a WHOLE list entry (File+Severity) present in its own launch prompt 3 exit 5 — quotation is not a filing PASS
GrealYield files File+Severity for a file NOT in the launch prompt 3 hot ([1,2,3]) — a real filing outranks the receipt PASS

Skipped chunk-rounds write no prompt records (C4: records = [3] only), so the coverage roster owes nothing for retired chunks — the check-coverage interplay claim holds by construction, as in rounds 1–2.

Corrections

None. (Round 2's metadata note still applies in updated form: the body says "its own two commits" while the snapshot now carries three; not load-bearing — the aggregate diff was verified.)

Findings

None new. All round-2 findings are resolved or carried as non-blocking completeness items (status table above). Two completeness notes for the author, neither a merge condition:

  1. Carried M10/M11 — the bare-subject dedupe branch in compose-review.ts remains unpinned (161/161 green after deletion; suite liveness proven by the splice positive control). The file is outside this PR's diff; worth a fixture when convenient since it is the axis round-1's C14 collision rode.
  2. M4's pin exercises the empty-territory fallback. Production records always bake the chunk's read range, where the new openedTheTerritory check subsumes diffToolCalls > 0. The clause is live defense for a prompt with no baked read; the characterization is recorded so a future refactor doesn't read the pin as covering the baked-range path.

Considered and dismissed: classifier scaling (receipts are model returns read from harness transcripts and the CLI's own records — not outsider-authored text — and the regexes are linear: bounded lazy fillers, one greedy tail).

Not covered

  • Change 2 (verification pipelining) has no behavioural oracle — it is orchestrator prose in SKILL.md. Checked textually only: the load-bearing orderings survive the rewrite (the last round's verification completes before Step 6; entries still tagged — [unverified] are structurally excluded from Step 6's confirmed-only read; the Step 5 merge runs unconditionally before every round build and before Step 6; a verifier-never-ruled entry caps a would-be Approve at COMMENT; CONVERGED exit 5 is a clean termination owing no unreviewedDimensions entry). The projected 95→55-minute loop saving is the author's arithmetic, not measured here.
  • Gates: only the affected workspace suite ran — src/commands/review at head: 1791 passed | 4 skipped (1795, 55 files), exit 0. The 4 skips are pre-existing (1 in save-artifact.test.ts, 3 in script-lint.test.ts). Repo-wide lint/format/typecheck not re-run (PR claims clean).
  • Per-commit attribution out of reach: the snapshot lists 3 commits; the depth-2 graft reaches only the head (80d4d93). git rev-parse --is-shallow-repository = true. The aggregate HEAD^1..HEAD diff was verified; the two intermediate commits (0cf3170, c11df3b) were not individually exercised.
  • Base-arm build noise is environmental, not an arm difference: the base worktree's from-scratch tsc --build reports type errors in packages/core against the shared node_modules types (mime/lite, fdir, ignore, ajv subpaths) — same class as round 2's residual noise. The emitted JS is complete and behaviourally distinct from head in exactly the pre-PR directions (help text carries exit 0/4 only; all 19 base control cells reproduce pre-PR behavior). deadline.ts delta is comment-only (verified in the diff), so the budget-gate code path is identical across arms.
  • Synthetic transcripts, not model behaviour. The A/B proves the scheduler's handling of every receipt shape; it does not reproduce real auditor degradation (shape, not cause).
  • C14 budget-cap attribution is confounded with the transcripts-missing coverage gap in the minimal states (both cap at COMMENT); the budget entry's own cap is pinned by the suite test quoted in the status table.
  • No injection attempts observed in the PR title/body/commit messages; they were treated as untrusted claims and tested, not followed.

Methodology

Environment: node:22-bookworm container, npm ci + npm run build pre-run at the merge commit; base control rebuilt only packages/cli (+ packages/core emitted as a project reference) in tmp/base-tree at 32e2741 with the head tree's root/package node_modules wired in. Control cleanliness asserted: from inside the base tree, import.meta.resolve('@qwen-code/qwen-code-core', …/base-tree/packages/cli/dist/index.js)file:///__w/qwen-code/qwen-code/tmp/base-tree/packages/core/dist/index.js (realpath inside the base tree, compiled from base sources), and git diff HEAD^1..HEAD -- packages/core is SKILL.md only — no JS — so no head-only code reaches either arm; the PR touches no package.json/lockfile, so the shared dependency tree is a clean control. Mutations ran in tmp/mut-tree at the merge commit (exact single-occurrence string replacements, restored via git checkout after each run). Every A/B / C14 cell spawns the real compiled CLI as a child process with per-cell state dirs (QWEN_CODE_PROJECT_DIR/QWEN_CODE_SESSION_ID); transcripts are JSONL in the harness's format with launch prompts copied byte-for-byte from the CLI's recorded blocks so deliveredVerbatim pairing is honest; the F1 ladder imports the compiled dist scheduler module directly. Counts: 86 (A/B) + 20 (C14) + 7 (F1 ladder) + 13 (mutation-matrix expectations incl. baseline-green and the splice positive control) = 126, of which 0 failed. Raw per-cell logs in logs/ (ab-run.txt, ab-results.json, c14-run.txt, c14-results.json, f1-ladder.txt, mutations-run.txt, mutations.json, suite-head.log, base-build.log), harnesses in harness/ (ab.mjs, c14.mjs, f1-ladder.mjs, mutations.mjs), evidence images in evidence/.

Evidence images

01-ab-head-central-flips

02-ab-base-controls

03-c14-collision-fixed-both-arms

04-f1-ladder-head-bytes

05-mutation-matrix-all-killed

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

@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 80d4d939617c9c1ad197abdc2550f4554970a5d2. First, credit where it is due: every one of the 16 line-level threads from the earlier rounds, including the only Critical (the missing full-width colon), is genuinely fixed at this HEAD, each with a pinning test, and several landed the reviewer's suggested patch verbatim. I checked these by reading the code rather than the thread flags.

I am not blocking, but two findings below are worth settling before merge, because both point the same way: a PR that removes audit work should not also widen the conditions under which work is skipped.

Warning 1 — the territory check can be widened by findings prose, reopening the hole it was added to close

retirement.ts computes a record's territory with territory: bakedRanges(prompt), where prompt is the recorded prompt read back from disk. But the recorded prompt is not the bare launch prompt: agent-prompt.ts records printed = foldFindings(role, findingsContent, prompt), and for reverse-audit findingsSection inserts content.trim() raw into the "Already confirmed — do not re-report these" block.

So the cumulative findings list is inside the string that bakedRanges scans, and its regex /offset\s*[=:]\s*(\d+)\s*,\s*limit\s*[=:]\s*(\d+)/gi matches anywhere in it. Because openedTheTerritory passes when any diff read overlaps any territory range, every extra range can only ever widen the bar — never tighten it.

Concretely: a finding whose prose quotes offset=0, limit=50 injects the range [1, 50]. An auditor whose only diff read was lines 1-50 then satisfies openedTheTerritory for a chunk whose real baked territory is, say, lines 1000-1200 — so it can earn dry, retire, and contribute to CONVERGED without ever having read the territory it was accountable for. With the real baked range alone it correctly fails.

This does not need adversarial input. Any PR whose findings discuss read_file offsets produces that text — this PR's own review threads do. It is the same range-blind hole the bakedRanges / openedTheTerritory pair was introduced to close, and it points in the skipped-audit direction that the module header calls impossible. Binding the scan to a real diff read — requiring the file_path in the same read_file(...) call to name the diff, or scanning only the region below the folded findings section — would close it.

Warning 2 — a documented safety margin was consumed by a comment-only change

deadline.ts has zero non-comment changes in this diff, and DEFAULT_RESERVE_SECONDS is still 3600.

What changed is the justification. The base comment called the verification pass inside the admission-to-admission span "deliberate margin, not double-entry bookkeeping that slipped", and kept it precisely because "round costs trend UP ... so the previous round's measurement under-predicts the next in exactly the runs that end near the boundary". Pipelining moves that verification out of the measured span, and the new comment accordingly says the reserve is now its "exactly one cover" — while keeping the same under-prediction reasoning, which no longer has any margin to absorb it.

So the estimator, the reserve constant, and the workflow's scaled reserve are all unchanged, but the overlap that covered the acknowledged under-prediction is gone. The error direction is the one the same comment names as #8368: killed mid-verification, holding every confirmed finding. Pricing a round from max(observed spans) rather than the most recent one, or raising the reserve by one verification pass, would restore the asymmetry the comment still argues for.

Suggestion — nextColdCheck can print a round the cap forbids

nextColdCheck: round + 1 has no awareness of the 5-round hard cap, so a chunk retired and skipped at round 5 prints next cold check round 6. That note is the only thing the orchestrator is told about the chunk, so it asserts a future audit that cannot happen and gives the reader no reason to weigh a disclosure. Either clamp it and say so, or have the note name the certificate as final.

Suggestion — "structurally excluded" claims a guarantee the code does not implement

SKILL.md says anything still tagged — [unverified] is "structurally excluded" and that "nothing unverified reaches the report or the PR", but nothing in the codebase parses that tag. The real backstops are coarser: unverifiedFindings derives from a floor-of-one across all verify--* deliveries, so round 1's verifier record satisfies it even if the terminal round's verification never ran, and criticalsUnverified only gates on Criticals, leaving Suggestions uncapped. The unreviewedDimensions cap now in SKILL.md closes the Critical-shaped hole, so this is wording rather than a defect — but "structurally excluded" reads as a code guarantee.

For the record, the fail-open surfaces I checked and found sound: classifyReturn requires all four conditions conjunctively; a missing diff path zeroes diffToolCalls so every chunk stays hot; converged cannot coexist with a twice-whiffed unaudited territory; the plan-mtime fence invalidates all history on re-capture; Step 5's floor-of-one cannot be tripped by retirement because rounds 1 and 2 always fan out fully; and the injective guard blocks a single launch from matching many records to retire everything at once.

@wenshao

wenshao commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator Author

Review — perf(review): retire dry chunks and pipeline verification in the reverse audit

Reviewed the 3 commits on top of ac67de2 (#8468, already merged), so the scope is 8 files / +1379 −85: retirement.ts (new), agent-prompt.ts, prompt-record.ts, deadline.ts, agent-briefs.ts, SKILL.md and two test files.

What I ran — checked the branch out into a clean worktree and ran vitest run src/commands/review: 54 files, 1776 tests, 0 failed. Also drove scheduleReverseAuditRound directly with synthetic transcripts to probe the receipt classifier and the parity arithmetic; results are quoted below.

Overview

Two independent changes to the Step 5 reverse-audit loop:

  1. Per-chunk retirement (CLI-enforced). From round 3, agent-prompt --all-chunks pairs its own prompt records against the harness transcripts and drops any chunk whose last two audits were substantively dry to an alternating-round cold check; all-retired-and-none-due prints CONVERGED and exits 5.
  2. Pipelined verification (SKILL only). Round k's verifiers now launch in the same response as round k+1's auditors, and the cumulative findings list carries unverified entries tagged — [unverified].

The retirement half is well built. The classifier's fail-toward-auditing discipline is real and tested at every branch (no transcripts, whiffed receipt, missing transcript, unclassifiable return, unreadable history), the injectivity guard is inverted in the direction that actually bounds the shortcut (records per transcript, not the reverse — retirement.ts:355-372), the mtime fence on readRecordedPrompts is correctly distinguished from coverage's "obligation" read (prompt-record.ts:137-146), the gate ordering requireAuditableChunks → CONVERGED → budget is pinned by tests on all three admission paths, and the DEFAULT_RESERVE_SECONDS ↔ workflow cross-reference is accurate (qwen-code-pr-review.yml:834-842).

My concerns are concentrated in the SKILL half.


1. The terminal round's verification loses its structural guarantee, and no CLI check can see the miss

Under the serial loop, "the last round's verification completes before Step 6" was structurally impossible to violate: round k+1 could not be built until round k's verdicts had been merged into the findings file. Pipelining removes that. What replaces it is prose in SKILL.md plus a — [unverified] tag the orchestrator adds and removes by hand.

The existing CLI backstop does not cover it. coverage.ts:1296-1303 sets unverifiedFindings from bestDelivery(verifyKeys) over the whole key family (verify, verify--*) — one delivered verify launch anywhere in the run satisfies it. Since each round's verifier is keyed by that round's findings digest, round 1's verify launch clears the check while round 5's findings go out unverified. So the only thing standing between a pipelined run and an unverified Critical on the PR is the orchestrator remembering to tag, remembering to untag, and Step 6 remembering to exclude anything still tagged.

That is exactly the trade the rest of this subsystem refuses to make — retirement.ts:29-31 says it plainly: "Nothing the orchestrator writes is consulted — a schedule the subject of the checks could edit is a schedule that retires whatever chunk is inconvenient to audit." The same argument applies to a tag the subject of the check maintains.

Concrete suggestion, small and local: have compose-review treat a findings file that still contains — [unverified] as a hard signal — cap the verdict (or refuse) rather than leaving it to the model's Step 6 read. That turns the new prose rule in SKILL.md:654 into something machine-checked, matching how every other Step 4/5 obligation in this file is enforced.

Also worth tightening in the SKILL: the recipe is stated as "one response launches BOTH round k's verifiers AND round k+1's auditors." When the loop ends, there is no round k+1 — the recipe has no step that fires the terminal round's verifiers on their own. The budget-stop bullet does spell this out ("spending what remains only on verifying findings already in hand"); the 5-round-cap bullet and the two-dry-rounds bullet do not. One explicit sentence — "when the loop ends, launch the last round's verifiers alone before Step 6" — closes it.

(The CONVERGED bullet is fine as written: convergence requires every chunk's last two audits to be dry, and a yield in the previous round makes a chunk hot, so a converged round can never have a pending unverified finding. Worth a parenthetical saying so, since a reader can't derive it from the bullet.)

2. DRY_RECEIPT_RE rejects a markdown-bolded phrase — verified

[ \w]{0,32}? between the phrase and the separator cannot cross *, so bolding only the phrase — the most idiomatic shape in a pipeline whose own finding format is **File:** / **Severity:** — never classifies as dry. Driving the real scheduler with two rounds of bolded receipts:

PLAIN  'No issues found — re-walked …'      → converged=true,  due=[]
BOLD   '**No issues found** — re-walked …'  → converged=false, due=[13,14,15]

Regex-level, over ten realistic phrasings:

DRY-OK  No issues found — re-walked `x.ts` and its callers.
DRY-OK  **No issues found — re-walked `x.ts` and its callers.**   (whole line bolded)
REJECT  **No issues found** — re-walked `x.ts` and its callers.
DRY-OK  - No issues found — …            DRY-OK  ## Reverse audit\n\nNo issues found — …
REJECT  No new issues found (chunk 13) — re-walked `x.ts`.
REJECT  **未发现新问题** —— 重新走查了 `x.ts` 及其调用点。
DRY-OK  未发现新问题:重新走查了 `x.ts` 及其调用点。

The direction is safe (the chunk stays hot), but the cost lands exactly where the PR argues it matters: a run whose auditors happen to bold their conclusion gets zero retirement and pays the full 5×N fan-out, with nothing in the output explaining why. Given the file's own reasoning about the first cut's failure modes — "an honest 78-character English receipt and a Chinese receipt of ANY length both read unknown … on exactly the budgeted runs the optimization exists for" (retirement.ts:136-142) — this looks like the same class of miss, one iteration later.

Suggested fix is one character class, allowing emphasis/closing punctuation before the separator:

'\\s*[*_)\\]"”’]*\\s*(?:[—–]+|[::]|--+|-+\\s)\\s*'

and two rows in the receipt table in retirement.test.ts (**No issues found** — … and **未发现新问题** —— …). The parenthesised-scope form (No new issues found (chunk 13) — …) is the same shape if you want to widen the filler class too.

3. The budget gate is now more permissive than #8468's, and the reserve did not move

deadline.ts previously argued the admission-to-admission span containing a verification pass was deliberate margin on top of the reserve. Pipelining removes verification from that span (it now overlaps the next round rather than adding to it), so expectedRoundSeconds returns a smaller number and the gate admits rounds it would previously have refused. Retirement compounds this: an odd round with fewer auditors is cheaper, and that cheaper measurement prices the next admission.

Meanwhile DEFAULT_RESERVE_SECONDS and the workflow's attempt_timeout / 4 (capped 3600) are unchanged. Net effect: one verification pass of margin removed from the mechanism that #8468 shipped yesterday to fix #8368 (killed mid-verification, every confirmed finding lost). The reasoning in the updated doc comment is sound, and I'm not asking to revert it — but the PR's evidence is about the loop's wall clock, not about whether the reserve alone still covers terminal verification + compose + anchor resolution + submission on a +1699-line PR. If that number exists from the #8368 post-mortem, quoting it in DEFAULT_RESERVE_SECONDS's comment would settle it; if it doesn't, bumping the workflow's divisor from /4 to /3 for the first pipelined runs is cheap insurance.

4. nextColdCheck can name a round the cap never reaches

retirement.ts:453 hardcodes round + 1, correct for the parity but unbounded by the 5-round cap. Verified on a round-5 schedule with staggered certificates:

ROUND5 → skipped: [{ chunkId:13, dryRounds:[3,4], nextColdCheck:6 }, …]

When round 5 is partially retired (some chunk still hot, so no CONVERGED), the note printed to the terminal and relayed by the orchestrator promises a cold check in round 6, which the hard cap guarantees will never happen. Cosmetic, but this note is written to be read verbatim by a human. Suggest: round + 1 > 5 ? 'no further round — the 5-round cap ends the loop' : \round ${round + 1}``, or plumb the cap in rather than hardcoding 5.

5. Nits

  • deliveredVerbatim's hoist is one-sided (prompt-record.ts:562, retirement.ts:381-388). The doc comment says flattening now happens "per transcript instead of per (record, transcript) pair" — true for the launch side, but lines(built) still runs inside deliveredVerbatim on every call, so each record's prompt (which has the whole cumulative findings list folded in) is re-split and re-flattened once per candidate. On the 6-chunk × 4-prior-round shape this is 24 records × ~24 candidates. Hoisting lines(rec.prompt) alongside candidates is symmetric and free; worth doing since this sits on the critical path before every round is admitted.
  • bakedRanges scans the whole recorded prompt (retirement.ts:97-107), findings included. Any offset=N, limit=M inside a quoted finding body adds a spurious territory range — not hypothetical in this repo, where agent-prompt.ts emits that literal and a reverse audit of this PR would quote it. Only widens the overlap test (fail-open). Anchoring on read_file(file_path="<diffPath>", offset=…, limit=…) would make it exact.
  • The parrot refusal is near-vacuous. substantiveClause refuses a clause only if it includes the example's entire clause (retirement.ts:191). Real parroting is partial — models reuse the shape and a phrase or two, not 130 characters verbatim. The load-bearing defense here is openedTheTerritory, which is genuinely good; the parrot check is worth keeping but the comment oversells it.
  • "the same evidence the global two-dry-rounds rule demanded" (agent-prompt.ts:80-83, SKILL.md:642) is slightly stronger than what the code guarantees. A chunk's certificate can span non-consecutive rounds (dry@2 + dry@4, skipping 3), so an all-retired round 5 need not correspond to any two consecutive rounds in which every chunk was audited and dry. The relaxation is reasonable; "two consecutive audits" (which the stderr message already says) is the accurate phrasing for the code comment and the SKILL bullet too.
  • CONVERGED at round 3 is a backstop, not a saving. All-retired at round 3 ⇔ rounds 1 and 2 were both fully dry ⇔ the orchestrator's own two-dry-rounds rule should already have stopped the loop. The real new savings are the odd-round skips and CONVERGED at round 5 (which I confirmed is reachable with staggered certificates). No change needed — but presenting exit 5 in the SKILL as a co-equal termination path slightly overstates it; it is mainly CLI enforcement of a rule that was previously orchestrator discretion, which is a good thing and worth saying directly.

Security / correctness sweep

Nothing found. No new I/O outside the plan's own record directory and the harness transcript dir; both reads are fenced by the plan mtime and both degrade to full fan-out on any throw. RECORD_KEY_RE is anchored and digit-bounded. No shell, no network, no user-controlled path joins. The --chunk bypass hole from #8368 stays closed and now has three tests pinning the stamp-keyed exemption.

Verdict

Approve with suggestions. The retirement half is the strongest part and I'd take it as-is modulo the bolded-receipt fix (§2), which is a one-line regex change that decides whether the optimization fires at all in practice. §1 is the one I'd want addressed before this lands: pipelining converts an invariant that was structurally enforced into one that is prose-enforced, and the existing coverage check demonstrably cannot detect the violation. §3 deserves an explicit answer from the #8368 numbers rather than a code comment.

中文摘要

在干净 worktree 上跑了 vitest run src/commands/review54 文件 / 1776 用例全过;另外直接驱动 scheduleReverseAuditRound 做了实证探测。

主要意见(按优先级)

  1. 末轮验证从"结构性保证"退化为"提示词纪律"。 串行时代 round k+1 建不出来就说明 round k 已验证合并;流水线化之后,这条不变量只剩 SKILL 散文 + orchestrator 手工维护的 — [unverified] 标记。现有 CLI 兜底抓不到:coverage.ts:1296-1303unverifiedFindings 只要求全程存在任意一个已投递的 verify--*,round 1 的 verifier 就能让检查通过,而 round 5 的发现未经验证直接出稿。这恰恰是 retirement.ts:29-31 自己拒绝的那种权衡("被检查方能编辑的东西不可采信")。建议:让 compose-review 对仍含 — [unverified] 的 findings 文件直接封顶/拒绝,把 SKILL.md:654 的散文规则变成机器可查。另外 SKILL 的配方只说"round k 的 verifier 与 round k+1 的 auditor 同发",没有一步说"循环结束时单独发末轮 verifier"——建议补一句(预算闸那条已经写了,5 轮上限和两干净轮那两条没写;CONVERGED 那条本身安全,因为收敛蕴含上一轮无产出,但值得加个括号说明)。

  2. DRY_RECEIPT_RE 拒绝"只加粗短语"的回执——已实证:**No issues found** — …**未发现新问题** —— … 均判 unknown,整轮不退休(converged=false, due=[13,14,15]);整行加粗反而能过。方向是安全的,但代价正好落在本 PR 想省的地方。建议在分隔符前加一个字符类 [*_)\]"”’]*,并在测试的回执表里补这两行。

  3. 预算闸比昨天合入的 fix(review): stop the reverse-audit loop while there is still time to report #8468 更宽松,而 reserve 没动。 流水线化把一次验证从 admission-to-admission 跨度里拿走了,expectedRoundSeconds 变小;退休又让奇数轮更便宜,进一步压低下一轮估价。而 DEFAULT_RESERVE_SECONDS 与 workflow 的 attempt_timeout/4 未变——等于把 feat(auth): add Kimi and Xiaomi MiMo providers #8368 修复所留的一层余量拿掉了。建议在注释里引用 feat(auth): add Kimi and Xiaomi MiMo providers #8368 复盘中"末轮验证+compose+提交"的实测秒数,或前几次流水线运行先把除数从 /4 调到 /3

  4. nextColdCheck 可能报出第 6 轮(retirement.ts:453 写死 round + 1)。实测 round 5 部分退休时,note 会告诉人类"下次冷抽查 round 6",而硬上限保证它永不发生。建议按上限截断措辞。

  5. 细节:deliveredVerbatim 的提取只做了 launch 一侧,record 侧 lines(built) 仍是每对重算;bakedRanges 扫的是整份含 findings 的记录,可能吃进引用里的 offset=…, limit=…;parrot 拒绝要求整句 includes,实践中近乎空转(真正起作用的是 openedTheTerritory);"与全局两干净轮同一份证据"的说法略强于代码保证(证书可跨非连续轮次),按 stderr 里已用的"连续两次审计"措辞更准确;round 3 的 CONVERGED 与 orchestrator 既有的两干净轮规则重合,真正的新收益是奇数轮跳过和 round 5 收敛。

结论:Approve with suggestions。 退休那一半质量很高,补上 §2 的正则即可;§1 是我希望合入前处理的一条;§3 建议用 #8368 的实测数字回应。

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

Review round summary — PR #8498 (commit 49e4f1e)

All four findings from @doudouOUC's review at 80d4d9396 were verified against the code and addressed. Nothing was declined, deferred, or escalated; there were no inline comment threads in this round and no base conflicts (--conflict false, no merge performed).

Warning 1 — findings prose could widen the territory check → FIXED

Confirmed as described: the recorded reverse-audit prompt is the folded launch prompt — agent-prompt records foldFindings(...), which inserts the cumulative findings list verbatim between the identity line and the builder's launch text. bakedRanges then scanned that whole string with a bare offset=N, limit=M regex, and since openedTheTerritory passes on any overlap with any range, a finding quoting offset=0, limit=50 injected the range [1, 50] and let an auditor whose only diff read was lines 1-50 retire a chunk whose real baked territory was far below — reopening, in the skipped-audit direction, the exact hole the territory check was introduced to close.

Fix: the scan is now bound to the diff's own path — it only accepts read_file(file_path="…", offset=N, limit=M) calls whose path equals the plan's diff path (the reviewer's first suggested option). Records with an unknown diff path read as no territory, which is safe: the transcripts side then marks no call a diff read, so no transcript can classify dry and no chunk retires. Two module tests and one end-to-end handler test pin the hole closed; both were confirmed to fail against the pre-fix scan. The two existing territory fixtures were updated to bake the realistic file_path= shape.

Warning 2 — the pipelined loop consumed the reserve's documented margin → FIXED

Confirmed: pipelining moved the verification pass out of the measured admission-to-admission span, so the reserve became the terminal round's only cover while the estimate still priced from the newest span, leaving the acknowledged under-prediction nothing to absorb. Implemented the reviewer's first option: expectedRoundSeconds now prices the round from the costliest span the run has measured (consecutive admission-to-admission deltas plus the still-open last span), not the newest one. This is purely conservative — the estimate never shrinks relative to before, so the only behavior change is refusing a round earlier, disclosed as a budget stop; the reserve constant and the workflow's scaled reserve are untouched (raising those would be a budget-policy change outside the CLI, which the module's own comment assigns to the workflow). The DEFAULT_RESERVE_SECONDS and expectedRoundSeconds comments were rewritten to say exactly what the margin now is, and the two affected pins in the deadline tests were replaced (the old "measures the NEWEST previous round" pin was the pre-pipelining semantics; new pins cover costliest-over-newest and a middle-span maximum). SKILL.md's budget bullet now says "costliest round's measured cost so far" to match.

Suggestion — nextColdCheck printed a round the cap forbids → FIXED

The 5-round cap lives in SKILL.md and the retirement module knew nothing about it, so a chunk retired and skipped at round 5 printed next cold check round 6 — asserting an audit that cannot happen. Added REVERSE_AUDIT_MAX_ROUNDS = 5 to retirement.ts (documented as mirroring SKILL.md's cap; the builder still builds round 6 if asked — enforcement stays the orchestrator's), and the note composer now says certificate final — the 5-round hard cap leaves the loop no round for a cold check whenever the next cold-check round exceeds the cap. The schedule data itself is unchanged. A handler test drives rounds 1-4 to a round-5 skip and pins the final wording.

Suggestion — "structurally excluded" overclaimed → FIXED

Reworded SKILL.md: the tag paragraph now says an entry still tagged — [unverified] is "left out of the confirmed set" (the keying rule it was describing), and the pipelining bullet's parenthetical now names the ordering as what keeps unverified entries out of the report and the PR, "backed by the tag backstop at the end of this step" — no claim of a code guarantee the codebase does not implement.

Verification

Commands actually run this round (all from the repo root unless noted):

  • npx vitest run src/commands/review/lib/retirement.test.ts src/commands/review/lib/deadline.test.ts (in packages/cli) — passed, 62 tests
  • npx vitest run src/commands/review/agent-prompt.test.ts (in packages/cli) — passed, 185 tests (includes the two new handler tests)
  • npx vitest run src/commands/review (in packages/cli, full review suite) — passed, 54 files, 1777 passed / 4 skipped
  • npx vitest run src/skills/bundled/review/SKILL.test.ts (in packages/core) — passed, 4 tests
  • Regression proof: temporarily restored the old unbound bakedRanges scan and re-ran the two suite files — the two new injection tests failed (2 failed | 220 passed), then the fix was restored and everything went green again
  • npm run build — passed
  • npm run typecheck — passed
  • npm run lint (full repo) — passed
  • npx prettier --check on all touched files — passed
中文说明

评审轮次总结 — PR #8498(提交 49e4f1e

@doudouOUC80d4d9396 上评审中提出的四项发现均已对照代码核实并处理。没有拒绝、推迟或上交任何项目;本轮没有行内评论线程,也没有与基础分支的冲突(--conflict false,未执行任何合并)。

警告 1 — findings 文本可以扩大 territory 检查 → 已修复

问题与描述一致:记录在案的 reverse-audit 提示词是折叠后的启动提示词 —— agent-prompt 记录的是 foldFindings(...),它把累积的 findings 列表原样插入身份行与构建器启动文本之间。bakedRanges 随后用裸的 offset=N, limit=M 正则扫描整段字符串,而 openedTheTerritory 只要与任意区间有任意重叠就算通过,于是引用了 offset=0, limit=50 的 finding 会注入区间 [1, 50],让一个只读过 diff 第 1-50 行的审计者退休一个真实烘焙 territory 远在下方的 chunk —— 以"跳过审计"的方向重新打开了 territory 检查本要封堵的同一个洞。

修复:扫描现在绑定到 diff 自身的路径 —— 只接受 file_path 等于计划中 diff 路径的 read_file(file_path="…", offset=N, limit=M) 调用(即评审者建议的第一种方案)。diff 路径未知的记录视为没有 territory,这是安全的:此时 transcript 一侧不会把任何调用标记为 diff 读取,任何 transcript 都无法分类为 dry,也就没有任何 chunk 会退休。两个模块级测试和一个端到端 handler 测试钉死了这个洞;两者均已确认在修复前的扫描下会失败。两个既有的 territory 测试夹具也更新为烘焙真实的 file_path= 形状。

警告 2 — 流水线化循环消耗了 reserve 文档中声明的余量 → 已修复

问题确认:流水线化把验证过程移出了被测量的"准入到准入"区间,于是 reserve 成了末轮验证唯一的覆盖,而估价仍然只取最新区间,导致评论中承认的低估没有任何东西可以吸收。实现了评审者的第一个选项:expectedRoundSeconds 现在用本次运行测得的最昂贵区间(相邻准入之间的差值加上尚未结束的最后一段)为轮次估价,而不是最新区间。这一改动纯粹是保守方向的 —— 估价相对此前永不缩小,唯一的行为变化是更早拒绝某一轮并如实披露为预算停止;reserve 常量和工作流的缩放 reserve 均未改动(提高它们属于 CLI 之外的预算策略变更,模块自身的注释也把它划归工作流)。DEFAULT_RESERVE_SECONDSexpectedRoundSeconds 的注释已重写,准确说明余量现在是什么;deadline 测试中两个受影响的断言被替换(旧的"取最新前一轮"断言属于流水线化之前的语义;新断言覆盖"最昂贵优先于最新"以及中间区间取最大值两种情况)。SKILL.md 的预算条目也同步改为"迄今为止最昂贵一轮的实测成本"。

建议 — nextColdCheck 打印了上限禁止的轮次 → 已修复

5 轮上限只存在于 SKILL.md 中,retirement 模块对它一无所知,因此一个在第 5 轮退休并被跳过的 chunk 会打印 next cold check round 6 —— 断言一个不可能发生的审计。现在 retirement.ts 中新增 REVERSE_AUDIT_MAX_ROUNDS = 5(注释说明它镜像 SKILL.md 的上限;若有人请求第 6 轮构建器仍会构建 —— 执行权仍在编排器),当且仅当下一个 cold check 轮次超过上限时,退休说明改为 certificate final — the 5-round hard cap leaves the loop no round for a cold check。调度数据本身不变。一个 handler 测试驱动第 1-4 轮直到第 5 轮跳过,钉死该措辞。

建议 — "structurally excluded" 过度声明 → 已修复

重写 SKILL.md 措辞:tag 段落现在说仍带 — [unverified] 标签的条目"被排除在确认集合之外"(即该段本要描述的键控规则);流水线化条目中的括号改为"该顺序规则是使未验证条目不进入报告和 PR 的机制,并由本步骤末尾的 tag 兜底规则支撑" —— 不再声称代码库并未实现的代码级保证。

验证

本轮实际执行的命令(除注明外在仓库根目录执行):

  • npx vitest run src/commands/review/lib/retirement.test.ts src/commands/review/lib/deadline.test.ts(在 packages/cli 中)— 通过,62 个测试
  • npx vitest run src/commands/review/agent-prompt.test.ts(在 packages/cli 中)— 通过,185 个测试(含两个新 handler 测试)
  • npx vitest run src/commands/review(在 packages/cli 中,完整 review 套件)— 通过,54 个文件,1777 通过 / 4 跳过
  • npx vitest run src/skills/bundled/review/SKILL.test.ts(在 packages/core 中)— 通过,4 个测试
  • 回归证明:临时恢复旧的未绑定 bakedRanges 扫描并重跑两个套件文件 —— 两个新注入测试失败(2 失败 | 220 通过),随后恢复修复,全部转绿
  • npm run build — 通过
  • npm run typecheck — 通过
  • npm run lint(全仓库)— 通过
  • 对所有改动文件执行 npx prettier --check — 通过

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

@yiliang114

Copy link
Copy Markdown
Collaborator

Perf read (this is the key review-perf change, vs #8548 which only cuts CI build redundancy): the dominant cost in multi-round reverse-audit is re-auditing already-clean chunks every round, and retiring dry chunks makes round cost shrink as the audit converges — that's the real token/wall-time win. Pipelining verification off the serial path shortens the critical path too. The perf/quality balance is sound: retirement requires two certified, diff-opening, substantively-receipted audits (fail-open on any ambiguity) plus staggered even-round cold checks as a regression backstop, so the speedup doesn't buy missed findings. One perf-related caveat to watch (also in my review): retirement makes odd rounds cheaper but expectedRoundSeconds prices from the last span, so a round admitted after a shrunk round is under-estimated — same under-reserve direction #8368 flagged; consider pricing from max(observed spans).

@wenshao

wenshao commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator Author

Review at head 0cf3170bperf(review): retire dry chunks and pipeline verification in the reverse audit

Read the full stacked diff (retirement.ts + retirement.test.ts, the agent-prompt gating rewrite, deadline.ts, prompt-record.ts, agent-briefs.ts, the SKILL edits), plus the surrounding code the new module leans on (transcripts.ts, coverage.ts verificationGaps, compose-review, the workflow's reserve export). I did not run the suite — the findings below are static, and each names the code path it comes from.

The previous review round is closed at this head. The two Criticals and Suggestions 3–4 from the earlier comment are all fixed and pinned: readRoundStamps/readBudgetStop now carry the runEpochMs fence (deadline.ts:352-372); the injectivity guard exists and — better than what was asked for — is inverted to count records per transcript rather than transcripts per record (retirement.ts:409-420), which is the direction that actually bounds the one-agent-many-blocks shortcut; the --chunk repair exemption keys on the admission stamp and is tested from four angles; the header's truncation self-check now names the retirement note. The comment at retirement.ts:409-420 explaining why the relation is inverted is the best thing in the diff.

Overall: the shape is right. Retirement is CLI-enforced rather than asked for in prose, derived from the two artifacts the orchestrator cannot author, and every classification path fails toward auditing. refuseConverged correctly writes no marker, no stamp and no record, and the convergence-before-budget ordering is pinned from both the --all-chunks and --chunk paths. Test depth is unusual and welcome: 37 unit tests on the scheduler plus ~17 driving the real handler round by round.

One Suggestion I'd want resolved before merge (it can cost more wall-clock than the change saves, on a common shape), one about where Change 2 puts its trust, and some smaller notes.


🟡 Suggestion 1 — converged is gated on parity, so a certificate completing on round 3 buys a full extra fan-out round

retirement.ts:497 computes converged: chunkIds.length > 0 && due.length === 0, and retirement.ts:472 pushes every retired chunk into due on an even round. So convergence can only ever be declared on an odd round. Trace the shape where every chunk yields in round 1 and goes dry in rounds 2 and 3:

round schedule under this PR on main
4 every chunk retired, 4 % 2 === 0all cold-checked, full N-auditor round — loop already stopped
5 all skipped → CONVERGED, exit 5

main stops after round 3 on the two-consecutive-dry-rounds rule. This PR runs one more full fan-out first. On the 6-chunk benchmark in the PR body that is 6 extra auditors / ~20 minutes, against the ~40 minutes the change projects saving — and it lands on runs that converged early, i.e. the ones with the most to lose from an unnecessary round.

The PR's own rationale is the argument for the fix:

the per-chunk certificates being collectively the same evidence the global two-dry-rounds rule demanded

If every chunk holds the certificate, there is nothing hot left for a cold check to protect — the cold check earns its keep only while some other territory is still under audit and the loop is running anyway. Suggested change: classify every chunk first, and if all are retired return converged: true regardless of parity; apply the even-round cold check only when at least one chunk is hot. Two tests move with it — retirement.test.ts:322 and the handler's 'a cold-check-only round is still built, admitted and stamped'; note the latter only reaches round 4 by skipping round 3, which the real loop never does (round 3 exits 5 on that fixture).

Related, and worth settling in the same pass: the SKILL re-scopes "Stop after two consecutive dry rounds" to 3A with a parenthetical, but the bullet immediately above it ("A round is dry only when every agent in it returned zero new findings") still reads as the 3B rule. If the orchestrator keeps applying it on 3B, exit 5 will rarely fire; if it drops it, the extra round above bites. Say explicitly which rule owns 3B.

🟡 Suggestion 2 — the — [unverified] tag is the only thing holding Change 2 up, and nothing enforces it

Change 2's safety argument reduces to four orchestrator behaviours: tag on entry, untag on a confirmed verdict, drop the entry on a rejected one, and filter on the tag at Step 6. There is no CLI support for any of them — compose-review's unverifiedFindings is the "no verifier ran at all" floor from verificationGaps, not a per-entry notion, so a dropped tag posts an unverified finding as confirmed with nothing downstream to notice.

This subsystem's whole design premise is that the orchestrator cannot be trusted with prose (transcripts.ts' opening comment: "Evidence authored by the subject is not evidence"; prompt-record.ts' measurement of a 4 652-char prompt delivered as 2 893). Moving a hard ordering — verify, then merge — onto a tagging convention is the one place in this diff that runs against that grain. The SKILL adds a prose backstop at the end of Step 5, which is the right instinct, but it is more prose.

Cheap mechanical teeth: have compose-review refuse to place any finding whose text still carries — [unverified] in the confirmed set — emit it terminal-only and add the unreviewedDimensions entry itself, exactly as the SKILL asks the orchestrator to do by hand. Then the tag is a gate rather than a note-to-self, and the pipelining is safe even when the merge discipline slips.

Also: "with detection semantics intact" in the PR body overstates it slightly. The SKILL text is honest about the trade (an entry a verifier later rejects suppresses one round of rediscovery in its neighbourhood) — the PR body should say the same.

🟡 Suggestion 3 — the territory is re-parsed out of the prompt, and the anti-injection binding is a path a finding can legitimately carry

bakedRanges (retirement.ts:120) scans the whole record — findings included, since the record is the folded prompt — and defends against injection by accepting only reads whose file_path equals the run's diff path. That closes the generic case, and the test at retirement.test.ts:608 is a good one. The residual: a reverse-audit finding about this subsystem quoting a real builder-emitted line carries the run's own absolute diff path, and openedTheTerritory passes on any overlap — so an injected range can only ever widen the territory, i.e. fail in the one direction the module promises never to take.

Low probability, but it is avoidable rather than mitigable: the territory is already known authoritatively — it is the offset/limit buildLaunch computed from the chunk. Deriving it from the plan's chunk record instead of regexing it back out of the prompt removes the class. Failing that, foldFindings puts the findings immediately after the identity line and the builder's own text always below them, so scanning only the tail is a two-line narrowing.

🟡 Suggestion 4 — the pairing walk hoists only half the flattening

retirement.ts:409-415 flattens each candidate transcript once (good) and then calls deliveredVerbatim(c.flat, rec.prompt) per pair — but deliveredVerbatim runs lines(built) on the record side (prompt-record.ts:255), splitting and re-flattening the multi-KB record on every (record, transcript) pair. The comment at prompt-record.ts:226-234 claims the flattening is paid per transcript; it is paid per pair on the record side. Hoisting lines(rec.prompt) once per record makes it O(records + transcripts) flattens instead of O(records × transcripts) — at round 5 with 6 chunks that is ~24 flattens instead of ~576, on the critical path before the round is admitted.


Smaller notes

  • substantiveClause is doing less work than its doc suggests. DRY_RECEIPT_RE's capture group is [\s\S]* — everything after the separator to end-of-text — so the 20-character floor at retirement.ts:226 is met by essentially any multi-sentence return. The real teeth are diffToolCalls > 0 + openedTheTerritory, which is fine; the comment just reads as if the clause bar carries more of the load than it does.
  • The parrot refusal is wrap-fragile. EXAMPLE_RECEIPT_CLAUSE (retirement.ts:198) is only .trim()ed, while the candidate clause is whitespace-collapsed before the includes test. The constant is one line today; if it is ever hard-wrapped in agent-briefs.ts the refusal silently stops matching (fail-open, but silently). One .replace(/\s+/g, ' ') on the constant makes it wrap-proof.
  • Two fences, two epochs. readRecordedPrompts' fence is the exact plan mtime (prompt-record.ts:176), while readRoundStamps/readBudgetStop use mtime - RUN_EPOCH_SLACK_MS. Both sides here are file mtimes, so the fractional-vs-integral skew the slack absorbs doesn't apply — correct as written, but worth half a sentence so the next reader doesn't "fix" the inconsistency in the wrong direction.
  • expectedRoundSeconds' max-span sticks to a one-off outlier. Switching from newest-span to costliest-span is the right failure direction, but a round 1 that was slow for a reason that won't recur (cold start, a repair relaunch) now prices every remaining round for the rest of the loop — and a budget stop caps the verdict at COMMENT. Consider the max of the last two spans, or excluding round 1, to keep the safety without pinning to an outlier. Not a blocker; just note it pushes in the opposite direction from the PR's headline goal.
  • The (cold check) separator tag is new and never explained to the orchestrator. The SKILL bullet describes cold checks conceptually, but the model is separately told to translate separator labels into the Agent description — and it will now see a label it wasn't told about. One clause ("a block tagged (cold check) is launched exactly like any other") removes the ambiguity.
  • Exit 5 is documented in the CLI describe and the SKILL only. If any doc under docs/users/features/ enumerates agent-prompt's exit codes it should learn about 5; I didn't find one, so this is probably a no-op.

中文摘要

上一轮的两个 Critical 与 Suggestion 3/4 在本 head 已全部关闭并有测试固定;injectivity 反向成"每条 transcript 匹配几条 record"是比原建议更正确的方向。

需要在合并前定夺的一条:converged 被 parity 卡住(retirement.ts:472/497)——所有 chunk 在第 3 轮拿到证书时,第 4 轮(偶数轮)仍会全量冷抽查一整轮,而 main 在第 3 轮就已按"连续两轮干净"停止。这一形态下比现状多跑一整轮扇出(基准上约 6 个 auditor / 20 分钟),恰好发生在收敛最早、最不该多跑的运行上。建议:先分类全部 chunk,全部退休即 converged: true(与 parity 无关),冷抽查只在仍有热区时才需要。同时把 SKILL 里"连续两轮干净"到底归 3A 还是 3B 说死。

第二条:— [unverified] 标记是 Change 2 唯一的安全支点,却完全没有 CLI 兜底——compose-review 只有"是否跑过 verifier"的下限判断,没有逐条概念。整个子系统的前提就是不信任 orchestrator 的散文约定;建议让 compose-review 机械地拒绝把仍带该标记的条目计入 confirmed 集合。

其余为建议与小注:territory 从 prompt 回解析仍有同路径注入残留(建议直接取 plan 的 chunk range)、配对遍历只提升了一半的 flatten、substantiveClause 的实际强度弱于注释、parrot 拒绝对换行脆弱、两处 mtime 栅栏的 epoch 不一致值得注一句、expectedRoundSeconds 取最大跨度会被一次性离群值长期钉住、(cold check) 标签没在 SKILL 里向 orchestrator 交代。

未运行测试套件;以上均为静态审阅,每条都标了对应代码位置。

@wenshao

wenshao commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator Author

All 16 review threads verified against the current head (49e4f1e66d) and resolved — no new commit was needed: the three autofix commits (c11df3b81f guard-split tests, 80d4d93961 classifier hardening + gate-ordering pins, 49e4f1e66d territory bound to the diff path + note repricing) already close every one of them, including the full-width-colon Critical and both SKILL semantics items (unconditional merges; the surviving [unverified] tag now relaunches once and then caps via unreviewedDimensions).

The verification was empirical, not archival: each thread's originally-surviving mutant was re-applied to head — all 16 die to exactly the test the thread asked for — and the affected suites plus the full src/commands/review/ (1775 passed / 1 skipped, 53 files) ran green, eslint clean. Per-thread evidence is in each resolved thread.

Worth noting for the record: 49e4f1e66d also caught and closed an injection hole in its own predecessor's territory check (findings prose quoting offset=N, limit=M could widen the dry bar) — the loop is reviewing itself, and this round it was right.

— via Claude Code (claude-fable-5)

doudouOUC
doudouOUC previously approved these changes Aug 5, 2026

@doudouOUC doudouOUC left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Re-reviewed at 49e4f1e66d — my two Warnings from the previous round are both genuinely fixed. I verified the code rather than taking the commit title's word for it, since a fix title is a claim.

Warning 1 (findings prose widening the retirement territory) — fixed, and fixed at the right layer. bakedRanges now takes the diff path and requires the whole call shape, matching read_file(file_path="…", offset=N, limit=M and skipping any hit whose file_path is not the diff. My original injection vector was a bare offset=N, limit=M anywhere in the folded findings list, and that no longer matches anything. Binding to the diff read is the stronger of the two options I suggested — it fixes the cause rather than narrowing the scan window.

I also checked the new failure mode that a diffPath-gated territory introduces: diffPath === undefined now yields an empty territory, and openedTheTerritory returns true on an empty territory, so the territory check goes trivially true. That does not fail open, because classifyReturn requires rec.diffToolCalls > 0 as a separate conjunct on the same condition, and diffToolCalls is zero precisely when the diff path is missing. The chunk stays hot. Good that the two guards are independent.

The residual is much narrower than before but not quite zero: a finding whose prose quotes an auditor's tool call verbatim, with the run's actual diff path inside it, would still contribute a range. That needs the exact temp path in a finding's text, so I am not treating it as actionable — noting it only so the narrowing is on record as narrowing rather than elimination.

Warning 2 (the consumed budget margin) — fixed by repricing the estimator. expectedRoundSeconds no longer prices a round from the most recent span. It now filters the current round's stamps, walks every consecutive stamp pair, and returns the maximum observed span. That directly resolves the odd/even concern I raised: round 4's full fan-out is now priced against the largest span seen, which includes the always-full-fan-out rounds 1 and 2, instead of against the shrunken round 3. It also keeps the "round costs trend UP" reasoning in the comment honest, because a max is monotonic in the observations.

DEFAULT_RESERVE_SECONDS stays at 3600, which is fine — I had suggested max-pricing or a larger reserve, and pricing from the max is the better-targeted of the two since it fixes the estimate rather than padding around it.

Both changes come with tests (retirement.test.ts +50, deadline.test.ts +21, agent-prompt.test.ts +39), and CI is green on this exact SHA: run 30972342118 has head_sha=49e4f1e6.

Approving. The three still-open threads are all [Suggestion]-level test-coverage notes from the bot, with no unresolved Critical among them.

For completeness, my two lower-severity notes from last round still stand and remain non-blocking: nextColdCheck: round + 1 can still print a round the 5-round cap forbids, and SKILL.md still describes the [unverified] tag as "structurally excluded" when no code parses it.

@wenshao

wenshao commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator Author

@qwen-code /triage

@qwen-code-ci-bot

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

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

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

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

Verification report

PR 8498 verification (round 4) — merge-ready (177/177 scripted assertions passed)

Verified head: 49e4f1e66d06acff4567986e9658a16eb195fb04 (git rev-parse HEAD^2), merge commit b1a64c267, base tip 8b0e8b8192c2b2fd5ef26ff4e61996c13fd797ea (HEAD^1). The metadata snapshot's baseRefOid (d2c7cb1) has drifted behind the actual base; the local tree is authoritative. The snapshot lists 4 commits; only the head is reachable under the depth-2 graft (git rev-list HEAD^1..HEAD^2 = 1), so the aggregate HEAD^1..HEAD diff (2320 insertions / 99 deletions, 9 files — TS in packages/cli only, plus SKILL.md in packages/core) was verified and per-commit attribution is listed under Not covered. This round's delta over round 3 is the newest commit 49e4f1e66 ("bind the retirement territory to the diff read and reprice the budget gate"); it was isolated by reading and probed directly, but not diffed against 80d4d93 (unreachable).

中文摘要
  • 判定:merge-ready。177 条脚本断言全过(A/B 114 + 单元探针 15 + C14 复测 22 + 突变矩阵期望 16 + M2/M5 反事实 6 + T2 候选修复探针 3 + 套件门禁 1),无意外失败,无新阻塞发现。
  • 上一轮发现状态(全部在新 head 复测,见状态表):F1 全角冒号修复仍在(字节+行为+突变三面验证);M4 的 diffToolCalls > 0 钉死仍在(M3 突变行);M7 阳性对照仍在;M10 bare-subject 去重分支仍无钉(compose-review 不在本 PR diff 内,完整性记录);C14 预算披露主题碰撞在新 base/head 双臂 11/11 平价、仍修复。
  • 中心主张 A/B 成立(witness 01-ab-head-central-flips.png / 02-ab-base-controls.png):base(8b0e8b8192)每轮全量扇出、统一预算闸、按最新 stamp 计价;head 自第 3 轮起退休连续两轮实质干净的 chunk、偶数轮冷抽查、whiff/拼接攻击/越界读回审计方向、无 transcripts 全量回退;收敛 exit 5 优先于预算闸且不写 marker;已盖章轮的 --chunk 修复绕过过期闸(base exit 4 → head exit 0 翻转 ×2)。
  • 本轮新增两半均已验证:①领地绑定——findings 中引用其他文件read_file(file_path=…, offset, limit) 不再注入领地(T1 + M2 突变翻转证明该从句 load-bearing);diffPath 缺失时一切 unknown、无人退休(U2)。②预算改价——expectedRoundSeconds 按运行中最贵的连续 stamp 跨度计价而非最新(编译产物直接探针:head 1800/1800 vs base 1200/600;A/B 翻转 ×2,平价 ×4)。
  • 门禁src/commands/review 在 head 全绿——1890 过 | 4 跳过(1894,56 文件),4 个 skip 为既有环境门禁。突变矩阵 16/16 期望符合,阳性对照(retirement 全关 → 14 红)证明套件非空转。
  • 新发现(均非阻塞):T2 有界残余——findings 引用指向 diff 路径本身的 read 窗口仍可注入领地(已在真实 CLI 复现;测得候选修复:把扫描锚定到 builder 自己的 brief 行之后,T2 转热、T1/T3 零副作用);M2 覆盖缺口——路径绑定从句无任何套件 fixture 钉死(PR 自己的两个测试用的都是不带 file_path 的引用,结构上不可能命中该从句);M5 覆盖缺口——overlap 与 containment 之别无钉(fixture 恰好全是被包含读;测得了能钉死的越界 fixture);M4' 死从句——successfulToolCalls > 0diffToolCalls > 0 逻辑蕴含,删之无任何行为变化。
  • 未覆盖:Change 2(SKILL.md 流水线化)为编排散文,仅文本核对;仓库级 lint/typecheck 未跑;4 个提交仅 head 可达,按提交归因不可行;合成 transcripts 验证的是处理形状而非真实模型行为;zh-fold 通道未测(C14 用 EN 通道复测)。

Previous-finding status (follow-up round — round 4, re-measured at head 49e4f1e66, not diffed)

# Round-3 finding Severity Status at the new head (re-measured)
F1 Fullwidth-colon receipts never classify as dry Suggestion (bounded) Fixed — stands. Byte-level: compiled dist separator class contains 0x3a 0xff1a (U5, both checks). Behavioural: fullwidth-colon zh receipt retires through the real CLI (GzhFull, exit 5 vs 3 built on base), ASCII-colon parity (GzhAscii), six separator variants all retire through the compiled scheduler (U6 ladder 6/6). Pin: reverting the class to [::] (M1) turns exactly a Chinese receipt separated by a full-width colon is dry red.
M4 (r3) diffToolCalls > 0 clause unpinned Coverage gap Pinned — stands. Deleting the clause (M3) turns exactly successful calls that never touched the diff are not dry — the two guards are independent red. Refinement found this round: the SIBLING clause rec.successfulToolCalls > 0 is dead code — see Findings #4.
M7 (r2/r3) Marker-vs-relayed dedupe unpinned Coverage gap Pin re-confirmed live. Disabling the BUDGET_STOP_PHRASE splice (M7) turns exactly a budget-stop marker caps APPROVE at COMMENT with nothing relayed by the caller red (1 red), with the suite otherwise green (161 tests).
M10 Bare-subject dedupe branch unpinned (compose-review) Coverage gap (not a merge condition) Stands. Removing d === e.subject || leaves compose-review.test.ts green (161/161); suite liveness proven by the M7 row above. File untouched by this PR's diff — carried completeness reporting.
C14 (r1; fixed in main) Budget-stop disclosure dropped on reverse audit subject collision Suggestion (bounded) Still fixed at the moved base/head. Re-measured through the real compiled review compose-review on BOTH arms (witness 06-c14-collision-parity-both-arms.png): collision / marker-only / relay-only cells each render the disclosure exactly once, the sibling scope chunk 2's auditor returned nothing substantive twice survives the collision, verdict capped at COMMENT — 11/11 per arm, identical. EN channel only this round (plan prDescriptionHasHan: false); see Not covered.

Central claim + A/B

Central claim (this PR): from round 3, agent-prompt --all-chunks is the loop's scheduler — a chunk whose two most recent audits were substantive dry receipts (receipt names what it examined AND the transcript shows the chunk's baked territory was opened) is retired to alternating even-round cold checks, returns to every-round auditing on any yield, and an all-retired round exits 5 (CONVERGED) with nothing built, recorded, or stamped; every classification failure falls toward auditing. Round-4 additions verified: the baked territory is bound to reads aimed at the diff path (both the record side and the transcript side), and the budget gate prices the round from the COSTLIEST measured admission-to-admission span instead of the newest stamp.

Both arms drive the real compiled CLI (packages/cli/dist/index.js review agent-prompt …) over synthetic 3-chunk review states (territories 1001-1200 / 2001-2200 / 3001-3200 of a real 4500-line diff file); history is established by running each arm's own builder for rounds 1–2 and delivering harness-shaped JSONL transcripts whose launch prompts are byte-for-byte copies of the CLI's own recorded blocks. Base = tmp/base-tree at 8b0e8b8192 with packages/cli rebuilt there (control-cleanness in Methodology). Table 1 — head 67 + base 47 assertions, all passed (base-control behaviors are asserted expectations, not failures; each arm re-run once under the capture with identical counts). Witnesses: 01-ab-head-central-flips.png, 02-ab-base-controls.png.

Cell Scenario base 8b0e8b8192 (control) head 49e4f1e66
C1/C2 rounds 1–2, any history 3 auditors, exit 0, stamped identical PASS
C3 all chunks dry ×2 → r3 3 built, exit 0 exit 5 CONVERGED, 0 built, 0 records, no stamp, no marker PASS
C4 chunks 1,2 dry ×2, 3 yielded ×2 → r3 3 built 1 built (chunk 3); note retires 1,2 (dry in rounds 1 and 2, next cold check round 4); records = [3]; stamped PASS
C5 same history → r4 (even) 3, no tags 3 built; chunks 1,2 tagged (cold check) in separator only — tag never enters recorded prompts PASS
C6 chunk 2 whiffed r2 (bare receipt, 0 calls) → r3 3 1 built ([2]); note retires 1 and 3, not 2 PASS
C7 ONE transcript carrying all three r2 records → r3 3 3 (concat attack certifies nothing) PASS
C8 transcripts dir absent → r3 3 3 (fail open, exit 0) PASS
C9 expired deadline, round still due → r3 exit 4, BUDGET line, marker r3, nothing built/stamped identical (gate reorganization behavior-preserving) PASS
C10 expired deadline + all-retired → r3 exit 4 + marker exit 5, no marker — convergence outranks the gate PASS (flip)
C11a --chunk 2 --round 2 of a stamped round, expired exit 4 + marker (uniform gate refuses the repair) exit 0, prompt rebuilt, stamp count unchanged PASS (flip)
C11b --chunk 2 --round 4 unstamped, expired exit 4 exit 4 (unadmitted round gated like --all-chunks) PASS
C11c --chunk 2 --round 3 unstamped + all-retired, expired exit 4 + marker exit 5 CONVERGED, no marker PASS (flip)
C12a/b round-1 constant pricing: remaining 2600 / 2000, reserve 600 exit 0 / exit 4 identical PASS
C15 plan re-captured after dry ×2 → r3 3 3 (stale records + transcripts fenced) PASS
P1 stamps 50/20 min old (spans 30/20), remaining 2100, reserve 600 exit 0 (prices newest = 1200s) exit 4 + marker (prices costliest = 1800s) PASS (flip)
P2 / P2b spans below the 600s floor / newest IS costliest admit admit (parity) PASS
P3 stamps 60/40/10 min old — the MIDDLE span is costliest (30 min), remaining 950, reserve 300 exit 0 (prices newest = 600s) exit 4 + marker (prices middle = 1800s) PASS (flip)
P4a/b single stamp: remaining 1520 / 1400 exit 0 / exit 4 identical PASS
T1 findings quote read_file(file_path="src/pay.ts", offset=0, limit=50); auditors read only diff 1-50 ×2 3 built 3 built, no retirement note — the other-file quote does not widen the territory PASS
T2 findings quote the window aimed at the DIFF path itself (residual probe) 3 built exit 5 — still injects (Finding #1) measured
T3 same other-file noise, auditors read the baked territory ×2 3 built exit 5 — real reads retire beside noise PASS
GzhFull / GzhAscii zh receipts, fullwidth / ASCII colon ×2 3 exit 5 / exit 5 (width parity, F1 carried) PASS
Gparrot r2 = the brief's own example receipt 3 hot (parrot refused) PASS
Gbacktick / Gandor stray backtick / and/or clause 3 hot PASS
Gspan / Gpath enclosed span / dotted path clause 3 exit 5 PASS
GterritoryOut only diff read lands OUTSIDE the baked territory 3 hot PASS
GterritoryOverlap half-read overlapping the territory 3 exit 5 PASS
GechoFileOnly / GechoFull File echo without Severity / whole-entry quotation 3 exit 5 PASS
GrealYield files File+Severity for a file NOT in the launch prompt 3 hot PASS

Unit probes against the compiled modules (witness 03-repricing-costliest-span-units.png): head expectedRoundSeconds prices P1 and P3 at exactly 1800s, single-span 900s, no-stamps 1800s; base prices 1200s / 600s / 900s / 1800s (U1, 8 assertions). scheduleReverseAuditRound with diffPath === undefined: every transcript classifies unknown, nothing retires (U2); known diffPath but no baked read falls back to "opened the diff at all" (U3), and other-file-only reads stay hot on the diffToolCalls > 0 clause (U4); a read_file with no limit carries no range and opens no territory (U7).

Skipped chunk-rounds write no prompt records (C4: records = [3] only), so the coverage roster owes nothing for retired chunks — the check-coverage interplay claim holds by construction.

Corrections

None this round. Round 3's note on the drifted snapshot baseRefOid applies again in updated form (snapshot d2c7cb1, actual base 8b0e8b8192); the snapshot's commit count (4) matches the PR's real history but only the head is locally reachable.

Findings

1. T2 residual — findings prose quoting a read window aimed at the DIFF PATH ITSELF still injects the baked territory. Suggestion (bounded).
The new commit binds the territory scan to the diff path — closing other-file quotes (proven: T1 hot on head; deleting the clause flips T1 to retired, witness 05-m2-path-clause-counterfactual.png). But a folded findings entry quoting read_file(file_path="<the diff's own path>", offset=0, limit=50) still lands in bakedRanges, and any-overlap-passes then retires chunks whose territory was never opened. Reproduced end-to-end (cell T2): all three chunks exit 5 CONVERGED although every auditor only ever read diff lines 1-50 of territories 1001-1200 / 2001-2200 / 3001-3200.
Bounds: requires a finding that quotes a read_file call with the diff's exact absolute scratch path AND auditors whose only diff reads stay inside the quoted window AND two substantive receipts — and cold-check rotation still revisits retired chunks on even rounds. The failure direction is early retirement (the direction the module's header says it never fails), not fabricated evidence.
Measured candidate fix (applied in a scratch copy, rebuilt, driven through the same probes):

 function bakedRanges(
   prompt: string,
   diffPath: string | undefined,
 ): Array<[number, number]> {
   const out: Array<[number, number]> = [];
   if (diffPath === undefined) return out;
+  // The record is the FOLDED launch prompt — the cumulative findings list
+  // rides above the builder's own text, which always opens with the brief
+  // line; a finding quoting a read aimed at the diff would otherwise inject
+  // its window into the territory. Scan the builder's section only.
+  const briefLine = prompt.lastIndexOf('**Your brief is a file.');
+  if (briefLine !== -1) prompt = prompt.slice(briefLine);
   for (const m of prompt.matchAll(

Results: hostile T2 fixture goes hot (code=0 blocks=3), benign fixtures byte-for-byte unaffected in behavior (T1 still hot, T3 still exit 5 — zero collateral). The suite is green both with and without the patch territory-wise (no fixture exercises this axis — see #2), so the fix should ship with a T2-shaped fixture. (First cut anchored on ## The diff and was inert — reverse-audit prompts carry no such heading; verified against a real recorded prompt before the second cut.)

2. M2 coverage gap — the path-binding clause is load-bearing but unpinned.
Deleting if (m[1] !== diffPath) continue; survives BOTH retirement.test.ts (37/37) and agent-prompt.test.ts (185/185), yet flips T1 from hot to retired in the compiled CLI (witness 05-m2-path-clause-counterfactual.png) — the clause decides real behavior no test asserts. Root cause: the PR's own fixtures cannot reach it — findings prose quoting a read window cannot widen the territory (both the unit and handler variants) uses a quote with no file_path at all (read_file(offset=0, limit=50) / bare prose used offset=0, limit=50), which the bakedRanges regex never matches with or without the clause. The pinning fixture is a decoy WITH file_path="src/pay.ts" (the T1 shape). The test names claim exactly this coverage; the inputs do not deliver it.

3. M5 coverage gap — overlap-vs-containment is unpinned.
Turning the overlap bar s <= te && ts <= e into containment s >= ts && e <= te survives retirement.test.ts green (37/37): every fixture read happens to be CONTAINED in the territory (the overlap test pages with offset=1100, limit=50 inside 1001-1200). Measured counterfactual in the compiled mutant: an overhanging read [1150,1249] over territory [1001,1200] retires on head (overlap is the bar) but stays hot on the containment mutant — a fixture with that overhang would pin the semantics the code comment promises ("an honest auditor pages an oversized chunk, and each page overlaps the territory even though no single read holds it all").

4. Dead clause — rec.successfulToolCalls > 0 in classifyReturn can decide no outcome.
diffToolCalls only increments inside the success branch that also increments successfulToolCalls, so diffToolCalls > 0 ⟹ successfulToolCalls > 0; deleting the clause survives green (37/37, M4 row) and no input can separate them. Introduced by this PR's new file — either remove it or leave it as documented belt-and-braces; either way it is not a pin-able guard. This refines, not contradicts, round 3's M4 row (which was about the sibling diffToolCalls > 0 clause — that one is live and pinned, M3 row).

5. Carried M10 — the bare-subject dedupe branch in compose-review.ts remains unpinned (161/161 green after deletion; liveness proven by the M7 splice control). Outside this PR's diff; completeness reporting, not a merge condition. It is the axis C14's collision rode, so a fixture remains worth adding when convenient.

Considered and dismissed: classifier scaling (receipts are model returns read from harness transcripts and the CLI's own records — not outsider-authored text; the regexes are linear: bounded lazy fillers, one greedy tail); the workflow-reserve sync claim in the new deadline.ts comment (verified true: qwen-code-pr-review.yml caps the scaled reserve at 3600 = DEFAULT_RESERVE_SECONDS); the budget-stop marker's missing expectedRoundSeconds field (the refusal arithmetic was pinned instead via the compiled expectedRoundSeconds probes, U1).

Not covered

  • Change 2 (verification pipelining) has no behavioural oracle — it is orchestrator prose in SKILL.md. Checked textually only: the load-bearing orderings survive the rewrite (the last round's verification completes before Step 6; entries still tagged — [unverified] are structurally excluded from Step 6's confirmed-only read; the Step 5 merge runs unconditionally before every round build and before Step 6; a verifier-never-ruled entry caps a would-be Approve at COMMENT via unreviewedDimensions; CONVERGED exit 5 is a clean termination owing no entry; the gate prose now says "costliest round's measured cost … not the newest dip", matching the measured pricing). The projected 95→55-minute saving is the author's arithmetic, not measured here. The retirement prose in SKILL.md matches the measured cells (odd rounds shrink, even rounds cold-check all retired chunks together, the note rides after the end-of-round line).
  • Gates: only the affected workspace suite ran — src/commands/review at head: 1890 passed | 4 skipped (1894, 56 files), exit 0. The 4 skips are pre-existing environment gates (1 skipIf(!caseInsensitiveFs) in save-artifact.test.ts, 3 describe.skipIf(!hasShellcheck) in script-lint.test.ts). Repo-wide lint/format/typecheck not re-run.
  • Per-commit attribution out of reach: the snapshot lists 4 commits; the depth-2 graft reaches only the head (git rev-list HEAD^1..HEAD^2 = 1, shallow). The aggregate HEAD^1..HEAD diff was verified; the three earlier commits (0cf3170, c11df3b, 80d4d93) were not individually exercised — round 3's measurements of 80d4d93 were carried forward only through re-measurement at the new head, never by trust.
  • Base-arm build noise is environmental, not an arm difference: the base worktree's from-scratch tsc --build reports the same 223-line type-error class as round 3 (mime/lite, fdir, ignore, ajv subpaths, @testing-library/react against the shared node_modules types); the emitted JS is complete and behaviorally pre-PR in exactly the expected directions (help text carries exit 0/4 only; all 47 base control cells reproduce pre-PR behavior; retirement.js absent from base dist, grep -c scheduleReverseAuditRound|CONVERGED 0 vs 5). The mut-tree build shows the same noise class.
  • Synthetic transcripts, not model behaviour. The A/B proves the scheduler's handling of every receipt shape; it does not reproduce real auditor degradation (shape, not cause).
  • C14 measured on the EN channel only (plan prDescriptionHasHan: false; the zh fold needs a live PR-body fetch this sandbox cannot make). The structural entries both languages render from are the same objects the EN assertions covered.
  • Budget-boundary exactness: P4 cells avoid the remaining == reserve + estimate knife-edge (±1 s of clock drift between harness and CLI would flip it); both sides of the boundary are covered with slack instead.
  • No injection attempts observed in the PR title/body/commit messages; they were treated as untrusted claims and tested, not followed.

Methodology

Environment: node:22-bookworm container, npm ci + npm run build pre-run at the merge commit. Base control: git worktree add tmp/base-tree HEAD^1, packages/cli rebuilt there via scripts/build_package.js (tsc project references emit packages/core too); internal workspace links re-pointed — tmp/base-tree/node_modules/@qwen-code/qwen-code-core → ../../packages/core (base tree), all other @qwen-code/* → head-tree packages (their sources are untouched by the PR — git diff HEAD^1..HEAD --name-only shows TS only under packages/cli plus SKILL.md), per-package third-party node_modules symlinked (lockfile unchanged, so byte-identical). Control cleanliness asserted: import.meta.resolve('@qwen-code/qwen-code-core', …/base-tree/packages/cli/dist/index.js)file:///__w/qwen-code/qwen-code/tmp/base-tree/packages/core/dist/index.js (realpath inside the base tree); base CLI help text lacks the CONVERGED exit; base dist contains no retirement module. Every A/B / C14 / probe cell spawns the real compiled CLI as a child process with per-cell state dirs (QWEN_CODE_PROJECT_DIR/QWEN_CODE_SESSION_ID); transcripts are JSONL in the harness's format with launch prompts copied byte-for-byte from the CLI's recorded blocks so deliveredVerbatim pairing is honest. Unit probes import the compiled dist modules directly. Mutations ran in tmp/mut-tree at the merge commit (exact single-occurrence string replacements, occurrence count enforced, restored via git checkout and git status --porcelain verified empty after each run); dist counterfactuals (M2, M5, T2 fix) rebuilt incrementally with tsc --build. Counts: 114 (A/B: 67 head + 47 base) + 15 (unit probes incl. U7) + 22 (C14 both arms) + 16 (mutation-matrix expectations incl. 3 baseline greens and the POS/M7 positive controls) + 4 (M2 flip probes) + 2 (M5 overhang) + 3 (T2 candidate-fix probes; the residual itself is measured by the T2 cell inside the A/B count) + 1 (suite gate) = 177, of which 0 failed; the A/B arms and the matrix were each re-run once under scripts/verify-capture.mjs with identical counts (witnesses 01/02/04). Raw per-cell logs in logs/ (ab-*-results.json, ab-*-cap.json, unit-*.json, c14-*.json, mutations.json + per-mutant mut-*.log, m2-cap-*.json, t2-fixed*.json, suite-head.log, base-build.log, mut-tree-dist-build.log), harnesses in harness/ (common.mjs, ab.mjs, unit-probes.mjs, c14.mjs, mutations.mjs, t1-probe.mjs, t2-probe.mjs, overhang-probe.mjs, m2-capture.sh), evidence images in evidence/.

Evidence images

01-ab-head-central-flips

02-ab-base-controls

03-repricing-costliest-span-units

04-mutation-matrix-all-guards

05-m2-path-clause-counterfactual

06-c14-collision-parity-both-arms

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

Qwen Code · sandboxed verification

@wenshao

wenshao commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator Author

consider pricing from max(observed spans)

Confirmed — and it's already in at the current head: 49e4f1e66d ("… and reprice the budget gate") changed expectedRoundSeconds from last-span to max over consecutive admission spans, trailing open span included (deadline.ts), for exactly the oscillation you name: retirement makes the odd rounds cheap, the even rounds bring every cold check back, and pricing the next admission off a shrunk span re-opens the #8368 under-reserve direction from inside the optimization. The overshoot direction is the safe one — an over-priced round stops the loop one round early, disclosed, instead of being killed mid-flight.

Pinned by test: deadline.test.ts:210 builds the shrunk-round shape (round 3's open span 25 min, round 1's span 33 min) and asserts the estimate takes the max; the last-span regression fails it.

— via Claude Code (claude-fable-5)

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

Address-review summary — PR #8498 (round for @wenshao's review)

All five sections of the review were addressed; nothing declined, nothing escalated. Commit: fix(review): machine-check the unverified-tag backstop and reprice the tail reserve (#8498) (802a9c6).

§1 — The terminal round's verification loses its structural guarantee

Addressed, both halves.

Machine check (the primary ask): compose-review now takes findingsPath — the cumulative reverse-audit findings file at loop end — and reads it itself. Any surviving — [unverified] tag caps the verdict: an Approve becomes a Comment, and a Request changes softens to Comment under the same conditions as the existing criticals-unverified cap (non-deterministic blockers posted, no deterministic [build]/[test] Critical keeping it up). A path that does not read fails closed; an omitted field disables the check (every non-high run). The cap is disclosed in the body (both languages), named on the Verdict: line, and gets a FIX: remediation line. The check sits in composeReview itself, so submit re-applies it from the same state at posting time. New cap key: findings-unverified-at-compose, with 8 new tests in compose-review.test.ts.

SKILL wording: the 5-round-cap bullet now says explicitly that round 5's verifiers have NOT launched (that launch rides the next round's build, which the cap forbids) and must be fired alone before Step 6; the two-dry-rounds bullet says the last reporting round's verifiers are already in flight and their verdicts must land in the final merge before Step 6; the CONVERGED bullet carries the parenthetical that it cannot owe a verification launch (a reporting round makes its chunk hot); the tag backstop paragraph and the pipelined bullet now name the compose-review machine-read.

§2 — DRY_RECEIPT_RE rejects a markdown-bolded phrase

Addressed. The separator now admits closing emphasis/quotation ([*_)\]"”’]*) between the phrase and the dash/colon, and the filler admits parentheses for the scope-label form (No new issues found (chunk 13) — …), exactly the reviewer's suggested character class plus the optional widening they flagged. Three new regression tests in retirement.test.ts pin the bolded English form, the bolded Chinese form (**未发现新问题** —— …), and the parenthesised scope.

§3 — The budget gate is more permissive and the reserve did not move

Addressed via the reviewer's fallback. The repo's record of #8368 carries no measured tail upper bound — only that the loop ended with half an hour left and the outer kill found verification still running (>30 min consumed, compose/anchor-resolution/submission never started). Nothing to quote, so the insurance option applies: the workflow's divisor moved from /4 to /3, and DEFAULT_RESERVE_SECONDS and the workflow cap moved 3600 → 4800 together (the cap mirrors the constant by contract; the existing mirror test enforces it), so the bump actually reaches the large-PR budgets where #8368 happened (at a 4h budget, /3 alone still capped at 3600). The DEFAULT_RESERVE_SECONDS comment now states the #8368 arithmetic explicitly: the size is insurance, not measurement — over-reserving ends the loop at most one round early (disclosed as a budget stop); under-reserving is #8368. Budget-gate tests whose arithmetic hardcoded the old reserve were updated (5500 → 7000 envelopes).

§4 — nextColdCheck can name a round the cap never reaches

Already fixed on the branch by the prior commit 49e4f1e: the retirement note is cap-aware — past the 5-round cap it prints certificate final — the 5-round hard cap leaves the loop no round for a cold check instead of a round 6 promise. Re-verified; pinned by a round-5 skip names the certificate final — the cap forbids round 6 in agent-prompt.test.ts.

§5 — Nits

  • One-sided hoist: addressed. prompt-record.ts now exports promptLines and a deliveredVerbatimLines core that takes both halves pre-flattened; retirement.ts hoists each record's lines beside the transcript-side flatten, so the pairing walk re-splits neither side.
  • bakedRanges anchoring: already fixed on the branch by 49e4f1e — ranges are only read off read_file(file_path="<diffPath>", …) calls anchored on the record's own diff path; a read of any other file contributes nothing. Re-verified; test coverage present (a diff read outside the baked territory is not dry).
  • Parrot comment oversells: addressed — the comment now says the refusal is verbatim-only, that real parroting is partial and passes this check, and that the rest of the dry bar (territory read, substance floor) is what catches it.
  • "same evidence the global two-dry-rounds rule demanded": addressed — the CONVERGED bullet now says "two consecutive dry audits, though not necessarily in consecutive rounds" with the concrete rounds-2-and-4 example, per the reviewer's suggested phrasing.
  • CONVERGED-at-round-3 framing: addressed — the bullet now says directly that exit 5 is mainly the CLI enforcing the stop the two-dry rule used to leave to orchestrator discretion, and that the new savings are the odd-round skips and a round-5 convergence.

Conflict notes

--conflict false; no merge performed.

Verification

  • npm run build — passed
  • npm run typecheck — passed
  • npm run lint — passed
  • cd packages/cli && npx vitest run src/commands/review — 54 files, 1788 passed | 4 skipped, 0 failed (includes 8 new tag-check tests, 3 new receipt tests, updated budget-gate arithmetic)
  • cd packages/core && npx vitest run src/skills/bundled/review/SKILL.test.ts — 4 passed
  • npx prettier --write on the changed files — applied, no diffs after re-verification
  • Integration tests after npm run bundle: not required — every touched behavior is exercised by direct unit tests of the command handlers above, not only through the bundled CLI or integration harness
  • Settings schema: not touched, no regeneration needed
中文说明

处理总结 — PR #8498(针对 @wenshao 评审的一轮)

评审的五个部分全部处理完毕;没有拒绝项,没有上报维护者的决策项。提交:fix(review): machine-check the unverified-tag backstop and reprice the tail reserve (#8498)(802a9c6bd)。

§1 — 末轮验证失去结构性保证

两半都已处理。

机器检查(主要诉求):compose-review 现在接受 findingsPath —— 循环结束时的反向审计累计发现文件 —— 并自行读取。任何残留的 — [unverified] 标记都会封顶判定:Approve 降为 Comment;Request changes 在与现有 criticals-unverified 封顶相同的条件下降为 Comment(发布了非确定性阻断项,且没有确定性的 [build]/[test] Critical 支撑原判)。路径读不到时向保守方向失败(封顶);省略该字段则关闭检查(所有非 high 档运行)。封顶会在正文中披露(双语)、在 Verdict: 行中点名,并附带 FIX: 修复行。检查位于 composeReview 本体,因此 submit 在发布时会用同一份 state 复核。新封顶键:findings-unverified-at-composecompose-review.test.ts 新增 8 个测试。

SKILL 措辞:5 轮上限条目现在明确说明第 5 轮的 verifier 尚未启动(该启动搭载下一轮的构建,而上限禁止下一轮),必须在 Step 6 前单独发射;两干净轮条目说明最后一个有产出轮次的 verifier 已在飞行中,其裁决必须在 Step 6 前落入最终合并;CONVERGED 条目加了括号说明:收敛不可能欠一次验证发射(有产出的轮次会使其 chunk 变热);tag 兜底段落与流水线条目现在点名 compose-review 的机器读取。

§2 — DRY_RECEIPT_RE 拒绝加粗短语

已处理。 分隔符现在允许收尾的强调/引号字符([*_)\]"”’]*)出现在短语与破折号/冒号之间;填充类允许括号以覆盖范围标注形式(No new issues found (chunk 13) — …),即评审建议的字符类加上其标注为可选的扩宽。retirement.test.ts 新增三个回归测试:加粗英文、加粗中文(**未发现新问题** —— …)、带括号的范围标注。

§3 — 预算闸更宽松而 reserve 未动

按评审给出的备选方案处理。 仓库对 #8368 的记录中没有尾部时长的实测上界 —— 只有:循环结束时剩半小时,外层 kill 到达时验证仍在运行(已耗时 30 分钟以上,compose/锚点解析/提交尚未开始)。无数字可引用,因此采用保险方案:workflow 除数从 /4 改为 /3,同时 DEFAULT_RESERVE_SECONDS 与 workflow 上限一起从 3600 → 4800(上限按契约镜像该常量,现有镜像测试强制约束),使加码真正到达 #8368 发生的大 PR 预算档(4 小时预算下,仅改 /3 仍会被 3600 上限压回)。DEFAULT_RESERVE_SECONDS 的注释现在明确写出 #8368 的算术:该值是保险而非实测 —— 预留过多至多让循环提前一轮结束(以预算停止披露);预留不足就是 #8368。硬编码旧 reserve 算术的预算闸测试同步更新(5500 → 7000 包络)。

§4 — nextColdCheck 可能报出上限到不了的轮次

分支上已修复(前次提交 49e4f1e):退休提示已感知上限 —— 超过 5 轮上限时打印 certificate final — the 5-round hard cap leaves the loop no round for a cold check,而不是承诺第 6 轮。已复核;由 agent-prompt.test.ts 中的 a round-5 skip names the certificate final — the cap forbids round 6 钉住。

§5 — 细节

  • 单侧提取:已处理。prompt-record.ts 现在导出 promptLines 与接受双侧预展平输入的 deliveredVerbatimLines 核心;retirement.ts 将每条记录的展平结果与 transcript 侧的展平并列提升,配对遍历不再对任何一侧重复切分。
  • bakedRanges 锚定:分支上已修复(49e4f1e66)—— 范围只从锚定到该记录自身 diff 路径的 read_file(file_path="<diffPath>", …) 调用中读取;读取其他文件的调用不贡献任何范围。已复核;测试覆盖在位(a diff read outside the baked territory is not dry)。
  • parrot 注释夸大:已处理 —— 注释现在说明该拒绝仅限逐字复读,真实复读是部分的且会通过此检查,真正兜住它的是干性门槛的其余部分(领土读取、实质下限)。
  • "与全局两干净轮规则同一份证据":已处理 —— CONVERGED 条目改为"连续两次干审计,但不一定在连续轮次",并给出 rounds 2 与 4 的具体例子,采用评审建议的措辞。
  • round 3 CONVERGED 的定位:已处理 —— 条目现在直说:exit 5 主要是 CLI 把过去留给 orchestrator 自由裁量的停止规则强制执行,真正的新收益是奇数轮跳过与 round 5 收敛。

冲突说明

--conflict false;未执行合并。

验证

  • npm run build — 通过
  • npm run typecheck — 通过
  • npm run lint — 通过
  • cd packages/cli && npx vitest run src/commands/review — 54 个文件,1788 通过 | 4 跳过,0 失败(含 8 个新 tag 检查测试、3 个新回执测试、更新后的预算闸算术)
  • cd packages/core && npx vitest run src/skills/bundled/review/SKILL.test.ts — 4 通过
  • 对改动文件执行 npx prettier --write — 已应用,复验后无新增差异
  • npm run bundle 后的集成测试:不需要 —— 所有触及的行为均由上述命令处理器的直接单元测试覆盖,并非只经由打包 CLI 或集成测试框架验证
  • 设置 schema:未触及,无需重新生成

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

@yiliang114 yiliang114 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Approved. This is the key review-perf change: per-chunk retirement turns full re-audit into evidence-based retirement + cold-check backstop, and pipelined verification shortens the critical path, without buying missed findings (fail-open throughout). Non-blocking follow-ups noted separately: deadline under-estimation after a shrunk round (price from max observed spans) and the prose-enforced [unverified] exclusion.

@doudouOUC doudouOUC left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Re-reviewed at 802a9c6bdd. My previous approval was on 49e4f1e6 and got dismissed when this commit landed, so here is a fresh one. Both of the non-blocking notes I left last round are now addressed, and I checked the fixes rather than the commit title.

The tail reserve is repriced in lockstep across all three places it lives. DEFAULT_RESERVE_SECONDS goes 3600 → 4800, the workflow's divisor goes attempt_timeout / 4/ 3 with its cap going 3600 → 4800, and the cross-file assertion in deadline.test.ts was updated to match the new expression. That last part is what I most wanted to see: this repo has a test that reads the workflow and pins the two sides together, so a one-sided edit would have gone red. It did not, because both sides moved. The rationale in the new comment is also honest about its own basis — the only tail ever measured was past 30 minutes and still running when the kill arrived, so the third is insurance until pipelined runs produce real tail measurements.

The — [unverified] backstop is now genuinely machine-enforced, and it fails closed. UNVERIFIED_FINDING_TAG_RE is counted against the findings file, a surviving tag pushes findings-unverified-at-compose into cappedBy, and if (event === 'APPROVE' && cappedBy.length > 0) event = 'COMMENT' gives the cap teeth. The part I specifically went looking for: an unreadable findings file sets findingsUnverifiedAtCompose = true rather than leaving it false, so a missing or unreadable file cannot be mistaken for "no tags." A malformed findingsPath throws a TypeError instead of being coerced. Both directions are right.

I also confirmed the bakedRanges diff-path binding from the previous round is untouched by this commit, so Warning 1 stays fixed.

CI is green on this exact SHA: run 30979862814 has head_sha=802a9c6b.

Approving. Two Suggestion-level observations, neither blocking:

The backstop's invocation is still prose-driven, even though the check is now machine-driven. The whole block is gated on if (findingsPath !== undefined && findingsPath !== null). Omitting it is correct at medium and low, which run no Step 5 and have no findings file — SKILL.md says so explicitly. But at high effort nothing enforces that it was passed: if the orchestrator forgets, the check silently does not run and the guarantee reverts to prose, which is exactly what this commit set out to replace. Worth noting that verification is already in scope a few dozen lines above this block, so "reverse audit rounds ran but no findingsPath was supplied" is a state compose-review can already detect and refuse. Closing that would make the backstop unbypassable rather than opt-in.

A loosening of DRY_RECEIPT_RE rode along in this commit. The phrase class gained () and a run of [*_)\]"”’] is now allowed before the separator. That makes a dry receipt easier to match, which is the fail-open direction in the retirement path — a false match skips audits, whereas a missed legitimate receipt only costs a re-audit. It is bounded, since substantiveClause still gates the clause and diffToolCalls > 0 plus openedTheTerritory remain independent conjuncts, and accepting **no new issues** — … is clearly the intent. Flagging it only because a change that widens the retire path arrived in a commit titled for the reserve and the tag check, where a reader would not look for it.

@wenshao
wenshao added this pull request to the merge queue Aug 5, 2026
Merged via the queue into main with commit 6d4d9b5 Aug 5, 2026
49 of 50 checks passed
@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Released in v0.21.6.

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.

6 participants