Reproduce the exact decision the HorizontalPodAutoscaler controller makes each control-loop tick — desiredReplicas = ceil(currentReplicas × currentValue / targetValue), guarded by the --horizontal-pod-autoscaler-tolerance band, minReplicas / maxReplicas clamps, and the v2 behavior.scaleUp / scaleDown stabilization windows and per-policy rate limits (Pods or Percent per periodSeconds). Paste a load timeline — the tool ticks through every 15-second sync and shows the replica count evolve.
A policy of 0 is treated as "no limit for this policy". When both a Pods and a Percent policy are set, selectPolicy=Max (the default for scale-up) picks the larger permitted change and Min picks the smaller (the default for scale-down, so a single fat pod won't allow a big drop).
current / target.|ratio − 1| ≤ tolerance (default 0.10), do nothing.desired = ceil(current × ratio).[minReplicas, maxReplicas].scaleUp.stabilizationWindowSeconds of desireds (min), scale-down uses the max. Then apply per-policy rate caps (Pods and Percent), pick according to selectPolicy.desiredReplicas; the deployment does the rest.Defaults: sync period 15 s, tolerance 0.10, scale-up unlimited + 0 s stabilization, scale-down 100%/60 s + 300 s stabilization. Kubernetes 1.29+ can tune tolerance per-HPA via spec.behavior.scaleUp.tolerance.