94 lines
2.7 KiB
Markdown
94 lines
2.7 KiB
Markdown
# Reply Rate Engine
|
|
|
|
## Problem
|
|
|
|
Current MVP replies to **every** matched warmup email (~100%). Real humans and reputable warmup tools reply to a **fraction** of mail (typically 30%, max recommended 45%).
|
|
|
|
## Configuration
|
|
|
|
| Parameter | Default | Min | Max recommended |
|
|
|-----------|---------|-----|-----------------|
|
|
| `replyRatePercent` | 30 | 10 | 45 |
|
|
|
|
Set per `WarmupCampaign`. Hard cap at 45% in validation.
|
|
|
|
## Semantics
|
|
|
|
**Reply rate** = of warmup emails received by the primary (or sent to primary from satellites), the percentage that receive an AI-generated reply that day.
|
|
|
|
Not the same as cold-email response rate — this is warmup engagement simulation only.
|
|
|
|
## Algorithm
|
|
|
|
### On rescuer cycle (per received warmup message)
|
|
|
|
```
|
|
function shouldReply(campaign, message, statsToday):
|
|
target = campaign.replyRatePercent
|
|
actual = statsToday.replies / max(statsToday.received, 1) * 100
|
|
|
|
if actual >= target:
|
|
return false // quota met for today
|
|
|
|
// Probabilistic: bias toward hitting target by end of day
|
|
remaining = statsToday.received - statsToday.replies
|
|
needed = ceil(statsToday.received * target/100) - statsToday.replies
|
|
probability = needed / max(remaining, 1)
|
|
|
|
return random() < probability
|
|
```
|
|
|
|
### Properties
|
|
|
|
- Deterministic enough to converge on daily target
|
|
- Stochastic enough to avoid fixed patterns
|
|
- Never exceeds 45% even if configured wrong (clamp)
|
|
|
|
## What still happens at 0% reply (for a given message)
|
|
|
|
Even when not replying:
|
|
|
|
1. Spam rescue still runs (move to inbox, flag)
|
|
2. Mark as read
|
|
3. Log status may be `complete` without `replied` — new status: `engaged_no_reply`
|
|
|
|
### Extended WarmupStatus enum
|
|
|
|
| Status | Meaning |
|
|
|--------|---------|
|
|
| sent | Delivered from satellite |
|
|
| delivered | Confirmed in primary inbox (optional) |
|
|
| rescued_from_spam | Moved from spam folder |
|
|
| engaged_no_reply | Read/flagged, no reply sent |
|
|
| replied | Reply sent |
|
|
| complete | Thread closed |
|
|
|
|
## Reply direction
|
|
|
|
| Step | From | To |
|
|
|------|------|-----|
|
|
| 1. Warmup send | Satellite | Primary |
|
|
| 2. Reply (if sampled) | Primary | Satellite |
|
|
|
|
Maintains realistic thread: primary appears engaged with incoming mail.
|
|
|
|
## Daily reply budget
|
|
|
|
```
|
|
plannedReplies = ceil(plannedSends * replyRatePercent / 100)
|
|
```
|
|
|
|
Shown on dashboard: `replies today: 8/12 planned`
|
|
|
|
## Edge cases
|
|
|
|
| Case | Handling |
|
|
|------|----------|
|
|
| All messages arrive at 23:59 | Spread replies across rescuer cycles |
|
|
| Reply SMTP fails | Retry once; log error; don't count toward rate |
|
|
| Primary in error | Pause replies; satellites may still send |
|
|
| Satellite in error | Exclude from pool; rebalance |
|
|
|
|
## ESP rationale
|
|
|
|
100% reply rate on automated mail is a detection signal. Variable reply rate + rescue without reply on some messages mimics real mailbox behavior more closely.
|