# Runbook — the notification never arrives

> **Symptom.** *"no me llegan las notificaciones cuando alguien agenda"* · *"no me avisa cuando un
> lead pide hablar con alguien"* · *"I never get the Slack alert"* · *"me llega el aviso pero sin
> los datos"*.
>
> Same chain as every other automation on this platform, and the same rule: the conversational agent
> does not send notifications. An external evaluator fills a property, and a notification consumes
> it. Check the chain from the end.

```text
lead does something  →  property flips  →  notification consumes it  →  message reaches a destination
```

---

### H1 — The destination is wrong

**Check this first, it is one call and it is frequently the whole answer.** A destination configured
with the wrong kind of identifier — a channel id where a webhook belongs — accepts the
configuration and delivers nothing. There is no error anywhere the operator can see.

- **Test:** `list_notification_destinations` and read what is actually stored.
- **Stop condition:** the destination holds the wrong kind of value → **you're done**.
- **Fix:** `upsert_notification_destination` with the correct one, then send a test.

*Evidence: the same identifier mix-up in two unrelated agents, months apart. It is not a one-off.*

### H2 — The alerting layer was never built

Detection (properties) and stopping (contact limits) get built together; alerting quietly does not,
because it usually needs a webhook that only the account owner can authorize. The work stalls there
and nobody notices until the operator asks why they were not told.

- **Test:** `list_custom_notifications`. Nothing at all is the answer.
- **Stop condition:** no notification exists → **you're done**.
- **Fix:** `upsert_custom_notification` gated on the property, and get the destination authorized.
  If it is blocked on the owner, say so explicitly rather than leaving it half-built.

### H3 — The property never flips

If the value never becomes true, the notification is correct and simply never triggers.

- **Test:** `list_custom_properties`, read the description, then check the value on a contact where
  the event definitely happened.
- **Stop condition:** false on a contact who clearly did the thing → **you're done**.
- **Fix:** `upsert_custom_property`. The description must contain the phrases leads actually use.
  A description missing its anchor phrases is the most common version of this.

*Evidence: a hand-off notification that never fired because the property description omitted the
phrases operators actually used to escalate.*

### H4 — The property fires far too broadly

The mirror image, and worse, because a property that gates a notification often gates a contact
limit too. One over-broad description then does three things at once: fires the alert on ordinary
messages, mutes the agent, and stops the follow-ups.

- **Test:** count how many contacts hold the property true. If it is most of them, the description
  is too wide.
- **Stop condition:** the true rate is implausible → **you're done**.
- **Fix:** narrow the description, and check what else consumes the same property before changing
  it. Changing a property is never a local edit.

*Evidence: a hand-off property that flipped on a casual "give me a second, let me check" — a phrase
the operator used constantly and meant nothing by. It muted the agent, killed the follow-ups and
fired the alert, all from one sentence.*

### H5 — It arrives, but without the data

The notification body is written assuming a substitution the destination does not perform. It
delivers, and the operator gets a message with placeholders or missing context, which they report as
"the notification doesn't work".

- **Test:** read the stored body and compare it to what actually arrived.
- **Stop condition:** the body contains a token that came through literally → **you're done**.
- **Fix:** rewrite the body with what the destination genuinely substitutes. Send a real test rather
  than reasoning about it.

*Evidence: a notification body written around a substitution that Slack does not do; it delivered
every time and was useless every time.*

---

## When to stop

If the destination is right, the notification exists and is gated on a property that holds the
expected value, and the body renders, capture it: the notification id, the destination, the contact
and property value with a timestamp, and the event that should have alerted. Send that with
`report_feedback`.
