real-debrid-downloader/tasks/todo.md
Sucukdeluxe 18f29a6a2c docs(tasks): Hybrid-Race .DL.-Doppeltonspur-Fix dokumentiert (v1.7.196) + Webhook-0/5-Diagnose
Markiert das offene Audit-Item "Hybrid race: 1 Datei/Staffel beim MKV-Move nicht
umbenannt" als erledigt und haelt Ursache, Fix, Verifikation und die offene
Altfile-Remediation fest. Zusaetzlich die Webhook-"0 von 5"-Diagnose (kein
Code-Bug: Notify-Toggles unchecked + ungespeichert).
2026-06-10 16:06:53 +02:00

274 lines
21 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Real-Debrid-Downloader — Tasks (Stand 2026-06-10)
**Status:** Webhook-Audit ABGESCHLOSSEN + released (v1.7.195). Davor: Bug-Audit (v1.7.189/190),
Sichtbarkeits-Paket (v1.7.191-194). Verbleibende QoL-Kandidaten weiter unten.
---
## ✅ Webhook-Bug-Audit — RELEASED v1.7.195 (2026-06-10, Gitea + GitHub-Mirror 37430ba)
User-Goal: "intensiv prüfen obs Bugs gibt wodurch Webhooks nicht getriggert werden + drumrum".
Workflow: 6 Finder → 29 adversarial bestätigte Findings (0 widerlegt, 65 Non-Findings),
dedupliziert auf 16 Themen in 6 Fix-Commits. Volle Gate: tsc=6, 801 Tests (+9), self-check, build.
### Gefixt (Commits f060d02, 99a2459, 8acb22d, 3fb9e85, 5f8b02e, 86d935e + Test-Commit)
1. **notify.ts Zustellung** (N5/RATELIMIT HIGH): Send-Queue seriell + 450ms-Gap (Discord
5/2s-Bucket), 429 mit retry_after (Sek→ms), 5xx/Netz-Backoff-Retries, Body-Konsum,
surrogat-sichere 2000er-Kappung, Invalid-URL-Warnung. 17 notify-Tests.
2. **Terminal-Abdeckung** (N1/DEDUP-2 HIGH, N2 HIGH, N4): refreshPackageStatus benachrichtigt
JEDEN Failed-Übergang (success===0-Gate weg — Mixed-Paket mit letztem Fail = häufigste
Reihenfolge verlor den ❌) + History für Mixed; 3 Early-Return-Fehlerpfade (416/toter
Link/Debrid-Link) riefen refreshPackageStatus nie → Paket hing bis Neustart auf
downloading; skipItems finalisiert jetzt jedes terminal gewordene Paket.
3. **Dedup-Lifecycle** (DEDUP-1 HIGH, -3, -4): recoverRetryableItems + retryExtraction/extractNow
geben den Notify-Marker frei (Recovery-✅ kam sonst NIE); retryExtraction tritt Run unbedingt
bei; addTrailingPostProcessPackageIds erhält Run-Mitgliedschaft laufender Entpackungen an
allen 5 runPackageIds-Ersetz/Clear-Stellen; Marker-Freigabe bei endgültig gescheitertem Send.
4. **Run-Lifecycle** (RUN-1..4): stop() schickt "Durchlauf gestoppt"-Summary; Scheduler-Respawn
in finally heilt Stop→Start-Race (führerloser Run!); finishRun sagt "Downloads beendet +
Entpacken läuft noch" statt zu lügen; armScheduledStart beim Boot re-armt (geplanter Start
überlebte keinen Neustart; vergangene Zeit → log+clear statt Blind-Start).
5. **Settings/Security** (SET-2, SET-4): notifyUrl in importBackup-SENSITIVE_KEYS;
Support-Bundle notifications-Block (konfiguriert/plausibel/Toggles, ohne URL-Leak).
6. **Renderer** (R1, R2): Testen-Toast mahnt Speichern bei dirty Settings; Button disabled
während Quick-Action läuft (statt Klick still zu schlucken).
### Bewusst NICHT gefixt (verifiziert, Begründung)
- **SET-3** (rememberToken=false wipt notifyUrl nicht): Webhook als Credential zu wipen würde
Benachrichtigungen für rememberToken=false-Setups brechen; Konsistenz-Trade-off akzeptiert.
- **R3** (URL als Klartext-Feld statt password): Sichtbarkeit hilft beim Prüfen/Debuggen,
Einzel-Operator-Setup.
- **R4** (Boot-Window Draft-Race): generisches, vorbestehendes Settings-Hydration-Muster,
nicht notify-spezifisch.
- **DEDUP-5** (immediate-Cleanup schrumpft Zähler in der ✅-Meldung): kosmetisch, Policy-Kombi
beim User nicht aktiv. **RUN-5** (Quit mid-run still): nach Prozesstod nicht zustellbar.
**RUN-6** (Dauer-Fallback 1s): kosmetisch. **N6**: durch Marker-Freigabe + URL-Warnung subsumiert.
---
## ✅ QoL Sichtbarkeits-Paket — RELEASED v1.7.191 (2026-06-09, Gitea + GitHub-Mirror)
1. **Push-Benachrichtigungen** (e753ea1, v1.7.192 auf Discord-Webhook-JSON umgebaut —
{username, content}, Emoji-Titel, 2000-Zeichen-Cap): Settings notifyUrl + 3 Toggles; 3 Hooks
(Post-Process-Ende, refreshPackageStatus all-failed-Lücke, finishRun-Summary); Dedup-Set
Lifecycle wie historyRecordedPackages; Guard running||runPackageIds (Recovery pusht nicht).
2. **audioStripSummary am Paket** (2a1a554): PackageEntry-Feld + Status-Spalten-Badge
("Tonspur: 5 OK · 1 ohne DE-Tag", Tooltip mit Datei-Details); storage-Whitelist + Delta-Hash.
3. **"Letzte Fehler anzeigen"** (be4d54a): Hilfe-Menü → Error-Ring-Snapshot im Dialog,
Bestätigen-Knopf = in Zwischenablage kopieren.
787 Tests, tsc=6, self-check+build grün; latest.yml-path verifiziert; Mirror f61fbc4 clean.
## 🟡 QoL-Backlog — code-verifiziert mit Hook-Punkten (aus Ideation 2026-06-09)
Volle Details (exakte Zeilennummern, Verifier-Gotchas) im Ideation-Workflow-Output; Kurzform:
1. **Mega-Web Per-Account-Timeout** (M, Score 9) — 20s eigenes Timeout pro Account via
AbortSignal.any + Signal-IDENTITÄT (nie Error-Text!) im Rotations-catch VOR Z.~1979;
äußeres 60s-Budget bleibt. GOTCHA: tests/debrid.test.ts:1376 asserted Signal-Objekt-Identität
→ Test lockern. Nur mode==='web'.
2. **ffmpeg-Pfad als Setting + Testen-Button** (M, Score 9) — ffmpegPath/ffprobePath, Setter +
resetVideoToolingCache(); GOTCHA: auch im KONSTRUKTOR setzen (setSettings reicht nicht nach
Neustart); IPC CHECK_VIDEO_TOOLING; UI unter keepGermanAudioOnly-Toggle.
3. **Bibliothek-Batch Tonspur für Bestand** (M, Score 9) — Button neben Toggle; Kandidaten-Filter
aus keepGermanAudioOnlyImpl als shared Predicate extrahieren (Overlap-Guard NICHT schwächen);
sequenziell + Single-In-Flight + AbortController + mtime-Age-Gate.
4. **Auto-Reset gefailter Items bei Tageswechsel** (SM, Score 8) — Toggle, Default aus;
GOTCHA: NICHT synchron aus ensureProviderDailyUsageFresh (Re-Entranz: läuft in getSnapshot/
Scheduler) → über 60s-runtimeStatsTimer (app-controller ~164); resetItems löscht Teil-Downloads.
5. **POST /control am Debug-Server** (M, Score 8) — add-links/start/stop/pause; GOTCHA: über
AppController routen (Audit-Log), nicht manager direkt; Start-Konflikt-Guard beachten.
6. **Mobile Statusseite GET /ui + Remote-Toggle** (M, Score 8) — handgeschriebenes flaches HTML,
pollt /status+/errors; Toggle schreibt debug_host.txt um; GOTCHA: stop+start Race (EADDRINUSE
→ Server tot bis Neustart) → closeAllConnections/restartDebugServer.
7. **Mega-Cooldown-Status + aufheben** (S, Score 7) — listMegaDebridAccountCooldowns() export,
Snapshot-Feld, Badge + Button; GOTCHA: Keys sind `${id}:api|web` getrennt; lazy expiry.
8. **Status-Filter-Chips Downloads-Tab** (S, Score 7) — GOTCHAS: PackageCard-memo-Comparator
braucht neue Prop; Prädikat an 2 Stellen (6615 + visibleOrderIds 3546); VOR Rendering-Limit.
9. **Support-Bundle: Explorer zeigen + Desktop-Schnellweg** (S, Score 7) — filePath wird schon
returned, Toast ignoriert ihn nur; shell.showItemInFolder; preload-api.ts nicht vergessen.
Long-Tail: Low-Disk-Auto-Pause (S), Autostart/Tray (S).
---
## ✅ ERLEDIGT — Bug-Audit 2026-06-08 (Multi-Agent find→verify, 18 bestätigt)
Advisor-Triage: **A = einzige echte Daten-Verlust-Notlage** (zerstört echte Datei auf Platte)
→ zuerst, ALLEINE Release. **B verifiziert demoted:** applyRetroactiveCleanupPolicy/
removePackageFromSession löschen KEINE Platten-Dateien (nur Session/Queue-Einträge + ggf.
History-Eintrag) → Queue-Integrität, nicht Daten-Verlust → in v1.7.190-Batch.
Sequenz: Release 1 (v1.7.189) = **A allein**; Release 2 (v1.7.190) = B/I,C,D/E,F,G,H,J,L,M,N,O,P,Q.
Ein Commit pro Fix, jeder einzeln verifiziert. **K übersprungen** (auto-rename-Reorder,
schlechtestes Risiko/Nutzen, kann für diesen User gar nicht feuern).
### Release 1 — Daten-Verlust-Stopper (v1.7.189, A ALLEIN)
- [x] **A** `video-processor.ts` atomic-replace zerstörte bei Windows-Lock BEIDE Kopien
(rm(original) VOR bestätigtem Replace + outer-catch rm(temp) → 0 Kopien). **GEFIXT:**
atomic replace-over + `renameWithRetry` (EBUSY/EACCES/EPERM/EEXIST, Backoff 200/500/1000ms),
rm-first-Fallback entfernt, **unique** Temp-Name (`~rd<pid><rand>`, löst auch C-Kollision).
Advisor bestätigt Ansatz besser als bak-dance (kein Missing-File-Window). 3 neue Tests
(Recovery + Retry-Pfad), 41 video-processor-Tests grün, tsc=6 (Baseline). Commit 189af22.
### Release 2 — v1.7.190 (GEFIXT + verifiziert, ein Commit pro Fix)
- [x] **L+M** video-processor.ts zu weite Deutsch-Erkennung. isGermanStream Titel-Fallback nur
ganze Wörter (ger/deu raus → konnten falsche Spur picken + echte dt. löschen); looksLikeGerman
Release 'dubbed' raus (ital./franz. Dub triggerte German-first). 2 Negativtests. Commit 272a41a.
- [x] **H** logger.ts flushAsync slice-snapshot korrumpiert bei 1MB-Cap-Trim während await →
ungeschriebene Zeilen verloren. Move-snapshot (Buffer auf [] übernehmen) + Requeue bei
Schreibfehler. Commit 4432fa2.
- [x] **J+Q** download-manager. J: runPackagePostProcessing finally löschte Map-Eintrag ohne
Identity-Guard → Abort+Neustart-Race riss neuen Task raus (Waise + Doppel-Lauf); jetzt nur
löschen wenn Map noch auf DIESEN Task/Controller zeigt (handle-Objekt wegen TS2454). Q:
collectFilesByExtensions filtert `~rd`-Temp-Präfix (crash-verwaiste Teil-Remuxe nie ins
Library). Commit 3c33b98.
- [x] **P** extractor.ts nested-Resume-Keys (`nested:<name>`) bei jedem extractPackageArchives
gepurged → verschachtelte Archive beim Resume neu entpackt; `startsWith("nested:")` im Prune
übersprungen. Commit 61a8304.
- [x] **B/I** app-controller.ts importBackup settings-only purgte LIVE-Queue (Dateien blieben auf
Platte) + rollte Usage-Zähler zurück. Fix: setSettings({suppressRetroactiveCleanup}) +
overlayLiveUsageCounters (extrahiert+wiederverwendet, inkl. Key-Filter). Commit dc05b51.
### Verifiziert KEINE Bugs / bewusst NICHT angefasst (Advisor-Disziplin: erst belegen, dann ändern)
- **G** dropItemContribution "subtrahiert Session-Totals nicht" → **KEIN Bug**: Test "keeps
cumulative session totals when completed items are removed" kodifiziert die Absicht (Session-
Zähler kumulativ, divergieren bewusst von der Item-Map; Retry-Pfad zieht ab, weil neu geladen
wird). Fix-Versuch ließ den Test failen → revertiert, Klarstellungs-Kommentar gesetzt.
- **N** stripDualLangFromFileName "Kollision" → **bereits geguarded**: existsAsync-Skip verhindert
Überschreiben; Remux machte Inhalt eh deutsch-only; collect strippt `.DL.` downstream. Residual
= generischer Rename-TOCTOU (in JEDEM Rename-Pfad), kein spezifischer Bug hier.
- **D/E** abort-Klassifizierung über signal.reason statt Text → **deferred (Robustheit, kein
Live-Bug auf User-Pfad)**. BELEGT: mega-web-fallback normalisiert JEDEN Abort (Timeout UND
Cancel) zu `new Error("aborted:mega-web")` → aktueller Guard `/aborted/i && !/timeout/i` FEUERT
→ v1.7.187-Cooldown LÄUFT auf dem Web-Pfad (User-Pfad). Einzige Imperfektion: Cancel >8s wird
fälschlich gecooled (minor). Empirisch bestätigt: `AbortSignal.any([ac,timeout]).reason?.name===
'TimeoutError'` (timeout) vs string/AbortError (cancel) — falls je gebaut: signal.aborted-gaten,
reason.name nutzen, Text-Fallback behalten, reason-Test. Hoch-Risiko (kritischer Unrestrict-Pfad
JEDES Downloads) → nicht für Robustheit anfassen. API-Pfad-Abort-Text nicht erschöpfend geprüft.
- **E** "API 'cancel'-Pfad umgeht" → **nicht real**: kein `'cancel'`-throw im Code gefunden.
- **O** classifyAccountFailure abort-Branch tot → **stehen lassen**: tot NUR wegen aktueller
Text-Interception; ein signal.aborted-gated D/E würde ihn wiederbeleben. Kein Kosmetik-Churn.
- **F** Mega-Web empty-streak Concurrency → **N-shaped, deferred**: Streak wird bei Erfolg (1956)
+ Nicht-Limit-Fehler (2005) gecleart; "bis Neustart gesperrt" ist bewusste Tageslimit-Logik,
Restart-cleared; Mega-Web single-flight → Concurrency greift nicht. Keine fühlbare Schädigung
konstruierbar → keine Park-State-Maschinerie.
- **C** → in A subsumiert (unique Temp-Name). **K** übersprungen (auto-rename-Reorder, Risiko≫Nutzen).
---
## 🟢 OFFEN — Backlog (optional, nie begonnen)
### ✅ Mega-Web Account-Rotation überspringt Account 3 — GEFIXT 2026-06-08 (v1.7.187)
**Fix:** Ein Mega-Web-Account-Abbruch (geteiltes Timeout feuert während der Account lief)
setzt jetzt einen 2-min-Cooldown auf den Account (nur wenn er ≥8s lief, sonst = User-Cancel,
RD_MEGA_ABORT_MIN_RUN_MS env). Dadurch überspringt der download-manager-Retry diesen Account
und rotiert zum nächsten (debrid.ts, abort-Handling im Rotations-catch, vor classifyAccountFailure).
Log-Event `TIMEOUT_COOLDOWN` (gelb, "Timeout/Abbruch → nächster Account beim Retry") statt
rotem "fataler Fehler" (App.tsx:1141 Label). 2 Regressionstests (Cooldown gesetzt → Call 2
rotiert; Quick-Abbruch → kein Cooldown). EHRLICH: fixt Korrektheit, NICHT Latenz — Account 1
brennt weiter ~60s ins Timeout bevor der Retry auf Account 2 wechselt (instant-Failover bräuchte
per-Account-Timeout = größerer Eingriff, bewusst verschoben). Advisor-gegengeprüft.
**(Ursprüngliche Analyse — Symptom & Mechanismus, zur Doku belassen)**
**Symptom (User):** 3 Mega-Debrid-Web-Accounts aktiv, Rotation pendelt aber nur zwischen
Account 1 ↔ 2 (bzw. nur Account 1), Account 3 (Su****xe) wird NIE probiert.
**Verifizierter Mechanismus (Code):**
- Rotationsschleife `debrid.ts:1898`. Account 1 → "Mega-Web Antwort leer" → Cooldown 20s →
weiter zu Account 2. Account 2 → `aborted:debrid`.
- `classifyAccountFailure` (`debrid.ts:2036`) stuft JEDEN Abbruch als **fatal** ein →
`throw` (`debrid.ts:1991`) → Schleife bricht ab → **Account 3 nie erreicht.**
- Account 2 bekommt beim Fatal-Abbruch **keinen Cooldown** (cooldownMs:0). Beim
download-manager-Retry wird Account 1 (Cooldown) übersprungen, aber Account 2 (kein
Cooldown) ERNEUT vor Account 3 probiert → bricht wieder ab → ewiges 1↔2.
- Geteiltes 60s-Unrestrict-Timeout `download-manager.ts:8590` (`AbortSignal.any([taskAbort,
timeout(60s)])`) gilt für die GANZE Rotation, nicht pro Account. Mega-Web pollt intern bis
180s (`mega-web-fallback.ts:235` + Poll-Loop `:371`). Sobald das geteilte 60s feuert, bleibt
das kombinierte Signal aborted → KEIN späterer Account kriegt im selben Pass eine echte Chance.
**BESTÄTIGT 2026-06-08 (zweite Screenshots):** Account 1 läuft 10x rasch "erfolgreich"
(11:51:4511:52:26), dann zwei "abgebrochen (aborted:debrid)" um 11:53:30 UND 11:54:30 —
**exakt 60s auseinander** = das geteilte 60s-Unrestrict-Timeout feuert (kein User-Stop, der
wiederholt sich nicht periodisch). Hier rotiert GAR NICHTS: Account 1 bricht ab → fatal →
Rotation stoppt sofort bei idx=0 → Account 2 und 3 werden NIE probiert. Bug eindeutig
bestätigt, elapsedMs nicht mehr nötig. Account 1 selbst ist gesund (10x ok) — Mega-Web hängt
nur sporadisch (no-server-Poll) bis ins 60s-Timeout.
**Fix-Design (wenn bestätigt):** Pro-Account-Timeout-Budget, abgekoppelt vom geteilten Cap.
debrid.ts braucht das **cancel-only** Signal getrennt vom Timeout (kombiniertes Signal kann
beides nicht unterscheiden). Minimal-invasiv: optionaler `opts`-Param an `unrestrictLink`
({cancelSignal, perAttemptTimeoutMs}) — nur die Mega-Rotation liest ihn, andere Provider
unberührt (kombiniertes Signal bleibt). Pro Account: `AbortSignal.any([cancelSignal,
AbortSignal.timeout(perAttemptMs)])`. Abbruch-Logik: cancelSignal aborted → echter Stop;
eigenes Account-Timer gefeuert → non-fatal, Cooldown, weiter zum nächsten Account (inkl. 3).
**Regressionstest ZUERST** (3 Accounts, 1+2 failen/aborten → assert Account 3 kriegt TEST).
**Advisor-Gate** vor Eingriff (kritischer Unrestrict-Pfad, betrifft jeden Download).
Hinweis: Grundursache der leeren Antworten = Mega-Debrid Server/IP-Thema — Fix macht Rotation
nur FAIRER (alle Accounts drankommen), bringt aber keinen busy Server zum Antworten.
### Features / UX (nach ROI)
App läuft headless auf Windows-Server → Nutzer sitzt nicht davor.
1. [ ] **Push-Benachrichtigungen** (Discord/Telegram/ntfy) — SM. Paket fertig/Fehler/Quota/Provider-down aufs Handy. Neuer `notifier.ts`, Hooks an Completion-Punkten. **Höchster ROI.**
2. [ ] **Fernsteuerung über Debug-Server** (POST-Endpunkte) — SM. Server hat HTTP + Token-Auth, aber nur GET. POST `/control/add-links`, `/start`, `/stop`.
3. [ ] **URL-Duplikat-Erkennung beim Hinzufügen** — S. History-`urls` existiert, wird nie geprüft → versehentliche Re-Downloads. Warnen: "3 Links bereits geladen".
4. [ ] **Pre-Flight-Check + Bulk-Skip toter Links** — M. Vor Start Größe/Name/Online für ganze Queue, "alle offline überspringen".
5. [ ] **Speicherplatz-Vorabprüfung vor Start** — S. Aktuell keine Free-Space-Prüfung für Downloads → Abbruch mitten drin bei voller Platte.
6. [ ] **Konsolidierte Fehler-Ansicht** — M. Alle fehlgeschlagenen Items flach + Fehlertext + "alle erneut versuchen". (Daten dafür liegen jetzt teils in der Error-Ring aus v1.7.185.)
7. [ ] **Per-Provider-Statistik** — M. Rohdaten (`providerTotalUsageBytes`) existieren, werden nicht dargestellt. Welches Abo lohnt sich?
8. [ ] **Auto-Retry fehlgeschlagener Pakete nach Wartezeit** — SM. Quota/Cooldown-Fails am nächsten Tag automatisch neu.
9. [ ] **Plex/Jellyfin Library-Refresh nach MKV-Move** — S. Gleicher Hook wie #1.
10. [ ] **Watch-Folder für DLC/Link-Auto-Import** — M.
### Design-Richtung (Entscheidung steht aus)
4 Mockups in `design-mockups/` (index.html = Vergleich): **Aurora** (verfeinert dark, geringstes Risiko) · **Command** (Terminal/Ops, dicht) · **Vellum** (light editorial) · **Nebula** (neon).
→ Richtung wählen. Siehe Memory: design-taste (Anti-KI-Look) + design-direction (Ember-Wärme, flach/ehrlich).
### Alte Audit-Items (2026-04-04, Status ggf. veraltet — VOR Fix gegen aktuellen Code verifizieren)
- [ ] Debrid-Link `maxDataHost` kühlt ganzen Key ab statt nur den Host
- [ ] Debrid-Link `fileNotAvailable` setzt Key auf "error" statt temporär
- [ ] AllDebrid: kein per-host-Cooldown für erschöpfte Quotas
- [ ] LinkSnappy: keine Auth-Dedup (parallele Requests rufen beide authenticate())
- [ ] Extractor password-cache race (parallele Worker mutieren `packageLearnedPasswords`)
- [x] Hybrid race: 1 Datei/Staffel evtl. beim MKV-Move nicht umbenannt (NUR per-package fixen — Post-MKV-Move-Scan ist tabu, v1.7.107 revertiert) → GEFIXT v1.7.196
---
## ✅ Hybrid-Race .DL.+Doppeltonspur — v1.7.196 (2026-06-10)
User-Goal: Desperate Housewives S03E08/E11/E17 behielten .DL. + DE+EN-Tonspur trotz keepGermanAudioOnly.
Vermutung "langer Titel" widerlegt (gleich lange Namen). Support-Bundle: genau die 3 hatten 0× "Tonspur-Bereinigung OK".
Ursache: Hybrid-Extraktor laeuft SEPARAT von der per-Paket-Kette (autoRename→keepGermanAudio→collect).
Waehrend langsamer ~3s-Remux (1,5GB) lief, entpackte er frische .DL.-MKVs in extractDir — nach dem
keepGermanAudio-Datei-Scan, vor dem Ketten-collect. collectMkvFilesToLibrary (deferFreshFiles=true)
verschob sie mit .DL. in die Library, bevor ihr Audio-Strip lief; raus aus extractDir fand der finale
Deferred-keepGermanAudio sie nie. 2000ms-Frische-Gate griff nicht (Dateien ~2,3s alt).
Fix: collectMkvFilesToLibrary haelt bei deferFreshFiles && keepGermanAudioOnly remuxbare (.mkv/.mp4)
Dateien mit .DL.-Marker zurueck → bleiben in extractDir, spaetere Hybrid-Runde ODER finaler Deferred-Pass
bereinigt+sammelt. Praezise (eine .DL.avi wird nie remuxt → nicht zurueckhalten). Deferred-Pass
(deferFreshFiles=false) unberuehrt → legitim doppeltonige Datei ohne DE-Track wird weiter gesammelt.
Regressionstest tests/hybrid-collect-race.test.ts (3 Faelle). 804 Tests, tsc=6, self-check+build,
Gitea+Mirror 3664e78 verifiziert (beide draft=false, 4 Assets, latest.yml path==Asset).
OFFEN: Altfiles in entpackt2 werden NICHT retroaktiv bereinigt — nur neue Downloads. Remediation der
3 Episoden nur auf Admin-Account (ploet-Session sieht Administrator-Profil nicht) oder via geplantes
"Bibliothek-Batch Tonspur"-QoL.
## Webhook "0 von 5 getriggert" (2026-06-10) — KEIN Code-Bug
Test-Nachricht kam an (URL OK), aber alle 3 Notify-Toggles unchecked + "Einstellungen speichern" offen
(ungespeichert). Toggle-Default=aus. User muss Toggles aktivieren UND speichern.
---
## ✅ ERLEDIGT — Archiv (Details in git-History + Memory)
- **Erweitertes Logging** → released **v1.7.185** (Crash-Handler, Renderer-Fehler-IPC, RD_DEBUG-Level, Error-Ring + `/errors`, ENOSPC-Klassifizierung, Memory-Heartbeat). → Memory: extended-logging
- **Link-Prefetch** → untersucht (6-Agent) + **bewusst verworfen** (marginal bei maxParallel 8, Mega-Web single-flight). → Memory: link-prefetch-declined
- **Backup nur Settings** → v1.7.184 (`backupIncludeDownloads`-Toggle + 4 Selektions/Flicker-Fixes). → Memory: backup-settings-only
- **Account-Rotation-Overhaul** → v1.7.164168 (Validity/Premium-Badges, Live-Panel, "Alle prüfen"). → Memory: account-rotation
- **Mega-Debrid-Account deaktivieren (UI)** → erledigt (Toggle im Edit-Dialog, im Code verifiziert 2026-06-07)
- **Bugs/Robustheit (Deferred-Pipeline H1/H2/H3/M1/M2/N1)** → v1.7.158/159; M3 bewusst übersprungen (Generation-Guard schützt Integrität bereits)
- **Deferred-Pfad Rename-Gap** → gefixt v1.7.162+ (finaler Deferred-Pass benennt frische Dateien vor Collect um; Repro-Test grün)
- **Repo-Privacy-Audit** → GitHub gelöscht+neu (saubere History), Gitea unberührt. → Memory: repo-privacy-audit
### Bewusst NICHT angefasst (Crash-Debris / alte Experimente)
- Gestashtes Crash-Debris `stash@{0}` (Revert von 08372f9/18eada9/98dc366 + log.old) — bei Bedarf recoverbar, sonst verwerfbar
- Untracked `*-postprocess/` + `fix-library-renames.mjs` — alte Experimente (Apr/Mai)