Release
v3.1.2
thresholda hardening release. A second adversarial cross-examination of the codebase, plus a new check at the threshold of every run — the versions a coupling would write are proven against the registries before a single fix is planned — so a config typo or a subtle edge case is caught at the door rather than in a customer's build.
Highlights
- 01
Coupling versions are checked before the run starts
Every version a couplings rule could write into a POM is verified against the configured registries at the first step. A typo (a companion floor no registry publishes) now stops the run naming the rule, instead of silently withholding the trigger's own legitimate fix on every run — or, in report-only mode, writing an unbuildable patch and exiting green. Registry errors and empty listings warn and proceed; only a confirmed absence fails.
- 02
Runs survive cancels, hung builds, and throttling
Maven subprocesses run as their own process group, so a CI cancel or timeout kills forked test JVMs and app servers instead of letting them hold the run open. SIGINT/SIGTERM cancel gracefully so cleanup and telemetry flush still happen. The GitLab client honours 429 Retry-After, and permanent registry auth failures are no longer retried as transient or published as unvalidated MRs.
- 03
npm never closes a still-wanted merge request
An npm run that defers plans because of the MR budget, or because a stale registry answer flipped a fix to unfixable for one run, no longer closes the deferred plans' open MRs — matching the guard the Maven pipeline has had since ADR-039. And a dependency pinned to a git fork, local path, or npm: alias is never silently rewritten to a registry version.
- 04
Couplings and reactors do the right thing throughout
Coupling comparisons use the version each library actually resolves to, the final remediation pass applies couplings, and every re-render path rebuilds companion edits so a merge request never advertises a companion its diff omits. In reactors, a fix no longer downgrades a module already on a newer safe version, and a transitive override reaches every module that pins the coordinate in its own dependencyManagement.
Full notes
Added
- Startup preflight: coupling companion versions are proven against the configured registries before planning; a version no registry publishes fails the run naming the rule, coordinate, and latest available version.
- Three new end-to-end regression cases covering the couplings feature, the reactor module-level dependencyManagement shape, and the npm MR-budget deferral guard.
Fixed
- Maven subprocesses run as process-group leaders so a cancel or timeout kills forked grandchildren (test JVMs, app servers) instead of hanging the run past its timeout.
- SIGINT/SIGTERM cancel the run gracefully so deferred cleanup and the telemetry flush still happen; a second signal exits immediately.
- Permanent Maven failures (401/403/404 auth, absent artifacts) are no longer retried as transient nor published as an unvalidated inconclusive merge request.
- The GitLab client retries 429 responses honouring Retry-After and re-sending the body, so a rate-limited fan-out no longer strands half-published runs.
- npm reconciliation is deferred (not closing still-wanted MRs) when plans were held back by the MR budget or a non-moving staging regeneration.
- A direct npm dependency pinned to a non-registry specifier (git, file, github, npm: alias, tarball) is never rewritten to a registry version.
- Coupling companion and trigger comparisons use the version each coordinate actually resolves to rather than a BOM's release-train number, and an unfixable plan no longer blocks a real companion.
- The final remediation pass applies couplings (single-POM and reactor), and aggregation, final-pass, and reactor re-render paths rebuild companion edits so an MR never advertises a companion its diff omits; a re-rendered governor import keeps its reclaim comment.
- A reactor Bump no longer downgrades a module already on a newer safe version, and a transitive Override reaches every module that self-manages the coordinate in its own dependencyManagement, not only the root.