An availability target's configured poll interval only seeded the
adaptive scheduler: BuildPlan derived every instance's cadence from the
global adaptive bounds, and a failing probe raised the staleness score
and error penalty, collapsing the probe interval toward the global
5-second minimum. With interval 120s and failure threshold 4 the alert
was promised after ~8 minutes of downtime but fired within the first
minute because the four consecutive failures accumulated at the
collapsed cadence (#1582).
Availability checks promise pollInterval x failureThreshold as the
detection window, so the cadence is a user contract, not a scheduling
hint. Add a FixedIntervalPollProvider extension that pins an instance
to its configured interval, implement it for availability targets, and
bypass adaptive selection wherever the next run is computed (plan
building, rescheduling, and the non-adaptive fallback paths).
46 test cases covering:
- clampFloat helper (9 cases: range checks, boundary conditions)
- Staleness score impact (5 cases: 0/0.25/0.5/0.75/1 scores)
- Error penalty (5 cases: 0 to 10 errors, min clamping)
- Queue depth stretching (5 cases: 1 to 50 depth, max clamping)
- EMA smoothing (convergence behavior with alpha=0.6)
- Jitter (bounds checking, deterministic tests with seeded RNG)
- Boundary conditions (6 cases: zero/negative intervals, max<min)
- Combined factors (3 cases: all factors interacting)
- State persistence (per-instance EMA state isolation)
First unit test file for scheduler.go (previously only had integration tests).