From 87f464cc5f79eabd310bf76034193c12e6d536e6 Mon Sep 17 00:00:00 2001 From: jochen Date: Tue, 15 Sep 2026 20:26:42 +0200 Subject: [PATCH] A finished mesh holds twelve, and two rows were one module each MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The substrate's store and the postgres module are the same thing. They were two rows only while the substrate was a different KIND of thing — a store raised from a bundle cannot provide postgres-database, so anything wanting a database needed a second server. It is visible on any mesh built today: mesh-store and postgres, two containers, the same image. Which name survives is settled by the naming rule. Where a consumer speaks a protocol the interface is the protocol, and "database" is not a capability. The control plane's own queries use distinct on and on conflict, so the coupling is to postgres and a "store" module would advertise a swap that fails the first time anyone tries it. The broker collapses the same way with a different outcome: amqp IS a protocol that several implementations speak, so amqp is a legitimate provision and lavinmq is one provider of it. So adopting the substrate is not only an upgrade path — it is two rows of a mesh's module list becoming one, twice. And it leaves nothing that is a specialty after the pivot, which is the claim the whole design rests on and is not true today for exactly those two. Claude-Session: https://claude.ai/code/session_01D6qtiYU3P9jk3pnAXyAFyx --- .../01-to-be/21-the-installation-in-full.md | 56 +++++++++++++++++++ .../00-report.md | 11 ++++ 2 files changed, 67 insertions(+) diff --git a/03-DESIGN/01-to-be/21-the-installation-in-full.md b/03-DESIGN/01-to-be/21-the-installation-in-full.md index d8486d8..f07375f 100644 --- a/03-DESIGN/01-to-be/21-the-installation-in-full.md +++ b/03-DESIGN/01-to-be/21-the-installation-in-full.md @@ -120,3 +120,59 @@ puts the shipped unit on the machine. **Nothing asserts a mesh was installed this way.** A claim that a machine was brought up by this procedure cannot be contradicted by anything afterwards. + +## What a finished mesh holds + +**Twelve, and after the pivot none of them is a specialty.** Every row is a module the mesh built, +holds a version of, and can upgrade — which is the whole claim, and is not true today for the first +two. + +| # | module | provides | note | +|---|---|---|---| +| 1 | `postgres` | `postgres-database` | **the control plane's own records and every module's.** One server, not two | +| 2 | `lavinmq` | `amqp` | the broker every node dials, and what modules are granted vhosts on | +| 3 | `mesh-control` | *claims* `the-control-plane` | decides what runs where | +| 4 | `registry` | `artifact-store` | what the mesh built, pinned by digest | +| 5 | `builder` | — | turns source into artifacts | +| 6 | `mesh-tools` | build inputs | the base everything with code compiles against. **Runs nowhere** | +| 7 | `mesh-catalog` | the module graph | what is held, what a change reaches, what must be rebuilt | +| 8 | `networking` | `private-network`, naming | requirements only — assigning it brings `mesh-wireguard` and `mesh-names` | +| 9 | `dnsmasq` + one of `resolved-split-dns` / `resolv-conf` | `wildcard-resolution` | names that actually resolve, on top of `mesh-resolver`'s data | +| 10 | `step-ca` | `acme-ca` | certificates for `.internal` | +| 11 | `firewall` | *claims* `the-packet-filter` | rules generated from what modules declared | +| 12 | `gitea` | `package-registry` | where a module's dependencies come from ([ADR 0014](../../02-DECISIONS/0014-no-npm-workspace.md)), and the git host | + +### Why it is twelve and not thirteen + +**The substrate's store and the `postgres` module are the same module.** They were two rows while the +substrate was a different *kind* of thing: a store raised from a bundle cannot provide +`postgres-database`, so anything wanting a database needed a second server. That is visible on any +mesh built today — `mesh-store` and `postgres`, two containers, **the same image**. + +The naming rule settles which name survives +([ADR 0040](../../02-DECISIONS/0040-what-a-module-is.md)): + +> Where the consumer **speaks a protocol** — a database's wire protocol and query dialect — the +> interface *is* the protocol. **"database" is not a capability; the protocol is.** Never false +> genericity: a name must not promise a swap the contract cannot deliver. + +So there is no `store` module. The control plane is coupled to postgres — its own queries use +`distinct on` and `on conflict`, which are not portable — and calling it `store` would advertise a +swap that would fail the first time somebody tried it. + +**The same applies to the broker**, with a different outcome: `amqp` *is* a protocol and more than +one implementation speaks it, so `amqp` is a legitimate provision and `lavinmq` is one provider of +it. The substrate's broker and the `lavinmq` module collapse the same way. + +### What this costs, and it is the last specialty + +Adopting the store and the broker as modules is [issue 051](../../04-ISSUES/051-the-mesh-cannot-update-what-it-depends-on/00-report.md), +and it is the only part of this that has not been designed. The two hard parts: + +- **upgrading a store the control plane is reading from** — a rollout where the thing being replaced + is the thing holding the record of the rollout +- **upgrading a broker over the broker** — the instruction arrives on what it replaces, so the + machine must finish without being able to report progress + +Both are operations with windows, and a machine rebooting inside one is an operator's problem during +an operation rather than a reason not to do it. diff --git a/04-ISSUES/051-the-mesh-cannot-update-what-it-depends-on/00-report.md b/04-ISSUES/051-the-mesh-cannot-update-what-it-depends-on/00-report.md index 816c774..37774f6 100644 --- a/04-ISSUES/051-the-mesh-cannot-update-what-it-depends-on/00-report.md +++ b/04-ISSUES/051-the-mesh-cannot-update-what-it-depends-on/00-report.md @@ -51,6 +51,17 @@ rather than a *kind*: how a mesh starts, not what it permanently is. duplication as a side effect, and the control plane already reaches its three contexts through three separate credentials — which is the shape of a consumer, not an owner. +**And the module it becomes is `postgres`, not `store`.** The naming rule settles it +([ADR 0040](../../02-DECISIONS/0040-what-a-module-is.md)): where a consumer speaks a protocol, the +interface *is* the protocol, and *"database" is not a capability*. The control plane's own queries +use `distinct on` and `on conflict`, so the coupling is to postgres and a `store` module would +promise a swap that fails the first time anybody tries it. The broker collapses the same way with a +different outcome — `amqp` **is** a protocol that several implementations speak, so `amqp` is a +legitimate provision and `lavinmq` is one provider of it. + +So adoption is not only an upgrade path. It is two rows of a mesh's module list becoming one, +twice. + ## What makes this harder than it looks **The recursion is real, not incidental.** The control plane learns what modules exist by reading