feat(call): implement abort cascade for nested calls (ADR-016) (task: call/protocol/abort-cascade)

- PendingEntry stores parent_request_id (Call and Subscribe) and started flag
  for abort-cascade tree indexing
- register_call/register_subscribe accept optional parent_request_id
- AbortCascade::cascade_abort walks the call tree by parent_request_id and
  aborts descendants per AbortPolicy (AbortDependents: all; ContinueRunning:
  unstarted only). Returns sorted list of aborted request IDs
- call.aborted for unknown request_id silently discarded (empty result)
- Composed child request_ids stay internal (not sent as call.requested)
- mark_started() tracks dispatch state for ContinueRunning decisions
- 20 unit tests covering AbortDependents/ContinueRunning, depth-3 tree,
  unknown root, mixed Call/Subscribe, determinism
This commit is contained in:
2026-06-23 15:49:07 +00:00
parent bea19de3cf
commit 3317bc8d1a
4 changed files with 498 additions and 18 deletions

View File

@@ -89,7 +89,11 @@ impl CallConnection {
let receiver = {
let mut pending = self.pending.lock();
pending.register_call(request_id.clone(), Instant::now() + DEFAULT_CALL_TIMEOUT)
pending.register_call(
request_id.clone(),
Instant::now() + DEFAULT_CALL_TIMEOUT,
None,
)
};
if let Err(err) = self.write_request(send, &request_id, payload).await {
@@ -133,7 +137,7 @@ impl CallConnection {
let receiver = {
let mut pending = self.pending.lock();
pending.register_subscribe(request_id.clone(), None)
pending.register_subscribe(request_id.clone(), None, None)
};
if let Err(err) = self.write_request(send, &request_id, payload).await {