Skip to content

fix(serve): Release managed session writer locks on shutdown - #7812

Merged
doudouOUC merged 5 commits into
mainfrom
agent/7752-managed-session-writer-shutdown
Jul 28, 2026
Merged

fix(serve): Release managed session writer locks on shutdown#7812
doudouOUC merged 5 commits into
mainfrom
agent/7752-managed-session-writer-shutdown

Conversation

@doudouOUC

Copy link
Copy Markdown
Collaborator

What this PR does

This PR adds cooperative shutdown for daemon-managed ACP children. On the first shutdown signal, session and turn admission close synchronously, all transcript work accepted before that cutoff drains, exact-owned writer locks are retired atomically, and SessionEnd hooks and remaining resources are cleaned up only after the writer phase has settled.

It also tracks every ACP child spawned for primary, secondary, and dynamically added workspace runtimes on one daemon-scoped shutdown timeline. Shutdown sends SIGTERM immediately, escalates to SIGKILL after 5 seconds, requires raw process reaping within 10 seconds, and remains unclean if a child exits nonzero, exits by signal, or cannot be confirmed reaped. Partial channel construction and overlapping live-channel teardown now join those same terminal outcomes before returning.

Managed acquisition intentionally never reclaims an existing writer lock from hostname, age, or container-visible PID evidence. Standalone ACP keeps its existing local stale-owner recovery behavior.

Why it's needed

A managed daemon replacement can start on a different hostname while the previous ACP child still owns a v1 session writer lock. If that child is terminated without cooperative cleanup, the replacement cannot safely prove that the foreign-host owner is dead and returns session_writer_conflict indefinitely.

Automatically stealing by lock age or hostname would be unsafe when two Pods overlap on the same workspace. This P0 fixes the normal termination path by making lock release an acknowledged part of managed child shutdown while preserving the existing fail-closed behavior whenever flush, integrity, ownership, or process-reaping evidence is uncertain.

Reviewer Test Plan

How to verify

  1. Start a bundled qwen serve, create persisted sessions that hold writer locks, and send SIGTERM while at least one session remains live. Confirm that new session/turn admission closes, accepted transcript writes finish, every primary writer lock disappears, the ACP child exits with code 0, and a replacement daemon can load and append to the sessions without session_writer_conflict.
  2. Repeat with an injected transcript flush or lock-release failure. Confirm that shutdown is reported as incomplete, the child does not acknowledge a clean exit, the primary lock is retained when ownership is uncertain, and the replacement continues to return the conflict instead of creating a second writer.
  3. Run a child that ignores SIGTERM. Confirm that the parent sends SIGKILL at about 5 seconds, reports the signal exit as unclean, and keeps the 10-second not-reaped deadline stable across repeated shutdown calls.
  4. Exercise primary, secondary, and dynamically added workspace runtimes plus a partial channel-construction failure. Confirm that all spawned children are tracked before publication, construction does not return before teardown settles, and one failed channel cannot make bridge shutdown return while another live channel is still being reaped.
  5. Automated verification on the exact commit: core writer/config tests passed 520 with 1 skipped; ACP bridge/process tests passed 487; ACP agent and serve tests passed 524; full build, typecheck, and lint passed. A real managed-ACP harness created three live writer locks, then released all 3/3 and exited cleanly about 266 ms after SIGTERM, well before the 5-second escalation deadline.

Evidence (Before & After)

N/A — daemon lifecycle and persistence behavior only; no TUI or Web UI changes.

Tested on

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

Environment (optional)

macOS (Darwin), Node.js v22.22.3, npm 10.9.8, local bundled qwen serve, Vitest, and a real managed ACP child-process harness.

Risk & Scope

  • Main risk or tradeoff: Shutdown ordering spans session admission, transcript durability, hooks, resource cleanup, and child reaping. Ambiguous failures deliberately produce an unclean shutdown and may retain a stale lock rather than risk two writers.
  • Not validated / out of scope: Windows and Linux were not tested locally; an actual Kubernetes rolling replacement was not exercised. SIGKILL before the child handler, an event-loop stall, or a storage failure can still retain a lock. Sealed takeover/fencing, historical foreign-host lock recovery, maintenance leases, and automated repair remain follow-up work.
  • Breaking changes / migration notes: No public ACP or REST contract changes. Mixed-version deployment remains unsupported for writer handoff; drain old managed writers before a replacement accepts sessions, and use the same drain discipline when rolling back.

Linked Issues

Part of #7752

中文说明

本 PR 做了什么

本 PR 为 daemon 托管的 ACP 子进程增加协作式关闭。收到第一次关闭信号时,会同步关闭新会话和新轮次准入,排空截止点之前已接受的所有 transcript 工作,以原子方式退役精确属于当前 owner 的 writer 锁;只有 writer 阶段终态确定后,才执行 SessionEnd hook 和其余资源清理。

同时,primary、secondary 和动态新增 workspace runtime 所派生的全部 ACP 子进程会由同一个 daemon 作用域的关闭时间线管理。关闭时立即发送 SIGTERM,5 秒后升级为 SIGKILL,10 秒内必须观察到原始进程回收;如果子进程非零退出、因信号退出或无法确认已回收,关闭结果会稳定保持为不干净。部分 channel 构造失败和重叠存活 channel 的清理也必须等待相同的终态后才能返回。

托管模式下的锁获取明确不会根据 hostname、锁年龄或容器内可见的 PID 证据回收已有 writer 锁。独立 ACP 仍保留现有的本机 stale owner 回收行为。

为什么需要

托管 daemon 的替代实例可能使用不同 hostname 启动,而上一个 ACP 子进程仍持有 v1 session writer 锁。如果旧子进程在未协作清理的情况下被终止,替代实例无法安全证明这个外部 hostname 的 owner 已死亡,因此会无限期返回 session_writer_conflict

当两个 Pod 可能同时挂载同一个 workspace 时,按锁年龄或 hostname 自动抢锁是不安全的。本 P0 把锁释放变成托管子进程关闭确认的一部分,从而修复正常终止路径;只要 flush、完整性、所有权或进程回收证据存在不确定性,仍保持现有的 fail-closed 行为。

Reviewer 测试计划

如何验证

  1. 启动打包后的 qwen serve,创建持有 writer 锁的持久化会话,并在至少一个会话仍存活时发送 SIGTERM。确认新会话/轮次准入关闭、已接受的 transcript 写入完成、所有主 writer 锁消失、ACP 子进程以退出码 0 结束,并且替代 daemon 能加载会话并继续追加,且不出现 session_writer_conflict
  2. 注入 transcript flush 或锁释放失败后重复测试。确认关闭被报告为不完整、子进程不会确认干净退出、所有权不确定时保留主锁,并且替代实例继续返回冲突而不是产生第二个 writer。
  3. 使用忽略 SIGTERM 的子进程。确认父进程约在 5 秒时发送 SIGKILL,将信号退出报告为不干净,并且多次调用关闭也不会重启 10 秒的未回收截止时间。
  4. 覆盖 primary、secondary、动态新增 workspace runtime 以及部分 channel 构造失败。确认所有派生子进程在发布前已纳管,构造不会早于清理终态返回,并且一个 channel 失败时,bridge 不能在另一个存活 channel 尚未回收时提前结束关闭。
  5. 精确提交上的自动验证结果:core writer/config 测试 520 通过、1 跳过;ACP bridge/process 测试 487 通过;ACP agent 和 serve 测试 524 通过;完整 build、typecheck、lint 均通过。真实 managed ACP harness 创建了三个存活 writer 锁,SIGTERM 后约 266 ms 内全部释放(3/3)并干净退出,明显早于 5 秒升级截止时间。

证据(修改前与修改后)

N/A——仅涉及 daemon 生命周期与持久化行为,没有 TUI 或 Web UI 变化。

测试平台

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

环境(可选)

macOS(Darwin)、Node.js v22.22.3、npm 10.9.8、本地打包的 qwen serve、Vitest,以及真实的 managed ACP 子进程 harness。

风险与范围

  • 主要风险或权衡:关闭顺序跨越会话准入、transcript 持久性、hook、资源清理和子进程回收。含糊的失败会刻意产生不干净关闭,并可能保留 stale 锁,以避免产生两个 writer。
  • 未验证 / 范围外:Windows 和 Linux 未在本地测试,也没有执行真实 Kubernetes 滚动替换。子进程 handler 执行前被 SIGKILL、事件循环卡死或存储失败仍可能保留锁。带封印的 takeover/fencing、历史外部 hostname 锁恢复、maintenance lease 和自动修复仍属于后续工作。
  • 破坏性变更 / 迁移说明:没有公开 ACP 或 REST 协议变更。混合版本部署仍不支持 writer handoff;替代实例接受会话前必须先排空旧的托管 writer,回滚时也要遵循相同的 drain 规则。

关联 Issue

属于 #7752 的一部分

@github-actions

github-actions Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Summary

