Refolk
StandardEngineering and open source

The Dependency Adoption Standard: Grade a Library Before You Add It

You can produce a documented adopt, adopt-with-conditions, or reject call on any candidate library that another engineer would grade the same way.

17 min readLast reviewed August 3, 2026Read as Markdown

Deciding whether to take on a new open-source library as a production dependency is a judgement call that two competent engineers routinely get wrong in opposite directions. This guide is for engineers, engineering managers, and technical founders who want that call to be gradeable: a written standard, with named thresholds against searchable public signals, that another engineer applying the same rules would grade the same way. It delivers an adopt, adopt-with-conditions, or reject decision you can defend, and a checklist you can adopt as team policy for a dependency review.

The public answers already exist and they are good as far as they go. OpenSSF's concise guide, vendor blog checklists, and CHAOSS metrics all list things to look at. What they leave to your gut is the pass/fail line. This guide fixes that line where the evidence supports fixing it, and says plainly where no universal line exists.

Why two engineers grade the same repo differently

The core problem is that the existing guidance names signals but not thresholds, so the decision collapses into taste. CHAOSS tells you the Contributor Absence Factor is the smallest number of contributors responsible for 50% of total contributions, and that a lower value means higher dependency on fewer people. It does not tell you the number below which you should walk away, because it deliberately leaves that to organizational risk tolerance. Smaller projects may feel comfortable with a factor of 2, while larger organizations expect much higher factors before they consider a project viable.

That is honest, but it is not gradeable. If the standard says "look at the bus factor" and stops, one engineer reads a 2 as fine and another reads it as a red flag, and both are correct under the guidance. A standard has to do one more thing than a guide: it has to state the line, or state that the line is a local policy decision and force you to write it down. Either way, two people end up with the same answer.

The stakes make this worth the discipline. In Refolk's index there are only 11 OSPO-type leads in the United States and 3 in Germany. That is far too few people to hand-review every dependency a large codebase pulls in. A reproducible written threshold scales where headcount cannot, which is the whole reason a standard beats a case-by-case call.

11
OSPO-type leads in the US, in Refolk's index
With only 3 equivalent leads in Germany, hand-review does not scale - a written threshold does.

The four signals that carry the decision

Four public signals do most of the grading work, and each fails in a specific, nameable way when it lies. The table below gives the concrete threshold for each, and the sections after it explain what each signal proves and how it deceives you.

SignalConcrete thresholdSource
Last release age365 days since last release = stale defaultstale-deps default
Time to first response2 business days from a humanCHAOSS
Contributor Absence Factor2 (small project) to much higher (large org)CHAOSS viability model
Fork-to-star ratiounder 1% suspicious, 10 to 30% normalpractitioner heuristic

Read these thresholds as defaults you can override in writing, not as physics. The last-release-age and fork-to-star lines come from practitioner tooling and heuristics; the two-business-day figure and the absence-factor guidance come from CHAOSS. None of them is a universal, authoritative cutoff, and I will say so again where it matters. The value of writing them down is that an override becomes a decision on the record rather than a silent gut call.

What the Contributor Absence Factor proves

The Contributor Absence Factor, previously called the Bus Factor, is the smallest number of contributors responsible for 50% of total contributions. It proves how concentrated the project's future is in a few hands. CHAOSS's own example treats a factor of 5 as healthy: a project at 5 would likely continue with minimal interruption if a couple of people suddenly left. The CHAOSS Project itself measured a bus factor of 5 on git commits in 2020.

Here is where it lies. The metric reports the same number for one engaged maintainer and one departed maintainer whose token still merges Dependabot pull requests. It counts contributions, not engagement, so a factor of 1 or 2 driven by automated merges from an absent owner looks identical to a live solo maintainer. That ambiguity is now the main risk in the number, not the number itself. The fix is cheap: confirm the top contributor has human commits in the last 90 days, not just bot or automation merges.

What time to first response proves

Time to First Response is how long a project takes to respond to something that needs attention, such as a pull request, issue, or email. The nearest published numeric benchmark is a practitioner guideline that every pull request should get a response from a human within two business days. It proves that maintainers are present and paying attention now, which is exactly what release age cannot tell you.

It lies in two ways. First, median response time rises purely because issue volume rose. A project that went from twenty to two hundred issues a month will show a worse median even if maintainers do the identical work, so an absolute time threshold unfairly penalizes popular projects. Grade the within-benchmark hit rate, the share of items answered inside two business days, not the raw median. Second, automation and bot activity can inflate the metric; it is only meaningful when driven by humans. Exclude bot and author responses before you count.

What last release age proves, and what it does not

