Commit Graph
4 Commits
Author SHA1 Message Date
chan1103 45203a1b56 fix(ai): org qualifies — not replaces — base identity in active matching; upgrade org-only rows on identity recovery
Addresses the Codex review round on c3fcb4fa7:

- Active-account matching (/logout preselection, /usage 'in use by this
  session' marker) treated a shared org as sufficient: two Anthropic Team
  seats in one org (same orgId, per-user pools, distinct email/account)
  matched each other's rows and reports. The org is now a gate that
  qualifies the base identity — mismatched org presence or different orgs
  still never match (round-3 semantics unchanged), a shared org falls
  through to the account/email/project checks, and only an org-only
  active identity (no base identifiers recovered) matches on the org
  alone.
- An org-only credential row keyed org:<id> (stored when login recovered
  neither email nor account) was never claimed by a later same-org login
  that does recover the identity, duplicating one subscription across two
  rows. matchesReplacementCredential now upgrades and re-keys such a row
  in place; the upgrade stays one-way — an org-only incoming key still
  only claims rows via exact key equality.

Regression tests: same-org different-member rows/reports stay unmatched
while the member's own row matches; org-only identities match same-org
rows on the org alone; org-only row upgraded in place on identity
recovery with the one-way direction preserved.
2026-07-11 22:49:12 +09:00
chan1103 a47c3c90ec fix(ai): org-decisive active matching on either side; org in status-line cache key and health results
Addresses the second review round (internal re-review + Codex on c38840482):

- Active-account matching (logout preselection, /usage in-use marker) is
  org-decisive when EITHER side carries an org: a legacy bare-email active
  row no longer flags org-scoped siblings via the shared email (reverse of
  the previous fix). Both-org-less keeps the email/account fallback, so
  providers without orgs are unaffected.
- Status-line usage context key includes orgId, so rotating between two
  same-email subscriptions invalidates the cached quota immediately
  instead of showing the previous org's numbers for the cache TTL.
- CredentialHealthResult carries orgId/orgName and auth-gateway check
  labels rows with the org, so a failing row names the subscription.
- getOAuthAccountIdentity preserves org-only identities; the login
  success message renders them.
- ACP /usage account-id fallback labels get the org suffix too.
- Regression tests for both matching directions (marker + logout).
2026-07-11 22:49:12 +09:00
chan1103 bee01bfc4a fix(ai): carry org through OAuth access results; org-scoped active never matches org-less rows
Addresses Codex review on #5170:

- OAuthAccess/OAuthAccessFailure and every resolution site now carry
  orgId/orgName; dry-balance bench keys and labels are org-qualified so
  two same-email subscriptions stay two benchmark targets.
- When the active identity is org-scoped, logout active-marking and the
  /usage in-use marker match ONLY the same org — an org-less legacy row
  or pre-upgrade report can no longer be flagged active via the shared
  email, so the logout preselection cannot land on the wrong row.
- Regression tests: org-scoped active vs sibling org and vs legacy
  bare-email row (logout + in-use marker), org-suffixed logout labels.
2026-07-11 22:49:12 +09:00
can1357 b0d2597715 refactor(coding-agent): share active-account matching across /usage renderers
- Extracted `limitMatchesActiveAccount`/`reportMatchesActiveAccount` into `slash-commands/helpers/active-oauth-account.ts` as the single definition of the report-to-account matching rules, including projectId matching against `limit.scope.projectId`/metadata.
- Dropped the duplicated `ActiveAccountIdentity`/`OAuthAccessResolver` shims, `as unknown` session casts, the dead `getOAuthAccountId` fallback, and the email-vs-scope-accountId comparison from `command-controller.ts` and `usage-report.ts`.
- Replaced the async per-provider `resolveActiveAccountsForReports` map with one synchronous typed `authStorage.getOAuthAccountIdentity()` call per render, gated to the session's current provider.
- Re-exported `OAuthAccountIdentity` from `session/auth-storage.ts` and added `active-oauth-account.test.ts` covering the matching rules.
2026-06-12 04:23:54 +02:00