Business logic

This module is the answer to "why did the system do that?". Every page describes rules that are implemented in code, with the thresholds, formulas, and suppression conditions spelled out and the implementing file named.

The proposition

Payability advances marketplace sellers their revenue ahead of the platform’s payout cycle. A seller who is growing, holds a lot of inventory, and waits two weeks for Amazon to pay feels that gap acutely. Morpheus exists to find those sellers, prove they are worth a call, and put them in front of a human at the moment a call is most likely to land.

Three judgements drive everything:

  1. Is this seller in the ideal customer profile? — revenue band, category, marketplace. Decided at discovery.

  2. How acutely do they feel payout pain? — the payout-pain score, 0–100. Decided by an AI pass over structured seller data and enrichment notes.

  3. Is now the right moment to call? — re-engagement segmentation and priority. Decided every few hours from CRM engagement data.

Rule pages

Page What it decides

Outbound funnel

The end-to-end lifecycle from marketplace row to booked demo, and which component owns each transition

Seller discovery

Which sellers enter the pipeline: ICP bounds, pagination, the kill switch

Seller enrichment

How contact intelligence is gathered and written back, and what is skipped

Payout-pain score

The eight signals and weights behind payoutPainScore

CRM sync

How sellers become HubSpot Companies and contacts become HubSpot Contacts, and the search priority for matching

Re-engagement segments

The five segments that surface a contact for another call, with each priority formula

Daily call lists

How today’s list is assembled, prioritised, and materialised in HubSpot

Follow-up tasks and escalation

Task creation, HubSpot mirroring, the three-stage Slack escalation ladder

Email engagement

Reply categorisation, engagement events, opt-outs and suppression

Phone line intelligence

Line-type classification, risk tiers, and automatic blocking

Call logging and dispositions

AI dialer and Five9 call sync, disposition mapping, lifecycle promotion

Ownership and round-robin

Who a contact gets assigned to, and when ownership is overridden

Cross-cutting rules

These hold everywhere and are not repeated on each page.

Single tenant, explicitly checked

Production runs one subscription, b191a905-5d19-4fa0-941b-d8eb81c0c477. Handlers that receive a subscription_id on the event compare it to their configured value and drop mismatches. email-agent instead derives the tenant from the row it loaded. See tenant isolation.

Idempotence over exactness

Every write is designed to be safely repeatable — ON CONFLICT DO UPDATE upserts on natural keys, find-or-create for contacts, "already done" guards on enrichedAt and payoutPainScore. A handler that runs twice must not double anything that matters.

Suppression beats enrolment

When a suppression rule and an enrolment rule both apply, suppression wins. Blocked dispositions, do-not-contact reasons, open deals, and "called today" checks all remove a contact from a segment before any priority is computed.

US Eastern is the business day

"Today" for call lists means the calendar date in US Eastern, approximated as UTC−4 in code. The daily list refresh runs at 6 AM ET, an hour at which EDT and EST agree on the date, so the fixed offset is safe there. Handlers that run around midnight UTC can disagree with a true America/New_York date by an hour during EST.

Ownership is sticky, except when it is not real

A contact keeps its owner. Reassignment happens only when there is no owner, the owner is the AI fallback owner (86817215), or the owner is not an active sales_reps row. See Ownership and round-robin.

AI output is validated, never trusted raw

Every agent that produces data uses Strands structured output with a Pydantic model. Nothing parses JSON out of free-form model text.