diff --git a/docs/IMPROVEMENT_LOG.md b/docs/IMPROVEMENT_LOG.md index 19bc6c9..2d6f323 100644 --- a/docs/IMPROVEMENT_LOG.md +++ b/docs/IMPROVEMENT_LOG.md @@ -2,6 +2,37 @@ Dated entries from improvement cycles. Newest at top. +## 2026-05-03 — Cycle 4: GQL retry + VOD sort + shutdown consolidation + +Three independent improvements landed this cycle. + +### 1. Public Twitch GQL fallback retries on transient failures (defensive error handling) + +- **File**: `src/main.ts` — new `isTransientAxiosError` + retry loop in `fetchPublicTwitchGql`. +- **Problem**: `fetchPublicTwitchGql` swallowed every network error with `catch (e) { console.error(...); return null; }`. The public-API fallback path is what users without a Twitch client_id/secret hit on every VOD list load — a single TCP RST or a transient `503` from `gql.twitch.tv` produced an empty list and the user had to click refresh. +- **Fix**: Up to 3 attempts with exponential backoff (`400ms × 2^(attempt-1)` + jitter, capped by attempt count). Retries cover transient HTTP (`408`, `429`, `5xx`) and pure network failures (no response). GraphQL errors in `errors[]` are still returned without retry — those are application-level rejections of the query itself. Recovery is logged via `appendDebugLog('public-gql-recovered', ...)` so we can later see in logs whether the retries actually pay off. + +### 2. VOD list sort dropdown with persistence (client feature: VM/state + UI + persistence) + +- **Files**: `src/renderer-streamers.ts`, `src/renderer.ts`, `src/renderer-texts.ts`, `src/index.html`, `src/renderer-locale-de.ts`, `src/renderer-locale-en.ts`. +- **Problem**: VODs always rendered in the order Twitch returned them (`sort:TIME` desc). With long archives users had no way to find the longest stream, the most-watched, or the oldest. +- **Fix**: `vodSortSelect` dropdown next to the filter input. Five sort modes: newest first, oldest first, most viewed, longest first, shortest first. State (`vodSortKey`) persisted to `localStorage` under `twitch-vod-manager:vod-sort` and validated against an enum on load — an unknown stored value falls back to `date_desc` so a future rename can't strand the user. `renderVodGridFromCurrentState` now applies `sortVods` before `filterVodsByQuery` so the filter sees the sort order and the match-counter is consistent. Sort labels and the "Sort:" prefix label are localized (DE + EN), and `refreshVodSortSelectLabels` re-runs on language switch so the option labels stay in the active language. Browser-default keyboard nav on the select (arrow keys, type-ahead) covers keyboard access. + +### 3. `shutdownCleanup()` consolidates `window-all-closed` + `before-quit` (cleanup of meaningful size) + +- **File**: `src/main.ts`. +- **Problem**: Both lifecycle handlers ran nearly identical cleanup blocks but had drifted: `window-all-closed` killed children and was platform-aware (`app.quit()` on non-darwin), `before-quit` only stopped timers and saved state. There was no single place to add a new "must run on exit" step — every future addition had to be pasted into both handlers and inevitably one would diverge. +- **Fix**: Single `shutdownCleanup(reason)` helper, gated by an idempotent `shutdownCleanupDone` flag so a `before-quit` immediately following a `window-all-closed` is a no-op. The helper kills `activeDownloads`, `activeClipProcesses`, and `currentEditorProcess` (with try/catch so an already-exited proc doesn't throw), persists config + queue, then stops timers. Debug-log flush is reordered to run AFTER `saveConfig` / `flushQueueSave` so any error in those persistence calls actually reaches the log file before the flush timer is gone. Both `app.on(...)` handlers shrank to one line each. + +### Regression + +- `npm run build` — clean (TypeScript strict, 0 errors). +- `npm run test:e2e:update-logic` — passed. +- `npm run test:merge-split` — passed. +- `npm run test:e2e` — passed (`issues: []`). +- `npm run test:e2e:guide` — passed (`failures: []`). +- `npm run test:e2e:full` — passed (`failures: []`, `runtimeIssues: []`). + ## 2026-05-03 — Cycle 3: clip hardening + VOD filter + cancel-cross-talk fix Three independent improvements landed this cycle. diff --git a/src/index.html b/src/index.html index e502863..2de1a02 100644 --- a/src/index.html +++ b/src/index.html @@ -239,9 +239,17 @@