Summary
The visibility-based desync recovery dispatches CustomEvents that nobody listens to, so when the WebSocket drops during job completion the UI stays stuck on "Batch in Progress" until the page is reloaded.
Where
src/web/static/js/utils/lifecycle-manager.js:228,240 (checkStateConsistency dispatches new CustomEvent('translationUpdate', …) and new CustomEvent('resetUIToIdle') on window)
- The real handler is
TranslationTracker.handleTranslationUpdate, wired only to the socket event translation_update — not to a window translationUpdate event.
Details
checkStateConsistency() runs every 10 s and on tab re-focus. It correctly detects that the server finished/errored a job while the UI still thinks it's running, then fires window CustomEvents — but a repo-wide grep confirms zero listeners for translationUpdate or resetUIToIdle. So the recovery logs "state desync — syncing" and then does nothing.
Impact
A user whose WebSocket dropped during completion keeps a stuck "Batch in Progress" UI (Translate button disabled) until they reload.
Suggested fix
Call the real handlers directly from checkStateConsistency — TranslationTracker.handleTranslationUpdate(payload) and the actual idle-reset routine — instead of dispatching events with no subscribers. (See the related issue about lifecycle state being smeared across four modules.)
Found during the June 2026 repo audit. Severity: high. Confidence: certain.
Summary
The visibility-based desync recovery dispatches
CustomEvents that nobody listens to, so when the WebSocket drops during job completion the UI stays stuck on "Batch in Progress" until the page is reloaded.Where
src/web/static/js/utils/lifecycle-manager.js:228,240(checkStateConsistencydispatchesnew CustomEvent('translationUpdate', …)andnew CustomEvent('resetUIToIdle')onwindow)TranslationTracker.handleTranslationUpdate, wired only to the socket eventtranslation_update— not to a windowtranslationUpdateevent.Details
checkStateConsistency()runs every 10 s and on tab re-focus. It correctly detects that the server finished/errored a job while the UI still thinks it's running, then fires window CustomEvents — but a repo-wide grep confirms zero listeners fortranslationUpdateorresetUIToIdle. So the recovery logs "state desync — syncing" and then does nothing.Impact
A user whose WebSocket dropped during completion keeps a stuck "Batch in Progress" UI (Translate button disabled) until they reload.
Suggested fix
Call the real handlers directly from
checkStateConsistency—TranslationTracker.handleTranslationUpdate(payload)and the actual idle-reset routine — instead of dispatching events with no subscribers. (See the related issue about lifecycle state being smeared across four modules.)Found during the June 2026 repo audit. Severity: high. Confidence: certain.