## Ergebnis **Keine echte Dokument-/OCR-Regression in den untersuchten Dateien.** Die Fehler entstehen durch **Interpreter-/`PYTHONPATH`-Drift im temporären Testaufbau**. Mit sauber isolierten Zusatzpaketen laufen beide Dateien vollständig: ```text 19 passed in 44.00s ``` Mit dem problematischen temporären Package-Target reproduzierbar: ```text 5 failed, 14 passed ``` ### P0 – Test-Gate reparieren **Ursache:** Temporäres `pip install --target ... pytest reportlab openpyxl` installiert zusätzlich Pillow in das Target. Dieses Target wird per `PYTHONPATH` gesetzt und an externe Prozesse vererbt. Dadurch startet `/usr/bin/ocrmypdf` mit `/usr/bin/python3` (Python 3.12), importiert aber Pillow aus dem für den produktiven Python-3.11-Interpreter installierten Target: ```text ImportError: cannot import name '_imaging' from 'PIL' ``` `ocrmypdf` endet mit RC 1; `extract_pages()` meldet `ocr_failed`. **Sofortfix für Tests:** Zusatzpakete ohne Pillow-Duplikat bereitstellen, insbesondere `--no-deps`, oder ein Package-Target verwenden, das kein `PIL/` enthält. Beispiel: ```bash PY=/home/agent/.hermes/hermes-agent/venv/bin/python3 TARGET=/tmp/health-test-deps rm -rf "$TARGET" "$PY" -m pip install --target "$TARGET" --no-deps \ pytest==8.4.2 reportlab==4.4.3 openpyxl==3.1.5 \ pluggy iniconfig packaging pygments et-xmlfile charset-normalizer PYTHONPATH="$TARGET" "$PY" -m pytest -q \ tests/test_dashboard_v5_sprint6i_a.py \ tests/test_dashboard_v5_sprint6i_c.py \ --tb=short ``` Ergebnis hier: **19 passed**. ### Warum CRP-Kandidaten, Pages und Review-Queue fehlen - `CRP 4.2 mg/l` hat weniger als 20 nutzbare Zeichen. - `extract_pages()` akzeptiert die PDF-Textschicht erst ab `useful >= max(20, pages * 12)` (`document_review.py:289-301`). - Die kurze, eigentlich textbasierte PDF wird deshalb ebenfalls über `ocrmypdf` geleitet. - Schlägt OCR fehl, fängt `apply_document_import()` die Exception pauschal ab und setzt: - `extraction_status='failed'` - `search_status='not_searchable'` - `last_error_code='extraction_failed'` (`health_dashboard_action_worker.py:1673-1677`) - Der transaktionale Block für `document_text_versions`, `document_pages` und `document_candidates` wird komplett zurückgerollt. - Reconciliation ordnet `extraction_status='failed'` korrekt als `technical_blocked` ein, nicht als `now_reviewable` (`document_reconciliation.py:216-225`). Damit sind die Folgefehler in 6I-A/6I-C kausal erklärt; sie sind keine voneinander unabhängigen Contract-Regressions. ### Einordnung des „Bild-OCR“-Tests In `test_scanned_pdf_uses_local_ocr_and_image_is_registered` wird zuerst die Scan-PDF, danach das JPEG importiert. Die Statusabfrage sortiert absteigend: ```python statuses == ["ocr", "failed"] ``` Das bedeutet konkret: - JPEG/Foto: **`ocr`** - zuvor importierte Scan-PDF: **`failed`** Also scheitert hier nicht die direkte JPEG-OCR, sondern der `ocrmypdf`-Pfad der bildbasierten PDF. ## P1 – Produktiven Intake gegen Umgebungseinfluss härten Die externen Aufrufe in `document_review.py` erben derzeit ungefiltert `PYTHONPATH`/`PYTHONHOME`: - `pdfinfo` - `pdftotext` - `ocrmypdf` - `tesseract` Robuster Code-Fix: Für diese Tool-Aufrufe eine explizite Umgebung verwenden, mindestens: ```python env = { **os.environ, "PATH": "/usr/bin:/bin", "LC_ALL": "C.UTF-8", } env.pop("PYTHONPATH", None) env.pop("PYTHONHOME", None) ``` Das sollte zentral für `_pdf_pages()`, `_pdftotext_page()`, `_tool_version()` und die OCR-Aufrufe erfolgen. Damit kann ein Test-/Service-`PYTHONPATH` das System-`ocrmypdf` nicht mehr vergiften. Zusätzlich sollte ein dokumentierter Runtime-Preflight folgende Abhängigkeiten prüfen: ```bash command -v pdfinfo pdftotext ocrmypdf tesseract ffmpeg ffprobe tesseract --list-langs ``` Aktuelle Maschine: - `pdfinfo`, `pdftotext`, `ocrmypdf 15.2.0`, `tesseract 5.3.4`: vorhanden - Tesseract-Sprachen `deu`, `eng`, `osd`: vorhanden - Produktiver Worker-Interpreter besitzt Pillow/pillow-heif. - `/usr/bin/python3` besitzt dagegen kein `pillow_heif`; damit ist dieser Interpreter für den aktuellen Media-Intake ungeeignet. - `deploy/requirements-health-media.txt` deklariert nur Pillow und pillow-heif, nicht die Poppler/OCR/Tesseract-Systemabhängigkeiten. ## P2 – Contracts, Fixture und Diagnose verbessern ### Fixtureinhalt Die synthetische Fixture ist nicht die Ursache: ```text dokumente 0 document_processing 0 document_pages 0 document_candidates 0 document_reconciliation 0 laborwerte 6 ``` Sie enthält synthetische CRP-Werte, jedoch für andere Daten (2024 bis 2026-05-01), nicht für den Intake-Tag `2026-07-18`. Es gibt somit keine vorab vorhandenen Dokumentseiten oder Kandidaten, welche die Tests unterdrücken könnten. ### Aktuelle Intake-Verträge - Importpayload verlangt exakt: `version`, `action`, `quarantine_token`, `sha256`, `metadata`. - Metadaten verlangen exakt sechs Felder: `document_date`, `document_type`, `institution`, `personal_title`, `investigation_day`, `note`. - Für JPEG/PNG wird inzwischen ebenfalls der komplette Media-Runtime-Self-Test ausgeführt, einschließlich `pillow_heif`. - Ein technischer Extraktionsfehler erzeugt vertragsgemäß einen persistierten, technisch blockierten Dokumentdatensatz ohne Pages/Kandidaten. ### Weitere kleine Befunde - Der Worker reduziert jede Extraktionsursache auf `last_error_code='extraction_failed'`; der eigentliche `ocrmypdf`-stderr geht verloren. Ein begrenzter, nicht sensitiver technischer Fehlercode wie `ocr_tool_unavailable`, `ocr_tool_runtime_error` oder `ocr_timeout` würde die Diagnose deutlich verbessern. - `_tool_version("pdftotext")` verwendet `--version`; Poppler erwartet `-v`. Aktuell landet daher als „Version“ sinngemäß: `Couldn't open file '--version'`. Kein Funktionsfehler, aber falsche Provenienz. - Ein fokussierter Test sollte ausdrücklich beweisen, dass externe OCR-Tools trotz eines fremden `PYTHONPATH/PIL` mit bereinigter Umgebung funktionieren. ## Reproduzierbare Minimalchecks ```bash cd /home/agent/.hermes/repos/HealthManager # Runtime /home/agent/.hermes/hermes-agent/venv/bin/python3 -c \ 'import PIL, pillow_heif; print(PIL.__version__, pillow_heif.__version__)' ocrmypdf --version tesseract --list-langs # Nur betroffene Tests PYTHONPATH=/tmp/health-test-deps \ /home/agent/.hermes/hermes-agent/venv/bin/python3 -m pytest -q \ tests/test_dashboard_v5_sprint6i_a.py \ tests/test_dashboard_v5_sprint6i_c.py --tb=short ``` **Dateien:** Keine Repository-Dateien erstellt oder geändert. Temporäre Testtargets unter `/tmp` wurden nach der Analyse entfernt. Im Working Tree existieren parallele/fremde Änderungen; keine davon stammt aus dieser Untersuchung.