ADR-0017: Request ID and trace context strategy (Phase 1)
Architecture decision record 0017.
ADR-0017: Request ID and trace context strategy (Phase 1)
- Status: Accepted
- Date: 2026-06-07
- Authors: IBEX Harness team
Context
M1.2.3 introduced RequestContextMiddleware, response headers (X-Request-ID, X-Trace-ID, X-Response-Time), and an error envelope with a request_id field. Generated IDs used UUID v4 and inbound header values were accepted without validation (garbage strings could propagate).
ARCHITECTURE.md requires request_id in every structured log line so auth gRPC calls, rate limit checks, and handlers can be correlated. M1.3.1 adds OTel distributed tracing; request ID must be established first as the internal correlation token.
Decision
1) UUID v7 for generated request IDs
New request IDs use UUID v7 (RFC 9562) via github.com/google/uuid v1.6.0+:
- First 48 bits encode millisecond timestamp — IDs are time-ordered in logs
- Falls back to UUID v4 if v7 generation fails
Inbound X-Request-ID (or IBEX_REQUEST_ID_HEADER) is honoured when it parses as a valid UUID (v4 or v7). Invalid values are discarded and a fresh v7 ID is generated.
2) Shared package packages/reqid
Request ID generation, validation, and context propagation live in packages/reqid:
New()— generate v7 (v4 fallback)ResolveInbound(raw)— honour valid UUID or generateWithRequestID/FromContext/MustFromContext- Constants:
Header(X-Request-ID),GRPCMetadataKey(x-request-id)
Proxy internal/http thin-wraps context helpers; it does not maintain a separate context key.
3) HTTP middleware (no duplicate middleware)
M1.2.3 RequestContextMiddleware in services/proxy/internal/http/middleware.go is refactored, not replaced:
- Request ID:
reqid.ResolveInbound+reqid.WithRequestID - Trace ID: unchanged (UUID v4 synthetic until M1.3.1 OTel)
ResponseHeadersMiddlewareunchanged — sets configurable request ID header on every response
Outer chain order unchanged:
metrics → requestContext → responseHeaders → logging → muxProtected route order unchanged per ADR-0016.
4) gRPC propagation to auth
Proxy auth gRPC client connection uses a unary client interceptor that appends x-request-id from Go context to outgoing metadata on every call (ValidateToken, ValidateAgent).
Bearer token metadata remains in individual verifiers; the interceptor only adds request ID.
Auth service may log the metadata key in M1.3.3 (shared logger); no auth-side changes in this ADR.
5) Relationship to OTel trace ID
| Token | Purpose | Phase 1 source |
|---|---|---|
| Request ID | Internal log correlation; error envelope; response header | packages/reqid / middleware |
Trace ID (X-Trace-ID) | Placeholder until OTel | Synthetic UUID v4 in middleware |
| OTel trace ID | Distributed tracing span | M1.3.1 — W3C traceparent |
They coexist. Request ID appears in all log lines; OTel trace ID replaces synthetic trace ID when the tracer is active (M1.3.1).
6) Error envelope
All proxy JSON error responses populate error.request_id from reqid.FromContext (via RequestIDFromContext wrapper). Value matches the X-Request-ID response header.
Consequences
Positive
- Time-ordered request IDs improve log search and debugging
- Untrusted inbound IDs cannot inject arbitrary strings
- Single shared package for future services (auth HTTP, dashboard API)
- Auth gRPC calls correlate with proxy logs via metadata
Negative
- Existing deployments relying on non-UUID inbound request IDs will receive fresh generated IDs instead
References
- Milestone 1.2.6
- ADR-0013 (amended §7)
- ADR-0016
- Milestone 1.3.1
Was this page helpful?
Last updated on