diff --git a/crates/legolas-cli/src/reporters/sarif.rs b/crates/legolas-cli/src/reporters/sarif.rs index 8a11dd4..bd983e5 100644 --- a/crates/legolas-cli/src/reporters/sarif.rs +++ b/crates/legolas-cli/src/reporters/sarif.rs @@ -165,13 +165,13 @@ fn duplicate_package_record( &item.finding, match language { ReportLanguage::Ko => format!( - "{} 중복 버전 {} (정리 가능 {} KB)", + "{} 중복 버전 {} (방향성 정리 후보 {} KB)", item.name, item.versions.join(", "), item.estimated_extra_kb ), ReportLanguage::En => format!( - "{} duplicated across {} ({} KB avoidable)", + "{} duplicated across {} ({} KB duplicate dependency pressure)", item.name, item.versions.join(", "), item.estimated_extra_kb diff --git a/crates/legolas-cli/src/reporters/text.rs b/crates/legolas-cli/src/reporters/text.rs index 9a69109..d556948 100644 --- a/crates/legolas-cli/src/reporters/text.rs +++ b/crates/legolas-cli/src/reporters/text.rs @@ -1287,7 +1287,7 @@ fn duplicate_scope_summary_ko(scope: DuplicateImpactScope) -> &'static str { fn duplicate_scope_summary_en(scope: DuplicateImpactScope) -> &'static str { match scope { - DuplicateImpactScope::ProductionLikely => "initial payload candidate", + DuplicateImpactScope::ProductionLikely => "directional initial payload cleanup candidate", DuplicateImpactScope::DevOnly => { "development/test dependency duplication, dependency hygiene" } @@ -1305,8 +1305,13 @@ fn duplicate_context_headline( duplicate.name, duplicate.versions.join(", ") ), - (ReportLanguage::Ko, _) => format!( - "{} 버전 중복 정리 ({})", + (ReportLanguage::Ko, DuplicateImpactScope::ProductionLikely) => format!( + "{} 방향성 중복 정리 후보 ({})", + duplicate.name, + duplicate.versions.join(", ") + ), + (ReportLanguage::Ko, DuplicateImpactScope::Unknown) => format!( + "{} 방향성 중복 정리 검토 ({})", duplicate.name, duplicate.versions.join(", ") ), @@ -1315,8 +1320,13 @@ fn duplicate_context_headline( duplicate.name, duplicate.versions.join(", ") ), - (ReportLanguage::En, _) => format!( - "Deduplicate {} versions ({})", + (ReportLanguage::En, DuplicateImpactScope::ProductionLikely) => format!( + "Review {} duplicate dependency pressure ({})", + duplicate.name, + duplicate.versions.join(", ") + ), + (ReportLanguage::En, DuplicateImpactScope::Unknown) => format!( + "Review {} directional duplicate cleanup ({})", duplicate.name, duplicate.versions.join(", ") ), @@ -1347,7 +1357,7 @@ fn duplicate_action_headline( duplicate.estimated_extra_kb ), (ReportLanguage::En, _) => format!( - "Deduplicate {} versions ({}) to recover roughly {} KB.", + "Review {} duplicate versions ({}) as a directional cleanup candidate for roughly {} KB of dependency pressure.", duplicate.name, duplicate.versions.join(", "), duplicate.estimated_extra_kb diff --git a/crates/legolas-cli/tests/sarif_contract.rs b/crates/legolas-cli/tests/sarif_contract.rs index 77fb7db..83f9770 100644 --- a/crates/legolas-cli/tests/sarif_contract.rs +++ b/crates/legolas-cli/tests/sarif_contract.rs @@ -105,6 +105,10 @@ fn scan_sarif_preserves_rule_ids_locations_and_metadata() { .iter() .find(|result| result["ruleId"] == "duplicate-package:lodash") .expect("duplicate result"); + assert_eq!( + duplicate["message"]["text"], + json!("lodash 중복 버전 4.17.20, 4.17.21 (방향성 정리 후보 18 KB)") + ); assert!(duplicate.get("locations").is_none()); assert_eq!( duplicate["properties"]["analysisSource"], @@ -116,6 +120,27 @@ fn scan_sarif_preserves_rule_ids_locations_and_metadata() { duplicate["properties"]["recommendedFix"]["kind"], json!("dedupe-package") ); + let duplicate_property_keys = duplicate["properties"] + .as_object() + .expect("duplicate properties") + .keys() + .cloned() + .collect::>(); + assert_eq!( + duplicate_property_keys, + BTreeSet::from([ + "actionPriority".to_string(), + "analysisSource".to_string(), + "confidence".to_string(), + "count".to_string(), + "estimatedExtraKb".to_string(), + "evidence".to_string(), + "name".to_string(), + "origins".to_string(), + "recommendedFix".to_string(), + "versions".to_string(), + ]) + ); } #[test] @@ -164,6 +189,21 @@ fn scan_sarif_language_flag_changes_human_text_not_rule_ids() { chart_js_rule["shortDescription"]["text"], json!("Review chart.js upfront bundle weight") ); + + let duplicate = en_results + .iter() + .find(|result| result["ruleId"] == "duplicate-package:lodash") + .expect("duplicate result"); + let duplicate_message = duplicate["message"]["text"] + .as_str() + .expect("duplicate message"); + assert_eq!( + duplicate_message, + "lodash duplicated across 4.17.20, 4.17.21 (18 KB duplicate dependency pressure)" + ); + assert!(!duplicate_message.contains("avoidable")); + assert!(!duplicate_message.contains("payload")); + assert!(!duplicate_message.contains("savings")); } #[test] diff --git a/crates/legolas-cli/tests/text_report_parity.rs b/crates/legolas-cli/tests/text_report_parity.rs index c9ba693..8f0fdef 100644 --- a/crates/legolas-cli/tests/text_report_parity.rs +++ b/crates/legolas-cli/tests/text_report_parity.rs @@ -403,7 +403,7 @@ fn english_scan_report_renders_dev_only_duplicates_as_dependency_hygiene() { } #[test] -fn scan_report_confirms_production_likely_duplicate_savings_without_other_findings() { +fn scan_report_frames_production_likely_duplicate_pressure_as_directional() { let mut analysis = base_analysis("production-duplicate-app"); analysis.duplicate_packages = vec![DuplicatePackage { name: "lodash".to_string(), @@ -427,7 +427,11 @@ fn scan_report_confirms_production_likely_duplicate_savings_without_other_findin assert!(ko_report.contains("초기 페이로드 절감 후보")); assert!(en_report.contains("Confirmed initial payload savings: not confirmed")); assert!(!en_report.contains("Confirmed initial payload savings: ~48 KB")); - assert!(en_report.contains("initial payload candidate")); + assert!(en_report.contains("directional initial payload cleanup candidate")); + assert!(en_report.contains( + "Review lodash duplicate dependency pressure (4.17.20, 4.17.21) [medium | high confidence | ~48 KB]" + )); + assert!(!en_report.contains("to recover roughly 48 KB")); } #[test]