fix: stop no-answer retry racing dialplan hangup + fix event catalog validation #11

Merged
arystanbek merged 1 commits from fix/retry-channel-resolution-and-event-catalog into main 2026-08-30 20:04:05 +00:00
Owner

Found via a live test with two real registered browser softphones (2001/2002):

  1. retry_escalation_no_answer used a slow ~10s AMI channel re-discovery that lost the race against the dialplan MusicOnHold wait window added earlier - confirmed via escalation timeline: Channel does not exist: PJSIP/.... Fixed to reuse the already-known link.channel_name directly.

  2. VoiceEventIn.event_type Literal never included the Phase 2 event catalog names - every escalation event emit has been failing 422 since Phase 2 shipped, silently swallowed. Extended the Literal.

Tests: test_escalation_retry.py + test_asterisk_bridge_service.py + test_routing_engine.py all green.

Found via a live test with two real registered browser softphones (2001/2002): 1. retry_escalation_no_answer used a slow ~10s AMI channel re-discovery that lost the race against the dialplan MusicOnHold wait window added earlier - confirmed via escalation timeline: `Channel does not exist: PJSIP/...`. Fixed to reuse the already-known link.channel_name directly. 2. VoiceEventIn.event_type Literal never included the Phase 2 event catalog names - every escalation event emit has been failing 422 since Phase 2 shipped, silently swallowed. Extended the Literal. Tests: test_escalation_retry.py + test_asterisk_bridge_service.py + test_routing_engine.py all green.
arystanbek added 1 commit 2026-08-30 20:03:59 +00:00
Two bugs found via a live test with two real registered browser softphones:

1. retry_escalation_no_answer() re-resolved the client channel via
   _resolve_handoff_channel() -> a live AMI CoreShowChannels round-trip that
   can take ~10s. The new mvpcc-transfer dialplan wait window (MusicOnHold,
   also ~10s, added to give the backend time to redirect before the final
   Hangup) was consistently LOST to this exact same duration: the backend's
   AMI Redirect fired against a channel the dialplan had already hung up
   ('Channel does not exist: PJSIP/...', confirmed in escalation timeline).
   Fixed by reusing the actively-maintained AsteriskCallLinkRow.channel_name
   directly (unchanged for a PJSIP channel across Redirect between contexts
   of the same call) instead of re-discovering it, falling back to the slow
   path only if that field is empty.

2. VoiceEventIn.event_type is a pydantic Literal restricted to 6 legacy
   values (call.started/ivr.completed/...). None of the Phase 2 event
   catalog names (AgentReserved/AgentRinging/AgentNoAnswer/AgentConnected/
   TransferCompleted/TransferFailed) were ever in it, so every single
   _emit_escalation_event() call has been failing with 422 since Phase 2
   shipped (swallowed silently by the broad except there) - confirmed by
   calling app._emit_voice_event() directly against the running service.
   Extended the Literal to include all six.
arystanbek merged commit 3c5c233071 into main 2026-08-30 20:04:05 +00:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: digiops/call-center#11