test(terminal): pin the spawn watchdog against main's real daemon timeouts

The budget test imported the startup gate but hand-copied the daemon client's
connect and request timeouts, because those were module-private. Raising
REQUEST_TIMEOUT_MS in main would then leave the watchdog silently short and the
test still green — the drift it exists to catch.

Move the three to an import-free module both sides can read, and note in each
pinned file that it is typechecked under the web config so it stays that way.
This commit is contained in:
Merge Sim
2026-09-07 12:32:40 -07:00
parent 60c4daff14
commit b437e185e6
5 changed files with 17 additions and 9 deletions
+1
View File
@@ -38,6 +38,7 @@
"../src/main/persistence/applying-settings/ui-selection-normalization.ts",
"../src/main/persistence/applying-settings/ui-interaction-merge.ts",
"../src/main/protected-secret-persistence.ts",
"../src/main/daemon/rpc-timeouts.ts",
"../src/main/startup/first-window-startup-services.ts",
"../src/main/startup/serve-desktop-activation.ts",
"../src/main/startup/serve-mode-argv.ts",
+1 -3
View File
@@ -2,6 +2,7 @@ import type { Socket } from 'node:net'
import { readFileSync } from 'node:fs'
import { randomUUID } from 'node:crypto'
import { encodeNdjson } from './ndjson'
import { CONNECTION_ATTEMPT_WAIT_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS } from './rpc-timeouts'
import {
PROTOCOL_VERSION,
NOTIFY_PREFIX,
@@ -25,9 +26,6 @@ import {
import { writeNotifyWithSettlement } from './daemon-client-notify-settlement'
import { requestDaemonRpc } from './daemon-client-rpc-request'
const CONNECT_TIMEOUT_MS = 5000
const CONNECTION_ATTEMPT_WAIT_MS = CONNECT_TIMEOUT_MS * 4
const REQUEST_TIMEOUT_MS = 30000
const NOTIFY_SETTLEMENT_TIMEOUT_MS = 5000
export type DaemonClientOptions = {
+6
View File
@@ -0,0 +1,6 @@
// Why these live apart from the client: the renderer's spawn-settlement watchdog must
// outlast them, and its budget test imports them from here to prove it still does. That
// test typechecks under the web config, so this file must stay import-free.
export const CONNECT_TIMEOUT_MS = 5000
export const CONNECTION_ATTEMPT_WAIT_MS = CONNECT_TIMEOUT_MS * 4
export const REQUEST_TIMEOUT_MS = 30000
@@ -22,6 +22,9 @@ export const FIRST_WINDOW_STARTUP_SERVICE_TIMEOUT_MS = 12_000
// them lose their daemon sessions permanently (#5232). The PTY gate therefore
// waits for the daemon attempt itself and only fail-opens at a hard cap that
// exists solely as a deadlock backstop.
// The renderer's spawn-settlement watchdog must outlast this, and its budget test
// imports it from here — so this file is typechecked under the web config too and
// must stay import-free.
export const LOCAL_PTY_STARTUP_FAIL_OPEN_TIMEOUT_MS = 60_000
function startService(
@@ -1,5 +1,9 @@
import { describe, expect, it } from 'vitest'
import { LOCAL_PTY_STARTUP_FAIL_OPEN_TIMEOUT_MS } from '../../../../../main/startup/first-window-startup-services'
import {
CONNECTION_ATTEMPT_WAIT_MS,
REQUEST_TIMEOUT_MS
} from '../../../../../main/daemon/rpc-timeouts'
import {
REMOTE_RUNTIME_SPAWN_SETTLEMENT_WATCHDOG_MS,
SPAWN_SETTLEMENT_WATCHDOG_MS
@@ -13,12 +17,8 @@ import { REMOTE_RUNTIME_AUTO_RECOVERY_TIMEOUT_MS } from '../remote-runtime-pty-r
describe('spawn settlement watchdog budget', () => {
// Sequential, not overlapping: pty:spawn awaits the startup gate, and only then
// does the daemon client spend its connection-attempt wait plus one request timeout.
const DAEMON_CONNECTION_ATTEMPT_WAIT_MS = 5_000 * 4
const DAEMON_REQUEST_TIMEOUT_MS = 30_000
const worstLegitimateLocalSettleMs =
LOCAL_PTY_STARTUP_FAIL_OPEN_TIMEOUT_MS +
DAEMON_CONNECTION_ATTEMPT_WAIT_MS +
DAEMON_REQUEST_TIMEOUT_MS
LOCAL_PTY_STARTUP_FAIL_OPEN_TIMEOUT_MS + CONNECTION_ATTEMPT_WAIT_MS + REQUEST_TIMEOUT_MS
it('outlasts the slowest settle a local cold start can legitimately take', () => {
expect(SPAWN_SETTLEMENT_WATCHDOG_MS).toBeGreaterThan(worstLegitimateLocalSettleMs)
@@ -26,7 +26,7 @@ describe('spawn settlement watchdog budget', () => {
it('keeps real headroom over that worst case rather than racing it', () => {
expect(SPAWN_SETTLEMENT_WATCHDOG_MS - worstLegitimateLocalSettleMs).toBeGreaterThanOrEqual(
DAEMON_REQUEST_TIMEOUT_MS
REQUEST_TIMEOUT_MS
)
})