Package Lines Statements Functions Branches
CLI 83.12% 83.12% 89.15% 82.41%
Core 87.22% 87.22% 88.79% 86.04%
CLI Package - Full Text Report
-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |   83.12 |    82.41 |   89.15 |   83.12 |                   
 src               |   84.12 |    80.71 |   88.88 |   84.12 |                   
  cli.ts           |   94.54 |    84.07 |     100 |   94.54 | ...86-487,497-498 
  gemini.tsx       |   73.89 |    76.49 |    82.6 |   73.89 | ...1183-1187,1308 
  ...ractiveCli.ts |   85.02 |    80.82 |   86.84 |   85.02 | ...2363,2369,2421 
  ...liCommands.ts |   88.34 |    83.87 |      90 |   88.34 | ...63,480,514,635 
  ...ActiveAuth.ts |     100 |     87.5 |     100 |     100 | 66-80             
 ...cp-integration |   68.92 |     71.5 |   89.37 |   68.92 |                   
  acpAgent.ts      |   68.56 |    71.34 |   89.38 |   68.56 | ...46,11051-11053 
  authMethods.ts   |      92 |       60 |     100 |      92 | 33-34             
  errorCodes.ts    |       0 |        0 |       0 |       0 | 1-22              
  ...ion-skills.ts |     100 |    88.23 |     100 |     100 | 17,32             
  generation.ts    |    97.1 |    81.25 |     100 |    97.1 | 109,112           
  ...DirContext.ts |     100 |      100 |     100 |     100 |                   
 ...ration/service |   97.04 |    95.71 |   93.33 |   97.04 |                   
  filesystem.ts    |   97.04 |    95.71 |   93.33 |   97.04 | ...21-122,238-239 
 ...ration/session |   91.75 |    85.85 |   95.97 |   91.75 |                   
  Session.ts       |   91.32 |    84.51 |   95.23 |   91.32 | ...8493,8520-8524 
  ...entTracker.ts |   91.87 |    89.18 |   88.88 |   91.87 | ...33,197,280-289 
  ...stop-guard.ts |     100 |    97.05 |     100 |     100 | 37,127,247        
  ...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 |    86.76 |     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.68 |     93.7 |   96.66 |   95.68 |                   
  ...ageEmitter.ts |   95.34 |    94.11 |     100 |   95.34 | 52-59             
  PlanEmitter.ts   |     100 |    83.33 |     100 |     100 | 59                
  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.17 |    97.43 |     100 |   99.17 | 352-353           
 ...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/commands      |      89 |    73.18 |   64.51 |      89 |                   
  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        |   97.95 |      100 |      50 |   97.95 | 60                
  serve.ts         |   86.85 |     67.3 |     100 |   86.85 | ...32-635,649-653 
  sessions.ts      |     100 |      100 |      50 |     100 |                   
  update.ts        |   98.13 |    94.44 |   66.66 |   98.13 | 82-83             
 ...mmands/channel |   86.92 |    87.05 |   90.44 |   86.92 |                   
  channel-cwd.ts   |     100 |      100 |     100 |     100 |                   
  ...l-registry.ts |   79.66 |    84.61 |      80 |   79.66 | 36-39,48-51,62-65 
  ...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 |    94.2 |    85.09 |   97.82 |    94.2 | ...1155,1162-1163 
  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       |   81.42 |    87.71 |     100 |   81.42 | ...70-174,234-236 
  set.ts           |   75.72 |    85.71 |      50 |   75.72 | 65-83,111-116     
  start.ts         |   75.05 |    73.17 |   76.92 |   75.05 | ...31,537-540,552 
  ...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.82 |   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 |     90.9 |     100 |     100 | 18                
  new.ts           |     100 |      100 |     100 |     100 |                   
  settings.ts      |   99.15 |      100 |   83.33 |   99.15 | 151               
  sources.ts       |   93.42 |    87.09 |   92.85 |   93.42 | ...4-66,96-98,167 
  uninstall.ts     |   74.57 |       40 |   66.66 |   74.57 | 45-47,60-67,70-73 
  update.ts        |   96.71 |    97.05 |     100 |   96.71 | 114-118           
  utils.ts         |      75 |    55.55 |     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 |   84.56 |    85.97 |    84.7 |   84.56 |                   
  agent-prompt.ts  |   90.88 |    92.78 |      96 |   90.88 | ...1259,1729-1798 
  capture-local.ts |   68.26 |    83.33 |      75 |   68.26 | 106-110,157-188   
  ...k-coverage.ts |   48.38 |    14.28 |   66.66 |   48.38 | ...21-226,239-249 
  cleanup.ts       |   87.36 |    82.35 |   83.33 |   87.36 | ...77-482,484-485 
  ...ent-status.ts |   93.03 |    83.87 |   83.33 |   93.03 | 291,531-551       
  ...ose-review.ts |   95.86 |    91.66 |   93.75 |   95.86 | ...1385,1413-1435 
  fetch-pr.ts      |   73.92 |    51.72 |      50 |   73.92 | ...97,331,401-406 
  load-rules.ts    |   26.41 |      100 |   16.66 |   26.41 | ...41-153,155-156 
  parse-args.ts    |   99.25 |       96 |     100 |   99.25 | 341,413           
  plan-diff.ts     |   63.63 |      100 |   66.66 |   63.63 | 126-162           
  pr-context.ts    |   84.44 |    79.38 |   91.66 |   84.44 | ...29-910,939-941 
  presubmit.ts     |   83.75 |    92.72 |   88.88 |   83.75 | ...77-578,655-685 
  ...ve-anchors.ts |   77.02 |    88.46 |      75 |   77.02 | ...70-175,187-204 
  script-lint.ts   |   83.67 |    78.41 |   88.88 |   83.67 | ...59-773,775-797 
  submit.ts        |   76.74 |    82.05 |   81.81 |   76.74 | ...03-639,641-642 
  test-efficacy.ts |   80.68 |    69.41 |    92.3 |   80.68 | ...93-594,602-622 
 ...nds/review/lib |   95.61 |    93.01 |   94.92 |   95.61 |                   
  agent-briefs.ts  |   98.68 |      100 |       0 |   98.68 | 520-521           
  anchors.ts       |     100 |    94.79 |     100 |     100 | ...33,169,178,225 
  coverage.ts      |   95.47 |    94.25 |   95.45 |   95.47 | ...98,335,433-450 
  diff-flags.ts    |     100 |        0 |     100 |     100 | 63                
  diff-plan.ts     |   98.73 |    93.01 |     100 |   98.73 | ...41,264,290-291 
  gh.ts            |    85.6 |    88.37 |   71.42 |    85.6 | ...20,257-258,285 
  git.ts           |   97.64 |    95.65 |     100 |   97.64 | 180-181           
  heavy.ts         |     100 |      100 |     100 |     100 |                   
  inline-counts.ts |     100 |      100 |     100 |     100 |                   
  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         |    92.3 |    83.33 |   83.33 |    92.3 | 76-77             
  prompt-record.ts |   94.73 |    88.23 |     100 |   94.73 | ...28,151-152,156 
  receipt.ts       |     100 |      100 |     100 |     100 |                   
  report.ts        |   94.38 |    93.75 |     100 |   94.38 | 173-177           
  roster.ts        |     100 |    94.23 |     100 |     100 | 143,161,206       
  shell-quote.ts   |     100 |      100 |     100 |     100 |                   
  transcripts.ts   |   96.27 |    93.18 |     100 |   96.27 | ...83,269-270,294 
  workspaces.ts    |   97.76 |     91.3 |     100 |   97.76 | 186-187,212-213   
 ...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.16 |    88.68 |    95.9 |   94.16 |                   
  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.29 |    88.15 |   84.84 |   88.29 | ...2367,2369-2377 
  ...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.74 |     100 |     100 | 47,160,220        
  keyBindings.ts   |   97.38 |       50 |     100 |   97.38 | 234-237           
  ...ngsAdapter.ts |     100 |    94.11 |     100 |     100 | 64                
  ...ig-watcher.ts |   95.17 |    83.05 |     100 |   95.17 | ...78,200,292-293 
  ...er-secrets.ts |   98.97 |    96.96 |     100 |   98.97 | 85                
  mcpApprovals.ts  |   96.55 |    95.65 |     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 |   96.52 |    93.93 |     100 |   96.52 | 90-91,201-202     
  settings.ts      |   90.74 |    92.02 |   89.65 |   90.74 | ...72,974,976-977 
  ...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/i18n          |   85.98 |    81.92 |   89.65 |   85.98 |                   
  index.ts         |   73.45 |    77.77 |      90 |   73.45 | ...70-271,294-299 
  languages.ts     |   93.07 |     92.3 |   85.71 |   93.07 | ...35,164-169,184 
  ...nslateKeys.ts |     100 |      100 |     100 |     100 |                   
  ...lationDict.ts |   93.33 |    66.66 |     100 |   93.33 | 15                
 src/i18n/locales  |     100 |      100 |     100 |     100 |                   
  ca.js            |     100 |      100 |     100 |     100 |                   
  de.js            |     100 |      100 |     100 |     100 |                   
  en.js            |     100 |      100 |     100 |     100 |                   
  fr.js            |     100 |      100 |     100 |     100 |                   
  ja.js            |     100 |      100 |     100 |     100 |                   
  pt.js            |     100 |      100 |     100 |     100 |                   
  ru.js            |     100 |      100 |     100 |     100 |                   
  zh-TW.js         |     100 |      100 |     100 |     100 |                   
  zh.js            |     100 |      100 |     100 |     100 |                   
 ...nonInteractive |      80 |    76.31 |   81.35 |      80 |                   
  session.ts       |   84.08 |    75.27 |   93.61 |   84.08 | ...1007,1016-1026 
  types.ts         |    42.5 |      100 |   33.33 |    42.5 | ...24-625,628-629 
 ...active/control |   76.11 |    89.09 |      80 |   76.11 |                   
  ...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 |     7.4 |        0 |       0 |     7.4 | 46-185            
 ...ol/controllers |   39.78 |    63.24 |   47.22 |   39.78 |                   
  ...Controller.ts |   39.49 |      100 |      80 |   39.49 | 88-92,127-210     
  ...Controller.ts |       0 |        0 |       0 |       0 | 1-56              
  ...Controller.ts |   49.11 |    62.96 |   54.54 |   49.11 | ...63-568,570-575 
  ...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.14 |     94.4 |   95.23 |   98.14 |                   
  ...putAdapter.ts |   98.09 |    93.65 |   98.07 |   98.09 | ...1319,1422-1423 
  ...putAdapter.ts |      96 |    91.66 |   85.71 |      96 | 51-52             
  ...nputReader.ts |     100 |    94.73 |     100 |     100 | 67                
  ...putAdapter.ts |   98.38 |      100 |   90.47 |   98.38 | 84-85,125-126     
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/patches       |       0 |        0 |       0 |       0 |                   
  is-in-ci.ts      |       0 |        0 |       0 |       0 | 1-17              
 src/remoteInput   |   87.31 |    75.32 |   88.23 |   87.31 |                   
  ...utContext.tsx |     100 |      100 |     100 |     100 |                   
  ...putWatcher.ts |   88.01 |       76 |   93.33 |   88.01 | ...49-350,361-364 
  index.ts         |       0 |        0 |       0 |       0 | 1-8               
 src/serve         |   87.55 |    83.51 |   91.01 |   87.55 |                   
  ...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.87 |     100 |     100 | 629               
  ...cp-command.ts |     100 |      100 |     100 |     100 |                   
  ...horization.ts |   92.79 |    93.33 |    87.5 |   92.79 | 75-80,135-136     
  ...livery-ipc.ts |     100 |     90.9 |     100 |     100 | 94,106,134        
  ...l-delivery.ts |     100 |      100 |     100 |     100 |                   
  ...nt-service.ts |   93.65 |    86.02 |     100 |   93.65 | ...52-454,461,463 
  ...-selection.ts |     100 |      100 |     100 |     100 |                   
  ...ings-store.ts |   85.85 |    91.78 |   95.83 |   85.85 | ...94-206,366-369 
  ...ebhook-ipc.ts |    98.5 |    86.66 |     100 |    98.5 | 47                
  ...iagnostics.ts |     100 |      100 |     100 |     100 |                   
  ...worker-env.ts |     100 |      100 |     100 |     100 |                   
  ...rker-group.ts |   91.42 |    86.72 |     100 |   91.42 | ...26,732-736,748 
  ...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 |   96.49 |    86.37 |   96.72 |   96.49 | ...1253,1307-1311 
  ...e-grouping.ts |     100 |    94.11 |     100 |     100 | 69,132            
  core-runtime.ts  |     100 |      100 |     100 |     100 |                   
  ...ub-session.ts |   92.04 |    77.77 |     100 |   92.04 | ...36-445,470,508 
  daemon-logger.ts |    82.2 |    77.26 |   91.76 |    82.2 | ...1720,1747-1753 
  ...trics-ring.ts |     100 |      100 |     100 |     100 |                   
  ...s-provider.ts |   68.04 |    52.77 |     100 |   68.04 | ...44-249,282-290 
  daemon-status.ts |   98.37 |    90.06 |     100 |   98.37 | ...1041,1043-1044 
  debug-mode.ts    |     100 |      100 |     100 |     100 |                   
  demo.ts          |     100 |      100 |     100 |     100 |                   
  env-snapshot.ts  |    91.3 |       80 |     100 |    91.3 | ...24-127,205-212 
  ...-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.33 |    80.23 |   95.45 |   90.33 | ...83-492,558-559 
  ...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.62 |     79.3 |   73.86 |   82.62 | ...6648,6653-6654 
  ...tup-errors.ts |     100 |      100 |     100 |     100 |                   
  ...-keepalive.ts |   95.04 |       88 |     100 |   95.04 | ...07,511-512,552 
  ...-lifecycle.ts |     100 |      100 |     100 |     100 |                   
  server.ts        |   93.93 |    93.52 |      75 |   93.93 | ...2044,2065-2069 
  ...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 |                   
  ...erver-name.ts |     100 |      100 |     100 |     100 |                   
  ...ion-limits.ts |     100 |      100 |     100 |     100 |                   
  ...t-sessions.ts |   93.34 |    76.57 |     100 |   93.34 | ...17,820,833-835 
  ...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 |                   
  ...-constants.ts |     100 |      100 |     100 |     100 |                   
  ...-summaries.ts |   86.66 |       50 |     100 |   86.66 | 11,19             
  ...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 | ...17-518,524-525 
  ...ber-errors.ts |     100 |    95.32 |     100 |     100 | 53,93-94,172,192  
  ...e-remember.ts |   98.14 |    88.92 |     100 |   98.14 | ...31,335-340,381 
  ...te-runtime.ts |   82.62 |    88.88 |     100 |   82.62 | ...48-156,216-237 
  ...management.ts |   72.63 |    72.72 |      96 |   72.63 | ...88-889,896-900 
  ...ls-mapping.ts |     100 |      100 |     100 |     100 |                   
  ...lls-status.ts |     100 |    92.85 |     100 |     100 | 127               
  ...reconciler.ts |    91.6 |     83.9 |     100 |    91.6 | ...70-272,305-306 
 ...serve/acp-http |    76.7 |    77.99 |   93.04 |    76.7 |                   
  ...r-registry.ts |     100 |    95.45 |     100 |     100 | 191               
  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.11 |    73.69 |   95.23 |   71.11 | ...4685,4733-4739 
  index.ts         |   81.78 |    79.64 |   90.56 |   81.78 | ...2273,2343-2344 
  json-rpc.ts      |     100 |    96.96 |     100 |     100 | 92                
  safe-ws-send.ts  |   52.94 |    71.42 |     100 |   52.94 | 33-42,47-55       
  sse-stream.ts    |   93.96 |    88.57 |   84.61 |   93.96 | ...57-159,161-163 
  ...ort-stream.ts |       0 |        0 |       0 |       0 | 1                 
  ws-stream.ts     |   91.86 |       80 |     100 |   91.86 | 45,50,96,100-103  
 src/serve/auth    |   86.86 |     79.7 |   93.87 |   86.86 |                   
  device-flow.ts   |   96.35 |    80.57 |   97.61 |   96.35 | ...1358,1453,1519 
  ...w-provider.ts |   44.24 |    74.07 |   71.42 |   44.24 | ...23-284,297,301 
 ...rve/cdp-tunnel |   85.73 |    73.17 |    97.5 |   85.73 |                   
  ...r-emulator.ts |   88.57 |    63.63 |     100 |   88.57 | ...72-175,194-195 
  ...verse-link.ts |      88 |    76.19 |     100 |      88 | ...28-329,420-423 
  ...l-registry.ts |     100 |      100 |     100 |     100 |                   
  cdp-ws.ts        |   76.28 |    61.29 |    87.5 |   76.28 | ...13-217,223-228 
 ...nel/acceptance |       0 |        0 |       0 |       0 |                   
  ...mcp-smoke.mjs |       0 |        0 |       0 |       0 | 1-119             
  ...cceptance.mjs |       0 |        0 |       0 |       0 | 1-473             
  real-tab.mjs     |       0 |        0 |       0 |       0 | 1-218             
 src/serve/fs      |   85.64 |    78.41 |     100 |   85.64 |                   
  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.6 |     100 |   77.64 | ...65,594-598,611 
  policy.ts        |   90.32 |    89.18 |     100 |   90.32 | 142-150           
  ...ile-system.ts |   85.14 |    76.25 |     100 |   85.14 | ...2073,2083-2084 
 src/serve/routes  |   86.16 |     79.9 |   95.52 |   86.16 |                   
  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 |   86.78 |     81.9 |   95.65 |   86.78 | ...1195,1238-1239 
  ...on-runtime.ts |     100 |    90.47 |     100 |     100 | 58,94             
  session.ts       |   86.27 |    81.47 |      95 |   86.27 | ...4295,4297-4298 
  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 |   89.29 |    75.72 |     100 |   89.29 | ...91-392,411-412 
  ...d-contacts.ts |     100 |      100 |     100 |     100 |                   
  ...controller.ts |   83.41 |    78.89 |      90 |   83.41 | ...1024,1030,1033 
  ...extensions.ts |    87.2 |    72.76 |   94.11 |    87.2 | ...1822,1867-1868 
  ...-file-read.ts |   92.34 |    80.31 |     100 |   92.34 | ...96-597,600-601 
  ...file-write.ts |   84.44 |    64.51 |     100 |   84.44 | ...73-275,355-357 
  ...e-git-diff.ts |   97.32 |    90.56 |     100 |   97.32 | 161-162,189-191   
  ...ce-git-log.ts |     100 |    92.68 |     100 |     100 | 52,77,183         
  workspace-git.ts |   77.08 |    89.65 |     100 |   77.08 | 97-118            
  ...github-prs.ts |      97 |    91.66 |     100 |      97 | 133-135           
  ...-lifecycle.ts |   95.23 |    75.75 |     100 |   95.23 | ...50-151,186-187 
  ...management.ts |   88.15 |    85.19 |     100 |   88.15 | ...1537,1557-1562 
  ...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.81 |    70.31 |     100 |   74.81 | ...47-658,664-665 
  ...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.77 |    89.47 |   95.27 |   90.77 |                   
  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.45 |    76.57 |     100 |   85.45 | ...93,710,773-782 
  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.14 |     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.61 |    90.38 |   88.23 |   89.61 | ...36-441,513-523 
  ...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.01 |    97.43 |     100 |   99.01 | ...13,627,769-771 
 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.4 |    85.59 |      90 |    89.4 |                   
  index.ts         |   88.94 |    85.16 |   88.57 |   88.94 | ...1211-1215,1218 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/services      |   92.17 |    88.29 |   97.82 |   92.17 |                   
  ...mandLoader.ts |     100 |    88.88 |     100 |     100 | 104-117           
  ...killLoader.ts |   97.14 |    87.87 |     100 |   97.14 | 140,151-152       
  ...andService.ts |   98.73 |      100 |     100 |   98.73 | 107               
  ...mandLoader.ts |   86.83 |    83.87 |     100 |   86.83 | ...30-335,340-345 
  ...omptLoader.ts |   77.36 |    85.52 |   83.33 |   77.36 | ...43,168,210-211 
  ...mandLoader.ts |   97.36 |    92.68 |     100 |   97.36 | 153,160-161       
  ...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.11 |     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.54 |    90.47 |    87.5 |   93.54 | 201-203,217-223   
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...e-keyterms.ts |   98.64 |    95.83 |     100 |   98.64 | 116,142-143       
  voice-model.ts   |     100 |      100 |     100 |     100 |                   
  voice-service.ts |   90.37 |    87.87 |     100 |   90.37 | ...80,287,352-357 
  ...e-settings.ts |     100 |    95.23 |     100 |     100 | 19                
  ...ranscriber.ts |   90.46 |    82.19 |      96 |   90.46 | ...66-668,671-673 
 ...rvices/insight |     100 |      100 |     100 |     100 |                   
  dates.ts         |     100 |      100 |     100 |     100 |                   
 ...ght/generators |   88.91 |    86.29 |   96.15 |   88.91 |                   
  DataProcessor.ts |   88.28 |    86.24 |   94.73 |   88.28 | ...1352,1356-1363 
  ...tGenerator.ts |   98.24 |    85.71 |     100 |   98.24 | 47                
  ...teRenderer.ts |     100 |      100 |     100 |     100 |                   
 .../insight/types |       0 |       50 |      50 |       0 |                   
  ...sightTypes.ts |       0 |        0 |       0 |       0 |                   
  ...sightTypes.ts |       0 |        0 |       0 |       0 | 1                 
 ...mpt-processors |   97.27 |    94.04 |     100 |   97.27 |                   
  ...tProcessor.ts |     100 |      100 |     100 |     100 |                   
  ...eProcessor.ts |   94.52 |    84.21 |     100 |   94.52 | 46-47,93-94       
  ...tionParser.ts |     100 |      100 |     100 |     100 |                   
  ...lProcessor.ts |   97.41 |    95.65 |     100 |   97.41 | 95-98             
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/services/tips |   97.27 |    84.61 |     100 |   97.27 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  tipHistory.ts    |   92.59 |       70 |     100 |   92.59 | ...24,146,153,162 
  tipRegistry.ts   |     100 |      100 |     100 |     100 |                   
  tipScheduler.ts  |     100 |    91.66 |     100 |     100 | 55                
 src/startup       |   88.99 |    83.47 |    90.9 |   88.99 |                   
  ...p-prefetch.ts |   98.09 |    94.23 |    87.5 |   98.09 | 50,209,225-226    
  ...reeStartup.ts |   80.53 |     74.6 |     100 |   80.53 | ...94,403,409-412 
 src/test-utils    |   94.04 |    83.33 |      80 |   94.04 |                   
  ...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            |   71.81 |     74.3 |   67.07 |   71.81 |                   
  App.tsx          |   33.33 |       75 |   33.33 |   33.33 | 32-86             
  AppContainer.tsx |   73.12 |    71.91 |   67.85 |   73.12 | ...4104,4146-4156 
  ...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.22 |     100 |   95.91 | 25-26             
  ...tic-colors.ts |     100 |      100 |     100 |     100 |                   
  ...ractiveUI.tsx |   62.73 |    47.22 |   66.66 |   62.73 | ...95-296,313-318 
  ...inePresets.ts |   96.27 |    83.87 |     100 |   96.27 | ...97,402,410-412 
  textConstants.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/ui/auth       |   58.53 |    66.18 |   51.06 |   58.53 |                   
  AuthDialog.tsx   |   59.01 |     42.1 |   16.66 |   59.01 | ...25,332-354,358 
  ...nProgress.tsx |       0 |        0 |       0 |       0 | 1-64              
  ...etupSteps.tsx |   60.21 |    70.73 |   57.69 |   60.21 | ...90,794,803,806 
  useAuth.ts       |    94.6 |    73.52 |     100 |    94.6 | ...21-222,241-247 
  ...rSetupFlow.ts |   43.18 |    33.33 |      50 |   43.18 | ...78-399,416-459 
 src/ui/commands   |    81.4 |    83.02 |    89.4 |    81.4 |                   
  aboutCommand.ts  |     100 |      100 |     100 |     100 |                   
  agentsCommand.ts |   83.78 |      100 |      60 |   83.78 | 30-32,42-44       
  ...odeCommand.ts |    93.1 |    95.23 |     100 |    93.1 | 77-82             
  arenaCommand.ts  |   63.89 |    65.71 |   65.21 |   63.89 | ...01-606,691-699 
  authCommand.ts   |     100 |      100 |     100 |     100 |                   
  branchCommand.ts |     100 |      100 |     100 |     100 |                   
  btwCommand.ts    |   94.32 |    81.25 |     100 |   94.32 | 35-36,114-119     
  bugCommand.ts    |     100 |    77.77 |     100 |     100 | 27,61             
  cdCommand.ts     |   92.46 |    83.63 |     100 |   92.46 | ...4-69,94-99,178 
  clearCommand.ts  |    80.9 |    70.83 |     100 |    80.9 | ...24-125,133-142 
  ...essCommand.ts |   67.95 |    55.88 |      75 |   67.95 | ...86-187,201-204 
  ...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 
  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   |   91.13 |    83.72 |      90 |   91.13 | ...81-184,196-199 
  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  |   86.27 |    83.01 |     100 |   86.27 | ...22-935,969-974 
  ...onsCommand.ts |     100 |      100 |     100 |     100 |                   
  planCommand.ts   |   78.82 |    76.92 |     100 |   78.82 | 30-35,51-56,68-73 
  quitCommand.ts   |     100 |      100 |     100 |     100 |                   
  recapCommand.ts  |   21.81 |      100 |      50 |   21.81 | 24-73             
  ...ns-command.ts |   98.83 |    81.81 |     100 |   98.83 | 100               
  ...berCommand.ts |     100 |     87.5 |     100 |     100 | 46                
  renameCommand.ts |   89.06 |    88.37 |     100 |   89.06 | ...72-176,202-209 
  ...oreCommand.ts |    90.9 |    86.04 |     100 |    90.9 | ...41-146,176-177 
  resumeCommand.ts |     100 |      100 |     100 |     100 |                   
  rewindCommand.ts |   81.25 |      100 |      50 |   81.25 | 20-22             
  ...ngsCommand.ts |     100 |      100 |     100 |     100 |                   
  ...hubCommand.ts |   89.47 |       75 |      80 |   89.47 | 54-59             
  skillsCommand.ts |   78.82 |    81.81 |     100 |   78.82 | 37-52,78,97       
  statsCommand.ts  |   90.65 |    76.73 |     100 |   90.65 | ...30-733,825-832 
  ...ineCommand.ts |     100 |      100 |     100 |     100 |                   
  ...aryCommand.ts |    6.43 |      100 |      50 |    6.43 | 31-330            
  tasksCommand.ts  |   77.22 |    72.13 |     100 |   77.22 | ...46-150,172-177 
  ...tupCommand.ts |     100 |      100 |     100 |     100 |                   
  themeCommand.ts  |     100 |      100 |     100 |     100 |                   
  toolsCommand.ts  |     100 |      100 |     100 |     100 |                   
  trustCommand.ts  |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...te-command.ts |     100 |    94.11 |     100 |     100 | 74,148            
  vimCommand.ts    |   54.54 |      100 |      50 |   54.54 | 19-29             
  voice-command.ts |   93.57 |       88 |     100 |   93.57 | 35,97-102         
  ...owsCommand.ts |   91.82 |    78.87 |   66.66 |   91.82 | ...59-160,169-174 
 src/ui/components |    70.6 |     78.3 |   76.29 |    70.6 |                   
  AboutBox.tsx     |     100 |      100 |     100 |     100 |                   
  ...ateScreen.tsx |   97.29 |     87.5 |   66.66 |   97.29 | 49                
  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 |   86.55 |    87.67 |     100 |   86.55 | ...00-302,353-357 
  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-597             
  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       |   75.11 |     61.4 |      50 |   75.11 | ...48-253,271-275 
  ...ngSpinner.tsx |   68.42 |    85.71 |      50 |   68.42 | 35-52,73,80-81    
  GoalPill.tsx     |   83.33 |    76.92 |     100 |   83.33 | 24-30             
  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 |   78.45 |    64.28 |     100 |   78.45 | ...98,501,504-510 
  ...ngeDialog.tsx |     100 |      100 |     100 |     100 |                   
  InputPrompt.tsx  |   83.05 |    81.58 |      80 |   83.05 | ...2194,2220,2294 
  ...Shortcuts.tsx |   20.65 |      100 |       0 |   20.65 | ...7,50-52,68-126 
  ...Indicator.tsx |   98.18 |    97.82 |     100 |   98.18 | 161-162           
  ...firmation.tsx |   91.42 |      100 |      50 |   91.42 | 26-31             
  MainContent.tsx  |   95.82 |    92.53 |      50 |   95.82 | ...97,440-444,447 
  MemoryDialog.tsx |   86.59 |    80.15 |     100 |   86.59 | ...34-435,485,553 
  ...geDisplay.tsx |       0 |        0 |       0 |       0 | 1-41              
  ModelDialog.tsx  |   83.41 |    71.65 |     100 |   83.41 | ...69,971,976-992 
  ...tsDisplay.tsx |     100 |    97.22 |     100 |     100 | 270               
  ...fications.tsx |       0 |        0 |       0 |       0 | 1-56              
  ...onsDialog.tsx |       0 |        0 |       0 |       0 | 1-1004            
  ...ryDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...icePrompt.tsx |   92.64 |    85.71 |     100 |   92.64 | 102-106,134-139   
  PrepareLabel.tsx |   91.66 |    77.27 |     100 |   91.66 | 73-75,77-79,110   
  ...atePrompt.tsx |       0 |        0 |       0 |       0 | 1-134             
  ...geDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...ngDisplay.tsx |       0 |        0 |       0 |       0 | 1-39              
  ...hProgress.tsx |   85.25 |    88.46 |     100 |   85.25 | 121-147           
  ...dSelector.tsx |   92.79 |    82.65 |     100 |   92.79 | ...19-323,354-370 
  ...ionPicker.tsx |   83.66 |    72.13 |     100 |   83.66 | ...96,402,444-466 
  ...onPreview.tsx |   93.58 |    83.78 |     100 |   93.58 | ...,70-71,195-197 
  ...ryDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...putPrompt.tsx |   72.56 |       80 |      40 |   72.56 | ...06-109,114-117 
  ...tedDialog.tsx |     100 |      100 |     100 |     100 |                   
  ...ngsDialog.tsx |   71.49 |    73.89 |   69.23 |   71.49 | ...1244,1250-1251 
  ...ionDialog.tsx |    92.3 |    96.15 |   33.33 |    92.3 | 60-63,68-75,164   
  ...putPrompt.tsx |    15.9 |      100 |       0 |    15.9 | 20-63             
  ...Indicator.tsx |   57.14 |      100 |       0 |   57.14 | 12-15             
  ...MoreLines.tsx |       0 |        0 |       0 |       0 | 1-40              
  ...iewDialog.tsx |   97.77 |    87.67 |     100 |   97.77 | ...97,305-307,324 
  ...tsDisplay.tsx |   95.86 |       75 |     100 |   95.86 | 67-71             
  ...ionPicker.tsx |       0 |        0 |       0 |       0 | 1-172             
  ...tivityTab.tsx |    3.94 |      100 |       0 |    3.94 | 27-275            
  StatsDialog.tsx  |    8.64 |      100 |       0 |    8.64 | ...76-111,130-322 
  StatsDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...ciencyTab.tsx |    78.9 |    56.52 |     100 |    78.9 | ...26,213,262-288 
  ...atmapView.tsx |    8.98 |      100 |       0 |    8.98 | 20-107            
  ...essionTab.tsx |      80 |    66.66 |     100 |      80 | ...70-277,283-300 
  ...ineDialog.tsx |    93.5 |    85.18 |     100 |    93.5 | ...05,267,287-289 
  ...yTodoList.tsx |   96.36 |    88.23 |     100 |   96.36 | 138-141           
  ...nsDisplay.tsx |   92.97 |    83.87 |     100 |   92.97 | ...43,246,273-275 
  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             
  ...criptView.tsx |   98.27 |    84.21 |     100 |   98.27 | 45,53             
  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 |   53.72 |    70.87 |   42.85 |   53.72 |                   
  ...atContent.tsx |    9.09 |      100 |       0 |    9.09 | 54-275,281-283    
  ...tChatView.tsx |   21.05 |      100 |       0 |   21.05 | 21-39             
  ...tComposer.tsx |   64.78 |    29.41 |   33.33 |   64.78 | ...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.2 |    81.36 |    90.9 |    82.2 |                   
  ...sksDialog.tsx |   77.53 |     76.9 |   80.76 |   77.53 | ...1781,1803-1809 
  ...TasksPill.tsx |   67.03 |     86.2 |     100 |   67.03 | ...02-122,130-138 
  ...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.14 |   70.83 |   71.92 |                   
  DiscoverTab.tsx  |   68.22 |    67.66 |   55.55 |   68.22 | ...93,656-660,664 
  InstalledTab.tsx |   75.49 |    67.28 |   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 |   86.99 |     81.3 |   91.89 |   86.99 |                   
  ...rListBody.tsx |   95.29 |    85.18 |     100 |   95.29 | 95-98             
  ...etailStep.tsx |   75.32 |    71.42 |      60 |   75.32 | ...56-169,173-186 
  ...etailStep.tsx |     100 |      100 |     100 |     100 |                   
  ...rListStep.tsx |     100 |      100 |     100 |     100 |                   
  ...entHeader.tsx |     100 |    85.71 |     100 |     100 | 47                
  ...rListStep.tsx |     100 |      100 |     100 |     100 |                   
  ...etailStep.tsx |     100 |      100 |     100 |     100 |                   
  ...abledStep.tsx |     100 |      100 |     100 |     100 |                   
  ...sListStep.tsx |     100 |      100 |     100 |     100 |                   
  ...entDialog.tsx |   72.29 |    70.24 |     100 |   72.29 | ...51,563-568,572 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-13              
  ...erGrouping.ts |     100 |      100 |     100 |     100 |                   
  sourceLabels.ts  |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...components/mcp |   40.04 |    61.53 |   70.58 |   40.04 |                   
  ...ealthPill.tsx |   68.42 |    85.71 |     100 |   68.42 | 40-46             
  ...entDialog.tsx |   32.09 |    26.19 |      40 |   32.09 | ...12,914,927-933 
  ...valDialog.tsx |   15.06 |      100 |       0 |   15.06 | 40-109            
  constants.ts     |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-35              
  types.ts         |     100 |      100 |     100 |     100 |                   
  utils.ts         |      97 |       95 |     100 |      97 | 24,113-114        
 ...ents/mcp/steps |   53.94 |    73.51 |   57.14 |   53.94 |                   
  ...icateStep.tsx |    5.65 |      100 |       0 |    5.65 | 40-66,69-308      
  ...electStep.tsx |   10.95 |      100 |       0 |   10.95 | 16-88             
  ...etailStep.tsx |     100 |      100 |     100 |     100 |                   
  ...eListStep.tsx |   99.09 |    97.36 |     100 |   99.09 | 71                
  ...etailStep.tsx |   62.83 |       60 |   33.33 |   62.83 | ...87-296,307-332 
  ...rListStep.tsx |   88.53 |    81.25 |     100 |   88.53 | ...64,170,175-180 
  ...etailStep.tsx |    10.3 |      100 |       0 |    10.3 | ...1,67-79,82-140 
  ToolListStep.tsx |   69.29 |       50 |     100 |   69.29 | ...23,126,135-144 
 ...nents/messages |   89.95 |    86.14 |      87 |   89.95 |                   
  ...ionDialog.tsx |   89.23 |    84.27 |   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 |   96.71 |    97.77 |   91.66 |   96.71 | 223-233           
  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 |   76.52 |     42.1 |   66.66 |   76.52 | ...00,102,125,156 
  ...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 |   89.75 |     79.1 |     100 |   89.75 | ...33-635,642-644 
  ...upMessage.tsx |   98.32 |    95.16 |     100 |   98.32 | 184-187,414       
  ToolMessage.tsx  |   92.43 |    84.84 |   93.33 |   92.43 | ...56-961,988-990 
 ...ponents/shared |   85.75 |    82.09 |   94.05 |   85.75 |                   
  ...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 |    85.11 |   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.59 |    81.27 |   86.11 |   83.59 |                   
  ...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.1 |    84.53 |     100 |    85.1 | ...1583-1585,1591 
  ...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 | 155-156           
  ...teContext.tsx |   86.66 |       50 |     100 |   86.66 | 234-235           
  ...deContext.tsx |      80 |     87.5 |      75 |      80 | ...11-112,118-120 
 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.94 |    82.68 |    89.6 |   84.94 |                   
  ...dProcessor.ts |      84 |    84.12 |     100 |      84 | ...41-873,920-921 
  ...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.21 |     66.4 |   81.81 |   85.21 | ...1407,1428-1432 
  ...rt-command.ts |     100 |      100 |     100 |     100 |                   
  ...sced-flush.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.08 |     100 |   88.28 | ...66,175,179-187 
  ...waySummary.ts |   96.26 |       75 |     100 |   96.26 | 126-128,170       
  ...ndTaskView.ts |   94.73 |    76.59 |     100 |   94.73 | 162-166,255,261   
  ...chedScroll.ts |     100 |      100 |     100 |     100 |                   
  ...ketedPaste.ts |    23.8 |      100 |       0 |    23.8 | 19-37             
  ...nchCommand.ts |   94.85 |    80.76 |     100 |   94.85 | ...54,229,292-295 
  ...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 |   78.53 |    88.57 |     100 |   78.53 | ...96-104,112-113 
  ...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.7 |     100 |   99.12 | 182-183           
  ...ionUpdates.ts |   93.72 |    92.98 |     100 |   93.72 | ...87-291,314-320 
  ...agerDialog.ts |   88.88 |      100 |     100 |   88.88 | 21,25             
  ...backDialog.ts |    63.9 |    76.47 |   66.66 |    63.9 | ...66-168,190-191 
  useFocus.ts      |     100 |      100 |     100 |     100 |                   
  ...olderTrust.ts |     100 |    93.33 |     100 |     100 | 62                
  ...ggestions.tsx |   96.47 |    78.94 |     100 |   96.47 | 121,155-156       
  ...miniStream.ts |   85.61 |    81.45 |   96.15 |   85.61 | ...3927,4089-4097 
  ...BranchName.ts |     100 |    91.66 |     100 |     100 | 30                
  ...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 |    9.67 |      100 |       0 |    9.67 | 11-32,39-90       
  ...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.5 |     100 |     100 | 99                
  ...delCommand.ts |     100 |       95 |     100 |     100 | 53                
  ...ouseEvents.ts |   94.31 |    97.43 |   83.33 |   94.31 | 76-80             
  ...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 |   91.16 |     90.9 |     100 |   91.16 | ...35-338,453-463 
  ...oryCommand.ts |       0 |        0 |       0 |       0 | 1-7               
  ...tleRepaint.ts |     100 |      100 |     100 |     100 |                   
  ...umeCommand.ts |   94.67 |    74.28 |     100 |   94.67 | ...19,174,233-238 
  ...ompletion.tsx |   90.67 |    83.33 |     100 |   90.67 | ...02,105,138-141 
  ...ectionList.ts |   97.12 |    96.22 |     100 |   97.12 | ...92-193,247-250 
  ...sionPicker.ts |   92.87 |    90.35 |     100 |   92.87 | ...99-501,503-505 
  ...earchInput.ts |     100 |    97.29 |     100 |     100 | 82                
  ...ngsCommand.ts |   18.75 |      100 |       0 |   18.75 | 10-25             
  ...ellHistory.ts |   93.28 |    80.95 |     100 |   93.28 | ...96,153-154,164 
  ...oryCommand.ts |   85.48 |    58.33 |     100 |   85.48 | 22-28,40,71       
  ...agerDialog.ts |   88.23 |      100 |     100 |   88.23 | 20,24             
  ...Completion.ts |   82.85 |    85.13 |   94.73 |   82.85 | ...78-680,688-724 
  ...tateAndRef.ts |     100 |      100 |     100 |     100 |                   
  ...tatsDialog.ts |     100 |      100 |     100 |     100 |                   
  useStatusLine.ts |   97.13 |    93.33 |     100 |   97.13 | ...78-382,478-485 
  ...eateDialog.ts |   88.23 |      100 |     100 |   88.23 | 14,18             
  ...mInProcess.ts |   27.35 |       80 |      25 |   27.35 | ...82-183,186-188 
  ...tification.ts |     100 |     87.5 |     100 |     100 | 50                
  ...alProgress.ts |   53.06 |       50 |   66.66 |   53.06 | ...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.16 |    84.98 |   94.97 |   86.16 |                   
  ...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    |    95.4 |    98.38 |     100 |    95.4 | 123-126           
  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 |    97.05 |     100 |      96 | 102-105           
  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 |   69.47 |       75 |   66.66 |   69.47 | ...24-129,157-158 
  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.23 |    69.06 |   95.12 |   86.23 | ...1284,1324-1330 
  ...alRenderer.ts |   86.69 |     71.9 |     100 |   86.69 | ...1476,1513-1519 
  ...lsBySource.ts |     100 |    95.23 |     100 |     100 | 84                
  mouse.ts         |   92.85 |    73.77 |     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 |   71.08 |    79.03 |   93.75 |   71.08 | ...03-525,656-657 
  ...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           
  ...wOptimizer.ts |     100 |    96.77 |     100 |     100 | 69                
  terminalSetup.ts |    4.37 |      100 |       0 |    4.37 | 44-393            
  textUtils.ts     |   95.97 |    94.06 |   94.44 |   95.97 | ...29-330,490-491 
  ...background.ts |     100 |      100 |     100 |     100 |                   
  todoSnapshot.ts  |   89.65 |       92 |     100 |   89.65 | ...83-184,217-218 
  ...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.27 |    87.03 |   92.49 |   81.27 |                   
  ...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.17 |     100 |   90.65 | ...72,370,372-373 
  ...arResolver.ts |   97.14 |    96.55 |     100 |   97.14 | 125-126           
  errors.ts        |   97.56 |    94.73 |     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 | ...59,376-377,422 
  jsonc-editor.ts  |   93.18 |    92.66 |     100 |   93.18 | ...80-381,384-385 
  languageUtils.ts |   98.88 |    97.01 |     100 |   98.88 | 184-185           
  load-undici.ts   |     100 |      100 |     100 |     100 |                   
  ...npm-update.ts |   86.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 |   74.38 |    69.56 |     100 |   74.38 | ...92-103,105-116 
  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       
  ...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.22 |    86.04 |   88.79 |   87.22 |                   
 src               |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/__mocks__/fs  |       0 |        0 |       0 |       0 |                   
  promises.ts      |       0 |        0 |       0 |       0 | 1-48              
 src/agents        |   89.98 |    83.97 |   94.02 |   89.98 |                   
  ...transcript.ts |   88.09 |    85.71 |     100 |   88.09 | ...97,605,611-615 
  ...ent-resume.ts |   84.58 |     76.2 |   78.26 |   84.58 | ...1678-1682,1685 
  ...ound-tasks.ts |   96.14 |     90.1 |   98.76 |   96.14 | ...1728,1748-1751 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...ent-result.ts |    96.8 |    92.68 |     100 |    96.8 | 106,129-131       
  ...n-registry.ts |   95.65 |    89.28 |     100 |   95.65 | ...12-413,485-489 
  ...w-snapshot.ts |   91.86 |       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.2 |     85.4 |   87.28 |    90.2 |                   
  agent-context.ts |     100 |      100 |     100 |     100 |                   
  agent-core.ts    |   84.17 |    73.91 |   76.47 |   84.17 | ...2141,2187-2189 
  agent-events.ts  |     100 |      100 |     100 |     100 |                   
  ...t-headless.ts |   93.49 |    88.09 |   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.95 |     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.79 |    87.79 |   82.35 |   91.79 | ...1774,1823-1826 
  ...ow-prompts.ts |     100 |      100 |     100 |     100 |                   
  ...ow-sandbox.ts |   96.87 |    94.51 |     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.93 |    87.5 |   81.81 |                   
  TeamManager.ts   |   72.02 |     79.2 |   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        |   83.94 |    86.67 |   73.59 |   83.94 |                   
  approval-mode.ts |     100 |      100 |     100 |     100 |                   
  ...xtDefaults.ts |     100 |      100 |     100 |     100 |                   
  config.ts        |   83.16 |    86.32 |   71.69 |   83.16 | ...7676,7680-7681 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  models.ts        |     100 |      100 |     100 |     100 |                   
  storage.ts       |   94.11 |    91.95 |      88 |   94.11 | ...25-426,429-430 
 ...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.57 |    88.06 |   92.87 |   91.57 |                   
  baseLlmClient.ts |   88.28 |    82.48 |   81.81 |   88.28 | ...47,660,666-668 
  client.ts        |   91.23 |     87.2 |   90.41 |   91.23 | ...3247,3343-3344 
  ...tGenerator.ts |   86.34 |    87.34 |   84.61 |   86.34 | ...65-466,511-517 
  ...lScheduler.ts |   89.71 |    86.04 |   95.83 |   89.71 | ...5355,5383-5394 
  geminiChat.ts    |   92.29 |    89.24 |   95.95 |   92.29 | ...4376,4424-4425 
  geminiRequest.ts |     100 |      100 |     100 |     100 |                   
  genai-compat.ts  |     100 |      100 |     100 |     100 |                   
  ...MediaLimit.ts |     100 |    95.83 |     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.33 |    83.33 |      50 |   93.33 | 46-47             
  ...on-helpers.ts |   93.49 |    78.57 |     100 |   93.49 | ...10-211,228-229 
  ...issionFlow.ts |   98.97 |    96.96 |     100 |   98.97 | 107               
  ...try-policy.ts |     100 |      100 |     100 |     100 |                   
  ...ell-policy.ts |   95.19 |    89.47 |     100 |   95.19 | ...44-245,290-291 
  prompts.ts       |   93.57 |    91.42 |   83.33 |   93.57 | ...1187,1390-1391 
  ...ing-effort.ts |     100 |      100 |     100 |     100 |                   
  ...n-recovery.ts |   95.13 |       80 |     100 |   95.13 | ...06-107,142-144 
  ...t-profiler.ts |   96.89 |    80.88 |   88.23 |   96.89 | ...10,117-118,123 
  ...port-retry.ts |     100 |      100 |     100 |     100 |                   
  tokenLimits.ts   |     100 |     92.1 |     100 |     100 | 87,122-139        
  ...reparation.ts |     100 |      100 |     100 |     100 |                   
  ...allIdUtils.ts |   98.41 |    93.02 |     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.49 |    91.17 |     100 |   98.49 | ...94,622-623,669 
 ...ntentGenerator |   96.18 |    87.11 |   95.38 |   96.18 |                   
  ...tGenerator.ts |   97.09 |    86.94 |   94.44 |   97.09 | ...1322,1351,1362 
  converter.ts     |   96.04 |    87.15 |     100 |   96.04 | ...,931,1086-1088 
  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.21 |    86.46 |    92.3 |   95.21 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...tGenerator.ts |   95.12 |     85.4 |   91.89 |   95.12 | ...1169-1170,1198 
  ...tDetection.ts |     100 |      100 |     100 |     100 |                   
 ...ntentGenerator |   91.65 |    90.23 |   95.23 |   91.65 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  converter.ts     |   91.15 |    89.32 |   96.87 |   91.15 | ...1914,2083-2098 
  errorHandler.ts  |     100 |      100 |     100 |     100 |                   
  index.ts         |   60.31 |       75 |      50 |   60.31 | ...71,74-78,90-94 
  ...tGenerator.ts |    66.4 |    70.58 |   88.88 |    66.4 | ...51-157,168-169 
  pipeline.ts      |   96.63 |    90.94 |     100 |   96.63 | ...1100,1108,1203 
  ...ureContext.ts |     100 |      100 |     100 |     100 |                   
  ...ingOptions.ts |       0 |        0 |       0 |       0 | 1                 
  ...CallParser.ts |   92.24 |     92.4 |     100 |   92.24 | ...28-529,549-552 
  ...kingParser.ts |     100 |    96.87 |     100 |     100 | 42                
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...rator/provider |   96.73 |    89.76 |   98.27 |   96.73 |                   
  dashscope.ts     |   97.48 |    91.91 |      95 |   97.48 | ...85-386,528-529 
  deepseek.ts      |   94.91 |    89.36 |     100 |   94.91 | ...31-132,145-146 
  default.ts       |   99.16 |    96.96 |     100 |   99.16 | 198               
  index.ts         |     100 |      100 |     100 |     100 |                   
  mimo.ts          |   94.11 |    66.66 |     100 |   94.11 | 29,52-53          
  minimax.ts       |     100 |      100 |     100 |     100 |                   
  mistral.ts       |   96.07 |    73.33 |     100 |   96.07 | 32-33             
  modelscope.ts    |     100 |      100 |     100 |     100 |                   
  types.ts         |       0 |        0 |       0 |       0 |                   
  utils.ts         |     100 |      100 |     100 |     100 |                   
  zai.ts           |   92.13 |    82.14 |     100 |   92.13 | ...,39-40,135-137 
 src/extension     |   86.12 |    83.12 |   92.19 |   86.12 |                   
  ...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 |   80.59 |    78.06 |   80.23 |   80.59 | ...2577,2599-2600 
  ...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      |   77.38 |    79.84 |    90.9 |   77.38 |                   
  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   |   65.26 |    62.63 |   71.42 |   65.26 | ...17-618,625-626 
  ...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         |   93.95 |    88.55 |    95.9 |   93.95 |                   
  ...eGoalStore.ts |   87.61 |    88.88 |   86.66 |   87.61 | ...85-188,196-204 
  goal-evidence.ts |   87.59 |     85.1 |   95.65 |   87.59 | ...12-613,636-639 
  ...projection.ts |   89.41 |    72.22 |   66.66 |   89.41 | ...28,131,135-137 
  ...ersistence.ts |   83.96 |       76 |      80 |   83.96 | ...0,93-94,97-106 
  goal-protocol.ts |    91.3 |       90 |     100 |    91.3 | 107-108           
  goal-reducer.ts  |   92.21 |    85.48 |     100 |   92.21 | ...67-368,381,436 
  goal-runtime.ts  |   98.74 |    93.43 |     100 |   98.74 | ...66-667,690-691 
  goal-tools.ts    |   98.32 |    93.18 |   95.23 |   98.32 | ...48-149,256-257 
  ...rn-context.ts |     100 |      100 |     100 |     100 |                   
  goal-verifier.ts |   92.46 |    92.85 |     100 |   92.46 | ...67-170,183-185 
  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         |   87.43 |    85.86 |   88.38 |   87.43 |                   
  ...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.46 |       84 |   94.59 |   95.46 | ...1015-1016,1026 
  hookPlanner.ts   |    87.5 |    85.36 |   86.66 |    87.5 | ...21-225,232-243 
  hookRegistry.ts  |   92.53 |    85.43 |     100 |   92.53 | ...39,458,462,466 
  hookRunner.ts    |   62.48 |    72.04 |   66.66 |   62.48 | ...67-768,777-778 
  hookSystem.ts    |   87.55 |      100 |   70.21 |   87.55 | ...45-746,752-753 
  ...HookRunner.ts |   75.51 |     61.9 |      80 |   75.51 | ...05-406,424-425 
  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     |   77.22 |    86.74 |     100 |   77.22 | ...57,261-267,273 
  stopHookCap.ts   |     100 |      100 |     100 |     100 |                   
  trustedHooks.ts  |      90 |    52.63 |     100 |      90 | ...53,66-67,97-98 
  types.ts         |   94.24 |    96.09 |   88.88 |   94.24 | ...42-543,628-632 
  urlValidator.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.17 |     82.8 |   90.29 |   87.17 |                   
  ...y-document.ts |   89.52 |    84.61 |     100 |   89.52 | ...24-325,329-330 
  ...nel-memory.ts |   97.11 |    95.72 |   96.29 |   97.11 | ...85-287,361-362 
  const.ts         |   94.28 |     92.3 |     100 |   94.28 | 66-67             
  dream.ts         |    64.6 |    72.22 |      50 |    64.6 | ...04-109,124-165 
  ...entPlanner.ts |     100 |    81.81 |     100 |     100 | 126,136           
  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.51 |    76.19 |     100 |   91.51 | ...04,113-116,290 
  ...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 |   82.27 |    77.92 |   83.33 |   82.27 | ...66,285,292-298 
  memoryAge.ts     |   90.47 |       80 |     100 |   90.47 | 50-51             
  paths.ts         |   94.73 |    95.94 |     100 |   94.73 | ...35-336,357-358 
  ...ing-skills.ts |     100 |       72 |     100 |     100 | 31-35,73-78,97    
  prompt.ts        |   97.26 |    86.79 |     100 |   97.26 | ...10-218,222,225 
  recall.ts        |   82.06 |       75 |    90.9 |   82.06 | ...59-364,395-406 
  refresh.ts       |   89.85 |    82.92 |     100 |   89.85 | ...54-155,162-163 
  ...ceSelector.ts |    93.1 |    81.81 |     100 |    93.1 | ...25,127-128,136 
  remember.ts      |   98.89 |    89.79 |     100 |   98.89 | 50,70             
  scan.ts          |   93.12 |    74.19 |     100 |   93.12 | ...08-109,154,157 
  ...et-scanner.ts |     100 |      100 |     100 |     100 |                   
  ...entPlanner.ts |   71.68 |    65.51 |   68.75 |   71.68 | ...90-394,397,403 
  status.ts        |   10.52 |      100 |       0 |   10.52 | 41-98             
  store.ts         |   92.92 |    81.81 |     100 |   92.92 | ...16-117,147-148 
  ...git-status.ts |     100 |     87.5 |     100 |     100 | 30                
  ...cret-guard.ts |     100 |      100 |     100 |     100 |                   
  ...emory-sync.ts |   94.24 |    82.85 |     100 |   94.24 | ...34-236,246-247 
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...ontextFile.ts |   81.21 |    81.53 |   81.81 |   81.21 | ...63-277,291-296 
 src/mocks         |       0 |        0 |       0 |       0 |                   
  msw.ts           |       0 |        0 |       0 |       0 | 1-9               
 src/models        |   92.54 |    88.91 |   91.13 |   92.54 |                   
  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,260           
  modelsConfig.ts  |   89.36 |    86.77 |   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.57 |    91.01 |   70.71 |   83.57 |                   
  autoMode.ts      |   97.65 |    93.13 |     100 |   97.65 | ...79-586,632,709 
  ...transcript.ts |      98 |    84.61 |     100 |      98 | 200-201           
  classifier.ts    |      94 |    94.54 |     100 |      94 | 158-165,389-393   
  ...erousRules.ts |     100 |    89.36 |     100 |     100 | 110,133,147,175   
  ...alTracking.ts |     100 |      100 |     100 |     100 |                   
  ...e-commands.ts |   86.77 |     73.8 |     100 |   86.77 | 131-141,210-214   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...on-manager.ts |   86.54 |    89.57 |      80 |   86.54 | ...1096,1202-1206 
  rule-parser.ts   |   94.18 |    91.89 |     100 |   94.18 | ...1345,1379-1381 
  ...-semantics.ts |   70.36 |    91.04 |   46.66 |   70.36 | ...2237,2300-2303 
  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.55 |    85.02 |   96.44 |   89.55 |                   
  ...ionTrailer.ts |     100 |      100 |     100 |     100 |                   
  ...llRegistry.ts |   97.66 |    85.71 |     100 |   97.66 | ...95,118,487-488 
  ...ionService.ts |   96.71 |    95.79 |     100 |   96.71 | ...83,699,832-840 
  ...ingService.ts |   89.85 |    83.42 |   93.93 |   89.85 | ...2021,2048-2049 
  ...ttribution.ts |   91.73 |    87.71 |      90 |   91.73 | ...80-685,826-827 
  ...utSlimming.ts |    97.2 |    94.05 |     100 |    97.2 | ...39-340,378-381 
  cronScheduler.ts |   94.12 |    90.45 |      98 |   94.12 | ...1323,1726-1727 
  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.22 |    86.11 |   91.66 |   92.22 | ...80-281,349-356 
  ...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.88 |     100 |   98.39 | 154-155,215-216   
  ...ionService.ts |   98.22 |    97.32 |     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.27 |    91.22 |     100 |   97.27 | ...50-451,606-607 
  ...ttachments.ts |   97.74 |     90.8 |     100 |   97.74 | 298-308,646       
  ...ersistence.ts |   90.95 |    78.75 |     100 |   90.95 | ...78,963-964,992 
  ...on-service.ts |   94.49 |    92.26 |   97.14 |   94.49 | ...98-600,656-664 
  ...ce-service.ts |   98.38 |    93.75 |   88.88 |   98.38 | 63-64             
  ...ipt-reader.ts |   94.61 |    89.76 |      98 |   94.61 | ...1083-1084,1148 
  ...est-helper.ts |       0 |        0 |       0 |       0 | 1-65              
  ...iter-lease.ts |   74.62 |    74.87 |   90.24 |   74.62 | ...69-887,908-920 
  sessionRecap.ts  |   67.56 |    43.47 |     100 |   67.56 | ...60,178,180-183 
  ...ionService.ts |   88.73 |     83.5 |    97.1 |   88.73 | ...2401,2471-2491 
  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.68 |     100 |   97.42 | ...30,169,369-370 
  ...Estimation.ts |     100 |    86.66 |     100 |     100 | 96-97             
  ...ageService.ts |   97.76 |    91.59 |   93.75 |   97.76 | ...61-262,366,567 
  ...UseSummary.ts |   94.63 |    88.46 |     100 |   94.63 | ...62-164,214-215 
  ...rd-service.ts |     100 |    88.37 |     100 |     100 | ...29,145-146,241 
  ...oryService.ts |   90.72 |    84.07 |     100 |   90.72 | ...06-509,561-562 
  ...reeCleanup.ts |   14.42 |      100 |   33.33 |   14.42 | 58-186            
  ...ionService.ts |   87.98 |    86.84 |     100 |   87.98 | ...38-439,455-456 
 ...icrocompaction |   99.41 |    96.06 |     100 |   99.41 |                   
  microcompact.ts  |   99.41 |    96.06 |     100 |   99.41 | 244-245,677       
 ...s/visionBridge |    98.6 |    94.11 |     100 |    98.6 |                   
  ...capability.ts |     100 |      100 |     100 |     100 |                   
  ...part-utils.ts |     100 |      100 |     100 |     100 |                   
  ...-constants.ts |     100 |      100 |     100 |     100 |                   
  ...ge-service.ts |   98.32 |    92.64 |     100 |   98.32 | ...23,647,660-661 
 src/skills        |   88.37 |    87.22 |   90.16 |   88.37 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...activation.ts |     100 |    93.33 |     100 |     100 | 93,112            
  skill-load.ts    |   94.84 |     87.5 |     100 |   94.84 | ...03,223,235-237 
  skill-manager.ts |   83.78 |    82.63 |   82.35 |   83.78 | ...1218,1225-1229 
  skill-paths.ts   |   89.65 |    86.95 |     100 |   89.65 | ...11-112,117-118 
  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.63 |    88.64 |   96.55 |   87.63 |                   
  ...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.25 |    85.31 |   94.87 |   84.25 | ...1566,1643-1644 
  types.ts         |     100 |      100 |     100 |     100 |                   
  validation.ts    |   92.46 |    95.18 |     100 |   92.46 | 47-52,63-68,71-76 
 src/telemetry     |   80.69 |    83.11 |   84.29 |   80.69 |                   
  ...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 |     100 |    90.47 |     100 |     100 | 49,76             
  ...-exporters.ts |   65.78 |    83.33 |   55.55 |   65.78 | ...04-105,108-109 
  ...ai-content.ts |    74.5 |    66.41 |   91.66 |    74.5 | ...1480,1493-1502 
  ...i-provider.ts |     100 |       99 |     100 |     100 | 99                
  ...ai-request.ts |   87.52 |    92.79 |   83.78 |   87.52 | ...55-561,564-570 
  gen-ai-usage.ts  |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...t.circular.ts |       0 |        0 |       0 |       0 | 1-111             
  ...-processor.ts |   99.09 |    95.61 |      95 |   99.09 | 141,365-366       
  ...t.circular.ts |       0 |        0 |       0 |       0 | 1-128             
  loggers.ts       |   55.35 |    71.56 |   63.46 |   55.35 | ...1350,1367-1387 
  metrics.ts       |   78.44 |    79.62 |   79.66 |   78.44 | ...1079,1082-1093 
  otlp-urls.ts     |     100 |      100 |     100 |     100 |                   
  ...attributes.ts |     100 |      100 |     100 |     100 |                   
  ...ime-config.ts |       0 |        0 |       0 |       0 | 1                 
  sanitize.ts      |      80 |    83.33 |     100 |      80 | 35-36,41-42       
  ...rters-grpc.ts |     100 |      100 |     100 |     100 |                   
  ...rters-http.ts |     100 |      100 |     100 |     100 |                   
  sdk-impl.ts      |   91.06 |    87.15 |   68.75 |   91.06 | ...32,478-479,495 
  sdk.ts           |   79.22 |    89.18 |   63.63 |   79.22 | ...57-161,199-221 
  ...on-context.ts |     100 |      100 |     100 |     100 |                   
  ...on-tracing.ts |   90.38 |    89.22 |   96.66 |   90.38 | ...1611,1642-1645 
  ...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.05 |    86.95 |   85.71 |   82.05 | ...1332,1336-1343 
  uiTelemetry.ts   |   97.18 |    93.93 |      88 |   97.18 | ...70,314,461-462 
 ...ry/qwen-logger |   73.62 |    81.25 |   69.49 |   73.62 |                   
  event-types.ts   |       0 |        0 |       0 |       0 |                   
  qwen-logger.ts   |   73.62 |    81.08 |   68.96 |   73.62 | ...1095,1133-1134 
 src/test-utils    |      94 |    98.24 |   78.94 |      94 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  ...st-helpers.ts |   94.11 |       90 |     100 |   94.11 | 69-70             
  index.ts         |     100 |      100 |     100 |     100 |                   
  mock-tool.ts     |   92.57 |      100 |   75.75 |   92.57 | ...63,227-228,241 
  ...aceContext.ts |     100 |      100 |     100 |     100 |                   
 src/tools         |   85.88 |    84.61 |   88.23 |   85.88 |                   
  ...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 |                   
  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.24 |    92.85 |     100 |   99.24 | 44                
  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.63 |       79 |   85.41 |   81.63 | ...3221,3223-3224 
  mcp-client.ts    |   79.83 |    85.09 |   89.47 |   79.83 | ...2233,2237-2240 
  ...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      |   95.43 |    93.89 |     100 |   95.43 | ...79-780,830-831 
  ...sport-pool.ts |   83.49 |    80.15 |   84.61 |   83.49 | ...1409,1416-1420 
  ...ace-budget.ts |   87.27 |     82.6 |     100 |   87.27 | ...00-305,340-345 
  memory-config.ts |     100 |      100 |     100 |     100 |                   
  ...iable-tool.ts |     100 |    84.61 |     100 |     100 | 101,108           
  monitor.ts       |   91.74 |    84.28 |   88.46 |   91.74 | ...93,606,804-809 
  notebook-edit.ts |   85.55 |    77.39 |   81.25 |   85.55 | ...86-902,948-949 
  ...escendants.ts |   36.17 |    64.51 |   55.55 |   36.17 | ...46-310,385-390 
  ...nforcement.ts |   82.57 |    90.24 |     100 |   82.57 | 174-185,234-247   
  read-file.ts     |   95.48 |    88.52 |   86.66 |   95.48 | ...48,463,535-536 
  ...p-resource.ts |   96.85 |      100 |   91.66 |   96.85 | 92-96             
  ...d-artifact.ts |    90.9 |    86.71 |    87.5 |    90.9 | ...13-414,428-440 
  ripGrep.ts       |    95.9 |     88.4 |   94.73 |    95.9 | ...61-662,668-669 
  ...-transport.ts |   71.42 |    55.55 |   71.42 |   71.42 | ...36-137,143-144 
  send-message.ts  |    81.2 |    89.74 |    62.5 |    81.2 | ...80-286,369-377 
  ...n-mcp-view.ts |   93.57 |     92.3 |      90 |   93.57 | 122-130           
  shell.ts         |   78.61 |     83.9 |   91.91 |   78.61 | ...5012,5075-5076 
  skill-utils.ts   |     100 |      100 |     100 |     100 |                   
  skill.ts         |   91.06 |    93.33 |   89.47 |   91.06 | ...71,475,520-542 
  ...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     |   93.92 |    83.13 |   92.85 |   93.92 | ...86-391,413-414 
  tool-error.ts    |     100 |      100 |     100 |     100 |                   
  tool-names.ts    |     100 |      100 |     100 |     100 |                   
  tool-registry.ts |   78.06 |    78.83 |   82.22 |   78.06 | ...37-938,946-947 
  tool-search.ts   |   96.19 |    89.72 |   93.33 |   96.19 | ...09,259-264,426 
  tools.ts         |   92.74 |    91.52 |    91.3 |   92.74 | ...63-564,580-586 
  ...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    |   85.66 |    85.04 |   85.71 |   85.66 | ...53-756,793-828 
  zoom-image.ts    |   95.38 |    94.54 |   91.66 |   95.38 | ...54-258,355-356 
 src/tools/agent   |   85.37 |    85.69 |   86.66 |   85.37 |                   
  agent.ts         |   85.22 |    85.48 |   86.17 |   85.22 | ...4155,4177-4187 
  fork-subagent.ts |   88.32 |       90 |    90.9 |   88.32 | ...05-123,200-201 
 ...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 |   87.46 |    79.41 |   85.71 |   87.46 |                   
  workflow.ts      |   87.46 |    79.41 |   85.71 |   87.46 | ...51-652,664-667 
 src/utils         |   92.67 |    89.68 |   96.78 |   92.67 |                   
  LruCache.ts      |     100 |      100 |     100 |     100 |                   
  ...Controller.ts |     100 |      100 |     100 |     100 |                   
  ...ssageQueue.ts |     100 |      100 |     100 |     100 |                   
  ...cFileWrite.ts |   94.94 |    92.47 |     100 |   94.94 | ...43-544,651-655 
  bareMode.ts      |   81.81 |      100 |      50 |   81.81 | 18-19             
  ...ry-content.ts |   98.45 |    95.45 |     100 |   98.45 | 132-133,159-160   
  browser.ts       |   86.84 |    78.94 |     100 |   86.84 | 34,36-37,65-66    
  btwUtils.ts      |   13.95 |      100 |       0 |   13.95 | 17-31,34-55       
  bundlePaths.ts   |     100 |      100 |     100 |     100 |                   
  ...on-context.ts |     100 |      100 |     100 |     100 |                   
  ...ncyLimiter.ts |   94.64 |    95.23 |     100 |   94.64 | 64-66             
  ...igResolver.ts |     100 |      100 |     100 |     100 |                   
  ...engthError.ts |   91.06 |    89.47 |     100 |   91.06 | ...46-147,154-155 
  ...n-branches.ts |   95.81 |    93.95 |      95 |   95.81 | ...91-492,504-517 
  ...tion-chain.ts |     100 |      100 |     100 |     100 |                   
  cronDisplay.ts   |     100 |    97.61 |     100 |     100 | 46                
  cronParser.ts    |   95.34 |    93.33 |     100 |   95.34 | 41-42,47-48,70-71 
  debugLogger.ts   |   96.66 |    96.61 |   88.88 |   96.66 | 192-196           
  editHelper.ts    |   93.63 |     83.9 |     100 |   93.63 | ...27-428,462-463 
  editor.ts        |   97.65 |    95.45 |     100 |   97.65 | ...35-336,338-339 
  encoding.ts      |     100 |      100 |     100 |     100 |                   
  env.ts           |     100 |      100 |     100 |     100 |                   
  ...arResolver.ts |   94.28 |    88.88 |     100 |   94.28 | 28-29,125-126     
  ...entContext.ts |   96.63 |    90.06 |   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     |    95.3 |    92.06 |   96.15 |    95.3 | ...1773,1798-1799 
  forkedAgent.ts   |   92.45 |    82.35 |   93.75 |   92.45 | ...34,642,647-654 
  formatters.ts    |   81.81 |       75 |     100 |   81.81 | 15-16             
  ...eUtilities.ts |    92.4 |    86.95 |     100 |    92.4 | ...52-158,168-169 
  ...rStructure.ts |   94.36 |    94.28 |     100 |   94.36 | ...17-120,331-336 
  getPty.ts        |   31.57 |       50 |     100 |   31.57 | 26-38             
  gitDiff.ts       |   95.12 |    81.03 |     100 |   95.12 | ...1073,1390-1391 
  gitDirect.ts     |   98.46 |    90.17 |     100 |   98.46 | 148,268,352       
  ...noreParser.ts |   94.48 |    93.22 |     100 |   94.48 | ...23-124,158-159 
  gitUtils.ts      |      75 |    89.47 |   83.33 |      75 | ...,78-79,103-154 
  github-prs.ts    |    99.3 |    90.62 |     100 |    99.3 | 204               
  iconvHelper.ts   |     100 |      100 |     100 |     100 |                   
  ...rePatterns.ts |     100 |      100 |     100 |     100 |                   
  ...ionManager.ts |     100 |     90.9 |     100 |     100 | 27                
  ...lPromptIds.ts |     100 |      100 |     100 |     100 |                   
  ...on-context.ts |     100 |      100 |     100 |     100 |                   
  jsonl-utils.ts   |   95.27 |    93.25 |     100 |   95.27 | ...16-317,359-362 
  ...-detection.ts |     100 |      100 |     100 |     100 |                   
  ...iconv-lite.ts |     100 |      100 |     100 |     100 |                   
  ...simple-git.ts |   96.77 |    91.66 |     100 |   96.77 | 38                
  ...m-headless.ts |      96 |    88.88 |     100 |      96 | 34                
  ...iagnostics.ts |    96.4 |     94.2 |     100 |    96.4 | ...66,293-294,376 
  ...yDiscovery.ts |    92.4 |    89.13 |     100 |    92.4 | ...28,331,522-525 
  ...tProcessor.ts |   93.77 |    89.15 |     100 |   93.77 | ...13-319,406-407 
  ...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.61 |     100 |     100 | 206               
  pathReader.ts    |   97.77 |       90 |     100 |   97.77 | 93,121            
  paths.ts         |   93.95 |    92.79 |     100 |   93.95 | ...78-479,481-483 
  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 |   97.73 |    93.24 |     100 |   97.73 | 85-86,107,262-263 
  readManyFiles.ts |   96.29 |     87.5 |     100 |   96.29 | 225,275,286-290   
  retry.ts         |   96.03 |    92.38 |     100 |   96.03 | ...60,551-552,570 
  retryContext.ts  |     100 |      100 |     100 |     100 |                   
  ...sification.ts |   97.65 |    96.96 |     100 |   97.65 | ...00,250-251,277 
  retryPolicy.ts   |   97.72 |    90.56 |     100 |   97.72 | 130-131           
  ripgrepUtils.ts  |   80.47 |     82.6 |    90.9 |   80.47 | ...75-380,384-387 
  ...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 |   97.98 |     97.7 |     100 |   97.98 | 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.8 |     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.05 |    88.59 |     100 |   86.05 | ...2251,2258-2262 
  ...lAstParser.ts |   98.16 |    91.91 |     100 |   98.16 | ...1244-1246,1256 
  ...ContextEnv.ts |     100 |    90.47 |     100 |     100 | 46-48             
  ...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.82 |     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 |    30.76 |      75 |   54.62 | ...03-105,108-134 
  ...Compaction.ts |   96.11 |    96.22 |     100 |   96.11 | ...22-327,329-334 
  ...pt-records.ts |   85.85 |    83.63 |     100 |   85.85 | ...86-390,420-435 
  truncation.ts    |   90.56 |    90.51 |     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.68 |    80.38 |   94.69 |   83.68 |                   
  crawlCache.ts    |     100 |      100 |     100 |     100 |                   
  crawler.ts       |   82.47 |    76.22 |      95 |   82.47 | ...1525,1559-1560 
  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 commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

