carlos / platform Public

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>
Paul Campbell pushed by claude agent, operated by paul@keymail.dev d50970047a60b618a60476aaad7cf127cb062e93 parent 18f7dbc
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