Skip to content

Repository Check — add Fairness Signals card to surface per-miner merge-speed bias #1271

Description

@Khaostica

Summary

Adds a new Fairness Signals card to the bottom of the Repo Check tab on every repository details page (RepositoryCheckTab). The card flags miners whose pull requests merge noticeably faster than the rest of the repo — a leading indicator of maintainer favoritism, sockpuppet accounts, or self-dealing — before a miner commits time to contributing.

The card has three coordinated panels:

  1. Fastest median time-to-merge (TTM) — a ranked top-5 leaderboard of miners with the shortest median TTM in this repo. Each row shows the miner, their median TTM, merged-PR count, and a percent delta vs the repo median (e.g. "91% faster than repo median").
  2. vs Repo baseline chart — a horizontal ECharts bar chart of the same top 5, with a dashed reference line at the repo median TTM. When the repo median is more than ~1.5× the slowest top-5 bar (skewed distributions like entrius/gittensor), the line is suppressed and the value is surfaced as a caption below the chart ("Repo Median: 6d 12h") so the bars stay readable.
  3. Detail table — one row per qualifying miner with Miner · Merged PRs · Median TTM · Reject Rate. Miners whose median TTM is below the repo median are highlighted red across the whole row (name, bar, value label, and y-axis label in the chart), making the "this miner is being fast-tracked" pattern visible at a glance.

Miner names link to /miners/details?githubId={id}, matching the existing pattern from RepositoryMinersTab.

Motivation

A repo's emission share is finite. If maintainers are consistently fast-tracking PRs from a small set of favored accounts while letting other miners' PRs sit for days, new miners are effectively competing for whatever scoring slack remains — without any way to know that before they start. Today the Repo Check tab tells contributors whether the repo has a CONTRIBUTING.md, but says nothing about whether the repo's PR pipeline is fair.

Surfacing this pattern lets miners:

  • Spot repos with an obvious favored author before investing time in PRs that will languish
  • Compare merge speeds across repos when deciding where to allocate effort
  • Self-audit — a maintainer running the tool on their own repo sees the same picture validators see, and can address bias before it costs them credibility

The framing in the card is intentionally signals to investigate, not verdicts — colored cells are outliers vs the repo's own distribution, not proof of self-dealing. This matches the existing language around collateralScore, credibilityMultiplier, and the TrustBadge component.

Scope

Surface Change
RepositoryCheckTab New FairnessSignalsCard rendered at the bottom of the tab
Data sources useRepositoryMiners (canonical PR counts), useAllPrs (TTM timestamps), useRepositoryMaintainers (filter)
Counted miners totalMergedPrs ≥ 1, maintainers excluded by login (case-insensitive)
Median TTM median(mergedAt − prCreatedAt) per author, hours
Repo baseline Median of all non-maintainer miners' TTMs in this repo
Highlight rule Row + chart turn red when miner's median TTM < repo median
Eligibility Green dot next to login, tooltip shows credibility
Empty states "No miner PR activity recorded" / "No merged PRs yet — no TTM to rank"
Miner name link /miners/details?githubId={githubId} (consistent with RepositoryMinersTab)

Out of scope: top-merger %, self-merge count, takeover/duplicate-PR detection (each requires per-PR detail fetches and per-PR GitHub /pulls/{n}/files calls; deferred to a follow-up issue once the v1 design is validated). No change to existing Health Score, Activity, Issue Analysis, or Community Standards sections of RepositoryCheckTab.

Technical notes

  • New component: src/components/repositories/FairnessSignalsCard.tsx, wired into src/components/repositories/RepositoryCheckTab.tsx via a single <FairnessSignalsCard repositoryFullName={repositoryFullName} /> at the end of the Grid.
  • Case-insensitive repo match for pr.repository vs repositoryFullName — backend stores mkdev11/gittensor-hub while frontend routes use canonical MkDev11/gittensor-hub. Exact-match comparison silently drops every PR; both sides lowercased before comparison.
  • Authoritative counts come from m.totalMergedPrs / m.totalClosedPrs on the RepositoryMiner row, not inferred from filtering /prs. The /prs endpoint excludes some historical closed PRs that the backend has already counted, so deriving counts from it diverges from the Miners tab — e.g. Khaostica on touchpilot/touchpilot (3 merged + 1 closed in the miner row, but 3 merged + 1 open in /prs).
  • TTM is computed from /prs because that's where the per-PR mergedAt / prCreatedAt timestamps live; the miner row only carries aggregates.
  • Maintainer filter: build a Set<string> of useRepositoryMaintainers(repo) logins, lowercased; skip any miner whose githubUsername.toLowerCase() is in the set. Maintainers' PRs also don't feed the repo-baseline median.
  • Median (not mean) for TTM: even-count lists take the average of the two middle values. Mean was tried briefly but discarded because a single legitimate slow PR drags the value up disproportionately.
  • Chart rendering uses the existing echartsAxisTooltipChrome / echartsFontFamily / echartsMutedCartesianAxisColors / echartsTransparentBackground helpers from src/utils/echarts/gittensorChartTheme.ts. Per-bar and per-axis-label coloring uses item-level itemStyle.color / label.color and rich-text {r|name} / {n|name} tokens in axisLabel.rich — ECharts v6 ignores callback functions on those fields.
  • Off-chart median fallback: when repoMedianTtm > maxBarValue * 1.5, clamp xAxis.max to maxBarValue * 1.15, set markLine.data to [], and render a <Typography> caption below the chart reading Repo Median: {formatTtm(repoMedianTtm)}.
  • Style parity: card chrome (border, radius, padding, header icon + subtitle pattern) matches the existing Health Score / Activity & Feasibility / Issue Analysis cards in RepositoryCheckTab.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestfeatureNet-new functionality

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions