diff --git a/01-RESEARCH/011-the-module-graph/00-overview.md b/01-RESEARCH/011-the-module-graph/00-overview.md index a4a4a3e..3b4dd90 100644 --- a/01-RESEARCH/011-the-module-graph/00-overview.md +++ b/01-RESEARCH/011-the-module-graph/00-overview.md @@ -17,7 +17,7 @@ touches: Whether the catalogue's missing structure is a **graph** — modules declaring what they need, what they offer, and what they exclude — and what that replaces. -**[`worked-postgres.md`](worked-postgres.md) works one module through completely**, and breaks +**[`worked-provider.md`](worked-provider.md) works one module through completely**, and breaks the tidy version. A database is nine things, not one — and a small game asking the mesh for its own database shows there are **two kinds of edge**: *presence*, where the thing must exist, and *instantiation*, where a provider makes something for a consumer and hands back credentials. diff --git a/01-RESEARCH/011-the-module-graph/proposal.md b/01-RESEARCH/011-the-module-graph/proposal.md index ee6e281..8cb5c4b 100644 --- a/01-RESEARCH/011-the-module-graph/proposal.md +++ b/01-RESEARCH/011-the-module-graph/proposal.md @@ -1,6 +1,6 @@ # One kind of edge -> **Superseded in part by [`worked-postgres.md`](worked-postgres.md).** Working postgres through +> **Superseded in part by [`worked-provider.md`](worked-provider.md).** Working postgres through > completely shows there are **two** kinds of edge, not one: *presence* — the thing exists and is > reachable, nothing created — and *instantiation* — the provider is asked to make something for > this consumer and hands back credentials. Instantiation implies presence; presence does not diff --git a/01-RESEARCH/011-the-module-graph/worked-postgres.md b/01-RESEARCH/011-the-module-graph/worked-provider.md similarity index 68% rename from 01-RESEARCH/011-the-module-graph/worked-postgres.md rename to 01-RESEARCH/011-the-module-graph/worked-provider.md index e79e6c2..450bc42 100644 --- a/01-RESEARCH/011-the-module-graph/worked-postgres.md +++ b/01-RESEARCH/011-the-module-graph/worked-provider.md @@ -1,8 +1,10 @@ -# Postgres, all the way through +# A provider, 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. +Postgres is the example. **The shape is not specific to it** — see the end. + ## What it carries **1 — A supervised container.** An image, a version, a data volume, and configuration. Easy, @@ -109,3 +111,53 @@ declaration leaves — which makes the host decide something, against 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. + + +## The same shape, three more times + +The message broker has all nine. So does the object store, and so does the image registry. They +differ in what a consumer asks for — a database, a virtual host, a bucket, a repository — and in +nothing structural. + +**A substrate service is a service plus a factory.** That is the whole pattern, and there are +four of them. It generalises past the substrate too: anything that grants something per consumer +has this shape, and anything that does not is the simpler case. + +But two things differ *between* them, and both matter more than the similarity. + +### The broker cannot be managed over the broker + +[ADR 0001](../../02-DECISIONS/0001-nodes-communicate-over-a-broker.md) makes the broker the +channel every node takes work from, and +[ADR 0039](../../02-DECISIONS/0039-the-link-is-the-security-boundary.md) makes it the security +boundary — everything a node applies arrives through it. + +So the module providing the broker is also **the way modules are managed**. A declaration cannot +be delivered to it over itself, and reconfiguring it is done through the thing being +reconfigured. Nothing else in the catalogue has that property; the store is consumed by the +control plane but is not how the control plane *reaches* anything. + +This is exactly what the carried bundle exists for +([ADR 0038](../../02-DECISIONS/0038-a-node-joins-by-linking-first.md)): the broker is raised from +what the host carries, before there is a channel, because there is no other way to raise it. +Recorded here because it is a constraint on *one module*, not a general rule, and a schema with +no way to say so hides it. + +### Two modules of identical shape want different instance counts + +The broker is one per mesh — a single point of failure and a single point of trust, by decision +rather than by accident. The store cannot be: a node that must keep working while disconnected +([ADR 0036](../../02-DECISIONS/0036-a-node-is-a-managed-machine.md)) cannot depend on a database +somewhere else. + +Same nine properties, opposite answers. Which settles something the cases file left open: **how +many instances is not derivable from what a module is.** It is a decision per module, it has to +be declared, and nothing in `provides`, `requires` or `excludes` says it. + +### And revocation differs in consequence + +Revoking a database leaves data behind until something drops it — a leak, and recoverable. +Revoking a virtual host drops whatever had not been delivered — not recoverable, and silent. + +The relation is the same and the blast radius is not, which is an argument for the provider +deciding what revocation means rather than the mesh applying one rule to all of them.