Cron locks were CRONS_TMP_PATH . md5(generateUniqueCode(live_streaming_pass)
. class), so rotating the viewer-token secret (the cluster plan rotates it
at cutover and again at lockdown) renamed every lock and let a second
instance of each cron start beside one still running.
ProcessManager::cronLockPath() names the lock from the class alone; CronTrait,
RootSignalsCronJob and server:diagnose use it. For the upgrade itself,
exitIfCronLockHeld() honours a live, fresh lock under the previous name, so
an instance started by the old release is not doubled.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Es8UhyPS8MNjuYTagqfGWi