🩺 serve daemon A/B

Built the PR base vs this PR head 7396e3e, drove a fixed endpoint set against each, and diffed the JSON responses. Only fields that changed are shown.

No response changes against the PR base across 4 scenario(s).

Qwen Code · serve A/B

@doudouOUC
doudouOUC marked this pull request as ready for review July 27, 2026 09:22
@doudouOUC
doudouOUC enabled auto-merge July 27, 2026 09:23
@doudouOUC doudouOUC self-assigned this Jul 27, 2026
@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

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

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

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Thanks for the PR!

Template looks good ✓

Problem: observed bug with clear evidence. Linked to P0 issue #7752 — a managed daemon replacement on a different hostname cannot prove the previous ACP child's foreign-host writer lock is stale, so it returns session_writer_conflict indefinitely. The failure mode is well-described and the fix targets the normal termination path (cooperative lock release) rather than trying to make stale-lock detection safe across hosts.

Direction: aligned. This is the correct P0 fix — making lock release an acknowledged part of managed child shutdown, while preserving fail-closed behavior when evidence is uncertain. The design doc (docs/design/managed-session-writer-shutdown.md) clearly scopes what's in and what's deferred (sealed handoff, TTL, hostname stealing, maintenance leases). CHANGELOG: no direct reference to this specific fix, but daemon session management is an active area.

