Backend test coverage for the WhatsApp Cloud Calling pipeline introduced in #14356. Stacked on top of that PR so the controller and service under test exist when CI runs. ## Closes - Replaces #14348 (which was based on the abandoned \`feature/pla-150\`) ## What's covered - \`spec/enterprise/controllers/api/v1/accounts/whatsapp_calls_controller_spec.rb\` (new, ~210 lines) - \`show / accept / reject / terminate / initiate / upload_recording\` happy paths - 422 paths: missing sdp_offer, missing recording, calling_disabled inbox, missing contact phone, ringing-state guards, AlreadyAccepted, NotRinging, CallFailed - 138006 (no permission) → throttled opt-in template send under conversation lock; idempotency on retry - \`upload_recording\` idempotency guard (\`already_uploaded\`) - \`spec/enterprise/services/whatsapp/call_service_spec.rb\` (new, ~135 lines) - State machine: ringing → in_progress → completed; ringing → failed (reject); ringing → no_answer (terminate) - Lock contention: concurrent terminate during accept doesn't corrupt the message/conversation broadcast - Provider failure paths surface as \`Voice::CallErrors::CallFailed\` (transport and business) - \`spec/models/channel/whatsapp_spec.rb\` — extends existing file with \`voice_enabled?\` matrix (provider × source × calling_enabled) ## Verification - 77/77 examples pass locally on this branch (controller + service + channel + incoming-call + permission-reply + open-ai message builder) - RuboCop clean ## Stack - Backend: #14356 (\`feat/whatsapp-call-meta-bridge\` — base of this PR) - FE: #14346 (\`feat/whatsapp-call-ui\`) --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>