Skip to content

rankPerformers() can return overlapping top and bottom lists when the project count is small relative to n #431

Description

@abayomicornelius

Where: src/lib/analytics.ts, rankPerformers() (lines ~100-111),
used by GET /v1/dashboard/performers (default n=5, or
?limit= up to 50 per routes/dashboard.ts).

What's wrong:

export function rankPerformers(scores: ProjectScore[], n = 5) {
  const sorted = [...mapped].sort((a, b) => b.combined_score - a.combined_score);
  const top = sorted.slice(0, n);
  const bottom = sorted.slice(-n).reverse();
  return { top, bottom };
}

top and bottom are sliced independently from opposite ends of the same
sorted array with no check that n and n don't overlap. Whenever
scores.length < 2 * n, the two slices share entries — e.g. with 8 total
projects and the default n = 5: top covers ranks 1–5, bottom
(reversed) covers ranks 4–8 — ranks 4 and 5 appear in both lists
simultaneously. This triggers for any deployment with 9 or fewer total
projects at the default n=5 (a realistic count for early-stage/staging/demo
data, exactly when a "top and bottom performers" dashboard widget is most
likely to be looked at closely), and for larger project counts whenever a
caller requests a limit close to or above half the total.

Impact: GET /v1/dashboard/performers can report the same project as
both a top performer and a bottom performer in one response — confusing
for any dashboard rendering "best" and "worst" project lists side by side.

Suggested fix: cap n at Math.floor(scores.length / 2) before
slicing (or explicitly exclude whatever top already selected from the
bottom slice) so the two lists never share a project when there aren't
enough distinct projects to fill both non-overlapping.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bug-backlogKnown bugs and edge caseslowCosmetic, minor improvement, code quality, documentation

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions