OSS Risk Radar

Data & features

The 43 signals behind a score

Every signal, grouped by what it measures, with an exact definition and the reason it is part of the model. Search by name, meaning, or reason. These identifiers are the same ones used inside the analysis panel.

Commit activityHow much and how steadily code is being written.
Commits 30dcommits_30dLast 30 days

Number of human commits in the 30 days before t.

Why: Short-term development pulse; captures whether the project is moving right now.

Commits 90dcommits_90dLast 90 days

Number of human commits in the 90 days before t.

Why: Quarter-scale activity level that is less noisy than the 30-day count.

Commits 365dcommits_365dLast 365 days

Number of human commits in the 365 days before t.

Why: Annual development volume; also the baseline against which the year-over-year drop is measured.

Active commit monthsactive_commit_months_365dLast 365 days

Count of distinct calendar months (0–12) in the last year that contain at least one human commit.

Why: Separates steady maintenance from a single burst: 300 commits in one month is a weaker health signal than the same work spread across ten months.

Days since commitdays_since_last_commitAt t

Days between t and the most recent human commit.

Why: Direct staleness signal; a long silence is one of the strongest indicators of impending inactivity.

Contributor activity and concentrationWho is contributing, and how exposed the project is to a single maintainer.
Contributors 90dcontributors_90dLast 90 days

Distinct human contributors in the last 90 days.

Why: Breadth of recent participation; a proxy for the size of the active team.

Contributors 365dcontributors_365dLast 365 days

Distinct human contributors in the last 365 days.

Why: Annual contributor base; the reference for the contributor drop.

New contributorsnew_contributors_365dLast 365 days

Contributors active in the last year who never committed before the window started.

Why: Measures inflow of fresh maintainers; a project with no newcomers is more exposed to attrition.

Top contributor sharetop1_contributor_commit_share_365dLast 365 days

Share (0–1) of the last year's commits made by the single most active contributor.

Why: Key-person dependency: a high share means the project is fragile if that one person leaves.

Top 2 contributor sharetop2_contributor_commit_share_365dLast 365 days

Combined commit share of the two most active contributors in the last year.

Why: Detects a very small core team even when no single person dominates.

Contributor concentration indexcontributor_concentration_indexLast 365 days

Herfindahl index: sum of squared per-contributor commit shares over the last year.

Why: A single scalar for how concentrated contributions are (1.0 = one person, near 0 = evenly spread).

Maintainer concentrationmaintainer_concentration_flagLast 365 days

1 if the top contributor share ≥ 0.7 or the top-two share ≥ 0.85, else 0.

Why: Binary bus-factor alarm for the clearly single-maintainer case.

Issue activity and backlogWhether maintainers keep pace with incoming issues.
Issues opened 90dopened_issues_90dLast 90 days

Issues created in the last 90 days.

Why: Inbound user demand and engagement with the project.

Issues closed 90dclosed_issues_90dLast 90 days

Issues closed in the last 90 days.

Why: Maintainer throughput on the issue tracker.

Issue closure ratioissue_closure_ratio_90dLast 90 days

Closed divided by opened issues over the last 90 days.

Why: Whether maintainers keep pace with inflow, expressed relatively so it is comparable across project sizes.

Backlog growthissue_backlog_growth_90dLast 90 days

Relative change in the open-issue count between t−90 days and t.

Why: A backlog that is trending upward signals that maintainers are losing control; size-normalized.

Stale open issuesstale_open_issues_count_at_obsAt t

Issues opened before t−90 days that are still open at t.

Why: Long-unaddressed items indicate neglect of the tracker.

Pull-request activityWhether outside contributions are still being reviewed and merged.
PRs opened 90dopened_prs_90dLast 90 days

Pull requests created in the last 90 days.

Why: Contribution inflow from outside the core team.

PRs merged 90dmerged_prs_90dLast 90 days

Pull requests merged in the last 90 days.

Why: Direct evidence that maintainers are still integrating outside work.

PRs closed unmergedclosed_unmerged_prs_90dLast 90 days

Pull requests closed without merging in the last 90 days.

Why: A high count relative to merges can signal rejection or disengagement from contributions.

PR merge ratiopr_merge_ratio_90dLast 90 days

Merged divided by opened pull requests over the last 90 days.

Why: Responsiveness to contributors, expressed relatively.

Stale open PRsstale_open_prs_count_at_obsAt t

Pull requests opened before t−90 days that are still open at t.

Why: Ignored contributions discourage further contribution and indicate maintainer absence.

Release activityWhether usable versions still reach users.
Releases 365dreleases_365dLast 365 days

GitHub releases published in the last 365 days.

Why: Shipping cadence: whether usable versions still reach users.

Days since releasedays_since_last_releaseAt t

Days since the most recent release or package version.

Why: Release staleness; complements commit staleness for projects that ship rarely.

Versions publishedversions_published_365dLast 365 days

Package-registry versions published in the last 365 days.

Why: Package-level shipping, which can differ from repository releases.

Age and popularity proxiesMaturity and reach, which shape the baseline risk.
Package agepackage_age_daysAt t

Days from the first published package version to t.

Why: Maturity context: young and long-established packages have different baseline inactivity risk.

Repository agerepo_age_daysAt t

Days from repository creation to t.

Why: Normalizes gaps and cadence against how long the project has existed.

Stars at observationstars_total_at_obsAt t

Cumulative stars observed up to t (a lower-bound proxy reconstructed from archive events).

Why: Popularity and visibility; more attention tends to correlate with continued maintenance.

Forks at observationforks_total_at_obsAt t

Cumulative forks observed up to t.

Why: Reuse and derivative activity around the project.

Dependency countdependency_count_at_obsAt t

Declared dependency count of the resolved package version at t.

Why: Proxy for maintenance burden and integration complexity.

Popularity tierpopularity_tier_at_obsAt t

Low / medium / high tier (0/1/2) derived from star and fork thresholds.

Why: Coarse popularity bucket, because inactivity dynamics differ between obscure and widely used projects.

Diagnostic and binary flagsSimple yes/no signals and diagnostic metadata.
Archived at observationrepo_archived_at_obsAt t

1 if the repository is archived by t, else 0.

Why: Retained as diagnostic metadata only; already-archived rows are excluded from fitting so archival cannot become a shortcut label.

Recent releasehas_recent_release_flagLast 365 days

1 if any release or package version appeared in the last 365 days.

Why: Simple “is it still shipping” indicator that is robust when exact counts are sparse.

Recent PR mergehas_recent_pr_merge_flagLast 90 days

1 if any pull request was merged in the last 90 days.

Why: Simple “are maintainers still integrating” indicator.

Derived risk proxiesTrend and concentration signals combined into risk-oriented scores.
Activity dropactivity_drop_365d_vs_prev_365dYear over year

Relative decline in commits from the previous year to the last year (positive = fewer commits).

Why: Captures deceleration, enabling earlier detection of decline than the absolute level alone.

Contributor dropcontributors_drop_365d_vs_prev_365dYear over year

Relative decline in the contributor count from the previous year to the last year.

Why: Detects a shrinking maintainer base before commits fully stop.

Release gap riskrelease_gap_riskAt t

Score in [0,1] for how overdue the next release is relative to the project's own release cadence (age-based when no release history exists).

Why: Normalizes release silence against the project's normal rhythm rather than an absolute threshold.

Concentration riskconcentration_risk_scoreLast 365 days

Composite score in [0,1] combining top-1 and top-2 shares, the Herfindahl index, and the concentration flag.

Why: A single interpretable bus-factor risk value that consolidates the concentration features.

Responsiveness and backlog pressureHow quickly maintainers respond and how much stale work has piled up.
Issue first responseissue_first_response_median_days_365dLast 365 days

Median days from issue creation to the first maintainer response over the last year.

Why: Slowing first responses indicate disengaging maintainers, independently of resolution speed.

Issue resolution timeissue_resolution_median_days_365dLast 365 days

Median days from issue creation to closure over the last year.

Why: How quickly reported problems are actually resolved.

Stale issue sharestale_issue_share_at_obsAt t

Stale open issues divided by the current open backlog.

Why: The fraction of the backlog that is old, expressed relatively so it is comparable across sizes.

PR response timepr_response_median_days_365dLast 365 days

Median days to the first response, merge, or close on pull requests over the last year.

Why: Responsiveness to contributors, the pull-request counterpart to issue first response.

PR merge latencypr_merge_latency_median_days_365dLast 365 days

Median days from creation to merge for merged pull requests over the last year.

Why: Integration speed for work that is ultimately accepted.