claude-code agent, operated by bill@keymail.devoperated by bill@keymail.devsession c1b691bc · claude-code/2.1.271 · DOCS-T1
Pre-existing, found by the Opus review of mail-events-push, which makes it matter more. Not changed on that branch because it's the instances code's rule to decide.
The guard.apiinstances.go ~620–633 refuses a member-written manifest that pins a host at a sibling app's apex (<other-app>.<sqid>.<AppsDomain>), because the domains pass would then skip minting the sibling's own apex for ever (byHost). It decides "is this label another claimed app" with HasAppIn, which counts only live rows (deleted_at = 0).
The hole.
App A is trashed. Its name is still reserved until purge, but HasAppIn no longer sees it.
App B, with its own app-scoped token, writes a manifest with an instance at a.<sqid>.<AppsDomain>. The guard lets it through.
A is restored. Per the guard's own comment, the domains pass now skips A's apex — B holds it.
Anything addressed to A's platform host reaches B.
Why it now matters more.carlos email events push POSTs recipient addresses to https://<app>.<sqid>.<AppsDomain><path>. The push checks the app is live (so nothing goes out while A is trashed), but after step 3 A is live again and its events — guests' email addresses — go to B's instance.
Suggested fix. Have the sibling check count trashed rows too (HasAppIn → a query without the deleted_at = 0 filter, or HasAppIn || HasTrashedAppIn), since a trashed name stays reserved until purge — the same reading CreateAppIn and RenameAppIn already give it. Within one account, but across the app-scoped credential boundary.
Suggest this is settled before events push is turned on for anyone.
claude-code agent, operated by bill@keymail.devoperated by bill@keymail.devsession c1b691bc · claude-code/2.1.271 · DOCS-T1
Fix on branch instances-trashed-apex (e7e00cba): the sibling-apex guard in the instances create door now also asks HasTrashedAppIn, so a trashed app's apex stays reserved until purge — matching how CreateAppIn and RenameAppIn already treat a trashed name. The refusal says the app is in the trash; a purge frees the label.
TestAPIInstanceCreateSiblingApexRefused now covers trashed (409), restored (409) and purged (201), and fails with the new check removed. mail-events-push is merged (a430d4d); this should land before the push is turned on for any app.