concept
CH table metadata: esios.alert_rules
User-defined alerts. One row per rule: a freeform ClickHouse condition (`condition_sql`, fires when it returns ≥1 row) or a freshness watch (`kind='freshness'`), checked on a `schedule` spec (interval | daily | weekly | monthly | cron | on_ingest — see src/alerts/schedule.py). The worker drain loop evaluates rules whose `next_due_at` has passed; delivery is webhook (signed POST) or pull (read via MCP `alerts_pending`). The condition is validated against the creator's tier at creation AND re-vali
# `esios.alert_rules`
User-defined alerts. One row per rule: a freeform ClickHouse condition (`condition_sql`, fires when it returns ≥1 row) or a freshness watch (`kind='freshness'`), checked on a `schedule` spec (interval | daily | weekly | monthly | cron | on_ingest — see src/alerts/schedule.py). The worker drain loop evaluates rules whose `next_due_at` has passed; delivery is webhook (signed POST) or pull (read via MCP `alerts_pending`). The condition is validated against the creator's tier at creation AND re-validated on every evaluation, so a rule can never read what a live `query` on that tier couldn't. MCP tools: alerts_create/list/delete/pending/ack. Quotas: ALERT_RULE_QUOTA; schedule floors: ALERT_SCHEDULE_FLOORS.