Repository navigation
feat(telemetry): identify signed-in CLI users by their HyperFrames user id, and say signed-in usage is not anonymous - #6703
Merged
Conversation
…nonymous After hyperframes auth login the CLI sends a PostHog $identify with the account email (username as fallback) and merges the install's earlier anonymous usage; media-use does the same when it finds a signed-in account. Several places still called all telemetry anonymous. Say it is anonymous until you sign in, in the CLI reference (media-use, --skill, feedback, events, telemetry), the hyperframes-cli skill references, and the CLI help and notice strings. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Automations to automatically generate PRs for you. |
…er id The CLI and media-use identified a signed-in install by account email, so CLI usage landed on a different PostHog person than the same account in the HyperFrames web app, which keys on toUUID(username). Identify by that same sha256-derived id instead, and $set email plus heygen_username on the person. heygen_username is the cross-project join column for the Snowflake event table (HeyGen's own project stores it as `name`). An account with no username still falls back to the lowercased email. Notices and docs now say usage is keyed on an id derived from the username with email and username stored on it. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
The Snowflake event sync may not carry PostHog person properties, so a $set alone does not let an event row join across projects. The CLI now adds the signed-in HeyGen username (raw, from ~/.heygen/credentials) to every event and drops it once the credentials hold no user; media-use does the same on each event it sends. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Telemetry now imports it to read the signed-in username. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
CodeQL flagged the stat-then-read as a file system race. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Contributor
Edit accuracy: accurate 271 (base branch 271), smooth 137 of thoseThe gate passes. Quarantined, measured but not gated (0) Unstable (1)
|
Contributor
There was a problem hiding this comment.
Verdict: REQUEST CHANGES · 1 blocker · 1 important · 2 nits · head c1f79e53
- blocker (not in the diff, so no inline anchor): two "anonymous / no PII" claims survive, and they contradict the new "signed-in usage is not anonymous" wording.
packages/cli/src/commands/telemetry.ts:108lists "Any personally identifiable information" under WHAT WE DON'T COLLECT inhyperframes telemetry --help, the same help screen this PR edits. Signed-in events now carry email andheygen_username.skills/media-use/references/meta.md:39still says resolve sends "an anonymous usage event". Both are two-line fixes.
Scope / verified
Audited: all of packages/cli/src in the diff, both media-use telemetry.mjs copies (byte-identical), docs and skill references, and the web app's toUUID/resolveHeygenUser in hyperframes-internal.
Verified OK:
- The username is read only after the
shouldTrack/optedOutgates. - Signed out, the property is
undefined, andJSON.stringifydrops it. auth logout(here, and in heygen-cli'sClearOAuthTokens) deletes the file.--keep-api-keykeepsusertogether withapi_key, which is correct because that user is still signed in.- The mtime cache is re-checked with
fstaton every call, and ENOENT clears it. - Login error paths clear stale
userblocks. - The CodeQL TOCTOU alert is fixed by the fd-based read.
- Local runs: 32 vitest and 15 node tests pass. All Actions runs at this head are green.
Trusting: that HeyGen's /v3/users/me username equals the OIDC username/sub the web app hashes.
…nymity copy Genesis review on #6703: - telemetry --help listed 'Any personally identifiable information' as never collected, and media-use's meta.md still said anonymous. - Installs already identified by email under an older CLI never merge into the new person, so send signed-in events with distinct_id = the account id (back to the install id after logout), in the CLI and in media-use, and stop claiming earlier usage always merges. - A user block with no credential no longer counts as signed in. - A UUID-shaped username passes through unhashed, as on the web. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
7 of 8 tasks
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Why: so one person can be joined across HeyGen's PostHog projects (HyperFrames, HyperFrames Desktop, HeyGen) in the Snowflake master event table, and so the docs stop calling signed-in usage anonymous.
Identity (CLI + media-use). A signed-in install used to be identified by its account email. The HyperFrames web app keys its users and PostHog persons on
toUUID(username), a sha256-derived UUID (demo-next/src/lib/auth/derive-user-id.ts; HeyGen's OIDCsubis the username). Desktop uses the same id. So the same account showed up as two people in the HyperFrames project. Now:hyperframes auth login(all three paths) andmedia-useidentify byheygenUserId(username), the same algorithm. The id is pinned by test vectors taken from the web app's function.$setaddsemail(lowercased) andheygen_usernameto the person.heygen_usernameis the join column across projects. HeyGen's own project already stores the username as the person propertyname, and the hyperframes-internal PR addsheygen_usernameto web and Desktop.heygen_usernameas an event property, because the Snowflake event sync may not include person properties. After logout, events go back to the install's anonymous id. media-use does the same. A UUID-shaped username passes through unhashed, matching the web app.packages/cli/src/auth/telemetryIdentity.ts.media-use/lib/telemetry.mjshas the same function, and its two copies stay byte-identical.Older installs: PostHog won't merge two people who are both already identified unless you use
$merge_dangerously, which this PR doesn't use. If an older CLI already linked an install to an email-keyed person, that person keeps the install's earlier history. Every signed-in event from now on lands on the new account-id person, though, because those events are now sent under the account id. Both people carryheygen_username, so the Snowflake join still works. The docs say this rather than claiming earlier usage always merges.Docs: signed-in usage is not anonymous.
docs/packages/cli.mdx:render --skill,feedbackandeventssay "anonymous until you sign in".telemetry,feedbackandeventshelp text: same correction.Nothing else new is collected. The opt-outs are unchanged.
Testing
Review fixes (Genesis):
telemetry --helpno longer lists "any personally identifiable information" as never collected, and media-usemeta.mdno longer says anonymous.client.test.tscovers signed-in events keyed on the account id withheygen_username, and the install id after sign-out.signedInUser.test.tscovers a user block with no credential.telemetryIdentity.test.tscovers UUID passthrough.telemetryIdentity.test.ts(new): web-app parity vectors, key and traits, the email fallback, and the empty case. 5 pass.login.test.ts(31 pass),events.test.ts(81 pass).media-use/lib/telemetry.test.mjs(15 pass): the identify distinct_id is the parity vector, with$setemail andheygen_username.skills/media-usecopy: 5 pass.check-media-use-copy-parity: pass.check-skill-mirror,lint-skills, oxlint, format, typecheck and fallow all pass in the pre-commit hook.Not exercised
A live PostHog round trip. I didn't confirm that a real sign-in lands on the same person as the web app for one account.
🤖 Generated with Claude Code