Skip to content

feat(telemetry): client-side HTTP span + opt-in W3C traceparent propagation (#4384)#4390

Merged
wenshao merged 19 commits into
mainfrom
feat/telemetry-traceparent-propagation
May 25, 2026
Merged

feat(telemetry): client-side HTTP span + opt-in W3C traceparent propagation (#4384)#4390
wenshao merged 19 commits into
mainfrom
feat/telemetry-traceparent-propagation

Conversation

@doudouOUC

@doudouOUC doudouOUC commented May 21, 2026

Copy link
Copy Markdown
Collaborator

Closes #4384 (partial — outbound correlation headers split into follow-up). Sub-issue of #3731 (P3 deeper observability).

This PR was originally split into two stacked PRs (this one for traceparent + #4393 for session id), merged into a single PR per reviewer request, then scope-reduced again in R4 following @LaZzyMan's round-8 follow-up review. See "Scope evolution" below.

Summary

Telemetry observability only. Two changes that genuinely fit under telemetry.*:

  1. Client-side HTTP span on outbound fetch() — registers @opentelemetry/instrumentation-undici@^0.14.0. UndiciInstrumentation creates a client HTTP span per outbound fetch (LLM SDKs, MCP, WebFetch, IDE-extension out-of-process calls), exported into the operator's own OTLP collector. Lets you separate network latency (TTFB / response body transfer) from upstream model processing time — the api.generateContent span alone can't distinguish them.

  2. OTLP feedback-loop guardHttpInstrumentation and UndiciInstrumentation both receive ignoreRequestHook / ignoreOutgoingRequestHook that skip configured OTLP endpoints (telemetry.otlpEndpoint, telemetry.otlpTracesEndpoint, etc.). Without this guard, every OTLP upload would create a parasitic client span → exported → infinite loop. The hook uses WHATWG URL parsing (handles surrounding quotes, #fragment, trailing slash, default-port stripping), boundary-safe origin+path matching, and fail-open on missing protocol — accumulated across multiple wenshao review iterations.

Out of scope (split out per R4)

The earlier R1–R3 versions of this PR also injected X-Qwen-Code-Session-Id and traceparent onto every outbound LLM request as a default behavior. After @LaZzyMan's round-8 review, that work was separated out under the principle that telemetry's settings namespace shouldn't encompass wire-level behavior aimed at third-party LLM provider request streams:

  • X-Qwen-Code-Session-Id header: removed from this PR. Will land in a separate follow-up PR under the new outboundCorrelation.* namespace, with its own threat model, default-off, and own design-doc discussion. The R3 host-allowlist + fetch-wrapper code lives in git history (commits 1c8528a / cb162e7 / 7a1b4f8 / 40e1efc / 106598c) for the follow-up to cherry-pick.

  • traceparent wire propagation: now gated by a single new setting in this PR:

    "outboundCorrelation": {
      "propagateTraceContext": false // default
    }

    When false (default), NoopTextMapPropagator is installed on NodeSDK so propagation.inject() writes nothing into outbound requests. Trace IDs stay internal to the operator's OTLP collector. When true, the SDK's default W3C composite propagator (tracecontext + baggage) is installed and traceparent is written on every outbound fetch — opt in only when the LLM provider also reports into your collector (e.g. ARMS Tracing + DashScope cross-process trace continuation).

    The outboundCorrelation.* top-level namespace is intentionally separate from telemetry.*: different recipient (LLM provider vs operator's collector), different consent decision, security-relevant. The single boolean here establishes the namespace for the follow-up session-id PR.

Dependency

Adds @opentelemetry/instrumentation-undici@^0.14.0 (peer-compatible with installed @opentelemetry/instrumentation@0.203.0).

Settings

"outboundCorrelation": {
  "propagateTraceContext": false
}

Default false. See docs/developers/development/telemetry.md "Outbound correlation (SECURITY-RELEVANT)" section.

Test plan

  • sdk.test.ts: instrumentation registration, OTLP guard correctness (default-port matching, host fallback strip, asymmetric-quote tolerance, missing-protocol fail-open, IPv6 bracket handling), new propagator-gate tests (NoopTextMapPropagator installed by default, undefined when opt-in)
  • Provider construction tests still verify telemetry off / on behaviors that survived the split
  • tsc clean (core)
  • CLI/IDE-companion settings.schema.json regenerated and committed

Scope evolution (for reviewers re-reading the thread)

Round Date Trigger Result
R1 2026-05-21 initial design broadcast traceparent + X-Qwen-Code-Session-Id to all outbound LLM
R2 2026-05-22 wenshao review URL boundary normalization, OTLP-guard hardening
R3 2026-05-23 @LaZzyMan REQUEST_CHANGES (severity:high broadcast) session-id scoped to first-party Alibaba/DashScope host allowlist (telemetry.sessionIdHeaderHosts)
R4 2026-05-25 @LaZzyMan round-8 follow-up (scope conflation) Session-id apparatus removed from this PR (→ follow-up under outboundCorrelation.); traceparent moved behind explicit opt-in (default off, NoopPropagator); new outboundCorrelation. namespace established

🤖 Generated with Qwen Code


📝 描述准确性更新(2026-05-31,作者自查)

补充:Closes #4384 实际只完成 traceparent;session-id 传播(原 #4393)已移除/降级到未来 PR,建议补 tracking issue 以免 #3731 清单悬空。

Copilot AI review requested due to automatic review settings May 21, 2026 09:22
@github-actions

Copy link
Copy Markdown
Contributor

📋 Review Summary

This PR implements W3C traceparent propagation for outbound LLM requests by wiring @opentelemetry/instrumentation-undici into the SDK. The implementation is well-designed with proper safeguards against feedback loops, comprehensive test coverage, and clear documentation. The split approach (traceparent first, session ID header in part 2) is justified and reduces risk.

🔍 General Feedback

Positive aspects:

  • Excellent design doc that thoroughly analyzes the problem space and all affected providers
  • Smart use of ignoreRequestHook to prevent infinite feedback loops when OTel uploads via fetch
  • Comprehensive test coverage with 5 new tests covering edge cases (per-signal endpoints, query string stripping, no-op in outfile mode)
  • Clear justification for dependency version choice (0.14.0 vs 0.15+)
  • Good documentation updates explaining the new functionality

Architectural decisions:

  • The split into two PRs (traceparent + session ID) is well-reasoned and reduces review complexity
  • Default propagator choice (W3CTraceContextPropagator + W3CBaggagePropagator) is correct and requires no explicit configuration
  • The prefix-matching approach for OTLP endpoints is robust (strips trailing slash and query string)

Concerns:

  • One test file shows a potential issue with mock setup (see Medium priority below)
  • Documentation update claims a "Trace context propagation" subsection was added, but this doesn't appear in the diff

🎯 Specific Feedback

🟢 Medium

  • File: packages/core/src/telemetry/sdk.test.ts:55-56 - The new mocks for HttpInstrumentation and UndiciInstrumentation are added, but the existing test structure may need verification. The test at line 652 uses vi.mocked(UndiciInstrumentation).mock.calls[0]![0]! which assumes the instrumentation is always the first call. If other tests instantiate the instrumentation differently, this could be fragile. Consider adding a guard or more explicit assertion about mock call indices.

  • File: packages/core/src/telemetry/sdk.ts:328 - The otlpUrlPrefixes array is built from config values but doesn't validate that endpoints are valid URLs before using them in prefix matching. While validateUrl() exists and is used for exporter construction, the ignoreRequestHook could potentially match against malformed prefixes. Consider adding validation or at least filtering out empty strings before the .map() call (though the .filter((u): u is string => !!u) does catch empty strings).

🔵 Low

  • File: docs/developers/development/telemetry.md - The PR description mentions adding a "Trace context propagation" subsection, but the diff shows extensive updates to resource attributes, cardinality controls, and Aliyun telemetry sections instead. Either the subsection was added elsewhere or this documentation update is incomplete. Verify the intended documentation was actually added.

  • File: packages/core/src/telemetry/sdk.ts:353 - The comment explaining why undici instrumentation is needed is excellent, but consider adding a link to the design doc (docs/design/telemetry-outbound-propagation-design.md) for future maintainers who want deeper context on why this was necessary and which providers are affected.

  • File: packages/core/src/telemetry/sdk.ts:324-327 - The comment about feedback-loop avoidance is clear, but consider mentioning that this protection is specifically for file-outfile mode where there are no outbound HTTP uploads (as noted in the PR description). This would help future maintainers understand when the hook is vs isn't active.

✅ Highlights

  • Design doc quality - The design document (telemetry-outbound-propagation-design.md) is exemplary: it includes a thorough provider audit table showing which files need changes, clear reasoning for the split approach, and explicit test plans. This level of documentation makes the code review significantly easier.

  • Test coverage - The 5 new tests cover not just the happy path but important edge cases:

    • Per-signal endpoint matching
    • Query string stripping for robust prefix matching
    • No-op behavior in outfile mode
    • Distinction between OTLP endpoints and LLM provider URLs
  • Dependency management - Careful version pinning (0.14.0 instead of 0.15+) shows attention to peer compatibility and avoids breaking changes. The explicit reasoning in the PR description ("0.14.0 declares ^0.203.0 peer; newer 0.15+ versions require 0.204+") is exactly the kind of documentation that prevents future dependency headaches.

  • Provider analysis - The audit of OpenAI family providers (identifying that DashScope overrides buildHeaders() without calling super, while OpenRouter/DeepSeek/Minimax/Mistral/ModelScope would inherit automatically) demonstrates thorough code ownership understanding and will make part 2 implementation smoother.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR wires OpenTelemetry’s undici/fetch instrumentation into the core telemetry SDK so outbound LLM HTTP calls made via globalThis.fetch (undici) propagate W3C trace context (traceparent) and produce client HTTP spans, while avoiding tracing OTLP exporter uploads to prevent feedback loops. It also adds a design doc and developer documentation describing the outbound trace propagation behavior.

Changes:

  • Register @opentelemetry/instrumentation-undici alongside existing HttpInstrumentation in initializeTelemetry().
  • Add ignoreRequestHook logic to skip OTLP exporter endpoints and prevent infinite self-tracing loops.
  • Add unit tests validating both instrumentations are registered and that OTLP endpoints are ignored correctly.

Reviewed changes

Copilot reviewed 5 out of 6 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
packages/core/src/telemetry/sdk.ts Adds UndiciInstrumentation and OTLP endpoint ignore logic to propagate trace context on fetch/undici calls.
packages/core/src/telemetry/sdk.test.ts Adds tests covering instrumentation registration and ignoreRequestHook endpoint matching.
packages/core/package.json Adds @opentelemetry/instrumentation-undici@0.14.0 dependency.
package-lock.json Updates lockfile to include the new OTel undici instrumentation dependency and related dependency graph changes.
docs/developers/development/telemetry.md Documents automatic traceparent propagation on outbound LLM fetch requests and the feedback-loop avoidance approach.
docs/design/telemetry-outbound-propagation-design.md Adds the design document covering outbound propagation (part 1 + planned part 2).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/core/src/telemetry/sdk.ts Outdated
Comment thread packages/core/src/telemetry/sdk.ts Fixed
doudouOUC added a commit that referenced this pull request May 21, 2026
Review feedback on #4390:

1. CI was failing on npm ci because the lockfile was generated with npm 11
   locally (it sprinkles `peer: true` annotations npm 10 reads differently
   and rejects). Regenerated with npm 10 (matching CI's Node 22.x default),
   so the diff vs main is now 18 lines (the actual instrumentation-undici
   entry) instead of 105 lines of npm-version drift noise.

2. (Copilot inline at sdk.ts:330) `otlpUrlPrefixes` was derived from raw
   Config strings, so a settings.json `"otlpEndpoint": "\"http://...\""`
   (quoted) or trailing `#fragment` would silently miss the prefix match
   and reintroduce the feedback loop the hook exists to prevent. Replaced
   the regex-based suffix trim with a WHATWG URL parser:
   - strips ?query, #fragment, trailing slash
   - trims symmetric ASCII quotes a user may have placed in settings.json
   - falls back to safe suffix trimming if URL parsing fails (misconfigured
     endpoint still gets SOME protection)

3. (CodeQL inline) Replaced the `/\?.*$/` regex in ignoreRequestHook with
   `indexOf('?')`/`indexOf('#')` slicing for ReDoS hygiene. The regex was
   linear in practice but flagged as polynomial — using indexOf removes
   the ambiguity and is arguably simpler.

Added 3 tests in sdk.test.ts covering the new normalizations (#fragment
on incoming path, quoted endpoint, #fragment on configured endpoint).

🤖 Generated with [Qwen Code](https://github.com/QwenLM/qwen-code)
doudouOUC added a commit that referenced this pull request May 21, 2026
Review feedback on #4390:

1. CI was failing on npm ci because the lockfile was generated with npm 11
   locally (it sprinkles `peer: true` annotations npm 10 reads differently
   and rejects). Regenerated with npm 10 (matching CI's Node 22.x default),
   so the diff vs main is now 18 lines (the actual instrumentation-undici
   entry) instead of 105 lines of npm-version drift noise.

2. (Copilot inline at sdk.ts:330) `otlpUrlPrefixes` was derived from raw
   Config strings, so a settings.json `"otlpEndpoint": "\"http://...\""`
   (quoted) or trailing `#fragment` would silently miss the prefix match
   and reintroduce the feedback loop the hook exists to prevent. Replaced
   the regex-based suffix trim with a WHATWG URL parser:
   - strips ?query, #fragment, trailing slash
   - trims symmetric ASCII quotes a user may have placed in settings.json
   - falls back to safe suffix trimming if URL parsing fails (misconfigured
     endpoint still gets SOME protection)

3. (CodeQL inline) Replaced the `/\?.*$/` regex in ignoreRequestHook with
   `indexOf('?')`/`indexOf('#')` slicing for ReDoS hygiene. The regex was
   linear in practice but flagged as polynomial — using indexOf removes
   the ambiguity and is arguably simpler.

Added 3 tests in sdk.test.ts covering the new normalizations (#fragment
on incoming path, quoted endpoint, #fragment on configured endpoint).

🤖 Generated with [Qwen Code](https://github.com/QwenLM/qwen-code)
@github-actions

github-actions Bot commented May 21, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Summary

Package Lines Statements Functions Branches
CLI 76.9% 76.9% 79.54% 79.98%
Core 80.15% 80.15% 82.47% 83%
CLI Package - Full Text Report
-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |    76.9 |    79.98 |   79.54 |    76.9 |                   
 src               |      76 |    69.51 |   81.08 |      76 |                   
  gemini.tsx       |   68.69 |    66.66 |   77.77 |   68.69 | ...29,946-949,961 
  ...ractiveCli.ts |   80.23 |     68.3 |   78.57 |   80.23 | ...1054,1092,1195 
  ...liCommands.ts |    74.9 |     75.6 |     100 |    74.9 | ...41-265,290,391 
  ...ActiveAuth.ts |     100 |     87.5 |     100 |     100 | 66-80             
 ...cp-integration |   61.97 |    65.24 |   78.12 |   61.97 |                   
  acpAgent.ts      |   63.32 |    65.35 |   83.05 |   63.32 | ...2112,2126-2134 
  authMethods.ts   |   12.19 |      100 |       0 |   12.19 | 11-31,34-38,41-50 
  errorCodes.ts    |       0 |        0 |       0 |       0 | 1-22              
  ...DirContext.ts |     100 |      100 |     100 |     100 |                   
 ...ration/service |   68.65 |    83.33 |   66.66 |   68.65 |                   
  filesystem.ts    |   68.65 |    83.33 |   66.66 |   68.65 | ...32,77-94,97-98 
 ...ration/session |   75.88 |    72.05 |   86.25 |   75.88 |                   
  ...ryReplayer.ts |   67.34 |     75.6 |   81.81 |   67.34 | ...54-269,282-283 
  Session.ts       |   74.93 |    70.81 |   88.46 |   74.93 | ...2658,2664-2667 
  ...entTracker.ts |   90.85 |    84.84 |      90 |   90.85 | ...35,199,251-260 
  index.ts         |       0 |        0 |       0 |       0 | 1-40              
  ...ssionUtils.ts |   84.21 |    77.77 |     100 |   84.21 | ...37-153,209-211 
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...ssion/emitters |   96.01 |    90.75 |    92.3 |   96.01 |                   
  BaseEmitter.ts   |   76.92 |    66.66 |      80 |   76.92 | 23-24,39-40,55-56 
  ...ageEmitter.ts |     100 |    89.47 |     100 |     100 | 109,111           
  PlanEmitter.ts   |     100 |      100 |     100 |     100 |                   
  ...allEmitter.ts |   98.06 |     92.3 |     100 |   98.06 | 227-228,327,335   
  index.ts         |       0 |        0 |       0 |       0 | 1-10              
 ...ession/rewrite |   90.36 |    87.83 |   94.11 |   90.36 |                   
  LlmRewriter.ts   |      81 |       84 |     100 |      81 | ...,88-89,155-159 
  ...Middleware.ts |   95.83 |    85.71 |     100 |   95.83 | 119,127-129       
  TurnBuffer.ts    |     100 |      100 |     100 |     100 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 src/commands      |   47.93 |    85.71 |   43.47 |   47.93 |                   
  auth.ts          |     100 |    83.33 |     100 |     100 | 11,14             
  channel.ts       |   56.66 |      100 |       0 |   56.66 | 15-19,27-34       
  extensions.tsx   |   96.55 |      100 |      50 |   96.55 | 37                
  hooks.tsx        |   66.66 |      100 |       0 |   66.66 | 20-24             
  mcp.ts           |   94.73 |      100 |      50 |   94.73 | 28                
  review.ts        |   51.85 |      100 |       0 |   51.85 | 24-35,38          
  serve.ts         |    7.74 |      100 |       0 |    7.74 | ...51-147,149-230 
 ...mmands/channel |   39.25 |    79.45 |      50 |   39.25 |                   
  ...l-registry.ts |    8.57 |      100 |       0 |    8.57 | 6-21,24-42        
  config-utils.ts  |      92 |      100 |   66.66 |      92 | 21-26             
  configure.ts     |    14.7 |      100 |       0 |    14.7 | 18-21,23-84       
  pairing.ts       |   26.31 |      100 |       0 |   26.31 | ...30,40-50,52-65 
  pidfile.ts       |   96.34 |    86.95 |     100 |   96.34 | 49,59,91          
  start.ts         |   30.98 |       52 |   69.23 |   30.98 | ...72-475,484-486 
  status.ts        |   17.85 |      100 |       0 |   17.85 | 15-26,32-76       
  stop.ts          |      20 |      100 |       0 |      20 | 14-48             
 ...nds/extensions |   84.89 |    88.52 |   81.81 |   84.89 |                   
  consent.ts       |   71.65 |    89.28 |   42.85 |   71.65 | ...85-141,156-162 
  disable.ts       |     100 |      100 |     100 |     100 |                   
  enable.ts        |     100 |      100 |     100 |     100 |                   
  install.ts       |    75.6 |    66.66 |   66.66 |    75.6 | ...39-142,145-153 
  link.ts          |     100 |      100 |     100 |     100 |                   
  list.ts          |     100 |      100 |     100 |     100 |                   
  new.ts           |     100 |      100 |     100 |     100 |                   
  settings.ts      |   99.15 |      100 |   83.33 |   99.15 | 151               
  uninstall.ts     |    37.5 |      100 |   33.33 |    37.5 | 23-45,57-64,67-70 
  update.ts        |   96.32 |      100 |     100 |   96.32 | 101-105           
  utils.ts         |   65.06 |    31.25 |     100 |   65.06 | ...85,87-91,93-97 
 ...les/mcp-server |       0 |        0 |       0 |       0 |                   
  example.ts       |       0 |        0 |       0 |       0 | 1-60              
 src/commands/mcp  |   92.29 |    86.08 |   88.88 |   92.29 |                   
  add.ts           |     100 |    98.03 |     100 |     100 | 293               
  list.ts          |   91.22 |    80.76 |      80 |   91.22 | ...19-121,146-147 
  reconnect.ts     |   76.72 |    71.42 |   85.71 |   76.72 | 35-48,153-175     
  remove.ts        |     100 |       80 |     100 |     100 | 21-25             
 ...ommands/review |   11.57 |      100 |       0 |   11.57 |                   
  cleanup.ts       |   17.94 |      100 |       0 |   17.94 | ...01-106,108-109 
  deterministic.ts |   13.75 |      100 |       0 |   13.75 | ...22-738,740-741 
  fetch-pr.ts      |   11.36 |      100 |       0 |   11.36 | ...80-201,203-204 
  load-rules.ts    |   11.32 |      100 |       0 |   11.32 | ...41-153,155-156 
  pr-context.ts    |    6.22 |      100 |       0 |    6.22 | ...97-312,314-315 
  presubmit.ts     |    9.35 |      100 |       0 |    9.35 | ...62-287,289-290 
 ...nds/review/lib |      30 |      100 |       0 |      30 |                   
  gh.ts            |   22.58 |      100 |       0 |   22.58 | ...49,53-54,62-69 
  git.ts           |   22.72 |      100 |       0 |   22.72 | 15-18,29-39,43-44 
  paths.ts         |   52.94 |      100 |       0 |   52.94 | ...26,37-38,42-43 
 src/config        |   92.95 |    85.06 |   89.13 |   92.95 |                   
  auth.ts          |   86.98 |    80.32 |     100 |   86.98 | ...26-227,243-244 
  config.ts        |   87.97 |    84.36 |      80 |   87.97 | ...1857,1859-1867 
  keyBindings.ts   |   96.55 |       50 |     100 |   96.55 | 193-196           
  ...ngsAdapter.ts |     100 |    94.11 |     100 |     100 | 64                
  ...idersScope.ts |      92 |       90 |     100 |      92 | 11-12             
  sandboxConfig.ts |   61.64 |    71.87 |   66.66 |   61.64 | ...54-68,73,77-89 
  settings.ts      |   85.76 |    87.25 |   89.18 |   85.76 | ...1148,1153-1156 
  ...ingsSchema.ts |     100 |      100 |     100 |     100 |                   
  ...tedFolders.ts |   96.22 |       94 |     100 |   96.22 | ...88-190,205-206 
 ...nfig/migration |   94.89 |    78.94 |   83.33 |   94.89 |                   
  index.ts         |   94.87 |    88.88 |     100 |   94.87 | 91-92             
  scheduler.ts     |   96.55 |    77.77 |     100 |   96.55 | 19-20             
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...ation/versions |   94.74 |       96 |     100 |   94.74 |                   
  ...-v2-shared.ts |     100 |      100 |     100 |     100 |                   
  v1-to-v2.ts      |   81.75 |    90.19 |     100 |   81.75 | ...28-229,231-247 
  v2-to-v3.ts      |     100 |      100 |     100 |     100 |                   
  v3-to-v4.ts      |     100 |      100 |     100 |     100 |                   
 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    |   63.09 |    64.51 |   55.55 |   63.09 |                   
  ...tputBridge.ts |   62.94 |    65.51 |   56.25 |   62.94 | ...22-323,331-334 
  ...utContext.tsx |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-8               
 src/export        |       0 |        0 |       0 |       0 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-7               
 src/generated     |     100 |      100 |     100 |     100 |                   
  git-commit.ts    |     100 |      100 |     100 |     100 |                   
 src/i18n          |   81.47 |    75.94 |   65.71 |   81.47 |                   
  index.ts         |   63.68 |    69.56 |   53.84 |   63.68 | ...70-271,281-286 
  languages.ts     |   96.92 |    86.66 |     100 |   96.92 | 134-135,167,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 |   72.57 |    71.12 |   74.07 |   72.57 |                   
  session.ts       |   76.64 |     69.4 |   85.71 |   76.64 | ...23-824,833-843 
  types.ts         |    42.5 |      100 |   33.33 |    42.5 | ...87-588,591-592 
 ...active/control |   77.04 |    88.23 |      80 |   77.04 |                   
  ...rolContext.ts |    7.14 |        0 |       0 |    7.14 | 49-84             
  ...Dispatcher.ts |   91.66 |    91.83 |   88.88 |   91.66 | ...54-372,388,391 
  ...rolService.ts |       8 |        0 |       0 |       8 | 46-179            
 ...ol/controllers |    7.03 |       80 |   13.33 |    7.03 |                   
  ...Controller.ts |   19.32 |      100 |      60 |   19.32 | 81-118,127-210    
  ...Controller.ts |       0 |        0 |       0 |       0 | 1-56              
  ...Controller.ts |    3.94 |      100 |   11.11 |    3.94 | ...63-381,391-496 
  ...Controller.ts |   14.06 |      100 |       0 |   14.06 | ...82-117,130-133 
  ...Controller.ts |    5.21 |      100 |       0 |    5.21 | ...21-433,442-471 
 .../control/types |       0 |        0 |       0 |       0 |                   
  serviceAPIs.ts   |       0 |        0 |       0 |       0 | 1                 
 ...Interactive/io |   98.01 |    93.77 |   95.23 |   98.01 |                   
  ...putAdapter.ts |   97.89 |    92.82 |   98.07 |   97.89 | ...1303,1398-1399 
  ...putAdapter.ts |      96 |     90.9 |   85.71 |      96 | 51-52             
  ...nputReader.ts |     100 |    94.73 |     100 |     100 | 67                
  ...putAdapter.ts |   98.38 |      100 |   90.47 |   98.38 | 83-84,124-125     
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/patches       |       0 |        0 |       0 |       0 |                   
  is-in-ci.ts      |       0 |        0 |       0 |       0 | 1-17              
 src/remoteInput   |   86.98 |       75 |   85.71 |   86.98 |                   
  ...utContext.tsx |     100 |      100 |     100 |     100 |                   
  ...putWatcher.ts |   88.12 |    76.08 |   91.66 |   88.12 | ...21-222,233-236 
  index.ts         |       0 |        0 |       0 |       0 | 1-8               
 src/serve         |    79.3 |     78.8 |   92.85 |    79.3 |                   
  auth.ts          |   88.49 |    88.63 |     100 |   88.49 | ...49-150,153-155 
  capabilities.ts  |     100 |     90.9 |     100 |     100 | 264               
  ...usProvider.ts |   67.01 |    51.42 |     100 |   67.01 | ...40-245,278-286 
  debugMode.ts     |     100 |      100 |     100 |     100 |                   
  demo.ts          |     100 |      100 |     100 |     100 |                   
  envSnapshot.ts   |    92.3 |       84 |     100 |    92.3 | 108-111,170-177   
  eventBus.ts      |     100 |      100 |     100 |     100 |                   
  httpAcpBridge.ts |   79.62 |    78.84 |   96.38 |   79.62 | ...4246,4277-4318 
  ...oryChannel.ts |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-106             
  loopbackBinds.ts |     100 |      100 |     100 |     100 |                   
  runQwenServe.ts  |   73.98 |    87.83 |   55.55 |   73.98 | ...94-710,735-737 
  server.ts        |   86.18 |    82.94 |   90.62 |   86.18 | ...2478,2543-2552 
  status.ts        |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...paceAgents.ts |   64.87 |    70.45 |    90.9 |   64.87 | ...1306,1316-1326 
  ...paceMemory.ts |   87.13 |    78.46 |     100 |   87.13 | ...54-361,421-428 
 src/serve/auth    |   86.54 |    78.75 |   93.75 |   86.54 |                   
  deviceFlow.ts    |   96.33 |    79.51 |    97.5 |   96.33 | ...1526,1630,1700 
  ...owProvider.ts |   45.23 |    74.07 |      75 |   45.23 | ...90-359,375,379 
 src/serve/fs      |   84.85 |    79.75 |     100 |   84.85 |                   
  audit.ts         |     100 |    96.15 |     100 |     100 | 201               
  errors.ts        |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  paths.ts         |   77.82 |    77.08 |     100 |   77.82 | ...64,493-497,510 
  policy.ts        |   90.32 |    89.18 |     100 |   90.32 | 142-150           
  ...FileSystem.ts |   83.55 |    76.22 |     100 |   83.55 | ...1859,1886-1887 
 src/serve/routes  |   89.41 |       70 |     100 |   89.41 |                   
  ...ceFileRead.ts |   94.41 |    76.92 |     100 |   94.41 | ...28-329,390-392 
  ...eFileWrite.ts |    82.1 |    60.52 |     100 |    82.1 | ...42-244,247-249 
 src/services      |   91.66 |    91.21 |   97.56 |   91.66 |                   
  ...mandLoader.ts |     100 |    93.75 |     100 |     100 | 92                
  ...killLoader.ts |     100 |    96.15 |     100 |     100 | 47                
  ...andService.ts |    98.7 |      100 |     100 |    98.7 | 107               
  ...mandLoader.ts |   86.83 |    83.87 |     100 |   86.83 | ...30-335,340-345 
  ...omptLoader.ts |   75.84 |    80.64 |   83.33 |   75.84 | ...10-211,277-278 
  ...mandLoader.ts |     100 |      100 |     100 |     100 |                   
  ...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.21 |    96.66 |     100 |   98.21 | 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 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...ght/generators |    85.9 |    85.61 |   90.47 |    85.9 |                   
  DataProcessor.ts |   85.63 |     85.6 |   92.85 |   85.63 | ...1122,1126-1133 
  ...tGenerator.ts |   98.21 |    85.71 |     100 |   98.21 | 46                
  ...teRenderer.ts |   45.45 |      100 |       0 |   45.45 | 13-51             
 .../insight/types |       0 |       50 |      50 |       0 |                   
  ...sightTypes.ts |       0 |        0 |       0 |       0 |                   
  ...sightTypes.ts |       0 |        0 |       0 |       0 | 1                 
 ...mpt-processors |   97.27 |    94.04 |     100 |   97.27 |                   
  ...tProcessor.ts |     100 |      100 |     100 |     100 |                   
  ...eProcessor.ts |   94.52 |    84.21 |     100 |   94.52 | 46-47,93-94       
  ...tionParser.ts |     100 |      100 |     100 |     100 |                   
  ...lProcessor.ts |   97.41 |    95.65 |     100 |   97.41 | 95-98             
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/services/tips |   97.35 |    83.07 |     100 |   97.35 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  tipHistory.ts    |   92.45 |       70 |     100 |   92.45 | ...22,144,151,160 
  tipRegistry.ts   |     100 |    95.23 |     100 |     100 | 33                
  tipScheduler.ts  |     100 |    91.66 |     100 |     100 | 55                
 src/test-utils    |   93.75 |    83.33 |      80 |   93.75 |                   
  ...omMatchers.ts |   69.69 |       50 |      50 |   69.69 | 32-35,37-39,45-47 
  ...andContext.ts |     100 |      100 |     100 |     100 |                   
  render.tsx       |     100 |      100 |     100 |     100 |                   
 src/ui            |   65.51 |    73.04 |   60.34 |   65.51 |                   
  App.tsx          |     100 |      100 |     100 |     100 |                   
  AppContainer.tsx |   63.66 |     64.7 |      50 |   63.66 | ...3151,3155-3159 
  ...tionNudge.tsx |    9.58 |      100 |       0 |    9.58 | 24-94             
  ...ackDialog.tsx |   29.23 |      100 |       0 |   29.23 | 25-75             
  ...tionNudge.tsx |    7.69 |      100 |       0 |    7.69 | 25-103            
  colors.ts        |      60 |      100 |   35.29 |      60 | ...52,54-55,60-61 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  keyMatchers.ts   |   95.91 |    97.05 |     100 |   95.91 | 25-26             
  ...tic-colors.ts |     100 |      100 |     100 |     100 |                   
  ...inePresets.ts |   98.17 |    88.88 |     100 |   98.17 | ...12,239,387-389 
  textConstants.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/ui/auth       |   52.97 |    51.21 |   42.42 |   52.97 |                   
  AuthDialog.tsx   |   62.87 |     42.1 |   18.18 |   62.87 | ...03,310-332,336 
  ...nProgress.tsx |       0 |        0 |       0 |       0 | 1-64              
  ...etupSteps.tsx |    39.4 |       32 |   38.46 |    39.4 | ...68,471,477,480 
  useAuth.ts       |   94.55 |    73.52 |     100 |   94.55 | ...19-220,239-245 
  ...rSetupFlow.ts |   43.45 |    33.33 |      50 |   43.45 | ...68-389,406-449 
 src/ui/commands   |   74.11 |    80.97 |   82.22 |   74.11 |                   
  aboutCommand.ts  |     100 |      100 |     100 |     100 |                   
  agentsCommand.ts |   83.78 |      100 |      60 |   83.78 | 30-32,42-44       
  ...odeCommand.ts |   89.04 |    81.25 |     100 |   89.04 | 91-92,94-99       
  arenaCommand.ts  |   62.81 |    58.73 |   65.21 |   62.81 | ...91-596,681-689 
  authCommand.ts   |     100 |      100 |     100 |     100 |                   
  branchCommand.ts |     100 |      100 |     100 |     100 |                   
  btwCommand.ts    |   95.59 |    71.42 |     100 |   95.59 | 72,154-159        
  bugCommand.ts    |   81.13 |    71.42 |     100 |   81.13 | 60-69             
  clearCommand.ts  |      92 |    76.47 |     100 |      92 | 43-44,72-73,91-92 
  ...essCommand.ts |    64.7 |       50 |      75 |    64.7 | ...48-149,163-166 
  ...extCommand.ts |   35.24 |    28.57 |   45.45 |   35.24 | ...86-521,532-533 
  copyCommand.ts   |   98.28 |    94.89 |     100 |   98.28 | ...80,280,321,327 
  deleteCommand.ts |     100 |      100 |     100 |     100 |                   
  diffCommand.ts   |     100 |     87.5 |     100 |     100 | ...61,224-225,238 
  ...ryCommand.tsx |   76.87 |    79.03 |   88.88 |   76.87 | ...59-264,318-326 
  docsCommand.ts   |     100 |    88.88 |     100 |     100 | 25                
  doctorCommand.ts |   95.06 |    88.28 |     100 |   95.06 | ...92-293,320-321 
  dreamCommand.ts  |      75 |    66.66 |   66.66 |      75 | 22-27,44-47       
  editorCommand.ts |     100 |      100 |     100 |     100 |                   
  exportCommand.ts |   98.25 |    91.02 |     100 |   98.25 | ...81,198-199,364 
  ...onsCommand.ts |   49.33 |     90.9 |   63.63 |   49.33 | ...06-110,163-215 
  forgetCommand.ts |   26.82 |      100 |      50 |   26.82 | 18-51             
  goalCommand.ts   |   91.41 |    84.44 |      90 |   91.41 | ...86-189,201-204 
  helpCommand.ts   |     100 |      100 |     100 |     100 |                   
  hooksCommand.ts  |    20.4 |       40 |      40 |    20.4 | ...48-180,204-205 
  ideCommand.ts    |   60.75 |    64.28 |   41.17 |   60.75 | ...05-306,310-324 
  initCommand.ts   |   84.33 |    72.72 |     100 |   84.33 | 68,82-87,89-94    
  ...ghtCommand.ts |   74.56 |    68.42 |     100 |   74.56 | ...31-245,250-273 
  ...ageCommand.ts |   92.17 |    82.69 |     100 |   92.17 | ...43,164,173-183 
  lspCommand.ts    |     100 |    86.95 |     100 |     100 | 31,101-102        
  mcpCommand.ts    |     100 |      100 |     100 |     100 |                   
  memoryCommand.ts |     100 |      100 |     100 |     100 |                   
  modelCommand.ts  |   75.09 |    78.18 |      75 |   75.09 | ...20-225,262-267 
  ...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             
  ...berCommand.ts |   32.43 |      100 |      50 |   32.43 | 23-57             
  renameCommand.ts |   85.71 |    86.04 |     100 |   85.71 | ...02-209,216-221 
  ...oreCommand.ts |    92.3 |    87.87 |     100 |    92.3 | ...,83-88,129-130 
  resumeCommand.ts |     100 |      100 |     100 |     100 |                   
  rewindCommand.ts |      80 |      100 |      50 |      80 | 19-21             
  ...ngsCommand.ts |     100 |      100 |     100 |     100 |                   
  ...hubCommand.ts |   81.43 |    65.21 |      80 |   81.43 | ...70-173,176-179 
  skillsCommand.ts |   37.06 |       50 |      50 |   37.06 | ...99-115,118-145 
  statsCommand.ts  |   88.19 |    84.21 |     100 |   88.19 | ...,58-61,143-146 
  ...ineCommand.ts |     100 |      100 |     100 |     100 |                   
  ...aryCommand.ts |    6.46 |      100 |      50 |    6.46 | 31-329            
  tasksCommand.ts  |   77.22 |    72.13 |     100 |   77.22 | ...46-150,172-177 
  ...tupCommand.ts |     100 |      100 |     100 |     100 |                   
  themeCommand.ts  |     100 |      100 |     100 |     100 |                   
  toolsCommand.ts  |     100 |      100 |     100 |     100 |                   
  trustCommand.ts  |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
  vimCommand.ts    |   54.54 |      100 |      50 |   54.54 | 19-29             
 src/ui/components |   62.49 |    75.12 |   64.85 |   62.49 |                   
  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    |   89.06 |       75 |     100 |   89.06 | 37,39-44,46       
  ...odeDialog.tsx |     9.7 |      100 |       0 |     9.7 | 35-47,50-182      
  AsciiArt.ts      |     100 |      100 |     100 |     100 |                   
  ...Indicator.tsx |   13.04 |      100 |       0 |   13.04 | 18-61             
  ...TextInput.tsx |   77.01 |       76 |     100 |   77.01 | ...20,234-236,263 
  Composer.tsx     |    81.6 |     64.7 |     100 |    81.6 | ...90,108,160,173 
  ...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 
  ...ification.tsx |   28.57 |      100 |       0 |   28.57 | 16-36             
  ...gProfiler.tsx |       0 |        0 |       0 |       0 | 1-36              
  ...ogManager.tsx |   11.98 |      100 |       0 |   11.98 | 65-508            
  DiffDialog.tsx   |    2.47 |      100 |       0 |    2.47 | 68-732            
  ...ngsDialog.tsx |    8.44 |      100 |       0 |    8.44 | 37-195            
  ExitWarning.tsx  |     100 |      100 |     100 |     100 |                   
  ...hProgress.tsx |    87.8 |    33.33 |     100 |    87.8 | 28-31,56          
  ...ustDialog.tsx |     100 |      100 |     100 |     100 |                   
  Footer.tsx       |   76.59 |    48.64 |     100 |   76.59 | ...35-136,175-180 
  ...ngSpinner.tsx |   68.42 |       80 |      50 |   68.42 | 35-52,73,80-81    
  GoalPill.tsx     |   76.19 |    81.81 |     100 |   76.19 | 24-30,46-50       
  Header.tsx       |   98.62 |    94.28 |     100 |   98.62 | 162,164           
  Help.tsx         |   98.32 |       90 |     100 |   98.32 | ...24,381,447-448 
  ...emDisplay.tsx |    61.7 |       36 |     100 |    61.7 | ...42,345,348-354 
  ...ngeDialog.tsx |     100 |      100 |     100 |     100 |                   
  InputPrompt.tsx  |   83.01 |    79.78 |   83.33 |   83.01 | ...1399,1531,1581 
  ...Shortcuts.tsx |   20.87 |      100 |       0 |   20.87 | ...6,49-51,67-125 
  ...Indicator.tsx |     100 |    91.42 |     100 |     100 | 65,74             
  ...firmation.tsx |   91.42 |      100 |      50 |   91.42 | 26-31             
  MainContent.tsx  |   81.75 |       75 |     100 |   81.75 | ...70-274,282-286 
  MemoryDialog.tsx |    55.1 |    54.54 |   57.14 |    55.1 | ...56,368,381-383 
  ...geDisplay.tsx |       0 |        0 |       0 |       0 | 1-41              
  ModelDialog.tsx  |   80.12 |    63.55 |     100 |   80.12 | ...39-555,612-616 
  ...tsDisplay.tsx |     100 |    97.22 |     100 |     100 | 270               
  ...fications.tsx |   18.18 |      100 |       0 |   18.18 | 15-58             
  ...onsDialog.tsx |    2.13 |      100 |       0 |    2.13 | 62-133,148-1004   
  ...ryDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...icePrompt.tsx |   92.64 |    85.71 |     100 |   92.64 | 102-106,134-139   
  PrepareLabel.tsx |   91.66 |    77.27 |     100 |   91.66 | 73-75,77-79,110   
  ...atePrompt.tsx |    8.57 |      100 |       0 |    8.57 | 24-55,58-134      
  ...geDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...ngDisplay.tsx |   21.42 |      100 |       0 |   21.42 | 13-39             
  ...hProgress.tsx |   85.25 |    88.46 |     100 |   85.25 | 121-147           
  ...dSelector.tsx |   41.26 |    61.53 |   71.42 |   41.26 | ...74-472,476-520 
  ...ionPicker.tsx |   83.66 |    72.13 |     100 |   83.66 | ...96,402,444-466 
  ...onPreview.tsx |   92.42 |    84.37 |     100 |   92.42 | ...,70-71,143-145 
  ...ryDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...putPrompt.tsx |   72.56 |       80 |      40 |   72.56 | ...06-109,114-117 
  ...ngsDialog.tsx |   66.27 |    71.16 |      75 |   66.27 | ...12-820,826-827 
  ...ionDialog.tsx |    87.8 |      100 |   33.33 |    87.8 | 36-39,44-51       
  ...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             
  ...ionPicker.tsx |   17.59 |      100 |       0 |   17.59 | 55-172            
  StatsDisplay.tsx |     100 |      100 |     100 |     100 |                   
  ...ineDialog.tsx |   93.69 |    83.92 |     100 |   93.69 | ...11,273,293-295 
  ...yTodoList.tsx |   94.17 |       80 |     100 |   94.17 | 56-57,131-134     
  ...nsDisplay.tsx |   87.25 |       64 |     100 |   87.25 | ...47-149,156-158 
  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 |    81.81 |     100 |     100 | 71-86             
  ...ification.tsx |   36.36 |      100 |       0 |   36.36 | 15-22             
  ...ackDialog.tsx |    7.84 |      100 |       0 |    7.84 | 24-134            
  ...xitDialog.tsx |   80.36 |    43.47 |      60 |   80.36 | ...24-238,248-251 
 ...nts/agent-view |   38.31 |    70.83 |   36.36 |   38.31 |                   
  ...atContent.tsx |    8.79 |      100 |       0 |    8.79 | 53-265,271-273    
  ...tChatView.tsx |   21.05 |      100 |       0 |   21.05 | 21-39             
  ...tComposer.tsx |   10.28 |      100 |       0 |   10.28 | 58-311            
  AgentFooter.tsx  |   17.07 |      100 |       0 |   17.07 | 28-66             
  AgentHeader.tsx  |   15.38 |      100 |       0 |   15.38 | 27-64             
  AgentTabBar.tsx  |    87.8 |    27.27 |     100 |    87.8 | ...,85,98-106,124 
  ...oryAdapter.ts |     100 |    91.83 |     100 |     100 | 103,109-110,138   
  index.ts         |       0 |        0 |       0 |       0 | 1-12              
 ...mponents/arena |   45.72 |    70.53 |   60.86 |   45.72 |                   
  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 |   10.15 |      100 |       0 |   10.15 | 27-161            
  ...tusDialog.tsx |    5.63 |      100 |       0 |    5.63 | 33-75,80-288      
  ...topDialog.tsx |    6.17 |      100 |       0 |    6.17 | 33-213            
 ...ackground-view |   75.63 |    84.44 |   85.29 |   75.63 |                   
  ...sksDialog.tsx |   70.92 |    80.39 |   76.19 |   70.92 | ...1118,1194-1196 
  ...TasksPill.tsx |   63.75 |    86.95 |     100 |   63.75 | 44,86-106,114-122 
  ...gentPanel.tsx |   99.53 |    93.18 |     100 |   99.53 | 123               
 ...nts/extensions |   45.28 |    33.33 |      60 |   45.28 |                   
  ...gerDialog.tsx |   44.31 |    34.14 |      75 |   44.31 | ...71-480,483-488 
  index.ts         |       0 |        0 |       0 |       0 | 1-9               
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...tensions/steps |   54.88 |    94.23 |   66.66 |   54.88 |                   
  ...ctionStep.tsx |   95.12 |    92.85 |   85.71 |   95.12 | 84-86,89          
  ...etailStep.tsx |    6.18 |      100 |       0 |    6.18 | 20-131            
  ...nListStep.tsx |   88.43 |    94.73 |      80 |   88.43 | 52-53,59-72,106   
  ...electStep.tsx |   13.46 |      100 |       0 |   13.46 | 20-70             
  ...nfirmStep.tsx |   19.56 |      100 |       0 |   19.56 | 23-65             
  index.ts         |     100 |      100 |     100 |     100 |                   
 ...mponents/hooks |   68.67 |    69.07 |   69.56 |   68.67 |                   
  ...etailStep.tsx |   74.68 |    66.66 |   66.66 |   74.68 | ...71-184,188-201 
  ...etailStep.tsx |    87.4 |    73.68 |     100 |    87.4 | 41-42,99-113,119  
  ...abledStep.tsx |     100 |      100 |     100 |     100 |                   
  ...sListStep.tsx |     100 |      100 |     100 |     100 |                   
  ...entDialog.tsx |   34.51 |    47.05 |   42.85 |   34.51 | ...78,482-495,499 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-13              
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...components/mcp |   20.98 |    86.36 |   83.33 |   20.98 |                   
  ...ealthPill.tsx |   68.42 |    85.71 |     100 |   68.42 | 40-46             
  ...entDialog.tsx |    3.64 |      100 |       0 |    3.64 | 41-717            
  constants.ts     |     100 |      100 |     100 |     100 |                   
  index.ts         |       0 |        0 |       0 |       0 | 1-30              
  types.ts         |     100 |      100 |     100 |     100 |                   
  utils.ts         |   95.83 |    88.88 |     100 |   95.83 | 16,20,109-110     
 ...ents/mcp/steps |   26.74 |    54.54 |   42.85 |   26.74 |                   
  ...icateStep.tsx |    5.88 |      100 |       0 |    5.88 | 40-55,58-296      
  ...electStep.tsx |   10.95 |      100 |       0 |   10.95 | 16-88             
  ...etailStep.tsx |    5.26 |      100 |       0 |    5.26 | 31-247            
  ...rListStep.tsx |   75.18 |    59.37 |     100 |   75.18 | ...53-158,169-173 
  ...etailStep.tsx |   10.41 |      100 |       0 |   10.41 | ...1,67-79,82-139 
  ToolListStep.tsx |   69.02 |       50 |     100 |   69.02 | ...22,125,134-143 
 ...nents/messages |   82.44 |    79.55 |    72.6 |   82.44 |                   
  ...ionDialog.tsx |   80.84 |     77.6 |    62.5 |   80.84 | ...98,516,534-536 
  BtwMessage.tsx   |     100 |      100 |     100 |     100 |                   
  ...upDisplay.tsx |   97.67 |    83.72 |     100 |   97.67 | 119,142,150       
  ...onMessage.tsx |   91.93 |    82.35 |     100 |   91.93 | 57-59,61,63       
  ...nMessages.tsx |   79.06 |      100 |      70 |   79.06 | ...51-264,268-280 
  DiffRenderer.tsx |   93.19 |    86.17 |     100 |   93.19 | ...09,237-238,304 
  ...tsDisplay.tsx |   97.82 |    77.27 |     100 |   97.82 | 87,89             
  ...usMessage.tsx |   76.31 |     42.1 |   66.66 |   76.31 | ...99,101,124,155 
  ...ssMessage.tsx |    12.5 |      100 |       0 |    12.5 | 18-59             
  ...edMessage.tsx |   16.66 |      100 |       0 |   16.66 | 22-38             
  ...sMessages.tsx |   55.67 |       40 |   28.57 |   55.67 | ...20-125,133-145 
  ...ryMessage.tsx |   14.28 |      100 |       0 |   14.28 | 23-62             
  ...onMessage.tsx |   81.02 |    69.23 |   33.33 |   81.02 | ...24-426,433-435 
  ...upMessage.tsx |      84 |    93.61 |     100 |      84 | ...56-383,405-420 
  ToolMessage.tsx  |   88.84 |    75.71 |    92.3 |   88.84 | ...44-749,776-778 
 ...ponents/shared |   86.23 |    79.33 |   95.94 |   86.23 |                   
  ...ctionList.tsx |   99.03 |    95.65 |     100 |   99.03 | 85                
  ...tonSelect.tsx |     100 |      100 |     100 |     100 |                   
  EnumSelector.tsx |     100 |    96.42 |     100 |     100 | 58                
  MaxSizedBox.tsx  |   83.01 |    86.25 |   88.88 |   83.01 | ...12-513,618-619 
  MultiSelect.tsx  |   84.31 |    74.19 |     100 |   84.31 | ...37,193-195,205 
  ...tonSelect.tsx |     100 |      100 |     100 |     100 |                   
  ...eSelector.tsx |     100 |       60 |     100 |     100 | 40-45             
  TextInput.tsx    |   77.77 |    48.78 |      80 |   77.77 | ...14-218,230-236 
  ...apsedTime.tsx |     100 |      100 |     100 |     100 |                   
  ...Indicator.tsx |     100 |      100 |     100 |     100 |                   
  text-buffer.ts   |   85.38 |       80 |   97.77 |   85.38 | ...2437,2535-2536 
  ...er-actions.ts |   86.71 |    67.79 |     100 |   86.71 | ...07-608,809-811 
 ...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.51 |    59.52 |   27.27 |   21.51 |                   
  ...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.42 |    59.52 |     100 |   35.42 | ...20-432,437-439 
  ...iewerStep.tsx |   13.72 |      100 |       0 |   13.72 | 18-73             
  ...gerDialog.tsx |    6.74 |      100 |       0 |    6.74 | 35-341            
 ...mponents/views |   42.16 |    69.23 |   21.42 |   42.16 |                   
  ContextUsage.tsx |     4.7 |      100 |       0 |     4.7 | ...52-167,170-456 
  DoctorReport.tsx |     9.8 |      100 |       0 |     9.8 | 25-54,57-131      
  ...sionsList.tsx |   87.69 |    73.68 |     100 |   87.69 | 65-72             
  McpStatus.tsx    |   89.53 |    60.52 |     100 |   89.53 | ...72,175-177,262 
  SkillsList.tsx   |   27.27 |      100 |       0 |   27.27 | 18-35             
  ToolsList.tsx    |     100 |      100 |     100 |     100 |                   
 src/ui/contexts   |   77.34 |    78.06 |   80.35 |   77.34 |                   
  ...ewContext.tsx |    64.7 |    85.71 |      50 |    64.7 | ...22-225,231-241 
  AppContext.tsx   |      80 |       50 |     100 |      80 | 19-20             
  ...ewContext.tsx |   95.18 |    67.56 |      50 |   95.18 | ...94-195,222-226 
  ...deContext.tsx |     100 |      100 |     100 |     100 |                   
  ...igContext.tsx |   81.81 |       50 |     100 |   81.81 | 15-16             
  ...ssContext.tsx |   82.31 |    82.84 |     100 |   82.31 | ...1153,1159-1161 
  ...owContext.tsx |   89.28 |       80 |   66.66 |   89.28 | 34,47-48,60-62    
  ...deContext.tsx |     100 |      100 |      50 |     100 |                   
  ...onContext.tsx |   43.28 |     62.5 |    62.5 |   43.28 | ...56-259,263-266 
  ...gsContext.tsx |   83.33 |       50 |     100 |   83.33 | 17-18             
  ...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             
  ...nsContext.tsx |   88.23 |       50 |     100 |   88.23 | 118-119           
  ...teContext.tsx |   86.66 |       50 |     100 |   86.66 | 194-195           
  ...deContext.tsx |   76.08 |    72.72 |     100 |   76.08 | 47-48,52-59,77-78 
 src/ui/daemon     |   90.76 |    73.73 |   95.45 |   90.76 |                   
  ...TuiAdapter.ts |   90.76 |    73.73 |   95.45 |   90.76 | ...53,771-772,858 
 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      |   82.25 |    82.19 |   87.33 |   82.25 |                   
  ...dProcessor.ts |   83.12 |    82.56 |     100 |   83.12 | ...88-389,408-435 
  keyToAnsi.ts     |    3.92 |      100 |       0 |    3.92 | 19-77             
  ...dProcessor.ts |    94.8 |    70.58 |     100 |    94.8 | ...76-277,282-283 
  ...dProcessor.ts |   75.75 |    63.01 |   61.53 |   75.75 | ...84,908,927-931 
  ...amingState.ts |   12.22 |      100 |       0 |   12.22 | 54-157            
  ...agerDialog.ts |   88.23 |      100 |     100 |   88.23 | 20,24             
  ...ationFrame.ts |      32 |       60 |     100 |      32 | 42-44,51-90       
  ...odeCommand.ts |   58.82 |      100 |     100 |   58.82 | 28,33-48          
  ...enaCommand.ts |      85 |      100 |     100 |      85 | 23-24,29          
  ...aInProcess.ts |   19.81 |    66.66 |      25 |   19.81 | 57-175            
  ...Completion.ts |   92.81 |    89.09 |     100 |   92.81 | ...86-187,224-227 
  ...ifications.ts |   92.07 |    96.29 |     100 |   92.07 | 116-124           
  ...tIndicator.ts |   83.49 |    70.96 |     100 |   83.49 | ...60,168,170-178 
  ...waySummary.ts |   96.22 |    69.69 |     100 |   96.22 | 125-127,169       
  ...ndTaskView.ts |   94.21 |    76.08 |     100 |   94.21 | 122-126,213,219   
  ...ketedPaste.ts |    23.8 |      100 |       0 |    23.8 | 19-37             
  ...nchCommand.ts |   94.36 |    74.35 |     100 |   94.36 | ...60,168-169,209 
  ...ompletion.tsx |   95.96 |    83.33 |     100 |   95.96 | ...22-223,225-226 
  ...dMigration.ts |   90.62 |       75 |     100 |   90.62 | 38-40             
  useCompletion.ts |    92.4 |     87.5 |     100 |    92.4 | 68-69,93-94,98-99 
  ...nitMessage.ts |     100 |      100 |     100 |     100 |                   
  ...extualTips.ts |   76.92 |       50 |     100 |   76.92 | 55,68,71-75,88-96 
  ...eteCommand.ts |   78.53 |    88.57 |     100 |   78.53 | ...96-104,112-113 
  ...ialogClose.ts |   13.33 |      100 |     100 |   13.33 | 82-173            
  useDiffData.ts   |   11.62 |      100 |       0 |   11.62 | 44-87             
  ...oublePress.ts |   53.12 |       75 |     100 |   53.12 | 33-35,41-54       
  ...orSettings.ts |     100 |      100 |     100 |     100 |                   
  ...Completion.ts |   99.12 |    97.67 |     100 |   99.12 | 182-183           
  ...ionUpdates.ts |   93.45 |     92.3 |     100 |   93.45 | ...83-287,300-306 
  ...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 |      100 |     100 |     100 |                   
  ...ggestions.tsx |   89.15 |     62.5 |      50 |   89.15 | ...22-124,149-150 
  ...miniStream.ts |   78.06 |    75.47 |   91.66 |   78.06 | ...2573,2586-2594 
  ...BranchName.ts |    90.9 |     92.3 |     100 |    90.9 | 19-20,55-58       
  ...oryManager.ts |   93.15 |    93.75 |     100 |   93.15 | 44,107-110        
  ...ooksDialog.ts |    87.5 |      100 |     100 |    87.5 | 19,23             
  ...stListener.ts |     100 |      100 |     100 |     100 |                   
  ...nAuthError.ts |   76.19 |       50 |     100 |   76.19 | 39-40,43-45       
  ...putHistory.ts |   92.59 |    85.71 |     100 |   92.59 | 63-64,72,94-96    
  ...storyStore.ts |     100 |    94.11 |     100 |     100 | 69                
  useKeypress.ts   |     100 |      100 |     100 |     100 |                   
  ...rdProtocol.ts |   36.36 |      100 |       0 |   36.36 | 24-31             
  ...unchEditor.ts |    9.67 |      100 |       0 |    9.67 | 11-32,39-90       
  ...gIndicator.ts |     100 |      100 |     100 |     100 |                   
  useLogger.ts     |   21.05 |      100 |       0 |   21.05 | 15-37             
  useMCPHealth.ts  |   63.15 |       75 |      50 |   63.15 | 42-52,64-67       
  useMcpDialog.ts  |    87.5 |      100 |     100 |    87.5 | 19,23             
  ...moryDialog.ts |    87.5 |      100 |     100 |    87.5 | 19,23             
  ...oryMonitor.ts |     100 |      100 |     100 |     100 |                   
  ...ssageQueue.ts |     100 |      100 |     100 |     100 |                   
  ...delCommand.ts |     100 |       75 |     100 |     100 | 22                
  ...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 |   86.49 |    77.96 |    90.9 |   86.49 | ...26,288-300,348 
  useQwenAuth.ts   |     100 |      100 |     100 |     100 |                   
  ...lScheduler.ts |    84.7 |    93.33 |     100 |    84.7 | ...71-276,372-382 
  ...oryCommand.ts |       0 |        0 |       0 |       0 | 1-7               
  ...umeCommand.ts |   97.08 |    83.33 |     100 |   97.08 | 103-104,133       
  ...ompletion.tsx |   90.59 |    83.33 |     100 |   90.59 | ...01,104,137-140 
  ...ectionList.ts |   96.98 |    95.65 |     100 |   96.98 | ...83-184,238-241 
  ...sionPicker.ts |   92.87 |    90.35 |     100 |   92.87 | ...99-501,503-505 
  ...earchInput.ts |     100 |      100 |     100 |     100 |                   
  ...ngsCommand.ts |   18.75 |      100 |       0 |   18.75 | 10-25             
  ...ellHistory.ts |   91.74 |    79.41 |     100 |   91.74 | ...74,122-123,133 
  ...oryCommand.ts |       0 |        0 |       0 |       0 | 1-73              
  ...Completion.ts |    82.7 |    85.41 |   94.73 |    82.7 | ...69-671,679-715 
  ...tateAndRef.ts |     100 |      100 |     100 |     100 |                   
  useStatusLine.ts |   96.09 |    90.37 |     100 |   96.09 | ...62-365,450-457 
  ...eateDialog.ts |   88.23 |      100 |     100 |   88.23 | 14,18             
  ...tification.ts |     100 |    85.71 |     100 |     100 | 47                
  ...alProgress.ts |   53.06 |       50 |   66.66 |   53.06 | ...53,61-68,79-85 
  ...rminalSize.ts |   76.19 |      100 |      50 |   76.19 | 21-25             
  ...emeCommand.ts |   67.01 |    29.41 |     100 |   67.01 | ...10-111,115-116 
  useTimer.ts      |   88.09 |    85.71 |     100 |   88.09 | 44-45,51-53       
  ...lMigration.ts |       0 |        0 |       0 |       0 |                   
  ...rustModify.ts |     100 |      100 |     100 |     100 |                   
  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 | 44-45,87          
  vim.ts           |   83.77 |    80.31 |     100 |   83.77 | ...55,759-767,776 
 src/ui/layouts    |   89.72 |     87.5 |     100 |   89.72 |                   
  ...AppLayout.tsx |   89.88 |     87.5 |     100 |   89.88 | 51-53,93-98       
  ...AppLayout.tsx |   89.47 |     87.5 |     100 |   89.47 | 58-63             
 src/ui/models     |   80.24 |    79.16 |   71.42 |   80.24 |                   
  ...ableModels.ts |   80.24 |    79.16 |   71.42 |   80.24 | ...,61-71,123-125 
 ...noninteractive |     100 |      100 |   14.28 |     100 |                   
  ...eractiveUi.ts |     100 |      100 |   14.28 |     100 |                   
 src/ui/state      |   94.91 |    81.81 |     100 |   94.91 |                   
  extensions.ts    |   94.91 |    81.81 |     100 |   94.91 | 68-69,88          
 src/ui/themes     |   98.53 |    70.58 |     100 |   98.53 |                   
  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   |     100 |      100 |     100 |     100 |                   
  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 |   87.98 |    82.89 |     100 |   87.98 | ...48-357,362-363 
  theme.ts         |     100 |    38.02 |     100 |     100 | ...34-449,457-461 
  xcode.ts         |     100 |      100 |     100 |     100 |                   
 src/ui/utils      |   83.98 |       83 |   92.61 |   83.98 |                   
  ...Colorizer.tsx |   79.53 |    83.78 |     100 |   79.53 | ...51-152,249-275 
  ...nRenderer.tsx |   68.83 |    70.14 |      50 |   68.83 | ...52-254,274-293 
  ...wnDisplay.tsx |   86.01 |    87.41 |     100 |   86.01 | ...87,704,729-754 
  ...idDiagram.tsx |   87.79 |    95.34 |     100 |   87.79 | 156-179           
  ...eRenderer.tsx |   92.08 |    80.45 |      95 |   92.08 | ...76-679,723-728 
  ...dWorkUtils.ts |     100 |      100 |     100 |     100 |                   
  ...boardUtils.ts |   59.61 |    58.82 |     100 |   59.61 | ...,86-88,107-149 
  commandUtils.ts  |    95.9 |    88.42 |     100 |    95.9 | ...62,164-165,289 
  computeStats.ts  |     100 |      100 |     100 |     100 |                   
  customBanner.ts  |   90.68 |    91.22 |     100 |   90.68 | ...13,324-327,334 
  displayUtils.ts  |   88.37 |    72.22 |     100 |   88.37 | 23,25,29,31,33    
  formatters.ts    |   95.23 |    98.27 |     100 |   95.23 | 117-120           
  gradientUtils.ts |     100 |      100 |     100 |     100 |                   
  highlight.ts     |     100 |      100 |     100 |     100 |                   
  ...oryMapping.ts |     100 |    94.28 |     100 |     100 | 35,57             
  historyUtils.ts  |   94.11 |       94 |     100 |   94.11 | 94-97             
  isNarrowWidth.ts |     100 |      100 |     100 |     100 |                   
  ...olDetector.ts |    8.23 |      100 |       0 |    8.23 | ...31-132,135-136 
  latexRenderer.ts |   94.95 |     73.8 |     100 |   94.95 | ...76-178,184-187 
  layoutUtils.ts   |     100 |      100 |     100 |     100 |                   
  ...ightLoader.ts |     100 |    89.47 |     100 |     100 | 81,110            
  ...nUtilities.ts |   69.84 |    85.71 |     100 |   69.84 | 75-91,100-101     
  ...ToolGroups.ts |   98.66 |    96.77 |     100 |   98.66 | 48-49             
  ...geRenderer.ts |   86.23 |    69.06 |   95.12 |   86.23 | ...1284,1324-1330 
  ...alRenderer.ts |   86.69 |     71.9 |     100 |   86.69 | ...1476,1513-1519 
  ...lsBySource.ts |     100 |    95.23 |     100 |     100 | 84                
  osc8.ts          |   94.73 |    87.75 |     100 |   94.73 | ...49,434,438-439 
  ...mConstants.ts |     100 |      100 |     100 |     100 |                   
  restoreGoal.ts   |   98.98 |    97.05 |     100 |   98.98 | 98                
  ...storyUtils.ts |   61.89 |    69.87 |      90 |   61.89 | ...76,424,429-451 
  ...ickerUtils.ts |     100 |      100 |     100 |     100 |                   
  ...izedOutput.ts |   94.94 |      100 |   88.88 |   94.94 | 112-117           
  ...wOptimizer.ts |     100 |    96.77 |     100 |     100 | 69                
  terminalSetup.ts |    4.37 |      100 |       0 |    4.37 | 44-393            
  textUtils.ts     |   97.61 |    94.84 |   92.85 |   97.61 | ...50-251,386-387 
  todoSnapshot.ts  |   89.11 |    93.33 |     100 |   89.11 | ...,66-78,180-181 
  updateCheck.ts   |     100 |    80.95 |     100 |     100 | 30-42             
 ...i/utils/export |   56.77 |     40.8 |   79.41 |   56.77 |                   
  collect.ts       |   55.92 |    50.58 |   86.36 |   55.92 | ...25-640,642-647 
  index.ts         |     100 |      100 |     100 |     100 |                   
  normalize.ts     |   57.47 |    20.51 |      80 |   57.47 | ...09-310,324-359 
  types.ts         |       0 |        0 |       0 |       0 | 1                 
  utils.ts         |      40 |      100 |       0 |      40 | 11-13             
 ...ort/formatters |    3.38 |      100 |       0 |    3.38 |                   
  html.ts          |    9.61 |      100 |       0 |    9.61 | ...28,34-76,82-84 
  json.ts          |      50 |      100 |       0 |      50 | 14-15             
  jsonl.ts         |     3.5 |      100 |       0 |     3.5 | 14-76             
  markdown.ts      |    0.94 |      100 |       0 |    0.94 | 13-295            
 src/utils         |   76.49 |    89.66 |   94.02 |   76.49 |                   
  acpModelUtils.ts |     100 |      100 |     100 |     100 |                   
  apiPreconnect.ts |   96.72 |    97.14 |     100 |   96.72 | 165-168           
  checks.ts        |   33.33 |      100 |       0 |   33.33 | 23-28             
  cleanup.ts       |   84.12 |    93.33 |      80 |   84.12 | 75,106-115        
  commands.ts      |     100 |      100 |     100 |     100 |                   
  commentJson.ts   |   87.17 |     90.9 |     100 |   87.17 | 64-73             
  ...Calculator.ts |     100 |      100 |     100 |     100 |                   
  deepMerge.ts     |     100 |       90 |     100 |     100 | 41-43,49          
  ...ScopeUtils.ts |   97.56 |    88.88 |     100 |   97.56 | 67                
  doctorChecks.ts  |   70.98 |       75 |     100 |   70.98 | ...95-301,325-341 
  ...putCapture.ts |   90.65 |    86.17 |     100 |   90.65 | ...72,370,372-373 
  ...arResolver.ts |   94.28 |       88 |     100 |   94.28 | 28-29,125-126     
  errors.ts        |   98.67 |    96.36 |     100 |   98.67 | 67-68             
  events.ts        |     100 |      100 |     100 |     100 |                   
  gitUtils.ts      |   91.91 |    84.61 |     100 |   91.91 | 78-81,124-127     
  ...AutoUpdate.ts |   90.76 |    93.33 |   88.88 |   90.76 | 103-114           
  ...lationInfo.ts |     100 |      100 |     100 |     100 |                   
  languageUtils.ts |   97.89 |    96.42 |     100 |   97.89 | 132-133           
  math.ts          |       0 |        0 |       0 |       0 | 1-15              
  ...iagnostics.ts |   94.57 |    83.01 |   88.88 |   94.57 | ...05,311,315-317 
  ...onfigUtils.ts |     100 |      100 |     100 |     100 |                   
  ...iveHelpers.ts |   96.79 |    93.28 |     100 |   96.79 | ...76-477,575,588 
  osc.ts           |    97.5 |      100 |   88.88 |    97.5 | 195-196           
  package.ts       |   88.88 |       80 |     100 |   88.88 | 33-34             
  processUtils.ts  |     100 |      100 |     100 |     100 |                   
  readStdin.ts     |   79.62 |       90 |      80 |   79.62 | 33-40,52-54       
  relaunch.ts      |   98.07 |    76.92 |     100 |   98.07 | 70                
  resolvePath.ts   |   66.66 |       25 |     100 |   66.66 | 12-13,16,18-19    
  sandbox.ts       |       0 |        0 |       0 |       0 | 1-1047            
  sessionPaths.ts  |   90.84 |    90.56 |     100 |   90.84 | ...81-182,185-186 
  settingsUtils.ts |   82.51 |    91.66 |   89.74 |   82.51 | ...76-694,701-709 
  spawnWrapper.ts  |     100 |      100 |     100 |     100 |                   
  ...upProfiler.ts |   98.46 |    94.52 |     100 |   98.46 | 130-131,305       
  ...upWarnings.ts |     100 |      100 |     100 |     100 |                   
  stdioHelpers.ts  |     100 |       60 |     100 |     100 | 23,32             
  systemInfo.ts    |   95.12 |    89.06 |     100 |   95.12 | ...43-244,249-253 
  ...InfoFields.ts |    87.5 |       65 |     100 |    87.5 | ...24-125,146-147 
  ...iffPreview.ts |   94.11 |    83.33 |     100 |   94.11 | 13                
  ...entEmitter.ts |     100 |      100 |     100 |     100 |                   
  ...upWarnings.ts |   91.17 |    82.35 |     100 |   91.17 | 67-68,73-74,77-78 
  version.ts       |     100 |       50 |     100 |     100 | 11                
  windowTitle.ts   |     100 |      100 |     100 |     100 |                   
  ...WithBackup.ts |   63.15 |    81.25 |     100 |   63.15 | 93,118-157        
-------------------|---------|----------|---------|---------|-------------------
Core Package - Full Text Report
-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |   80.15 |       83 |   82.47 |   80.15 |                   
 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        |   88.06 |    79.77 |   92.13 |   88.06 |                   
  ...transcript.ts |   92.25 |    85.71 |     100 |   92.25 | ...87,306-307,438 
  ...ent-resume.ts |    82.8 |    71.63 |   77.41 |    82.8 | ...1059-1063,1066 
  ...ound-tasks.ts |   95.76 |    87.57 |     100 |   95.76 | ...26-827,898-899 
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/agents/arena  |   76.54 |    66.87 |   78.72 |   76.54 |                   
  ...gentClient.ts |   79.47 |    88.88 |   81.81 |   79.47 | ...68-183,189-204 
  ArenaManager.ts  |   75.37 |    63.37 |   78.26 |   75.37 | ...1860,1866-1867 
  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 |   76.29 |    86.15 |   73.04 |   76.29 |                   
  ITermBackend.ts  |   97.97 |    93.93 |     100 |   97.97 | ...78-180,255,307 
  ...essBackend.ts |   91.25 |    90.62 |   86.66 |   91.25 | ...94,249-269,328 
  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 |   81.15 |     76.7 |   71.42 |   81.15 |                   
  agent-context.ts |     100 |      100 |     100 |     100 |                   
  agent-core.ts    |   76.51 |    72.35 |   60.86 |   76.51 | ...1609,1636-1683 
  agent-events.ts  |     100 |      100 |     100 |     100 |                   
  ...t-headless.ts |   81.19 |    71.73 |   60.86 |   81.19 | ...98-399,402-403 
  ...nteractive.ts |   79.71 |    79.62 |      75 |   79.71 | ...54,456,458,461 
  ...statistics.ts |   98.19 |    82.35 |     100 |   98.19 | 127,151,192,225   
  agent-types.ts   |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/agents/tasks  |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/config        |   78.39 |    82.11 |   65.55 |   78.39 |                   
  config.ts        |   76.25 |    80.93 |   60.96 |   76.25 | ...3827,3838-3850 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  models.ts        |     100 |      100 |     100 |     100 |                   
  storage.ts       |   95.01 |     90.9 |   90.47 |   95.01 | ...71-372,375-376 
 ...nfirmation-bus |   98.29 |    97.14 |     100 |   98.29 |                   
  message-bus.ts   |   98.14 |    97.05 |     100 |   98.14 | 42-43             
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/core          |   87.82 |    83.36 |   92.07 |   87.82 |                   
  baseLlmClient.ts |   87.24 |    76.47 |    87.5 |   87.24 | ...82,484-494,503 
  client.ts        |   87.43 |    80.57 |   86.36 |   87.43 | ...2075,2114-2117 
  ...tGenerator.ts |    72.1 |    61.11 |     100 |    72.1 | ...63,365,372-375 
  ...lScheduler.ts |   85.36 |    82.08 |   94.73 |   85.36 | ...3209,3270-3281 
  geminiChat.ts    |   90.87 |    86.62 |   97.22 |   90.87 | ...2563,2630-2631 
  geminiRequest.ts |     100 |      100 |     100 |     100 |                   
  ...htProtocol.ts |    9.09 |      100 |       0 |    9.09 | 34-42,45-49,52-87 
  logger.ts        |   87.33 |    87.02 |     100 |   87.33 | ...61-565,611-625 
  ...tyDefaults.ts |     100 |      100 |     100 |     100 |                   
  ...olExecutor.ts |   92.59 |       75 |      50 |   92.59 | 41-42             
  ...on-helpers.ts |   86.48 |    72.22 |     100 |   86.48 | ...97-198,212-221 
  ...issionFlow.ts |   98.59 |       95 |     100 |   98.59 | 93                
  prompts.ts       |   89.24 |    86.41 |   76.92 |   89.24 | ...-972,1175-1176 
  tokenLimits.ts   |     100 |    89.47 |     100 |     100 | 51-52             
  ...okTriggers.ts |   99.33 |    90.47 |     100 |   99.33 | 156,167           
  turn.ts          |   96.44 |    88.88 |     100 |   96.44 | ...08,421-422,470 
 ...ntentGenerator |   94.93 |    82.59 |   93.87 |   94.93 |                   
  ...tGenerator.ts |   96.49 |    84.28 |   92.59 |   96.49 | ...04,922-926,966 
  converter.ts     |   94.51 |    80.72 |     100 |   94.51 | ...06-607,617,823 
  index.ts         |       0 |        0 |       0 |       0 | 1-21              
  usage.ts         |     100 |      100 |     100 |     100 |                   
 ...ntentGenerator |   91.53 |    71.64 |   93.33 |   91.53 |                   
  ...tGenerator.ts |      90 |    70.96 |   92.85 |      90 | ...80-286,304-305 
  index.ts         |     100 |       80 |     100 |     100 | 50                
 ...ntentGenerator |   93.86 |    82.98 |    90.9 |   93.86 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...tGenerator.ts |   93.72 |    81.27 |   90.32 |   93.72 | ...29,939-940,968 
  ...tDetection.ts |     100 |      100 |     100 |     100 |                   
 ...ntentGenerator |   81.75 |    84.38 |    90.9 |   81.75 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  converter.ts     |   76.88 |    82.25 |    87.5 |   76.88 | ...1589,1610-1616 
  errorHandler.ts  |     100 |      100 |     100 |     100 |                   
  index.ts         |   54.54 |    68.75 |      50 |   54.54 | ...79,87-91,95-99 
  ...tGenerator.ts |    66.4 |    70.58 |   88.88 |    66.4 | ...51-157,168-169 
  pipeline.ts      |    93.8 |    85.45 |     100 |    93.8 | ...81-482,490,558 
  ...ureContext.ts |     100 |      100 |     100 |     100 |                   
  ...ingOptions.ts |       0 |        0 |       0 |       0 | 1                 
  ...CallParser.ts |   90.66 |    88.57 |     100 |   90.66 | ...15-319,349-350 
  ...kingParser.ts |     100 |    96.87 |     100 |     100 | 42                
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...rator/provider |   96.63 |     88.2 |   96.07 |   96.63 |                   
  dashscope.ts     |   97.29 |    89.77 |   93.33 |   97.29 | ...81-282,358-359 
  deepseek.ts      |   94.91 |    89.36 |     100 |   94.91 | ...31-132,145-146 
  default.ts       |   95.79 |    89.65 |   88.88 |   95.79 | 122-123,193-195   
  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 |                   
 src/extension     |   62.19 |    79.05 |   80.31 |   62.19 |                   
  ...-converter.ts |    65.2 |    49.58 |     100 |    65.2 | ...90-791,800-832 
  ...ionManager.ts |   47.05 |    82.19 |    65.9 |   47.05 | ...1400,1410-1429 
  ...onSettings.ts |   93.46 |    93.05 |     100 |   93.46 | ...17-221,228-232 
  ...-converter.ts |   54.88 |    94.44 |      60 |   54.88 | ...35-146,158-192 
  github.ts        |   46.41 |     87.3 |   63.63 |   46.41 | ...68-374,413-466 
  index.ts         |     100 |      100 |     100 |     100 |                   
  marketplace.ts   |   97.31 |    93.75 |     100 |   97.31 | ...65,185-186,275 
  npm.ts           |   59.01 |    71.69 |    87.5 |   59.01 | ...23-425,432-436 
  override.ts      |   94.11 |    88.88 |     100 |   94.11 | 63-64,81-82       
  redaction.ts     |     100 |      100 |     100 |     100 |                   
  settings.ts      |   66.26 |      100 |      50 |   66.26 | 81-108,143-149    
  storage.ts       |     100 |      100 |     100 |     100 |                   
  ...ableSchema.ts |     100 |      100 |     100 |     100 |                   
  variables.ts     |   88.75 |    83.33 |     100 |   88.75 | ...28-231,234-237 
 src/followup      |   55.57 |    84.14 |   81.25 |   55.57 |                   
  followupState.ts |      96 |    89.74 |     100 |      96 | 159-161,218-219   
  index.ts         |     100 |      100 |     100 |     100 |                   
  overlayFs.ts     |   95.06 |       84 |     100 |   95.06 | 78,108,122,133    
  speculation.ts   |   13.02 |      100 |   16.66 |   13.02 | 89-464,524-575    
  ...onToolGate.ts |     100 |    96.42 |     100 |     100 | 94                
  ...nGenerator.ts |    71.6 |    72.13 |   83.33 |    71.6 | ...88-246,316-318 
 src/generated     |       0 |        0 |       0 |       0 |                   
  git-commit.ts    |       0 |        0 |       0 |       0 | 1-10              
 src/goals         |   89.57 |    83.45 |   94.44 |   89.57 |                   
  ...eGoalStore.ts |    85.1 |    95.45 |   84.61 |    85.1 | ...63-166,174-182 
  goalHook.ts      |   97.26 |    91.48 |     100 |   97.26 | 100-105           
  goalJudge.ts     |   84.33 |    74.28 |     100 |   84.33 | ...57-358,366-368 
  index.ts         |     100 |      100 |     100 |     100 |                   
 src/hooks         |   83.65 |    85.46 |   86.88 |   83.65 |                   
  ...okRegistry.ts |   86.48 |    77.08 |     100 |   86.48 | ...41-344,362-369 
  ...bortSignal.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.4 |    90.78 |     100 |    96.4 | ...91,293-294,367 
  ...entHandler.ts |    94.6 |    86.07 |   93.33 |    94.6 | ...42,799-800,810 
  hookPlanner.ts   |   88.19 |       85 |    90.9 |   88.19 | ...68-170,188-199 
  hookRegistry.ts  |   90.17 |    83.33 |     100 |   90.17 | ...33,352,356,360 
  hookRunner.ts    |   58.56 |    71.26 |   66.66 |   58.56 | ...48-749,758-759 
  hookSystem.ts    |   84.57 |      100 |   65.85 |   84.57 | ...21-622,628-629 
  ...HookRunner.ts |   75.51 |     61.9 |      80 |   75.51 | ...05-406,424-425 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...HookRunner.ts |   93.63 |    89.47 |      90 |   93.63 | ...45-353,427-428 
  ...SkillHooks.ts |   78.75 |       75 |   66.66 |   78.75 | 62-66,137-152     
  ...oksManager.ts |   96.66 |    91.66 |     100 |   96.66 | ...90,209-210,223 
  ssrfGuard.ts     |   77.22 |    85.36 |     100 |   77.22 | ...57,261-267,273 
  stopHookCap.ts   |     100 |      100 |     100 |     100 |                   
  trustedHooks.ts  |       0 |        0 |       0 |       0 | 1-124             
  types.ts         |   91.21 |    92.13 |   85.71 |   91.21 | ...40-441,501-505 
  urlValidator.ts  |     100 |      100 |     100 |     100 |                   
 src/ide           |   74.28 |    83.39 |   78.33 |   74.28 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  detect-ide.ts    |     100 |      100 |     100 |     100 |                   
  ide-client.ts    |    64.2 |    81.48 |   66.66 |    64.2 | ...9-970,999-1007 
  ide-installer.ts |   89.06 |    79.31 |     100 |   89.06 | ...36,143-147,160 
  ideContext.ts    |     100 |      100 |     100 |     100 |                   
  process-utils.ts |   84.84 |    71.79 |     100 |   84.84 | ...37,151,193-194 
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/lsp           |   41.24 |    52.14 |   51.42 |   41.24 |                   
  ...nfigLoader.ts |   70.27 |    35.89 |   94.73 |   70.27 | ...20-422,426-432 
  ...ionFactory.ts |   42.69 |    79.16 |      50 |   42.69 | ...62-413,419-436 
  ...Normalizer.ts |   23.09 |    13.72 |   30.43 |   23.09 | ...04-905,909-924 
  ...verManager.ts |   25.31 |    62.06 |   41.66 |   25.31 | ...85-704,710-740 
  ...eLspClient.ts |   32.77 |       80 |   17.64 |   32.77 | ...84-288,294-295 
  ...LspService.ts |   48.49 |    67.16 |   65.71 |   48.49 | ...1352,1369-1379 
  constants.ts     |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/mcp           |   78.69 |    75.34 |   75.92 |   78.69 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...h-provider.ts |   86.95 |      100 |   33.33 |   86.95 | ...,93,97,101-102 
  ...h-provider.ts |   73.82 |    53.92 |     100 |   73.82 | ...88-895,902-904 
  ...en-storage.ts |   98.62 |    97.72 |     100 |   98.62 | 87-88             
  oauth-utils.ts   |   70.58 |    85.29 |    90.9 |   70.58 | ...70-290,315-344 
  ...n-provider.ts |   89.83 |    95.83 |   45.45 |   89.83 | ...43,147,151-152 
 .../token-storage |   79.52 |    86.66 |   86.36 |   79.52 |                   
  ...en-storage.ts |     100 |      100 |     100 |     100 |                   
  ...en-storage.ts |   82.87 |    82.35 |   92.85 |   82.87 | ...63-173,181-182 
  ...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        |   68.01 |    76.27 |   66.66 |   68.01 |                   
  const.ts         |     100 |      100 |     100 |     100 |                   
  dream.ts         |   65.65 |    73.33 |      50 |   65.65 | 50,107-148        
  ...entPlanner.ts |   57.84 |    72.72 |   33.33 |   57.84 | ...35,140-147,152 
  entries.ts       |   63.77 |    79.16 |      50 |   63.77 | ...72-180,183-189 
  extract.ts       |    95.2 |    79.16 |     100 |    95.2 | 81-86,125         
  ...entPlanner.ts |   63.08 |    65.71 |   41.17 |   63.08 | ...17,222-223,332 
  ...ionPlanner.ts |       0 |        0 |       0 |       0 | 1                 
  forget.ts        |    45.8 |    61.53 |   44.44 |    45.8 | ...04,211,214-346 
  indexer.ts       |   83.87 |    45.45 |     100 |   83.87 | ...50,56-57,69-70 
  manager.ts       |   75.31 |    81.04 |    75.6 |   75.31 | ...1278,1291-1293 
  memoryAge.ts     |   90.47 |    77.77 |     100 |   90.47 | 50-51             
  paths.ts         |   55.47 |    89.47 |   85.71 |   55.47 | ...,89-90,106-114 
  prompt.ts        |   93.36 |    71.42 |     100 |   93.36 | ...58,161,228-229 
  recall.ts        |   77.54 |    69.38 |   88.88 |   77.54 | ...53-258,282-293 
  ...ceSelector.ts |   91.86 |    77.27 |     100 |   91.86 | ...15,117-118,126 
  scan.ts          |   87.91 |    68.42 |     100 |   87.91 | ...47-48,58,82-87 
  ...entPlanner.ts |    11.5 |      100 |       0 |    11.5 | ...57-192,210-298 
  status.ts        |   10.52 |      100 |       0 |   10.52 | 41-98             
  store.ts         |   94.44 |    83.33 |     100 |   94.44 | 56-57,92-93       
  types.ts         |     100 |      100 |     100 |     100 |                   
  ...ontextFile.ts |   79.38 |    78.33 |   81.81 |   79.38 | ...58-272,286-291 
 src/mocks         |       0 |        0 |       0 |       0 |                   
  msw.ts           |       0 |        0 |       0 |       0 | 1-9               
 src/models        |   89.35 |    86.14 |    87.5 |   89.35 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...tor-config.ts |   90.24 |    91.42 |     100 |   90.24 | 142,148,151-160   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...nfigErrors.ts |   74.22 |    47.82 |   84.61 |   74.22 | ...,67-74,106-117 
  ...igResolver.ts |   98.66 |    92.85 |     100 |   98.66 | 162,324,330       
  modelRegistry.ts |     100 |    98.59 |     100 |     100 | 222               
  modelsConfig.ts  |   84.57 |    82.14 |   81.57 |   84.57 | ...1223,1252-1253 
  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   |   74.62 |    88.85 |   58.28 |   74.62 |                   
  autoMode.ts      |   61.59 |    93.54 |   83.33 |   61.59 | ...00-238,340-356 
  ...transcript.ts |      98 |       84 |     100 |      98 | 200-201           
  classifier.ts    |   92.89 |     87.5 |     100 |   92.89 | 146-153,333-337   
  ...erousRules.ts |     100 |    89.36 |     100 |     100 | 110,133,147,175   
  ...alTracking.ts |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...on-manager.ts |    78.3 |    85.24 |   82.14 |    78.3 | ...-917,1023-1027 
  rule-parser.ts   |   96.06 |    93.22 |     100 |   96.06 | ...-875,1024-1026 
  ...-semantics.ts |   58.28 |    85.27 |    30.2 |   58.28 | ...1604-1614,1643 
  types.ts         |     100 |      100 |     100 |     100 |                   
 ...sifier-prompts |   98.18 |       90 |     100 |   98.18 |                   
  system-prompt.ts |   98.18 |       90 |     100 |   98.18 | 150               
 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     |   77.46 |    70.94 |   60.71 |   77.46 |                   
  all-providers.ts |      68 |      100 |       0 |      68 | 68-69,73-79,83-89 
  index.ts         |     100 |      100 |     100 |     100 |                   
  install.ts       |   98.87 |    87.27 |     100 |   98.87 | 268-269           
  ...der-config.ts |   66.11 |    55.93 |   63.15 |   66.11 | ...08-409,416-425 
  types.ts         |       0 |        0 |       0 |       0 | 1                 
 ...viders/presets |   97.12 |    86.36 |      50 |   97.12 |                   
  ...oding-plan.ts |   87.17 |      100 |       0 |   87.17 | 81-83,86-88,90-93 
  ...a-standard.ts |     100 |      100 |     100 |     100 |                   
  ...token-plan.ts |     100 |      100 |     100 |     100 |                   
  ...m-provider.ts |   97.01 |    81.25 |      75 |   97.01 | 120-121           
  deepseek.ts      |     100 |      100 |     100 |     100 |                   
  idealab.ts       |     100 |      100 |     100 |     100 |                   
  minimax.ts       |     100 |      100 |     100 |     100 |                   
  modelscope.ts    |     100 |      100 |     100 |     100 |                   
  openrouter.ts    |     100 |      100 |     100 |     100 |                   
  zai.ts           |     100 |      100 |     100 |     100 |                   
 src/qwen          |   83.87 |    77.46 |   95.83 |   83.87 |                   
  ...tGenerator.ts |   98.64 |    98.18 |     100 |   98.64 | 105-106           
  qwenOAuth2.ts    |   80.85 |    70.74 |   90.32 |   80.85 | ...1169-1185,1215 
  ...kenManager.ts |   83.76 |    76.22 |     100 |   83.76 | ...62-767,788-793 
 src/services      |   85.39 |    83.35 |    91.3 |   85.39 |                   
  ...ionTrailer.ts |     100 |      100 |     100 |     100 |                   
  ...llRegistry.ts |   98.44 |    91.83 |     100 |   98.44 | 268-269           
  ...ionService.ts |   95.54 |    96.29 |     100 |   95.54 | ...19,387,389-393 
  ...ingService.ts |   83.88 |    83.33 |   83.33 |   83.88 | ...1266,1283-1284 
  ...ttribution.ts |   91.73 |    87.71 |      90 |   91.73 | ...80-685,826-827 
  ...utSlimming.ts |     100 |    96.77 |     100 |     100 | 133,182           
  cronScheduler.ts |   97.56 |    92.98 |     100 |   97.56 | 62-63,77,155      
  ...eryService.ts |   80.43 |    95.45 |      75 |   80.43 | ...19-134,140-141 
  ...oryService.ts |   86.18 |    76.76 |   91.17 |   86.18 | ...1150,1191-1194 
  fileReadCache.ts |     100 |      100 |     100 |     100 |                   
  ...temService.ts |   91.27 |    82.69 |    90.9 |   91.27 | ...94,196,294-301 
  ...ratedFiles.ts |      96 |    88.23 |     100 |      96 | 119-120,146-147   
  gitInit.ts       |     100 |      100 |     100 |     100 |                   
  gitService.ts    |   68.75 |     92.3 |   55.55 |   68.75 | ...12-122,125-129 
  ...reeService.ts |   73.83 |    69.31 |    97.5 |   73.83 | ...1460,1488-1489 
  ...ionService.ts |   98.13 |     97.8 |   95.45 |   98.13 | ...32-333,380-381 
  ...orRegistry.ts |   96.54 |    91.73 |     100 |   96.54 | ...70-471,622-623 
  sessionRecap.ts  |   12.65 |      100 |       0 |   12.65 | 44-150            
  ...ionService.ts |   90.47 |     79.2 |   96.87 |   90.47 | ...1324,1328-1329 
  sessionTitle.ts  |   93.87 |    71.15 |     100 |   93.87 | ...33-236,267-268 
  ...ionService.ts |   81.24 |    78.31 |   89.28 |   81.24 | ...1923,1929-1934 
  ...UseSummary.ts |   94.63 |    88.46 |     100 |   94.63 | ...62-164,214-215 
  ...reeCleanup.ts |   14.56 |      100 |   33.33 |   14.56 | 58-185            
  ...ionService.ts |   84.21 |    79.41 |     100 |   84.21 | ...22-223,239-240 
 ...icrocompaction |   98.05 |     91.8 |     100 |   98.05 |                   
  microcompact.ts  |   98.05 |     91.8 |     100 |   98.05 | ...19,289,293,391 
 src/skills        |   88.34 |    85.29 |   94.54 |   88.34 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...activation.ts |     100 |     93.1 |     100 |     100 | 93,112            
  skill-load.ts    |      94 |    86.56 |     100 |      94 | ...08,228,240-242 
  skill-manager.ts |   84.26 |    80.87 |   90.32 |   84.26 | ...1155,1162-1166 
  skill-paths.ts   |   86.74 |    77.77 |     100 |   86.74 | ...00-101,106-107 
  symlinkScope.ts  |     100 |      100 |     100 |     100 |                   
  types.ts         |     100 |      100 |     100 |     100 |                   
 src/subagents     |   82.61 |    78.89 |   95.23 |   82.61 |                   
  ...tin-agents.ts |     100 |      100 |     100 |     100 |                   
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...nt-manager.ts |   77.15 |    71.36 |    93.1 |   77.15 | ...1178,1200-1201 
  types.ts         |     100 |      100 |     100 |     100 |                   
  validation.ts    |   92.46 |    95.18 |     100 |   92.46 | 51-56,69-74,78-83 
 src/telemetry     |   76.84 |    88.32 |   79.86 |   76.84 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  constants.ts     |     100 |      100 |     100 |     100 |                   
  ...attributes.ts |   98.13 |       88 |     100 |   98.13 | 185-187           
  ...-exporters.ts |   46.37 |      100 |   44.44 |   46.37 | ...85,88-89,92-93 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...t.circular.ts |       0 |        0 |       0 |       0 | 1-111             
  ...-processor.ts |   93.93 |    90.21 |   94.11 |   93.93 | ...75-280,299-300 
  ...t.circular.ts |       0 |        0 |       0 |       0 | 1-128             
  loggers.ts       |    51.9 |       64 |   57.77 |    51.9 | ...1214,1231-1251 
  metrics.ts       |   75.03 |    82.95 |   74.54 |   75.03 | ...8-988,991-1002 
  ...attributes.ts |     100 |      100 |     100 |     100 |                   
  sanitize.ts      |      80 |    83.33 |     100 |      80 | 35-36,41-42       
  sdk.ts           |   93.01 |    88.23 |   80.95 |   93.01 | ...58-559,579-583 
  ...on-context.ts |     100 |      100 |     100 |     100 |                   
  ...on-tracing.ts |   92.75 |    88.26 |     100 |   92.75 | ...27-930,934-937 
  ...etry-utils.ts |     100 |      100 |     100 |     100 |                   
  ...l-decision.ts |     100 |      100 |     100 |     100 |                   
  ...e-id-utils.ts |     100 |      100 |     100 |     100 |                   
  tracer.ts        |   98.61 |    89.36 |     100 |   98.61 | 53,108            
  types.ts         |   79.17 |    94.49 |   83.33 |   79.17 | ...1149,1152-1181 
  uiTelemetry.ts   |   92.97 |    96.96 |   81.25 |   92.97 | ...93-194,200-207 
 ...ry/qwen-logger |   68.24 |    79.56 |   64.91 |   68.24 |                   
  event-types.ts   |       0 |        0 |       0 |       0 |                   
  qwen-logger.ts   |   68.24 |    79.34 |   64.28 |   68.24 | ...1055,1093-1094 
 src/test-utils    |   93.16 |    95.91 |   76.47 |   93.16 |                   
  config.ts        |     100 |      100 |     100 |     100 |                   
  ...st-helpers.ts |   94.11 |       90 |     100 |   94.11 | 69-70             
  index.ts         |     100 |      100 |     100 |     100 |                   
  mock-tool.ts     |   91.19 |    97.14 |   72.41 |   91.19 | ...38,202-203,216 
  ...aceContext.ts |     100 |      100 |     100 |     100 |                   
 src/tools         |   78.94 |    81.46 |   85.71 |   78.94 |                   
  ...erQuestion.ts |   88.93 |    76.74 |    90.9 |   88.93 | ...39-340,347-348 
  cron-create.ts   |   88.11 |    88.88 |    62.5 |   88.11 | ...,43-44,165-172 
  cron-delete.ts   |   96.82 |      100 |   83.33 |   96.82 | 26-27             
  cron-list.ts     |   96.66 |      100 |   83.33 |   96.66 | 25-26             
  diffOptions.ts   |     100 |      100 |     100 |     100 |                   
  edit.ts          |   81.02 |    84.07 |      75 |   81.02 | ...15-716,826-876 
  ...r-worktree.ts |   82.95 |    67.56 |    87.5 |   82.95 | ...82-185,276-277 
  exit-worktree.ts |   84.23 |    85.96 |   91.66 |   84.23 | ...92-293,298-312 
  exitPlanMode.ts  |   85.09 |    85.71 |     100 |   85.09 | ...60-163,177-189 
  glob.ts          |   90.63 |    88.33 |   84.61 |   90.63 | ...28,171,302,305 
  grep.ts          |   79.19 |    85.71 |   78.94 |   79.19 | ...20,560,569-576 
  ls.ts            |   96.74 |    90.27 |     100 |   96.74 | 176-181,212,216   
  lsp.ts           |   72.77 |    60.09 |   90.32 |   72.77 | ...1211,1213-1214 
  ...nt-manager.ts |   84.36 |    82.74 |   84.21 |   84.36 | ...2099-2103,2142 
  mcp-client.ts    |   33.18 |    77.65 |   66.66 |   33.18 | ...1490,1494-1497 
  mcp-tool.ts      |   90.98 |    88.88 |   96.42 |   90.98 | ...95-596,646-647 
  memory-config.ts |       0 |        0 |       0 |       0 | 1-47              
  ...iable-tool.ts |     100 |    84.61 |     100 |     100 | 102,109           
  monitor.ts       |   91.36 |    83.94 |   88.46 |   91.36 | ...61,574,770-775 
  notebook-edit.ts |   85.11 |    76.42 |   81.25 |   85.11 | ...54-870,916-917 
  ...nforcement.ts |   82.57 |       90 |     100 |   82.57 | 174-185,234-247   
  read-file.ts     |    95.4 |    90.32 |      90 |    95.4 | ...99,298-301,304 
  ripGrep.ts       |   94.59 |    85.71 |   93.33 |   94.59 | ...60,463,541-542 
  ...-transport.ts |    6.34 |      100 |       0 |    6.34 | 47-145            
  send-message.ts  |   84.68 |    91.66 |    62.5 |   84.68 | ...,82-90,167-170 
  shell.ts         |   73.05 |    79.66 |   91.42 |   73.05 | ...4216,4265-4271 
  skill-utils.ts   |     100 |      100 |     100 |     100 |                   
  skill.ts         |   88.35 |    91.42 |   86.66 |   88.35 | ...12,416,439-461 
  ...eticOutput.ts |   95.12 |      100 |      80 |   95.12 | 87-88             
  task-stop.ts     |   93.14 |    96.15 |   85.71 |   93.14 | 39-40,54-64       
  todoWrite.ts     |   89.17 |    82.05 |   92.85 |   89.17 | ...41-546,568-569 
  tool-error.ts    |     100 |      100 |     100 |     100 |                   
  tool-names.ts    |     100 |      100 |     100 |     100 |                   
  tool-registry.ts |   74.85 |    76.85 |   80.95 |   74.85 | ...30-831,839-840 
  tool-search.ts   |   95.19 |    86.48 |    92.3 |   95.19 | ...47-153,208-213 
  tools.ts         |   90.49 |    90.19 |   84.21 |   90.49 | ...78-479,495-501 
  web-fetch.ts     |   88.84 |       80 |   92.85 |   88.84 | ...12-313,315-316 
  write-file.ts    |   82.65 |    80.45 |   84.61 |   82.65 | ...65-668,696-731 
 src/tools/agent   |   75.07 |    80.49 |   73.61 |   75.07 |                   
  agent.ts         |   75.33 |    80.72 |   74.24 |   75.33 | ...2474,2483-2486 
  fork-subagent.ts |   69.62 |    71.42 |   66.66 |   69.62 | ...04-105,140-151 
 src/utils         |   89.07 |    87.52 |   93.66 |   89.07 |                   
  LruCache.ts      |       0 |        0 |       0 |       0 | 1-41              
  ...ssageQueue.ts |     100 |      100 |     100 |     100 |                   
  ...cFileWrite.ts |   77.96 |    80.48 |     100 |   77.96 | ...35,156,173-176 
  bareMode.ts      |   27.27 |      100 |       0 |   27.27 | 9-15,18-19        
  browser.ts       |    7.69 |      100 |       0 |    7.69 | 17-56             
  bundlePaths.ts   |     100 |      100 |     100 |     100 |                   
  ...igResolver.ts |     100 |      100 |     100 |     100 |                   
  ...engthError.ts |   89.11 |     87.5 |     100 |   89.11 | ...28-129,132-133 
  cronDisplay.ts   |   42.85 |    23.07 |     100 |   42.85 | 26-31,33-45,47-54 
  cronParser.ts    |   89.74 |    85.71 |     100 |   89.74 | ...,63-64,183-186 
  debugLogger.ts   |    95.9 |    93.93 |   94.73 |    95.9 | 106-107,214-218   
  editHelper.ts    |   93.63 |    83.52 |     100 |   93.63 | ...28-429,463-464 
  editor.ts        |    97.6 |     95.4 |     100 |    97.6 | ...25-326,328-329 
  ...arResolver.ts |   94.28 |    88.88 |     100 |   94.28 | 28-29,125-126     
  ...entContext.ts |     100 |    95.45 |     100 |     100 | 83                
  errorParsing.ts  |    97.7 |    97.05 |     100 |    97.7 | 72-73             
  ...rReporting.ts |   88.46 |       90 |     100 |   88.46 | 69-74             
  errors.ts        |   70.92 |    79.59 |   53.33 |   70.92 | ...03-219,223-229 
  fetch.ts         |   70.18 |    71.42 |   71.42 |   70.18 | ...42,148,161,186 
  fileUtils.ts     |    91.5 |    86.25 |   95.23 |    91.5 | ...1191,1195-1201 
  forkedAgent.ts   |   80.68 |    78.12 |   83.33 |   80.68 | ...39-545,550-556 
  formatters.ts    |   81.81 |       75 |     100 |   81.81 | 15-16             
  ...eUtilities.ts |   89.21 |    86.66 |     100 |   89.21 | 16-17,49-55,65-66 
  ...rStructure.ts |   94.36 |    94.28 |     100 |   94.36 | ...17-120,330-335 
  getPty.ts        |    12.5 |      100 |       0 |    12.5 | 21-34             
  gitDiff.ts       |   92.36 |    79.53 |     100 |   92.36 | ...55-856,928-929 
  ...noreParser.ts |    92.3 |    89.36 |     100 |    92.3 | ...15-116,186-187 
  gitUtils.ts      |   73.64 |    90.32 |   83.33 |   73.64 | ...,78-79,103-154 
  iconvHelper.ts   |     100 |      100 |     100 |     100 |                   
  ...rePatterns.ts |     100 |      100 |     100 |     100 |                   
  ...ionManager.ts |     100 |     90.9 |     100 |     100 | 26                
  ...lPromptIds.ts |     100 |      100 |     100 |     100 |                   
  jsonl-utils.ts   |    74.1 |    90.76 |   58.33 |    74.1 | ...23-326,336-342 
  ...-detection.ts |     100 |      100 |     100 |     100 |                   
  ...iagnostics.ts |    96.4 |     90.9 |     100 |    96.4 | ...66,293-294,376 
  ...yDiscovery.ts |   88.27 |    83.87 |     100 |   88.27 | ...76,279,407-410 
  ...tProcessor.ts |    93.2 |    89.18 |     100 |    93.2 | ...82-288,370-371 
  ...Inspectors.ts |   61.53 |      100 |      50 |   61.53 | 18-23             
  modelId.ts       |   98.95 |    98.21 |     100 |   98.95 | 148               
  ...kerChecker.ts |   90.78 |    91.66 |     100 |   90.78 | 73-79             
  notebook.ts      |   94.57 |    89.83 |   95.83 |   94.57 | ...21,333,385-387 
  openaiLogger.ts  |   90.85 |    87.87 |     100 |   90.85 | ...97-199,222-227 
  partUtils.ts     |     100 |    98.61 |     100 |     100 | 206               
  pathReader.ts    |     100 |      100 |     100 |     100 |                   
  paths.ts         |   93.21 |    91.86 |     100 |   93.21 | ...89-390,392-394 
  pdf.ts           |   93.68 |    87.05 |     100 |   93.68 | ...96-297,321-325 
  projectPath.ts   |     100 |      100 |     100 |     100 |                   
  projectRoot.ts   |   71.73 |    78.57 |     100 |   71.73 | 54-66             
  ...ectSummary.ts |   89.39 |    72.41 |     100 |   89.39 | ...37-142,193-196 
  ...tIdContext.ts |     100 |      100 |     100 |     100 |                   
  proxyUtils.ts    |     100 |      100 |     100 |     100 |                   
  ...rDetection.ts |   58.57 |       76 |     100 |   58.57 | ...4,88-89,95-100 
  ...noreParser.ts |   85.45 |    85.18 |     100 |   85.45 | ...59,65-66,72-73 
  rateLimit.ts     |   92.55 |    85.92 |     100 |   92.55 | ...70-272,309-310 
  readManyFiles.ts |   87.59 |       84 |     100 |   87.59 | ...09-211,227-238 
  retry.ts         |   89.81 |    88.05 |     100 |   89.81 | ...29,350,357-358 
  ripgrepUtils.ts  |   46.79 |    84.37 |   66.66 |   46.79 | ...45-246,258-335 
  ...sDiscovery.ts |   97.42 |    92.85 |     100 |   97.42 | ...04,182-183,202 
  ...iagnostics.ts |   83.08 |     67.5 |   92.59 |   83.08 | ...23,543-544,550 
  ...tchOptions.ts |   81.72 |    85.04 |   95.23 |   81.72 | ...18,543,572-581 
  runtimeStatus.ts |    97.5 |    88.57 |     100 |    97.5 | 167-168           
  safeJsonParse.ts |   74.07 |    83.33 |     100 |   74.07 | 40-46             
  ...nStringify.ts |     100 |      100 |     100 |     100 |                   
  ...aConverter.ts |   90.78 |    88.23 |     100 |   90.78 | ...41-42,93,95-96 
  ...aValidator.ts |   94.57 |    80.26 |     100 |   94.57 | ...04,213-216,270 
  ...r-launcher.ts |   76.92 |     91.3 |   66.66 |   76.92 | ...34,136,157-195 
  ...orageUtils.ts |   96.89 |    85.84 |     100 |   96.89 | ...51,367,447,466 
  shell-utils.ts   |   82.93 |    89.89 |     100 |   82.93 | ...1522,1529-1533 
  ...lAstParser.ts |   95.58 |    85.79 |     100 |   95.58 | ...1059-1061,1071 
  ...nlyChecker.ts |   95.75 |    92.39 |     100 |   95.75 | ...00-301,313-314 
  sideQuery.ts     |   98.71 |    97.14 |     100 |   98.71 | 110               
  ...pEventSink.ts |     100 |       80 |     100 |     100 | 61                
  ...tGenerator.ts |     100 |      100 |     100 |     100 |                   
  ...ameContext.ts |     100 |      100 |     100 |     100 |                   
  symlink.ts       |   77.77 |       50 |     100 |   77.77 | 44,54-59          
  ...emEncoding.ts |   96.36 |    91.17 |     100 |   96.36 | 59-60,124-125     
  terminalSafe.ts  |     100 |      100 |     100 |     100 |                   
  ...Serializer.ts |   98.72 |       90 |     100 |   98.72 | 42-43,134,201-203 
  testUtils.ts     |   53.33 |      100 |   33.33 |   53.33 | ...53,59-64,70-72 
  textUtils.ts     |      60 |      100 |   66.66 |      60 | 36-55             
  thoughtUtils.ts  |     100 |    92.85 |     100 |     100 | 71                
  ...-converter.ts |   94.59 |    85.71 |     100 |   94.59 | 35-36             
  tool-utils.ts    |    93.6 |     91.3 |     100 |    93.6 | ...58-159,162-163 
  truncation.ts    |     100 |       92 |     100 |     100 | 52,71             
  windowsPath.ts   |   89.47 |    79.31 |     100 |   89.47 | ...57-58,62,90-91 
  ...aceContext.ts |   93.71 |    89.28 |   93.33 |   93.71 | ...24-225,249-251 
  xml.ts           |     100 |      100 |     100 |     100 |                   
  yaml-parser.ts   |      92 |    84.61 |     100 |      92 | 49-53,65-69       
 ...ils/filesearch |   86.21 |    81.61 |   96.42 |   86.21 |                   
  crawlCache.ts    |     100 |      100 |     100 |     100 |                   
  crawler.ts       |   82.84 |    77.49 |   94.82 |   82.84 | ...1451,1485-1486 
  fileSearch.ts    |   93.58 |    87.32 |     100 |   93.58 | ...46-247,249-250 
  ignore.ts        |     100 |      100 |     100 |     100 |                   
  result-cache.ts  |     100 |     92.3 |     100 |     100 | 46                
 ...uest-tokenizer |   56.63 |    74.52 |   74.19 |   56.63 |                   
  ...eTokenizer.ts |   41.86 |    76.47 |   69.23 |   41.86 | ...70-443,453-507 
  index.ts         |     100 |      100 |     100 |     100 |                   
  ...tTokenizer.ts |   68.39 |    69.49 |    90.9 |   68.39 | ...24-325,327-328 
  ...ageFormats.ts |      76 |      100 |   33.33 |      76 | 45-48,55-56       
  textTokenizer.ts |     100 |      100 |     100 |     100 |                   
  types.ts         |       0 |        0 |       0 |       0 | 1                 
-------------------|---------|----------|---------|---------|-------------------

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

Comment thread packages/core/src/telemetry/sdk.ts Outdated
Comment thread packages/core/src/telemetry/sdk.ts
Comment thread packages/core/src/telemetry/sdk.ts
Comment thread packages/core/src/telemetry/sdk.test.ts
doudouOUC added a commit that referenced this pull request May 21, 2026
…uests

Part 2 of #4384. Stacks on top of PR #4390 (traceparent via undici).

Adds a product-namespaced HTTP header X-Qwen-Code-Session-Id to every
outbound LLM request when telemetry is enabled, so server-side ingestion
can correlate observed requests with qwen-code session metric/log records.
Pattern matched from claude-code (X-Claude-Code-Session-Id, verified at
src/services/api/client.ts:108 in their open-source repo).

Critical design decision (design doc section 4.3): the OpenAI / Anthropic
providers use a per-request fetch wrapper rather than the SDK defaultHeaders
option, because content-generator SDK clients are constructed once and NOT
recreated on /clear-triggered session resets (Config.resetSession updates
this.sessionId but the contentGenerator keeps using the stale header value).
Reading config.getSessionId() from inside the wrapper at request time gives
the live value.

Gemini provider uses static httpOptions.headers — @google/genai HttpOptions
interface does not expose a fetch hook (only headers, baseUrl, apiVersion,
timeout, extraParams). This is a known limitation: after session reset,
Gemini X-Qwen-Code-Session-Id stays stale until the contentGenerator is
recreated. Documented in telemetry.md and the design doc section 8.6;
spans/logs continue to carry the live session id for trace/log correlation.
Lazy-invalidate fix is a follow-up sub-issue.

Header is omitted when telemetry is disabled OR when getSessionId returns
an empty string (some HTTP middleware rejects empty header values).

Integration sites:
- packages/core/src/core/openaiContentGenerator/provider/default.ts
  (base class — automatically covered by deepseek/minimax/mistral/
  modelscope/openrouter subclasses; openrouter calls super.buildHeaders)
- packages/core/src/core/openaiContentGenerator/provider/dashscope.ts
  (overrides buildClient — must be touched separately; QwenContentGenerator
  inherits via this provider)
- packages/core/src/core/anthropicContentGenerator/anthropicContentGenerator.ts
- packages/core/src/core/geminiContentGenerator/index.ts (factory function,
  not the GeminiContentGenerator class — no signature change)

End-to-end verification (local HTTP server in tmux):
  PASS: traceparent + X-Qwen-Code-Session-Id on every LLM request
  PASS: session id refreshes after simulated /clear (staleness regression
        guarded by llm-correlation-fetch.test.ts)
  PASS: OTLP upload traffic not traced (no feedback loop — PR A
        ignoreRequestHook working)

Robot generated with Qwen Code https://github.com/QwenLM/qwen-code
@doudouOUC doudouOUC changed the title feat(telemetry): propagate W3C traceparent on outbound LLM requests (part 1 of #4384) feat(telemetry): propagate W3C traceparent + X-Qwen-Code-Session-Id to outbound LLM requests (#4384) May 21, 2026
doudouOUC added a commit that referenced this pull request May 21, 2026
…ry safety

Adopts 7 review findings from wenshao on #4390 (+ duplicates from now-closed
#4393). Critical bugs first, polish second.

CRITICAL:

1. tsc TS2322 — wrapper return type incompatible with Anthropic SDK Fetch.
   `typeof fetch` (Node WHATWG, 2 overloads) is not structurally assignable
   to Anthropic's narrower `Fetch = (input: RequestInfo, init?) => ...`,
   even though they're call-compatible at runtime. Make wrapper generic
   `<TFetch extends FetchLikeLoose>` so callers preserve their exact fetch
   signature; cast the Anthropic call site through `unknown` with a comment
   explaining why.

2. tsc TS2352 / TS2493 — `baseFetch.mock.calls[0]![1] as RequestInit` was
   out-of-bounds when wrapped was called with no init arg. Replaced with a
   `makeFetchMock()` helper returning typed accessors.

3. normalizeOtlpPrefix catch fallback was DANGEROUS — a config of `"http"`
   produced prefix `"http"` which `startsWith`-matched every outbound HTTP
   request → silently disabled ALL instrumentation (no client spans, no
   correlation header — defeats the entire feature). Fixed: catch returns
   undefined + diag.warn. Misconfigured endpoint loses its feedback-loop
   guard (acceptable) instead of disabling all guards (catastrophic).

4. `url.startsWith(prefix)` matching was NOT boundary-safe — port collision
   (`:4318` matches `:43180`), hostname suffix collision (`otlp.example.com`
   matches `otlp.example.com.evil.net`), path-segment collision (`/v1`
   matches `/v1foo/x`). Replaced with origin-equality + path-prefix +
   boundary-char check (next char must be `/`, `?`, `#`, or end-of-string).

5. HttpInstrumentation also lacked the OTLP feedback-loop guard. The OTLP
   HTTP exporter (`@opentelemetry/exporter-trace-otlp-http`) uses node:http
   (patched by HttpInstrumentation, NOT undici). Without this, every OTLP
   upload batch creates a parasitic client span → feedback loop. Added
   `ignoreOutgoingRequestHook` that reuses the same `matchesOtlpPrefix` /
   `stripPathSuffix` helpers as the undici instrumentation.

SAFETY:

6. Request input + undefined init dropped the Request's own headers
   (Authorization etc.) because `new Headers(undefined)` → `{...init, headers}`
   replaced them with just our session header. Fix: when input is a Request
   and init.headers is unset, seed from input.headers before adding ours.

7. Wrapped fetch had no try/catch — a throwing Config getter or Headers
   constructor would propagate as TypeError and break the LLM request path.
   Wrapped header construction in try/catch; on failure, fall through to
   baseFetch with original init (no header) + diag.warn. Telemetry must
   never break the model call.

COVERAGE:

- 3 new sdk.test.ts boundary tests (port/host/path)
- 1 new sdk.test.ts normalizeOtlpPrefix catch-branch coverage
- 1 new sdk.test.ts HttpInstrumentation OTLP guard test
- 1 new sdk.test.ts proxy-mode wrapped-fetch test (default.test.ts)
- 1 new anthropic test asserting wrapped fetch installed on Anthropic SDK
- 2 new llm-correlation-fetch.test.ts (Request-headers preservation + try/catch fall-through)

All 668 tests pass (1 pre-existing Anthropic User-Agent failure on main is
unrelated). tsc clean.

Declined: #10 DRY-refactor of baseFetch extraction across 3 sites — the
duplication was pre-existing (default/dashscope buildClient was already
near-identical), refactoring is a separate cleanup PR not gated by this
feature. Will reply on the thread.

🤖 Generated with [Qwen Code](https://github.com/QwenLM/qwen-code)

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

All 4 findings from the previous review round are resolved in 00434502a:

  • Critical: normalizeOtlpPrefix catch block now returns undefined + diag.warn — no more dangerous "http" fallback
  • Suggestion: startsWith replaced with matchesOtlpPrefix (origin-exact + path-boundary check)
  • Suggestion: HttpInstrumentation now has ignoreOutgoingRequestHook for OTLP feedback-loop guard
  • Suggestion: Comprehensive test coverage added (boundary tests, Anthropic fetch wrapper test, catch-branch test)

tsc clean (0 errors), eslint clean, 215/215 tests pass locally. LGTM ✅

Downgraded from Approve to Comment: CI still running.

— qwen-latest-series-invite-beta-v34 via Qwen Code /review

doudouOUC added 4 commits May 21, 2026 19:56
Part 1 of #4384 (sub-issue of #3731 P3 deeper observability).

Today qwen-code's only OTel instrumentation is `HttpInstrumentation`,
which only patches Node's `http`/`https` modules. The `openai` and
`@google/genai` SDKs use `globalThis.fetch` (undici), so outbound LLM
requests carry no `traceparent` header and trace context dies at the
qwen-code process boundary.

Adds `@opentelemetry/instrumentation-undici@0.14.0` (peer-compatible
with the installed `@opentelemetry/instrumentation@0.203.0`) and wires
it into `initializeTelemetry()` next to the existing
`HttpInstrumentation`. Default propagator (W3C tracecontext + baggage)
remains unchanged — no explicit `textMapPropagator` needed.

`ignoreRequestHook` skips OTLP exporter endpoints to avoid the
classic feedback loop (OTel SDK uses fetch to upload OTLP data; without
the hook each upload would create a span that gets uploaded, infinitely).
Configured `otlpEndpoint` / per-signal endpoints are stripped of trailing
slash and query string for robust prefix matching against undici's
`request.origin + request.path`.

Outbound LLM calls now also produce a client-side HTTP span (separating
network TTFB / transfer time from the existing `api.generateContent`
total-duration span).

Design doc: docs/design/telemetry-outbound-propagation-design.md
(Part A — traceparent; Part B — session id header — lands in a
follow-up PR per the design's split rationale.)

🤖 Generated with [Qwen Code](https://github.com/QwenLM/qwen-code)
Review feedback on #4390:

1. CI was failing on npm ci because the lockfile was generated with npm 11
   locally (it sprinkles `peer: true` annotations npm 10 reads differently
   and rejects). Regenerated with npm 10 (matching CI's Node 22.x default),
   so the diff vs main is now 18 lines (the actual instrumentation-undici
   entry) instead of 105 lines of npm-version drift noise.

2. (Copilot inline at sdk.ts:330) `otlpUrlPrefixes` was derived from raw
   Config strings, so a settings.json `"otlpEndpoint": "\"http://...\""`
   (quoted) or trailing `#fragment` would silently miss the prefix match
   and reintroduce the feedback loop the hook exists to prevent. Replaced
   the regex-based suffix trim with a WHATWG URL parser:
   - strips ?query, #fragment, trailing slash
   - trims symmetric ASCII quotes a user may have placed in settings.json
   - falls back to safe suffix trimming if URL parsing fails (misconfigured
     endpoint still gets SOME protection)

3. (CodeQL inline) Replaced the `/\?.*$/` regex in ignoreRequestHook with
   `indexOf('?')`/`indexOf('#')` slicing for ReDoS hygiene. The regex was
   linear in practice but flagged as polynomial — using indexOf removes
   the ambiguity and is arguably simpler.

Added 3 tests in sdk.test.ts covering the new normalizations (#fragment
on incoming path, quoted endpoint, #fragment on configured endpoint).

🤖 Generated with [Qwen Code](https://github.com/QwenLM/qwen-code)
…uests

Part 2 of #4384. Stacks on top of PR #4390 (traceparent via undici).

Adds a product-namespaced HTTP header X-Qwen-Code-Session-Id to every
outbound LLM request when telemetry is enabled, so server-side ingestion
can correlate observed requests with qwen-code session metric/log records.
Pattern matched from claude-code (X-Claude-Code-Session-Id, verified at
src/services/api/client.ts:108 in their open-source repo).

Critical design decision (design doc section 4.3): the OpenAI / Anthropic
providers use a per-request fetch wrapper rather than the SDK defaultHeaders
option, because content-generator SDK clients are constructed once and NOT
recreated on /clear-triggered session resets (Config.resetSession updates
this.sessionId but the contentGenerator keeps using the stale header value).
Reading config.getSessionId() from inside the wrapper at request time gives
the live value.

Gemini provider uses static httpOptions.headers — @google/genai HttpOptions
interface does not expose a fetch hook (only headers, baseUrl, apiVersion,
timeout, extraParams). This is a known limitation: after session reset,
Gemini X-Qwen-Code-Session-Id stays stale until the contentGenerator is
recreated. Documented in telemetry.md and the design doc section 8.6;
spans/logs continue to carry the live session id for trace/log correlation.
Lazy-invalidate fix is a follow-up sub-issue.

Header is omitted when telemetry is disabled OR when getSessionId returns
an empty string (some HTTP middleware rejects empty header values).

Integration sites:
- packages/core/src/core/openaiContentGenerator/provider/default.ts
  (base class — automatically covered by deepseek/minimax/mistral/
  modelscope/openrouter subclasses; openrouter calls super.buildHeaders)
- packages/core/src/core/openaiContentGenerator/provider/dashscope.ts
  (overrides buildClient — must be touched separately; QwenContentGenerator
  inherits via this provider)
- packages/core/src/core/anthropicContentGenerator/anthropicContentGenerator.ts
- packages/core/src/core/geminiContentGenerator/index.ts (factory function,
  not the GeminiContentGenerator class — no signature change)

End-to-end verification (local HTTP server in tmux):
  PASS: traceparent + X-Qwen-Code-Session-Id on every LLM request
  PASS: session id refreshes after simulated /clear (staleness regression
        guarded by llm-correlation-fetch.test.ts)
  PASS: OTLP upload traffic not traced (no feedback loop — PR A
        ignoreRequestHook working)

Robot generated with Qwen Code https://github.com/QwenLM/qwen-code
…ry safety

Adopts 7 review findings from wenshao on #4390 (+ duplicates from now-closed
#4393). Critical bugs first, polish second.

CRITICAL:

1. tsc TS2322 — wrapper return type incompatible with Anthropic SDK Fetch.
   `typeof fetch` (Node WHATWG, 2 overloads) is not structurally assignable
   to Anthropic's narrower `Fetch = (input: RequestInfo, init?) => ...`,
   even though they're call-compatible at runtime. Make wrapper generic
   `<TFetch extends FetchLikeLoose>` so callers preserve their exact fetch
   signature; cast the Anthropic call site through `unknown` with a comment
   explaining why.

2. tsc TS2352 / TS2493 — `baseFetch.mock.calls[0]![1] as RequestInit` was
   out-of-bounds when wrapped was called with no init arg. Replaced with a
   `makeFetchMock()` helper returning typed accessors.

3. normalizeOtlpPrefix catch fallback was DANGEROUS — a config of `"http"`
   produced prefix `"http"` which `startsWith`-matched every outbound HTTP
   request → silently disabled ALL instrumentation (no client spans, no
   correlation header — defeats the entire feature). Fixed: catch returns
   undefined + diag.warn. Misconfigured endpoint loses its feedback-loop
   guard (acceptable) instead of disabling all guards (catastrophic).

4. `url.startsWith(prefix)` matching was NOT boundary-safe — port collision
   (`:4318` matches `:43180`), hostname suffix collision (`otlp.example.com`
   matches `otlp.example.com.evil.net`), path-segment collision (`/v1`
   matches `/v1foo/x`). Replaced with origin-equality + path-prefix +
   boundary-char check (next char must be `/`, `?`, `#`, or end-of-string).

5. HttpInstrumentation also lacked the OTLP feedback-loop guard. The OTLP
   HTTP exporter (`@opentelemetry/exporter-trace-otlp-http`) uses node:http
   (patched by HttpInstrumentation, NOT undici). Without this, every OTLP
   upload batch creates a parasitic client span → feedback loop. Added
   `ignoreOutgoingRequestHook` that reuses the same `matchesOtlpPrefix` /
   `stripPathSuffix` helpers as the undici instrumentation.

SAFETY:

6. Request input + undefined init dropped the Request's own headers
   (Authorization etc.) because `new Headers(undefined)` → `{...init, headers}`
   replaced them with just our session header. Fix: when input is a Request
   and init.headers is unset, seed from input.headers before adding ours.

7. Wrapped fetch had no try/catch — a throwing Config getter or Headers
   constructor would propagate as TypeError and break the LLM request path.
   Wrapped header construction in try/catch; on failure, fall through to
   baseFetch with original init (no header) + diag.warn. Telemetry must
   never break the model call.

COVERAGE:

- 3 new sdk.test.ts boundary tests (port/host/path)
- 1 new sdk.test.ts normalizeOtlpPrefix catch-branch coverage
- 1 new sdk.test.ts HttpInstrumentation OTLP guard test
- 1 new sdk.test.ts proxy-mode wrapped-fetch test (default.test.ts)
- 1 new anthropic test asserting wrapped fetch installed on Anthropic SDK
- 2 new llm-correlation-fetch.test.ts (Request-headers preservation + try/catch fall-through)

All 668 tests pass (1 pre-existing Anthropic User-Agent failure on main is
unrelated). tsc clean.

Declined: #10 DRY-refactor of baseFetch extraction across 3 sites — the
duplication was pre-existing (default/dashscope buildClient was already
near-identical), refactoring is a separate cleanup PR not gated by this
feature. Will reply on the thread.

🤖 Generated with [Qwen Code](https://github.com/QwenLM/qwen-code)

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

No review findings. Downgraded from Approve to Comment: CI failing: Test (macos-latest, Node 22.x), Test (ubuntu-latest, Node 22.x), Test (windows-latest, Node 22.x). — gpt-5.5 via Qwen Code /review

@doudouOUC doudouOUC force-pushed the feat/telemetry-traceparent-propagation branch from 0043450 to a1a8a5a Compare May 21, 2026 12:08
@wenshao

wenshao commented May 21, 2026

Copy link
Copy Markdown
Collaborator

Local maintainer validation — ⚠️ blocking issue surfaced

Reviewed at head a1a8a5ac (against base 6b0e75816) in a dedicated tmux session (pr4390, 8 windows) under git worktree /.qwen/tmp/review-pr-4390.

TL;DR: Header propagation works end-to-end (proven against the built artifact with the staleness regression in scope). However the PR breaks packages/core/src/core/contentGenerator.test.ts — same root cause as the Ubuntu CI failure. Verified by reproducing locally on PR head, and confirming the same test passes on main. Two-line fix; see "Required follow-up" at the end.

Environment

  • macOS 26.4.1 (Darwin 25.4.0 arm64), Node 22.17.0, npm 11.8.0
  • Fresh npm ci (1453 packages incl. the new @opentelemetry/instrumentation-undici@0.14.0)
  • Repo version 0.15.11

Results

Stage Command Result
Install npm ci ✅ exit 0
Build npm run build ✅ exit 0 (15 unrelated curly warnings in vscode-ide-companion)
Typecheck npm run typecheck ✅ exit 0 across all 5 workspaces
Lint npm run lint ✅ exit 0
PR-touched core tests (6 files: sdk, llm-correlation-fetch, default/dashscope providers, gemini/anthropic generators) npx vitest run ... 214 / 215 (1 pre-existing UA env failure — see Triage)
Full packages/core suite cd packages/core && npx vitest run ⚠️ 9203 passed / 3 skipped / 22 failed2 are PR-caused (see below)
Full packages/cli suite cd packages/cli && npx vitest run 6779 passed / 9 skipped / 0 failed across 377 files
End-to-end against built artifact custom Node harness driving dist/.../llm-correlation-fetch.js 14 happy-path assertions pass; ⚠️ exposes the same defensiveness gap CI hit (item [8])

🚨 PR-caused regression

src/core/contentGenerator.test.ts — 2 of 4 tests fail with:

TypeError: config.getTelemetryEnabled is not a function
 ❯ staticCorrelationHeaders src/telemetry/llm-correlation-fetch.ts:121:15
 ❯ createGeminiContentGenerator src/core/geminiContentGenerator/index.ts:48:30
 ❯ Module.createContentGenerator src/core/contentGenerator.ts:370:21
 ❯ src/core/contentGenerator.test.ts:31:23

Verified PR-caused (not pre-existing or environmental):

  • ✅ Reproduces on PR head a1a8a5ac2 failed | 2 passed (4)
  • ✅ Passes on main (qwen-code-x3 at 16f0fde19) — 4 passed (4)
  • ✅ Same failure surface on GitHub Actions Ubuntu (Test (ubuntu-latest, Node 22.x)2 failed | 9261 passed)

Root cause (diagnosed by e2e harness item [8]):

staticCorrelationHeaders(config) at llm-correlation-fetch.ts:119-127 calls config.getTelemetryEnabled() synchronously without defensive wrapping:

export function staticCorrelationHeaders(config: Config): Record<string, string> {
  if (!config.getTelemetryEnabled()) return {};   // ← throws on legacy mocks
  ...
}

But the sibling wrapFetchWithCorrelation at llm-correlation-fetch.ts:73-100 does wrap the same call in try/catch, with this comment (line 63):

Telemetry must never break the LLM request path — if Config getters throw, header construction fails, etc., we still want the model call to proceed.

The contentGenerator.test.ts mock (line 22 / 60) predates this PR and doesn't stub getTelemetryEnabled. The Gemini factory function (geminiContentGenerator/index.ts:48) now calls staticCorrelationHeaders on every construction, exposing the missing method.

Required follow-up — pick one:

  1. Defensive fix in staticCorrelationHeaders (consistent with the wrap function's stated contract — recommended):
    export function staticCorrelationHeaders(config: Config): Record<string, string> {
      try {
        if (!config.getTelemetryEnabled()) return {};
        const sid = config.getSessionId();
        if (!sid) return {};
        return { [SESSION_ID_HEADER]: sid };
      } catch {
        return {};   // telemetry must never break the LLM request path
      }
    }
  2. Fix the test mocks in contentGenerator.test.ts (add getTelemetryEnabled: () => false to both mockConfig blocks). Mechanical, but leaves other downstream Config-mock consumers vulnerable to the same trap.

Triage of the other 20 core failures (NOT caused by this PR)

File Fails Cause Verified
src/skills/skill-manager.test.ts 2 .qwen path fixture bug Reproduces on PR bases of #4314 / #4345 / #4354 / #4386 — every .qwen/tmp/ worktree
src/core/anthropicContentGenerator/anthropicContentGenerator.test.ts 1 Claude Code UA injection (claude-cli/1.2.3 (external, cli) overrides QwenCode/1.2.3) Reproduces on qwen-code-x3 main and every prior PR validation
src/utils/gitDiff.test.ts 12 5 s testTimeout under parallel load (core + cli running together saturates IO/CPU) Same pattern as PR 4345 validation — passes in isolation
src/utils/filesearch/crawler.test.ts 5 Same — git ls-files / ripgrep subprocesses time out under parallel load Same pattern as PR 4345 — passes in isolation

End-to-end proof against built packages/core/dist/.../llm-correlation-fetch.js

Drove the compiled wrapFetchWithCorrelation + staticCorrelationHeaders and asserted:

[0] SESSION_ID_HEADER = "X-Qwen-Code-Session-Id" (matches PR spec)

[1] wrapFetchWithCorrelation: telemetry ON adds session header
  ✓ request carried X-Qwen-Code-Session-Id: sess-abc
  ✓ Authorization header preserved

[2] wrapFetchWithCorrelation: telemetry OFF skips header
  ✓ no X-Qwen-Code-Session-Id header sent when telemetry off

[3] CRITICAL: sessionId is read at request time (not captured at construction)
  ✓ first=sess-initial, second=sess-after-clear — staleness regression NOT present

[4] Empty session id → header omitted (no empty value)
[5] Request input: Authorization preserved when init.headers undefined
[6] Defensive: throwing Config.getTelemetryEnabled does not break request (wrap path)
[7] staticCorrelationHeaders contract (Gemini fallback path) — happy path holds
[8] staticCorrelationHeaders defensiveness ⚠ NOT defensive — reproduces Ubuntu CI fail

[3] is the critical design property the PR description calls out — confirmed: wrapFetchWithCorrelation reads config.getSessionId() at request time, so after a simulated /clear (mutating sessionId on the same Config object), subsequent requests carry the new session id without the SDK being rebuilt.

[6] confirms the wrap path correctly absorbs a throwing Config.getTelemetryEnabled and still sends the request — exactly what the [8] gap should mirror.

Scope / risk

  • Diff: +1709 / −4 across 16 files (2 docs + 4 new/edited core source + 7 core tests + 1 new test file + 1 dep added).
  • New dep: @opentelemetry/instrumentation-undici@0.14.0 (peer-compatible with the existing @opentelemetry/instrumentation@0.203.0 per the PR description).
  • The fetch-wrapper-vs-defaultHeaders choice is sound and well-defended in the PR body — /clear staleness is a real concern and this PR is the right shape to address it. Gemini fallback to httpOptions.headers is documented and a follow-up sub-issue is tracked.
  • OTLP feedback-loop avoidance via ignoreRequestHook (with WHATWG URL normalization addressing the Copilot-flagged quoted-endpoint case) is well-handled.

Reviewer recommendation

Hold for a one-block fix. The header-propagation core mechanics are correct and the staleness regression is closed. The only blocking issue is the contentGenerator.test.ts breakage, which has a 1-block fix (either in staticCorrelationHeaders or in the test mocks). Once that lands:

  • Local full core suite goes from 22 failed20 failed (all 20 are the same environmental issues observed on every recent PR validation; they don't affect CI on clean Ubuntu/macOS/Windows runners)
  • Ubuntu CI should turn green (it only failed on the 2 PR-caused tests)
  • macOS CI was still running at validation time; should also pass once the fix lands

The defensive try/catch fix in staticCorrelationHeaders is recommended because it aligns with the stated "telemetry must never break the LLM request path" contract that already governs wrapFetchWithCorrelation, and it future-proofs against the same trap recurring in other Config-mock-using tests.

— Maintainer local validation, run on a1a8a5ac from upstream pull/4390/head.

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

⚠️ Downgraded from Approve to Comment: CI failing: Test (windows-latest, Node 22.x), Test (ubuntu-latest, Node 22.x), Test (macos-latest, Node 22.x). Approve with inline suggestions below.

— qwen-latest-series-invite-beta-v36 via Qwen Code /review

Comment thread packages/core/package.json Outdated

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

No review findings. Downgraded from Approve to Comment: CI failing: Test (windows-latest, Node 22.x), Test (ubuntu-latest, Node 22.x), Test (macos-latest, Node 22.x). — gpt-5.5 via Qwen Code /review

…ndici

Switch from exact pin `0.14.0` to `^0.14.0` for consistency with the rest
of the `@opentelemetry/*` deps in this block (all carated).

For 0.x semver, npm treats `^0.14.0` as `>=0.14.0 <0.15.0`, so patch
updates within the 0.14.x line — which are tied to the same
`@opentelemetry/instrumentation@0.203.x` peer — flow in via `npm update`
without requiring a manual package.json edit. A bump across the 0.x
minor (e.g. 0.15.x) would shift the instrumentation peer compatibility
and still requires explicit attention, which the caret correctly blocks.

Per review feedback on #4390 (wenshao).

🤖 Generated with [Qwen Code](https://github.com/QwenLM/qwen-code)
@wenshao

wenshao commented May 22, 2026

Copy link
Copy Markdown
Collaborator

PR 4390 本地 tmux 验证报告

PR: #4390 feat(telemetry): propagate W3C traceparent + X-Qwen-Code-Session-Id to outbound LLM requests
作者: @doudouOUC
Base: fc15b3312 (v0.16.0)
Tip: a1a8a5ac6 (R2 review fixes)
验证时间: 2026-05-22
验证环境: macOS Darwin 25.4.0 / tmux 会话 pr4390(8 + 3 个验证窗口)


1. 总体结论

维度 结果
设计 ✅ 通过(fetch wrapper vs defaultHeaders 的取舍正确,staleness 防回归覆盖到位)
PR 自测试套件 ✅ 9 文件 / 314 个测试全过
CLI 包测试 ✅ 377 文件 / 6779 全过
构建 / typecheck ✅ 全过(lint 有 15 个 warning,全部为旧代码 curly 风格)
E2E 真实 fetch 行为 ✅ 8 大场景全过,包括 /clear staleness 回归与 OTLP 反馈环
PR 引入的真实回归 ⚠️ 1 个staticCorrelationHeaders 缺少 try/catch 防御)
看似失败、实为基线/工具 20 个(已逐项核对,详见 §4)

合并建议📋 待修一个小问题再合(详见 §5 "建议动作")。整体方向、测试覆盖、E2E 行为都过关;缺的只是 staticCorrelationHeaderswrapFetchWithCorrelation 的对称防御 — 3 行 try/catch 即可。


2. 验证方法

在 tmux 会话 pr4390 内并行执行:

Window 用途 结果
0 install npm ci on PR worktree EXIT=0
1 build npm run build EXIT=0(15 个 lint warning,全在 vscode-ide-companion,PR 未触碰)
2 typecheck npm run typecheck EXIT=0
4 test-pr PR 直接相关测试 1 failed(基线问题)
5 test-core packages/core 全套测试 22 failed(已逐项核对)
6 test-cli packages/cli 全套测试 6779 passed
7 e2e node /tmp/pr4390-e2e-correlation.mjs 跑 built artifacts ✅ PASS(含 1 ⚠ 防御缺口提示)
8 baseline 独立 worktree on fc15b3312 (v0.16.0) 用于隔离对比
9 pr-tests PR 新增 9 个测试文件 + 失败子集对比 314 passed
10 e2e-rerun 复测 e2e 脚本 EXITCODE=0

关键方法学:所有 "test-core 失败" 都在独立 worktree /tmp/pr4390-baseline(基于 fc15b3312)上跑同一子集做了 baseline 对照,保证不会把基线/工具问题误判为 PR 回归。


3. PR 自身行为验证

3.1 PR 新增/修改的 9 个测试文件(隔离运行)

src/telemetry/llm-correlation-fetch.test.ts    11 tests ✓
src/telemetry/sdk.test.ts                       44 tests ✓
src/telemetry/resource-attributes.test.ts          ✓
src/telemetry/config.test.ts                       ✓
src/telemetry/session-tracing.test.ts              ✓
src/telemetry/metrics.test.ts                      ✓
src/core/openaiContentGenerator/provider/default.test.ts   ✓
src/core/openaiContentGenerator/provider/dashscope.test.ts ✓
src/core/geminiContentGenerator/index.test.ts             ✓
────────────────────────────────────────────────────────
Test Files  9 passed (9)
Tests       314 passed (314)
Duration    10.80s

3.2 E2E 端到端行为验证(驱动已构建产物)

脚本 /tmp/pr4390-e2e-correlation.mjs 直接 import packages/core/dist/src/telemetry/llm-correlation-fetch.js,用捕获式 mock fetch 验证 8 大场景:

[0] SESSION_ID_HEADER 常量       ✓ "X-Qwen-Code-Session-Id"
[1] telemetry ON 注入 session id ✓ + Authorization 保留
[2] telemetry OFF 不注入头        ✓
[3] /clear staleness 回归         ✓ first=sess-initial, second=sess-after-clear
[4] 空 sessionId 不注入           ✓
[5] Request 输入 + init.headers=undefined  ✓ Authorization / X-Foo / Session id 三者都正确
[6] Config.getTelemetryEnabled 抛错 ✓ wrapper 走 try/catch 容灾
[7] staticCorrelationHeaders 3 情形 ✓
[8] staticCorrelationHeaders 防御性 ⚠ → 见 §4.1

亮点:[3] 是 PR 设计文档 §4.3 的核心 — 之所以不能用 defaultHeaders,是因为 SDK client 在 /clear 时不重建,必须每次请求时读 live sessionId。E2E 通过 "构造时 sess-initial → 模拟 /clear → 第二次请求 sess-after-clear" 完整证明此不变量。


4. 失败逐项核对(基线 vs PR)

测试运行 PR 时报 23 个失败,逐项在 baseline (v0.16.0) 上做同样隔离测试,分类如下:

4.1 ⚠️ PR 引入的真实回归(1 项 / 2 个 test case)

✗ src/core/contentGenerator.test.ts > should create a Gemini content generator
✗ src/core/contentGenerator.test.ts > should create a Gemini content generator with client install id logging disabled

TypeError: config.getTelemetryEnabled is not a function
  ❯ staticCorrelationHeaders src/telemetry/llm-correlation-fetch.ts:121:15
  ❯ createGeminiContentGenerator src/core/geminiContentGenerator/index.ts:48:30

baseline (fc15b33):同 2 个测试 PASS(72 passed in 3.34s)
PR:FAIL(同 72 文件,70 passed / 2 failed)

根因:PR 在 geminiContentGenerator/index.ts:48 新增了

headers = { ...headers, ...staticCorrelationHeaders(gcConfig) };

staticCorrelationHeaders 内部直接 config.getTelemetryEnabled()llm-correlation-fetch.ts:121),没有 try/catch 保护。其姊妹函数 wrapFetchWithCorrelation 有完整 try/catch(line 73-99)。当 legacy 测试 mock 不包含 getTelemetryEnabled 时,Gemini 路径就直接抛。

这正是 E2E [8] 场景里早就标记的 "Ubuntu CI failure root cause"。

建议修法(任选其一)

  • 🔧 推荐:给 staticCorrelationHeaders 加 try/catch,与 wrapFetchWithCorrelation 的 "telemetry must never break the request path" 契约保持对称:

    export function staticCorrelationHeaders(config: Config): Record<string, string> {
      try {
        if (!config.getTelemetryEnabled()) return {};
        const sid = config.getSessionId();
        if (!sid) return {};
        return { [SESSION_ID_HEADER]: sid };
      } catch (err) {
        diag.warn(`staticCorrelationHeaders: ${err instanceof Error ? err.message : String(err)}`);
        return {};
      }
    }
  • 或更新 packages/core/src/core/contentGenerator.test.ts:21,56 的 mockConfig 补上 getTelemetryEnabled / getSessionId(治标,未来还可能在别处复发)。

倾向方案 1:作者在 wrapFetch 已经明确写了 "telemetry must never break LLM request path" 的契约(注释见 line 60-62),staticCorrelationHeaders 应当遵循同样契约。

4.2 ❌ 基线已有的失败(1 项)

✗ src/core/anthropicContentGenerator/anthropicContentGenerator.test.ts
  > treats unset baseURL as Anthropic-native (SDK default targets api.anthropic.com)

AssertionError: expected 'claude-cli/1.2.3 (external, cli)' to contain 'QwenCode/1.2.3'
  • baseline (fc15b33):FAIL(同表现,复现 100%)
  • PR diff 验证:PR 对 anthropicContentGenerator.test.ts 只加了 +2 mock 字段 + 1 个新测试,完全没碰这个 "treats unset baseURL" 用例
  • 结论与 PR 无关,是 v0.16.0 已有的回归,需另开 issue 跟进(推测和 ce82d65a revert "x-api-key alongside Authorization" 相关副作用)

4.3 🧪 测试基础设施 bug(不算回归,2 项)

✗ src/skills/skill-manager.test.ts > bundled skills > should load bundled skills in listSkills
✗ src/skills/skill-manager.test.ts > bundled skills > should fall back to bundled level in loadSkill
  • baseline (/tmp/pr4390-baseline):72/72 PASS
  • PR worktree (/Users/wenshao/.../qwen-code/.qwen/tmp/review-pr-4390/):70/72,2 FAIL(隔离运行也复现)

根因:测试 mock 在 skill-manager.test.ts:971 写了:

const isBundled = pathStr.endsWith(bundledDirSegment) && !pathStr.includes('.qwen');

PR worktree 路径含 .qwen/.qwen/tmp/review-pr-4390/),触发误判 — 跟 PR 4390 改的代码 完全无关(PR 对 packages/core/src/skills/ 0 行改动,已 git diff fc15b3312..HEAD -- packages/core/src/skills/ 确认)。

建议:另开 issue 修测试 mock 用更稳健的判定(如 !pathStr.includes('/.qwen/skills/') 或基于 userPrefix 反向匹配),不阻塞本 PR。

4.4 🌀 高负载 flake(17 项)

完整 test-core 跑 9228 个测试时报告:

  • src/utils/filesearch/crawler.test.ts:5 timeout
  • src/utils/gitDiff.test.ts:12 失败(11 timeout + 1 计数 assertion)
验证 结果
baseline (v0.16.0) 跑同一子集 crawler 44/44 ✓,gitDiff 59/59 ✓
PR worktree 隔离跑同一子集 crawler 44/44 ✓,gitDiff 59/59 ✓
PR worktree 全套并发跑 crawler 5 / gitDiff 12 timeout

根因:这些测试用了真实 git fork + 文件 IO,5s timeout 在多 worker 并发争抢时偶发超时;与 PR telemetry 改动无关。
建议:可考虑给 crawler / gitDiff 加 testTimeout: 15000,但是独立工程问题。


5. 建议动作

5.1 合并前(阻断性 1 项)

  • staticCorrelationHeaders 防御性:按 §4.1 推荐方案给函数加 try/catch + diag.warn,保持与 wrapFetchWithCorrelation 的契约对称。改动约 3-5 行 + 加 1 个单测覆盖(构造一个无 getTelemetryEnabled 的 Config 传入,断言返回 {})。

5.2 合并后(跟踪性 3 项,可另开 issue)

5.3 不影响合并、值得点赞

  • llm-correlation-fetch.ts 行 33-36 的 FetchLikeLoose + 行 64 的 <TFetch extends FetchLikeLoose> 泛型设计,把 openai / anthropic / @google/genai 三个 SDK 各异的 Fetch 类型差异完美隔离
  • 设计文档 §8.6 明确写了 Gemini staleness 的已知短板和未来子任务,技术诚实
  • OTLP 反馈环 boundary-safe 匹配(origin 精确比 + pathname 路径边界)超出常规防护

6. 复现指引

# 进入 tmux 会话
tmux attach -t pr4390

# 关键命令
tmux capture-pane -t pr4390:e2e -p -S -200    # E2E 输出
tmux capture-pane -t pr4390:pr-tests -p        # PR 自测试输出
tmux capture-pane -t pr4390:baseline -p -S -100 # baseline 对照输出

# 重跑 E2E 脚本
node /tmp/pr4390-e2e-correlation.mjs

报告由 Claude Opus 4.7 在本地 tmux 上完整验证,作为维护者 merge 决策参考。

doudouOUC added 2 commits May 23, 2026 00:10
Lint check `Check settings schema is up-to-date` failed because the
checked-in `packages/vscode-ide-companion/schemas/settings.schema.json`
wasn't regenerated after adding `telemetry.sessionIdHeaderHosts` to
`settingsSchema.ts` in commit 1c8528a. Regenerated via
`npm run generate:settings-schema`.

🤖 Generated with [Qwen Code](https://github.com/QwenLM/qwen-code)
…t-allowlist scoping

Adds a "修订历史" header table at the top and a new §11 "R3 修订 —
Host-Allowlist Scoping for X-Qwen-Code-Session-Id" capturing what changed
after LaZzyMan's REQUEST_CHANGES review, why, and how. Inline pointers
added at §3.1, §3.2, §4.3, §4.4, §9 (claude-code comparison table) to
point readers at §11 — original prose preserved as a record of the
decision path rather than rewritten in place.

Concretely §11 covers:
- The three-step LazzyMan critique and why R1's "broadcast to all
  providers" was structurally wrong for an open-source multi-provider CLI
- The default allowlist (`DEFAULT_SESSION_ID_HEADER_HOSTS`) and its
  semantic alignment with the DashScope provider detector
- Pattern grammar (bare hostname / `*.suffix` dot-anchored), the
  TLD-suffix attack vectors it rejects, why no regex / port-aware globbing
- `wrapFetchWithCorrelation` host gate, wrap-time vs request-time
  semantics, `[" * "]` whitespace tolerance
- `staticCorrelationHeaders` `destinationUrl` parameter, Gemini factory's
  fail-closed treatment of unset `baseUrl` (avoids the Vertex
  vs `generativelanguage.googleapis.com` ambiguity)
- All R3 file changes mapped to the original §5 file-change list
- Mapping of LazzyMan's three concerns to R3's responses
- §10 future-work additions: `traceparent` per-destination toggle,
  `X-Qwen-Code-Request-Id`, IPv6 allowlist syntax

No code changes; documentation only.

🤖 Generated with [Qwen Code](https://github.com/QwenLM/qwen-code)

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

No review findings. Downgraded from Approve to Comment: CI still running. — gpt-5.5 via Qwen Code /review

Comment thread packages/core/src/telemetry/llm-correlation-fetch.ts Outdated
wenshao
wenshao previously approved these changes May 22, 2026
Comment thread packages/core/src/telemetry/llm-correlation-fetch.ts Outdated
Comment thread packages/core/src/core/openaiContentGenerator/provider/default.test.ts Outdated
@doudouOUC doudouOUC changed the title feat(telemetry): propagate W3C traceparent + scoped X-Qwen-Code-Session-Id to outbound LLM requests (#4384) feat(telemetry): propagate W3C traceparent + first-party-scoped session id header (#4384) May 24, 2026
Three issues found by wenshao reviewing the R3 host-allowlist scoping.

1. **[Critical] `broadcastAll` outside safety try/catch**
   (llm-correlation-fetch.ts wrapFetchWithCorrelation)
   The try/catch only fires when `getTelemetrySessionIdHeaderHosts()`
   throws. If it returns a malformed value — a bare string (settings.json
   typo `"sessionIdHeaderHosts": "host"` instead of `["host"]`), an array
   containing `null`/`undefined`/number entries, or whitespace-padded
   entries — `.some((p) => p.trim() === '*')` throws TypeError at
   buildClient time, bricking the LLM session before the first prompt.
   `staticCorrelationHeaders` already handled this via its end-to-end
   try/catch but the sister helper diverged. Settings loader does no
   runtime schema validation so this is reachable via a single typo.

   Fix: normalize the allowlist at wrap time:
     1. catch a throwing getter (existing)
     2. reject non-array → default allowlist (NEW — bare string typo)
     3. filter out non-string elements (NEW — [null, ...] typo)
     4. trim every surviving entry uniformly (NEW — see #2 below)
   Then `trustedHosts.includes('*')` instead of `.some((p) => p.trim() === '*')`,
   since patterns are already pre-trimmed.

2. **Trim asymmetry between `*` detection and host-pattern match**
   (llm-correlation-fetch.ts)
   `[" * "]` was tolerated (trimmed before `===` compare) but
   `[" dashscope.aliyuncs.com "]` silently never matched. The
   normalization above fixes this by trimming uniformly upstream.

3. **Proxy fetch test: only negative assertions**
   (openaiContentGenerator/provider/default.test.ts)
   The test asserted `callArg.fetch !== proxyFetch` and `!== globalThis.fetch`
   but both passed for ANY wrapper, including a buggy one that
   accidentally wraps globalThis.fetch instead of proxyFetch. Added a
   positive assertion: call the wrapped fetch and verify proxyFetch was
   the delegation target.

Tests: 4 new cases — whitespace-padded host pattern, bare-string
malformed config (both wrapper and static), null/number-containing
array malformed config (both wrapper and static), positive proxy fetch
delegation. All pass; pre-existing Anthropic User-Agent failure
unrelated.

🤖 Generated with [Qwen Code](https://github.com/QwenLM/qwen-code)
wenshao
wenshao previously approved these changes May 24, 2026

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

No high-confidence issues at commit 7a1b4f8d (round 7). Build passes, 9270/9272 tests pass (2 pre-existing unrelated), tsc/eslint clean. All 7 low-confidence suggestions are incremental quality improvements — see terminal output for details. — qwen3.7-max via Qwen Code /review

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

Review (round 8 follow-up)

Thanks for the substantive response — the host allowlist in 1c8528a56 genuinely addresses constraint #1 by removing the dangerous default, and the defensive normalization in 7a1b4f8d is the right hardening. The original severity: high finding is materially resolved.

But I want to step back from the rename suggestion I drafted earlier and push on a different, harder line, because I think the rename framing concedes too much:

Telemetry is not a container for adjacent features

The traceparent cross-process propagation and the X-Qwen-Code-Session-Id header injection are not telemetry. They are outbound-identity / outbound-correlation work that uses some OTel APIs internally as an implementation detail. The fact that they're convenient to land alongside a telemetry change does not make them telemetry work.

I don't think the right resolution is "rename the namespace inside this PR." I think the right resolution is scope discipline going forward: telemetry PRs should land telemetry, and outbound-correlation work should land in its own PR under its own design discussion, with its own settings tree, its own threat model, and its own user consent flow. Bundling them — even with safe defaults — sets a precedent that future telemetry work can dictate wire-level behavior to third parties, which is exactly the misframing risk that surfaced this whole conversation.

What I'm asking for this round

  1. Split this PR. Land in this PR only what is genuinely user-facing observability:

    • UndiciInstrumentation registration (provides the client-side HTTP span — pure observability for the qwen-code operator's own collector)
    • The OTLP feedback-loop guard (necessary side-effect of the above)
    • Configure the instrumentation so it does not propagate trace context on the wire (use a no-op propagator on the undici instrumentation, or disable requestHook injection — whichever the API supports)

    Remove from this PR:

    • The entire X-Qwen-Code-Session-Id apparatus (llm-correlation-fetch.ts, trusted-llm-hosts.ts, telemetry.sessionIdHeaderHosts, the fetch-wrapper plumbing across four provider construction points, the related tests)
    • The active traceparent propagation to upstream LLM providers (keep the trace IDs internal to the user's collector, don't put them on outbound wires)
  2. Open a separate issue/PR for outbound correlation headers. If the ARMS+DashScope cross-process trace continuation is a real product requirement (and I believe you that it is), that's a feature on its own merits and deserves its own design discussion. The discussion should cover at minimum:

    • Threat model: what's the recipient set, what's the worst-case correlation possibility
    • Settings tree: independent of telemetry.*, named for what it actually does (e.g., outboundCorrelation.*, llmRequestHeaders.*)
    • Default: off, per the principle "an open-source client shouldn't broadcast stable identifiers to third parties without explicit user consent"
    • Override semantics: same trustedHosts allowlist mechanism you've built here can carry over unchanged
    • Audit trail: documented in docs/users/configuration/settings.md as a security-relevant setting, not buried under "observability"
  3. The work you've already done is not wasted. The fetch wrapper, the host allowlist, the defensive normalization, the test coverage — all of that lifts cleanly into the follow-up PR. You're moving it from one PR to another, not redoing it. What you lose is the ability to land everything in one shot; what you gain is a settings tree whose names match what they do, a separate design doc that names the recipient and threat model, and a precedent that telemetry PRs don't quietly extend wire-level behavior to third parties.

@wenshao @doudouOUC — I'd rather we settle this before I dismiss vs. hold. The principle I'm asking for is "telemetry's scope of work doesn't include sending identifiers to LLM providers, and shouldn't quietly grow to include it." If we accept that principle, the split is mechanical. If we don't, this PR is the wrong place to debate it because the technical fixes are already in.

Verdict

REQUEST_CHANGES (continued) — defaults are now safe, but the scope conflation is the underlying problem. Asking for the outbound-correlation work to be split into a separate PR/issue with its own settings namespace and design discussion, leaving this PR to land the actual telemetry work (client-side HTTP spans + OTLP loop prevention) on its own.

…e (R4)

Address LaZzyMan round-8 follow-up review on PR #4390: even though R3's
host allowlist made the default behavior safe, the meta-architectural
concern remains: telemetry's namespace and consent flow shouldn't quietly
extend to wire-level behavior aimed at third-party LLM provider request
streams. The recipient sets differ; the consent decisions differ; they
deserve separate namespaces, separate threat models, separate PRs.

This commit (called R4 in the design doc) collapses the PR scope so it
lands ONLY telemetry observability work:

REMOVED from this PR:
  - packages/core/src/telemetry/llm-correlation-fetch.ts(.test.ts)
  - packages/core/src/telemetry/trusted-llm-hosts.ts(.test.ts)
  - telemetry.sessionIdHeaderHosts setting + Config getter +
    resolveTelemetrySettings wiring + settingsSchema entry
  - wrapFetchWithCorrelation usage from four provider construction
    points (default.ts, dashscope.ts, anthropicContentGenerator.ts,
    geminiContentGenerator/index.ts)
  - All session-id provider tests across the four providers + the
    contentGenerator.test.ts mock stub
  - "Session correlation header" section in telemetry.md

ADDED:
  - OutboundCorrelationSettings interface in packages/core/src/config/config.ts,
    standalone top-level namespace separate from TelemetrySettings —
    SECURITY-RELEVANT label, all defaults off
  - Config.getOutboundCorrelationPropagateTraceContext() getter
  - outboundCorrelation top-level entry in settingsSchema.ts with
    propagateTraceContext: { default: false } and explicit
    SECURITY-RELEVANT framing in the description
  - CLI config-load pipeline passes settings.outboundCorrelation into
    ConfigParameters
  - NOOP_PROPAGATOR (TextMapPropagator no-op) in sdk.ts, conditionally
    installed on NodeSDK when propagateTraceContext is false (default).
    When true, omits textMapPropagator from NodeSDK options so the SDK
    keeps its default W3C composite propagator
  - 2 new sdk.test.ts cases covering the propagator gate behavior

UNCHANGED:
  - UndiciInstrumentation registration + OTLP feedback-loop guard +
    HttpInstrumentation OTLP guard from R2/R3 stay intact — they are
    pure telemetry (client HTTP spans into the operator's own OTLP
    collector), no wire-level data egress
  - Documentation rewrites telemetry.md to split "client-side HTTP
    span on outbound fetch" (telemetry) from a new "Outbound
    correlation (SECURITY-RELEVANT)" top-level section
  - design doc gets R4 revision row + new §12 "R4 Scope Conflation
    Split" capturing the rationale and follow-up PR outline

The session-id apparatus (R3 code) lives in git history at commits
1c8528a / cb162e7 / 7a1b4f8 / 40e1efc / 106598c; the
follow-up PR can cherry-pick or restore those files under the new
outboundCorrelation.* namespace as LazzyMan suggested.

Vscode-ide-companion settings.schema.json regenerated.

🤖 Generated with [Qwen Code](https://github.com/QwenLM/qwen-code)
@doudouOUC doudouOUC changed the title feat(telemetry): propagate W3C traceparent + first-party-scoped session id header (#4384) feat(telemetry): client-side HTTP span + opt-in W3C traceparent propagation (#4384) May 25, 2026
@doudouOUC

Copy link
Copy Markdown
Collaborator Author

@LaZzyMan — accepting the split.

The scope-conflation principle you laid out is correct, and the technical fixes already being in (R3 + R2) means there's no good reason to debate it inside this PR. Took the "split is mechanical" path you described — see commit 9bdd3bd6f for the trim-down. PR title and description updated to reflect the new scope.

What's in this PR now

  • UndiciInstrumentation registration (client HTTP span for the operator's own OTLP collector)
  • OTLP feedback-loop guard on both HttpInstrumentation and UndiciInstrumentation
  • NoopTextMapPropagator installed by default on NodeSDK — so propagation.inject() writes nothing into outbound requests. Client spans still emit; traceparent does NOT reach third-party LLM provider request streams.
  • One new boolean setting in a new top-level namespace (not telemetry.*):
    "outboundCorrelation": {
      "propagateTraceContext": false  // default
    }
    When true, switches to the SDK's default W3C composite propagator → traceparent is written on outbound requests. This is the explicit, separate opt-in for ARMS+DashScope-style cross-process trace continuation.

The single boolean here establishes the outboundCorrelation.* namespace as a place for the follow-up correlation-headers work. Description in settingsSchema.ts is explicitly labelled SECURITY-RELEVANT, and telemetry.md documents it under a top-level "Outbound correlation (SECURITY-RELEVANT)" section rather than buried under "observability".

What moved to a follow-up PR

The entire X-Qwen-Code-Session-Id apparatus removed from this branch:

  • packages/core/src/telemetry/llm-correlation-fetch.ts + .test.ts (deleted)
  • packages/core/src/telemetry/trusted-llm-hosts.ts + .test.ts (deleted)
  • wrapFetchWithCorrelation / staticCorrelationHeaders usage from default.ts / dashscope.ts / anthropicContentGenerator.ts / geminiContentGenerator/index.ts (reverted)
  • TelemetrySettings.sessionIdHeaderHosts field + Config getter + resolveTelemetrySettings wiring + settingsSchema.ts entry (removed)
  • All session-id related test cases (removed)
  • telemetry.md "Session correlation header" section (removed; replaced with a note pointing at the follow-up PR)

The R3 implementation code lives in git history at commits 1c8528a56 / cb162e716 / 7a1b4f8d0 / 40e1efc1f / 106598ca2 — the follow-up PR can git restore --source=<commit> or cherry-pick. As you noted, the work isn't wasted, just relocated to a place where the recipient (LLM provider) matches the namespace name (outboundCorrelation.*).

How the new arrangement maps to your three asks

  1. "Land only genuine user-facing observability" ✅ — only UndiciInstrumentation registration + OTLP guard remain in this PR. The follow-up outboundCorrelation.propagateTraceContext: true opt-in is a single boolean for operators who want the W3C standard cross-process behavior.
  2. "Configure instrumentation to NOT propagate trace context on the wire" ✅ — NoopTextMapPropagator does exactly this. UndiciInstrumentation still produces client spans (operator's collector), but propagation.inject() is no-op so outbound HTTP requests carry no traceparent.
  3. "Open a separate issue/PR for outbound correlation headers" ✅ — namespace outboundCorrelation.* established; design doc R4 section (docs/design/telemetry-outbound-propagation-design.md §12 R4) carries the follow-up outline with default-off, threat model section requirements, security-relevant docs.

Verdict request

Asking for a re-review at your convenience. Happy to iterate further if there's anything I missed in the split — e.g. if you'd rather the outboundCorrelation.propagateTraceContext toggle also moves to the follow-up PR and this PR keeps the propagator hardcoded to noop (which would make this PR even more minimal). I can do that pretty trivially.

@doudouOUC doudouOUC requested review from LaZzyMan and wenshao May 25, 2026 05:56
…aceContext

Self-review pass on R4 commit 9bdd3bd flagged one footgun: both
`docs/developers/development/telemetry.md` and the settingsSchema.ts
description for `outboundCorrelation.propagateTraceContext` describe
the toggle's behavior without noting that the flag is a silent no-op
when `telemetry.enabled` is false. An operator who sets only
`outboundCorrelation.propagateTraceContext: true` and forgets the
telemetry switch gets zero behavior change — no error, no warning, no
traceparent.

Fix: add the dependency disclosure to both surfaces, plus a JSON
example showing both flags wired together for the ARMS+DashScope
cross-process trace continuation use case.

Also fix a minor comment accuracy nit at `sdk.test.ts:683`: said the
SDK installs `W3CTraceContextPropagator` instance when opt-in is true,
but the actual default is `CompositePropagator(W3CTraceContextPropagator
+ W3CBaggagePropagator)` per `@opentelemetry/sdk-node` source.

Vscode-ide-companion settings.schema.json regenerated to reflect the
expanded description string.

🤖 Generated with [Qwen Code](https://github.com/QwenLM/qwen-code)
Comment thread packages/core/src/config/config.ts
R4 (commit 9bdd3bd) added the getter but the test file didn't grow a
corresponding describe block — sibling telemetry getters all have unit
tests but this new one was missed.

Add 4 cases covering the security-relevant default-to-false invariant
and explicit-set behavior:
- omitted outboundCorrelation → false
- empty outboundCorrelation: {} → false (the `?? false` collapse on the
  getter, complementing the same on the constructor)
- explicit true → true
- explicit false → false

PR #4390 review (wenshao).

🤖 Generated with [Qwen Code](https://github.com/QwenLM/qwen-code)
@doudouOUC doudouOUC requested a review from wenshao May 25, 2026 06:56
@doudouOUC doudouOUC self-assigned this May 25, 2026
doudouOUC added 2 commits May 25, 2026 20:01
R4 (commit 9bdd3bd) was followed by two polish commits that the
design doc §12 didn't track:

- 0be0df2 (docs): telemetry.enabled dependency disclosure on
  propagateTraceContext — added to telemetry.md + settingsSchema
  description because a self-review pass identified the silent-no-op
  footgun (operator sets propagateTraceContext: true but forgets
  telemetry.enabled: true, sees zero behavior change with no error).
- c0352fd (test): 4 config.test.ts cases covering the
  getOutboundCorrelationPropagateTraceContext default-false invariant
  (omitted / {} / explicit true / explicit false) — wenshao review
  flagged the test gap.

Updates §12.4 with a new "Hidden dependency: telemetry.enabled" sub-
section explaining the gating relationship and pointing forward at the
follow-up PR (future outboundCorrelation.* settings inherit the same
dependency). Updates §12.5 implementation table to add the
config.test.ts row and clarify the telemetry.md / vscode-schema rows
were touched again in the polish pass.

🤖 Generated with [Qwen Code](https://github.com/QwenLM/qwen-code)
/simplify review pass on commits 0be0df2 + c0352fd + 62cf6b4
flagged 4 concerns. Fix all 4:

1. **settingsSchema.ts description**: footgun warning ("Depends on
   telemetry.enabled: true") was at char 600+ of a 650-char description.
   VS Code settings UI truncates to ~300 chars inline → the most
   important warning was hidden in the most-glanced view. Hoist to first
   sentence ("Requires telemetry.enabled: true.").

2. **config.test.ts**: drop the task-narration comment
   ("PR #4390 R4: keep wire-level toggle out of telemetry namespace.")
   that just restated the change context. The remaining 2-line comment
   explaining WHY default-to-false is security-relevant survives.

3. **config.test.ts**: collapse 4 separate `it()` blocks into a single
   `it.each([...])` covering the same 4 precondition × expectation
   combinations. Removes boilerplate (`new Config({...baseParams, ...})`
   repeated 4×) without losing assertion power; case-3 ("explicit false")
   was a weak duplicate of case-2 ("empty object") since both hit the
   same `?? false` branch, but keeping all 4 in the parametric table
   documents intent more clearly than dropping case-3.

4. **design doc §12.4 + §12.5**: strip specific commit SHAs
   (`0be0df270`, `c0352fd5b`) — design docs should be evergreen, not
   doubled-up commit logs (those live in `git log`). Keep the design
   intent ("two panels both document the dependency" / "test block
   added") without naming the specific commits.

Regenerated vscode-ide-companion/schemas/settings.schema.json to
reflect the hoisted description sentence.

🤖 Generated with [Qwen Code](https://github.com/QwenLM/qwen-code)

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

Review

The R4 split lands cleanly. This PR is now scoped to the two changes that genuinely belong under telemetry.* — the client-side HTTP span from UndiciInstrumentation and the OTLP feedback-loop guard. The whole X-Qwen-Code-Session-Id apparatus (the fetch wrapper, the host allowlist, the related provider-constructor plumbing, the telemetry.sessionIdHeaderHosts setting) is gone from the production diff; only the design-doc narrative retains the R1/R3 history.

traceparent is no longer written on the wire by default. The new outboundCorrelation.propagateTraceContext switch lives in its own top-level namespace (separate from telemetry.*), defaults to false, and installs a no-op propagator on the OTel SDK until explicitly opted in. The schema description leads with SECURITY-RELEVANT. and the inner propagateTraceContext field's description opens with the telemetry.enabled dependency — both well inside the VS Code settings-UI inline truncation window.

Verdict

APPROVE — All three round-8 asks (telemetry-only scope, session-id apparatus removed, traceparent off-by-default under its own namespace) are fully delivered. The single residual nit — propagateTraceContext: true with telemetry.enabled: false silently no-ops without a runtime warning — is docs-disclosed and fine to ship as a follow-up.

@wenshao wenshao left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

R8 config test gap fully addressed (c0352fd) — 4-case it.each locks down the default-false security invariant. Description front-loads the telemetry.enabled dependency notice. Design doc documents the footgun. tsc clean, 176 config tests pass. No new findings. LGTM! ✅ — qwen3.7-max via Qwen Code /review

@wenshao

wenshao commented May 25, 2026

Copy link
Copy Markdown
Collaborator

Local Real-Test Verification Report (R4-polish)

Re-validating after R4 scope reduction. The earlier R2 verification (#issuecomment-4513932536, 2026-05-21) tested an obsolete shape (always-on traceparent + X-Qwen-Code-Session-Id). This report covers the current PR HEAD 6518e6d87 rebased onto today's main, exercising real undici instrumentation against local mock servers (no upstream LLM provider, no real OTel collector — capture only).

Test environment

  • PR HEAD: 6518e6d87 (refactor: simplify post-R4 polish per /simplify review)
  • Test-merge HEAD (what CI checks): acd850d61 (= 6518e6d87 merged onto main 5493888c1)
  • Worktree: /Users/wenshao/Work/git/qwen-code/.qwen/tmp/review-pr-4390, on refs/pull/4390/merge
  • Node: v22.17.0, macOS 25.4.0
  • Tmux session: pr4390 (9 windows: install / build / typecheck / lint / unit / mock-llm / mock-otlp / integration / verify)
  • Mock LLM server: http://127.0.0.1:18411 — captures every inbound HTTP request to disk
  • Mock OTLP collector: http://127.0.0.1:18412 — captures every inbound HTTP request and dumps the OTLP-JSON body for span inspection

Suite results

Step Result
npm run build --workspace=packages/core ✅ clean (after first wiping stale R2-era dist/)
tsc -p packages/core --noEmit ✅ 0 errors, 3.6 s
eslint on the 6 changed files ✅ 0 issues
vitest run packages/core/src/telemetry/sdk.test.ts 55 / 55 pass, 164 ms
vitest run packages/core/src/config/config.test.ts 176 / 176 pass, 110 ms

The 4 boundary-safety tests from the R2 review all pass on this commit:

  • ignoreRequestHook does NOT bleed across port boundary (4318 vs 43180)
  • ignoreRequestHook does NOT bleed across hostname boundary (otlp vs otlp.evil)
  • ignoreRequestHook does NOT bleed across path-segment boundary (/v1 vs /v1foo)
  • normalizeOtlpPrefix rejects unparseable URLs entirely (no dangerous "http" fallback)

The R4 propagator-gate tests are also green:

  • installs a no-op TextMapPropagator by default (propagateTraceContext=false)
  • uses the SDK default propagator when propagateTraceContext=true (operator opt-in)

Real-network integration test

Each phase runs in a fresh node process (otherwise the global propagator from phase 1 bleeds into phase 2 — NodeSDK only calls propagation.setGlobalPropagator() when textMapPropagator is set). The driver (run-real-test.mjs) duck-types a minimal Config and calls the real initializeTelemetry() exported from packages/core/dist/src/telemetry/sdk.js, then fetch()'s the mock LLM and the OTLP endpoint inside an active span, then shuts down and inspects what the mock servers received.

Result: ✅ 16 / 16 assertions pass.

Phase A — default (outboundCorrelation.propagateTraceContext: false)

[default] propagation.fields() = []                                  ← NoopPropagator installed
[default] LLM-server received 1 request:
  POST /v1/chat/completions  traceparent=null  baggage=null          ← clean wire
ID Assertion Detail
A1 propagation.fields() empty (NoopPropagator) fields=[]
A2 Outbound LLM request carries NO traceparent traceparent=null
A3 Outbound LLM request carries NO baggage baggage=null

Phase B — opt-in (outboundCorrelation.propagateTraceContext: true)

[optin] propagation.fields() = ["traceparent","tracestate","baggage"]  ← W3C composite installed
[optin] active span: traceId=1f2983b0a47afce44f9bf9e9037651d1 spanId=0e1d05fac956aae2
[optin] LLM-server received 1 request:
  POST /v1/chat/completions  traceparent=00-1f2983b0a47afce44f9bf9e9037651d1-a318eddf0cee3759-01
                                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                                              matches active span's traceId
ID Assertion Detail
B1 propagation.fields() contains traceparent ["traceparent","tracestate","baggage"]
B2 Outbound LLM request carries valid W3C traceparent (00-<32hex>-<16hex>-<2hex>) 00-1f2983b0…-a318eddf0cee3759-01
B3 traceparent's traceId == active span's traceId both 1f2983b0a47afce44f9bf9e9037651d1

The span-id portion (a318eddf0cee3759) differs from the parent span id (0e1d05fac956aae2) because UndiciInstrumentation correctly creates a CLIENT child span for each outbound request and propagates that child's id — standard W3C behavior, this is what we want.

Phase C/D — OTLP feedback-loop guard

UndiciInstrumentation's ignoreRequestHook and HttpInstrumentation's ignoreOutgoingRequestHook both received the same otlpUrlPrefixes set. To prove the guard works end-to-end, the phase script also fetch()s the OTLP endpoint directly inside an active span (simulating any module that might POST to /v1/traces itself).

ID Assertion Detail
C1 Default phase: OTLP collector got span uploads 2 POSTs to /v1/traces
C2 Opt-in phase: OTLP collector got span uploads 2 POSTs to /v1/traces
C3 Even in opt-in mode, OTLP /v1/traces uploads carry NO traceparent both traceparent=null
D1 Manual probe to OTLP endpoint reached collector (default) 1 body-empty POST
D2 Manual probe to OTLP endpoint reached collector (opt-in) 1 body-empty POST
D3 Opt-in manual probe carries NO traceparent (because ignoreRequestHook excluded it from instrumentation → propagation.inject was never invoked on its carrier) traceparent=null

Phase E — Client HTTP span exported via OTLP

The mock collector dumps every uploaded OTLP-JSON body to disk. The harness parses them and looks for kind=3 (CLIENT) spans whose scope is @opentelemetry/instrumentation-undici.

// /tmp/pr4390-test/otlp-bodies/0001-_v1_traces.bin (default phase)
"scope":{"name":"@opentelemetry/instrumentation-undici","version":"0.14.0"},
"spans":[{
  "traceId":"21e4605424efef838bf3df1d9afa486b",
  "spanId":"7bda1ed529b2c791",
  "parentSpanId":"cf3261b6c4d0f71b",       // ← parent = api.generateContent.default
  "name":"POST", "kind":3,                 // ← CLIENT span
  "attributes":[
    {"key":"http.request.method","value":{"stringValue":"POST"}},
    {"key":"url.full","value":{"stringValue":"http://127.0.0.1:18411/v1/chat/completions"}},
    {"key":"http.response.status_code","value":{"intValue":200}},
    
  ]
}]
ID Assertion Detail
E1 Default phase: undici emitted CLIENT span for outbound LLM POST /v1/chat/completions (status 200) found
E2 Opt-in phase: undici emitted CLIENT span for outbound LLM found
E3 Default phase: NO undici CLIENT span exists for the OTLP URL (127.0.0.1:18412) none — guard works
E4 Opt-in phase: NO undici CLIENT span exists for the OTLP URL none — guard works

E3/E4 are the strongest end-to-end proof of the loop guard: even with a manual fetch(MOCK_OTLP/v1/traces) issued inside an active span, the exported span tree contains zero instrumentation-undici entries pointing at the OTLP host. ★ The PR's ignoreRequestHook correctly suppresses span creation, which is the only break in the export → span → export feedback loop.

What I did NOT verify (caveats)

  1. Real LLM provider request flow (DashScope/OpenAI/Anthropic SDK actually using globalThis.fetch). I trusted the design doc's audit: openai@5.11.0, @google/genai@1.30.0, @anthropic-ai/sdk — all globalThis.fetch (undici). Easy to reverify by grepping node_modules if anyone is paranoid.
  2. gRPC OTLP. The PR's guard is wired to HttpInstrumentation (for the HTTP exporter) and UndiciInstrumentation; gRPC traffic doesn't go through either, so no guard is needed there. Not tested locally — would need a gRPC collector.
  3. TUI / Ink-render interaction. Telemetry init runs before Ink, the design doc covers this; I did not run qwen interactively.
  4. MCP StreamableHTTP propagation. PR description claims propagation also covers MCP; inferred since MCP uses the same globalThis.fetch. Not exercised by the integration test (only the LLM endpoint was hit).
  5. Pre-existing flake: anthropicContentGenerator.test.ts > treats unset baseURL as Anthropic-native (SDK default targets api.anthropic.com) fails locally on macOS Node 22.17 (User-Agent mismatch: claude-cli/1.2.3 (external, cli) vs expected QwenCode/1.2.3). This failure also reproduces on origin/main with PR feat(telemetry): client-side HTTP span + opt-in W3C traceparent propagation (#4384) #4390 reverted — it is not introduced by feat(telemetry): client-side HTTP span + opt-in W3C traceparent propagation (#4384) #4390. CI shows green for the same commit on Linux/macOS/Windows Node 22, so this looks environment-specific. Flagging for separate triage.

Recommendation

Code is correct, well-tested at the unit level (231 tests across the two changed files), and behavior is exactly what's documented in OutboundCorrelationSettings's description and the design doc. The R4 split (telemetry observability ↔ outbound-wire correlation) cleanly addresses @LaZzyMan's scope-conflation concern. OK to merge from a verification standpoint.

Two low-priority follow-ups (not blockers):

  • The PR is 27 commits behind main; before merging, recommend a rebase + green CI rerun rather than landing the test-merge as-is.
  • anthropicContentGenerator macOS-local User-Agent test failure is pre-existing on main and worth a separate triage issue.

Verification artifacts retained at /tmp/pr4390-test/{result.json,otlp-bodies/} and .pr4390-test/ inside the worktree. Reproducible end-to-end with node .pr4390-test/mock-servers.mjs & then node .pr4390-test/run-real-test.mjs.

@wenshao wenshao merged commit 62ed44e into main May 25, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

need-discussion scope/data-privacy Data privacy concerns status/on-hold Temporarily paused type/feature-request New feature or enhancement request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(telemetry): propagate W3C traceparent + X-Qwen-Code-Session-Id to LLM service calls

6 participants