Protokoll #15642

ID15642
Zeitstempel2025-12-25 16:56:09.785303
Clientroot
IP
Warning: Undefined array key "request_ip" in /var/www/dev.campus.systemische-tools.de/src/View/protokoll/show.php on line 13

Deprecated: htmlspecialchars(): Passing null to parameter #1 ($string) of type string is deprecated in /var/www/dev.campus.systemische-tools.de/src/View/protokoll/show.php on line 13
Modellclaude-sonnet-4-20250514
Statuscompleted
Tokens4,441 (Input: 0, Output: 0)
Dauer112 ms
Request-Zeit
Warning: Undefined array key "request_timestamp" in /var/www/dev.campus.systemische-tools.de/src/View/protokoll/show.php on line 18
Response-Zeit-

Warning: Undefined array key "error_message" in /var/www/dev.campus.systemische-tools.de/src/View/protokoll/show.php on line 22

Request

{
    "event": "PreToolUse",
    "tool_name": "Write",
    "tool_input": {
        "file_path": "\/var\/www\/tools\/ki-protokoll\/claude-hook\/quality\/rules_quality.py",
        "content": "#!\/usr\/bin\/env python3\n\"\"\"\nQuality Rules (W1, W4, W6) - SRP, KISS, OOP, SOLID.\n\nRegeln für Code-Qualität: Klassengröße, Single Responsibility,\nOOP-Prinzipien, Encapsulation, Interface Segregation.\n\"\"\"\n\nimport re\nfrom pathlib import Path\nfrom typing import List\nfrom .rule_base import Rule, DTO_ALLOWLIST\n\n\n# =============================================================================\n# W1: SRP + KISS - Single Responsibility & Keep It Simple\n# =============================================================================\n\nclass W1_1_ClassSize(Rule):\n    \"\"\"W1.1: Klassengröße (max 300 LOC).\"\"\"\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        from .rule_base import count_non_empty_lines\n        loc = count_non_empty_lines(content)\n        warnings = []\n\n        if loc > 300:\n            warnings.append(f\"W1.1: Class has {loc} lines (max 300). Consider splitting.\")\n        elif loc > 200:\n            warnings.append(f\"W1.1: Class has {loc} lines (approaching limit of 300).\")\n\n        return warnings\n\n\nclass W1_2_PublicMethodCount(Rule):\n    \"\"\"W1.2: Anzahl public methods (max 10).\"\"\"\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        public_methods = re.findall(r\"public\\s+function\\s+\\w+\", content)\n        count = len(public_methods)\n\n        if count > 10:\n            return [f\"W1.2: Class has {count} public methods (max 10). Consider splitting.\"]\n\n        return []\n\n\nclass W1_3_ConstructorParams(Rule):\n    \"\"\"W1.3: Constructor-Parameter (max 5).\"\"\"\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        constructor_match = re.search(r\"function\\s+__construct\\s*\\(([^)]*)\\)\", content, re.DOTALL)\n        if not constructor_match:\n            return []\n\n        params = constructor_match.group(1)\n        param_count = len([p for p in params.split(',') if p.strip()])\n\n        if param_count > 5:\n            return [f\"W1.3: Constructor has {param_count} parameters (max 5). Consider refactoring.\"]\n\n        return []\n\n\nclass W1_4_DependencyCount(Rule):\n    \"\"\"W1.4: Anzahl use-Statements (max 10).\"\"\"\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        use_statements = re.findall(r\"^use\\s+\", content, re.MULTILINE)\n        count = len(use_statements)\n\n        if count > 10:\n            return [f\"W1.4: Class has {count} dependencies (max 10). Consider reducing coupling.\"]\n\n        return []\n\n\nclass W1_5_SuspiciousNames(Rule):\n    \"\"\"W1.5: Verdächtige Namen (Manager, And).\"\"\"\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        filename = Path(file_path).stem\n        hints = []\n\n        if \"Manager\" in filename:\n            hints.append(f\"W1.5: Hint - '{filename}' contains 'Manager'. Verify single responsibility.\")\n\n        if re.search(r\"[a-z]And[A-Z]\", filename):\n            hints.append(f\"W1.5: Hint - '{filename}' contains 'And'. May indicate multiple responsibilities.\")\n\n        return hints\n\n\n# =============================================================================\n# W4: OOP - Object-Oriented Programming Principles\n# =============================================================================\n\nclass W4_1_AnemicModel(Rule):\n    \"\"\"W4.1: Anämisches Model (hohe Accessor-Ratio > 70%).\"\"\"\n\n    def __init__(self):\n        super().__init__(allowlist=DTO_ALLOWLIST)\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        getters = len(re.findall(r\"public\\s+function\\s+get[A-Z]\\w*\\s*\\(\", content))\n        setters = len(re.findall(r\"public\\s+function\\s+set[A-Z]\\w*\\s*\\(\", content))\n        all_public = len(re.findall(r\"public\\s+function\\s+\\w+\", content))\n\n        if all_public > 4:\n            accessor_ratio = (getters + setters) \/ all_public\n            if accessor_ratio > 0.7:\n                return [f\"W4.1: Potential anemic model: {int(accessor_ratio*100)}% accessors. Consider adding behavior.\"]\n\n        return []\n\n\nclass W4_2_ClassWithoutBehavior(Rule):\n    \"\"\"W4.2: Klasse ohne Verhalten.\"\"\"\n\n    def __init__(self):\n        super().__init__(allowlist=DTO_ALLOWLIST)\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        has_properties = bool(re.search(r\"(?:private|protected|public)\\s+.*\\$\\w+\", content))\n        methods = re.findall(r\"(?:public|private|protected)\\s+function\\s+(\\w+)\", content)\n        real_methods = [m for m in methods if not m.startswith((\"get\", \"set\", \"__\"))]\n\n        if has_properties and len(real_methods) == 0:\n            return [\"W4.2: Class has properties but no behavior methods.\"]\n\n        return []\n\n\nclass W4_3_LowEncapsulation(Rule):\n    \"\"\"W4.3: Niedrige Kapselung (> 50% exposed properties).\"\"\"\n\n    def __init__(self):\n        super().__init__(allowlist=DTO_ALLOWLIST)\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        public_props = len(re.findall(r\"public\\s+(?!function|const).*\\$\", content))\n        protected_props = len(re.findall(r\"protected\\s+(?!function|const).*\\$\", content))\n        private_props = len(re.findall(r\"private\\s+(?!function|const).*\\$\", content))\n\n        total = public_props + protected_props + private_props\n        if total > 3:\n            exposed_ratio = (public_props + protected_props) \/ total\n            if exposed_ratio > 0.5:\n                return [f\"W4.3: Low encapsulation: {int(exposed_ratio*100)}% exposed properties.\"]\n\n        return []\n\n\nclass W4_4_HighStaticRatio(Rule):\n    \"\"\"W4.4: Hohe Static-Ratio (> 50% static methods).\"\"\"\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        static_methods = len(re.findall(r\"public\\s+static\\s+function\", content))\n        all_methods = len(re.findall(r\"public\\s+function\", content))\n\n        if all_methods > 0 and static_methods > 2:\n            static_ratio = static_methods \/ all_methods\n            if static_ratio > 0.5:\n                return [f\"W4.4: High static method ratio: {static_methods}\/{all_methods}. Consider instance methods.\"]\n\n        return []\n\n\n# =============================================================================\n# W6: SOLID + DIP - Interface Segregation Principle\n# =============================================================================\n\nclass W6_1_InterfaceTooLarge(Rule):\n    \"\"\"W6.1: Interface mit zu vielen Methoden (max 7).\"\"\"\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        interface_match = re.search(r\"interface\\s+(\\w+)[^{]*\\{\", content)\n        if not interface_match:\n            return []\n\n        interface_name = interface_match.group(1)\n        interface_start = interface_match.end()\n        interface_content = content[interface_start:]\n\n        # Finde Interface-Ende\n        brace_count = 1\n        end_pos = 0\n        for i, char in enumerate(interface_content):\n            if char == '{':\n                brace_count += 1\n            elif char == '}':\n                brace_count -= 1\n                if brace_count == 0:\n                    end_pos = i\n                    break\n\n        interface_body = interface_content[:end_pos]\n        method_count = len(re.findall(r\"function\\s+\\w+\", interface_body))\n\n        if method_count > 7:\n            return [f\"W6.1: Interface '{interface_name}' has {method_count} methods (max 7). Consider splitting (ISP).\"]\n\n        return []\n\n\nclass W6_2_TooManyInterfaces(Rule):\n    \"\"\"W6.2: Klasse implementiert zu viele Interfaces (max 5).\"\"\"\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        implements_match = re.search(r\"implements\\s+([^{]+)\", content)\n        if not implements_match:\n            return []\n\n        interfaces = [i.strip() for i in implements_match.group(1).split(',') if i.strip()]\n        count = len(interfaces)\n\n        if count > 5:\n            return [f\"W6.2: Class implements {count} interfaces (max 5). Potential role confusion.\"]\n\n        return []\n\n\n# =============================================================================\n# RULE COLLECTION\n# =============================================================================\n\nRULES = [\n    W1_1_ClassSize(),\n    W1_2_PublicMethodCount(),\n    W1_3_ConstructorParams(),\n    W1_4_DependencyCount(),\n    W1_5_SuspiciousNames(),\n    W4_1_AnemicModel(),\n    W4_2_ClassWithoutBehavior(),\n    W4_3_LowEncapsulation(),\n    W4_4_HighStaticRatio(),\n    W6_1_InterfaceTooLarge(),\n    W6_2_TooManyInterfaces(),\n]\n"
    }
}

