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
|
# 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.**
|
> **Etappe 25: Rippy Windows Worker komplett modernisiert.**
|
||||||
> Der Installer und der Worker selbst wurden auf eine Flet-App (mit pystray) migriert,
|
> Der Installer und der Worker selbst wurden auf eine Flet-App (mit pystray) migriert,
|
||||||
|
|||||||
Reference in New Issue
Block a user