Document EngineHandle's already-realized primary/profile routing (ticket 106)

Ticket 106 asked for a real way for API handlers to address the
primary vs. profile actor. That routing was already built out of
necessity while landing tickets 104/105 (metric queries had to reach
the profile actor's snapshot for those tickets' own tests to pass) --
EngineHandle ended up as one combined handle (option (b) from the
ticket's own scope note) that internally proxies metric/alert writes
to the profile actor and routes MetricDeclarations/BucketValues/Promql
reads to its snapshot, with no changes needed to any API handler,
reload_engine_declarations/activate_profile, or Profile::load_into_engine
-- they already just send EngineMessages the same way they did before
the split. mcp_server.rs talks to the HTTP API rather than EngineHandle
directly, so it needed no changes either. This commit documents that
resolution in handle.rs so a future reader doesn't go looking for
routing logic that isn't there.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TeyhRfMYjMditek6geDRoQ
This commit is contained in:
Hugh Kaznowski
2026-09-07 13:56:59 +01:00
co-authored by Claude Sonnet 5
parent 3751508de8
commit 3ee6dddb0e
2 changed files with 11 additions and 62 deletions
@@ -1,62 +0,0 @@
# 106 — Give API handlers a real way to address the primary vs. the profile actor
## Summary
By the time [[104-move-metric-computation-to-profile-actor]] and
[[105-move-alert-evaluation-to-profile-actor]] land, metric/alert
messages need to route to the profile actor while param/log messages
stay on the primary — today's single `EngineHandle` (one `mpsc::Sender`
+ one `IndexReader`) can't express that. This ticket gives `api.rs`'s
handlers, and the runtime profile-switch path, a real API surface for
both actors, per [[0001-actor-split]]'s resolved decision to decide
during implementation whether that's two handle types or one
internally-fanning-out handle.
## Where
- `src/engine/handle.rs:74-78` (`EngineHandle { tx, reader }`) — the
single handle type `ApiState` holds today.
- `src/api/mod.rs` — `ApiState`'s definition (wherever it stores the
`EngineHandle`) and every handler that sends an `EngineMessage`;
metric/alert-related routes need to target the profile actor's
channel instead of the primary's.
- `src/api/mod.rs:812-852` (`reload_engine_declarations`,
`activate_profile`) — today removes/redeclares params *and* metrics
against one engine. After this split, param removal/redeclare stays
primary-side, metric removal/redeclare targets the profile actor —
this function needs to send to both.
- `src/config/profile.rs`'s `load_into_engine` (referenced in
[[0004-profile-switch-reindexing-cost]] at `:332-384`) — same
dual-target concern at startup load time as well as runtime
reactivation.
- `src/api/mcp_server.rs` — check whether the MCP server's query
surface holds its own `EngineHandle` reference that also needs the
updated shape.
## Scope
- Decide and implement the concrete shape: either (a) `ApiState` holds
two handles (`primary: EngineHandle`, `profile: ProfileHandle`) and
each handler picks the right one, or (b) one combined handle type
that internally holds both channels/readers and routes by message
kind. Document the choice in the PR description since
[[0001-actor-split]] deliberately left it open.
- Update every `api.rs` handler that currently sends a
`DeclareMetric`/`UpdateMetric`/`RemoveMetricDeclaration` or alert-
related message to target the profile actor; param-related messages
(`DeclareParam`/`RemoveParamDeclaration`/`ClearParams`/
`SetMaxLogs`/`EnsureSortHelperIndex`) stay on the primary.
- Update `reload_engine_declarations`/`activate_profile` and
`Profile::load_into_engine` to split their remove-then-redeclare
sequence across both actors correctly, preserving today's behavior
(still fully synchronous from the caller's perspective — this
ticket doesn't change the blocking nature of profile switching,
only which actor(s) the messages go to; see
[[0004-profile-switch-reindexing-cost]] for the separate question of
making that async).
- Out of scope: the query fan-out layer for requests needing both raw
logs and profile-derived data in one response — that's
[[107-query-fan-out-across-primary-and-profile]]. Read-only query
handlers can be touched here only insofar as they need updating to
compile against the new handle shape, not to actually merge two data
sources yet.