A last release older than 365 days is the most-cited concrete staleness default, encoded in common tooling that flags packages by release inactivity. It proves the project is not shipping new versions on a normal cadence. OpenSSF frames the risk qualitatively: most software needs continuous maintenance, and if it is unmaintained it is also likely to be insecure.

But release age produces a real false positive. A project can be complete, not abandoned. Some projects seem inactive because they fulfilled their goal, while the community stays responsive to bug reports and security issues. That is a materially different situation from neglect, and the tell is recent responsiveness even without new features. This is why the responsiveness sample matters: it distinguishes "finished and answering" from "gone."

Why stars are not on this list

Stars are absent from the four signals on purpose. They fail structurally, not just because of fraud. A star count is a cumulative total that only goes up, and no one unstars a project because it is declining in quality, so stars cannot signal current health. On top of that structural weakness, a CMU study found 6 million fake GitHub stars across more than 18,600 repositories, and a malicious package with 3,000 stars can look like a desirable dependency and trick developers into installing it.

Stars only ever go up and no one unstars a dying project, so they cannot tell you a library is healthy now.

Substitute signals that are harder to fake. The fork-to-star ratio is one heuristic: legitimate projects typically show forks at 10 to 30% of star count, and a ratio under 1% is a warning sign. The registry download trend is another, since it reflects real installs over time. And treat zero issues on a popular repo as a red flag rather than a green one, because real users file real bugs, so an absence of issue traffic is suspicious, not reassuring.

License class: the cheapest hard gate

Classify the license before you spend a minute on health analysis, because a strong copyleft license can reject a candidate in five minutes. License class turns on one question - what you must disclose if you distribute - and four classes recur.

License classExamplesObligation when you distribute
PermissiveMIT, Apache 2.0Include license text and copyright notice; modifications may stay proprietary
Weak copyleftMPL 2.0, LGPL, EPLRelease only modifications to the licensed files themselves
Strong copyleftGPL, GPLv2, GPLv3, AGPLRelease the entire program, including linked libraries, under the same license

For proprietary commercial software that you distribute, strong copyleft is a critical red flag: if you integrate and distribute, you will likely be required to release your own source code. That is why it belongs at the front of the review as a gate. A permissive license clears in seconds. A strong copyleft license against a distributed proprietary product is an immediate block or escalation, before anyone computes an absence factor.

The class turns on linkage, and weak copyleft only covers the licensed files themselves. So read the actual files you import, not the top-level LICENSE of a monorepo. A repository can carry a permissive license at the root and a copyleft subdirectory you happen to depend on. Grading the wrong file is the classic license misread.

OpenSSF Scorecard: read the checks, not the headline

Scorecard automates a chunk of this review and returns a number, but the number is where people go wrong. Scorecard runs 18 checks across three themes - holistic security practices, source code risk, and build process risk. Each check returns a score from 0 to 10 with 10 the best, and the aggregate is a weight-based average of the checks weighted by risk. Named checks include Code-Review, Branch-Protection, Maintained, Dependency-Update-Tool, Binary-Artifacts, Signed-Releases, Fuzzing, and SAST, and each carries a risk level.

The trap is the aggregate. It can hide a fatal check. A consumer may care most that the repo is not archived, which the Maintained check catches, but that signal gets averaged away in a headline X out of 10. Pull the per-check scores for Maintained and Code-Review at minimum. A project can score respectably overall while failing the one check that would have stopped you.

Scorecard is credible at scale: it scans more than a million of the most-used OSS projects weekly and publishes the results as a public dataset, so for many candidates a recent score already exists. Use it as one input to a decision you still make deliberately, not as the decision itself.

Where each signal sits in the decision

  1. License class
    Five-minute read; strong copyleft in a distributed product blocks before anything else
  2. Maintenance and abandonment
    Last release and last human commit against a 365-day default
  3. Contributor and responsiveness health
    Absence factor plus two-business-day hit rate
  4. Automated posture
    Scorecard per-check scores and known CVEs
Cheapest, most decisive gates sit on top; you spend effort downward only on candidates that survive.

Because so few people can review dependencies by hand, the point of encoding all of this is that the standard, not a named expert, does the grading. This is where a sourcing view of your own bench helps: if you need to find the engineers who can own this policy, you can ask Refolk in plain English rather than guessing who has done the work before.

That framing matters because the talent skews. In Refolk's index the Software Supply Chain Security tag outnumbers Software Composition Analysis by 99 to 44, a 2.25x gap, which suggests reviewers frame the job as provenance and supply chain rather than license and composition. A license-and-maintenance standard directly fills the composition gap that skew leaves open.

The review procedure, start to decision

