The cachedMaxConcurrent variable driving the AgentSemaphore was only
updated during unpause transitions and merge retry timers. Changing
maxConcurrent in the dashboard had no effect on the semaphore until one
of those events fired, causing fewer tasks to run than configured.
Also adds HeartbeatMonitor and HeartbeatTriggerScheduler wiring to both
serve and dashboard commands, with tests.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>