From 6847bbc180da3f88ad4ce30afcb61c212aa61869 Mon Sep 17 00:00:00 2001 From: root Date: Sat, 2 May 2026 06:16:25 -0500 Subject: [PATCH] validatord: honor X-Lakehouse-Trace-Id even when Langfuse is off MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Surfaced by the 2026-05-02 cross-runtime test: when a caller forwarded X-Lakehouse-Trace-Id but the langfuse middleware was a passthrough (no Langfuse env), the header was never read — Go minted a fallback id, breaking cross-daemon parent-trace linkage. The middleware only honored the header when its lf client was non-nil. With LANGFUSE_URL unset on the persistent stack, every inbound iterate request lost the parent linkage. Fix: validatord's iterate handler reads the header DIRECTLY (matches Rust's iterate.rs pattern) before falling through to the ctx value + fallback id. Now Go behavior matches Rust regardless of Langfuse configuration. Resolution order is: 1. req.TraceID (caller put it in the JSON body) 2. X-Lakehouse-Trace-Id header (read directly here) 3. context value from langfuse middleware (when configured) 4. fallback to a locally-minted time-ordered hex id Verified end-to-end: curl -H 'X-Lakehouse-Trace-Id: go-cmp-fixed' POST /v1/iterate → response.trace_id = "go-cmp-fixed" ✓ → sessions.jsonl row session_id = "go-cmp-fixed" ✓ Pre-fix (this commit's parent ran from /tmp/val-fresh3 binary): same call → trace_id minted as 18abbb5a008061b7-008061e9 (header silently ignored) Co-Authored-By: Claude Opus 4.7 (1M context) --- cmd/validatord/main.go | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) 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()) }