Skip to content

feat(check): streaming Kameo actor pipeline for multi check (MULTI-1368)#145

Merged
RobbieMcKinstry merged 1 commit into
trunkfrom
robbie/multi-1368
Jun 25, 2026
Merged

feat(check): streaming Kameo actor pipeline for multi check (MULTI-1368)#145
RobbieMcKinstry merged 1 commit into
trunkfrom
robbie/multi-1368

Conversation

@RobbieMcKinstry

Copy link
Copy Markdown
Contributor

Re-architect the multi check pipeline from its barrier-based shape into a
streaming, fire-and-forget actor pipeline using Kameo (v0.20). Each phase
becomes its own actor wired with one-way tell:

DiscoveryActor --CheckDiscovered--> ExecutionActor --CheckCompleted--> ReportingActor

This removes the two synchronization barriers between phases: a check begins
executing the moment Discovery has validated it, and a result is folded into
Reporting the moment its agent returns — no waiting on an owned Vec.

  • messages.rs: the inter-actor message protocol (CheckJob carried end-to-end,
    plus DiscoveryComplete/ExecutionComplete end-of-stream sentinels).
  • DiscoveryActor: runs the whole-suite parse + validation gate (discover()),
    then streams one CheckDiscovered per check with a run-unique CheckId; any
    invalid CHECKS.md aborts the whole run via DiscoveryFailed with no agents
    spawned (strict whole-run abort).
  • ExecutionActor: offloads each agent run onto a spawned task bounded by a
    shared Semaphore(cfg.concurrency) acquired inside the task (the semaphore is
    the cap, not the mailbox); retries reframed as RetryCheck self-messages.
  • ReportingActor: folds verdicts incrementally, then buffers and sorts by
    (req_index, declaration order) before the final render — output ordering,
    AND-aggregation, and exit codes are byte-for-byte unchanged.
  • Coordinator in run(): spawns the actors, kicks discovery, awaits the terminal
    result over a oneshot, and maps a dead actor to a diagnostic rather than
    hanging the run.

The CheckExecutor/Sandbox DI seams are reused unchanged. Tests drive the actor
pipeline deterministically (FakeExecutor + NoopSandbox), with new coverage for
concurrent (non-barriered) execution, the retry self-message path, and the
strict abort-without-spawning-agents path.

Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com

RobbieMcKinstry commented Jun 25, 2026

Copy link
Copy Markdown
Contributor Author

…1368)

Re-architect the `multi check` pipeline from its barrier-based shape into a
streaming, fire-and-forget actor pipeline using Kameo (v0.20). Each phase
becomes its own actor wired with one-way `tell`:

    DiscoveryActor --CheckDiscovered--> ExecutionActor --CheckCompleted--> ReportingActor

This removes the two synchronization barriers between phases: a check begins
executing the moment Discovery has validated it, and a result is folded into
Reporting the moment its agent returns — no waiting on an owned `Vec`.

- messages.rs: the inter-actor message protocol (CheckJob carried end-to-end,
  plus DiscoveryComplete/ExecutionComplete end-of-stream sentinels).
- DiscoveryActor: runs the whole-suite parse + validation gate (discover()),
  then streams one CheckDiscovered per check with a run-unique CheckId; any
  invalid CHECKS.md aborts the whole run via DiscoveryFailed with no agents
  spawned (strict whole-run abort).
- ExecutionActor: offloads each agent run onto a spawned task bounded by a
  shared Semaphore(cfg.concurrency) acquired inside the task (the semaphore is
  the cap, not the mailbox); retries reframed as RetryCheck self-messages.
- ReportingActor: folds verdicts incrementally, then buffers and sorts by
  (req_index, declaration order) before the final render — output ordering,
  AND-aggregation, and exit codes are byte-for-byte unchanged.
- Coordinator in run(): spawns the actors, kicks discovery, awaits the terminal
  result over a oneshot, and maps a dead actor to a diagnostic rather than
  hanging the run.

The CheckExecutor/Sandbox DI seams are reused unchanged. Tests drive the actor
pipeline deterministically (FakeExecutor + NoopSandbox), with new coverage for
concurrent (non-barriered) execution, the retry self-message path, and the
strict abort-without-spawning-agents path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@RobbieMcKinstry RobbieMcKinstry added this pull request to the merge queue Jun 25, 2026
Merged via the queue into trunk with commit 73950f5 Jun 25, 2026
10 checks passed
@RobbieMcKinstry RobbieMcKinstry deleted the robbie/multi-1368 branch June 25, 2026 03:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant