# Normalize OOM control-plane selector

## Background

The OOM dashboard and older saved links can send `seed/{provider}-{region}`, while the backend cache and canonical O11Y identity use `seed/{provider}-{region}/seed`. The legacy control-plane proxy performs an exact cache lookup and returns a successful empty Prometheus matrix when the two-part selector is not found.

## Goal and target contract

- Normalize only the supported two-part logical seed selector to its canonical three-part form.
- Resolve explicit control-plane selectors through the canonical O11Y resolver and use `InternalReadUri`.
- Preserve valid three-part selectors and the no-selector legacy fallback.
- Return 400 for malformed explicit selectors, 404 for a valid missing seed, and 5xx for metadata/upstream failures.
- Avoid global cache aliases that could collide across Dedicated and NextGen seed records.

## Affected modules and route

- Root Go module: `pkg/o11y/urls`, `pkg/proxy`, and `pkg/api/datasource`.
- Customer-facing route: `/data/control_plane/metrics`, including selector extraction from headers and PromQL.
- Executable/image/CD component: `cmd/server`, `clinic`, Clinic CD `components=clinic`.
- app-delivery application/workload: `clinic-api` / Clinic Deployment.

## Implementation

1. Add strict logical selector normalization in the canonical URL resolver.
2. Keep Dedicated-seed-first and NextGen-seed-on-`ErrNotFound` lookup order.
3. Add a control-plane proxy entrypoint that detects explicit selectors, resolves them canonically, maps error classes, and proxies by internal-read target.
4. Route `/data/control_plane/metrics` through that entrypoint; keep the legacy path only when no selector is present.
5. Add safe trace-aware lifecycle logs and regression tests for header/PromQL selectors, malformed forms, missing records, metadata failures, and existing three-part behavior.

## Compatibility and exclusions

- No UI change is required; old and saved two-part selectors become compatible server-side.
- No public DTO or successful Prometheus response shape changes.
- Explicit invalid selectors intentionally stop returning misleading HTTP 200 empty matrices.
- Existing cache keys and unrelated metric routes are unchanged.

## Validation and release boundary

- Run focused resolver, proxy, datasource API, and `cmd/server` tests, formatting, and `git diff --check`.
- In staging deploy `components=clinic`, verify old two-part OOM links, three-part links, error status mapping, image/Pod state, and trace-correlated logs.
- Keep the branch uncommitted, unpushed, and undeployed pending review.
