Skip to content

feat(telemetry): identify signed-in CLI users by their HyperFrames user id, and say signed-in usage is not anonymous - #6703

Merged
jrusso1020 merged 7 commits into
mainfrom
docs/telemetry-signed-in-not-anonymous
Oct 29, 2026
Merged

jrusso1020 merged 7 commits into
mainfrom
docs/telemetry-signed-in-not-anonymous

Conversation

@jrusso1020

@jrusso1020 jrusso1020 commented Oct 29, 2026 •

Copy link
Copy Markdown
Collaborator

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 OIDC sub is 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) and media-use identify by heygenUserId(username), the same algorithm. The id is pinned by test vectors taken from the web app's function.
  • $set adds email (lowercased) and heygen_username to the person. heygen_username is the join column across projects. HeyGen's own project already stores the username as the person property name, and the hyperframes-internal PR adds heygen_username to web and Desktop.
  • Every event while signed in (credentials file holds a user and a credential) is sent with distinct_id = that account id and carries heygen_username as 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.
  • An account with no username falls back to the lowercased email, as before.
  • New: packages/cli/src/auth/telemetryIdentity.ts. media-use/lib/telemetry.mjs has 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 carry heygen_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:
    • the media-use note, render --skill, feedback and events say "anonymous until you sign in".
    • the telemetry section says what sign-in links: an id derived from the username, plus email and username.
  • Skill references for hyperframes-cli and media-use: same correction.
  • CLI first-run notice, media-use notice, and the telemetry, feedback and events help text: same correction.

Nothing else new is collected. The opt-outs are unchanged.

Testing

  • Review fixes (Genesis): telemetry --help no longer lists "any personally identifiable information" as never collected, and media-use meta.md no longer says anonymous. client.test.ts covers signed-in events keyed on the account id with heygen_username, and the install id after sign-out. signedInUser.test.ts covers a user block with no credential. telemetryIdentity.test.ts covers 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 $set email and heygen_username. skills/media-use copy: 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

…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]>
@mintlify

mintlify Bot commented Oct 29, 2026 •

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated
hyperframes 🟢 Ready View Preview Oct 29, 2026, 2:35 AM

💡 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]>
@jrusso1020 jrusso1020 changed the title docs(telemetry): say signed-in usage is linked to your account, not anonymous feat(telemetry): identify signed-in CLI users by their HyperFrames user id, and say signed-in usage is not anonymous Oct 29, 2026
jrusso1020 and others added 3 commits October 29, 2026 01:55
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]>
@github-actions

github-actions Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Edit accuracy: accurate 271 (base branch 271), smooth 137 of those

The gate passes.
Smoothness is reported in the artifact, not gated. A case fails only if it fails 2 of 3 runs.

Quarantined, measured but not gated (0)

Unstable (1)

  • seqplainkeys-none-center-r0-root-z100: tracking 0.06, pressJump 0, drop 0, reload 0, render 0.03, renderKey -, undo false, teleport true / tracking 0.06, pressJump 0, drop 0, reload 0, render 0.03, renderKey -, undo true, teleport true / tracking 0.06, pressJump 0, drop 0, reload 0, render 0.03, renderKey -, undo true, teleport true

@heygengenesis heygengenesis Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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:108 lists "Any personally identifiable information" under WHAT WE DON'T COLLECT in hyperframes telemetry --help, the same help screen this PR edits. Signed-in events now carry email and heygen_username. skills/media-use/references/meta.md:39 still 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/optedOut gates.
  • Signed out, the property is undefined, and JSON.stringify drops it.
  • auth logout (here, and in heygen-cli's ClearOAuthTokens) deletes the file. --keep-api-key keeps user together with api_key, which is correct because that user is still signed in.
  • The mtime cache is re-checked with fstat on every call, and ENOENT clears it.
  • Login error paths clear stale user blocks.
  • 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.

Comment thread packages/cli/src/telemetry/events.ts Resolved
…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]>

@heygengenesis heygengenesis Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Verdict: APPROVE — 4 resolved, 0 open, 0 new · c1f79e53 → caa419c4 (CI green: CI ×2, Windows render, CodeQL).

@jrusso1020
jrusso1020 added this pull request to the merge queue Oct 29, 2026
Merged via the queue into main with commit 1c3fcf4 Oct 29, 2026
118 of 119 checks passed
@jrusso1020
jrusso1020 deleted the docs/telemetry-signed-in-not-anonymous branch October 29, 2026 03:21

This branch was successfully deployed

1 active deployment
staging - docs — caa419c4 Deployed Oct 29, 2026 by mintlify[bot]
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.

2 participants