SQLAlchemy fires after_commit and after_rollback for a savepoint too. The host-agent ingest releases one after recording its metrics, so an alert raised by a sample started its email before the outer transaction committed; twice on 2026-10-12 the outbox row hit the event's foreign key first and the email was lost. A savepoint rolling back (a docker persist failing) cleared every pending notification, the outer one's included. _after_commit now runs its jobs only on the outermost commit, and a rolled-back savepoint drops only the jobs added inside it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>