Size: this is a cross-package change touching core paths (packages/core/src/config/config.ts, packages/core/src/services/chatRecordingService.ts, packages/core/src/services/session-writer-lease.ts) plus packages/acp-bridge/ and packages/cli/. Production logic: ~1304 lines (additions + deletions, excluding tests). Test lines: ~1235. Doc/config: ~141. The 1000+ advisory applies — this is a large PR, but the scope is justified: cooperative shutdown necessarily spans process lifecycle, writer locks, session admission, and resource cleanup. Splitting would create artificial seams in what is a single atomic behavior change.

Approach: the scope feels right for the problem. The atomic rename (PR) as the release commit point is the key insight — it makes the old owner's cleanup safe regardless of successor state. The ProcessRegistry cleanly replaces the ad-hoc killChild timer logic. The beginManagedShutdown() / finishManagedShutdown() split in acpAgent.ts correctly separates writer terminal from resource cleanup. I don't see a materially simpler path that preserves the safety guarantees.

Risk: ⚠️ high-risk path detected — packages/cli/src/acp-integration/acpAgent.ts matches the revert-correlated acp-integration pattern. This escalates review depth: full CI evidence required before approval, and E2E verification recommended (author has write access, so the sandboxed lanes are available).

Moving on to code review. 🔍

中文说明

感谢贡献!

模板完整 ✓

问题:已观测到的 bug,有明确证据。关联 P0 issue #7752——托管 daemon 替代实例在不同 hostname 启动时,无法证明前一个 ACP 子进程的外部 hostname writer 锁已过期,因此无限期返回 session_writer_conflict。失败模式描述清晰,修复针对正常终止路径(协作式锁释放),而非尝试让跨 host 的 stale-lock 检测变安全。

方向:对齐。这是正确的 P0 修复——将锁释放变成托管子进程关闭确认的一部分,同时在证据不确定时保持 fail-closed 行为。设计文档清楚地界定了范围内和范围外的内容。

规模:跨包变更,触及核心路径。生产逻辑约 1304 行,测试约 1235 行,文档/配置约 141 行。超过 1000 行大 PR 建议适用——但范围合理:协作式关闭必然跨越进程生命周期、writer 锁、会话准入和资源清理。

方案:范围合理。原子 rename(PR)作为释放提交点是关键洞察。ProcessRegistry 干净地替代了临时 killChild 定时器逻辑。beginManagedShutdown() / finishManagedShutdown() 分离正确区分了 writer 终态和资源清理。

风险:⚠️ 检测到高风险路径——packages/cli/src/acp-integration/acpAgent.ts 匹配 revert 相关的 acp-integration 模式。升级 review 深度:批准前需要完整 CI 证据,建议 E2E 验证。

进入代码审查 🔍

Qwen Code · qwen3.8-max-preview

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

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Code Review

Independent proposal: for this problem I would have (1) made the ACP child release writer locks in its SIGTERM handler, (2) tracked all spawned children in the daemon parent with a bounded TERM→KILL→deadline timeline, (3) made lock release atomic so a successor can't be confused, (4) closed session admission once shutdown starts, and (5) reported unclean shutdown when release fails.

Comparison: the PR matches and exceeds this baseline. The atomic rename (P → owner-unique R) as the release commit point is strictly better than a plain unlink — it makes the old owner's post-commit cleanup safe regardless of whether a successor has already created a new P. The initializingConfigs tracking and strictResourceCleanup mode handle a race I would have missed: a Config mid-initialization when shutdown starts could otherwise create watchers or MCP managers after cleanup has returned. The reclaimPolicy: 'never' for managed mode is a clean addition that prevents lock stealing even for local stale locks, which is correct when two Pods can overlap on the same workspace.

No critical blockers found. No AGENTS.md violations. The new process-registry.ts follows kebab-case naming, tests are collocated, ESM throughout. The retryableChannelWorkerShutdownErrors WeakSet is non-obvious but solves a real distinction (channel-worker retryable vs ACP-process fatal) without adding a new error class hierarchy — acceptable.

One observation (non-blocking): the multiple sessionWriterShutdownRequested checks at each await boundary in activateChatRecording() are verbose but necessary — without them, a slow lease acquisition could complete after shutdown, creating a writer nobody will close. The pattern is correct.

Testing

