# ASG Floor Lock Detected

> An Auto Scaling Group whose MinSize equals its DesiredCapacity, both above 1, can never shed capacity. The floor blocks every scale-in. ZopNight flags these only when a scaling policy exists and a measured idle window backs a schedule, pricing the saving as monthly cost times the measured idle fraction.

Source: https://zop.dev/integrations/aws/recommendations/asg-floor-lock-detected
Updated: 2026-08-19

---

## Why a floor lock wastes money quietly

When MinSize and DesiredCapacity are set to the same number (say both at 4), the
group's scale-in policy has nowhere to go. Demand drops at night, the policy tries to
remove an instance, and the floor refuses. The group holds peak capacity 24/7 while
looking, on a dashboard, like autoscaling is working. Nothing errors. Every pinned
instance keeps [billing at its full on-demand hourly rate](https://aws.amazon.com/ec2/pricing/), so the bill just never
goes down.

The usual origin is a load test or an incident: someone raises MinSize to force
capacity, the incident ends, and the setting stays.

## The four gates, in order

1. The group is floor-locked: MinSize equals DesiredCapacity and both are greater than 1.
2. The group has at least one scaling policy. Lowering MinSize on a group with zero
   policies is inert: nothing would scale it in anyway, so that case abstains
   (it belongs to a different rule).
3. A real monthly cost figure exists for the group. No price, no finding.
4. The usage heatmap shows a measured off-hours idle fraction greater than zero.

Miss any gate and the rule says nothing.

## Check a group yourself

```bash
aws autoscaling describe-auto-scaling-groups \
  --query 'AutoScalingGroups[?MinSize==DesiredCapacity && MinSize>`1`].[AutoScalingGroupName,MinSize,DesiredCapacity]' \
  --output table
```

Then confirm each listed group actually has a scale-in policy:

```bash
aws autoscaling describe-policies \
  --auto-scaling-group-name my-asg \
  --query 'ScalingPolicies[].[PolicyName,PolicyType]'
```

## What the number means

The saving is monthly cost multiplied by the measured idle percentage from the
heatmap, the fraction of the week the group demonstrably sits idle. It is never a
flat assumed percentage. The lever is a recurring schedule that lowers MinSize during
that window so the existing policy can scale in, then restores it before demand
returns. It is not a stop, and not a deletion. The group keeps serving through the
whole cycle.

## Where it deliberately stays silent

- Groups with no scaling policies, where lowering the floor changes nothing.
- Groups without pricing data, since the rule never reports an unpriced saving.
- Groups with no measured idle window. A floor-locked group that is busy around the
  clock is correctly pinned, and flagging it would be noise.
