---
id: w3/m4/t003
title: "Source selection: prefer Prometheus when BEX_PROM_URL is set, fall back to metrics-server"
worker: worker3
status: done
estimate: 30m
depends_on: [w3/m4/t002]
---

## Objective

Wire the new source into bex-api startup: when `BEX_PROM_URL` is set, resource metrics come from `NewPrometheusResourceSource` (history); otherwise today's metrics-server snapshot path stays, and a missing source still yields 503 (`ErrMetricsUnavailable`) — no behavior regression for clusters without Prometheus.

## Context

- Wiring lives in `operator/cmd/api/main.go` (~lines 75–80): `ResourceMetrics: api.NewResourceMetricsSource(cs)` unconditionally; `RequestMetrics` already gated on `BEX_PROM_URL`.
- The 503 semantics for unwired sources are established in `operator/internal/api/metrics.go` — keep them.
- `docs/ADR010-observability.md` documents "snapshot resolution" as a known deviation; the env-var table in `CLAUDE.md` already lists `BEX_PROM_URL`, whose meaning now widens to resource metrics too.

## Steps

1. In `main.go`, when `BEX_PROM_URL` is set, assign the Prometheus resource source; else keep `NewResourceMetricsSource(cs)`.
2. Decide and encode the degraded case: Prometheus set but unreachable at query time → surface the source error (same contract as request metrics today).
3. Update the `BEX_PROM_URL` row in `CLAUDE.md`'s env table to mention resource-metrics history.

## Files

- `operator/cmd/api/main.go`
- `CLAUDE.md` (env var table row)

## Acceptance criteria

- [ ] With `BEX_PROM_URL` set, `/v1/metrics/cpu` returns multi-point series; unset, it returns the single-point metrics-server snapshot exactly as before.
- [ ] With neither source available, the endpoint still returns 503.
- [ ] `make test` green.

## Out of scope

- Live-cluster verification and docs rewrite (t004).
