Skip to content

feat: add telemetry adoption funnel#484

Merged
mohanagy merged 2 commits into
nextfrom
issue-471-adoption-funnel
Jun 2, 2026
Merged

feat: add telemetry adoption funnel#484
mohanagy merged 2 commits into
nextfrom
issue-471-adoption-funnel

Conversation

@mohanagy
Copy link
Copy Markdown
Owner

@mohanagy mohanagy commented Jun 2, 2026

Summary

  • expand local opt-in telemetry into a v2 adoption funnel with clear/report controls and source-safe buckets
  • record funnel events for install/generate/pack/prompt/doctor/status/compare plus MCP context_pack
  • document the new telemetry contract and lock it with CLI, runtime, and docs tests

Testing

  • npm run test:run -- tests/unit/cli.test.ts
  • npm run typecheck
  • npm run build
  • CI=1 npm run test:run

Refs #471

Summary by CodeRabbit

  • New Features

    • Added madar telemetry clear to delete local telemetry spools
    • Added madar telemetry report [spool.json ...] to view anonymized local reports
    • Telemetry now records command+stage events with richer, coarse metadata (OS, Node major, repo/graph size buckets, failure/status buckets) while excluding prompt text, file contents, and repo names
  • Documentation

    • Docs updated to describe new commands, event shape, and local-only spool behavior

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 2, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR migrates telemetry to a structured command+stage (v2) schema, adds CLI controls telemetry clear and telemetry report, implements v1→v2 spool migration, adds graph/repo bucketing and failure/status buckets, instruments CLI and MCP flows, and updates docs and tests.

Changes

Telemetry v2 Schema and Full Instrumentation

Layer / File(s) Summary
Telemetry v2 type contract and schema migration
src/shared/telemetry.ts
Adds TelemetryCommand, TelemetryStage, new bucket/target types, runtime guards, legacy v1→v2 migration, and normalization for persisted spools.
Telemetry storage, bucketing, and reporting APIs
src/shared/telemetry.ts
Adds graphSizeBucketFromNodeCount(), defaults spool to schema v2, clearTelemetry(), readTelemetryReport(), summarizeCounts(), and updates recordTelemetryEvent() to persist v2 events with snake_case fields.
CLI parser and dependency contract
src/cli/parser.ts, src/cli/main.ts
Parser accepts telemetry clear and telemetry report [spool.json ...]. CliDependencies extended with clearTelemetry, readTelemetryReport, and doctor/status bucket readers; default implementations and node-major helper added.
Per-command stage-based telemetry and failure classification
src/cli/main.ts
Commands emit stage-based events (started/succeeded/failed), use telemetryBase() and graphSizeBucket, classify failures via classifyTelemetryFailure(), and centralize failed emission in the top-level handler. Agent installs include agentTarget; generate/prompt include spiEnabled and size buckets.
Telemetry clear and report commands
src/cli/main.ts, src/cli/parser.ts
telemetry help updated; clear dispatches clearTelemetry(); report invokes readTelemetryReport(spoolPaths?) for a local anonymized funnel summary.
MCP context_pack telemetry
src/runtime/stdio-server.ts
tools/call captures responses and, for context_pack, builds a graph summary and records v2 telemetry (succeeded/failed) with size buckets and node/package metadata while suppressing telemetry failures.
Doctor utility exports and docs
src/infrastructure/doctor.ts, README.md, docs/telemetry.md, docs/reference/cli-and-mcp.md
Exports DoctorReport and buildDoctorReport. README/docs updated with madar telemetry clear/report, v2 field contract, exclusions (including repository name), graph_size_bucket, and spool storage (schema_version: 2).
Test coverage updates
tests/unit/cli.test.ts, tests/unit/telemetry.test.ts, tests/unit/stdio-server.test.ts, tests/unit/telemetry-doc.test.ts
CLI tests updated for parse/help/routing and v2 payloads; telemetry tests updated for v2 spool persistence, clear/report behavior, and migration; stdio-server test verifies context_pack telemetry and sensitive-data exclusions; doc tests assert new docs strings and field names.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related issues