Run these eight steps in order. The order is cheapest-gate-first, so most rejects fire before you spend on health analysis. OpenSSF leads with "can you avoid it" and security posture; CHAOSS-first practitioners lead with contributor and responsiveness health. Both converge on license and maintenance as the gates, which is why those sit near the front here.

Grade a candidate library

  1. Scope and avoid
    Confirm the dependency is necessary and cannot be avoided or covered by something you already ship, since every new dependency increases attack surface. Done means a written justification.
  2. Classify the license
    Read the actual LICENSE files you import, classify permissive, weak copyleft, or strong copyleft, and match to your distribution model. Strong copyleft in a distributed proprietary product blocks or escalates.
  3. Check maintenance and abandonment
    Record the last release date and last meaningful human commit and apply a staleness threshold such as 365 days. Log the figure with a pass or fail.
  4. Compute the Contributor Absence Factor
    Find the smallest number of contributors making 50% of contributions, compare to a team floor, and check the top contributor has human commits in the last 90 days.
  5. Sample responsiveness
    Measure how often a human responds within two business days on recent issues and PRs, excluding bots and the author. Log the hit rate, not the median.
  6. Run OpenSSF Scorecard
    Capture the aggregate plus per-check scores for Maintained, Code-Review, Branch-Protection, and Dependency-Update-Tool. Attach the JSON.
  7. Check vulnerabilities and real usage
    Query a vulnerability database for unpatched CVEs and confirm real adoption via the download trend, not stars. Require no unpatched critical CVEs.
  8. Record the decision
    Aggregate into adopt, adopt-with-conditions, or reject and name the criteria that fired. Sign a record another engineer could reproduce.

The three outcomes map to the evidence cleanly. Adopt means every gate passed and no substitute signal contradicted the others. Adopt-with-conditions means a signal failed but the failure is bounded and mitigable, for example a solo maintainer on an otherwise healthy, permissive, actively-responsive project where you accept the concentration risk and plan for a fork. Reject means a gate fired hard: strong copyleft against a distributed product, an unpatched critical CVE, or an abandoned project with no recent responsiveness.

License risk against maintenance health

Actively maintainedAbandoned, no recent responsiveness
Maintained and permissive
Proceed to health and Scorecard checks; strong adopt candidate
Maintained but strong copyleft
Block or escalate to legal despite health
Abandoned and permissive
Reject or plan to vendor and self-maintain
Abandoned and strong copyleft
Reject outright; worst quadrant on both axes
Permissive or weak copyleftStrong copyleft in a distributed product
The two cheapest gates plotted together; most decisions resolve without deeper analysis.

How this standard goes wrong

Every signal in this standard has a way of reading healthy when it is not, or reading broken when it is fine. This is the most important section, because a standard that trusts its own signals blindly is worse than no standard. Here are the failure modes and the check that catches each.

Failure modeWhat it looks likeCheck that catches it
Absence factor reads healthy but the maintainer leftA factor of 1 or 2 driven by a departed owner's token merging bot PRsConfirm human commits from the top contributor in the last 90 days
Response time inflated by volumeMedian rises when issue count jumps twentyfoldGrade the within-two-days hit rate, not the median
Response time gamed by botsFast responses that are all automationExclude bot and author responses
Stars as a safety proxyA malicious 3,000-star package looks desirableUse fork-to-star ratio and download trend
No issues read as stabilityThousands of stars, zero issuesTreat empty issue traffic as a red flag
Last-release-age false positiveAn old but finished projectCheck for recent responsiveness even without new features

Two more failures do not fit a one-line cell and deserve full attention.

The Scorecard aggregate hides a fatal check. A repository can post a decent aggregate while being archived, or while scoring near zero on Maintained or Code-Review, because the weighted average smooths over the one check you cared about. Never accept or reject on the headline alone; read Maintained and Code-Review as named per-check results every time.

The license misread on a subdirectory. Weak versus strong copyleft turns on linkage, and weak copyleft only covers the licensed files themselves. A repo can be permissive at the root and copyleft in exactly the module you import. Classify the files you actually pull in, not the license badge at the top of the README.

The checklist you adopt as team policy

Before you call any dependency review done, verify every item below. This is the artifact you make policy: paste it into your review template so every reviewer produces the same record.

Dependency adoption review - definition of done

  • A written justification records why the dependency is necessary and cannot be avoided.
  • The license class is recorded from the actual files imported, and any strong copyleft in a distributed proprietary product is blocked or escalated.
  • The last release date and last human commit are logged with a pass or fail against a stated staleness threshold.
  • The Contributor Absence Factor is recorded against a stated team floor, with a 90-day human-commit check on the top contributor.
  • The two-business-day response hit rate is logged from a human-only, non-author sample.
  • Scorecard aggregate and the per-check scores for Maintained and Code-Review are attached, not just the headline.
  • No unpatched critical CVEs are present, and real usage is confirmed by download trend rather than star count.
  • The final call is adopt, adopt-with-conditions, or reject, names the criteria that fired, and is signed.

