From 38706a6f0ceb773d473c4f5ddebf49e8e5ae46dc Mon Sep 17 00:00:00 2001 From: nsfisis Date: Sun, 3 May 2026 22:07:34 +0900 Subject: fix(update): apply --minimal-changes via policy preferred versions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous implementation pinned every resolved package back to its locked version after the resolve, which discarded the new versions the solver had to pick when a root constraint moved off the lock (e.g. a require bumped from `1.*` to `2.*`). The lock effectively never moved, so transitive cascades from a forced root-level update were lost. Mirror Composer's `Installer::createPolicy(forUpdate=true, minimalUpdate=true)` instead: thread the lock's `name → normalized version` map through the policy as `preferred_versions`. The solver now picks the locked version as a tiebreaker when it still satisfies the active constraints, but moves freely when a constraint forces a different version. Drop the post-process hook entirely. --- crates/mozart-registry/src/lockfile.rs | 1 + crates/mozart-registry/src/resolver.rs | 22 ++++++++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) (limited to 'crates/mozart-registry') diff --git a/crates/mozart-registry/src/lockfile.rs b/crates/mozart-registry/src/lockfile.rs index 701a6f7..197335f 100644 --- a/crates/mozart-registry/src/lockfile.rs +++ b/crates/mozart-registry/src/lockfile.rs @@ -1680,6 +1680,7 @@ mod tests { locked_packages: Vec::new(), block_abandoned: false, root_branch_alias: None, + preferred_versions: IndexMap::new(), }; let resolved = resolve(&resolve_request) diff --git a/crates/mozart-registry/src/resolver.rs b/crates/mozart-registry/src/resolver.rs index 66e923d..33c3659 100644 --- a/crates/mozart-registry/src/resolver.rs +++ b/crates/mozart-registry/src/resolver.rs @@ -733,6 +733,11 @@ pub struct ResolveRequest { /// alias's version for any link originally written as `self.version`. /// `None` when the root carries no matching `branch-alias` entry. pub root_branch_alias: Option, + /// `name → normalized version` map fed to the policy's preferred-version + /// override. Used by `update --minimal-changes` so the solver only moves + /// a package when a constraint actually forces a different version. + /// Empty for a normal full update. + pub preferred_versions: IndexMap, } /// Full data for a lock-pinned package, used in partial updates. Carried on @@ -1337,8 +1342,20 @@ pub async fn resolve(request: &ResolveRequest) -> Result, R return Err(ResolveError::NoSolution(report)); } - // Create policy and solve - let policy = DefaultPolicy::new(request.prefer_stable, request.prefer_lowest); + // Create policy and solve. When `preferred_versions` is non-empty (the + // `--minimal-changes` flow) feed it through the policy so the locked + // version wins over the regular highest/lowest pick whenever a candidate + // matches it. Mirrors Composer's + // `Installer::createPolicy` minimal-update branch. + let policy = if request.preferred_versions.is_empty() { + DefaultPolicy::new(request.prefer_stable, request.prefer_lowest) + } else { + DefaultPolicy::with_preferred( + request.prefer_stable, + request.prefer_lowest, + request.preferred_versions.clone(), + ) + }; let fixed_set: IndexSet = fixed_ids.into_iter().collect(); let solver = Solver::new(rules, &pool, policy, fixed_set); @@ -1786,6 +1803,7 @@ mod tests { locked_packages: Vec::new(), block_abandoned: false, root_branch_alias: None, + preferred_versions: IndexMap::new(), }; let result = resolve(&request).await; -- cgit v1.3.1