From 98b6647f2a9652a637db8eee19a2381c97d9674d Mon Sep 17 00:00:00 2001 From: root Date: Sat, 2 May 2026 06:24:41 -0500 Subject: [PATCH] gateway: IterateResponse echoes trace_id + enable session_log_path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes the 2026-05-02 cross-runtime parity gap: Go's validator.IterateResponse carried trace_id back to callers; Rust's didn't. A caller pivoting from response → Langfuse → session log worked on Go but failed on Rust because the join key wasn't visible in the response body. ## Changes crates/gateway/src/v1/iterate.rs: - IterateResponse + IterateFailure gain `trace_id: Option` (skip-serializing-if-none preserves backward-compat for any consumer parsing the response without the field) - Both return sites populated with the resolved trace_id lakehouse.toml: - [gateway].session_log_path set to /tmp/lakehouse-validator/sessions.jsonl — same path Go validatord writes to. The two daemons now co-write one unified longitudinal log; rows tag daemon="gateway" vs daemon="validatord" so producers stay distinguishable in DuckDB queries. Append-write is atomic at the row sizes both runtimes produce, so concurrent writes from both daemons are safe. ## Verification Post-restart of lakehouse.service: POST /v1/iterate with X-Lakehouse-Trace-Id: rust-fix1-test → response.trace_id = "rust-fix1-test" ✓ (was: field absent) → sessions.jsonl latest row daemon=gateway, session_id=rust-fix1-test ✓ (was: no row) Cross-runtime drive — same prompt to Rust :3100 and Go :4110: Rust: trace_id=unified-rust-001, daemon=gateway, accepted Go: trace_id=unified-go-001, daemon=validatord, accepted Same file, distinct daemons, one query covers both: SELECT daemon, COUNT(*) FROM read_json_auto('sessions.jsonl', format='nd') GROUP BY daemon → gateway: 2, validatord: 19 All 4 parity probes still 6/6 + 12/12 + 4/4 + 2/2 against live :3100 + :4110 stacks. Cargo test 4/4 PASS for v1::iterate module. ## Architecture invariant The "unified longitudinal log" thesis is now demonstrated. Operators running both runtimes in production point both daemons at the same session_log_path and DuckDB queries naturally span both producers. Co-Authored-By: Claude Opus 4.7 (1M context) --- crates/gateway/src/v1/iterate.rs | 12 ++++++++++++ lakehouse.toml | 10 +++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/crates/gateway/src/v1/iterate.rs b/crates/gateway/src/v1/iterate.rs index 38e6538..06872d7 100644 --- a/crates/gateway/src/v1/iterate.rs +++ b/crates/gateway/src/v1/iterate.rs @@ -87,6 +87,14 @@ pub struct IterateResponse { pub validation: serde_json::Value, pub iterations: u32, pub history: Vec, + /// Echoes the resolved trace id (caller-forwarded header, body + /// field, langfuse-middleware mint, or local fallback). Operators + /// pivot from this id straight into Langfuse + the + /// coordinator_sessions.jsonl join key. Cross-runtime parity with + /// Go's `validator.IterateResponse` (commit 6847bbc in + /// golangLAKEHOUSE). + #[serde(skip_serializing_if = "Option::is_none")] + pub trace_id: Option, } #[derive(Serialize)] @@ -94,6 +102,8 @@ pub struct IterateFailure { pub error: String, pub iterations: u32, pub history: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + pub trace_id: Option, } pub async fn iterate( @@ -217,6 +227,7 @@ pub async fn iterate( validation: report, iterations: iteration + 1, history, + trace_id: Some(trace_id.clone()), })).into_response(); } Err(err) => { @@ -259,6 +270,7 @@ pub async fn iterate( error: format!("max iterations reached ({max_iter}) without passing validation"), iterations: max_iter, history, + trace_id: Some(trace_id.clone()), })).into_response() } diff --git a/lakehouse.toml b/lakehouse.toml index d0eea54..1c1582f 100644 --- a/lakehouse.toml +++ b/lakehouse.toml @@ -5,9 +5,13 @@ host = "0.0.0.0" port = 3100 # Coordinator session JSONL — one row per /v1/iterate session for # offline DuckDB analysis. Cross-runtime parity with the Go-side -# [validatord].session_log_path. Empty = disabled. Production: -# session_log_path = "/var/lib/lakehouse/gateway/sessions.jsonl" -session_log_path = "" +# [validatord].session_log_path. Set to the SAME path Go validatord +# writes to so DuckDB queries see one unified longitudinal stream +# across both runtimes (rows are tagged daemon="gateway" vs +# daemon="validatord" so producers stay distinguishable). Append-write +# is atomic at the row sizes both runtimes produce — both daemons +# co-writing is safe. +session_log_path = "/tmp/lakehouse-validator/sessions.jsonl" [storage] root = "./data"