Repository navigation
Quota pools; accepting_new and quota_pool on POST /fmsgid - #7
Merged
Merged
Conversation
Quota pools let addresses share one quota. The new nullable
address.quota_pool column (a foreign key to address_lower, indexed,
added idempotently by dd.sql) names the pool owner; NULL means the
address is its own pool. GET /fmsgid/:address reports a pooled
address's owner's limits and the usage summed over the owner and every
address in its pool, and an owner's usage includes its members' too.
accepting_new stays per address. The response gains an optional
quotaPool field naming the pool owner.
POST /fmsgid accepts optional accepting_new and quota_pool, applied to
a new address or an existing one, so a caller can stop an address
accepting new messages, reinstate it, or pool it. It now answers with
{"created":bool,"reinstated":bool}; reinstated is true when an address
that wasn't accepting new messages now is. Requests without the new
fields behave as before. Pools are one level deep: quota_pool must name
an existing address in no other pool, and a pool owner can't join one
(422 otherwise).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Merged
3 tasks done
markmnl
added a commit
to markmnl/fmsg-docker
that referenced
this pull request
Oct 10, 2026
…23) fmsgid main (quota pools, markmnl/fmsgid#7) selects address.quota_pool, which the copied fmsgid DD here didn't have, so every address lookup failed with 500 ("column a.quota_pool does not exist"). The integration tests then stopped at creating API keys: create-delegation failed checking the owner in fmsgid, and only the rotate fallback's error ("grant not found") was printed. Refresh docker/postgres/init/002-fmsgid-dd.sql with scripts/update-dd.sh from fmsgid main. When both create-delegation and rotate-delegation fail, print both errors. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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
Quota pools. Addresses can now share one quota, e.g. linked addresses such as
@alice_bot@example.comsharing@alice@example.com's.dd.sql: new nullableaddress.quota_pool textreferencingaddress (address_lower)(on delete set null), indexed. Added idempotently (add column if not exists, a catalog-checkeddoblock for the FK,create index if not exists); a nullable column without a default doesn't rewrite the table, so it is safe to re-run on a populated database.GET /fmsgid/:address: whenquota_poolis set, thelimit*fields are the pool owner's, and the six usage fields are summed over the owner plus every address whosequota_poolis the owner. An unpooled address's usage includes its pool members' too, so the owner's own check counts its members' usage.acceptingNewstays per address. Response shape unchanged apart from an optionalquotaPool(pool owner's address), omitted when not pooled. Defensive left join keeps an address's own limits if its owner were missing.UPDATE (quota_pool)onaddress.POST /fmsgidaccepts optionalaccepting_new(bool) andquota_pool(address;""or the address itself clears it), applied to both new and existing addresses, and returns{"created":bool,"reinstated":bool}(reinstated= existed, wasn't accepting, now is). Requests without the new fields behave exactly as before (201/200, existing rows untouched). Pools are one level deep:quota_poolmust name an existing address in no other pool, and an address that owns a pool can't join one, otherwise422 {"error":...}. The insert names only the given columns so everything else still takes the column defaults.This gives a client that creates linked addresses (e.g. fmsg-webapi sub-accounts) one call to create-or-reinstate an address in its owner's pool, and one to stop it accepting new messages when it's deleted.
Test plan
go test -race ./...,go vet ./..., gofmt cleanFMSGID_TEST_DATABASE_URL): pooled limits and summed usage, owner sees members' usage, unpooled unchanged, missing owner refused (FK, 422) and deleted owner reverts members to their own limits, quota_pool set/clear/one-level rules, accepting_new disable/reinstate andreinstated, dd.sql re-applied gives one FK and one indexdd.sqlto a fresh DB, inserted rows, then applied the new one twice withON_ERROR_STOP=1EXPLAINof the pooled usage query usesaddress_pkey+address_quota_pool(BitmapOr) andaddress_tx_addr_type_ts🤖 Generated with Claude Code