---
id: w1/m1/t001
title: Drop the Reconcile early-return so desired state always applies
worker: worker1
status: done
estimate: 25m
depends_on: []
---

## Objective

The operator early-returns when `Status.ObservedGeneration == Generation && Phase == Running`, so operator-level config changes never reach already-running Apps (flipping `BEX_CLUSTER_ISSUER` staging→prod did not re-point beancount's Ingress until nudged by hand). Make reconcile idempotently apply desired state on every pass.

## Context

- `operator/internal/controller/app_controller.go` — the `ObservedGeneration == Generation && Running` return.
- Deployment/Service/Ingress are already built with `controllerutil.CreateOrUpdate` (idempotent), so re-running them every pass is safe.
- History: memory `bex-hetzner-first-deploy` (gotcha #3).

## Steps

1. Remove/narrow the early-return so `CreateOrUpdate` for Deployment/Service/Ingress runs every reconcile.
2. Keep the expensive build path gated on an actual spec/revision change.

## Files

- `operator/internal/controller/app_controller.go`

## Acceptance criteria

- [ ] Changing `BEX_CLUSTER_ISSUER` + restarting the operator re-points a running App's Ingress annotation with no manual `kubectl`.
- [ ] `go vet ./...` / `make build` green; no rebuild triggered when only status changed.

## Out of scope

- Startup requeue-all (t002).
