Skip to content

Close two holes left by the update-install bypass - #118

Merged
alpha5611331 merged 1 commit into
mainfrom
fix/save-prompt-review-2
Aug 28, 2026
Merged

Close two holes left by the update-install bypass#118
alpha5611331 merged 1 commit into
mainfrom
fix/save-prompt-review-2

Conversation

@alpha5611331

Copy link
Copy Markdown
Member

Follow-up to #115/#117 after a second review pass on main post-merge.

Guard never re-armed after a failed install

autoUpdaterService.quitAndInstall() reports whether it started an install (true/false), but electron-updater's own quitAndInstall(false, true) says nothing when the install itself fails downstream - it simply does not quit. The handler was returning success: true for "started" regardless, so allowNextClose() stayed set with nothing ever putting it back.

Concretely: update downloads, user clicks Restart, the install fails for any reason (disk permissions, AV interference, whatever), the app is still running - and now sits there with the close guard permanently disarmed. The next Clear or Start still asks, but the window closes without a word, silently dropping whatever interview follows.

rearmCloseGuardIfStillRunning() schedules a check 5s out and puts the guard back unless before-quit fired in that window. Keyed on the quitting flag rather than a window count, since re-arming a quit that legitimately started would veto the close it had just approved.

UpdateNotification was subscribed to app state for no reason

It read hasHistory through useSaveHistoryGuard, which subscribes to the full app-state broadcast - during an interview, a new object several times a second (every ASR partial, every streamed token). That re-rendered UpdateNotification on the same cadence, which re-ran its status effect and its lastStatusRef bookkeeping constantly, for a flag it only needs once, on a button click that happens at most a few times per app lifetime.

Now reads hasHistory via electron.appState.get() at the moment the Restart/Open Installer button is clicked - which is also where the flag is derived, rather than a broadcast tick behind.

Checks

pnpm lint, both tsc configs, pnpm build, pnpm test:main pass locally. test/save-history.test.mjs gains source-level checks for the re-arm path and for UpdateNotification no longer importing useSaveHistoryGuard.

🤖 Generated with Claude Code

`quitAndInstall` reports nothing when an install fails - it just does not
quit - and the handler was reporting success either way, so one failed
update left `closeConfirmed` set for the rest of the session and the next
close took the interview with it silently. That is the failure the guard
exists to stop, so `rearmCloseGuardIfStillRunning()` puts it back unless
`before-quit` has fired. Keyed on `quitting` rather than a window count:
re-arming a quit that is under way would veto the close it just approved.

And `UpdateNotification` was reading `hasHistory` through
`useSaveHistoryGuard`, which subscribes to the app state - a new object
several times a second during an interview. The component re-rendered and
re-armed its status effect on every ASR partial to answer a question it
only asks on a click. It reads the flag over `appState.get()` at that
click instead, which is also where the flag is derived rather than one
broadcast behind.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@gitar-bot

gitar-bot Bot commented Aug 28, 2026

Copy link
Copy Markdown

Important

You are using the Gitar free plan. Upgrade to unlock code review, CI analysis, auto-apply, custom automations, and more.

Gitar

@alpha5611331
alpha5611331 merged commit 4c4af78 into main Aug 28, 2026
2 checks passed
@alpha5611331
alpha5611331 deleted the fix/save-prompt-review-2 branch August 28, 2026 05:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant