fix(desktop): log the latched-failure refusal once in the supervisor, not per request
799a4cc7f2 put a rememberLog before each of the three latched-failure throws in runHermesStart (main.ts:13257/13262/13270). That path is not rare while a failure is latched: ensureBackend() calls startHermes() for every proxied primary API request, and the renderer's boot retries (BOOT_RETRY_MAX_ATTEMPTS=5) hit it too. Each hit pushed an identical timestamped line into the 300-line hermesLog ring and the disk flush buffer, evicting the lines that explain the original failure -- the same eviction 3f9380daba was fixing. Remove the per-request lines (runHermesStart's short-circuit is as cheap and silent as on base, WHY comments kept) and log the refusal once at the only new consumer that needs the reason: the terminal-latch early return in runPrimaryRecoverySpawn, which runs once per refused respawn. Both sites now go through latchedBootFailure() (ordered bootstrapFailure -> backendStartFailure -> remoteReauthFailure, same order as before) so the trio can no longer drift between them. Proof: tsc (tsconfig.electron.json) and eslint clean; vitest 25/25 (backend-start-failure + backend-exit-recovery). Per-request path: the only rememberLog left in runHermesStart before the E2E block is the pre-existing non-primary-instance line (awk over the function body); `grep -c 'latched; refusing restart'` = 0. Helper probe: (null,null,null)->null, (B,S,R)->B, (null,S,R)->S, (null,null,R)->R.
This commit is contained in:
@@ -13186,7 +13186,11 @@ function runPrimaryRecoverySpawn(code: number | null, signal: string | null) {
|
||||
// Terminal boot failures still own their existing recovery UI. Only a
|
||||
// supervisor-owned respawn that failed transiently before ready may spend
|
||||
// another bounded recovery slot.
|
||||
if (bootstrapFailure || backendStartFailure || remoteReauthFailure) {
|
||||
const latched = latchedBootFailure()
|
||||
|
||||
if (latched) {
|
||||
rememberLog(`[supervisor] respawn refused: boot failure latched: ${firstLine(latched.message)}`)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -13232,6 +13236,17 @@ function scheduleUnexpectedPrimaryRecovery({
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* The terminal boot failure currently latched in this process, if any. These
|
||||
* latches are cleared only by an explicit recovery path (reset, repair,
|
||||
* apply-config, confirmed sign-in, or the child 'exit' handler), never by a
|
||||
* retry, so both the per-request short-circuit in runHermesStart and the
|
||||
* supervisor's respawn refusal must consult the same trio in the same order.
|
||||
*/
|
||||
function latchedBootFailure(): Error | null {
|
||||
return bootstrapFailure ?? backendStartFailure ?? remoteReauthFailure ?? null
|
||||
}
|
||||
|
||||
async function runHermesStart({ supervisorRecovery = false }: { supervisorRecovery?: boolean } = {}) {
|
||||
// Only the single-instance lock holder may reap/spawn/claim the desktop
|
||||
// backend. A lock-losing instance must stay inert even if some path reaches
|
||||
@@ -13253,22 +13268,19 @@ async function runHermesStart({ supervisorRecovery = false }: { supervisorRecove
|
||||
// ensureGatewayOpen retries (and any other getConnection callers) from
|
||||
// restarting a 5-10 minute install loop while the user is still reading
|
||||
// the failure overlay.
|
||||
if (bootstrapFailure) {
|
||||
rememberLog(`[boot] bootstrap failure latched; refusing restart: ${firstLine(bootstrapFailure.message)}`)
|
||||
throw bootstrapFailure
|
||||
}
|
||||
//
|
||||
// A confirmed remote reauth rejection is likewise terminal until the user
|
||||
// signs in. Short-circuiting here keeps the boot-failure overlay latched and
|
||||
// its "Sign in" button clickable, instead of re-driving boot on every retry.
|
||||
//
|
||||
// Deliberately silent: this runs on every proxied request while a failure is
|
||||
// latched (ensureBackend -> startHermes), so a log line here would flood the
|
||||
// bounded rememberLog ring and evict the lines that explain the original
|
||||
// failure. The supervisor logs the refusal once in runPrimaryRecoverySpawn.
|
||||
const latched = latchedBootFailure()
|
||||
|
||||
if (backendStartFailure) {
|
||||
rememberLog(`[boot] backend start failure latched; refusing restart: ${firstLine(backendStartFailure.message)}`)
|
||||
throw backendStartFailure
|
||||
}
|
||||
|
||||
// A confirmed remote reauth rejection is terminal until the user signs in.
|
||||
// Short-circuiting here keeps the boot-failure overlay latched and its
|
||||
// "Sign in" button clickable, instead of re-driving boot on every retry.
|
||||
if (remoteReauthFailure) {
|
||||
rememberLog(`[boot] remote reauth failure latched; refusing restart: ${firstLine(remoteReauthFailure.message)}`)
|
||||
throw remoteReauthFailure
|
||||
if (latched) {
|
||||
throw latched
|
||||
}
|
||||
|
||||
// E2E: simulate a boot failure without breaking the real backend. The boot
|
||||
|
||||
Reference in New Issue
Block a user