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_30dLast 30 daysNumber of human commits in the 30 days before t.
Why: Short-term development pulse; captures whether the project is moving right now.
commits_90dLast 90 daysNumber of human commits in the 90 days before t.
Why: Quarter-scale activity level that is less noisy than the 30-day count.
commits_365dLast 365 daysNumber 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_months_365dLast 365 daysCount 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_last_commitAt tDays 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_90dLast 90 daysDistinct human contributors in the last 90 days.
Why: Breadth of recent participation; a proxy for the size of the active team.
contributors_365dLast 365 daysDistinct human contributors in the last 365 days.
Why: Annual contributor base; the reference for the contributor drop.
new_contributors_365dLast 365 daysContributors 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.
top1_contributor_commit_share_365dLast 365 daysShare (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.
top2_contributor_commit_share_365dLast 365 daysCombined 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_indexLast 365 daysHerfindahl 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_concentration_flagLast 365 days1 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.
opened_issues_90dLast 90 daysIssues created in the last 90 days.
Why: Inbound user demand and engagement with the project.
closed_issues_90dLast 90 daysIssues closed in the last 90 days.
Why: Maintainer throughput on the issue tracker.
issue_closure_ratio_90dLast 90 daysClosed 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.
issue_backlog_growth_90dLast 90 daysRelative 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_issues_count_at_obsAt tIssues 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.
opened_prs_90dLast 90 daysPull requests created in the last 90 days.
Why: Contribution inflow from outside the core team.
merged_prs_90dLast 90 daysPull requests merged in the last 90 days.
Why: Direct evidence that maintainers are still integrating outside work.
closed_unmerged_prs_90dLast 90 daysPull 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_ratio_90dLast 90 daysMerged divided by opened pull requests over the last 90 days.
Why: Responsiveness to contributors, expressed relatively.
stale_open_prs_count_at_obsAt tPull 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_365dLast 365 daysGitHub releases published in the last 365 days.
Why: Shipping cadence: whether usable versions still reach users.
days_since_last_releaseAt tDays since the most recent release or package version.
Why: Release staleness; complements commit staleness for projects that ship rarely.
versions_published_365dLast 365 daysPackage-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_age_daysAt tDays from the first published package version to t.
Why: Maturity context: young and long-established packages have different baseline inactivity risk.
repo_age_daysAt tDays from repository creation to t.
Why: Normalizes gaps and cadence against how long the project has existed.
stars_total_at_obsAt tCumulative 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_total_at_obsAt tCumulative forks observed up to t.
Why: Reuse and derivative activity around the project.
dependency_count_at_obsAt tDeclared dependency count of the resolved package version at t.
Why: Proxy for maintenance burden and integration complexity.
popularity_tier_at_obsAt tLow / 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.
repo_archived_at_obsAt t1 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.
has_recent_release_flagLast 365 days1 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.
has_recent_pr_merge_flagLast 90 days1 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_drop_365d_vs_prev_365dYear over yearRelative 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.
contributors_drop_365d_vs_prev_365dYear over yearRelative 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_riskAt tScore 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_risk_scoreLast 365 daysComposite 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_response_median_days_365dLast 365 daysMedian 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_median_days_365dLast 365 daysMedian days from issue creation to closure over the last year.
Why: How quickly reported problems are actually resolved.
stale_issue_share_at_obsAt tStale 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_median_days_365dLast 365 daysMedian 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_latency_median_days_365dLast 365 daysMedian days from creation to merge for merged pull requests over the last year.
Why: Integration speed for work that is ultimately accepted.