docs(savepoint): v3.16 Uebergabe - externes Encoden konnte nie funktionieren
Ampel / ampel (push) Successful in 27s

Diese Sitzung endete wegen vollem Kontext. Der Savepoint ist so geschrieben,
dass die naechste ohne Nachfragen weitermachen kann.

ZUSTAND, den man kennen MUSS: Repo fd1feaa mit gruener Ampel, aber die VM laeuft
noch 61c38a0 - die letzten zwei Commits sind NICHT deployt, und der
Windows-Worker des Commanders laeuft mit altem Code. Der 80-GB-Rohschnitt liegt
intakt auf der NAS, "Neu komprimieren" genuegt also, sobald der Blocker faellt.

DER KERNBEFUND aus dem fehlgeschlagenen Test-Rip, mit Messung statt Vermutung:
Das gezielte Routing funktionierte einwandfrei - sein PC nahm die Aufgabe an und
lehnte sie 182 ms spaeter ab. Drei Ursachen griffen ineinander, zwei sind
behoben, eine bleibt der Blocker (RIPPY_PATH_MAP wird von niemandem gesetzt).

Die offenen Punkte stehen nach Prioritaet, jeweils MIT dem Kontext, der zum
Weiterarbeiten fehlt: Format von pfad_lokal fuer Punkt 1, warum Punkt 2 nicht
ohne die Preset-Liste vom Worker geht (AGENTS Regel D - Namen erfinden hat das
Projekt zweimal teuer bezahlt), welcher Messpunkt sich fuer die ETA bewaehrt hat
(/proc/<pid>/fdinfo statt Fortschrittsanzeige), und welche Datei jeweils dran ist.

