mail-events-push
carlos email events push: tell the app itself, signed, at a path on its own host. Builds on mail-events-log, now merged into main. The booking app that consumes this is billhorsman/bunkhouse#54.
What it does
carlos email events push --app <a> --path /mail/events — the console POSTs each Delivery, Bounce, Complaint, Reject and DeliveryDelay SES attributes to the app's own sending identity, as JSON.
- To whom, where. Only events for an identity CARLOS minted for that app. Only to
https://<app>.<account>.<AppsDomain><path>— validated names and path, redirects refused. Travels the public edge (wakes a hibernating app; a gated app can't receive). - Authenticity. Dedicated Ed25519 key; public half delivered as
CARLOS_MAIL_EVENTS_KEYbefore the hook is recorded.Carlos-Signature: t=<unix>,ed25519=<b64>overcarlos-mail-event\n<t>\n<body>. Apps also check account/app against the Host. - Delivery. Console-DB queue, one row per notification per app, same
idacross retries. Every 15s a pass starts from the apps that asked and seeks each one's ≤5 oldest due rows through an index — cost per app, not per backlog. ≤8 apps in parallel, 10s per POST, an app's turn ends at its first failure. Retries at 1m…12h, then given up. - Suspension. An app that accepts nothing for a day is suspended: its queue is given up on and nothing new is queued until the push is turned on again. The CLI says SUSPENDED, why, and how to lift it.
- Lifecycle. Nothing queued or sent for an app that isn't live. Hooks and queues forgotten on purge and account reap; hooks carried and queued bodies dropped on rename or move.
--offgives up on the queue and always removes the key. - Doors. GET/PUT/DELETE
.../email/events/push, Admin, 404 for non-members and with no provisioner, 503 with no apps domain.
Reviews
Two Opus rounds and one Fable round. Opus: tenant starvation, lifecycle leaks, prune index, races, a failing app holding its turn. Fable (6c78d716): a failing app's backlog grew for 30 days and every pass sorted it on the console's one DB connection — fixed with the per-app index seek and the day-long suspension; status reporting give-ups as failures; --off after a half-failed enable; queue prune; dead code; docs. Each new test checked to fail with its fix undone.
Open, not on this branch: discussion 153 — a sibling can take a trashed app's apex and keep it after restore; settle before enabling push for anyone.
Gate
Local make test green under umask 022; push tests clean under -race.
Discussions 1 open
Tasks 4/5 done
- Signed push to the app's own host, key delivered as config Done
- Fair queue: per-app cap, parallel apps, turn ends on failure Done
- Nothing sent for an app that is not live; carry/forget with the app Done
- Two Opus review rounds addressed Done
- Instances sibling-apex hole (discussion 153) settled before enabling Not started
Activity
- claude-code agent, operated by bill@keymail.dev replied to Instances: a trashed app's apex can be taken by a sibling and kept after restore
- task updated: Signed push to the app's own host, key delivered as config
- task updated: Fair queue: per-app cap, parallel apps, turn ends on failure
- task updated: Nothing sent for an app that is not live; carry/forget with the app
- task updated: Two Opus review rounds addressed
- claude-code agent, operated by bill@keymail.dev added task Instances sibling-apex hole (discussion 153) settled before enabling
- claude-code agent, operated by bill@keymail.dev added task Signed push to the app's own host, key delivered as config
- claude-code agent, operated by bill@keymail.dev added task Fair queue: per-app cap, parallel apps, turn ends on failure
- claude-code agent, operated by bill@keymail.dev added task Nothing sent for an app that is not live; carry/forget with the app
- claude-code agent, operated by bill@keymail.dev added task Two Opus review rounds addressed
- claude-code agent, operated by bill@keymail.dev opened Instances: a trashed app's apex can be taken by a sibling and kept after restore