Tier rules

Thresholds version 9.

Calibrated on .

The values stay frozen until the yearly recalibration. Any change raises the version.

Every threshold lives in data/thresholds.toml

Tiers at a glance

Featured
Shown first. It passes every Featured gate.
Listed
Shown in the normal listing. No other tier applies.
New
A project whose first release is recent.
Archived
No longer maintained, or ended by its author.

The check applies the rules in this order: instant archive, expected update interval, dormancy, rot signals, dead, finished, New, Featured, outside approval, Listed, demotion guard. A signal that is missing counts neither way.

What each tier requires

A library is Featured when it is active and passes every gate.

Active means not dormant, or finished.

  • Adoption passes on one of three routes: active dependents reach their limit, new dependents (365 days) reach their limit, or the repository route passes.
  • No vulnerability advisory is unpatched past the grace window.
  • The commit in the crate’s .cargo_vcs_info.json is on a branch or tag of the repository. A commit that only a fork holds does not count. When the release records no commit, or the repository is on Codeberg or GitLab, a Cargo.toml on the default branch that declares the crate counts instead. A recorded commit that the GitHub repository lacks still fails.
  • Former glory reaches its floor.
  • Docs are present.
  • At least one version is neither a prerelease nor 0.0.x. A library with only prereleases passes this gate when its active or new dependents reach their limit. The repository route never lifts it. A library whose every version is 0.0.x never passes, because that only reserves the name.

A gate that lacks its signal does not pass.

Thresholds of Featured library
ThresholdValueMeaning
library_featured.min_active_users11Fewest active dependents. This gate or the new-dependents gate passes.
library_featured.min_new_adopters9Fewest new dependents (365 days). This gate or the active-dependents gate passes.
library_featured.min_former_glory0.5Lowest former glory, a share from 0 to 1.

An app is Featured when it is active and enough of these use signals pass.

An app has no dependents, so the repository route counts as one use signal.

  • Binary downloads over the last three releases.
  • Homebrew installs on request over 365 days.
  • Repology repository families that package the app.
  • Docker pull growth over 90 days.
  • The repository route.

An app with no crate skips the release gate. An app that publishes a crate needs a version outside prereleases and 0.0.x.

Apps have no dependents signal. ecosyste.ms lists no dependents for a repository that publishes no package.

Thresholds of Featured app
ThresholdValueMeaning
app_featured.min_signals2How many of the five use signals must pass. The repository route is one of them.
app_featured.binary_downloads884Fewest binary downloads over the last three releases.
app_featured.homebrew_on_request_365d500Fewest Homebrew installs on request over 365 days.
app_featured.repology_families2Fewest Repology repository families that package the app.
app_featured.docker_pull_growth_90d10000Smallest Docker pull growth over 90 days.

Repository route Featured

The repository route passes when stars, forks and contributors each reach their limit on the same check.

Stars alone never qualify a project. GitHub hides who starred, so stars cannot be screened for fakes. The route also needs forks and contributors, because faking all three together is much harder.

The route measures a whole repository, so an entry with crates must list the repository's main crate: the crate with the repository's own name that claims the repository. An entry that lists only side crates does not pass, whatever the numbers say.

A library can pass its adoption gate on this route. An app counts it as one use signal. Every other Featured gate still applies.

This is a gate of separate limits. No page adds them into a score.

  • Stars The star count GitHub states. Raw key stars.
  • Forks The fork count GitHub states. Raw key forks. A snapshot from before the check read forks reads as not measured.
  • Contributors The contributors with a GitHub account, from one GitHub request. Raw key contributors. A list GitHub calls too large reads as not measured.
  • Commits The total commits on the default branch. Raw key commits. Each entry page shows it, and no tier rule reads it.

A value below its limit fails the route. Otherwise a value that is not measured leaves the route unknown, and an unknown route does not pass.

Thresholds of Repository route
ThresholdValueMeaning
repo_route.min_stars4539Fewest GitHub stars. Never enough alone.
repo_route.min_forks434Fewest GitHub forks.
repo_route.min_contributors79Fewest contributors with a GitHub account.

New New

An entry is New when its first release is younger than the age limit.

Age alone decides. An old entry with few dependents or only prerelease versions is not New.

Thresholds of New
ThresholdValueMeaning
new.max_age_days180Age limit: a first release fewer days ago than this is New.

Listed Listed

An entry that no rule above places is Listed.

Archived Archived

An entry is Archived when an instant archive signal fires, or when enough dead checks come in a row.

Instant archive Archived

