# Methodology versions

> The complete version history of the inspect.software metrics methodology — every formula, weight, and threshold change, dated and documented.


The methodology is **versioned as a whole**. Any change to a formula, a
weight, or a band threshold bumps the metrics version, and every published
report records the version it was produced under (`metrics.metrics_version`).
That makes results auditable over time: a historical value can be re-derived
under the exact rules that produced it.

The current version is **1.13.0**.

Each entry identifies the precise change, its scope, and whether existing
results remain comparable. Dates are part of the public methodology record.

## Version history

### 1.13.0 — 2026-07-22

Two corrections, both prompted by the first malicious-dependency finding this
record ever published.

**Red flags stop compounding.** Each policy used to multiply whatever the
previous one left, so a repository carrying two landed on the product of both.
One project went from a weighted 50 to 18 under the malicious-dependency
multiplier and then to 11 under abandonment — a number no policy chose, and
none could be pointed at to explain. A multiplier states how serious a finding
is; it is not a cost to be added up. The strictest policy now governs alone and
the others are reported without moving the score again. Scores can only rise
under this change, and only for repositories carrying more than one flag.

**A withdrawn package is no longer scored as live malware.** Every malicious
finding now asks the registry whether it still serves that exact version. Where
it does not, nothing installable remains: the finding stays on the report,
because the project depends on a name that was compromised, but it raises no
flag and costs no points.

The check asks about the resolved version rather than the package's latest one,
and the distinction decides real cases. After a takedown npm leaves a
placeholder release as the package's latest, which protects everyone resolving
a version range and nobody who pinned the bad version exactly. Reading the
latest version would have cleared the very repository this finding first fired
on, which pins the compromised package at the precise version the registry
still serves. Where the question cannot be answered at all, the finding is
scored as though the package were live — failing to reach a registry is not
evidence that malware was withdrawn.

### 1.12.0 — 2026-07-22

The Abandonment Policy's *declared* tier was over-firing on registry evidence
that did not belong to the repository it was judging.

That tier exists to quote the maintainer rather than infer anything: a project
is declared unmaintained when it is archived, or when every package it
publishes has been retired. Two defects widened it. A package counted as the
project's own unless the registry positively said otherwise — which admitted
entries declaring no repository at all, exactly the shape a squatted name
takes. And a yanked latest release counted as retirement, though withdrawing a
release is usually a bad build with a fix right behind it.

Together they took one 68-rated project to 27 on the strength of a PyPI
placeholder it does not publish. A package must now declare *this* repository
and be deprecated outright; a yanked release no longer contributes. Of 403
repositories in the declared tier, 391 rested on GitHub's own archive flag and
were never in question.

### 1.11.0 — 2026-07-21

**Abandonment** becomes a red flag over the whole report.

Every tool in this space answers "is this project dead?" with days since the
last commit, and every one of them is wrong about the same projects: a small,
complete library that has not needed a commit in three years is finished, not
abandoned. Marking it dead costs a public record its credibility on exactly the
software that deserves the most confidence.

So the assessment rests on a different question — abandonment is an unmet
obligation, not an absence of noise. Silence is measured from the last human
commit and is never a finding on its own; it becomes one only when work is
visibly arriving and not being acted on: an unanswered contribution queue,
issues no maintainer ever replied to, an unfixed advisory in a direct
dependency, a release stall measured against the project's own cadence, a
failing or year-stale CI, a sole maintainer absent from the whole window.
Readings that explain the silence hold the result at *dormant*, which carries
no penalty — quiet is already priced inside development activity, and charging
for it twice would punish the finished libraries the distinction exists to
protect.

Findings multiply the health index: 85% at risk, 60% likely abandoned with an
at-risk ceiling of 49, 40% declared with a critical ceiling of 29. *Declared*
is the maintainer's own statement quoted rather than inferred — the repository
is archived, or every package it publishes is deprecated or yanked.
Repositories that cannot be assessed read *unverified* and are not penalized.
See [abandonment](/wiki/abandonment).

**Comparability:** values can only fall relative to 1.10.0, and only for
repositories where a drought is corroborated by unmet obligations. Quiet,
well-kept projects are unaffected by design.

### 1.10.0 — 2026-07-21

Dependencies reported as **malicious packages** become a security red flag of
their own, separate from vulnerability advisories.

The evidence was already arriving. OSV.dev serves the OpenSSF
malicious-packages corpus alongside ordinary advisories, on the same query this
record already made — but a malicious-package report carries no severity rating
and no fixed version, so it was falling through to "unknown severity" and
scoring like a moderate vulnerability. A package found to be malware counted
for slightly less than an average CVE.

