Review R8 D3. A verified `held` verdict (the update exited, a process it
started still holds the checkout lock) used to stop blocking after 7200 s and
let the local backend start while that process could still be writing the
install. The gate now never opens on its own while an update hold lasts.
- update-marker-gate.ts: no held ceiling. Each blocking state carries a stable
hold id (sha256 of the marker body) and `blocking` (held/busy/error, not a
live pid). `allowStartOverHold(id)` is the only way through while the hold
lasts, scoped to that exact marker body and process-wide (pool waits honour
it; a new body blocks again). `requestHoldRecheck()` makes every probe
re-ask the script helper on its next poll. The marker is never touched.
- main.ts: past a 5 s grace the boot shows the blocked screen (boot progress
`updateHold`): what holds the install, since when, last check. IPC from the
primary window only: recheck, quit, and start-anyway, which needs
`confirmed: true` and the hold id on screen, logs a USER OVERRIDE line and
flushes desktop.log. The non-blocking "started anyway" dialog is gone. Pool
waits log the hold once and wait for it to end or the primary's override.
- Renderer: UpdateHoldOverlay with Check again, Quit Hermes, Open logs and a
two-step Start anyway (confirmation copy says what can break). en/de/fr/es.
Tests: the ceiling cells are replaced by two invariants (held stays closed 10x
past the old ceiling and Retry re-asks at once; a confirmed Start anyway opens
only its hold, for every wait, and a new body blocks again). Both RED on
8855353024e, GREEN here. A real-process probe (SIGKILLed UpdateLock updater,
custody child holding the real checkout flock, real posix.sh) with the clock
jumped 3 h: the old gate opens, this one stays closed until Start anyway.
(cherry picked from commit 324a489259ab90e1f7158dcc2fa7d1c8a2da20f8)