Install-time summary¶
With the plugin installed, composer require, composer update and
composer install print a block above Composer's operations list. It covers only the packages the
transaction installs or updates, not the whole lock. It never fails the install unless you set
install-time-strict.
| To | Use |
|---|---|
| See why one package is flagged | composer lockrot --explain=<package> (explaining one package) |
| Accept what is flagged | A baseline |
| Never flag one package | The allowlist |
| Turn the block off for a project | "install-time": "off" in extra.lockrot |
| Silence all of lockrot for one command | LOCKROT_DISABLE=1: not even the skipped line prints |
| Give the check more or less time | install-time-budget, in seconds |
Stop the install on a finding at fail-on |
"install-time-strict": true |
The block has this shape, on stderr; example-run.md shows a recorded run of the full report:
lockrot: dependency rot in <flagged> of <changed> changed packages
<verdict> <package> <version>: <evidence>
<verdict> <package> <version>: <evidence> (via <direct> > <intermediate>)
… and <n> more
note: <note text>
Run composer lockrot for details.
At most ten lines, always¶
The block is at most ten lines, in this order:
- the header;
- one line per flagged package, in the report's order (highest priority
first), cut with
… and <n> morewhen they do not fit; - up to three of the run's notes, in the order the run wrote them (run notes);
- the footer,
Run composer lockrot for details.
Lines are counted as written, not as terminal rows: a long line can wrap in a narrow terminal.
A transitive package's line ends with the chain that pulls it in, (via a > b), resolved through
the whole lock. The block does not show the other direct requirements that reach the package, or,
for a direct requirement, the flagged packages it pulls in (S7). composer lockrot shows both
(transitive exposure).
An extra.lockrot key lockrot does not read adds one lockrot: unknown key … line above the
block, outside its ten, whether or not anything is flagged
(unknown keys). It prints whenever the block would run: not under
LOCKROT_DISABLE, not with install-time: off, and only for a transaction that installs or
updates something.
Never silent about a package it could not check¶
A package whose metadata never arrived is unknown, which is not flagged. When nothing is
flagged but the run had a network failure (a note with sets_network_failures: true), a short
block prints instead of nothing:
| Header | When |
|---|---|
lockrot: <n> of <m> changed packages could not be checked |
<n> packages are unknown |
lockrot: <m> changed packages checked, one check incomplete |
Metadata arrived for every package, and a later lookup failed: advisories, a monorepo parent's metadata, or a repository host |
Up to three notes and the footer follow the header. They are the run's first notes, so the one
behind the failure can fall past the cut. composer lockrot --format=json lists every note, each
with its sets_network_failures (run notes).
Silence means nothing is flagged and no note is a network failure. It does not mean every check ran: skipped repository activity, a skipped advisory check or the anonymous cap (run notes) prints nothing on its own. The unknown-key line still prints.
Time budget¶
Once install-time-budget seconds have passed, the install-time check starts no new metadata or
advisory request, and repository-activity requests are cut to the time left. A request already
running finishes first, so an install can take somewhat longer than the budget. composer lockrot
has no budget.
The default is 5 seconds (range). The install-time keys
have no CLI option and no environment override.
When the budget runs out, a verdict that needs repository activity (S3, S4) can read milder than
the one composer lockrot gives for the same package.
| The budget ran out before or during | Effect on the block | Note |
|---|---|---|
| A package's metadata | The package is unknown; when nothing is flagged, the could-not-be-checked header counts it |
metadata_unavailable, a network failure |
| The advisory check | A priority an advisory would raise stays one step lower | advisories_not_checked |
| A monorepo parent's metadata | Split packages whose own tags have no trusted date stay unmeasured and carry S10 undated_releases (dates from the monorepo) |
None |
| The repository activity check, before it began | S3 and S4 are not read; findings carry S10 install_time_budget |
repository_activity_not_checked |
| The repository activity check, part way | Requests still running are cut to the time left; those that time out have no activity, and their findings carry S10 fetch_failed |
repository_activity_unreachable, a network failure |
composer require and composer update reuse the metadata Composer has just fetched in the same
process, so they rarely run out. A composer install with a cold cache on a large lock, such as a
fresh clone or a CI job, can run out before every package is checked. Raise the budget for such a
lock, or lower it to spend less time checking.
When the install continues and when it stops¶
| Symptom | Cause | Install | What to do |
|---|---|---|---|
| A note in the block | Something the run could not see: an unreachable repository, an exhausted budget, a missing token | Continues, unless install-time-strict is on with fail-on: unchecked and a finding carries S10 |
Look up its code in run notes |
One lockrot: install-time check skipped: … line |
lockrot could not run the check: a malformed extra.lockrot or lockrot environment variable, an unreadable composer.lock, an unreadable baseline file, an extra.lockrot.baseline naming a missing one, or a defect in lockrot |
Continues, and install-time-strict does not apply |
Run composer lockrot; for a configuration problem it names the problem and exits 2 (exit codes) |
lockrot: findings at or above fail-on=… and Composer exits 1 |
install-time-strict is on and a finding reaches fail-on |
Stopped | See after a stop |
install-time-strict¶
install-time-strict needs a fail-on, from LOCKROT_FAIL_ON or extra.lockrot.fail-on; without
one, nothing is stopped. When a finding reaches fail-on, lockrot stops the transaction before any
package operation runs, and Composer exits 1. Choosing --fail-on covers the values.
- A finding in the baseline does not stop the install unless its verdict is worse than the baseline recorded. The block lists both kinds.
- A gap in what the run could see stops the install only through
fail-on: unchecked, which matches every finding that carries S10 (what was not checked). A repository-activity gap adds S10no_token,anonymous_budget,rate_limit,fetch_failedorinstall_time_budget; a monorepo parent that never arrived addsundated_releasesto the split packages it would date. Such a finding can beokand missing from the block. Advisory gaps andmetadata_unavailabledo not stop the install on their own, and--strict-networkhas no install-time counterpart. --dry-runis never stopped, since no operation is about to run.
A stopped composer require or composer update leaves composer.lock updated (and, for
require, composer.json) and nothing new in vendor/. composer install then stops on the same
finding. Either:
- undo the change: run
composer remove <package>, or restorecomposer.jsonandcomposer.lockfrom version control; - or, for a flagged finding, accept it into the baseline, then run
composer install; - or allowlist the package (the allowlist), then run
composer install.
A baseline covers only flagged findings: a fail-on: unchecked stop on an ok or unknown
finding clears through the allowlist, or, for a repository-activity gap, when that check runs (set a
token, raise the budget or rerun).
Under --dry-run¶
Under composer require --dev … --dry-run, a package absent from the lock on disk is treated as
production, so its priority can read one step high. composer lockrot on
the real lock has the flag.
Related¶
- configuration.md — the
install-time,install-time-strictandinstall-time-budgetkeys - notes.md — every note the block can print, and which are network failures
- baseline.md — how the baseline applies at install time
- verdicts.md — what the verdicts and priorities mean
- example-run.md — a recorded run of the full report the footer points to