feat: report reflex subpackage versions in telemetry#6610
Conversation
Now that reflex is split across many independently-versioned packages, the single reflex_version field no longer describes the full install. Add a reflex_package_version telemetry property mapping each installed reflex-* subpackage (reflex-base, the reflex-components-* family, reflex-hosting-cli, etc.) to its version, discovered dynamically from installed distribution metadata. https://claude.ai/code/session_016xJwZ48c1napKaCCkyARtC
Greptile SummaryThis PR adds a
Confidence Score: 5/5Safe to merge. The change is additive — it appends a new field to the telemetry payload without touching any existing fields or logic. The new function is well-guarded (None-name check, canonicalization, de-duplication) and only runs once thanks to the existing @once_unless_none cache. Tests cover both a real-environment smoke check and a thorough mocked scenario. No existing behavior is altered. No files require special attention. Important Files Changed
Reviews (1): Last reviewed commit: "docs: add news fragment for reflex_packa..." | Re-trigger Greptile |
masenf
left a comment
There was a problem hiding this comment.
you can't just report any package version that is prefixed with reflex-, those could be third party packages and that's invasive... only report on subpackages that we distribute from this repository
Derive the reported subpackages from reflex's own declared dependencies (importlib.metadata.requires) instead of scanning every installed reflex-* distribution. This reports only the subpackages distributed from this repository (reflex-base, the reflex-components-* family, reflex-hosting-cli) and never an unrelated third-party reflex-* package the user happens to have installed. https://claude.ai/code/session_016xJwZ48c1napKaCCkyARtC
The "Update branch" merge of main combined `import importlib.metadata` (#6610) with this branch's `import uuid` but left a blank line splitting the stdlib import group, which ruff's isort rejected in CI pre-commit. Remove it. https://claude.ai/code/session_0162Wc1GmkskbgCRs7fjg9Cy
…6611) * fix(telemetry): send distinct ids as UUID strings to preserve uniqueness distinct_id and distinct_app_id were reported as 128-bit integers. PostHog coerces large JSON numbers to float64, discarding all but ~16 significant digits, so two distinct users or apps could collapse onto the same truncated value and have their events incorrectly correlated. Encode both identifiers as canonical UUID hex strings before sending. A UUID holds the same 128 bits, so str(UUID(int=existing_id)) is a lossless re-encoding: the value is unchanged, only its wire form differs. Existing installs derive their UUID from the stored integer (never regenerated), so post-migration events stay linkable to their pre-migration history. New installs now generate a real uuid4, persisted as its integer form to keep the installation_id and reflex.json files readable by older Reflex versions. https://claude.ai/code/session_0162Wc1GmkskbgCRs7fjg9Cy * feat(telemetry): alias legacy numeric distinct_id to its UUID in PostHog Re-encoding distinct_id as a UUID string makes PostHog treat the new UUID identity and the old (float-truncated) numeric identity as separate persons, breaking continuity with pre-migration events. On the first telemetry send of a process, emit a one-time PostHog $create_alias event linking the new UUID distinct_id to the legacy numeric id. The legacy id is sent as a JSON number so PostHog coerces it to the same lossy float as the historic events, merging the two persons. The attempt is best-effort and runs exactly once: a flag in reflex.json records that it ran (set even when the alias does not match, since the lossy legacy id may not), and it is written with a merging update so it survives Reflex downgrades and upgrades. Brand-new UUID-native projects preset the flag during init since they have no legacy numeric telemetry to alias. https://claude.ai/code/session_0162Wc1GmkskbgCRs7fjg9Cy * refactor(telemetry): store distinct_id alias marker per-machine, not per-app The alias links the per-machine installation distinct_id, so gating it on a per-app reflex.json flag was the wrong scope. Replace that flag with a marker file next to the installation id in the Reflex dir, recording that the install uses v0.9.5 UUID distinct_id semantics. - New installs write the marker when the id is first generated (ensure_reflex_installation_id), so they never attempt a pointless alias. - Legacy installs (id present, marker absent) attempt the one-time $create_alias, then write the marker regardless of outcome so it is not retried on every run. The marker lives in the per-user Reflex dir, which no Reflex version clears, so it persists across downgrades and upgrades. reflex.json is no longer touched for telemetry. https://claude.ai/code/session_0162Wc1GmkskbgCRs7fjg9Cy * chore: add changelog news fragment for telemetry UUID distinct_id PR https://claude.ai/code/session_0162Wc1GmkskbgCRs7fjg9Cy * style: drop stray blank line in test_telemetry imports after main merge The "Update branch" merge of main combined `import importlib.metadata` (#6610) with this branch's `import uuid` but left a blank line splitting the stdlib import group, which ruff's isort rejected in CI pre-commit. Remove it. https://claude.ai/code/session_0162Wc1GmkskbgCRs7fjg9Cy --------- Co-authored-by: Claude <noreply@anthropic.com>
What
Adds a
reflex_package_versionfield to anonymous telemetry: a dict mapping each first-party Reflex subpackage to its installed version, e.g.{ "reflex-base": "0.9.4", "reflex-components-core": "0.9.0", "reflex-components-radix": "0.9.2", "reflex-hosting-cli": "0.1.66" }Why
Now that Reflex is split across many independently-versioned workspace packages (
reflex-base, thereflex-components-*family,reflex-hosting-cli), the singlereflex_versionfield no longer describes the full install. The existingreflex_versionandreflex_enterprise_versionfields are unchanged.How
get_reflex_package_versions()derives the reported set from thereflexdistribution's own declared dependencies (importlib.metadata.requires("reflex")), then looks up each one's installed version:reflex's ownreflex-*dependencies, so an unrelated third-partyreflex-*package a user happens to have installed is never reported.reflexpackage stays inreflex_version;reflex-enterprise(separate repo) stays inreflex_enterprise_versionand is not duplicated here.reflex's metadata is unavailable, the field is an empty dict.Testing
test_get_reflex_package_versions_real_environment— asserts the first-party subpackages are discovered with string versions.test_get_reflex_package_versions_reports_only_first_party— asserts third-partyreflex-*packages and non-reflex deps are excluded, and uninstalled declared deps are skipped.test_get_reflex_package_versions_handles_missing_reflex_metadata— covers the missing-metadata fallback.All
tests/units/test_telemetry.pypass;ruffandpyrightare clean.https://claude.ai/code/session_016xJwZ48c1napKaCCkyARtC
Generated by Claude Code