rules_tradeoffs.py
- Pfad:
/var/www/tools/ki-protokoll/claude-hook/quality/rules_tradeoffs.py
- Namespace: claude-hook.quality
- Zeilen: 252 | Größe: 7,265 Bytes
- Geändert: 2025-12-28 14:21:16 | Gescannt: 2025-12-31 10:22:15
Code Hygiene Score: 95
- Dependencies: 100 (25%)
- LOC: 82 (20%)
- Methods: 100 (20%)
- Secrets: 100 (15%)
- Classes: 100 (10%)
- Magic Numbers: 90 (10%)
Issues 1
| Zeile |
Typ |
Beschreibung |
| 217 |
magic_number |
Magic Number gefunden: 100 |
Dependencies 4
- extends Rule
- use re
- use typing.List
- use rule_base.Rule
Klassen 6
-
W10_1_AbstractFactoryWithoutDocs
class
Zeile 22
-
W10_2_EventDispatcherWithoutDocs
class
Zeile 57
-
W10_3_CacheWithoutStrategy
class
Zeile 96
-
W10_4_MultipleInheritanceWithoutDocs
class
Zeile 137
-
W10_5_ExternalServiceWithoutDocs
class
Zeile 165
-
W10_6_DeprecationWithoutMigration
class
Zeile 206
Code
#!/usr/bin/env python3
"""
Post-Hook Trade-off Documentation Regeln (WARN).
W10.x Regeln: Warnt bei Architektur-Mustern ohne Trade-off-Dokumentation.
Prinzip: "Make Trade-offs Explicit" (#10)
Diese Regeln erkennen komplexe Architektur-Entscheidungen und
warnen, wenn keine entsprechende Dokumentation vorhanden ist.
"""
import re
from typing import List
from .rule_base import Rule
# =============================================================================
# W10: TRADE-OFF DOCUMENTATION
# =============================================================================
class W10_1_AbstractFactoryWithoutDocs(Rule):
"""W10.1: Abstract Factory Pattern ohne @see ADR-Verweis."""
def __init__(self):
super().__init__(allowlist=[])
def check(self, file_path: str, content: str) -> List[str]:
warnings = []
# Erkennung: Abstract class mit Factory im Namen und create-Methoden
is_factory = bool(re.search(
r"abstract\s+class\s+\w*Factory",
content
)) or bool(re.search(
r"interface\s+\w*Factory",
content
))
if is_factory:
# Prüfe ob ADR-Referenz vorhanden
has_adr_ref = bool(re.search(
r"@see\s+ADR-\d+|ADR-\d+|Architecture Decision",
content,
re.IGNORECASE
))
if not has_adr_ref:
warnings.append(
"W10.1: Factory pattern without architecture documentation. "
"Add @see ADR-XXX reference explaining the design choice."
)
return warnings
class W10_2_EventDispatcherWithoutDocs(Rule):
"""W10.2: Event-basierte Architektur ohne Dokumentation."""
EVENT_PATTERNS = [
r"class\s+\w+Event\b",
r"implements\s+\w*EventSubscriber",
r"->dispatch\s*\(\s*new\s+\w+Event",
r"EventDispatcher",
]
def __init__(self):
super().__init__(allowlist=[
"/Framework/", # Framework definiert Event-System
])
def check(self, file_path: str, content: str) -> List[str]:
warnings = []
has_events = any(
re.search(pattern, content)
for pattern in self.EVENT_PATTERNS
)
if has_events:
has_docs = bool(re.search(
r"@see\s+ADR|Event\s+Flow|Event-Dokumentation",
content,
re.IGNORECASE
))
if not has_docs:
warnings.append(
"W10.2: Event-based architecture without documentation. "
"Consider documenting event flow with ADR."
)
return warnings
class W10_3_CacheWithoutStrategy(Rule):
"""W10.3: Caching ohne dokumentierte Invalidation-Strategie."""
CACHE_PATTERNS = [
r"->cache\s*\(",
r"Cache::",
r"setCache\s*\(",
r"apcu_",
r"redis",
r"memcache",
]
def __init__(self):
super().__init__(allowlist=[
"/Infrastructure/Cache/", # Cache-Infrastruktur selbst
])
def check(self, file_path: str, content: str) -> List[str]:
warnings = []
has_cache = any(
re.search(pattern, content, re.IGNORECASE)
for pattern in self.CACHE_PATTERNS
)
if has_cache:
has_invalidation_docs = bool(re.search(
r"invalidat|TTL|cache\s+strateg|@cache",
content,
re.IGNORECASE
))
if not has_invalidation_docs:
warnings.append(
"W10.3: Caching without invalidation strategy. "
"Document cache TTL and invalidation approach."
)
return warnings
class W10_4_MultipleInheritanceWithoutDocs(Rule):
"""W10.4: Trait-Nutzung ohne Dokumentation der Komposition."""
def __init__(self):
super().__init__(allowlist=[])
def check(self, file_path: str, content: str) -> List[str]:
warnings = []
# Zähle verwendete Traits
trait_uses = re.findall(r"use\s+(\w+Trait)", content)
if len(trait_uses) >= 3:
has_composition_docs = bool(re.search(
r"@composition|@uses|Trait-Komposition|Mixin",
content,
re.IGNORECASE
))
if not has_composition_docs:
warnings.append(
f"W10.4: Class uses {len(trait_uses)} traits without documentation. "
"Document trait composition and potential conflicts."
)
return warnings
class W10_5_ExternalServiceWithoutDocs(Rule):
"""W10.5: External Service Integration ohne Fehlerbehandlungs-Doku."""
EXTERNAL_PATTERNS = [
r"curl_",
r"file_get_contents\s*\(\s*['\"]https?:",
r"new\s+GuzzleHttp",
r"new\s+HttpClient",
r"->request\s*\(",
]
def __init__(self):
super().__init__(allowlist=[
"/Infrastructure/External/",
"/Infrastructure/Http/",
])
def check(self, file_path: str, content: str) -> List[str]:
warnings = []
has_external = any(
re.search(pattern, content)
for pattern in self.EXTERNAL_PATTERNS
)
if has_external:
has_error_handling_docs = bool(re.search(
r"@throws|timeout|retry|fallback|circuit.?breaker",
content,
re.IGNORECASE
))
if not has_error_handling_docs:
warnings.append(
"W10.5: External service call without error handling documentation. "
"Document timeout, retry, and fallback strategy."
)
return warnings
class W10_6_DeprecationWithoutMigration(Rule):
"""W10.6: @deprecated ohne Migrations-Hinweis."""
def __init__(self):
super().__init__(allowlist=[])
def check(self, file_path: str, content: str) -> List[str]:
warnings = []
# Finde @deprecated Annotations
deprecated = re.findall(
r"@deprecated\s+(.{0,100})",
content,
re.IGNORECASE
)
for deprecation_msg in deprecated:
# Prüfe ob Migration dokumentiert ist
has_migration = bool(re.search(
r"use\s+\w+\s+instead|migrate\s+to|replacement|@see",
deprecation_msg,
re.IGNORECASE
))
if not has_migration:
warnings.append(
"W10.6: @deprecated without migration path. "
"Add 'Use XY instead' or '@see NewClass'."
)
break
return warnings
# =============================================================================
# RULE COLLECTION
# =============================================================================
RULES = [
W10_1_AbstractFactoryWithoutDocs(),
W10_2_EventDispatcherWithoutDocs(),
W10_3_CacheWithoutStrategy(),
W10_4_MultipleInheritanceWithoutDocs(),
W10_5_ExternalServiceWithoutDocs(),
W10_6_DeprecationWithoutMigration(),
]