Outbound funnel

Stages

flowchart TD
  A["Marketplace row\nSmartScout search result"] --> B["Seller row\nsellers.lifeCycleStage = new"]
  B --> C["Enriched seller\nwebsite, LinkedIn, contacts\nlifeCycleStage = enriched"]
  C --> D["Scored seller\npayoutPainScore 0-100"]
  D --> E["HubSpot Company\n+ associated Contacts"]
  E --> F["Outreach\nemail campaign / AI dialer"]
  F --> G["Engagement signal\nclick, reply, call outcome, account created"]
  G --> H["Re-engagement segment\nBigQuery view membership"]
  H --> I["Daily call list\ncall_list_date + call_priority + owner"]
  I --> J["Rep call\nFive9 or Nooks"]
  J --> K["Follow-up task\nfollow_up_tasks + HubSpot Task"]
  K --> L["Deal\nHubSpot Deal / demo booked"]
  J -->|no answer, stale| H
  L -->|lost or stalled| H

Who owns each transition

Transition Owner Rule reference

Marketplace row → seller row

enrichment-scraper → EnrichmentPipelineQueue → enrichment-scorer

Seller discovery

Seller row → enriched

enrichment-scorer, first AI pass (Claude Haiku 4.5 + Tavily + HubSpot MCP)

Seller enrichment

Enriched → scored

enrichment-scorer, second AI pass (Claude Haiku 3, no tools)

Payout-pain score

Scored → HubSpot Company + Contacts

Seller.CrmSync → morpheus-hubspot

CRM sync

HubSpot → outreach

The Payability web application (campaigns, sequences, AI dialer) — outside this repository

—

Outreach → engagement signal

HubSpot engagements, email_campaign_targets state, Call rows; mirrored into BigQuery

Email engagement, Call logging

Engagement signal → segment membership

BigQuery views in bigquery/*.sql

Re-engagement segments

Segment → daily call list

Five scheduled handlers across morpheus-hubspot and phone-agent

Daily call lists

Call list → materialised HubSpot list

Hubspot.SalesRepCallListRefresh, daily

List materialisation

Rep call → logged call

Crm.DialerCallEnded (AI dialer) and Hubspot.Five9CallSync (human dialer)

Call logging and dispositions

Call → follow-up task

Crm.TaskCreate, plus Phone.CampaignTargetReEngagement

Follow-up tasks and escalation

Task → completion or failure

Hubspot.FollowUpTaskPoll and Phone.TaskDeadlineReminder

Escalation ladder

Deal stage changes

Crm.DealUpdate

Deals

Seller lifecycle stages

sellers.lifeCycleStage (SellerLifeCycleStage enum). The pipeline only ever writes new (at ingest) and enriched (after a successful enrichment pass). The later stages exist for the wider platform.

new → raw_lead → enriched → in_sequence → engaged → qualified
    → bdr_handoff → demo_scheduled → opportunity → customer
    (or disqualified)

Two columns act as pipeline gates rather than stages:

Column Gate

enrichedAt

Non-null means the enrichment pass has run. SellerReceivedHandler skips enrichment when it is set; get_pending_enrichment() selects rows where lifeCycleStage = new and it is null.

payoutPainScore

Non-null means the scoring pass has run. get_pending_scoring() selects enriched rows where it is null.

Contact lifecycle stages

contacts.lifecycleStage mirrors HubSpot’s lifecyclestage. Morpheus only ever promotes, never demotes: maybe_promote_lifecycle_stage() in lambdas/morpheus_hubspot/services/lifecycle_stage.py ranks the current stage and writes marketingqualifiedlead only when the current rank is lower.

Stage Rank

subscriber

0

lead

1

other

1

marketingqualifiedlead

2

salesqualifiedlead

3

opportunity

4

customer

5

evangelist

6

The whole function is best-effort: a CRM read or write failure is logged and the caller continues. See lifecycle promotion.

Two directions of travel

Forward — new sellers

Discovery → enrichment → scoring → CRM. Driven by SmartScout and queue messages. This path creates records.

Backward — existing contacts

Engagement signal → BigQuery segment → call list. Driven by schedules and CRM data. This path creates attention, not records. It is where most of the business logic now lives, because the CRM already contains far more contacts than discovery adds.

Both converge on the same asset: a prioritised, owned, dated call list that a human works top-down.