Response

{
    "tool_response": {
        "type": "create",
        "filePath": "\/var\/www\/tools\/ki-protokoll\/claude-hook\/quality\/rules_quality.py",
        "content": "#!\/usr\/bin\/env python3\n\"\"\"\nQuality Rules (W1, W4, W6) - SRP, KISS, OOP, SOLID.\n\nRegeln für Code-Qualität: Klassengröße, Single Responsibility,\nOOP-Prinzipien, Encapsulation, Interface Segregation.\n\"\"\"\n\nimport re\nfrom pathlib import Path\nfrom typing import List\nfrom .rule_base import Rule, DTO_ALLOWLIST\n\n\n# =============================================================================\n# W1: SRP + KISS - Single Responsibility & Keep It Simple\n# =============================================================================\n\nclass W1_1_ClassSize(Rule):\n    \"\"\"W1.1: Klassengröße (max 300 LOC).\"\"\"\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        from .rule_base import count_non_empty_lines\n        loc = count_non_empty_lines(content)\n        warnings = []\n\n        if loc > 300:\n            warnings.append(f\"W1.1: Class has {loc} lines (max 300). Consider splitting.\")\n        elif loc > 200:\n            warnings.append(f\"W1.1: Class has {loc} lines (approaching limit of 300).\")\n\n        return warnings\n\n\nclass W1_2_PublicMethodCount(Rule):\n    \"\"\"W1.2: Anzahl public methods (max 10).\"\"\"\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        public_methods = re.findall(r\"public\\s+function\\s+\\w+\", content)\n        count = len(public_methods)\n\n        if count > 10:\n            return [f\"W1.2: Class has {count} public methods (max 10). Consider splitting.\"]\n\n        return []\n\n\nclass W1_3_ConstructorParams(Rule):\n    \"\"\"W1.3: Constructor-Parameter (max 5).\"\"\"\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        constructor_match = re.search(r\"function\\s+__construct\\s*\\(([^)]*)\\)\", content, re.DOTALL)\n        if not constructor_match:\n            return []\n\n        params = constructor_match.group(1)\n        param_count = len([p for p in params.split(',') if p.strip()])\n\n        if param_count > 5:\n            return [f\"W1.3: Constructor has {param_count} parameters (max 5). Consider refactoring.\"]\n\n        return []\n\n\nclass W1_4_DependencyCount(Rule):\n    \"\"\"W1.4: Anzahl use-Statements (max 10).\"\"\"\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        use_statements = re.findall(r\"^use\\s+\", content, re.MULTILINE)\n        count = len(use_statements)\n\n        if count > 10:\n            return [f\"W1.4: Class has {count} dependencies (max 10). Consider reducing coupling.\"]\n\n        return []\n\n\nclass W1_5_SuspiciousNames(Rule):\n    \"\"\"W1.5: Verdächtige Namen (Manager, And).\"\"\"\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        filename = Path(file_path).stem\n        hints = []\n\n        if \"Manager\" in filename:\n            hints.append(f\"W1.5: Hint - '{filename}' contains 'Manager'. Verify single responsibility.\")\n\n        if re.search(r\"[a-z]And[A-Z]\", filename):\n            hints.append(f\"W1.5: Hint - '{filename}' contains 'And'. May indicate multiple responsibilities.\")\n\n        return hints\n\n\n# =============================================================================\n# W4: OOP - Object-Oriented Programming Principles\n# =============================================================================\n\nclass W4_1_AnemicModel(Rule):\n    \"\"\"W4.1: Anämisches Model (hohe Accessor-Ratio > 70%).\"\"\"\n\n    def __init__(self):\n        super().__init__(allowlist=DTO_ALLOWLIST)\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        getters = len(re.findall(r\"public\\s+function\\s+get[A-Z]\\w*\\s*\\(\", content))\n        setters = len(re.findall(r\"public\\s+function\\s+set[A-Z]\\w*\\s*\\(\", content))\n        all_public = len(re.findall(r\"public\\s+function\\s+\\w+\", content))\n\n        if all_public > 4:\n            accessor_ratio = (getters + setters) \/ all_public\n            if accessor_ratio > 0.7:\n                return [f\"W4.1: Potential anemic model: {int(accessor_ratio*100)}% accessors. Consider adding behavior.\"]\n\n        return []\n\n\nclass W4_2_ClassWithoutBehavior(Rule):\n    \"\"\"W4.2: Klasse ohne Verhalten.\"\"\"\n\n    def __init__(self):\n        super().__init__(allowlist=DTO_ALLOWLIST)\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        has_properties = bool(re.search(r\"(?:private|protected|public)\\s+.*\\$\\w+\", content))\n        methods = re.findall(r\"(?:public|private|protected)\\s+function\\s+(\\w+)\", content)\n        real_methods = [m for m in methods if not m.startswith((\"get\", \"set\", \"__\"))]\n\n        if has_properties and len(real_methods) == 0:\n            return [\"W4.2: Class has properties but no behavior methods.\"]\n\n        return []\n\n\nclass W4_3_LowEncapsulation(Rule):\n    \"\"\"W4.3: Niedrige Kapselung (> 50% exposed properties).\"\"\"\n\n    def __init__(self):\n        super().__init__(allowlist=DTO_ALLOWLIST)\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        public_props = len(re.findall(r\"public\\s+(?!function|const).*\\$\", content))\n        protected_props = len(re.findall(r\"protected\\s+(?!function|const).*\\$\", content))\n        private_props = len(re.findall(r\"private\\s+(?!function|const).*\\$\", content))\n\n        total = public_props + protected_props + private_props\n        if total > 3:\n            exposed_ratio = (public_props + protected_props) \/ total\n            if exposed_ratio > 0.5:\n                return [f\"W4.3: Low encapsulation: {int(exposed_ratio*100)}% exposed properties.\"]\n\n        return []\n\n\nclass W4_4_HighStaticRatio(Rule):\n    \"\"\"W4.4: Hohe Static-Ratio (> 50% static methods).\"\"\"\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        static_methods = len(re.findall(r\"public\\s+static\\s+function\", content))\n        all_methods = len(re.findall(r\"public\\s+function\", content))\n\n        if all_methods > 0 and static_methods > 2:\n            static_ratio = static_methods \/ all_methods\n            if static_ratio > 0.5:\n                return [f\"W4.4: High static method ratio: {static_methods}\/{all_methods}. Consider instance methods.\"]\n\n        return []\n\n\n# =============================================================================\n# W6: SOLID + DIP - Interface Segregation Principle\n# =============================================================================\n\nclass W6_1_InterfaceTooLarge(Rule):\n    \"\"\"W6.1: Interface mit zu vielen Methoden (max 7).\"\"\"\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        interface_match = re.search(r\"interface\\s+(\\w+)[^{]*\\{\", content)\n        if not interface_match:\n            return []\n\n        interface_name = interface_match.group(1)\n        interface_start = interface_match.end()\n        interface_content = content[interface_start:]\n\n        # Finde Interface-Ende\n        brace_count = 1\n        end_pos = 0\n        for i, char in enumerate(interface_content):\n            if char == '{':\n                brace_count += 1\n            elif char == '}':\n                brace_count -= 1\n                if brace_count == 0:\n                    end_pos = i\n                    break\n\n        interface_body = interface_content[:end_pos]\n        method_count = len(re.findall(r\"function\\s+\\w+\", interface_body))\n\n        if method_count > 7:\n            return [f\"W6.1: Interface '{interface_name}' has {method_count} methods (max 7). Consider splitting (ISP).\"]\n\n        return []\n\n\nclass W6_2_TooManyInterfaces(Rule):\n    \"\"\"W6.2: Klasse implementiert zu viele Interfaces (max 5).\"\"\"\n\n    def check(self, file_path: str, content: str) -> List[str]:\n        implements_match = re.search(r\"implements\\s+([^{]+)\", content)\n        if not implements_match:\n            return []\n\n        interfaces = [i.strip() for i in implements_match.group(1).split(',') if i.strip()]\n        count = len(interfaces)\n\n        if count > 5:\n            return [f\"W6.2: Class implements {count} interfaces (max 5). Potential role confusion.\"]\n\n        return []\n\n\n# =============================================================================\n# RULE COLLECTION\n# =============================================================================\n\nRULES = [\n    W1_1_ClassSize(),\n    W1_2_PublicMethodCount(),\n    W1_3_ConstructorParams(),\n    W1_4_DependencyCount(),\n    W1_5_SuspiciousNames(),\n    W4_1_AnemicModel(),\n    W4_2_ClassWithoutBehavior(),\n    W4_3_LowEncapsulation(),\n    W4_4_HighStaticRatio(),\n    W6_1_InterfaceTooLarge(),\n    W6_2_TooManyInterfaces(),\n]\n",
        "structuredPatch": [],
        "originalFile": null
    }
}
← Vorheriger Zur Liste Nächster →