LeadRefinery — How the Platform Works

Import and scrub

Traced at commit ffe4e48 · apps/api/src/app/imports/* · libs/contracts/src/lib/scrub.ts · libs/temporal/src/activities/scrub.ts

Summary

  1. A client uploads a CSV or XLSX file.
  2. The platform checks the shape of each row.
  3. A rejected row is either remediable or terminal.
  4. An accepted row becomes a lead.
  5. Every number starts with the scrub status PENDING.
  6. A PENDING number never dials. Gate check 4 refuses it.
  7. A scrub provider checks the number. The worst hit wins.
  8. If nobody configures a provider, numbers stay PENDING and nothing dials. This is the designed behaviour.
A client uploads a file. The platform checks the shape of each row and separates rejects into remediable ones the client can fix and resend, and terminal ones that cannot be used. Accepted rows become leads and their numbers are stored with a scrub status of pending. A pending number never dials. A scrub provider then checks each number against do-not-call, litigator and reassigned-number databases, and the worst hit wins. A clean number can be queued and a hit suppresses the lead. If no provider is configured, numbers stay pending forever and nothing dials.
Workflow 1 of 2 — the file. Rows become leads, or become a reject with a class and a reason.

Workflow 1 — the file

  1. A client uploads a CSV file or an XLSX file.
  2. The platform reads the columns and checks the format of each field.
  3. The platform checks each phone number.
  4. An accepted row becomes a lead in the state INGESTED, then VALIDATED.
  5. The platform records a rejected row with a class and a reason.

The two reject classes

  1. Remediable — the client can correct the row and send the file again.
  2. Terminal — the platform cannot use the row.
  3. The distinction tells a client where to spend effort.
  4. A client can act on a remediable reject. A client cannot act on a terminal one.

Workflow 2 — the scrub

Every imported number starts pending, and a pending number never dials because gate check four refuses it. A provider checks each number against do-not-call registers, litigator lists and reassigned-number data, and the worst hit wins. A clean number lets the lead be queued, a hit suppresses the lead, and a result older than the freshness window is refused as if it were absent. Three provider settings exist: none, the default, which scrubs nothing so nothing dials; a stub, which returns clean and stamps its result so no audit record mistakes it for a vendor verdict; and a real vendor.
Workflow 2 of 2 — the scrub. The default setting dials nothing, on purpose.

What the scrub does

  1. Every imported number starts with the status PENDING.
  2. A scrub provider checks the number against three databases.
  3. The databases cover do-not-call registers, litigators and reassigned numbers.
  4. A number can match more than one. The worst hit wins.
  5. The hit types are dnc_federal, dnc_state, litigator, reassigned_number and invalid_number.
  6. A clean number lets the lead move to QUEUED.
  7. A hit suppresses the lead.
  8. The result has a freshness window. Gate check 4 refuses a result that is too old.

When nobody configures a provider

  1. The default provider is none.
  2. The provider none scrubs nothing.
  3. Numbers stay PENDING.
  4. Gate check 4 refuses every PENDING number.
  5. Nothing dials. The platform fails closed.
  6. A stub provider returns clean for every number.
  7. The stub stamps its result so no audit record can mistake it for a vendor verdict.
  8. The stub is for pilot and development use. An unset environment does not enable it.

Do not fix a stalled import by hand. Setting scrub_status to CLEAN in the database satisfies the gate by assertion. No vendor verdict stands behind that value. The audit record cannot show the difference later.

Lead lifecycle and cadence — what happens to a lead after the scrub clears it.