Protokoll #6872

ID6872
Zeitstempel2025-12-23 07:19:48.952405
Clientroot
IP145.224.96.190
Modellclaude-sonnet-4-20250514
Statuscompleted
Tokens7,700 (Input: 1,631, Output: 6,069)
Dauer149 ms
Request-Zeit2025-12-23 07:19:48.952405
Response-Zeit2025-12-23 07:19:49.100909

Request

{
    "event": "PreToolUse",
    "tool_name": "Edit",
    "tool_input": {
        "file_path": "\/var\/www\/dev.campus.systemische-tools.de\/docs\/plan-code-quality-gates.md",
        "old_string": "# Prüfung 5-6\n\n*Werden nach Abnahme von Prüfung 4 definiert.*",
        "new_string": "# Prüfung 5: DRY\n\n## Ziel\n\n**DRY (Don't Repeat Yourself):**\n- Jedes Wissen hat genau einen Ort\n- Duplikation = technische Schuld\n- Änderung an einer Stelle soll genügen\n\n## Grundsatz\n\nDRY-Verletzungen sind schwer automatisch zu erkennen:\n- Semantische Duplikation erfordert Verständnis\n- Near-Misses (fast gleicher Code) erfordert AST\n- Cross-File-Duplikation erfordert Projekt-weite Analyse\n\n**Was Regex-Hooks können:**\n- Identische Literale innerhalb einer Datei erkennen\n- Offensichtliche Magic Numbers finden\n\n**Was Regex-Hooks NICHT können:**\n- Semantisch äquivalenten Code erkennen\n- Near-Misses finden\n- Cross-File-Duplikate erkennen\n\n**Konsequenz:** Nur Post-Hook-Warnungen. Keine Blockaden.\n\n## Abgrenzung zu anderen Prüfungen\n\n| Aspekt | Prüfung | Begründung |\n|--------|---------|------------|\n| Code-Größe | 1 (SRP) | Strukturelle Metrik |\n| Verantwortungs-Trennung | 1 (SRP) | Semantische Kohärenz |\n| **Wiederholtes Wissen** | **5 (DRY)** | Identische Literale, Magic Numbers |\n\n---\n\n## Pre-Hook (BLOCK)\n\n**Keine.**\n\n**Begründung:**\n- DRY-Verletzungen sind niemals eindeutig blockierbar\n- Manchmal ist Duplikation die richtige Entscheidung (YAGNI vor DRY)\n- \"Premature abstraction\" ist schlimmer als Duplikation\n- False Positives würden Entwicklung blockieren\n\n---\n\n## Post-Hook (WARN)\n\n### W5.1: Wiederholte String-Literale\n\n**Regel:** Warnung wenn identische Strings > 20 Zeichen mehr als 3x vorkommen.\n\n**Warum 20 Zeichen:**\n- Kurze Strings sind oft legitim (\"id\", \"name\", \"GET\", \"POST\")\n- 20+ Zeichen sind wahrscheinlich Business-relevante Texte\n- Feldnamen, HTTP-Methoden, einfache Labels zählen nicht\n\n**Warum > 3x:**\n- 2x kann bewusste Entscheidung sein\n- 3+ deutet auf fehlende Konstante\n\n**Pattern:**\n```python\nstring_literals = re.findall(r'\"([^\"]{20,})\"', content)\nfrom collections import Counter\ncounts = Counter(string_literals)\nfor s, count in counts.items():\n    if count > 3:\n        warn(f\"String repeated {count}x: '{s[:40]}...' - consider constant\")\n```\n\n**Nicht gewarnt:**\n- Strings < 20 Zeichen\n- Strings die nur 2-3x vorkommen\n\n---\n\n### W5.2: Wiederholte Magic Numbers\n\n**Regel:** Warnung wenn gleiche Zahl (nicht in Common-Liste) > 2x vorkommt.\n\n**Common-Liste (erlaubt):**\n```python\nCOMMON_NUMBERS = {\n    '0', '1', '2',           # Index, Boolean, Paar\n    '10', '100', '1000',     # Dezimal-Einheiten\n    '60', '24', '365',       # Zeit (Sekunden, Stunden, Tage)\n    '30', '31', '28', '29',  # Monatstage\n    '12', '52', '7',         # Kalender (Monate, Wochen, Wochentage)\n    '200', '201', '204',     # HTTP Success\n    '301', '302', '304',     # HTTP Redirect\n    '400', '401', '403', '404', '500',  # HTTP Errors\n}\n```\n\n**Pattern:**\n```python\n# Zahlen finden, aber nicht in Konstanten-Definitionen\nnumbers = re.findall(r'(?<![A-Z_])(\\d{2,})(?![A-Z_])', content)\nfor num in set(numbers):\n    if num not in COMMON_NUMBERS and numbers.count(num) > 2:\n        warn(f\"Magic number {num} repeated {numbers.count(num)}x - consider constant\")\n```\n\n**Warum > 2x:**\n- Einmalig: Okay (könnte kontextspezifisch sein)\n- Zweimal: Grenzfall\n- Dreimal+: Wahrscheinlich systematisches Problem\n\n**Warum Common-Liste:**\n- HTTP-Statuscodes sind universell bekannt\n- Zeitkonstanten (60, 24, 365) sind selbstdokumentierend\n- Kleine Zahlen (0, 1, 2) sind unvermeidlich\n\n---\n\n## Gestrichen\n\n### Regex-Pattern-Duplikation\n\n**Ursprüngliche Idee:** Wiederholte Regex-Patterns finden.\n\n**Warum gestrichen:**\n- Regex für Regex-Erkennung ist fehleranfällig\n- Pfade (\/path\/to\/file) matchen als False Positives\n- Zu komplex für marginalen Nutzen\n\n### Cross-File-Duplikation\n\n**Warum gestrichen:**\n- Single-File-Hooks können das nicht\n- Erfordert externes Tool (phpcpd)\n- Ist fundamentale Limitation, nicht Versäumnis\n\n### Code-Block-Ähnlichkeit\n\n**Warum gestrichen:**\n- Erfordert AST-Analyse oder Token-Vergleich\n- Regex kann semantische Ähnlichkeit nicht erkennen\n\n### String-Längen-Block\n\n**Ursprüngliche Idee:** Strings > 100 Zeichen blockieren.\n\n**Warum gestrichen:**\n- Lange Strings können legitim sein (SQL, Templates)\n- Nicht DRY-spezifisch\n\n---\n\n## Zusammenfassung\n\n### Pre-Hook\n\n| ID | Prüfung | Aktion |\n|----|---------|--------|\n| - | Keine | - |\n\n### Post-Hook\n\n| ID | Prüfung | Schwelle | Aktion |\n|----|---------|----------|--------|\n| W5.1 | Wiederholte Strings | > 20 chars, > 3x | WARN |\n| W5.2 | Magic Numbers | nicht in Common, > 2x | WARN |\n\n### Allowlist\n\n| Pfad | Grund |\n|------|-------|\n| \/vendor\/ | Third-party |\n| \/tests\/ | Test-Fixtures oft identisch |\n| \/Test\/ | PHPUnit |\n| \/migrations\/ | SQL-Statements oft ähnlich |\n\n---\n\n## Externe Tools\n\n**Für vollständige DRY-Prüfung wird phpcpd empfohlen:**\n\n```bash\nphpcpd src\/\n```\n\n**Warum nicht im Hook integriert:**\n- phpcpd ist langsam (Projekt-weite Analyse)\n- Hooks sollen schnell sein (< 5s Timeout)\n- CI-Pipeline ist der richtige Ort für phpcpd\n\n**Empfehlung:** phpcpd in Quality-Check-Script integrieren, nicht in Hook.\n\n---\n\n## Selbstkritik und Entscheidungen\n\n| Frage | Entscheidung | Begründung |\n|-------|--------------|------------|\n| Warum kein Pre-Hook? | DRY nie blockierbar | Duplikation kann bewusst sein |\n| Ist das zu dünn? | Nein, ehrlich | Mehr wäre False-Positive-Gefahr |\n| Gehören Magic Numbers zu DRY? | Grenzfall, aber ja | Zahl = dupliziertes Wissen über Bedeutung |\n| Warum nicht phpcpd integrieren? | Performance | Hooks müssen schnell sein |\n| Sind 20 Zeichen die richtige Schwelle? | Konservativ | Lieber zu wenig warnen als zu viel |\n\n---\n\n## DRY vs. Prüfbarkeit\n\n| DRY-Aspekt | Prüfbar? | Methode |\n|------------|----------|---------|\n| Identische Strings | Ja | Regex |\n| Magic Numbers | Ja | Regex |\n| Near-Miss-Code | Nein | Braucht AST |\n| Semantische Duplikation | Nein | Braucht Verständnis |\n| Cross-File | Nein | Braucht phpcpd |\n\n**Fazit:** DRY-Hooks erkennen nur die offensichtlichsten Symptome. Für echte DRY-Prüfung ist phpcpd erforderlich. Das ist keine Schwäche des Hooks, sondern ehrliche Anerkennung der Grenzen von Regex-basierter Analyse.\n\n---\n\n# Prüfung 6\n\n*Wird nach Abnahme von Prüfung 5 definiert.*"
    }
}

