Problem
Distributed tracing has to be wired before the first feature ships, or instrumentation never gets retrofitted.
Proposed solution
Port src/observability/{logging.py, spans.py, tracing.py} from Teller. Tracing: OTel SDK + OTLP gRPC exporter pointed at OTEL_EXPORTER_OTLP_ENDPOINT (Jaeger via docker-compose). Logging: structured JSON logs correlated with active span ID. Span helpers: official OTel semantic-convention attribute names only (per feedback_otel_semconv memory). Wire FastAPI auto-instrumentation in src/api/main.py.
Acceptance criteria
Priority rationale
High: observability retrofitted is observability never done. Locks in correct tracing posture from day one.
Depends on
#17
Problem
Distributed tracing has to be wired before the first feature ships, or instrumentation never gets retrofitted.
Proposed solution
Port
src/observability/{logging.py, spans.py, tracing.py}from Teller. Tracing: OTel SDK + OTLP gRPC exporter pointed atOTEL_EXPORTER_OTLP_ENDPOINT(Jaeger via docker-compose). Logging: structured JSON logs correlated with active span ID. Span helpers: official OTel semantic-convention attribute names only (perfeedback_otel_semconvmemory). Wire FastAPI auto-instrumentation insrc/api/main.py.Acceptance criteria
/api/v1/healthproduces a span visible in Jaeger UI.trace_idandspan_idfields.tests/test_observability.pyasserts span creation and semconv attribute names.Priority rationale
High: observability retrofitted is observability never done. Locks in correct tracing posture from day one.
Depends on
#17