Commit Graph

3 Commits

Author SHA1 Message Date
Sucukdeluxe
1a33fc2573 Fix: Einstellungen gehen nicht mehr durch zeitgleiches Speichern verloren (Lost Update)
Der asynchrone Settings-Writer hatte — anders als der Session-Writer — keinen
Generations-Schutz. Lief eine periodische async Settings-Speicherung gerade,
während gleichzeitig synchron saveSettings() lief (z.B. Nutzer ändert eine
Option, oder ein Settings-Backup wird wiederhergestellt), konnte der async
rename die frisch synchron geschriebene Datei wieder mit dem ALTEN Stand
überschreiben. Die gerade gespeicherte Änderung war damit auf der Platte (und im
.bak) verloren — bis zur nächsten Speicherung.

Fix: Der Settings-Pfad spiegelt jetzt exakt den bereits abgesicherten
Session-Pfad:
- Eigener Generations-Zähler syncSettingsSaveGeneration; saveSettings() (sync)
  erhöht ihn.
- writeSettingsPayload bekommt die zum Zeitpunkt des Aufrufs erfasste Generation
  und bricht vor rename UND vor dem EXDEV-Copy ab, wenn inzwischen eine
  synchrone Speicherung passiert ist (generation < aktuell).
- saveSettingsAsync/saveSettingsPayloadAsync trägt die ORIGINAL-Generation auch
  durch die Warteschlange (vorher wurde beim Abarbeiten der Queue eine frische
  Generation erfasst → hätte den Schutz ausgehebelt).
- Eigener Zähler statt Wiederverwendung von syncSaveGeneration, damit eine
  synchrone Settings-Speicherung keine laufenden async SESSION-Schreibvorgänge
  fälschlich verwirft (keine Datei-übergreifende Kopplung).

Zusätzlich (verwandt): shutdown() ruft jetzt cancelPendingAsyncSaves() vor der
finalen synchronen Speicherung auf, damit eine noch laufende/eingereihte async
Settings-Schreibung den Shutdown-Save nicht mehr überholen kann.

Test: in-flight + eingereihte async Settings-Speicherung (ALT), dann synchron
NEU — nach dem Settle steht NEU auf der Platte. Ohne den Generations-Schutz
gewinnt ALT (rot bewiesen).
2026-06-17 04:57:23 +02:00
Sucukdeluxe
3ed3877ac9 chore: remove all source code comments and internal artifacts
Strip every comment from the source (parsed with the TypeScript compiler so
strings, template literals, regex literals and JSX are never touched), and drop
internal/working artifacts that do not belong in the public repository
(design mockups, internal analysis docs, a stray backup file and an old log).
No functional change: build is green, the full test suite passes.
2026-06-06 04:53:54 +02:00
Sucukdeluxe
8d03ca124f Update-Neustart: laufende Downloads als queued parken statt als "Gestoppt" haengenzubleiben
Beim Update parkte installUpdate() aktive Downloads via stop() -> deren Abbruch-
Continuation markierte die Items "cancelled"/"Gestoppt". autoResumeOnStart nimmt
nach dem Neustart aber nur "queued"/"reconnect_wait" auf, also liefen die gerade
ladenden Downloads nach dem Update nicht weiter (timing-abhaengig: "manchmal").
Jetzt: stop({parkForRestart:true}) bricht aktive Tasks mit Grund "shutdown" ab,
sodass sie als "queued" re-queued werden (wie bei normalem App-Shutdown). Das
schliesst zugleich den einzigen plausiblen Loesch-Pfad (all-cancelled-Pakete sind
ueber applyRetroactiveCleanupPolicy entfernbar). Stop-Button-Verhalten unveraendert.

Zusaetzliche Robustheit in storage.ts (enge Blast-Radien, nicht die Hauptursache):
- async-Save-Clobber: eine gequeuete, veraltete Payload konnte einen neueren
  Sync-Save (persistNowSync/prepareForShutdown) ueberschreiben; Generation wird
  jetzt zum Snapshot-Zeitpunkt erfasst und durch die Queue getragen.
- loadSession gab leer zurueck (und ignorierte ein gefuelltes .bak), wenn die
  Primaerdatei fehlte; faellt jetzt auf die Backup/Temp-Recovery zurueck.

Regressionstests: tests/update-restart-resume.test.ts (echter Live-Download ->
Park -> Reload = queued, plus Charakterisierung plain stop() -> cancelled) und
tests/session-restart-loss.test.ts (Clobber + Backup-Fallback). Volle Suite gruen.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 05:19:54 +02:00