Skip to content

fix(cli-updates): an update that cannot start says so and stays dismissable - #1447

Merged
Juliusolsson05 merged 5 commits into
integration/batch-2026-09-27-pfrom
fix/cli-update-could-not-start
Sep 27, 2026
Merged

Juliusolsson05 merged 5 commits into
integration/batch-2026-09-27-pfrom
fix/cli-update-could-not-start

Conversation

@Juliusolsson05

@Juliusolsson05 Juliusolsson05 commented Sep 27, 2026 •

Copy link
Copy Markdown
Owner

Fixes #1425 (found by #1423's review b). Refs #1250.

What was wrong

  • CliUpdateOrchestrator.runUpdate publishes updating, which the banner marks undismissable. It then awaited openLog's mkdir outside any catch. A data folder the app can't write (EACCES) or a full disk (ENOSPC) rejected there, and the row said "Updating…" forever.
  • The banner's Update Now / Update now actions were void window.api.cliUpdatesUpdateNow(cli), so the IPC rejection was dropped and nothing was said.

Fix

  • failed.logPath is now string | null, and CliUpdateFailureReason adds 'could-not-start'.
  • runUpdate catches openLog, warns the cause in main's log only (q22), and publishes failed { reason: 'could-not-start', logPath: null } without running the command.
    • Ruling: no update without a log. A full or unwritable disk makes a package install likely to fail too, and a log-less failure leaves nothing to look at.
    • openLog was the one throw that could strand the state: appendLog and appendDiagnostics catch, and readInstalledVersion returns a result.
  • openLog CREATES the attempt's log file (wx) before anything runs (round 1, a+b). A folder that exists but will not take a new file (EACCES, ENOSPC) is could-not-start too; it used to run the update with no log and a View Log pointing at nothing.
  • updateSnapshot commits the state and then contains a throwing publication (round 1, a). A window torn down mid-send used to abort runUpdate right after updating and strand it.
  • cli-updates:open-log opens nothing for a failure with no log.
  • Banner:

Tests (fail-first)

  • cliUpdateOrchestrator.couldNotStart.test.ts: the real orchestrator with mkdir rejecting EACCES at the fs boundary. The states go updating → failed {could-not-start, logPath: null}, the command is never run, and the OS text is not in the state. On main, updateOnce rejects with the EACCES and the state stays updating.
  • CliUpdateBanner.renderer.test.tsx:
    • the could-not-start row: its sentence, no View Log, Update now calls the IPC, and it is dismissable;
    • per-attempt dismiss keys;
    • a rejected Update now request shows the fixed sentence (no IPC text) on the notify and the deferral rows.
  • cliUpdates.test.ts: open-log for a null logPath answers false without shell.openPath.
  • Round 1 adds these fail-first tests:
    • a log file that cannot be created is could-not-start and the command never runs;
    • a state listener that throws does not strand updating;
    • a rejected retry on the could-not-start row is said;
    • a successful Update now says nothing;
    • the could-not-start hint is fixed copy.
  • Mutations caught: restoring the void action (3 cases red); per-version keys for could-not-start (1 red); a success reported as failure (1 red).
  • npx tsc -b clean. The CLI update suites pass 28/28 across 6 files at 50761ac (count corrected per verification a).

Boundary

The app is not launched. The read-only data folder is simulated at the fs boundary.

🤖 Generated with Claude Code

Juliusolsson05 and others added 2 commits September 27, 2026 08:20
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t, and Update now says a rejected request (#1425)

runUpdate caught nothing after publishing the undismissable 'updating':
openLog's mkdir (EACCES/ENOSPC) stranded it forever. It now publishes
failed { reason: 'could-not-start', logPath: null } without running the
command. The banner says so in fixed words with Update now as the retry
(keyed per attempt), open-log opens nothing for it, and every Update now
action awaits its IPC and shows 'Couldn't start the update. Try again.'
on rejection instead of dropping it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Juliusolsson05 Juliusolsson05 added type:bug Something works wrong class:C3-silent-failure The app knows it failed and does not say sev:P3 Minor labels Sep 27, 2026
Juliusolsson05 and others added 3 commits September 27, 2026 10:54
…ation strand updating (#1447 review a)

openLog now creates the attempt's log file (flag wx): a folder that exists
but will not take a file (EACCES, ENOSPC) used to let the update run with no
log and a View Log pointing nowhere; it is could-not-start now. updateSnapshot
contains a throwing publication (a window torn down mid-send), which used to
abort runUpdate right after 'updating' and strand it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…too (#1447 review b)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…art hint copy (#1447 review c)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Juliusolsson05

Copy link
Copy Markdown
Owner Author

Round-1 disposition. a and b were FIX-BEFORE-MERGE, with the same major finding, and c was MERGE-READY on the fixed head. Everything is fixed fail-first.

  • a and b (major): a log FILE that cannot be created still ran the update. Fixed in d9b18e9. openLog creates the file (wx) up front. EACCES or ENOSPC on the file now counts as could-not-start, and the command never runs. Pinned (it was red before).
  • a (major): a throwing state publication stranded updating. Fixed in d9b18e9. updateSnapshot commits the state, then contains the emit. It is pinned with a listener that throws on updating.
  • b (surviving mutation): the could-not-start retry's rejection text. Pinned in 0e32433.
  • c (minor): the success half of Update now, and the hint copy (q22). Both pinned in 50761ac; the success-as-failure mutation is red.
  • c (minor): the body was stale. It now describes the log creation, the contained publication and the round-1 tests.
  • Immaterial per c, unchanged: the console.warn in the publication catch is diagnostic only, and the wx vs w difference is unreachable (per-CLI mutex, multi-second commands).
  • Checks: npx tsc -b clean; the CLI update suites pass.

Head: 50761ac.

🤖 Generated with Claude Code

@Juliusolsson05
Juliusolsson05 changed the base branch from main to integration/batch-2026-09-27-p September 27, 2026 20:36
@Juliusolsson05
Juliusolsson05 merged commit 64f0565 into integration/batch-2026-09-27-p Sep 27, 2026
2 checks passed
@Juliusolsson05
Juliusolsson05 deleted the fix/cli-update-could-not-start branch September 27, 2026 20:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

class:C3-silent-failure The app knows it failed and does not say sev:P3 Minor type:bug Something works wrong

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(cli-updates): Update Now that cannot start leaves an undismissable 'Updating' row

1 participant