Watchdogs
Overview
trigger/watchdog.ts is SABLE's independent backstop for board delivery: it
does not trust the report pipeline's own success signal (reports.md),
it verifies delivery directly against the board_runs table. trigger/smoke.ts's
sableSmoke is grouped here as the closest fit among the four pages, even
though — as noted below — it is not actually a scheduled health check.
How it works
checkKind(kind) ("morning" or "eod") runs in three steps:
- Self-test the alert channel first, before any database work. If
RESEND_API_KEYorSABLE_OPS_ALERT_EMAILisn't set, the run throws immediately. This is deliberate: a watchdog whose alert path is broken otherwise "passes" every single day right up until the one day it actually needs to alert — and only then discovers the alert channel was never configured. - Resolve the org and query
board_runsfor rows whereas_ofis today (America/New_York) andorg_idmatches, wrapped inwithAlertOnCheckFailure: if the query itself throws (e.g. Supabase is unreachable), the watchdog still fires a best-effort ops alert saying delivery status is unknown, not confirmed-missing, and then always rethrows so the Trigger run fails red. The code comments call out that this is exactly the failure mode behind a July 15–21 outage, where the check itself failing went silent before this guard existed. - Apply
watchdogVerdict. Adelivered: truerow for today and the requested kind isok. A row that exists but isn't delivered reports thedelivery_status. No row at all reports "no delivered<kind>board for<date>". Any non-okverdict triggers a Resend alert naming the reason and pointing at Trigger.dev runs,trigger_runs, andREPORT_REQUIRED_CONNECTORSas starting points.
sendOpsAlert posts directly to the Resend API (POST https://api.resend.com/emails) — it is a separate call path from the
best-effort alerting reports.md's report pipeline uses, and that
separation is intentional: the watchdog's own ability to alert must not
depend on anything in the report pipeline having worked correctly.
sableSmoke is unrelated to any of this. It opens a trigger_runs row,
records which two env vars it checked (SUPABASE_URL,
SUPABASE_SERVICE_ROLE_KEY), and marks itself complete. It has no cron, no
alerting, and no verdict logic — it exists to be triggered by hand as a
basic "is this environment wired up at all" connectivity check.
Tasks
| Task | Trigger / cron | What it does |
|---|---|---|
morningWatchdog | schedule, cron pattern 45 6 * * 1-5 (weekdays only), timezone America/New_York | Verifies a delivered "morning" board_runs row exists for today; alerts via Resend if not. Runs 45 minutes after morningBoard's own 0 6 * * 1-5 cron. |
eodWatchdog | schedule, cron pattern 15 17 * * 1-5 (weekdays only), timezone America/New_York | Same check for "eod". Runs 45 minutes after eodPacket's own 30 16 * * 1-5 cron. |
sableSmoke (smoke.ts) | event — manual/on-demand, no cron | Records a trigger_runs row and reports which env vars it checked (SUPABASE_URL, SUPABASE_SERVICE_ROLE_KEY) — a manual connectivity smoke test, not a scheduled or alerting health check. See the note below on why it's placed on this page. |