# 107 — Fan out and merge queries that need both raw logs and profile-derived data ## Summary Today, `Logs`/`Timeline` queries read raw log text *and* profile-derived params/metrics from a single `EngineSnapshot` in one pass — e.g. `query.rs`'s log-entry building calls `log_entry_params` against `compiled_params` from the same snapshot the raw text came from. Once params/logs live on the primary and metrics live on the profile actor (per tickets 103-106), any query needing both becomes a real join across two snapshots instead of one borrow. This is the piece of [[0001-actor-split]]'s design explicitly called out as "a query-fan-out/merge layer is still needed." ## Where - `src/engine/snapshot/query.rs` (`handle_query_inner` and the log- entry-building helpers around line 70-117 per prior research) — the read path that currently assumes one `EngineSnapshot` has everything a `Logs`/`Timeline` response needs. - `src/engine/message.rs:12-27` (`EngineQuery`) — currently answered entirely off the primary's `left_right` reader (`EngineHandle::ask`/`handle_query_ro`, per [[0001-actor-split]]'s "queries already bypass this actor" note); after the split, some query variants need data from both actors' read sides. - `src/api/mod.rs` — wherever `EngineQuery` results are turned into HTTP responses; the merge/join logic likely belongs here or in a new helper alongside `query.rs`, not duplicated per handler. - Dashboard/PromQL panel queries (`src/engine/promql.rs`) — confirm whether these are profile-only reads (metrics live entirely on the profile actor) and therefore need no fan-out, versus `Logs`/ `Timeline` which do. ## Scope - Identify every `EngineQuery` variant that currently reads both raw log data and profile-derived data (params, metrics) from one snapshot, and design the two-snapshot join for each — likely: read matching log entries from the primary by sequence range, then look up each entry's profile-derived fields (declared param values, metric-driven fields) from the profile actor's snapshot by the same sequence, filtering/merging results. - Confirm ordering/consistency expectations: the profile actor can lag the primary (per [[0001-actor-split]]'s accepted eviction/lag tradeoff), so a joined query may find a primary-side log entry with no corresponding profile-side data yet — decide and document the behavior (omit those fields vs. error) rather than leaving it implicit. - Update PromQL/dashboard panel query handling only if it's confirmed to need primary-side data too (e.g. `ottyl_seq`/`ottyl_ts` bare queries per prior ticket history) — otherwise leave it reading the profile actor alone. - Out of scope: query result caching or performance optimization beyond what's needed for correctness — this ticket is about producing correct joined results, not making them fast (see [[0005-additional-read-indexes]] for read-path performance work, which should be sequenced after this settles).