AI Sales Bot โ€” Complete Logic Flowchart

Generated 2026-09-09 ยท Tap "Save as PDF" then open in your iPad's Files app

1. Lead Intake (How leads enter the system)

  +---------------+     +---------------+     +----------------------+
  | Google Sheets  |     |  Wix Forms    |     |  Manual / AI Agent   |
  |  (Sheet1+4)   |     |  Webhook      |     |  (in-app creation)  |
  +-------+-------+     +-------+-------+     +----------+-----------+
          |                     |                        |
          v                     v                        v
  syncGoogleSheetLeads   handleWixFormSubmission   AgentLead.create()
  (scheduled workflow)   (Wix webhook workflow)   (manual via UI)
          |                     |                        |
          v                     v                        v
  +-----------------------------------------------------------+
  |                    DEDUP CHECK                              |
  |  * Phone in deleted-phones blocklist? -> SKIP             |
  |  * Phone already in AgentLeads? -> SKIP (or backfill)     |
  |  * Date newer than sync marker? -> PROCESS                 |
  +----------------------------+------------------------------+
                               |
                               v
                    +---------------------+
                    |  AgentLead.create() |
                    |  status = "New"     |
                    +----------+----------+
                               |
                               v
                    +---------------------+
                    |  startAIChatForLead |
                    |  (shared/startAIChat)|
                    +----------+----------+
                               |
                               v
              +--------------------------------+
              |  1. Pick Twilio number (pool)  |
              |  2. Pin to lead forever        |
              |  3. Build opening message       |
              |  4. Send via sendSmsValidated  |
              |  5. Create SMSConversation     |
              |     (is_ai_managed=true)       |
              |  6. Update lead -> "Contacted"|
              +--------------------------------+

2. Inbound SMS Processing (When a customer replies)

  Customer sends SMS
         |
         v
  +------------------------------------------+
  |  Twilio receives SMS                     |
  |  -> fires webhook (handleSMSWebhook)     |
  |  AND/OR polled by pollIncomingSMS        |
  |     (5 workflows: Minute 0-4 + Redundant)|
  +---------------------+---------------------+
                        |
                        v
  +------------------------------------------+
  |  pollIncomingSMS                         |
  |  1. Fetch recent messages from Twilio    |
  |  2. Is this an ADMIN reply? (7788614055)|
  |     YES -> route to handleEPPReply       |
  |            or handleWirelessReply        |
  |     NO  -> continue to customer flow     |
  +---------------------+---------------------+
                        |
                        v
  +------------------------------------------+
  |  MATCH to SMSConversation by phone number|
  |  Prefer AI-managed conversation          |
  +---------------------+---------------------+
                        |
                        v
  +------------------------------------------+
  |  Save inbound message to messages[]      |
  +---------------------+---------------------+
                        |
                        v
  +------------------------------------------+
  |  Is lead "Stale"?                         |
  |  YES -> Reactivate to "In Conversation" |
  |        Clear re-engagement state         |
  |        Resume bot (ai_bot_active=true)   |
  |  NO  -> continue                         |
  +---------------------+---------------------+
                        |
                        v
  +------------------------------------------+
  |  Trigger processAgentLeadReply           |
  |  (the AI brain - see next section)      |
  +------------------------------------------+

