Files
ottyl/tickets/103-profile-actor-skeleton-and-primary-signaling.md
T
Hugh KaznowskiandClaude Sonnet 5 2c1aaa6e9c Break ticket 102's actor split into reviewable sub-tickets (103-108)
Ticket 102 (splitting the engine into reader/primary/profile actors)
was a single multi-thousand-line ticket covering a new actor
topology, an EngineHandle API redesign, a query fan-out layer, moving
alerts, and a full test-harness rewrite, with some design decisions
deliberately left open. Splitting it into six sequenced tickets
(profile actor skeleton + signaling, move metric computation, move
alert evaluation, split the handle API, query fan-out, test harness
rework) lets each land as its own reviewable commit instead of one
large speculative rewrite.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TeyhRfMYjMditek6geDRoQ
2026-09-07 13:33:01 +01:00

3.5 KiB

103 — Stand up the profile actor skeleton and primary→profile signaling, with no behavior moved yet

Summary

First slice of 0001-actor-split's step 3 (splitting the single engine actor into reader/primary/profile actors). This ticket is pure plumbing: a second actor task with its own left_right write side for profile-owned state, a way for it to read the primary's index (EngineHandle's IndexReader is already Clone, so no primary-side change is needed to hand out a read-only view), and a tokio::sync::watch the primary signals on after each left_right sync so the profile actor wakes without busy-polling. No metric computation, alert evaluation, or query routing moves in this ticket — that's 104-move-metric-computation-to-profile-actor and 105-move-alert-evaluation-to-profile-actor. Depends on 101-extract-metric-computation-into-separate-stage (done) for the ingest_params/apply_all_metrics seam this split will eventually route across two actors.

Where

  • src/engine/handle.rs:33-47 (IndexWriter) — mutate() calls self.handle.append(...) then self.handle.publish(); this is where the new watch-sender notification hooks in, right after publish().
  • src/engine/handle.rs:48-73 (IndexReadHandle/IndexReader) — the existing read-side pattern to mirror for the profile actor's own derived state; IndexReader is already Clone (handle.rs:61-67 is a template, not something to reuse directly — the profile actor needs its own left_right pair for its own state, plus a cloned primary IndexReader for read access).
  • src/engine/handle.rs:74-78 (EngineHandle) and :119-124 (spawn) — the shape to parallel for a new profile-actor spawn function.
  • src/engine/snapshot/mod.rs:208-255 (logs_range/ logs_in_sequence_range) — the read-side primary API the profile actor will use (via its cloned IndexReader) to pull newly-visible lines after waking on the watch signal.

Scope

  • Add a ProfileSnapshot type (new module, e.g. src/engine/profile.rs) with its own left_right write/read pair, parallel to EngineSnapshot's pattern in handle.rs — for now it can be effectively empty (a placeholder struct), since no state moves into it yet.
  • Add a tokio::sync::watch<u64> (carrying, e.g., the primary's latest processed sequence) that IndexWriter::mutate sends on after publish() succeeds.
  • Add a profile actor task: holds a cloned primary IndexReader plus its own ProfileSnapshot write side, wakes on the watch channel, and — for this ticket only — reads whatever new lines logs_in_sequence_range exposes since its last-seen sequence and does nothing with them (e.g. just advances its own watermark). The goal is proving the wake/read loop works end-to-end, not doing real work with the data yet.
  • Wire spawn (src/cli/mod.rs:95) to also spawn the profile actor alongside the primary, but do not yet change what ApiState holds or what any API handler talks to — EngineHandle and its public API stay exactly as they are today. That's 106-split-enginehandle-api-for-primary-and-profile's concern.
  • Out of scope: moving apply_all_metrics, metric declarations, or alert evaluation; changing EngineHandle's public surface; eviction coordination beyond what already exists (primary still evicts on its own schedule per 0001-actor-split's resolved decision — this ticket doesn't need to handle the profile actor falling behind eviction yet, since it isn't consuming anything meaningful).