**TL;DR:** Check webhook delivery health before trusting cached stage, and do a live ATS stage read right before every outreach send. The follow-up went to a declined candidate because status-change webhooks were the only update path and they died silently. Monitor the pipe itself, not just the work it carries.

```text
outreach agent sent a follow-up to a candidate who already declined  -  the ATS webhook for status changes wasn't firing
```

1. Check webhook delivery status in the ATS dashboard and your endpoint logs.
   Expected: deliveries failing, the subscription paused, or the endpoint returning errors.
2. Fix the endpoint or re-subscribe, then replay the missed status-change events.
   Expected: the candidate's stage updates to declined in the agent's records.
3. Add a pre-send stage gate: every follow-up does a live ATS read of the candidate's stage, and terminal stages block the send.
   Expected: in a test against a declined candidate, the gate stops the email.
4. Add a dead-man's switch: if no status-change events arrive for a job in 24 hours on a business day, alert the team.
   Expected: the alert fires during a simulated webhook outage.
5. Maintain a suppression list of terminal stages and check it at send time regardless of webhook state.
   Expected: declined, rejected, and hired candidates are excluded even with webhooks fully down.

## Use this when
- Outreach reaches candidates in terminal stages (declined, rejected, hired).
- The agent caches candidate stage and depends on webhooks for updates.
- Webhook delivery is unmonitored.

## Not for this skill when
- The webhook fired and the agent processed it but still sent (that is a sequencing bug in the agent, not a delivery failure).
- The stage was wrong in the ATS itself.
- The candidate declined after the follow-up was correctly sent.

## Variant phrasings
- follow-up email sent to a candidate who already declined
- outreach agent did not know the candidate said no
- status change webhook stopped firing and outreach kept going
- declined candidates still getting sequenced emails

## Why it happens
The outreach agent cached stage at campaign start and subscribed to webhooks as its only freshness mechanism. Webhook delivery is best-effort: subscriptions pause, endpoints break, secrets rotate. When the pipe went quiet, the agent read silence as "nothing changed" instead of "I have stopped hearing anything." Emailing a candidate who said no is the kind of error that costs trust, so the send-time gate matters more than the cache.

## Edge cases
- Webhook delayed vs dead: a delayed event eventually arrives and a dead one never does. The dead-man's switch distinguishes them by time, and the pre-send gate covers both.
- The candidate declines between the pre-send check and the send: keep that window seconds long and accept the residual risk.
- Custom terminal stages per job: the suppression list must be per-workflow, or a renamed stage slips through.
- Re-applied candidates: someone declined in March who reapplies in October is a new opportunity, not a suppression hit. Key suppression on the application, not the person.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_H9HgQvxCLIdlKAQEZQyrCg
