Every significant architecture decision in this system is documented here in full ADR format: context, decision, alternatives considered, consequences (positive and negative), and the hardest rebuttals a design review would surface. The reasoning is the design.
send_message(worker_id, text, language) and receive_message(sender_id, content). Swapping the underlying provider is a gateway module replacement — no agent code, no state machine, no Firestore schema changes. The IVR channel provides full feature parity as a fallback. Migration timeline to an alternative channel: estimated 2 weeks of engineering.INBOUND_MSG → STT_RESULT → AGENT_EVENT → HITL_ESCALATION → NOTIFICATION_OUT. Each topic has a dead-letter queue. Message retention is 7 days for replay on failure.employee_id + date + leave_type. Before writing a new leave record, the agent checks for an existing record with the same key. A duplicate Pub/Sub delivery triggers a duplicate check — the second invocation finds the existing record and returns the already-committed decision without creating a new one. The audit log entry for the duplicate is flagged as a replay.min-instances: 1 configured in Terraform. One warm instance is kept always-on at a cost of approximately $3.20/month (1 vCPU + 16Gi memory idle rate on Cloud Run). This eliminates cold starts entirely on the critical IVR path. The 10-second GPU cold start only occurs if the min-instance is recycled — Cloud Run keeps min-instances warm indefinitely. P99 STT latency with min-instance warm: consistently < 4 seconds.initiate_call(number), stream_audio(session_id), end_call(session_id). Swapping Exotel for Twilio for a non-India deployment is a gateway config change — one environment variable and one provider SDK import. The cost methodology page shows region-specific provider recommendations. A global enterprise deployment would use Twilio globally and Exotel for India — the architecture supports both simultaneously.decision_by: TIMEOUT, reason: "Owner did not respond within configured timeout period"./employees/{id} as the mobile field. Every subsequent interaction is authenticated by matching the sender number against registered employees. The telco and Meta have already performed KYC on this number — the system inherits that verification.