docs: SAVEPOINT fuer v4.0-alpha — v2-Konzept entschieden, Etappe V2-0 gruen
Ampel / ampel (push) Successful in 39s
Ampel / ampel (push) Successful in 39s
WAS: Neuer Kopfeintrag mit dem gemessenen Zustand (b98dc5e, Ampel gruen,
290 Tests, 0 doppelte Module), den drei Commander-Entscheiden, der
gebauten Etappe V2-0 und dem naechsten Schritt.
WARUM: AGENTS-Workflow Punkt 5 — die naechste Sitzung faengt nicht bei
Null an. Besonders wichtig diesmal, weil der Deploy auf die VM bewusst
aussteht und beim ersten Deploy nach V2-0 zwei Dinge gezielt zu pruefen
sind (liegt /app/rippy in beiden Containern, enthaelt das Worker-Zip
den Ordner).
Dokumentiert ist ausserdem der Fehler, den der Umbau fast ausgeliefert
haette: ein "try/except ImportError" um den detection-Import in
tasks.py haette einen falschen Modulpfad STILL geschluckt und auf Linux
jeden Rip verweigert. Die Lehre steht dabei — bei einem Modul-Umzug
reicht grep auf Zeilenanfaenge nicht.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
b98dc5eef5
commit
edfe0d4313
+144
-1
@@ -1,6 +1,149 @@
|
||||
# SAVEPOINT — Rippy
|
||||
|
||||
## Aktueller Stand: v3.21 — Rippy Windows Worker (27.07.2026)
|
||||
## Aktueller Stand: v4.0-alpha — Rippy v2 beginnt, Etappe V2-0 steht (28.08.2026)
|
||||
|
||||
> **Zwei Dinge sind passiert: Das Konzept für Rippy v2 liegt vor und ist vom
|
||||
> Commander entschieden — und die erste Etappe ist gebaut, geprüft und grün.**
|
||||
|
||||
### ZUSTAND, gemessen
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| Repo | `b98dc5e` auf `main`, Ampel **GRÜN** (Gitea-Lauf b98dc5ee: success) |
|
||||
| VM | **NICHT deployt** — bewusst, siehe „Was als Nächstes ansteht" |
|
||||
| Tests lokal | **290 grün**, 1 übersprungen (ohne die zwei Linux-only-Module) |
|
||||
| Doppelte Module im Repo | **0** — vorher 3 (`detection`, `makemkv_daten`, `notify`) |
|
||||
| Zeilen netto | **−492** (234 hinzu, 726 weg) |
|
||||
|
||||
### 1. Das v2-Konzept: drei Betriebsmodi statt einem
|
||||
|
||||
Der Commander wollte Rippy in drei Ausprägungen: Docker (wie heute), eine
|
||||
native Windows-App **ohne Docker**, und eine Headless-Linux-Anwendung — alle
|
||||
drei mit demselben Webinterface.
|
||||
|
||||
**Vollständige Spezifikation: `KONZEPT-V2.md`** (Systemarchitektur,
|
||||
Daten-/Queue-Strategie, die drei Plattformen im Detail, API-/Event-Design,
|
||||
Migrationsplan). Etappen V2-0 bis V2-7 stehen in `ROADMAP.md`.
|
||||
|
||||
**Der tragende Gedanke:** Rippy v2 ist EINE Anwendung mit DREI Verdrahtungen,
|
||||
keine drei Produkte. Ein Betriebsmodus ist nur die Auswahl der Treiber hinter
|
||||
vier Ports — Store, Queue, Bus, Drives. Standalone heißt SQLite + lokale
|
||||
Queue + asyncio-Bus, verteilt heißt Postgres + Celery/Redis. Derselbe
|
||||
Rip-Code, dieselben Tests, dasselbe UI.
|
||||
|
||||
Zwei Entwurfs-Entscheidungen, die von der naheliegenden Option abweichen:
|
||||
|
||||
- **Keine Queue-Bibliothek** (nicht Taskiq, nicht ARQ). Stattdessen der
|
||||
Grundsatz *„die Datenbank ist die Wahrheit, der Broker ist nur der Wecker"*
|
||||
plus zwei sehr kleine Treiber. Nebenwirkung: `zombies.py` (206 Z + 263 Z
|
||||
Tests) wird durch eine Lease ersetzt, statt portiert zu werden.
|
||||
- **Mounten wandert auf den Host.** Die CIFS-Ausfälle waren kein Bug, sondern
|
||||
die Folge davon, dass der Container mountet (Befund 26.07.2026). Damit
|
||||
fallen `SYS_ADMIN`, `DAC_READ_SEARCH`, `apparmor:unconfined`, `rshared` und
|
||||
die Mount-Wache weg. Die PRÜF-Logik aus `mounts.py` bleibt vollständig.
|
||||
|
||||
### 2. Drei Entscheide des Commanders (28.08.2026)
|
||||
|
||||
Alle drei stehen jetzt in `KONZEPT.md` § 10 — **wer nur eine Datei liest,
|
||||
findet sie dort, nicht nur in KONZEPT-V2.md.**
|
||||
|
||||
1. **Reihenfolge:** Echtzeit (SSE statt Polling) VOR der Windows-App.
|
||||
2. **Disc-Schlüssel: automatischer Abruf MIT Rückfallebene.** Das verschiebt
|
||||
die Grenze vom 25.07.2026 (*„Rippy verteilt KEINE Disc-Schlüssel"*)
|
||||
**bewusst**. Umgesetzt als Kette in drei Stufen: eigener Bestand →
|
||||
automatischer Abruf → Import von Hand. Fünf Regeln gehören dazu, allen
|
||||
voran: **die Bezugsadresse steht in der Konfiguration und ist LEER
|
||||
vorbelegt** (eine vorbelegte tote Adresse wäre genau die Falle aus
|
||||
`.env.example`), ein Fehlschlag ist LAUT, ein funktionierender Bestand
|
||||
wird nie still überschrieben, und Rippy bringt selbst nichts mit.
|
||||
3. **Speicherziele:** Der Host mountet, Rippy erzeugt die kopierbare Zeile
|
||||
(fstab / `.mount`-Unit / `compose.yml`). Die Eingabemaske im UI bleibt,
|
||||
nur der Knopf „Verbinden" wird zu „Zeile kopieren".
|
||||
|
||||
### 3. Etappe V2-0 gebaut: ein Paket statt drei Zwillingen
|
||||
|
||||
`detection.py`, `makemkv_daten.py` und `notify.py` lagen je ZWEIMAL im Repo,
|
||||
byte-identisch, weil es kein geteiltes Paket gab. Jetzt gibt es `src/rippy/`
|
||||
(`core` / `drives` / `rip`); beide Container importieren dieselbe Datei.
|
||||
|
||||
- `conftest.py` in der Wurzel legt `src/` auf den `sys.path` (die Ampel ruft
|
||||
pytest dort auf).
|
||||
- Beide Dockerfiles kopieren `src/rippy` nach `/app/rippy` — `/app` ist
|
||||
Arbeitsverzeichnis und uvicorn-App-Dir, also ohne `PYTHONPATH` findbar.
|
||||
Die Anordnung wurde nachgestellt und der Import geprüft, nicht vermutet.
|
||||
- **`worker_setup_paket` packt das Paket ausdrücklich mit ins Zip.** Die
|
||||
Schleife dort sah nur die oberste Ebene — ein Unterordner wäre nie
|
||||
mitgekommen, und der Windows-Worker beim Start gestorben.
|
||||
- Die zwei Test-Dateien für `makemkv_daten` sind zu einer verschmolzen.
|
||||
Damit entfällt auch der `importlib`-Umweg im Worker-Test (er war nötig,
|
||||
weil bei `pytest -q` aus der Wurzel `docker/api` zuerst eingesammelt wird
|
||||
und jeder weitere Import nur noch den `sys.modules`-Cache trifft — die
|
||||
Worker-Kopie wurde also nie angefasst). Netto −13 doppelte Tests.
|
||||
- `test_zwillinge_sind_byteweise_identisch` ist weg. Der Wächter war nötig,
|
||||
weil die Konstruktion falsch war; jetzt ist sie es nicht mehr.
|
||||
|
||||
### 4. DER FEHLER, DEN DIESER UMBAU FAST AUSGELIEFERT HÄTTE
|
||||
|
||||
In `tasks.py` steht der `detection`-Import in einem `try/except ImportError` —
|
||||
**absichtlich**, denn der native Windows-Worker hat kein `fcntl` und soll
|
||||
trotzdem starten (er komprimiert nur).
|
||||
|
||||
Das `except` verschluckt aber **jeden** ImportError, auch einen falschen
|
||||
Modulpfad. Auf Linux hätte der Worker ab sofort still `detect_disc_type=None`
|
||||
gesetzt und **jeden Rip verweigert, ohne dass irgendwo ein Fehler gestanden
|
||||
hätte** — die Klasse „still scheiternder Hintergrund-Prozess" aus `AGENTS.md`,
|
||||
diesmal selbst gebaut.
|
||||
|
||||
**Warum er fast durchkam:** Die erste Suche nach Import-Stellen prüfte nur
|
||||
Zeilenanfänge (`^from detection import`). Dieser Import ist eingerückt.
|
||||
Gefunden hat ihn erst eine zweite Suche ohne Zeilenanker.
|
||||
|
||||
**Lehre fürs nächste Mal:** Bei einem Modul-Umzug reicht `grep '^import x'`
|
||||
nicht — Importe stehen auch in `try`-Blöcken, in Funktionen und in
|
||||
`if TYPE_CHECKING`. Und ein `except ImportError` um einen Umzug herum ist die
|
||||
gefährlichste Stelle im ganzen Vorgang, weil sie den Fehler frisst.
|
||||
|
||||
**Wächter dagegen:** `src/rippy/test_paket.py` prüft mit
|
||||
`importlib.util.find_spec`, dass es die drei Modulpfade wirklich gibt.
|
||||
`find_spec` **führt nichts aus** — der Test läuft deshalb auch auf Windows
|
||||
ohne `fcntl` und ist nicht nur in der Ampel wirksam. Gegengeprüft: Modul
|
||||
weggenommen → Test rot, zurückgelegt → grün. Ein Wächter, den man nicht hat
|
||||
scheitern sehen, ist Deko.
|
||||
|
||||
### WAS ALS NÄCHSTES ANSTEHT
|
||||
|
||||
- [ ] **Deploy auf die VM steht aus — bewusst.** Ein Deploy startet die
|
||||
Container neu, und der `api`-Container HÄLT die NAS-Verbindung: mitten
|
||||
in einem Rip wäre das ein Datenverlust. Erst prüfen, ob etwas läuft
|
||||
(`docker compose -p rippy ps`, Job-Liste im UI), dann
|
||||
`git pull --ff-only && docker compose up -d --build`.
|
||||
**Beim ersten Deploy nach V2-0 gezielt nachsehen:** Liegt `/app/rippy`
|
||||
in BEIDEN Containern? (`docker exec <c> ls /app/rippy`) Und enthält das
|
||||
Worker-Zip den Ordner? (`GET /worker-setup/paket` herunterladen,
|
||||
hineinschauen — der Windows-Worker startet sonst nicht.)
|
||||
- [ ] **Etappe V2-1: Ports einziehen** — `Store`/`Queue`/`Bus`/`Drives` als
|
||||
Protocol, v1-Verhalten läuft weiter über Postgres/Celery/Redis/Linux.
|
||||
Wieder ohne Verhaltensänderung. Danach ist jeder weitere Betriebsmodus
|
||||
eine Treiber-Datei statt eines Umbaus.
|
||||
- [ ] Die zweite echte Doppelung anfassen: `api/db.py` und `worker/db.py`
|
||||
(überlappend, nicht identisch) sowie `devices.eject` gegen
|
||||
`ripping.wirf_disc_aus` — beides gehört in V2-1 (Store bzw. DAL).
|
||||
|
||||
### HINWEIS FÜR DIE NÄCHSTE SITZUNG (lokale Umgebung)
|
||||
|
||||
Die pydantic-Falle hat erneut zugeschlagen: global lag `pydantic 2.13.4` mit
|
||||
`pydantic-core 2.48.0` (unverträglich, 2.13.4 verlangt 2.46.4), und das
|
||||
Einsammeln ALLER API-Tests brach mit `SystemError`. Repariert mit
|
||||
`python -m pip install "pydantic-core==2.46.4"`. Die Ampel merkt das nie, weil
|
||||
sie in ein frisches venv aus `requirements.txt` installiert. Wenn lokal
|
||||
plötzlich alle API-Tests wegbrechen: erst die Versionspaarung prüfen.
|
||||
|
||||
Und der Ignore-Pfad hat sich geändert — Linux-only-Module beim lokalen
|
||||
pytest-Lauf:
|
||||
`--ignore=src/rippy/drives/test_detection.py --ignore=docker/api/test_prescan_helpers.py`
|
||||
(vorher `docker/worker/test_detection.py`).
|
||||
|
||||
## Letzter Stand davor: v3.21 — Rippy Windows Worker (27.07.2026)
|
||||
|
||||
> **Etappe 25: Rippy Windows Worker komplett modernisiert.**
|
||||
> Der Installer und der Worker selbst wurden auf eine Flet-App (mit pystray) migriert,
|
||||
|
||||
Reference in New Issue
Block a user