Files
rippy/AGENTS.md
T
Hitonabi 2587fe63af
Ampel / ampel (push) Successful in 27s
docs(savepoint): v3.17 - neun Punkte zu, vier Bestandsfehler dazu
Der Savepoint trennt wie immer gemessen von vermutet - und stellt zwei
Behauptungen aus v3.16 richtig, die sich als falsch erwiesen haben:

1. "Die Namen der Hardware-Presets sind auf der Rippy-VM nicht ermittelbar."
   Falsch - `--preset-list` nennt sie vollstaendig, auch ohne Hardware-Encoder.
   Der vermeintliche Blocker fuer Punkt 1 existierte nicht.
2. "Rohschnitt intakt -> 'Neu komprimieren' genuegt." Falsch - can_retry war
   false, den Knopf gab es nicht.

AGENTS.md bekommt zwei neue Lehren aus dieser Sitzung: Hintergrund-Schleifen
muessen ihre Fehler melden (ein stiller except hat eine Stunde gekostet), und
Netz-Pfade nie ungebremst anfassen - os.path.isdir haengt auf einem toten CIFS
im Kernel und laesst sich aus Python nicht abbrechen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-26 13:55:41 +02:00

5.9 KiB

AGENTS.md — Arbeits-Konventionen für Rippy

Grundregeln

1. Plan vor Code. Vor jeder Etappe: Klare Akzeptanzkriterien schreiben, dann bauen. 2. Kleine Schritte. Max. eine Feature pro Commit. Commit-Nachrichten beschreiben WAS und WARUM. 3. Beweisen statt behaupten. Testen, was gebaut wurde. Keine "es sollte funktionieren"-Commits. 4. Deutsch-Nicht-Entwickler. Der Commander liest alles — Variablennamen auf Englisch, aber Kommentare und Docs auf Deutsch.

HARTE Regeln (mechanisch geprüft — seit 22.07.2026)

A. Die CI-Ampel muss GRÜN sein, bevor irgendetwas „fertig" heißt. .gitea/workflows/ci.yml läuft bei jedem Push auf dem Gitea-Runner (NICHT löschen, NICHT abschwächen). Keine Tests = rot = nicht fertig. Der Commander liest die Ampel, nicht den Code.

