Address two issues raised during review:
P1 – When a recording is cancelled or restarted, setRecordingState(false)
enqueues its cursor batch but store-recorded-session is never called,
leaving a stale batch that contaminates the next recording's telemetry.
Add discardLatestPending() to the buffer and a discard-cursor-telemetry
IPC handler; the renderer now calls it on the discard path.
P2 – takeNextBatch() dequeued the batch before fs.writeFile, so a write
failure would permanently lose the telemetry. Wrap the write in
try/catch and re-insert the batch via prependBatch() on failure.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Previously, the main process kept two module-scope arrays —
activeCursorSamples and pendingCursorSamples — and set-recording-state
on a new recording wiped BOTH. When a user stopped recording and
immediately started a new one before store-recorded-session fired,
the previous recording's pending samples were discarded or later
overwritten with the new session's data, producing empty or mismatched
.cursor.json files.
Replace the two arrays with a small FIFO buffer
(createCursorTelemetryBuffer) that:
- Keeps pending batches per completed recording, never wiping them on
a new session start.
- Yields batches in arrival order to storeRecordedSessionFiles.
- Caps pending batches (default 8) so a never-stored sequence cannot
leak unbounded memory.
Unit-tested directly in src/lib/cursorTelemetryBuffer.test.ts, including
the rapid-restart race that motivated the change.
On Linux/Wayland the implicit GPU-to-2D texture-sharing path used by
drawImage(webglCanvas) fails silently (EGL/Ozone), producing green
frames. Use explicit gl.readPixels to copy from GPU to CPU memory,
bypassing that path.
- Replace useRef with useState for prefsHydrated to prevent race condition
- Wrap localStorage.getItem in try/catch in loadUserPreferences
- Validate aspectRatio against known valid values
- Include 'good' in exportQuality validation, 'mp4' in exportFormat validation
- Read currentTime directly from the video element instead of the React
ref so rapid arrow key presses each advance by exactly one frame
- Add JSDoc docstrings to frameStep.ts exports
- Add HTMLSelectElement and contentEditable to the arrow key input guard
to prevent intercepting native keyboard behavior on form controls
- Add i18nKey field to FixedShortcut interface and wire up i18n lookups
in ShortcutsConfigDialog and KeyboardShortcutsHelp so fixed shortcut
labels are properly localized