One ChatGPT email can hold several workspaces (a personal Plus/Pro plan
plus Team/Enterprise seats), each with its own workspace-scoped OAuth
token and independent limit pools. Codex credentials were deduped by
bare email, so logging into the second workspace silently replaced the
first, and usage reports from the two pools merged into one row.
- capture the workspace (chatgpt_account_id) as orgId at login, with
the plan type as its display label; token refreshes never rewrite it
- key openai-codex credential identity as email + org via the existing
org-scoped machinery; legacy email-keyed rows are claimed in place by
the first workspace-scoped login, and workspace-less credentials
never clobber workspace-scoped rows
- exclude the org-mirroring account base from same-org row claims so
two members of one workspace (shared chatgpt_account_id) keep
separate rows
- partition usage-report dedupe by workspace and require every shared
identity dimension to agree when reconciling codex usage blocks
Fixes the openai-codex half of #2966 (anthropic half shipped in #5170);
also covers the #633 scenario.