Skip to content

fix(telemetry): installation_id is always the machine id (per-install id → install_id)#1159

Draft
deepme987 wants to merge 1 commit into
mainfrom
deepme987/desktop/device-id-join-key
Draft

fix(telemetry): installation_id is always the machine id (per-install id → install_id)#1159
deepme987 wants to merge 1 commit into
mainfrom
deepme987/desktop/device-id-join-key

Conversation

@deepme987

Copy link
Copy Markdown
Collaborator

Quick Read

installation_id is documented as the machine key (SHA-256(machine_id+salt), one per machine). But ~24 main-process emit sites pass the per-install record id (inst-<ts>, from installations.json) as installation_id, which overrides the machine-id default. So the field means machine on renderer/onboarding events and install-record on main events — they share no value, so the install → boot → canvas funnel can't join on it even after v1.0.24 stamped the machine id everywhere.

This fixes it in one place: capture() now guarantees installation_id is always the machine id, and redirects any per-call install id to a secondary install_id.

The bug (audited)

  • identify() correctly sets defaultEventProperties.installation_id = machine_id.
  • ~24 main emit sites then pass installation_id: installationId where installationId is the inst-<ts> record id (boot_started/completed/failed, canvas_rendered, install.completed, install.phase, execution.*, snapshot.*, op.result, …). Per-call props win the merge → the machine default is overwritten.
  • Result, confirmed in prod data: renderer events carry a 64-char SHA-256; main events carry inst-<ts>; cross-boundary overlap is 0 (method.selected → install.completed = 0/239). The funnel reads ~100% false drop at the install boundary.

The fix

In capture(), before merging defaults:

const callInstallId = properties.installation_id
if (callInstallId != null && callInstallId !== defaultEventProperties.installation_id) {
  const { installation_id: _movedToInstallId, ...rest } = properties
  perCall = { ...rest, install_id: callInstallId }
}
  • installation_id is always the machine id (the documented invariant, now enforced).
  • A per-call install id is preserved as install_id — available for the minority of per-install analyses (multi-install machines, instance.switched), just not overloaded onto the canonical key.
  • An explicit machine id (== default) is left as-is; no install_id introduced.

Why central, not 24 call sites

The bug exists because call sites can override installation_id. Fixing 24 sites is large, error-prone, and a 25th site re-breaks it. Enforcing the invariant in the single capture path makes it complete and self-protecting. Header identity-model doc updated to match.

Scope / what to know

  • What changes: every main event's installation_id flips from inst-<ts> to the machine hash; the install id rides along as install_id.
  • boot_id (per-launch, feat(telemetry): boot_completed + boot_id for a per-attempt boot-success rate #1156) and user_id (per-person, login) are untouched — different scopes, different purposes.
  • Dashboards: funnels keyed on installation_id become true per-machine (e.g. "weekly active machines" stops counting installs, drops the multi-install over-count). Any query that genuinely wanted per-install switches to install_id. Most analyses want per-machine, so this is the intended direction.
  • Rollout-gated, like the other v1.0.x telemetry: takes effect on the build carrying it; older builds keep the split.

Testing

telemetry.test.ts: a per-install id under installation_id is redirected to install_id while installation_id stays the machine id; a renderer event (no install id) and an explicit-machine-id event are left untouched. 76 telemetry tests green; eslint + typecheck clean on the changed file.

Related

Completes the desktop identity-stitch line (#1147 stamped the machine id as a default; #1156 added boot_id). This is the last blocker on a clean, single-key install → boot → canvas funnel.

… id -> install_id

installation_id is documented as the machine key (SHA-256(machine_id+salt)),
but ~24 main-process emit sites pass the per-install record id (inst-<ts>)
under installation_id, which overrides the machine-id default. So
installation_id means the MACHINE on renderer/onboarding events and the
install-RECORD on main events (boot/execution/canvas/install.completed), and
the two cannot join -- the install->boot->canvas funnel is structurally
un-stitchable on installation_id even after the v1.0.24 default landed.

Enforce the invariant centrally in capture(): installation_id is ALWAYS the
machine id; any per-call installation_id is redirected to a secondary
install_id (preserved for the minority of per-install analyses, e.g.
multi-install machines). One change covers all current and future call sites
and stops the override from recurring. boot_id (per-launch) and user_id
(per-person) are untouched -- different scopes.
@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: bb8f5d46-4239-4160-8123-00e6bc89c581

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch deepme987/desktop/device-id-join-key
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch deepme987/desktop/device-id-join-key

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

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