3. The AI Brain: processAgentLeadReply (Core decision engine)

  START
    |
    v
  +-----------------------------+
  | Load conversation + lead     |
  +--------------+--------------+
                 |
                 v
  +-----------------------------+      NO   +------------------+
  | is_ai_managed AND           |---------->| SKIP (rep handles|
  | ai_bot_active = true?       |           | manually)         |
  +--------------+--------------+           +------------------+
                 | YES
                 v
  +-----------------------------+
  | Mark lead "In Conversation"  |
  | (immediately, before LLM)   |
  +--------------+--------------+
                 |
                 v
  +-----------------------------+      YES  +------------------+
  | Already replied to this SID?|---------->| SKIP (dedup)     |
  | (last_replied_inbound_sid)   |           +------------------+
  +--------------+--------------+
                 | NO
                 v
  +-----------------------------+
  | CLAIM this inbound SID       |
  | (prevent concurrent triggers)|
  +--------------+--------------+
                 |
                 v
  +-----------------------------------------------------+
  |              SHORT-CIRCUIT CHECKS                    |
  |  (skip LLM, send canned response instead)          |
  |                                                      |
  |  1. Callback pending + short confirmation?          |
  |     -> Send warm ack ("Sounds great, talk then!")  |
  |                                                      |
  |  2. Pending callback proposal + "yes/ok/sure"?      |
  |     -> Confirm callback_at, clear proposal, ack     |
  |                                                      |
  |  3. STOP / UNSUBSCRIBE / OPT-OUT?                   |
  |     -> Send stop ack, mark "Not Interested",        |
  |       permanently stop bot                          |
  +---------------------+------------------------------+
                 | (none matched)
                 v
  +-----------------------------------------------------+
  |              FIRST-REPLY NOTIFICATION               |
  |  If this is the customer's FIRST inbound reply:     |
  |  -> SMS reps (+17788614055, +16047103216)          |
  |    "New lead reply! {name} just responded"          |
  +---------------------+------------------------------+
                 |
                 v
  +-----------------------------------------------------+
  |              BUILD LLM CONTEXT                        |
  |  * Conversation history (all messages)              |
  |  * Lead data (TELUS status, product interest, notes)|
  |  * City population check (for Wireless Internet)    |
  |  * Pending callback context (don't re-follow-up)    |
  |  * Learned patterns (from past rep interventions)   |
  |  * Current Vancouver time (for callback scheduling) |
  +---------------------+------------------------------+
                 |
                 v
  +-----------------------------------------------------+
  |              INVOKE LLM (Claude Sonnet 4.6)         |
  |  Sends:                                             |
  |  * Massive sales persona prompt (~15K tokens)      |
  |  * Conversation history + context                  |
  |  * Customer's latest message                       |
  |                                                      |
  |  Receives JSON:                                     |
  |  { message, ready_for_quote, ready_for_veriff,      |
  |    extracted_params: { segment, products, speed,  |
  |      telusHomeCustomer, callback_at, ... } }       |
  +---------------------+------------------------------+
                 |
                 v
  +-----------------------------------------------------+
  |              DECISION BRANCHES                       |
  |                                                      |
  |  ready_for_veriff? --------> CREATE VERIFF SESSION  |
  |  (customer agreed to price)        |                 |
  |                                    v                 |
  |                             Append Veriff URL       |
  |                             Update lead veriff data |
  |                                                      |
  |  ready_for_quote? ------------> CALL PLAN ADVISOR   |
  |  (qualification complete)         |                  |
  |  AND not already quoted?          v                  |
  |  AND not Veriff done?    getPlanRecommendationInline|
  |  AND (re-quote OR no quote)?    (LLM reads plan PDFs)|
  |                                   |                 |
  |                            Append quote text         |
  |                            Start 1-min quote timer  |
  |                                                      |
  |  customer_declined? -----------> SEND THANK-YOU     |
  |  (no / stop / not interested)    |                  |
  |                                   v                 |
  |                            Mark "Not Interested"    |
  |                            Stop bot permanently     |
  |                                                      |
  |  customer_requested_space? ----> PAUSE RE-ENGAGE    |
  |  (leave me alone / will contact)  |                 |
  |                            Schedule single 5-day    |
  |                            soft follow-up           |
  |                                                      |
  |  customer_in_contract? --------> STOP CONVERSATION  |
  |  (existing TELUS contract)       |                   |
  |                            Mark "Not Interested"    |
  |                            Stop bot                  |
  |                                                      |
  |  end_conversation? ------------> STOP BOT           |
  |  (already contacted/serviced)    |                   |
  |                            Stop bot (no status chg)  |
  |                                                      |
  |  is_renewal? ------------------> TAG AS RENEWAL      |
  |  (existing TELUS internet)      |                   |
  |                            Add [INTERNET RENEWAL]    |
  |                            to rep_notes             |
  |                            No quote (team handles)  |
  |                                                      |
  |  manager_credit_pending? ------> START 2-MIN TIMER  |
  |  (customer agreed to check)      |                   |
  |                            manager_credit_at set    |
  |                            (poller sends approval   |
  |                             follow-up after 2 min)  |
  |                                                      |
  |  callback_at set? --------------> SCHEDULE CALLBACK |
  |  (customer asked for call)       |                  |
  |                            Save callback_at         |
  |                            Clear pending proposal   |
  |                                                      |
  |  pending_callback_proposed_at? -> STORE PROPOSAL    |
  |  (bot proposed a time)           |                  |
  |                            Save proposed time        |
  |                            Start 5-min auto-confirm |
  |                                                      |
  |  wireless_serviceability_request? > SMS TEAM        |
  |  (rural address check)           |                  |
  |                            Send address to team     |
  |                            Store pending_wireless    |
  |                                                      |
  |  customer_asked_epp + workplace? -> SMS TEAM        |
  |  (customer asked about EPP)       |                 |
  |                            Send employer to team     |
  |                            Quote WITHOUT EPP disc.  |
  +---------------------+------------------------------+
                 |
                 v
  +-----------------------------------------------------+
  |              SEND REPLY VIA TWILIO                   |
  |  sendSmsValidated (shared/twilioSms.ts)             |
  |  * If pinned number fails -> retry on another pool  |
  |  * If all numbers fail -> mark lead "Failed"       |
  |  * Update pinned number if switched                |
  +---------------------+------------------------------+
                 |
                 v
  +-----------------------------------------------------+
  |              UPDATE CONVERSATION + LEAD              |
  |  * Append outbound message to messages[]            |
  |  * Mark inbound message as replied=true            |
  |  * Update callback/proposal/credit/quote timers     |
  |  * Update space_requested state                    |
  |  * Update lead status -> "In Conversation"         |
  |  * Save recommendation_summary if quote sent        |
  +-----------------------------------------------------+

4. Re-Engagement Flow (When customers go quiet)

  Scheduled hourly (Re-engagement Pings workflow)
         |
         v
  +------------------------------------------------+
  |  Load all AI-managed, bot-active conversations  |
  |  + all AgentLeads (for status check)            |
  +---------------------+--------------------------+
                        |
                        v
  +------------------------------------------------+
  |  Skip leads with status:                       |
  |  Not Interested / Closed / Awaiting Install /  |
  |  Failed / Stale                                |
  +---------------------+--------------------------+
                        |
                        v
  +------------------------------------------------+
  |  SPACE REQUESTED? (customer asked to be left   |
  |  alone)                                         |
  |  YES -> Did they reply since?                  |
  |        YES -> Clear space state, resume normal |
  |        NO  -> 5 days passed?                   |
  |              YES -> Send ONE soft follow-up    |
  |              NO  -> Skip                        |
  +---------------------+--------------------------+
                        | (no space request)
                        v
  +------------------------------------------------+
  |  LAST MESSAGE INBOUND? (customer replied)      |
  |  YES -> Reset re-engagement state (step=0)     |
  |        Skip (bot handles live)                |
  +---------------------+--------------------------+
                        | (last is outbound)
                        v
  +------------------------------------------------+
  |  DETERMINE SEQUENCE TYPE:                      |
  |                                                 |
  |  inboundCount === 0  -> NORMAL (never replied) |
  |  inboundCount > 0    -> RE-ENGAGEMENT (replied |
  |                        then went quiet)        |
  +---------------------+--------------------------+
                        |
           +------------+------------+
           v                        v
  +--------------+        +----------------------+
  |  NORMAL LEAD |        | RE-ENGAGEMENT LEAD   |
  |  (never      |        | (has replied before) |
  |   replied)   |        +----------+-----------+
  +-------+------+                   |
          |                           v
          v              +---------------------------+
  +--------------+       | 7-DAY, 1/DAY SEQUENCE    |
  | 20-MSG OFFSET|       |                           |
  | SEQUENCE     |       | * Sent at customer's last|
  |              |       |   reply hour              |
  | * Day 1: 4   |       | * Step 0: wait 1 full day|
  |   msgs       |       | * Steps 1-6: 1 msg/day  |
  | * Day 2: 3   |       |   at reply hour          |
  | * Day 4: 3   |       | * Step 7: FINAL store-   |
  | * Day 6: 3   |       |   contact message        |
  | * Day 9: 3   |       |   -> mark "Stale"        |
  | * Day 12+: 4 |       |   -> stop bot            |
  |   (less freq)|       +-----------+--------------+
  +-------+------+                   |
          |                           |
          v                           v
  +------------------------------------------------+
  |  EXHAUSTION CHECK:                              |
  |  Normal: 20+ outbound, 0 inbound               |
  |    -> mark "Stale", stop bot, keep record      |
  |  Re-engagement: 7 days + final msg sent       |
  |    -> mark "Stale", stop bot                   |
  +---------------------+--------------------------+
                        |
                        v
  +------------------------------------------------+
  |  3-DAY RULE (In Conversation -> Contacted):    |
  |  If status is "In Conversation" but customer   |
  |  hasn't replied to last outbound for 3+ days:  |
  |  -> downgrade to "Contacted"                   |
  |  (re-engagement continues from current step)   |
  +---------------------+--------------------------+
                        |
                        v
  +------------------------------------------------+
  |  MESSAGE GENERATION:                           |
  |  LLM (Gemini Flash) generates context-aware    |
  |  follow-up based on actual conversation history |
  |  * Never references non-existent discussions   |
  |  * Varies wording each time                    |
  |  * Max 1-2 sentences, no "haha"/"lol"          |
  +------------------------------------------------+

5. Scheduled Callbacks & Timers (processScheduledCallbacks)

  Runs frequently (Process Scheduled Callbacks workflow)
         |
         v
  +-----------------------------------------------------+
  |  Load all AI-managed conversations                    |
  +---------------------+------------------------------+
                         |
                         v
  +-----------------------------------------------------+
  |  CHECK EACH TIMER (in priority order):              |
  |                                                      |
  |  1. MANAGER CREDIT (manager_credit_at)              |
  |     * 2 minutes passed since customer agreed?       |
  |     * Not already sent? (manager_credit_sent=false)|
  |     -> Send "manager approved" follow-up SMS       |
  |     -> Set manager_credit_sent=true                |
  |                                                      |
  |  2. QUOTE FOLLOW-UP (quote_followup_at)             |
  |     * 1 minute passed since quote sent?            |
  |     * Customer hasn't replied? (last msg outbound) |
  |     * Not already sent? (quote_followup_sent=false)|
  |     -> Send "Any comments?" follow-up             |
  |     -> Set quote_followup_sent=true                |
  |                                                      |
  |  3. CALLBACK QUEUE (callback_at)                     |
  |     * callback_at time arrived?                    |
  |     * callback_sent != true?                        |
  |     -> Send "following up as planned" SMS          |
  |     -> callback_attempts++                          |
  |     -> If 3 attempts with no reply:                |
  |         clear callback_at (badge removed)          |
  |     -> If customer replies: clear callback_at     |
  |                                                      |
  |  4. CALLBACK PROPOSAL AUTO-CONFIRM                  |
  |     (pending_callback_proposed_at)                  |
  |     * 5 minutes passed since proposal sent?        |
  |     -> Promote to callback_at (auto-confirm)      |
  |     -> Clear pending proposal                      |
  |                                                      |
  |  5. BOT REACTIVATION SAFETY NET                     |
  |     * ai_bot_active = false? (rep paused it)     |
  |     * bot_permanently_stopped = false?            |
  |     * 15 minutes passed since last activity?      |
  |     * Lead not Stale/Failed?                       |
  |     -> Re-enable bot (ai_bot_active = true)       |
  |     (rep can pause for 15 min, then auto-resumes)|
  +-----------------------------------------------------+

6. Plan Advisor (Quote generation)

  Called by processAgentLeadReply when ready_for_quote=true
         |
         v
  +------------------------------------------------+
  |  INPUT: extracted_params from LLM              |
  |  * customerSegment (consumer/business)        |
  |  * products (internet/mobility/optik_tv/etc)  |
  |  * internet_speed (500MB/1.5GB/3GB)           |
  |  * telusHomeCustomer (M&H eligibility)        |
  |  * byodLines, contractLines (mobility)        |
  |  * eppDiscount (always false - bot never uses)|
  +---------------------+--------------------------+
                        |
                        v
  +------------------------------------------------+
  |  FETCH PLAN DOCUMENTS                          |
  |  * Filter by segment (consumer/business)      |
  |  * Filter by product type                     |
  |  * Check expiration_date (skip expired)       |
  |  * Get device price docs if mobility_w_device |
  +---------------------+--------------------------+
                        |
                        v
  +------------------------------------------------+
  |  BUILD LLM PROMPT                              |
  |  * Plan PDF URLs (uploaded docs)              |
  |  * Customer parameters                         |
  |  * Strict pricing rules:                       |
  |    - 1.5GB only ($75 2yr / $120 m2m)          |
  |    - No 1GB / 300MB                            |
  |    - Auto-pay already included                 |
  |    - M&H $10 off only if consumer mobility     |
  |    - No stacking discounts                     |
  |    - 2-year term default                       |
  +---------------------+--------------------------+
                        |
                        v
  +------------------------------------------------+
  |  INVOKE LLM (Claude Sonnet)                    |
  |  Reads plan PDFs + applies rules               |
  |  Returns formatted price quote                 |
  +---------------------+--------------------------+
                        |
                        v
  +------------------------------------------------+
  |  RETURN quote text to processAgentLeadReply    |
  |  -> appended to bot's reply message            |
  +------------------------------------------------+

7. Twilio SMS Infrastructure (Number pool & delivery)

  Any outbound SMS (bot reply, re-engagement, manual)
         |
         v
  +------------------------------------------------+
  |  sendSmsValidated(base44, {from, to, body})   |
  +---------------------+--------------------------+
                        |
                        v
  +------------------------------------------------+
  |  GET AVAILABLE POOL NUMBERS                    |
  |  * From env vars (TWILIO_PHONE_NUMBER 1-6)    |
  |  * Check each number's health record:          |
  |    - Permanently banned? -> exclude           |
  |    - Temporarily banned (24h)? -> exclude     |
  |  * Round-robin selection (rotate start index)  |
  +---------------------+--------------------------+
                        |
                        v
  +------------------------------------------------+
  |  TRY SEND on first number                      |
  |  POST to Twilio API                            |
  +---------------------+--------------------------+
                        |
             +----------+----------+
             v                     v
          SUCCESS               FAILURE
             |                     |
             v                     v
  +--------------+      +--------------------------+
  | Track success |      | Track failure            |
  | Update health |      | Update health:           |
  | (success++)   |      | failure++                |
  |               |      | * 3 fails in 24h -> 24h ban|
  |               |      | * 10+ fails -> permanent |
  |               |      |   ban                    |
  +-------+------+      +----------+---------------+
          |                        |
          |                        v
          |             +--------------------------+
          |             | RETRY on next pool number|
          |             | (repeat until success or |
          |             |  all numbers exhausted) |
          |             +----------+---------------+
          |                        |
          v                        v
  +----------------------------------------------+
  |  RETURN result                                |
  |  * ok: true/false                             |
  |  * sid: Twilio message SID                    |
  |  * from_number: the number that worked        |
  |  * error: failure reason                      |
  +----------------------------------------------+
         |
         v
  +------------------------------------------------+
  |  IF from_number changed (retry switched):     |
  |  * Update conversation.from_number            |
  |  * Update AgentLead.pinned_phone_number       |
  |  (so all future messages use the working num) |
  +------------------------------------------------+
         |
         v
  +------------------------------------------------+
  |  IF ALL NUMBERS FAILED:                        |
  |  * Mark lead "Failed" (undeliverable)         |
  |  * Stop bot permanently                         |
  |  * (This is NOT "Stale" - Stale = no reply)   |
  +------------------------------------------------+

8. Admin Reply Routing (EPP & Wireless checks)

  Team member at 7788614055 replies to a check SMS
         |
         v
  +------------------------------------------------+
  |  pollIncomingSMS detects admin number          |
  |  -> routes to specialized handler              |
  +---------------------+--------------------------+
                        |
           +------------+------------+
           v                        v
  +--------------+        +------------------+
  | EPP CHECK    |        | WIRELESS CHECK   |
  | handleEPPReply|       | handleWirelessReply|
  +-------+------+        +--------+---------+
          |                        |
          v                        v
  +--------------+        +--------------------------+
  | Match to     |        | Match to                 |
  | conversation |        | conversation              |
  | by pending_  |        | by pending_wireless_     |
  | epp_workplace|        | address                  |
  +-------+------+        +--------+-----------------+
          |                        |
          v                        v
  +--------------+        +--------------------------+
  | Reply "YES"? |        | Reply contains          |
  | -> Customer  |        | availability info?       |
  |   qualifies  |        | -> Send $65 Wireless    |
  | -> Rep follows|       |   offer to customer     |
  |   up with    |        |   (or "not available")  |
  |   EPP price  |        |                          |
  |              |        | Store result,            |
  | Reply "NO"?  |        | clear pending state     |
  | -> Customer  |        |                          |
  |   doesn't    |        | Customer replies ->     |
  |   qualify    |        | processAgentLeadReply   |
  |              |        | handles next step        |
  | Clear pending|        | (Veriff if YES,          |
  | epp state    |        |  reassurance if NO)      |
  +--------------+        +--------------------------+

9. Lead Status Lifecycle

  +---------+
  |   New   | <- Created (sync/manual/ai_agent)
  +----+----+
       | (opening message sent)
       v
  +-----------+
  | Contacted | <- Bot sent opening, no customer reply yet
  +-----+-----+
       | (customer replies)
       v
  +------------------+
  | In Conversation | <- Customer actively replying
  +--------+---------+
       |            |
       | (3+ days    | (customer agrees to price)
       |  silent)    v
       v        +----------+
  +----------+  | Awaiting | <- Sale done, install date TBD
  | Contacted|  | Install  |
  +-----+----+  +-----+----+
       |              | (install date set)
       |              v
       |         +--------+
       |         | Closed | <- Sale complete + install date
       |         +--------+
       |
       | (20+ outbound, 0 inbound)
       v
  +--------+         +------------------+
  | Stale  |         |   Not Interested  |
  +--------+         | <- Customer declined/
                     |   STOP / in contract /
                     |   already serviced
                     +------------------+

  +--------+
  | Failed | <- SMS undeliverable / invalid number
  +--------+ (bot permanently stopped)

  REACTIVATION RULES:
  * Stale + customer replies -> "In Conversation" (bot resumes)
  * Contacted + customer replies -> "In Conversation"
  * Any status + send fails -> "Failed" (bot stops)
  * Any status + customer declines -> "Not Interested" (bot stops)

10. Veriff ID Verification Flow

  Customer agrees to price (processAgentLeadReply)
         |
         v
  +------------------------------------------------+
  |  LLM sets ready_for_veriff = true              |
  |  (or mentions Veriff/link in message)          |
  +---------------------+--------------------------+
                        |
                        v
  +------------------------------------------------+
  |  createVeriffSession (shared/veriff.ts)        |
  |  * POST to Veriff API                          |
  |  * Returns { sessionId, url }                  |
  +---------------------+--------------------------+
                        |
                        v
  +------------------------------------------------+
  |  Append Veriff URL to bot reply                |
  |  Update AgentLead:                             |
  |  * veriff_session_id = sessionId                |
  |  * veriff_verification_status = "pending"      |
  +---------------------+--------------------------+
                        |
                        v
  +------------------------------------------------+
  |  Customer clicks link -> Veriff web session    |
  |  Customer completes ID verification             |
  +---------------------+--------------------------+
                        |
                        v
  +------------------------------------------------+
  |  Veriff webhook -> handleVeriffWebhook        |
  |  * Updates veriff_verification_status           |
  |    (approved / declined / resubmitted)         |
  +------------------------------------------------+

11. Learning System (Manual rep interventions)

  Rep manually replies to a customer (pauses bot)
         |
         v
  +------------------------------------------------+
  |  learnFromManualReply (shared)                 |
  |  * Capture trigger_message (customer's msg)    |
  |  * Capture conversation_context (last msgs)    |
  |  * Capture manual_reply (rep's response)       |
  |  -> Store as ManualReplyExample                |
  +---------------------+--------------------------+
                        |
                        v
  +------------------------------------------------+
  |  Infer LearnedPattern via LLM                  |
  |  * situation: what was happening               |
  |  * customer_need: what customer wanted         |
  |  * obstacle: what was blocking                 |
  |  * human_action: what rep did                   |
  |  * reasoning: why it was appropriate           |
  |  * conditions: when to apply                   |
  |  * exclusions: when NOT to apply               |
  |  * generalized_rule: reusable decision rule     |
  |  * keywords: tags for matching                 |
  |  * pattern_status: "candidate" (single example)|
  |  * confidence: 0.0-1.0                         |
  +---------------------+--------------------------+
                        |
                        v
  +------------------------------------------------+
  |  FUTURE CONVERSATIONS:                         |
  |  processAgentLeadReply loads top patterns      |
  |  * Score by keyword overlap + status + conf    |
  |  * Inject top 4 into LLM context               |
  |  * Bot applies pattern ONLY if:                |
  |    - Current conditions match                  |
  |    - Action is authorized by core rules        |
  |    - (patterns never grant new authority)      |
  +---------------------+--------------------------+
                        |
                        v
  +------------------------------------------------+
  |  VALIDATION OVER TIME:                         |
  |  * Similar situation + similar action ->       |
  |    validation_count++, -> "validated"          |
  |  * Similar situation + different action ->     |
  |    contradiction_count++, -> "invalidated"      |
  +------------------------------------------------+

12. End-to-End Customer Journey Summary

  1. Lead fills Facebook/Google form
     -> Google Sheet
     -> syncGoogleSheetLeads (every 2 min)
     -> AgentLead created
     -> startAIChatForLead sends opening SMS
     -> Status: "Contacted"

  2. Customer replies
     -> Twilio webhook / pollIncomingSMS
     -> Save inbound message
     -> Reactivate if Stale
     -> processAgentLeadReply
     -> LLM generates reply (with context)
     -> Plan Advisor quote (if qualified)
     -> Send via Twilio pool
     -> Status: "In Conversation"

  3. Customer goes quiet
     -> sendReengagementMessages (hourly)
     -> 20-msg sequence (never replied) OR
       7-day sequence (replied then quiet)
     -> LLM-generated follow-ups
     -> If exhausted: Status "Stale", bot stops

  4. Customer re-engages
     -> pollIncomingSMS detects reply
     -> Reactivate Stale -> "In Conversation"
     -> Clear re-engagement state
     -> processAgentLeadReply resumes

  5. Customer agrees to price
     -> LLM sets ready_for_veriff
     -> createVeriffSession
     -> Veriff URL sent to customer
     -> Customer verifies ID
     -> Veriff webhook updates status
     -> Rep follows up to complete sale

  6. Sale complete
     -> Rep marks "Closed" (with install date)
     -> OR "Awaiting Install" (TBD)
     -> installationFollowup sent 1 day post-install