# RCU Scale-Down: High-RU Skip Guard

## Purpose

Stop the RCU spec scale-down cron (`RcuScaleDownJob`) from downgrading
components whose max RU is very large. Above a fixed RU threshold the
job leaves the component alone.

## Scope

Applies only to the **RCU-based spec downgrade** path
(`domain/app/cron/rcu_scale_down.go`), for the whitelist components in
`server.GetRcuScaleComponents()`. Does not touch scale-up, HPA,
NodeCount, or disk.

## Problem

With an unlimited top tier (`Max: 0`, the prod default), *any* RU
resolves to the highest configured tier's spec. A component manually
provisioned above that spec (e.g. TiKV at `32c` when config tops out at
`16c`) satisfies `needsDowngrade` and gets clobbered back down. RCU
scale-down must not undo a deliberate high-end provision.

## Rule

> If the max RU used to drive the decision is **greater than the
> configured `rcuScaleDownMaxRu` (default 50000)**, skip the component —
> do not add it to the downgrade batch.

- Shared-pool-scoped components compare against the pool aggregate
  `poolMaxRu`.
- Per-cluster-scoped components compare against that cluster's
  `clusterMaxRu`.

The threshold is a config field. Everything below it keeps the existing
`needsDowngrade` + `ScaleOverride` behavior unchanged.

## Where It Lives

- Config: `config.CronJobConfig.RcuScaleDownMaxRu`
  (`yaml:"rcuScaleDownMaxRu" default:"50000"`), passed into
  `NewRcuScaleDownJob` and stored on the job.
- `domain/app/cron/rcu_scale_down.go`:
  - `DefaultRcuScaleDownMaxRuThreshold uint32 = 50000` — fallback used
    by `(*RcuScaleDownJob).effectiveMaxRuThreshold()` when the configured value is 0.
  - early `return` in `collectSharedPoolDowngrades` when
    `poolMaxRu > j.effectiveMaxRuThreshold()`
  - early `return` in `checkAndAppendDowngrade` when `ru > j.effectiveMaxRuThreshold()`

## Observability

New outcome value on the existing counter plus a stable `Info` log:

```
AutoscaleRcuScaleDownTotal{shared_pool_id, scope, component_type, result="skip_high_ru"}
```

## Test Expectations

In `rcu_scale_down_test.go`:

1. `poolMaxRu` above threshold → shared-pool component skipped
   (empty batch), even though `needsDowngrade` would otherwise fire.
2. `clusterMaxRu` above threshold → per-cluster component skipped.
3. RU at/below threshold → existing downgrade behavior unchanged.

## Rollout

Behavioral tightening of a cron; no schema/proto/API change. Gated by
the existing `enableScaleSharedPoolByRu` / `enableScaleTidbGroupByRu`
flags.
