91 lines
4.3 KiB
Markdown
91 lines
4.3 KiB
Markdown
|
|
# Senior QA Review — Integrity Scanner
|
|||
|
|
|
|||
|
|
## Urteil: **PASS WITH CONCERNS**
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### ✅ Bestanden (8/8)
|
|||
|
|
|
|||
|
|
| Check | Ergebnis | Befehl/Evidenz |
|
|||
|
|
|---|---|---|
|
|||
|
|
| Module-Import | 11/11 ✅ | `python3 -c "import scanner.*"` — alle OK |
|
|||
|
|
| Tests | **266/266 grün** (2.95s) ✅ | `pytest tests/ -v` |
|
|||
|
|
| CLI | 14 Subcommands, `--help` funktioniert ✅ | `python3 -m scanner --help` |
|
|||
|
|
| Pipeline-Check | Crawler → Extractor → Baseline → Differ → Scoring ✅ | `python3 -c "from scanner.differ import compare_snapshots"` |
|
|||
|
|
| Echter Check (`bredelar.info`) | 🟢 Score 0, 46 Seiten geprüft ✅ | `python3 -m scanner --config bredelar.info/config.yaml check` |
|
|||
|
|
| Report-Generierung | JSON + Markdown ✅ | `bredelar.info/reports/20260614_171847/report.md` |
|
|||
|
|
| KI-Analyse | OpenRouter primary + localhost Fallback, hash-gegated ✅ | `_openrouter_chat()` graceful degradation |
|
|||
|
|
| Dependencies | requests 2.32, bs4 4.13, lxml 5.4, PyYAML 6.0, pytest 8.3 ✅ | `requirements.txt` erfüllt |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 🔴 Blocker (0)
|
|||
|
|
|
|||
|
|
Keine.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 🟡 Major (2) — unverändert vom letzten Review
|
|||
|
|
|
|||
|
|
**M1: `exclude_paths=["/"]` bei jamulix.de blockt ALLE Pfade**
|
|||
|
|
*Datei:* `jamulix.de/config.yaml` (Zeile 28-30)
|
|||
|
|
*Befehl:* `python3 -c "from scanner.crawler import should_crawl; print(should_crawl('https://jamulix.de/podcasts/episode-1', 'jamulix.de', [], ('/hackernews/', '/'), ('/podcasts/',)))"` → `False`
|
|||
|
|
*Reproduktion:* `exclude_paths=['/']` + `p.path.startswith('/')` → **jeder Pfad** wird blockiert. Baseline hat nur **1 Seite**.
|
|||
|
|
*Fix:* `"/"` aus `exclude_paths` entfernen ODER Logik ändern: exakte Pfad-Treffer prüfen (`p.path == "/"`), nicht `startswith`.
|
|||
|
|
|
|||
|
|
**M2: Seed-URL umgeht `should_crawl`-Filter**
|
|||
|
|
*Datei:* `scanner/crawler.py` (Zeile 10-16)
|
|||
|
|
*Befehl:* `grep -n "should_crawl" scanner/crawler.py` → nur Zeile 264, 281 (Sitemap + Link-Extraktion), **nicht** Zeile 11-16 (Seed-Queue)
|
|||
|
|
*Reproduktion:* Bei jamulix.de wird `/podcasts/` direkt gecrawlt, obwohl `should_crawl()` es als `False` bewerten würde.
|
|||
|
|
*Fix:* Seed-URLs durch `should_crawl()` filtern.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 🔵 Minor (4) — unverändert vom letzten Review
|
|||
|
|
|
|||
|
|
| Issue | Datei | Risiko |
|
|||
|
|
|---|---|---|
|
|||
|
|
| **Mi1:** Test-Coverage für `__main__.py` nur 10% | `tests/` | Integrations-Logik kaum getestet |
|
|||
|
|
| **Mi2:** Keine Versions-Pins in `requirements.txt` | `requirements.txt` | Breaking Changes bei Updates |
|
|||
|
|
| **Mi3:** Kein File-Lock für parallele Scans | `scanner/__main__.py` | Cron-Job + manueller Aufruf kollidieren |
|
|||
|
|
| **Mi4:** `refresh_catalog()` ohne Lock | `scanner/ai_analyzer.py` | Race Condition bei parallelen Scans |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 📊 Fehlende Tests (Coverage < 40%)
|
|||
|
|
|
|||
|
|
| Modul | Coverage | Fehlend |
|
|||
|
|
|---|---|---|
|
|||
|
|
| `__main__.py` | **10%** | `cmd_scan`, `cmd_check`, `_worst_level`, Report-Pipeline |
|
|||
|
|
| `crawler.py` | **28%** | Live-Crawl, Sitemap-Parsing, Seed-URL-Logik |
|
|||
|
|
| `config.py` | **28%** | `resolve_paths()`, Config-Merge |
|
|||
|
|
| `report.py` | **37%** | Markdown-Rendering, JSON-Export |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### ⚠️ Produktionsrisiken
|
|||
|
|
|
|||
|
|
1. **Jamulix-Crawl:** Nur 1 Seite gecrawlt (M1 + M2). Bei `check` → alle anderen URLs als "fehlend" gemeldet.
|
|||
|
|
2. **Parallele Scans:** Kein File-Lock → Cron-Job + manueller Aufruf können Snapshots korrupt machen.
|
|||
|
|
3. **Dependency-Updates:** Keine Obergrenzen in `requirements.txt` → potentielles Breaking Change bei `requests` v3.x oder `beautifulsoup4` v5.x.
|
|||
|
|
4. **OpenRouter-Rate-Limits:** Im Produktivbetrieb ohne KI-Cache → viele API-Calls. Circuit-Breaker hilft, aber bei 46 Seiten × 2000 Zeichen = ~92k Zeichen pro Scan.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 🔧 Konkrete Fix-Aufträge an den Coder
|
|||
|
|
|
|||
|
|
1. **Fix M1:** `jamulix.de/config.yaml` → `"/"` aus `exclude_paths` entfernen.
|
|||
|
|
2. **Fix M2:** `scanner/crawler.py` Zeile 10-16 → Seed-URLs durch `should_crawl()` filtern.
|
|||
|
|
3. **Add Lock:** `scanner/__main__.py` → File-Lock vor `cmd_scan` (`fcntl.flock` oder `portalocker`).
|
|||
|
|
4. **Add Tests:** `tests/test_main.py` → Integrationstests für `cmd_scan`, `cmd_check`, `_worst_level`.
|
|||
|
|
5. **Pin Versions:** `requirements.txt` → Obergrenzen hinzufügen (z.B. `requests>=2.31,<3.0`).
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### Fazit
|
|||
|
|
|
|||
|
|
Das Projekt **funktioniert** und ist **produktionsreif für bredelar.info** (46 Seiten, alle Checks grün). Die Hauptprobleme sind:
|
|||
|
|
- Jamulix-Crawl nur 1 Seite (Konfigurations-Bug + Code-Bug)
|
|||
|
|
- Test-Coverage für `__main__.py` nur 10%
|
|||
|
|
|
|||
|
|
**Empfehlung:** M1 + M2 fixen → dann **PASS**.
|