Skip to content

fix(web-shell): persist model reasoning preferences - #10489

Open
callmeYe wants to merge 9 commits into
mainfrom
codex/fix-webshell-reasoning-preferences
Open

fix(web-shell): persist model reasoning preferences#10489
callmeYe wants to merge 9 commits into
mainfrom
codex/fix-webshell-reasoning-preferences

Conversation

@callmeYe

Copy link
Copy Markdown
Collaborator

What this PR does

This PR persists the WebShell model and reasoning preference across daemon sessions by reusing the existing model.reasoningEffort setting. An absent value means the model default, none means thinking is disabled, and the five fixed effort tiers mean thinking is enabled at that tier. default is only a daemon command that clears the stored value and restores the model default; it is neither stored nor rendered as a UI option.

Welcome remains lazy: changing the model, thinking switch, or effort only updates the local preview. The first prompt creates and attaches the session, sets the model, persists the reasoning selection, and then sends the prompt. Existing and running sessions apply and persist reasoning changes immediately, with WebShell updating only after the daemon confirms the resulting options and persistence result.

Every model switch validates the current selection against the target model. Compatible tiers are retained; incompatible tiers such as max, unsupported reasoning, toggle-only capabilities, and mandatory-thinking constraints clear the persisted value and live override without downgrading or restoring an older dormant effort. Tiered models show only real effort choices, toggle-only models show only the thinking switch, unsupported models show no reasoning section, and all fixed effort labels are rendered from WebShell English and Chinese translations.

The change adds only the optional persist flag and strict reasoning selection/result types to the daemon HTTP boundary and TypeScript SDK. It does not add model.reasoningEnabled, change the public ACP protocol, alter provider clamping or the Core request pipeline, or modify the Java SDK.

Why it's needed

Model and reasoning choices should behave as one coherent session preference instead of depending on whether the user is on Welcome, already has messages, or currently has a request running. Persisting a capability-incompatible tier is also unsafe because it can silently leak into a later model switch. This keeps the contract small and explicit while preserving lazy session creation.

Reviewer Test Plan

How to verify

  • On Welcome, select a model and supported effort, confirm that no session or reasoning mutation is created before sending, then send the first prompt and verify the order is create/attach, model, persisted reasoning, prompt. Open a new session and confirm the model and reasoning choice are read back.
  • Select max on a supporting model, switch to a model that does not support it, and switch back. The stored setting and live override should be cleared, the target model default should be shown, and max should not be restored or downgraded.
  • Turn thinking off, then turn it on again. The persisted none value should be removed and the model default effort should be used instead of restoring the effort that was active before disabling.
  • Verify the capability matrix: compatible tiered models retain the tier; toggle-only models show only a thinking switch with no effort heading, buttons, or Default label; unsupported models have no reasoning section; mandatory-thinking models cannot retain none.
  • Switch WebShell between English and Chinese at runtime and verify every fixed effort label changes language without showing translation keys or daemon-provided labels.
  • Repeat reasoning changes in a session with existing messages and while a prompt is running; the next request should use the confirmed persisted value.

Evidence (Before & After)

Before: the current main branch does not provide the complete Welcome-to-live persistence and capability-reconciliation contract described above.

After: request-ledger and DOM Playwright coverage verifies all 10 reasoning scenarios, including Welcome lazy creation, live updates, mandatory thinking, incompatible model round trips, toggle-only rendering, unsupported/older-daemon behavior, and authoritative live capabilities. Unit regression suites cover persistence, strict validation, daemon confirmation, SDK request/response shape, model switching, and English/Chinese rendering.

Tested on

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

Environment (optional)

Local macOS checkout with the fake daemon/request ledger and Playwright Chromium. Verified with 730 CLI Session tests, 517 ACP agent tests, 1,700 TypeScript SDK tests, 645 WebUI tests, 4,572 WebShell tests, 10 focused Playwright tests, the root build and typecheck, relevant lint checks, Prettier, and two clean diff-review passes.

Risk & Scope

  • Main risk or tradeoff: the daemon's exact Qwen reasoning capability table must stay aligned with the supported model catalog; unknown Qwen models intentionally expose no reasoning control instead of guessing.
  • Not validated / out of scope: TUI flows, dynamic/custom effort strings, provider request mapping, public ACP changes, Java SDK changes, and cross-provider refactoring.
  • Breaking changes / migration notes: no public protocol break. Existing supported values continue to work; incompatible or invalid persisted reasoning selections are cleared to the target model default.

Linked Issues

Supersedes #10011.

中文说明

本 PR 做了什么

本 PR 复用现有的 model.reasoningEffort 设置,使 WebShell 的模型和思考偏好能够跨 daemon 会话持久化。未设置表示使用模型默认值,none 表示关闭思考,五个固定强度表示开启思考并使用对应档位。default 仅是 daemon 用来清除持久化值并恢复模型默认的控制命令;它不会写入配置,也不会作为 UI 选项展示。

Welcome 保持懒创建:切换模型、思考开关或强度时只更新本地预览。首次发送会依次创建并挂载会话、设置模型、持久化思考选择,然后发送提示词。已有消息和运行中的会话会立即应用并持久化思考修改,WebShell 只在 daemon 确认最终选项和持久化结果后更新界面。

每次模型切换都会根据目标模型能力校验当前选择。兼容档位会保留;不兼容档位(例如 max)、不支持思考、仅开关能力以及强制思考约束都会清除持久化值和 live override,不做降级映射,也不会恢复旧的 dormant effort。分档模型只显示真实强度选项,仅开关模型只显示思考开关,不支持模型完全不显示思考区域;所有固定强度文案都由 WebShell 的中英文翻译渲染。

变更只在 daemon HTTP 边界和 TypeScript SDK 增加可选 persist 参数以及严格的思考选择/结果类型。它不会新增 model.reasoningEnabled,不会修改公共 ACP 协议、provider clamp、Core 请求管线或 Java SDK。

为什么需要

模型和思考选择应该作为一组一致的会话偏好,而不应因用户位于 Welcome、已有消息或请求运行中而行为不同。持久化与目标能力不兼容的档位还可能在之后切换模型时错误泄漏。本实现保持契约小而明确,同时保留会话懒创建。

Reviewer 测试计划

验证方式

  • 在 Welcome 选择模型和支持的强度,确认发送前不会创建会话或调用思考 mutation;首次发送后确认顺序为创建/挂载、模型、持久化思考、提示词。新建会话后确认模型和思考选择能被读回。
  • 在支持的模型上选择 max,切换到不支持它的模型,再切回原模型。磁盘设置和 live override 应被清除,界面应显示目标模型默认值,且不会恢复或降级 max
  • 关闭思考后重新开启。持久化的 none 应被删除,并使用模型默认强度,而不是恢复关闭前的档位。
  • 验证能力矩阵:兼容的分档模型保留档位;仅开关模型只显示思考开关,DOM 中没有强度标题、按钮或 Default 文案;不支持模型没有思考区域;强制思考模型不能保留 none
  • 在运行时切换 WebShell 中英文,确认所有固定强度文案同步切换,不出现翻译 key 或 daemon 原始标签。
  • 在已有消息和提示词运行中的会话里修改思考设置;下一次请求应使用 daemon 已确认并持久化的值。

前后证据

之前:当前 main 分支不具备上述从 Welcome 到 live session 的完整持久化和能力校验契约。

之后:request-ledger 与 DOM Playwright 覆盖全部 10 个思考场景,包括 Welcome 懒创建、live 修改、强制思考、不兼容模型往返、仅开关渲染、不支持/旧 daemon 行为和 live capability 权威性。单元回归覆盖持久化、严格校验、daemon 确认、SDK 请求响应、模型切换以及中英文渲染。

测试平台

OS 状态
🍏 macOS
🪟 Windows N/A
🐧 Linux N/A

环境(可选)

本地 macOS checkout,使用 fake daemon/request ledger 和 Playwright Chromium。已通过 730 条 CLI Session 测试、517 条 ACP agent 测试、1,700 条 TypeScript SDK 测试、645 条 WebUI 测试、4,572 条 WebShell 测试、10 条 focused Playwright、根目录 build 与 typecheck、相关 lint、Prettier 以及两轮完整 diff 净审。

风险与范围

  • 主要风险或取舍:daemon 中精确的 Qwen 思考能力表需要与支持的模型目录保持一致;未知 Qwen 模型会有意隐藏思考控件,而不是猜测能力。
  • 未验证 / 不在范围内:TUI 流程、动态或自定义强度字符串、provider 请求映射、公共 ACP 改动、Java SDK 改动以及跨 provider 重构。
  • Breaking change / 迁移说明:没有公共协议破坏。已有支持值继续工作;与目标模型不兼容或无效的持久化思考选择会被清除并恢复目标模型默认值。

关联问题

替代 #10011

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Qwen Triage finished — CI landed green on 6a9bf19 and the deferred approval was posted. finalize run

Qwen Triage 已完成 —— 6a9bf19 的 CI 全绿,延迟审批已提交。查看 finalize 运行

@callmeYe

Copy link
Copy Markdown
Collaborator Author

E2E test report

Environment: local macOS checkout, fake daemon/request ledger, Playwright Chromium.

  • reasoning focused group: 7 passed.
  • mandatory|incompatible welcome effort focused group: 3 passed.
  • Total reasoning scenarios: 10 passed.

The scenarios verify Welcome lazy session creation and first-send ordering, persisted tier changes in existing and running sessions, none followed by a model-default reset, mandatory thinking, incompatible effort clearing across a model round trip, toggle-only DOM without an effort row or Default option, unsupported/older-daemon behavior, and live-session capability authority over Welcome previews.

Supporting regression evidence: CLI Session 730/730, ACP agent 517/517, TypeScript SDK 1,700/1,700, WebUI 645/645, WebShell 4,572/4,572, plus root build and typecheck.

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

🖼️ web-shell visual preview

Rendered against a mock daemon (no real backend): the PR base vs this PR head 9c63c7f. Only screenshots that changed are shown (flows below, if any, are head-only) — refreshes on every push.

Screenshots · before / after

ℹ️ No screenshot changed against the PR base — but this PR edits 6 render-shaping files:

  • packages/web-shell/client/App.tsx
  • packages/web-shell/client/components/ChatEditor.tsx
  • packages/web-shell/client/components/ChatPane.tsx
  • packages/web-shell/client/components/messages/SettingsMessage.tsx
  • packages/web-shell/client/daemon/session/DaemonSessionProvider.tsx
  • packages/web-shell/client/i18n.tsx

Either the change has no visual effect (logic, plumbing, a state the scenarios never reach), or no scenario renders this UI — in which case the preview cannot see it, and an empty result is a coverage gap rather than a clean bill of health. To make it visible, add a scenario to packages/web-shell/client/e2e/visuals/screenshots.spec.ts that seeds whatever state the UI is gated on; it then appears here as a head-only (NEW) capture.

Full-resolution recordings (.webm) are attached to the workflow run.

Qwen Code · web-shell visuals

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Thanks for the PR!

Template looks good ✓

Problem: observed gap, not theory. WebShell's model/reasoning choice today lives only on the live daemon session — a new session starts from scratch, and an incompatible persisted tier could leak into a later model switch. This is the persistence half of the reasoning-controls work already landed in #9599, #10008, #9574 and #10244, superseding the closed #10011 with a deliberately smaller contract (reuses model.reasoningEffort instead of adding a second setting). The follow-up commit addresses a second, self-discovered instance of the same problem class: the Welcome preview not reflecting a just-persisted selection after New task.

Direction: aligned. Persisting a preference the product already exposes is expected behavior, and reusing the existing model.reasoningEffort key — which Core already clamps per provider — keeps the surface small. The PR also explicitly avoids the public ACP protocol and the Core request pipeline. Reference signal: claude-code's CHANGELOG shows the same problem class under active iteration (effort xhigh/max interacting with thinking-off, and a "thinking toggle had no effect for the rest of the session" fix), so this area is squarely in scope.

Size: cross-package (cli, sdk-typescript, web-shell, webui, vscode schema) and touches packages/cli/src/config/. The author is a write-access collaborator who self-merges in this area, so the two-tier core gate is exempt; reporting the breakdown for the record: 865 production-logic lines vs 1033 test vs 3 schema vs 66 design-doc across 41 files. Below the 1000-line advisory; no block on size.

Approach: scope feels right. Every file in the diff serves the feature — no drive-by edits — and the committed design doc pins the contract (absent = model default, none = off, five tiers = on, default = clear-only control command). The capability matrix (tiered / toggle-only / unsupported / mandatory-thinking) is inherently stateful, but the rule set is small and explicit, with "clear, never downgrade or restore" as the invariant. The follow-up commit 6a9bf199 stays inside the same boundary — a pure cached-snapshot update plus a clear-time wait, no provider GET on clear, no new surface. Nothing I'd cut.

Risk: packages/cli/src/acp-integration/ (acpAgent.ts, model-configuration.ts, session/Session.ts) matches this repo's high-risk, revert-correlated path set — review depth set accordingly: full CI evidence quoted in the review comment, plus a sandboxed-lane suggestion for the behavioural claims. The follow-up commit touches only webui session actions and tests — no new high-risk paths.

Moving on to code review. 🔍

中文说明

感谢贡献!

模板完整 ✓

问题: 真实存在的缺口,不是理论问题。WebShell 的模型/思考选择目前只存在于存活的 daemon 会话上——新会话从零开始,且与能力不兼容的持久化档位可能泄漏到之后的模型切换。这是 #9599#10008#9574#10244 已落地的思考控制系列中"持久化"这半部分,用更小的契约取代已关闭的 #10011(复用 model.reasoningEffort,不新增第二个设置)。后续提交处理了同一问题类的第二个自发现实例:New task 之后 Welcome 预览未反映刚刚持久化的选择。

方向: 对齐。持久化产品已暴露的偏好是预期行为;复用现有 model.reasoningEffort(Core 已按 provider 做 clamp)保持了小改动面。PR 也明确不触碰公共 ACP 协议与 Core 请求管线。参考信号:claude-code 的 CHANGELOG 显示同类问题正在被持续处理(effort xhigh/max 与关闭思考的交互、"思考开关在会话剩余时间无效"的修复),该方向在范围内。

规模: 跨包(cli、sdk-typescript、web-shell、webui、vscode schema)并触及 packages/cli/src/config/。作者是拥有写权限、在该领域自行合入的 collaborator,两层核心门禁豁免;仅记录规模:生产逻辑 865 行 / 测试 1033 行 / schema 3 行 / 设计文档 66 行,共 41 个文件。低于 1000 行建议线,不因规模拦截。

方案: 范围合理。diff 中每个文件都服务于该功能,无顺手改动;已提交的设计文档固定了契约(未设置 = 模型默认、none = 关闭、五个档位 = 开启、default = 仅清除的控制命令)。能力矩阵(分档/仅开关/不支持/强制思考)天然有状态,但规则集小而明确,不变量是"清除、绝不降级或恢复"。后续提交 6a9bf199 仍在同一边界内——纯缓存快照更新加清除时等待,清除时不发 provider GET,无新增面。没有可砍的部分。

风险: packages/cli/src/acp-integration/(acpAgent.ts、model-configuration.ts、session/Session.ts)命中本仓库高回滚相关路径集——已相应提高审查深度:审查评论中引用完整 CI 证据,并对行为性声明给出沙箱验证通道建议。后续提交只触及 webui 会话 actions 与测试,无新的高风险路径。

进入代码审查 🔍

Qwen Code · qwen3.8-max

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

@callmeYe

Copy link
Copy Markdown
Collaborator Author

Visual CI note

The visual workflow's incomplete-preview comment is a baseline failure, not a PR regression. Both the PR head and the merge base fail the same two workspace sidebar scenarios (dark and light) because the existing strict locator for Run auth migration resolves to two elements. The head result is 35 passed / 2 failed; the base result is 30 passed / 2 failed. The focused reasoning Playwright matrix remains 10/10 passed.

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Code review

My independent baseline for "persist WebShell reasoning preferences" was: reuse model.reasoningEffort, add an optional persist flag on the daemon mutation, clear-don't-downgrade on model switch, and update the UI only from the daemon's confirmation. This PR is exactly that shape, executed with strict typing across every boundary — and in a few places it is better than the baseline: the mappers drop the old fallbackEffort heuristic entirely (state now derives only from daemon-confirmed configOptions, which kills the stale-restore bug class), and default exists only as a clear-only control command that is neither stored nor rendered.

Things I checked against the surrounding code, all clean:

  • Reconcile ordering: reconcileReasoningSelection runs after await this.config.switchModel(...) in Session.setModel — a failed switch leaves persisted settings untouched, and the reconcile reads thinkingMandatory from the post-switch config.
  • Skipped extra_body/samplingParams cleanup for none/default: safe. For none, the Core request pipeline itself forces the wire shape disabled (pipeline.ts deletes enable_thinking/thinking_budget and emits reasoning_effort: 'none' for tiered DashScope models, or enable_thinking: false otherwise) even when a static enable_thinking: true sits in extra_body. For default, deferring to the static config is the correct semantics.
  • Trust boundary on the route: the HTTP route derives _meta strictly from a validated boolean persist field and never forwards client-supplied _meta (explicitly tested: "does not trust persistence metadata when persist is omitted"). Write failures roll back via reloadScopeFromDisk before rethrowing.
  • Response shape change on POST /session/:id/config-option ({configOptions, persisted}): the TypeScript SDK is updated in the same PR, and the Java SDK does not call this endpoint at all, so nothing is orphaned.
  • Read sites for every added field: persist, persisted, defaultEffort, and both _meta keys are each set and read; model.reasoningEffort is hidden from the generic settings panel so there is one surface, not two.

The two questions from the first pass are now settled by author confirmation — both behaviors are deliberate. Daemon-owned standalone sessions keep their no-shared-persistence boundary: a persisted mutation failing outright there is preferred over silently degrading to live-only writes into shared user/workspace defaults. And old-daemon responses without persisted: true cannot prove the persistence contract, so they error instead of showing a value as durable. With both confirmed as intent, nothing is outstanding from the first pass.

Follow-up commit 6a9bf199 — Welcome preview regression

The author found a real regression in their own PR (select medium on Welcome → first prompt persists it → New task rebuilt the Welcome controls from a stale cached provider preview showing low) and fixed it at the state boundary rather than by re-fetching providers on clear — which is the smaller fix, and the one I'd pick:

  • withPersistedReasoningPreview is a pure, immutable update of the cached workspace-provider snapshot: it only touches the matching model entry, only models that already advertise a reasoning_effort option, and returns the same reference when nothing changes. A failed or unconfirmed persistence leaves the preview untouched.
  • clearSession() awaits the in-flight persisted mutation before deriving the next Welcome model list. The wait is on completion, not success (finally resolves it, and the clear uses .catch(() => undefined)), so a failed persistence still clears promptly without leaking into the preview.
  • Late or superseded results can't smear the preview: the apply path requires actionToken > appliedReasoningActionToken and re-checks session identity, model-generation, and current model inside the setConnection updater, and clearSession nulls the session ref before deriving post-clear state — I walked all three interleavings (slow-first, fast-first, in-flight-at-clear) and each resolves to the daemon-confirmed value or nothing.

Tests pin the actual regression rather than the implementation: preview retained after clear, clear waiting for an in-flight mutation before detach, unconfirmed persistence leaving the preview at the old value while clear still resolves, and the e2e now drives the exact reported path (persist → send → turn complete → New task → model button still says Medium) while asserting no additional providers GET and no second session creation.

Nothing blocking across either commit.

sequenceDiagram
    participant P1 as WebShell client
    participant P2 as daemon HTTP route
    participant P3 as ACP agent
    participant P4 as Session settings
    P1->>P2: POST config-option (value, persist true)
    P2->>P3: setSessionConfigOption (_meta persist flag)
    P3->>P4: persistReasoningSelection (clear other scopes, write or roll back)
    P3->>P3: apply live, rebuild confirmed options
    P3-->>P2: configOptions + persisted meta
    P2-->>P1: configOptions, persisted
    P1->>P1: update cached provider preview (persisted confirmed only)
Loading
Files changed (30 of 41 shown)
File What changed
docs/design/webshell-reasoning-preferences.md New design doc pinning the stored-value semantics, lazy lifecycle, and reconciliation rules
packages/cli/src/acp-integration/acpAgent.ts reasoning_effort mutation validated against live options, persistence wired via _meta, option hidden on unsupported models
packages/cli/src/acp-integration/acpAgent.test.ts Mutation validation, persist meta round-trip, unsupported-model rejection tests
packages/cli/src/acp-integration/model-configuration.ts Strict selection types plus parse/validate/apply helpers and the persisted-state projection
packages/cli/src/acp-integration/model-configuration.test.ts Capability matrix and persisted-projection cases
packages/cli/src/acp-integration/session/Session.ts persistReasoningSelection, post-switch reconciliation, scoped clearing with write rollback
packages/cli/src/acp-integration/session/Session.test.ts Persistence and reconciliation coverage incl. user/workspace scope writes
packages/cli/src/config/settingsSchema.ts Adds the none option and rewords the setting description
packages/cli/src/config/settingsSchema.test.ts none accepted, default never stored
packages/cli/src/serve/routes/session.ts Validates the persist flag, forwards it via _meta, returns shaped configOptions + persisted
packages/cli/src/serve/server.test.ts Route persist contract and the untrusted-_meta case
packages/cli/src/serve/workspace-providers-status.ts Welcome previews project the persisted selection per model
packages/cli/src/serve/workspace-providers-status.test.ts Preview projection matrix incl. incompatible and mandatory cases
packages/cli/src/utils/modelConfigUtils.ts CLI startup reads none as reasoning disabled unless thinking is mandatory
packages/cli/src/utils/modelConfigUtils.test.ts none loads as an explicit disable without a warning
packages/sdk-typescript/src/daemon/DaemonClient.ts Strict ReasoningSelection value type and an options overload carrying persist
packages/sdk-typescript/src/daemon/DaemonSessionClient.ts Passes the persist option through
packages/sdk-typescript/src/daemon/index.ts Exports ReasoningSelection
packages/sdk-typescript/src/daemon/types.ts ReasoningSelection type and persisted result field
packages/sdk-typescript/test/unit/DaemonClient.test.ts Request shape with persist
packages/sdk-typescript/test/unit/DaemonSessionClient.test.ts Session client pass-through
packages/vscode-ide-companion/schemas/settings.schema.json Enum gains none, description synced
packages/web-shell/client/App.tsx Welcome intent bookkeeping, clear-don't-restore on model switch, persist on live changes
packages/web-shell/client/App.test.tsx Updated stale-disable expectations to the clear semantics
packages/web-shell/client/components/ChatEditor.tsx Strict selection callbacks, toggle sends default, label fallback for none/default
packages/web-shell/client/components/ChatEditor.test.tsx Runtime language switch localization and unknown-default rendering
packages/web-shell/client/components/ChatPane.tsx Persist pass-through on live changes
packages/web-shell/client/components/messages/SettingsMessage.tsx Hides model.reasoningEffort from the generic settings panel
packages/web-shell/client/components/messages/SettingsMessage.dom.test.tsx Hidden-key coverage
packages/web-shell/client/e2e/utils/mockDaemon.ts Mock daemon honors persist and the new response shape
…and 11 more files e2e smoke scenarios (10 reasoning flows + the New-task preview round trip), i18n keys for high/max, sessionPreparation persist-on-first-send, webui provider/actions/mappers/types plus their tests

Testing evidence — the PR's own CI, read via API

This is an unattended CI run, so no PR code was built or executed here; the evidence below is the PR's own check results fetched once via the API. Context on the previous head: 14673c7 settled with the primary ubuntu unit suite (Qwen Code CI) cancelled — never green — and the Java 17 transport flake below; the approve-on-green marker on that head correctly never fired. The follow-up commit re-triggers everything; the table tracks the current head 6a9bf199 and the finalize job rewrites it in place once CI settles.

Final CI results for 6a9bf19 (auto-updated by the triage finalize job after CI completed):

Check Conclusion
Capture web-shell visuals (ubuntu-latest, Node 22.x) ✅ success
Classify PR ✅ success
Dependency CVE audit ✅ success
Desktop Shell (ubuntu-22.04) ✅ success
Desktop Shell (windows-2022) ✅ success
Integration Tests (no-AK, No Sandbox) ✅ success
Live Host (macos-latest) ✅ success
macos-latest / Java 21 ✅ success
Post Coverage Comment (ubuntu-latest, 22.x) ✅ success
Real daemon E2E / Java 11 ✅ success
Secret scan (TruffleHog) ✅ success
Serve A/B (ubuntu-latest, Node 22.x) ✅ success
Test (ubuntu-latest, Node 22.x) ✅ success
ubuntu-latest / Java 11 ✅ success
ubuntu-latest / Java 17 ✅ success
ubuntu-latest / Java 21 ✅ success
web-shell E2E Smoke (ubuntu-latest, Node 22.x) ✅ success
windows-latest / Java 21 ✅ success

One row per check name (latest run); skipped checks omitted; failures sort first. / 每个检查名一行(取最新一次运行),省略 skipped,失败项排在最前。

ubuntu-latest / Java 17 carries a known-flake history. On 14673c7 its 5 errors were all in DaemonSessionClientTest and all transport/timing failures (GET /capabilities transport failed, Timeout, SessionCreationOutcomeUnknown POST /session) — no reasoning/model assertions. This PR changes zero Java files, and the identical suite passed on Java 11, Java 21 (ubuntu), and Java 21 (macOS, Windows) at that same commit; the repo also runs a scheduled CI failure patrol, consistent with known flakiness. If it lands red on the new head with the same signature, it stays classified pre-existing; any new failure shape in that suite would be a real finding.

The serve-daemon A/B run on the previous head diffed base vs PR responses across 12 scenarios and found no response changes; it re-runs on the new head (queued above).

Sandboxed verification would still settle the one claim CI cannot: @qwen-code /verify — that with a real daemon the persisted model.reasoningEffort actually hits disk in the documented first-send order (create/attach → model → reasoning → prompt) and that an incompatible tier round-trip clears it on disk. The earlier /verify run on this PR was cancelled before producing a report, and the disk-level evidence otherwise remains mocked-settings unit tests plus mock-daemon Playwright flows — the author's real-daemon local results (including the New-task regression path) are their claim, attributed here, not evidence this run carries.

中文说明

代码审查

我对"持久化 WebShell 思考偏好"的独立基线方案是:复用 model.reasoningEffort、在 daemon mutation 上加可选 persist 标志、模型切换时"清除而非降级"、界面只根据 daemon 确认更新。本 PR 正是这个形状,且在每个边界上用了严格类型——几处比基线更好:mapper 完全移除了旧的 fallbackEffort 回退(状态只来自 daemon 确认的 configOptions,消灭了"恢复旧档位"这类 bug);default 只是清除命令,不落盘也不渲染。

与周边代码核对过的点,均无问题:

  • 顺序: Session.setModelreconcileReasoningSelectionawait switchModel(...) 成功之后执行——切换失败不会动持久化设置;thinkingMandatory 读的是切换后的配置。
  • none/default 跳过 extra_body/samplingParams 清理: 安全。选 none 时 Core 请求管线本身会强制下线形态(pipeline.ts 删除 enable_thinking/thinking_budget 并对分档 DashScope 模型发 reasoning_effort: 'none'),即使 extra_body 里有静态 enable_thinking: true;选 default 时遵从静态配置本就是正确语义。
  • 路由信任边界: HTTP 路由只从校验过的布尔 persist 字段派生 _meta,从不转发客户端自带的 _meta(有显式测试覆盖);写设置失败会先 reloadScopeFromDisk 回滚再抛出。
  • 响应结构变化: TypeScript SDK 同 PR 更新;Java SDK 完全不调用该端点,无孤儿消费者。
  • 新增字段读取点: persistpersisteddefaultEffort、两个 _meta 键均有设置有读取;model.reasoningEffort 从通用设置面板隐藏,保证只有一个入口。

第一遍的两个问题已由作者确认,均为有意设计。 受管 standalone 会话保持"不写共享设置"的边界:这类会话上持久化修改直接失败,优于悄悄降级为仅 live 写入共享的用户/工作区默认值;旧版 daemon 不带 persisted: true 的响应无法证明持久化契约,因此报错而不是把值显示为已持久。两点确认为意图后,第一遍已无未决问题。

后续提交 6a9bf199 —— Welcome 预览回归

作者自行发现了本 PR 中的一个真实回归(Welcome 上选 medium → 首次提示词已持久化 → New task 却用陈旧的缓存 provider 预览重建控件,仍显示 low),并在状态边界处修复,而不是在清除时重新拉取 providers——这是更小的修法,也是我会选的:

  • withPersistedReasoningPreview 是对缓存 workspace-provider 快照的纯函数式不可变更新:只改匹配的模型条目、只改本就声明了 reasoning_effort 选项的模型、无变化时返回同一引用。失败或未确认的持久化不动预览。
  • clearSession() 在推导下一个 Welcome 模型列表前等待在途的持久化 mutation。等待的是"完成"而非"成功"(finally 中 resolve,清除侧用 .catch(() => undefined)),因此失败的持久化依然能迅速清除、不泄漏进预览。
  • 迟到或被取代的结果不会污染预览:应用路径要求 actionToken > appliedReasoningActionToken,且 setConnection 更新器内再次校验会话身份、模型代际与当前模型;clearSession 在推导清除后状态前已将 session ref 置空——我推演了三种交错(先慢后快、先快后慢、清除时在途),结果都收敛为 daemon 确认值或不更新。

测试钉住的是回归本身而非实现:清除后预览保留、清除等待在途 mutation 再 detach、未确认持久化时预览停在旧值且清除仍可完成;e2e 直接走报告路径(持久化 → 发送 → turn complete → New task → 模型按钮仍显示 Medium),并断言没有额外的 providers GET、没有创建第二个会话。

两个提交均无阻塞问题。

测试证据

这是无人值守 CI 运行,未构建或执行任何 PR 代码;以上证据为通过 API 一次性读取的 PR 自身检查结果。前一提交 14673c7 的最终状态:主 ubuntu 单测套件(Qwen Code CI被取消、始终未绿,另有下述 Java 17 传输类易失败;该提交上的 approve-on-green 标记因此正确地未触发。后续提交重新触发全部 CI;表格跟踪当前提交 6a9bf199,finalize 作业会在 CI 结束后原地更新。

ubuntu-latest / Java 17 有已知易失败历史。14673c7 上其 5 个错误全部位于 DaemonSessionClientTest,均为传输/超时类失败,不涉及思考/模型断言。本 PR 未改动任何 Java 文件,同一套测试在同一提交的 Java 11、Java 21(ubuntu)及 macOS/Windows 的 Java 21 上全部通过;仓库亦有定期 CI 失败巡检,与已知易失败一致。若新提交上以同样特征再次变红,仍判定为既有问题;该套件中任何新形态的失败才是真实发现。

前一提交上的 serve daemon A/B 对比了 base 与 PR 在 12 个场景下的响应,无差异;新提交上该作业重新运行(排队中)。

沙箱验证仍可补齐 CI 无法覆盖的唯一声明:@qwen-code /verify —— 在真实 daemon 下验证 model.reasoningEffort 确实按文档顺序(创建/挂载 → 模型 → 思考 → 提示词)写盘,且不兼容档位往返确实从磁盘清除。此前本 PR 的 /verify 运行在生成报告前被取消;否则磁盘层证据仍只有 mock 设置的单测与 mock daemon 的 Playwright 流程——作者的真实 daemon 本地结果(含 New-task 回归路径)在此仅作为其声明转述,不是本次运行携带的证据。

Qwen Code · qwen3.8-max

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

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Confidence: 4/5 — the same clean, tightly scoped consolidation as the first pass, now including a self-discovered regression fixed with a minimal, well-guarded patch; both first-pass questions confirmed as intent; waiting on the new head's CI before approving.

Stepping back: this is the sixth PR in the author's reasoning-controls series, and it still reads like consolidation rather than expansion — it reuses the existing setting key, deletes a fallback heuristic instead of adding one, and pins the contract in a design doc. Against my independent proposal (reuse model.reasoningEffort, optional persist flag, clear-don't-downgrade reconciliation, confirmation-gated UI) the PR matches on every point and goes further where it counts: strict ReasoningSelection typing across the daemon/SDK/webui boundary, and UI state that derives only from daemon-confirmed options.

The follow-up commit is the strongest signal in this re-run. The author found the Welcome-preview regression themselves, reported it precisely (stale cached provider snapshot after a confirmed persist), and fixed it at the state boundary — a pure snapshot update plus a clear-time wait — instead of the heavier clear-time provider refresh, explicitly avoiding a provider GET, cross-workspace ownership fallback, and late-refresh overwrite. I verified the guards statically rather than taking that framing on faith: the token ordering (actionToken > appliedReasoningActionToken), the re-checks inside the setConnection updater, and the nulled session ref before post-clear derivation together cover every slow/fast/in-flight interleaving I could construct. The new tests assert the regression's exact user path, including "no extra providers GET, no second session" — pinning behavior, not implementation.

Both first-pass questions came back confirmed as deliberate (standalone sessions keep the no-shared-persistence boundary; unversioned persisted: true strictness is the price of a provable persistence contract), and both fail clean, so nothing is outstanding. The failure paths I pressed hardest on the first pass still hold: reconciliation runs after the model switch succeeds, settings writes roll back their scope before rethrowing, and the route never forwards client-supplied _meta. The serve A/B comparison found no response changes against the base across 12 scenarios.

What keeps this at 4 rather than 5 is evidence, not code: the primary ubuntu suite on the first head ended cancelled rather than green, the /verify run was cancelled before producing a report, and the new head's CI is still queued or running. The disk-level first-send ordering claim still rests on mocked-settings tests and the author's local real-daemon account; @qwen-code /verify would settle it. None of that is a defect in the diff — but approval attests to results, not expectations, so it waits for CI.

Approval is therefore deferred until CI lands green on 6a9bf199d5cd0dd6b58ed88b55a9c51b358eb36c.

中文说明

置信度:4/5 —— 与第一遍相同的干净、收口的整合,现已包含一个自发现回归的最小化、有防护的修复;第一遍的两个问题均已确认为有意设计;批准前等待新提交的 CI。

整体来看:这是作者思考控制系列的第六个 PR,读起来仍是收口而非扩张——复用既有设置键、删除回退启发式而不是新增、并用设计文档固定契约。与我的独立方案(复用 model.reasoningEffort、可选 persist 标志、清除而非降级的协调、确认驱动的界面)逐点一致,并在关键处更进一步:跨 daemon/SDK/webui 边界的严格 ReasoningSelection 类型,以及界面状态只来自 daemon 确认的选项。

后续提交是本次重审中最强的信号。作者自行发现了 Welcome 预览回归,精确描述了成因(确认持久化后缓存 provider 快照陈旧),并在状态边界处修复——纯快照更新加清除时等待——而不是更重的清除时 provider 刷新,明确避免了 provider GET、跨工作区所有权回退和迟到刷新覆盖。我没有轻信这一表述,而是静态验证了防护:令牌顺序(actionToken > appliedReasoningActionToken)、setConnection 更新器内的复核、以及清除后推导前置空的 session ref——我能构造的所有慢/快/在途交错都收敛正确。新测试断言的正是回归的用户路径,包括"无额外 providers GET、无第二个会话"——钉住的是行为而非实现。

第一遍的两个问题均被确认为有意设计(standalone 会话保持不写共享设置的边界;无版本协商的 persisted: true 严格性是持久化契约可证明性的代价),且两者都干净失败,因此已无未决项。第一遍我最严格审查的失败路径依然成立:协调在模型切换成功后执行、设置写入失败先回滚再抛出、路由从不转发客户端自带的 _meta。serve A/B 对比在 12 个场景下未发现响应差异。

停在 4 而非 5 的原因是证据而非代码:第一个提交的主 ubuntu 套件以取消告终而非绿色,/verify 运行在生成报告前被取消,新提交的 CI 仍在排队或运行中。磁盘层的首次发送顺序声明仍依赖 mock 设置的测试与作者本地的真实 daemon 陈述;@qwen-code /verify 可以补齐。这些都不是 diff 的缺陷——但批准是对结果的背书而非预期,因此等待 CI。

因此批准将延迟到 6a9bf199d5cd0dd6b58ed88b55a9c51b358eb36c 上 CI 全绿之后。

Qwen Code · qwen3.8-max

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

@callmeYe

Copy link
Copy Markdown
Collaborator Author

Author confirmation on the two non-blocking questions:

  1. The reserved sourceType: standalone behavior is deliberate for this PR. Normal WebShell sessions are created and listed with sourceType: default; daemon-owned standalone Conversations are a separate ownership domain and must not mutate shared user/workspace model defaults. This PR therefore keeps their existing no-shared-persistence boundary instead of silently degrading a requested persisted mutation to live-only success. If reasoning controls are intentionally exposed for that separate surface later, they need an explicit session-local persistence contract rather than writing the WebShell preference.
  2. The old-daemon strictness is also deliberate. The WebShell bundle and daemon endpoint ship together, and a response without persisted: true cannot prove the requested persistence contract. Treating that as an error avoids displaying a value as durable when only the live override may have changed.

I am also requesting the suggested real-daemon verification for the on-disk first-send ordering and incompatible-tier clearing paths.

@callmeYe

Copy link
Copy Markdown
Collaborator Author

@qwen-code /verify

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Sandboxed verification: ✅ passed — merge-ready (agent verdict) - workflow run

Ran the PR in an isolated, token-free container: A/B against the base build, mock-free harness assertions, targeted gates. Advisory evidence for human reviewers — not a review, an approval, or a CI check.

Scripted assertions: 92 passed · 0 failed · 92 total

Flakiness gate: ⚠️ timeout — the 15-minute budget elapsed before two full rounds completed (1 done) — no flakiness signal either way

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

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

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

抖动门:⚠️ timeout — the 15-minute budget elapsed before two full rounds completed (1 done) — no flakiness signal either way

Verification report

PR #10489 Deep Verification — fix(web-shell): persist model reasoning preferences

Verdict: merge-ready — 92/92 scripted harness assertions passed, 0 unexpected failures. All targeted gates green (4,071 vitest unit tests across the changed files + 45 Playwright e2e, details below). One Suggestion-level coverage gap found; nothing blocking.

  • Verified head: 14673c7a6c9245922fb86c313c3695662ba27c35 (HEAD^2), base 866b7fe9a63c4c9a164cc27882147449a8c1aea6 (HEAD^1), merge-ref checkout depth 2. Reachable commits HEAD^1..HEAD^2 = 1, matching the metadata snapshot's commits array — per-commit attribution equals the aggregate diff.
  • A/B: real head daemon vs real base-build daemon, identical scenario, identical fixtures. Evidence: 01-ab-head-persist-readback-reconcile.png, 02-ab-base-no-persist-path.png, 03-sdk-wire-body-head-vs-base.png, 04-mutation-matrix.png.
中文摘要

结论:merge-ready 92/92 脚本化断言通过,无意外失败;定向门禁全绿(4,816 个仓库测试 + 45 个 Playwright e2e)。

A/B 结论(真实 daemon,head 对 base):

  • 中心主张成立且是承重的:persist:true 时 head 把选择写入设置文件并在响应中返回 persisted:true,新会话能读回;base 完全没有该路径(忽略 persist 字段、不落盘、无 persisted 字段)。
  • default 作为"清除命令"仅在 head 存在;base 把 default 当非法值拒绝(实测错误信息),也没有任何 API 能清除已存值。
  • 能力回收(reconcile)在 head 生效:不兼容的 max 在 setModel 时从所有 scope 清除、往返切换后不恢复;base 则把陈旧 max 留在磁盘、运行时静默 clamp 成 xhigh(正是本 PR 消除的泄漏)。
  • none 语义、严格 persist 布尔校验(400)、错误选项枚举均按设计工作。

Findings: 1 条 Suggestion(persistReasoningSelection 的 managed-conversation 守卫没有任何测试钉住);1 条变更矩阵幸存者,判定为冗余防御(各消费方各自复校验);2 条观察项(无效值经 agent 层以 500/-32602 返回系 base 既有行为;持久化 scope 跟随 modelProviders 属主,已验证跨 scope 清除)。均不阻塞合并。

未覆盖: TUI 流程(PR 自述范围外)、真实模型 prompt 往返(持久化不经过 prompt 路径)、Live Voice managed 会话(环境不可达)、Playwright visuals/perf、运行时中英文切换(仅静态核对 i18n key + DOM 测试)、Java SDK/公共 ACP(仅 diff 级核对)、整仓套件(只跑定向门禁)。

Central claim and A/B proof

Central claim: WebShell reasoning selection persists across daemon sessions via model.reasoningEffort, through a new persist:true flag on POST /session/:id/config-option; default is a clear-only command; every model switch reconciles the stored value against the target model's capabilities (no clamping, no restore).

Method: two real daemons — head build (port 18999) and a control build from HEAD^1 with only packages/cli rebuilt at base (port 19999) — each with an isolated QWEN_HOME, a trusted scratch workspace declaring two fixture models on the lane's model proxy: qwen3.8-max (tiered, efforts low/medium/xhigh, default xhigh) and qwen3.5-plus (toggle-only). Observation is non-mutating: GET /session/:id/context — the same seam WebShell maps through mapSessionContextReasoning. Flow mirrors the PR's lazy-creation contract: create (sessionScope:'thread' for a genuinely fresh session) → setModel → observe. Harness: ab-daemon.mjs, raw logs logs/ab-head.log, logs/ab-base.log, raw-*.json.

Control purity: the PR's diff against packages/core is empty (0 lines) and @qwen-code/qwen-code-core resolves to that unchanged package from both arms; grep -c persistReasoningSelection is 0 in base cli dist vs 1 in head; base build used tsc --build --noCheck because full-check compilation of the base tree hits pre-existing type-resolution errors masked at head by incremental buildinfo (logged: logs/base-cli-build*.log).

Cell table (36 scripted assertions per arm; all passed)

# Cell Oracle head base
1 Providers list + previews GET providers both models listed; tiered preview [none,low,medium,xhigh], no default choice; toggle preview renders (none/default only) same tiered preview; toggle preview absent (base buildModelReasoningConfigPreview returns undefined for toggleOnly)
2 Clean session, nothing persisted context + settings files currentValue xhigh (model default); no stored value identical (symmetric control)
3 persist medium response + settings on disk persisted:true; settings file holds medium no persisted field; nothing written
4 persist default response + disk accepted; stored value cleared rejected: "Unknown reasoning effort: default. Choose one of: none, low, medium, xhigh"; no clear path exists at base
5 Read-back: seed medium, new session context currentValue medium currentValue medium (read path pre-exists — positive control runs on both arms)
6 persist none response + disk live none; settings hold none live none; nothing written (seeded medium stays)
7 New session honors persisted none context currentValue none currentValue medium (none never persisted)
8 Cross-scope clear both settings files default clears the workspace-scope value too n/a (no clear path; harness-side cleanup, disclosed)
9 Seed incompatible max, setModel context + disk max cleared from every scope; live falls back to model default max left on disk; live silently clamps to xhigh
10 Round trip via toggle model context + disk settings stay clear; max not restored stale max still on disk after round trip
11 bogus-tier error shape invalid-params, choices none, low, medium, xhigh same error shape (pre-existing mapping)
12 persist:'yes' (non-boolean) status 400 "persist must be a boolean" 200 — field silently ignored

The flip count: 5 behavior classes (write-on-persist, persisted field, default-as-clear, reconcile-clear, strict persist validation) are present at head and structurally absent at base; the two symmetric controls (read-back of a valid tier, live-apply of values) pass on both arms, isolating the change. See 01-ab-head-persist-readback-reconcile.png and 02-ab-base-no-persist-path.png.

Corrections

None (first round; no prior review claims to correct).

Findings

S1 (Suggestion) — the managed-conversation guard in persistReasoningSelection has no test

packages/cli/src/acp-integration/session/Session.ts, persistReasoningSelection() throws invalidParams('Reasoning selection cannot be persisted for this session') when requiresManagedConversationBinding is set. No unit test asserts this throw (grep across Session.test.ts/acpAgent.test.ts finds no reference), and my daemon A/B cannot reach it — REST-created sessions are not managed-bound. The behavior is plausible as written, but the guard is unpinned: a future refactor could delete the throw and every suite stays green. Coverage gap, not a defect. Minimal fix: one Session.test.ts case with requiresManagedConversationBinding: true asserting the throw.

Scope note for S1

Do not read this as "the guard is wrong" — only that nothing would notice if it disappeared. The sibling checks (route-level scope validation, reconcile) are separately pinned.

N1 (Nice to have) — mutation survivor adjudicated: parseReasoningSelection strictness is redundant defence, not a gap

Matrix row M4 (accept any string) survived both model-configuration.test.ts (43 tests) and the Session reconcile suite (7 tests). Adjudication: every consumer of parseReasoningSelection independently re-validates — the config-option handler checks the parsed value against the advertised option choices, reconcileReasoningSelection runs isReasoningSelectionSupported, resolvePersistedReasoningConfigState runs it again, and the webui mapper has its own strict parser. A garbage value gets rejected/cleared at each site even with a permissive parse. Classification: redundant defence — correct exactly as it stands; nothing to write or delete. (Contrast with S1, which is a genuine gap.)

N2 (observation) — invalid values surface as HTTP 500 with JSON-RPC -32602

A bogus tier returns 500/-32602 ("Invalid params: …") rather than 400, because the agent's RequestError.invalidParams maps to 500 at the bridge boundary; only the route's own persist validation returns a clean 400. Measured identical at base (both arms, cell 11) — pre-existing mapping, not introduced by this PR. Noting because a reader of the WebShell error path might expect 400 uniformly.

N3 (observation) — persistence scope follows the modelProviders owner

With modelProviders declared in workspace settings, persist:true wrote into the workspace scope (owner-scope policy, same as model selection), and persist default cleared both writable scopes (cell 8). In a default setup (no workspace modelProviders) this lands in user scope. Matches the existing getPersistScopeForModelSelection contract; verified, no action.

Mutation matrix (vacuity + load-bearing of the new tests)

Scratch worktree at HEAD; each mutant run against the suite that should catch it; positive control first. Baselines green: Session reconcile filter 7/7, server config-option 3/3, model-configuration 43/43, modelConfigUtils 61/61, settingsSchema (with the others: 152/152). See 04-mutation-matrix.png.

Row Mutation Suite Result
CTL (positive control) persist key typo in persistReasoningSelection Session reconcile (7) KILLED 1/7expected 'max' to be 'none', the intended write-path assertion
M1 route persist plumbing reverted (whole hunk) server config-option (3) KILLED 3/3
M2 non-boolean persist 400 check deleted server config-option (3) KILLED 1/3 (its own test)
M3 reconcile call deleted from setModel Session reconcile (7) KILLED 4/7 (survivors bypass setModel)
M6 mustClear: !supported → false Session reconcile (7) KILLED 4/7
M7 mustClear → always true Session reconcile (7) KILLED 1/7 — proves keeps a compatible persisted tier pins the over-clearing direction
M5 none semantics reverted in resolveCliGenerationConfig modelConfigUtils (61) KILLED 1/61expected { effort: 'xhigh' } to be false, intended assertion
M4 parse accepts any string model-config (43) + Session (7) SURVIVED → redundant defence (N1)

Note on the 3 M3/M6 survivors: two (persists none…, treats default…) exercise persistReasoningSelection directly and correctly don't depend on reconcile; keeps a compatible persisted tier passes trivially when reconcile never runs but is pinned against over-clearing by M7 — the suite covers both directions between rows.

Targeted gates (all at verified head)

Gate Scope Result
cli acpAgent, Session, model-configuration, settingsSchema, server, workspace-providers-status, modelConfigUtils test files 2529/2529 passed (7 files)
sdk-typescript DaemonClient, DaemonSessionClient unit tests 432/432 passed
webui actions, mappers, DaemonSessionProvider 394/394 passed (149 + 245)
web-shell (vitest) App, ChatEditor, SettingsMessage.dom, sessionPreparation 716/716 passed
web-shell (Playwright smoke) full @smoke suite incl. the 10 reasoning scenarios (fake daemon + Chromium 1228) 45/45 passed (4.3 min)
Generated artifact scripts/generate-settings-schema.ts re-run regenerated settings.schema.json byte-identical to committed (clean git status)

Repo-suite totals are reported here, not folded into assertions.json (which counts only this round's harness assertions).

Not covered

  • TUI flows — PR declares them out of scope; not exercised.
  • No prompt was ever sent — the persistence path is config-only; model-request wire behavior (provider clamping) is untouched by the diff and was not A/B'd. Session creation and model switching did run against the lane's real model proxy.
  • Managed-conversation (Live Voice) sessions — unreachable from REST in this environment; their guard is the subject of S1.
  • Runtime EN/ZH switching in a browser — i18n keys verified statically (added reasoning.effort.high/max in both EN and ZH tables) and label rendering covered by the DOM/unit tests; no live language-toggle e2e was run.
  • Playwright visuals/perf suites — not run (smoke only).
  • Java SDK / public ACP protocol — not in this repo / diff-level check only: the change rides on _meta keys inside the daemon boundary; no ACP schema types changed.
  • Full repo-wide suite — targeted gates only; PR's own CI covers the rest.
  • Uncalibrated-replay caveat does not apply (no workflow/CI YAML changes in this PR).

Methodology

Ran inside the CI verify container (node v22.23.2, merge-ref checkout at depth 2, npm ci + npm run build pre-done at head). A/B daemons were the real packages/cli/dist/index.js serve on each arm with isolated QWEN_HOME/workspace fixtures; the base arm ran a base-tree rebuild of packages/cli only (tsc --build --noCheck, justified above; logs in logs/). The SDK wire harness pointed each arm's compiled SDK at a real loopback capture server and asserted both sides of the wire (wire-sdk.mjs, wire-*.json). Mutations ran in a scratch worktree at HEAD with dependency dists symlinked from untouched packages; every mutant row includes the exact vitest filter and log (logs/matrix-*.log). Playwright smoke used the PR's own @smoke suite after installing the matching Chromium (1228) into the lane's browser cache. All raw per-cell daemon responses are in raw-head.json/raw-base.json; harness sources are in this directory for rerun.

Flakiness gate log

e2e suite, out of gate scope: packages/web-shell/client/e2e/web-shell.smoke.spec.ts
rounds=5 files=16 skipped=1
file packages/cli/src/acp-integration/acpAgent.test.ts: (cd packages/cli) npx --no-install vitest run ./src/acp-integration/acpAgent.test.ts
file packages/cli/src/acp-integration/model-configuration.test.ts: (cd packages/cli) npx --no-install vitest run ./src/acp-integration/model-configuration.test.ts
file packages/cli/src/acp-integration/session/Session.test.ts: (cd packages/cli) npx --no-install vitest run ./src/acp-integration/session/Session.test.ts
file packages/cli/src/config/settingsSchema.test.ts: (cd packages/cli) npx --no-install vitest run ./src/config/settingsSchema.test.ts
file packages/cli/src/serve/server.test.ts: (cd packages/cli) npx --no-install vitest run ./src/serve/server.test.ts
file packages/cli/src/serve/workspace-providers-status.test.ts: (cd packages/cli) npx --no-install vitest run ./src/serve/workspace-providers-status.test.ts
file packages/cli/src/utils/modelConfigUtils.test.ts: (cd packages/cli) npx --no-install vitest run ./src/utils/modelConfigUtils.test.ts
file packages/sdk-typescript/test/unit/DaemonClient.test.ts: (cd packages/sdk-typescript) npx --no-install vitest run ./test/unit/DaemonClient.test.ts
file packages/sdk-typescript/test/unit/DaemonSessionClient.test.ts: (cd packages/sdk-typescript) npx --no-install vitest run ./test/unit/DaemonSessionClient.test.ts
file packages/web-shell/client/App.test.tsx: (cd packages/web-shell) npx --no-install vitest run ./client/App.test.tsx
file packages/web-shell/client/components/ChatEditor.test.tsx: (cd packages/web-shell) npx --no-install vitest run ./client/components/ChatEditor.test.tsx
file packages/web-shell/client/components/messages/SettingsMessage.dom.test.tsx: (cd packages/web-shell) npx --no-install vitest run ./client/components/messages/SettingsMessage.dom.test.tsx
file packages/web-shell/client/utils/sessionPreparation.test.ts: (cd packages/web-shell) npx --no-install vitest run ./client/utils/sessionPreparation.test.ts
file packages/webui/src/daemon/session/DaemonSessionProvider.test.tsx: (cd packages/webui) npx --no-install vitest run ./src/daemon/session/DaemonSessionProvider.test.tsx
file packages/webui/src/daemon/session/actions.test.ts: (cd packages/webui) npx --no-install vitest run ./src/daemon/session/actions.test.ts
file packages/webui/src/daemon/session/mappers.test.ts: (cd packages/webui) npx --no-install vitest run ./src/daemon/session/mappers.test.ts


per-file results (P=pass F=fail I=infra-exit, one letter per run):
  packages/cli/src/acp-integration/acpAgent.test.ts: PP
  packages/cli/src/acp-integration/model-configuration.test.ts: PP
  packages/cli/src/acp-integration/session/Session.test.ts: P
  packages/cli/src/config/settingsSchema.test.ts: P
  packages/cli/src/serve/server.test.ts: P
  packages/cli/src/serve/workspace-providers-status.test.ts: P
  packages/cli/src/utils/modelConfigUtils.test.ts: P
  packages/sdk-typescript/test/unit/DaemonClient.test.ts: P
  packages/sdk-typescript/test/unit/DaemonSessionClient.test.ts: P
  packages/web-shell/client/App.test.tsx: P
  packages/web-shell/client/components/ChatEditor.test.tsx: P
  packages/web-shell/client/components/messages/SettingsMessage.dom.test.tsx: P
  packages/web-shell/client/utils/sessionPreparation.test.ts: P
  packages/webui/src/daemon/session/DaemonSessionProvider.test.tsx: P
  packages/webui/src/daemon/session/actions.test.ts: P
  packages/webui/src/daemon/session/mappers.test.ts: P

verdict: timeout
summary: the 15-minute budget elapsed before two full rounds completed (1 done) — no flakiness signal either way

--- per-invocation detail (full copy in the artifact) ---
round 1 · packages/cli/src/acp-integration/acpAgent.test.ts: P (exit 0)
round 1 · packages/cli/src/acp-integration/model-configuration.test.ts: P (exit 0)
round 1 · packages/cli/src/acp-integration/session/Session.test.ts: P (exit 0)
round 1 · packages/cli/src/config/settingsSchema.test.ts: P (exit 0)
round 1 · packages/cli/src/serve/server.test.ts: P (exit 0)
round 1 · packages/cli/src/serve/workspace-providers-status.test.ts: P (exit 0)
round 1 · packages/cli/src/utils/modelConfigUtils.test.ts: P (exit 0)
round 1 · packages/sdk-typescript/test/unit/DaemonClient.test.ts: P (exit 0)
round 1 · packages/sdk-typescript/test/unit/DaemonSessionClient.test.ts: P (exit 0)
round 1 · packages/web-shell/client/App.test.tsx: P (exit 0)
round 1 · packages/web-shell/client/components/ChatEditor.test.tsx: P (exit 0)
round 1 · packages/web-shell/client/components/messages/SettingsMessage.dom.test.tsx: P (exit 0)
round 1 · packages/web-shell/client/utils/sessionPreparation.test.ts: P (exit 0)
round 1 · packages/webui/src/daemon/session/DaemonSessionProvider.test.tsx: P (exit 0)
round 1 · packages/webui/src/daemon/session/actions.test.ts: P (exit 0)
round 1 · packages/webui/src/daemon/session/mappers.test.ts: P (exit 0)
round 2 · packages/cli/src/acp-integration/acpAgent.test.ts: P (exit 0)
round 2 · packages/cli/src/acp-integration/model-configuration.test.ts: P (exit 0)

Evidence images

01-ab-head-persist-readback-reconcile

02-ab-base-no-persist-path

03-sdk-wire-body-head-vs-base

04-mutation-matrix

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

Qwen Code · sandboxed verification

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

🩺 serve daemon A/B

Built the PR base vs this PR head b5f5359, 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 12 scenario(s).

Qwen Code · serve A/B

@callmeYe

Copy link
Copy Markdown
Collaborator Author

Follow-up: Welcome reasoning preview regression

The reported local regression was real: after selecting medium on Welcome and sending the first prompt, the daemon had persisted model.reasoningEffort: medium, but clicking New task rebuilt the Welcome controls from a stale workspace-provider preview that still said low.

The follow-up commit fixes that state boundary without adding a clear-time provider refresh:

  • after a persist: true reasoning mutation is confirmed by the daemon, WebUI updates the matching model's already-advertised reasoning option in the cached workspace-provider snapshot;
  • clearSession() waits for an in-flight persisted reasoning mutation before deriving the next Welcome model list;
  • failed or unconfirmed persistence leaves the cached preview unchanged;
  • clearing a session performs no provider GET, so there is no cross-workspace ownership fallback or late-refresh overwrite.

Real Chrome verification on the local daemon now passes the exact report path: [Idealab] qwen3.8-max · Medium → send and complete a prompt → New task → root Welcome still shows [Idealab] qwen3.8-max · Medium.

Regression evidence on 6a9bf199d5:

  • focused WebUI actions: 111/111 passed;
  • full WebUI: 647/647 passed;
  • focused first-send/New-task Playwright: 1/1 passed;
  • full reasoning capability matrix Playwright: 10/10 passed;
  • WebUI and WebShell package typechecks passed;
  • root build and root typecheck passed serially;
  • changed-file ESLint/Prettier and both diff checks passed;
  • two clean final diff-audit passes.

This still uses only model.reasoningEffort; no model.reasoningEnabled setting was added.

@callmeYe

Copy link
Copy Markdown
Collaborator Author

@qwen-code /verify

@callmeYe

Copy link
Copy Markdown
Collaborator Author

@qwen-code /triage

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Triage re-run completed without a new review.

⚠️ The bot has neither a verdict nor a deferral on 6a9bf199d5cd0dd6b58ed88b55a9c51b358eb36c — no APPROVED, CHANGES_REQUESTED, or COMMENTED review of its own. A DISMISSED one does not count: dismiss_stale_reviews voids the bot's approval on every push, which is exactly when a fresh one is needed. If this re-run was meant to review or approve, it did not, and an approval left by another account is a separate vote that does not count as the bot's own.

⚠️ 机器人在 6a9bf199d5cd0dd6b58ed88b55a9c51b358eb36c既没有裁决也没有 defer —— 没有属于它自己的 APPROVEDCHANGES_REQUESTEDCOMMENTED 评审。DISMISSED 不算:dismiss_stale_reviews 会在每次推送时作废机器人的批准,而那恰恰是需要一次新批准的时刻。如果这次重跑本应评审或批准,那么它没有做到;而其他账号留下的批准是另一张票,不能算作机器人自己的。

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

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

@github-actions

github-actions Bot commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Summary

Package Lines Statements Functions Branches
CLI 85.81% 85.81% 91.18% 84.74%
Core 88.9% 88.9% 90.57% 87.31%
CLI Package - Full Text Report
-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |   85.81 |    84.74 |   91.18 |   85.81 |                   
 src               |   86.53 |    82.86 |   88.88 |   86.53 |                   
  cli.ts           |   95.92 |    88.23 |     100 |   95.92 | ...00-701,705-706 
  llm.tsx          |   73.22 |    77.73 |   80.76 |   73.22 | ...1345-1349,1476 
  ...ractiveCli.ts |   89.27 |    83.13 |   89.06 |   89.27 | ...3157,3163,3229 
  ...liCommands.ts |   89.71 |    84.17 |   81.81 |   89.71 | ...31-633,650,757 
  ...ActiveAuth.ts |     100 |     87.5 |     100 |     100 | 66-80             
 ...cp-integration |   75.16 |    77.75 |   93.83 |   75.16 |                   
  acpAgent.ts      |   74.12 |    77.31 |   93.04 |   74.12 | ...07,13330-13331 
  ...k-reporter.ts |     100 |       80 |     100 |     100 | 81,84,119,141     
  authMethods.ts   |      92 |       60 |     100 |      92 | 33-34             
  ...heap-probe.ts |   97.39 |    96.66 |     100 |   97.39 | 243,264-265       
  errorCodes.ts    |     100 |      100 |     100 |     100 |                   
  ...ion-skills.ts |     100 |     87.5 |     100 |     100 | 17,28             
  generation.ts    |    97.1 |    81.25 |     100 |    97.1 | 109,112           
  ...figuration.ts |     100 |    95.18 |     100 |     100 | 135,188,234,251   
  ...DirContext.ts |     100 |      100 |     100 |     100 |                   
  ...ersistence.ts |   94.95 |    92.24 |     100 |   94.95 | ...13-118,227-228 
  ...management.ts |   74.75 |     66.3 |     100 |   74.75 | ...92-496,505-509 
  ...e-download.ts |    64.7 |    62.24 |    87.5 |    64.7 | ...08-609,615-619 
 ...tegration/live |   97.53 |    88.23 |   92.85 |   97.53 |                   
  ...en-context.ts |   95.89 |    82.85 |     100 |   95.89 | ...,72-73,105-106 
  ...structions.ts |     100 |      100 |     100 |     100 |                   
  ...ak-to-user.ts |   96.66 |      100 |    87.5 |   96.66 | 37-38             
  ...task-tools.ts |   98.97 |      100 |   88.88 |   98.97 | 201-202           
 ...ration/service |    97.1 |    95.89 |   93.75 |    97.1 |                   
  filesystem.ts    |    97.1 |    95.89 |   93.75 |    97.1 | ...22-123,246-247 
 ...ration/session |   90.89 |    86.38 |   95.79 |   90.89 |                   
  Session.ts       |   90.27 |    85.14 |   95.22 |   90.27 | ...23,13650-13654 
  ...entTracker.ts |   96.88 |    89.36 |      90 |   96.88 | 139-145,224       
  ...projection.ts |   98.85 |    91.59 |     100 |   98.85 | 234,250,262       
  ...stop-guard.ts |     100 |    98.07 |     100 |     100 | 37,127            
  ...eplay-page.ts |   94.19 |    86.53 |     100 |   94.19 | ...53,357,437,441 
  ...y-replayer.ts |   83.41 |    93.33 |   94.11 |   83.41 | ...30-148,266-268 
  index.ts         |       0 |        0 |       0 |       0 | 1-40              
  ...ssionUtils.ts |   89.19 |     87.8 |     100 |   89.19 | ...85-304,363-365 
  ...oal-update.ts |   98.61 |    97.29 |     100 |   98.61 | 64                
  ...lure-guard.ts |   98.32 |    97.72 |     100 |   98.32 | 294-295,340-341   
  tasksSnapshot.ts |    94.3 |     87.5 |     100 |    94.3 | 65-71             
  ...on-tracker.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...ssion/emitters |   95.65 |    92.34 |   97.14 |   95.65 |                   
  ...ageEmitter.ts |   95.36 |    92.42 |     100 |   95.36 | ...16,129-130,223 
  PlanEmitter.ts   |     100 |       90 |     100 |     100 | 66                
  base-emitter.ts  |   78.26 |    77.77 |     100 |   78.26 | 23-24,26-28       
  index.ts         |       0 |        0 |       0 |       0 | 1-10              
  ...ll-emitter.ts |   98.57 |    94.84 |     100 |   98.57 | 75-76,394-395     
 ...ession/rewrite |   96.03 |    89.79 |   94.44 |   96.03 |                   
  LlmRewriter.ts   |   94.01 |    88.23 |     100 |   94.01 | 101-102,179-183   
  ...Middleware.ts |   96.99 |    88.37 |     100 |   96.99 | 145,153-155       
  TurnBuffer.ts    |     100 |      100 |     100 |     100 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 src/agent-view    |   86.63 |     80.8 |   94.01 |   86.63 |                   
  attach-lease.ts  |     100 |    97.05 |     100 |     100 | 173               
  ...t-cli-argv.ts |     100 |     92.3 |     100 |     100 | 15                
  ...ged-detach.ts |     100 |     90.9 |     100 |     100 | 40,64             
  presentation.ts  |   94.13 |    88.72 |   94.73 |   94.13 | ...57-358,382-384 
  protocol.ts      |     100 |      100 |     100 |     100 |                   
  pty-host-env.ts  |     100 |      100 |     100 |     100 |                   
  ...st-process.ts |   88.43 |    78.79 |   94.44 |   88.43 | ...1294,1384-1386 
  pty-host.ts      |   85.25 |    87.03 |   90.69 |   85.25 | ...22-524,539-540 
  ...sor-client.ts |   80.38 |    72.81 |   77.41 |   80.38 | ...22-626,652-656 
  ...r-dispatch.ts |      98 |    85.18 |     100 |      98 | 117,173,190       
  ...or-process.ts |    83.5 |     77.3 |   98.72 |    83.5 | ...4479-4482,4485 
  ...sor-runner.ts |   82.43 |    76.82 |   80.95 |   82.43 | ...69,493,496-506 
  ...sor-server.ts |   84.39 |    83.56 |    93.1 |   84.39 | ...67-568,571-588 
  ...isor-store.ts |   94.76 |    84.95 |     100 |   94.76 | ...,966,1008,1023 
  ...nal-bridge.ts |   93.98 |    91.54 |   83.33 |   93.98 | 228-238           
  ...r-sideband.ts |   94.91 |    89.36 |     100 |   94.91 | ...75-276,299-304 
 src/commands      |   90.73 |    78.53 |   65.62 |   90.73 |                   
  auth.ts          |     100 |    83.33 |     100 |     100 | 11,14             
  channel.ts       |   55.55 |      100 |       0 |   55.55 | 18-22,30-40       
  extensions.tsx   |   96.77 |      100 |      50 |   96.77 | 39                
  hooks.tsx        |   66.66 |      100 |       0 |   66.66 | 20-24             
  mcp.ts           |   95.45 |      100 |      50 |   95.45 | 31                
  review.ts        |   98.94 |      100 |      50 |   98.94 | 106               
  serve.ts         |   89.46 |    76.02 |     100 |   89.46 | ...12-915,927,938 
  sessions.ts      |     100 |      100 |      50 |     100 |                   
  update.ts        |   98.13 |    94.44 |   66.66 |   98.13 | 82-83             
 ...mmands/channel |   89.47 |    88.73 |   90.68 |   89.47 |                   
  channel-cwd.ts   |     100 |      100 |     100 |     100 |                   
  ...l-registry.ts |   94.78 |    94.59 |      90 |   94.78 | ...32-335,380-383 
  ...entry-path.ts |      75 |       50 |     100 |      75 | 8-9               
  config-utils.ts  |   96.84 |    96.22 |     100 |   96.84 | ...40-245,303-306 
  configure.ts     |    14.7 |      100 |       0 |    14.7 | 18-21,23-84       
  daemon-worker.ts |   93.75 |    85.86 |   94.33 |   93.75 | ...1318,1325-1326 
  loop-runtime.ts  |   91.66 |      100 |      50 |   91.66 | 15,22             
  ...classifier.ts |   98.53 |    96.66 |     100 |   98.53 | 115-116,161       
  ...tact-store.ts |   93.51 |    87.65 |     100 |   93.51 | ...71,288-289,337 
  pairing.ts       |      75 |      100 |      50 |      75 | 22-28,59-70       
  pidfile.ts       |   95.55 |       90 |     100 |   95.55 | ...50-251,315-316 
  proxy.ts         |     100 |      100 |     100 |     100 |                   
  reload.ts        |    77.5 |    86.95 |      75 |    77.5 | 72-84,93-97       
  runtime.ts       |   82.43 |    86.44 |     100 |   82.43 | ...87-191,251-253 
  set.ts           |   75.72 |    85.71 |      50 |   75.72 | 65-83,111-116     
  start.ts         |    87.7 |    83.63 |      88 |    87.7 | ...95,601-604,616 
  ...ure-format.ts |   93.65 |    82.45 |     100 |   93.65 | ...42,48-49,74-75 
  status.ts        |   78.57 |    59.25 |   66.66 |   78.57 | ...36-137,150-161 
  stop.ts          |   57.83 |    82.35 |      50 |   57.83 | ...3,74-76,85-111 
 ...nds/extensions |   88.85 |    87.73 |   87.09 |   88.85 |                   
  consent.ts       |   72.53 |    90.32 |   42.85 |   72.53 | ...86-142,157-163 
  disable.ts       |     100 |       90 |     100 |     100 | 30                
  enable.ts        |     100 |    91.66 |     100 |     100 | 38                
  install.ts       |   82.95 |    81.57 |      75 |   82.95 | ...96-199,202-211 
  link.ts          |     100 |      100 |     100 |     100 |                   
  list.ts          |     100 |     87.5 |     100 |     100 | 18                
  new.ts           |     100 |      100 |     100 |     100 |                   
  settings.ts      |   99.15 |      100 |   83.33 |   99.15 | 151               
  sources.ts       |   93.42 |    87.09 |   92.85 |   93.42 | ...4-66,96-98,167 
  uninstall.ts     |   74.57 |       40 |   66.66 |   74.57 | 45-47,60-67,70-73 
  update.ts        |   96.71 |    97.05 |     100 |   96.71 | 114-118           
  utils.ts         |   75.63 |    55.55 |     100 |   75.63 | ...30-134,136-140 
 ...les/mcp-server |       0 |        0 |       0 |       0 |                   
  example.ts       |       0 |        0 |       0 |       0 | 1-60              
 ...amples/starter |       0 |        0 |       0 |       0 |                   
  example.ts       |       0 |        0 |       0 |       0 | 1-64              
 src/commands/mcp  |   91.19 |    88.76 |   85.71 |   91.19 |                   
  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.9 |    84.84 |      80 |    92.9 | ...79-181,199-200 
  reconnect.ts     |   85.54 |    86.76 |    90.9 |   85.54 | 45-58,337-359     
  remove.ts        |     100 |       80 |     100 |     100 | 21-25             
 ...ommands/review |   91.96 |    90.53 |   93.54 |   91.96 |                   
  ab-drive.ts      |   85.22 |    90.47 |   94.11 |   85.22 | ...50-926,969-972 
  agent-prompt.ts  |   94.89 |    93.01 |   97.95 |   94.89 | ...3296,3631-3711 
  base-tree.ts     |   77.02 |    80.76 |   77.77 |   77.02 | ...63-384,386-399 
  capture-local.ts |   94.68 |     97.6 |   94.11 |   94.68 | 269,1334-1372     
  ...k-coverage.ts |   50.71 |       35 |   66.66 |   50.71 | ...40-245,279-289 
  cleanup.ts       |   92.34 |     89.5 |    90.9 |   92.34 | ...1107,1109-1110 
  comment-body.ts  |   67.85 |    87.09 |   66.66 |   67.85 | ...30,157,159-164 
  ...ent-status.ts |   94.22 |    87.32 |    90.9 |   94.22 | ...96,462,738-758 
  ...ose-review.ts |   97.41 |    93.96 |   98.73 |   97.41 | ...6570-6614,6874 
  cost-ledger.ts   |   94.58 |     94.4 |   81.25 |   94.58 | ...53-654,694-704 
  ...candidates.ts |   93.12 |    93.95 |   84.61 |   93.12 | ...49-660,662-674 
  drive.ts         |   97.12 |    89.85 |     100 |   97.12 | ...83-985,990-992 
  emit-workflow.ts |   90.57 |     93.1 |   83.33 |   90.57 | 154,176,285-295   
  extract-step.ts  |   91.36 |    90.62 |   88.88 |   91.36 | ...90-707,714-729 
  fetch-diff.ts    |   73.75 |      100 |   66.66 |   73.75 | 77-97             
  fetch-pr.ts      |   97.29 |    92.25 |     100 |   97.29 | ...1566,1724-1729 
  findings.ts      |    96.3 |    93.68 |     100 |    96.3 | ...1418,1427-1428 
  issue-context.ts |   88.15 |     93.1 |   85.71 |   88.15 | 249-276           
  load-rules.ts    |   26.41 |      100 |   16.66 |   26.41 | ...41-153,155-156 
  match-remote.ts  |   85.55 |     92.3 |   66.66 |   85.55 | 74-79,144-150     
  meta.ts          |   79.43 |    93.75 |   66.66 |   79.43 | 123-128,147-162   
  mock-provider.ts |   95.44 |    90.25 |   89.47 |   95.44 | 145,690-709       
  parse-args.ts    |   99.48 |    95.74 |     100 |   99.48 | 665,990,1046,1082 
  plan-diff.ts     |   71.42 |      100 |   66.66 |   71.42 | 162-197           
  pr-context.ts    |   96.22 |    88.86 |     100 |   96.22 | ...2580,2681-2697 
  presubmit.ts     |   94.32 |    90.83 |   94.11 |   94.32 | ...1219,1254-1285 
  ...ish-assets.ts |    81.3 |    82.22 |   85.71 |    81.3 | ...75-479,506-552 
  ...r-findings.ts |   90.74 |    83.75 |     100 |   90.74 | ...17-422,429-430 
  repo-context.ts  |   94.62 |    90.75 |     100 |   94.62 | ...66-467,482-487 
  ...ve-anchors.ts |   78.34 |    89.28 |      75 |   78.34 | ...83-188,200-217 
  revert-hunk.ts   |   91.48 |    87.94 |     100 |   91.48 | ...1189,1236-1239 
  run.ts           |   84.47 |    87.58 |   95.45 |   84.47 | ...00,816-870,884 
  save-artifact.ts |    94.2 |    92.46 |   94.11 |    94.2 | ...14-617,710-713 
  scratch-tree.ts  |   95.93 |       86 |     100 |   95.93 | ...91-392,461-464 
  script-lint.ts   |   81.27 |    80.45 |   88.88 |   81.27 | ...69-783,785-807 
  submit.ts        |   94.21 |       89 |   94.44 |   94.21 | ...1710,1738-1775 
  test-delta.ts    |   95.75 |     92.3 |      75 |   95.75 | 470-478           
  test-efficacy.ts |   84.03 |    80.48 |   96.07 |   84.03 | ...3249,3257-3277 
  test-plan.ts     |   94.61 |    91.79 |      95 |   94.61 | ...29-832,873-874 
  ...low-script.ts |     100 |      100 |     100 |     100 |                   
 ...w/__fixtures__ |     100 |      100 |     100 |     100 |                   
  ...r-default.mjs |     100 |      100 |     100 |     100 |                   
  ...der-empty.mjs |     100 |      100 |     100 |     100 |                   
  ...der-named.mjs |     100 |      100 |     100 |     100 |                   
 ...nds/review/lib |   97.34 |    94.73 |    98.7 |   97.34 |                   
  agent-briefs.ts  |   99.08 |      100 |      50 |   99.08 | 841-842           
  ...t-identity.ts |     100 |      100 |     100 |     100 |                   
  anchors.ts       |     100 |    97.04 |     100 |     100 | ...39,175,184,231 
  assets.ts        |     100 |      100 |     100 |     100 |                   
  audit-layers.ts  |   98.67 |    96.15 |     100 |   98.67 | 288-290           
  authorization.ts |    96.5 |    95.61 |     100 |    96.5 | ...54-255,629-630 
  budget.ts        |     100 |    97.95 |     100 |     100 | 887,940           
  build-budget.ts  |     100 |      100 |     100 |     100 |                   
  certification.ts |     100 |      100 |     100 |     100 |                   
  convergence.ts   |     100 |    97.94 |    92.3 |     100 | 52,515,620,716    
  coverage.ts      |   98.97 |    95.11 |     100 |   98.97 | ...1103,1648-1649 
  deadline.ts      |   98.03 |    91.66 |     100 |   98.03 | ...20,752,820,837 
  diff-flags.ts    |     100 |        0 |     100 |     100 | 75                
  diff-plan.ts     |   99.29 |    95.77 |     100 |   99.29 | 295-296,319       
  disk.ts          |     100 |      100 |     100 |     100 |                   
  effort.ts        |     100 |      100 |     100 |     100 |                   
  failing-files.ts |     100 |    93.33 |     100 |     100 | 41                
  gh.ts            |   89.53 |    95.52 |   78.94 |   89.53 | ...47,384-385,412 
  git.ts           |   96.92 |    94.11 |     100 |   96.92 | 264-265,302-303   
  heavy.ts         |     100 |      100 |     100 |     100 |                   
  import-graph.ts  |   96.68 |     95.6 |     100 |   96.68 | 180-182,211-212   
  ...ntal-scope.ts |     100 |      100 |     100 |     100 |                   
  inline-counts.ts |     100 |      100 |     100 |     100 |                   
  ...audit-gate.ts |     100 |     97.5 |     100 |     100 | 135               
  ledger.ts        |     100 |    99.47 |     100 |     100 | 884               
  local-anchor.ts  |   94.36 |    89.24 |     100 |   94.36 | ...36,669-670,818 
  local-diff.ts    |   86.77 |    94.28 |     100 |   86.77 | ...54-564,566-574 
  ...ry-context.ts |   96.61 |    95.48 |     100 |   96.61 | ...47-450,496-499 
  md-field.ts      |     100 |      100 |     100 |     100 |                   
  merge-base.ts    |     100 |      100 |     100 |     100 |                   
  narrow-diff.ts   |     100 |      100 |     100 |     100 |                   
  npm-toolchain.ts |   98.23 |    95.29 |     100 |   98.23 | ...,822,1203,1220 
  path-rules.ts    |     100 |      100 |     100 |     100 |                   
  paths.ts         |    95.6 |    88.67 |     100 |    95.6 | 40-41,168-173     
  prompt-record.ts |   98.03 |    94.23 |     100 |   98.03 | 293-294,300       
  receipt.ts       |     100 |      100 |     100 |     100 |                   
  remote-match.ts  |   98.03 |    94.73 |     100 |   98.03 | 109-110           
  report.ts        |   92.92 |    86.66 |     100 |   92.92 | 213-214,216-220   
  ...ry-context.ts |     100 |    98.66 |     100 |     100 | 187               
  resume.ts        |     100 |      100 |     100 |     100 |                   
  retirement.ts    |     100 |    94.36 |     100 |     100 | ...58-559,760,917 
  review-footer.ts |   99.55 |    98.09 |     100 |   99.55 | 548-549           
  ...w-settings.ts |     100 |    96.42 |     100 |     100 | 99                
  roster.ts        |     100 |    97.14 |     100 |     100 | 177,222           
  round-model.ts   |     100 |      100 |     100 |     100 |                   
  run-ledger.ts    |    98.2 |    93.87 |     100 |    98.2 | ...23,541,647,670 
  same-file.ts     |     100 |       95 |     100 |     100 | 46                
  ...boxed-exec.ts |   94.26 |    89.32 |   95.65 |   94.26 | ...49-550,728-729 
  shell-quote.ts   |     100 |      100 |     100 |     100 |                   
  stale-bundle.ts  |   98.18 |    94.38 |     100 |   98.18 | 431,472,512-513   
  test-utils.ts    |   99.04 |    91.66 |     100 |   99.04 | 75                
  toolchain.ts     |     100 |      100 |     100 |     100 |                   
  transcripts.ts   |   98.09 |    95.07 |     100 |   98.09 | ...92,438,707-708 
  ...pace-scope.ts |     100 |    96.96 |     100 |     100 | 186               
  workspaces.ts    |     100 |    96.85 |     100 |     100 | 222,452,499,512   
  ...ree-reader.ts |     100 |      100 |     100 |     100 |                   
  worktree.ts      |   89.39 |    81.78 |     100 |   89.39 | ...1813-1814,1827 
 ...w/lib/platform |   94.71 |    87.89 |   97.05 |   94.71 |                   
  aone-client.ts   |   94.94 |     87.3 |     100 |   94.94 | ...92-293,299-302 
  aone.ts          |   93.06 |    89.86 |   94.73 |   93.06 | ...34,598-603,655 
  github.ts        |   99.08 |     75.8 |     100 |   99.08 | 249-250           
  registry.ts      |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...mands/sessions |   94.11 |    89.06 |   89.47 |   94.11 |                   
  common.ts        |     100 |      100 |     100 |     100 |                   
  list.ts          |   90.96 |    86.66 |   81.81 |   90.96 | 208-219,221-222   
  ps.ts            |     100 |    94.44 |     100 |     100 | 58                
 src/config        |   94.34 |    90.48 |   95.29 |   94.34 |                   
  ...l-fallback.ts |     100 |      100 |     100 |     100 |                   
  auth.ts          |   93.36 |    88.37 |     100 |   93.36 | ...06-307,330-331 
  ...eMcpImport.ts |   87.91 |    81.52 |     100 |   87.91 | ...63-371,453-454 
  compile-cache.ts |     100 |      100 |     100 |     100 |                   
  config.ts        |    88.2 |    90.75 |   86.11 |    88.2 | ...2314,2316-2324 
  ...cy-monitor.ts |      90 |    77.27 |     100 |      90 | ...72-73,90-92,98 
  ...ust-policy.ts |   83.02 |    88.88 |     100 |   83.02 | ...02-209,232-240 
  ...heme-names.ts |     100 |      100 |     100 |     100 |                   
  ...ScopeUtils.ts |   97.56 |    88.88 |     100 |   97.56 | 67                
  environment.ts   |   94.51 |    92.55 |   95.23 |   94.51 | ...24-625,679-680 
  ...le-watcher.ts |   90.86 |    83.65 |   95.83 |   90.86 | ...23-325,370,418 
  ...resh-state.ts |   90.57 |    97.29 |   93.75 |   90.57 | 137-142,146-152   
  ...ime-reload.ts |     100 |    69.69 |     100 |     100 | ...12-113,122-123 
  hot-reload.ts    |     100 |    89.13 |     100 |     100 | 47,172-178,238    
  keyBindings.ts   |    97.4 |       50 |     100 |    97.4 | 240-243           
  ...ngsAdapter.ts |     100 |    94.11 |     100 |     100 | 64                
  ...ig-watcher.ts |   95.17 |    83.05 |     100 |   95.17 | ...78,200,292-293 
  ...er-secrets.ts |   98.97 |    96.96 |     100 |   98.97 | 85                
  mcpApprovals.ts  |   78.57 |       92 |   86.66 |   78.57 | ...18-319,324-326 
  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.93 |     100 |   99.15 | 63                
  sandboxConfig.ts |   93.33 |    93.33 |     100 |   93.33 | ...42-147,216-217 
  session-id.ts    |     100 |      100 |     100 |     100 |                   
  ...ings-cache.ts |   96.52 |    93.93 |     100 |   96.52 | 90-91,201-202     
  settings.ts      |   91.16 |    93.02 |      90 |   91.16 | ...1037,1039-1040 
  ...ingsSchema.ts |     100 |      100 |     100 |     100 |                   
  settingsUtils.ts |   80.92 |     89.2 |   85.18 |   80.92 | ...87-605,612-620 
  ...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 
  ...el-options.ts |     100 |      100 |     100 |     100 |                   
  ...precedence.ts |   98.79 |     92.3 |     100 |   98.79 | 62                
  ...tedFolders.ts |   92.53 |    93.54 |     100 |   92.53 | ...36-337,373-384 
 ...nfig/migration |   95.23 |    78.94 |   85.71 |   95.23 |                   
  index.ts         |   95.65 |     87.5 |     100 |   95.65 | 117-118           
  scheduler.ts     |   96.55 |       80 |     100 |   96.55 | 19-20             
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...ation/versions |   94.91 |      100 |     100 |   94.91 |                   
  ...-v2-shared.ts |     100 |      100 |     100 |     100 |                   
  v1-to-v2.ts      |   81.75 |      100 |     100 |   81.75 | ...28-229,231-247 
  v2-to-v3.ts      |     100 |      100 |     100 |     100 |                   
  v3-to-v4.ts      |     100 |      100 |     100 |     100 |                   
  v5-to-v4.ts      |      96 |      100 |     100 |      96 | 94-95,99          
 src/core          |     100 |      100 |     100 |     100 |                   
  auth.ts          |     100 |      100 |     100 |     100 |                   
  initializer.ts   |     100 |      100 |     100 |     100 |                   
  theme.ts         |     100 |      100 |     100 |     100 |                   
 src/dualOutput    |   75.08 |    67.64 |   71.42 |   75.08 |                   
  ...tputBridge.ts |   75.33 |    68.18 |   73.68 |   75.33 | ...09-410,418-421 
  ...utContext.tsx |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-8               
 src/export        |       0 |        0 |       0 |       0 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-7               
 src/generated     |     100 |      100 |     100 |     100 |                   
  git-commit.ts    |     100 |      100 |     100 |     100 |                   
 src/hooks         |     100 |      100 |     100 |     100 |                   
  ...elete-hook.ts |     100 |      100 |     100 |     100 |                   
 src/i18n          |   89.68 |    88.66 |   93.02 |   89.68 |                   
  index.ts         |   73.45 |    77.77 |      90 |   73.45 | ...70-271,294-299 
  languageUtils.ts |   98.88 |    97.01 |     100 |   98.88 | 184-185           
  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 |   87.37 |    83.73 |   89.32 |   87.37 |                   
  ...ng-failure.ts |     100 |      100 |     100 |     100 |                   
  ...iveHelpers.ts |   94.95 |    91.05 |     100 |   94.95 | ...30-431,529,542 
  ...uggestions.ts |   84.29 |    70.83 |     100 |   84.29 | 70-76,92-103      
  session.ts       |   84.97 |    76.31 |   96.07 |   84.97 | ...1048,1057-1067 
  ...iagnostics.ts |    95.8 |     87.5 |   93.75 |    95.8 | ...03,277-278,289 
  types.ts         |    42.5 |      100 |   33.33 |    42.5 | ...33-634,637-638 
 ...active/control |   75.54 |    89.83 |      80 |   75.54 |                   
  ...rolContext.ts |    6.06 |        0 |       0 |    6.06 | 57-99             
  ...Dispatcher.ts |   91.95 |    92.98 |   88.88 |   91.95 | ...54-372,392,395 
  ...rolService.ts |    6.89 |        0 |       0 |    6.89 | 46-188            
 ...ol/controllers |   57.57 |    66.48 |   73.68 |   57.57 |                   
  ...Controller.ts |    42.4 |      100 |   83.33 |    42.4 | 101-105,140-223   
  ...Controller.ts |       0 |        0 |       0 |       0 | 1-56              
  ...Controller.ts |   70.23 |    63.33 |   91.66 |   70.23 | ...19-628,643-648 
  ...Controller.ts |   49.23 |       60 |      50 |   49.23 | ...07-108,111-121 
  ...Controller.ts |   53.96 |    67.08 |   66.66 |   53.96 | ...78-690,699-728 
 .../control/types |       0 |        0 |       0 |       0 |                   
  serviceAPIs.ts   |       0 |        0 |       0 |       0 | 1                 
 ...Interactive/io |   98.18 |    94.11 |   95.34 |   98.18 |                   
  ...putAdapter.ts |   98.07 |    93.21 |   98.11 |   98.07 | ...1448,1464-1465 
  ...putAdapter.ts |   96.22 |    91.66 |   85.71 |   96.22 | 52-53             
  ...nputReader.ts |     100 |    94.73 |     100 |     100 | 67                
  ...putAdapter.ts |   98.51 |      100 |   90.47 |   98.51 | 90-91,131-132     
  ...projection.ts |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/patches       |       0 |        0 |       0 |       0 |                   
  is-in-ci.ts      |       0 |        0 |       0 |       0 | 1-17              
 src/peerMessaging |   91.89 |    88.29 |   96.42 |   91.89 |                   
  ...ngContext.tsx |     100 |      100 |     100 |     100 |                   
  ...-messaging.ts |   91.78 |    88.17 |   96.29 |   91.78 | ...31-436,507-512 
 src/remoteInput   |   87.31 |    75.32 |   88.23 |   87.31 |                   
  ...utContext.tsx |     100 |      100 |     100 |     100 |                   
  ...putWatcher.ts |   88.01 |       76 |   93.33 |   88.01 | ...49-350,361-364 
  index.ts         |       0 |        0 |       0 |       0 | 1-8               
 src/runtime       |   99.72 |    95.47 |     100 |   99.72 |                   
  ...livery-ipc.ts |     100 |    91.17 |     100 |     100 | 94,106,134        
  ...l-delivery.ts |     100 |      100 |     100 |     100 |                   
  cpu-percent.ts   |     100 |      100 |     100 |     100 |                   
  ...ion-source.ts |     100 |      100 |     100 |     100 |                   
  ...d-task-run.ts |     100 |       70 |     100 |     100 | 57,71             
  ...erver-name.ts |     100 |      100 |     100 |     100 |                   
  ...-constants.ts |     100 |      100 |     100 |     100 |                   
  ...-summaries.ts |   86.66 |       50 |     100 |   86.66 | 11,19             
  ...ber-errors.ts |     100 |    95.53 |     100 |     100 | 53,93-94,172,192  
  ...ls-mapping.ts |     100 |      100 |     100 |     100 |                   
 src/serve         |    87.5 |    85.18 |   90.72 |    87.5 |                   
  ...extra-args.ts |     100 |      100 |     100 |     100 |                   
  ...tp-enabled.ts |     100 |      100 |     100 |     100 |                   
  ...ion-bridge.ts |     100 |      100 |     100 |     100 |                   
  auth.ts          |   93.99 |     91.5 |     100 |   93.99 | ...29-430,433-435 
  ...em-adapter.ts |     100 |      100 |     100 |     100 |                   
  capabilities.ts  |     100 |    98.21 |     100 |     100 | 737               
  ...cp-command.ts |     100 |      100 |     100 |     100 |                   
  ...horization.ts |   92.79 |    93.54 |    87.5 |   92.79 | 75-80,135-136     
  ...op-mcp-ipc.ts |   81.06 |    73.68 |   94.11 |   81.06 | ...37-242,267,289 
  ...nt-service.ts |    94.1 |    86.98 |     100 |    94.1 | ...75-477,484,486 
  ...-selection.ts |     100 |      100 |     100 |     100 |                   
  ...ings-store.ts |   89.61 |    94.37 |   96.55 |   89.61 | ...64-276,528-531 
  ...ebhook-ipc.ts |    98.5 |     87.5 |     100 |    98.5 | 47                
  ...iagnostics.ts |     100 |      100 |     100 |     100 |                   
  ...worker-env.ts |     100 |      100 |     100 |     100 |                   
  ...rker-group.ts |   87.32 |    85.33 |     100 |   87.32 | ...14,820-824,842 
  ...er-manager.ts |   89.39 |    83.88 |   93.33 |   89.39 | ...98,711,722-724 
  ...horization.ts |     100 |      100 |     100 |     100 |                   
  ...tartup-ipc.ts |   97.72 |    96.66 |     100 |   97.72 | 88-89             
  ...supervisor.ts |   93.24 |    85.42 |    97.4 |   93.24 | ...1765,1819-1823 
  ...e-grouping.ts |     100 |    94.28 |     100 |     100 | 71,137            
  core-runtime.ts  |     100 |      100 |     100 |     100 |                   
  ...ub-session.ts |   91.01 |    81.25 |   94.73 |   91.01 | ...1120,1141-1146 
  ...tree-guard.ts |   93.87 |    89.81 |     100 |   93.87 | ...3227,3297-3301 
  daemon-logger.ts |   82.82 |    78.68 |   92.04 |   82.82 | ...1775,1802-1808 
  ...y-pressure.ts |     100 |    96.96 |     100 |     100 | 135               
  ...trics-ring.ts |     100 |      100 |     100 |     100 |                   
  ...s-provider.ts |   68.04 |    52.77 |     100 |   68.04 | ...44-249,282-290 
  daemon-status.ts |   98.69 |    91.96 |     100 |   98.69 | ...1590,1592-1593 
  debug-mode.ts    |     100 |      100 |     100 |     100 |                   
  env-snapshot.ts  |   93.37 |    85.18 |     100 |   93.37 | 114-117,195-202   
  ...-scheduler.ts |   87.34 |    83.87 |     100 |   87.34 | 33-36,48-50,79-81 
  ...d-provider.ts |   92.06 |    87.09 |     100 |   92.06 | ...72,287-293,316 
  ...h-settings.ts |   94.94 |    90.45 |     100 |   94.94 | ...30,708,724,734 
  fast-path.ts     |   91.38 |       82 |   95.45 |   91.38 | ...46-555,633-634 
  ...ration-sse.ts |   42.55 |    33.33 |     100 |   42.55 | 23-24,30,33-56    
  health-query.ts  |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-149             
  ...e-observer.ts |   89.89 |    83.24 |      96 |   89.89 | ...11-512,541-543 
  ...-addresses.ts |     100 |     91.3 |     100 |     100 | 52,72             
  ...back-binds.ts |     100 |    88.88 |     100 |     100 | 32                
  ...-workspace.ts |   91.58 |    86.48 |     100 |   91.58 | ...44-145,156-157 
  ...pp-sandbox.ts |   96.72 |    95.23 |     100 |   96.72 | 41-42             
  ...iders-edit.ts |     100 |    82.14 |     100 |     100 | 58-60,65,81       
  ...ory-picker.ts |    90.9 |    91.66 |      75 |    90.9 | 32,55-64          
  ...-with-auth.ts |     100 |      100 |     100 |     100 |                   
  ...ate-blocks.ts |   99.03 |    94.73 |     100 |   99.03 | 133               
  ...sion-audit.ts |     100 |      100 |   93.33 |     100 |                   
  ...nal-ledger.ts |    94.9 |     85.1 |     100 |    94.9 | ...81,302,361-362 
  rate-limit.ts    |   92.68 |    88.29 |     100 |   92.68 | ...89-291,303-305 
  ...qwen-serve.ts |   84.82 |    81.88 |   77.13 |   84.82 | ...9263,9281-9285 
  ...tup-errors.ts |     100 |      100 |     100 |     100 |                   
  sandbox.ts       |   46.92 |     62.5 |   76.92 |   46.92 | ...1058,1070-1093 
  ...-keepalive.ts |   94.31 |    88.28 |     100 |   94.31 | ...37,541-542,581 
  ...-lifecycle.ts |     100 |      100 |     100 |     100 |                   
  ...-lifecycle.ts |   89.16 |    90.29 |   86.95 |   89.16 | ...24-325,330-334 
  serve-token.ts   |     100 |      100 |     100 |     100 |                   
  server.ts        |   89.09 |    91.05 |   70.31 |   89.09 | ...3175,3206-3207 
  ...-admission.ts |   99.13 |    95.94 |     100 |   99.13 | 308-309           
  ...on-helpers.ts |     100 |      100 |     100 |     100 |                   
  ...-redaction.ts |     100 |      100 |     100 |     100 |                   
  ...t-event-id.ts |     100 |    95.23 |     100 |     100 | 12                
  ...-admission.ts |   98.71 |    89.65 |     100 |   98.71 | 68                
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...ion-limits.ts |     100 |      100 |     100 |     100 |                   
  ...t-sessions.ts |   93.72 |    77.93 |     100 |   93.72 | ...51,854,867-869 
  ...l-resolver.ts |   90.32 |    66.66 |     100 |   90.32 | 16,45-46          
  ...ell-static.ts |   93.45 |    86.88 |     100 |   93.45 | ...77-280,323-326 
  ...ace-agents.ts |   66.13 |    70.57 |   92.68 |   66.13 | ...2246,2256-2266 
  ...generation.ts |    95.4 |    82.35 |   66.66 |    95.4 | 55-56,78,92       
  ...-git-state.ts |     100 |    91.93 |    90.9 |     100 | 161,172,202,265   
  ...ace-inputs.ts |     100 |      100 |     100 |     100 |                   
  ...ace-memory.ts |      83 |    74.54 |     100 |      83 | ...30-537,597-604 
  ...ers-status.ts |   98.65 |    80.18 |     100 |   98.65 | 111,139,193,196   
  ...tion-store.ts |   89.67 |    88.27 |   92.59 |   89.67 | ...91-400,411-414 
  ...e-registry.ts |   94.09 |    90.57 |     100 |   94.09 | ...90-591,598-599 
  ...e-remember.ts |   98.31 |    93.31 |     100 |   98.31 | ...47,351-356,397 
  ...te-runtime.ts |   89.85 |    90.76 |     100 |   89.85 | ...06-207,275-296 
  ...me-storage.ts |     100 |      100 |     100 |     100 |                   
  ...visibility.ts |     100 |      100 |     100 |     100 |                   
  ...management.ts |   72.63 |    72.83 |   96.15 |   72.63 | ...88-889,896-900 
  ...lls-status.ts |     100 |    95.45 |     100 |     100 | 152               
  ...reconciler.ts |   91.63 |    84.09 |     100 |   91.63 | ...71-273,306-307 
 ...serve/acp-http |   80.54 |    80.32 |   94.53 |   80.54 |                   
  ...r-registry.ts |   96.92 |    94.87 |     100 |   96.92 | 184-187           
  client-mcp-ws.ts |   54.85 |    58.62 |   72.72 |   54.85 | ...99-300,304-305 
  ...n-registry.ts |   93.03 |    84.13 |   98.52 |   93.03 | ...1624,1671-1682 
  dispatch.ts      |   75.99 |    77.48 |   93.44 |   75.99 | ...5708,5765-5771 
  index.ts         |   82.81 |    79.92 |   91.22 |   82.81 | ...2434,2520-2521 
  json-rpc.ts      |     100 |    96.96 |     100 |     100 | 92                
  ...ach-budget.ts |     100 |      100 |     100 |     100 |                   
  safe-ws-send.ts  |   52.94 |    71.42 |     100 |   52.94 | 33-42,47-55       
  sse-stream.ts    |   98.26 |    88.88 |     100 |   98.26 | 87-88,117         
  ...ort-stream.ts |       0 |        0 |       0 |       0 | 1                 
  ws-stream.ts     |   94.06 |    89.09 |     100 |   94.06 | 50,55,134,138-141 
 src/serve/auth    |   86.86 |     79.7 |   93.87 |   86.86 |                   
  device-flow.ts   |   96.35 |    80.57 |   97.61 |   96.35 | ...1358,1453,1519 
  ...w-provider.ts |   44.24 |    74.07 |   71.42 |   44.24 | ...23-284,297,301 
 ...rve/cdp-tunnel |   87.73 |    76.21 |    97.5 |   87.73 |                   
  ...r-emulator.ts |   93.27 |    77.77 |     100 |   93.27 | ...53-256,282-283 
  ...verse-link.ts |      88 |    76.19 |     100 |      88 | ...28-329,420-423 
  ...l-registry.ts |     100 |      100 |     100 |     100 |                   
  cdp-ws.ts        |   76.28 |    61.29 |    87.5 |   76.28 | ...13-217,223-228 
 ...nel/acceptance |    6.12 |    57.89 |   46.15 |    6.12 |                   
  ...helpers.d.mts |       0 |        0 |       0 |       0 | 1                 
  ...e-helpers.mjs |   97.64 |    70.96 |     100 |   97.64 | 22-23             
  ...mcp-smoke.mjs |       0 |        0 |       0 |       0 | 1-124             
  ...cceptance.mjs |       0 |        0 |       0 |       0 | 1-473             
  ...re-server.mjs |       0 |        0 |       0 |       0 | 1-59              
  ...ols-smoke.mjs |       0 |        0 |       0 |       0 | 1-268             
  real-tab.mjs     |       0 |        0 |       0 |       0 | 1-218             
  ...al-chrome.mjs |       0 |        0 |       0 |       0 | 1-223             
 .../conversations |    86.2 |    78.67 |   93.29 |    86.2 |                   
  ...e-activity.ts |     100 |      100 |     100 |     100 |                   
  ...ime-errors.ts |     100 |      100 |     100 |     100 |                   
  ...me-manager.ts |   97.88 |    94.91 |     100 |   97.88 | 64-65,92          
  ...-ownership.ts |   87.33 |    83.58 |   88.46 |   87.33 | ...57-558,601-602 
  ...-workspace.ts |   88.17 |    76.15 |     100 |   88.17 | ...52-554,568-572 
  ...on-journal.ts |   91.65 |    80.76 |     100 |   91.65 | ...44-745,751-753 
  ...on-service.ts |   83.22 |    75.11 |   89.01 |   83.22 | ...3014,3023-3025 
 src/serve/fs      |   87.77 |    82.34 |     100 |   87.77 |                   
  audit.ts         |     100 |    96.29 |     100 |     100 | 211               
  errors.ts        |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...x-registry.ts |     100 |      100 |     100 |     100 |                   
  paths.ts         |   77.64 |    74.01 |     100 |   77.64 | ...65,594-598,611 
  policy.ts        |   90.52 |    89.18 |     100 |   90.52 | 172-180           
  text-cursor.ts   |   88.23 |       90 |     100 |   88.23 | 74-77,92-95       
  ...ile-system.ts |   88.02 |    81.85 |     100 |   88.02 | ...3027,3037-3038 
 src/serve/live    |    76.6 |    70.53 |    90.2 |    76.6 |                   
  discovery.ts     |   85.89 |    82.05 |    91.3 |   85.89 | ...73-579,592-593 
  ...oordinator.ts |   82.67 |    76.63 |   97.01 |   82.67 | ...1319,1351-1353 
  ...-installer.ts |    64.3 |    82.35 |   80.76 |    64.3 | ...45-446,460-472 
  ...oordinator.ts |    76.7 |    67.47 |   85.71 |    76.7 | ...1885,1976-1977 
  ...controller.ts |   67.82 |    79.66 |      75 |   67.82 | ...66-278,287-295 
  ...sk-service.ts |   82.71 |    66.15 |   93.61 |   82.71 | ...1270,1283,1290 
  ...redentials.ts |   96.26 |    93.47 |     100 |   96.26 | 91-94             
  ...me-session.ts |   65.63 |    57.24 |   88.88 |   65.63 | ...2270,2275-2282 
  ...up-context.ts |   94.85 |    77.39 |     100 |   94.85 | ...18,327-330,350 
  types.ts         |     100 |      100 |     100 |     100 |                   
 .../local-control |   82.89 |    88.77 |      90 |   82.89 |                   
  credentials.ts   |   96.42 |    95.45 |     100 |   96.42 | 109-110           
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...interfaces.ts |   43.58 |    82.75 |   42.85 |   43.58 | ...09-117,130-142 
  ...r-identity.ts |     100 |    85.71 |     100 |     100 | 61                
  service.ts       |    93.4 |       90 |     100 |    93.4 | ...20-222,313-315 
 src/serve/routes  |   86.46 |    81.77 |   95.79 |   86.46 |                   
  a2ui-action.ts   |   96.84 |     88.5 |    87.5 |   96.84 | ...70-272,309-311 
  capabilities.ts  |   98.73 |    96.15 |     100 |   98.73 | 82                
  ...nel-notify.ts |   79.16 |    85.18 |     100 |   79.16 | ...03-104,120-126 
  ...l-webhooks.ts |   93.56 |    84.09 |     100 |   93.56 | ...42,292,332,334 
  daemon-status.ts |   85.71 |    83.33 |     100 |   85.71 | 101-108           
  goals.ts         |   98.94 |    91.17 |     100 |   98.94 | 143               
  health.ts        |   99.09 |    91.42 |     100 |   99.09 | 147               
  live-setup.ts    |   33.33 |     37.5 |      50 |   33.33 | ...18-123,130-135 
  live.ts          |   84.61 |    76.47 |     100 |   84.61 | ...04,106-111,131 
  permission.ts    |   96.03 |    87.87 |     100 |   96.03 | 81-84             
  ...uled-tasks.ts |   87.52 |    83.61 |   95.12 |   87.52 | ...2016,2061-2062 
  ...r-backfill.ts |    98.5 |    93.65 |     100 |    98.5 | ...98,600,824-825 
  ...on-runtime.ts |   91.42 |       90 |     100 |   91.42 | 56-64             
  session.ts       |   86.78 |    83.17 |   94.35 |   86.78 | ...7193,7195-7196 
  sse-events.ts    |   87.01 |    84.95 |   94.44 |   87.01 | ...40-951,954,961 
  ...e-sessions.ts |    86.9 |    80.57 |     100 |    86.9 | ...81-483,486-491 
  terminal.ts      |   92.81 |    90.35 |     100 |   92.81 | ...10-313,332-335 
  usage-stats.ts   |     100 |    95.45 |     100 |     100 | 118               
  ...space-auth.ts |   85.55 |    75.64 |     100 |   85.55 | ...21-326,331,345 
  ...el-control.ts |   86.26 |    78.94 |     100 |   86.26 | ...17-318,339-347 
  ...management.ts |   90.35 |    78.94 |     100 |   90.35 | ...52-553,576-577 
  ...d-contacts.ts |   83.62 |    94.59 |     100 |   83.62 | 123,125-142       
  ...controller.ts |   83.31 |    80.47 |      90 |   83.31 | ...1055,1060,1067 
  ...extensions.ts |   89.91 |    79.47 |   93.93 |   89.91 | ...2340,2385-2386 
  ...-file-read.ts |      91 |    80.91 |     100 |      91 | ...20-621,624-625 
  ...file-write.ts |   89.72 |    79.35 |     100 |   89.72 | ...05,719-726,807 
  ...t-branches.ts |   75.04 |     66.4 |     100 |   75.04 | ...99-604,613-620 
  ...e-git-diff.ts |   97.19 |    89.58 |     100 |   97.19 | 157-158,185-187   
  ...ce-git-log.ts |     100 |       95 |     100 |     100 | 48,73             
  workspace-git.ts |   74.71 |     87.5 |     100 |   74.71 | 83-104            
  ...github-prs.ts |   88.26 |    63.46 |     100 |   88.26 | ...38-239,264-265 
  ...-lifecycle.ts |   95.23 |    75.75 |     100 |   95.23 | ...50-151,186-187 
  ...al-control.ts |   74.17 |    69.23 |     100 |   74.17 | ...18,220-226,231 
  ...management.ts |   87.14 |    84.21 |     100 |   87.14 | ...1802,1812-1817 
  ...cp-control.ts |    73.2 |    67.54 |   85.71 |    73.2 | ...27-633,644-645 
  ...ace-models.ts |   95.53 |    89.74 |     100 |   95.53 | ...52-157,296-297 
  ...ermissions.ts |    77.9 |    72.41 |     100 |    77.9 | ...69-277,298-316 
  ...e-settings.ts |   75.67 |       75 |     100 |   75.67 | ...15-726,732-733 
  ...tup-github.ts |   77.97 |    70.58 |   84.21 |   77.97 | ...46-352,397-398 
  ...ace-skills.ts |   76.41 |    86.11 |     100 |   76.41 | ...29-354,360-394 
  ...ace-status.ts |   82.57 |    74.48 |     100 |   82.57 | ...71-473,477-478 
  ...pace-tools.ts |   75.94 |    69.69 |   66.66 |   75.94 | ...59-164,193-194 
  ...pace-trust.ts |   76.92 |     67.1 |      80 |   76.92 | ...38-343,351-352 
  ...pace-voice.ts |   91.33 |    81.02 |     100 |   91.33 | ...70-673,676-678 
 src/serve/server  |   93.13 |    91.49 |   96.15 |   93.13 |                   
  access-log.ts    |   98.73 |    97.26 |     100 |   98.73 | 119,196           
  ...-timestamp.ts |     100 |      100 |     100 |     100 |                   
  aone-mrs.ts      |   91.48 |    91.35 |   81.25 |   91.48 | ...53,299-300,466 
  ...er-helpers.ts |   63.82 |    78.15 |   81.81 |   63.82 | ...16,330,332-347 
  ...w-registry.ts |    98.8 |    81.81 |     100 |    98.8 | 107               
  ...r-handlers.ts |   97.87 |       80 |     100 |   97.87 | 27                
  ...r-response.ts |   88.93 |    84.37 |     100 |   88.93 | ...74,891,954-963 
  fs-factory.ts    |     100 |    95.52 |     100 |     100 | 77,144,200        
  ...branch-ops.ts |     100 |      100 |     100 |     100 |                   
  ...list-cache.ts |   99.01 |    95.52 |     100 |   99.01 | 184-185           
  ...t-deadline.ts |     100 |      100 |     100 |     100 |                   
  ...iter-setup.ts |      65 |       80 |   33.33 |      65 | 30-35,38-43,47-48 
  ...st-helpers.ts |   95.13 |    95.14 |     100 |   95.13 | ...66-168,423-428 
  self-origin.ts   |   76.19 |       80 |     100 |   76.19 | 45-54             
  ...e-features.ts |    95.2 |     87.5 |     100 |    95.2 | 191-197           
  ...on-archive.ts |   91.29 |    89.33 |   97.61 |   91.29 | ...1133,1196-1197 
  ...ion-export.ts |   98.57 |    90.47 |     100 |   98.57 | 85                
  session-list.ts  |   97.27 |    93.88 |     100 |   97.27 | ...1183,1392-1396 
  ...pr-refresh.ts |     100 |    97.05 |     100 |     100 | 199,252,427       
  ...ry-context.ts |    87.5 |       50 |     100 |    87.5 | 49-50             
  telemetry.ts     |   99.06 |    97.27 |     100 |   99.06 | ...04,873,952-954 
 src/serve/voice   |    92.7 |    91.53 |   97.72 |    92.7 |                   
  ...ice-config.ts |   84.81 |       30 |     100 |   84.81 | 91-100,104-105    
  voice-ws.ts      |   91.58 |    93.44 |      96 |   91.58 | ...68,483,521-523 
  ...oordinator.ts |     100 |    98.24 |     100 |     100 | 176               
 ...kspace-service |   89.85 |    86.73 |    91.3 |   89.85 |                   
  index.ts         |   89.49 |    86.34 |      90 |   89.49 | ...1393-1397,1400 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/services      |    92.7 |    89.68 |   98.13 |    92.7 |                   
  ...mandLoader.ts |     100 |       95 |     100 |     100 | 107               
  ...killLoader.ts |   97.19 |    85.71 |     100 |   97.19 | 142,153-154       
  ...andService.ts |   98.73 |      100 |     100 |   98.73 | 107               
  ...mandLoader.ts |   87.09 |    83.07 |     100 |   87.09 | ...35-340,345-350 
  ...omptLoader.ts |   79.55 |    88.42 |   85.71 |   79.55 | ...48,178,245-246 
  ...mandLoader.ts |   97.77 |    92.45 |     100 |   97.77 | 176,183-184       
  ...nd-factory.ts |   91.42 |    91.66 |     100 |   91.42 | 128,137-144       
  ...ation-tool.ts |     100 |    95.45 |     100 |     100 | 125               
  ...ndMetadata.ts |   98.23 |    96.72 |     100 |   98.23 | 83,87             
  commandUtils.ts  |      96 |     90.9 |     100 |      96 | 48                
  ...and-parser.ts |   90.69 |    85.71 |     100 |   90.69 | 63-66             
  ...ionService.ts |     100 |      100 |     100 |     100 |                   
  prompt-stash.ts  |   96.66 |    92.85 |     100 |   96.66 | 34-35             
  ...tree-lease.ts |   92.14 |    92.42 |     100 |   92.14 | ...91-296,329-330 
  ...low-loader.ts |     100 |    96.29 |     100 |     100 | 88                
  setup-github.ts  |    90.8 |    80.95 |     100 |    90.8 | ...49-450,457-458 
  ...-args-file.ts |   93.93 |    91.66 |    87.5 |   93.93 | 208-210,224-230   
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...e-keyterms.ts |   98.64 |    95.77 |     100 |   98.64 | 116,142-143       
  voice-model.ts   |     100 |      100 |     100 |     100 |                   
  voice-service.ts |    90.4 |    87.87 |     100 |    90.4 | ...81,288,353-358 
  ...e-settings.ts |     100 |    95.23 |     100 |     100 | 19                
  ...ranscriber.ts |   91.77 |    87.11 |   97.22 |   91.77 | ...96-898,901-903 
 ...s/housekeeping |   93.06 |    88.57 |      95 |   93.06 |                   
  scheduler.ts     |   93.06 |    88.57 |      95 |   93.06 | ...62-364,416-420 
 ...rvices/insight |     100 |      100 |     100 |     100 |                   
  dates.ts         |     100 |      100 |     100 |     100 |                   
 ...ght/generators |   88.94 |    86.86 |   96.29 |   88.94 |                   
  DataProcessor.ts |   88.31 |    86.84 |      95 |   88.31 | ...1368,1372-1379 
  ...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.25 |     100 |   97.27 |                   
  ...tProcessor.ts |     100 |      100 |     100 |     100 |                   
  ...eProcessor.ts |   94.52 |       85 |     100 |   94.52 | 46-47,93-94       
  ...tionParser.ts |     100 |      100 |     100 |     100 |                   
  ...lProcessor.ts |   97.41 |    95.83 |     100 |   97.41 | 96-99             
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/services/tips |   97.27 |    84.61 |     100 |   97.27 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  tipHistory.ts    |   92.59 |       70 |     100 |   92.59 | ...24,146,153,162 
  tipRegistry.ts   |     100 |      100 |     100 |     100 |                   
  tipScheduler.ts  |     100 |    91.66 |     100 |     100 | 55                
 src/startup       |   88.99 |    83.47 |    90.9 |   88.99 |                   
  ...p-prefetch.ts |   98.09 |    94.23 |    87.5 |   98.09 | 50,209,225-226    
  ...reeStartup.ts |   80.53 |     74.6 |     100 |   80.53 | ...94,403,409-412 
 src/test-utils    |    94.6 |    76.66 |      80 |    94.6 |                   
  ci-env.ts        |      88 |     62.5 |     100 |      88 | 22-23,28          
  ...omMatchers.ts |   69.69 |       50 |      50 |   69.69 | 32-35,37-39,45-47 
  ...mised-lock.ts |     100 |      100 |   66.66 |     100 |                   
  ...lot-client.ts |     100 |    66.66 |     100 |     100 | 31,39             
  ...andContext.ts |     100 |      100 |     100 |     100 |                   
  render.tsx       |     100 |      100 |     100 |     100 |                   
 src/ui            |   71.65 |    78.58 |   72.18 |   71.65 |                   
  App.tsx          |   33.33 |       75 |   33.33 |   33.33 | 32-86             
  AppContainer.tsx |    77.5 |    74.24 |   76.31 |    77.5 | ...4520,4636-4642 
  ...tionNudge.tsx |    9.58 |      100 |       0 |    9.58 | 24-94             
  ...ackDialog.tsx |    30.3 |      100 |       0 |    30.3 | 26-76             
  ...tionNudge.tsx |    7.69 |      100 |       0 |    7.69 | 25-103            
  colors.ts        |   63.63 |      100 |   41.17 |   63.63 | ...52,54-55,60-61 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...AutoUpdate.ts |   93.54 |    94.64 |      90 |   93.54 | 126,131,202-213   
  keyMatchers.ts   |   95.91 |    97.14 |     100 |   95.91 | 25-26             
  ...tic-colors.ts |     100 |      100 |     100 |     100 |                   
  ...one-update.ts |   39.81 |    77.44 |   62.16 |   39.81 | ...1193,1196-1215 
  ...ractiveUI.tsx |   68.53 |    78.26 |      50 |   68.53 | ...65-467,497-502 
  ...inePresets.ts |   96.27 |    83.87 |     100 |   96.27 | ...97,402,410-412 
  systemInfo.ts    |   95.09 |    90.27 |     100 |   95.09 | ...54-255,260-264 
  ...InfoFields.ts |    87.5 |    65.85 |     100 |    87.5 | ...24-125,146-147 
  textConstants.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...e-relaunch.ts |   89.61 |    86.66 |      50 |   89.61 | 56-61,83-84       
 src/ui/auth       |   69.23 |    72.03 |   61.22 |   69.23 |                   
  AuthDialog.tsx   |   59.01 |     42.1 |   16.66 |   59.01 | ...25,332-354,358 
  ...nProgress.tsx |       0 |        0 |       0 |       0 | 1-64              
  ...etupSteps.tsx |   74.93 |    78.62 |   71.42 |   74.93 | ...92-902,918,921 
  useAuth.ts       |   94.83 |       75 |     100 |   94.83 | ...33-234,253-259 
  ...rSetupFlow.ts |   59.79 |    58.33 |     100 |   59.79 | ...82-403,420-463 
 src/ui/commands   |    84.7 |    84.48 |   91.66 |    84.7 |                   
  aboutCommand.ts  |     100 |      100 |     100 |     100 |                   
  ...or-command.ts |     100 |    95.65 |     100 |     100 | 104,182           
  agentsCommand.ts |   83.78 |      100 |      60 |   83.78 | 30-32,42-44       
  ...odeCommand.ts |    93.1 |    95.23 |     100 |    93.1 | 77-82             
  arenaCommand.ts  |   63.89 |    65.71 |   65.21 |   63.89 | ...01-606,691-699 
  authCommand.ts   |     100 |      100 |     100 |     100 |                   
  branchCommand.ts |     100 |      100 |     100 |     100 |                   
  btwCommand.ts    |   94.32 |    77.41 |     100 |   94.32 | 35-36,114-119     
  bugCommand.ts    |     100 |    77.77 |     100 |     100 | 28,62             
  cdCommand.ts     |    92.3 |    82.75 |     100 |    92.3 | ...,94-99,178,187 
  clearCommand.ts  |    80.9 |    70.83 |     100 |    80.9 | ...28-129,137-146 
  commands.ts      |   97.45 |    96.66 |     100 |   97.45 | 153-155           
  ...essCommand.ts |   86.91 |    66.66 |     100 |   86.91 | ...22-223,237-240 
  ...astCommand.ts |   84.75 |    76.47 |     100 |   84.75 | ...96-102,130-135 
  ...ig-command.ts |   93.12 |    88.42 |     100 |   93.12 | ...07-315,321-323 
  ...extCommand.ts |   73.75 |    74.02 |   83.33 |   73.75 | ...72-605,616-617 
  copyCommand.ts   |    98.7 |    96.29 |     100 |    98.7 | 66-67,172,272,323 
  ...or-command.ts |   85.95 |    80.55 |   88.88 |   85.95 | ...68-274,298-309 
  deleteCommand.ts |     100 |      100 |     100 |     100 |                   
  diffCommand.ts   |     100 |    87.87 |     100 |     100 | ...63,231-232,245 
  ...ryCommand.tsx |   90.56 |    87.83 |    90.9 |   90.56 | ...75-280,327-334 
  docsCommand.ts   |     100 |     90.9 |     100 |     100 | 26                
  doctorChecks.ts  |   70.31 |    74.57 |     100 |   70.31 | ...95-301,325-341 
  doctorCommand.ts |   70.16 |    84.61 |      95 |   70.16 | ...29-679,682-816 
  dreamCommand.ts  |   85.45 |    88.88 |     100 |   85.45 | 58-65             
  editorCommand.ts |     100 |      100 |     100 |     100 |                   
  ...rt-command.ts |   80.95 |       80 |     100 |   80.95 | 49-54,69-72,93-98 
  effort-utils.ts  |     100 |      100 |     100 |     100 |                   
  exportCommand.ts |   98.25 |    91.02 |     100 |   98.25 | ...81,198-199,364 
  ...onsCommand.ts |   52.31 |    56.25 |   69.23 |   52.31 | ...09,277-329,390 
  forgetCommand.ts |     100 |       90 |     100 |     100 | 59                
  forkCommand.ts   |     100 |    94.11 |     100 |     100 | 95,146            
  goalCommand.ts   |     100 |    96.49 |     100 |     100 | 139,192           
  helpCommand.ts   |     100 |      100 |     100 |     100 |                   
  ...oryCommand.ts |     100 |      100 |     100 |     100 |                   
  hooksCommand.ts  |   81.25 |    65.71 |   85.71 |   81.25 | ...,86-93,131-132 
  ideCommand.ts    |   60.75 |    64.28 |   41.17 |   60.75 | ...05-306,310-324 
  ...figCommand.ts |    58.5 |    74.07 |      80 |    58.5 | ...21-331,334-343 
  initCommand.ts   |   91.86 |       80 |     100 |   91.86 | 48,83-88          
  ...ghtCommand.ts |   77.87 |    71.42 |     100 |   77.87 | ...44-245,250-272 
  ...ageCommand.ts |   94.63 |    90.66 |     100 |   94.63 | ...25-226,253-263 
  learn-command.ts |     100 |      100 |     100 |     100 |                   
  lspCommand.ts    |     100 |    86.95 |     100 |     100 | 31,102-103        
  mcpCommand.ts    |     100 |      100 |     100 |     100 |                   
  memoryCommand.ts |     100 |      100 |     100 |     100 |                   
  modelCommand.ts  |   86.28 |    86.29 |     100 |   86.28 | ...1112,1146-1151 
  peers-command.ts |     100 |    94.36 |     100 |     100 | 59,70,223,228     
  ...onsCommand.ts |     100 |      100 |     100 |     100 |                   
  planCommand.ts   |   78.82 |    76.92 |     100 |   78.82 | 30-35,51-56,68-73 
  quitCommand.ts   |     100 |      100 |     100 |     100 |                   
  recapCommand.ts  |   21.81 |      100 |      50 |   21.81 | 24-73             
  ...ns-command.ts |   98.83 |    81.81 |     100 |   98.83 | 100               
  ...berCommand.ts |     100 |     87.5 |     100 |     100 | 46                
  renameCommand.ts |    89.6 |       90 |     100 |    89.6 | ...72-176,212-219 
  ...oreCommand.ts |   90.96 |    86.04 |     100 |   90.96 | ...41-146,177-178 
  resumeCommand.ts |     100 |      100 |     100 |     100 |                   
  rewindCommand.ts |   81.25 |      100 |      50 |   81.25 | 20-22             
  ...ngsCommand.ts |     100 |      100 |     100 |     100 |                   
  ...hubCommand.ts |   89.47 |       75 |      80 |   89.47 | 54-59             
  skillsCommand.ts |   78.82 |    81.81 |     100 |   78.82 | 37-52,78,97       
  statsCommand.ts  |   90.65 |    76.73 |     100 |   90.65 | ...30-733,825-832 
  ...ineCommand.ts |     100 |      100 |     100 |     100 |                   
  ...aryCommand.ts |   73.04 |     82.3 |      90 |   73.04 | ...20-547,561-565 
  tasksCommand.ts  |   77.33 |    72.13 |     100 |   77.33 | ...46-150,173-178 
  ...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    |     100 |      100 |     100 |     100 |                   
  voice-command.ts |   93.63 |       88 |     100 |   93.63 | 36,98-103         
  ...owsCommand.ts |   94.38 |    85.29 |     100 |   94.38 | ...78-183,282-287 
 src/ui/components |   74.07 |    80.32 |   78.81 |   74.07 |                   
  AboutBox.tsx     |     100 |      100 |     100 |     100 |                   
  AnsiOutput.tsx   |   65.57 |      100 |      50 |   65.57 | 69-90             
  ApiKeyInput.tsx  |       0 |        0 |       0 |       0 | 1-97              
  AppHeader.tsx    |    88.7 |       75 |     100 |    88.7 | 36,38-43,45       
  ...odeDialog.tsx |   87.24 |    72.22 |   33.33 |   87.24 | ...85,233-238,245 
  AsciiArt.ts      |     100 |      100 |     100 |     100 |                   
  ...Indicator.tsx |   95.65 |    66.66 |     100 |   95.65 | 27,52             
  ...TextInput.tsx |   89.06 |    90.78 |     100 |   89.06 | ...87-289,303-305 
  ...ontroller.tsx |     100 |      100 |     100 |     100 |                   
  Composer.tsx     |   94.54 |    66.66 |     100 |   94.54 | ...-76,88,143,158 
  ...entPrompt.tsx |     100 |      100 |     100 |     100 |                   
  ...ryDisplay.tsx |   75.89 |    62.06 |     100 |   75.89 | ...,88,93-108,113 
  ...geDisplay.tsx |   68.42 |    57.14 |     100 |   68.42 | 16-17,31-32,42-50 
  CronPill.tsx     |     100 |    93.75 |     100 |     100 | 19                
  ...ification.tsx |      84 |       60 |     100 |      84 | 23-24,40-42       
  ...gProfiler.tsx |       0 |        0 |       0 |       0 | 1-36              
  ...ogManager.tsx |   11.28 |      100 |       0 |   11.28 | 71-598            
  DiffDialog.tsx   |    53.5 |     37.5 |   69.23 |    53.5 | ...32-737,747-760 
  ...ngsDialog.tsx |    8.44 |      100 |       0 |    8.44 | 37-195            
  EffortDialog.tsx |   97.36 |      100 |     100 |   97.36 | 55-56             
  ExitWarning.tsx  |     100 |      100 |     100 |     100 |                   
  ...hProgress.tsx |    87.8 |    33.33 |     100 |    87.8 | 28-31,56          
  ...gsDisplay.tsx |     100 |    96.87 |   83.33 |     100 | 69                
  ...ustDialog.tsx |     100 |      100 |     100 |     100 |                   
  Footer.tsx       |   81.27 |    69.23 |      50 |   81.27 | ...06,245,267-272 
  GoalPill.tsx     |   93.51 |    81.81 |     100 |   93.51 | 37-38,106-109,123 
  Header.tsx       |   98.65 |    94.73 |     100 |   98.65 | 173,175           
  Help.tsx         |   98.33 |       90 |     100 |   98.33 | ...25,382,448-449 
  ...emDisplay.tsx |   79.69 |    67.61 |     100 |   79.69 | ...17,520,523-529 
  ...ngeDialog.tsx |     100 |      100 |     100 |     100 |                   
  InputPrompt.tsx  |   86.36 |    83.41 |      80 |   86.36 | ...2242,2263,2366 
  ...Shortcuts.tsx |     100 |       88 |     100 |     100 | 98,119            
  ...Indicator.tsx |   98.18 |    97.82 |     100 |   98.18 | 161-162           
  ...firmation.tsx |   91.42 |      100 |      50 |   91.42 | 26-31             
  MainContent.tsx  |   95.88 |    96.03 |   46.15 |   95.88 | ...20,523-527,530 
  MemoryDialog.tsx |   86.59 |    80.15 |     100 |   86.59 | ...34-435,485,553 
  ModelDialog.tsx  |   85.22 |    74.17 |     100 |   85.22 | ...1042,1098,1100 
  ...tsDisplay.tsx |     100 |    97.22 |     100 |     100 | 270               
  ...fications.tsx |   16.66 |      100 |       0 |   16.66 | 14-56             
  ...onsDialog.tsx |    2.13 |      100 |       0 |    2.13 | 62-133,148-1004   
  ...ryDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...icePrompt.tsx |   92.64 |    85.71 |     100 |   92.64 | 102-106,134-139   
  PrepareLabel.tsx |   91.66 |    77.27 |     100 |   91.66 | 73-75,77-79,110   
  ...atePrompt.tsx |   91.34 |       70 |     100 |   91.34 | 48-51,63-66,78    
  ...geDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...ngDisplay.tsx |   21.42 |      100 |       0 |   21.42 | 13-39             
  ...hProgress.tsx |   85.25 |    88.46 |     100 |   85.25 | 121-147           
  ...ngSpinner.tsx |   67.85 |    85.71 |      50 |   67.85 | 33-50,71,78-79    
  ...dSelector.tsx |   92.79 |    82.65 |     100 |   92.79 | ...19-323,354-370 
  ...ionPicker.tsx |   83.66 |    72.13 |     100 |   83.66 | ...96,402,444-466 
  ...onPreview.tsx |   93.58 |    83.78 |     100 |   93.58 | ...,70-71,195-197 
  ...ryDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...putPrompt.tsx |   92.06 |    86.36 |   83.33 |   92.06 | ...,70-72,120-123 
  ...tedDialog.tsx |     100 |      100 |     100 |     100 |                   
  ...ngsDialog.tsx |   71.55 |    73.89 |   69.23 |   71.55 | ...1252,1258-1259 
  ...ionDialog.tsx |    92.3 |    96.15 |   33.33 |    92.3 | 60-63,68-75,164   
  ...putPrompt.tsx |    15.9 |      100 |       0 |    15.9 | 20-63             
  ...Indicator.tsx |   57.14 |      100 |       0 |   57.14 | 12-15             
  ...MoreLines.tsx |      28 |      100 |       0 |      28 | 18-40             
  ...iewDialog.tsx |   97.77 |    87.67 |     100 |   97.77 | ...97,305-307,324 
  ...tsDisplay.tsx |   95.86 |       75 |     100 |   95.86 | 67-71             
  ...ionPicker.tsx |       0 |        0 |       0 |       0 | 1-171             
  ...tivityTab.tsx |    3.94 |      100 |       0 |    3.94 | 27-275            
  StatsDialog.tsx  |    8.64 |      100 |       0 |    8.64 | ...76-111,130-322 
  StatsDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...ciencyTab.tsx |    78.9 |    56.52 |     100 |    78.9 | ...26,213,262-288 
  ...atmapView.tsx |    8.98 |      100 |       0 |    8.98 | 20-107            
  ...essionTab.tsx |      80 |    66.66 |     100 |      80 | ...70-277,283-300 
  ...ineDialog.tsx |    93.9 |    86.88 |     100 |    93.9 | ...20,282,302-304 
  ...yTodoList.tsx |   96.36 |    88.23 |     100 |   96.36 | 138-141           
  ...nsDisplay.tsx |   96.01 |    88.05 |     100 |   96.01 | ...29-130,295-297 
  ...inalImage.tsx |     100 |    93.93 |     100 |     100 | 75,129            
  ThemeDialog.tsx  |   89.95 |    46.15 |      75 |   89.95 | ...71-173,243-245 
  Tips.tsx         |   93.54 |       75 |     100 |   93.54 | 39-40             
  TodoDisplay.tsx  |     100 |      100 |     100 |     100 |                   
  ...tsDisplay.tsx |     100 |     87.5 |     100 |     100 | 31-32             
  TrustDialog.tsx  |     100 |    83.33 |     100 |     100 | 72-87             
  ...ification.tsx |   36.36 |      100 |       0 |   36.36 | 15-22             
  ...Indicator.tsx |    92.5 |     87.5 |     100 |    92.5 | 50-53             
  ...ackDialog.tsx |    7.84 |      100 |       0 |    7.84 | 24-134            
  ...xitDialog.tsx |   80.36 |    43.47 |      60 |   80.36 | ...24-238,248-251 
  ...odeVisuals.ts |   97.22 |    85.71 |     100 |   97.22 | 25                
  ...s-helpers.tsx |   66.25 |    81.25 |      50 |   66.25 | 25-32,46-53,62-72 
 ...nts/agent-view |    61.5 |    75.57 |    62.5 |    61.5 |                   
  ...atContent.tsx |    9.09 |      100 |       0 |    9.09 | 54-275,281-283    
  ...tChatView.tsx |     100 |    81.81 |     100 |     100 | 82                
  ...tComposer.tsx |   78.35 |     64.7 |   66.66 |   78.35 | ...64,277,303-305 
  AgentFooter.tsx  |   15.38 |      100 |       0 |   15.38 | 28-65             
  AgentHeader.tsx  |   15.38 |      100 |       0 |   15.38 | 27-64             
  AgentTabBar.tsx  |    87.9 |    63.88 |     100 |    87.9 | ...88,110-118,136 
  ...oryAdapter.ts |     100 |    91.83 |     100 |     100 | 103,109-110,138   
  index.ts         |       0 |        0 |       0 |       0 | 1-12              
 ...mponents/arena |   45.51 |    70.53 |   60.86 |   45.51 |                   
  ArenaCards.tsx   |   73.06 |    71.79 |   85.71 |   73.06 | ...83-185,321-326 
  ...ectDialog.tsx |   83.48 |    69.86 |   88.88 |   83.48 | ...88-392,409-410 
  ...artDialog.tsx |    9.77 |      100 |       0 |    9.77 | 27-166            
  ...tusDialog.tsx |    5.63 |      100 |       0 |    5.63 | 33-75,80-288      
  ...topDialog.tsx |    6.17 |      100 |       0 |    6.17 | 33-213            
 ...ackground-view |   85.86 |     85.1 |   92.98 |   85.86 |                   
  ...sksDialog.tsx |   82.66 |    83.09 |   85.71 |   82.66 | ...1854,1977-1983 
  ...TasksPill.tsx |   78.84 |    94.28 |     100 |   78.84 | 64,109-129        
  ...gentPanel.tsx |   97.08 |    86.31 |     100 |   97.08 | 132,442-446,520   
  agent-forest.ts  |    99.2 |    93.93 |     100 |    99.2 | 258               
  ...Visibility.ts |     100 |      100 |     100 |     100 |                   
  ...e-overlay.tsx |    88.2 |    76.47 |     100 |    88.2 | ...36-138,140-142 
 ...nts/extensions |   84.32 |    76.78 |   83.33 |   84.32 |                   
  ...gerDialog.tsx |   82.15 |    76.08 |     100 |   82.15 | ...91-198,258,260 
  TabBar.tsx       |   97.29 |    88.88 |     100 |   97.29 | 33                
  index.ts         |       0 |        0 |       0 |       0 | 1-12              
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...tensions/steps |   46.26 |       85 |   58.82 |   46.26 |                   
  ...ctionStep.tsx |   95.12 |    92.85 |   85.71 |   95.12 | 84-86,89          
  ...etailStep.tsx |       0 |        0 |       0 |       0 | 1-145             
  ...nListStep.tsx |   75.26 |    88.37 |   66.66 |   75.26 | ...53,174,203-209 
  ...electStep.tsx |       0 |        0 |       0 |       0 | 1-83              
  ...nfirmStep.tsx |   16.32 |      100 |       0 |   16.32 | 28-74             
  index.ts         |       0 |        0 |       0 |       0 | 1-11              
 ...xtensions/tabs |   71.92 |    68.21 |   70.83 |   71.92 |                   
  DiscoverTab.tsx  |   68.22 |    67.66 |   55.55 |   68.22 | ...93,656-660,664 
  InstalledTab.tsx |   75.49 |    67.44 |   83.33 |   75.49 | ...77,782-783,820 
  SourcesTab.tsx   |   71.67 |    70.47 |   77.77 |   71.67 | ...28,547,621-633 
 ...tensions/views |    50.7 |    52.38 |   20.83 |    50.7 |                   
  ...tionsView.tsx |   73.75 |    56.36 |   66.66 |   73.75 | ...30,353,369-374 
  ...tionsView.tsx |   43.45 |    44.82 |    6.66 |   43.45 | ...98-405,408-420 
  ...etailView.tsx |    9.24 |      100 |       0 |    9.24 | 40-67,70-163      
 ...mponents/hooks |   87.11 |    81.37 |   91.89 |   87.11 |                   
  ...rListBody.tsx |   95.29 |    85.18 |     100 |   95.29 | 95-98             
  ...etailStep.tsx |   75.32 |    71.42 |      60 |   75.32 | ...56-169,173-186 
  ...etailStep.tsx |     100 |      100 |     100 |     100 |                   
  ...rListStep.tsx |     100 |      100 |     100 |     100 |                   
  ...entHeader.tsx |     100 |    85.71 |     100 |     100 | 47                
  ...rListStep.tsx |     100 |      100 |     100 |     100 |                   
  ...etailStep.tsx |     100 |      100 |     100 |     100 |                   
  ...abledStep.tsx |     100 |      100 |     100 |     100 |                   
  ...sListStep.tsx |     100 |      100 |     100 |     100 |                   
  ...entDialog.tsx |   72.29 |    70.49 |     100 |   72.29 | ...51,563-568,572 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-13              
  ...erGrouping.ts |     100 |      100 |     100 |     100 |                   
  sourceLabels.ts  |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...components/mcp |   40.91 |    63.44 |   70.58 |   40.91 |                   
  ...ealthPill.tsx |     100 |      100 |     100 |     100 |                   
  ...entDialog.tsx |   32.09 |    26.19 |      40 |   32.09 | ...12,914,927-933 
  ...valDialog.tsx |   15.06 |      100 |       0 |   15.06 | 40-109            
  constants.ts     |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-35              
  types.ts         |     100 |      100 |     100 |     100 |                   
  utils.ts         |      97 |       95 |     100 |      97 | 24,113-114        
 ...ents/mcp/steps |   53.94 |    73.51 |   57.14 |   53.94 |                   
  ...icateStep.tsx |    5.65 |      100 |       0 |    5.65 | 40-66,69-308      
  ...electStep.tsx |   10.95 |      100 |       0 |   10.95 | 16-88             
  ...etailStep.tsx |     100 |      100 |     100 |     100 |                   
  ...eListStep.tsx |   99.09 |    97.36 |     100 |   99.09 | 71                
  ...etailStep.tsx |   62.83 |       60 |   33.33 |   62.83 | ...87-296,307-332 
  ...rListStep.tsx |   88.53 |    81.25 |     100 |   88.53 | ...64,170,175-180 
  ...etailStep.tsx |    10.3 |      100 |       0 |    10.3 | ...1,67-79,82-140 
  ToolListStep.tsx |   69.29 |       50 |     100 |   69.29 | ...23,126,135-144 
 ...nents/messages |   90.83 |    87.76 |   86.53 |   90.83 |                   
  ...orMessage.tsx |     100 |      100 |     100 |     100 |                   
  ...ionDialog.tsx |   89.23 |     84.9 |   81.81 |   89.23 | ...75,593,611-613 
  BtwMessage.tsx   |     100 |      100 |     100 |     100 |                   
  ...upDisplay.tsx |     100 |    94.73 |     100 |     100 | ...43,289,402,432 
  ...onMessage.tsx |     100 |      100 |     100 |     100 |                   
  ...nMessages.tsx |   94.11 |    95.91 |   76.92 |   94.11 | ...47-349,352-355 
  DiffRenderer.tsx |   93.17 |    86.02 |     100 |   93.17 | ...07,235-236,302 
  ...tsDisplay.tsx |   97.08 |    77.77 |     100 |   97.08 | 95,97,106         
  ...usMessage.tsx |   81.73 |     65.9 |      75 |   81.73 | ...10-214,222,245 
  ...tsDisplay.tsx |   95.52 |    88.31 |     100 |   95.52 | ...40,142,175-180 
  ...ssMessage.tsx |    12.5 |      100 |       0 |    12.5 | 18-59             
  ...edMessage.tsx |   21.05 |      100 |       0 |   21.05 | 23-39             
  ...sMessages.tsx |   59.04 |       50 |    37.5 |   59.04 | ...21-126,147-159 
  ...ryMessage.tsx |   13.63 |      100 |       0 |   13.63 | 23-64             
  ...onMessage.tsx |   91.87 |    82.51 |     100 |   91.87 | ...49-651,658-660 
  ...upMessage.tsx |   98.38 |    95.38 |     100 |   98.38 | 188-191,422       
  ToolMessage.tsx  |   95.04 |    89.55 |     100 |   95.04 | ...1075,1120-1122 
 ...ponents/shared |   86.34 |    82.18 |    86.6 |   86.34 |                   
  ...ctionList.tsx |     100 |      100 |      75 |     100 |                   
  ...tonSelect.tsx |     100 |      100 |     100 |     100 |                   
  ...rBoundary.tsx |     100 |      100 |     100 |     100 |                   
  MaxSizedBox.tsx  |   84.71 |    86.95 |      90 |   84.71 | ...67-568,685-686 
  MultiSelect.tsx  |   93.58 |       75 |     100 |   93.58 | ...43,199-201,211 
  ...tonSelect.tsx |     100 |      100 |     100 |     100 |                   
  ...ontroller.tsx |     100 |      100 |     100 |     100 |                   
  ...eSelector.tsx |     100 |       60 |     100 |     100 | 40-45             
  ...lableList.tsx |   90.37 |    82.85 |   18.18 |   90.37 | ...60-63,65,73-76 
  StaticRender.tsx |     100 |      100 |     100 |     100 |                   
  TextInput.tsx    |    80.8 |    67.79 |      80 |    80.8 | ...36-240,252-258 
  ...ontroller.tsx |     100 |    81.81 |     100 |     100 | 59-62             
  ...apsedTime.tsx |     100 |      100 |     100 |     100 |                   
  ...Indicator.tsx |     100 |      100 |     100 |     100 |                   
  ...lizedList.tsx |   91.49 |    86.66 |   83.33 |   91.49 | ...18-846,859,959 
  text-buffer.ts   |   85.98 |    81.78 |   97.91 |   85.98 | ...2664,2762-2763 
  ...er-actions.ts |   73.93 |    67.22 |     100 |   73.93 | ...32-733,934-936 
 ...ponents/skills |    3.99 |      100 |       0 |    3.99 |                   
  ...gerDialog.tsx |    3.99 |      100 |       0 |    3.99 | 79-137,140-678    
 ...ents/subagents |   30.87 |        0 |       0 |   30.87 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-11              
  reducers.tsx     |    12.1 |      100 |       0 |    12.1 | 33-190            
  types.ts         |     100 |      100 |     100 |     100 |                   
  utils.ts         |   10.95 |      100 |       0 |   10.95 | ...1,56-57,60-102 
 ...bagents/create |    9.13 |      100 |       0 |    9.13 |                   
  ...ionWizard.tsx |    7.28 |      100 |       0 |    7.28 | 34-299            
  ...rSelector.tsx |   14.75 |      100 |       0 |   14.75 | 26-85             
  ...onSummary.tsx |    4.26 |      100 |       0 |    4.26 | 27-331            
  ...tionInput.tsx |    8.63 |      100 |       0 |    8.63 | 23-177            
  ...dSelector.tsx |   33.33 |      100 |       0 |   33.33 | 20-21,26-27,36-63 
  ...nSelector.tsx |    37.5 |      100 |       0 |    37.5 | 20-21,26-27,36-58 
  ...EntryStep.tsx |   12.76 |      100 |       0 |   12.76 | 34-78             
  ToolSelector.tsx |    4.16 |      100 |       0 |    4.16 | 31-253            
 ...bagents/manage |    21.6 |    59.52 |   27.27 |    21.6 |                   
  ...ctionStep.tsx |   10.25 |      100 |       0 |   10.25 | 21-103            
  ...eleteStep.tsx |   20.93 |      100 |       0 |   20.93 | 23-62             
  ...tEditStep.tsx |   25.53 |      100 |       0 |   25.53 | ...2,37-38,51-124 
  ...ctionStep.tsx |   35.61 |    59.52 |     100 |   35.61 | ...21-433,438-440 
  ...iewerStep.tsx |   13.72 |      100 |       0 |   13.72 | 18-73             
  ...gerDialog.tsx |    6.74 |      100 |       0 |    6.74 | 35-341            
 ...mponents/views |   69.22 |    71.81 |   61.11 |   69.22 |                   
  ContextUsage.tsx |   71.49 |    64.86 |      80 |   71.49 | ...30-436,473-567 
  DoctorReport.tsx |     9.8 |      100 |       0 |     9.8 | 25-54,57-131      
  ...sionsList.tsx |   88.05 |       75 |     100 |   88.05 | 70-77             
  McpStatus.tsx    |   92.01 |     73.8 |     100 |   92.01 | ...36,175-177,262 
  SkillsList.tsx   |   20.51 |      100 |       0 |   20.51 | 17-20,27-57       
  ToolsList.tsx    |      75 |    81.81 |     100 |      75 | 39-42,59-67       
 src/ui/contexts   |   86.47 |    82.34 |   86.48 |   86.47 |                   
  ...ewContext.tsx |   91.66 |       90 |      75 |   91.66 | ...89-193,279-289 
  AppContext.tsx   |      80 |       50 |     100 |      80 | 19-20             
  ...ewContext.tsx |   93.83 |    68.51 |   42.85 |   93.83 | ...44,281-285,317 
  ...igContext.tsx |   81.81 |       50 |     100 |   81.81 | 15-16             
  ...ssContext.tsx |   85.65 |    84.85 |     100 |   85.65 | ...1612-1614,1620 
  ...owContext.tsx |   91.07 |    81.81 |     100 |   91.07 | 47-48,60-62       
  ...deContext.tsx |     100 |      100 |      50 |     100 |                   
  ...onContext.tsx |   80.77 |       80 |    92.3 |   80.77 | ...31-434,443-446 
  ...gsContext.tsx |     100 |      100 |     100 |     100 |                   
  ...usContext.tsx |     100 |      100 |     100 |     100 |                   
  ...ngContext.tsx |   71.42 |       50 |     100 |   71.42 | 17-20             
  ...utContext.tsx |   85.71 |      100 |   66.66 |   85.71 | 13-14             
  ...edContext.tsx |     100 |      100 |      50 |     100 |                   
  ...nsContext.tsx |   88.88 |       50 |     100 |   88.88 | 156-157           
  ...teContext.tsx |   86.66 |       50 |     100 |   86.66 | 237-238           
  ...deContext.tsx |      80 |     87.5 |      75 |      80 | ...11-112,118-120 
  ...rtContext.tsx |     100 |      100 |     100 |     100 |                   
 src/ui/daemon     |   89.51 |    76.92 |   95.65 |   89.51 |                   
  ...ui-adapter.ts |   89.51 |    76.92 |   95.65 |   89.51 | ...59,877-878,964 
 src/ui/editors    |   93.33 |    85.71 |   66.66 |   93.33 |                   
  ...ngsManager.ts |   93.33 |    85.71 |   66.66 |   93.33 | 49,63-64          
 src/ui/hooks      |   86.49 |    84.45 |   88.88 |   86.49 |                   
  ...dProcessor.ts |   85.53 |     85.2 |     100 |   85.53 | ...-970,1017-1018 
  ...ention-ref.ts |   97.72 |       84 |     100 |   97.72 | 65                
  keyToAnsi.ts     |    3.92 |      100 |       0 |    3.92 | 19-77             
  ...esourceRef.ts |     100 |      100 |     100 |     100 |                   
  ...completion.ts |     100 |    95.45 |     100 |     100 | 95                
  ...ention-ref.ts |     100 |      100 |     100 |     100 |                   
  ...dProcessor.ts |   94.51 |    73.58 |     100 |   94.51 | ...97-298,303-304 
  ...dProcessor.ts |   86.83 |    71.86 |   83.33 |   86.83 | ...1536,1565-1569 
  ...rt-command.ts |     100 |      100 |     100 |     100 |                   
  ...sced-flush.ts |     100 |      100 |     100 |     100 |                   
  ...llm-stream.ts |   88.85 |    85.07 |   85.18 |   88.85 | ...6260,6262,6367 
  ...ng-enabled.ts |     100 |      100 |     100 |     100 |                   
  ...oice-input.ts |   92.41 |    82.08 |   66.66 |   92.41 | ...12,514-515,670 
  ...ke-repaint.ts |     100 |      100 |     100 |     100 |                   
  ...amingState.ts |   12.22 |      100 |       0 |   12.22 | 54-157            
  ...agerDialog.ts |   88.23 |      100 |     100 |   88.23 | 20,24             
  ...dScrollbar.ts |     100 |      100 |     100 |     100 |                   
  ...ationFrame.ts |      42 |       75 |     100 |      42 | 42-44,53-59,62-87 
  ...odeCommand.ts |   58.82 |      100 |     100 |   58.82 | 28,33-48          
  ...enaCommand.ts |      85 |      100 |     100 |      85 | 23-24,29          
  ...aInProcess.ts |   27.92 |       80 |      25 |   27.92 | ...69-170,173-175 
  ...Completion.ts |   86.44 |    88.48 |     100 |   86.44 | ...14-515,525-541 
  ...ifications.ts |   87.82 |    96.77 |     100 |   87.82 | 138-152           
  ...tIndicator.ts |   88.28 |    81.57 |     100 |   88.28 | ...66,175,179-187 
  ...waySummary.ts |   96.26 |       75 |     100 |   96.26 | 126-128,170       
  ...ndTaskView.ts |   94.89 |    77.55 |     100 |   94.89 | 164-168,257,263   
  ...chedScroll.ts |     100 |      100 |     100 |     100 |                   
  ...ketedPaste.ts |    23.8 |      100 |       0 |    23.8 | 19-37             
  ...nchCommand.ts |   96.03 |    88.75 |     100 |   96.03 | ...04-205,362-365 
  ...ompletion.tsx |    97.1 |    87.23 |     100 |    97.1 | ...26-327,337-338 
  ...dMigration.ts |    92.1 |    88.88 |     100 |    92.1 | 42-44             
  useCompletion.ts |   96.64 |    91.37 |     100 |   96.64 | ...37-238,242-243 
  ...nitMessage.ts |     100 |      100 |     100 |     100 |                   
  ...extualTips.ts |   78.26 |       50 |     100 |   78.26 | ...2,75-79,96-104 
  ...eteCommand.ts |   89.52 |    90.69 |     100 |   89.52 | ...98-106,114-115 
  ...ialogClose.ts |   36.11 |       10 |     100 |   36.11 | ...89-195,202-207 
  useDiffData.ts   |   11.62 |      100 |       0 |   11.62 | 44-87             
  ...oublePress.ts |   53.12 |       75 |     100 |   53.12 | 33-35,41-54       
  ...orSettings.ts |     100 |      100 |     100 |     100 |                   
  ...Completion.ts |   99.12 |    97.64 |     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       
  ...BranchName.ts |     100 |    94.44 |     100 |     100 | 54                
  ...oryManager.ts |   98.44 |     98.9 |     100 |   98.44 | 157-160           
  ...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    
  useKeypress.ts   |     100 |      100 |     100 |     100 |                   
  ...rdProtocol.ts |   36.36 |      100 |       0 |   36.36 | 24-31             
  ...unchEditor.ts |   22.58 |      100 |      50 |   22.58 | 11-32,44-85       
  ...gIndicator.ts |     100 |    96.66 |     100 |     100 | 109               
  useLogger.ts     |      16 |      100 |       0 |      16 | 15-45             
  useMCPHealth.ts  |   10.52 |      100 |       0 |   10.52 | 36-75             
  ...cpApproval.ts |   93.12 |    86.11 |     100 |   93.12 | ...24-127,139-140 
  useMcpDialog.ts  |    87.5 |      100 |     100 |    87.5 | 19,23             
  ...moryDialog.ts |    87.5 |      100 |     100 |    87.5 | 19,23             
  ...oryMonitor.ts |   83.14 |    78.57 |     100 |   83.14 | 54-63,74-79       
  ...ssageQueue.ts |     100 |    95.19 |     100 |     100 | ...53,289,360,375 
  ...delCommand.ts |     100 |       96 |     100 |     100 | 61                
  ...ouseEvents.ts |   94.89 |       95 |   83.33 |   94.89 | 78-82             
  ...raseCycler.ts |   84.74 |    76.47 |     100 |   84.74 | ...49,52-53,69-71 
  ...rredEditor.ts |   58.33 |    22.22 |     100 |   58.33 | 23-27,29-33       
  ...derUpdates.ts |   89.16 |     82.6 |     100 |   89.16 | ...77,329-339,419 
  useQwenAuth.ts   |     100 |      100 |     100 |     100 |                   
  ...lScheduler.ts |   89.13 |     86.9 |     100 |   89.13 | ...61-463,496-506 
  ...oryCommand.ts |       0 |        0 |       0 |       0 | 1-7               
  ...umeCommand.ts |   96.51 |    90.19 |     100 |   96.51 | 279,306-311       
  ...ompletion.tsx |   90.67 |    83.33 |     100 |   90.67 | ...02,105,138-141 
  ...ectionList.ts |   97.12 |    96.19 |     100 |   97.12 | ...92-193,247-250 
  ...sionPicker.ts |   92.87 |    90.35 |     100 |   92.87 | ...99-501,503-505 
  ...earchInput.ts |     100 |    97.29 |     100 |     100 | 82                
  ...ngsCommand.ts |   18.75 |      100 |       0 |   18.75 | 10-25             
  ...ellHistory.ts |   93.28 |    80.95 |     100 |   93.28 | ...96,153-154,164 
  ...oryCommand.ts |   85.48 |    58.33 |     100 |   85.48 | 22-28,40,71       
  ...agerDialog.ts |   88.23 |      100 |     100 |   88.23 | 20,24             
  ...Completion.ts |   82.79 |    85.33 |   94.73 |   82.79 | ...86-688,696-732 
  ...tateAndRef.ts |     100 |      100 |     100 |     100 |                   
  ...tatsDialog.ts |     100 |      100 |     100 |     100 |                   
  useStatusLine.ts |   97.32 |    93.93 |     100 |   97.32 | ...18-422,518-525 
  ...eateDialog.ts |   88.23 |      100 |     100 |   88.23 | 14,18             
  ...mInProcess.ts |   27.35 |       80 |      25 |   27.35 | ...82-183,186-188 
  ...tification.ts |     100 |     87.5 |     100 |     100 | 50                
  ...alProgress.ts |   67.34 |    58.82 |   66.66 |   67.34 | 52-53,61-68,79-85 
  ...rminalSize.ts |     100 |      100 |     100 |     100 |                   
  ...emeCommand.ts |    79.2 |    35.29 |     100 |    79.2 | ...15-116,120-121 
  useTimer.ts      |   97.59 |    94.73 |     100 |   97.59 | 17-18             
  ...lMigration.ts |       0 |        0 |       0 |       0 |                   
  ...rustModify.ts |     100 |    90.47 |     100 |     100 | 112,134           
  useTurnDiffs.ts  |   95.12 |    78.57 |     100 |   95.12 | 133-134,156-157   
  ...elcomeBack.ts |   87.36 |     90.9 |     100 |   87.36 | ...,94-96,114-115 
  ...reeSession.ts |   93.75 |       70 |     100 |   93.75 | 47-48,72          
  vim.ts           |      74 |    67.56 |   69.23 |      74 | ...1854-1861,1869 
 src/ui/layouts    |   91.25 |    89.47 |     100 |   91.25 |                   
  ...AppLayout.tsx |   90.99 |     87.5 |     100 |   90.99 | 61-63,111-116,152 
  ...AppLayout.tsx |   91.66 |    92.85 |     100 |   91.66 | 75-80             
 src/ui/model      |   97.91 |    98.36 |     100 |   97.91 |                   
  ...ggregation.ts |     100 |      100 |     100 |     100 |                   
  ...ming-model.ts |   97.43 |    97.72 |     100 |   97.43 | 261-265           
 src/ui/models     |   80.72 |       80 |   71.42 |   80.72 |                   
  ...ableModels.ts |   80.72 |       80 |   71.42 |   80.72 | ...,61-71,125-127 
 ...noninteractive |     100 |      100 |    6.66 |     100 |                   
  ...eractiveUi.ts |     100 |      100 |    6.66 |     100 |                   
 src/ui/selection  |   93.56 |    86.19 |     100 |   93.56 |                   
  screen-buffer.ts |   94.73 |    66.66 |     100 |   94.73 | 51-52             
  ...ion-coords.ts |     100 |      100 |     100 |     100 |                   
  ...ction-span.ts |   93.81 |     92.1 |     100 |   93.81 | ...1,45-46,99-100 
  ...tion-state.ts |     100 |      100 |     100 |     100 |                   
  ...ction-text.ts |   93.85 |    93.44 |     100 |   93.85 | 30-34,130-131     
  ...selection.tsx |   91.88 |    78.57 |     100 |   91.88 | ...16-417,446-447 
 src/ui/state      |      95 |    81.81 |     100 |      95 |                   
  extensions.ts    |      95 |    81.81 |     100 |      95 | 69-70,89          
 src/ui/themes     |    98.5 |    73.06 |     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.33 |     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      |   88.06 |    86.02 |   96.14 |   88.06 |                   
  ...Colorizer.tsx |   80.31 |    85.41 |     100 |   80.31 | ...00-201,313-339 
  ...nRenderer.tsx |   80.07 |     75.6 |     100 |   80.07 | ...70,274,332-333 
  ...wnDisplay.tsx |   92.87 |     93.5 |     100 |   92.87 | ...,955,1002-1020 
  ...idDiagram.tsx |   87.79 |    95.34 |     100 |   87.79 | 156-179           
  ...eRenderer.tsx |   93.63 |    81.77 |   95.23 |   93.63 | ...47-750,803-808 
  ...odeDisplay.ts |   94.28 |    85.71 |     100 |   94.28 | 23,40             
  asciiCharts.ts   |    96.7 |     87.5 |     100 |    96.7 | 170-177,278       
  ...dWorkUtils.ts |     100 |      100 |     100 |     100 |                   
  ...boardUtils.ts |    52.9 |    74.15 |    92.3 |    52.9 | ...29,632-641,644 
  commandUtils.ts  |   98.61 |    93.27 |     100 |   98.61 | 189,217-218,424   
  ...ssion-text.ts |   90.54 |    71.42 |     100 |   90.54 | 66-68,80,82,90-91 
  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 
  ...coalescing.ts |     100 |      100 |     100 |     100 |                   
  formatters.ts    |   94.87 |    98.24 |     100 |   94.87 | 116-119           
  goal-runtime.ts  |   94.44 |    96.29 |     100 |   94.44 | 32-34             
  gradientUtils.ts |     100 |      100 |     100 |     100 |                   
  highlight.ts     |     100 |      100 |     100 |     100 |                   
  ...gap-notice.ts |     100 |      100 |     100 |     100 |                   
  ...oryMapping.ts |     100 |    95.65 |     100 |     100 | 45,151            
  historyUtils.ts  |   96.07 |     97.1 |     100 |   96.07 | 104-107           
  ...mage-parts.ts |   97.75 |       95 |     100 |   97.75 | 82-83             
  inline-math.ts   |   98.48 |    95.23 |     100 |   98.48 | 129-130           
  input-mouse.ts   |     100 |    85.71 |     100 |     100 | 48,93             
  isNarrowWidth.ts |     100 |      100 |     100 |     100 |                   
  ...olDetector.ts |   68.81 |       75 |   66.66 |   68.81 | ...27-132,160-161 
  latexRenderer.ts |   94.95 |     73.8 |     100 |   94.95 | ...76-178,184-187 
  layoutUtils.ts   |     100 |      100 |     100 |     100 |                   
  list-mouse.ts    |     100 |      100 |     100 |     100 |                   
  ...ightLoader.ts |     100 |       95 |     100 |     100 | 81                
  ...nUtilities.ts |   98.72 |    94.36 |     100 |   98.72 | 145-146           
  ...t-position.ts |     100 |     87.5 |     100 |     100 | 85                
  ...geRenderer.ts |   86.51 |    70.16 |   95.12 |   86.51 | ...1286,1326-1332 
  ...alRenderer.ts |   86.69 |     71.9 |     100 |   86.69 | ...1476,1513-1519 
  ...lsBySource.ts |     100 |    95.23 |     100 |     100 | 84                
  mouse-hit.ts     |     100 |     90.9 |     100 |     100 | 62-64             
  mouse.ts         |   92.85 |    74.19 |     100 |   92.85 | ...38,145,149-152 
  osc8.ts          |   91.33 |    79.03 |     100 |   91.33 | ...73,273,277-278 
  ...red-height.ts |   98.38 |    97.14 |     100 |   98.38 | 195-197           
  ...mConstants.ts |     100 |      100 |     100 |     100 |                   
  restoreGoal.ts   |     100 |      100 |     100 |     100 |                   
  ...storyUtils.ts |   84.37 |    81.09 |     100 |   84.37 | ...03-625,759-760 
  ...ickerUtils.ts |     100 |      100 |     100 |     100 |                   
  ...evel-label.ts |   77.77 |    66.66 |     100 |   77.77 | 18,22-24          
  ...are-cursor.ts |      90 |     87.5 |     100 |      90 | 39-44             
  ...ataService.ts |   93.17 |     79.1 |     100 |   93.17 | ...14,227,254-256 
  suggestions.ts   |     100 |      100 |     100 |     100 |                   
  ...izedOutput.ts |   95.19 |      100 |   88.88 |   95.19 | 121-126           
  ...nal-buffer.ts |     100 |      100 |     100 |     100 |                   
  ...e-renderer.ts |   90.61 |    83.44 |     100 |   90.61 | ...80,482-484,607 
  ...ize-reflow.ts |     100 |     92.3 |     100 |     100 | 57,62,209,217,347 
  ...wOptimizer.ts |     100 |    94.73 |     100 |     100 | 35,78             
  terminalSetup.ts |    4.37 |      100 |       0 |    4.37 | 44-393            
  textUtils.ts     |   98.71 |    95.72 |     100 |   98.71 | 292-293,478-479   
  ...background.ts |     100 |      100 |     100 |     100 |                   
  todoSnapshot.ts  |   95.81 |     92.3 |     100 |   95.81 | ...09-210,243-244 
  ...isplay-map.ts |     100 |      100 |     100 |     100 |                   
  updateCheck.ts   |     100 |    92.75 |     100 |     100 | 227-239,331       
  windowTitle.ts   |   96.55 |    94.73 |     100 |   96.55 | 56-57             
  ...ow-keyword.ts |     100 |      100 |     100 |     100 |                   
 ...i/utils/export |   75.03 |     60.1 |   94.59 |   75.03 |                   
  collect.ts       |   71.27 |    65.81 |      96 |   71.27 | ...90-633,655-656 
  index.ts         |     100 |      100 |     100 |     100 |                   
  normalize.ts     |   80.42 |    51.35 |     100 |   80.42 | ...59-364,376-378 
  types.ts         |       0 |        0 |       0 |       0 | 1                 
  utils.ts         |     100 |      100 |     100 |     100 |                   
 ...ort/formatters |   52.92 |    47.22 |   71.42 |   52.92 |                   
  html.ts          |   84.61 |       50 |     100 |   84.61 | ...53,57-58,62-63 
  json.ts          |     100 |      100 |     100 |     100 |                   
  jsonl.ts         |   82.45 |     37.5 |     100 |   82.45 | ...48,50-51,65-66 
  markdown.ts      |   36.32 |    47.05 |      50 |   36.32 | ...16-219,233-295 
 src/ui/voice      |   81.24 |    79.78 |   81.69 |   81.24 |                   
  ...d-recorder.ts |     6.2 |      100 |       0 |     6.2 | ...33-159,162-163 
  ...o-recorder.ts |   84.61 |    93.33 |   57.14 |   84.61 | ...16-117,131-136 
  ...me-session.ts |   91.09 |     92.1 |     100 |   91.09 | ...99,305,316-319 
  sox-recorder.ts  |    92.7 |    71.87 |     100 |    92.7 | ...34-135,153-154 
  ...ailability.ts |     100 |      100 |     100 |     100 |                   
  ...e-keyterms.ts |     100 |      100 |     100 |     100 |                   
  voice-model.ts   |     100 |      100 |     100 |     100 |                   
  ...e-recorder.ts |   88.29 |    67.74 |   81.81 |   88.29 | ...,98-99,112,115 
  voice-refine.ts  |     100 |    93.33 |     100 |     100 | 92                
  ...ream-retry.ts |   86.79 |       70 |     100 |   86.79 | 16-18,48-49,59-60 
  ...am-session.ts |   88.02 |    66.66 |   84.61 |   88.02 | ...26,343-345,363 
  ...ranscriber.ts |     100 |      100 |     100 |     100 |                   
 src/utils         |   92.33 |    90.04 |   96.14 |   92.33 |                   
  ...p-profiler.ts |   98.39 |    92.59 |     100 |   98.39 | 141,185,235       
  acpModelUtils.ts |   97.36 |    95.14 |     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       
  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        
  ...y-identity.ts |   89.38 |    85.32 |     100 |   89.38 | ...48-449,456-457 
  ...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 | 50-52,58          
  ...re-runtime.ts |     100 |      100 |     100 |     100 |                   
  ...putCapture.ts |   90.65 |    86.31 |     100 |   90.65 | ...73,371,373-374 
  ...arResolver.ts |   97.14 |    96.55 |     100 |   97.14 | 125-126           
  errors.ts        |   97.56 |    94.64 |     100 |   97.56 | 69-70,304-305     
  events.ts        |     100 |      100 |     100 |     100 |                   
  ...on-mention.ts |   88.48 |     82.6 |     100 |   88.48 | ...56-160,164-168 
  gitUtils.ts      |   92.85 |    86.66 |     100 |   92.85 | ...13-116,164-167 
  ...tyWarnings.ts |     100 |      100 |     100 |     100 |                   
  ...lationInfo.ts |   97.81 |    94.69 |     100 |   97.81 | ...03,420-421,466 
  ...projection.ts |   95.27 |    95.58 |     100 |   95.27 | 140-145           
  jsonc-editor.ts  |   93.18 |    92.66 |     100 |   93.18 | ...80-381,384-385 
  load-undici.ts   |     100 |      100 |     100 |     100 |                   
  ...npm-update.ts |   86.64 |    77.02 |     100 |   86.64 | ...03-304,335-345 
  math.ts          |       0 |        0 |       0 |       0 | 1-15              
  ...er-mention.ts |     100 |    66.66 |     100 |     100 | 14,30,44-46       
  ...iagnostics.ts |   94.57 |    83.01 |   88.88 |   94.57 | ...05,311,315-317 
  ...serMessage.ts |     100 |      100 |     100 |     100 |                   
  ...onfigUtils.ts |   96.05 |    93.79 |     100 |   96.05 | ...,85-86,334,443 
  ...-part-list.ts |     100 |      100 |     100 |     100 |                   
  osc.ts           |   97.18 |      100 |    87.5 |   97.18 | 182-183           
  package.ts       |   88.88 |    85.71 |     100 |   88.88 | 31-32             
  paths.ts         |     100 |      100 |     100 |     100 |                   
  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 |                   
  ...xImageName.ts |     100 |    77.77 |     100 |     100 | 10,18             
  sandboxMounts.ts |     100 |      100 |     100 |     100 |                   
  ...-path-argv.ts |     100 |      100 |     100 |     100 |                   
  sessionPaths.ts  |   90.84 |    90.56 |     100 |   90.84 | ...81-182,185-186 
  shell-args.ts    |     100 |      100 |     100 |     100 |                   
  spawnWrapper.ts  |     100 |      100 |     100 |     100 |                   
  ...ate-verify.ts |     100 |      100 |     100 |     100 |                   
  ...upProfiler.ts |   98.47 |    94.66 |     100 |   98.47 | 132-133,308       
  ...upWarnings.ts |     100 |      100 |     100 |     100 |                   
  stdioHelpers.ts  |   76.66 |       90 |   83.33 |   76.66 | 93-99             
  ...alSequence.ts |     100 |    97.61 |     100 |     100 | 60                
  ...iffPreview.ts |   76.47 |       25 |     100 |   76.47 | 13,17,23-24       
  ...on-handler.ts |    73.8 |       75 |     100 |    73.8 | 17-18,25-26,67-73 
  ...entEmitter.ts |     100 |      100 |     100 |     100 |                   
  ...ansionHook.ts |     100 |      100 |     100 |     100 |                   
  ...upWarnings.ts |   87.75 |       75 |     100 |   87.75 | 47-48,53-54,57-58 
  version.ts       |     100 |    66.66 |     100 |     100 | 11                
  ...ingHandler.ts |     100 |      100 |     100 |     100 |                   
  ...WithBackup.ts |   65.04 |    77.77 |     100 |   65.04 | 97,112,133-172    
 ...s/housekeeping |   94.35 |    94.11 |     100 |   94.35 |                   
  cleanup.ts       |   92.59 |    93.75 |     100 |   92.59 | ...02-205,209-211 
  ...eractionAt.ts |     100 |      100 |     100 |     100 |                   
  throttledOnce.ts |   95.95 |    93.93 |     100 |   95.95 | 77-78,153-154     
-------------------|---------|----------|---------|---------|-------------------
Core Package - Full Text Report
-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |    88.9 |    87.31 |   90.57 |    88.9 |                   
 src               |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/__mocks__/fs  |       0 |        0 |       0 |       0 |                   
  promises.ts      |       0 |        0 |       0 |       0 | 1-48              
 src/agents        |   90.53 |    84.82 |   94.55 |   90.53 |                   
  ...transcript.ts |   88.49 |    84.09 |     100 |   88.49 | ...32,640,646-650 
  ...ent-resume.ts |   85.74 |       78 |    85.1 |   85.74 | ...1803-1807,1810 
  ...ound-tasks.ts |   95.19 |    90.75 |   96.42 |   95.19 | ...1889,1897-1898 
  forkedAgent.ts   |   95.91 |    87.12 |   94.44 |   95.91 | ...76-478,601,728 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...ent-result.ts |    96.8 |    92.68 |     100 |    96.8 | 106,129-131       
  ...n-registry.ts |   95.27 |    88.23 |   98.33 |   95.27 | ...1478,1492-1494 
  ...w-snapshot.ts |   75.73 |    72.22 |    87.5 |   75.73 | ...21,445,452-454 
  worktree-pin.ts  |     100 |    88.23 |     100 |     100 | 78,99             
 src/agents/arena  |   76.87 |    68.43 |   78.94 |   76.87 |                   
  ...gentClient.ts |   79.47 |    88.88 |   81.81 |   79.47 | ...68-183,189-204 
  ArenaManager.ts  |    75.8 |    65.46 |   78.57 |    75.8 | ...1879,1885-1886 
  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 |   77.77 |    86.68 |   75.86 |   77.77 |                   
  ITermBackend.ts  |   97.97 |    93.93 |     100 |   97.97 | ...78-180,255,307 
  ...essBackend.ts |   92.12 |    90.74 |   97.05 |   92.12 | ...37-538,666-672 
  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 |   93.39 |    87.49 |   91.59 |   93.39 |                   
  agent-context.ts |     100 |      100 |     100 |     100 |                   
  ...-test-mock.ts |   98.82 |    66.66 |   58.33 |   98.82 | 85                
  agent-core.ts    |   90.38 |    80.91 |   81.25 |   90.38 | ...2550,2596-2598 
  agent-events.ts  |     100 |      100 |     100 |     100 |                   
  ...t-headless.ts |   93.57 |    89.41 |   83.33 |   93.57 | ...04-505,508-509 
  ...nteractive.ts |   81.64 |     82.6 |      80 |   81.64 | ...33,535-538,541 
  ...statistics.ts |   98.29 |    82.55 |     100 |   98.29 | 141,165,206,239   
  agent-types.ts   |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...ool-policy.ts |   98.38 |      100 |    92.3 |   98.38 | 85-86             
  ...low-budget.ts |     100 |      100 |     100 |     100 |                   
  ...-scheduler.ts |   97.43 |    96.36 |     100 |   97.43 | 128-130           
  ...ow-journal.ts |   92.78 |    78.12 |     100 |   92.78 | ...49-150,192-194 
  ...ta-literal.ts |   95.96 |    92.68 |     100 |   95.96 | ...78-379,395-396 
  ...chestrator.ts |   93.86 |    90.47 |     100 |   93.86 | ...2213,2306-2309 
  ...ow-prompts.ts |     100 |      100 |     100 |     100 |                   
  ...low-runner.ts |   93.17 |     83.6 |      95 |   93.17 | ...14,372,392-395 
  ...ow-sandbox.ts |    97.4 |    89.37 |     100 |    97.4 | ...1846,1852-1853 
  ...flow-saved.ts |    96.7 |     93.9 |     100 |    96.7 | 153-154,261-264   
  ...flow-stall.ts |    97.9 |    83.33 |     100 |    97.9 | 170-171,270       
 src/agents/tasks  |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/agents/team   |   85.75 |     86.2 |   91.15 |   85.75 |                   
  TeamManager.ts   |   80.12 |    84.78 |   84.37 |   80.12 | ...2089,2112-2113 
  identity.ts      |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...sionBridge.ts |     100 |      100 |     100 |     100 |                   
  mailbox.ts       |   96.02 |     87.5 |     100 |   96.02 | 352-358           
  ...ptAddendum.ts |     100 |      100 |     100 |     100 |                   
  tasks.ts         |   89.29 |       83 |     100 |   89.29 | ...1000,1044-1045 
  team-events.ts   |   73.68 |      100 |   66.66 |   73.68 | 140-144,151-155   
  teamHelpers.ts   |   92.99 |    94.52 |      95 |   92.99 | ...29-330,415-425 
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...eam/test-utils |   95.28 |    95.34 |   98.24 |   95.28 |                   
  ...on-harness.ts |   96.49 |    85.71 |     100 |   96.49 | 128-129,141-142   
  fake-agent.ts    |     100 |    96.96 |     100 |     100 | 189,198           
  fake-backend.ts  |   86.46 |    97.61 |   95.83 |   86.46 | 124-146           
 src/config        |    86.3 |    88.53 |   78.38 |    86.3 |                   
  approval-mode.ts |     100 |      100 |     100 |     100 |                   
  ...xtDefaults.ts |     100 |      100 |     100 |     100 |                   
  config.ts        |   84.86 |    87.79 |   76.28 |   84.86 | ...9551,9555-9557 
  ...ionManager.ts |     100 |     90.9 |     100 |     100 | 27                
  ...ver-config.ts |   97.29 |      100 |   83.33 |   97.29 | 48-49             
  models.ts        |     100 |      100 |     100 |     100 |                   
  ...sDiscovery.ts |   97.46 |    93.05 |     100 |   97.46 | ...04,182-183,202 
  storage.ts       |   96.05 |    93.43 |   89.47 |   96.05 | ...34-735,738-739 
 ...nfirmation-bus |   98.27 |    97.22 |     100 |   98.27 |                   
  message-bus.ts   |   98.14 |    97.14 |     100 |   98.14 | 42-43             
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/core          |   92.84 |    88.69 |   93.96 |   92.84 |                   
  ...on-restore.ts |   88.23 |    85.41 |     100 |   88.23 | ...60,63-64,67-68 
  baseLlmClient.ts |    88.4 |    83.68 |   81.81 |    88.4 | ...59,672,678-680 
  client.ts        |   92.48 |    88.27 |   91.91 |   92.48 | ...4688,4786-4787 
  ...tGenerator.ts |   87.45 |    88.09 |   88.88 |   87.45 | ...09-510,555-561 
  ...lScheduler.ts |   90.22 |    84.96 |   94.73 |   90.22 | ...6488,6516-6532 
  ...entContext.ts |   96.63 |    90.13 |   96.66 |   96.63 | ...42,444-445,512 
  geminiChat.ts    |     100 |      100 |     100 |     100 |                   
  geminiRequest.ts |     100 |      100 |     100 |     100 |                   
  genai-compat.ts  |     100 |      100 |     100 |     100 |                   
  ...MediaLimit.ts |     100 |       96 |     100 |     100 | 96                
  ...htProtocol.ts |    9.09 |      100 |       0 |    9.09 | ...9,62-66,69-110 
  ...ream-error.ts |     100 |      100 |     100 |     100 |                   
  llm-chat.ts      |   95.21 |     90.8 |   96.66 |   95.21 | ...5769,5814-5815 
  llm-request.ts   |     100 |      100 |     100 |     100 |                   
  logger.ts        |   87.41 |    87.02 |     100 |   87.41 | ...64-568,614-628 
  ...lay-buffer.ts |     100 |      100 |     100 |     100 |                   
  ...dispatcher.ts |     100 |      100 |     100 |     100 |                   
  ...tyDefaults.ts |     100 |      100 |     100 |     100 |                   
  ...olExecutor.ts |   93.54 |    83.33 |      50 |   93.54 | 46-47             
  output-styles.ts |     100 |      100 |     100 |     100 |                   
  ...on-helpers.ts |   95.38 |    84.31 |     100 |   95.38 | ...87,215,217-218 
  ...issionFlow.ts |   98.98 |    96.96 |     100 |   98.98 | 109               
  ...try-policy.ts |     100 |      100 |     100 |     100 |                   
  ...ell-policy.ts |   94.89 |    88.54 |     100 |   94.89 | ...51-252,297-298 
  prompts.ts       |   93.89 |     91.2 |      85 |   93.89 | ...1272,1475-1476 
  ...ing-effort.ts |     100 |      100 |     100 |     100 |                   
  ...n-recovery.ts |   95.13 |       80 |     100 |   95.13 | ...06-107,142-144 
  ...t-profiler.ts |    97.9 |    81.15 |   88.23 |    97.9 | 117,124-125,130   
  stream-guards.ts |   91.16 |    93.18 |     100 |   91.16 | ...89,218-229,294 
  ...port-retry.ts |     100 |      100 |     100 |     100 |                   
  tokenLimits.ts   |     100 |    91.89 |     100 |     100 | 87,122-139        
  ...-arguments.ts |     100 |      100 |     100 |     100 |                   
  ...reparation.ts |     100 |      100 |     100 |     100 |                   
  ...tion-guard.ts |   90.38 |    94.73 |     100 |   90.38 | 83-87             
  ...allIdUtils.ts |   98.81 |    91.22 |     100 |   98.81 | 43,52             
  ...okTriggers.ts |   99.45 |     92.5 |     100 |   99.45 | 182,193           
  ...terruption.ts |     100 |     92.3 |     100 |     100 | 86,104            
  turn.ts          |   99.21 |    94.69 |     100 |   99.21 | 784-785,854       
  ...l-fallback.ts |     100 |      100 |     100 |     100 |                   
 ...ntentGenerator |   96.62 |    89.21 |   97.43 |   96.62 |                   
  ...tGenerator.ts |   97.71 |    89.13 |   97.43 |   97.71 | ...1539,1568,1579 
  converter.ts     |   96.19 |    89.25 |     100 |   96.19 | ...1334,1555-1557 
  index.ts         |       0 |        0 |       0 |       0 | 1-21              
  usage.ts         |     100 |      100 |     100 |     100 |                   
 ...ntentGenerator |     100 |      100 |     100 |     100 |                   
  ...tGenerator.ts |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
 ...tent-generator |   89.24 |    72.72 |   94.11 |   89.24 |                   
  index.ts         |     100 |    85.71 |     100 |     100 | 51                
  ...-generator.ts |   87.54 |    71.42 |   93.75 |   87.54 | ...93-294,356-362 
 ...ntentGenerator |   95.78 |    90.51 |   96.22 |   95.78 |                   
  ...e-snapshot.ts |   97.39 |    89.65 |     100 |   97.39 | ...,49-50,151-152 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...tGenerator.ts |   95.38 |    90.14 |   95.12 |   95.38 | ...1345-1346,1374 
  ...tDetection.ts |     100 |      100 |     100 |     100 |                   
 ...ntentGenerator |   92.41 |    90.86 |   96.33 |   92.41 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  converter.ts     |   91.25 |    89.66 |   96.87 |   91.25 | ...1946,2115-2130 
  errorHandler.ts  |     100 |      100 |     100 |     100 |                   
  index.ts         |   76.19 |    88.88 |      50 |   76.19 | 44-53,90-94       
  ...tGenerator.ts |      70 |    73.33 |     100 |      70 | ...07-112,121-127 
  pipeline.ts      |    96.3 |    91.36 |     100 |    96.3 | ...1204-1205,1312 
  ...ix-caching.ts |   95.23 |    92.85 |     100 |   95.23 | 45-46,69-70       
  ...ureContext.ts |     100 |      100 |     100 |     100 |                   
  ...ingOptions.ts |       0 |        0 |       0 |       0 | 1                 
  ...CallParser.ts |   92.11 |    92.25 |     100 |   92.11 | ...21-522,542-545 
  ...kingParser.ts |     100 |    96.87 |     100 |     100 | 42                
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...rator/provider |   97.24 |       92 |   98.64 |   97.24 |                   
  dashscope.ts     |   98.42 |    95.27 |   96.55 |   98.42 | ...51-752,894-895 
  deepseek.ts      |   95.27 |    90.56 |     100 |   95.27 | ...52-153,166-167 
  default.ts       |   98.87 |       96 |     100 |   98.87 | 178,304           
  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 |                   
  openrouter.ts    |     100 |      100 |     100 |     100 |                   
  types.ts         |       0 |        0 |       0 |       0 |                   
  utils.ts         |     100 |      100 |     100 |     100 |                   
  zai.ts           |      90 |    76.31 |     100 |      90 | ...,72-73,173-175 
 src/extension     |   89.16 |    86.49 |   93.61 |   89.16 |                   
  ...ive-safety.ts |    97.9 |     92.8 |     100 |    97.9 | 235-236,313-316   
  ...-converter.ts |   80.55 |    73.66 |     100 |   80.55 | ...1133,1179-1180 
  corruptFile.ts   |     100 |       50 |     100 |     100 | 40-45             
  ...-converter.ts |     100 |      100 |     100 |     100 |                   
  ...git-client.ts |     100 |      100 |     100 |     100 |                   
  ...redentials.ts |   95.33 |    89.47 |     100 |   95.33 | ...21-122,173-175 
  ...me-refresh.ts |     100 |      100 |     100 |     100 |                   
  ...sion-store.ts |   92.82 |     89.1 |    98.3 |   92.82 | ...1641-1647,1691 
  ...ionManager.ts |   84.96 |    84.05 |      83 |   84.96 | ...3159,3197-3198 
  ...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 |   78.91 |    86.04 |   85.71 |   78.91 | ...95,202,214-248 
  github.ts        |   92.61 |    87.44 |     100 |   92.61 | ...1310-1311,1321 
  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.16 |     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.54 |     100 |   94.11 | 63-64,81-82       
  ...-converter.ts |   94.89 |    90.41 |     100 |   94.89 | ...50-151,222-224 
  redaction.ts     |     100 |      100 |     100 |     100 |                   
  settings.ts      |   66.26 |      100 |      50 |   66.26 | 81-107,141-146    
  ...ceRegistry.ts |   94.01 |    83.33 |     100 |   94.01 | ...38-344,365-366 
  storage.ts       |     100 |      100 |     100 |     100 |                   
  ...ableSchema.ts |     100 |      100 |     100 |     100 |                   
  variables.ts     |   88.95 |    84.21 |     100 |   88.95 | ...32-235,238-241 
  ...extraction.ts |   85.77 |       81 |   89.47 |   85.77 | ...02-205,260-261 
 ...ent-plugins-v1 |   84.94 |    79.51 |     100 |   84.94 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  manifest.ts      |   81.87 |    84.48 |     100 |   81.87 | ...55-156,161-174 
  mcp.ts           |   84.98 |    79.56 |     100 |   84.98 | ...88-389,419-420 
  paths.ts         |     100 |    94.44 |     100 |     100 | 59                
  skills.ts        |   82.31 |    63.88 |     100 |   82.31 | ...38-141,150-151 
 src/followup      |   84.78 |    82.27 |   86.84 |   84.78 |                   
  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   |   76.53 |    71.96 |   58.33 |   76.53 | ...48-749,756-757 
  ...onToolGate.ts |   97.97 |     87.5 |     100 |   97.97 | 105,110           
  ...nGenerator.ts |   86.11 |    87.17 |     100 |   86.11 | ...39-244,356-358 
 src/generated     |       0 |        0 |       0 |       0 |                   
  git-commit.ts    |       0 |        0 |       0 |       0 | 1-10              
 src/goals         |   93.59 |    90.38 |      95 |   93.59 |                   
  ...eGoalStore.ts |   87.61 |    88.88 |   86.66 |   87.61 | ...85-188,196-204 
  ...t-verifier.ts |   99.45 |    97.05 |     100 |   99.45 | 155               
  ...checkpoint.ts |   86.08 |    85.18 |     100 |   86.08 | ...29-132,142-145 
  ...ion-prompt.ts |     100 |      100 |     100 |     100 |                   
  goal-evidence.ts |    88.7 |     88.2 |   97.67 |    88.7 | ...1219,1242-1245 
  ...projection.ts |   66.66 |    72.97 |   33.33 |   66.66 | ...87,190,194-196 
  ...ersistence.ts |   87.36 |    85.96 |    87.5 |   87.36 | ...53-154,185-190 
  goal-protocol.ts |   97.56 |    96.42 |     100 |   97.56 | 322-323           
  goal-reducer.ts  |   95.75 |    93.82 |   97.36 |   95.75 | ...76,666,684-685 
  goal-runtime.ts  |   96.51 |    90.64 |   96.49 |   96.51 | ...1645-1646,1777 
  ...provenance.ts |     100 |      100 |     100 |     100 |                   
  goal-tools.ts    |   98.58 |     95.2 |   96.15 |   98.58 | ...41-242,350-351 
  ...rn-context.ts |     100 |      100 |     100 |     100 |                   
  goal-verifier.ts |   92.46 |    93.02 |     100 |   92.46 | ...69-172,185-187 
  goal-wire.ts     |       0 |        0 |       0 |       0 | 1-28              
  goalHook.ts      |   96.91 |    92.53 |     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         |   90.59 |    86.89 |   90.32 |   90.59 |                   
  ...okRegistry.ts |   86.48 |    77.08 |     100 |   86.48 | ...41-344,362-369 
  ...bortSignal.ts |     100 |      100 |     100 |     100 |                   
  context-usage.ts |     100 |      100 |     100 |     100 |                   
  ...terpolator.ts |   96.66 |    93.33 |     100 |   96.66 | 66-67             
  ...HookRunner.ts |   96.68 |    87.23 |     100 |   96.68 | 110-112,231-233   
  ...Aggregator.ts |   96.57 |    91.48 |     100 |   96.57 | ...20-321,402,404 
  ...entHandler.ts |   95.57 |    84.76 |   94.73 |   95.57 | ...1040-1041,1051 
  hookPlanner.ts   |   87.55 |    85.54 |   86.66 |   87.55 | ...22-226,233-244 
  hookRegistry.ts  |   92.53 |    85.43 |     100 |   92.53 | ...39,458,462,466 
  hookRunner.ts    |   85.68 |    82.96 |    92.3 |   85.68 | ...1289,1299-1302 
  hookSystem.ts    |   87.64 |     98.5 |   70.83 |   87.64 | ...58-759,765-766 
  ...HookRunner.ts |   79.06 |    66.66 |      80 |   79.06 | ...33-434,452-456 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...edCallback.ts |     100 |      100 |     100 |     100 |                   
  ...HookRunner.ts |   94.19 |    84.37 |   81.81 |   94.19 | ...76-384,458-459 
  ...SkillHooks.ts |   82.47 |    84.21 |      75 |   82.47 | 63-67,169-184     
  ...oksManager.ts |   94.87 |    90.12 |     100 |   94.87 | ...84,325,327-329 
  ssrfGuard.ts     |   86.45 |    89.13 |     100 |   86.45 | ...85,289-295,301 
  stopHookCap.ts   |     100 |      100 |     100 |     100 |                   
  trustedHooks.ts  |      90 |    52.63 |     100 |      90 | ...53,66-67,97-98 
  types.ts         |   94.25 |    96.09 |   88.88 |   94.25 | ...46-547,632-636 
  urlValidator.ts  |     100 |      100 |     100 |     100 |                   
  ...it-context.ts |     100 |      100 |     100 |     100 |                   
 src/ide           |   76.98 |    85.03 |   79.03 |   76.98 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  detect-ide.ts    |     100 |      100 |     100 |     100 |                   
  ide-client.ts    |   69.16 |    84.65 |   68.29 |   69.16 | ...1068,1097-1105 
  ide-installer.ts |   89.06 |    79.31 |     100 |   89.06 | ...36,143-147,160 
  ideContext.ts    |     100 |      100 |     100 |     100 |                   
  process-utils.ts |   84.84 |    71.79 |     100 |   84.84 | ...37,151,193-194 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/ipc           |   94.64 |    94.01 |   96.72 |   94.64 |                   
  inbound-gate.ts  |   98.99 |    89.71 |     100 |   98.99 | 557-559           
  ...-directory.ts |     100 |      100 |     100 |     100 |                   
  peer-envelope.ts |     100 |      100 |     100 |     100 |                   
  peer-frames.ts   |   97.61 |    97.22 |     100 |   97.61 | 262-264           
  peer-routing.ts  |     100 |      100 |     100 |     100 |                   
  peer-send.ts     |   97.17 |     98.3 |   88.88 |   97.17 | 183-187           
  socket-path.ts   |   85.71 |    93.33 |     100 |   85.71 | 83-88             
  uds-client.ts    |   88.52 |    92.59 |   85.71 |   88.52 | 172-185           
  uds-inbox.ts     |   82.42 |    84.09 |     100 |   82.42 | ...33,240-250,282 
 src/lsp           |   58.96 |    70.67 |   66.49 |   58.96 |                   
  ...nfigLoader.ts |   80.55 |    72.22 |   95.65 |   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 |    81.81 |   21.05 |   32.78 | ...89-293,299-300 
  ...LspService.ts |      60 |    73.36 |   78.26 |      60 | ...1575,1635-1645 
  configHash.ts    |     100 |      100 |     100 |     100 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/mcp           |    82.3 |    77.81 |   78.33 |    82.3 |                   
  configHash.ts    |     100 |      100 |     100 |     100 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...h-provider.ts |   86.95 |      100 |   33.33 |   86.95 | ...,93,97,101-102 
  ...h-provider.ts |   79.31 |    58.06 |     100 |   79.31 | ...26-933,940-942 
  ...en-storage.ts |   98.78 |    97.95 |     100 |   98.78 | 106-107           
  oauth-utils.ts   |   73.61 |    85.48 |    92.3 |   73.61 | ...46-366,392-421 
  ...n-provider.ts |   89.83 |       96 |   45.45 |   89.83 | ...43,147,151-152 
 .../token-storage |   82.12 |    88.48 |   89.28 |   82.12 |                   
  ...en-storage.ts |     100 |      100 |     100 |     100 |                   
  ...en-storage.ts |   87.08 |    87.71 |   95.23 |   87.08 | ...00-201,214-215 
  ...en-storage.ts |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...en-storage.ts |   68.14 |    82.35 |   64.28 |   68.14 | ...81-295,298-314 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/memory        |   89.47 |    85.72 |    92.1 |   89.47 |                   
  ...y-document.ts |   89.52 |    84.61 |     100 |   89.52 | ...24-325,329-330 
  ...nel-memory.ts |   97.36 |    96.63 |   96.42 |   97.36 | ...91-293,367-368 
  dream.ts         |    64.6 |    72.22 |      50 |    64.6 | ...04-109,124-165 
  ...entPlanner.ts |     100 |    83.33 |     100 |     100 | 135,145           
  entries.ts       |   75.59 |    84.84 |   83.33 |   75.59 | ...56-157,172-180 
  extract.ts       |   93.82 |    84.09 |     100 |   93.82 | 78-83,122,154-157 
  ...entPlanner.ts |   91.55 |    76.74 |     100 |   91.55 | ...05,118-121,296 
  ...ionPlanner.ts |       0 |        0 |       0 |       0 | 1                 
  forget.ts        |   90.71 |    81.14 |   94.44 |   90.71 | ...17,640,657-663 
  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.43 |    83.16 |   77.77 |   78.43 | ...1493,1506-1508 
  ...ent-config.ts |   92.22 |    84.78 |      92 |   92.22 | ...64,473-474,478 
  memoryAge.ts     |   90.47 |    83.33 |     100 |   90.47 | 50-51             
  ...yDiscovery.ts |   93.48 |    90.09 |     100 |   93.48 | ...42,401,629-632 
  paths.ts         |     100 |      100 |     100 |     100 |                   
  ...ing-skills.ts |     100 |       72 |     100 |     100 | 31-35,73-78,97    
  prompt.ts        |   97.26 |    86.79 |     100 |   97.26 | ...10-218,222,225 
  recall.ts        |   86.86 |    86.23 |   92.85 |   86.86 | ...33-538,571-582 
  refresh.ts       |   93.58 |    89.58 |     100 |   93.58 | ...75-176,183-184 
  ...ceSelector.ts |    93.2 |    85.71 |     100 |    93.2 | ...45-146,148-149 
  remember.ts      |   97.21 |    95.29 |     100 |   97.21 | ...29,341,345-347 
  scan.ts          |   93.75 |       80 |     100 |   93.75 | ...08-109,154,157 
  scopes.ts        |     100 |      100 |     100 |     100 |                   
  ...et-scanner.ts |     100 |      100 |     100 |     100 |                   
  ...entPlanner.ts |   79.76 |    76.84 |      80 |   79.76 | ...69-473,476,482 
  status.ts        |   10.52 |      100 |       0 |   10.52 | 41-98             
  store.ts         |   92.92 |    81.81 |     100 |   92.92 | ...16-117,147-148 
  ...git-status.ts |     100 |    85.71 |     100 |     100 | 27                
  ...cret-guard.ts |     100 |      100 |     100 |     100 |                   
  ...emory-sync.ts |   94.24 |    82.85 |     100 |   94.24 | ...34-236,246-247 
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...ontextFile.ts |   81.21 |     79.1 |   81.81 |   81.21 | ...66-280,294-299 
 src/mocks         |       0 |        0 |       0 |       0 |                   
  msw.ts           |       0 |        0 |       0 |       0 | 1-9               
 src/models        |   92.82 |    89.74 |   91.35 |   92.82 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...tor-config.ts |   97.77 |    91.83 |     100 |   97.77 | 155,161,171       
  ...capability.ts |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...nfigErrors.ts |   79.43 |    68.96 |   85.71 |   79.43 | ...,89-96,131-142 
  ...igResolver.ts |   98.71 |    93.33 |     100 |   98.71 | 166,328,334       
  modelRegistry.ts |     100 |    98.11 |     100 |     100 | 177,262           
  modelsConfig.ts  |   89.36 |    86.93 |   88.09 |   89.36 | ...1407,1436-1437 
  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   |   84.33 |    91.62 |   71.54 |   84.33 |                   
  autoMode.ts      |   97.66 |    93.13 |     100 |   97.66 | ...82-589,635,712 
  ...transcript.ts |      98 |       84 |     100 |      98 | 200-201           
  classifier.ts    |      94 |    94.54 |     100 |      94 | 158-165,389-393   
  ...erousRules.ts |     100 |    90.19 |     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 |   88.26 |     91.9 |   82.35 |   88.26 | ...1374,1480-1484 
  rule-parser.ts   |    94.9 |    92.81 |     100 |    94.9 | ...1552,1586-1588 
  ...-semantics.ts |   70.44 |    91.09 |   46.66 |   70.44 | ...2237,2311-2314 
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...sifier-prompts |   99.05 |    95.23 |     100 |   99.05 |                   
  system-prompt.ts |   99.05 |    95.23 |     100 |   99.05 | 226               
 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     |   85.14 |    80.63 |   82.85 |   85.14 |                   
  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 
  ...-discovery.ts |    95.4 |    94.44 |     100 |    95.4 | 31-32,42-43       
  ...der-config.ts |   75.91 |    73.48 |   78.26 |   75.91 | ...74-475,503-504 
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...viders/presets |   98.04 |    91.66 |   63.63 |   98.04 |                   
  ...oding-plan.ts |    87.5 |      100 |       0 |    87.5 | 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 |                   
  moonshot.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.36 |    78.59 |   95.94 |   85.36 |                   
  ...tGenerator.ts |    98.6 |    98.14 |     100 |    98.6 | 103-104           
  qwenOAuth2.ts    |   82.79 |    73.45 |    90.9 |   82.79 | ...1205-1221,1251 
  ...kenManager.ts |   85.36 |     76.8 |     100 |   85.36 | ...52-757,778-783 
 src/resources     |     100 |      100 |     100 |     100 |                   
  ...e-registry.ts |     100 |      100 |     100 |     100 |                   
 src/services      |   90.67 |    86.22 |   96.57 |   90.67 |                   
  ...ionTrailer.ts |     100 |      100 |     100 |     100 |                   
  ...llRegistry.ts |   98.48 |    87.28 |     100 |   98.48 | 81-82,105,474-475 
  branch-points.ts |     100 |    95.23 |     100 |     100 | ...20,211,224,327 
  ...ionService.ts |   97.77 |    96.56 |     100 |   97.77 | ...1098,1241-1249 
  ...ingService.ts |   92.25 |    87.61 |   94.79 |   92.25 | ...2924,2939-2940 
  ...ttribution.ts |   91.73 |    87.71 |      90 |   91.73 | ...80-685,826-827 
  ...utSlimming.ts |    97.2 |    94.23 |     100 |    97.2 | ...39-340,378-381 
  cronScheduler.ts |   94.11 |    89.74 |   98.03 |   94.11 | ...1366,1775-1776 
  cronTasksFile.ts |   95.88 |       92 |     100 |   95.88 | ...72,381-382,520 
  cronTasksLock.ts |   94.44 |    89.47 |     100 |   94.44 | ...02-103,132-133 
  ...eryService.ts |   96.22 |    93.54 |      90 |   96.22 | 121,155-156,161   
  ...oryService.ts |   88.17 |    79.02 |    92.3 |   88.17 | ...1303,1344-1347 
  fileReadCache.ts |    97.5 |    96.07 |     100 |    97.5 | 349-350,363-364   
  ...temService.ts |    92.8 |    84.68 |   94.11 |    92.8 | ...53,479-486,531 
  ...ratedFiles.ts |      96 |    88.23 |     100 |      96 | 119-120,146-147   
  gitInit.ts       |     100 |      100 |     100 |     100 |                   
  ...reeService.ts |   74.75 |    70.76 |   96.07 |   74.75 | ...2296,2325-2326 
  ...on-service.ts |   86.58 |    74.39 |     100 |   86.58 | ...56-460,498-499 
  ...references.ts |   98.57 |    91.42 |     100 |   98.57 | 156-157,217-218   
  ...ionService.ts |   98.26 |    97.23 |     100 |   98.26 | ...65-866,889-890 
  ...ticsDumper.ts |   98.37 |    95.23 |     100 |   98.37 | 185-186           
  ...ureMonitor.ts |   95.82 |    90.52 |   97.05 |   95.82 | ...60,861,875-877 
  ...orRegistry.ts |   97.22 |    90.99 |     100 |   97.22 | ...55-456,609-610 
  ...ttachments.ts |   97.74 |     90.9 |     100 |   97.74 | 298-308,646       
  ...pi-history.ts |   98.94 |    89.13 |     100 |   98.94 | 43                
  ...ersistence.ts |   91.88 |    81.19 |     100 |   91.88 | ...1073-1074,1119 
  ...tory-state.ts |     100 |    95.23 |     100 |     100 | 31                
  ...on-service.ts |   94.61 |    92.44 |   97.22 |   94.61 | ...11-613,669-677 
  ...pr-service.ts |   96.04 |    89.74 |     100 |   96.04 | 72,98-101,190-191 
  ...ce-service.ts |    98.5 |    94.11 |    90.9 |    98.5 | 64-65             
  ...n-registry.ts |    98.8 |    96.73 |     100 |    98.8 | 630,684-685,743   
  ...ken-counts.ts |     100 |       96 |     100 |     100 | 58                
  ...ipt-reader.ts |    93.7 |    91.09 |    97.8 |    93.7 | ...2791-2792,2869 
  ...turn-state.ts |   94.11 |     90.9 |   91.66 |   94.11 | 108-112,129-130   
  ...est-helper.ts |       0 |        0 |       0 |       0 | 1-65              
  ...iter-lease.ts |   84.57 |    75.18 |   97.72 |   84.57 | ...2567,2589,2603 
  sessionRecap.ts  |   67.56 |    43.47 |     100 |   67.56 | ...60,178,180-183 
  ...ionService.ts |   89.13 |     85.9 |   91.66 |   89.13 | ...4182-4183,4224 
  sessionTitle.ts  |   96.35 |    79.71 |     100 |   96.35 | ...08-311,342-343 
  ...ContextEnv.ts |     100 |    94.73 |     100 |     100 | 76,111            
  ...ionService.ts |   84.43 |    78.45 |   97.18 |   84.43 | ...2496,2502-2507 
  ...pInhibitor.ts |   97.42 |    92.77 |     100 |   97.42 | ...30,169,369-370 
  ...e-encoding.ts |   85.96 |    76.47 |     100 |   85.96 | 58-61,64-65,78-79 
  ...Estimation.ts |     100 |    95.83 |     100 |     100 | 139               
  ...ageService.ts |   97.76 |    91.59 |   93.75 |   97.76 | ...61-262,366,567 
  ...ite-origin.ts |     100 |    93.33 |     100 |     100 | 32                
  ...UseSummary.ts |   94.63 |    88.46 |     100 |   94.63 | ...62-164,214-215 
  ...rd-service.ts |     100 |    88.37 |     100 |     100 | ...29,145-146,241 
  ...oryService.ts |   90.77 |    84.92 |     100 |   90.77 | ...43-546,598-599 
  ...l-registry.ts |   92.99 |    83.19 |     100 |   92.99 | ...66-367,377-378 
  ...reeCleanup.ts |   14.42 |      100 |   33.33 |   14.42 | 58-186            
  ...ionService.ts |   88.36 |     87.8 |     100 |   88.36 | ...48-449,465-466 
 ...icrocompaction |   98.91 |    95.06 |     100 |   98.91 |                   
  microcompact.ts  |   98.91 |    95.06 |     100 |   98.91 | ...60,769,778-779 
 ...s/visionBridge |    98.8 |    92.12 |     100 |    98.8 |                   
  ...capability.ts |     100 |      100 |     100 |     100 |                   
  ...part-utils.ts |     100 |      100 |     100 |     100 |                   
  ...ion-bridge.ts |   98.72 |    82.35 |     100 |   98.72 | 65,71             
  ...ge-service.ts |   98.61 |     94.7 |     100 |   98.61 | ...06,666,679-680 
 src/skills        |   89.78 |    86.08 |   94.73 |   89.78 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...activation.ts |     100 |    93.33 |     100 |     100 | 93,112            
  skill-curator.ts |   89.71 |    81.54 |     100 |   89.71 | ...01-902,904-907 
  skill-load.ts    |   94.84 |    87.69 |     100 |   94.84 | ...03,223,235-237 
  skill-manager.ts |   86.11 |    85.71 |   86.11 |   86.11 | ...1244,1251-1255 
  skill-paths.ts   |   90.42 |     87.5 |     100 |   90.42 | ...19-120,125-126 
  symlinkScope.ts  |     100 |      100 |     100 |     100 |                   
  types.ts         |   97.91 |    98.07 |     100 |   97.91 | 289-290           
 ...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     |   88.93 |    89.34 |   98.36 |   88.93 |                   
  ...ter-schema.ts |     100 |    98.18 |     100 |     100 | 99                
  ...tin-agents.ts |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...nt-manager.ts |   85.75 |    86.38 |   97.56 |   85.75 | ...1653,1730-1731 
  types.ts         |     100 |      100 |     100 |     100 |                   
  validation.ts    |   94.14 |    95.23 |     100 |   94.14 | 47-52,65-66,71-76 
 src/telemetry     |   83.23 |    85.33 |   86.51 |   83.23 |                   
  ...ty-tracker.ts |     100 |      100 |     100 |     100 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  context-usage.ts |   96.85 |    91.07 |     100 |   96.85 | ...26-127,199-200 
  ...on-metrics.ts |   99.08 |    80.95 |     100 |   99.08 | 185,199           
  ...on-tracing.ts |   80.71 |    81.91 |   79.16 |   80.71 | ...92,499-501,517 
  ...attributes.ts |   96.98 |    91.37 |     100 |   96.98 | ...47-348,366-367 
  ...ag-metrics.ts |     100 |    77.77 |     100 |     100 | 21,40             
  ...t-loop-lag.ts |   96.85 |    85.71 |     100 |   96.85 | 170-173           
  ...-exporters.ts |   65.38 |    83.33 |      50 |   65.38 | ...08-109,112-113 
  ...ai-content.ts |    74.5 |    66.41 |   91.66 |    74.5 | ...1480,1493-1502 
  ...i-provider.ts |     100 |    99.02 |     100 |     100 | 106               
  ...ai-request.ts |   87.88 |    92.79 |   83.78 |   87.88 | ...55-561,564-568 
  gen-ai-usage.ts  |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...t.circular.ts |       0 |        0 |       0 |       0 | 1-111             
  ...-processor.ts |   99.12 |    96.03 |      95 |   99.12 | 150,379-380       
  ...t.circular.ts |       0 |        0 |       0 |       0 | 1-128             
  loggers.ts       |   60.83 |    77.77 |   66.66 |   60.83 | ...1523,1540-1560 
  metrics.ts       |   80.37 |    82.35 |   80.95 |   80.37 | ...1150,1153-1164 
  otlp-urls.ts     |     100 |      100 |     100 |     100 |                   
  ...attributes.ts |     100 |      100 |     100 |     100 |                   
  ...ime-config.ts |       0 |        0 |       0 |       0 | 1                 
  sanitize.ts      |      80 |    83.33 |     100 |      80 | 35-36,41-42       
  ...rters-grpc.ts |     100 |      100 |     100 |     100 |                   
  ...rters-http.ts |     100 |      100 |     100 |     100 |                   
  sdk-impl.ts      |   94.13 |    86.66 |      75 |   94.13 | ...45,496-497,513 
  sdk.ts           |    82.7 |     90.9 |   66.66 |    82.7 | ...00-204,242-264 
  ...on-context.ts |     100 |      100 |     100 |     100 |                   
  ...ion-events.ts |     100 |      100 |     100 |     100 |                   
  ...on-tracing.ts |   91.29 |    88.88 |    97.5 |   91.29 | ...1946,1975-1978 
  ...etry-utils.ts |     100 |      100 |     100 |     100 |                   
  ...l-decision.ts |     100 |      100 |     100 |     100 |                   
  trace-context.ts |     100 |      100 |     100 |     100 |                   
  ...e-id-utils.ts |     100 |      100 |     100 |     100 |                   
  tracer.ts        |   98.56 |    88.63 |     100 |   98.56 | 52,101            
  types.ts         |   83.26 |    95.74 |   86.36 |   83.26 | ...1467,1471-1478 
  uiTelemetry.ts   |   98.87 |     95.1 |   97.05 |   98.87 | ...59,696,786-787 
 ...ry/qwen-logger |   74.23 |     80.7 |      70 |   74.23 |                   
  event-types.ts   |       0 |        0 |       0 |       0 |                   
  qwen-logger.ts   |   74.23 |    80.53 |   69.49 |   74.23 | ...1122,1160-1161 
 src/test-utils    |   96.38 |    98.64 |   84.09 |   96.38 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  ...st-helpers.ts |   94.11 |       90 |     100 |   94.11 | 69-70             
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...mised-lock.ts |     100 |      100 |     100 |     100 |                   
  mock-tool.ts     |   94.85 |      100 |      80 |   94.85 | ...53,227-228,241 
  ...aceContext.ts |     100 |      100 |     100 |     100 |                   
 src/tools         |   87.63 |    86.21 |   90.25 |   87.63 |                   
  ...erQuestion.ts |      90 |    82.75 |   92.85 |      90 | ...01-402,409-410 
  ...-registrar.ts |    77.7 |    66.66 |   66.66 |    77.7 | ...72-277,292-294 
  ...ub-session.ts |   89.72 |    91.48 |   83.33 |   89.72 | ...06-307,318-325 
  cron-create.ts   |   92.26 |    97.72 |      75 |   92.26 | ...,76-77,272-281 
  cron-delete.ts   |   97.56 |      100 |   85.71 |   97.56 | 31-32             
  cron-list.ts     |   98.23 |    95.45 |   88.88 |   98.23 | 57-58             
  diffOptions.ts   |     100 |      100 |     100 |     100 |                   
  display-image.ts |   87.42 |    85.71 |    90.9 |   87.42 | ...29-134,194-195 
  edit.ts          |   82.76 |    86.88 |   82.35 |   82.76 | ...45-746,865-915 
  ...r-worktree.ts |   83.14 |    68.42 |   88.88 |   83.14 | ...84-187,278-279 
  enterPlanMode.ts |      85 |       84 |      90 |      85 | ...28-133,161-175 
  exit-worktree.ts |   83.29 |     83.8 |   94.73 |   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.71 |   86.36 |   90.73 | ...76-677,727-728 
  ...adTracking.ts |     100 |      100 |     100 |     100 |                   
  image-gen.ts     |   91.66 |    78.12 |   91.66 |   91.66 | ...13-214,221-222 
  list-agents.ts   |   96.52 |    95.55 |    87.5 |   96.52 | 37-38,53-54       
  loop-wakeup.ts   |   99.27 |     93.1 |     100 |   99.27 | 45                
  ls.ts            |   96.74 |    90.54 |     100 |   96.74 | 176-181,212,216   
  lsp.ts           |   72.71 |     59.9 |    90.9 |   72.71 | ...1212,1214-1215 
  ...nt-manager.ts |   82.07 |    80.15 |   85.71 |   82.07 | ...3243,3245-3246 
  mcp-client.ts    |   86.25 |    87.61 |   93.93 |   86.25 | ...2552,2556-2559 
  ...ry-timeout.ts |     100 |      100 |     100 |     100 |                   
  mcp-errors.ts    |     100 |      100 |     100 |     100 |                   
  ...pool-entry.ts |   79.21 |    85.71 |   81.57 |   79.21 | ...1342,1350-1351 
  ...ool-events.ts |       8 |        0 |       0 |       8 | 132-158           
  mcp-pool-key.ts  |    97.5 |    93.93 |     100 |    97.5 | 178-179           
  ...ce-content.ts |   96.55 |    91.17 |     100 |   96.55 | 80-82             
  mcp-retry.ts     |   97.67 |    95.65 |     100 |   97.67 | 131-132           
  ...ion-config.ts |     100 |      100 |     100 |     100 |                   
  mcp-status.ts    |     100 |      100 |     100 |     100 |                   
  mcp-tool.ts      |    98.1 |       93 |     100 |    98.1 | ...1233,1288-1289 
  ...sport-pool.ts |   83.98 |     80.3 |   88.46 |   83.98 | ...1411,1418-1422 
  ...ace-budget.ts |   87.27 |     82.6 |     100 |   87.27 | ...00-305,340-345 
  memory-config.ts |     100 |      100 |     100 |     100 |                   
  ...iable-tool.ts |     100 |    84.61 |     100 |     100 | 101,108           
  monitor.ts       |   91.82 |    83.09 |   88.46 |   91.82 | ...99,612,810-815 
  notebook-edit.ts |   85.71 |    77.39 |   82.35 |   85.71 | ...96-912,958-959 
  ...escendants.ts |   36.17 |    64.51 |   55.55 |   36.17 | ...46-310,385-390 
  ...nforcement.ts |   83.21 |    90.69 |     100 |   83.21 | 147-158,207-220   
  read-file.ts     |   95.49 |    88.61 |    87.5 |   95.49 | ...49,464,536-537 
  ...p-resource.ts |   96.85 |      100 |   91.66 |   96.85 | 92-96             
  readManyFiles.ts |   96.04 |    82.25 |     100 |   96.04 | ...41,594,604-608 
  ...d-artifact.ts |   85.68 |    81.59 |   94.73 |   85.68 | ...1071,1095-1096 
  ...t-findings.ts |   99.13 |    93.93 |    92.3 |   99.13 | 255-257           
  ...t-shutdown.ts |    87.2 |    86.66 |   77.77 |    87.2 | ...,75-79,162-165 
  ripGrep.ts       |    94.6 |    87.34 |   95.45 |    94.6 | ...33-734,740-741 
  ...-transport.ts |   71.42 |    55.55 |   71.42 |   71.42 | ...36-137,143-144 
  send-message.ts  |   86.86 |    93.18 |      75 |   86.86 | ...20-426,568-575 
  ...n-mcp-view.ts |   94.07 |    91.89 |    90.9 |   94.07 | 131-139           
  shell.ts         |   78.96 |    84.29 |      93 |   78.96 | ...5036,5111-5112 
  skill-utils.ts   |     100 |      100 |     100 |     100 |                   
  skill.ts         |   93.56 |    90.78 |   91.66 |   93.56 | ...49,653,701-723 
  ...-constants.ts |     100 |      100 |     100 |     100 |                   
  ...eticOutput.ts |   95.12 |      100 |      80 |   95.12 | 87-88             
  task-create.ts   |    94.4 |    93.75 |   83.33 |    94.4 | 45-49,63-64,95    
  task-list.ts     |   80.43 |    86.95 |   85.71 |   80.43 | ...67,121,125-132 
  task-stop.ts     |   93.14 |    96.29 |    87.5 |   93.14 | 39-40,54-64       
  task-update.ts   |   82.87 |     86.5 |   92.85 |   82.87 | ...54-564,588-599 
  team-create.ts   |   97.24 |     87.5 |   85.71 |   97.24 | 48-49,129-130     
  team-delete.ts   |   88.67 |     87.5 |   85.71 |   88.67 | ...2-48,72-73,129 
  ...n-approval.ts |   92.14 |    96.96 |   81.81 |   92.14 | 38-39,42-43,93-99 
  todoWrite.ts     |   95.73 |    90.47 |   93.75 |   95.73 | ...48-552,565-570 
  ...repeat-key.ts |     100 |      100 |     100 |     100 |                   
  tool-error.ts    |     100 |      100 |     100 |     100 |                   
  tool-names.ts    |     100 |      100 |     100 |     100 |                   
  tool-registry.ts |   80.72 |    82.95 |   86.53 |   80.72 | ...1106,1114-1115 
  ...-finalizer.ts |    98.1 |    92.36 |   93.33 |    98.1 | ...34-235,237-241 
  ...iagnostics.ts |   99.06 |    97.69 |   91.66 |   99.06 | 133-134,205       
  ...-retention.ts |     100 |    95.83 |     100 |     100 | 116               
  tool-search.ts   |    96.2 |    89.79 |   93.75 |    96.2 | ...10,260-265,428 
  tool-utils.ts    |   97.46 |    96.55 |     100 |   97.46 | 26-27             
  tools.ts         |   92.93 |    92.18 |      92 |   92.93 | ...64-565,581-587 
  truncation.ts    |   90.61 |    90.35 |     100 |   90.61 | ...53-461,498-504 
  ...reapproved.ts |   99.27 |    94.11 |     100 |   99.27 | 170               
  web-fetch.ts     |   96.05 |    90.54 |   96.77 |   96.05 | ...85-786,800-801 
  web-search.ts    |   90.58 |    83.57 |      80 |   90.58 | ...1025,1083-1086 
  write-file.ts    |   87.29 |    86.15 |   89.47 |   87.29 | ...53-856,893-928 
  zoom-image.ts    |   95.76 |    93.93 |    90.9 |   95.76 | 54-59,203-204     
 src/tools/agent   |   87.26 |    88.53 |   89.71 |   87.26 |                   
  agent.ts         |   85.88 |    87.66 |   87.35 |   85.88 | ...4277,4311-4321 
  fork-profile.ts  |   93.65 |       90 |     100 |   93.65 | ...33-134,171-174 
  fork-subagent.ts |   98.73 |       95 |     100 |   98.73 | 101-102,173       
 ...tools/artifact |   95.83 |    92.51 |   88.63 |   95.83 |                   
  artifact-tool.ts |   91.69 |    88.46 |   71.42 |   91.69 | ...20-321,329-332 
  ...-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 |                   
 ...tools/workflow |   89.33 |    87.68 |   82.75 |   89.33 |                   
  workflow.ts      |   89.33 |    87.68 |   82.75 |   89.33 | ...33,878,880-881 
 src/utils         |   92.79 |    89.75 |    96.9 |   92.79 |                   
  ...Controller.ts |     100 |      100 |     100 |     100 |                   
  ...ssageQueue.ts |     100 |      100 |     100 |     100 |                   
  ...cFileWrite.ts |      95 |    92.76 |     100 |      95 | ...49-550,657-661 
  auth-type.ts     |     100 |      100 |     100 |     100 |                   
  bareMode.ts      |   81.81 |      100 |      50 |   81.81 | 18-19             
  ...ry-content.ts |   98.45 |    95.79 |     100 |   98.45 | 132-133,159-160   
  browser.ts       |   86.84 |    78.94 |     100 |   86.84 | 34,36-37,65-66    
  btwUtils.ts      |   13.95 |      100 |       0 |   13.95 | 17-31,34-55       
  bundlePaths.ts   |     100 |      100 |     100 |     100 |                   
  ...on-context.ts |     100 |      100 |     100 |     100 |                   
  ...igResolver.ts |     100 |      100 |     100 |     100 |                   
  ...engthError.ts |   91.06 |    89.47 |     100 |   91.06 | ...46-147,154-155 
  ...n-branches.ts |   95.89 |    94.11 |      95 |   95.89 | ...99-500,512-525 
  ...tion-chain.ts |     100 |      100 |     100 |     100 |                   
  cronDisplay.ts   |     100 |    97.61 |     100 |     100 | 46                
  cronParser.ts    |   95.34 |    93.33 |     100 |   95.34 | 41-42,47-48,70-71 
  debugLogger.ts   |   99.49 |    96.29 |     100 |   99.49 | 224               
  ...qwen-model.ts |     100 |      100 |     100 |     100 |                   
  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     
  errorParsing.ts  |     100 |      100 |     100 |     100 |                   
  ...rReporting.ts |   95.65 |    93.33 |     100 |   95.65 | 37-38             
  errors.ts        |   88.92 |    93.58 |      68 |   88.92 | ...92,394,410-411 
  fetch.ts         |   90.68 |    82.63 |     100 |   90.68 | ...72,483-484,503 
  ...ng-options.ts |     100 |      100 |     100 |     100 |                   
  file-identity.ts |     100 |      100 |     100 |     100 |                   
  fileUtils.ts     |   94.79 |    92.18 |   96.29 |   94.79 | ...2076,2084-2085 
  formatters.ts    |     100 |      100 |     100 |     100 |                   
  ...eUtilities.ts |    92.4 |    86.95 |     100 |    92.4 | ...52-158,168-169 
  ...rStructure.ts |   94.39 |    94.28 |     100 |   94.39 | ...29-132,343-348 
  getPty.ts        |   31.57 |       50 |     100 |   31.57 | 26-38             
  git-branches.ts  |   91.64 |    84.87 |    92.3 |   91.64 | ...00,415-420,580 
  ...fig-safety.ts |   97.01 |       80 |     100 |   97.01 | 53-54             
  git-ignore.ts    |     100 |      100 |     100 |     100 |                   
  gitDiff.ts       |   95.19 |    81.36 |     100 |   95.19 | ...1073,1419-1420 
  gitDirect.ts     |   98.84 |    94.28 |     100 |   98.84 | 234,318           
  ...noreParser.ts |   94.48 |    93.22 |     100 |   94.48 | ...23-124,158-159 
  gitUtils.ts      |   78.83 |    82.35 |    87.5 |   78.83 | ...22-123,164-215 
  github-prs.ts    |   96.06 |    84.09 |     100 |   96.06 | 251,350-358       
  iconvHelper.ts   |     100 |      100 |     100 |     100 |                   
  ...rePatterns.ts |     100 |      100 |     100 |     100 |                   
  image-view.ts    |   95.08 |    93.47 |     100 |   95.08 | ...62-166,234-238 
  ...lPromptIds.ts |     100 |      100 |     100 |     100 |                   
  ...on-context.ts |     100 |      100 |     100 |     100 |                   
  is-tool.ts       |     100 |      100 |     100 |     100 |                   
  jsonl-utils.ts   |   96.15 |    93.63 |     100 |   96.15 | ...86-387,429-432 
  ...-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                
  ...-constants.ts |   94.73 |     92.3 |     100 |   94.73 | 66-67             
  ...iagnostics.ts |    96.4 |     94.2 |     100 |    96.4 | ...66,293-294,376 
  ...tProcessor.ts |   94.01 |     90.1 |     100 |   94.01 | ...47-353,445-446 
  ...Inspectors.ts |     100 |      100 |     100 |     100 |                   
  modelId.ts       |   98.96 |    98.24 |     100 |   98.96 | 154               
  ...kerChecker.ts |    90.9 |    91.66 |     100 |    90.9 | 73-79             
  notebook.ts      |   94.57 |    89.91 |   95.83 |   94.57 | ...21,333,385-387 
  openaiLogger.ts  |   91.66 |    89.74 |     100 |   91.66 | ...26-228,251-256 
  osc8.ts          |   54.26 |    64.86 |   83.33 |   54.26 | ...72-195,197-257 
  partUtils.ts     |     100 |    98.64 |     100 |     100 | 211               
  pathReader.ts    |     100 |      100 |     100 |     100 |                   
  paths.ts         |   90.88 |     90.6 |     100 |   90.88 | ...28-629,631-633 
  pdf.ts           |   92.17 |    85.81 |     100 |   92.17 | ...64-565,606-611 
  ...s-liveness.ts |     100 |    93.47 |     100 |     100 | 62,72,108         
  projectPath.ts   |     100 |      100 |     100 |     100 |                   
  projectRoot.ts   |   71.73 |    78.57 |     100 |   71.73 | 54-66             
  ...ectSummary.ts |   89.62 |    72.41 |     100 |   89.62 | ...40-145,196-199 
  ...tIdContext.ts |     100 |      100 |     100 |     100 |                   
  proxyUtils.ts    |     100 |      100 |     100 |     100 |                   
  ...rDetection.ts |   71.15 |       86 |     100 |   71.15 | ...-90,96-101,147 
  ...noreParser.ts |   92.63 |    91.66 |     100 |   92.63 | ...77-178,197-198 
  rateLimit.ts     |   93.75 |    89.62 |     100 |   93.75 | ...13,218-219,262 
  ...text-range.ts |   96.98 |    87.36 |     100 |   96.98 | ...87-688,763-764 
  retry.ts         |   96.09 |    92.52 |     100 |   96.09 | ...72,563-564,582 
  retryContext.ts  |     100 |      100 |     100 |     100 |                   
  ...sification.ts |   97.63 |    97.08 |     100 |   97.63 | ...17,251-252,278 
  retryPolicy.ts   |   97.72 |    90.56 |     100 |   97.72 | 130-131           
  ripgrepUtils.ts  |   90.04 |    93.43 |   95.45 |   90.04 | ...55-565,598-599 
  ...iagnostics.ts |   83.08 |     67.5 |   92.59 |   83.08 | ...23,543-544,550 
  ...tchOptions.ts |   84.87 |    86.71 |   96.29 |   84.87 | ...71,696,725-734 
  ...odelPrefix.ts |     100 |      100 |     100 |     100 |                   
  runtimeStatus.ts |   97.77 |    91.48 |     100 |   97.77 | 172-173           
  safe-mode.ts     |     100 |      100 |     100 |     100 |                   
  safeJsonParse.ts |     100 |      100 |     100 |     100 |                   
  ...nStringify.ts |     100 |      100 |     100 |     100 |                   
  ...-child-env.ts |     100 |      100 |     100 |     100 |                   
  ...aConverter.ts |   98.22 |    98.01 |     100 |   98.22 | 100,102-103       
  ...aValidator.ts |   92.09 |    83.65 |   90.47 |   92.09 | ...60,882-883,896 
  ...r-launcher.ts |   96.35 |    93.97 |   85.71 |   96.35 | ...35-336,347-348 
  sedEditParser.ts |   91.78 |    92.18 |     100 |   91.78 | ...66-569,645-646 
  ...nIdContext.ts |     100 |       90 |     100 |     100 | 95                
  ...orageUtils.ts |   96.21 |    86.32 |     100 |   96.21 | ...70,386,466,485 
  ...-pager-env.ts |     100 |      100 |     100 |     100 |                   
  ...fety-rules.ts |     100 |     89.7 |     100 |     100 | ...01,304,309-311 
  shell-utils.ts   |   86.37 |    88.59 |     100 |   86.37 | ...2361,2368-2372 
  ...lAstParser.ts |    98.3 |    91.59 |     100 |    98.3 | ...1340-1342,1352 
  ...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 |    57.14 |     100 |   77.77 | 44,54-59          
  ...emEncoding.ts |   96.36 |    91.17 |     100 |   96.36 | 59-60,124-125     
  terminal-env.ts  |      50 |      100 |       0 |      50 | 18-19             
  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             
  ...error-type.ts |     100 |      100 |     100 |     100 |                   
  ...name-utils.ts |     100 |      100 |     100 |     100 |                   
  ...ultCleanup.ts |   54.62 |       25 |      75 |   54.62 | ...03-105,108-134 
  ...Compaction.ts |   96.83 |     92.7 |     100 |   96.83 | ...37-342,344-349 
  ...pt-records.ts |   87.61 |    86.23 |     100 |   87.61 | ...80-484,514-529 
  ...-constants.ts |     100 |      100 |     100 |     100 |                   
  windowsPath.ts   |   89.47 |    79.31 |     100 |   89.47 | ...57-58,62,90-91 
  ...-directory.ts |    83.7 |    80.95 |    87.5 |    83.7 | ...37-238,252-253 
  ...ifact-path.ts |   94.11 |    92.85 |     100 |   94.11 | 32-33             
  ...aceContext.ts |   95.39 |    89.47 |     100 |   95.39 | ...16-317,321-322 
  xml.ts           |    97.8 |    87.69 |     100 |    97.8 | 98-99             
  yaml-parser.ts   |   83.87 |    77.27 |     100 |   83.87 | ...31-234,239-240 
 ...ils/filesearch |   83.94 |    80.75 |   94.78 |   83.94 |                   
  crawlCache.ts    |     100 |      100 |     100 |     100 |                   
  crawler.ts       |    82.9 |    76.81 |   95.08 |    82.9 | ...1563,1597-1598 
  fileSearch.ts    |   93.78 |    87.67 |     100 |   93.78 | ...71-272,274-275 
  fzfWorker.ts     |       0 |        0 |       0 |       0 | 1-109             
  ...rkerHandle.ts |   84.05 |    75.86 |      90 |   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 |    92.3 |      100 |   88.88 |    92.3 |                   
  ...ageFormats.ts |   81.81 |      100 |   66.66 |   81.81 | 56-61             
  textTokenizer.ts |     100 |      100 |     100 |     100 |                   
-------------------|---------|----------|---------|---------|-------------------

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

@qwen-code-ci-bot

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

Copy link
Copy Markdown
Collaborator

Sandboxed verification: ✅ passed — merge-ready (agent verdict) - workflow run

Ran the PR in an isolated, token-free container: A/B against the base build, mock-free harness assertions, targeted gates. Advisory evidence for human reviewers — not a review, an approval, or a CI check.

Scripted assertions: 77 passed · 0 failed · 77 total

Flakiness gate: ⚠️ timeout — the 15-minute budget elapsed before two full rounds completed (1 done) — no flakiness signal either way

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

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

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

抖动门:⚠️ timeout — the 15-minute budget elapsed before two full rounds completed (1 done) — no flakiness signal either way

Verification report

PR #10489 — Deep Verification Report

Verdict: merge-ready — scripted assertions 77 pass / 0 fail / 77 total (A/B wire harness).
Verified head: 6a9bf199d5cd0dd6b58ed88b55a9c51b358eb36c (HEAD^2), base tip: 5bd21da29d22c1d4c6b52b438bd7904f345b4fa6 (HEAD^1).

The central claim — WebShell model/reasoning preferences persist across daemon sessions via model.reasoningEffort, with capability reconciliation on model switch and lazy Welcome preserved — is proven load-bearing by an A/B against a rebuilt base control: the base daemon does not persist, does not reconcile, and cannot even express default for tiered models, while the head daemon persists to settings.json on disk, clears incompatible selections, and reads the value back. Every targeted gate, the vacuity check, and the Playwright reasoning e2e are green.

中文摘要

结论:merge-ready。脚本化断言 77 通过 / 0 失败 / 共 77(A/B 网络测试台)。

  • A/B 结论:中心主张被证实是“承重”的。用 HEAD^1 重新构建的对照组(base)守护进程不会把思考偏好写入磁盘、不会在切换模型时做能力协调、甚至对分档模型无法表达 default;而 PR 构建(head)会把选择写入 settings.json(含 none)、用 default 清除已存值、在切换到不兼容模型时清除冲突档位、并在 Welcome 预览与新会话中读回。共 8 项“base 缺失/错误 → head 修复”的翻转全部命中(下表 P1–P4、R1、C1、C3、V2)。
  • findings:无阻塞性缺陷。两条非阻塞观察见正文(内置 Qwen 目录中没有模型真正暴露 max/high 档位;config-option 端点的响应结构发生了变化,但仓库内唯一消费方 TS SDK 已同步更新并有“旧守护进程”容错测试)。
  • 未覆盖范围:见正文 Not covered(要点:逐提交归因因浅克隆不可达、TUI 流程、provider 请求映射/clamp、Java SDK、真实模型请求路径等)。

Central claim and A/B proof

Claim under test: reasoning selection is persisted to model.reasoningEffort on disk when persist: true is sent, default clears the stored value, incompatible selections are cleared (never downgraded/restored) on model switch, and the stored value is read back into the Welcome preview and live sessions — without creating an empty session early.

Method: a mock-free wire harness (ab-reasoning-persist.mjs) boots a real daemon from compiled dist/ on loopback for each cell (fresh HOME/settings.json per cell), drives it over HTTP (POST /session, POST /session/:id/config-option, POST /session/:id/model, GET /workspace/providers, GET /session/:id/context), and asserts the physical effects: the settings.json file on disk and the confirmed configOptions on the wire. Expectations are encoded per-arm, so a base cell that correctly fails to persist is a passing control. The head arm runs the PR build; the base arm runs a control rebuilt at HEAD^1 (only packages/cli + sdk-typescript recompiled; all other workspace deps byte-identical, so the control differs by nothing but the change under test).

Cell Scenario Head (PR) Base (control) Load-bearing?
P1 persist low writes settings.json, persisted:true, confirmed no write, no persisted field ✅ flip
P2 persist none writes none no write ✅ flip
P3 persist default clears stored key, confirms model default xhigh rejects (500 -32602), key untouched ✅ flip
P4 persist tier on non-Qwen model writes high no write ✅ flip
R1 Welcome preview read-back (no session) preview currentValue: medium (persisted) preview currentValue: xhigh (model default) ✅ flip
R2 live-session read-back medium medium parity (no regression)
C1 switch to incompatible (xhigh→toggle-only) clears xhigh from disk keeps stale xhigh ✅ flip
C2 switch, compatible (low) retains low retains low parity
C3 switch to mandatory-thinking with none clears none keeps none ✅ flip
C4 switch to toggle-only with none retains none retains none parity
V1 invalid value bogus 500 -32602, disk untouched same parity
V2 persist:"yes" (non-boolean) 400 200 (ignored) ✅ flip (head validates)
V3 spoofed _meta without persist persisted:false, no write no write parity (spoof-safe)
V4 max on qwen3.8-max rejected rejected parity
V5 tier on toggle-only rejected rejected parity
V6 none on mandatory model rejected rejected parity

Head: 42/42 pass. Base control: 35/35 pass (base asserts fewer because head-only confirmations are skipped). Witness images: 01-ab-summary-head-vs-base.png (combined table) and 02-head-arm-live-assertions.png (all 42 head assertions as printed). Raw per-cell logs are in logs/ab-head.txt / logs/ab-base.txt.

Two control-run behaviors worth flagging because they sharpen the claim: on base, sending default to a tiered model is rejected outright (its option set has no default choice), and the Welcome preview always shows the model default rather than the persisted value. Both are exactly the gaps the PR closes.

Corrections

None — no earlier review round or bot comment in this workspace misdescribed the code.

Findings

No blocking findings. Non-blocking observations:

  1. max/high are not advertised by any built-in catalog model (nit / documentation). The strict tier universe is low|medium|high|xhigh|max (REASONING_EFFORT_TIERS), and the PR adds EN/ZH labels for all five. But the only catalog model that exposes effort tiers, qwen3.8-max, advertises only [low, medium, xhigh]; every other Qwen catalog entry is toggle-only. So the description's "max on a supporting model" round-trip is only reachable via a custom / non-catalog modelProviders entry (the generic path accepts all five tiers — proven by cell P4 with high). The reconciliation mechanism itself is identical and proven with xhigh (cell C1). No code change needed; noting only so the description's max example isn't read as a built-in-model scenario.

  2. POST /session/:id/config-option response shape changed (compat note, not a defect). Base returned the full ACP SetSessionConfigOptionResponse ({sessionId, configId, value, configOptions, …}); head returns {configOptions, persisted}. The only in-repo consumer is the TypeScript SDK, which is updated in lockstep and now types the result as {configOptions, persisted}; the web-shell additionally tolerates an older daemon (does not invent welcome reasoning for an older daemon e2e passes). Reverse direction (new daemon + old client) is a boundary change, acknowledged by the PR ("adds … strict reasoning selection/result types to the daemon HTTP boundary and TypeScript SDK"). No public ACP protocol change. Recorded for reviewer awareness only.

Vacuity / mutation check (the new tests are not vacuous)

The PR's central unit tests (Session.test.ts) were proven to actually pin the new logic by mutating the production file in a scratch worktree and re-running (control first, then each mutant, then restore):

Arm Change Result
Control unmutated Session.ts 730/730 pass
Mutant A removed the reconcileReasoningSelection(...) call from setModel KILLED — 4 new tests fail with behavioral assertions, e.g. expected { reasoningEffort: 'max' } to not have property "reasoningEffort"
Mutant B disabled the settings.setValue write inside persistReasoningSelection KILLEDpersists none… fails with expected 'max' to be 'none'

Both mutants die on the intended behavioral assertion (not an import/compile break), and the surviving sibling tests are consistent with each mutant's scope (e.g. the default-as-delete test still passes under Mutant B because that path goes through clearPersistedReasoningSelection, which Mutant B leaves intact). Witnesses: 03-mutant-a-reconcile-removed-kills-4-tests.png, 04-mutant-b-persist-write-disabled-kills-test.png. Control junit: logs/session-test-control-junit.xml.

Targeted gates (all green)

Gate Scope Result
packages/cli changed files server.test.ts, model-configuration.test.ts, acpAgent.test.ts, settingsSchema.test.ts, modelConfigUtils.test.ts, workspace-providers-status.test.ts 1799/1799 pass
packages/cli Session.test.ts full file (control arm of vacuity) 730/730 pass
packages/sdk-typescript DaemonClient.test.ts, DaemonSessionClient.test.ts 432/432 pass
packages/webui actions.test.ts, mappers.test.ts, DaemonSessionProvider.test.tsx 396/396 pass
packages/web-shell App.test.tsx, ChatEditor.test.tsx, SettingsMessage.dom.test.tsx, sessionPreparation.test.ts 716/716 pass
Playwright e2e (@smoke, chromium) web-shell.smoke.spec.ts incl. all 10 reasoning scenarios 45/45 pass (05-playwright-reasoning-e2e-10-scenarios.png)
Typecheck cli, sdk, webui, web-shell (tsc --noEmit) PASS (all four)
Generated schema re-ran scripts/generate-settings-schema.ts output byte-identical to committed packages/vscode-ide-companion/schemas/settings.schema.json

Raw gate logs: logs/gate-cli.txt, logs/gate-sdk.txt, logs/gate-webui.txt, logs/gate-webshell.txt, logs/gate-e2e.txt.

Not covered

  • Per-commit attribution. The PR has 2 commits (14673c7a, 6a9bf199) but the checkout is depth-2/shallow and only HEAD^2 (6a9bf199) is reachable — git rev-list HEAD^1..HEAD^2 yields 1 commit, mismatching the 2-commit snapshot. I verified the aggregate HEAD^1..HEAD diff. The second commit's focus ("retain reasoning preview for new tasks") is nonetheless exercised by the webui actions.test.ts cases keeps the confirmed persisted reasoning preview after clearing the session and waits for an in-flight persisted reasoning change before clearing (both green).
  • TUI flows and the /effort slash command path (out of scope per the PR; only the daemon/WebShell boundary was exercised).
  • Provider request mapping / clamping — I asserted the value written to disk and the confirmed configOptions, not the final per-provider request payload sent to a model API.
  • No real model call was made. Sessions were created and configured but never prompted; OPENAI_BASE_URL pointed at an unreachable stub. Prompt-time behavior (the first-prompt create/attach/set-model/persist/submit ordering) is covered by the Playwright mock-daemon ledger tests, not by a live model round-trip.
  • Java SDK (separate repo) and any non-TS client of the config-option endpoint — see Findings Where is the config saved? #2.
  • Windows/macOS rendering; Linux only. Visual/layout correctness beyond the Playwright DOM assertions.
  • Repo-wide test suite and repo-wide lint were not re-run (targeted gates above instead); the PR's own CI covers the full matrix.

Methodology

Environment: the repo's own compiled output (npm ci + npm run build had completed at HEAD). The A/B control was rebuilt at HEAD^1 in a scratch worktree by recompiling only packages/cli and packages/sdk-typescript with tsc --build; every other workspace dependency is byte-identical between base and head (verified via git diff over packages/core, acp-bridge, web-templates, audio-capture, and all channel packages), so the control differs from head by exactly the change under test. Harnesses drove the real compiled daemon over loopback HTTP with no stubs of the code under test; the only mocks were the unreachable model endpoint and, for the e2e suite, the repo's own mockDaemon request ledger. All assertions are scripted (ab-reasoning-persist.mjs prints one ok/NOT OK per check and writes results-{head,base}.json); vacuity mutants were applied in a scratch worktree and reverted (git status clean afterward). Raw per-cell daemon logs, build logs, and gate outputs are in logs/; harness and summary scripts are in this directory for rerun.

Flakiness gate log

e2e suite, out of gate scope: packages/web-shell/client/e2e/web-shell.smoke.spec.ts
rounds=5 files=16 skipped=1
file packages/cli/src/acp-integration/acpAgent.test.ts: (cd packages/cli) npx --no-install vitest run ./src/acp-integration/acpAgent.test.ts
file packages/cli/src/acp-integration/model-configuration.test.ts: (cd packages/cli) npx --no-install vitest run ./src/acp-integration/model-configuration.test.ts
file packages/cli/src/acp-integration/session/Session.test.ts: (cd packages/cli) npx --no-install vitest run ./src/acp-integration/session/Session.test.ts
file packages/cli/src/config/settingsSchema.test.ts: (cd packages/cli) npx --no-install vitest run ./src/config/settingsSchema.test.ts
file packages/cli/src/serve/server.test.ts: (cd packages/cli) npx --no-install vitest run ./src/serve/server.test.ts
file packages/cli/src/serve/workspace-providers-status.test.ts: (cd packages/cli) npx --no-install vitest run ./src/serve/workspace-providers-status.test.ts
file packages/cli/src/utils/modelConfigUtils.test.ts: (cd packages/cli) npx --no-install vitest run ./src/utils/modelConfigUtils.test.ts
file packages/sdk-typescript/test/unit/DaemonClient.test.ts: (cd packages/sdk-typescript) npx --no-install vitest run ./test/unit/DaemonClient.test.ts
file packages/sdk-typescript/test/unit/DaemonSessionClient.test.ts: (cd packages/sdk-typescript) npx --no-install vitest run ./test/unit/DaemonSessionClient.test.ts
file packages/web-shell/client/App.test.tsx: (cd packages/web-shell) npx --no-install vitest run ./client/App.test.tsx
file packages/web-shell/client/components/ChatEditor.test.tsx: (cd packages/web-shell) npx --no-install vitest run ./client/components/ChatEditor.test.tsx
file packages/web-shell/client/components/messages/SettingsMessage.dom.test.tsx: (cd packages/web-shell) npx --no-install vitest run ./client/components/messages/SettingsMessage.dom.test.tsx
file packages/web-shell/client/utils/sessionPreparation.test.ts: (cd packages/web-shell) npx --no-install vitest run ./client/utils/sessionPreparation.test.ts
file packages/webui/src/daemon/session/DaemonSessionProvider.test.tsx: (cd packages/webui) npx --no-install vitest run ./src/daemon/session/DaemonSessionProvider.test.tsx
file packages/webui/src/daemon/session/actions.test.ts: (cd packages/webui) npx --no-install vitest run ./src/daemon/session/actions.test.ts
file packages/webui/src/daemon/session/mappers.test.ts: (cd packages/webui) npx --no-install vitest run ./src/daemon/session/mappers.test.ts


per-file results (P=pass F=fail I=infra-exit, one letter per run):
  packages/cli/src/acp-integration/acpAgent.test.ts: PP
  packages/cli/src/acp-integration/model-configuration.test.ts: PP
  packages/cli/src/acp-integration/session/Session.test.ts: PP
  packages/cli/src/config/settingsSchema.test.ts: PP
  packages/cli/src/serve/server.test.ts: PP
  packages/cli/src/serve/workspace-providers-status.test.ts: PP
  packages/cli/src/utils/modelConfigUtils.test.ts: P
  packages/sdk-typescript/test/unit/DaemonClient.test.ts: P
  packages/sdk-typescript/test/unit/DaemonSessionClient.test.ts: P
  packages/web-shell/client/App.test.tsx: P
  packages/web-shell/client/components/ChatEditor.test.tsx: P
  packages/web-shell/client/components/messages/SettingsMessage.dom.test.tsx: P
  packages/web-shell/client/utils/sessionPreparation.test.ts: P
  packages/webui/src/daemon/session/DaemonSessionProvider.test.tsx: P
  packages/webui/src/daemon/session/actions.test.ts: P
  packages/webui/src/daemon/session/mappers.test.ts: P

verdict: timeout
summary: the 15-minute budget elapsed before two full rounds completed (1 done) — no flakiness signal either way

--- per-invocation detail (full copy in the artifact) ---
round 1 · packages/cli/src/acp-integration/acpAgent.test.ts: P (exit 0)
round 1 · packages/cli/src/acp-integration/model-configuration.test.ts: P (exit 0)
round 1 · packages/cli/src/acp-integration/session/Session.test.ts: P (exit 0)
round 1 · packages/cli/src/config/settingsSchema.test.ts: P (exit 0)
round 1 · packages/cli/src/serve/server.test.ts: P (exit 0)
round 1 · packages/cli/src/serve/workspace-providers-status.test.ts: P (exit 0)
round 1 · packages/cli/src/utils/modelConfigUtils.test.ts: P (exit 0)
round 1 · packages/sdk-typescript/test/unit/DaemonClient.test.ts: P (exit 0)
round 1 · packages/sdk-typescript/test/unit/DaemonSessionClient.test.ts: P (exit 0)
round 1 · packages/web-shell/client/App.test.tsx: P (exit 0)
round 1 · packages/web-shell/client/components/ChatEditor.test.tsx: P (exit 0)
round 1 · packages/web-shell/client/components/messages/SettingsMessage.dom.test.tsx: P (exit 0)
round 1 · packages/web-shell/client/utils/sessionPreparation.test.ts: P (exit 0)
round 1 · packages/webui/src/daemon/session/DaemonSessionProvider.test.tsx: P (exit 0)
round 1 · packages/webui/src/daemon/session/actions.test.ts: P (exit 0)
round 1 · packages/webui/src/daemon/session/mappers.test.ts: P (exit 0)
round 2 · packages/cli/src/acp-integration/acpAgent.test.ts: P (exit 0)
round 2 · packages/cli/src/acp-integration/model-configuration.test.ts: P (exit 0)
round 2 · packages/cli/src/acp-integration/session/Session.test.ts: P (exit 0)
round 2 · packages/cli/src/config/settingsSchema.test.ts: P (exit 0)
round 2 · packages/cli/src/serve/server.test.ts: P (exit 0)
round 2 · packages/cli/src/serve/workspace-providers-status.test.ts: P (exit 0)

Evidence images

01-ab-summary-head-vs-base

02-head-arm-live-assertions

03-mutant-a-reconcile-removed-kills-4-tests

04-mutant-b-persist-write-disabled-kills-test

05-playwright-reasoning-e2e-10-scenarios

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

Qwen Code · sandboxed verification

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

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

@callmeYe
callmeYe requested a review from ytahdn August 29, 2026 14:14
@callmeYe
callmeYe enabled auto-merge August 29, 2026 14:50
…asoning-preferences

# Conflicts:
#	packages/webui/src/daemon/session/DaemonSessionProvider.tsx
@callmeYe

Copy link
Copy Markdown
Collaborator Author

Local retest follow-up: reproduced the Welcome reasoning regression by holding a pre-mutation provider snapshot for 500 ms. The daemon had already confirmed medium with persisted=true, but the late provider response replaced the confirmed preview and the next task rebuilt Welcome as the old tier. The update now applies the existing config-generation guard to provider snapshots as well. The same probe failed before the fix and passes at 41beaa6; the 9-case reasoning Playwright matrix, 408 focused WebUI tests, 139 focused WebShell tests, 438 TypeScript SDK tests, package typechecks/builds, lint, and format all pass. The broader CLI run passed 2540/2541; its unrelated side-task timing case passed immediately when rerun alone.

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Partially reviewed — gaps disclosed.

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

中文说明

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

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

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

Comment thread packages/cli/src/acp-integration/acpAgent.ts Outdated
Comment thread packages/cli/src/acp-integration/model-configuration.ts
Comment thread packages/cli/src/acp-integration/acpAgent.ts Outdated
Comment thread packages/cli/src/acp-integration/acpAgent.ts Outdated
Comment thread packages/cli/src/acp-integration/model-configuration.ts
Comment thread packages/web-shell/client/daemon/session/actions.test.ts
Comment thread packages/web-shell/client/daemon/session/actions.ts
Comment thread packages/web-shell/client/daemon/session/actions.ts
Comment thread packages/cli/src/utils/modelConfigUtils.ts
Comment thread packages/web-shell/client/e2e/web-shell.smoke.spec.ts
…asoning-preferences

Resolve sessionPreparation.ts import: take main's
@qwen-code/web-shell/daemon-react-sdk specifier and keep this branch's
ReasoningSelection type import.

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

Independent static review @ head 7ac6790 / 独立静态审查 @ head 7ac6790

Pure static review (no tests executed). Four module batches (ACP core / serve+schema+docs / SDK+session actions / web-shell UI) walked all 41 files at this head — a clean merge of origin/main whose substantive content is commits 14673c7, 6a9bf19, 4885a6b. I independently re-verified every one of the 25 findings from the latest /review round against the head tree, and also re-tested the earlier triage/verify "path is clean" conclusions on the exact disputed code paths. This message reports my own verdicts with evidence; it does not re-argue points where I simply agree with the inline threads.

纯静态审查(未运行测试)。4 个模块批次(ACP 核心 / serve+schema+docs / SDK+会话动作层 / web-shell UI)走查全部 41 个文件。head 是干净的 origin/main 合并,实质内容为三个提交 14673c7、6a9bf199、4885a6b0。我对最新一轮 /review 的 25 条 findings 逐条在 head tree 中独立复验,并对更早 triage/verify 轮"路径干净"的结论在争议代码路径上重新核对。本文只报告带证据的独立裁决。

What holds up / 站得住的部分

The boundaries are genuinely strict: the HTTP route derives _meta only from a validated boolean persist and never forwards client-supplied _meta (server.test pins all three properties); ReasoningSelection is a closed literal union across daemon/SDK/webui; the UI updates only after daemon confirmation with token/generation/model re-checks; fallbackEffort is gone tree-wide with no residue; the design doc matches the implemented contract point-for-point (default never stored, clear-don't-downgrade, no restore of dormant effort). The self-found Welcome preview regression fixes (6a9bf19, 4885a6b) are minimal and correctly guarded.

边界确实严格:HTTP 路由只从已校验的布尔 persist 派生 _meta、从不透传客户端 _meta(server.test 三个用例钉住);ReasoningSelection 在 daemon/SDK/webui 全链路是封闭字面量联合;界面只在 daemon 确认后更新并有 token/代际/模型复核;fallbackEffort 全树删净无残留;设计文档与实现契约逐条一致(default 不落盘、不兼容即清不降级、不恢复旧档位)。两次自发现的 Welcome 预览回归修复(6a9bf199、4885a6b0)最小化且防护正确。

Independently confirmed Criticals / 独立复验成立的 Critical

All 11 Critical findings from the /review round were re-verified line-by-line in the head tree and still hold. The earlier triage/verify conclusions on these same paths do not survive contact with the code (on each disputed path — reconcile ordering, none/default cleanup, refreshAuth interaction — the failure chain below walks through). Locations as they read at this head:

最新一轮 /review 的全部 11 条 Critical 均在 head tree 中逐行复验成立。更早的 triage/verify 轮对这些路径的"干净"结论与代码不符(每条争议路径——reconcile 顺序、none/default 清理、refreshAuth 交互——下述失败链都能走通)。位置以当前 head 为准:

  1. R1-1 acpAgent.ts:5763 — on the generic path applyReasoningSelection mutates the live generation config before setReasoningEffort runs and before the confirm readback; when generation.reasoning === false, {...(generation.reasoning || {}), effort} silently re-enables thinking (false || {} → {}). The merge base rejected the same request.
    通用路径先变异后回读:generation.reasoning === false{...(false || {}), effort} 静默重启用思考。合并基线对同一请求是拒绝。
  2. R1-2 config.ts:4109-4147refreshAuth restores only truthy prior reasoning (priorReasoning.effort), so the persisted none seed (reasoning = false) this PR introduces is wiped on every auth refresh and never restored; tier values mask the gap, false does not. Reconcile has exactly one call site (Session.setModel) — nothing re-seeds at session start.
    refreshAuth 只恢复 truthy 的旧值,本 PR 新引入的 none 种子(reasoning=false)每次鉴权刷新即被抹掉且不恢复;档位值掩盖缺口,false 不能。reconcile 唯一调用点是 setModel,会话启动无重播种。
  3. R1-3 acpAgent.ts:5743-5785 — settings write happens before live apply + confirm; default skips the static-knob cleanup (gate at 5747-5752), so on a model with extra_body: {enable_thinking: false} the confirm fails — but the persisted preference was already permanently cleared before the throw.
    设置写盘先于应用+确认;default 跳过静态旋钮清理,带 enable_thinking: false 静态旋钮的模型上确认必失败,但抛错前持久化值已被永久清除。
  4. R1-4 same gate — with a static knob configured, a "Default" reset can never complete its confirmation; pre-PR the cleanup ran for every selection on non-toggleOnly models.
    同一门控:有静态旋钮时 "Default" 复位永远无法通过确认;PR 前该清理对所有选择执行。
  5. R1-5 model-configuration.ts:160-174 — the default branch blank-wipes the whole reasoning object on both live and rebuildable config, destroying the sibling budget_tokens escape hatch; Config.setReasoningEffort (config.ts:5084-5097) deliberately deletes only effort and preserves siblings. The wipe on the rebuildable config also survives refreshAuth.
    default 分支整体擦除 reasoning 对象(live+rebuildable),摧毁兄弟字段 budget_tokens;与 setReasoningEffort 只删 effort 保兄弟的文档化不变量背离,且 rebuildable 上的擦除跨 refreshAuth 存续。
  6. R1-6 Session.ts:9827-9845 — reconcile runs after the irreversible switchModel; the mustClear path writes with throwOnWriteFailure: true, so a settings-write failure rejects setModel for a switch that already took effect, skips the subsequent model.name/baseUrl persistence (Session.ts:9889-9908, which is best-effort elsewhere in the same function), and re-throws on every later switch to an incompatible model until the disk is fixed.
    reconcile 在不可逆 switchModel 之后;mustClear 用 throwOnWriteFailure 写盘,写盘失败会使已生效的切换报错、跳过后续 model.name 持久化,且每次切不兼容模型重复抛错直到磁盘修复。
  7. R1-7 App.tsx:11460-11489 — the no-session branch derives a source selection from the model's reasoningPreview even when the user never touched a reasoning control, and fabricates {modelId, value: 'default'} for unsupported targets; default passes every support gate and reaches persistReasoningSelection('default') which deletes the stored value from all writable scopes. Concrete walk: persisted xhigh → on Welcome with zero reasoning interaction click a toggle-only model and back → first prompt sends setReasoningEffort('default', {persist: true}) → persisted setting silently deleted. The new e2e discards an incompatible welcome effort when switching away and back pins this destructive behavior as expected.
    无会话分支即使用户未碰推理控件也从预览推导源选择,并对不支持的目标伪造 {modelId,'default'}default 通过一切门控到达 persistReasoningSelection('default') 并删除所有可写 scope 的已存值。具体路径:持久化 xhigh → Welcome 零交互点仅开关模型再点回 → 首条提示发出 ('default', {persist:true}) → 持久化设置被静默删除。新 e2e 用例把这一破坏性行为钉成预期。
  8. R1-8 Session.ts:9935-9995persistReasoningSelection deletes the key from all sibling writable scopes (each a durable disk commit via throwOnWriteFailure) before writing the target scope; on target write failure the catch reloads only the target scope — the siblings' preferences are permanently destroyed. LoadedSettings.setValues (settings.ts:566-603) already implements correct multi-scope rollback but is not reused.
    persist 先删所有兄弟 scope(逐个落盘即永久提交)再写目标;目标写失败时 catch 只回滚目标 scope,兄弟偏好永久丢失。setValues 已有正确的多 scope 回滚但未被复用。
  9. R1-9 App.tsx:6747-6756 + 11480-11486 — the none→default conversion is a one-way latch in both the effect and handleModelSelect; no transition ever restores none when disabling becomes supported again. Baseline (setPendingReasoningIntent(undefined) in the same effect) sent nothing for this sequence — this is a regression. The rewritten unit test clears a stale welcome disable after reasoning becomes mandatory pins the latch.
    none→default 单向闩锁(effect 与 handleModelSelect 两处),禁用重新受支持后也不恢复。合并基线该序列什么都不发——是回归。改写的单测把闩锁钉成预期。
  10. R1-10 App.tsx:11463-11464 — the welcome branch of handleModelSelect is the only read site of pendingReasoningIntent without the modelId === currentModel gate (the other three reads at 6222, 6749, 6764 all gate). A stale intent left by the /model no-session branch revives on the next model click and is applied — or, combined with R1-7, converted to a destructive default — at first-prompt time with {persist: true}. Baseline applied nothing here; regression, no timing dependency.
    welcome 分支是唯一不做 modelId === currentModel 门控的意图读取点(其余三处 6222/6749/6764 均有门控)。/model 无会话分支留下的孤儿意图在下次点模型时复活并被应用,或与 R1-7 叠加转成破坏性 default。基线此处不应用任何东西;回归,无时序依赖。
  11. R1-11 actions.ts:1707-1712clearSession awaits the pending persisted mutation before capturing sessionRef.current and setting manualSessionClearRef.current = true (both synchronous at entry on the merge base). The await window is up to DEFAULT_ACTION_TIMEOUT_MS (30s); a session create/attach landing inside it sets the flag false at entry (createSession:1492), passes its own abort check, and commits sessionRef.current = nextSession — clearSession then detaches the freshly created session, and the designed AbortError interruption path is bypassed. Fix direction: keep the await, move the capture + flag-set before it.
    clearSession 在捕获会话与置清除标志之前 await 挂起的持久化动作(基线这两步同步)。窗口最长 30s;窗口内落地的 create 会置标志为 false、通过自身检查并提交新会话,随后被恢复的 clearSession 剥离 detach,设计内的中断路径被绕过。修复方向:保留 await,把捕获与置标志前移。

Two test files pin the R1-7/R1-9 defective behaviors and must be rewritten together with the fixes, otherwise they will block correct repairs: web-shell.smoke.spec.ts (the discards-an-incompatible-welcome-effort case) and App.test.tsx (clears-a-stale-welcome-disable).

两个测试文件把 R1-7/R1-9 的缺陷行为钉成预期,修复时必须同步改写,否则会阻挡正确修复。

Three root-cause patterns cover most of the above: (a) write-first/mutate-first, confirm-later non-atomic ordering (3/6/8); (b) the new reasoning === false state is not accepted by the existing "restore only truthy" machinery (1/2); (c) default semantics interact badly with static knobs and sibling fields (3/4/5).

三类根因覆盖大部分问题:(a) 先写盘/先变异、后确认的非原子顺序(3/6/8);(b) 新状态 reasoning === false 未被既有"仅恢复 truthy"机制接纳(1/2);(c) default 与静态旋钮/兄弟字段的交互未清理(3/4/5)。

New finding (this review) / 本次新发现

🟡 Important — out-of-catalog Qwen-family models lose their entire ACP reasoning surface. buildConfigOptions gains an early return (acpAgent.ts:13156-13165) when !isReasoningSelectionSupported(rawCurrentModelId, 'default'), and that function returns false for every selection — including default — whenever the model has no MODEL_CONFIGURATIONS entry but matches the qwen family prefix (model-configuration.ts:136-138). So qwen-plus / dated aliases / coder variants that previously went through the generic path (effort applied via applyReasoningEffort, set_config_option accepted) now get no reasoning option at all and a "not supported" rejection. The PR description states this hiding is deliberate for unknown Qwen models — if so, please confirm the product consequence for existing ACP users of those model ids and pin the rejection with a test; nothing in the diff currently does. (Same shape as the deferred-model decision in the predecessor PR; still worth an explicit confirmation because it shrinks a previously working surface.)

🟡 Important — 表外 Qwen 系模型整体失去 ACP 推理控制面。 buildConfigOptions 新增早退(acpAgent.ts:13156-13165):!isReasoningSelectionSupported(rawCurrentModelId, 'default') 时直接返回;而该函数对无 MODEL_CONFIGURATIONS 条目但匹配 qwen 系前缀的模型(model-configuration.ts:136-138)对包括 default 在内的一切选择返回 false。于是 qwen-plus / 带日期别名 / coder 变体等此前走通用路径(档位经 applyReasoningEffort 生效、set_config_option 被接受)的模型,现在完全没有推理选项并得到 "not supported" 拒绝。PR 描述称对未知 Qwen 模型隐藏控件是有意为之——若是,请确认这些模型 id 的既有 ACP 用户的产品后果,并用测试钉住该拒绝;diff 中目前没有任何测试覆盖。(与前序 PR 的 deferred-model 决定同形;因它收缩了此前可用的表面,仍值得显式确认。)

Confirmed suggestions (compact) / 成立的建议(摘要)

All 15 suggestion-level findings from the /review round were re-verified and hold, with two refinements: R1-13's stale object is the concurrently-running runtime sub-agent generator config, not the primary (daemon RPC handlers execute outside the ALS); R1-20's premise needs correction — the /model branch's drop of pending intent pre-existed this PR, what is new is the menu-path-vs-slash-path inconsistency (design doc line "Every model switch reconciles the stored selection") and the fact that /model orphans can now feed the R1-10 revival. Additionally R1-21 (two interpreters) upgrades in practice: a hand-edited non-canonical value (e.g. "High") is applied by the lenient CLI path but the strict parseReasoningSelection makes the first reconcile treat it as mustClear — silent permanent deletion of a value another surface considers valid. Product writers only ever write canonical values, so trigger requires hand-edited settings; still worth normalizing at read or at load.

/review 轮的 15 条 Suggestion 级 findings 全部复验成立,两点精化:R1-13 真正滞留的是并发运行中的运行时子代理 generator 配置而非 primary(daemon RPC handler 在 ALS 外执行);R1-20 前提需更正——/model 分支丢弃意图早于本 PR,新增的是菜单路径与斜杠路径的不一致(设计文档声称"每次模型切换都协调已存选择")以及 /model 孤儿意图现在会喂养 R1-10 的复活。另 R1-21(双解释器)实际后果升级:手编非规范值(如 "High")被宽容 CLI 路径应用,但严格 parseReasoningSelection 使首次 reconcile 判其 mustClear——被另一读取面认为合法的值遭静默永久删除。产品内写入方只写规范值,触发需手改 settings;仍建议读取侧或加载侧归一化。

CI status at head / head 上的 CI 状态

Facts, not verdict: at this head the primary Qwen Code CI run (Test ubuntu, web-shell E2E Smoke, Serve A/B) was cancelled mid-run — there is no green primary-suite result for it. The SDK Java lane failed on Java 11 only (DaemonSessionClientTest transport timeouts, 15/103; Java 17/21 green); this PR contains no Java changes and the same lane was green on the previous head, so that failure looks environmental, but CI must land green before the merge queue regardless.

事实陈述而非裁决:当前 head 的主 CI 运行(Test ubuntu、web-shell E2E Smoke、Serve A/B)中途被取消——没有绿色主套件结果。SDK Java 仅 Java 11 失败(DaemonSessionClientTest 传输超时,15/103;Java 17/21 绿);本 PR 无任何 Java 改动且同一 lane 在上一个 head 是绿的,该失败更像环境问题,但无论如何入合并队列前 CI 需全绿。

Verdict / 结论

💬 Comment — changes needed. The contract and typing work are solid, but 11 Criticals are independently confirmed at this head (several are regressions against the merge base with concrete data-loss walks), plus one new Important. I cannot approve until these are addressed; the fix directions above are consistent with the inline threads.

💬 评论——需要修改。 契约与类型工作是扎实的,但当前 head 上 11 条 Critical 经独立复验全部成立(其中数条是对合并基线的回归,有具体的数据丢失路径),另加一条新 Important。在这些解决之前无法批准;上述修复方向与行内讨论一致。

@callmeYe

Copy link
Copy Markdown
Collaborator Author

Review follow-up at b5f5359

Accepted and fixed:

  • R1-1, R1-3 through R1-6, R1-8, R1-10, and R1-11.
  • R1-2 is fixed at the daemon authentication boundary by replaying only an explicitly persisted none after refreshAuth. I did not add a global Core restore for every reasoning=false value because provider and model presets share that shape and a global restore can carry stale state across model switches.

Intentional scope decisions:

  • R1-7 and R1-9 are unchanged. The design contract is clear-never-restore: once a tier or none becomes incompatible, switching back does not revive it. Welcome therefore carries default until first send so the deletion is persisted without pre-creating a session.
  • The unknown-Qwen Important is also intentional fail-closed behavior. Unregistered Qwen model ids do not advertise ACP reasoning controls because capability is unknown. A direct qwen-plus regression now asserts that the option is absent and mutation is rejected.
  • Suggestion-level items were recorded as deferred in their individual threads. This update stays limited to confirmed correctness blockers after repeated review rounds.

Validation:

  • CLI focused files: 1320 passed.
  • WebShell App and session actions: 717 passed.
  • Reasoning UI, localization, hidden-setting, and first-send ordering: 140 passed.
  • Focused Playwright reasoning matrix: 10 passed.
  • Root build and typecheck passed.
  • CLI and WebShell lint passed.
  • Changed files passed Prettier check.

@callmeYe
callmeYe dismissed qwen-code-ci-bot’s stale review August 30, 2026 03:18

Stale automated review on 41beaa6. Current head b5f5359 addresses or explicitly resolves every Critical thread with focused regression evidence; a fresh review is required for the new head.

@callmeYe

Copy link
Copy Markdown
Collaborator Author

@qwen-code /review

@callmeYe

Copy link
Copy Markdown
Collaborator Author

CI follow-up at a1b25139b1:

  • Corrected this PR’s own stale type-only SDK import in the ChatEditor test (@qwen-code/webui/daemon-react-sdk@qwen-code/web-shell/daemon-react-sdk).
  • Focused ChatEditor coverage passes 105/105; WebShell typecheck, focused ESLint, Prettier, and git diff --check pass.
  • The remaining two local WebShell failures are exclusively main-boot.test.tsx, whose stale mock is unchanged on current origin/main and is already isolated in test(web-shell): mock the provider module main.tsx actually imports in the boot test #10526. I did not copy that unrelated baseline fix into this feature PR.

@callmeYe

Copy link
Copy Markdown
Collaborator Author

@qwen-code /review

@callmeYe

Copy link
Copy Markdown
Collaborator Author

Baseline follow-up at 9c63c7f163:

#10526 has merged, so I normally merged the latest origin/main into this branch (no history rewrite). The formerly failing main-boot path now comes from upstream. Local verification on the resulting tree:

  • main-boot.test.tsx + ChatEditor.test.tsx: 107/107
  • full WebShell suite with coverage: 232/232 files, 5233/5233 tests
  • WebShell typecheck and git diff --check: pass

No additional feature logic was added.

@callmeYe

Copy link
Copy Markdown
Collaborator Author

@qwen-code /review

@github-actions

Copy link
Copy Markdown
Contributor

Qwen Code review request accepted. Review is running in workflow run. A command-triggered review is not listed under the checks of this PR; the result is posted here as a review when it finishes.

@qwen-code-ci-bot

Copy link
Copy Markdown
Collaborator

Qwen Code review did not complete successfully. The review pipeline failed before a review could be posted. A transient error is retried automatically; if you are seeing this, retry with @qwen-code /review. See workflow logs.

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Partially reviewed — gaps disclosed.

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

  • R1-13 applyReasoningSelection context-dependent config target — already reported (round 1 inline comment), author deferred
  • R1-14 strict === 'none' vs normalized tiers — already reported, author deferred
  • R1-16 persist gate negative test absent — already reported, author deferred
  • R1-17 route/runtime allowReasoning:false clear untested — already reported, author deferred (re-discovered independently this round)
  • R1-18 none-seed thinkingMandatory guard untested — already reported, author deferred (re-discovered three times independently)
  • R1-19 SDK positional clientId overload untested — already reported, author deferred (re-discovered)
  • R1-20 /model slash path bypasses intent reconciliation — already reported, author deferred (re-discovered; the PR's own design doc says 'Every model switch reconciles the stored selection')
  • R1-21 two disagreeing interpreters of model.reasoningEffort — already reported, author deferred (alias-deletion escalation re-discovered by this round's audit and the independent review)
  • R1-22 smoke test rewrite dropped cross-model coverage — already reported, author deferred
  • R1-23 non-persist success test converted to persist:true — already reported, author deferred
  • R1-24 preview merged into target model provider entry only — already reported, author deferred
  • R1-25 pendingPersistedReasoningAction unconditional overwrite — already reported, author deferred
  • R1-26 unhonored 'none' silently dropped without warning — already reported, author deferred (re-discovered)
  • R1-27 no-refetch guard lacks settling — already reported, author deferred

Not reviewed: build-and-test — no test suite could be executed in this review: the build-test run exhausted its budget on install + dependency builds (packages/cli build timed out — infrastructure; web-shell, vscode-ide-companion, webui never built), and the test-efficacy probe was 18/18 inconclusive (harnessValidated null).

Not reviewed: build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally; Test (ubuntu-latest, Node 22.x) failed at this commit.

Not explored to full depth (tool budget reached): "agent 1b": none — though I did not trace where resolveCliGenerationConfig 's output is stored in ModelsConfig at daemon boot, so I could not rule in/out that a persiste…; chunk 4: executing Session.test.ts reasoning tests in the worktree (no node_modules present; dependency install plus prerequisite builds would exceed the tool budget) — ….

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

  • packages/cli/src/acp-integration/session/Session.ts:9925 — [review] managed-session persist guard untested (D2-1)
  • packages/cli/src/acp-integration/acpAgent.ts:7042 — [review] acpAgent-side persisted projection untested (D2-2)
  • packages/web-shell/client/e2e/web-shell.smoke.spec.ts:586 — [review] no-refetch guard counts an endpoint the client never fetches (D2-3)
  • packages/web-shell/client/e2e/web-shell.smoke.spec.ts:554 — [review] turn-complete event promptId can never match — silent no-op (D2-4)
中文说明

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

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

未审查:build-and-test — no test suite could be executed in this review: the build-test run exhausted its budget on install + dependency builds (packages/cli build timed out — infrastructure; web-shell, vscode-ide-companion, webui never built), and the test-efficacy probe was 18/18 inconclusive (harnessValidated null)。

未审查:build-and-test — Integration Tests (CLI, No Sandbox) was skipped in CI and its suite did not run locally; Test (ubuntu-latest, Node 22.x) failed at this commit。

未探索到全部深度(达到工具调用预算):"agent 1b"none — though I did not trace where resolveCliGenerationConfig 's output is stored in ModelsConfig at daemon boot, so I could not rule in/out that a persiste…;chunk 4:executing Session.test.ts reasoning tests in the worktree (no node_modules present; dependency install plus prerequisite builds would exceed the tool budget) — …

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

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

'The persisted reasoning preference. Use none to disable thinking, a supported effort tier to enable it, or leave it unset to use the model/provider default.',
showInDialog: true,
options: [
{ value: 'none', label: 'None' },

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Critical] R2-1: [certifies-falsely] [new-surface] This diff adds none to the dialog-visible (showInDialog: true) model.reasoningEffort options and rewrites the description to tell users "Use none to disable thinking" — but the TUI settings dialog is the one surface where none is never honored. A TUI user who follows the new description and picks None saves model.reasoningEffort: 'none'; every subsequent TUI/headless session seeds reasoning: false in resolveCliGenerationConfig, then performInitialAuth runs the plain core Config.refreshAuth, whose syncAfterAuthRefresh overwrites every MODEL_GENERATION_CONFIG_FIELDS entry (including reasoning) and whose restore block re-applies only a TRUTHY prior effort — false is excluded (the code comment says so). Only the daemon's refreshAuthWithPersistedReasoning replays a persisted none; no TUI/headless path uses it. Net effect: thinking stays ON (thinking tokens billed) in every session while the setting still says none. Pre-PR the dialog offered no none option, so this trap was unreachable — the PR creates the surface the pre-existing wipe defeats.

Witness:

probe (packages/core scratch tree, seeded generationConfig.reasoning=false, refreshAuth as performInitialAuth does):
PR:    FAIL  AssertionError: expected undefined to be false   <- seeded disable dropped by the initial auth refresh
FIXED: 1 passed   <- with a restore branch for priorReasoning === false; probe flips

Until TUI/headless flows honor none, stop advertising it in the TUI dialog: set showInDialog: false for model.reasoningEffort (Web Shell already hides this key via SettingsMessage), or exclude none from the dialog options while keeping it in the schema. Note that enum writes are validated against def.options at packages/cli/src/config/settingsUtils.ts:235 — removing none from the schema options outright would reject API-driven none writes, so hide it from the dialog instead; settingsSchema.test.ts 'accepts none but never stores the default reasoning command' asserts the options list contains none. Please add a settingsSchema/settingsUtils test asserting the TUI settings dialog does not offer none for model.reasoningEffort, then remove that protection and confirm the new test reds.

中文说明

本 diff 把 none 加入了对话框可见(showInDialog: true)的 model.reasoningEffort 选项,并把描述改写为告诉用户 "Use none to disable thinking"——但 TUI 设置对话框恰恰是 none 从不生效的表面。TUI 用户按新描述选择 None 后会保存 model.reasoningEffort: 'none';此后每个 TUI/headless 会话先经 resolveCliGenerationConfig 播种 reasoning: false,随后 performInitialAuth 直接调用 core 的 Config.refreshAuth,其 syncAfterAuthRefresh 会用预设覆盖所有 MODEL_GENERATION_CONFIG_FIELDS 条目(含 reasoning),而恢复块只恢复 truthy 的旧 effort——false 被排除(代码注释明确说明)。只有 daemon 的 refreshAuthWithPersistedReasoning 会重放持久化的 none;TUI/headless 路径均不使用。结果:设置仍是 none,但每个会话思考都保持开启(计费思考 token)。PR 前对话框没有 none 选项,该陷阱不可达——是本 PR 创造了这个被既有刷新机制击败的表面。

见证(probe,packages/core 临时树,播种 generationConfig.reasoning=false,按 performInitialAuth 方式调用 refreshAuth):PR 原样 FAIL(AssertionError: expected undefined to be false,初始鉴权刷新丢弃了播种的禁用);加上 priorReasoning === false 恢复分支后 1 passed,探针翻转。

在 TUI/headless 支持 none 之前,请停止在 TUI 对话框中提供它:将 model.reasoningEffort 设为 showInDialog: false(Web Shell 已通过 SettingsMessage 隐藏该键),或保留 schema 选项但在对话框中排除 none。注意枚举写入在 packages/cli/src/config/settingsUtils.ts:235def.options 校验——直接从 schema 删除 none 会拒绝 API 驱动的 none 写入,因此应只在对话框层面隐藏;settingsSchema.test.ts 的 'accepts none but never stores the default reasoning command' 断言选项列表包含 none。请新增 settingsSchema/settingsUtils 测试,断言 TUI 设置对话框不为 model.reasoningEffort 提供 none,然后移除该保护并确认新测试变红。

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

Comment on lines +12209 to +12213
await this.refreshAuthWithPersistedReasoning(
config,
this.settings,
authType,
);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Critical] R2-2: [certifies-falsely] [new-surface] workspaceReload's model-name-change branch (await config.switchModel(authType, newModelName), ~12194) wipes the session's live reasoning: false and never re-applies the persisted model.reasoningEffort: 'none' — unlike this wrapped sibling branch here, and unlike Session.setModel, whose post-switch reconcileReasoningSelection re-applies a compatible persisted selection after the same core switchModel call. applyResolvedModelDefaults overwrites every MODEL_GENERATION_CONFIG_FIELDS entry (reasoning included); on the full-refresh path the restore re-applies only truthy effort. Concretely: a user persists none (settings written, live reasoning = false); model.name changes in settings.json and a workspace reload runs — the handler takes the model-change branch, reasoning is wiped, and the session silently runs with thinking ON while settings still say none, until some unrelated replay fires. The identical switch via setSessionConfigOption reconciles correctly. At merge base none was not a storable value, so this state could not be lost.

Witness:

probe (real ModelsConfig, scratch tree):
PR:    seeded reasoning=false; switch to a preset-less model -> reasoning=undefined
CTRL:  switch to a model whose preset carries reasoning:false -> reasoning=false (preserved)

Reuse the replay half of refreshAuthWithPersistedReasoning (persisted-none check + support gate + applyReasoningSelection(config, REASONING_EFFORT_NONE)) after await config.switchModel(authType, newModelName) succeeds in that branch. Keep the wrapper's support gate isReasoningSelectionSupported(modelId, REASONING_EFFORT_NONE, generation?.thinkingMandatory === true) (model-configuration.ts:130) so none is never replayed onto a thinking-mandatory model. Please extend the acpAgent.test.ts workspaceReload suite: merged settings { model: { name: 'next-model', reasoningEffort: 'none' } }, live reasoning: false; after workspaceReload assert the session's generation config still has reasoning === false on the new model — then remove the post-switchModel replay and confirm the new test reds.

中文说明

workspaceReload 的模型名变更分支(await config.switchModel(authType, newModelName),约 12194 行)会抹掉会话 live 的 reasoning: false,且从不重新应用持久化的 model.reasoningEffort: 'none'——不同于此处被包装的兄弟分支,也不同于 Session.setModel(其在同一个 core switchModel 调用之后通过 reconcileReasoningSelection 重新应用兼容的持久化选择)。applyResolvedModelDefaults 会覆盖所有 MODEL_GENERATION_CONFIG_FIELDS 条目(含 reasoning);全量刷新路径上的恢复只恢复 truthy effort。具体场景:用户持久化 none(设置已写盘,live reasoning = false);settings.json 中 model.name 变化触发 workspace reload——handler 走模型变更分支,reasoning 被抹掉,设置在仍为 none 的情况下会话静默以思考开启运行,直到某个无关的重放触发。同样的切换经 setSessionConfigOption 则会正确 reconcile。合并基线上 none 不可持久化,因此该状态不可能丢失。

见证(probe,真实 ModelsConfig,临时树):播种 reasoning=false 后切换到无预设模型 → reasoning=undefined;对照组切换到预设携带 reasoning:false 的模型 → reasoning=false(保留)。

请在该分支的 await config.switchModel(authType, newModelName) 成功后,复用 refreshAuthWithPersistedReasoning 的重放半边(持久化 none 检查 + 支持门控 + applyReasoningSelection(config, REASONING_EFFORT_NONE))。保留包装器的支持门控 isReasoningSelectionSupported(modelId, REASONING_EFFORT_NONE, generation?.thinkingMandatory === true)(model-configuration.ts:130),避免把 none 重放到强制思考模型上。请扩展 acpAgent.test.ts 的 workspaceReload 套件:合并设置 { model: { name: 'next-model', reasoningEffort: 'none' } }、live reasoning: false;workspaceReload 后断言新模型上会话的 generation config 仍为 reasoning === false——然后移除 switchModel 后的重放并确认新测试变红。

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

Comment on lines +156 to +159
if (selection === REASONING_EFFORT_NONE) {
generation.reasoning = false;
return;
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Critical] R2-3: [certifies-falsely] [new-surface] The 'none' branch assigns generation.reasoning = false, destroying sibling fields — user-configured budget_tokens, the Anthropic escape hatch, which is settings-reachable because reasoning is a MODEL_GENERATION_CONFIG_FIELDS member — on both the live config and the rebuildable ModelsConfig._generationConfig. No later selection restores them: 'default' hits !generation.reasoningundefined, tier branches spread false || {}, and mergeSettingsGenerationConfig cannot repair because the reasoning key was assigned, not deleted (its guard is !(field in this._generationConfig), modelsConfig.ts:645-648). This defeats the sibling-preservation guarantee your R1-5 fix pins in 'preserves reasoning siblings when returning to the model default'. A user with model.generationConfig.reasoning: { budget_tokens: N } who gets 'none' applied (Web Shell toggle on a generic model, reconcileReasoningSelection, or the auth-refresh replay) loses budget_tokens permanently: turning thinking back on never restores it, settings still declare budget_tokens: N, and every request runs effort-derived thinking for the daemon's lifetime. The seed site has the same defect: resolveCliGenerationConfig (modelConfigUtils.ts:445) assigns reasoning = false at daemon session construction, discarding settings-derived siblings before this function ever runs.

Witness:

probe (real applyReasoningSelection, scratch tree):
baseline-default live={"reasoning":{"budget_tokens":42000}}   <- control arm preserves
after-none live={"reasoning":false} -> after-default live={} -> after-high live={"reasoning":{"effort":"high"}}
                                                                  <- budget_tokens gone permanently

Preserve siblings across the false transition: capture the prior reasoning object before overwriting with false (e.g. a WeakMap keyed by the generation config) and re-spread the stashed siblings (minus effort for 'default') when leaving false — or re-merge settings-derived reasoning siblings on leaving false; cover the seed site in resolveCliGenerationConfig too, since a stash inside this function has nothing to stash there. The reasoning === false wire signal must survive: core Config.setReasoningEffort (if (!cfg || cfg.reasoning === false) return;, config.ts:5091) and anthropicContentGenerator.ts both key off it, and restoring siblings on 'default' must not resurrect a stale effort. Please extend 'preserves reasoning siblings when returning to the model default' into a none→default cycle (start live/rebuildable at { effort: 'high', budget_tokens: 42000 }, apply 'none' then 'default', assert { budget_tokens: 42000 } — it reds today), and confirm it still reds when the preservation is removed.

中文说明

'none' 分支直接赋值 generation.reasoning = false,会摧毁同级字段——用户配置的 budget_tokens(Anthropic 逃生舱;reasoningMODEL_GENERATION_CONFIG_FIELDS 成员,可经设置写入)——且同时作用于 live 与可重建的 ModelsConfig._generationConfig。之后任何选择都无法恢复它们:'default' 命中 !generation.reasoningundefined,档位分支展开 false || {},而 mergeSettingsGenerationConfigreasoning 键是被赋值而非删除(其守卫为 !(field in this._generationConfig),modelsConfig.ts:645-648)无法修复。这击败了 R1-5 修复在 'preserves reasoning siblings when returning to the model default' 中钉住的同级保留保证。配置了 model.generationConfig.reasoning: { budget_tokens: N } 的用户一旦被应用 'none'(通用模型上的 Web Shell 开关、reconcileReasoningSelection 或鉴权刷新重放),budget_tokens 永久丢失:重新开启思考不会恢复它,设置仍声明 budget_tokens: N,而整个 daemon 生命周期内每个请求都按 effort 推导思考。播种点存在同样缺陷:resolveCliGenerationConfig(modelConfigUtils.ts:445)在 daemon 会话构造时赋值 reasoning = false,在本函数运行前就丢弃了来自设置的同级字段。

见证(probe,真实 applyReasoningSelection,临时树):基线 default 时 live={"reasoning":{"budget_tokens":42000}}(对照组保留);应用 none 后 live={"reasoning":false} → default 后 live={} → high 后 live={"reasoning":{"effort":"high"}}——budget_tokens 永久消失。

请跨 false 转换保留同级字段:在用 false 覆盖前捕获原 reasoning 对象(如以 generation config 为键的 WeakMap),离开 false 时重新展开暂存的同级字段('default' 时去掉 effort)——或在离开 false 时重新合并来自设置的 reasoning 同级字段;同时覆盖 resolveCliGenerationConfig 播种点,因为本函数内的暂存在那里无物可存。reasoning === false 线信号必须保留:core Config.setReasoningEffortif (!cfg || cfg.reasoning === false) return;,config.ts:5091)与 anthropicContentGenerator.ts 都依赖它,且 'default' 恢复同级字段时不得复活陈旧的 effort。请把 'preserves reasoning siblings when returning to the model default' 扩展为 none→default 循环(起始 live/可重建为 { effort: 'high', budget_tokens: 42000 },依次应用 'none''default',断言 { budget_tokens: 42000 }——当前即为红色),并确认移除保留逻辑后该测试仍变红。

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

Comment on lines 1708 to +1712
const session = sessionRef.current;
manualSessionClearRef.current = true;
if (pendingPersistedReasoningAction) {
await pendingPersistedReasoningAction.catch(() => undefined);
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Critical] R2-4: [certifies-falsely] [new-surface] After your R1-11 fix (session captured + manualSessionClearRef set before the await — good), clearSession still resumes into the unconditional global resets below (clearActiveSessionState(); sessionRef.current = undefined) without re-validating the captured session — and the flag blocks no creation/attach path: createSession resets manualSessionClearRef as its first act (actions.ts:1492), submitPrompt never checks it, and the UI stays interactive during the up-to-30s await (DEFAULT_ACTION_TIMEOUT_MS; the only composer gate, sessionWriteBlocked = Boolean(connection.loadingTranscript), is not set). A session committed inside that window is destroyed: clearActiveSessionState() aborts its in-flight prompt controller, the transcript store is reset, sessionRef.current = undefined orphans it, and getConnectionAfterSessionClear skips field-stripping (current.sessionId !== clearedSessionId) — leaving a connection claiming session-b with no client, and session-b never detached on the daemon.

Witness:

probe (real createDaemonSessionActions, scratch tree; persist pending, replacement session committed mid-await):
PR:    after={"sessionRef":"undefined","connectionSessionId":"session-b","promptAborted":true,"storeResetCalls":1,"sessionADetachCalls":1,"sessionBDetachCalls":0}
FIXED: after={"sessionRef":"session-b","connectionSessionId":"session-b","promptAborted":false,"storeResetCalls":0,...}   <- probe flips

After the await, skip the global resets when the session was replaced during the wait (sessionRef.current !== undefined && sessionRef.current !== session), while still completing the captured session's connection cleanup and detach. The test added by this diff, 'captures and marks a clear before waiting for persisted reasoning', pins that a mid-window swap still completes the captured session's cleanup (session.detach once, replacement not detached) — the guard must skip only the global resets, not early-return wholesale. Please add an actions.test.ts case that fully attaches a replacement during the unresolved persist and asserts sessionRef.current is still the replacement, connection.sessionId is still 'session-b', and no registered active prompt was aborted — then remove the guard and confirm it reds.

中文说明

在 R1-11 修复之后(await 之前捕获会话并置位 manualSessionClearRef——很好),clearSession 恢复后仍会无条件执行下方的全局重置(clearActiveSessionState(); sessionRef.current = undefined),没有复核捕获的会话是否仍然有效——而且该标志无法阻止任何创建/挂载路径:createSession 第一步就重置 manualSessionClearRef(actions.ts:1492),submitPrompt 从不检查它,且 UI 在最长 30 秒的 await 期间保持可交互(DEFAULT_ACTION_TIMEOUT_MS;唯一的输入框门控 sessionWriteBlocked = Boolean(connection.loadingTranscript) 未置位)。在该窗口内落地的会话会被摧毁:clearActiveSessionState() 中止其进行中的 prompt 控制器,转写存储被重置,sessionRef.current = undefined 使其成为孤儿,而 getConnectionAfterSessionClear 跳过字段剥离(current.sessionId !== clearedSessionId)——留下一个声称 session-b 却无客户端的连接,且 session-b 从未在 daemon 上 detach。

见证(probe,真实 createDaemonSessionActions,临时树;persist 挂起期间替换会话落地):PR 原样 after={"sessionRef":"undefined","connectionSessionId":"session-b","promptAborted":true,"storeResetCalls":1,...};修复后 after={"sessionRef":"session-b","connectionSessionId":"session-b","promptAborted":false,"storeResetCalls":0,...},探针翻转。

请在 await 之后、当等待期间会话已被替换时(sessionRef.current !== undefined && sessionRef.current !== session)跳过全局重置,同时继续完成被捕获会话的连接清理与 detach。本 diff 新增的测试 'captures and marks a clear before waiting for persisted reasoning' 钉住了窗口内替换仍完成被捕获会话的清理(session.detach 一次、替换会话不 detach)——守卫只应跳过全局重置,而不是整体提前返回。请新增 actions.test.ts 用例:在未解析的 persist 期间完整挂载替换会话,断言 sessionRef.current 仍是替换会话、connection.sessionId 仍是 'session-b'、已注册的活跃 prompt 未被中止——然后移除守卫并确认变红。

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

Comment on lines +5796 to +5799
if (persist) {
reasoningSelectionPersisted =
session.persistReasoningSelection(selected);
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] R2-5: A persistence failure throws AFTER the live reasoning selection was applied and confirmed here — the request reports failure while the daemon session keeps the changed live state, and nothing rolls it back. Two reachable triggers at head: an unwritable settings file (read-only checkout, EROFS/ENOSPC — writeReasoningSelection uses throwOnWriteFailure: true) with persist: true, which Web Shell always sends; and a standalone-source session whose persistReasoningSelection deliberately throws RequestError.invalidParams. The client then shows "Failed to update reasoning options" and keeps its old connection.reasoning, while the daemon session actually runs with the new selection until the next context resync — error and reality disagree. Creation-path consequence: sessionPreparation.ts:146 hard-codes { persist: true }, so the same failure aborts the whole first prompt — the freshly created session is released and cleared, the prompt is never sent, and every retry fails identically in that environment; the mid-session toggle path, by contrast, keeps running. This ordering is fix-induced: the R1-3 fix moved persist after confirm, which created the apply-then-throw path.

Witness:

witness: not run — the ordering is unconditional in the quoted source (apply -> confirm -> persist, no try/catch between), and both throw paths were verified at their definitions (settings.ts saveSettings rethrows under throwOnWriteFailure; Session.ts managed-session invalidParams)

Wrap the persistence call so a failure rolls the live/rebuildable generation config back to its pre-request reasoning value before rethrowing (or persist before applying) — but do not swallow the failure: the design doc's "writes the setting and live state before returning success" must hold (no success on a failed write), and genuine apply failures must still abort the creation path (pinned by 'releases and clears the session when an explicit reasoning effort cannot be applied'). Note the client confirmation contract at actions.ts:1254 (if (!confirmed || (opts?.persist && result.persisted !== true))) must survive any fix. Please add an acpAgent.test.ts case where persistReasoningSelection throws with the persist meta set — assert the request rejects AND generation.reasoning is restored to its prior value; removing the rollback/reorder must turn it red.

中文说明

持久化失败会在 live 思考选择已应用并确认之后才抛出——请求报告失败,但 daemon 会话保持已变更的 live 状态,且没有任何回滚。当前 head 有两个可达触发:设置文件不可写(只读 checkout、EROFS/ENOSPC——writeReasoningSelection 使用 throwOnWriteFailure: true)且带 persist: true(Web Shell 总是发送);以及 persistReasoningSelection 故意抛出 RequestError.invalidParams 的 standalone 来源会话。客户端随后显示 "Failed to update reasoning options" 并保留旧的 connection.reasoning,而 daemon 会话实际以新选择运行直到下次上下文重同步——错误与现实不一致。创建路径后果:sessionPreparation.ts:146 硬编码 { persist: true },同样的失败会中止整个首条 prompt——新创建的会话被释放清除、prompt 从未发送,且在该环境下每次重试都以相同方式失败;而会话中的切换路径则继续运行。该顺序是修复引入的:R1-3 修复把持久化移到确认之后,从而产生了先应用后抛错的路径。

见证:未运行——顺序在引用源码中是无条件的(应用 → 确认 → 持久化,中间无 try/catch),两个抛出路径均已在其定义处核实(settings.ts 的 saveSettings 在 throwOnWriteFailure 下重新抛出;Session.ts 的 managed-session invalidParams)。

请包装持久化调用,使失败时先把 live/可重建 generation config 回滚到请求前的 reasoning 值再重新抛出(或先持久化后应用)——但不要吞掉失败:设计文档的 "在返回成功前写入设置与 live 状态" 必须保持(写盘失败不得返回成功),真正的应用失败仍须中止创建路径(由 'releases and clears the session when an explicit reasoning effort cannot be applied' 钉住)。注意 actions.ts:1254 的客户端确认契约(if (!confirmed || (opts?.persist && result.persisted !== true)))必须在任何修复后保持。请新增 acpAgent.test.ts 用例:设置 persist meta 且 persistReasoningSelection 抛错——断言请求被拒绝且 generation.reasoning 恢复为原值;移除回滚/调整顺序必须使其变红。

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

Comment on lines +5765 to +5771
if (
!modelReasoning &&
tierSelected &&
generation.reasoning === false
) {
config.setReasoningEffort?.(selected);
} else {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] R2-6: This R1-1 fix branch calls config.setReasoningEffort?.(selected), which is a documented no-op precisely when generation.reasoning === false (config.ts:5087-5092) — so this branch can never apply the tier; the rejection actually comes from the confirm check below, while the dead call reads as an attempt to apply. There is also a cross-class inconsistency: on non-MODEL_CONFIGURATIONS models a tier-after-off gesture errors ('Reasoning effort cannot be applied while thinking is disabled' — user must select Default first, then the tier), while on manifest models the identical gesture silently re-enables via applyReasoningSelection's {...(false || {}), effort} spread. The no-op invariant itself should stand — it is the R1-1 contract, pinned by 'does not re-enable an explicitly disabled generic model with a tier' — the defect is the dead call's opacity and the divergent gesture behavior. The Web Shell disables tier buttons while thinking is off, so the divergence is reachable only through the daemon/ACP API.

Witness:

probe (scratch tree, head): vitest -t "does not re-enable an explicitly disabled generic model with a tier" -> Tests 1 passed | 528 skipped
contradicting behavior: `if (!cfg || cfg.reasoning === false) return;` (config.ts:5091) vs `{...(generation.reasoning || {}), effort: selection}` in applyReasoningSelection

Replace the dead no-op call with an explicit throw so the intent is visible (keeping the rejection semantics), or delete the branch and let the confirm check alone produce the error — either way, pin the chosen behavior: add an acpAgent.test.ts case with a non-MODEL_CONFIGURATIONS model, reasoning === false, setSessionConfigOption({configId: 'reasoning_effort', value: 'high'}), asserting the explicit rejection and that generation.reasoning stays false. The fix must not rely on setReasoningEffort to re-enable thinking ("No-op when thinking is explicitly disabled so effort cannot silently re-enable it", config.ts:5084-5087); removing the chosen guard must turn the new test red.

中文说明

这个 R1-1 修复分支调用 config.setReasoningEffort?.(selected),而它在 generation.reasoning === false 时恰好是文档化的空操作(config.ts:5087-5092)——因此该分支永远无法应用档位;拒绝实际来自下方的确认检查,而这个死调用读起来像是在尝试应用。还存在跨类别不一致:对非 MODEL_CONFIGURATIONS 模型,关闭后直接选档位会报错('Reasoning effort cannot be applied while thinking is disabled'——用户必须先选 Default 再选档位),而对清单模型同样的手势会经 applyReasoningSelection{...(false || {}), effort} 展开静默重新启用。空操作不变量本身应当保留——它是 R1-1 的契约,由 'does not re-enable an explicitly disabled generic model with a tier' 钉住——缺陷在于死调用的不透明和手势行为的不一致。Web Shell 在思考关闭时禁用档位按钮,因此该分歧只能经 daemon/ACP API 触达。

见证(probe,临时树,head):vitest -t "does not re-enable an explicitly disabled generic model with a tier" → Tests 1 passed | 528 skipped;矛盾行为:if (!cfg || cfg.reasoning === false) return;(config.ts:5091)对比 applyReasoningSelection 中的 {...(generation.reasoning || {}), effort: selection}

请把死空操作调用替换为显式 throw 使意图可见(保留拒绝语义),或删除该分支让确认检查单独产生错误——无论哪种,都请钉住所选行为:新增 acpAgent.test.ts 用例,非 MODEL_CONFIGURATIONS 模型、reasoning === falsesetSessionConfigOption({configId: 'reasoning_effort', value: 'high'}),断言显式拒绝且 generation.reasoning 保持 false。修复不得依赖 setReasoningEffort 重新启用思考("思考被显式禁用时空操作,防止档位静默重启用",config.ts:5084-5087);移除所选守卫必须使新测试变红。

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

Comment on lines +4887 to +4890
switchModelSpy.mockImplementation(
async (authType: AuthType, modelId: string) => {
currentAuthType = authType;
currentModel = modelId;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] R2-7: The new installReasoningPreference helper mocks switchModel as updating only model/authType — but the real Config.switchModel wipes/rebuilds reasoning: applyResolvedModelDefaults overwrites every MODEL_GENERATION_CONFIG_FIELDS entry (reasoning included, constants.ts:34), and the full-refresh restore re-applies only truthy effort. The mock keeps live/rebuildable reasoning intact across the switch, so the setModel reconcile tests pass vacuously for the restore branch. Mutation at head proves it: deleting the final applyReasoningSelection(this.config, selection) (supported branch) from reconcileReasoningSelection leaves all 22 setModel tests green, because {effort:'low'} was never wiped by the mock. This same PR contains an unguarded instance of exactly that wipe (the workspaceReload branch, flagged separately), and no case covers a persisted 'none' surviving a compatible switch — the one case core's restore provably cannot cover. A restore regression ships green.

Witness:

probe (scratch tree, packages/cli vitest):
intact  'keeps a compatible persisted tier when switching models' -> 1 passed
mutant  (supported-branch re-apply removed) -t setModel          -> 22 passed | 0 failed
control (mustClear-branch apply removed instead)                 -> 6 failed | 16 passed
        <- the harness detects reconcile mutations; the tests pin the clear path, not the restore path

Have the mocked switchModel reproduce the wipe (live.reasoning = undefined; rebuildable.reasoning = undefined; before setting the new model, mirroring applyResolvedModelDefaults for a preset-less model), and add a persisted-'none'-survives-compatible-switch case. Core's restore cannot help there: if (priorReasoningEffort) { (config.ts:5390) re-applies only truthy effort, and getReasoningEffort() returns undefined for reasoning: false (config.ts:5011) — restoring a persisted 'none' depends solely on the session-level reconcile, so the mock must not paper over that by carrying false across the switch. 'keeps a compatible persisted tier when switching models' must go red when the supported-branch apply is removed; the new 'none' case must go red when the restore is skipped.

中文说明

新的 installReasoningPreference 助手把 switchModel mock 为只更新 model/authType——但真实 Config.switchModel 会抹除/重建 reasoningapplyResolvedModelDefaults 覆盖所有 MODEL_GENERATION_CONFIG_FIELDS 条目(含 reasoning,constants.ts:34),全量刷新恢复只恢复 truthy effort。mock 在切换前后保持 live/可重建 reasoning 不变,因此 setModel reconcile 测试对恢复分支是空转通过。head 上的变异证明了这一点:从 reconcileReasoningSelection 删除最后的 applyReasoningSelection(this.config, selection)(支持分支)后全部 22 个 setModel 测试仍绿,因为 {effort:'low'} 从未被 mock 抹掉。同一个 PR 里就存在一处对该抹除毫无防护的实例(workspaceReload 分支,已另行指出),且没有任何用例覆盖持久化 'none' 在兼容切换后存活——而这恰是 core 恢复逻辑证明无法覆盖的情形。恢复分支回归会绿灯通过。

见证(probe,临时树,packages/cli vitest):原样 'keeps a compatible persisted tier when switching models' → 1 passed;变异(移除支持分支重应用)-t setModel → 22 passed | 0 failed;对照(改移除 mustClear 分支应用)→ 6 failed | 16 passed——脚手架能检测 reconcile 变异;测试钉住的是清除路径而非恢复路径。

请让 mock 的 switchModel 复现抹除(设置新模型前 live.reasoning = undefined; rebuildable.reasoning = undefined;,模拟无预设模型的 applyResolvedModelDefaults),并新增持久化 'none' 兼容切换存活用例。core 恢复在此无能为力:if (priorReasoningEffort) {(config.ts:5390)只恢复 truthy effort,且 getReasoningEffort()reasoning: false 返回 undefined(config.ts:5011)——持久化 'none' 的恢复完全依赖会话级 reconcile,mock 不得通过在切换间携带 false 来掩盖这一点。移除支持分支应用时 'keeps a compatible persisted tier when switching models' 必须变红;跳过恢复时新 'none' 用例必须变红。

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

Comment on lines +11484 to +11486
setPendingReasoningIntent(
sourceReasoningIntent && keepReasoningIntent
? { modelId, value: sourceReasoningIntent.value }

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] R2-8: The retarget branch of handleModelSelect's welcome path — an explicit reasoning intent bound to the current model that the target supports is carried over with its value — has zero test witness. The only welcome-mode onSelectModel test ('does not retarget a stale model-bound reasoning intent') routes its model switch through /model (the slash path at ~10204 bypasses handleModelSelect), so at its step 3 the intent is stale (modelId mismatch), sourceReasoningIntent is undefined, and this branch never executes in any test — the other onSelectModel sites run with live sessions and take the session branch. A mutation proves the branch is load-bearing: dropping it (or substituting 'default' for the carried value) leaves the entire App.test.tsx suite green while every picker-driven welcome model switch silently loses the explicit selection — user picks max on model A, picker-switches to model B supporting max, sends the first prompt, and Web Shell persists 'default' instead of max, wiping the stored preference and starting on the target's default.

Witness:

probe (scratch tree):
INTACT: reasoning.effort === 'max' carried with its value (Tests 2 passed)
MUTANT  (branch removed): AssertionError: expected 'medium' to be 'max' <- explicit 'max' silently dropped
        stale-intent test still passes; FULL SUITE 1 failed | 582 passed — the only failure is the probe

Add an App.test.tsx case: welcome mode (mockConnection.sessionId = undefined), onSelectReasoningEffort('max'), then onSelectModel to a target whose preview efforts include 'max'; assert reasoning.effort still displays 'max', then submit and assert mockSessionActions.setReasoningEffort was called with ('max', { persist: true }) — the design doc's Capability reconciliation says "a supported tier and an allowed none value are retained", and createAndAttachSessionForPrompt applies the carried intent with { persist: true } (sessionPreparation.ts), so the assertion must include the persist option. Removing the retarget branch or mutating it to 'default' must turn the new test red.

中文说明

handleModelSelect welcome 路径的重定向分支——绑定当前模型且目标支持的显式推理意图按原值携带——没有任何测试见证。唯一的 welcome 态 onSelectModel 测试('does not retarget a stale model-bound reasoning intent')经由 /model 路由切换模型(约 10204 行的斜杠路径绕过 handleModelSelect),因此其第 3 步时意图已过期(modelId 不匹配)、sourceReasoningIntent 为 undefined,该分支在任何测试中都未执行——其余 onSelectModel 调用点都在 live 会话下走会话分支。变异证明该分支承重:删除它(或把携带值替换为 'default')时整个 App.test.tsx 套件仍绿,而每次选层器驱动的 welcome 模型切换都会静默丢失显式选择——用户在模型 A 选 max,选层器切到支持 max 的模型 B,发送首条 prompt,Web Shell 却持久化 'default' 而非 max,清除已存偏好并以目标默认启动。

见证(probe,临时树):原样 reasoning.effort === 'max' 按原值携带(Tests 2 passed);变异(移除分支)AssertionError: expected 'medium' to be 'max'——显式 'max' 被静默丢弃;陈旧意图测试仍通过;全套件 1 failed | 582 passed,唯一失败即探针。

请新增 App.test.tsx 用例:welcome 态(mockConnection.sessionId = undefined)、onSelectReasoningEffort('max'),然后 onSelectModel 到预览 efforts 包含 'max' 的目标;断言 reasoning.effort 仍显示 'max',再提交并断言 mockSessionActions.setReasoningEffort('max', { persist: true }) 被调用——设计文档的能力协调写明 "支持的档位与允许的 none 值会被保留",且 createAndAttachSessionForPrompt{ persist: true } 应用携带的意图(sessionPreparation.ts),断言必须包含 persist 选项。移除重定向分支或将其变异为 'default' 必须使新测试变红。

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

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Partially reviewed — gaps disclosed.

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

  • R1-2 round-1 blocker residual (persisted 'none' wiped on every non-ACP refreshAuth; TUI dialog now offers None) — already reported at this head as R2-1 (comment 3889107196)
  • R1-3 fix-induced residual (managed-session apply-then-throw) — already reported at this head as R2-5 (comment 3889107205), as a Suggestion; this run's verification graded the same mechanism Critical
  • clearSession destroys a session installed during the wait — already reported at this head as R2-4 (comment 3889107203)
  • workspaceReload model-change branch wipes a persisted none — already reported at this head as R2-2 (comment 3889107198)
  • reconcile supported-branch apply has no test witness — already reported at this head as R2-7 (comment 3889107211)
  • retarget branch of the welcome reconciliation untested — already reported at this head as R2-8 (comment 3889107214)
  • untested route/runtime allowReasoning gate — already reported as R1-17 (comment 3887695492), author deferred
  • untested thinkingMandatory none-guard — already reported as R1-18 (comment 3887695493), author deferred
  • untested positional clientId overload — already reported as R1-19 (comment 3887695496), author deferred
  • two disagreeing persisted-value parsers — already reported as R1-21 (comment 3887695501), author deferred
  • strict === 'none' case sensitivity — already reported as R1-14 (comment 3887695485), author deferred
  • silent none-skip on thinking-mandatory models — already reported as R1-26 (comment 3887695515), author deferred
  • cross-model non-application e2e coverage removed — already reported as R1-22 (comment 3887695502), author deferred
  • none→default conversion at the mandatory-thinking boundary — already discussed in R1-9 (comment 3887695470): author maintains it as the shipped clear-don't-restore contract; the rewritten test pins it

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

Not explored to full depth (tool budget reached): chunk 11: exhaustive read of App.tsx / DaemonSessionProvider.tsx for a session-attach-triggered GET /workspace/providers reload (the uncertainty behind the low-confiden….

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

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

  • packages/cli/src/acp-integration/session/Session.ts:9925 — [review] managed-conversation guards untested (probe: removing both guards keeps Session.test.ts at 747/747 green) — deferred, code-age rule
  • packages/cli/src/acp-integration/acpAgent.ts:7047 — [review] buildWorkspaceProvidersStatus persisted-reasoning projection untested (probe: hunk reverted, 6/6 stay green) — deferred, code-age rule
  • packages/cli/src/acp-integration/model-configuration.ts:54 — [review] isQwenFamilyModel is a verbatim duplicate of core's isQwenFamilyWireModel (second source of truth for the family set) — deferred, code-age rule
  • packages/web-shell/client/e2e/web-shell.smoke.spec.ts:583 — [review] New-task no-refetch guard counts a route this flow never issues (structurally 0 === 0, probe: 8 GETs all on the global route) — deferred, code-age rule
  • packages/cli/src/acp-integration/acpAgent.ts:12207 — [review] workspaceReload never propagates a reasoningEffort-only settings edit to live sessions (UI and wire disagree until restart) — deferred, code-age rule
中文说明

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

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

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

未探索到全部深度(达到工具调用预算):chunk 11:exhaustive read of App.tsx / DaemonSessionProvider.tsx for a session-attach-triggered GET /workspace/providers reload (the uncertainty behind the low-confiden…

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

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

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

Comment on lines +11484 to +11490
setPendingReasoningIntent(
sourceReasoningIntent && keepReasoningIntent
? { modelId, value: sourceReasoningIntent.value }
: sourceReasoningSelection && !keepReasoningIntent
? { modelId, value: 'default' }
: undefined,
);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Critical] R1-7: [certifies-falsely] [new-surface] Round-1 mechanism re-checked at this head and still present: this no-session branch synthesizes a 'default' reasoning intent from a PREVIEW-DERIVED selection even when the user never touched a reasoning control — sourceReasoningSelection falls back to getReasoningSelection(sourceReasoningPreview). 'default' passes ensureSessionForPrompt's gates unconditionally (reasoningPreviewSupports returns true for 'default', App.tsx:1285), the first prompt sends setReasoningEffort('default', { persist: true }), and daemon-side persistReasoningSelection('default') clears the stored preference from every writable scope. A second entrance of the same arm: an explicit tier intent laundered through a preview-less intermediate model is rewritten to 'default' (keepReasoningIntent is falsy without a target preview to check) and later retargeted by the first arm — the explicit selection is destroyed and the stored preference wiped. Persisted medium projecting into the welcome preview → two model clicks through a reasoning-less model and back, zero reasoning interaction → the stored medium is deleted from every scope; pre-diff no intent was synthesized and the stored value survived. The design doc's Capability reconciliation speaks of removing 'every explicit selection', and default is described as a control command sent when the user turns thinking on again — this input is neither. The author maintains this is the explicit PR contract (round-1 thread); the re-check rules the mechanism still stands as filed, and the doc's own 'explicit' qualifier does not describe it.

Witness:

probe (App.test.tsx harness, scratch tree — welcome preview effort 'medium', zero reasoning interaction,
onSelectModel('qwen-plus') then onSelectModel('qwen3.8-max'), first prompt):
PROBE_C20_SET_REASONING_CALLS: [["default",{"persist":true}]]
flip (synthesis gated on an explicit sourceReasoningIntent): PROBE_C20_SET_REASONING_CALLS: [] and the displayed effort stays 'medium'
Suggested change
setPendingReasoningIntent(
sourceReasoningIntent && keepReasoningIntent
? { modelId, value: sourceReasoningIntent.value }
: sourceReasoningSelection && !keepReasoningIntent
? { modelId, value: 'default' }
: undefined,
);
setPendingReasoningIntent(
sourceReasoningIntent && keepReasoningIntent
? { modelId, value: sourceReasoningIntent.value }
: sourceReasoningIntent && !keepReasoningIntent
? { modelId, value: 'default' }
: undefined,
);

The fix must not turn a preview-derived (non-explicit) selection into an implicit default command — the daemon-side reconcileReasoningSelection at the create-time setModel still removes an unsupported persisted tier, preserving the design's end state (docs/design/webshell-reasoning-preferences.md 'Capability reconciliation': 'a model without reasoning controls removes every explicit selection'). Note the e2e 'discards an incompatible welcome effort when switching away and back' currently pins the destructive no-interaction behavior and must be re-pinned with the fix. Fix witness: add an App.test.tsx case — welcome preview projecting 'medium', no explicit selection, switch to a reasoning-less model and back, submit — asserting mockSessionActions.setReasoningEffort was NOT called; it goes red if the synthesis for non-explicit selections is reintroduced.

中文说明

第一轮 R1-7 的机制在当前 head 复查后仍然存在:这个无会话分支即使用户从未触碰推理控件,也会从预览推导的选择合成 'default' 推理意图——sourceReasoningSelection 回退到 getReasoningSelection(sourceReasoningPreview)'default' 无条件通过 ensureSessionForPrompt 的门控(reasoningPreviewSupports'default' 恒返回 true,App.tsx:1285),首条提示发出 setReasoningEffort('default', { persist: true }),daemon 侧 persistReasoningSelection('default') 从所有可写 scope 清除已存偏好。同一分支还有第二个入口:显式档位意图经过一个无预览的中间模型时被改写为 'default'(没有目标预览可判断时 keepReasoningIntent 为假),随后被第一个分支重定向——显式选择被摧毁、已存偏好被清除。具体路径:已存 medium 投射到 Welcome 预览 → 零推理交互地切换到一个无推理控件的模型再切回 → 已存的 medium 从所有 scope 被删除;PR 前不会合成意图、不会调用 setReasoningEffort,已存值得以保留。设计文档的 Capability reconciliation 写的是移除 "every explicit selection",且 default 被描述为用户重新开启思考时发出的控制命令——本输入两者皆非。作者坚持这是 PR 的明确契约(第一轮线程);复查裁决该机制按第一轮所述仍然存在,且文档自身的 "explicit" 限定无法描述该输入。

见证(probe,App.test.tsx 脚手架,临时树——Welcome 预览 effort 'medium'、零推理交互、onSelectModel('qwen-plus') 后 onSelectModel('qwen3.8-max')、首条提示):PROBE_C20_SET_REASONING_CALLS: [["default",{"persist":true}]];将合成门控为仅显式 sourceReasoningIntent 后翻转:PROBE_C20_SET_REASONING_CALLS: [] 且显示 effort 保持 'medium'。

修复不得把预览推导(非显式)的选择变成隐式 default 命令——创建时 setModel 的 daemon 侧 reconcileReasoningSelection 仍会移除不兼容的已存档位,设计终态得以保留(设计文档 'Capability reconciliation':"无推理控件的模型移除所有显式选择")。注意 e2e 'discards an incompatible welcome effort when switching away and back' 目前钉住了这一无交互破坏行为,需随修复重新钉住。修复见证:新增 App.test.tsx 用例——Welcome 预览投射 'medium'、无显式选择、切到无推理模型再切回、提交——断言 mockSessionActions.setReasoningEffort 未被调用;重新引入非显式合成时该测试变红。

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

Comment on lines +11463 to +11464
const models = connectionRef.current.models;
const reasoningIntent = pendingReasoningIntentRef.current;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Critical] R2-c9: [certifies-falsely] The /model <id> slash command's welcome branch (App.tsx:10203-10206, unchanged lines) does only setPendingModel(modelArg) and never runs this new reasoning-intent reconciliation; setPendingModel touches only the model state (5995-5997). An explicit reasoning selection therefore survives a picker switch but is silently dropped after a slash switch: ensureSessionForPrompt gates on reasoningIntent.modelId === modelId (6227-6231), the stale-bound intent yields reasoningEffort = undefined, and createAndAttachSessionForPrompt never calls setReasoningEffort. Concretely: Welcome on qwen3.8-max, the user selects 'Thinking off' (intent {modelId: 'qwen3.8-max', value: 'none'}), submits /model qwen3.7-plus (toggle-only, canDisable !== false), and sends the first prompt — the intent stays bound to qwen3.8-max, the modelId gate fails, and the new session starts with thinking ON, the exact opposite of the explicit choice; the identical switch through the picker retargets the intent and applies + persists 'none'. This contradicts the PR's own design doc ('Every model switch reconciles the stored selection against the target model'; 'a supported tier and an allowed none value are retained'). The bypass itself was noted as R1-20 (Suggestion, deferred); this is the traced consequence for explicit new selections.

Witness:

witness: not run — the scenario is a React-state sequence through a private ref; the nearest capability was a DOM-level probe
of onSubmit('/model …') after an explicit 'none' selection, but each of the four code links (slash branch has no reconciliation
call; setPendingModel touches only model state; ensureSessionForPrompt's modelId gate; createAndAttachSessionForPrompt's
truthy-only setReasoningEffort) was read and quoted at HEAD and leaves no gap for the intent to be cleared or retargeted on the slash path.

Extract the reconciliation block into a shared helper and call it in the slash welcome branch:

// App.tsx — shared helper used by BOTH handleModelSelect's welcome branch and the /model welcome branch
const reconcilePendingReasoningIntentForSwitch = (targetModelId: string) => {
  const models = connectionRef.current.models;
  const reasoningIntent = pendingReasoningIntentRef.current;
  const sourceReasoningIntent =
    reasoningIntent?.modelId === currentModelRef.current ? reasoningIntent : undefined;
  // …same derivation/keep/synthesize logic as handleModelSelect…
};
// in the /model welcome branch (~10204): reconcilePendingReasoningIntentForSwitch(modelArg); setPendingModel(modelArg);

The fix must not retroactively retarget an already-stale intent — App.test.tsx:14649 pins that a stale intent's value stays unapplied; the picker-path reconciliation here is the reference behavior the slash fix must reach parity with. Fix witness: when the slash welcome branch reconciles, flip App.test.tsx 'does not retarget a stale model-bound reasoning intent' (~14685) to the reconciled outcome for a supported intent — its current assertion (preview value after the slash switch) pins the drop and goes red the moment the fix lands.

中文说明

/model <id> 斜杠命令的 welcome 分支(App.tsx:10203-10206,未改动行)只做 setPendingModel(modelArg),从不运行这里新增的推理意图协调;setPendingModel 只更新模型状态(5995-5997)。因此显式的推理选择在选层器切换后存活,但在斜杠切换后被静默丢弃:ensureSessionForPromptreasoningIntent.modelId === modelId 门控(6227-6231),过期绑定的意图得到 reasoningEffort = undefinedcreateAndAttachSessionForPrompt 不再调用 setReasoningEffort。具体场景:Welcome 处于 qwen3.8-max,用户选择 'Thinking off'(意图 {modelId: 'qwen3.8-max', value: 'none'}),提交 /model qwen3.7-plus(仅开关、canDisable !== false)后发送首条提示——意图仍绑定 qwen3.8-max,modelId 门控失败,新会话以思考开启启动,与显式选择完全相反;同样的切换经选层器则会重定向意图并应用+持久化 'none'。这与 PR 自身设计文档矛盾("每次模型切换都会对目标模型协调已存选择";"支持的档位与允许的 none 值会被保留")。该绕过本身在 R1-20(Suggestion,已延期)中被提及;本条是对显式新选择追踪出的实际后果。

见证:未运行——场景是经由私有 ref 的 React 状态序列;最近的能力是显式 'none' 选择后驱动 onSubmit('/model …') 的 DOM 级探针,但四个代码链接(斜杠分支无协调调用;setPendingModel 只动模型状态;ensureSessionForPrompt 的 modelId 门控;createAndAttachSessionForPrompt 仅对 truthy 调用 setReasoningEffort)均已在 HEAD 逐一定位并引用,斜杠路径上不存在清空或重定向意图的缝隙。

请把协调块抽成共享 helper 并在斜杠 welcome 分支调用(见英文侧代码)。修复不得追溯重定向已过期意图——App.test.tsx:14649 钉住过期意图的值不被应用;此处选层器路径的协调是斜杠修复必须对齐的参照行为。修复见证:斜杠 welcome 分支实现协调后,将 App.test.tsx 'does not retarget a stale model-bound reasoning intent'(~14685)翻转为支持意图的协调结果——其当前断言(斜杠切换后显示预览值)钉住了丢弃行为,修复落地即变红。

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

Comment on lines +9842 to +9845
this.reconcileReasoningSelection(effectiveModelId, {
persist: !this.requiresManagedConversationBinding,
allowReasoning: !isRuntime && !rawModelId.startsWith(ACP_ROUTE_ID_PREFIX),
});

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Critical] R2-c14: [certifies-falsely] [new-surface] CLASS FINDING, two entrances (bounded family): this allowReasoning gate judges the OPAQUE id shape, not the resolved model's capabilities, so selecting a runtime snapshot model OR a colliding qwen-route:v1:<hash> route permanently deletes a persisted reasoning preference that the resolved BASE model fully supports — while the same setModel call persists that base model as the durable default (LoadedSettings.setValue strips the runtime prefix, 'Never persist a runtime snapshot ID to model.name', settings.ts:541-543; route selection writes model.name = effectiveModelId at Session.ts:9894). The clear decision and the persisted outcome disagree. While a route id is current, buildConfigOptions omits the reasoning_effort option entirely (acpAgent.ts:13214-13221), so there is no UI path to re-persist. Route entrance: two providers exposing the same model id+authType make buildAcpModelOptions emit ONLY route ids for that model (counts.get(legacyModelId) !== 1, acpModelUtils.ts:104-110), so the picker has no plain entry and every selection of that model clears the preference. With persisted 'none', the next start re-enables thinking (paid tokens) against the explicit choice; switching back never restores it. The identical model selected by plain id retains the preference (pinned by 'keeps a compatible persisted tier when switching models').

Witness:

probe (persisted 'low', two colliding USE_OPENAI providers for qwen3.8-max, scratch tree):
PROBE-C29 routeId: qwen-route:v1:OS5gD3-V5wq6z6fg
PROBE-C29 after ROUTE selection, user reasoningEffort: undefined (deleted)
PROBE-C29 after ROUTE selection, workspace reasoningEffort: undefined
PROBE-C29 persisted model.name: [["User","model.name","qwen3.8-max"]]
PROBE-C29 after PLAIN selection, user reasoningEffort: "low" (retained)
flip (allowReasoning: !isRuntime): route arm retains "low" in both scopes
Suggested change
this.reconcileReasoningSelection(effectiveModelId, {
persist: !this.requiresManagedConversationBinding,
allowReasoning: !isRuntime && !rawModelId.startsWith(ACP_ROUTE_ID_PREFIX),
});
this.reconcileReasoningSelection(effectiveModelId, {
persist: !this.requiresManagedConversationBinding,
allowReasoning: !isRuntime,
});

resolveAcpModelOption returns the plain id (modelId: matched.effectiveModelId, packages/cli/src/utils/acpModelUtils.ts:129) and effectiveModelId is what reconcile receives and what persistDefault writes as model.name (Session.ts:9894) — the fix must keep judging/persisting that resolved id, not the opaque route id. Fix witness: new Session.test.ts case mirroring the existing route switches (Session.test.ts:5008): build a two-provider colliding list for a reasoning-capable model, installReasoningPreference('low'), setModel({ modelId: routeId }) → assert state.user.settings.model.reasoningEffort is still 'low' and state.live.reasoning equals { effort: 'low' }; re-adding !rawModelId.startsWith(ACP_ROUTE_ID_PREFIX) makes it red.

中文说明

类发现,两个入口(有界族):该 allowReasoning 门控按不透明 id 的形状判断,而不是按解析后模型的能力判断,因此选择运行时快照模型或冲突产生的 qwen-route:v1:<hash> 路由会永久删除一个解析后基础模型完全支持的已存推理偏好——而同一个 setModel 调用却把该基础模型作为持久默认写入(LoadedSettings.setValue 会剥离运行时前缀,"绝不把运行时快照 ID 持久化到 model.name(重启时会重新包装)",settings.ts:541-543;路由选择把 model.name = effectiveModelId 写入 Session.ts:9894)。清除决定与持久化结果互相矛盾。路由 id 为当前模型时,buildConfigOptions 完全省略 reasoning_effort 选项(acpAgent.ts:13214-13221),没有任何 UI 路径可以重新持久化。路由入口:两个 provider 暴露相同 model id+authType 时,buildAcpModelOptions 对该模型只发出路由 id(counts.get(legacyModelId) !== 1,acpModelUtils.ts:104-110),选层器没有普通条目,该模型的每次选择都会清除偏好。若已存 'none',下次启动会在违背显式选择的情况下重新开启思考(计费 token);切回也永不恢复。同一模型以普通 id 选择时偏好被保留(由 'keeps a compatible persisted tier when switching models' 钉住)。

见证(probe,已存 'low'、qwen3.8-max 的两个冲突 USE_OPENAI provider,临时树):路由选择后 user/workspace reasoningEffort 均为 undefined(被删除),持久化 model.name 为 [["User","model.name","qwen3.8-max"]];普通 id 选择后 user reasoningEffort 为 "low"(保留);将门控改为 allowReasoning: !isRuntime 后,路由分支两个 scope 均保留 "low"。

resolveAcpModelOption 返回普通 id(modelId: matched.effectiveModelId,packages/cli/src/utils/acpModelUtils.ts:129),effectiveModelId 正是 reconcile 收到的、也是 persistDefault 写入 model.name 的值(Session.ts:9894)——修复必须继续判断/持久化该解析后的 id,而不是不透明路由 id。修复见证:仿照现有路由切换测试(Session.test.ts:5008)新增 Session.test.ts 用例:为支持推理的模型构造双 provider 冲突列表,installReasoningPreference('low')setModel({ modelId: routeId }) → 断言 state.user.settings.model.reasoningEffort 仍为 'low'state.live.reasoning 等于 { effort: 'low' };重新加回 !rawModelId.startsWith(ACP_ROUTE_ID_PREFIX) 时变红。

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

Comment on lines +170 to +173
generation.reasoning = {
...(generation.reasoning || {}),
effort: selection,
};

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Critical] R2-c22: [certifies-falsely] [regression] CLASS FINDING, two branches (bounded family): applyReasoningSelection bypasses the documented Config.setReasoningEffort invariant — 'No-op when thinking is explicitly disabled (reasoning: false) so effort cannot silently re-enable it' (config.ts:5083-5093). Tier branch (here): the model-switch reconcile applies a persisted effort tier over an explicit reasoning: false preset of the target model — isReasoningSelectionSupported judges by model id only (generic branch REASONING_EFFORT_TIERS.includes(selection)), so the selection counts as 'supported', {...(generation.reasoning || {}), effort} spreads false || {}{}, and the disable is overwritten on BOTH live and rebuildable configs; the selection is retained and re-applied on every later switch. DEFAULT branch (160-162): !generation.reasoning treats an explicit false identically to 'no reasoning set' and erases it to undefined on the mustClear cleanup path (reconcileReasoningSelection calls applyReasoningSelection(config, 'default'), Session.ts:9960-9977), silently re-enabling thinking without any user selection of 'default'. A fix guarding only one branch leaves the other erasing the same disable. Trigger: persisted model.reasoningEffort: 'medium'; switch to a model whose provider/registry generationConfig sets reasoning: false (constructible: ModelGenerationConfig includes 'reasoning', models/types.ts:44; applyResolvedModelDefaults copies it on switch, modelsConfig.ts:915-921) — thinking the provider explicitly disabled is silently re-enabled (paid tokens, changed output) and the selection is kept, so every subsequent switch/restart re-applies it. Contrast: choosing the tier directly via the reasoning_effort option takes the guarded branch (acpAgent.ts:5764-5766) and rejects; core's own switch restoration deliberately skips this case (config.ts:5379-5392). Distinct from the posted R2-3 (sibling destruction on the none branch) and R2-6 (dead no-op call in the R1-1 fix branch): this is the switch-time reconcile overriding a preset disable.

Witness:

probe (real Session.setModel, scratch tree):
tier branch — persisted 'max', target preset reasoning:false:
  intact: live.reasoning = {"effort":"max"} rebuildable.reasoning = {"effort":"max"} persisted = "max" (disable overwritten)
  with guard: live.reasoning = false rebuildable.reasoning = false
DEFAULT branch — mustClear over reasoning:false preset:
  intact: live/rebuildable reasoning = undefined (explicit disable erased)
  with fix: false (disable kept)

Guard both branches:

// tier branch (here): skip the apply when the config explicitly disables thinking
    if (generation.reasoning === false) return;
    generation.reasoning = {
      ...(generation.reasoning || {}),
      effort: selection,
    };
// DEFAULT branch (160-162): keep an explicit disable sticky
    if (selection === REASONING_EFFORT_DEFAULT) {
      if (generation.reasoning === false) return;
      if (!generation.reasoning) {

The fix must make applyReasoningSelection consistent with the config.ts:5083-5093 invariant, and the existing 'preserves reasoning siblings when returning to the model default' test must still pass for truthy reasoning objects. Fix witness: model-configuration.test.ts cases starting from { reasoning: false } on both live and rebuildable — applyReasoningSelection(config, 'max') and ('default') must both leave reasoning === false; removing either guard makes them red. Plus a Session.test.ts variant whose switchModelSpy lands reasoning: false on both configs — the persisted tier must be cleared, not applied.

中文说明

类发现,两个分支(有界族):applyReasoningSelection 绕过了 Config.setReasoningEffort 的文档化不变量——"思考被显式禁用(reasoning: false)时空操作,防止档位静默重新启用它"(config.ts:5083-5093)。档位分支(此处):模型切换 reconcile 会把已存档位应用在目标模型显式 reasoning: false 的预设之上——isReasoningSelectionSupported 只按模型 id 判断(通用分支 REASONING_EFFORT_TIERS.includes(selection)),该选择被视为"支持",{...(generation.reasoning || {}), effort} 展开 false || {}{},live 与可重建两个 config 上的禁用都被覆盖;选择被保留并在之后每次切换时重新应用。DEFAULT 分支(160-162):!generation.reasoning 把显式 false 与"未设置"同等对待,在 mustClear 清理路径上把它抹成 undefinedreconcileReasoningSelection 调用 applyReasoningSelection(config, 'default'),Session.ts:9960-9977),在用户没有选择 'default' 的情况下静默重新启用思考。只修一个分支,另一个仍会抹掉同一个禁用。触发:已存 model.reasoningEffort: 'medium';切换到一个 provider/注册表 generationConfig 设置 reasoning: false 的模型(可构造:ModelGenerationConfig'reasoning',models/types.ts:44;applyResolvedModelDefaults 在切换时拷贝,modelsConfig.ts:915-921)——provider 显式禁用的思考被静默重新启用(计费 token、输出变化),且选择被保留,之后每次切换/重启都会重新应用。对照:直接经 reasoning_effort 选项选择档位会走有守卫的分支(acpAgent.ts:5764-5766)并被拒绝;core 自身的切换恢复也刻意跳过该情形(config.ts:5379-5392)。与已发布的 R2-3(none 分支摧毁同级字段)和 R2-6(R1-1 修复分支的死空操作调用)不同:本条是切换时 reconcile 覆盖预设禁用。

见证(probe,真实 Session.setModel,临时树):档位分支——已存 'max'、目标预设 reasoning:false:原样时 live/rebuildable 均为 {"effort":"max"}、persisted = "max"(禁用被覆盖);加守卫后均为 false。DEFAULT 分支——对 reasoning:false 预设执行 mustClear:原样时 live/可重建 reasoning = undefined(显式禁用被抹除);修复后为 false(禁用保留)。

修复必须使 applyReasoningSelection 与 config.ts:5083-5093 不变量一致,且现有 'preserves reasoning siblings when returning to the model default' 测试对 truthy reasoning 对象仍须通过。修复见证:model-configuration.test.ts 用例,从 live/可重建均为 { reasoning: false } 开始——applyReasoningSelection(config, 'max')('default')reasoning 均须保持 === false;移除任一首卫即变红。另加 Session.test.ts 变体,其 switchModelSpy 在两个 config 上落地 reasoning: false——已存档位必须被清除而不是被应用。

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

Comment on lines +12854 to +12858
if (isInitialAuth === undefined) {
await config.refreshAuth(authType);
} else {
await config.refreshAuth(authType, isInitialAuth);
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] R2-c1: Both branches of this isInitialAuth === undefined check make the identical call: Config.refreshAuth is async refreshAuth(authMethod: AuthType, isInitialAuth?: boolean) with no default initializer (packages/core/src/config/config.ts:4109), and passing undefined explicitly is indistinguishable from omitting the optional parameter. The branch encodes a semantic difference that does not exist at the single choke point through which every ACP-agent auth refresh now flows — a maintainer reading it infers a false omit-vs-pass distinction, cargo-cults it into new call sites, or avoids simplifying the call out of fear of breaking a non-existent difference.

Witness:

witness: not run — no probe can distinguish the two arms; they both reduce to refreshAuth(authType, undefined) by language
semantics, and the sole read of the parameter (`requireCached ? true : isInitialAuth`, packages/core/src/config/config.ts:4146)
was quoted from the real source.
Suggested change
if (isInitialAuth === undefined) {
await config.refreshAuth(authType);
} else {
await config.refreshAuth(authType, isInitialAuth);
}
await config.refreshAuth(authType, isInitialAuth);

The collapse must keep forwarding isInitialAuthasync refreshAuth(authMethod: AuthType, isInitialAuth?: boolean) at packages/core/src/config/config.ts:4109 — because ensureAuthenticated deliberately passes true (initial-auth semantics feed createContentGenerator(..., requireCached ? true : isInitialAuth)).

中文说明

这个 isInitialAuth === undefined 判断的两个分支执行的是完全相同的调用:Config.refreshAuthasync refreshAuth(authMethod: AuthType, isInitialAuth?: boolean),无默认初始值(packages/core/src/config/config.ts:4109),显式传 undefined 与省略可选参数没有任何区别。该分支在"所有 ACP agent 鉴权刷新唯一必经之路"上编码了一个并不存在的语义差异——维护者读到它会误以为传与不传不同,把它照抄进新的调用点,或因为害怕破坏一个不存在的差异而不敢简化调用。

见证:未运行——没有任何探针能区分两个分支;按语言语义两者都归约为 refreshAuth(authType, undefined),参数的唯一读取处(requireCached ? true : isInitialAuth,packages/core/src/config/config.ts:4146)已从真实源码引用。

折叠后必须继续转发 isInitialAuth——packages/core/src/config/config.ts:4109 的 async refreshAuth(authMethod: AuthType, isInitialAuth?: boolean)——因为 ensureAuthenticated 刻意传入 true(初始鉴权语义会进入 createContentGenerator(..., requireCached ? true : isInitialAuth))。

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

Comment on lines +29 to +37
const REASONING_SELECTIONS = new Set<ReasoningSelection>([
'none',
'default',
'low',
'medium',
'high',
'xhigh',
'max',
]);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] R2-c2: AGGREGATE location 2 (of 2) — the web-shell twin of the hand-listed ladder: this file lists the ladder TWICE (here all 7 selections, plus isReasoningEffortSelection's 5 tiers at mappers.ts:48-59), decoupled from the SDK union (ReasoningSelection is a type with no runtime counterpart, packages/sdk-typescript/src/daemon/types.ts:2808). When core ships a new tier, the daemon advertises it in reasoning_effort options/currentValue; parseReasoningSelection rejects the unknown string, and with currentValue on the new tier the !currentValue || !values.includes(currentValue) guard makes mapReasoningControls return undefined — the composer's thinking toggle/effort buttons and the model-picker preview silently disappear for a thinking-capable model. No compile error catches the drift (Set<ReasoningSelection> is satisfied by a subset), and the two in-file lists can diverge from each other: a value added to the Set but not the predicate parses as a valid current value yet is excluded from efforts, so the selected tier renders no button and nothing shows pressed.

Witness:

probe (mapReasoningControls, scratch tree):
PROBE_C17_CONTROLS_FOR_ULTRA: undefined          ← unknown tier hides the controls
flip (adding 'ultra' to both in-file lists): {"enabled":true,"effort":"ultra","efforts":["low","ultra"],...}

Export a runtime selection list from @qwen-code/sdk/daemon and derive both REASONING_SELECTIONS and isReasoningEffortSelection from it; at minimum derive the predicate from the Set (value !== 'none' && value !== 'default' && REASONING_SELECTIONS.has(value)) so the two in-file lists cannot diverge. ReasoningSelection exists today only as a type (packages/sdk-typescript/src/daemon/types.ts:2808) and AGENTS.md forbids relative imports between packages — the shared constant must be added to @qwen-code/sdk/daemon; web-shell must not reach into packages/core for REASONING_EFFORT_TIERS. Fix witness: an mappers.test.ts case building configOptions by iterating the SDK's exported runtime selection list and asserting mapReasoningControls returns defined controls for every member — restoring a stale hand-list makes it red.

中文说明

聚合发现第 2 处(共 2 处)——手工列举阶梯的 web-shell 孪生:本文件把阶梯列了两遍(此处为全部 7 个选择,另有 mappers.ts:48-59 的 isReasoningEffortSelection 的 5 个档位),与 SDK 联合类型脱钩(ReasoningSelection 只是类型,无运行时对应物,packages/sdk-typescript/src/daemon/types.ts:2808)。当 core 发布新档位时,daemon 会在 reasoning_effort 选项/currentValue 中声明它;parseReasoningSelection 拒绝未知字符串,currentValue 落在新档位上时 !currentValue || !values.includes(currentValue) 守卫使 mapReasoningControls 返回 undefined——支持思考的模型的输入框思考开关/档位按钮与选层器预览静默消失。编译错误抓不到这种漂移(Set<ReasoningSelection> 对子集也成立),且文件内两个列表可以互相漂移:加入 Set 但未加入谓词的值能解析为有效 currentValue 却被排除在 efforts 之外,所选档位不渲染按钮、也无按下状态。

见证(probe,mapReasoningControls,临时树):PROBE_C17_CONTROLS_FOR_ULTRA: undefined(未知档位隐藏控件);把 'ultra' 加入文件内两个列表后翻转:{"enabled":true,"effort":"ultra","efforts":["low","ultra"],...}。

请从 @qwen-code/sdk/daemon 导出运行时选择列表,并用它推导 REASONING_SELECTIONSisReasoningEffortSelection;至少让谓词从 Set 推导(value !== 'none' && value !== 'default' && REASONING_SELECTIONS.has(value)),使文件内两个列表无法漂移。ReasoningSelection 目前只是类型(packages/sdk-typescript/src/daemon/types.ts:2808),AGENTS.md 禁止包间相对导入——共享常量必须加在 @qwen-code/sdk/daemon;web-shell 不得伸手到 packages/coreREASONING_EFFORT_TIERS。修复见证:新增 mappers.test.ts 用例,按 SDK 导出的运行时选择列表构造 configOptions,断言 mapReasoningControls 对每个成员返回已定义控件——恢复陈旧的手工列表时变红。

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

Comment on lines +1254 to 1257
if (!confirmed || (opts?.persist && result.persisted !== true)) {
throw new Error(
`Daemon did not confirm reasoning effort ${JSON.stringify(value)}`,
);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] R2-c13: This branch reuses the 'Daemon did not confirm reasoning effort' error even when the daemon DID confirm the effort (confirmed === true, only result.persisted !== true), misattributing a persistence failure as a confirmation failure — and the throw skips the setConnection block below (1258-1295), with the catch path going through dispatchActionError, which only appends a notice — so connection.reasoning stays stale while the daemon session's effort actually changed. The old-daemon case is exactly when this fires: such a daemon applies the change live and confirms it via configOptions, yet the user sees a confirmation-denied message, retries a change that is already live, and the reasoning menu keeps showing the old effort until the next context snapshot re-syncs it.

Witness:

witness: not run — both facts are directly quotable at the throw site (condition, message, and throw-before-setConnection
ordering) and in dispatchActionError (actions.ts:2658-2695, notice-only); the committed actions.test.ts case covers the same
path but was not re-run because executing web-shell tests writes artifacts into the shared review worktree.
Suggested change
if (!confirmed || (opts?.persist && result.persisted !== true)) {
throw new Error(
`Daemon did not confirm reasoning effort ${JSON.stringify(value)}`,
);
if (!confirmed || (opts?.persist && result.persisted !== true)) {
throw new Error(
confirmed
? `Daemon did not persist reasoning effort ${JSON.stringify(value)}`
: `Daemon did not confirm reasoning effort ${JSON.stringify(value)}`,
);

Consider also applying the confirmed live reasoning state instead of discarding it when only persistence failed. Fix witness: update 'does not update reasoning when persistence is not confirmed' to assert the persistence-specific message; reverting to the conflated message makes it red.

中文说明

该分支即使在 daemon 已经确认了档位(confirmed === true,仅 result.persisted !== true)时也复用 'Daemon did not confirm reasoning effort' 错误,把持久化失败误标为确认失败——而且 throw 跳过了下方的 setConnection 块(1258-1295),catch 路径只走 dispatchActionError(仅追加通知)——于是 daemon 会话的档位实际已变,connection.reasoning 却保持陈旧。旧版 daemon 正是触发场景:它会在 live 应用更改并通过 configOptions 确认,但用户看到的是"确认被拒"的提示,进而重试一个已经生效的更改,推理菜单持续显示旧档位直到下一次上下文快照重新同步。

见证:未运行——两个事实均可在 throw 处直接引用(条件、消息、先 throw 后 setConnection 的顺序)以及 dispatchActionError(actions.ts:2658-2695,仅通知)中引用;已提交的 actions.test.ts 用例覆盖同一路径,但未重跑,因为执行 web-shell 测试会向共享审查工作树写入产物。

也可考虑在仅持久化失败时应用已确认的 live 推理状态而不是丢弃它。修复见证:更新 'does not update reasoning when persistence is not confirmed',断言持久化专用消息;回退为混用消息时变红。

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

const session = sessionRef.current;
manualSessionClearRef.current = true;
if (pendingPersistedReasoningAction) {
await pendingPersistedReasoningAction.catch(() => undefined);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] R2-c16: clearSession blocks session teardown on the pending persisted-reasoning action, which resolves only in setReasoningEffort's finally after withActionTimeout settles — DEFAULT_ACTION_TIMEOUT_MS = 30_000 (daemon/timing.ts:9). All three UI sites pass persist: true (App.tsx handleReasoningEffort, ChatPane.tsx:1140, sessionPreparation.ts:145-147), so any reasoning change arms the pending action; a slow or hung daemon then stalls 'New task' (createNewSession awaits clearSession) for up to 30 seconds while the old session stays fully operable — pre-diff clearSession cleared state synchronously. The await's documented purpose (letting the confirmed persisted preview land in providers before Welcome renders) answers the happy path; it names no answer for the hung-daemon path. Distinct from the posted R2-4 replacement-destruction defect: this is the latency itself, no race required.

Witness:

probe (actions harness, deferred setConfigOption, scratch tree):
PROBE_C16_WHILE_PENDING: {"clearCompleted":false,"connectionSessionId":"session-a","sessionRefStillSet":true}
after settle: {"clearCompleted":true,"sessionRefStillSet":false}
flip (await removed): clear immediate — sessionRef already undefined while the persist is still pending
Suggested change
await pendingPersistedReasoningAction.catch(() => undefined);
await Promise.race([
pendingPersistedReasoningAction.catch(() => undefined),
new Promise((resolve) => setTimeout(resolve, 1_500)),
]);

The grace bound must not be shorter than the settle window relied on by 'keeps the confirmed persisted reasoning preview after clearing the session' (actions.test.ts:3236), which pins that a settled persist is captured into the post-clear models preview. Fix witness: new actions.test.ts case — leave the setConfigOption mock unresolved, start setReasoningEffort('medium', { persist: true }) then clearSession(), advance timers past the grace period → assert getConnection().sessionId is cleared while the persist is still pending; the preview-capture test must stay green.

中文说明

clearSession 将会话拆除阻塞在挂起的持久化推理动作上,而该动作只在 withActionTimeout 落定后由 setReasoningEffortfinally 解析——DEFAULT_ACTION_TIMEOUT_MS = 30_000(daemon/timing.ts:9)。三个 UI 调用点都传 persist: true(App.tsx handleReasoningEffort、ChatPane.tsx:1140、sessionPreparation.ts:145-147),因此任何推理更改都会挂上该动作;daemon 缓慢或挂起时,"新建任务"(createNewSession await clearSession)会被卡住最长 30 秒,而旧会话在此期间完全可操作——PR 前 clearSession 是同步清理状态的。该 await 的文档化目的(让已确认的持久化预览在 Welcome 渲染前落入 providers)只覆盖顺利路径;对挂起的 daemon 没有任何方案。与已发布的 R2-4(替换会话被摧毁)不同:本条是延迟本身,无需竞态。

见证(probe,actions 脚手架,延迟 setConfigOption,临时树):PROBE_C16_WHILE_PENDING: {"clearCompleted":false,"connectionSessionId":"session-a","sessionRefStillSet":true};解析后:{"clearCompleted":true,"sessionRefStillSet":false};移除 await 后翻转:清理立即完成——persist 仍挂起时 sessionRef 已为 undefined。

宽限下限不得短于 'keeps the confirmed persisted reasoning preview after clearing the session'(actions.test.ts:3236)依赖的解析窗口——该测试钉住已解析的 persist 会被捕获进清理后的 models 预览。修复见证:新增 actions.test.ts 用例——保持 setConfigOption mock 未解析,启动 setReasoningEffort('medium', { persist: true }) 后调用 clearSession(),推进定时器越过宽限期→断言 persist 仍挂起时 getConnection().sessionId 已被清除;预览捕获测试须保持绿色。

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

Comment on lines 8333 to 8335
).rejects.toThrow(
'Unknown reasoning effort: high. Choose one of: none, low, medium, xhigh',
);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] R2-c25: The new supported check accepts 'default' for registered tiered models (selected === REASONING_EFFORT_DEFAULT || choices.includes(selected), acpAgent.ts:5727-5731), but the registered-model rejection branch still builds allowedChoices = choices (5733-5734), and buildModelReasoningConfigOption never emits a 'default' option for tiered models — so 'default' is valid yet absent from the 'Choose one of' list, while the unregistered branch explicitly prepends it (5735-5740) and toggle-only models carry it in choices. The same test proves 'default' works for that branch three lines earlier (the reset call at ~8318); the same omission appears in the thinking-mandatory rejection (~8835). An ACP client sending an unsupported tier (e.g. 'high') to qwen3.8-max receives 'Unknown reasoning effort: high. Choose one of: none, low, medium, xhigh' — any consumer deriving retry values from the message cannot discover the reset-to-default control this same PR's reset flow relies on.

Witness:

probe (real agent boot via the file's own scaffolding, scratch tree):
PROBE-C25 default accepted; currentValue=xhigh
PROBE-C25 rejection message: Unknown reasoning effort: high. Choose one of: none, low, medium, xhigh
flip (default added to the registered branch): Choose one of: default, none, low, medium, xhigh
Suggested change
).rejects.toThrow(
'Unknown reasoning effort: high. Choose one of: none, low, medium, xhigh',
);
).rejects.toThrow(
'Unknown reasoning effort: high. Choose one of: default, none, low, medium, xhigh',
);

Build allowedChoices the same way for both branches in setSessionConfigOption[REASONING_EFFORT_DEFAULT, ...choices.filter((choice) => choice !== REASONING_EFFORT_DEFAULT)] (drop the modelReasoning ? choices : … ternary) — and update this assertion. The generic-model message is pinned verbatim at acpAgent.test.ts:8138 ('Unknown reasoning effort: ultra. Choose one of: default, none, low, medium, high, xhigh, max'), so the unified construction must keep 'default' first and include 'none' there too. Fix witness: the updated rejects assertion at acpAgent.test.ts:8334 goes red if the fix reverts allowedChoices to choices for registered models.

中文说明

新的 supported 检查对注册的分档模型接受 'default'selected === REASONING_EFFORT_DEFAULT || choices.includes(selected),acpAgent.ts:5727-5731),但注册模型的拒绝分支仍构造 allowedChoices = choices(5733-5734),且 buildModelReasoningConfigOption 从不为分档模型发出 'default' 选项——于是 'default' 合法却缺席 'Choose one of' 列表,而未注册分支会显式前置它(5735-5740)、仅开关模型的 choices 也天然含它。同一测试在三行之前已证明 'default' 对该分支有效(~8318 的 reset 调用);思考强制拒绝(~8835)存在同样的遗漏。向 qwen3.8-max 发送不支持档位(如 'high')的 ACP 客户端会收到 'Unknown reasoning effort: high. Choose one of: none, low, medium, xhigh'——任何从错误消息推导重试值的消费者都无法发现本 PR 的 reset 流程所依赖的 default 复位控制。

见证(probe,经该文件自身脚手架真实启动 agent,临时树):PROBE-C25 default 被接受;currentValue=xhigh;拒绝消息:Unknown reasoning effort: high. Choose one of: none, low, medium, xhigh;把 default 加入注册分支后翻转:Choose one of: default, none, low, medium, xhigh。

请在 setSessionConfigOption 中为两个分支用同一方式构造 allowedChoices——[REASONING_EFFORT_DEFAULT, ...choices.filter((choice) => choice !== REASONING_EFFORT_DEFAULT)](去掉 modelReasoning ? choices : … 三元式)——并更新此断言。通用模型消息在 acpAgent.test.ts:8138 被逐字钉住('Unknown reasoning effort: ultra. Choose one of: default, none, low, medium, high, xhigh, max'),统一构造必须保持 'default' 在前且同样包含 'none'。修复见证:若修复把注册模型的 allowedChoices 还原为 choices,acpAgent.test.ts:8334 更新后的 rejects 断言变红。

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

Comment on lines +9982 to +9986
private clearPersistedReasoningSelection(except?: SettingScope): void {
this.commitReasoningSelectionWrites(
this.getReasoningSelectionClearWrites(except),
);
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] R2-c26: clearPersistedReasoningSelection(except?) declares and forwards except, but no caller ever sets it — the only call site (reconcile's mustClear path, Session.ts:9967) passes nothing, and the one place that actually needs scope exclusion (persistReasoningSelection, Session.ts:9934, excluding persistScope) bypasses this wrapper and calls getReasoningSelectionClearWrites directly. Per the AGENTS.md read-site rule for added optional parameters this is a dead switch: the exclusion branch is never exercised by any production path, so a future maintainer wiring a new clear site through the wrapper with except would rely on exclusion semantics that have never run and have no test — a silent first-use experiment on the path that deletes user preferences.

Witness:

call-site sweep at HEAD: clearPersistedReasoningSelection has exactly one call site (Session.ts:9967, passes nothing);
the only site needing exclusion (Session.ts:9934) calls getReasoningSelectionClearWrites directly — 1 caller, 0 passing except.
Suggested change
private clearPersistedReasoningSelection(except?: SettingScope): void {
this.commitReasoningSelectionWrites(
this.getReasoningSelectionClearWrites(except),
);
}
private clearPersistedReasoningSelection(): void {
this.commitReasoningSelectionWrites(
this.getReasoningSelectionClearWrites(),
);
}

Or inline it into the sole caller and delete the method.

中文说明

clearPersistedReasoningSelection(except?) 声明并转发了 except,但没有任何调用方设置它——唯一调用点(reconcile 的 mustClear 路径,Session.ts:9967)什么都不传,而真正需要 scope 排除的地方(persistReasoningSelection,Session.ts:9934,排除 persistScope)绕过该包装器、直接调用 getReasoningSelectionClearWrites。按 AGENTS.md 对新增可选参数的"读点"规则,这是一个死开关:排除分支在生产路径上从未执行过,未来若有维护者通过该包装器带着 except 接入新的清除点,将依赖一套从未运行过、也没有测试的排除语义——在删除用户偏好的路径上做一次无声的首用实验。

见证:HEAD 上的调用点扫描:clearPersistedReasoningSelection 恰好一个调用点(Session.ts:9967,不传参);唯一需要排除的调用点(Session.ts:9934)直接调用 getReasoningSelectionClearWrites——1 个调用方,0 个传 except。

或直接内联到唯一调用点并删除该方法。

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

@wenshao

wenshao commented Aug 30, 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 Aug 30, 2026
@qwen-code-dev-bot

Copy link
Copy Markdown
Collaborator

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

中文说明

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

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

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Partially reviewed — gaps disclosed.

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

  • dead/misleading setReasoningEffort call in the R1-1 fix branch (acpAgent.ts:~5773) — already reported (comment 3889107207)
  • live-apply-then-persist-throw divergence (acpAgent.ts:~5806) — already reported as R2-5 (comment 3889107205)
  • hand-listed reasoning ladder, model-configuration.ts:67-76 + mappers.ts:29-37 — already reported as R2-c2 aggregate (comments 3889181457, 3889181463)
  • strict-vs-tolerant persisted-value interpreters (alias/case wipe via parseReasoningSelection) — already reported as R1-14/R1-21 (comments 3887695485, 3887695501), author deferred
  • 'None' case-sensitivity in the modelConfigUtils seed — already reported as R1-14 (comment 3887695485), author deferred
  • mandatory-'none' skip without warning — already reported as R1-26 (comment 3887695515), author deferred
  • single-slot pendingPersistedReasoningAction drain race (clearSession/newSession) — already reported as R1-25 (comment 3887695512), author deferred
  • withPersistedReasoningPreview patches only the current model's entry — already reported as R1-24 (comment 3887695508), author deferred
  • none→'default' one-way latch on canDisable flip (App.tsx:6753-6756) — already discussed as R1-9 (comment 3887695470); author maintains the shipped clear-never-restore contract, the rewritten test pins it
  • no-refetch guard counts an endpoint the flow never fetches (web-shell.smoke.spec.ts:586) — deferred in round 2 (D2-3)
  • workspaceReload never propagates reasoningEffort-only settings edits — deferred in round 2 (code-age rule)
  • isQwenFamilyModel duplicate of core isQwenFamilyWireModel — deferred in round 2 (code-age rule)
  • isInitialAuth identical-branch call (acpAgent.ts:~12916) — already reported as R2-c1 (comment 3889181450), still standing, not re-posted
  • 'Daemon did not confirm reasoning effort' misattribution on persist-only failure — already reported as R2-c13 (comment 3889181467), still standing, not re-posted
  • clearSession blocks teardown up to 30s — already reported as R2-c16 (comment 3889181474), still standing, not re-posted
  • 'default' absent from registered-model rejection message — already reported as R2-c25 (comment 3889181482), still standing, not re-posted
  • clearPersistedReasoningSelection(except?) dead parameter — already reported as R2-c26 (comment 3889181489), still standing, not re-posted

Not reviewed: build-and-test — test suites never ran in this review: the packages/cli build fails (TS2554, see R3-1), which ended the build-test run before its test phase; test-efficacy probe 18/18 inconclusive (harnessValidated null).

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

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

  • docs/users/configuration/settings.md:176 — [review] reasoningEffort row left stale by the new 'none' semantics (tiers-only via /effort; /effort rejects none) — deferred, code-age rule (file outside the diff, unchanged since round 2)

Convergence: round 3 posted 5 inline comment(s), 4 of them reported for the first time; the previous round posted 11 (10 new). Findings keep coming back to the same files: packages/cli/src/acp-integration/acpAgent.ts (findings in round 2; 2 more now); packages/cli/src/acp-integration/session/Session.ts (findings in round 2; 1 more now). A cluster that keeps producing siblings usually means the fixes are treating instances of a shared root cause — triaging that cause before the next round, or splitting an independent cluster into its own pull request, tends to end the loop faster than fixing them one at a time. (Observation only — nothing was withheld from this review because of this observation.)

[Critical] R2-1: [certifies-falsely] [new-surface] The /model <id> slash command's welcome branch (App.tsx:10203-10206) does only setPendingModel(modelArg) and never runs the new reasoning-intent reconciliation that the picker path runs — an explicit reasoning selection survives a picker switch but is silently dropped after a slash switch: ensureSessionForPrompt gates on reasoningIntent.modelId === modelId, the stale-bound intent yields reasoningEffort = undefined, and the new session starts with thinking ON against the explicit 'none' choice, contradicting the design doc's 'Every model switch reconciles the stored selection against the target model'. Witness: probe (App.test.tsx harness, scratch tree — explicit 'none' on qwen3.8-max, onSubmit('/model qwen3.7-plus'), first prompt): INTACT AssertionError: expected "spy" to be called with arguments: [ 'none', { persist: true } ] — Number of calls: 0; FIXED (reconciliation ported into the /model branch): probe passes. Fix: extract the reconciliation block from handleModelSelect's welcome branch into a shared helper and call it in the /model welcome branch before setPendingModel(modelArg); re-baseline the new test 'does not retarget a stale model-bound reasoning intent' (App.test.tsx:~14685), which manufactures staleness via this very branch and must not be satisfied by a false fix that merely clears the intent. (Unanchorable: the mechanism lives on unchanged lines outside the diff's hunks.)

[Critical] R3-5: [certifies-falsely] [new-surface] workspaceReload's model-name-change branch (acpAgent.ts:~12255-12266) calls raw config.switchModel(authType, newModelName) and never re-applies the persisted model.reasoningEffort: 'none' — unlike the PR-added sibling branch (which uses refreshAuthWithPersistedReasoning) and unlike Session.setModel, whose post-switch reconcile re-applies a compatible persisted selection after the same core switchModel call; applyResolvedModelDefaults overwrites every MODEL_GENERATION_CONFIG_FIELDS entry (reasoning included). A user who persisted 'none' and then changes model.name in settings.json gets a workspace reload that wipes the disable: the session silently runs with thinking ON while settings still say 'none', until an unrelated replay fires; the identical switch via setSessionConfigOption reconciles correctly. Witness: probe (booted QwenAgent, live generation.reasoning=false, settings reload flipping model.name with reasoningEffort 'none' persisted): branch taken — switchModel called — then AssertionError: expected undefined to be false (disable wiped, no replay); replaying via refreshAuthWithPersistedReasoning after the switch passes the probe. Fix: reuse the replay half of refreshAuthWithPersistedReasoning (persisted-none check + support gate + applyReasoningSelection(config, REASONING_EFFORT_NONE)) after await config.switchModel(authType, newModelName) succeeds in that branch, keeping the support gate so 'none' is never replayed onto a thinking-mandatory model. Fix witness: extend the acpAgent.test.ts workspaceReload suite — merged settings { model: { name: 'next-model', reasoningEffort: 'none' } }, live reasoning: false; after workspaceReload assert the session's generation config still has reasoning === false on the new model, then remove the post-switchModel replay and confirm the new test reds. (Unanchorable: the model-change branch is pre-existing code outside the diff's hunks.)

中文说明

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

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

未审查:build-and-test — test suites never ran in this review: the packages/cli build fails (TS2554, see R3-1), which ended the build-test run before its test phase; test-efficacy probe 18/18 inconclusive (harnessValidated null)。

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

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

收敛情况:第 3 轮发布了 5 条行内评论,其中 4 条是首次提出;上一轮发布了 11 条(其中 10 条首次提出)。发现反复回到同一批文件:packages/cli/src/acp-integration/acpAgent.ts(第 2 轮已出过发现,本轮又有 2 条);packages/cli/src/acp-integration/session/Session.ts(第 2 轮已出过发现,本轮又有 1 条)。一个不断再生兄弟发现的簇,通常意味着逐条修复只在处理同一根因的实例——先定位并处理该根因,或把独立的簇拆成单独的 PR,通常比逐条修复更快结束循环。(仅为观察——本轮评审未因此扣留任何内容。)

[Critical] R2-1: [certifies-falsely] [new-surface] The /model <id> slash command's welcome branch (App.tsx:10203-10206) does only setPendingModel(modelArg) and never runs the new reasoning-intent reconciliation that the picker path runs — an explicit reasoning selection survives a picker switch but is silently dropped after a slash switch: ensureSessionForPrompt gates on reasoningIntent.modelId === modelId, the stale-bound intent yields reasoningEffort = undefined, and the new session starts with thinking ON against the explicit 'none' choice, contradicting the design doc's 'Every model switch reconciles the stored selection against the target model'. Witness: probe (App.test.tsx harness, scratch tree — explicit 'none' on qwen3.8-max, onSubmit('/model qwen3.7-plus'), first prompt): INTACT AssertionError: expected "spy" to be called with arguments: [ 'none', { persist: true } ] — Number of calls: 0; FIXED (reconciliation ported into the /model branch): probe passes. Fix: extract the reconciliation block from handleModelSelect's welcome branch into a shared helper and call it in the /model welcome branch before setPendingModel(modelArg); re-baseline the new test 'does not retarget a stale model-bound reasoning intent' (App.test.tsx:~14685), which manufactures staleness via this very branch and must not be satisfied by a false fix that merely clears the intent. (Unanchorable: the mechanism lives on unchanged lines outside the diff's hunks.)

[Critical] R3-5: [certifies-falsely] [new-surface] workspaceReload's model-name-change branch (acpAgent.ts:~12255-12266) calls raw config.switchModel(authType, newModelName) and never re-applies the persisted model.reasoningEffort: 'none' — unlike the PR-added sibling branch (which uses refreshAuthWithPersistedReasoning) and unlike Session.setModel, whose post-switch reconcile re-applies a compatible persisted selection after the same core switchModel call; applyResolvedModelDefaults overwrites every MODEL_GENERATION_CONFIG_FIELDS entry (reasoning included). A user who persisted 'none' and then changes model.name in settings.json gets a workspace reload that wipes the disable: the session silently runs with thinking ON while settings still say 'none', until an unrelated replay fires; the identical switch via setSessionConfigOption reconciles correctly. Witness: probe (booted QwenAgent, live generation.reasoning=false, settings reload flipping model.name with reasoningEffort 'none' persisted): branch taken — switchModel called — then AssertionError: expected undefined to be false (disable wiped, no replay); replaying via refreshAuthWithPersistedReasoning after the switch passes the probe. Fix: reuse the replay half of refreshAuthWithPersistedReasoning (persisted-none check + support gate + applyReasoningSelection(config, REASONING_EFFORT_NONE)) after await config.switchModel(authType, newModelName) succeeds in that branch, keeping the support gate so 'none' is never replayed onto a thinking-mandatory model. Fix witness: extend the acpAgent.test.ts workspaceReload suite — merged settings { model: { name: 'next-model', reasoningEffort: 'none' } }, live reasoning: false; after workspaceReload assert the session's generation config still has reasoning === false on the new model, then remove the post-switchModel replay and confirm the new test reds. (Unanchorable: the model-change branch is pre-existing code outside the diff's hunks.)

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

Comment on lines +12937 to +12940
private async ensureAuthenticated(
config: Config,
settings: LoadedSettings,
): Promise<void> {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Critical] R3-1: packages/cli no longer compiles. This PR changed ensureAuthenticated to require (config: Config, settings: LoadedSettings) and updated 7 of the 8 call sites, but missed await this.ensureAuthenticated(config); at acpAgent.ts:13155 — inside the pre-publish model-provider reload loop of createAndStoreSession that arrived via the merge of main (#10269). Every build/bundle of the CLI package fails with TS2554, and no test suite can run until it is fixed. Pass the settings parameter that is already in scope there, mirroring the sibling call this PR updated at acpAgent.ts:13079 — it also gives this pre-publish auth refresh the same persisted-none replay as the other call sites.

Witness:

npm run build --workspace="packages/cli" → exit 1
src/acp-integration/acpAgent.ts(13155,24): error TS2554: Expected 2 arguments, but got 1.

Fix (acpAgent.ts:13155):

await this.ensureAuthenticated(config, settings);

Fix witness: the deterministic gate is the build itself — npm run build --workspace="packages/cli" is red with TS2554 at acpAgent.ts:13155 without the one-token fix and must go green with it; please confirm the build passes after applying it.

中文说明

packages/cli 已无法编译。本 PR 将 ensureAuthenticated 改为必须传入 (config: Config, settings: LoadedSettings),更新了 8 个调用点中的 7 个,但遗漏了 acpAgent.ts:13155 处 createAndStoreSession 发布前 model-provider 重载循环里的 await this.ensureAuthenticated(config);(该调用点随 main 合并 (#10269) 进入)。CLI 包的每次构建/打包都会以 TS2554 失败,修复前任何测试套件都无法运行。请传入该处已在作用域内的 settings 参数,与本 PR 已更新的 acpAgent.ts:13079 兄弟调用保持一致——这同时让该发布前鉴权刷新获得与其他调用点相同的持久化 none 重放。

见证:npm run build --workspace="packages/cli" 退出码 1,报错 src/acp-integration/acpAgent.ts(13155,24): error TS2554: Expected 2 arguments, but got 1.

修复见证:确定性门控就是构建本身——不加这一个 token 的修复,npm run build --workspace="packages/cli" 在 acpAgent.ts:13155 处红;修复后应变绿,请确认后回复。

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

Comment on lines +11472 to +11476
const sourceReasoningSelection =
sourceReasoningIntent?.value ??
(sourceReasoningPreview
? getReasoningSelection(sourceReasoningPreview)
: undefined);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Critical] R1-7: [certifies-falsely] [regression] Round-1 mechanism re-checked at this head and still present: this welcome no-session branch synthesizes a {modelId, value: 'default'} reasoning intent from a PREVIEW-DERIVED selection even when the user never touched a reasoning control — sourceReasoningSelection falls back to getReasoningSelection(sourceReasoningPreview). 'default' passes ensureSessionForPrompt's gates unconditionally (reasoningPreviewSupports returns true for 'default'), the first prompt sends setReasoningEffort('default', { persist: true }), and daemon-side persistReasoningSelection('default') clears the stored preference from every writable scope. Concretely: persisted medium projecting into the welcome preview → two model clicks through a reasoning-less model and back, zero reasoning interaction → the first prompt deletes the stored medium from every scope; pre-diff no intent was synthesized and the stored value survived. The design doc's Capability reconciliation speaks of removing 'every explicit selection' — a preview-derived proxy selection is not one, and at deletion time the selection is compatible: the user ends back on the model that supports the stored tier.

Witness:

probe (App.test.tsx harness, scratch tree — welcome preview 'medium', zero reasoning interaction,
clicks through a reasoning-less model and back, first prompt):
INTACT: AssertionError: expected "spy" to not be called at all, but actually been called 1 times
        1st spy call: [ "default", { "persist": true } ]
FIXED (synthesis gated on an explicit intent): probe passes, no call

Fix (gate the synthesis on an explicit selection; the daemon-side create-time reconcile still removes an unsupported persisted tier, preserving the design's end state):

setPendingReasoningIntent(
  sourceReasoningIntent && keepReasoningIntent
    ? { modelId, value: sourceReasoningIntent.value }
    : sourceReasoningIntent && !keepReasoningIntent
      ? { modelId, value: 'default' }
      : undefined,
);

Fix witness: add an App.test.tsx case — welcome preview projecting 'medium', no explicit selection, switch to a reasoning-less model and back, submit — asserting mockSessionActions.setReasoningEffort was NOT called; it goes red if the synthesis for non-explicit selections is reintroduced. The e2e discards an incompatible welcome effort when switching away and back currently pins the destructive no-interaction behavior and must be re-pinned with the fix.

中文说明

第一轮 R1-7 的机制在当前 head 复查后仍然存在:这个无会话分支即使用户从未触碰推理控件,也会从预览推导的选择合成 {modelId, value: 'default'} 推理意图——sourceReasoningSelection 回退到 getReasoningSelection(sourceReasoningPreview)'default' 无条件通过 ensureSessionForPrompt 的门控(reasoningPreviewSupports'default' 恒返回 true),首条提示发出 setReasoningEffort('default', { persist: true }),daemon 侧 persistReasoningSelection('default') 从所有可写 scope 清除已存偏好。具体路径:已存 medium 投射到 Welcome 预览 → 零推理交互地切换到一个无推理控件的模型再切回 → 首条提示把已存的 medium 从所有 scope 删除;PR 前不会合成意图,已存值得以保留。设计文档的 Capability reconciliation 写的是移除 "every explicit selection"——预览推导的代理选择不属于此列,且删除时该选择是兼容的:用户最终停在支持该档位的模型上。

见证(探针,临时树):INTACT AssertionError: expected "spy" to not be called at all, but actually been called 1 times — 1st spy call: [ "default", { "persist": true } ];将合成门控为仅显式意图后探针通过、无调用。

修复见证:新增 App.test.tsx 用例——Welcome 预览投射 'medium'、无显式选择、切到无推理模型再切回、提交——断言 mockSessionActions.setReasoningEffort 未被调用;重新引入非显式合成时该测试变红。e2e discards an incompatible welcome effort when switching away and back 目前钉住了这一无交互破坏行为,需随修复重新钉住。

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

Comment on lines +9854 to +9856
const persistDefault =
!this.requiresManagedConversationBinding &&
(options.persistDefault ?? true);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Critical] R3-2: [certifies-falsely] [new-surface] A session-scoped model switch (persistDefault: false) still permanently deletes the stored reasoning preference, crossing the operation's own persistence boundary. setModel passes persist: !this.requiresManagedConversationBinding to reconcileReasoningSelection (three lines below), ignoring the just-computed persistDefault. The only production caller passing { persistDefault: false } is the ACP setSessionConfigOption 'model' case (acpAgent.ts:5711-5718) — a session-scoped model change from any ACP host. With persisted model.reasoningEffort: 'max' valid for the user's persisted default model, switching one session to qwen3.8-max (efforts low/medium/xhigh — 'max' unsupported) via the config option deletes 'max' from settings forever while model.name/baseUrl/selectedType are deliberately not written; switching the session back restores nothing. Two explicitly non-persisting operations destroy a durable preference the unchanged default model still supports.

Witness:

probe (real Session.setModel, scratch tree):
INTACT: AssertionError: expected undefined to be 'max'
        (stored 'max' deleted by setModel(..., {persistDefault:false}); setValue never called with 'model.name')
FIXED (persist: persistDefault): 'max' kept — and the PR's pinning test
'still deletes an incompatible reasoning preference when the model default is not persisted'
fails, isolating this hunk as load-bearing

Fix:

this.reconcileReasoningSelection(effectiveModelId, {
  persist: persistDefault,
  allowReasoning: !isRuntime && !rawModelId.startsWith(ACP_ROUTE_ID_PREFIX),
});

Fix constraint: the live DEFAULT apply must remain even when the persist clear is skipped — applyReasoningSelection(this.config, REASONING_EFFORT_DEFAULT); in the mustClear branch (Session.ts:~9991) keeps the session-scoped switch from sending an unsupported effort; the model-default write gate if (persistDefault) at Session.ts:~9904 keeps its current semantics.

Fix witness: invert the new test still deletes an incompatible reasoning preference when the model default is not persisted (Session.test.ts:5195) — with persistDefault: false, assert state.user.settings.model.reasoningEffort is still 'max' and no model.reasoningEffort setValue occurred; then remove the persist: persistDefault gate and confirm the test reds.

中文说明

会话级(persistDefault: false)模型切换仍会永久删除已存的推理偏好,越过了该操作自身的持久化边界。setModelreconcileReasoningSelection(下方三行)传入 persist: !this.requiresManagedConversationBinding,忽略了刚计算出的 persistDefault。唯一传 { persistDefault: false } 的生产调用方是 ACP setSessionConfigOption 的 'model' 分支(acpAgent.ts:5711-5718)——任意 ACP 宿主发起的会话级模型变更。用户已存 model.reasoningEffort: 'max'(对其持久化默认模型有效)时,把单个会话经 config option 切到 qwen3.8-max(efforts 为 low/medium/xhigh,不支持 'max')会从设置中永久删除 'max',而 model.name/baseUrl/selectedType 刻意不写;再切回也不恢复任何东西。两个明确不持久化的操作摧毁了一个未变更默认模型仍然支持的持久偏好。

见证(探针,真实 Session.setModel,临时树):INTACT AssertionError: expected undefined to be 'max'setModel(..., {persistDefault:false}) 删除已存 'max',setValue 从未以 'model.name' 调用);改为 persist: persistDefault 后 'max' 保留,且 PR 的钉住测试 'still deletes an incompatible reasoning preference when the model default is not persisted' 变红——证明该 hunk 是承重行为。

修复约束:跳过持久化清除时 live 的 DEFAULT 应用必须保留——mustClear 分支的 applyReasoningSelection(this.config, REASONING_EFFORT_DEFAULT);(Session.ts:~9991)保证会话级切换不会发送不支持的 effort;Session.ts:~9904 的模型默认写入门控 if (persistDefault) 保持现有语义。

修复见证:把新测试 still deletes an incompatible reasoning preference when the model default is not persisted(Session.test.ts:5195)反转——persistDefault: false 时断言 state.user.settings.model.reasoningEffort 仍为 'max' 且没有发生 model.reasoningEffortsetValue;随后移除 persist: persistDefault 门控并确认测试变红。

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

(value: ReasoningSelection) =>
actions
.setReasoningEffort(value)
.setReasoningEffort(value, { persist: true })

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Critical] R3-3: [fails-closed] [regression] Reasoning controls are permanently broken for managed-conversation sessions. Every reasoning selection from the active-session UI now demands persistence (this call site and App.tsx handleReasoningEffort both send { persist: true }), but this PR's new daemon guard makes persistence impossible for managed-conversation (sourceType: 'standalone') sessions — Session.persistReasoningSelection throws Reasoning selection cannot be persisted for this session. The daemon handler live-applies the selection first (acpAgent.ts:~5780) and only then persists (~5804-5806), so the RPC fails AFTER the live mutation: the user sees reasoning.updateFailed, the chip keeps the stale state while the session actually generates with the changed setting, and every retry fails identically. Pre-PR the same controls applied live without persisting. Reachability: Web Shell standalone sessions created via DaemonSessionProvider with sessionContext.kind === 'standalone' (the daemon creates those with sourceType 'standalone'requiresManagedConversationBinding); the bundled browser app uses workspace contexts, so the affected class is integrations of the exported DaemonSessionProvider/daemon-react-sdk API.

Witness:

probe (Session constructed with getSessionSourceType() === 'standalone', scratch tree):
persistReasoningSelection('medium') threw 'Reasoning selection cannot be persisted for this session'
ordering quoted from source: live apply at acpAgent.ts:~5780 precedes persist at ~5804-5806

Fix: don't make persistence a hard requirement of the live change for sessions that cannot persist — e.g. have the daemon apply live and return persisted: false with a _meta marker naming the managed-conversation refusal instead of throwing after applying, and relax actions.setReasoningEffort's opts?.persist && result.persisted !== true check to accept that marker; or expose a 'cannot persist reasoning' capability so ChatPane/App omit persist for such sessions. Either way the live apply must not be reported as a failure.

Fix constraint: managed-conversation sessions must never write model.reasoningEffort into settings scopes — the guard is deliberate (Session.ts:9941-9945), matching reconcileReasoningSelection's persist: !this.requiresManagedConversationBinding (Session.ts:9858).

Fix witness: add an actions.test.ts case whose setConfigOption reports the managed-conversation refusal (no persisted: true) — setReasoningEffort('medium', { persist: true }) must still resolve and update connection.reasoning (live apply surfaced) rather than rejecting; removing the relaxation reds it.

中文说明

managed-conversation 会话的推理控件被永久性破坏。活跃会话 UI 的每次推理选择现在都要求持久化(本调用点与 App.tsx handleReasoningEffort 均发送 { persist: true }),但本 PR 新增的 daemon 守卫使 managed-conversation(sourceType: 'standalone')会话无法持久化——Session.persistReasoningSelection 抛出 Reasoning selection cannot be persisted for this session。daemon 处理器先 live 应用(acpAgent.ts:~5780)再持久化(~5804-5806),因此 RPC 在 live 变更之后才失败:用户看到 reasoning.updateFailed,界面保持旧状态而会话实际已按变更后的设置生成,且每次重试都以同样方式失败。PR 前同样的控件只做 live 应用、不持久化。可达性:经 DaemonSessionProvidersessionContext.kind === 'standalone' 创建的 Web Shell standalone 会话(daemon 以 sourceType 'standalone' 创建 → requiresManagedConversationBinding);内置浏览器应用使用 workspace 上下文,受影响的是导出组件 DaemonSessionProvider/daemon-react-sdk API 的集成方。

见证(探针,临时树):以 getSessionSourceType() === 'standalone' 构造的 Session 调用 persistReasoningSelection('medium') 抛出 'Reasoning selection cannot be persisted for this session';顺序引自源码:live 应用(acpAgent.ts:~5780)先于持久化(~5804-5806)。

修复:不要把持久化作为不可持久化会话 live 变更的硬性前提——例如 daemon 先 live 应用并返回 persisted: false 加一个说明 managed-conversation 拒绝的 _meta 标记,而不是应用后再抛错;同时放宽 actions.setReasoningEffortopts?.persist && result.persisted !== true 检查以接受该标记;或暴露 'cannot persist reasoning' 能力,让 ChatPane/App 对此类会话省略 persist。无论如何,live 应用成功不得被报告为失败。

修复约束:managed-conversation 会话绝不能把 model.reasoningEffort 写入设置 scope——该守卫是刻意的(Session.ts:9941-9945),与 reconcileReasoningSelectionpersist: !this.requiresManagedConversationBinding(Session.ts:9858)一致。

修复见证:新增 actions.test.ts 用例,setConfigOption 报告 managed-conversation 拒绝(无 persisted: true)——setReasoningEffort('medium', { persist: true }) 仍应 resolve 并更新 connection.reasoning(live 应用被呈现)而不是 reject;移除放宽逻辑后该测试变红。

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

Comment on lines +13340 to +13347
if (
activeRuntimeSnapshot ||
currentModelId.startsWith(ACP_ROUTE_ID_PREFIX) ||
!isReasoningSelectionSupported(
rawCurrentModelId,
REASONING_EFFORT_DEFAULT,
)
) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

[Suggestion] R3-8: For unconfigured qwen-family models, this gate hides every reasoning control and rejects every value — including 'default', the one that would clear the override — while the CLI seed path and TUI /effort still apply and persist tiers for exactly those models, model-independently. A user who runs /effort high in the TUI while a generic qwen model (not in MODEL_CONFIGURATIONS) is active persists the tier (effort-command has no model gate); every later session seeds generationConfig.reasoning = { effort: 'high' } (modelConfigUtils.ts:447-451, no family check) and emits high-effort thinking on the wire — while WebShell offers no control to inspect or clear it. Pre-PR the generic ladder was shown for all models and 'default' cleared the override; the design doc's capability policy ('a model without reasoning controls removes every explicit selection') is enforced on model switch but not at session start.

Witness:

probe (same commit):
resolveCliGenerationConfig with settings { name: 'qwen-plus', reasoningEffort: 'high' }
  → generationConfig.reasoning = { effort: 'high' }
PR's own test 'does not guess reasoning capabilities for an unregistered Qwen model' passes
  (option undefined + 'high' rejected) — both halves of the inconsistency observed together

Fix: align the two stances — either gate the seed (skip seeding the persisted tier and warn when !isReasoningSelectionSupported(modelId, selection, thinkingMandatory)), or keep offering 'default' in setSessionConfigOption as a reset for these models so the override is clearable.

中文说明

对未配置的 qwen 系模型,该门控隐藏所有推理控件并拒绝每一个值——包括唯一能清除覆盖的 'default'——而 CLI 种子路径与 TUI /effort 仍会为这些模型按模型无关的方式应用并持久化档位。用户在通用 qwen 模型(不在 MODEL_CONFIGURATIONS 中)处于激活状态时于 TUI 执行 /effort high,档位即被持久化(effort-command 无模型门控);之后每个会话都会播种 generationConfig.reasoning = { effort: 'high' }(modelConfigUtils.ts:447-451,无家族检查)并在线上发出高强度思考——而 WebShell 没有任何控件可以查看或清除它。PR 前通用档位阶梯对所有模型展示,'default' 可清除覆盖;设计文档的能力策略("无推理控件的模型移除所有显式选择")只在模型切换时执行,会话启动时不执行。

见证(探针,同一提交):resolveCliGenerationConfig 在设置 { name: 'qwen-plus', reasoningEffort: 'high' } 下产生 generationConfig.reasoning = { effort: 'high' };同时 PR 自己的测试 'does not guess reasoning capabilities for an unregistered Qwen model' 通过(option 为 undefined 且 'high' 被拒绝)——不一致的两半在同一提交上同时观察到。

修复:统一两种立场——要么门控种子(当 !isReasoningSelectionSupported(modelId, selection, thinkingMandatory) 时跳过播种并告警),要么在 setSessionConfigOption 中为这些模型保留 'default' 作为复位,使覆盖可被清除。

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

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

Labels

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants