From 78849c2826c8fbd7d38e3797ac2bd15be9085d49 Mon Sep 17 00:00:00 2001 From: CTO Hermes Date: Sat, 30 May 2026 11:05:41 +0700 Subject: [PATCH] fix: use String for issue_type to handle LLM output variations LLMs return various forms (bugs, security, etc.) that don't match the strict enum variants. Switch issue_type to Option with serde aliases for both 'type' and 'issue_type' JSON fields. Also adds from_str_lossy() for manual parsing when needed. --- src/engine/types.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/engine/types.rs b/src/engine/types.rs index d791bba..c35383e 100644 --- a/src/engine/types.rs +++ b/src/engine/types.rs @@ -81,6 +81,21 @@ impl fmt::Display for IssueType { } } +impl IssueType { + /// Parse from string with lenient matching (accepts plural forms, etc.) + pub fn from_str_lossy(s: &str) -> Self { + match s.to_lowercase().as_str() { + "security" | "sec" => IssueType::Security, + "performance" | "perf" => IssueType::Performance, + "bug" | "bugs" => IssueType::Bug, + "best_practice" | "best-practice" | "bestpractice" | "best practice" => IssueType::BestPractice, + "style" | "formatting" => IssueType::Style, + "suggestion" | "info" => IssueType::Suggestion, + _ => IssueType::Suggestion, // fallback + } + } +} + /// A single review issue found in code #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ReviewIssue { @@ -88,8 +103,10 @@ pub struct ReviewIssue { #[serde(default)] pub line: Option, pub severity: Severity, + /// Issue type/category — stored as string since LLM output varies. + /// Common values: security, performance, bug, best_practice, style, suggestion #[serde(rename = "type", alias = "issue_type")] - pub issue_type: Option, + pub issue_type: Option, pub title: String, pub body: String, #[serde(default)]