fix(ai): require member identity within a shared org for report routing, overlays, and coverage
Codex review round 7 on e90a72bdd flagged that broker usage-report matching, header-overlay keying, and omp-usage coverage all treated a matching organization as a sufficient match. Two Team members share the org id while drawing on per-user pools, so the first same-org report (or a lone sibling report) was handed to the wrong member. The org is now a gate: within the same-org subset the member's own base identity (account/email/project) must still match, with org-only entities (no base identifiers) matching on the org alone when unambiguous. The overlay merger (findMatchingReportIndex) had the identical same-org flaw and receives the symmetric fix. Org-presence-mismatch semantics are unchanged: org-scoped vs org-less stays fall-through/unreported, and both-org-less keeps the legacy base-identity fallback.
This commit is contained in:
@@ -163,6 +163,34 @@ describe("collectUnreportedAccounts", () => {
|
||||
const orglessAccounts: UsageAccountIdentity[] = [{ provider: "anthropic", type: "oauth", email: shared }];
|
||||
expect(collectUnreportedAccounts([orglessReport], orglessAccounts)).toEqual([]);
|
||||
});
|
||||
|
||||
it("gates same-org coverage on the member's own identity", () => {
|
||||
const org = "org-team";
|
||||
const alice: UsageAccountIdentity = {
|
||||
provider: "anthropic",
|
||||
type: "oauth",
|
||||
email: "alice@example.test",
|
||||
accountId: "account-alice",
|
||||
orgId: org,
|
||||
};
|
||||
const bob: UsageAccountIdentity = {
|
||||
provider: "anthropic",
|
||||
type: "oauth",
|
||||
email: "bob@example.test",
|
||||
accountId: "account-bob",
|
||||
orgId: org,
|
||||
};
|
||||
const orgOnly: UsageAccountIdentity = { provider: "anthropic", type: "oauth", orgId: org };
|
||||
const aliceReport = {
|
||||
...makeReport("anthropic", alice.email!, []),
|
||||
metadata: { email: alice.email, accountId: alice.accountId, orgId: org },
|
||||
};
|
||||
// Alice reported, Bob not: the sibling's same-org report must not count
|
||||
// as Bob's coverage — two Team members share the org id but draw on
|
||||
// per-user pools. An org-only account (no base identifiers to gate on)
|
||||
// stays covered by any same-org report.
|
||||
expect(collectUnreportedAccounts([aliceReport], [alice, bob, orgOnly])).toEqual([bob]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("formatUsageBreakdown", () => {
|
||||
|
||||
Reference in New Issue
Block a user