Audit finding. checkForUpdate → upd.Apply → quitForRestart (main.go:393-417, :279-285) takes no mu; only checkNativeUpdate TryLocks. A concurrent start() legitimately holds mu mid-Up for up to ~2 minutes (app health budget) when the 20s-delayed update check fires on a stale launcher. The handover then exits the process between gateway-up and app-spawn: bifrost is recorded-and-alive with no app, the relaunched binary can't adopt (not healthy) and Up refuses ('the previous bifrost is still running — stop it first') — honest, but demands a manual Stop+Start right after an update; in the narrower spawn-to-record window it orphans unrecorded.
Fix: take mu (blocking) around Apply + quitForRestart so a handover waits for an in-flight Up/Down.
Status (re-triaged 2026-08-28)
Still valid: checkForUpdate takes checkMu only; upd.Apply and quitForRestart() run without mu, while checkNativeUpdate, installUpdate, and start all TryLock it. Self-contained; document the mu/checkMu ordering to avoid a deadlock.
Done means: A self-update handover fired mid-start() waits for Up to finish before the launcher exits.
Audit finding.
checkForUpdate→upd.Apply→quitForRestart(main.go:393-417, :279-285) takes nomu; only checkNativeUpdate TryLocks. A concurrentstart()legitimately holds mu mid-Up for up to ~2 minutes (app health budget) when the 20s-delayed update check fires on a stale launcher. The handover then exits the process between gateway-up and app-spawn: bifrost is recorded-and-alive with no app, the relaunched binary can't adopt (not healthy) and Up refuses ('the previous bifrost is still running — stop it first') — honest, but demands a manual Stop+Start right after an update; in the narrower spawn-to-record window it orphans unrecorded.Fix: take
mu(blocking) around Apply + quitForRestart so a handover waits for an in-flight Up/Down.Status (re-triaged 2026-08-28)
Still valid:
checkForUpdatetakescheckMuonly;upd.ApplyandquitForRestart()run withoutmu, whilecheckNativeUpdate,installUpdate, andstartall TryLock it. Self-contained; document themu/checkMuordering to avoid a deadlock.Done means: A self-update handover fired mid-
start()waits for Up to finish before the launcher exits.