from __future__ import annotations from review_agent.models import FileSummaryBatch from review_agent.regulatory_review.schemas import Finding def run_completeness_check(batch: FileSummaryBatch, rule_set: dict) -> list[Finding]: items = list(batch.items.order_by("file_index")) findings: list[Finding] = [] for requirement in rule_set.get("requirements", []): if requirement.get("type") not in {"required", "conditional", "recommended", "chapter", "directory"}: continue matched = [ item for item in items if _matches_item( item.file_name, item.relative_path, item.directory_level, [*requirement.get("file_keywords", []), *requirement.get("aliases", [])], ) ] if matched: continue findings.append( Finding( rule_code=requirement["code"], category=requirement.get("category", "completeness"), severity=requirement.get("severity", "medium"), title=f"缺少{_numbered_title(requirement)}", detail=f"当前文件汇总批次未发现{_numbered_title(requirement)}。", suggestion=requirement.get("suggestion", ""), evidence={ "requirement_type": requirement.get("type"), "matched_files": [], "searched_keywords": requirement.get("file_keywords", []), "searched_fields": ["file_name", "relative_path", "directory_level"], }, ) ) return findings def _matches_item(file_name: str, relative_path: str, directory_level: str, keywords: list[str]) -> bool: haystack = f"{file_name} {relative_path} {directory_level}".lower() return any(str(keyword).lower() in haystack for keyword in keywords) def _numbered_title(requirement: dict) -> str: attachment4_code = requirement.get("attachment4_code") if not attachment4_code: return requirement["title"] return f"{attachment4_code}{requirement['title']}"