Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion platform/lib/queries/org-summary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1160,6 +1160,26 @@ export function computeHyperEngineers(
}
>();

// Learn email -> github wherever a name-based lookup resolves one, before
// grouping. This is the same "known mapping learned elsewhere" trick as
// the nameToGithub/userMap checks below, just keyed by raw commit email
// instead of name: a person can show up "identified" in one repo (their
// email there matched a name we could resolve) and "unidentified" in
// another (same actual email, but paired with a name variant that never
// resolved) — this bridges the second occurrence to the first without
// requiring push-time API resolution to have succeeded for every repo.
const emailToGithub = new Map<string, string>();
for (const [, p] of payloads) {
if (!p.author_velocity?.authors) continue;
for (const a of p.author_velocity.authors) {
if (!isHyperEngineer(a) || !a.email) continue;
const nameLower = a.name.toLowerCase();
const github =
nameToGithub.get(nameLower) ?? userMap.get(nameLower)?.github;
if (github) emailToGithub.set(a.email.toLowerCase(), github);
}
}

for (const [repoId, p] of payloads) {
if (!p.author_velocity?.authors) continue;
const av = p.author_velocity;
Expand All @@ -1168,15 +1188,20 @@ export function computeHyperEngineers(
if (!isHyperEngineer(a)) continue;

const nameLower = a.name.toLowerCase();
const emailLower = a.email?.toLowerCase();
// nameToGithub alone misses a real case: some people's local git
// config uses their GitHub handle itself as the commit author name
// (e.g. author name "lucastribioliclickbus" instead of "Lucas
// Tribioli") in repos where the push-time API resolution didn't tie
// that name's email to a login. userMap is *also* keyed by github
// username when known, so checking it here — not just at display
// time — catches that case during grouping instead of after.
// emailToGithub is the last resort: the same raw commit email tied to
// a resolved identity somewhere else entirely, regardless of name.
const github =
nameToGithub.get(nameLower) ?? userMap.get(nameLower)?.github;
nameToGithub.get(nameLower) ??
userMap.get(nameLower)?.github ??
(emailLower ? emailToGithub.get(emailLower) : undefined);
const key = github ?? normalizeEmailIdentity(a.email) ?? nameLower;

const existing = authors.get(key) ?? {
Expand Down
38 changes: 38 additions & 0 deletions platform/tests/org-summary.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,44 @@ describe("computeHyperEngineers — dedupes the same person across name variants
expect(result[0].repos).toBe(1);
});

it("merges an 'unidentified' entry into an 'identified' one via a shared raw email, when neither name nor userMap resolves it directly", () => {
// Same person, two repos: repo-a's commit name resolves to a github via
// nameToGithub (this repo would render "identified"). repo-b uses a
// completely different name string (e.g. a nickname) with the SAME raw
// email — neither nameToGithub nor userMap has an entry for that name,
// so without the email bridge this would render as a second,
// "unidentified" card for the same real person.
const payloads = new Map<string, ReportMetrics>([
[
"repo-a",
payload({
author_velocity: {
authors: [
hyperAuthor({ name: "Carla Souza", email: "carla@corp.com" }),
],
},
}),
],
[
"repo-b",
payload({
author_velocity: {
authors: [
hyperAuthor({ name: "carlinha", email: "carla@corp.com" }),
],
},
}),
],
]);
const nameToGithub = new Map([["carla souza", "carla-gh"]]);

const result = computeHyperEngineers(payloads, new Map(), nameToGithub);

expect(result).toHaveLength(1);
expect(result[0].github).toBe("carla-gh");
expect(result[0].repos).toBe(2);
});

it("still includes an engineer with no resolved GitHub username, with github left undefined", () => {
// computeHyperEngineers doesn't filter these out — the "identified" vs
// "unidentified" split is a display concern, done in HyperEngineers.tsx.
Expand Down
Loading