Possibly related PRs

  • mohanagy/madar#449: Prior local telemetry opt-in work; this PR extends and migrates that feature to a v2 schema and adds clear/report controls.
  • mohanagy/madar#395: Related compare command changes; both PRs touch compare error handling which affects emitted telemetry.

Poem

🐰 I’m a rabbit with a log and pen,
I hop and bucket nodes again,
Commands and stages, tidy spool,
Clear and report — local and cool,
V1 retires; v2 begins.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The PR description includes a summary of changes, testing commands, and references a related issue. However, it lacks structured sections matching the template (Summary, Testing checklist, Checklist items, Related issues in proper format). Restructure the description to match the template format: add proper Testing checkbox sections, confirm checklist items explicitly, and format the issue reference as '' per template.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: add telemetry adoption funnel' clearly and concisely describes the main feature addition: implementing a telemetry adoption funnel as documented across the PR changes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-471-adoption-funnel

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
tests/unit/telemetry-doc.test.ts (1)

22-32: ⚡ Quick win

Lock the remaining documented telemetry fields too.

This contract test now enumerates the stored fields, but it still skips agent_target and spi_enabled. If either drops from docs/telemetry.md, CI will miss it even though the runtime/docs advertise both.

Suggested assertion additions
     expect(doc).toContain('node_major')
     expect(doc).toContain('graph_size_bucket')
     expect(doc).toContain('repo_size_bucket')
+    expect(doc).toContain('agent_target')
+    expect(doc).toContain('spi_enabled')
     expect(doc).toContain('failure_bucket')
     expect(doc).toContain('status_bucket')
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/telemetry-doc.test.ts` around lines 22 - 32, The test
telemetry-doc.test.ts currently asserts many telemetry fields but omits two
documented fields; update the test by adding assertions on the test variable doc
to lock the remaining documented telemetry fields by including checks for
'agent_target' and 'spi_enabled' (e.g., add
expect(doc).toContain('agent_target') and expect(doc).toContain('spi_enabled')
alongside the other expects in the same file).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/telemetry.md`:
- Around line 67-73: The telemetry docs list omits the newly emitted `failed`
event for some CLI commands; update docs/telemetry.md so the entries for `madar
compare`, `madar doctor`, and `madar status` explicitly include `failed` (e.g.,
change `madar compare` (`succeeded`) to include `failed`, and `madar doctor` and
`madar status` to list both `succeeded` and `failed` while preserving
`status_bucket` for `madar status`), ensuring the documented schema matches the
CLI telemetry contract.

In `@src/cli/main.ts`:
- Around line 405-429: The function classifyTelemetryFailure incorrectly returns
'usage_error' immediately for any UsageError, preventing more specific buckets
from matching; change classifyTelemetryFailure to first derive the normalized
message via messageFromError(error) and run the pattern checks for
'invalid_params', 'missing_graph', 'stale_graph', 'stale_context',
'unsupported_corpus', and 'install_error', and only if none match then fall back
to checking error instanceof UsageError to return 'usage_error' (or finally
'unknown'); refer to classifyTelemetryFailure, UsageError, messageFromError, and
TelemetryFailureBucket when making the change.

In `@src/shared/telemetry.ts`:
- Around line 651-659: readTelemetryReport currently calls loadSpool for every
resolved path without guarding against unreadable paths, causing the whole
report to crash; modify readTelemetryReport so when mapping over resolvedPaths
it calls loadSpool inside a try/catch (or checks readability first using
fs.stat/ access) and skips any path that throws or is not a regular readable
file, optionally logging a warning, then continue to collect events; ensure the
logic around telemetrySpoolFilePath, resolvedPaths, and the events aggregation
remains intact so unreadable inputs are ignored rather than aborting the
function.

---

