Protokoll #28788

ID28788
Zeitstempel2025-12-28 14:21:16.807373
Clientroot
IP145.224.72.140
Modellclaude-sonnet-4-20250514
Statuscompleted
Tokens3,923 (Input: 1,959, Output: 1,964)
Dauer93 ms
Request-Zeit2025-12-28 14:21:16.807373
Response-Zeit2025-12-28 14:21:16.900794

Request

{
    "event": "PreToolUse",
    "tool_name": "Write",
    "tool_input": {
        "file_path": "\/var\/www\/tools\/ki-protokoll\/claude-hook\/quality\/rules_tradeoffs.py",
        "content": "#!\/usr\/bin\/env python3\n\"\"\"\nPost-Hook Trade-off Documentation Regeln (WARN).\n\nW10.x Regeln: Warnt bei Architektur-Mustern ohne Trade-off-Dokumentation.\n\nPrinzip: \"Make Trade-offs Explicit\" (#10)\n\nDiese Regeln erkennen komplexe Architektur-Entscheidungen und\nwarnen, wenn keine entsprechende Dokumentation vorhanden ist.\n\"\"\"\n\nimport re\nfrom typing import List\nfrom .rule_base import Rule\n\n\n# =============================================================================\n# W10: TRADE-OFF DOCUMENTATION\n# =============================================================================\n\nclass W10_1_AbstractFactoryWithoutDocs(Rule):\n    \"\"\"W10.1: Abstract Factory Pattern ohne @see ADR-Verweis.\"\"\"\n\n    def __init__(self):\n        super().__init__(allowlist=[])\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        warnings = []\n\n        # Erkennung: Abstract class mit Factory im Namen und create-Methoden\n        is_factory = bool(re.search(\n            r\"abstract\\s+class\\s+\\w*Factory\",\n            content\n        )) or bool(re.search(\n            r\"interface\\s+\\w*Factory\",\n            content\n        ))\n\n        if is_factory:\n            # Prüfe ob ADR-Referenz vorhanden\n            has_adr_ref = bool(re.search(\n                r\"@see\\s+ADR-\\d+|ADR-\\d+|Architecture Decision\",\n                content,\n                re.IGNORECASE\n            ))\n\n            if not has_adr_ref:\n                warnings.append(\n                    \"W10.1: Factory pattern without architecture documentation. \"\n                    \"Add @see ADR-XXX reference explaining the design choice.\"\n                )\n\n        return warnings\n\n\nclass W10_2_EventDispatcherWithoutDocs(Rule):\n    \"\"\"W10.2: Event-basierte Architektur ohne Dokumentation.\"\"\"\n\n    EVENT_PATTERNS = [\n        r\"class\\s+\\w+Event\\b\",\n        r\"implements\\s+\\w*EventSubscriber\",\n        r\"->dispatch\\s*\\(\\s*new\\s+\\w+Event\",\n        r\"EventDispatcher\",\n    ]\n\n    def __init__(self):\n        super().__init__(allowlist=[\n            \"\/Framework\/\",  # Framework definiert Event-System\n        ])\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        warnings = []\n\n        has_events = any(\n            re.search(pattern, content)\n            for pattern in self.EVENT_PATTERNS\n        )\n\n        if has_events:\n            has_docs = bool(re.search(\n                r\"@see\\s+ADR|Event\\s+Flow|Event-Dokumentation\",\n                content,\n                re.IGNORECASE\n            ))\n\n            if not has_docs:\n                warnings.append(\n                    \"W10.2: Event-based architecture without documentation. \"\n                    \"Consider documenting event flow with ADR.\"\n                )\n\n        return warnings\n\n\nclass W10_3_CacheWithoutStrategy(Rule):\n    \"\"\"W10.3: Caching ohne dokumentierte Invalidation-Strategie.\"\"\"\n\n    CACHE_PATTERNS = [\n        r\"->cache\\s*\\(\",\n        r\"Cache::\",\n        r\"setCache\\s*\\(\",\n        r\"apcu_\",\n        r\"redis\",\n        r\"memcache\",\n    ]\n\n    def __init__(self):\n        super().__init__(allowlist=[\n            \"\/Infrastructure\/Cache\/\",  # Cache-Infrastruktur selbst\n        ])\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        warnings = []\n\n        has_cache = any(\n            re.search(pattern, content, re.IGNORECASE)\n            for pattern in self.CACHE_PATTERNS\n        )\n\n        if has_cache:\n            has_invalidation_docs = bool(re.search(\n                r\"invalidat|TTL|cache\\s+strateg|@cache\",\n                content,\n                re.IGNORECASE\n            ))\n\n            if not has_invalidation_docs:\n                warnings.append(\n                    \"W10.3: Caching without invalidation strategy. \"\n                    \"Document cache TTL and invalidation approach.\"\n                )\n\n        return warnings\n\n\nclass W10_4_MultipleInheritanceWithoutDocs(Rule):\n    \"\"\"W10.4: Trait-Nutzung ohne Dokumentation der Komposition.\"\"\"\n\n    def __init__(self):\n        super().__init__(allowlist=[])\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        warnings = []\n\n        # Zähle verwendete Traits\n        trait_uses = re.findall(r\"use\\s+(\\w+Trait)\", content)\n\n        if len(trait_uses) >= 3:\n            has_composition_docs = bool(re.search(\n                r\"@composition|@uses|Trait-Komposition|Mixin\",\n                content,\n                re.IGNORECASE\n            ))\n\n            if not has_composition_docs:\n                warnings.append(\n                    f\"W10.4: Class uses {len(trait_uses)} traits without documentation. \"\n                    \"Document trait composition and potential conflicts.\"\n                )\n\n        return warnings\n\n\nclass W10_5_ExternalServiceWithoutDocs(Rule):\n    \"\"\"W10.5: External Service Integration ohne Fehlerbehandlungs-Doku.\"\"\"\n\n    EXTERNAL_PATTERNS = [\n        r\"curl_\",\n        r\"file_get_contents\\s*\\(\\s*['\\\"]https?:\",\n        r\"new\\s+GuzzleHttp\",\n        r\"new\\s+HttpClient\",\n        r\"->request\\s*\\(\",\n    ]\n\n    def __init__(self):\n        super().__init__(allowlist=[\n            \"\/Infrastructure\/External\/\",\n            \"\/Infrastructure\/Http\/\",\n        ])\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        warnings = []\n\n        has_external = any(\n            re.search(pattern, content)\n            for pattern in self.EXTERNAL_PATTERNS\n        )\n\n        if has_external:\n            has_error_handling_docs = bool(re.search(\n                r\"@throws|timeout|retry|fallback|circuit.?breaker\",\n                content,\n                re.IGNORECASE\n            ))\n\n            if not has_error_handling_docs:\n                warnings.append(\n                    \"W10.5: External service call without error handling documentation. \"\n                    \"Document timeout, retry, and fallback strategy.\"\n                )\n\n        return warnings\n\n\nclass W10_6_DeprecationWithoutMigration(Rule):\n    \"\"\"W10.6: @deprecated ohne Migrations-Hinweis.\"\"\"\n\n    def __init__(self):\n        super().__init__(allowlist=[])\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        warnings = []\n\n        # Finde @deprecated Annotations\n        deprecated = re.findall(\n            r\"@deprecated\\s+(.{0,100})\",\n            content,\n            re.IGNORECASE\n        )\n\n        for deprecation_msg in deprecated:\n            # Prüfe ob Migration dokumentiert ist\n            has_migration = bool(re.search(\n                r\"use\\s+\\w+\\s+instead|migrate\\s+to|replacement|@see\",\n                deprecation_msg,\n                re.IGNORECASE\n            ))\n\n            if not has_migration:\n                warnings.append(\n                    \"W10.6: @deprecated without migration path. \"\n                    \"Add 'Use XY instead' or '@see NewClass'.\"\n                )\n                break\n\n        return warnings\n\n\n# =============================================================================\n# RULE COLLECTION\n# =============================================================================\n\nRULES = [\n    W10_1_AbstractFactoryWithoutDocs(),\n    W10_2_EventDispatcherWithoutDocs(),\n    W10_3_CacheWithoutStrategy(),\n    W10_4_MultipleInheritanceWithoutDocs(),\n    W10_5_ExternalServiceWithoutDocs(),\n    W10_6_DeprecationWithoutMigration(),\n]\n"
    }
}

Response

{
    "tool_response": {
        "type": "create",
        "filePath": "\/var\/www\/tools\/ki-protokoll\/claude-hook\/quality\/rules_tradeoffs.py",
        "content": "#!\/usr\/bin\/env python3\n\"\"\"\nPost-Hook Trade-off Documentation Regeln (WARN).\n\nW10.x Regeln: Warnt bei Architektur-Mustern ohne Trade-off-Dokumentation.\n\nPrinzip: \"Make Trade-offs Explicit\" (#10)\n\nDiese Regeln erkennen komplexe Architektur-Entscheidungen und\nwarnen, wenn keine entsprechende Dokumentation vorhanden ist.\n\"\"\"\n\nimport re\nfrom typing import List\nfrom .rule_base import Rule\n\n\n# =============================================================================\n# W10: TRADE-OFF DOCUMENTATION\n# =============================================================================\n\nclass W10_1_AbstractFactoryWithoutDocs(Rule):\n    \"\"\"W10.1: Abstract Factory Pattern ohne @see ADR-Verweis.\"\"\"\n\n    def __init__(self):\n        super().__init__(allowlist=[])\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        warnings = []\n\n        # Erkennung: Abstract class mit Factory im Namen und create-Methoden\n        is_factory = bool(re.search(\n            r\"abstract\\s+class\\s+\\w*Factory\",\n            content\n        )) or bool(re.search(\n            r\"interface\\s+\\w*Factory\",\n            content\n        ))\n\n        if is_factory:\n            # Prüfe ob ADR-Referenz vorhanden\n            has_adr_ref = bool(re.search(\n                r\"@see\\s+ADR-\\d+|ADR-\\d+|Architecture Decision\",\n                content,\n                re.IGNORECASE\n            ))\n\n            if not has_adr_ref:\n                warnings.append(\n                    \"W10.1: Factory pattern without architecture documentation. \"\n                    \"Add @see ADR-XXX reference explaining the design choice.\"\n                )\n\n        return warnings\n\n\nclass W10_2_EventDispatcherWithoutDocs(Rule):\n    \"\"\"W10.2: Event-basierte Architektur ohne Dokumentation.\"\"\"\n\n    EVENT_PATTERNS = [\n        r\"class\\s+\\w+Event\\b\",\n        r\"implements\\s+\\w*EventSubscriber\",\n        r\"->dispatch\\s*\\(\\s*new\\s+\\w+Event\",\n        r\"EventDispatcher\",\n    ]\n\n    def __init__(self):\n        super().__init__(allowlist=[\n            \"\/Framework\/\",  # Framework definiert Event-System\n        ])\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        warnings = []\n\n        has_events = any(\n            re.search(pattern, content)\n            for pattern in self.EVENT_PATTERNS\n        )\n\n        if has_events:\n            has_docs = bool(re.search(\n                r\"@see\\s+ADR|Event\\s+Flow|Event-Dokumentation\",\n                content,\n                re.IGNORECASE\n            ))\n\n            if not has_docs:\n                warnings.append(\n                    \"W10.2: Event-based architecture without documentation. \"\n                    \"Consider documenting event flow with ADR.\"\n                )\n\n        return warnings\n\n\nclass W10_3_CacheWithoutStrategy(Rule):\n    \"\"\"W10.3: Caching ohne dokumentierte Invalidation-Strategie.\"\"\"\n\n    CACHE_PATTERNS = [\n        r\"->cache\\s*\\(\",\n        r\"Cache::\",\n        r\"setCache\\s*\\(\",\n        r\"apcu_\",\n        r\"redis\",\n        r\"memcache\",\n    ]\n\n    def __init__(self):\n        super().__init__(allowlist=[\n            \"\/Infrastructure\/Cache\/\",  # Cache-Infrastruktur selbst\n        ])\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        warnings = []\n\n        has_cache = any(\n            re.search(pattern, content, re.IGNORECASE)\n            for pattern in self.CACHE_PATTERNS\n        )\n\n        if has_cache:\n            has_invalidation_docs = bool(re.search(\n                r\"invalidat|TTL|cache\\s+strateg|@cache\",\n                content,\n                re.IGNORECASE\n            ))\n\n            if not has_invalidation_docs:\n                warnings.append(\n                    \"W10.3: Caching without invalidation strategy. \"\n                    \"Document cache TTL and invalidation approach.\"\n                )\n\n        return warnings\n\n\nclass W10_4_MultipleInheritanceWithoutDocs(Rule):\n    \"\"\"W10.4: Trait-Nutzung ohne Dokumentation der Komposition.\"\"\"\n\n    def __init__(self):\n        super().__init__(allowlist=[])\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        warnings = []\n\n        # Zähle verwendete Traits\n        trait_uses = re.findall(r\"use\\s+(\\w+Trait)\", content)\n\n        if len(trait_uses) >= 3:\n            has_composition_docs = bool(re.search(\n                r\"@composition|@uses|Trait-Komposition|Mixin\",\n                content,\n                re.IGNORECASE\n            ))\n\n            if not has_composition_docs:\n                warnings.append(\n                    f\"W10.4: Class uses {len(trait_uses)} traits without documentation. \"\n                    \"Document trait composition and potential conflicts.\"\n                )\n\n        return warnings\n\n\nclass W10_5_ExternalServiceWithoutDocs(Rule):\n    \"\"\"W10.5: External Service Integration ohne Fehlerbehandlungs-Doku.\"\"\"\n\n    EXTERNAL_PATTERNS = [\n        r\"curl_\",\n        r\"file_get_contents\\s*\\(\\s*['\\\"]https?:\",\n        r\"new\\s+GuzzleHttp\",\n        r\"new\\s+HttpClient\",\n        r\"->request\\s*\\(\",\n    ]\n\n    def __init__(self):\n        super().__init__(allowlist=[\n            \"\/Infrastructure\/External\/\",\n            \"\/Infrastructure\/Http\/\",\n        ])\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        warnings = []\n\n        has_external = any(\n            re.search(pattern, content)\n            for pattern in self.EXTERNAL_PATTERNS\n        )\n\n        if has_external:\n            has_error_handling_docs = bool(re.search(\n                r\"@throws|timeout|retry|fallback|circuit.?breaker\",\n                content,\n                re.IGNORECASE\n            ))\n\n            if not has_error_handling_docs:\n                warnings.append(\n                    \"W10.5: External service call without error handling documentation. \"\n                    \"Document timeout, retry, and fallback strategy.\"\n                )\n\n        return warnings\n\n\nclass W10_6_DeprecationWithoutMigration(Rule):\n    \"\"\"W10.6: @deprecated ohne Migrations-Hinweis.\"\"\"\n\n    def __init__(self):\n        super().__init__(allowlist=[])\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        warnings = []\n\n        # Finde @deprecated Annotations\n        deprecated = re.findall(\n            r\"@deprecated\\s+(.{0,100})\",\n            content,\n            re.IGNORECASE\n        )\n\n        for deprecation_msg in deprecated:\n            # Prüfe ob Migration dokumentiert ist\n            has_migration = bool(re.search(\n                r\"use\\s+\\w+\\s+instead|migrate\\s+to|replacement|@see\",\n                deprecation_msg,\n                re.IGNORECASE\n            ))\n\n            if not has_migration:\n                warnings.append(\n                    \"W10.6: @deprecated without migration path. \"\n                    \"Add 'Use XY instead' or '@see NewClass'.\"\n                )\n                break\n\n        return warnings\n\n\n# =============================================================================\n# RULE COLLECTION\n# =============================================================================\n\nRULES = [\n    W10_1_AbstractFactoryWithoutDocs(),\n    W10_2_EventDispatcherWithoutDocs(),\n    W10_3_CacheWithoutStrategy(),\n    W10_4_MultipleInheritanceWithoutDocs(),\n    W10_5_ExternalServiceWithoutDocs(),\n    W10_6_DeprecationWithoutMigration(),\n]\n",
        "structuredPatch": [],
        "originalFile": null
    }
}
← Vorheriger Zur Liste Nächster →