v0.8.3 — daemon CPU: pegged core → near-idle
The performance release. Two rounds of live profiling (#598, #619) eliminated every daemon hot path — each fix verified by before/after measurement on a production 18-repo deployment. Behavior-preserving; no defaults change.
Round 1 (#615): bounded worker-tick retry scans (indexed candidate queries instead of 36 full jobs-table scans + ~1.3 GB JSON parsed per sweep); dispatcher no longer busy-spins on a busy runtime session (was 36 re-dispatches/s, writing runtime_lock_wait events that had grown to 56% of job_events); escalation auto-finalize is candidate-driven.
Round 2 (#620): per-tick candidate queries run once per tick, not once per repo (was 18× ≈ 71% of all daemon reads; errors deliberately not memoized to keep fault isolation); covering index job_events(kind,job_id,id) + drop of the redundant single-column index; PR poll path fetches only review jobs, once per poll (was a full 40 MB payload scan up to 2× per open PR); partial-index + ORDER BY hygiene for queued/running scans, plan-asserted against the production SQL.
Also: merge-gate no-CI race closed with a grace window (#614); setTaskState branch-unique crash fix + doctor --json (#580); dashboard galaxy polish (#610, #613, #616, #618).
Upgrading: drop-in; two append-only schema migrations run on first start (covering-index build may take a few seconds on a large job_events table). Operators with long-lived DBs can reclaim more headroom by pruning historical advance_retry/runtime_lock_wait events.
Full notes: https://gitmoot.io/docs/release-notes/v0.8.3