2️⃣ Copy–paste prompt for Replit (CTO work) Here’s a single block you can send straight to the Replit agent to implement A + B: You are a senior Python/FastAPI engineer working on the LIA backend. We’ve just verified that /api/lia/outbound works end-to-end (LIA → Twilio → WhatsApp). Next, we need two safety features: 1) Only allow outbound for specific payment bands (18, 12, 9, 6, 3). 2) Prevent duplicate conversations for the same customer/campaign/stage/channel. Do NOT change any LLM/URE logic or db schema. Just add validation + dedupe in the outbound flow. ──────────────────────── TASK 1 – Validate payments_remaining band In app/lia_outbound.py (where the outbound request model and process_outbound_message live): 1. After parsing the request payload, enforce: - `payments_remaining` must be one of: 18, 12, 9, 6, 3. 2. If it is not, raise: ```python raise HTTPException( status_code=400, detail="payments_remaining must be one of [18, 12, 9, 6, 3] for this endpoint" ) Use the same band mapping you already use to derive stage: 18 → "18" 12 → "12" 9 → "9" 6 → "6" 3 → "3" If there is an existing function that maps payments_remaining → stage, reuse it. Otherwise, implement a small helper. ──────────────────────── TASK 2 – Duplicate-conversation fail-safe Definition of duplicate: Same customer_id Same campaign Same stage (derived from payments_remaining) Same channel We must NOT start a new conversation if one already exists for that combination. In app/lia_outbound.py, before creating a new dp_conversations row, add a check using the existing db connection helper: Pseudocode: existing = await conn.fetchrow( """ SELECT conversation_id, status FROM dp_conversations WHERE customer_id = $1 AND campaign = $2 AND stage = $3 AND channel = $4 LIMIT 1 """, customer_id, campaign, stage, channel, ) If existing is not None: Do NOT create a new conversation. Do NOT generate a new outbound message for Twilio. Raise an HTTP 409 with a clear payload, for example: raise HTTPException( status_code=409, detail={ "error": "Conversation already exists for this customer, campaign, stage and channel", "conversation_id": str(existing["conversation_id"]), "stage": stage, }, ) (If your existing error handling expects detail to be a string, you can instead return a string and include conversation_id in the log – but ideally return a JSON object as shown.) If existing is None: Proceed with the existing logic to: create a new dp_conversations row, generate message_text, return OutboundResponse as currently implemented. Make sure that: This duplicate check runs regardless of sandbox_mode (true/false). Status (active/paused/dnc) does NOT bypass the check; any existing row for the same tuple should block a new conversation from being created. ──────────────────────── CONSTRAINTS Do NOT change any table schemas. Do NOT change how message_text, conversation_id, or to_number are built if the request is valid and not a duplicate. Do NOT change inbound or nudge endpoints. Only: Enforce payments_remaining ∈ {18, 12, 9, 6, 3}. Enforce the duplicate-conversation rule described above for /api/lia/outbound. ──────────────────────── WHEN DONE Reply with: The code snippet showing: where you validate payments_remaining, and how stage is derived. The code snippet showing: the SELECT on dp_conversations, and the HTTPException you raise on duplicates. Example 409 JSON body returned for a duplicate case (payload can be anonymised). Once that’s in, Make will see: - **200** → send via Twilio - **400** (bad band / missing phone, etc.) → log/skips - **409** (duplicate conversation) → log/skips That gives you the safe “don’t spam / don’t double start” behaviour you want. --- ## 3️⃣ Which agent for scripts / guides? > “we could ask another agent (cant remember which) to help generate the script guides for each campaign?” That’s your **LIA – CPO (Chief Product / Prompt Officer) agent** – the one we used when designing LIA Prompt v2 and behaviour. - **CTO agent (me)** → backend, APIs, DB, logic, safety nets - **CPO agent** → behavioural design, script guides, tone, per-campaign playbooks, “what should Lia say at 18/12/9/6/3 months, PCP vs HP, new vs used, etc.” So once you’re happy the backend safety bits above are in, you can open a fresh chat and start with: > “You are now LIA – CPO (Chief Product / Prompt) agent…” and we’ll build the script/guide pack for each band. --- If you like, after Replit finishes this duplicate/band work, we can: - design how to **loop** through a DB view of eligible customers per band, - and hook that into Make as a daily/weekly mini-campaign.