# CAPACITY-PLANNER KNOWLEDGE BASE

## OVERVIEW

`capacity-planner` is a standalone controller-runtime module for dataplane autoscaling. It provides the Autoscaler API, metrics collection, policy evaluation, and Kubernetes target execution.

The reconciler skips deleting or `DISABLED` Autoscalers. `AUTO` and `DRY_RUN` query decision metrics and choose a tier and replica count once target Pod samples are complete. `DRY_RUN` logs the recommendation; `AUTO` applies it to the referenced target through the executor. The reconciler does not write Autoscaler status. See `pkg/controller/autoscaler_reconciler.go` for the current mode handling.

-> Parent service map: [`../AGENTS.md`](../AGENTS.md)

## STRUCTURE

- `cmd/main.go`: manager bootstrap, runtime config wiring, health and readiness probes.
- `pkg/config/`: strict unified runtime configuration; tier templates remain a separate file.
- `api/v1alpha1/`: Autoscaler API types and generated deepcopy code.
- `pkg/controller/`: Autoscaler reconciler wiring and behavior.
- `pkg/recorder/`: decision schema, data projection, and hourly JSONL persistence.
- `pkg/metrics/`: decision metric Provider contract and data model.
- `pkg/prom/`: embedded Prometheus TSDB, fixed scraper manager, scraper implementations, independent recording-rule evaluator, and PromQL query implementations.
- `pkg/runtime/metrics/`: capacity planner self-metrics collectors.
- `pkg/policy/`, `pkg/replicas/`, `pkg/tier/`: autoscaling policy, replica, and tier helpers.
- `pkg/executor/`: applies tier patches and replica counts to Kubernetes targets.
- `pkg/webhook/`: typed Autoscaler admission validator; compiled and tested, but not served.
- `config/crd/bases/`: generated CRD manifests.
- `charts/capacity-planner/`: self-contained Helm chart and synchronized Autoscaler CRD.
- `hack/`: local verification scripts for Helm, image, and Kind install smoke tests.

## WHERE TO LOOK

| Task | Location | Notes |
|------|----------|-------|
| Manager startup or runtime config | `cmd/main.go`, `pkg/config/` | Keep defaults side-effect free unless rollout wiring changes. |
| API or schema changes | `api/v1alpha1/` | Regenerate CRDs/deepcopy after type edits. |
| Reconcile behavior | `pkg/controller/` | Mode handling, metric completeness, policy evaluation, and execution. |
| Decision records | `pkg/recorder/` | Schema, record projection, file layout, and closed-file discovery. |
| Admission validation | `pkg/webhook/` | Validator exists, webhook serving is not wired. |
| Decision metric contracts | `pkg/metrics/` | Keep runtime self-metrics separate. |
| Prometheus decision metric implementation | `pkg/prom/` | TSDB, scraper, and restricted PromQL engine. |
| Capacity Planner self-metrics | `pkg/runtime/metrics/` | Do not mix with autoscaling decision metrics. |
| Helm deployment | `charts/capacity-planner/`, `hack/verify-helm.sh` | Keep the chart self-contained and its CRD synchronized. |
| Replica/tier/policy calculations | `pkg/replicas/`, `pkg/tier/`, `pkg/policy/` | Prefer focused table tests. |
| Image verification | `Dockerfile`, `hack/verify-image.sh` | Build/smoke only; never push. |
| Install smoke | `hack/verify-install.sh` | Ephemeral Kind only; not a production install path. |

## COMMANDS

```bash
make build
make lint
make test
make verify
make generate
make deploy
make testdeploy
make test/e2e
make dockerbuild
make test/container
make test/install
```

## LOCAL GUARDRAILS

- Keep autoscaling side effects explicit. Do not add metric reads, TiDBGroup mutations, status writes, webhook serving, or deployment wiring without focused tests and matching design intent.
- Do not hand-edit generated files such as `api/v1alpha1/zz_generated.deepcopy.go` or `config/crd/bases/*.yaml`; change source types and regenerate.
- Keep `pkg/runtime/metrics` for the capacity planner's own Prometheus metrics, `pkg/metrics` for the decision Provider contract, and `pkg/prom` for its Prometheus-backed implementation.
- Keep manager defaults safe for local and test runs: metrics disabled unless TLS/authn/authz is accounted for, and leader election opt-in outside Helm.
- `make dockerbuild/capacity-planner` and `make test/container` build and smoke local images only. They must not push images, log into registries, or depend on external clusters.
- `make test/install` must remain an isolated Kind smoke test with unique temporary names and cleanup. It must not touch user clusters or long-lived namespaces.

## GO CODING PRINCIPLES

- Prefer passing structs by pointer, especially Kubernetes objects, controller state, options/config structs, and other non-trivial values. This keeps copies low and preserves mutation semantics. Keep small scalar values and clearly immutable tiny structs by value when that matches local style.
- Avoid broad defensive programming in trusted internal code. Do not sprinkle `nil` checks everywhere just because a value could theoretically be nil; encode invariants through constructors, typed fields, clear function contracts, and tests.
- Do `nil` checks at trust or ownership boundaries where absence is part of the API contract: external input, unmarshaled optional fields, third-party/client returns, map initialization before mutation, and values not created or validated by the current path.
- If a function's inputs come entirely from trusted internal code, its callers should guarantee correctness; if inputs involve API objects, config, CRDs, webhooks, files, or other user-controlled data, validate them at the first parse or admission boundary.
- Check `err` before using companion return values from `(value, error)` APIs instead of separately defending every returned pointer.
- Make pointer optionality meaningful. If a field must always exist, prefer a value type or constructor-initialized pointer; if a pointer means optional data, handle that optionality once near the boundary.
- Prefer invariant-driven code over defensive clutter: validate inputs at boundaries, make invalid states hard to represent, and keep internal paths concise once their preconditions are established.
