Folge-Fund zu 18eada9 (Opus-Verifikation des deferFreshFiles-Konzepts):
18eada9 schloss den "frische Datei landet mit Original-Scene-Namen in der
Library"-Bug nur fuer den Hybrid-Pfad (deferFreshFiles=true + Mehrfach-Paesse).
Der finale Deferred-Pass blieb betroffen.
Root Cause (verifiziert via failing Test gegen HEAD):
- runDeferredPostExtraction macht Rename -> Collect (deferFreshFiles=false). Ist
eine Datei beim Deferred-Rename noch "frisch" (juenger als fileStabilizeMinAgeMs,
prod=2000ms) -- v.a. eine eben per Nested-Extraction geschriebene Datei --
ueberspringt der Frische-Gate sie, und der Collect moved sie mit Original-
Scene-Namen in die Library. collectMkvFilesToLibrary benennt selbst nicht um
(buildUniqueFlattenTargetPath, nur Flatten).
- Im Deferred-FINAL-Pass gibt es keinen concurrent Extractor-Write mehr
(Extraktion inkl. Nested ist awaited) -- der Frische-Gate ist dort ein False
Positive. Pre-existierender Gap (Frische-Skip aelter als 18eada9), auch
v1.7.162 betroffen.
Fix (minimal): treatFilesAsStable-Param durch autoRenameExtractedVideoFiles(Impl).
Der Deferred-Final-Pass ruft mit treatFilesAsStable=true -> Frische-Gate umgangen
-> alle Dateien werden umbenannt, bevor der Collect sie sammelt. Hybrid-Pfad
unangetastet (nutzt ...Impl mit Default false -> Frische-Skip bleibt aktiv).
Regressionstest: frische Datei im Deferred-Pass landet UMBENANNT in der Library.
623 Tests gruen, tsc unveraendert (9 pre-existing).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Problem: nach importBackup hielt der Manager weiter die STALE In-Memory-Session
(Import schrieb nur auf Disk). blockAllPersistence wurde gesetzt um Überschreiben
zu verhindern, aber nie zurückgesetzt → ignorierte der User die manuelle
"Bitte neustarten"-Aufforderung und arbeitete weiter, ging bei hartem Crash
alles verloren (stille Persistenz-Blockade).
In-Memory-Reload verworfen: aborted activeTasks settlen ASYNC und greifen in
ihren finally-Blöcken auf this.session.items[id] zu — ein Session-Swap würde
dagegen racen. Sicherer Reload bräuchte async-Refactor (alle Tasks awaiten).
Lösung: Auto-Relaunch. Nach restored===true startet main.ts die App automatisch
neu (1.5s Delay für Toast). Der frische Prozess lädt die restored Session sauber
über den bewährten Startup-Pfad — null Stale-State-Risiko. Main-getrieben (nicht
Renderer), damit ein Renderer-Fehler den Restart nicht verhindern kann.
skipShutdownPersist/blockAllPersistence schützen weiterhin das kurze Fenster +
den Quit (prepareForShutdown:5680 überspringt Persistenz sauber, fasst die stale
Session nicht an). Nach Relaunch: frischer Prozess, Flags zurückgesetzt — Footgun weg.
621 Tests grün, tsc-Fehlerzahl unverändert (9 pre-existing).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Aus der Bug-Analyse (3 Subagents): die Deferred-Post-Processing-Pipeline war
nur halb ins Abbruch-/Lifecycle-Management integriert — gleiche Ecke wie der
v1.7.156-Datenverlust.
H1: abortPostProcessing (globaler Stop/Shutdown/clearAll/external) bricht jetzt
auch packageDeferredPostProcessAbortControllers + die neue Hybrid-Map ab.
Vorher rasten MKV-Move/Cleanup/Rename gegen den synchronen Shutdown-Save.
H2: Hybrid-Post-Extract (Rename+MKV-Collect) lief als komplett ungetracktes
detached Promise. Jetzt in packageHybridPostProcessControllers (Set/Package)
registriert — SYNCHRON vor dem Promise, mit shouldAbort an beide Aufrufe.
Bewusst SEPARAT von der Deferred-Map, sonst würde runDeferredPostExtraction's
replace-Logik die laufende Hybrid-Arbeit selbst killen (Advisor-Fund).
Cancel/Reset/Stop stoppt jetzt laufende Hybrid-Verschiebungen.
M1: hasAnyDeferredPostProcessPending() — Scheduler-Abschluss + finishRun-Clear
gaten darauf. Run endet/Summary feuert nicht mehr während im Hintergrund
noch Dateien verschoben werden; Run-State wird nicht mehr mittendrin geleert.
H3: validateDownloadedFileCompletion akzeptierte 0-Byte bei source=stream-end
(kein Content-Length, keine Provider-Größe) als "fertig". Jetzt ok:false
-> bestehender download_underflow-Retry-Pfad. Verhindert leere Datei = komplett.
N1: toter (unerreichbarer) Disk-Fallback-Block in findReadyArchiveSets +
verwaiste pendingItemStatus-Map entfernt (verhaltensneutral).
Bewusst übersprungen: M2 (blockAllPersistence — vorgeschlagener Reset wäre
unsicher, In-Memory-Session ist nach Import stale) und M3 (cancelPendingAsyncSaves
— Generation-Guard schützt Korrektheit bereits). Siehe tasks/todo.md.
8 neue Tests (tests/download-completion.test.ts) inkl. H3-Regression. 621 Tests grün.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>