id: capacity
title: A deployment stops minting before somebody else's quota does
status: open
crates: [didbot-pds, didbot-identity, didbot-serve]
dependsOn: [zone-scale, account-types]
exitCriterion: >
A deployment configured with a maximum account count refuses provisioning
once that many accounts hold records, names which zone is full, and an
operator watching the dashboard saw the number climbing before it refused
anything. #
Agent hostnames resolve through one wildcard record, so the zone holds a
handful of records whatever the account count and Route53's record quota is
not this deployment's ceiling. What is finite is this server's own: the
account store and the write-ahead log, the name pool
zone-scale tracks, and the operator's budget for what an
account costs to serve. This epic is the cap on that population, and the
number an operator watches before it refuses anything.
docs/deployment.md states it plainly: two hostnames
per account, one for the DID and one for the handle, and both resolve the
moment they are chosen through *.<zone>. An account costs the zone nothing.
The certificate does not add to that per account either:
agent-accounts commits to one wildcard certificate per
zone over ACME DNS-01, so the _acme-challenge TXT records it needs and the
apex CAA are fixed overhead on the zone.
What an account does cost is one row in the account store, one repository
and its blobs in the write-ahead log, and one ledger entry that outlives it
(name-pools is why the ledger only grows). Route53's own
quotas — 10,000 records per hosted zone and 500 hosted zones per account by
default, both soft (see Amazon Route 53
quotas)
— bound the number of zones a deployment can hold, not the number of
accounts.
Every account stays until the operator deletes it. The document a DID serves
has to keep answering for as long as a reader might hold a reference to it —
an at:// URI copied out of a log, a citation, a mention — which is longer
than the session that minted the account. An account whose DID document must
still answer still holds its row, whether or not anything is presently
running as that account.
So the population this cap is checked against is not "live sessions right
now." It is every account whose document still answers:
Live (provisioned, in use or idle): a row and a repository held.
Erased (its data gone, its document still answering because something
might still reference it): a row held. This is why "historical" is the
right word for the population that matters here, not "active."
Removed (the operator's hard delete, or the sweep taking a row a killed
create left): nothing held. The name itself moves to NameRegistry's
Released hold, which is a name-pool cost tracked in
zone-scale, not a cost tracked here.
Reserved (a zone apex, or an operational block in NameRegistry):
nothing held. A reservation is a name held out of the naming pool; it never
had a row to begin with.
A cap that only ever counted the first bucket would let a deployment mint
past what it can serve, because the erased bucket only shrinks when the
operator deletes something.