# Execution log: e2e test — OTel tracing against real Tempo Plan: `docs/plans/2026-08-24-1224-tracing-e2e.md` - [x] Step 1 — `test/e2e/tracing_test.go` - [x] Step 2 — Makefile - [x] Step 3 — Docs ## Steps 1–3 — spec, Makefile, docs (one commit) The three steps landed together — the spec is one new file and the other two are its wiring. `Describe("OTel tracing", Ordered)` is fully self-contained (own ns create → `make install`/`make deploy` → teardown) because Ginkgo randomizes top-level container order, so it cannot share the Manager Describe's deployment. It reuses the package-level `namespace` / `managerImage` and the suite's idioms (`utils.Run`, curl-pod with the restricted-PSS overrides JSON, log-substring `Eventually`s). Judgment calls beyond the plan's letter: - The squid pre-pull (`docker pull` + `kind load`) is **best effort** — a missing docker binary logs a note and continues rather than failing the spec; the 5m Ready timeout still covers an in-cluster pull. - The OTLP preflight pod prints per-attempt HTTP codes and a final `OTLP_OK`/`OTLP_UNREACHABLE` marker; the assertion quotes the pod's output, so an unreachable endpoint names itself in the failure. - `kubectl set env` is passed the literal `OTEL_RESOURCE_ATTRIBUTES=...$(POD_NAME)...` string via `exec.Command` — no shell involved, kubectl stores `$()` verbatim, and the in-place update keeps the var after the downward-API vars it references. - Tempo helpers are stdlib-only; `/api/traces/` is decoded as OTLP-JSON (`batches[].scopeSpans[].spans[].name`), which is Tempo's actual shape (not Jaeger's). Verified so far: `go vet -tags=e2e ./...` clean. The live run against Tempo (`TEMPO_URL=http://192.168.0.30:3200 OTLP_ENDPOINT=http://192.168.0.30:4318 make test-e2e`) is recorded below once it has been executed.