Lead lifecycle and cadence
Traced at commit ffe4e48 ·
libs/contracts/src/lib/lifecycle-machine.ts ·
libs/contracts/src/lib/{cadence-schedule,cadence-c1}.ts ·
libs/db/src/schema/leads.ts
Summary
- A lead has 10 states.
- The platform ingests, validates, scrubs and queues a lead before a campaign can use it.
- The pacer releases the lead. The lead then becomes
CYCLE_ACTIVE. - Each dispatched attempt moves the lead to
HELD. - A lead in
HELDcannot advance, cannot be re-dialled and cannot rest. - The lead leaves
HELDonly after the platform writes the outcome. - The programme has 3 cycles: 5, 4 and 3 attempts, over 6, 5 and 4 business days.
- A lead in
TERMINALalways has a recorded reason. The database enforces this.
HELD stops a lead while a call has no outcome.Workflow 1 — the states
Before a campaign can use the lead
INGESTED— the platform has the row.VALIDATED— the row passed the shape checks.SCRUB_PENDING— the number is waiting for a do-not-call check.QUEUED— the scrub cleared the number. The pacer can release the lead.SUPPRESSED— the scrub flagged the number. The lead stops here.
Inside a cycle
- The pacer releases the lead. The state becomes
CYCLE_ACTIVE. - The platform dispatches an attempt. The state becomes
HELD. - The platform writes the outcome. The state returns to
CYCLE_ACTIVE. - A captured commitment, such as a call-back time, moves the lead to
SCHEDULED. - A completed cycle moves the lead to
CYCLE_GAP. - The gap ends. The state returns to
CYCLE_ACTIVEfor the next cycle.
HELD is the important state. Three events are absent from
it, on purpose. The cycle cannot complete. The gap cannot start. The platform cannot
dispatch a second attempt. That absence stops the attempt counter when a call merely
ends. The counter advances only after the platform knows the outcome. Without
HELD, a lead spends its cycle on calls that nobody resolved.
Workflow 2 — the calling calendar
- Cycle 1 — 5 attempts over 6 business days.
- Cycle 2 — 4 attempts over 5 business days.
- Cycle 3 — 3 attempts over 4 business days.
- A gap separates each cycle from the next.
- Attempts spread across four dayparts: morning, midday, afternoon and evening.
- After cycle 3 the programme has no attempts left. The lead becomes
TERMINAL.
How a lead ends
CONVERTED— the lead reached the outcome the campaign wanted.DECLINED— the person said no.CYCLES_EXHAUSTED— the programme used every attempt.NO_DIALABLE_NUMBER— the platform cannot call any number on the lead.CAMPAIGN_KILLED— an operator stopped the campaign.PROGRAMME_ENDED— the programme finished.MANUAL— a person ended the lead.- The database rejects a lead in
TERMINALthat has no reason.
The dial gate — what happens between
CYCLE_ACTIVE and a ringing phone.