Dazu ein eigener Abschnitt "Fallen, die diese Sitzung gekostet haben" - deutsche
Anfuehrungszeichen in doppelt gequoteten Python-Strings (dreimal), Code in
f-String-Einsetzungen, docker exec ohne sh -c verschluckt Globs, /proc-Suche
trifft die eigene Shell, und pydantic-core springt lokal wiederholt zurueck.
Alles auch in den Memory-Notizen, damit es nicht wieder entdeckt werden muss.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Hitonabi
2026-07-26 12:06:32 +02:00
parent fd1feaaee3
commit 4c78914529
+165 -1
View File
@@ -1,6 +1,170 @@
# SAVEPOINT — Rippy
## Aktueller Stand: v3.15Aufräum-Runde: Tempo, tote Routen, 4K-Entscheidung (25.07.2026, 20:00)
## Aktueller Stand: v3.16ÜBERGABE: externes Encoden konnte nie funktionieren (26.07.2026)
> **Zuerst lesen.** Diese Sitzung endete wegen vollem Kontext. Der Auftrag war
> Commander-Feedback aus der ersten Selbst-Einrichtung plus die Diagnose eines
> fehlgeschlagenen Test-Rips. Die Diagnose ist abgeschlossen, zwei Commits sind
> gebaut — **aber NICHT deployt**, und der Kern-Blocker steht noch offen.
### ZUSTAND, gemessen
| | |
|---|---|
| Repo | `fd1feaa`, Ampel **grün** |
| **VM** | **`61c38a0` — die letzten 2 Commits sind NICHT aktiv** |
| Windows-Worker des Commanders | läuft mit **altem** Code (vor der Windows-Erkennung) |
| Job `95afdc89` | `failed` beim Encoden |
| **Rohschnitt** | **79,6 GB intakt** auf `/app/media/rippy/95afdc89-…/title_t00.mkv` (NAS) → „Neu komprimieren" genügt, **kein Neu-Rip** |
| Commander-PC | AMD Ryzen 7 9700X · **avx512f** · 16 Kerne · RX 9070 XT |
| Rippy-VM-CPU | QEMU-Generikum · nur `sse4_2` · 4 Kerne |
### DER KERNBEFUND: drei Ursachen, die ineinandergriffen
Der Commander vermutete „das System sieht den externen Encoder nicht". **Falsch —
das Routing funktionierte einwandfrei.** Gemessen:
```
meta.transcode_node = tobisnicerpc@TobisNicerPC
VM-Worker-Log = nur rip_disc, KEIN transcode_files
22:19:41.271 Kompression eingereiht
22:19:41.453 "Keine Roh-MKVs gefunden" ← 182 ms später
```
Sein PC nahm die Aufgabe an und lehnte sie sofort ab. Warum:
1. **`RIPPY_PATH_MAP` wird von NIEMANDEM gesetzt** — nicht vom Installer, nicht
vom UI, nicht von Compose. `pfad_lokal()` in `tasks.py` hat sogar Tests, aber
keinen Anschluss. `/app/media/...` sind Container-Pfade; ein externer Worker
sieht sie nur übersetzt. **Ein Windows-Worker konnte also nie transcodieren.**
⚠️ **DAS IST DER OFFENE BLOCKER.**
2. **Die Ablage war im UI überhaupt nicht einstellbar.** `outputDir` wurde von
Vollautomatik und Schnellwahl gelesen, hatte aber **kein Eingabefeld**. Das
Arbeitsverzeichnis hatte eine Auswahl eingehängter Ziele, das Ziel nicht.
Folge: Rohdaten auf der NAS (erreichbar), Ziel auf der VM-Platte (nicht
erreichbar — dort läuft **kein Samba**). Die richtige Einstellung war mit den
vorhandenen Bedienelementen **nicht erreichbar.** → behoben, siehe unten.
3. **Die Fehlermeldung log.** „Keine Roh-MKVs gefunden" klang nach kaputtem Rip,
obwohl der Rip vollständig war. → behoben.
### GEBAUT in dieser Sitzung (2 Commits, gepusht, Ampel grün)
**`fe12401`** — Hardware-Encoder + CPU-Merkmale auf Windows, ehrliche Fehler:
- **Hardware-Erkennung war MEIN Bug:** `leite_backends_ab()` verlangte
`/dev/dri` bzw. `nvidia-smi` — beides gibt es unter Windows nicht. Der PC des
Commanders meldete deshalb nur CPU, obwohl HandBrakes Windows-Build `vce_*`
kennt. Die Prüfung war zudem überflüssig: **HandBrake probiert Hardware selbst
an und listet nur Nutzbares** (auf der VM belegt: „qsv: not available", und
`qsv_*` fehlt dann in `--help`). Jetzt ist HandBrakes Liste die einzige
Auskunft, unterschieden nach Familie (`nvenc`/`qsv`/`vce`/`vaapi`) plus eigener
Kennung für Hardware-AV1.
- **Vektorbefehle unter Windows** über `IsProcessorFeaturePresent` (kernel32,
winnt.h) + CPU-Name aus der Registry. Auf dem Commander-PC gegengeprüft:
vorher „AMD64 Family 26 Model 68 / unbekannt", jetzt „AMD Ryzen 7 9700X /
avx512f". Damit verschwindet die AVX2-Warnung für diesen Worker von selbst.
- **`_erreichbarkeit_pruefen()`** unterscheidet jetzt „Pfad nicht erreichbar +
kein Mapping" (nennt `RIPPY_PATH_MAP` mit Beispiel), „Mapping greift nicht"
und „Ordner leer" — und prüft **beide** Pfade, nicht nur die Quelle. Jede
Meldung sagt ausdrücklich, dass die Rohdaten nicht verloren sind.
- Vier Platzhalter mit der Umgebung des Commanders (`192.168.178.20`,
`TOBIS-PC`, seine Jellyfin- und Rippy-IP) verallgemeinert.
**`fd1feaa`** — Ablage einstellbar + Kohärenz-Prüfung:
- Auswahlliste **„Ablage"** in Einstellungen → Ripping, gleiche Liste wie beim
Arbeitsverzeichnis. Wirkt automatisch in Vollautomatik und Schnellwahl, weil
beide `outputDir` lesen — genau wie vom Commander gefordert.
- **Warnung, sobald ein EXTERNER Worker gemeldet ist** und Ablage +
Arbeitsverzeichnis nicht beide auf einer erreichbaren Freigabe liegen. Drei
Fälle mit Konsequenz im Klartext (kann nicht lesen / kann nicht schreiben /
läuft, kostet aber eine Vollkopie).
- „Extern" ist keine Heuristik: `caps.py` meldet `extern` selbst (`/app` gibt es
im Rippy-Image immer, außerhalb nie) und zusätzlich `pfad_map`.
### OFFENE PUNKTE — nach Priorität, mit Kontext
**1. `RIPPY_PATH_MAP` setzen (DER BLOCKER).** Der Installer muss fragen „wie
erreicht dieser PC die Freigabe?" und den Wert in `start-tray.bat` /
`start-worker.bat` schreiben. Format laut `pfad_lokal()`:
`/app/media=\\NAS\rippy;/app/temp=…` (Paare per `;`, Präfix-Ersetzung, wandelt
`/` zu `\`, wenn das Ziel Backslashes enthält). Commander-Vorgabe dazu: *„Wenn
ein externes Ziel für den Speicher eingehängt ist, soll Rippy das ausgewählte als
Arbeitsziel verwenden … das muss auch für den Automatik-Modus so sein."* Punkt 2
oben erfüllt die Einstellungs-Seite davon; es fehlt die Worker-Seite.
Danach: Commander kann seinen 80-GB-Rohschnitt per „Neu komprimieren" auf dem
Ryzen laufen lassen.
**2. Preset-Liste vom Worker holen** — Voraussetzung für „immer das Beste".
Commander: *„Bei den Presets soll IMMER das Beste ausgewählt werden"* und *„wenn
der Worker AV1 oder noch besseres kann, immer diesem empfehlen, die Warnung
verschwindet oder wird von orange zu grün"*. Blocker: Die Namen der
HandBrake-**Hardware**-Presets sind auf der Rippy-VM **nicht ermittelbar** (deren
HandBrake hat keinen Hardware-Encoder), und Erfinden verstößt gegen AGENTS
Regel D — das Projekt hat das zweimal teuer bezahlt. Richtige Lösung: `caps.py`
meldet `HandBrakeCLI --preset-list` des jeweiligen Workers, das UI bietet genau
diese an. Beendet das Raten dauerhaft.
**3. Dashboard + ETA.** Commander: *„Der Server Status muss dringend überarbeitet
werden, das Dashboard soll ja quasi alles auf einen Blick zeigen"* — „Auslastung:
0 % (Aktiv)" ist nichtssagend. Dazu eine **ETA** im Dashboard und beim externen
Worker. Restzeit ist aus dem Fortschrittsverlauf schätzbar; ehrlich bleiben,
solange die Datenlage dünn ist. Verlässlichster Messpunkt (in dieser Sitzung
bewährt): Leseposition im Quellstrom über `/proc/<pid>/fdinfo/`.
**4. Datei-Browser aus dem Rip-Dialog.** Commander: *„Warum wird hier der Datei
Browser noch angezeigt — das ist doch quatsch"*. Prüfen, ob wirklich redundant
(darüber gibt es Schnellwahl + Arbeitsverzeichnis-Auswahl), dann raus oder
einklappen. Datei: `docker/ui/src/components/RipTargetModal.tsx`.
**5. Nicht-Debian-Hosts.** `install.sh` nennt bei fehlendem Compose nur
`sudo apt install docker-compose-plugin`; auf Arch/Fedora/openSUSE falsch.
Paketmanager erkennen. Klarstellen: der Worker-**Container** ist unabhängig vom
Host-System.
**6. Warnung im Rip-Dialog** (nicht nur in den Einstellungen), wenn der gewählte
externe Encoder die Pfade nicht erreicht — vor dem Start, nicht nach einer Stunde.
Bausteine liegen: `caps.py` meldet `extern` und `pfad_map`.
**7. Jikan-Reihenfolge prüfen** (Nebenbefund). Kette ist TMDB → **Jikan** → OMDb
mit Gate `MINDEST_AEHNLICHKEIT = 0.55`. Jikan wird also wirklich benutzt (Antwort
auf die Commander-Frage), läuft aber **vor** OMDb: bei einem Nicht-Anime, den
TMDB verpasst, antwortet zuerst eine Anime-Datenbank. 0,55 ist großzügig.
**8. Aus dem ARM-Vergleich, nicht gebaut:** ISO-Sicherung für Datenträger, die
weder Film noch Audio-CD sind (daran scheitert Rippy heute), und **mehrere
Laufwerke gleichzeitig** — Rippy sieht sie (`/dev/sr[0-9]*`), ob parallel gerippt
wird, ist **unbewiesen**.
**9. Ältere offene Punkte, unverändert gültig:**
- „Job aus der Liste entfernen" sagt nicht, wie viel daneben liegen bleibt — der
Rohschnitt verwaist unsichtbar (v3.14).
- Discord-Webhook und MakeMKV-Key liegen im Klartext in der settings-Tabelle.
- **VM-CPU-Typ steht auf `qemu64`** → `host` würde AVX2 freischalten, 24×
schneller. Anleitung steht in der README („Rippy schneller machen").
- **`install.sh` ist nie als root durchgelaufen** — Verzeichnisse anlegen,
`mount --make-rshared` und die systemd-Unit sind ungetestet.
- Zwei API-Tests laufen nur in der Ampel (`test_api_smoke.py` überspringt sich
unter Windows selbst).
### FALLEN, die diese Sitzung gekostet haben
- **Deutsche Anführungszeichen in DOPPELT gequoteten Python-Strings** beenden den
String vorzeitig. Dreimal hineingetappt. Der Bestand nutzt dafür **einfach**
gequotete f-Strings (`f'…„{x}"…'`). In dreifach gequoteten Docstrings ist es
unproblematisch.
- **In f-Strings steht in `{...}` CODE, kein Text.** Ein Umlaut-Konverter machte
aus `f"{groesse}"` ein `f"{größe}"`, während die Variable `groesse` hieß —
Ruff fand es als F821.
- **`docker exec` ohne `sh -c` expandiert kein `*`** — ein `du -sh /pfad/*`
liefert dann still nichts und sieht wie „leer" aus.
- **Eine `/proc`-Suche nach „HandBrake" trifft die eigene Shell mit**, weil deren
Kommandozeile das Wort enthält. Zwei Fehlalarme.
- **`pydantic-core` springt lokal wiederholt auf 2.47.0** und bricht damit das
Einsammeln ALLER API-Tests (`SystemError`). Fix:
`python -m pip install "pydantic-core==2.46.4"`. Zweimal nötig gewesen.
---
## Vorheriger Stand: v3.15 — Aufräum-Runde: Tempo, tote Routen, 4K-Entscheidung (25.07.2026, 20:00)
> **Deployt und live gegengeprüft.** Auftrag war „bau alles so um, dass es
> sauber ist" mit fünf Vorgaben: saubere Codebase, selbsterklärendes UI,