Category: bug Severity: major
Location: Sources/ARCP/Client/ARCPClient.swift:484-508
What
pendingByInvoke[invokeId] is created with continuation == nil before send, and the continuation is attached only after await transport.send returns. During that await the actor is released and the dispatcher can process job.accepted + the terminal envelope; resolve() then removes the state and calls state.continuation?.resume (nil, dropped). attachContinuation then finds no state and throws 'lost invocation', so the real outcome is lost. Same waiter-before-send race class as the already-fixed pong path.
Evidence
do {
try await transport.send(envelope) // actor suspends here; dispatcher can run
} catch { ... }
let (outcome, jobId) = try await withCheckedThrowingContinuation { cont in
attachContinuation(invokeId: invokeId, cont: cont)
}
...
private func attachContinuation(invokeId: MessageId, cont: ...) {
if var state = pendingByInvoke[invokeId] { state.continuation = cont; ... }
else { cont.resume(throwing: ARCPError.internal(detail: "lost invocation \(invokeId)", cause: nil)) }
}
Proposed fix
Attach the continuation into pendingByInvoke BEFORE sending the invoke (mirroring the pong slot's pending/ready states), or buffer the outcome on the state so a terminal arriving pre-attach is delivered when the continuation attaches.
Acceptance criteria
Category: bug Severity: major
Location:
Sources/ARCP/Client/ARCPClient.swift:484-508What
pendingByInvoke[invokeId] is created with continuation == nil before send, and the continuation is attached only after
await transport.sendreturns. During that await the actor is released and the dispatcher can process job.accepted + the terminal envelope; resolve() then removes the state and callsstate.continuation?.resume(nil, dropped). attachContinuation then finds no state and throws 'lost invocation', so the real outcome is lost. Same waiter-before-send race class as the already-fixed pong path.Evidence
Proposed fix
Attach the continuation into pendingByInvoke BEFORE sending the invoke (mirroring the pong slot's pending/ready states), or buffer the outcome on the state so a terminal arriving pre-attach is delivered when the continuation attaches.
Acceptance criteria