Paitho
← Product / Stage 11 · Funnel Tracked
Pipeline · Stage 11

Outcomes back to
the exact prompt.

IMAP poll detects replies and tags funnel_replied. Humans move the lead through booked, demo, won, or lost. Every event links back to the email_prompt_id that drafted the message — the input the self-teaching loop runs on.

What goes in, what comes out.

Inputs
Sent message + IMAP
  • email_message.messageId — RFC id for thread match
  • workspace.imap[] — per-brand inboxes polled (default ~120s cadence)
  • imap.replyDetectRegex — ID + In-Reply-To header check
  • lead.activityLog — opens, clicks, replies, manual notes
  • workspace.userId — operator transitioning the lead
Outputs
funnel_event[]
  • funnel_replied — auto, on IMAP detect
  • funnel_call_booked — manual transition
  • funnel_demo — manual transition
  • funnel_closed_won, funnel_closed_lost
  • funnel_event.email_prompt_id — back-link for attribution
  • funnel_event.lagDays — days since send
  • funnel_event.notes — operator-added context
Closes the loop: prompt_v × pack × outcome

Auto on reply.
Manual past that.

funnel_replied— auto
funnel_call_booked— manual
funnel_demo— manual
funnel_closed_won— manual
funnel_closed_lost— manual + reason
— each event back-links to the email_prompt_id that drafted the message

Reply detection is automatic. The IMAP service polls each brand's inbox on a short cadence and matches incoming messages by RFC In-Reply-To header against the workspace's outgoing message ids. A match fires funnel_replied on the lead, attaches the reply body to the activity log, and surfaces the lead at the top of the operator's queue. The system does not classify reply sentiment — that's an operator judgment, made cleanly with the message text in front of them.

From funnel_replied onwards the operator drives the lead through the funnel. funnel_call_booked when a meeting lands. funnel_demo when the call happens. funnel_closed_won or funnel_closed_lost at the end, with a structured loss-reason on lost deals. Each transition timestamps and stores the operator id, so the activity log per lead reads as a clean timeline a sales manager can audit.

The attribution is what closes the self-teaching loop. Every funnel event carries the email_prompt_id of the message that earned it. After enough volume, the prompt registry can answer questions like "which email_draft_v19 variant has the highest reply-to-booked rate on the marketing pack" from a single SQL query — not a slide deck. That's the input that makes next quarter's prompts measurably better than this quarter's.

Header match. Header attribution.

imap · reply_detect · fintech +
--- imap poll ---
every 120s, per workspace.brands[]:
  inbox = imap.connect(brand.imap)
  for msg in inbox.unread():
    inReply  = msg.header("In-Reply-To")
    refs     = msg.header("References")
    candidate = inReply || pickFrom(refs)
    if (!candidate) continue;

    sent = email_messages.findOne({ messageId: candidate });
    if (!sent) continue;       # not ours, skip

    db.funnel_events.insert({
      lead_id:         sent.lead_id,
      kind:            "funnel_replied",
      detected_at:     now(),
      email_prompt_id: sent.email_prompt_id,   # self-teaching link
      lag_days:        daysBetween(sent.sent_at, now()),
      reply_body:      msg.text
    });

    activity_log.append(lead_id: sent.lead_id, event: "replied", body: msg.text);

--- manual transitions ---
PUT /leads/:id/funnel
{
  "kind":  "call_booked"|"demo"|"closed_won"|"closed_lost",
  "notes": string,
  "lossReason": string|null     # required on closed_lost
}

--- attribution rollup ---
SELECT email_prompt_id, COUNT(*) AS replied
FROM   funnel_events
WHERE  kind = 'funnel_replied'
       AND lead.pack = 'fintech'
GROUP BY email_prompt_id
ORDER BY replied DESC;

# <!-- PLACEHOLDER — exact poll cadence per workspace plan -->

What can break.
And what catches it.

Risk
Auto-reply false positive

Out-of-office bounce-back tags the lead as replied, pollutes the funnel.

Mitigation

Auto-response detection (Auto-Submitted, X-Auto-Response-Suppress, common OOO patterns) tags the event as replied_auto, separated from human replies in attribution.

Risk
Lost attribution chain

Funnel event lacks the prompt id that drafted it; loop is broken.

Mitigation

Funnel write requires email_prompt_id via foreign key. Manual transitions inherit it from the lead's most recent sent message.

Risk
Stalled lead drift

Lead replies, no manual follow-up, sits in the pipeline forever.

Mitigation

Stale-replied alert per assignee. After a configurable window, the lead surfaces in the operator's daily queue with a nudge.

Funnel events feed the self-teaching loop. Each outcome links back to the prompt variant that drafted the message.

Close the loop on outcomes.
In a sandbox, in 2 minutes.

Send a thread. Reply from another inbox. Watch the funnel event land with the prompt id attached.