real-debrid-downloader/tasks/audit-loop.md

26 KiB
Raw Blame History

Autonomer Audit-Loop — Download/Fehler/Rotation (Goal 2026-06-17, 8h)

Disziplin: erst BELEGEN (Code-Zitat + konkretes Szenario), dann adversarisch verifizieren, dann TDD-Fix. Kein Blind-Fix. Tests gruen + tsc=6 nach jeder Runde. Periodisch releasen.

Runde 1 (laeuft)

  • Discover+Verify-Workflow ueber 7 Subsysteme (scheduler-slots, unrestrict-retry, mega-rotation, classify-cooldown, mega-web-token, provider-chain-timeout, account-availability).

Meine unabhaengigen Verdachtsfaelle (Cross-Check gegen Workflow)

  1. Web-Selbst-Cooldown (Analog zum API-214-Bug, HOCH): Caller-Timeout = 60s (DEFAULT_UNRESTRICT_TIMEOUT_MS, download-manager 114) umschliesst die GANZE Kette. Mega-Web braucht legitim laenger (per-Account-Queue bis 90s + Login + Generate). Feuert die 60s nach >=8s (MEGA_DEBRID_ABORT_MIN_RUN_MS_DEFAULT=8000), setzt die Rotation aborted:debrid → 120s Account-Cooldown (debrid.ts ~2037-2048), obwohl der Account GESUND ist — die App hat aufgegeben. → Kaskade ueber Accounts. Live im jf.zip belegt: Mega-Debrid Web | TIMEOUT_COOLDOWN | reason=aborted:debrid | cooldownSec=120. Fix-Kandidat: (a) per-Provider-Timeout statt globaler 60s; und/oder (b) Caller-Timeout- Abort NICHT als Account-Cooldown werten (EMA-Demotion regelt langsame Accounts bereits), oder nur sehr kurz.
  2. Globaler 60s-Timeout kappt Failover (Advisor-bewiesen, HOCH): download-manager 8759 AbortSignal.any([cancel, timeout]) → bei Provider1-Verbrauch des Budgets abortet das Signal → debrid.ts 3805 signal.aborted → throw, kein nextProvider. Fix: per-Provider- AbortSignal.timeout, Stop nur bei USER-Cancel.
  3. Exponential-Backoff bis 120s (generic unrestrict retry) — Item sitzt bis 2 min. Pruefen ob fuer haeufige transiente Faelle zu lang.

Bestaetigte Bugs (Workflow R1: 14 confirmed / 11 refuted) — priorisiert

  • [IN ARBEIT] #1 HIGH Scheduler-Freeze: findNextQueuedItem ohne activeTasks-Guard → synchroner Admission-Loop dreht endlos wenn ein reset/overwrite-Item noch im activeTasks parkt (non-abort- observing await, z.B. Integrity-Check). Fix: if (this.activeTasks.has(itemId)) continue;. TDD-Test (Freeze-Repro mit non-abort Mock + resetItems) geschrieben.
  • #2/#3 MED mega_debrid_cooldown: Delay verworfen — kein Parser (nur debrid_link_cooldown). Fix: Parser fuer beide Praefixe, queueRetry mit echtem delayMs. (Erklaert Rapid-Retry-trotz-Cooldown im jf.zip.)
  • #7/#8 MED Mega per-Account Daily-Usage wird am Tagesgrenze NIE resettet → Accounts faelschlich "am Limit" → schrumpft MEIN neues serialized-limit. Fix: megaDebridAccountDailyUsageBytes in ensureProviderDailyUsageFresh resetten.
  • #4 MED transiente leere Web-Antwort → permanenter until-restart-Park (limitSignal vom generischen "antwort leer"). Fix: limitSignal nur vom echten Daily-Limit (NO_SERVER_RE).
  • #5 MED Web echte Bad-Credentials erreichen invalid-Branch nicht (werden ewig retried). Fix: echte Web-Login-Fehlerphrasen in invalid-Branch.
  • #6 MED onefichier/ddownload-Routing ignoriert autoProviderFallback=off. Fix: Guard in catch.
  • #14 LOW Regex-Ordering classify: quota-Branch shadowt rate_limit. Fix: rate_limit vor quota.
  • #9 LOW overwrite wipet frisch geclaimten targetPath via altem .finally.
  • #10 LOW HTTP416 shared counter mit genericErrorRetries.
  • #11 LOW fresh-retry preempt typed transient handlers.
  • #12 LOW 15-failure-shelve + shared counters → mehr Retries als retryLimit.
  • #13 LOW self-poison: queue-wait zaehlt zu elapsedMs → abort-cooldown (Analog zu meinem Web-Verdacht #1).

