mirror of
https://github.com/storytold/craft-ai-integrations.git
synced 2026-11-02 18:06:49 +00:00
8d74c5d2b9
* feat(ai-core): share the image.segment request and result contract * fix(ai-core): take only an inline PNG as the selection mask * feat(ai-engine-rten): bounded picture decoding, mask encoding and resampling for selection models * feat(ai-engine-rten): run SAM 2.1 through the shared selection contract * fix(ai-engine-rten): bound a thin picture's memory, refuse extreme sides, and make the mask size fallible * feat(ai-features): let each built-in engine follow its own recipe A built-in engine now plans, offers, registers and checks files from the first usable recipe that lists it (`Feature::engine_recipe`), instead of every engine acting on the first usable recipe. A first recipe that lists one engine no longer hides a later recipe that lists another. The plain built-in offer and engine advice still start from the first usable recipe, and `Feature::engines` lists every engine some usable recipe names, once each, in catalogue order. The catalogue is unchanged, so no behaviour changes today; the tests build the two-recipe shape from the real SAM 3 recipe. * fix(ai-engine-rten): judge a match on the mask handed on, not on the raw logits A review finding: matched was set from the model's raw logits before resampling and 8-bit quantization, so one positive logit that a small picture never samples reported a match with an all-black mask. The match is now whether any pixel of the emitted mask is above half, using the same quantization as the PNG. Written first and seen to fail (matched stayed true for a speck at logit 8 in a 10 by 6 picture). The runner's raw-logit test stays as a shortcut that skips the resampling; forcing it open gives the same answer, so its mutation case is retired with the reason in the group header. * docs(mutation): point the usage text at GROUPS instead of a list that was out of date A review finding: the usage line named only the early groups and left out rt, which is new here, and also seg, gs and others. A list in the usage text goes stale each time a group is added, so it now says to take the group from GROUPS and README.md.
25 lines
4.0 KiB
Python
25 lines
4.0 KiB
Python
"""Deliberate-bug cases for group `ns`: built-in file discovery, the setup plan and installation.
|
|
|
|
Loaded by mutation_check.py. Each case breaks one rule and names the test that should notice.
|
|
All transfers are scripted localhost or tiny cached test files.
|
|
Format: (name, file, old, new, package, test target, test filter).
|
|
"""
|
|
NS = [
|
|
('native-option-without-engine-is-actionable', 'crates/ai-client/src/picker_groups.rs', 'if client.has_adapter(provider) {', 'if true {', 'craft-ai-client', 'picker_native', 'the_builtin_model_only_offers_setup'),
|
|
('native-files-mixed-across-directories', 'crates/ai-client/src/folders/native.rs', 'candidates.entry(dir.to_owned())', 'candidates.entry(root.to_owned())', 'craft-ai-client', 'folders', 'native_files_in_separate_directories'),
|
|
('native-default-allows-linked-folder', 'crates/ai-client/src/folders/native.rs', '.find(|f| f.default && f.origin == FolderOrigin::Chosen)', '.find(|f| f.default)', 'craft-ai-client', 'folders', 'native_downloads_go_only'),
|
|
('native-unusable-recipe-allowed', 'crates/ai-client/src/folders/native.rs', '.engine_recipe(provider)\n .and_then(|recipe| {', '.locals\n .first()\n .and_then(|recipe| {', 'craft-ai-client', 'native_install', 'an_unusable'),
|
|
('native-discovery-fails-on-a-gone-folder', 'crates/ai-client/src/folders/native.rs', 'Err(ScanError::NotAFolder) => continue,', 'Err(ScanError::NotAFolder) => return Err(AiError::invalid("gone")),', 'craft-ai-client', 'folders', 'has_gone'),
|
|
('native-cancel-before-start-ignored', 'crates/ai-client/src/folders/native.rs', 'if request.cancel.load(Ordering::Relaxed) {', 'if false {', 'craft-ai-client', 'native_install', 'cancelled_before_start'),
|
|
('native-licence-skipped', 'crates/ai-client/src/folders/native.rs', ' if !request.licences_accepted\n && route\n .models\n .iter()\n .any(|model| model.licence.accept_required)\n {', ' if false {', 'craft-ai-client', 'native_download', 'declining_a_licence'),
|
|
('native-cached-install-not-rehashed', 'crates/ai-client/src/folders/native.rs', 'verify_file(&path, model, request.cancel, &mut progress)?;', 'let _ = path;', 'craft-ai-client', 'folders', 'native_install_requires_licence'),
|
|
('native-existing-files-not-rehashed', 'crates/ai-client/src/folders/native.rs', ' verify_file(&directory.join(&file.filename), file, cancel, &mut |p| {\n progress(index, p)\n })?;', ' let _ = (index, file, cancel, &mut *progress);', 'craft-ai-client', 'native_install', 'existing_files_are_hashed'),
|
|
('native-recipe-filename-can-escape', 'crates/ai-client/src/folders/native.rs', 'if route.models.iter().any(|file| {', 'if false && route.models.iter().any(|file| {', 'craft-ai-client', 'native_install', 'a_recipe_filename_cannot_escape'),
|
|
('native-scan-lists-any-small-file', 'crates/ai-comfy-env/src/model_folder_scan.rs', '!(is_model_file(&name) || is_known)', '!(is_model_file(&name) || true)', 'craft-ai-comfy-env', 'lib', 'a_known_bundle_file'),
|
|
('native-scan-known-name-ignores-size', 'crates/ai-comfy-env/src/model_folder_scan.rs', 'k.size == meta.len() && k.filename.eq_ignore_ascii_case(&name)', 'k.filename.eq_ignore_ascii_case(&name)', 'craft-ai-comfy-env', 'lib', 'a_known_bundle_file'),
|
|
('native-known-bundle-file-counted-unrecognised', 'crates/ai-comfy-env/src/model_folder_scan.rs', '} else if basis.is_none() {', '} else {', 'craft-ai-comfy-env', 'lib', 'a_known_bundle_file'),
|
|
('native-picker-hides-setup-when-the-file-is-gone', 'crates/ai-client/src/picker_groups.rs', '.is_some_and(|file| Path::new(file).is_file())', '.is_some()', 'craft-ai-client', 'picker_native', 'file_is_gone'),
|
|
('native-picker-matches-any-connection-of-the-runtime', 'crates/ai-client/src/picker_groups.rs', '&& c.id.as_str() == native_connection_id(feature, provider)', '&& true', 'craft-ai-client', 'picker_native', 'another_model'),
|
|
('native-picker-ignores-the-model-id', 'crates/ai-client/src/picker_groups.rs', '&& m.id.as_str() == current)', '&& true)', 'craft-ai-client', 'picker_native', 'older_model'),
|
|
]
|