fix: correct false breakage detection for flavored packages and confi… (#3149)

fix: correct false breakage detection for flavored packages and config changes

Two bugs caused the UI to incorrectly warn about dependency breakages:

1. dryUpdate (version path): Flavored package versions (e.g. #knots:27.0.0:0)
   failed exver.satisfies() against flavorless ranges (e.g. >=26.0.0) due to
   flavor mismatch. Now checks the manifest's `satisfies` declarations,
   matching the pattern already used in DepErrorService. Added `satisfies`
   field to PackageVersionInfo so it's available from registry data.

2. checkConflicts (config path): fast-json-patch's compare() treated missing
   keys as conflicts (add ops) and used positional array comparison, diverging
   from the backend's conflicts() semantics. Replaced with a conflicts()
   function that mirrors core/src/service/action.rs — missing keys are not
   conflicts, and arrays use set-based comparison.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Matt Hill
2026-03-29 13:07:52 -06:00
committed by GitHub
parent b0b4b41c42
commit e3b7277ccd
11 changed files with 69 additions and 13 deletions

View File

@@ -615,6 +615,7 @@ fn check_matching_info_short() {
sdk_version: None,
hardware_acceleration: false,
plugins: BTreeSet::new(),
satisfies: BTreeSet::new(),
},
icon: DataUrl::from_vec("image/png", vec![]),
dependency_metadata: BTreeMap::new(),

View File

@@ -110,6 +110,8 @@ pub struct PackageMetadata {
pub hardware_acceleration: bool,
#[serde(default)]
pub plugins: BTreeSet<PluginId>,
#[serde(default)]
pub satisfies: BTreeSet<VersionString>,
}
#[derive(Debug, Deserialize, Serialize, HasModel, TS)]

View File

@@ -197,7 +197,6 @@ impl TryFrom<ManifestV1> for Manifest {
Ok(Self {
id: value.id,
version: version.into(),
satisfies: BTreeSet::new(),
can_migrate_from: VersionRange::any(),
can_migrate_to: VersionRange::none(),
metadata: PackageMetadata {
@@ -219,6 +218,7 @@ impl TryFrom<ManifestV1> for Manifest {
PackageProcedure::Script(_) => false,
},
plugins: BTreeSet::new(),
satisfies: BTreeSet::new(),
},
images: BTreeMap::new(),
volumes: value

View File

@@ -32,7 +32,6 @@ pub(crate) fn current_version() -> Version {
pub struct Manifest {
pub id: PackageId,
pub version: VersionString,
pub satisfies: BTreeSet<VersionString>,
#[ts(type = "string")]
pub can_migrate_to: VersionRange,
#[ts(type = "string")]

View File

@@ -358,7 +358,7 @@ pub async fn check_dependencies(
};
let manifest = package.as_state_info().as_manifest(ManifestPreference::New);
let installed_version = manifest.as_version().de()?.into_version();
let satisfies = manifest.as_satisfies().de()?;
let satisfies = manifest.as_metadata().as_satisfies().de()?;
let installed_version = Some(installed_version.clone().into());
let is_running = package
.as_status_info()