Refutiert / Nicht-Bug (11) — nicht anfassen

providerStartReservations dead-state; debrid_link_cooldown cleanup; supprimé-fallthrough; mega-web 180s aborts whole rotation; EMA-removed-premise; quota-no-park asymmetry; connectApi single-flight cancel-couple; per-account queue chain-break (NON-BUG); mega-web slot-hold (NON-BUG); provider abort-vs-timeout heuristic; daily-limit aggregate early-exit.

Fixes (TDD, mit Test + Release)

Batch 1 → v1.7.215 (Suite laeuft)

  • #1 HIGH Scheduler-Freeze: findNextQueuedItem activeTasks-Guard. Repro-Test (ohne Fix haengt der Event-Loop so hart, dass nicht mal vitest-Timeout feuert = Freeze empirisch bewiesen). Mit Fix 288ms.
  • #2/#3 MED parseMegaDebridCooldownRetry (export) + Handler VOR transient/generic branch → Item wartet den ECHTEN Cooldown (min ueber alle Accounts) statt 5s-Busy-Loop. 5 Parser-Tests.
  • #7/#8 MED megaDebridAccountDailyUsageBytes Reset in ensureProviderDailyUsageFresh (laeuft via getSnapshot, also auch im Stall). Test: Tagesgrenze → leer.
  • #14 LOW rate_limit-Branch VOR quota (quota matchte "limit" in "rate limit"). Test: rate_limit-Kategorie.
  • [deferred] #4 empty-response→until-restart-park: 3-consecutive-streak ist reale Mitigation gegen transiente Blips; Mega-empty-Semantik nicht sicher verifizierbar → kein Blind-Change.

Strategie-Update (LIVE-Server, Advisor-bestaetigt)

  • LOW-Fix-Schwelle HOCH: nur fixen bei NULL plausibler Regression UND einem Test der OHNE Fix rot ist. Sonst dokumentieren ("gefunden & charakterisiert" ist valides Audit-Ergebnis). Server laeuft live, auto-update, ~1 TB/h → jede unnoetige Verhaltensaenderung = Risiko.
  • Releases BUENDELN (alle 2-3 Runden / Roll-up), nicht pro Fix. Weniger Update-Churn auf dem Live-Server.
  • #5 NICHT raten: conversion.log faengt den echten Web-Login-Fehler-String schon (web-queue-Phase-Detail). Aus naechstem Bundle ernten, dann erst invalid-Phrasen ergaenzen. Kein Phrasen-Halluzinieren.
  • #13 defer: Web ist seit v1.7.214 nur noch Fallback (API-first), Selbstcooldown trifft kaum mehr; braucht workMs-Threading → groesserer Eingriff, nicht LOW-billig.
  • Vor Runde 4-5: SYNTHESE-Pass — ist Retry/Cooldown/Rotation END-TO-END kohaerent selbstheilend?

Runde 3 (Failover/Reconnect/Cooldown-Lifecycle/Scheduler/IPC-Toggle/Updater) — Workflow wcwztx7e9

