From 442cfc0e511dc04d53e89e9ee62027f69086d769 Mon Sep 17 00:00:00 2001 From: Igor Apresov Date: Fri, 14 Aug 2026 17:20:40 +0300 Subject: [PATCH] fix(load): unblock first load of an absent extension MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - classify Designer's "Конфигурация 'Расширение конфигурации' недоступна" as NotSupported, so `load --mode load` proceeds on the first load of an extension the infobase does not carry yet instead of failing the compatibility probe with `failed to determine infobase compatibility state` - switch the probe classifier to Unicode `to_lowercase`; `to_ascii_lowercase` leaves Cyrillic untouched, so every Russian branch silently never matched a capitalised platform diagnostic - cover the absent-extension wording in ru and en, and keep unrelated extension probe failures classified as Unknown --- src/use_cases/load_artifact.rs | 63 ++++++++++++++++++++++++++++------ 1 file changed, 52 insertions(+), 11 deletions(-) diff --git a/src/use_cases/load_artifact.rs b/src/use_cases/load_artifact.rs index 79319cc..574a636 100644 --- a/src/use_cases/load_artifact.rs +++ b/src/use_cases/load_artifact.rs @@ -503,7 +503,10 @@ fn classify_probe_failure( target_kind: LoadTargetKind, combined_output: &str, ) -> CompatibilityState { - let lower = combined_output.to_ascii_lowercase(); + // Unicode-aware on purpose: the platform capitalises its Russian + // diagnostics, and `to_ascii_lowercase` leaves Cyrillic untouched, so every + // Russian branch below would silently never match. + let lower = combined_output.to_lowercase(); match target_kind { LoadTargetKind::Configuration => { if lower.contains("vendorconfiguration") @@ -517,15 +520,19 @@ fn classify_probe_failure( } } LoadTargetKind::Extension => { - if (lower.contains("extension") || lower.contains("расширен")) - && (lower.contains("not found") || lower.contains("не найден")) - { - CompatibilityState::NotSupported - } else if (lower.contains("extension") || lower.contains("расширен")) - && (lower.contains("not supported") - || lower.contains("unsupported") - || lower.contains("не поддерж")) - { + let mentions_extension = lower.contains("extension") || lower.contains("расширен"); + // An extension the infobase does not carry yet. Designer reports it + // as "Конфигурация 'Расширение конфигурации' недоступна", which is + // the normal state before the very first load. + let absent = lower.contains("not found") + || lower.contains("не найден") + || lower.contains("unavailable") + || lower.contains("not available") + || lower.contains("недоступ"); + let unsupported = lower.contains("not supported") + || lower.contains("unsupported") + || lower.contains("не поддерж"); + if mentions_extension && (absent || unsupported) { CompatibilityState::NotSupported } else { CompatibilityState::Unknown @@ -895,7 +902,7 @@ fn with_platform_log_artifact( #[cfg(test)] mod tests { - use super::{execute, resolve_request}; + use super::{classify_probe_failure, execute, resolve_request}; use crate::config::model::{ AppConfig, BuildConfig, BuilderBackend, PlatformToolConfig, SourceFormat, TestsConfig, ToolsConfig, @@ -981,6 +988,40 @@ mod tests { } } + /// Designer reports an absent extension as "Конфигурация 'Расширение + /// конфигурации' недоступна". A first load of an extension the infobase + /// does not have yet must classify as NotSupported so that `--mode load` + /// proceeds instead of failing the compatibility probe. + /// https://github.com/IngvarConsulting/unica/issues/355 + #[test] + fn absent_extension_probe_failure_classifies_as_not_supported() { + let combined = "Конфигурация 'Расширение конфигурации' недоступна"; + assert_eq!( + classify_probe_failure(LoadTargetKind::Extension, combined), + CompatibilityState::NotSupported + ); + } + + #[test] + fn absent_extension_probe_failure_classifies_as_not_supported_english() { + let combined = "Configuration 'Configuration extension' is unavailable"; + assert_eq!( + classify_probe_failure(LoadTargetKind::Extension, combined), + CompatibilityState::NotSupported + ); + } + + /// The widened wording must not turn an unrelated extension probe failure + /// into a silent NotSupported verdict. + #[test] + fn unrelated_extension_probe_failure_stays_unknown() { + let combined = "Ошибка при выполнении операции сравнения"; + assert_eq!( + classify_probe_failure(LoadTargetKind::Extension, combined), + CompatibilityState::Unknown + ); + } + #[cfg(unix)] #[test] fn resolve_request_rejects_unsupported_artifacts_and_missing_flags() {