Problem
After #347, schedule wakes are serialized per runner target. A manual fire for a different invocation targeting the same busy runner can therefore wait in the target queue before its own bounded wake begins.
The operator CLI is synchronous and #348 gives it a transport budget slightly larger than the maximum wake budget. That covers one wake, but it cannot cover an unbounded queue wait plus the wake itself. The current API contract does not state whether a busy target should reject immediately, enqueue asynchronously, or synchronously wait with a separately bounded queue budget.
Required decision
Define the manual-fire contract when the selected runner target already has an active wake:
- fail fast with a conflict and actionable retry guidance;
- accept asynchronously and return an invocation/queue handle; or
- wait synchronously under an explicit queue deadline distinct from the runner wake deadline.
The decision must preserve per-target serialization from #347, final-result semantics where promised, and neutral accounting for requests canceled before a wake attempt.
Verification
- RED-first API/client tests for two different invocations sharing one target
- explicit status/response contract for the chosen behavior
- no regression to same-invocation duplicate rejection
- no change to automatic scheduler fairness or per-target serialization
- focused tests, full unit suite, vet, and integration coverage
Relationship
Discovered while closing #348. #348 correctly aligns the client with the longest single wake budget; this issue owns queue time and busy-target semantics rather than stretching that timeout without a bound.
Problem
After #347, schedule wakes are serialized per runner target. A manual fire for a different invocation targeting the same busy runner can therefore wait in the target queue before its own bounded wake begins.
The operator CLI is synchronous and #348 gives it a transport budget slightly larger than the maximum wake budget. That covers one wake, but it cannot cover an unbounded queue wait plus the wake itself. The current API contract does not state whether a busy target should reject immediately, enqueue asynchronously, or synchronously wait with a separately bounded queue budget.
Required decision
Define the manual-fire contract when the selected runner target already has an active wake:
The decision must preserve per-target serialization from #347, final-result semantics where promised, and neutral accounting for requests canceled before a wake attempt.
Verification
Relationship
Discovered while closing #348. #348 correctly aligns the client with the longest single wake budget; this issue owns queue time and busy-target semantics rather than stretching that timeout without a bound.