# Postgres, all the way through One module, worked out completely, because it is the case that breaks the tidy version. It looks like *a container that runs a database* and it is at least nine things. ## What it carries **1 — A supervised container.** An image, a version, a data volume, and configuration. Easy, and the only part the phrase "a docker service" describes. **2 — Persistent state, and where it lives matters.** The volume is the database. Moving this module between nodes is not rescheduling; it is a migration. Almost nothing else in the catalogue has this property, and nothing in `provides` / `requires` expresses it. **3 — Configuration that is partly the machine's.** Tuning follows the hardware — memory, storage. A declaration generated centrally cannot know those, and [research 012](../012-the-minimum-viable-node/00-overview.md) says the machine's own values win on conflict. So some of this module's configuration is *derived from the node it lands on*. **4 — A tool surface.** It exposes capabilities agents can call — query, list, provision. That is not a resource on a machine and not an artifact; it is a contract the mesh publishes on the module's behalf. **5 — A provisioner.** The part that matters, and the one below. **6 — Its own bookkeeping.** The provisioner must remember what it granted to whom, or it cannot revoke, rotate or clean up. So a module that provides state to others *also* holds state about its providing — and that state is not the database's data. **7 — An exposure decision, per node it runs on.** Reachable from the machine only, from the local network, or publicly. That is a property of *this assignment*, not of the module: the same module on two nodes may answer differently. **8 — Credentials it generates.** Per consumer, and they have to reach the consumer. Which means a provisioning edge carries a payload, and the payload is a secret. **9 — Health that is not "the container is up".** A container running and a database accepting connections are different facts, and the second is the one anything cares about. This is the host's read-back rule, at a distance. ## The provisioner is a second kind of edge The tidy version of this effort said: *a module provides names, a module requires names, that is the only edge.* A small game wanting to store data shows it is not. ``` my-cool-game requires postgres # I speak its protocol, it must exist my-cool-game requires a database FROM postgres, called my-cool-game ``` The first is **presence**: the thing exists and is reachable. Nothing is created; nothing flows back. `vscode requires terminal` is this, and so is `requires container-runtime`. The second is **instantiation**: the provider is asked to make something *for this consumer*, and hands back what the consumer needs to use it. A database, a user, a password, an address. They differ in every way that matters: | | presence | instantiation | |---|---|---| | creates something | no | yes, one per consumer | | carries a payload back | no | credentials, an address | | can be revoked | — | yes, and must be when the consumer goes | | provider holds state about it | no | yes — who was granted what | | satisfied by | anything providing the name | that provider, specifically | **This is the mesh's actual power**, in the operator's words: a small game declares it wants a database and the mesh makes one. Nobody creates a user by hand, nobody pastes a connection string. That is worth being precise about rather than folding into a single relation because one relation is prettier. ## What that costs the design **The proposal's "one kind of edge" is wrong**, and the current system already knew: it has `dependencies` for presence and `requires: provision:` for instantiation, with the resolver deriving a presence edge from every instantiation edge. [`analysis.md`](analysis.md) recorded that derivation as a convenience. It is not — it is the correct relationship between two genuinely different relations. So: **two kinds of edge, one graph.** Instantiation implies presence. Presence does not imply instantiation. ## What still has no answer **Which postgres?** A mesh with two of them, and a game that wants a database. Presence would be satisfied by either. Instantiation cannot be — the data will live in exactly one, and choosing wrongly is not a preference, it is the game's data in the wrong place, discovered later. This is the *who chooses between providers* question from [`proposal.md`](proposal.md), and the worked example shows it is far sharper for instantiation than for presence. For `terminal` the consumer genuinely does not care. For a database it cares permanently. **How many instances of postgres should exist?** One per mesh is wrong — a node that must work while disconnected cannot depend on a database elsewhere. One per node is wrong — the mesh's own registry is one thing, not one per node. So the answer is per-module, and nothing in the schema says it. This is [`cases.md`](cases.md) axis *how many instances*, and postgres is the case that proves it cannot be a global rule. **What happens to a grant when the consumer is removed?** The game is uninstalled. Its database still exists, holding its data. Dropping it silently is data loss; keeping it forever is a leak. [ADR 0043](../../02-DECISIONS/0043-a-declaration-is-an-ordered-list-of-owned-resources.md) says the host removes what it applied and no longer declares — but this is not on the host, it is inside another module's state, and the same reasoning does not obviously carry. **Where does node-derived configuration come from?** (3) The control plane composes a declaration, and cannot know this machine's memory. Either the host fills in a blank the declaration leaves — which makes the host decide something, against [ADR 0037](../../02-DECISIONS/0037-the-host-applies-it-does-not-decide.md) — or the control plane reads the node's inventory first and composes with it. The second is consistent and means a declaration is composed *per node from what the node reported*, which is a stronger claim than anything recorded so far.