Use a fixed record so the decision is reproducible. The template below is the minimum that lets another engineer reconstruct your call.

Dependency adoption record
Library: <name and version>
Reviewer / date: <name / date>
Justification (why not avoid): <one or two sentences>
License class: <permissive | weak copyleft | strong copyleft> - imported files checked: <yes/no>
Last release: <date> - last human commit: <date> - staleness pass/fail: <>
Contributor Absence Factor: <n> vs team floor <n> - top contributor human commits in 90d: <yes/no>
Two-business-day response hit rate: <x of y sampled, bots/author excluded>
Scorecard aggregate: <x/10> - Maintained: <x/10> - Code-Review: <x/10>
Unpatched critical CVEs: <none | list> - monthly download trend: <up/flat/down>
Decision: <adopt | adopt-with-conditions | reject>
Criteria that fired: <list>
Conditions (if any): <list, with owner and revisit date>

Fill every field. An empty field is a failed review, not a pass.

Keeping the standard current

A standard rots if the thresholds drift out from under it, so review the numbers on a fixed cadence rather than treating them as permanent. Three of the four headline thresholds are practitioner defaults, not authoritative cutoffs, and the tooling that encodes them changes. The 365-day staleness default lives in configurable tools; the two-business-day response benchmark and the absence-factor guidance come from CHAOSS, which deliberately leaves the viability line to your risk tolerance.

Re-check the mechanism, not the memorized value. Once a quarter, confirm your staleness threshold still matches your dependency-update tooling's defaults, confirm your Scorecard version is current so you are not scoring against retired checks, and revisit your team floor for the Contributor Absence Factor as your codebase's criticality profile changes. Note that CHAOSS metrics were designed before AI-speed contribution volumes, which is another reason the absence-factor number deserves the paired human-commit check rather than standalone trust.

Finally, tune the floor by criticality. A logging helper and a cryptography library do not deserve the same absence-factor floor, and the standard should let a reviewer raise the bar in writing for a dependency that sits on a critical path. The goal is not one number for everything. It is that whatever number a reviewer uses is recorded, justified, and reproducible, so the next engineer inherits a decision rather than a mystery.

Questions practitioners ask

How do I evaluate an open source dependency without it taking a whole day?

Run the eight-step review in roughly two hours total. The gates are ordered cheapest-first: scope-and-avoid and the license class check each take about fifteen minutes and can reject a candidate before you spend anything on health analysis. Maintenance, Contributor Absence Factor, and responsiveness are fifteen minutes each, Scorecard is a ten-minute automated run, and the vulnerability check is fifteen. Most rejects fire in the first two steps.

Is a high GitHub star count enough to trust a package?

No. Stars only ever go up and no one unstars a declining project, so they cannot signal current health. A CMU study found 6 million fake stars across more than 18,600 repos, and a malicious package with 3,000 stars can look like a desirable dependency. Grade the fork-to-star ratio instead, where under 1% is suspicious and 10 to 30% is normal, plus the registry download trend, which is harder to fake.

What last-release age means a library is abandoned?

No single authoritative number exists, but 365 days since the last release is the most-cited concrete default and the value tools like a common stale-deps checker encode. Treat it as a flag, not a verdict. A project can be finished rather than abandoned, so before you reject on age alone, check whether maintainers still respond to recent bug reports and security issues.

What Contributor Absence Factor is safe?

CHAOSS deliberately does not fix a universal line. Smaller projects may be comfortable with a factor of 2, while larger organizations expect much higher before they consider a project viable. CHAOSS's own example treats 5 as healthy because the project would continue with minimal interruption if a couple of people left. Set a team floor by how critical the dependency is, and pair the number with a 90-day human-commit check on the top contributor.

Does a strong copyleft license automatically disqualify a library?

Not automatically, but for proprietary commercial software that you distribute it is a critical red flag. Strong copyleft such as GPL, GPLv2, GPLv3, and AGPL can require you to release your own source under the same license if you integrate and distribute. Weak copyleft like MPL and LGPL only covers the modified licensed files, and the class turns on linkage, so check the actual files you import.

Can I rely on the OpenSSF Scorecard aggregate score?

Read the per-check scores, not just the aggregate. Scorecard scores each of its 18 checks from 0 to 10 and produces a weight-based average weighted by risk, but that aggregate can hide a fatal check. A repo could score well overall while being archived, or scoring poorly on Maintained or Code-Review. Pull the individual Maintained and Code-Review results before you decide.

Read next