Context
PostHog telemetry has been exceeding the free-tier monthly quota (Product analytics 1M, Session replay 5K, Error tracking 100K — all exceeded in the June 6–July 6 cycle, driven by a ~2.7M-event spike on June 7–9). Once a free-tier limit is exceeded, PostHog silently drops ingestion for the rest of the billing cycle, which is why PostHog showed near-zero events for weeks despite Marketplace installs (45K+) continuing to grow — this was initially mistaken for a broken telemetry pipeline before the billing page confirmed the real cause.
Separately, a telemetry best-practice gap analysis (see TELEMETRY_GAP_ANALYSIS.md in the repo root) found consent/privacy issues that are largely inherited unchanged from upstream Roo Code. Both problems live in the same subsystem (packages/telemetry, Task.ts, code-index services), so this issue bundles the fixes together.
Breakdown of the June 7–9 spike (~2.7M events):
| Event |
Count |
People |
Per-person |
Verdict |
Conversation Message |
1,318,290 |
3,949 |
334 |
Real signal, tracked at message-granularity — expensive |
Tool Used |
804,551 |
3,761 |
214 |
Real signal, same issue |
Code Index Error |
254,786 |
309 |
825 |
Bug — looks like an unbounded file-watcher retry loop against a broken embedder/vector-store config |
Checkpoint Created |
153,787 |
2,910 |
53 |
Real usage |
Model Cache Empty Response |
50,095 |
3,023 |
17 |
Possibly tracking an expected/benign condition every time |
Developer Notes
Part A — Event volume (get back under free tier)
A1. Circuit-breaker for CODE_INDEX_ERROR retry storm (highest impact)
309 people generated 254,786 events (9.4% of the entire monthly analytics quota) — consistent with a small number of installs stuck in a permanently-broken embedder/vector-store config, where file-watcher.ts re-triggers indexing on every file-system event with no backoff. Add a per-workspace circuit breaker: stop retrying/firing telemetry after N consecutive failures until the embedder config changes.
- Files:
src/services/code-index/processors/file-watcher.ts, src/services/code-index/manager.ts
A2. Aggregate Conversation Message into Task Completed
Currently fires once per message turn (Task.ts:2606, Task.ts:3523 via TelemetryService.captureConversationMessage). Replace with a messageCount property summarized once on Task Completed instead of one event per turn.
- Files:
src/core/task/Task.ts, packages/telemetry/src/TelemetryService.ts
A3. Aggregate Tool Used into Task Completed
Same treatment — 2 call sites, summarize as a per-task tool-usage breakdown (e.g. toolsUsed: { read: 12, edit: 8 }) instead of one event per tool call.
- Files:
src/core/task/Task.ts, packages/telemetry/src/TelemetryService.ts
A4. Review Model Cache Empty Response noise
Check whether this represents an expected/benign condition being tracked unconditionally; throttle or remove if so.
Part B — Privacy / consent gaps (from TELEMETRY_GAP_ANALYSIS.md)
B1. Fix consent banner dark pattern (Critical)
webview-ui/src/components/common/TelemetryBanner.tsx sends telemetrySetting: "enabled" when the user dismisses the banner with "×" — there's no neutral dismiss or explicit decline. Make "×" a neutral dismiss that leaves the setting as "unset" (routed to disabled), and add explicit Accept/Decline actions.
B2. Salt-hash the persistent machine ID (Critical)
Both PostHog clients (packages/telemetry/src/PostHogTelemetryClient.ts, webview-ui/src/utils/TelemetryClient.ts) use raw, unhashed vscode.env.machineId as the distinct ID. Hash it (e.g. SHA-256 + fixed salt) before use, or generate a separate installation UUID.
B3. Clarify PRIVACY.md dual-pipeline scope (High)
The "Telemetry" bullet says "does not collect your code or AI prompts" without noting this only applies to the PostHog path — the separate Cloud sync pipeline (packages/cloud/src/TelemetryClient.ts) does transmit task messages when cloud sync is enabled. Add one clarifying sentence.
B4. Adopt vscode.env.isTelemetryEnabled (Medium)
Code only checks the deprecated telemetry.telemetryLevel config setting. Add an onDidChangeTelemetryEnabled listener alongside it so the extension reacts live to VS Code's global telemetry toggle.
B5. Await telemetry shutdown properly (Medium)
extension.ts calls TelemetryService.instance.shutdown() in deactivate() without awaiting it, and TelemetryService.shutdown() itself uses forEach instead of Promise.all + await — risking dropped events (including the most diagnostically useful ones) on process exit.
Estimated scope
Roughly 300–500 changed lines across ~10–12 files, no new dependencies, no data/schema migrations, no breaking API changes. B1/B3/B5 are trivial (a few lines each); B2/B4 are small, mechanical changes; A1/A2/A3 need a bit of design judgment (retry threshold, aggregation shape) but are localized.
Context
PostHog telemetry has been exceeding the free-tier monthly quota (Product analytics 1M, Session replay 5K, Error tracking 100K — all exceeded in the June 6–July 6 cycle, driven by a ~2.7M-event spike on June 7–9). Once a free-tier limit is exceeded, PostHog silently drops ingestion for the rest of the billing cycle, which is why PostHog showed near-zero events for weeks despite Marketplace installs (45K+) continuing to grow — this was initially mistaken for a broken telemetry pipeline before the billing page confirmed the real cause.
Separately, a telemetry best-practice gap analysis (see
TELEMETRY_GAP_ANALYSIS.mdin the repo root) found consent/privacy issues that are largely inherited unchanged from upstream Roo Code. Both problems live in the same subsystem (packages/telemetry,Task.ts, code-index services), so this issue bundles the fixes together.Breakdown of the June 7–9 spike (~2.7M events):
Conversation MessageTool UsedCode Index ErrorCheckpoint CreatedModel Cache Empty ResponseDeveloper Notes
Part A — Event volume (get back under free tier)
A1. Circuit-breaker for
CODE_INDEX_ERRORretry storm (highest impact)309 people generated 254,786 events (9.4% of the entire monthly analytics quota) — consistent with a small number of installs stuck in a permanently-broken embedder/vector-store config, where
file-watcher.tsre-triggers indexing on every file-system event with no backoff. Add a per-workspace circuit breaker: stop retrying/firing telemetry after N consecutive failures until the embedder config changes.src/services/code-index/processors/file-watcher.ts,src/services/code-index/manager.tsA2. Aggregate
Conversation MessageintoTask CompletedCurrently fires once per message turn (
Task.ts:2606,Task.ts:3523viaTelemetryService.captureConversationMessage). Replace with amessageCountproperty summarized once onTask Completedinstead of one event per turn.src/core/task/Task.ts,packages/telemetry/src/TelemetryService.tsA3. Aggregate
Tool UsedintoTask CompletedSame treatment — 2 call sites, summarize as a per-task tool-usage breakdown (e.g.
toolsUsed: { read: 12, edit: 8 }) instead of one event per tool call.src/core/task/Task.ts,packages/telemetry/src/TelemetryService.tsA4. Review
Model Cache Empty ResponsenoiseCheck whether this represents an expected/benign condition being tracked unconditionally; throttle or remove if so.
Part B — Privacy / consent gaps (from
TELEMETRY_GAP_ANALYSIS.md)B1. Fix consent banner dark pattern (Critical)
webview-ui/src/components/common/TelemetryBanner.tsxsendstelemetrySetting: "enabled"when the user dismisses the banner with "×" — there's no neutral dismiss or explicit decline. Make "×" a neutral dismiss that leaves the setting as"unset"(routed to disabled), and add explicit Accept/Decline actions.B2. Salt-hash the persistent machine ID (Critical)
Both PostHog clients (
packages/telemetry/src/PostHogTelemetryClient.ts,webview-ui/src/utils/TelemetryClient.ts) use raw, unhashedvscode.env.machineIdas the distinct ID. Hash it (e.g. SHA-256 + fixed salt) before use, or generate a separate installation UUID.B3. Clarify PRIVACY.md dual-pipeline scope (High)
The "Telemetry" bullet says "does not collect your code or AI prompts" without noting this only applies to the PostHog path — the separate Cloud sync pipeline (
packages/cloud/src/TelemetryClient.ts) does transmit task messages when cloud sync is enabled. Add one clarifying sentence.B4. Adopt
vscode.env.isTelemetryEnabled(Medium)Code only checks the deprecated
telemetry.telemetryLevelconfig setting. Add anonDidChangeTelemetryEnabledlistener alongside it so the extension reacts live to VS Code's global telemetry toggle.B5. Await telemetry shutdown properly (Medium)
extension.tscallsTelemetryService.instance.shutdown()indeactivate()without awaiting it, andTelemetryService.shutdown()itself usesforEachinstead ofPromise.all+await— risking dropped events (including the most diagnostically useful ones) on process exit.Estimated scope
Roughly 300–500 changed lines across ~10–12 files, no new dependencies, no data/schema migrations, no breaking API changes. B1/B3/B5 are trivial (a few lines each); B2/B4 are small, mechanical changes; A1/A2/A3 need a bit of design judgment (retry threshold, aggregation shape) but are localized.