Any one of these signals archives an entry at once.

  • The repository is archived.
  • RustSec lists an unmaintained advisory for the crate.
  • The crate carries a deprecation notice.
  • Every version is yanked.
  • The crate is deleted from crates.io.

A “maintained” statement does not override these signals.

Dead Archived

A dormant entry is dead on a check when it has enough rot signals and no “maintained” statement.

Enough dead checks in a row archive the entry.

Unknown dormancy is not dead.

Thresholds of Dead
ThresholdValueMeaning
dormancy.dead_rot_signals2Fewest rot signals that make a dormant entry dead.
dormancy.dead_consecutive_checks2Dead checks in a row that archive an entry.

How the check reads activity

Expected update interval

Each entry gets an expected update interval E, in days.

A library starts from a base chosen by its latest version. The first matching base in the table applies.

Then E is capped at the release count times the days-per-release cap.

Then E doubles when monthly downloads pass their limit. It doubles again when active dependents pass theirs.

E is never below the dormancy floor.

An app, or a library with no known latest version, uses the dormancy floor.

A step that lacks its signal is left out.

Thresholds of Expected update interval
ThresholdValueMeaning
interval.patch_gt3_major_ge1700Base in days: patch above 3 and major at least 1.
interval.patch_gt3450Base in days: patch above 3.
interval.patch_gt0300Base in days: patch above 0.
interval.major_ge1200Base in days: major at least 1.
interval.minor_gt3140Base in days: minor above 3.
interval.other80Base in days: every other version.
interval.days_per_release_cap50Days per release. E is at most the release count times this.
interval.downloads_per_month_double50000Monthly downloads above this double E.
interval.active_users_double10Active dependents above this double E.
dormancy.min_days365The dormancy floor: smallest E in days, and E for every app.

Dormancy

An entry is dormant when the days since its latest release or latest human commit reach E.

Bot commits do not count.

With neither date known, dormancy is unknown.

Rot signals

Each check counts six rot signals.

  • R1 An outside issue is unanswered past the issue limit, and no maintainer replied within the reply window.
  • R2 A vulnerability advisory is unpatched past the grace window.
  • R3 A library’s former glory is below the lost-glory limit.
  • R4 The latest release requires a deprecated dependency.
  • R5 The repository no longer exists.
  • R6 A library’s latest release fails cargo check on current stable Rust.

Former glory is active dependents as a share of their peak.

R3 and R6 apply to libraries only. Apps have no former glory and no crate release to check.

A sandbox build check older than its age limit counts as unknown.

A rot check that lacks a signal counts neither way.

Thresholds of Rot signals
ThresholdValueMeaning
rot.unanswered_days270R1 issue limit: days an outside issue stays unanswered.
rot.maintainer_silence_days365R1 reply window: days over which maintainer replies count.
rot.advisory_grace_days60R2 grace window: days an advisory stays unpatched.
rot.lost_glory_below0.5R3 lost-glory limit: a former glory below this share is rot.
rot.build_check_max_age_days45R6 age limit: days a sandbox build check stays valid.

Finished

A dormant entry with no rot signal that is still adopted is finished.

A “finished” maintainer statement with no rot signal also makes an entry finished.

No rot signal means every rot check is known and none fires.

A library stays adopted on new dependents (365 days) or on former glory.

An app stays adopted on binary downloads per release.

A finished entry carries a stable label. It counts as active for Featured.

Thresholds of Finished
ThresholdValueMeaning
finished.min_former_glory0.8Lowest former glory of a finished library.
finished.min_new_adopters1Fewest new dependents (365 days) of a finished library.
finished.min_binary_downloads_per_release200Fewest binary downloads per release of a finished app.

Review and failed fetches

Outside approval

An org-affiliated entry that passes Featured needs a featured-approval judgment.

A maintainer outside the ml-rust organization approves it. Without it, the entry is Listed.

Demotion guard

A Featured entry keeps Featured until a demotion judgment approves the drop.

An instant archive skips this guard.

How values refresh

A weekly scan fetches repo facts, app distribution counts, the crates.io dump and the RustSec archive.

The contributor count and the README refresh only after a newer push, after a new version, or once the value passes its refresh age.

The repo link check refreshes only after a new version, or once the value passes its refresh age.

The refresh age of an entry is between 30 and 57 days. The entry slug sets it, so refreshes spread over several scans.

A run between scans fetches new entries at most, and reuses every other value. When the last scan is over 8 days old, the next run scans instead.

A reused value keeps its original fetch date.

A run that reuses the values of an entry is no check of that entry for the dead rule.

Failed fetches

