Sentry alert rules runbook
System: Sentry (issue alert rules — trademaster-raptor project) Owner: operator Last incident: 2026-06-10 (2026-06-10-beta-walk-500), 2026-06-12 (2026-06-12-beta-walkthrough-500) Last reviewed: 2026-06-18 UTC
Managed rules
| Rule name | Fingerprint / filter | Condition | Action | Frequency | Created | Issue |
|---|---|---|---|---|---|---|
| skipped_no_postmark_token — email silent failure | message contains skipped_no_postmark_token |
>= 1 event in 5m | email ops@raxx.app (IssueOwners / AllMembers) | 60 min | 2026-05-30 | #3135 |
| beta-walk-5xx — beta walkthrough 500 class | http.url starts-with /beta/walk/ AND http.status_code starts-with 5 |
>= 1 event in 5m | email ops@raxx.app (IssueOwners / AllMembers) | 60 min | 2026-06-18 | #3683 |
Notification posture: both rules use IssueOwners / AllMembers fallthrough which routes to
kris@moosequest.net (the sole org member, who monitors ops@raxx.app). The Sentry email
action is out-of-band from the GitHub Actions SLACK_NOTIFY_LEVEL gate; it fires
unconditionally regardless of that variable, matching the loud tier posture in
docs/ops/runbooks/slack-notification-policy.md.
Auth
Sentry API token lives at vault path /MooseQuest/sentry/SENTRY_API (env: SENTRY_AUTH_TOKEN).
Fetch it from vault before running any script below:
export SENTRY_AUTH_TOKEN=$(python3 scripts/ops/mint_secret.py /MooseQuest/sentry/SENTRY_API 2>/dev/null)
Or pass it directly to the script; the script fetches from vault automatically when
SENTRY_AUTH_TOKEN is absent and INFISICAL_* + CF_ACCESS_* env vars are present.
How to create or verify an alert rule
The script accepts a --rule flag. Default is skipped-no-postmark-token (backward-compat).
Create / idempotent re-run (original postmark rule)
python3 scripts/ops/create_sentry_alert_rule.py
Create / idempotent re-run (beta-walk 5xx rule — issue #3683)
python3 scripts/ops/create_sentry_alert_rule.py --rule beta-walk-5xx
The script is idempotent for each rule: if the rule already exists (matched by name), it prints the existing rule ID and exits 0 without creating a duplicate.
Dry-run (inspect payload without creating)
python3 scripts/ops/create_sentry_alert_rule.py --rule beta-walk-5xx --dry-run
Target a different org or project
python3 scripts/ops/create_sentry_alert_rule.py \
--rule beta-walk-5xx \
--org moosequest \
--project trademaster-raptor
Verify all rules exist via Sentry API
curl -s \
-H "Authorization: Bearer $SENTRY_AUTH_TOKEN" \
-H "User-Agent: raxx-sre-ops/1.0" \
"https://sentry.io/api/0/projects/moosequest/trademaster-raptor/rules/" \
| python3 -m json.tool | grep -E '"name"|"id"'
How to tell skipped_no_postmark_token is firing
- Sentry issue "skipped_no_postmark_token — email silent failure" appears in trademaster-raptor.
- Email lands at ops@raxx.app with subject containing the rule name.
- Sentry dashboard:
https://sentry.io/organizations/moosequest/issues/→ filter project = trademaster-raptor.
What it means: POSTMARK_SERVER_TOKEN is absent or empty on the dyno that attempted an
email send. Waitlist confirmation emails are being silently skipped.
Remediation for skipped_no_postmark_token
-
Verify the config var on prod:
bash heroku config:get POSTMARK_SERVER_TOKEN --app raxx-api-prod | wc -c # Expect > 5. If 0 or 1: the token is unset. -
If unset, set it (silence stdout — token must not appear in terminal history):
bash heroku config:set POSTMARK_SERVER_TOKEN="$POSTMARK_SERVER_TOKEN" \ --app raxx-api-prod >/dev/null 2>&1Full procedure:docs/ops/runbooks/postmark.md→ "Setting POSTMARK_SERVER_TOKEN on Heroku". -
Verify:
bash heroku run --app raxx-api-prod \ python -c "from api.services.postmark_client import test_postmark_token; test_postmark_token()" # Expect: ✓ Postmark token valid server=<ServerName> id=<ServerID> -
Resolve the Sentry issue only after verifying the fix is deployed and the smoke passes.
How to tell beta-walk-5xx is firing
- Sentry issue "beta-walk-5xx — beta walkthrough 500 class" appears in trademaster-raptor.
- Email lands at ops@raxx.app with subject containing the rule name.
- Sentry dashboard: filter project = trademaster-raptor, URL =
/beta/walk/*.
What it means: A request to any /beta/walk/<token>/* route returned HTTP 5xx.
Common causes (both observed in production):
1. A Raptor DB table required by the route is missing (migration not applied). Check
backend_v2/alembic/versions/ — the route's table must have a Raptor-side migration.
2. An unhandled exception in the route handler (any except Exception that returns 500).
Remediation for beta-walk-5xx
-
Pull the Sentry event to get the stack trace and breadcrumbs:
https://sentry.io/organizations/moosequest/issues/?project=trademaster-raptorFilter bybeta-walk. Open the issue and read the full stack trace. -
If the trace shows a SQLAlchemy
Table not founderror: - Checkbackend_v2/alembic/versions/for a migration that creates the missing table. - If absent, write the migration (seedocs/incidents/2026-06-10-beta-walk-500.mdanddocs/incidents/2026-06-12-beta-walkthrough-500.mdfor the established pattern). - PR the migration → merge → release phase applies it → retry the walkthrough URL. -
If the trace shows a different error: escalate to the operator with the full stack trace.
-
Resolve the Sentry issue only after the fix is deployed and the route returns 200.
Adding new alert rules
- Define the rule parameters (condition, filter, action, frequency).
- Add an entry to the "Managed rules" table above with the notification posture note.
- Add the rule key to
_KNOWN_RULESinscripts/ops/create_sentry_alert_rule.py. - Implement
_build_<rule>_payload()in the same file. - Add tests to
scripts/ops/tests/test_create_sentry_alert_rule.py. - Run the script with
--dry-runto inspect the payload, then without to create the rule. - Record the Sentry rule ID returned by the script in this table.
Escalation
Wake the operator when:
- The alert rule is missing (script exits non-zero or GET returns empty rules list).
- Sentry API returns 401 — the SENTRY_API token may have expired or been revoked.
- The skipped_no_postmark_token issue fires repeatedly after POSTMARK_SERVER_TOKEN has been set correctly (indicates a different skip path not covered by the alert filter).
- The beta-walk-5xx issue fires and the stack trace does not match any documented remediation above.