Response

{
    "tool_response": {
        "filePath": "\/var\/www\/dev.campus.systemische-tools.de\/docs\/plan-code-quality-gates.md",
        "oldString": "# Prüfung 5-6\n\n*Werden nach Abnahme von Prüfung 4 definiert.*",
        "newString": "# Prüfung 5: DRY\n\n## Ziel\n\n**DRY (Don't Repeat Yourself):**\n- Jedes Wissen hat genau einen Ort\n- Duplikation = technische Schuld\n- Änderung an einer Stelle soll genügen\n\n## Grundsatz\n\nDRY-Verletzungen sind schwer automatisch zu erkennen:\n- Semantische Duplikation erfordert Verständnis\n- Near-Misses (fast gleicher Code) erfordert AST\n- Cross-File-Duplikation erfordert Projekt-weite Analyse\n\n**Was Regex-Hooks können:**\n- Identische Literale innerhalb einer Datei erkennen\n- Offensichtliche Magic Numbers finden\n\n**Was Regex-Hooks NICHT können:**\n- Semantisch äquivalenten Code erkennen\n- Near-Misses finden\n- Cross-File-Duplikate erkennen\n\n**Konsequenz:** Nur Post-Hook-Warnungen. Keine Blockaden.\n\n## Abgrenzung zu anderen Prüfungen\n\n| Aspekt | Prüfung | Begründung |\n|--------|---------|------------|\n| Code-Größe | 1 (SRP) | Strukturelle Metrik |\n| Verantwortungs-Trennung | 1 (SRP) | Semantische Kohärenz |\n| **Wiederholtes Wissen** | **5 (DRY)** | Identische Literale, Magic Numbers |\n\n---\n\n## Pre-Hook (BLOCK)\n\n**Keine.**\n\n**Begründung:**\n- DRY-Verletzungen sind niemals eindeutig blockierbar\n- Manchmal ist Duplikation die richtige Entscheidung (YAGNI vor DRY)\n- \"Premature abstraction\" ist schlimmer als Duplikation\n- False Positives würden Entwicklung blockieren\n\n---\n\n## Post-Hook (WARN)\n\n### W5.1: Wiederholte String-Literale\n\n**Regel:** Warnung wenn identische Strings > 20 Zeichen mehr als 3x vorkommen.\n\n**Warum 20 Zeichen:**\n- Kurze Strings sind oft legitim (\"id\", \"name\", \"GET\", \"POST\")\n- 20+ Zeichen sind wahrscheinlich Business-relevante Texte\n- Feldnamen, HTTP-Methoden, einfache Labels zählen nicht\n\n**Warum > 3x:**\n- 2x kann bewusste Entscheidung sein\n- 3+ deutet auf fehlende Konstante\n\n**Pattern:**\n```python\nstring_literals = re.findall(r'\"([^\"]{20,})\"', content)\nfrom collections import Counter\ncounts = Counter(string_literals)\nfor s, count in counts.items():\n    if count > 3:\n        warn(f\"String repeated {count}x: '{s[:40]}...' - consider constant\")\n```\n\n**Nicht gewarnt:**\n- Strings < 20 Zeichen\n- Strings die nur 2-3x vorkommen\n\n---\n\n### W5.2: Wiederholte Magic Numbers\n\n**Regel:** Warnung wenn gleiche Zahl (nicht in Common-Liste) > 2x vorkommt.\n\n**Common-Liste (erlaubt):**\n```python\nCOMMON_NUMBERS = {\n    '0', '1', '2',           # Index, Boolean, Paar\n    '10', '100', '1000',     # Dezimal-Einheiten\n    '60', '24', '365',       # Zeit (Sekunden, Stunden, Tage)\n    '30', '31', '28', '29',  # Monatstage\n    '12', '52', '7',         # Kalender (Monate, Wochen, Wochentage)\n    '200', '201', '204',     # HTTP Success\n    '301', '302', '304',     # HTTP Redirect\n    '400', '401', '403', '404', '500',  # HTTP Errors\n}\n```\n\n**Pattern:**\n```python\n# Zahlen finden, aber nicht in Konstanten-Definitionen\nnumbers = re.findall(r'(?<![A-Z_])(\\d{2,})(?![A-Z_])', content)\nfor num in set(numbers):\n    if num not in COMMON_NUMBERS and numbers.count(num) > 2:\n        warn(f\"Magic number {num} repeated {numbers.count(num)}x - consider constant\")\n```\n\n**Warum > 2x:**\n- Einmalig: Okay (könnte kontextspezifisch sein)\n- Zweimal: Grenzfall\n- Dreimal+: Wahrscheinlich systematisches Problem\n\n**Warum Common-Liste:**\n- HTTP-Statuscodes sind universell bekannt\n- Zeitkonstanten (60, 24, 365) sind selbstdokumentierend\n- Kleine Zahlen (0, 1, 2) sind unvermeidlich\n\n---\n\n## Gestrichen\n\n### Regex-Pattern-Duplikation\n\n**Ursprüngliche Idee:** Wiederholte Regex-Patterns finden.\n\n**Warum gestrichen:**\n- Regex für Regex-Erkennung ist fehleranfällig\n- Pfade (\/path\/to\/file) matchen als False Positives\n- Zu komplex für marginalen Nutzen\n\n### Cross-File-Duplikation\n\n**Warum gestrichen:**\n- Single-File-Hooks können das nicht\n- Erfordert externes Tool (phpcpd)\n- Ist fundamentale Limitation, nicht Versäumnis\n\n### Code-Block-Ähnlichkeit\n\n**Warum gestrichen:**\n- Erfordert AST-Analyse oder Token-Vergleich\n- Regex kann semantische Ähnlichkeit nicht erkennen\n\n### String-Längen-Block\n\n**Ursprüngliche Idee:** Strings > 100 Zeichen blockieren.\n\n**Warum gestrichen:**\n- Lange Strings können legitim sein (SQL, Templates)\n- Nicht DRY-spezifisch\n\n---\n\n## Zusammenfassung\n\n### Pre-Hook\n\n| ID | Prüfung | Aktion |\n|----|---------|--------|\n| - | Keine | - |\n\n### Post-Hook\n\n| ID | Prüfung | Schwelle | Aktion |\n|----|---------|----------|--------|\n| W5.1 | Wiederholte Strings | > 20 chars, > 3x | WARN |\n| W5.2 | Magic Numbers | nicht in Common, > 2x | WARN |\n\n### Allowlist\n\n| Pfad | Grund |\n|------|-------|\n| \/vendor\/ | Third-party |\n| \/tests\/ | Test-Fixtures oft identisch |\n| \/Test\/ | PHPUnit |\n| \/migrations\/ | SQL-Statements oft ähnlich |\n\n---\n\n## Externe Tools\n\n**Für vollständige DRY-Prüfung wird phpcpd empfohlen:**\n\n```bash\nphpcpd src\/\n```\n\n**Warum nicht im Hook integriert:**\n- phpcpd ist langsam (Projekt-weite Analyse)\n- Hooks sollen schnell sein (< 5s Timeout)\n- CI-Pipeline ist der richtige Ort für phpcpd\n\n**Empfehlung:** phpcpd in Quality-Check-Script integrieren, nicht in Hook.\n\n---\n\n## Selbstkritik und Entscheidungen\n\n| Frage | Entscheidung | Begründung |\n|-------|--------------|------------|\n| Warum kein Pre-Hook? | DRY nie blockierbar | Duplikation kann bewusst sein |\n| Ist das zu dünn? | Nein, ehrlich | Mehr wäre False-Positive-Gefahr |\n| Gehören Magic Numbers zu DRY? | Grenzfall, aber ja | Zahl = dupliziertes Wissen über Bedeutung |\n| Warum nicht phpcpd integrieren? | Performance | Hooks müssen schnell sein |\n| Sind 20 Zeichen die richtige Schwelle? | Konservativ | Lieber zu wenig warnen als zu viel |\n\n---\n\n## DRY vs. Prüfbarkeit\n\n| DRY-Aspekt | Prüfbar? | Methode |\n|------------|----------|---------|\n| Identische Strings | Ja | Regex |\n| Magic Numbers | Ja | Regex |\n| Near-Miss-Code | Nein | Braucht AST |\n| Semantische Duplikation | Nein | Braucht Verständnis |\n| Cross-File | Nein | Braucht phpcpd |\n\n**Fazit:** DRY-Hooks erkennen nur die offensichtlichsten Symptome. Für echte DRY-Prüfung ist phpcpd erforderlich. Das ist keine Schwäche des Hooks, sondern ehrliche Anerkennung der Grenzen von Regex-basierter Analyse.\n\n---\n\n# Prüfung 6\n\n*Wird nach Abnahme von Prüfung 5 definiert.*",
        "originalFile": "# Code Quality Gates\n\n## Prüfungsreihenfolge\n\n| # | Prinzip | Begründung der Reihenfolge |\n|---|---------|---------------------------|\n| 1 | SRP + KISS | Grundlage für alles. Ohne klare Verantwortung ist nichts anderes prüfbar. |\n| 2 | MVC + CRUD | Strukturelle Trennung. Setzt SRP voraus. |\n| 3 | PSR + Types | Typdisziplin. Muss VOR DIP kommen, weil Interfaces ohne Typen wirkungslos sind. |\n| 4 | OOP | Verhalten + Zustand. Setzt Typen voraus. |\n| 5 | DRY | Duplikationserkennung. Setzt funktionierende Struktur voraus. |\n| 6 | SOLID + DIP | Abhängigkeitsrichtung. Setzt Typen und Interfaces voraus. Kommt zuletzt. |\n\n---\n\n# Prüfung 1: SRP + KISS\n\n## Ziel\n\n**SRP:** Eine Klasse hat genau einen Grund sich zu ändern.\n\n**KISS:** Einfachste Lösung die funktioniert. Keine vorzeitigen Abstraktionen.\n\n## Grundsatz\n\nSRP ist semantisch. Maschinen können \"Verantwortung\" nicht verstehen.\n\nDaher:\n- **Pre-Hook:** Erzwingt explizite Deklaration + blockiert eindeutige Symptome\n- **Post-Hook:** Warnt bei statistischen Indikatoren\n\n---\n\n## Pre-Hook (BLOCK)\n\n### P1.1: Verantwortungs-Header\n\n**Regel:** Jede PHP-Datei muss ihre Verantwortung explizit deklarieren.\n\n**Format:**\n```php\n<?php\ndeclare(strict_types=1);\n\n\/\/ @responsibility: <genau-eine-verantwortung>\n```\n\n**Validierung:**\n\n| Check | Begründung |\n|-------|------------|\n| Header vorhanden | Ohne Deklaration entsteht Scope Creep |\n| Nicht leer | Leerer Header ist wertlos |\n| Keine Multi-Responsibility-Wörter | \"und\", \"sowie\", \"außerdem\", \"zusätzlich\" im Header = mehrere Verantwortungen |\n\n**Pattern:**\n```python\nheader_pattern = r\"\/\/\\s*@responsibility:\\s*(.+)\"\nmulti_words = r\"\\b(und|sowie|außerdem|also|zusätzlich)\\b\"\n\nmatch = re.search(header_pattern, content)\nif not match:\n    block(\"Missing @responsibility header\")\n\nresponsibility_text = match.group(1)\nif re.search(multi_words, responsibility_text, re.IGNORECASE):\n    block(\"@responsibility contains multi-responsibility indicator\")\n```\n\n**Warum diese Wörter:**\n- \"Validiert Benutzer und erstellt Sessions\" = 2 Verantwortungen\n- \"Lädt Daten sowie formatiert Ausgabe\" = 2 Verantwortungen\n- Erzwingt Nachdenken über Singular-Verantwortung\n\n**Allowlist:** `\/vendor\/`, `\/tests\/`, `\/Test\/`\n\n---\n\n### P1.2: Müllhalden-Namen\n\n**Regel:** Bestimmte Begriffe im Dateinamen sind immer Symptome für fehlende klare Verantwortung.\n\n**Blockiert (case-insensitive):**\n\n| Begriff | Begründung |\n|---------|------------|\n| Helper | \"Hilft bei allem\" = keine klare Verantwortung |\n| Utils | Sammelbecken für Funktionen ohne Heimat |\n| Common | \"Wird überall gebraucht\" = gehört nirgends hin |\n| Misc | Explizit: \"Verschiedenes\" |\n| Base | Oft Gott-Klasse mit Shared-State |\n\n**Nicht blockiert:**\n- \"Manager\" → Kann legitim sein (TransactionManager, EntityManager)\n- \"And\" im Namen → Sprachlich, nicht strukturell\n\n**Pattern:**\n```python\nforbidden = [\"helper\", \"utils\", \"common\", \"misc\", \"base\"]\nfilename_lower = filename.lower()\nfor term in forbidden:\n    if term in filename_lower:\n        block(f\"Forbidden name: '{term}' indicates unclear responsibility\")\n```\n\n**Keine Ausnahmen.** Diese Begriffe sind niemals architektonisch sauber.\n\n---\n\n## Post-Hook (WARN)\n\n### W1.1: Klassengröße (LOC)\n\n**Regel:** Große Klassen haben oft mehrere Verantwortungen.\n\n| LOC | Aktion |\n|-----|--------|\n| > 200 | Hinweis |\n| > 300 | Warnung |\n\n**Warum zwei Schwellen:**\n- 200: \"Du näherst dich dem Limit\"\n- 300: \"Hier stimmt strukturell etwas nicht\"\n\n**Messung:** Nicht-leere Zeilen.\n\n---\n\n### W1.2: Public-Method-Count\n\n**Regel:** Viele öffentliche Methoden = viele Interaktionspunkte = breite Verantwortung.\n\n| Count | Aktion |\n|-------|--------|\n| > 10 | Warnung |\n\n**Warum 10:**\n- Ein fokussiertes Interface hat 3-7 Methoden\n- 10+ deutet auf Feature Creep\n\n---\n\n### W1.3: Constructor-Parameter\n\n**Regel:** Viele Dependencies = viele Gründe sich zu ändern.\n\n| Count | Aktion |\n|-------|--------|\n| > 5 | Warnung |\n\n**Warum 5:**\n- 1-3: Normal\n- 4-5: Grenzwertig\n- 6+: Fast immer strukturelles Problem\n\n---\n\n### W1.4: Dependency-Count (use-Statements)\n\n**Regel:** Viele Imports = Kopplung an viele Module = viele Änderungsgründe.\n\n| Count | Aktion |\n|-------|--------|\n| > 10 | Warnung |\n\n**Warum 10:**\n- PHP-interne Classes zählen mit\n- Framework-Imports zählen mit\n- 10+ externe Abhängigkeiten ist ein Warnsignal\n\n---\n\n### W1.5: Verdächtige Namen\n\n**Regel:** Manche Begriffe sind nicht eindeutig Müll, aber verdächtig.\n\n| Begriff | Aktion |\n|---------|--------|\n| Manager | Hinweis |\n| And (als Wort) | Hinweis |\n\n**Warum Hinweis statt Block:**\n- \"UserManager\" kann legitim sein\n- \"ReadAndWrite\" kann legitim sein (obwohl fragwürdig)\n- Menschliche Entscheidung erforderlich\n\n---\n\n## Gestrichen\n\n### Verschachtelungstiefe\n\n**Ursprüngliche Idee:** > 4 Ebenen = Warnung\n\n**Warum gestrichen:**\n- Indent-basierte Messung ist nicht zuverlässig\n- PHP erlaubt verschiedene Styles (2, 4, Tabs)\n- Fluent Interfaces erzeugen tiefe Indents ohne Kontrollfluss\n- Array-Definitionen erzeugen tiefe Indents\n- False Positives zu hoch\n\n**Alternative:** Erst implementieren wenn AST-Parsing verfügbar.\n\n---\n\n## Zusammenfassung\n\n### Pre-Hook\n\n| ID | Prüfung | Aktion |\n|----|---------|--------|\n| P1.1 | @responsibility fehlt oder Multi-Responsibility | BLOCK |\n| P1.2 | Müllhalden-Name (Helper, Utils, Common, Misc, Base) | BLOCK |\n\n### Post-Hook\n\n| ID | Prüfung | Schwelle | Aktion |\n|----|---------|----------|--------|\n| W1.1 | LOC | > 300 | WARN |\n| W1.2 | Public Methods | > 10 | WARN |\n| W1.3 | Constructor Params | > 5 | WARN |\n| W1.4 | Dependencies (use) | > 10 | WARN |\n| W1.5 | Verdächtige Namen | Manager, And | HINT |\n\n### Allowlist\n\n| Pfad | Grund |\n|------|-------|\n| \/vendor\/ | Third-party Code |\n| \/tests\/ | Test-Konventionen anders |\n| \/Test\/ | PHPUnit |\n\n---\n\n## Selbstkritik und Entscheidungen\n\n| Frage | Entscheidung | Begründung |\n|-------|--------------|------------|\n| Ist Multi-Word-Check im Header Over-Engineering? | Nein | Ein Regex. Verhindert \"Macht A und B\". Minimaler Aufwand, hoher Nutzen. |\n| Ist Dependency-Count SRP? | Ja | Viele Dependencies = viele Änderungsgründe = SRP-Verletzung per Definition. |\n| Sollen Factories in Allowlist? | Nein | Auch Factories sollten nicht 50 Methoden haben. Wenn zu groß, aufteilen. |\n| Warum keine Kontext-Schwellen für Repositories? | YAGNI | Komplexität ohne klaren Nutzen. Wer > 10 Methoden braucht, soll bewusst entscheiden. |\n\n---\n\n## Implementierung\n\n**Dateien:**\n- `\/var\/www\/tools\/ki-protokoll\/claude-hook\/srp_kiss_guard.py` (Pre-Hook)\n- `\/var\/www\/tools\/ki-protokoll\/claude-hook\/srp_kiss_metrics.py` (Post-Hook)\n\n**Hooks in settings.json:**\n```json\n{\n  \"PreToolUse\": [\n    {\n      \"matcher\": \"Write\",\n      \"hooks\": [\n        {\n          \"type\": \"command\",\n          \"command\": \"\/var\/www\/tools\/ki-protokoll\/claude-hook\/srp_kiss_guard.py\",\n          \"timeout\": 5\n        }\n      ]\n    }\n  ],\n  \"PostToolUse\": [\n    {\n      \"matcher\": \"Write|Edit\",\n      \"hooks\": [\n        {\n          \"type\": \"command\",\n          \"command\": \"\/var\/www\/tools\/ki-protokoll\/claude-hook\/srp_kiss_metrics.py\",\n          \"timeout\": 5\n        }\n      ]\n    }\n  ]\n}\n```\n\n---\n\n# Prüfung 2: MVC + CRUD\n\n## Ziel\n\n**MVC:** Klare Rollentrennung.\n- Controller: Orchestrierung (nimmt Request, ruft UseCase, gibt Response)\n- View: Darstellung (keine Logik)\n- Model: Geschäftslogik (Domain + UseCases)\n\n**CRUD:** Persistenz-Disziplin.\n- Create\/Read\/Update\/Delete gehören in Repository\n- Transaktionen gehören in UseCase oder Repository, nicht Controller\n- Controller orchestriert, persistiert nicht\n\n## Grundsatz\n\nMVC ist strukturell. Die Rollen sind durch Pfade definiert:\n- `\/Controller\/` = Presentation Layer\n- `\/View\/`, `\/templates\/` = Templates\n- `\/Domain\/` = Business Logic\n- `\/UseCases\/`, `\/Application\/` = Application Logic\n- `\/Infrastructure\/Persistence\/` = Repositories\n\n## Abgrenzung zu anderen Prüfungen\n\n| Aspekt | Prüfung | Begründung |\n|--------|---------|------------|\n| Klassen-Größe | 1 (SRP) | Strukturelle Metrik |\n| Methoden-Anzahl | 1 (SRP) | Strukturelle Metrik |\n| Abhängigkeits-Richtung | 6 (DIP) | Dependency Inversion |\n| **Rollen-Einhaltung** | **2 (MVC)** | Controller\/View\/Model Trennung |\n| **Persistenz-Ort** | **2 (CRUD)** | Wer darf DB anfassen |\n\n---\n\n## Pre-Hook (BLOCK)\n\n### P2.1: Keine SQL-Statements in Controller\n\n**Regel:** Controller dürfen keine direkten SQL-Queries enthalten.\n\n**Scope:** `\/Controller\/`\n\n**Pattern:**\n```python\nsql_patterns = [\n    r\"\\bSELECT\\s+.+\\s+FROM\\b\",\n    r\"\\bINSERT\\s+INTO\\b\",\n    r\"\\bUPDATE\\s+\\w+\\s+SET\\b\",\n    r\"\\bDELETE\\s+FROM\\b\",\n]\n```\n\n**Warum diese Pattern:**\n- Spezifisch genug um False Positives zu vermeiden\n- `SELECT your country` matcht nicht (kein FROM)\n- `INSERT INTO users` matcht (eindeutig SQL)\n\n**Unterschied zu Prüfung 1\/6:**\n- H-Regeln prüfen Objekte (new Repository, DatabaseFactory)\n- P2.1 prüft String-Literale (SQL-Statements)\n\n---\n\n### P2.2: Keine Transaktionen in Controller\n\n**Regel:** Transaktions-Kontrolle gehört nicht in Controller.\n\n**Scope:** `\/Controller\/`\n\n**Pattern:**\n```python\ntransaction_patterns = [\n    r\"\\bbeginTransaction\\s*\\(\",\n    r\"\\bcommit\\s*\\(\",\n    r\"\\brollBack\\s*\\(\",\n    r\"\\brollback\\s*\\(\",\n]\n```\n\n**Begründung:**\n- Transaktionen sind Infrastruktur-Concern\n- Controller soll Request→Response orchestrieren, nicht DB-Konsistenz managen\n- Transaktionen gehören in UseCase oder Repository\n\n---\n\n### P2.3: Kein direktes Rendering in Controller\n\n**Regel:** Controller erzeugen keine direkte Ausgabe.\n\n**Scope:** `\/Controller\/`\n\n**Pattern:**\n```python\noutput_patterns = [\n    r\"\\becho\\s\",\n    r\"\\becho\\(\",\n    r\"\\bprint\\s\",\n    r\"\\bprint\\(\",\n]\n```\n\n**Nicht blockiert:**\n- `print_r` (Debug)\n- `printf` (Formatierung, selten)\n- `return json_encode()` (Response-Objekt)\n\n**Begründung:**\n- Output gehört in View oder Response-Objekt\n- echo\/print in Controller = MVC-Verletzung\n- CLI-Code gehört in `\/Console\/` oder `\/Command\/`, nicht `\/Controller\/`\n\n---\n\n### P2.4: Keine DB-Artefakte in UseCases\n\n**Regel:** UseCases nutzen Repository-Interfaces, nicht direkte DB.\n\n**Scope:** `\/UseC... [TRUNCATED-95ec29301be93107]",
        "structuredPatch": [
            {
                "oldStart": 1119,
                "oldLines": 6,
                "newStart": 1119,
                "newLines": 228,
                "lines": [
                    " ",
                    " ---",
                    " ",
                    "-# Prüfung 5-6",
                    "+# Prüfung 5: DRY",
                    " ",
                    "-*Werden nach Abnahme von Prüfung 4 definiert.*",
                    "+## Ziel",
                    "+",
                    "+**DRY (Don't Repeat Yourself):**",
                    "+- Jedes Wissen hat genau einen Ort",
                    "+- Duplikation = technische Schuld",
                    "+- Änderung an einer Stelle soll genügen",
                    "+",
                    "+## Grundsatz",
                    "+",
                    "+DRY-Verletzungen sind schwer automatisch zu erkennen:",
                    "+- Semantische Duplikation erfordert Verständnis",
                    "+- Near-Misses (fast gleicher Code) erfordert AST",
                    "+- Cross-File-Duplikation erfordert Projekt-weite Analyse",
                    "+",
                    "+**Was Regex-Hooks können:**",
                    "+- Identische Literale innerhalb einer Datei erkennen",
                    "+- Offensichtliche Magic Numbers finden",
                    "+",
                    "+**Was Regex-Hooks NICHT können:**",
                    "+- Semantisch äquivalenten Code erkennen",
                    "+- Near-Misses finden",
                    "+- Cross-File-Duplikate erkennen",
                    "+",
                    "+**Konsequenz:** Nur Post-Hook-Warnungen. Keine Blockaden.",
                    "+",
                    "+## Abgrenzung zu anderen Prüfungen",
                    "+",
                    "+| Aspekt | Prüfung | Begründung |",
                    "+|--------|---------|------------|",
                    "+| Code-Größe | 1 (SRP) | Strukturelle Metrik |",
                    "+| Verantwortungs-Trennung | 1 (SRP) | Semantische Kohärenz |",
                    "+| **Wiederholtes Wissen** | **5 (DRY)** | Identische Literale, Magic Numbers |",
                    "+",
                    "+---",
                    "+",
                    "+## Pre-Hook (BLOCK)",
                    "+",
                    "+**Keine.**",
                    "+",
                    "+**Begründung:**",
                    "+- DRY-Verletzungen sind niemals eindeutig blockierbar",
                    "+- Manchmal ist Duplikation die richtige Entscheidung (YAGNI vor DRY)",
                    "+- \"Premature abstraction\" ist schlimmer als Duplikation",
                    "+- False Positives würden Entwicklung blockieren",
                    "+",
                    "+---",
                    "+",
                    "+## Post-Hook (WARN)",
                    "+",
                    "+### W5.1: Wiederholte String-Literale",
                    "+",
                    "+**Regel:** Warnung wenn identische Strings > 20 Zeichen mehr als 3x vorkommen.",
                    "+",
                    "+**Warum 20 Zeichen:**",
                    "+- Kurze Strings sind oft legitim (\"id\", \"name\", \"GET\", \"POST\")",
                    "+- 20+ Zeichen sind wahrscheinlich Business-relevante Texte",
                    "+- Feldnamen, HTTP-Methoden, einfache Labels zählen nicht",
                    "+",
                    "+**Warum > 3x:**",
                    "+- 2x kann bewusste Entscheidung sein",
                    "+- 3+ deutet auf fehlende Konstante",
                    "+",
                    "+**Pattern:**",
                    "+```python",
                    "+string_literals = re.findall(r'\"([^\"]{20,})\"', content)",
                    "+from collections import Counter",
                    "+counts = Counter(string_literals)",
                    "+for s, count in counts.items():",
                    "+    if count > 3:",
                    "+        warn(f\"String repeated {count}x: '{s[:40]}...' - consider constant\")",
                    "+```",
                    "+",
                    "+**Nicht gewarnt:**",
                    "+- Strings < 20 Zeichen",
                    "+- Strings die nur 2-3x vorkommen",
                    "+",
                    "+---",
                    "+",
                    "+### W5.2: Wiederholte Magic Numbers",
                    "+",
                    "+**Regel:** Warnung wenn gleiche Zahl (nicht in Common-Liste) > 2x vorkommt.",
                    "+",
                    "+**Common-Liste (erlaubt):**",
                    "+```python",
                    "+COMMON_NUMBERS = {",
                    "+    '0', '1', '2',           # Index, Boolean, Paar",
                    "+    '10', '100', '1000',     # Dezimal-Einheiten",
                    "+    '60', '24', '365',       # Zeit (Sekunden, Stunden, Tage)",
                    "+    '30', '31', '28', '29',  # Monatstage",
                    "+    '12', '52', '7',         # Kalender (Monate, Wochen, Wochentage)",
                    "+    '200', '201', '204',     # HTTP Success",
                    "+    '301', '302', '304',     # HTTP Redirect",
                    "+    '400', '401', '403', '404', '500',  # HTTP Errors",
                    "+}",
                    "+```",
                    "+",
                    "+**Pattern:**",
                    "+```python",
                    "+# Zahlen finden, aber nicht in Konstanten-Definitionen",
                    "+numbers = re.findall(r'(?<![A-Z_])(\\d{2,})(?![A-Z_])', content)",
                    "+for num in set(numbers):",
                    "+    if num not in COMMON_NUMBERS and numbers.count(num) > 2:",
                    "+        warn(f\"Magic number {num} repeated {numbers.count(num)}x - consider constant\")",
                    "+```",
                    "+",
                    "+**Warum > 2x:**",
                    "+- Einmalig: Okay (könnte kontextspezifisch sein)",
                    "+- Zweimal: Grenzfall",
                    "+- Dreimal+: Wahrscheinlich systematisches Problem",
                    "+",
                    "+**Warum Common-Liste:**",
                    "+- HTTP-Statuscodes sind universell bekannt",
                    "+- Zeitkonstanten (60, 24, 365) sind selbstdokumentierend",
                    "+- Kleine Zahlen (0, 1, 2) sind unvermeidlich",
                    "+",
                    "+---",
                    "+",
                    "+## Gestrichen",
                    "+",
                    "+### Regex-Pattern-Duplikation",
                    "+",
                    "+**Ursprüngliche Idee:** Wiederholte Regex-Patterns finden.",
                    "+",
                    "+**Warum gestrichen:**",
                    "+- Regex für Regex-Erkennung ist fehleranfällig",
                    "+- Pfade (\/path\/to\/file) matchen als False Positives",
                    "+- Zu komplex für marginalen Nutzen",
                    "+",
                    "+### Cross-File-Duplikation",
                    "+",
                    "+**Warum gestrichen:**",
                    "+- Single-File-Hooks können das nicht",
                    "+- Erfordert externes Tool (phpcpd)",
                    "+- Ist fundamentale Limitation, nicht Versäumnis",
                    "+",
                    "+### Code-Block-Ähnlichkeit",
                    "+",
                    "+**Warum gestrichen:**",
                    "+- Erfordert AST-Analyse oder Token-Vergleich",
                    "+- Regex kann semantische Ähnlichkeit nicht erkennen",
                    "+",
                    "+### String-Längen-Block",
                    "+",
                    "+**Ursprüngliche Idee:** Strings > 100 Zeichen blockieren.",
                    "+",
                    "+**Warum gestrichen:**",
                    "+- Lange Strings können legitim sein (SQL, Templates)",
                    "+- Nicht DRY-spezifisch",
                    "+",
                    "+---",
                    "+",
                    "+## Zusammenfassung",
                    "+",
                    "+### Pre-Hook",
                    "+",
                    "+| ID | Prüfung | Aktion |",
                    "+|----|---------|--------|",
                    "+| - | Keine | - |",
                    "+",
                    "+### Post-Hook",
                    "+",
                    "+| ID | Prüfung | Schwelle | Aktion |",
                    "+|----|---------|----------|--------|",
                    "+| W5.1 | Wiederholte Strings | > 20 chars, > 3x | WARN |",
                    "+| W5.2 | Magic Numbers | nicht in Common, > 2x | WARN |",
                    "+",
                    "+### Allowlist",
                    "+",
                    "+| Pfad | Grund |",
                    "+|------|-------|",
                    "+| \/vendor\/ | Third-party |",
                    "+| \/tests\/ | Test-Fixtures oft identisch |",
                    "+| \/Test\/ | PHPUnit |",
                    "+| \/migrations\/ | SQL-Statements oft ähnlich |",
                    "+",
                    "+---",
                    "+",
                    "+## Externe Tools",
                    "+",
                    "+**Für vollständige DRY-Prüfung wird phpcpd empfohlen:**",
                    "+",
                    "+```bash",
                    "+phpcpd src\/",
                    "+```",
                    "+",
                    "+**Warum nicht im Hook integriert:**",
                    "+- phpcpd ist langsam (Projekt-weite Analyse)",
                    "+- Hooks sollen schnell sein (< 5s Timeout)",
                    "+- CI-Pipeline ist der richtige Ort für phpcpd",
                    "+",
                    "+**Empfehlung:** phpcpd in Quality-Check-Script integrieren, nicht in Hook.",
                    "+",
                    "+---",
                    "+",
                    "+## Selbstkritik und Entscheidungen",
                    "+",
                    "+| Frage | Entscheidung | Begründung |",
                    "+|-------|--------------|------------|",
                    "+| Warum kein Pre-Hook? | DRY nie blockierbar | Duplikation kann bewusst sein |",
                    "+| Ist das zu dünn? | Nein, ehrlich | Mehr wäre False-Positive-Gefahr |",
                    "+| Gehören Magic Numbers zu DRY? | Grenzfall, aber ja | Zahl = dupliziertes Wissen über Bedeutung |",
                    "+| Warum nicht phpcpd integrieren? | Performance | Hooks müssen schnell sein |",
                    "+| Sind 20 Zeichen die richtige Schwelle? | Konservativ | Lieber zu wenig warnen als zu viel |",
                    "+",
                    "+---",
                    "+",
                    "+## DRY vs. Prüfbarkeit",
                    "+",
                    "+| DRY-Aspekt | Prüfbar? | Methode |",
                    "+|------------|----------|---------|",
                    "+| Identische Strings | Ja | Regex |",
                    "+| Magic Numbers | Ja | Regex |",
                    "+| Near-Miss-Code | Nein | Braucht AST |",
                    "+| Semantische Duplikation | Nein | Braucht Verständnis |",
                    "+| Cross-File | Nein | Braucht phpcpd |",
                    "+",
                    "+**Fazit:** DRY-Hooks erkennen nur die offensichtlichsten Symptome. Für echte DRY-Prüfung ist phpcpd erforderlich. Das ist keine Schwäche des Hooks, sondern ehrliche Anerkennung der Grenzen von Regex-basierter Analyse.",
                    "+",
                    "+---",
                    "+",
                    "+# Prüfung 6",
                    "+",
                    "+*Wird nach Abnahme von Prüfung 5 definiert.*"
                ]
            }
        ],
        "userModified": false,
        "replaceAll": false
    }
}
← Vorheriger Zur Liste Nächster →