7 confirmed / 1 refuted. provider-failover-Finder crashte (Socket) → diese Dimension via MEINER unabhaengigen Code-Verifikation abgedeckt (60s-Timeout kappt Failover, debrid.ts 3845 + dl-mgr 8814).

Batch 3 → v1.7.217 (GEFIXT, je rot-bewiesener Test)

  • #R3-1 HIGH (3/3) Self-Cooldown bis Neustart — DER vom Nutzer gemeldete „Tool sperrt sich selbst". (a) limitSignal aus MEGA_DEBRID_NO_SERVER_RE-Zweig entfernt (Hoster-Problem != Account-Limit), (b) until-restart-Park laeuft jetzt zum Tagesreset (lokale Mitternacht) ab statt MAX_SAFE_INTEGER → heilt <=24h selbst. Texte „bis Neustart"→„bis zum Tagesreset". Commit 76b3f99.
  • #R3-5 HIGH (3/3) Fehlgeschlagenes Update → Queue-Stillstand bis Neustart. runInstallWithResume() (neue reine Funktion) resumt bei started:false UND throw. Commit dfd1926.
  • #R3-3 MED (3/3) Account-Edit ueberschreibt megaDebridPreferApi. Hardcode entfernt → ...settings reicht Nutzerwahl durch. Commit 1e04b7b.

Dokumentiert / NICHT autonom gefixt (Advisor-Disziplin)

  • #R3-2 HIGH (2/3, UMSTRITTEN) Mega API/Web-Account-Zeilen teilen EINE login-only Enable-Flag → Toggle spiegelt sich (= Nutzer-Report „API aus → Web an"). KEIN Auto-Fix: Daten-Modell-Fix braucht Settings-Migration (kann deaktivierte Accounts re-aktivieren), UI-Collapse = Layout-Redesign (Nutzer UI-Geschmack-sensibel). → DEM NUTZER vorlegen: gemeinsamer Schalter vs. unabhaengige pro-Modus-Flags.
  • 60s-Failover-Kappung (HIGH, mein Fund, Finder gecrasht) — debrid.ts 3845 wertet JEDEN combined-signal- Abort (cancel ODER 60s-Timeout) als kein-Failover; langsamer Provider1 hungert Provider2 aus, auch ueber Retries. Post-214 (API-first) groesstenteils latent. → eigene Runde: gecrashten Finder ERST neu laufen lassen (unabhaengige Verifikation fehlt), dann per-Provider-Timeout-Design mit Advisor. NICHT in 217.
  • #R3-6 MED (3/3) Update-Mirror-Failover feuert nie (nur Gitea). NICHT fixen: aendert den Update-Fetch-Pfad = der Kanal, ueber den jeder Fix den Nutzer erreicht; faellt heute sicher aus (App behaelt alte Version).
  • #R3-4 LOW (2/3) providerPrimary kann auf disabled Mega normalisieren — self-heilt zur Laufzeit. Belassen (Refuter: Fix riskanter als Bug — schreibt persistierte Absicht um).
  • #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)

  • 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, Drehregler ueber Pro-Provider-Wert) 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).

SYNTHESE-Pass (Cross-Layer: Manager-Cooldown-Keys vs Debrid Account/Daily-Park) — Workflow wrfxpjudj

