feat: follow-up prompt to record telemetry denial#93
Conversation
When a user declines the first-run telemetry prompt, raid now asks one follow-up: may we send a single anonymous event recording your denial? Default is no (capital N) just like the main prompt. If accepted, raid fires exactly one raid_telemetry_opt_out event (reason: "prompt-declined") under explicit per-event consent and then leaves telemetry permanently off. If declined or skipped, raid makes zero network calls for the remainder of the install. The opt-out-rate signal is the most useful single data point for prioritization that's otherwise impossible to recover from website analytics alone — without it, we can't tell whether a quiet user opted out actively or just never finished setup. Implementation: - New CaptureOptOutConsented(reason) bypasses the IsActive() gate (which is false the moment after a decline) but still respects APIKey == "" and DO_NOT_TRACK. Scoped strictly to this code path in a comment — the trust model rests on per-event consent being explicit. - Follow-up runs only on the explicit-decline branch of MaybePromptForConsent. All skip paths (non-TTY, headless, DO_NOT_TRACK, already-decided, telemetry subcommand) continue to ask nothing further. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #93 +/- ##
==========================================
+ Coverage 90.80% 90.81% +0.01%
==========================================
Files 47 47
Lines 4034 4063 +29
==========================================
+ Hits 3663 3690 +27
- Misses 244 245 +1
- Partials 127 128 +1 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Adds a first-run follow-up prompt that (only with explicit per-event consent) allows sending a single anonymous raid_telemetry_opt_out event after a user declines telemetry, so the project can measure opt-out rate while keeping telemetry permanently disabled.
Changes:
- Introduces
CaptureOptOutConsented(reason)to send the opt-out event even whenIsActive()is false, while still honoringAPIKey == ""andDO_NOT_TRACK. - Wires a follow-up consent prompt into
MaybePromptForConsent’s decline path and adds targeted tests for the new behavior (including EOF/Enter defaulting to “no”). - Updates telemetry documentation and release notes to describe the new follow-up and the new
reason: "prompt-declined"value.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/internal/telemetry/telemetry.go | Adds a new synchronous, per-event-consent opt-out capture path that bypasses IsActive(). |
| src/internal/telemetry/prompt.go | Adds a follow-up prompt on decline and conditionally fires the one-off opt-out event. |
| src/internal/telemetry/telemetry_test.go | Adds tests covering follow-up consent outcomes and the new capture entry point’s gates. |
| site/docs/telemetry.mdx | Documents the follow-up prompt and expands the opt-out event’s reason semantics. |
| site/docs/whats-new.mdx | Adds release note entry describing the follow-up prompt and one-off event behavior. |
| // CaptureOptOutConsented fires the opt-out event under explicit | ||
| // per-event consent — used by the first-run prompt when a user | ||
| // declines telemetry generally but agrees to send a single | ||
| // anonymous "denial recorded" event. Bypasses the standard | ||
| // IsActive() gate (which would short-circuit because consent has |
| ### Follow-up: may we record the denial? | ||
|
|
||
| If you decline the first prompt, raid asks one follow-up question: | ||
|
|
| // "y" accepts. If the follow-up wrongly fired, the second line | ||
| // would be the input — but the test reader has only one line, | ||
| // so the missing line proves the follow-up was skipped. |
Updates the telemetry package godoc and the public telemetry docs page to spell out the narrow per-event-consent exception introduced by the follow-up prompt (CaptureOptOutConsented may create the anonymous ID and send one event after a declined first-run prompt). Also clarifies the test comment for TestMaybePromptForConsent_acceptSkipsFollowUp so it describes the actual output-based assertion rather than the input length. Co-Authored-By: Copilot <copilot@github.com>
|
Auto-review by meeseeks Updates pushed: 1 commit
Copilot comments addressed: 3 of 3
Skipped: 0 Codecov patch: 93.10% (project 90.81%, +0.01%) — at-or-above project, both checks green. |
Summary
When a user declines the first-run telemetry prompt, raid now asks one follow-up: may we send a single anonymous event recording your denial? Default is no (capital N), just like the main prompt.
If accepted, raid fires exactly one
raid_telemetry_opt_outevent (withreason: "prompt-declined") under explicit per-event consent and then leaves telemetry permanently off. If declined or skipped, raid makes zero network calls for the remainder of the install.Why this matters. Opt-out rate is the most useful single data point for prioritization that's otherwise impossible to recover from website analytics alone — without it, we can't tell whether a quiet user opted out actively or just never finished setup.
Implementation
CaptureOptOutConsented(reason string)in telemetry.go bypasses theIsActive()gate (which is false the moment after a decline because the state hasn't been written yet) but still respects the two hard kill-switches: a build with noAPIKeyandDO_NOT_TRACK. The function comment scopes its use strictly to the prompt-decline path — the trust model rests on per-event consent being explicit.MaybePromptForConsent. All skip paths (non-TTY, headless,DO_NOT_TRACK, already-decided,raid telemetry ...invocations) continue to ask nothing further.EOFcase (stray Enter, closed stdin after the main prompt) defaults to no — verified by a dedicated test.Test plan
go test ./... -race— all packages greenTestMaybePromptForConsent_declineThenConsentToOptOutEvent— happy path: decline + yes → exactly one event delivered + state persisted offTestMaybePromptForConsent_declineRefuseOptOutEventSendsNothing— decline + no → zero eventsTestMaybePromptForConsent_declineEmptyFollowUpSendsNothing— decline + EOF → zero eventsTestMaybePromptForConsent_acceptSkipsFollowUp— accept main → no follow-up prompt renderedTestCaptureOptOutConsented_bypassesInactive— fires whenIsActive() == false, payload includes event name + reasonTestCaptureOptOutConsented_respectsAPIKeyEmpty— no-op whenAPIKey == ""TestCaptureOptOutConsented_respectsDoNotTrack— no-op whenDO_NOT_TRACK=1askOptOutEventConsentandoptOutFollowUpTextat 100% line coveragecd site && npm run build— no broken anchorsDocs
raid_telemetry_opt_out'sreasonfield now documents both the"prompt-declined"value and the--why "..."free-text value🤖 Generated with Claude Code