Verdicts and priority¶
Every package in composer.lock gets exactly one verdict and one priority. The verdict says what
was observed about the package. The priority says how much that applies to your project.
The eight verdicts¶
| Verdict | Meaning | Signals |
|---|---|---|
abandoned |
The package's Composer repository marks it abandoned (Packagist by default), or its GitHub repository is archived | S1 or S3 |
silent |
No stable release for at least release-high-years (default 5y) and no repository push for at least push-high-years (default 5y); an archived repository is reported as abandoned instead |
S2 high AND S4 high, NOT S1, NOT S3 |
pinned |
Installed version is a branch snapshot (dev-* or #hash), or the package has no stable release at all |
S6 |
old-promise |
The installed version was released before the target PHP's GA date, and its require.php constraint is open-ended (>=N, *) for that target |
S5 |
stale |
Old release or old push, but not old enough (or not on both fronts) for silent |
one of S2/S4 |
unknown |
No data could be obtained (not found in any configured Composer repository, or all lookups failed) | — |
finished |
Matched the built-in or project allowlist — the package is complete by design, not neglected | allowlist match |
ok |
None of the above | — |
Severity order among the signal-derived verdicts, used by --fail-on and the baseline:
abandoned > silent > pinned > old-promise > stale > unknown > ok.
finished and ok sit equal and lowest in that ordering, and neither is ever a finding.
An allowlist match never competes in the order at all. It is checked before any signal is read and
always wins, so an allowlisted package reports finished whatever its signals say — see
configuration.md.
The signals¶
| Signal | What it observes |
|---|---|
| S1 | The Composer repository marks the package abandoned, sometimes naming a replacement |
| S2 | Time since the last stable release, against release-warn-years / release-high-years |
| S3 | The GitHub repository is archived |
| S4 | Time since the last repository push, against push-warn-years / push-high-years |
| S5 | The installed release predates the target PHP's GA date and the require.php constraint has no upper bound |
| S6 | The installed version is a branch snapshot (dev-*, #hash), or the package has no stable release |
S3 and S4 come from GitHub and need network access; see internals.md for how that data is fetched and cached, and configuration.md for the thresholds.
Every finding's evidence line states the concrete fact — release date, push date, constraint string — and the report footer states the data date. There are no severity words beyond the verdict names above.
Priority¶
A package reported the same way matters less when nothing in the project requires it directly, and less again when it is only ever installed for development.
Three rules, in order:
- A package the report does not flag (
unknown,finished,ok) has prioritynone. - Otherwise the verdict sets the base level:
abandonedandsilentstart at critical,pinnedandold-promiseat high,staleat medium. - The base drops one step when the package is transitive (nothing you require names it) and one more step when it is a development dependency. It never drops below low.
| Verdict | direct, prod | transitive, prod | direct, dev | transitive, dev |
|---|---|---|---|---|
abandoned, silent |
critical |
high |
high |
medium |
pinned, old-promise |
high |
medium |
medium |
low |
stale |
medium |
low |
low |
low |
unknown, finished, ok |
none |
none |
none |
none |
A package nothing in your require/require-dev can reach counts as transitive.
The priority orders the report — highest first, then by verdict severity, then direct dependencies ahead of transitive ones, then by package name — and it is carried in every format.
The exit code and
--fail-onstay on the verdict. Priority is there to tell you what to read first, not to decide whether the build fails.
--dev is what brings development packages into the run at all. Once they are in, each of them sits
one step below the same finding on a production package.
Priority in each format¶
| Format | How the priority appears |
|---|---|
table |
Findings are grouped under the priority level, highest group first |
json |
Each finding carries priority, direct and dev; the document carries a priorities object with all five counts next to counts |
github |
In each annotation's title: lockrot: abandoned (critical) |
gitlab |
Opens each issue's description: … — abandoned (critical): … |
markdown |
A first Priority column |
sarif |
The result's rank (critical 100.0, high 75.0, medium 50.0, low 25.0, none 0.0) plus properties.priority, properties.direct and properties.dev |
The JSON schema number stays 1 — these are additions, so anything already reading the document
keeps working.
Nothing that decides an outcome moved. The GitHub annotation level, the GitLab severity and
fingerprint, and the SARIF ruleId and level all still read the verdict alone.
Related¶
- example-run.md — a full run with every verdict in it
- configuration.md — the thresholds behind S2 and S4, and the allowlist
- baseline.md — accepting findings you have already decided to live with
- ci.md — exit codes and the six output formats