gateway: IterateResponse echoes trace_id + enable session_log_path
Some checks failed
lakehouse/auditor 14 blocking issues: cloud: claim not backed — "Verified end-to-end against persistent Go stack on :4110:"
Some checks failed
lakehouse/auditor 14 blocking issues: cloud: claim not backed — "Verified end-to-end against persistent Go stack on :4110:"
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<String>`
(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) <noreply@anthropic.com>
This commit is contained in:
parent
57bde63a06
commit
98b6647f2a
@ -87,6 +87,14 @@ pub struct IterateResponse {
|
|||||||
pub validation: serde_json::Value,
|
pub validation: serde_json::Value,
|
||||||
pub iterations: u32,
|
pub iterations: u32,
|
||||||
pub history: Vec<IterateAttempt>,
|
pub history: Vec<IterateAttempt>,
|
||||||
|
/// 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<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
@ -94,6 +102,8 @@ pub struct IterateFailure {
|
|||||||
pub error: String,
|
pub error: String,
|
||||||
pub iterations: u32,
|
pub iterations: u32,
|
||||||
pub history: Vec<IterateAttempt>,
|
pub history: Vec<IterateAttempt>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub trace_id: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn iterate(
|
pub async fn iterate(
|
||||||
@ -217,6 +227,7 @@ pub async fn iterate(
|
|||||||
validation: report,
|
validation: report,
|
||||||
iterations: iteration + 1,
|
iterations: iteration + 1,
|
||||||
history,
|
history,
|
||||||
|
trace_id: Some(trace_id.clone()),
|
||||||
})).into_response();
|
})).into_response();
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
@ -259,6 +270,7 @@ pub async fn iterate(
|
|||||||
error: format!("max iterations reached ({max_iter}) without passing validation"),
|
error: format!("max iterations reached ({max_iter}) without passing validation"),
|
||||||
iterations: max_iter,
|
iterations: max_iter,
|
||||||
history,
|
history,
|
||||||
|
trace_id: Some(trace_id.clone()),
|
||||||
})).into_response()
|
})).into_response()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,9 +5,13 @@ host = "0.0.0.0"
|
|||||||
port = 3100
|
port = 3100
|
||||||
# Coordinator session JSONL — one row per /v1/iterate session for
|
# Coordinator session JSONL — one row per /v1/iterate session for
|
||||||
# offline DuckDB analysis. Cross-runtime parity with the Go-side
|
# offline DuckDB analysis. Cross-runtime parity with the Go-side
|
||||||
# [validatord].session_log_path. Empty = disabled. Production:
|
# [validatord].session_log_path. Set to the SAME path Go validatord
|
||||||
# session_log_path = "/var/lib/lakehouse/gateway/sessions.jsonl"
|
# writes to so DuckDB queries see one unified longitudinal stream
|
||||||
session_log_path = ""
|
# 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]
|
[storage]
|
||||||
root = "./data"
|
root = "./data"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user