Fix: Provider-Cooldown-Fallback fuehrt die Kette jetzt wirklich mit dem Ersatz-Provider an (Routing-Slice)
Wenn ein Provider in den Manager-Cooldown laeuft (>=20 Fehler in Folge) und auto-Fallback aktiv ist, berechnete der Manager zwar einen Ersatz-Provider (findFallbackProviderNotInCooldown), warf ihn dann aber weg: der unrestrictLink- Aufruf bekam keinen Hint, also baute debrid.ts die Provider-Kette frisch aus providerOrder und fuehrte erneut mit dem ausgebremsten Provider 1 an — ein meist in den 60s-Timeout laufender, verschwendeter Versuch, bevor ueberhaupt der gesunde Provider drankam. Jetzt wird der Ersatz-Provider als bevorzugter Lead durchgereicht. Die Kette wird UMSORTIERT, nicht beschnitten: der ausgebremste Provider bleibt als letzter Notnagel in der Reihenfolge, sodass kein Link gestrandet werden kann. Sind ALLE Provider im Cooldown, erreicht der Aufruf unrestrictLink ohnehin nicht (der else-Zweig queued einen Retry). Greift damit nur, wenn ein Provider bereits nachweislich degradiert ist — strikt besser, wenn aktiv, und ohne Timeout-, Cancel- oder Budget-Vertrag anzufassen. - debrid.ts: reine leadProviderChainWith(order, preferred) (export) + optionaler 4. Param preferredLeadProvider an unrestrictLink; Reorder direkt nach Aufbau der Reihenfolge. - download-manager.ts: Ersatz-Provider in preferredLeadProvider festhalten und an den unrestrictLink-Aufruf durchreichen. - Tests: Integration (ohne Hint fuehrt realdebrid, mit Hint fuehrt debridlink) + drei reine Helper-Tests fuer die No-Stranding-Invariante. Zwei verbleibende HIGH-Punkte sind bewusst NICHT autonom geaendert, sondern als Produkt-/UI-Entscheidung in tasks/entscheidungen-offen.md vorgelegt (globaler 60s-Failover-Timeout; gespiegelter Mega API/Web-Schalter).
This commit is contained in:
@@ -106,6 +106,30 @@ unabhaengigen Code-Verifikation abgedeckt (60s-Timeout kappt Failover, debrid.ts
|
||||
- #R3-7 LOW (3/3) Update-Integritaet hash-only, kein Authenticode — ehrliche Grenze, faellt sicher aus.
|
||||
- REFUTIERT (0/3): all-accounts-parked wirft plain error ohne cooldown-retry-Token.
|
||||
|
||||
## Runde 4 (Failover-Routing-Slice + Entscheidungs-Doku)
|
||||
Follow-on aus R3-Failover-Fund. Advisor-Disziplin: nur die SICHERE Scheibe autonom, der
|
||||
Produkt-Tradeoff geht an den Nutzer (tasks/entscheidungen-offen.md).
|
||||
|
||||
### Autonom gefixt (TDD, rot-bewiesen)
|
||||
- [x] MED Failover-Routing: Manager berechnete bei Provider-Cooldown (>=20 Fehler in Folge,
|
||||
auto-Fallback an) einen Ersatz-Provider (`findFallbackProviderNotInCooldown`), WARF ihn aber
|
||||
weg — `unrestrictLink(item.url, signal)` ohne Hint → debrid.ts baut `order` neu aus
|
||||
providerOrder und fuehrt WIEDER mit dem ausgebremsten Provider1 an (wahrsch. 60s-Timeout
|
||||
verschwendet). Fix: reine `leadProviderChainWith(order, preferred)` (debrid.ts, export) +
|
||||
4. optionaler Param `preferredLeadProvider` an `unrestrictLink`; Manager reicht den Ersatz
|
||||
durch (dl-mgr 8772/8828). REORDER nicht SKIP → ausgebremster Provider bleibt als letzter
|
||||
Notnagel in der Kette, kein Stranding. All-cooled-Fall erreicht `unrestrictLink` gar nicht
|
||||
(else-Zweig queueRetry'd). Tests: integration (control=realdebrid, preferred=debridlink) +
|
||||
3 reine Helper-Tests (null→unchanged, in-order→leads+keeps-all, not-in-order→unchanged).
|
||||
Suite 875 gruen, tsc=6. Commit folgt; HALTEN fuer Roll-up-Release (kein HIGH/dringend).
|
||||
|
||||
### An den Nutzer vorgelegt (NICHT autonom) → tasks/entscheidungen-offen.md
|
||||
- 60s-Failover-Kappung (HIGH): A) pro-Provider-Timeout (Failover immer, aber bis 3×60s
|
||||
Worst-Case) vs B) globales Budget mit Failover-Reserve (langsamer Provider1 frueher
|
||||
abgeschnitten). Produkt-Tradeoff = Nutzerwahl. Post-214 weitgehend latent.
|
||||
- Gespiegelter Mega API/Web-Schalter (HIGH, #R3-2): gemeinsamer Schalter vs unabhaengige
|
||||
pro-Modus-Flags (Migration + UI-Redesign noetig, Nutzer UI-sensibel).
|
||||
|
||||
## Runde 2 (Download-Ausfuehrung: stream/resume/disk/integrity/extract/persist) — Workflow whspc8ddv
|
||||
14 confirmed / 7 refuted (>=2/3 adversarisch). Alle HIGH/MED unten unabhaengig am echten Code
|
||||
verifiziert (Zeilen zitiert) bevor gefixt. Jeder Fix mit rot-bewiesenem Test, tsc bleibt 6.
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
# Offene Entscheidungen für dich (Audit-Loop 2026-06-17)
|
||||
|
||||
Diese zwei Punkte habe ich BEWUSST nicht autonom „gefixt", weil jede Lösung
|
||||
einen Produkt-/Geschmacks-Kompromiss enthält, den du entscheiden solltest, nicht ich.
|
||||
Beide sind verifiziert (Code-Zitat + Szenario), nur die Richtung ist deine Wahl.
|
||||
|
||||
---
|
||||
|
||||
## 1. Failover-Kappung durch globalen 60-Sekunden-Timeout (HIGH)
|
||||
|
||||
**Was passiert (belegt):**
|
||||
`download-manager.ts` baut EINEN Timeout fürs gesamte Unrestrict:
|
||||
```
|
||||
const unrestrictTimeoutSignal = AbortSignal.timeout(getUnrestrictTimeoutMs()); // 60s
|
||||
const unrestrictedSignal = AbortSignal.any([active.abortController.signal, unrestrictTimeoutSignal]);
|
||||
```
|
||||
Dieses EINE Signal geht an die komplette Provider-Kette in `debrid.ts`. Die 60s sind
|
||||
also ein Budget für ALLE Provider zusammen, nicht pro Provider. Wenn Provider 1
|
||||
(z.B. Mega-Web mit Account-Queue) das Budget verbraucht, dann sieht Provider 2 ein
|
||||
bereits abgelaufenes Signal → `debrid.ts` wertet den Abbruch als „kein Failover" und
|
||||
wirft, ohne Provider 2 echt zu versuchen.
|
||||
|
||||
**Aktuell weitgehend latent:** Seit v1.7.214 wird die API zuerst probiert (schneller Pfad),
|
||||
Mega-Web ist nur noch Fallback. Das Szenario „langsamer Provider 1 hungert Provider 2 aus"
|
||||
trifft in der Produktion derzeit selten. Deshalb dokumentiert statt dringend gefixt.
|
||||
|
||||
**Deine Entscheidung — zwei Richtungen (gleiche Spannung, andere Seite):**
|
||||
|
||||
- **A) Pro-Provider-Timeout:** Jeder Provider bekommt sein eigenes frisches 60s-Budget.
|
||||
Failover bekommt IMMER einen echten Versuch.
|
||||
*Kosten:* Worst-Case-Wartezeit pro Item steigt (3 Provider × 60s = bis zu 180s, bevor ein
|
||||
Item aufgibt). Du akzeptierst langsameres Worst-Case-pro-Item für vollständigeres Failover.
|
||||
|
||||
- **B) Globales Budget behalten, aber Slice für Failover reservieren:** Provider 1 wird auf
|
||||
z.B. 35s gedeckelt, damit garantiert Zeit für Provider 2 bleibt.
|
||||
*Kosten:* Ein legitim langsamer Provider 1 (Mega-Web-Account-Queue bis ~90s) wird früher
|
||||
abgeschnitten → mehr Failover, auch wenn Provider 1 noch erfolgreich gewesen wäre.
|
||||
|
||||
Kernfrage, die nur du beantworten kannst: **Wie lange darf ein Item bei einem langsamen
|
||||
aber funktionierenden Provider hängen, bevor wir ihn zugunsten des nächsten aufgeben?**
|
||||
|
||||
---
|
||||
|
||||
## 2. Gespiegelter Mega API/Web-Schalter (HIGH, in Runde 3 als 2/3 bestätigt)
|
||||
|
||||
**Was passiert (belegt):** Die Mega-Debrid API- und Web-Account-Zeilen teilen sich EINE
|
||||
login-only Enable-Flag (`hasMegaDebridCredentials` gilt für beide; die Pro-Modus-Auswahl
|
||||
läuft über `isMegaDebridModeEnabled(settings, "api"|"web")`). Dein Report: „API ausschalten
|
||||
schaltet Web an" — weil der Schalter sich spiegelt.
|
||||
|
||||
**Warum ich es NICHT autonom geändert habe:**
|
||||
- Daten-Modell-Fix (echte unabhängige Flags) braucht eine Settings-Migration, die
|
||||
deaktivierte Accounts versehentlich re-aktivieren könnte.
|
||||
- Die saubere UI-Variante (zwei echte unabhängige Schalter) ist ein Layout-Redesign — und
|
||||
du bist UI-Geschmack-sensibel; das will ich nicht ungefragt umbauen.
|
||||
|
||||
**Deine Entscheidung:** Ein gemeinsamer Schalter (API+Web zusammen an/aus, klar beschriftet)
|
||||
ODER zwei unabhängige Pro-Modus-Schalter (mehr Kontrolle, aber UI + Migration nötig)?
|
||||
|
||||
---
|
||||
|
||||
## Erledigt in dieser Runde (zur Info, kein Handlungsbedarf)
|
||||
|
||||
- **MED Failover-Routing:** Wenn ein Provider in den Manager-Cooldown läuft (≥20 Fehler in
|
||||
Folge) und auto-Fallback an ist, hat der Manager bisher zwar einen Ersatz-Provider berechnet,
|
||||
ihn aber WEGGEWORFEN — die Kette führte trotzdem wieder mit dem ausgebremsten Provider an.
|
||||
Jetzt wird der Ersatz-Provider als „Lead" durchgereicht und die Kette führt mit ihm an, OHNE
|
||||
einen Provider zu verlieren (der ausgebremste bleibt als letzter Notnagel in der Kette).
|
||||
Greift nur, wenn der Provider bereits nachweislich degradiert ist → strikt-besser-wenn-aktiv,
|
||||
kein Timeout/Cancel-Vertrag berührt. Rot-bewiesener Test. (Hält für Roll-up-Release bereit.)
|
||||
Reference in New Issue
Block a user