v0.9.0
Added
-
Published JSON schemas for every document lockrot writes for a machine, and the one it reads. The
--format=jsonreport (report-1.json), the--explaindocument (explain-1.json), the baseline file (baseline-1.json) andextra.lockrot(config-1.json). The report, the explanation and the baseline file now open with a$schemakey naming theirs, so an editor completes a baseline file as you type it and a CI step can validate a report with any draft-04 validator — no copy of lockrot required. The files ship underresources/in the repository and the PHAR. Objects are open: under one number a document only ever gains fields, so a report from a newer lockrot still validates against the copy you vendored earlier, and the number moves only when a field is removed or renamed —lockrot.schemastays1. The test suite validates what the formatters write, and every JSON sample in the docs, against these files, with a strict copy that rejects any undeclared field, so the published schema, the code and the docs cannot drift apart. See JSON schemas. -
A split package's release branches are dated by the monorepo they are cut from. Since 0.8.0 a tag sharing its commit with two others is read as undated, which killed the false
left-behindonilluminate/macroablebut also stopped measuring a branch that really did end. The monorepo's own tag for the same version carries the release date, andreplace: {illuminate/contracts: self.version}says the two are one release — so where a branch of the split package has no date, the branch of the same name in its parent supplies one. A lock onilluminate/contracts v5.8.36reported nothing in 0.8.0 and now reads:left-behind illuminate/contracts v5.8.36 direct branch 5.x last released 2020-08-18 (6.1 years ago, dated by laravel/framework); 12.x released v12.69.2 (2026-09-08); require ^12.69 to followEvery other Laravel component on a branch of its own is measured again rather than skipped. Laravel's late security tags on 6.x, 7.x and 8.x are recent enough that those branches read as current under the default thresholds: being measured is the difference, not the verdict.
The parent is taken from the lock when it is already there; otherwise it is loaded from the configured repositories, one request, and only when
resources/monorepo-parents.jsonlists that monorepo as carrying a package this lock needs dates for —laravel/framework,symfony/symfonyandcakephp/cakephp, with the components each replaces, refreshed bybin/refresh-monorepo-parents. A lock without such a package fetches nothing, and neither does one whose undated packages belong to no listed monorepo, which is the common case:symfony/polyfill-*is cut by a repository no Packagist package replaces. An install-time run that has used up its budget skips the request and the branch stays as it was. What a parent dates is its livereplacelist, never the snapshot.--format=jsoncarries the parent asdated_byon S8 and S2, and--explainmarks the branch rows it supplied.
Verify this release
curl -fsSL -O https://github.com/somework/lockrot/releases/download/v0.9.0/lockrot.phar
curl -fsSL -O https://github.com/somework/lockrot/releases/download/v0.9.0/lockrot.phar.sha256
sha256sum -c lockrot.phar.sha256
gpg --keyserver hkps://keys.openpgp.org --recv-keys 39ECC3F64AE8D06A9A63FD99AB6F7F52AE513141
curl -fsSL -O https://github.com/somework/lockrot/releases/download/v0.9.0/lockrot.phar.asc
gpg --verify lockrot.phar.asc lockrot.phar
gh attestation verify lockrot.phar --repo somework/lockrotOr rebuild it: check out v0.9.0, run build/build-phar.sh with Composer 2.10.3, and compare the sha256 — see the PHAR page.
Full changelog: CHANGELOG.md.