Malicious packages are now removed from the advisory findings and scored on
their own terms: a 35% multiplier on security posture and on the weighted
health index, with a Critical ceiling of 29 on both. That is one band stricter
than the high-risk jurisdiction ceiling, because a malicious dependency is a
confirmed compromise rather than an exposure to risk. Direct and indirect
dependencies count alike — an install-time payload runs at any depth in the
resolved graph.

The finding is expected to be rare: run over a 300-repository sample covering
46,889 resolved dependencies before release, it found nothing. Registries
remove malicious packages within days, so a lockfile that still resolves to one
is unusual. See [malicious dependencies](/wiki/malicious-dependencies).

**Comparability:** unchanged for every repository with no malicious dependency,
which is nearly all of them. Where one is found, Security and the health index
are not comparable to any earlier version.

### 1.9.0 — 2026-07-21

The human-authorship factor introduced in 1.6.0 stops firing on projects that
simply automate well.

Heavy automation on its own turned out to be a poor signal. Among the
repositories where machines author most of the commit traffic, the healthiest
were indistinguishable from the abandoned ones by share alone: one 59,000-star
project runs roughly three quarters of its commits through a dependency bot and
had a human commit two days ago, and a package registry whose entire purpose is
automated version bumps runs at 93%. Both were being marked down.

The discount now requires a second condition: the machines must also have been
committing alone for more than 90 days. The gap is measured inside the sampled
commit window rather than against the clock, so a stored report always rescores
to the same value. Repositories with a recent human commit are no longer
affected at any level of automation; genuinely automation-sustained projects
keep their discount.

**Comparability:** values can only rise relative to 1.8.0, and only in
Vitality.

### 1.8.0 — 2026-07-21

A signal is withdrawn. [Growth authenticity](/wiki/growth-authenticity)'s
**pre-substance spike** claimed that a burst arriving before a project's first
release was evidence of something. Measured against 795 ordinary repositories,
it fired in every one of the five findings the policy produced — and every one
of those five was an ordinary launch. Publish, attract attention, release
later is how projects work.

The comparison was unsound in a second way. The release list a report carries
is capped at its newest 100 entries, so for any project past that cap the
earliest entry is not its first release, and every burst appears to predate
it.

What replaces it, **no released substance**, keeps only the absolute case: the
project has never published a release at all. It is deliberately weaker, and
it corroborates rather than concludes. Findings across the ordinary population
return to none, and both confirmed findings in the evaluation sample survive.

A published methodology that cannot withdraw a signal it can no longer defend
is not a methodology. This is what the version history is for.

### 1.7.0 — 2026-07-21

[Growth authenticity](/wiki/growth-authenticity) gains a fifth signal,
**star concentration**: the five busiest days holding 80% or more of every
star the scan collected.

It was added after the first live evaluation of the policy, which found it
precise but nearly blind — across 714 ordinary repositories it flagged none,
and across 45 selected for the shape purchased attention leaves it flagged one.
The threshold is read off the record rather than chosen in advance: among 502
ordinary repositories in the 100–1,500 star band, the median puts 6.9% of its
stars in the five busiest days, and none reached 80%.

The signal corroborates a burst; it never concludes on its own. A legitimate
announcement-driven release approaches the same shape — a research model
release measured 73.7% — and a signal that cannot tell those apart must not
decide alone.

Scores can only fall under this change, and only for repositories that already
showed a burst. Nothing else moves.

### 1.6.0 — 2026-07-21

Inputs that can be inflated stop counting at face value.

Added [growth authenticity](/wiki/growth-authenticity). The per-day star and
fork history collected for every report is now read for growth whose shape
organic attention does not produce, and the **Inorganic Growth Policy**
discounts the stars and forks components of [popularity](/wiki/popularity) by
40% for one confirmed window and 70% for more. A burst on its own is never a
finding: confirmation requires at least two independent corroborating
signals, so launches and front-page days read as organic. Repositories whose
collected history cannot answer the question read *unverified* and are not
penalized. The policy carries no additive weight, so a clean history can never
raise a score.

[Development activity](/wiki/development-activity) gains a human-authorship
factor over its commit cadence and commit volume components. A project
sustained entirely by its own robots no longer reads as actively developed;
full marks apply from a 40% human share upward, so heavy but genuine
automation is unaffected. [Maintainer resilience](/wiki/maintainer-resilience)
now counts people only — automation accounts were previously ranked among a
project's maintainers, which flattered exactly the projects that automate
most.

