{
"event": "PreToolUse",
"tool_name": "mcp__mcp-docs__docs_create",
"tool_input": {
"title": "Hook-System Python-Erweiterung",
"slug": "hook-system-python-erweiterung",
"description": "Analyse und Implementierungsplan für Python-Datei-Unterstützung im Claude Code Hook-System",
"parent_id": 2,
"content": "# Hook-System Python-Erweiterung\n\n## 1. Problemanalyse\n\n### 1.1 Ausgangssituation\nHardcoded Model-Namen (`\"mistral\"`) in Pipeline-Backfill-Skripten wurden nicht erkannt.\n\n**Betroffene Dateien:**\n- `\/var\/www\/scripts\/pipeline\/backfill_text_semantics.py`\n- `\/var\/www\/scripts\/pipeline\/backfill_knowledge_semantics.py`\n\n### 1.2 Root Cause\n\n**hook_dispatcher.py Zeile 78-80:**\n```python\nif not file_path.endswith(\".php\"):\n # Nicht-PHP: durchlassen ohne Output (implizit allow)\n sys.exit(0)\n```\n\nDas Hook-System prüft **ausschließlich PHP-Dateien**. Python-Dateien werden komplett übersprungen.\n\n### 1.3 Ironische Entdeckung\n`pre_rules_constants.py` Zeile 56-58 hat bereits Python-Support:\n```python\nif not (file_path.endswith('.php') or file_path.endswith('.py')):\n return None\n```\nDiese Regel wird aber nie für Python aufgerufen, weil der Dispatcher vorher abbricht.\n\n---\n\n## 2. Bestehende Architektur\n\n### 2.1 Hook-Konfiguration (~\/.claude\/settings.json)\n\n| Event | Matcher | Command |\n|-------|---------|---------|\n| PreToolUse | Write | hook_dispatcher.py pre |\n| PostToolUse | Write\\|Edit | hook_dispatcher.py post |\n\n### 2.2 Regel-Module (quality\/)\n\n| Modul | Typ | Funktion |\n|-------|-----|----------|\n| pre_rules.py | Aggregator | Sammelt alle Pre-Hook-Regeln |\n| post_rules.py | Aggregator | Sammelt alle Post-Hook-Regeln |\n| pre_rules_guard.py | BLOCK | SRP, KISS, Dateigrößen |\n| pre_rules_mvc.py | BLOCK | MVC-Architektur |\n| pre_rules_layers.py | BLOCK | Layer-Trennung, DIP |\n| pre_rules_validation.py | BLOCK | PSR, Types |\n| pre_rules_htmx.py | BLOCK | HTMX Contract |\n| pre_rules_constants.py | BLOCK | Magic Numbers |\n| rules_quality.py | WARN | Qualitätswarnungen |\n| rules_security.py | WARN | Security Patterns |\n| rules_style.py | WARN | Code Style |\n| rules_constants.py | WARN | Constants Warnungen |\n\n### 2.3 Regel-Pattern\n\n**Pre-Hook (BLOCK):**\n```python\ndef p7_1_critical_magic_numbers(file_path: str, content: str) -> Optional[dict]:\n if should_skip(file_path):\n return None\n # Prüfung...\n return block(\"P7.1\", \"Message\") or None\n```\n\n**Post-Hook (WARN):**\n```python\ndef w_rule(file_path: str, content: str) -> List[str]:\n warnings = []\n # Prüfung...\n warnings.append(\"Message\")\n return warnings\n```\n\n---\n\n## 3. Implementierungsplan\n\n### 3.1 Phase 1: Dispatcher erweitern\n\n**Datei:** `hook_dispatcher.py`\n\n**Änderung:**\n```python\n# ALT (Zeile 78-80):\nif not file_path.endswith(\".php\"):\n sys.exit(0)\n\n# NEU:\nALLOWED_EXTENSIONS = {\".php\", \".py\"}\nPYTHON_PATHS = [\"\/var\/www\/scripts\/pipeline\/\"]\n\ndef should_check(file_path: str) -> bool:\n ext = Path(file_path).suffix\n if ext not in ALLOWED_EXTENSIONS:\n return False\n if ext == \".py\":\n return any(file_path.startswith(p) for p in PYTHON_PATHS)\n return True\n\n# In main():\nif not should_check(file_path):\n sys.exit(0)\n```\n\n### 3.2 Phase 2: Python-Regeln erstellen\n\n**Neue Datei:** `quality\/pre_rules_python.py`\n\n```python\n#!\/usr\/bin\/env python3\n\"\"\"\nPre-Hook Python Regeln (BLOCK) - Pipeline Code Quality.\n\nPP1.x: Hardcoded Values\nPP2.x: Config Patterns\n\"\"\"\n\nimport re\nfrom typing import Optional\nfrom .rule_base import block, is_in_allowlist\n\nPYTHON_ALLOWLIST = [\n \"\/tests\/\",\n \"\/venv\/\",\n \"\/__pycache__\/\",\n]\n\n# Hardcoded Model-Namen die blockiert werden\nHARDCODED_MODELS = [\n \"mistral\", \"llama\", \"gemma\", \"phi\", \"qwen\",\n \"claude\", \"gpt-4\", \"gpt-3.5\",\n \"minicpm\", \"nomic\",\n]\n\ndef pp1_1_hardcoded_model_names(file_path: str, content: str) -> Optional[dict]:\n \"\"\"PP1.1: Hardcoded LLM Model-Namen blockieren.\"\"\"\n if not file_path.endswith(\".py\"):\n return None\n if is_in_allowlist(file_path, PYTHON_ALLOWLIST):\n return None\n \n lines = content.split('\\n')\n for line_num, line in enumerate(lines, 1):\n # Skip Kommentare und Docstrings\n stripped = line.strip()\n if stripped.startswith('#') or stripped.startswith('\"\"\"') or stripped.startswith(\"'''\"):\n continue\n \n # Skip imports und Konstanten-Definitionen\n if 'import ' in line or line.startswith('VALID_') or line.startswith('ALLOWED_'):\n continue\n \n for model in HARDCODED_MODELS:\n # Pattern: default=\"mistral\" oder model=\"mistral\"\n pattern = rf'(?:default|model)\\s*=\\s*[\"\\']({model})[\"\\']'\n if re.search(pattern, line, re.IGNORECASE):\n return block(\n \"PP1.1\",\n f\"Hardcoded model name '{model}' at line {line_num}. \"\n f\"Use get_pipeline_model() or config parameter.\"\n )\n return None\n\n\ndef pp1_2_hardcoded_pipeline_id(file_path: str, content: str) -> Optional[dict]:\n \"\"\"PP1.2: Hardcoded Pipeline-IDs blockieren (außer als Konstante).\"\"\"\n if not file_path.endswith(\".py\"):\n return None\n if is_in_allowlist(file_path, PYTHON_ALLOWLIST):\n return None\n \n lines = content.split('\\n')\n for line_num, line in enumerate(lines, 1):\n stripped = line.strip()\n if stripped.startswith('#'):\n continue\n \n # Erlaubt: DEFAULT_PIPELINE_ID = 5\n if 'PIPELINE_ID' in line and '=' in line:\n continue\n \n # Verboten: pipeline_id=5 oder pipeline_id = 5 (nicht als Konstante)\n if re.search(r'pipeline_id\\s*=\\s*\\d+', line) and 'DEFAULT' not in line:\n return block(\n \"PP1.2\",\n f\"Hardcoded pipeline_id at line {line_num}. \"\n f\"Use DEFAULT_PIPELINE_ID constant or config parameter.\"\n )\n return None\n\n\nRULES = [\n pp1_1_hardcoded_model_names,\n pp1_2_hardcoded_pipeline_id,\n]\n```\n\n### 3.3 Phase 3: Integration\n\n**Datei:** `quality\/pre_rules.py`\n\n```python\n# Hinzufügen:\nfrom . import pre_rules_python\n\nRULES = [\n # ... bestehende Regeln ...\n *pre_rules_python.RULES,\n]\n```\n\n---\n\n## 4. Betroffene Python-Dateien\n\n### 4.1 Pipeline-Skripte (zu prüfen)\n\n| Datei | Beschreibung |\n|-------|--------------|\n| pipeline.py | Haupt-Orchestrator |\n| backfill_*.py | Backfill-Skripte |\n| step_*.py | Pipeline-Steps |\n| knowledge\/*.py | Knowledge-Extraction |\n\n### 4.2 Ausnahmen (nicht prüfen)\n\n| Pfad | Grund |\n|------|-------|\n| \/venv\/ | Virtual Environment |\n| \/__pycache__\/ | Bytecode |\n| \/tests\/ | Test-Dateien |\n| db.py | Infrastruktur |\n\n---\n\n## 5. Test-Szenarien\n\n### 5.1 Blockieren (DENY)\n```python\n# Sollte blockiert werden:\nparser.add_argument(\"--model\", default=\"mistral\")\nmodel = \"gemma\"\n```\n\n### 5.2 Erlauben (ALLOW)\n```python\n# Sollte erlaubt werden:\nmodel = get_pipeline_model(\"text_semantic_analyze\")\nDEFAULT_PIPELINE_ID = 5\n# Kommentar: mistral ist das Standard-Modell\n```\n\n---\n\n## 6. Rollout\n\n1. **pre_rules_python.py** erstellen\n2. **hook_dispatcher.py** erweitern\n3. **pre_rules.py** aktualisieren\n4. Manueller Test mit Beispiel-Datei\n5. Bestehende Pipeline-Dateien prüfen\n",
"status": "published"
}
}
{
"tool_response": [
{
"type": "text",
"text": "{\n \"success\": true,\n \"doc\": {\n \"id\": 155,\n \"parent_id\": 2,\n \"slug\": \"hook-system-python-erweiterung\",\n \"path\": \"\/server\/ssh\/hook-system-python-erweiterung\",\n \"title\": \"Hook-System Python-Erweiterung\",\n \"description\": \"Analyse und Implementierungsplan für Python-Datei-Unterstützung im Claude Code Hook-System\",\n \"content\": \"# Hook-System Python-Erweiterung\\n\\n## 1. Problemanalyse\\n\\n### 1.1 Ausgangssituation\\nHardcoded Model-Namen (`\\\"mistral\\\"`) in Pipeline-Backfill-Skripten wurden nicht erkannt.\\n\\n**Betroffene Dateien:**\\n- `\/var\/www\/scripts\/pipeline\/backfill_text_semantics.py`\\n- `\/var\/www\/scripts\/pipeline\/backfill_knowledge_semantics.py`\\n\\n### 1.2 Root Cause\\n\\n**hook_dispatcher.py Zeile 78-80:**\\n```python\\nif not file_path.endswith(\\\".php\\\"):\\n # Nicht-PHP: durchlassen ohne Output (implizit allow)\\n sys.exit(0)\\n```\\n\\nDas Hook-System prüft **ausschließlich PHP-Dateien**. Python-Dateien werden komplett übersprungen.\\n\\n### 1.3 Ironische Entdeckung\\n`pre_rules_constants.py` Zeile 56-58 hat bereits Python-Support:\\n```python\\nif not (file_path.endswith('.php') or file_path.endswith('.py')):\\n return None\\n```\\nDiese Regel wird aber nie für Python aufgerufen, weil der Dispatcher vorher abbricht.\\n\\n---\\n\\n## 2. Bestehende Architektur\\n\\n### 2.1 Hook-Konfiguration (~\/.claude\/settings.json)\\n\\n| Event | Matcher | Command |\\n|-------|---------|---------|\\n| PreToolUse | Write | hook_dispatcher.py pre |\\n| PostToolUse | Write\\\\|Edit | hook_dispatcher.py post |\\n\\n### 2.2 Regel-Module (quality\/)\\n\\n| Modul | Typ | Funktion |\\n|-------|-----|----------|\\n| pre_rules.py | Aggregator | Sammelt alle Pre-Hook-Regeln |\\n| post_rules.py | Aggregator | Sammelt alle Post-Hook-Regeln |\\n| pre_rules_guard.py | BLOCK | SRP, KISS, Dateigrößen |\\n| pre_rules_mvc.py | BLOCK | MVC-Architektur |\\n| pre_rules_layers.py | BLOCK | Layer-Trennung, DIP |\\n| pre_rules_validation.py | BLOCK | PSR, Types |\\n| pre_rules_htmx.py | BLOCK | HTMX Contract |\\n| pre_rules_constants.py | BLOCK | Magic Numbers |\\n| rules_quality.py | WARN | Qualitätswarnungen |\\n| rules_security.py | WARN | Security Patterns |\\n| rules_style.py | WARN | Code Style |\\n| rules_constants.py | WARN | Constants Warnungen |\\n\\n### 2.3 Regel-Pattern\\n\\n**Pre-Hook (BLOCK):**\\n```python\\ndef p7_1_critical_magic_numbers(file_path: str, content: str) -> Optional[dict]:\\n if should_skip(file_path):\\n return None\\n # Prüfung...\\n return block(\\\"P7.1\\\", \\\"Message\\\") or None\\n```\\n\\n**Post-Hook (WARN):**\\n```python\\ndef w_rule(file_path: str, content: str) -> List[str]:\\n warnings = []\\n # Prüfung...\\n warnings.append(\\\"Message\\\")\\n return warnings\\n```\\n\\n---\\n\\n## 3. Implementierungsplan\\n\\n### 3.1 Phase 1: Dispatcher erweitern\\n\\n**Datei:** `hook_dispatcher.py`\\n\\n**Änderung:**\\n```python\\n# ALT (Zeile 78-80):\\nif not file_path.endswith(\\\".php\\\"):\\n sys.exit(0)\\n\\n# NEU:\\nALLOWED_EXTENSIONS = {\\\".php\\\", \\\".py\\\"}\\nPYTHON_PATHS = [\\\"\/var\/www\/scripts\/pipeline\/\\\"]\\n\\ndef should_check(file_path: str) -> bool:\\n ext = Path(file_path).suffix\\n if ext not in ALLOWED_EXTENSIONS:\\n return False\\n if ext == \\\".py\\\":\\n return any(file_path.startswith(p) for p in PYTHON_PATHS)\\n return True\\n\\n# In main():\\nif not should_check(file_path):\\n sys.exit(0)\\n```\\n\\n### 3.2 Phase 2: Python-Regeln erstellen\\n\\n**Neue Datei:** `quality\/pre_rules_python.py`\\n\\n```python\\n#!\/usr\/bin\/env python3\\n\\\"\\\"\\\"\\nPre-Hook Python Regeln (BLOCK) - Pipeline Code Quality.\\n\\nPP1.x: Hardcoded Values\\nPP2.x: Config Patterns\\n\\\"\\\"\\\"\\n\\nimport re\\nfrom typing import Optional\\nfrom .rule_base import block, is_in_allowlist\\n\\nPYTHON_ALLOWLIST = [\\n \\\"\/tests\/\\\",\\n \\\"\/venv\/\\\",\\n \\\"\/__pycache__\/\\\",\\n]\\n\\n# Hardcoded Model-Namen die blockiert werden\\nHARDCODED_MODELS = [\\n \\\"mistral\\\", \\\"llama\\\", \\\"gemma\\\", \\\"phi\\\", \\\"qwen\\\",\\n \\\"claude\\\", \\\"gpt-4\\\", \\\"gpt-3.5\\\",\\n \\\"minicpm\\\", \\\"nomic\\\",\\n]\\n\\ndef pp1_1_hardcoded_model_names(file_path: str, content: str) -> Optional[dict]:\\n \\\"\\\"\\\"PP1.1: Hardcoded LLM Model-Namen blockieren.\\\"\\\"\\\"\\n if not file_path.endswith(\\\".py\\\"):\\n return None\\n if is_in_allowlist(file_path, PYTHON_ALLOWLIST):\\n return None\\n \\n lines = content.split('\\\\n')\\n for line_num, line in enumerate(lines, 1):\\n # Skip Kommentare und Docstrings\\n stripped = line.strip()\\n if stripped.startswith('#') or stripped.startswith('\\\"\\\"\\\"') or stripped.startswith(\\\"'''\\\"):\\n continue\\n \\n # Skip imports und Konstanten-Definitionen\\n if 'import ' in line or line.startswith('VALID_') or line.startswith('ALLOWED_'):\\n continue\\n \\n for model in HARDCODED_MODELS:\\n # Pattern: default=\\\"mistral\\\" oder model=\\\"mistral\\\"\\n pattern = rf'(?:default|model)\\\\s*=\\\\s*[\\\"\\\\']({model})[\\\"\\\\']'\\n if re.search(pattern, line, re.IGNORECASE):\\n return block(\\n \\\"PP1.1\\\",\\n f\\\"Hardcoded model name '{model}' at line {line_num}. \\\"\\n f\\\"Use get_pipeline_model() or config parameter.\\\"\\n )\\n return None\\n\\n\\ndef pp1_2_hardcoded_pipeline_id(file_path: str, content: str) -> Optional[dict]:\\n \\\"\\\"\\\"PP1.2: Hardcoded Pipeline-IDs blockieren (außer als Konstante).\\\"\\\"\\\"\\n if not file_path.endswith(\\\".py\\\"):\\n return None\\n if is_in_allowlist(file_path, PYTHON_ALLOWLIST):\\n return None\\n \\n lines = content.split('\\\\n')\\n for line_num, line in enumerate(lines, 1):\\n stripped = line.strip()\\n if stripped.startswith('#'):\\n continue\\n \\n # Erlaubt: DEFAULT_PIPELINE_ID = 5\\n if 'PIPELINE_ID' in line and '=' in line:\\n continue\\n \\n # Verboten: pipeline_id=5 oder pipeline_id = 5 (nicht als Konstante)\\n if re.search(r'pipeline_id\\\\s*=\\\\s*\\\\d+', line) and 'DEFAULT' not in line:\\n return block(\\n \\\"PP1.2\\\",\\n f\\\"Hardcoded pipeline_id at line {line_num}. \\\"\\n f\\\"Use DEFAULT_PIPELINE_ID constant or config parameter.\\\"\\n )\\n return None\\n\\n\\nRULES = [\\n pp1_1_hardcoded_model_names,\\n pp1_2_hardcoded_pipeline_id,\\n]\\n```\\n\\n### 3.3 Phase 3: Integration\\n\\n**Datei:** `quality\/pre_rules.py`\\n\\n```python\\n# Hinzufügen:\\nfrom . import pre_rules_python\\n\\nRULES = [\\n # ... bestehende Regeln ...\\n *pre_rules_python.RULES,\\n]\\n```\\n\\n---\\n\\n## 4. Betroffene Python-Dateien\\n\\n### 4.1 Pipeline-Skripte (zu prüfen)\\n\\n| Datei | Beschreibung |\\n|-------|--------------|\\n| pipeline.py | Haupt-Orchestrator |\\n| backfill_*.py | Backfill-Skripte |\\n| step_*.py | Pipeline-Steps |\\n| knowledge\/*.py | Knowledge-Extraction |\\n\\n### 4.2 Ausnahmen (nicht prüfen)\\n\\n| Pfad | Grund |\\n|------|-------|\\n| \/venv\/ | Virtual Environment |\\n| \/__pycache__\/ | Bytecode |\\n| \/tests\/ | Test-Dateien |\\n| db.py | Infrastruktur |\\n\\n---\\n\\n## 5. Test-Szenarien\\n\\n### 5.1 Blockieren (DENY)\\n```python\\n# Sollte blockiert werden:\\nparser.add_argument(\\\"--model\\\", default=\\\"mistral\\\")\\nmodel = \\\"gemma\\\"\\n```\\n\\n### 5.2 Erlauben (ALLOW)\\n```python\\n# Sollte erlaubt werden:\\nmodel = get_pipeline_model(\\\"text_semantic_analyze\\\")\\nDEFAULT_PIPELINE_ID = 5\\n# Kommentar: mistral ist das Standard-Modell\\n```\\n\\n---\\n\\n## 6. Rollout\\n\\n1. **pre_rules_python.py** erstellen\\n2. **hook_dispatcher.py** erweitern\\n3. **pre_rules.py** aktualisieren\\n4. Manueller Test mit Beispiel-Datei\\n5. Bestehende Pipeline-Dateien prüfen\\n\",\n \"status\": \"published\",\n \"sort_order\": 0,\n \"depth\": 2,\n \"created_at\": \"2025-12-28T09:42:14\",\n \"updated_at\": \"2025-12-28T09:42:14\"\n },\n \"message\": \"Document 'Hook-System Python-Erweiterung' created with ID 155\"\n}"
}
]
}