warmbox/docs/07-reply-rate-engine.md

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.