A network signal that fails to fetch keeps its value from the previous snapshot.

That value keeps its original fetch date, and the entry notes name the source.

A value past the age limit counts as unknown.

An answer that a repo or a name does not exist counts as a signal. It never falls back.

Values from the crates.io dump and the RustSec archive never fall back. A run without them stops.

Thresholds of Failed fetches
ThresholdValueMeaning
fallback.max_age_days14Most days a value stands in for a failed fetch.
fallback.max_failed_share0.05Largest share of a run's fetches that can fail with no usable earlier value. Above it the run stops and publishes nothing. A run under 20 fetches never stops on this.

Facts, lists and movement

Active dependents

Active dependents: crates from other owners that depend on this project in a current release. One owner counts at most once.

A crate with several owners splits its count among them, so the raw value can hold a fraction. Lists and sentences round it.

The project's own owners, its publishers and shared maintenance accounts never count. A dependency stops counting when the crate publishes a release without it, or when its latest release grows too old.

  • Active dependents Raw key active_users. The Featured rule reads this number.
  • New dependents (365 days) Raw key new_adopters. Active dependents whose dependency began in the last 365 days.
  • Peak active dependents Raw key peak_users. The highest level on record, from monthly samples.
  • Former glory Raw key former_glory. Active dependents as a share of the peak.

The raw keys keep their names in the data files and the rule outcomes.

Downloads

A library reads the downloads of its primary crate over the last 30 days, from the crates.io database dump. Raw key downloads_per_month.

An app with binary downloads reads them per release: GitHub release asset downloads over up to its last 3 releases, divided by those releases. Raw key binary_downloads_per_release.

An app with no binary download reads the downloads of its primary crate over the last 30 days, when it lists a crate. No tier rule reads that number.

An app with no release and no crate reads as not measured, never as 0.

Lists sort by these numbers. The tier rules read only the limits this page names.

Facts that never count

These facts help a person choose a project. They never count toward a tier.

Each comes from measured data, and each row in the signal table links its source.

  • License A library reads the license of its primary crate's default version on crates.io, as an SPDX expression. A primary crate with no license column falls back to the license GitHub states. An app reads the license GitHub states. So does a library the dump lacks. A license nobody can name reads as not measured. No license in either source reads as none stated.
  • Runs on Each listed crate's default version is matched against data/backends.toml, by its direct dependency names and its feature names. A feature name means the code offers the backend, and it does not prove the backend works. GPU support unknown means the dump holds the crates and no row matches. The project can still run on a GPU. A backend behind a deeper dependency stays unseen. So does a backend that needs no feature.
  • Native code No native code found, or what the project binds. The check follows the normal dependencies of each listed crate, and theirs in turn. A hit is a crate named -sys or a crate with a links key. Crates that bind no foreign library never count. An optional dependency of a listed crate names the feature that enables it. A build dependency such as cc or cmake shows that the build uses a native toolchain. C built with no links key, no -sys crate and no such build dependency stays unseen. So does native code kept outside crates.io.
  • Python bindings A direct dependency that data/backends.toml lists. A required one needs Python. An optional one needs Python only with the feature that enables it. No Python binding crate found means no such crate shows on crates.io. Bindings kept outside crates.io stay unseen.
  • Dependents The distinct crates outside the entry whose default version directly depends on a listed crate. Dev dependencies and crates with every version yanked stay out. An app reads as not applicable. Active dependents weigh history and owners, so the two numbers differ.

An unknown value reads as not measured.

List order

Lists show the strongest tier first, then the most downloads, then the name. A value not measured sorts last.

A library counts downloads over 30 days. An app counts binary downloads per release. An app with none counts its crate downloads over 30 days. The two units differ, and each row names its own.

This is an order and never a score. No page prints a rank, and no tier reads it.

A list shows one row per project family. A project that belongs to a bigger project in another repo keeps its own tier and its own page.

Movement

Movement comes from the stored snapshots. A weekly scan adds one each week. It never affects a tier.

  • New The entry first appears in the history inside the window. The first day of history does not count, because every entry appears then.
  • Rising Active dependents rose by at least the set share and the set number, between the snapshot nearest the window start and the newest snapshot.
  • Falling Active dependents fell by at least the set share and the set number, over the same two snapshots.

A value missing at either end gives no movement. History shorter than the window gives none, and pages say movement needs more history.

Thresholds of Movement
ThresholdValueMeaning
movement.window_days30Days between the newest snapshot and the window start.
movement.min_share0.25Smallest change, as a share of the value at the window start.
movement.min_users5Smallest change in active dependents.