fix(cli): Make org identity canonical and forward-compatible#64
Merged
Conversation
Treat the Taskless org UUID as the one canonical identity and prepare for the server namespacing its identifiers. - Drop installationId from the WhoamiOrg type and rule meta --json output; the CLI never used it and it should not round-trip through us. - Make WhoamiOrg.orgId optional and add githubOrgId?: number so consumers read githubOrgId ?? orgId across the server's rename; it is a convenience id only. - decodeOrgId now prefers the token's canonical id claim over the legacy numeric orgId, tolerating string|number on the legacy path; PostHog groups on that canonical id, falling back to the numeric claim until id claims are minted. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR makes the CLI treat the Taskless organization UUID as the canonical org identity and prepares the client for upcoming server-side org identity cleanup (while aiming to keep current behavior unchanged until tokens start carrying the new claim).
Changes:
- Update JWT org-subject decoding to prefer a canonical
idclaim (with legacyorgIdfallback) and update telemetry grouping to use that canonical subject. - Adjust the
WhoamiOrgtype to dropinstallationIdand to be forward-compatible with a server rename fromorgId→githubOrgId. - Remove
installationIdfromtaskless rule meta --jsonoutput schema and update/add tests plus a changeset entry.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/cli/test/telemetry.test.ts | Adds coverage ensuring telemetry groups by canonical id when present. |
| packages/cli/test/org.test.ts | Updates whoami org fixtures to align with the new WhoamiOrg shape. |
| packages/cli/test/jwt.test.ts | Expands decodeOrgId tests for canonical-claim precedence and new accepted types. |
| packages/cli/src/telemetry.ts | Switches PostHog org grouping from legacy orgId to canonical org subject. |
| packages/cli/src/schemas/rules-meta.ts | Drops installationId from the meta JSON output schema. |
| packages/cli/src/auth/org.ts | Refines WhoamiOrg typing for forward-compat (githubOrgId ?? orgId) and removes installationId. |
| packages/cli/src/auth/jwt.ts | Changes decodeOrgId to prefer the canonical id claim and return `string |
| .changeset/org-identity-forward-compat.md | Documents the forward-compat identity changes as a patch release. |
Address review: decodeOrgId now validates the canonical id claim and the legacy orgId claim independently — a valid id wins, an invalid (empty) id still lets a valid orgId through, and a non-numeric orgId is rejected rather than accepted as an identity (a numeric string is coerced). When neither a matched org nor a token claim resolves, the canonical id falls back to the nil UUID so the org subject and PostHog group are always a known, stable value. resolveOrgSubject is therefore total; resolveIdentity no longer throws on a token missing org info and instead sends the nil-UUID subject. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Treats the Taskless organization UUID as the single canonical identity and makes the CLI forward-compatible with the server's coming identity cleanup — without changing any observable behavior today.
What & why
The whoami/token payload currently carries three org identifiers with no clear hierarchy: a Taskless UUID (
id), a numeric GitHub org id (orgId), and a GitHub AppinstallationId. This PR establishesidas the one identity we act on and contains the other two.installationId. Dropped from theWhoamiOrgtype and from thetaskless rule meta --jsonoutput. It was already.optional()and documented as absent for public repos, so no consumer could rely on its presence. The CLI never used it and it shouldn't round-trip through us.WhoamiOrg.orgIdis now optional and a newgithubOrgId?: numberis added; consumers readgithubOrgId ?? orgIdand keep working across the server's rename. It's a convenience id, never an identity.decodeOrgIdprefers the token'sidclaim over the legacy numericorgId, and PostHog now groups organizations on that canonical id.number | stringon the legacy path only. The canonicalWhoamiOrg.idstays a UUIDstring;decodeOrgIdaccepts either type since we can't promise what a legacy claim carries.No behavior change today
Current tokens don't carry an
idclaim, sodecodeOrgIdfalls back to the numericorgIdand PostHog grouping is byte-for-byte unchanged until the server starts mintingid. The new path is dormant plumbing.Assumption to confirm
The canonical JWT claim is assumed to be named
id(matching the whoami field). It's safe either way — dormant until such a claim exists — but if the server will name it differently, that's a one-word change indecodeOrgId.Versioning
Marked patch (0.10.2): no observable change now, and the only external surface touched is an already-optional
--jsonfield. Bump to minor if you'd rather flag the field removal more loudly.367 tests pass; typecheck, eslint, prettier clean.
🤖 Generated with Claude Code