Resolved conflicts in src/App.tsx and src/components/launch/LaunchWindow.tsx:
- App.tsx: kept main's split useEffect for loadAllCustomFonts; placed PR's
HUD-overlay style block inside the original [windowType] effect.
- LaunchWindow.tsx: kept main's systemLocaleSuggestion modal in place of the
earlier inline language switcher; preserved PR's root-div className change
that fixes the Windows horizontal-scrollbar bug.
discardLatestPending() popped whichever batch happened to be at the
back of the queue. With a Stop → Record → Discard sequence, the
pending queue can have recording B's batch sitting in front of A's by
the time A's finalize callback resolves (because finalizeRecording
awaits fixWebmDuration), so the discard targets the wrong recording.
Tag each completed batch with the recording id supplied at
startSession() time and replace discardLatestPending() with
discardBatch(recordingId). takeNextBatch() now returns the full
{recordingId, samples} shape so prependBatch() can re-queue it on
write-failure without losing the id. The renderer already owns a
stable recordingId (Date.now() in useScreenRecorder) and the IPC
surface threads it through set-recording-state and
discard-cursor-telemetry.
Adds a regression test that mirrors FabLrc's scenario in PR #457:
two recordings finalize, A is discarded after B has already been
queued, and the buffer must drop A while keeping B intact.
Sandboxed preloads (Electron's default with contextIsolation) cannot
require node modules. Commit 702b733 added node:path / node:url imports
to preload.ts which fail at load time:
Unable to load preload script: dist-electron/preload.mjs
Error: module not found: node:path
This left window.electronAPI undefined, breaking every IPC call.
Compute the asset base URL in main process (windows.ts) and pass it
to preload via webPreferences.additionalArguments. Preload reads it
from process.argv. Sync API for renderer is preserved.
- Replace anonymous Error in resolveImageWallpaperUrl with typed
UnsafeImagePrefixError, mirroring UnsafeAssetPathError so cause
chains stay discriminable.
- Replace `(err as BackgroundLoadError).cause` casts in wallpaper
tests with instanceof narrowing (no `as` per project rules).
- Remove unused `WALLPAPER_PATHS` re-export from projectPersistence;
consumers import directly from @/lib/wallpaper (SSOT).
Reviewer audit found two real risks in the prior amendment:
1. LEGACY_FILE_WALLPAPER_RE was too permissive. Any file:// URL
containing /wallpapers/wallpaperN.jpg would match — including a user's
own file at /home/me/wallpapers/wallpaper1.jpg that happened to share
the name pattern. Silent data-loss potential: user's photo replaced
with a bundled asset. In-app upload flow uses data: URIs today so it
can't actually produce such a value, but the regex should be tight
on intent. Now requires a known install-layout segment:
resources/[assets/]wallpapers/ (packaged) or public/wallpapers/ (dev).
2. No upper bound on \d+. A corrupted or future-schema project with
wallpaper99.jpg was silently rewritten to /wallpapers/wallpaper99.jpg
which 404s. Now validates against WALLPAPER_PATHS; out-of-set
bundled-looking values fall back to DEFAULT_WALLPAPER.
Also applied R2.2 defensive guard: resolveImageWallpaperUrl's catch
block now checks instanceof BackgroundLoadError and rethrows unchanged
instead of wrapping a second time. Current getAssetPath cannot throw
BackgroundLoadError so this is a future-proof against refactors.
Tests: 56 pass (up from 54). Added coverage for "user file outside
install dir stays untouched" and "bundled-looking but out-of-set falls
back to default".