B. Abweichung vom KONZEPT = STOPP + fragen. Anderes Werkzeug, andere Bibliothek, gestrichenes Muss-Feature → erst den Commander fragen, NIE still ersetzen. (Vorgefallen: Muss-Feature „MakeMKV lossless" wurde still durch lossy HandBrake ersetzt.)

C. Single Source of Truth ist main — es gibt nur diesen einen Branch (seit 24.07.2026; der stable-Zwischenbranch ist abgeschafft). Die CI-Ampel läuft bei jedem Push und PRÜFT nur (Ruff/pytest/Vite-Build) — sie befördert nichts mehr. Deployt wird direkt aus main: auf der VM git pull bzw. ./deploy.sh (verifiziere vorher, dass die Ampel für den Commit GRÜN ist — rot heißt: nicht deployen). Nie freihändig per SSH auf der VM bauen. (Vorgefallen: Doppel-Anlage Rippy + rippy auf der VM durch Freihand-Deploys.)

D. Externe Schnittstellen NIE aus dem Kopf. Vor Nutzung fremder CLI-Flags oder Bibliotheks-APIs: --help/Doku prüfen und die Fundstelle im Commit nennen. (Vorgefallen: erfundene Celery-Methode self.send_task, erfundene abcde-Flags.)

Workflow

  1. Read: KONZEPT.md + ROADMAP.md lesen. Verstehen, welche Etappe dran ist.
  2. Plan: Was genau soll diese Sitzung bauen? Eine Zeile.
  3. Build: Code schreiben, testen, committen.
  4. Verify: docker compose up — funktioniert das Ganze?
  5. Savepoint: SAVEPOINT.md aktualisieren. Nächster Chat beginnt nicht von Null.

Modelle je Aufgabe

  • Planung: Heavy-Modell (Reasoning) für Architektur-Entscheidungen.
  • Bauen: schnelles Coding-Modell.
  • Review: Heavy nochmal für Code-Review vor Merge.

Docker-Praxis

  • Alles läuft in Containern: docker compose up -d
  • Keine System-Pakete auf dem Host — alles im Container.
  • Dockerfile immer multi-stage, kleinste Images.

Was NICHT gebaut wird

  • Kein Code direkt im Host-OS.
  • Kein Proxmox-LXC-Nesting-Workaround — das Projekt lebt bewusst in normalem Docker.
  • Kein ARM-Fork — Rippy ist ein Eigenbau von Grund auf.

Aktueller Stand (26.07.2026)

  • E2E bewiesen (v3.1): BD-50 komplett durch die Kette (43 GB → 4,8 GB)
  • Etappe 13 (v3.2): Universal-Komfort-Runde — Media-Server-Integration, echte Benachrichtigungen, SMB-Klartext-Fehler, UHD-Arbeitsverzeichnis, MakeMKV-Key via UI, Job-Detail-Popup, Toast-Feedback, Ampel-Blocker behoben
  • Etappe 17 (v3.10): 4K-UHD-Disc-Schlüssel — persistentes MakeMKV-Datenverzeichnis + KEYDB.cfg im UI
  • Etappe 18 (v3.11): 4K-UHD gelöst — makemkvcon holt Schlüssel unter Linux nie, unter Windows schon; Schlüsselspeicher übernehmbar. Akira-UHD geht auf der VM auf (TCOUNT:5, bewiesen)
  • Etappe 19 (v3.14): Durchsicht Frontend/Backend — vier Placebos weg (Fortschritt log, Auswurf tat nichts, „Alle Tracks" konnte nichts, Encoder wurden behauptet statt gemessen), Zombie-Erkennung gebaut, Pfad-Prüfung gehärtet, und der Platten-Schutz aus c065967 als unwirksam entlarvt
  • Etappe 20 (v3.15): Aufräum-Runde — /capabilities 1,010 s → 0,003 s (Ping im Hintergrund), Kompression je Disc-Typ abwählbar (4K verlustfrei), Wizard empfiehlt nach gemessener CPU, vier tote Routen entfernt
  • Etappe 21 (v3.17): Der Blocker externes Encoden ist zu — RIPPY_PATH_MAP leitet Rippy aus seinen eigenen Mounts ab, der Installer holt es selbst; Presets kommen vom Worker statt aus dem Quelltext; Dashboard ohne Placebos, mit Restzeit. Dazu vier Bestandsfehler, alle live gemessen (u. a. „Neu komprimieren" ging nie, und os.path.isdir hing im Kernel)
  • 📝 Details immer in SAVEPOINT.md — diese Sektion nennt nur die Etappe

Was diese Sitzungen wiederholt gekostet hat

Nicht aus einem Zustandswert auf einen Mechanismus schließen. Vorgefallen: aus „kein Schlüssel da" → „Server abgeschaltet" (falsch), aus Status transcoding → „Celery hat neu zugestellt" (falsch), aus progress=99 → „Altwert aus dem Absturz" (falsch — ein Bug), aus gleichem st_dev → „os.rename funktioniert" (falsch — der Kernel vergleicht den Mount). Jedes Mal hätte eine Messung von unter einer Minute gereicht.

Und die Umkehrung gilt genauso: gleiches st_dev heißt NICHT gleicher Mount. Wo eine Eigenschaft ausprobierbar ist, probiere sie aus, statt sie vorherzusagen.

Ein Hintergrund-Prozess, der still scheitert, ist schlimmer als einer, der laut scheitert (26.07.2026). Ein except Exception: pass in einer Vorrats-Schleife hat eine Stunde gekostet: Der Vorrat blieb leer, die Funktion lief direkt aufgerufen einwandfrei, und der Grund stand nirgends. Gefunden erst über die Thread-Zustände (/proc/<pid>/task/*/stat, Zustand D = im Kernel blockiert). Jede Hintergrund-Schleife MELDET ihren Fehler, und wer einen Vorrat anlegt, macht sein Alter abfragbar (GET /health/vorraete) — sonst ist am Endpunkt selbst nichts zu sehen.

Netz-Pfade nie ungebremst anfassen. os.path.isdir/open auf einem toten CIFS-Mount blockieren im Kernel und lassen sich aus Python NICHT abbrechen. Ein Kind-Prozess lässt sich abbrechen: timeout N ls -d <pfad> (Muster in mounts.ist_erreichbar und rohdaten.verzeichnis_da). Und „konnte nicht nachsehen" ist etwas anderes als „ist nicht da" — beides zu vermischen erzeugt falsche Aussagen im UI.