Nitpick comments:
In `@tests/unit/telemetry-doc.test.ts`:
- Around line 22-32: The test telemetry-doc.test.ts currently asserts many
telemetry fields but omits two documented fields; update the test by adding
assertions on the test variable doc to lock the remaining documented telemetry
fields by including checks for 'agent_target' and 'spi_enabled' (e.g., add
expect(doc).toContain('agent_target') and expect(doc).toContain('spi_enabled')
alongside the other expects in the same file).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 15eb1b45-2c35-4b03-a210-0062f4551952

📥 Commits

Reviewing files that changed from the base of the PR and between 9990781 and 4aae2f6.

📒 Files selected for processing (12)
  • README.md
  • docs/reference/cli-and-mcp.md
  • docs/telemetry.md
  • src/cli/main.ts
  • src/cli/parser.ts
  • src/infrastructure/doctor.ts
  • src/runtime/stdio-server.ts
  • src/shared/telemetry.ts
  • tests/unit/cli.test.ts
  • tests/unit/stdio-server.test.ts
  • tests/unit/telemetry-doc.test.ts
  • tests/unit/telemetry.test.ts

Comment thread docs/telemetry.md Outdated
Comment thread src/cli/main.ts Outdated
Comment thread src/shared/telemetry.ts
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
tests/unit/telemetry-doc.test.ts (1)

33-34: ⚡ Quick win

Avoid exact prose matching for doc-contract tests.

These assertions are brittle to harmless wording/Markdown edits. Prefer checking the stable tokens independently so the test still enforces the contract without pinning exact sentence text.

Suggested change
-    expect(doc).toContain('`madar compare` (`succeeded`, `failed`)')
-    expect(doc).toContain('`madar doctor` and `madar status` (`succeeded`, `failed`, plus `status_bucket`)')
+    expect(doc).toContain('madar compare')
+    expect(doc).toContain('madar doctor')
+    expect(doc).toContain('madar status')
+    expect(doc).toContain('succeeded')
+    expect(doc).toContain('failed')
+    expect(doc).toContain('status_bucket')
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/telemetry-doc.test.ts` around lines 33 - 34, The assertions in
tests/unit/telemetry-doc.test.ts are brittle because they match exact prose;
update the two expectations that currently check exact sentence text (the
assertions containing '`madar compare` (`succeeded`, `failed`)' and '`madar
doctor` and `madar status` (`succeeded`, `failed`, plus `status_bucket`)') to
instead assert the presence of stable tokens independently — e.g., check that
doc includes '`madar compare`' and separately includes 'succeeded' and 'failed',
and similarly check '`madar doctor`', '`madar status`', 'succeeded', 'failed',
and 'status_bucket' — so the contract is enforced without exact markdown
sentence matching.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@tests/unit/telemetry-doc.test.ts`:
- Around line 33-34: The assertions in tests/unit/telemetry-doc.test.ts are
brittle because they match exact prose; update the two expectations that
currently check exact sentence text (the assertions containing '`madar compare`
(`succeeded`, `failed`)' and '`madar doctor` and `madar status` (`succeeded`,
`failed`, plus `status_bucket`)') to instead assert the presence of stable
tokens independently — e.g., check that doc includes '`madar compare`' and
separately includes 'succeeded' and 'failed', and similarly check '`madar
doctor`', '`madar status`', 'succeeded', 'failed', and 'status_bucket' — so the
contract is enforced without exact markdown sentence matching.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 8f72d325-5a5a-422f-a824-a070ed8c30a0

📥 Commits

Reviewing files that changed from the base of the PR and between 4aae2f6 and d5e09f8.

📒 Files selected for processing (6)
  • docs/telemetry.md
  • src/cli/main.ts
  • src/shared/telemetry.ts
  • tests/unit/cli.test.ts
  • tests/unit/telemetry-doc.test.ts
  • tests/unit/telemetry.test.ts
✅ Files skipped from review due to trivial changes (1)
  • docs/telemetry.md
🚧 Files skipped from review as they are similar to previous changes (4)
  • tests/unit/telemetry.test.ts
  • tests/unit/cli.test.ts
  • src/shared/telemetry.ts
  • src/cli/main.ts

@mohanagy mohanagy merged commit 74aa855 into next Jun 2, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant