The two source warts #1443 documented as observed-but-not-fixed, now fixed.
getComposerOutdatedPackages read from a different project than it ran against. It parsed composer.json from process.cwd(), but every composer command it feeds those constraints to runs through runCommand, which spawns with cwd: this.projectPath. Whenever cwd differs from the project path — exactly the situation a projectPath constructor argument exists for — the constraints came from one project and the outdated report from another. The read now uses this.projectPath, matching the caller's own existence check and every other file read in the class.
An empty group could reach the PR loop. groupUpdatesByConfig guarded the group push on the pre-filter array, then applied the per-group strategy filter — so a group whose strategy filtered out every claimed update (e.g. a patch-strategy group claiming only a minor bump) was still pushed with updates: []. Benign downstream, but a no-op entry in the PR loop. The push is now guarded on what survives the filter, and the pinned test asserts the emptied group is not emitted at all (the claimed-but-suppressed update still stays out of the default groups, as before).
Verification
Full single-process suite: 2380 pass / 0 fail across 145 files. Typecheck and pickier clean.
🤖 Generated with Claude Code