2 Kandidaten, 1 confirmed (3/3), 1 refuted (0/3). Advisor-Hypothese (Key-Mismatch) WIDERLEGT.

  • REFUTED (0/3) KSM-1 Key-Mismatch: normalizeProviderOrder (storage.ts:144/411) speichert IMMER den aufgeloesten 'megadebrid-api'/'-web', NIE den virtuellen 'megadebrid'. Also fallen Cooldown-WRITE (recordProviderFailure), CHECK (getProviderFailureKeyForItem), CLEAR und READ (findFallbackProviderNotInCooldown) auf denselben aufgeloesten Key → KEINE Divergenz. Der 986fbab-Routing-Fix ist fuer den Mega-Fall nachweislich sicher (No-Stranding haelt).
  • CONFIRMED (3/3) LOW MEGA-UNTILRESTART-MISCLASS (GEFIXT): Der untilRestart-Park-Throw (debrid.ts:2167) trug KEINEN Maschinen-Token → Manager-Catch klassifiziert ihn als generischen Unrestrict-Fehler (isUnrestrictFailure matcht "mega_debrid") → Retry alle ~2min den ganzen Tag
    • recordProviderFailure (Circuit-Breaker-Verschmutzung), statt einmal bis Tagesreset zu parken. Default-Config (retryLimit=0=∞) self-heilt um Mitternacht, KEIN Stranding. Genau die Round-3-untilRestart-Park-Absicht, die hier unterlaufen wurde. Predates 986fbab. Fix: debrid.ts emittiert jetzt mega_debrid_reset_park:<msBisReset>: (megaDebridDailyParkExpiry); neue reine parseMegaDebridResetPark (kein 15min-Clamp, 26h-Cap) + Catch-Branch VOR der Cooldown-Klassifikation queued bis Tagesreset OHNE recordProviderFailure. Rot-bewiesen (Parser-Tests + debrid-Token-Assertion). tsc=6.
  • End-to-end-Verdikt: Retry/Cooldown/Rotation/Failover ist unter Default-Config kohaerent self-heilend (jeder Park hat Zeitgrenze + Auto-Clear). Einzige Rest-Inkohaerenz war die Layering-Naht oben (in-memory untilRestart-Park unsichtbar fuer getAvailableMegaDebridAccounts
    • isProviderDailyLimited) — mit dem konservativen String-Klassifikations-Fix geschlossen. Der breitere Fix (Selektierbarkeit cooldown-aware machen) bewusst NICHT gemacht (groesserer Blast-Radius auf Live-Server).

Boot-Verifikation (Advisor-Punkt: Suite gruen != App bootet)

Smoke-Test des gebauten 1.7.218-Binaries (release\win-unpacked, throwaway userData, leere Session): laeuft >10s stabil, spawnt die normalen 4 Electron-Prozesse (main+GPU+renderer+utility), schreibt userData/runtime → BOOTET. Boot-Pfad (main.ts-Boot, app-controller-Init, Window/IPC-Registrierung) von diesem Audit NICHT angefasst; alle editierten Methoden sind Download-Zeit (von der 884er-Suite importiert+konstruiert). Risiko Startup-Regression empirisch ausgeschlossen.

Advisor-Leitlinie (Stand Runde 8)

  • Nach Runde 8 KEINE weitere Discovery-Runde, sondern ein SYNTHESE/Regressions-Pass ueber den KUMULATIVEN Diff (Interaktion der 6 gestagten/releasten Fixes) — Confirmed-Yield faellt (R5:0/R6:1/R7:1), Risiko ist jetzt Fix-Interaktion, nicht unentdeckte Bugs.
  • Advisor NICHT auf Kadenz pollen — nur bei echter Ship/Fix-Entscheidung mit neuer Info.
  • Die 2 HIGH Produkt/UI-Entscheidungen bleiben beim Nutzer (nicht autonom shippen).

Release-Status: v1.7.219 RELEASED (Gitea 6ae9f5d + GitHub-Mirror df3670a)

Roll-up Runde 7+8: be15419 MED VP-1 dt.-Tonspur + eacd0c9 HIGH RANGE-1 Silent-Corruption + REWIND-TRUNCATE. HIGH rechtfertigt Release. Advisor explizit cleared (vor Implementierung konsultiert, Check A verifiziert). Mirror kuratiert ohne CLAUDE.md/tasks/ (Leak-Check sauber). NAECHSTER SCHRITT (Advisor): Synthese/Regressions- Pass ueber kumulativen Diff aller Session-Fixes (Interaktion), KEINE weitere Discovery-Runde.

Release-Status: v1.7.218 RELEASED (Gitea bbb9355 + GitHub-Mirror 94d143b)