CI evidence (from the PR's own checks on the reviewed commit):

Check Conclusion
Test (ubuntu-latest, Node 22.x) ✅ success
Serve A/B (ubuntu-latest, Node 22.x) ✅ success
Real daemon E2E / Java 11 ✅ success
web-shell E2E Smoke (ubuntu-latest, Node 22.x) ✅ success
Classify PR ✅ success
Post Coverage Comment (ubuntu-latest, 22.x) ✅ success
Test (macos-latest, Node 22.x) ⏭️ skipped (conditional)
Test (windows-latest, Node 22.x) ⏭️ skipped (conditional)
Integration Tests (CLI, No Sandbox) ⏭️ skipped (conditional)

All substantive checks green. The macOS/Windows/Integration skips are conditional (not failures). The Serve A/B and Real daemon E2E passes are particularly relevant — they exercise the daemon lifecycle path this PR modifies.

Real-scenario testing: N/A — daemon lifecycle and persistence behavior only; no TUI or Web UI changes. The author's test plan describes a real managed-ACP harness (3 writer locks released 3/3, clean exit ~266ms after SIGTERM), but that is the author's claim, not independently verified here. A maintainer can trigger @qwen-code /tmux or @qwen-code /verify for isolated E2E confirmation (author has write access, so the sandboxed lanes are available).

Not verified: Windows and Linux behavior (author tested macOS only). Kubernetes rolling replacement was not exercised. SIGKILL-before-handler and event-loop stall scenarios remain theoretical (by design — they produce unclean shutdown, which is the safe outcome).

中文说明

代码审查

独立方案: 我会 (1) 让 ACP 子进程在 SIGTERM handler 中释放 writer 锁,(2) 在 daemon 父进程中跟踪所有子进程并使用有界的 TERM→KILL→截止时间线,(3) 让锁释放原子化以免后继者混淆,(4) 关闭开始后拒绝新会话,(5) 释放失败时报告不干净关闭。

对比: PR 匹配并超越了基线方案。原子 rename(P → owner 唯一的 R)作为释放提交点严格优于普通 unlink——使旧 owner 提交后的清理安全,无论后继者是否已创建新的 PinitializingConfigs 跟踪和 strictResourceCleanup 模式处理了一个容易遗漏的竞态:关闭开始时正在初始化的 Config 可能在清理返回后创建 watcher 或 MCP manager。托管模式的 reclaimPolicy: 'never' 是干净的补充,在两个 Pod 可能重叠同一 workspace 时正确禁止锁抢占。

未发现关键阻塞问题。未发现 AGENTS.md 违规。

测试

CI 证据:所有实质性检查通过。Serve A/BReal daemon E2E 通过尤其相关——它们验证了本 PR 修改的 daemon 生命周期路径。

真实场景测试:N/A——仅涉及 daemon 生命周期与持久化行为,没有 TUI 或 Web UI 变化。维护者可触发 @qwen-code /tmux@qwen-code /verify 进行隔离 E2E 确认。

未验证:Windows 和 Linux 行为。Kubernetes 滚动替换未执行。

Qwen Code · qwen3.8-max-preview

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

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Confidence: 4/5 — solid P0 fix with sound design, thorough tests, and green CI; the high-risk path match and untested Windows/Linux paths keep it from a perfect score, but nothing blocks.

This is a well-executed fix for a real operational problem. The design doc scopes the work honestly — what's in, what's deferred, and why automatic lock stealing is unsafe. The implementation follows through: the atomic rename as release commit point, the fail-closed behavior on any uncertainty, the bounded process timeline, and the initialization-race handling all show careful thinking about the failure modes that matter in production.

The test coverage is extensive (1235 lines) and covers the right edge cases: flush failure, rename error after effect, successor acquisition, shutdown during initialization, concurrent shutdown calls, and the stable-terminal guarantee on release failure. CI is fully green, including the daemon-specific Serve A/B and Real daemon E2E checks that exercise the exact lifecycle path this PR modifies.

Non-blocking nits: the retryableChannelWorkerShutdownErrors WeakSet is clever but non-obvious — a short comment at the declaration site explaining why error-identity tagging was chosen over a subclass would help future readers. The Windows/Linux paths are untested (author notes this honestly), and the Kubernetes rolling replacement scenario remains a follow-up.

Ships the feature cleanly. The before/after is clear: managed daemon replacement goes from "indefinite session_writer_conflict" to "cooperative lock release in ~266ms, well before the 5s escalation deadline."

中文说明

置信度:4/5 —— 可靠的 P0 修复,设计合理,测试充分,CI 全绿;高风险路径匹配和未测试的 Windows/Linux 路径使其未达满分,但没有阻塞项。

这是一个针对真实运维问题的精心修复。设计文档诚实地界定了工作范围——范围内、范围外、以及为什么自动锁抢占不安全。实现跟进了:原子 rename 作为释放提交点、任何不确定性时的 fail-closed 行为、有界的进程时间线、以及初始化竞态处理,都展示了对生产环境中重要失败模式的仔细思考。

测试覆盖广泛(1235 行),覆盖了正确的边缘情况。CI 全绿,包括验证本 PR 修改的生命周期路径的 daemon 特定检查。

非阻塞建议:retryableChannelWorkerShutdownErrors WeakSet 巧妙但不直观——在声明处加一个短注释解释为什么选择错误标识标记而非子类会有助于未来读者。

干净地交付了功能。前后对比清晰:托管 daemon 替换从"无限期 session_writer_conflict"变为"约 266ms 内协作式锁释放,远早于 5 秒升级截止时间"。

Qwen Code · qwen3.8-max-preview

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

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

⏸️ Deferring to @doudouOUC — the review is clean and CI is green, but the core-path size escalation (1198 production lines touching packages/core config and services) requires a maintainer explicit sign-off per the gate policy. No blocking code concerns found — this needs a human approval decision on the scale, not a code fix.

@wenshao

wenshao commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

Review — fix(serve): Release managed session writer locks on shutdown

Reviewed at b1429f58a (19 files, +1855/-312). Read the full diff plus surrounding code in session-writer-lease.ts, chatRecordingService.ts, config.ts, acpAgent.ts, bridge.ts, process-registry.ts, run-qwen-serve.ts.

Overview

Makes writer-lock release an acknowledged part of managed ACP child shutdown so a replacement daemon on a new hostname isn't blocked by session_writer_conflict forever. Four moving parts:

  1. Lease — release commits via a same-directory rename(P → R) instead of unlink(P), a failed release is now a stable terminal (no retry of the primary path), plus reclaimPolicy: 'never' so managed acquisition never steals by hostname/age/PID.
  2. Recorder / ConfigbeginClose() closes write admission synchronously; Config.closeSessionWriter() is a single-flight writer terminal separate from resource cleanup, which now joins in-flight initialize().
  3. AgentbeginManagedShutdown() snapshots every writer-capable Config and starts all writer terminals before the first await; hooks and resource cleanup run after.
  4. Parent — a new daemon-scoped ProcessRegistry owns one SIGTERM→5s SIGKILL→10s reap timeline shared by primary/secondary/dynamic runtimes, and bridge.shutdown() now propagates teardown failures instead of swallowing them.

The core design is sound, and the ordering discipline (writer terminal first, hooks second, resources last) is exactly right for the P0. The design doc is genuinely useful. My concerns are about which failures are classified as "retain the lock" / "unclean", and about the blast radius of bridge.shutdown() becoming a rejecting call.


High

1. A single transient append failure now wedges the lock permanently — the exact failure mode this PR removes.

closeOnce() rethrows on flush failure and never reaches lease.release() (packages/core/src/services/chatRecordingService.ts:1114). flush() throws this.writeFailure (:1042), and writeFailure is sticky for the recorder's lifetime — set once in enterWriteFailure (:846) and never cleared anywhere in the file.

So the retention trigger is "any append failed at any point in this session", not "ownership is uncertain" as the PR description states. The PR's own new test encodes this:

vi.mocked(mockLease.appendJsonLine).mockRejectedValueOnce(failure);
chatRecordingService.recordUserMessage([{ text: 'not durable' }]);
await expect(chatRecordingService.close()).rejects.toBe(failure);
expect(mockLease.release).not.toHaveBeenCalled();

Failure scenario: a session runs for two hours; at minute 3 one appendJsonLine hits a transient EIO/ENOSPC. The recorder degrades (acceptingWrites = false — it will provably never write again). At shutdown, close() throws, the lock is retained, and because managed acquisition uses reclaimPolicy: 'never', no successor can ever acquire it — not by age, not by hostname, not after the pod is gone. Recovery is manual rm of the lock file. Pre-PR, that same session released its lock (old close() captured flushFailure, released, then rethrew).

Suggestions — either would resolve it:

  • Gate retention on this.integrityFailure (ownership / transcript-identity uncertainty) rather than this.writeFailure. A plain fs write error doesn't leave ownership ambiguous.
  • If retention is intended for all write failures, emit an operator-visible warning naming the lock path and the recovery step. debugLogger.error is invisible unless debug logging is on, so today this fails silently and the operator only learns about it from the successor's 409.

2. The child's own cleanup budget exceeds the parent's SIGKILL grace, so ordinary restarts will report unclean.

Parent: TERM_GRACE_MS = 5_000, EXIT_DEADLINE_MS = 10_000 (packages/acp-bridge/src/process-registry.ts:10). Child, after the writer terminal (packages/cli/src/acp-integration/acpAgent.ts:2851):

step budget
fireSessionEndOnce (:2857) DEFAULT_HOOK_TIMEOUT = 60000, sequential per Config
finishManagedShutdown (:2862) unbounded — joins in-flight Config.initialize() by design
drainPoolBeforeExit(label, true) (:2868) → shutdownMcpPool(8_000) (:2774) 8s

Any one of those crossing 5s ⇒ SIGKILL ⇒ signalCode !== nullexited uncleanly during shutdown (process-registry.ts:156) ⇒ registry rejects ⇒ bridgeShutdownErrordaemon shutdown incomplete and close() rejects.

The locks are released (writer terminal runs first), so the P0 still holds — but a user with one SessionEnd hook or one slow MCP server gets a nonzero daemon exit on every graceful restart. Worth either raising TERM_GRACE_MS above the child's own worst case, or bounding the child's post-writer phase to comfortably under 5s so the escalation stays exceptional.

3. Consequence of #2: qwen serve can now refuse to exit on the first SIGTERM.

close()'s rejection reaches onSignal's catch, which hits the pre-existing branch:

if (channelWorkerManager?.state().enabled) {
  daemonLog.error('refusing to exit while a channel worker or service lease remains; signal again to retry…');
  return;   // no process.exit
}

Before this PR that branch was unreachable from an ACP child, because bridge.shutdown() swallowed every kill error (channels.map((ci) => ci.channel.kill().catch(() => {}))). Now a child that exits by signal or nonzero — likely per #2 — propagates all the way to bridgeShutdownError (packages/cli/src/serve/run-qwen-serve.ts:6565) and can hang the daemon until a second signal. Under Kubernetes there is no second SIGTERM: the pod sits until terminationGracePeriodSeconds and is SIGKILLed, which is a worse restart story than the one being fixed.

Recommend keeping the process-registry/child-exit failure distinct from the errors that gate that "refuse to exit" path (that branch is about an un-reaped channel worker, not an ACP child the registry has already SIGKILLed).


Medium

4. shutdownMcpPool throws on a very low bar. if (result.forced > 0 || result.errors.length > 0) throw (acpAgent.ts:3609-3621). forced is computed by subtraction — it counts entries that merely hadn't settled when the deadline fired (mcp-transport-pool.ts:814), not entries that misbehaved. One MCP transport that rejects on forceShutdown (already-closed transport is a plausible case) makes the managed child exit 1 and the whole daemon shutdown unclean. Consider treating errors as unclean but forced as a warning, or logging which servers were responsible so the operator can act.

5. Config.shutdown() can never reject, so the resource-cleanup terminal is not actually a terminal. shutdownResourcesOnce wraps its entire body in try { … } catch { debugLogger.error('Error during Config shutdown:', error) } (packages/core/src/config/config.ts:4585-4621); closeWriter() is .catch-wrapped; telemetry is disabled on the managed path. Therefore the rejection-collecting loop in finishManagedShutdown:

const results = await Promise.allSettled(configs.map((c) => c.shutdown({ shutdownTelemetry: false, skipSessionWriter: true })));
for (const result of results) if (result.status === 'rejected') failures.push(result.reason);

is dead code in production, and the design doc's "Writer shutdown and Config resource shutdown are separate terminals" only holds for the writer half. The test that appears to cover it (keeps managed EOF unclean after writer failure while finishing resources) mocks innerConfig.shutdown to throw, so it passes without touching the real method — it proves the ordering assertion (['writer','resources']) but nothing about resource-failure propagation.


Low / nits

  1. releaseOnce() calls readOwnedLock() outside the try (session-writer-lease.ts:854-856). A pre-rename SessionWriterLostError (lock already gone) therefore leaves released === false while releasePromise memoizes the rejection forever. Old code set this.released = true on ENOENT. Downstream, Config.closeSessionWriterOnce pushes that error into failures unconditionally, so "the lock we were going to release is already gone" reports the whole managed shutdown as unclean. Setting released = true when readOwnedLock() throws SessionWriterLostError would keep isReleased truthful.

  2. ProcessRegistry.shutdown() ignores outstanding reservations. It snapshots this.children only; a token reserved before draining but attached after the snapshot is terminated out-of-band via if (this.draining) void tracked.terminate().catch(() => {}) (process-registry.ts:47), so shutdown() can resolve while that child is still being reaped. Unreachable today — spawn() is synchronous between reserve() and attach() — but ProcessRegistry is now public API (index re-export + new ./processRegistry subpath), so a third-party factory awaiting in that window would break the seal the design doc promises. Cheap fix: join outstanding reservations in shutdown().

  3. Missing vitest alias for the new subpath. run-qwen-serve.ts:1063 adds a runtime import('@qwen-code/acp-bridge/processRegistry'), but packages/cli/vitest.config.ts isn't updated — its sibling @qwen-code/acp-bridge/spawnChannel on the very next line is aliased, with a comment saying the alias block exists because "dist may be stale or absent during development". As written, the CLI suite resolves ProcessRegistry from packages/acp-bridge/dist, so runtime.ProcessRegistry in tests is a different class object from the one spawnChannel.ts uses internally, and the suite silently requires a fresh acp-bridge build.

  4. Orphan .released.* artifacts. The unlink(R) after the rename is best-effort and unlogged on crash; nothing ever GCs session-writer-locks/*.released.*. One stray file per affected session accumulates under the runtime base dir with no cleanup path.

  5. Silent mid-turn transcript truncation. beginClose() flips acceptingWrites = false synchronously and recordRecord returns early with no error (chatRecordingService.ts:904), while cancelPendingPrompt() is fire-and-forget (acpAgent.ts:3262). On the managed fast path there's also no finalize record, so after a daemon restart a transcript just ends mid-turn with no marker. Intentional per the design doc, but worth surfacing in user-facing docs.

  6. cannot remove a successor lock after release commits is weaker than its name. The second first.release() returns the memoized already-resolved promise, so the rename/inspect logic never runs; only the successor.appendJsonLine(...) assertion carries signal. A version that clears releasePromise (or drives releaseOnce directly) would actually test the guard.

  7. Doc filename convention. Every other file in docs/design/ is date-prefixed (2026-06-24-…); this one isn't.


What's good

  • The rename-to-owner-unique-path release commit, with the old owner only ever cleaning its exact R and never retrying the primary path — that's the right primitive, and readOwnedLock's new raw-bytes comparison against lockRecordRaw is a correct tightening (verified: the record is written as exactly JSON.stringify(record) at session-writer-lease.ts:394 and never rewritten).
  • reclaimPolicy: 'never' scoped to managed acquisition only, with standalone ACP keeping local stale-owner recovery — correctly conservative given container PID namespaces.
  • Distinguishing pre-spawn error (no process) from post-spawn error (raw exit is the only proof of reaping) — this fixes a real correctness bug in the old exited promise, and spawnChannel.test.ts covers both directions.
  • One shared registry across primary/secondary/dynamic workspace factories, with the timeline started before the slower worker/bridge phases.
  • bridge.shutdown() waiting for a retiring channel from an overlapping killSession before reporting — the new test for that is a good one.
  • Single-flight terminals with stable results throughout (terminate, close, closeSessionWriter, release, shutdown) — consistent and easy to reason about.

Verdict

The lock-release mechanism itself looks correct and well-tested. I'd want #1 resolved before merge (it can permanently wedge a lock in the same way the PR is fixing, and it's asserted by a new test as intended behavior), and #2/#3 addressed or explicitly accepted — as written, a normal restart with a SessionEnd hook or a slow MCP server ends in a nonzero daemon exit, or a daemon that won't exit at all on the first SIGTERM.

中文说明

概述

本 PR 把 writer 锁释放变成托管 ACP 子进程关闭确认的一部分,包含四块:lease 用同目录 rename(P → R) 提交释放并让失败成为稳定终态、新增 reclaimPolicy: 'never';recorder/Config 拆出同步的写入准入关闭与单次 writer 终态;agent 在第一个 await 之前快照所有 writer-capable Config 并启动全部 writer 终态;父进程新增 daemon 作用域的 ProcessRegistry(SIGTERM → 5s SIGKILL → 10s 回收)。整体设计合理,"先 writer、再 hook、最后资源"的顺序对 P0 是正确的。我的意见集中在哪些失败被归类为"保留锁"/"不干净",以及 bridge.shutdown() 变成会 reject 之后的影响面。

严重

  1. 单次瞬时写失败会永久卡死锁 —— closeOnce() 在 flush 失败时直接抛出、不再 release();而 flush() 抛的是 writeFailure,该字段在 recorder 生命周期内永不清除。所以保留锁的触发条件是"本会话内任意时刻发生过一次 append 失败",而不是 PR 描述里的"所有权不确定"。会话第 3 分钟一次 EIO,两小时后关闭时锁被保留;由于托管模式 reclaimPolicy: 'never'任何后继实例都无法再获取,只能人工删锁 —— 正是本 PR 想消除的故障模式。改动前该场景是会释放锁的。建议改为以 integrityFailure 为准,或至少输出面向运维、包含锁路径的可见告警(debugLogger.error 在未开调试日志时不可见)。
  2. 子进程自身的清理预算超过父进程的 5s 宽限期 —— SessionEnd hook 默认 60s、MCP drain 8s、initialize() join 无上限,任一超过 5s 都会被 SIGKILL,进而 exited uncleanlydaemon shutdown incomplete。锁确实已释放(writer 终态最先执行),但只要用户有一个 hook 或一个较慢的 MCP server,每次正常重启都会得到非零退出。
  3. Where is the config saved? #2 引出:qwen serve 可能在第一次 SIGTERM 时拒绝退出 —— close() 的 reject 会走到 onSignal 的 catch,命中既有的 refusing to exit while a channel worker… 分支并直接 return。改动前 ACP 子进程的 kill 错误被 .catch(() => {}) 吞掉,永远到不了这里。K8s 不会发第二次 SIGTERM,结果是等到 terminationGracePeriodSeconds 再被 SIGKILL。

中等

  1. shutdownMcpPool 的抛出门槛过低:forced 是用减法算出的"截止时刻尚未 settle"的条目数,并非行为异常;一个 transport 在关闭时 reject 就会让整个 daemon 关闭不干净。
  2. Config.shutdown() 实际上永远不会 rejectshutdownResourcesOnce 全量 try/catch 吞异常、closeWriter().catch、托管路径关闭 telemetry),因此 finishManagedShutdown 里收集 config.shutdown() 拒绝的循环在生产中是死代码;对应测试因为直接 mock 了 innerConfig.shutdown,只验证了顺序断言,没有覆盖真实方法。

次要

  1. releaseOnce()readOwnedLock() 放在 try 之外:锁已消失时 released 仍为 false,isReleased 长期不真实,且会让"锁本来就不在了"被记为不干净关闭。
  2. ProcessRegistry.shutdown() 未纳入未完成的 reservation(当前同步 spawn 下不可达,但它已是对外 API)。
  3. packages/cli/vitest.config.ts 缺少 @qwen-code/acp-bridge/processRegistry 别名(相邻的 spawnChannel 有),测试会从 dist 加载到与源码不同的类对象。
  4. .released.* 残留文件无任何回收路径。
  5. 托管快速关闭会静默截断进行中的 turn,且不写 finalize 记录,建议在用户文档中说明。
  6. cannot remove a successor lock after release commits 实际只等到了被 memo 的已完成 promise,没有真正跑到 rename/inspect 逻辑。
  7. docs/design/ 下其它文件均带日期前缀,本文件没有。

结论

锁释放机制本身正确且测试充分。建议合并前处理 #1(会以与本 PR 所修问题相同的方式永久卡死锁,且被新测试当作预期行为固化),并处理或明确接受 #2/#3

@doudouOUC

Copy link
Copy Markdown
Collaborator Author

Thanks @wenshao for the detailed review. I independently re-checked all 12 points against the reviewed head and pushed 4f8991bf0c with the fixes and explicit decisions below.

  1. Addressed with the operator-visible recovery path you suggested. Managed writer-terminal failures now print a stderr warning that the lock may be retained, lists the candidate lock path(s), and instructs the operator to verify the previous writer is gone before manual cleanup. I kept fail-closed retention because a generic filesystem write failure can be partial, so successful ownership alone does not prove transcript integrity.
  2. Explicitly accepted and documented. The P0 contract is to start and await writer release before hooks/resources; the parent deadline intentionally does not expand to the child's hook/init/MCP budgets because the platform termination window may be shorter and outside daemon control. Slow post-writer cleanup can therefore produce an unclean exit, but it does not restore the released lock.
  3. Fixed. First-signal retry is now gated by the exact error branded as an unconfirmed channel-worker shutdown, rather than by channelWorkerManager.state().enabled. ACP/process-registry or other bridge errors exit nonzero on the first signal. Added a regression test with a channel worker enabled and ACP registry shutdown failing.
  4. No change. forced means the transport did not settle within the graceful deadline and required forced shutdown; treating that as an unclean managed terminal is intentional. The aggregate error remains visible in daemon/ACP diagnostics.
  5. Fixed. Config.shutdown() now has an opt-in strict resource-cleanup mode. Managed ACP uses it, so real cleanup failures reach Promise.allSettled; existing callers retain best-effort compatibility. Added real-Config propagation and retry coverage.
  6. No change. isReleased means this owner proved its release commit. A missing/replaced primary lock is ownership loss, not proof that this owner released it; downstream already treats SessionWriterLostError as terminal and drops the reference.
  7. Deferred. All supported factories reserve and attach synchronously in one call stack, so there is no reachable outstanding-reservation window today. Expanding the public registry contract is outside this P0 and would add coordination machinery for a hypothetical asynchronous caller.
  8. Fixed. Added the missing CLI Vitest alias for @qwen-code/acp-bridge/processRegistry.
  9. Deferred. Crash-only garbage collection for owner-unique retired artifacts is separate storage hygiene work; release correctness never consults or reuses those artifacts.
  10. Already an explicit design tradeoff. Managed shutdown closes write admission and prioritizes the writer terminal; it does not promise a finalize record during mid-turn termination.
  11. No change. The test intentionally exercises the public single-flight release() contract: a repeated old-owner release must remain the same settled terminal and cannot touch a successor. Calling the private primitive again would test behavior callers cannot invoke and would violate the stable-terminal invariant.
  12. No change. docs/design/ contains many existing non-date-prefixed design documents, so this filename follows an established repository pattern.

Validation on the pushed commit:

  • Core config.test.ts: 446 passed
  • CLI acpAgent.test.ts + run-qwen-serve.test.ts: 525 passed
  • Root npm run build && npm run typecheck: passed
  • Two consecutive post-fix diff audits: clean

There were no inline review threads to resolve; this top-level comment records the disposition of every review item.

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed — no blockers. Suggestions are inline. 1 Suggestion-level finding(s) could not be anchored to a changed line and were dropped; nothing further to act on here.

中文说明

已审查——无阻断问题。 建议见行内评论。 1 条建议级发现无法锚定到改动行,已丢弃;此处无需进一步处理。

— qwen3.7-max via Qwen Code /review

Comment thread packages/cli/src/acp-integration/acpAgent.ts
Comment thread packages/acp-bridge/src/spawnChannel.ts
Comment thread packages/core/src/services/chatRecordingService.ts
@wenshao

wenshao commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

Local verification on head 4f8991bf0 — real bundled daemon

Follow-up to my earlier review and @doudouOUC's disposition comment. This round is execution, not reading: an isolated worktree at the PR head with its own npm ci, a real bundled qwen serve, a real managed ACP child, real on-disk writer locks, and — for the headline finding — a second full build of the base commit for an A/B.

Setup (for reproduction)
git fetch origin pull/7812/head:pr7812-head          # 4f8991bf0
git worktree add --detach $WT pr7812-head && cd $WT && npm ci && npm run bundle
git worktree add --detach $BASE 1f9a1a90a && cd $BASE && npm run build   # merge-base

Isolated HOME, folderTrust.enabled:false, dummy OPENAI_* pointing at a dead port.
Sessions created by driving the daemon's /acp WebSocket as a real ACP client
(initializesession/newsession/prompt). Verified the bundle contains the PR's
code (strictResourceCleanup, process-registry.js chunk) and that neither tree's dist
references the other's path.

Your reported numbers all reproduce

Claim Result
core writer/config tests 521 passed, 1 skipped (3 files, all collected)
ACP bridge/process tests 487 passed
ACP agent + serve tests 525 passed
build / typecheck / lint all pass
Managed harness releases every lock and exits clean reproduced — 3/3 locks released, ACP child reaped, daemon stopped, 101 ms after SIGTERM

The core mechanism works. On a healthy filesystem this PR does exactly what it says.

happy path and the wedge


1. Blocking — writer-lock retention is a regression against the base, not just a conservative choice

Your reply to review item 1 kept fail-closed retention on the grounds that "a generic filesystem write failure can be partial, so successful ownership alone does not prove transcript integrity." That reasoning is sound in isolation, but it was made against the wrong baseline: the base does not retain the lock in this situation.

chatRecordingService.ts on 1f9a1a90a captures the flush failure and still releases the lease, then rethrows:

let flushFailure: unknown;
try { await this.flush(); } catch (error) { flushFailure = error; }
try {
  await this.binding?.lease.release();     // <-- always runs
  ...
}
if (flushFailure !== undefined) throw flushFailure;   // caller still learns about it

The PR replaces this with closeOnce() (chatRecordingService.ts:1114), which await this.flush() at :1116 — and flush() rethrows the sticky writeFailure (:1044). enterWriteFailure sets that flag on any append error and never clears it (:847), so lease?.release() at :1123 is never reached. Independently, reclaimPolicy: 'never' (new in this PR — the base has no such concept) is applied to every managed session at acpAgent.ts:10685, which removes the stale-owner reclaim that used to recover exactly this state.

Neither change alone is fatal. Together they turn a recoverable state into a permanent one.

A/B, identical scenario, two real bundled builds — one metadata touch on the transcript, filesystem then fully healed (content byte-identical), then an ordinary SIGTERM:

base vs PR

Follow-through on the PR side: a replacement daemon calling session/load gets session_writer_conflictpermanently. The owner PID is dead and the hostname matches this host, and it still never recovers:

reclaimPolicy='never'  ->  session_writer_conflict     # what this PR sets for managed sessions
reclaimPolicy='local'  ->  ACQUIRED — self-heals

Only manual rm of the lock file clears it.

How reachable is this? I triggered it with chmod, which changes the file's metadata and trips the fingerprint check in appendJsonLineSessionTranscriptChangedError. Any backup agent, antivirus scanner, container-layer copy, or chown does the same. Separately — by code reading, not executed — appendJsonLine's catch normalises every non-SessionWriterError into SessionWriterUnavailableError, so a plain transient EACCES/ENOSPC/EIO on one append reaches the identical sticky path. A single recovered I/O blip permanently wedges that session.

Worth being clear about scope: the motivating k8s case is not regressed. The base returns {kind:'live'} for any foreign hostname (session-writer-lease.ts:265), so cross-host locks never self-healed before either, and this PR's cooperative release genuinely fixes them. The regression is on the same-host restart path, which is the common case for a local or single-node daemon.

Suggestion — the fail-closed intent and same-host recovery aren't actually in conflict. Either restore the base's ordering (release, then report the flush failure — the owner still holds provable exact ownership), or keep retention but scope reclaimPolicy: 'never' to the case it was written for, letting a same-host provably-dead owner still be reclaimed.


2. The regression test added for review item 3 is vacuous

Item 3's fix looks correct by inspection — retryableChannelWorkerShutdownErrors only tags an error when channelWorkerShutdownError !== undefined, so an ACP-only failure falls through to process.exit(1). But the test added for it does not pin it.

Keeping the round-2 tests and overlaying the round-1 source (reverting only the feedback commit's code):

discrimination check

  • acpAgent.test.ts2 tests fail. The strictResourceCleanup fix (item 5) is properly pinned. 👍
  • run-qwen-serve.test.tsall 204 pass. Nothing in the file pins the item-3 fix.

Why: probing the guard at signal time shows channelWorkerManager.state().enabled = false. enabled is committedSelection !== undefined || group !== undefined || leaseReserved (channel-worker-manager.ts:258), and the fixture never gets the manager there — passing channelSelection: {names:['telegram']} with a stubbed supervisor isn't sufficient. So the old if (channelWorkerManager?.state().enabled) guard and the new WeakSet guard are both skipped, and the test passes on either version. Swapping in makeReadyWorkerFactory doesn't fix it either — I tried.

Cheap to fix, and worth fixing: this is the one failure mode that is fatal under Kubernetes (no second SIGTERM before SIGKILL), so it should not be able to regress silently.


3. Item 2 (hook budget) — your assessment is correct, and I was over-worried

I raised the 60 s DEFAULT_HOOK_TIMEOUT vs 5 s TERM_GRACE_MS gap; you replied that slow post-writer cleanup "does not restore the released lock." Executed with a 20 s SessionEnd hook, that is exactly right:

hook budget

The writer phase runs before hooks, so all locks were still released — the PR's core guarantee holds under a slow hook. What remains is narrower than I implied: the hook is silently truncated at ~5 s despite its documented 60 s budget, and the restart reports daemon shutdown incomplete. Worth a documentation note about the effective SessionEnd budget under serve; not a merge blocker.

4. Nit — the new retention warning over-reports

The stderr message lists a candidate lock path per config in terminal.configs, including the daemon's own primary config, which holds no lock. My run printed 2 candidate paths when exactly 1 lock existed. Filtering to paths that exist would make it directly actionable for an operator.


Recommendation

Items 3–5 are handled well and item 5 is genuinely test-pinned. Finding 1 is the one I'd want resolved before merge — not because fail-closed is wrong, but because the combination with reclaimPolicy:'never' makes a previously self-healing state permanent on the same host, and that trade wasn't visible when the call was made. Finding 2 is a small test change that protects the most operationally severe path.

Happy to re-run this harness against a new head.

中文版本

在 head 4f8991bf0 上的本地验证 —— 真实打包 daemon

这是对我此前 review@doudouOUC逐条回复 的后续。本轮是实际执行,而非阅读代码:在 PR head 上使用独立 worktree 并单独 npm ci,真实打包的 qwen serve、真实的托管 ACP 子进程、真实的磁盘 writer 锁;针对核心结论,还完整构建了 base 提交做 A/B 对比。

你报告的数据全部复现

声明 结果
core writer/config 测试 521 通过,1 跳过(3 个文件全部收集)
ACP bridge/process 测试 487 通过
ACP agent + serve 测试 525 通过
build / typecheck / lint 全部通过
托管 harness 释放全部锁并干净退出 已复现 —— 3/3 锁释放,ACP 子进程回收,daemon stopped,SIGTERM 后 101 ms

核心机制是有效的。在文件系统健康的情况下,本 PR 的行为与描述完全一致。

1. 阻塞项 —— writer 锁保留相对 base 是功能回退,而不仅仅是保守选择

你在 review 第 1 条的回复中保留了 fail-closed 保留策略,理由是"通用文件系统写入失败可能是部分完成的,因此仅有所有权成功并不能证明 transcript 完整性"。这个理由本身成立,但它对照的基线不对:base 在这种情况下并不会保留锁。

1f9a1a90a 上的 chatRecordingService.ts 会捕获 flush 失败,仍然释放 lease,然后再抛出:

let flushFailure: unknown;
try { await this.flush(); } catch (error) { flushFailure = error; }
try {
  await this.binding?.lease.release();     // <-- 始终执行
  ...
}
if (flushFailure !== undefined) throw flushFailure;   // 调用方仍然会知道失败

本 PR 用 closeOnce()chatRecordingService.ts:1114)取代了它,其中 :1116await this.flush(),而 flush() 会重新抛出粘滞的 writeFailure:1044)。enterWriteFailure任何追加错误时设置该标志且永不清除(:847),因此 :1123lease?.release() 永远不会执行。另外,reclaimPolicy: 'never'(本 PR 新增,base 中不存在该概念)在 acpAgent.ts:10685 被应用到每一个托管会话,这移除了原本能恢复该状态的 stale owner 回收机制。

单独看任一改动都不致命。两者叠加,就把一个可恢复状态变成了永久状态。

A/B:相同场景,两个真实打包构建 —— 对 transcript 做一次元数据触碰,随后文件系统完全恢复(内容逐字节一致),再执行一次普通 SIGTERM:base 锁已释放、会话可恢复;PR 锁被保留、会话卡死

后续验证:PR 侧替代 daemon 调用 session/load 会得到 session_writer_conflict,且是永久性的。owner PID 已死亡、hostname 与本机相同,依然无法恢复:

reclaimPolicy='never'  ->  session_writer_conflict     # 本 PR 为托管会话设置的值
reclaimPolicy='local'  ->  ACQUIRED —— 可自愈

只有手动 rm 锁文件才能清除。

触发难度如何? 我用 chmod 触发,它改变文件元数据,从而触发 appendJsonLine 中的指纹校验 → SessionTranscriptChangedError。任何备份代理、杀毒扫描、容器层复制或 chown 都会产生同样效果。另外(这一条来自代码阅读而非实际执行):appendJsonLine 的 catch 会把所有SessionWriterError 归一化为 SessionWriterUnavailableError,因此单次瞬时 EACCES/ENOSPC/EIO 也会进入完全相同的粘滞路径。一次已恢复的 I/O 抖动就会永久卡死该会话。

需要明确范围:k8s 这一动机场景没有回退。base 对任何外部 hostname 都返回 {kind:'live'}session-writer-lease.ts:265),所以跨主机锁此前也从不自愈,本 PR 的协作式释放确实修复了它。回退发生在同主机重启路径上,而这正是本地或单节点 daemon 的常见情况。

建议 —— fail-closed 的意图与同主机恢复其实并不冲突。要么恢复 base 的顺序(先释放、再上报 flush 失败 —— 此时 owner 仍持有可证明的精确所有权),要么保留该策略但把 reclaimPolicy: 'never' 限定在它真正针对的场景,允许同主机上可证明已死亡的 owner 仍被回收。

2. 为 review 第 3 条新增的回归测试是空转的

第 3 条的修复从代码上看是正确的 —— retryableChannelWorkerShutdownErrors 只在 channelWorkerShutdownError !== undefined 时标记错误,因此纯 ACP 失败会落到 process.exit(1)。但为它新增的测试并没有锁定这个行为。

保留 round-2 的测试、覆盖回 round-1 的源码(只回退 feedback 提交的代码):

  • acpAgent.test.ts2 个测试失败。第 5 条的 strictResourceCleanup 修复确实被锁定了 👍
  • run-qwen-serve.test.ts204 个全部通过。文件中没有任何测试锁定第 3 条的修复。

原因:在信号触发时刻探测该 guard,得到 channelWorkerManager.state().enabled = falseenabled 的定义是 committedSelection !== undefined || group !== undefined || leaseReservedchannel-worker-manager.ts:258),而 fixture 从未让 manager 进入该状态 —— 仅传入 channelSelection: {names:['telegram']} 加一个 stub supervisor 并不够。因此旧的 if (channelWorkerManager?.state().enabled) 分支与新的 WeakSet 分支被跳过,测试在两个版本下都通过。改用 makeReadyWorkerFactory 也不行,我试过了。

修复成本很低,也值得修:这是在 Kubernetes 下唯一致命的失败模式(SIGKILL 之前不会有第二次 SIGTERM),不应该能够无声回退。

3. 第 2 条(hook 预算)—— 你的判断是对的,是我此前担心过度了

我此前提出 60 s 的 DEFAULT_HOOK_TIMEOUT 与 5 s 的 TERM_GRACE_MS 之间的落差;你回复说 writer 之后的缓慢清理"不会让已释放的锁复活"。用一个 20 s 的 SessionEnd hook 实测,结论完全正确:

writer 阶段在 hooks 之前执行,因此所有锁仍然被正确释放 —— 在慢 hook 下本 PR 的核心保证依然成立。剩下的问题比我此前描述的要小:hook 在约 5 s 时被静默截断(尽管其文档预算是 60 s),并且该次重启会被报告为 daemon shutdown incomplete。建议在文档中说明 serve 下 SessionEnd 的实际预算;不构成合并阻塞。

4. 小问题 —— 新增的保留警告存在过度上报

该 stderr 信息会为 terminal.configs 中的每个 config 列出一个候选锁路径,其中包含 daemon 自身的 primary config —— 而它并不持有锁。我这次运行打印了 2 个候选路径,而实际只存在 1 个锁。过滤为实际存在的路径会让它对运维人员更直接可用。

结论

第 3–5 条处理得很好,第 5 条确实有测试锁定。第 1 条是我希望在合并前解决的 —— 不是因为 fail-closed 本身有问题,而是因为它与 reclaimPolicy:'never' 叠加后,把同主机上原本可自愈的状态变成了永久状态,而做该决定时这个代价并不可见。第 2 条只是一个小的测试改动,用于保护运维影响最严重的那条路径。

如果推送新的 head,我很乐意再用这套 harness 重跑一遍。

@doudouOUC

Copy link
Copy Markdown
Collaborator Author

@wenshao Thanks for the execution-level A/B. I independently reproduced both blocking points and addressed them in 621e085a72.

Item Disposition Result
1. Sticky flush failure + managed never permanently wedges the same-host session Agree — fixed Restored the base ordering: close seals admission, records the flush failure, validates/releases the exact owned lock through the existing atomic rename path, then reports the original flush failure. Managed reclaimPolicy: 'never' remains in place for non-cooperative death, so this does not broaden hostname/PID trust or introduce cross-host stealing. The focused test now requires release, cleared ownership, and propagation of the original flush error.
2. ACP-only shutdown regression test was vacuous Agree — fixed The test now wraps the real channel-worker manager so state().enabled remains true after a successful worker shutdown while only ProcessRegistry.shutdown() fails. I mutation-tested it: restoring the old state-based guard makes the test fail (process.exit(1) is not called), while the current WeakSet provenance guard passes.
3. Effective SessionEnd budget Agree with the revised non-blocking assessment No additional code change. The design already states that the parent deadline does not expand for post-writer hooks and that these phases may be interrupted after writer release.
4. Candidate lock-path over-reporting Deferred This is a diagnostic nit rather than a correctness blocker, and the PR is already beyond the repository's review-round cutoff. The warning intentionally says “may”/“candidate”; filtering filesystem paths can be handled separately without widening this critical fix.

Validation: core writer/config tests 521 passed, 1 skipped; discriminating serve signal test passed and failed under the old-guard mutation; full npm run build, npm run typecheck, and npm run lint passed.

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed — no blockers. Suggestions are inline.

中文说明

已审查——无阻断问题。 建议见行内评论。

— qwen3.7-max via Qwen Code /review

Comment thread packages/acp-bridge/src/process-registry.ts
Comment thread packages/cli/src/acp-integration/acpAgent.ts
Comment thread packages/cli/src/acp-integration/acpAgent.ts
@wenshao

wenshao commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

@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 Jul 27, 2026
@doudouOUC

Copy link
Copy Markdown
Collaborator Author

Review: release managed session writer locks on shutdown

Reviewed the full diff (20 files). The core design holds up well:

  • ProcessRegistry / TrackedChild — using the spawn event as the discriminator for "does a process actually exist" is correct. Node emits error without spawn only when the spawn itself failed, so spawnConfirmed is a sound proxy for "raw exit is the only proof of reaping", and the single non-restarting TERM→KILL→deadline timeline is a real improvement over the old per-call timers.
  • The rename-to-retiredPath release commit is the right primitive. Deriving retiredPath from ownerId so an old owner can only ever clean its own R, never a successor's P, is the property that makes this safe under Pod replacement.
  • readOwnedLock() comparing raw !== this.lockRecordRaw — I checked this against the write path before flagging it, and it's correct: installLockRecord writes JSON.stringify(record) (session-writer-lease.ts:394) and the constructor stores JSON.stringify(lockRecord) from that same object (:483), with no rewrite in between. Byte-identical by construction.
  • ChatRecordingService.beginClose() separating the synchronous admission cutoff from the async drain is what makes the managed fast-close safe, and dropping the inner state !== 'active' re-check in runWithWriteBarrier is fine — the outer acceptingWrites check and the queue append are synchronous together, so any barrier admitted before the cutoff is already in operationTail when closeOnce() awaits flush().

Three points below, in descending order of how much I'd want them addressed.


1. A wedged child now turns a clean daemon exit into exit 1, and the operator-facing zombie warning is gone

The old killChild deliberately gave up after 10 s: it wrote a loud single-line stderr warning naming the pid and telling the operator to check for zombie qwen --acp processes, then resolved. The comment justifying it was explicit — the child is likely in uninterruptible sleep (D-state, e.g. NFS on a dead server), nothing can cancel that, and process.exit(0) reaps it on return.

TrackedChild.terminateOnce now rejects on that same deadline, bridge.shutdown() propagates channel-kill failures instead of .catch(() => {}), and run-qwen-serve surfaces it as bridgeShutdownErrorclose() rejects → process.exit(1).

Failing loudly instead of reporting a false "graceful" is the right call and I'm not arguing against it. Two consequences worth handling:

  • The stderr warning was deleted with no replacement. The failure now reaches daemonLog.error('ACP process registry shutdown error', …) only. The deleted comment specifically justified writing to process.stderr "so monitoring/log aggregators catch it" — under systemd/k8s, daemon-log-only visibility is a real downgrade for exactly the case where a zombie is holding workspace resources and racing a respawn.
  • The rollout impact isn't in the design doc. "Compatibility and rollout" covers writer versioning but not this. A D-state child is unavoidable and not the daemon's fault, yet it now produces a nonzero exit on SIGTERM, which supervisors read as a crash — affecting restart backoff and alerting. That's a deliberate tradeoff, but it belongs in the doc next to the parent-deadline discussion so operators aren't surprised.

2. shutdownMcpPool throws from inside its own try, so the log mislabels a partial drain as a failure

packages/cli/src/acp-integration/acpAgent.ts:3633

      debugLogger.warn(`MCP pool drain: ${result.drained} clean, …`);
      throw new Error(
        `MCP pool drain incomplete: ${result.forced} forced, ${result.errors.length} errors`,
      );
    }
  } catch (err) {
    debugLogger.error(`MCP pool drainAll failed: ${}`);
    throw err;
  }

The synthetic "incomplete" error is thrown inside the try and immediately caught by the adjacent catch, so an operator diagnosing a stuck managed shutdown reads MCP pool drainAll failed: MCP pool drain incomplete: 2 forced, 0 errors — but drainAll didn't fail, it returned normally with partial results. Those are different diagnoses.

Behaviour is correct (it rethrows either way), so this is purely about the log. Moving the throw below the try/catch fixes it.

I checked whether making this method throw regresses any existing caller: shutdownMcpPool has exactly one call site (drainPoolBeforeExit, acpAgent.ts:2774), which swallows unless strict is passed, and only the managed path passes strict. No regression.

3. The process-registry error overwrites an already-recorded bridge shutdown error

packages/cli/src/serve/run-qwen-serve.ts:6577

const processRegistryError = await processRegistryShutdown;
if (processRegistryError) {
  daemonLog.error('ACP process registry shutdown error', processRegistryError);
  bridgeShutdownError = processRegistryError;   // clobbers
}

If a workspace-runtime disposal (:6546) or a bridge shutdown (:6567) already assigned bridgeShutdownError, the registry error replaces it and only the registry failure reaches close()'s rejection. The earlier failure survives in the daemon log but disappears from the value the caller sees.

I traced whether this can corrupt the retry decision, and it can't: retryableChannelClose depends only on channelWorkerShutdownError !== undefined && channelWorkerManager?.state().enabled === true, neither of which this touches, so a retryable channel-worker close still keeps the daemon alive. So this is observability, not correctness.

It's also consistent with the pre-existing last-wins pattern between :6546 and :6567 — so if you'd rather keep it uniform, that's reasonable. Aggregating into an AggregateError would report the whole picture; either way is defensible, I'd just rather it be a decision than an accident.


One narrow race, low severity

Config.shutdown() picks the fast-close path from this.initializationPromise !== undefined && !this.initializationSucceeded (config.ts:4678), but initializationSucceeded = true is set in initialize() after await initialization (:2568). Between the initialization promise resolving and that continuation running, a concurrent shutdown() observes initializationSucceeded === false and takes earlyWriterClose, skipping finalize()/flush() on a session that actually initialized fine — losing the final metadata record.

The window is one microtask and the managed path passes skipSessionWriter: true (so it doesn't hit this branch at all), which is why I'm calling it low. Setting initializationSucceeded inside initializeOnce on the success path, rather than in the caller after the await, closes it.


Note on retryableChannelWorkerShutdownErrors

Narrowing the "stay alive and retry on the next signal" condition from channelWorkerManager?.state().enabled to an explicitly tagged error is a good tightening and matches the doc ("Only an unconfirmed channel-worker exit keeps the daemon alive"). The module-level WeakSet is safe across concurrent runQwenServe calls in one process since it's keyed on Error identity, and finalErr! at :6451 is justified — the retryable branch requires channelWorkerShutdownError !== undefined, so the ?? chain always yields a value.

Note on the optional processRegistry

createSpawnChannelFactory falls back to new ProcessRegistry() when none is injected, so defaultSpawnChannelFactory and every non-run-qwen-serve consumer gets a private registry that nothing can ever shutdown() or killAllSync(). Per-channel teardown still works through channel.kill(), so there's no functional regression — but the doc's "Each daemon handle owns one process registry" invariant only actually holds where the option is passed, and the optional parameter makes it easy to add a fourth factory later and silently miss it. Worth a line in the doc, or a comment on the option.

@doudouOUC
doudouOUC force-pushed the agent/7752-managed-session-writer-shutdown branch from 621e085 to 8e583a0 Compare July 27, 2026 23:58
@github-actions

Copy link
Copy Markdown
Contributor

Please do not rebase or force-push to an active PR as it invalidates existing review comments. Note for future reference, the bots always squash all changes into a single commit automatically as part of the integration.

中文

请勿对活跃的 PR 执行 rebase 或 force-push,因为这会使已有的评审评论失效。另外,供日后参考:作为集成流程的一部分,机器人始终会自动将所有改动压缩(squash)为单个提交。

@doudouOUC

Copy link
Copy Markdown
Collaborator Author

Rebased onto the latest main and resolved the ACP bridge overlap. The resulting code preserves both the new pre-registration session-spawn admission callback from main and this PR's bounded child teardown when bridge construction fails.

Verification after the rebase:

  • ACP bridge targeted tests: 491 passed
  • CLI targeted tests: 531 passed
  • Core targeted tests: 540 passed, 1 skipped
  • npm run build: passed
  • npm run typecheck: passed
  • npm run lint: passed
  • Two clean post-rebase diff audits completed

No new actionable review feedback appeared. Existing six suggestion-only threads already have author replies and remain intentionally unresolved under the repository's review-round cutoff. Resolved this round: 0.


已 rebase 到最新 main 并解决 ACP bridge 重叠冲突。最终代码同时保留了 main 新增的预注册 session-spawn 准入回调,以及本 PR 在 bridge 构造失败时对 child 进行有界清理的逻辑。

Rebase 后验证:

  • ACP bridge 定向测试:491 通过
  • CLI 定向测试:531 通过
  • Core 定向测试:540 通过,1 跳过
  • npm run build:通过
  • npm run typecheck:通过
  • npm run lint:通过
  • 已完成两轮干净的 rebase 后 diff 审计

本轮没有新增可执行 review feedback。现有 6 个仅建议级 thread 均已有作者回复,并依据仓库 review 轮次截止规则有意保持未解决。本轮 resolved:0。

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

No issues found. LGTM! ✅

中文说明

未发现问题。LGTM!✅

— qwen3.7-max via Qwen Code /review

@qwen-code-dev-bot

qwen-code-dev-bot commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

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

中文说明

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

doudouOUC and others added 3 commits July 28, 2026 12:40
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
@doudouOUC
doudouOUC force-pushed the agent/7752-managed-session-writer-shutdown branch from 1f7203a to da86eb0 Compare July 28, 2026 04:44
@wenshao

wenshao commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

Local verification report — real build, real daemon, real child processes

I built this PR from source and verified it end-to-end on Linux against a real bundled qwen serve with real qwen --acp children and real writer-lock files — no mocks and no fake timers anywhere in the evidence below. Every measurement was run twice: once on the PR head (1f7203aa1) and once on its merge base (923e5ab42), from the same harness and the same bundle pipeline.

Verdict: the behavior this PR claims is real, measurable, and does not regress the existing fail-closed paths. One blocker before merge: the branch no longer merges cleanly with main.

Environment: Linux 6.12.63 (Debian 13) · Node v22.22.2 · npm run build -- --cli-only && npm run bundle in two isolated worktrees.


1. The decisive A/B — what happens when the lock cannot be released

I made the lock directory immutable (chattr +i, so the exact-owner rename/unlink fails with EPERM even for root), created two persisted sessions holding writer locks, and sent SIGTERM.

fail injection A/B

base 923e5ab42 PR #7812
daemon exit code 0 1
writer locks 2 → 2 (retained) 2 → 2 (retained by design)
operator warning none qwen --acp: managed session writer shutdown failed; a writer lock may be retained for safety… + candidate lock paths
daemon log daemon stopped daemon shutdown incomplete / ACP child pid=… exited uncleanly during shutdown (code=1, signal=none)

This is the core of the P0. On main today a leaked writer lock is indistinguishable from a clean shutdown — the daemon exits 0 and logs daemon stopped. Under a Kubernetes rolling replacement that leaked lock carries a foreign hostname, so the replacement can never prove it stale and returns session_writer_conflict forever, with nothing in the previous Pod's logs to explain why. This PR turns that into a non-zero exit plus an operator-actionable warning naming the lock paths.

2. Managed acquisition never reclaims — and standalone still does

I hand-planted a writer lock and asked a replacement daemon to POST /session/:id/resume.

reclaim policy A/B

planted lock owner base 923e5ab42 PR #7812
dead local pid, same hostname 200 OKlock stolen, planted owner replaced 409 session_writer_conflict, planted lock untouched
foreign hostname (the k8s rollout shape) 409 session_writer_conflict 409 session_writer_conflict (unchanged)

The second row is the regression check that matters: the pre-existing fail-closed behavior is preserved exactly. A separate real-filesystem run against the built core dist confirms the split is per-policy and not a blanket change — 3/3 passed:

  • reclaimPolicy default (standalone ACP) still reclaims a provably-dead local owner;
  • reclaimPolicy: 'never' refuses the same lock and leaves it byte-identical;
  • release() never deletes a successor lock it does not own (rejects with SessionWriterLostError, successor intact) — the owner-exact rename commit works as documented.

3. Child-process timeline and end-to-end shutdown

registry timeline and e2e

ProcessRegistry, driven with real Node children and a wall clock — 5/5:

check measured
cooperative children exit 0 on TERM 3 children, clean shutdown in 5 ms (well inside the 5 s escalation)
child ignores SIGTERM SIGKILL at 5002 ms, reported unclean: exited uncleanly during shutdown (… signal=SIGKILL)
child can never be reaped 10005 msACP child pid=… did not exit within 10000ms
repeated shutdown() same terminal in 0 ms — the 10 s deadline is not restarted
reserve() while draining refused (ACP process registry is draining) — no child escapes tracking

Bundled qwen serve under SIGTERM (PR head):

scenario result
single workspace, 3 thread sessions locks 3 → 0, daemon exit 0 in 24 ms, 0 orphan qwen --acp; replacement daemon resumed all 3 (200) and appended (202); its own shutdown also clean
mid-turn — 3 sessions parked inside a never-ending model stream the three prompt turn completed lines land after received SIGTERM, draining (admission closed, turns cancelled), locks 3 → 0, exit 0 in 41 ms
primary + secondary workspace (--workspace A --workspace B), 4 sessions 2 ACP children, both reaped, 0 orphans, locks 4 → 0, exit 0 in 33 ms

For transparency: in the happy path and the mid-turn path, base 923e5ab42 also releases every lock and exits 0. Those two scenarios are non-regression evidence, not a reproduction of the bug — the bug only becomes observable when release fails (§1) or when a foreign-host lock is involved, which a single host cannot reproduce directly. §1 and §2 are the discriminating cases.

4. Static checks and test suites (PR head)

check result
tsc --noEmitcore, acp-bridge, cli ✅ 0 errors in all three
eslint --max-warnings 0 on all 18 changed TS files ✅ clean
npm run check:serve-fast-path-bundle Startup bundle closure checks passed
packages/core full suite 17981 passed, 13 skipped, 2 failed†
packages/acp-bridge full suite (20 files) 971 passed
cli acpAgent.test.ts + run-qwen-serve.test.ts 533 passed

† Both failures are session-writer-lease.test.ts cases that depend on chmod restricting access (classifies an unreadable owned lock as unavailable, exposes the owned lease when transcript inspection cleanup must be retried). They fail because my shell runs as root, where chmod 000/500 does not restrict anything. Both fail identically on the merge base 923e5ab42 — pre-existing environment artifact, not a regression from this PR.


Blocker: rebase needed

mergeable_state is dirty. git merge-tree origin/main pr-7812 conflicts in exactly two files:

  • packages/core/src/config/config.ts
  • packages/core/src/config/config.test.ts

Everything else auto-merges. The conflict is against #7894 "Gate session writer lease behind opt-in", which landed on main today. The semantic point to get right in the rebase — a purely textual resolution will silently undo #7894:

  1. activateChatRecording() must keep feat: Gate session writer lease behind opt-in #7894's gate if (!this.chatRecordingEnabled || !this.sessionWriterLeaseEnabled) return;not this PR's !this.experimentalZedIntegration.
  2. ChatRecordingService's default writerLeaseRequired must stay on config.isSessionWriterLeaseEnabled?.().
  3. This PR's additions to that method (the three sessionWriterShutdownRequested checkpoints and reclaimPolicy: this.sessionWriterReclaimPolicy) layer on top of the feat: Gate session writer lease behind opt-in #7894 gate cleanly.

Worth stating in the PR body afterwards: after #7894 the whole writer-lease protocol is behind experimental.sessionWriterLease (default false), so this shutdown path only activates for operators who opted in. That narrows the blast radius considerably and is a point in favor of merging.

Minor, non-blocking

The retained-lock warning derives candidate paths from every Config in the terminal, including ones that never acquired a lock — my run printed 3 candidate paths for 2 real locks. The wording already says "Candidate lock paths", so this is cosmetic; filtering to configs that actually held a lease would make the operator message tighter.

Recommendation

Approve after rebase. The correctness story holds up under real execution, the fail-loud behavior is a genuine improvement over silently-clean, and the no-reclaim policy is correctly scoped to managed children only.

Full harness sources (E2E shutdown, mid-turn, multi-workspace, fail-injection, reclaim A/B, real-process registry, real-fs lease policy) are reproducible from the descriptions above; happy to attach them if useful.

中文说明

本地验证报告 —— 真实构建、真实 daemon、真实子进程

我从源码构建了本 PR,并在 Linux 上针对真实打包的 qwen serve真实的 qwen --acp 子进程真实的 writer 锁文件做了端到端验证 —— 下面所有证据中没有任何 mock,也没有任何 fake timer。每一项测量都跑了两遍:一遍在 PR head(1f7203aa1),一遍在其 merge base(923e5ab42),使用同一套 harness 和同一条打包流水线。

结论:本 PR 声称的行为是真实、可测量的,并且没有破坏现有的 fail-closed 路径。合并前有一个阻塞项:该分支已经无法与 main 干净合并。

环境:Linux 6.12.63(Debian 13)· Node v22.22.2 · 在两个隔离的 worktree 中执行 npm run build -- --cli-only && npm run bundle


1. 决定性的 A/B —— 当锁无法被释放时会发生什么

我把锁目录设为不可变(chattr +i,这样即使是 root,精确 owner 的 rename/unlink 也会以 EPERM 失败),创建了两个持有 writer 锁的持久化会话,然后发送 SIGTERM

fail injection A/B

base 923e5ab42 PR #7812
daemon 退出码 0 1
writer 锁 2 → 2(保留) 2 → 2(按设计保留)
运维告警 qwen --acp: managed session writer shutdown failed; a writer lock may be retained for safety… + 候选锁路径
daemon 日志 daemon stopped daemon shutdown incomplete / ACP child pid=… exited uncleanly during shutdown (code=1, signal=none)

这就是这个 P0 的核心。在今天的 main 上,泄漏一个 writer 锁与干净关闭是无法区分的 —— daemon 退出码为 0,日志写 daemon stopped。在 Kubernetes 滚动替换场景下,这个泄漏的锁带着一个外部 hostname,替代实例永远无法证明它已失效,于是无限期返回 session_writer_conflict,而上一个 Pod 的日志里没有任何线索能解释原因。本 PR 把这种情况变成了非零退出码 + 一条列出锁路径、可供运维直接处置的告警。

2. 托管模式下永不抢锁 —— 而独立模式仍然会回收

我手工植入一个 writer 锁,然后让一个替代 daemon 执行 POST /session/:id/resume

reclaim policy A/B

植入的锁 owner base 923e5ab42 PR #7812
已死的本机 pid,相同 hostname 200 OK —— 锁被抢走,植入的 owner 被替换 409 session_writer_conflict,植入的锁原封不动
外部 hostname(k8s 滚动替换形态) 409 session_writer_conflict 409 session_writer_conflict(无变化)

第二行才是真正重要的回归检查:既有的 fail-closed 行为被完整保留。另外一轮针对已构建 core dist 的真实文件系统测试确认了这是按 policy 区分的、而不是一刀切的改动 —— 3/3 通过

  • reclaimPolicy 默认值(独立 ACP)仍会回收可证明已死的本机 owner;
  • reclaimPolicy: 'never' 会拒绝同一个锁,并让它保持逐字节不变;
  • release() 绝不会删除不属于自己的后继锁(以 SessionWriterLostError 拒绝,后继锁完好)—— owner-exact rename 提交语义与文档一致。

3. 子进程时间线与端到端关闭

registry timeline and e2e

ProcessRegistry,用真实 Node 子进程 + 真实墙上时钟驱动 —— 5/5:

检查项 实测
子进程收到 TERM 后正常退出 0 3 个子进程,5 ms 内干净关闭(远早于 5 秒升级点)
子进程忽略 SIGTERM 5002 ms 时 SIGKILL,报告为不干净:exited uncleanly during shutdown (… signal=SIGKILL)
子进程永远无法被回收 10005 msACP child pid=… did not exit within 10000ms
重复调用 shutdown() 0 ms 返回同一个终态 —— 10 秒截止时间不会被重启
draining 期间调用 reserve() 被拒绝(ACP process registry is draining)—— 没有子进程能逃出纳管

打包后的 qwen serveSIGTERM 下(PR head):

场景 结果
单 workspace,3 个 thread 会话 锁 3 → 0,daemon 退出码 0,耗时 24 ms,0 个孤儿 qwen --acp;替代 daemon 成功 resume 全部 3 个(200)并追加写入(202);它自身的关闭也是干净的
turn 进行中 —— 3 个会话停在一个永不结束的模型流里 三条 prompt turn completed 出现在 received SIGTERM, draining 之后(准入已关闭、turn 被取消),锁 3 → 0,退出码 0,耗时 41 ms
primary + secondary workspace(--workspace A --workspace B),4 个会话 2 个 ACP 子进程全部回收,0 孤儿,锁 4 → 0,退出码 0,耗时 33 ms

为了透明说明:在正常路径turn 进行中这两个场景下,base 923e5ab42 同样释放了全部锁并以 0 退出。这两项属于无回归证据,而不是对 bug 的复现 —— 该 bug 只有在释放失败(§1)或涉及外部 hostname 锁时才可观测,而后者在单机上无法直接复现。§1 和 §2 才是具有区分度的用例。

4. 静态检查与测试套件(PR head)

检查项 结果
tsc --noEmit —— coreacp-bridgecli ✅ 三者均 0 错误
对全部 18 个改动 TS 文件执行 eslint --max-warnings 0 ✅ 干净
npm run check:serve-fast-path-bundle Startup bundle closure checks passed
packages/core 全量套件 17981 通过,13 跳过,2 失败†
packages/acp-bridge 全量套件(20 个文件) 971 通过
cliacpAgent.test.ts + run-qwen-serve.test.ts 533 通过

† 两个失败都来自 session-writer-lease.test.ts 中依赖 chmod 限制访问的用例(classifies an unreadable owned lock as unavailableexposes the owned lease when transcript inspection cleanup must be retried)。失败原因是我的 shell 以 root 运行,而 chmod 000/500 对 root 不起任何限制作用。这两个用例在 merge base 923e5ab42 上以完全相同的方式失败 —— 属于既有的环境问题,不是本 PR 引入的回归。


阻塞项:需要 rebase

mergeable_statedirtygit merge-tree origin/main pr-7812 的冲突恰好只有两个文件:

  • packages/core/src/config/config.ts
  • packages/core/src/config/config.test.ts

其余文件都能自动合并。冲突来自今天刚合入 main#7894「Gate session writer lease behind opt-in」。rebase 时必须注意下面这个语义要点 —— 单纯按文本解决冲突会悄悄地把 #7894 撤销掉:

  1. activateChatRecording() 必须保留 feat: Gate session writer lease behind opt-in #7894 的开关:if (!this.chatRecordingEnabled || !this.sessionWriterLeaseEnabled) return; —— 不能用本 PR 的 !this.experimentalZedIntegration
  2. ChatRecordingServicewriterLeaseRequired 默认值必须继续基于 config.isSessionWriterLeaseEnabled?.()
  3. 本 PR 对该方法的新增内容(三处 sessionWriterShutdownRequested 检查点,以及 reclaimPolicy: this.sessionWriterReclaimPolicy)可以干净地叠加在 feat: Gate session writer lease behind opt-in #7894 的开关之上。

rebase 之后值得在 PR 描述里补一句:在 #7894 之后,整套 writer lease 协议都在 experimental.sessionWriterLease(默认 false)后面,因此本 PR 的关闭路径只对显式开启该开关的运维生效。这会显著缩小影响面,也是支持合并的一个理由。

次要问题(不阻塞)

保留锁的告警是从终态中的每一个 Config 推导候选路径的,其中包括从未获取过锁的 Config —— 我这次运行时,2 个真实锁却打印了 3 个候选路径。文案本身已经写的是「Candidate lock paths」,所以只是观感问题;如果过滤成只保留真正持有过 lease 的 Config,这条运维消息会更精准。

建议

rebase 后 Approve。 正确性在真实执行下站得住脚,「失败即大声报错」相比「静默地看起来干净」是实打实的改进,而「不抢锁」策略也正确地只限定在托管子进程上。

完整的 harness 源码(端到端关闭、turn 进行中、多 workspace、失败注入、抢锁 A/B、真实进程 registry、真实文件系统 lease policy)都可以按上文描述复现;如果有需要我可以附上。


🤖 Generated with Claude Code — Claude Opus 5 (1M context)

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed. Not reviewed: invariant-a — the coverage harness recorded the first launch's transcript (which did not open the brief); the substantive relaunch examined state, timers, and collections and found nothing, but the transcript gap persists. Not reviewed: the invariant check (state, timers, collections) on packages/acp-bridge/src/spawnChannel.ts — never opened its brief, so it reviewed without the instructions it was launched to follow.

中文说明

已审查。 未审查:invariant-a — the coverage harness recorded the first launch's transcript (which did not open the brief); the substantive relaunch examined state, timers, and collections and found nothing, but the transcript gap persists。 未审查:不变量检查(状态、定时器、集合)(packages/acp-bridge/src/spawnChannel.ts)——从未打开自己的 brief,审查时缺失了它本应遵循的指令。

— qwen3.7-max via Qwen Code /review

@doudouOUC

Copy link
Copy Markdown
Collaborator Author

@wenshao Thanks for the thorough real-process A/B report. The reported blocker is resolved on da86eb029c: the branch is rebased onto #7894 (b475d1a263) and preserves the sessionWriterLeaseEnabled gate, ChatRecordingService effective-gate default, all three shutdown admission checkpoints, and managed reclaimPolicy: never. GitHub now reports the PR mergeable and CI is 18/18 green. Operationally, the writer shutdown path is active only when experimental.sessionWriterLease is the boolean true and the ACP/daemon has restarted. The extra candidate-path filtering is valid but cosmetic and remains deferred under the repository review-round cutoff.

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

Autofix review round — no code changes

This round triaged the new feedback (newer than the last evaluation). No code
changes were made: the one blocker is already resolved on the branch, the
remaining suggestion is a non-Critical cosmetic item deferred under the
repository review-round cutoff, and the automated reviewer's note is an
informational disclosure of its own coverage gap, not a defect.

@wenshao — local verification report

Blocker "rebase needed" — verified resolved (no action required). The
branch already carries #7894 as its merge base:

  • git merge-base HEAD origin/mainb475d1a26 (feat: Gate session writer lease behind opt-in (#7894)), so the conflict source named in the report is
    now the branch's base, not a divergent change.
  • git merge-tree --write-tree origin/main HEAD returns a clean tree with no
    conflict output. The only main commit after the merge base is fix(review): give the review retry the remaining time budget #7852 (review
    retry timing), which does not touch config.ts / config.test.ts.
  • The semantic points the report flagged are preserved correctly after the
    rebase, not reverted by a textual resolution:
    • activateChatRecording() keeps the feat: Gate session writer lease behind opt-in #7894 gate
      if (!this.chatRecordingEnabled || !this.sessionWriterLeaseEnabled)
      (config.ts:2932), not !this.experimentalZedIntegration.
    • sessionWriterLeaseEnabled still requires the opt-in
      (experimentalZedIntegration === true && params.sessionWriterLeaseEnabled === true,
      config.ts:2123-2125).
    • ChatRecordingService's writerLeaseRequired default still resolves from
      config.isSessionWriterLeaseEnabled?.() (chatRecordingService.ts:691).

No merge was performed this round (the workflow signaled no conflict); the
verification above is read-only.

Minor, non-blocking — candidate lock paths include configs that never held a
lease: deferred.
Filtering the warning to only configs that actually acquired
a lease requires exposing that state from Config and wiring it through, a
cross-package (core + cli) widening of the mature P0 diff. The report itself
labels this cosmetic and non-blocking (the wording already says "Candidate lock
paths"), and it overlaps the already-deferred lock-path helper reuse (review
item 7) at the same code block. Under the repository review-round cutoff the PR
is past, only Critical fixes land; this is deferred as a follow-up.

@qwen-code-ci-bot — automated review

The note discloses that two of the reviewer's own sub-agents did not load their
review briefs (the invariant-a transcript gap and the spawnChannel.ts
state/timer/collection invariant check). It names no defect in the code, and
the reviewer's relaunch "examined state, timers, and collections and found
nothing." There is no evidence-backed code change to make from a coverage-gap
disclosure, so no action is taken.

Prior inline findings — unchanged

The earlier review's inline findings remain in their prior state after the
rebase: the correctness fixes (error tagging, ??= registry clobber guard,
admission check inside the writer-error mapping, bounded release pre-check
retry, and strict-only initialization join) are present in the rebased commits,
and the non-Critical suggestions remain deferred with their recorded reasons
from the prior round.

中文说明

Autofix 审查轮次 —— 无代码改动

本轮对新增反馈(晚于上次评估的部分)进行了分类处理。未做任何代码改动:唯一的阻塞项已经在分支上解决,剩余的建议是一个非关键的观感项、按仓库的审查轮次截止规则延期处理,而自动审查器的说明只是对其自身审查覆盖缺口的信息披露,并非缺陷。

@wenshao —— 本地验证报告

阻塞项「需要 rebase」—— 已验证解决(无需处理)。 分支已经把 #7894 作为其 merge base:

  • git merge-base HEAD origin/mainb475d1a26feat: Gate session writer lease behind opt-in (#7894)),因此报告中点名的冲突来源现在是分支的基线,而不再是一个分叉的改动。
  • git merge-tree --write-tree origin/main HEAD 返回一棵干净的树,没有任何冲突输出。merge base 之后 main 上唯一的提交是 fix(review): give the review retry the remaining time budget #7852(review 重试计时),它不触碰 config.ts / config.test.ts
  • 报告中标注的语义点在 rebase 之后被正确保留,而不是被一次按文本的解决方式撤销掉:
    • activateChatRecording() 保留了 feat: Gate session writer lease behind opt-in #7894 的开关 if (!this.chatRecordingEnabled || !this.sessionWriterLeaseEnabled)config.ts:2932),而不是 !this.experimentalZedIntegration
    • sessionWriterLeaseEnabled 仍然要求显式开启(experimentalZedIntegration === true && params.sessionWriterLeaseEnabled === trueconfig.ts:2123-2125)。
    • ChatRecordingServicewriterLeaseRequired 默认值仍然从 config.isSessionWriterLeaseEnabled?.() 解析(chatRecordingService.ts:691)。

本轮没有执行 merge(工作流给出的信号是无冲突);以上验证全部是只读的。

次要、不阻塞 —— 候选锁路径包含了从未持有过 lease 的 Config:延期处理。 要把这条告警过滤成只保留真正获取过 lease 的 Config,需要从 Config 暴露该状态并把它接线打通,这是一次跨包(core + cli)的改动,会扩大已经成熟的 P0 差异。报告本身就把这一项标注为观感问题、不阻塞(文案已经写的是「Candidate lock paths」),而且它与同一代码块处已经延期的锁路径 helper 复用(审查项 7)相互重叠。按本 PR 已经越过的仓库审查轮次截止规则,只有关键(Critical)修复才会合入;此项作为后续工作延期。

@qwen-code-ci-bot —— 自动审查

该说明披露了审查器自身的两个子代理没有加载它们的审查 brief(invariant-a 的 transcript 缺口,以及 spawnChannel.ts 的状态/定时器/集合不变量检查)。它没有指出代码中的任何缺陷,而且审查器的重新启动「检查了状态、定时器和集合,没有发现任何问题」。从一个覆盖缺口的披露中无法得出任何有证据支撑的代码改动,因此不采取行动。

此前的内联发现 —— 状态不变

上一轮审查的内联发现在 rebase 之后保持其先前状态:各项正确性修复(错误标记、??= 的 registry 覆盖保护、位于 writer-error 映射内部的准入检查、有界的释放预检重试,以及仅 strict 模式才等待初始化)都存在于 rebase 后的提交中;各项非关键的建议则保持延期,并附有上一轮记录的延期理由。

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


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

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

Autofix review round — no action taken

No code change was made this round.

The only new feedback is an issue-level comment from maintainer @doudouOUC. It is a status confirmation rather than a change request:

  • The reported blocker is confirmed resolved on the current HEAD (da86eb029c).
  • The branch is rebased onto feat: Gate session writer lease behind opt-in #7894 (b475d1a263) and preserves the sessionWriterLeaseEnabled gate, the ChatRecordingService effective-gate default, all three shutdown admission checkpoints, and managed reclaimPolicy: never.
  • GitHub reports the PR mergeable and CI is 18/18 green.

The single remaining item mentioned — "extra candidate-path filtering" — is explicitly described by the maintainer as "valid but cosmetic" and "deferred under the repository review-round cutoff." Per the repository's review policy, once a PR has been through roughly five review rounds only Critical fixes (correctness, security, data loss, regressions) are landed and remaining Suggestions are deferred to a follow-up. This item is a deferred Suggestion, not a Critical, so implementing it now would contradict the maintainer's stated decision and grow the diff without cause.

There were no reviews, no inline comments, and no failed or still-red checks to address.

中文说明

Autofix 审查轮次 —— 本轮未做任何改动

本轮未做任何代码改动。

唯一的新反馈是维护者 @doudouOUC 的一条 issue 级评论。它是状态确认,而非改动请求:

  • 已确认所报告的阻塞问题在当前 HEAD(da86eb029c)上解决。
  • 分支已 rebase 到 feat: Gate session writer lease behind opt-in #7894b475d1a263)之上,并保留了 sessionWriterLeaseEnabled 门控、ChatRecordingService 的有效门控默认值、全部三个关停准入检查点,以及 managed 的 reclaimPolicy: never
  • GitHub 显示该 PR 可合并,CI 为 18/18 全绿。

评论中提到的唯一剩余项 —— “额外的候选路径过滤(extra candidate-path filtering)” —— 被维护者明确描述为“有效但属于表面性(cosmetic)”,并“依据仓库的审查轮次截止规则予以推迟(deferred)”。根据仓库的审查政策,当一个 PR 经历大约五轮审查后,只落地 Critical 级修复(正确性、安全性、数据丢失、回归),其余 Suggestion 推迟到后续处理。该项是一个被推迟的 Suggestion,而非 Critical,因此现在实现它会与维护者已明确表达的决定相矛盾,并会毫无理由地扩大 diff。

本轮没有需要处理的 review、内联评论,也没有失败或持续飘红的检查项。

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


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

@wenshao

wenshao commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

Local verification, round 2 — real build, real daemon, real child processes, at head 7396e3e40

Follow-up to my report on 1f7203aa1. The blocker I raised there — the branch no longer merged with main — is resolved, and the resolution is the semantically correct one, not a textual one. I rebuilt both sides from source and re-ran every measurement on the current head, plus three new probes aimed at what changed since.

Verdict: LGTM. No blockers. The rebase preserved #7894, every discriminating A/B still reproduces, and under the shipping default the daemon is behaviourally indistinguishable from main.

Environment: Linux 6.12.63 (Debian 13) · Node v22.22.2 · npm run build -- --cli-only && npm run bundle in two isolated worktrees — PR head 7396e3e40 vs its merge base 2db663bec. No mocks and no fake timers anywhere below.


0. What actually changed since I last reviewed this

I diffed the two net patches — 923e5ab42…1f7203aa1 (what I reviewed) against 2db663bec…7396e3e40 (what is proposed now). They are identical except for one added line, a test fixture:

 it('treats managed shutdown during writer acquisition as a clean terminal', async () => {
   const config = new Config({
     ...baseParams,
     chatRecording: true,
     experimentalZedIntegration: true,
+    sessionWriterLeaseEnabled: true,

So the whole delta since my last round is the merge with main. The three points I flagged as easy to get wrong in that merge all landed correctly:

my point current head
activateChatRecording() must keep #7894's gate if (!this.chatRecordingEnabled || !this.sessionWriterLeaseEnabled) return;
ChatRecordingService default writerLeaseRequired config.isSessionWriterLeaseEnabled?.() ?? …
this PR's additions layer on top, not instead ✅ the shutdown checkpoints and reclaimPolicy sit inside the gated body; config.ts is no longer part of the lease-gate diff at all

That last row is the strongest form of the check: the gate expression is now identical on both sides of the diff, so #7894 cannot have been undone.

1. The decisive A/B — what happens when the lock cannot be released

Lock directory made immutable (chattr +i, so the exact-owner rename/unlink fails with EPERM even for root), two persisted sessions holding writer locks, then SIGTERM.

fail injection A/B

base 2db663bec PR #7812
daemon exit code 0 1
writer locks 2 → 2 (retained) 2 → 2 (retained by design)
operator warning none qwen --acp: managed session writer shutdown failed; a writer lock may be retained for safety… + candidate lock paths
daemon log daemon stopped daemon shutdown incomplete / ACP child pid=… exited uncleanly during shutdown (code=1, signal=none)

Unchanged from the previous round, which is the point: this is still the whole value of the P0. On main a leaked writer lock is indistinguishable from a clean shutdown; under a rolling replacement that lock carries a foreign hostname, the replacement can never prove it stale, and nothing in the departing Pod's logs explains why.

2. Managed acquisition never reclaims — and standalone still does

reclaim policy A/B

planted lock owner base 2db663bec PR #7812
dead local pid, same hostname 200 OKlock stolen, planted owner replaced 409 session_writer_conflict, planted lock untouched
foreign hostname (the k8s rollout shape) 409 session_writer_conflict 409 session_writer_conflict (unchanged)

The second row is the regression check that matters — fail-closed behaviour is preserved exactly. A separate real-filesystem run against the built core dist confirms the split is per-policy, 3/3: default policy still reclaims a provably-dead local owner; reclaimPolicy: 'never' refuses the same lock and leaves it byte-identical; release() rejects with SessionWriterLostError rather than deleting a successor lock it does not own.

3. Child-process timeline and end-to-end shutdown

registry timeline and e2e

ProcessRegistry driven with real Node children and a wall clock — 5/5: cooperative children clean in 5 ms; a SIGTERM-ignoring child SIGKILLed at 5002 ms and reported unclean; an unreapable child hitting the 10005 ms not-reaped deadline; a repeated shutdown() returning the same terminal in 0 ms (the deadline is not restarted); reserve() refused while draining.

Bundled qwen serve under SIGTERM, PR head: single workspace / 3 sessions — locks 3 → 0, exit 0 in 43 ms, 0 orphans, replacement daemon resumed 3× 200 and appended 3× 202. Mid-turn (3 sessions parked in a never-ending model stream) — the three prompt turn completed lines land after received SIGTERM, draining, locks 3 → 0, exit 0 in 51 ms. Primary + secondary workspace — 2 ACP children, both reaped, locks 4 → 0, exit 0 in 38 ms.

As before, and worth repeating: in the happy path and the mid-turn path the base also releases every lock and exits 0. Those are non-regression evidence, not a reproduction. §1 and §2 are the discriminating cases.

4. New this round — blast radius with the shipping default

Since #7894, experimental.sessionWriterLease defaults to false, so I re-ran the whole thing with the flag simply absent — including the same chattr +i injection, which is now a no-op because there is nothing to release. This is the configuration almost every operator will actually run.

default off blast radius

Base and PR are indistinguishable: 0 locks created, exit 0, daemon stopped, no "incomplete", 0 orphans, replacement daemon resumed 2× 200 and appended 2× 202, and the appended record is on disk in both (8 transcript records per session, append marker present). The fail-loud path only arms for operators who opted in — a genuinely small blast radius, and it doubles as a negative control for §1: the same injection, the same build, exit 0 when there is no lease to release.

I also checked the restart-required freeze, since experimental.sessionWriterLease can be flipped on disk and re-read by a live ACP child via POST /workspace/reload. Flipping it in both directions and then creating a new session in that same child: OFF→ON the new session still takes no lock, ON→OFF it still takes one — on both builds. So the freeze is main's behaviour (it arrived with #7894, not with this PR) and this PR leaves it intact; no leased/legacy writer mixing in either direction.

5. New this round — a wedged MCP server at shutdown

This PR makes shutdownMcpPool() throw where it used to only warn, and the managed path drains it strictly. I probed that with a stdio MCP server that answers initialize/tools/list normally and then ignores SIGTERM and stdin EOF forever.

wedged mcp server

base 2db663bec PR #7812
daemon exit 0 in 39 ms 0 in 4040 ms
writer locks 2 → 0 2 → 0
wedged MCP process survives — still alive 19 s after the daemon is gone; my harness had to SIGKILL it reaped — gone by the first sample after exit

Two things worth stating plainly. First, the strict drain does not produce a false "unclean": exit stays 0, the log still says daemon stopped. Second, this is an unadvertised improvement — on main the daemon exits before the ACP child's pool drain can finish, so the wedged MCP process is simply left behind; here the shutdown waits for the child to be reaped and the drain completes. Reproduced twice per side.

The cost is shutdown latency in that shape: 0.04 s → 4.0 s. It is bounded by the 5 s TERM→KILL escalation, so it cannot run away, but operators with slow-closing MCP servers will notice their pod termination getting slower. Worth a line in the PR description rather than a change.

6. Static checks and test suites (PR head)

check result
tsc --noEmitcore, acp-bridge, cli ✅ 0 errors in all three
eslint --max-warnings 0 on all 18 changed TS files ✅ clean
npm run check:serve-fast-path-bundle Startup bundle closure checks passed.
packages/core full suite 18050 passed, 13 skipped, 2 failed†
packages/acp-bridge full suite (20 files) 979 passed
cli acpAgent.test.ts + run-qwen-serve.test.ts 535 passed

† Both failures are the session-writer-lease.test.ts cases that depend on chmod restricting access (classifies an unreadable owned lock as unavailable, exposes the owned lease when transcript inspection cleanup must be retried). My shell runs as root, where chmod 000/500 restricts nothing. I re-ran that file on the merge base 2db663bec this round: the same 2 fail, 19 pass, 1 skipped — pre-existing environment artefact, not a regression.

Minor, non-blocking

Unchanged from last round, and I still would not hold the merge for it: the retained-lock warning derives candidate paths from every Config in the terminal, including ones that never acquired a lock — this run printed 3 candidate paths for 2 real locks. The wording already says "Candidate lock paths", so it is cosmetic; filtering to configs that actually held a lease would tighten the operator message.

Recommendation

Approve. The correctness story holds under real execution at the current head, the rebase preserved #7894's opt-in gate in the way that matters, the default configuration is unchanged from main, and the fail-loud behaviour is a real improvement over silently-clean. Please consider adding the MCP-drain observation from §5 to the PR description — it is a user-visible timing change and an unclaimed win.

中文说明

本地验证第 2 轮 —— 真实构建、真实 daemon、真实子进程,基于 head 7396e3e40

这是对我在 1f7203aa1 上那份报告的后续。当时提出的阻塞项 —— 分支已无法与 main 干净合并 —— 已经解决,而且解决方式在语义上是正确的,不是单纯的文本合并。我重新从源码构建了两侧,在当前 head 上重跑了全部测量,并针对这期间的变化新增了三项探测。

结论:LGTM,无阻塞项。这次 rebase 完整保留了 #7894,所有具备区分度的 A/B 依然可复现,并且默认配置下与 main 的行为完全一致。

环境:Linux 6.12.63(Debian 13)· Node v22.22.2 · 在两个隔离 worktree 中执行 npm run build -- --cli-only && npm run bundle —— PR head 7396e3e40 对比其 merge base 2db663bec。以下所有证据没有任何 mock,也没有任何 fake timer


0. 自我上次审阅以来,实际改动了什么

我对比了两份 net patch —— 923e5ab42…1f7203aa1(我审阅过的)与 2db663bec…7396e3e40(现在提交的)。二者完全一致,只多了一行,而且是测试 fixture:

 it('treats managed shutdown during writer acquisition as a clean terminal', async () => {
   const config = new Config({
     ...baseParams,
     chatRecording: true,
     experimentalZedIntegration: true,
+    sessionWriterLeaseEnabled: true,

也就是说,这一轮的全部增量就是与 main 的合并。我当时点名"合并时最容易做错"的三处,现在都处理正确:

我当时提的点 当前 head
activateChatRecording() 必须保留 #7894 的开关 if (!this.chatRecordingEnabled || !this.sessionWriterLeaseEnabled) return;
ChatRecordingServicewriterLeaseRequired 默认值 config.isSessionWriterLeaseEnabled?.() ?? …
本 PR 的新增应当叠加在上面,而不是替换 ✅ 关闭检查点与 reclaimPolicy 都位于被 gate 的函数体内;config.ts 已完全不在 lease-gate 的 diff 里

最后一行是最强形式的验证:这个 gate 表达式现在在 diff 两侧完全相同,因此 #7894 不可能被撤销。

1. 决定性的 A/B —— 当锁无法被释放时

把锁目录设为不可变(chattr +i,这样即使 root,精确 owner 的 rename/unlink 也会以 EPERM 失败),创建两个持有 writer 锁的持久化会话,然后发送 SIGTERM

fail injection A/B

base 2db663bec PR #7812
daemon 退出码 0 1
writer 锁 2 → 2(保留) 2 → 2(按设计保留)
运维告警 qwen --acp: managed session writer shutdown failed; a writer lock may be retained for safety… + 候选锁路径
daemon 日志 daemon stopped daemon shutdown incomplete / ACP child pid=… exited uncleanly during shutdown (code=1, signal=none)

与上一轮完全一致 —— 这正是重点:这依然是这个 P0 的全部价值所在。在 main 上,泄漏一个 writer 锁与干净关闭无法区分;在滚动替换场景下,这个锁带着外部 hostname,替代实例永远无法证明它已失效,而退出的那个 Pod 的日志里没有任何线索。

2. 托管模式下永不抢锁 —— 独立模式仍会回收

reclaim policy A/B

植入的锁 owner base 2db663bec PR #7812
已死的本机 pid,相同 hostname 200 OK —— 锁被抢走,植入的 owner 被替换 409 session_writer_conflict,植入的锁原封不动
外部 hostname(k8s 滚动替换形态) 409 session_writer_conflict 409 session_writer_conflict(无变化)

第二行才是真正重要的回归检查 —— fail-closed 行为被完整保留。另有一轮针对已构建 core dist 的真实文件系统测试确认这是按 policy 区分而非一刀切,3/3 通过:默认 policy 仍会回收可证明已死的本机 owner;reclaimPolicy: 'never' 拒绝同一个锁并让其逐字节不变;release()SessionWriterLostError 拒绝,而不会删除不属于自己的后继锁。

3. 子进程时间线与端到端关闭

registry timeline and e2e

用真实 Node 子进程 + 真实墙上时钟驱动 ProcessRegistry —— 5/5:协作式子进程 5 ms 内干净退出;忽略 SIGTERM 的子进程在 5002 ms 被 SIGKILL 并报告为不干净;无法回收的子进程触发 10005 ms 未回收截止;重复调用 shutdown()0 ms 返回同一终态(10 秒截止不会被重启);draining 期间 reserve() 被拒绝。

打包后的 qwen serveSIGTERM 下(PR head):单 workspace / 3 会话 —— 锁 3 → 0,退出码 0、耗时 43 ms、0 孤儿,替代 daemon 成功 resume 3× 200 并追加 3× 202。turn 进行中(3 个会话停在永不结束的模型流里)—— 三条 prompt turn completed 出现在 received SIGTERM, draining 之后,锁 3 → 0,退出码 0、耗时 51 ms。primary + secondary workspace —— 2 个 ACP 子进程全部回收,锁 4 → 0,退出码 0、耗时 38 ms。

需要再次说明:正常路径和 turn 进行中这两个场景,base 同样释放全部锁并以 0 退出。它们属于无回归证据,不是对 bug 的复现。§1 与 §2 才是具有区分度的用例。

4. 本轮新增 —— 默认配置下的影响范围

#7894 起,experimental.sessionWriterLease 默认为 false,所以我在完全不写这个开关的情况下重跑了全套流程 —— 包括同样的 chattr +i 注入(此时它是空操作,因为根本没有锁需要释放)。这是几乎所有运维实际会跑的配置。

default off blast radius

base 与 PR 无法区分:创建 0 个锁、退出码 0daemon stopped、无 "incomplete"、0 孤儿,替代 daemon resume 2× 200 并追加 2× 202,并且追加的记录在两侧都确实落盘(每个会话 8 条 transcript 记录,追加标记存在)。fail-loud 路径只对显式开启的运维生效 —— 影响范围确实很小;同时它也是 §1 的负对照:同样的注入、同样的构建,在没有 lease 需要释放时退出码为 0

我还验证了这个 requiresRestart 设置的"冻结"行为,因为 experimental.sessionWriterLease 可以在磁盘上被改写、并被存活的 ACP 子进程通过 POST /workspace/reload 重新读取。在两个方向上翻转后于同一子进程内新建会话:OFF→ON 新会话依然不取锁,ON→OFF 新会话依然取锁 —— 两侧构建行为一致。因此这个冻结是 main 的行为(随 #7894 引入,不是本 PR 带来的),本 PR 完整保留了它;两个方向都不会出现 leased/legacy writer 混用。

5. 本轮新增 —— 关闭时卡死的 MCP server

本 PR 把 shutdownMcpPool() 从"仅告警"改成了抛异常,并且托管路径会严格 drain。我用一个 stdio MCP server 来探测:它正常响应 initialize/tools/list,随后永远忽略 SIGTERM 和 stdin EOF。

wedged mcp server

base 2db663bec PR #7812
daemon 退出 0,耗时 39 ms 0,耗时 4040 ms
writer 锁 2 → 0 2 → 0
卡死的 MCP 进程 存活 —— daemon 退出 19 秒后仍在,最后由我的 harness SIGKILL 已回收 —— 退出后第一次采样即已消失

有两点需要明确说明。第一,严格 drain 不会产生误报的"不干净":退出码仍是 0,日志仍写 daemon stopped。第二,这是一个 PR 描述里没有提到的改进 —— 在 main 上,daemon 在 ACP 子进程的 pool drain 完成之前就退出了,卡死的 MCP 进程被直接遗留;而这里关闭流程会等待子进程被回收,drain 得以完成。两侧各复现两次。

代价是这种形态下的关闭延迟:0.04 秒 → 4.0 秒。它受 5 秒 TERM→KILL 升级的上界约束,不会失控,但使用关闭较慢的 MCP server 的运维会感觉到 Pod 终止变慢。这一点建议写进 PR 描述,而不是改代码。

6. 静态检查与测试套件(PR head)

检查项 结果
tsc --noEmit —— coreacp-bridgecli ✅ 三者均 0 错误
对全部 18 个改动 TS 文件执行 eslint --max-warnings 0 ✅ 干净
npm run check:serve-fast-path-bundle Startup bundle closure checks passed.
packages/core 全量套件 18050 通过,13 跳过,2 失败†
packages/acp-bridge 全量套件(20 个文件) 979 通过
cliacpAgent.test.ts + run-qwen-serve.test.ts 535 通过

† 两个失败都来自 session-writer-lease.test.ts 中依赖 chmod 限制访问的用例(classifies an unreadable owned lock as unavailableexposes the owned lease when transcript inspection cleanup must be retried)。我的 shell 以 root 运行,chmod 000/500 对 root 不产生任何限制。本轮我在 merge base 2db663bec 上重跑了这个文件:同样 2 失败、19 通过、1 跳过 —— 属于既有环境问题,不是本 PR 引入的回归。

次要问题(不阻塞)

与上一轮相同,我也不会因此拖住合并:保留锁的告警会从终态里的每一个 Config 推导候选路径,包括那些从未获取过锁的 —— 本次运行为 2 个真实锁打印了 3 条候选路径。措辞本身已经是 "Candidate lock paths",所以只是观感问题;过滤为真正持有过 lease 的 config 会让运维信息更精确。

建议

同意合并。 在当前 head 上,正确性在真实执行下成立;rebase 以正确方式保留了 #7894 的 opt-in gate;默认配置下与 main 行为一致;fail-loud 相比"静默干净"是实打实的改进。建议把 §5 的 MCP drain 观察补进 PR 描述 —— 那是一个用户可见的耗时变化,也是一个尚未被认领的收益。


Verified locally with Claude Code (model: claude-opus-5[1m]). Harnesses: fail-injection, reclaim A/B, real-process registry, real-fs lease policy, E2E / mid-turn / multi-workspace shutdown, default-off blast radius, writer-protocol freeze, wedged-MCP drain.

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

Autofix review round — no action taken

The only new feedback on this PR is an issue-level verification report from
@wenshao. It is an approval: "LGTM. No blockers." The report re-ran every
discriminating A/B at the current head 7396e3e40 against its merge base
2db663bec (real build, real daemon, real child processes, no mocks) and
confirms the rebase preserved #7894's opt-in gate, the default configuration
is behaviourally indistinguishable from main, and the fail-loud shutdown
behaviour is a real improvement. There are no review findings, no inline
comments, and no failed CI checks (all checks are green or intentionally
skipped). The two session-writer-lease.test.ts failures the report mentions
were reproduced by the reviewer on the merge base as well — a pre-existing
root/chmod environment artefact, not a regression from this PR.

The report carries two suggestions, both explicitly labelled "Minor,
non-blocking". Neither results in a code change this round:

1. Filter the retained-lock warning's candidate paths to configs that
actually held a lease — Declined (not worth the diff growth).

The warning already hedges its wording with "Candidate lock paths", and the
reviewer states they "still would not hold the merge for it" and that it is
"cosmetic". This is the operator-facing fail-loud safety signal that is the
entire point of the P0; over-listing candidate paths is safe (an operator
checks a few paths), while narrowing the list adds logic to a safety-critical
path and risks under-listing a genuinely retained lock for zero correctness
gain. Per the repository's Simplicity First principle and the review-round
ratchet rule (a nit is never a reason to grow the diff), the current message is
left as-is.

2. Add the §5 MCP-drain shutdown-latency observation to the PR description —
Out of scope for this round; surfaced for the maintainer.

The reviewer notes that a wedged stdio MCP server now gets reaped at shutdown
(an unclaimed improvement) at the cost of bounded shutdown latency
(~0.04 s → ~4.0 s, capped by the 5 s TERM→KILL escalation), and recommends "a
line in the PR description rather than a change." This is a PR-description
documentation edit, not a code change; this automated round has no GitHub
credentials and cannot edit the PR body. Recommended maintainer action: add a
short note to the PR description that, when experimental.sessionWriterLease
is enabled, a slow-closing/wedged MCP server can extend managed-shutdown
latency up to the 5 s escalation bound, and that such servers are now reliably
reaped instead of being left behind.

No commit was made and no source files were modified, so no build/typecheck/
lint/test verification was required this round.

中文说明

Autofix 审阅轮次 —— 未采取任何行动

本 PR 上唯一的新反馈是来自 @wenshao 的一条 issue 级验证报告。这是一份同意合并的结论:"LGTM。无阻塞项。" 该报告在当前 head 7396e3e40 与其 merge base 2db663bec 上重跑了所有具备区分度的 A/B(真实构建、真实 daemon、真实子进程,无任何 mock),确认这次 rebase 完整保留了 #7894 的 opt-in 开关、默认配置下与 main 的行为无法区分,并且 fail-loud 的关闭行为是一项实打实的改进。报告中没有审阅 finding、没有行内评论,也没有失败的 CI 检查(所有检查均为绿色或被有意跳过)。报告提到的两个 session-writer-lease.test.ts 失败,已被 reviewer 在 merge base 上同样复现 —— 属于既有的 root/chmod 环境问题,并非本 PR 引入的回归。

该报告附带两条建议,均被明确标注为"次要、不阻塞"。本轮二者均不产生代码改动:

1. 将保留锁告警的候选路径过滤为真正持有过 lease 的 config —— 拒绝(不值得增加 diff)。
该告警的措辞本身已经用 "Candidate lock paths" 做了 hedging,reviewer 也表示"依然不会因此拖住合并",并称其为"观感问题"。这正是 P0 的全部价值所在 —— 面向运维的 fail-loud 安全信号;候选路径列得多一些是安全的(运维多检查几个路径即可),而收窄列表会向一条安全关键路径添加逻辑,并可能为了零正确性收益而漏报真正被保留的锁。依据本仓库的 Simplicity First 原则以及审阅轮次的棘轮规则(一个 nit 永远不是扩大 diff 的理由),当前消息保持原样。

2. 将 §5 中 MCP drain 关闭延迟的观察补进 PR 描述 —— 本轮范围之外;已转交 maintainer。
reviewer 指出,一个卡死的 stdio MCP server 现在会在关闭时被回收(一项尚未被认领的改进),代价是受限的关闭延迟(约 0.04 秒 → 约 4.0 秒,上界为 5 秒的 TERM→KILL 升级),并建议"写进 PR 描述,而不是改代码"。这是一项 PR 描述层面的文档编辑,而非代码改动;本自动化轮次没有 GitHub 凭证,无法编辑 PR 正文。建议 maintainer 采取的行动:在 PR 描述中补充一句简短说明 —— 当 experimental.sessionWriterLease 开启时,关闭缓慢/卡死的 MCP server 可能将托管关闭延迟拉长到 5 秒升级上界,并且这类 server 现在会被可靠回收,而不再被遗留。

本轮未创建任何提交,也未修改任何源文件,因此本轮无需执行 build/typecheck/lint/test 验证。

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


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

@yiliang114

yiliang114 commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

Reviewed QwenLM/qwen-code#7812 at 7396e3e: no blocking correctness, security, data-loss, coverage, or quality issues found; CI is green.

The GitHub posting action was cancelled, so no comment was published.


✅ completed

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed. Suggestions are inline. Not reviewed: reverse audit — an auditor ran and opened its brief, but no agent was launched with the prompt the CLI built — the launch was written by hand, and what the agent was actually asked is not what this skill certifies.

中文说明

已审查。 建议见行内评论。 未审查:反向审计——有审计 agent 运行并打开了自己的 brief,但没有 agent 是用 CLI 构建的 prompt 启动的——启动 prompt 是手写的,agent 实际被要求做的并不是本 skill 所认证的内容。

— qwen3.7-max via Qwen Code /review

Comment on lines +3794 to +3796
throw new Error(
`MCP pool drain incomplete: ${result.forced} forced, ${result.errors.length} errors`,
);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] shutdownMcpPool now throws when drainAll resolves with forced > 0 || errors.length > 0 (line 3794), but only the rejection path is tested — the existing test "reports managed MCP pool drain failure" uses mockRejectedValueOnce, exercising only the catch (err) → throw err branch. — Failure scenario: MCP pool drainAll resolves with { drained: 5, forced: 1, errors: [] } (slow MCP subprocess). The new throw fires, managed shutdown re-throws, and the ACP child exits code 1 — a path with no test coverage.

Suggested fix: add a test with mockMcpPoolDrainAll.mockResolvedValueOnce({ drained: 0, forced: 1, errors: [] }) that verifies managed shutdown reports unclean exit.

— qwen3.7-max via Qwen Code /review

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Thanks — deferring. The coverage observation is valid, but it is a non-blocking missing-test suggestion and this PR is past the roughly five-review-round cutoff; the resolved-forced drain behavior has also been independently exercised with a real wedged MCP process.

Comment on lines +8698 to +8703
if (teardownFailures.length > 1) {
throw new AggregateError(
teardownFailures,
'ACP bridge shutdown failed',
);
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] The multi-failure AggregateError branch (teardownFailures.length > 1) is untested — all new shutdown-failure tests produce exactly one failure, exercising only the length === 1 path. — Failure scenario: two alive channels both reject kill() during shutdown; the AggregateError wrapping is never validated by any test, so a future refactor that drops or reorders errors would go undetected.

Suggested fix: add a test where both channels' kill() rejects during bridge.shutdown() and assert the rejection is an AggregateError containing both failures (similar to the construction-path test that asserts AggregateError shape).

— qwen3.7-max via Qwen Code /review

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Thanks — deferring. The current code preserves every rejected reason via Promise.allSettled and wraps multiple failures in AggregateError; this is a non-blocking coverage-only suggestion, so under the roughly five-review-round cutoff it is not expanding the PR.

@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

No action taken

Both inline suggestions from the automated reviewer were already explicitly deferred by maintainer @doudouOUC in the PR thread:

  • rc:3663865797 (test for drainAll resolving with forced > 0): Deferred — the maintainer noted the coverage observation is valid but non-blocking, the PR is past the ~5 review round cutoff, and the resolved-forced drain behavior was independently exercised with a real wedged MCP process.
  • rc:3663865804 (test for AggregateError multi-failure branch): Deferred — the maintainer noted the code preserves every rejected reason via Promise.allSettled and wraps multiple failures in AggregateError; this is a non-blocking coverage-only suggestion and the PR is past the cutoff.

No other findings require action. Reviewer @yiliang114 confirmed no blocking correctness, security, data-loss, coverage, or quality issues, and CI is green.

中文说明

未采取任何操作

自动化审查器的两条行内建议均已被维护者 @doudouOUC 在 PR 线程中明确推迟:

  • rc:3663865797(为 drainAllforced > 0 解决的路径添加测试):已推迟——维护者指出覆盖率观察有效但非阻塞,PR 已超过约 5 轮审查截止线,且 resolved-forced drain 行为已通过真实卡住的 MCP 进程独立验证。
  • rc:3663865804(为 AggregateError 多失败分支添加测试):已推迟——维护者指出代码通过 Promise.allSettled 保留了所有被拒绝的原因,并将多个失败包装在 AggregateError 中;这是一个非阻塞的纯覆盖率建议,且 PR 已超过截止线。

无其他需要处理的发现。审查者 @yiliang114 确认无阻塞性的正确性、安全性、数据丢失、覆盖率或质量问题,CI 为绿色。

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


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

@wenshao

wenshao commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

@qwen-code /triage

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM, looks ready to ship. ✅

@doudouOUC
doudouOUC added this pull request to the merge queue Jul 28, 2026
Merged via the queue into main with commit 4703cc5 Jul 28, 2026
129 of 131 checks passed
@doudouOUC
doudouOUC deleted the agent/7752-managed-session-writer-shutdown branch July 28, 2026 10:43
@doudouOUC
doudouOUC restored the agent/7752-managed-session-writer-shutdown branch July 28, 2026 11:28
@doudouOUC
doudouOUC deleted the agent/7752-managed-session-writer-shutdown branch July 28, 2026 11:30

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed — no blockers. Suggestions are inline. 2 Suggestion-level finding(s) could not be anchored to a changed line and were dropped; nothing further to act on here.

中文说明

已审查——无阻断问题。 建议见行内评论。 2 条建议级发现无法锚定到改动行,已丢弃;此处无需进一步处理。

— qwen3.8-max-preview via Qwen Code /review

Comment on lines +3794 to +3802
throw new Error(
`MCP pool drain incomplete: ${result.forced} forced, ${result.errors.length} errors`,
);
}
} catch (err) {
debugLogger.error(
`MCP pool drainAll failed: ${err instanceof Error ? err.message : String(err)}`,
);
throw err;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] shutdownMcpPool 中新增的 throw new Error(...) 位于 try 块内部,会被紧邻的 catch 自行捕获,导致一条误导性的 "MCP pool drainAll failed" 错误日志——实际上 drainAll() 成功返回了,只是报告了不完整的 drain。— 失败场景:当 drainAll() 成功但报告 forced > 0 时,catch 记录 "MCP pool drainAll failed: MCP pool drain incomplete: Y forced, Z errors",暗示 drainAll() 本身抛了异常,而实际原因是 MCP server 超时。事故排查时会将调查方向引向 drainAll 异常(网络错误、池损坏),而非真正的原因。

Suggested change
throw new Error(
`MCP pool drain incomplete: ${result.forced} forced, ${result.errors.length} errors`,
);
}
} catch (err) {
debugLogger.error(
`MCP pool drainAll failed: ${err instanceof Error ? err.message : String(err)}`,
);
throw err;
async shutdownMcpPool(timeoutMs = 10_000): Promise<void> {
if (!this.mcpPool) return;
let result: Awaited<ReturnType<typeof this.mcpPool.drainAll>>;
try {
result = await this.mcpPool.drainAll({ force: true, timeoutMs });
} catch (err) {
debugLogger.error(
`MCP pool drainAll failed: ${err instanceof Error ? err.message : String(err)}`,
);
throw err;
}
if (result.forced > 0 || result.errors.length > 0) {
debugLogger.warn(
`MCP pool drain: ${result.drained} clean, ${result.forced} timed out, ` +
`${result.errors.length} errors`,
);
throw new Error(
`MCP pool drain incomplete: ${result.forced} forced, ${result.errors.length} errors`,
);
}
}
中文说明

shutdownMcpPool 中新增的 throw new Error(...) 位于 try 块内部,会被紧邻的 catch 自行捕获,产生一条误导性的 "MCP pool drainAll failed" 错误日志。实际上 drainAll() 成功返回了,只是报告了不完整的 drain(有连接超时)。建议将不完整 drain 的 throw 移到 try/catch 之外,使 catch 只处理真正的 drainAll() 异常。

— qwen3.8-max-preview via Qwen Code /review

Comment on lines +6911 to +6919
} catch (error) {
if (
error instanceof SessionWriterLostError ||
pendingLease.isReleased
) {
this.pendingSessionWriterLease = undefined;
}
failures.push(error);
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] closeSessionWriterOnce 无条件地将 lease 释放错误推入 failures——包括良性的 SessionWriterLostError / 已释放的情况——而 activateChatRecording 中相同的释放清理 catch 块(约第 3006–3019 行)会刻意吞掉该情况,仅升级其他错误。— 失败场景:在 ACP 托管关闭期间(beginManagedShutdowncloseSessionWriter),如果并发进程在 closeSessionWriterOnce 释放 pendingSessionWriterLease 之前回收了 writer 锁,release() 抛出 SessionWriterLostError(lease 实际已消失——releaseOnce 在抛出前设置 released = true)。if 分支正确清除了 pendingSessionWriterLease,但 failures.push(error) 无条件执行,导致 closeSessionWriterOnce 抛出异常。ACP agent 的 writerShutdown promise 被拒绝,产生一个虚假的 "Managed session writer shutdown failed" AggregateError 和一条误导性 stderr 警告("a writer lock may be retained for safety"),尽管实际上没有锁被保留。

Suggested change
} catch (error) {
if (
error instanceof SessionWriterLostError ||
pendingLease.isReleased
) {
this.pendingSessionWriterLease = undefined;
}
failures.push(error);
}
} catch (error) {
if (
error instanceof SessionWriterLostError ||
pendingLease.isReleased
) {
this.pendingSessionWriterLease = undefined;
} else {
failures.push(error);
}
}
中文说明

closeSessionWriterOnce 无条件地将 lease 释放错误推入 failures(包括良性的 SessionWriterLostError),而 activateChatRecording 中相同的 catch 块会吞掉该情况。这种不对称会在锁已被并发进程回收时产生虚假的关闭失败报告。建议将 failures.push(error) 移入 else 分支,与 activateChatRecording 保持一致。

— qwen3.8-max-preview via Qwen Code /review

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Released in v0.21.1.

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.

7 participants