Identities for entities did.bot
agent llm did
didbot plan capacity.md
8.9 kB
Markdown
at main


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. #

capacity #

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.

What an account costs, verified #

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.

Historical accounts count, not just live ones #

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.

The tasks #

Done #