feat(sending): operator notice for access requests carries account facts - #1058
Merged
Merged
Conversation
The operator email for an external-sending-access request showed only Category/Account id/Request id/volume, so a reviewer had to run -inspect-external-sending just to learn who filed it. Add a server-owned account-facts block (owner identity, signed-up age, non-standard account class, plan, owner-mailbox verification, live/verified resource counts, sending state, and prior decided requests) between the volume line and the command block, still above the customer-supplied fence. A display name is sanitized and length-capped before printing; any fact-read failure logs a warning and falls back to the base notice instead of blocking the request. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018tVLxUHk3fqQuq8C3wqyHW
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The operator email for an external-sending-access request (
NotifySendingAccessRequest) showed only Category, Account id, Request id, and Expected daily volume before the audited approve/decline commands — the operator had to run-inspect-external-sendingjust to learn who filed the request. This adds a server-owned account-facts block, read fresh from the database, between the volume line and the command block (still above the customer-supplied fence).New block (placeholder values):
standard.freewhen the account has noaccount_limitsrow.active) unless paused, in which case it adds the pause class.nonewhen the account has no decided history, otherwise a count + the most recently decided outcome (excluding the request currently being notified).The decision notice to the account owner, the MCP/SDK/CLI, and the OpenAPI spec are all unchanged.
Implementation
internal/agent/external_access.go:NotifySendingAccessRequestnow composes anaccountFactsBlock, which reads the account via the existingidentity.Store.GetUserByIDand the existing owner-proof predicate (sendingpolicy.ExternalAccessStatus'sOwnerRecipientVerified), plus one small new identity read and one small new sendingpolicy read (below).sanitizeOperatorLineneutralizes the display name.internal/identity/sending_access_notice.go(new):Store.SendingAccessNoticeCounts— one statement (plus two bounded subqueries) for plan code, sending-control state/pause class, live-agent count, and verified-domain count. No new tables.internal/sendingpolicy/external_access_admin.go:Module.PriorDecidedAccessRequests— count of decided requests + most recent outcome, excluding the request being notified. Added to the narrowExternalAccessinterface (Moduleis still its only implementer).Operational risk
Low. Additive to an existing best-effort notification path (
sendFeedbackEmail); no schema change, no/v1change, no change to what the account owner or any client surface sees. A read failure degrades to the pre-existing notice body rather than failing the request.Test plan
go build ./...— clean.go vet ./internal/agent/... ./internal/identity/... ./internal/sendingpolicy/...— no new findings (pre-existingresp-ordering vet warnings in unrelated test files predate this change).go test -tags integration ./internal/agent/ -run 'External|Access|Notify|Quote'— all pass, including three new tests: all-facts-present body assertions (owner/plan/verified/agents/domains/paused+class/prior-requests, positioned above the fence), a display name with an embedded newline + bidi override neutralized to one safe line, and a failed fact read (nonexistent account) still sending the base notice with a logged warning and no facts block.go test -tags integration ./internal/identity/... -run SendingAccessNoticeCountsand full package run — pass (a handful of unrelated pre-existing failures — account-trash/outreach tests — reproduce identically against a clean shared local test DB; documented local-DB-contention/outreach-baseline issues, not touched by this change).go test -tags integration ./internal/sendingpolicy/...— full package passes, including newTestPriorDecidedAccessRequests.🤖 Generated with Claude Code
https://claude.ai/code/session_018tVLxUHk3fqQuq8C3wqyHW