Roll-up Runde 4+5+6: 986fbab MED Provider-Cooldown-Routing + 03c908b No-Stranding-Test + f1e35f5 LOW Mega-Tagesreset-Park + d2a1b83 HIGH Shelve-Loop-RetryLimit. HIGH rechtfertigt das Release. Gitea (Live-Update-Quelle): .../releases/tag/v1.7.218. GitHub-Mirror (kuratierter Single-Commit ohne CLAUDE.md/tasks/, Leak-Check sauber): Sucukdeluxe/multi-debrid-downloader v1.7.218. Advisor war die GANZE Session ueberlastet → autonom released auf Basis: 3x rot-bewiesene Tests (je per Temp-Revert verifiziert), volle Suite 882 gruen, tsc=6, unabhaengige Code-Verifikation + Multi-Agent-adversarisch, Routing-Fix frueher advisor-gesegnet, Praezedenz 215/216/217 autonom. Runde-5/6-Charakterisierungen (PP-SEM-1 benign, DISK-1 deferred, deferred-LOW-Cluster #10/#11/#13 benign) NICHT released — dokumentiert.

Runde 8 (Byte-Streaming downloadToFile: Range/Resume/Append/Truncation) — Workflow wwjz4srkq

3 Finder + adversarisch verifizieren. 3 confirmed (1 HIGH + 2 MED, alle Silent-Corruption-Familie), 1 refuted. Advisor VOR Implementierung konsultiert (HIGH-Hot-Path) — Design + Check-A-Branch (totalBytes-null) bestaetigt.

  • CONFIRMED HIGH (GEFIXT, known-total) RANGE-1 Silent-Mid-File-Corruption: Auf dem LETZTEN inneren Versuch wird ein injizierter Garbage-Tail nicht zurueckgespult (attempt < maxAttempts-Guard greift nicht), resumeRewindBytesNextAttempt ist funktions-lokal (ueberlebt downloadToFile-Re-Entry nicht), der Outer-Handler nimmt fuer terminated-class den generic-retry-Zweig (kein File-Delete), und der Fresh-Link-Resume haengt echte Bytes NACH dem Garbage an → exakt-laengen-Datei besteht die Length-only-Completion-Pruefung; bei manifestlosen .mkv/.mp4 nie erkannt. Fix: Rewind-vor-Throw am Exhaustion-Punkt (truncate letzte RESUME_REWIND_BYTES + downloadedBytes ZUERST setzen → binary-Re-Entry-prealloc-reconcile robust auch bei truncate-Fehler), GEGATED auf totalBytes != null && > 0. Check A verifiziert: known-total → rewound size < totalBytes=minBytes → tryFinalizeItemFromDisk(9238) REJECTET → Re-Entry ueberschreibt Garbage. EHRLICHER Scope (Advisor): GEFIXT fuer known-total Medien (Debrid liefert fast immer fileSize); null-total behaelt die separate, vor-bestehende Silent-Corruption unter dem dokumentierten Size-only-Validation-Blindspot (durch Rewind NICHT fixbar — kein Laengensignal; nur Hard-Reset wuerde helfen, groesserer Eingriff). Rot-bewiesen: Cross-Call-Test (final-attempt Garbage → Exhaustion → queueRetry → 2. downloadToFile → CONTENT-Gleichheit); ohne Fix Length-Assert gruen + Content-Assert rot.
  • CONFIRMED MED (GEFIXT) REWIND-TRUNCATE-FAIL: Das finally setzte resumeRewindBytesNextAttempt=0 UNBEDINGT, auch wenn die Rewind-truncate (9633) warf → transienter win32-EBUSY/AV-Lock-Fehler liess den Garbage-Tail + cleart das Flag (nie retried). Fix: Reset NUR im Success-Branch → fehlgeschlagenes Rewind wird naechsten Versuch erneut probiert. Defensive Haertung (Advisor "ship it"); Happy-Path von Test 1113
    • RANGE-1-Test abgedeckt.
  • DOKUMENTIERT, nicht gefixt (MED, schwaechste, Workload-immun) PREALLOC-ZEROS-ACCEPTED: win32-Prealloc- Nullen am Ende als komplett akzeptiert fuer NICHT-binaere Typen (1MB-Slack) wenn truncate skip/faellt. Dominante Medien/Archive sind immun (threshold=0). Narrow Conjunction (non-binary >20MB, Gap<1MB, Crash/ truncate-fail). Fix bekannt (binary-strict footprint im 416-accept + recovery-finalize), aber deferred.
  • Refuted (1/3) TRUNC-1: fsync auf resume-append fehlt — als Power-Loss-Edge eingestuft, nicht confirmed.
  • Cross-cutting (Advisor: NICHT jetzt anfassen): Size-only-Completion-Validation ist der gemeinsame Blindspot; kein billiger Content-Check fuer manifestlose Medien → validateDownloadedFileCompletion NICHT umbauen (Risiko 4. Bug). Punkt-Fixes sind korrekt; Blindspot bleibt langfristiges Item.

Runde 7 (Post-Download: Extraction + Video-Processor + Companion/Orchestrierung) — Workflow wcxk08n5i

3 Finder + adversarisch verifizieren. 2 confirmed, 0 refuted. Schliesst den deferred-Extraction-Cluster ab.

  • CONFIRMED MED (GEFIXT) VP-1 Falsche Tonspur: isGermanStream (video-processor.ts:99-108) wertet die Titel-Regex /\b(german|deutsch)\b/ fuer JEDEN nicht-deutsch-getaggten Stream — NICHT auf "Sprach-Tag fehlt" gegated, obwohl der Kommentar (104-106) genau das als Absicht nennt. pickAudioTrack (124, EINZIGER Caller) nimmt den ERSTEN Treffer → eine eng-Spur mit Titel "...German..." vor der echten ger-Spur GEWINNT → Remux behaelt Englisch, verwirft die korrekte dt. Spur, ersetzt das Original atomar in-place (500) und strippt .DL. → irreversibler Datenverlust + falsche Sprache, als Erfolg gemeldet. Single-Trigger (nicht compound). Betrifft genau die vom Nutzer bestaetigte dt.-Tonspur-Funktion project_german_audio_feature. Fix: if (lang) return false; VOR dem Titel-Fallback (deckt sich mit der Kommentar-Absicht). Rot-bewiesen (2 Tests: eng-Titel-"German" vs echte ger → audioRelIndex 1; eng-Titel-"Deutsch entfernt" → skip). tsc=6.
  • DOKUMENTIERT, nicht gefixt (LOW compound) PP-1/#13 Companion-Overwrite: renameCompanionFiles/ moveCompanionFiles (dl-mgr 3735/3791) ohne Uniqueness-Guard (anders als MKV via buildUniqueFlattenTargetPath); cross-volume copyFile ohne COPYFILE_EXCL (3696) → ueberschreibt einen vorhandenen Orphan-Companion still (nur .srt/.idx/.nfo, nie Archiv/Video). Compound (Orphan + Namenskollision), Sekundaerdateien, Integrations- TDD noetig → dokumentiert. Fix bekannt (Uniqueness-Guard spiegeln).
  • Deferred-Extraction-Cluster re-klassifiziert (aus Runde 2): #10 CRC-Kleindatei-Delete BENIGN (failed Archive aus cleanupSources ausgeschlossen, nicht geloescht); #12 7z-Exit-1-als-Erfolg BENIGN (nur Erfolg wenn KEINE Error-Marker — echte CRC/Korruption korrekt als Fehler); #11 resume-empty-output NOT-CONFIRMED (compound, unbewiesene Hybrid-Collect-Ordering-Annahme); #13 = PP-1.

Runde 6 (Retry/Backoff/Error-Klassifikations-State-Machine + Disk/IO) — Workflow wqurq83ma

3 Finder + adversarisch verifizieren. 1 confirmed (2/3), 3 refuted. Schliesst den deferred-LOW-Cluster ab.

  • CONFIRMED HIGH (GEFIXT) SHELVE-LOOP-RETRYLIMIT: Bei FINITEM retryLimit>=5 sind alle drei Per-Klasse- Caps = retryLimit; die 15-Failure-Shelve-Zweige (dl-mgr 9166 stall + 9352 error) feuern aber auf hartkodiertem sum>=15 OBERHALB der Per-Klasse-Terminal-Fails und HALBIEREN danach alle Counter → Per-Klasse-Caps werden nie gleichzeitig ueberschritten → Item failt NIE, schleift ewig, item.retries waechst ueber das konfigurierte Limit, Slot gestrandet, providerFailures.delete besiegt wiederholt den Circuit-Breaker → Hoster-Hammering. resetStaleRetryState rettet nicht (<=90s-Re-Admit haelt updatedAt frisch < 10min-Stale). Default retryLimit=0=∞ NICHT betroffen (Shelve ist dort der gewollte Park-Backstop). Fix: in BEIDEN Shelve-Zweigen vor dem queueRetry if (configuredRetryLimit > 0 && item.retries >= configuredRetryLimit) → terminal failen statt requeue (∞-Modus unberuehrt). Rot-bewiesen (Single-Pass- Integrationstest: genericErrorRetries=15 vorgeseedet + injizierter Generic-Error → status "failed" statt requeue). tsc=6.
  • Deferred-LOW-Cluster re-klassifiziert (aus Runden 1-2): #10 HTTP416-shared-counter BENIGN (maxHttp416Retries eigenes Budget, speist Shelve-Summe NICHT); #11 fresh-retry-preempt BENIGN (One-Shot-Booleans); STALL-CAP-OFF-BY-ONE real aber +1 (Zutat von CONFIRMED-1, kein eigener Strand); #13 queue-wait→elapsedMs BENIGN (queueRetry resettet attempts/updatedAt, Stall-Detektor misst nur aktiven Download). #12 = der gefixte Bug. DISK-1 (ENOSPC/EACCES via Generic-Budget) kein eigener Bug (in finite vom Cap + diesem Fix begrenzt; in ∞ by-design) → optionale Klassifikations-Erweiterung, deferred bis Nutzer Full-Disk-Hammering meldet.

Runde 5 (unberuehrte Subsysteme: auto-reconnect, Scheduler-Fairness, Crash/Persistenz) — Workflow w7woztsxx

3 Finder (reconnect / scheduler / persistence) → adversarisch verifizieren (3 Lenses). 1 Kandidat, 0 confirmed. Sauberes „kein bestaetigter Bug"-Ergebnis. Auto-reconnect-Resume, Slot-Accounting/Fairness und Crash-Recovery/targetPath-Lifecycle sind solide (jeder Park/Slot hat Auto-Clear, stop/reset/abort drainen Waiter + nullen Counter).

  • DOKUMENTIERT, nicht gefixt (LOW, benign): PP-SEM-1 Post-Process-Semaphore (acquire/releasePostProcessSlot, ~7269-7304). Mechanismus real: ein geweckter Waiter, dem ein Fast-Path-Queue-Jumper im Microtask-Gap den Slot klaut, laeuft trotzdem (Re-Check nach next.resolve() nicht autoritativ) und released spaeter einen nie inkrementierten Slot → packagePostProcessActive UNTER-zaehlt um 1/Vorkommen. Wirkung: Ueber-Admission (mehr als maxParallelExtract parallele Extraktionen) = gebundene CPU/IO-Verschwendung, NIE Strand/Loss/ Korruption. Der einzige Strand-Pfad (<=0-Guard skippt Waiter-Wake) war NICHT organisch erreichbar (nur durch manuelles Nullen des Counters). Self-heilt bei jedem stop/reset/drain. Fix bekannt (Re-Check autoritativ machen ODER Increment in den Releaser ziehen) + rot-testbar, aber benign → kein Live-Server- Hotfix wert (LOW-Fix-Schwelle: Wirkung ist Verschwendung, keine Korrektheit).

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.

Batch 2b → noch nicht released (buendeln, dann v1.7.216)

  • #R2-1/4 HIGH Pre-alloc-stat-Reconciliation blaeht written auf Padding-Groesse auf → stille Null-Byte-Korruption auf win32. reconcileFinalizedSize() (download-completion.ts, rein+getestet), nur noch ABWAERTS-Korrektur bei preAllocated. Commit 2646cba.
  • #R2-3 HIGH Nicht-Archiv-".001" ohne Signatur wurde als extrahiert gezaehlt → ganze .00x-Familie beim Cleanup geloescht (Datenverlust). skippedNonArchives (pathSetKey) aus cleanupSources gefiltert, frisch + resume. End-to-end-Test. Commit 56bae4a.
  • #R2-9 MED + #R2-14 LOW Settings-async-Writer ohne Generations-Schutz → Lost Update; shutdown rief cancelPendingAsyncSaves nicht. Eigener syncSettingsSaveGeneration (Spiegel des Session-Pfads) + cancel in shutdown. Commit 1a33fc2.
  • #R2-6 MED Teildatei verwaist beim Entfernen eines laufenden Downloads (catch-early-return vor Cancel-Cleanup). rmSync im catch vor dem return (nach Stream-Close, kein Race). Commit 2b639b7.
  • #R2-8 MED Hash-Manifest: Pro-Zeile-Algorithmus von Dateiendung ueberschrieben → gute Datei geloescht bei fehl-etikettiertem Manifest. parseHashLine-Algorithmus uebernehmen. Commit 4578991.
  • #R2-7 MED Startup-Dedup ersetzt gute kanonische Datei durch kleineres Duplikat (+ EXDEV-Loss- Fenster). Size-Guard (kanonisch >= Duplikat → behalten) + rename-zu-.dedupbak-Reihenfolge mit Restore. Commit folgt nach voller DM-Suite.
  • [deferred/dokumentiert] #R2-5 stream-end akzeptiert truncated download (ohne Laengensignal nicht entscheidbar; Web ist post-214 nur Fallback) — nur WARN-Log sinnvoll, kein sicherer Fix.
  • [deferred/dokumentiert] #R2-10 CRC-verifizierte Kleindatei vom suspicious-small-Heuristik geloescht; #R2-11 Resume-empty-output-Bypass; #R2-12 7z-Exit-1-Warnung als Erfolg; #R2-13 Companion-.srt/.nfo- Overwrite. Je narrow/heuristisch → charakterisiert, nicht blind gefixt (LIVE-Server-Schwelle).

Batch 2 (commit, noch nicht released — buendeln mit Runde-2-Findings)

  • #6 MED onefichier/ddownload-catch respektiert autoProviderFallback=off (Guard nach abort-rethrow). Test: 1fichier KO + Fallback aus → reject, mega getLink NICHT aufgerufen (rot-ohne-Fix beweisbar). ACHTUNG-Notiz: replace_all matchte faelschlich auch den getLinkInfos-Filename-catch (~3614) → revertet (Filename-Aufloesung muss nicht-fatal bleiben). Nur die zwei Hoster-catch-Bloecke geaendert. Commit 21fb09b.
  • [deferred LOW, dokumentiert statt blind-fix] #9 overwrite targetPath-wipe, #10 HTTP416 shared counter, #11 fresh-retry preempt typed handlers, #12 shelve+shared counter, #13 queue-wait→elapsedMs, #5 Web-bad-creds. → je nur fixen wenn rot-ohne-Fix billig beweisbar + null Regression; sonst bleibt's charakterisiert.