diff --git a/cmd/validatord/main.go b/cmd/validatord/main.go index 6179a9c..a4264ba 100644 --- a/cmd/validatord/main.go +++ b/cmd/validatord/main.go @@ -244,15 +244,23 @@ func (h *handlers) handleIterate(w http.ResponseWriter, r *http.Request) { return } - // Pull the per-request trace id from the langfuse middleware. If - // the caller forwarded an upstream trace via X-Lakehouse-Trace-Id - // the middleware reuses that one; otherwise it minted a fresh trace - // at HTTP entry. When Langfuse isn't configured at all the - // middleware skips the mint, so we generate a fallback id locally — - // session_id MUST always be populated so the JSONL log + Langfuse - // (when later configured) can correlate by id across logs. - // Surfaced 2026-05-02 deploy: empty session_id breaks DuckDB - // joins on coordinator_sessions.jsonl ↔ replay_runs.jsonl. + // Resolve the parent trace id, in priority order: + // 1. req.TraceID (caller put it in the JSON body) + // 2. X-Lakehouse-Trace-Id header (read DIRECTLY here so the path + // works even when Langfuse is off and the middleware is a + // passthrough — matches Rust's iterate handler shape) + // 3. context value set by the langfuse middleware (when Langfuse + // is configured) + // 4. fallback to a locally-minted time-ordered hex id + // + // Surfaced 2026-05-02 cross-runtime test: Go was minting fallback + // even when caller forwarded the header, because middleware + // passthrough mode never read it. Reading the header here closes + // the gap and makes Go behavior match Rust regardless of + // Langfuse configuration. + if req.TraceID == "" { + req.TraceID = r.Header.Get(shared.TraceIDHeader) + } if req.TraceID == "" { req.TraceID = shared.TraceIDFromCtx(r.Context()) }