[AI Readiness](/wiki/ai-readiness) stops measuring only which files exist.
[Agent context](/wiki/ai-agent-context) gains a **legible commit history**
component and rebalances away from `llms.txt`: before this change the metric
could only ask whether a rare file had been written, and most projects had no
way to move it at all. [Verify loop](/wiki/ai-verify-loop) gains its
first two components that observe an outcome rather than the presence of a
file: **demonstrated agent practice**, and **automated maintenance** — whether
a dependency bot's machine-authored changes actually land, judged on observed
commits rather than a configuration file, since the most widely used tool is
routinely configured outside the repository. It also now credits a language
toolchain as a one-command bootstrap, which had scored well-run Rust projects
zero for shipping no Makefile. The badge still carries no weight in the health
index.

Existing values remain comparable except in Community & Adoption for
repositories with a confirmed growth finding, and in Vitality and
Sustainability & Governance for repositories whose contributor list is largely
automation. Scores under these changes can only fall, never rise.

### 1.5.0 — 2026-07-20

Added [dependency advisories](/wiki/dependency-advisories). The resolved
dependency set already collected for every report — direct dependencies plus
the transitive closure — is now matched against the
[OSV](https://osv.dev) advisory database, and affected packages are reported
with their severity and the version each was fixed in.

Security becomes a weighted mean of
[security posture](/wiki/security-posture) at 80% and the new metric at 20%.
The [High-Risk Jurisdiction Policy](/wiki/jurisdiction-exposure) multiplier
is unchanged: it still applies to posture and to the weighted overall score,
and carries no additive weight of its own.

The new metric is excluded, with the remaining weight renormalized, whenever
the dependency graph or the advisory lookup was unavailable — a repository is
never penalized for having its dependency graph switched off. Existing values
remain comparable except in Security, where any repository with a dependency
graph is now scored on evidence that was not previously considered.

### 1.4.0 — 2026-07-19

Added [High-Risk Jurisdiction Exposure](/wiki/jurisdiction-exposure) for
high-confidence self-published public profile evidence within the Russia, Iran,
and North Korea policy scope. It is a hierarchy-wide policy multiplier: owner
20%, displayed top contributor
50%, public contributor-organization affiliation 75%, no match 100%. A
confirmed match multiplies and caps [Security posture](/wiki/security-posture)
at 49; Security reflects that adjusted posture. The same multiplier and cap
then apply to the weighted overall score. Missing, ambiguous, and clean
evidence do not reduce either score.

The classifier is offline, adds no API request, excludes internationally
recognized Ukrainian territories from Russia place matching unless Russia is
explicitly self-declared, and publishes only aggregate country/role evidence.
The signal routes a dependency into enhanced review; it does not determine
nationality, citizenship, sanctions status, malicious intent, or individual
trustworthiness.

**Comparability:** affected repositories can move to a lower Security and
overall band. Existing reports contain owner and top-contributor locations
and can be rescored without repository network access. Organization-affiliation
location is available only on new scans because schema 0.15.0 adds it to the
existing batched GraphQL selection.

### 1.3.0 — 2026-07-18

[Community health](/wiki/community-health)'s license signal became a
**three-state tier** — standard, custom, or none — replacing a single
present/absent test. A repository whose license file exists but whose text is
not a recognized license now earns three quarters of the license weight rather
than either full credit or none.

Detection also changed: the state is resolved from **all three** license
sources together (the repository's license metadata, GitHub's community
profile, and the Scorecard `License` check) instead of preferring Scorecard
alone. Presence is a logical OR, so a file that any one source sees counts.
The sources disagree on roughly 1% of repositories.

Custom licenses already scored slightly below standard ones before this
version, because Scorecard grades them 9 out of 10 rather than 10. That gap
was inherited from the tool rather than stated as a position; it is now
deliberate and documented.

**Comparability:** existing results were recomputed under 1.3.0 from the data
already stored in each report — no repository was rescanned, so nothing moved
for any reason other than this change. Movement is small: the license row is
22.5 of 100 points within community health, itself 35% of Community &
Adoption, which is 18% of the index.

### 1.2.0 — 2026-07-14

Published-package registry adapters were added for **Go** (the module proxy),
**Maven Central**, and **NuGet**, and PyPI package identification was extended
to legacy `setup.py` manifests. Repositories publishing in those ecosystems
now carry registry evidence in [package
maintenance](/wiki/package-maintenance) — publish recency, version history,
deprecation state — and NuGet additionally feeds [ecosystem
adoption](/wiki/ecosystem-adoption) through its lifetime download total. Go
and Maven Central publish no download statistics of any kind, so they
contribute no adoption signal. No formulas or weights changed — only which
repositories have registry evidence available.

### 1.1.0 — 2026-07-14

[Community health](/wiki/community-health) now detects a license **once**. It
previously carried two overlapping license components — a GitHub
community-profile flag and a separate `License` shared-evidence card. These are
merged into a single `License` row detected by OpenSSF Scorecard's `License`
check, with the community-profile flag kept only as a fallback for repositories
that have no Scorecard. Scorecard's own `License` check remains a full component
of [Security posture](/wiki/security-posture). The merge removes double-counting
and defers to Scorecard's more reliable detection where the two sources
disagree. This release changes affected `community_health` scores; reports
remain reproducible through their recorded `metrics_version`.

### 1.0.0 — 2026-07-13

OpenSSF Scorecard checks now provide **shared evidence** where a security
practice also substantiates another health dimension. Scorecard remains fully
risk-weighted in [Security posture](/wiki/security-posture); seven selected
checks additionally receive small, documented weights in their destination
metrics: `Maintained`, `Signed-Releases`, `Contributors`, `Code-Review`,
`License`, `CI-Tests`, and `Pinned-Dependencies`.

This is intentional cross-category influence, not a reuse of Scorecard's
security-risk weights. A check reported as `n/a`, or unavailable Scorecard
data, is excluded from the destination metric and its remaining components
are renormalized. This release changes affected repository scores; reports
remain reproducible through their recorded `metrics_version`.

### 0.9.0 — 2026-07-07

The [security posture](/wiki/security-posture) fallback stopped treating a
missing dependency lockfile as a fault for published libraries. Lockfiles are
an application-level practice; many libraries and gems correctly omit them.
For those repositories, the fallback component is now excluded and the
remaining components renormalize. The OpenSSF Scorecard path was unchanged.

### 0.8.0 — 2026-06-30

Added the **[AI Readiness](/wiki/ai-readiness)** category with four metrics:
([agent context](/wiki/ai-agent-context), [verify loop](/wiki/ai-verify-loop),
[code legibility](/wiki/ai-code-legibility), [interfaces](/wiki/ai-interfaces))
assessing whether a repository supports reliable AI-assisted development. The
category carries weight 0.0: it is an independent, additive badge and never
changes the overall health index. Existing repository formulas were unchanged.

### 0.7.0 — 2026-06-20

Supported ecosystems extended. [Ecosystem adoption](/wiki/ecosystem-adoption)
falls back to lifetime total downloads when a registry publishes no monthly
figure (RubyGems), so Ruby and Hex packages now receive adoption values.
RubyGems and Hex registry adapters added; declared-dependency parsing extended
to Go, Maven, RubyGems, NuGet, and Hex. See
[supported ecosystems](/wiki/supported-ecosystems).

### 0.6.0 — 2026-06-09

[Security posture](/wiki/security-posture) rebuilt on the **OpenSSF
Scorecard**: tool-agnostic, risk-weighted checks that no longer penalize
projects for using non-GitHub tooling, with inconclusive checks excluded
rather than counted as zero. Coarse file-tree checks remain as a fallback.
Only the Security category affected.

### 0.5.0 — 2026-05-29

Package-ecosystem metrics added: [ecosystem adoption](/wiki/ecosystem-adoption)
(registry downloads) in Community & Adoption and
[package maintenance](/wiki/package-maintenance) (publish recency,
deprecation) in Sustainability & Governance. Both are `null` for repositories
that publish no package. Category inner weights rebalanced; category weights
and other formulas unchanged.

### 0.4.0 — 2026-05-18

Metrics regrouped into five weighted **categories** with rolled-up values.
Four new repository metrics: [release discipline](/wiki/release-discipline),
[popularity](/wiki/popularity), [stewardship](/wiki/stewardship), and
[documentation](/wiki/documentation). `activity` renamed
[development activity](/wiki/development-activity). The overall index now
rolls up categories rather than individual metrics.

### 0.3.0 — 2026-05-06

Organization metrics added — profile completeness, portfolio activity,
community reach, and an organization overall (see
[organization assessment](/wiki/organization-assessment)). Repository
formulas unchanged.

### 0.2.0 — 2026-04-25

Per-component results added to every metric, so a report shows exactly which
criteria passed, partially passed, or were excluded. Formulas, weights, and
band thresholds unchanged from 0.1.0.

### 0.1.0 — 2026-04-15

Initial methodology.

## What versioning guarantees

- **Reproducibility** — a report plus its recorded version fully determines
  how every value was computed.
- **Comparability** — two repositories inspected under the same version are
  measured by identical rules.
- **Accountability** — methodology changes are public, dated, and explained;
  there are no silent adjustments.

Related: [the health index](/wiki/health-index) ·
[rating bands](/wiki/scoring-bands) ·
[scan configuration](/wiki/scan-configuration)
