docs: add the tenant email senders roll note to README (final review, item 1)
The final whole-branch review for plan 2 of 5 (senders) held the merge on this: nothing in the repo told an operator what the release changes. Add a "Releasing the platform" section to README.md (this repo's README had none yet) and give this release its note: counts now attribute to the sender that sent them, the app's email record moved to email/senders/app.json with a rollback data-loss consequence, spec §4.2's two rollout prerequisites in full, and what CARLOS_MAIL_LEGACY_SWEEP=1 actually does and when it is safe to set.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 file changed,
+33
−0
README.md+33 −0
diff --git a/README.md b/README.md| index 44f103eec..e8c1c817a 100644 |
| --- a/README.md |
| +++ b/README.md |
| @@ -224,6 +224,39 @@ old build, this is the way off those keys. |
| **It never deletes a legacy object.** Deleting them is a separate operator |
| step, and an unhurried one now that nothing resolves through them. |
| +## Releasing the platform |
| + |
| +A release-specific note goes here when a release changes something an |
| +operator needs to check or act on before rolling it. Read the note for |
| +the release you are about to roll. |
| + |
| +### Tenant email senders, plan 2 of 5 (2026-09-21) |
| + |
| +This release turns the one implicit per-app email sender into an explicit |
| +sender record (design spec `2026-09-15-tenant-email-senders-design.md`). |
| + |
| +- SES event counts now attribute to the sender that sent them. an app |
| + sharing a domain with a sibling app stops being charged for the |
| + sibling's sends. a tenant watching their own numbers will see them move. |
| +- the app's email record moved to |
| + `apps/<acct>/<app>/email/senders/app.json`, with a read fallback to the |
| + old `email.json`. a console rolled back after the first sender write |
| + loses any pause or rotation made in between. that has to be redone by |
| + hand. |
| +- two prerequisites from the design spec (§4.2) before any release sends |
| + with a tenant header. |
| + - every domain provisioned before this release has no SES tenant |
| + association, and nothing will create one on its own. a backfill, or |
| + a re-run of `carlos email domains add` against every existing |
| + domain, is needed before any release that sends with a tenant |
| + header. |
| + - the control-plane role needs `ses:CreateTenantResourceAssociation` |
| + and `ses:DeleteTenantResourceAssociation` before this rolls. |
| +- `CARLOS_MAIL_LEGACY_SWEEP=1` is off by default. it does two separate |
| + things. it deletes the bucket's legacy `email.json` objects, and it |
| + drops the database's `mail_counts` table. do not set it until the |
| + release after this one has been live for a while. |
| + |
| ## App config & secrets |
| Per-app config lives in the deployment bucket |