Establish the repo for the completed Phase 0-3 build
Settles the design repository now that the self-upgrade build is on main: - Records the two decisions that shipped without a record — ADR 0077 (the controller/foundation/node vocabulary) and ADR 0078 (the store and broker are ordinary modules); accepts ADR 0075 and 0076, which shipped work rests on. - Fills issue 051's amended-design and wires ADR 0078 into 07-the-foundation. - Sweeps the repo rename (mesh-control -> mesh-controller) into the mutable docs now that the forge repo is renamed; updates the glossary note and repos.md. - Fixes the six broken links from the design-doc renames, indexes the glossary, regenerates the decisions reading order. Both checks (records.py, index.py) are green. Statuses stay honest: the build is on main and lab-proven but not deployed as the production mesh, so the to-be docs remain in-progress and the as-is layer (the hal mesh) is unchanged — graduation to implemented + as-is belongs to deployment, not merge. https://claude.ai/code/session_01D6qtiYU3P9jk3pnAXyAFyx
This commit is contained in:
@@ -104,6 +104,6 @@ Without that, this record is a convention, and a convention is what the previous
|
||||
## References
|
||||
|
||||
- [ADR 0009](0009-modules-and-the-graph.md) — provisions, and refusing on ambiguity
|
||||
- [`03-DESIGN/01-to-be/07-the-substrate.md`](../03-DESIGN/01-to-be/07-the-substrate.md) — *the
|
||||
- [`03-DESIGN/01-to-be/07-the-foundation.md`](../03-DESIGN/01-to-be/07-the-foundation.md) — *the
|
||||
provisioning model uses databases, roles and schemas as PostgreSQL means them*, which is this
|
||||
record's point made about the substrate before it was made about modules
|
||||
|
||||
@@ -18,7 +18,7 @@ conditional, and said exactly why:
|
||||
|---|---|---|
|
||||
| identity provider | — | **conditional**: substrate only if the control plane delegates authentication, which is undecided |
|
||||
|
||||
[`07-the-substrate.md`](../03-DESIGN/01-to-be/07-the-substrate.md) carried it as an open question —
|
||||
[`07-the-foundation.md`](../03-DESIGN/01-to-be/07-the-foundation.md) carried it as an open question —
|
||||
*whether identity is the fifth* — noting it followed from a decision nobody had taken.
|
||||
|
||||
**The decision is taken: the control plane does not delegate authentication.** There is no mesh
|
||||
|
||||
@@ -12,7 +12,7 @@ extends: 02-DECISIONS/0035-one-implementation-several-surfaces.md
|
||||
## Context
|
||||
|
||||
Bootstrap currently ends when the control plane starts
|
||||
([`07-the-substrate.md`](../03-DESIGN/01-to-be/07-the-substrate.md)). That is a mesh that runs and
|
||||
([`07-the-foundation.md`](../03-DESIGN/01-to-be/07-the-foundation.md)). That is a mesh that runs and
|
||||
cannot yet be used by anybody who is not standing at the machine: the networked surfaces need an
|
||||
OAuth2 identity provider ([ADR 0035](0035-one-implementation-several-surfaces.md)), the provider is
|
||||
a module, and no module has been assigned.
|
||||
|
||||
@@ -16,7 +16,7 @@ claims, what each is made of — all of it lives inside the control plane becaus
|
||||
was first written, not because anything decided it belonged there.
|
||||
|
||||
**The control plane's own test says it does not belong there.**
|
||||
[`06-the-control-plane`](../03-DESIGN/01-to-be/06-the-control-plane.md) defines the tier as
|
||||
[`06-the-control-plane`](../03-DESIGN/01-to-be/06-the-controller.md) defines the tier as
|
||||
*everything that needs to know about more than one node*, and states the corollary plainly:
|
||||
anything a single machine could answer alone is not the control plane's. What a module is, and
|
||||
what it needs, requires no knowledge of any node whatsoever.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
topic: the tiers
|
||||
status: proposed
|
||||
status: accepted
|
||||
date: 2026-09-15
|
||||
deciders: jochen
|
||||
reconstructed: false
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
topic: building it
|
||||
status: proposed
|
||||
status: accepted
|
||||
date: 2026-09-16
|
||||
deciders: jochen
|
||||
reconstructed: false
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
---
|
||||
topic: the mesh
|
||||
status: accepted
|
||||
date: 2026-09-16
|
||||
deciders: jochen
|
||||
reconstructed: false
|
||||
extends: 0006-the-substrate-and-the-control-plane.md
|
||||
---
|
||||
|
||||
# 77. The parts are named controller, foundation, node — not control plane, substrate, master
|
||||
|
||||
## Context
|
||||
|
||||
The words drifted. In conversation and in code the same thing was called *control plane*,
|
||||
*controller*, *master*, and *hub*; the store-and-broker pair was called *substrate* and
|
||||
*foundation*; a machine was a *node*, a *worker-node*, a *peer*, a *slave*. A mesh named
|
||||
differently by two people is a mesh they describe differently, and the drift was worst on the
|
||||
parts talked about most.
|
||||
|
||||
Three of the terms carried wrong ideas. *Control plane* is borrowed from networking's
|
||||
control-plane/data-plane split and means nothing here. *Master/slave* and *hub/peer* imply a
|
||||
subordinate — but no node is: a node applies its own declaration and keeps running when the
|
||||
control-node dies, so it is as much its own machine as any other. *Substrate* is a biology
|
||||
metaphor that landed for no one.
|
||||
|
||||
## Considered Options
|
||||
|
||||
1. **Keep the inherited words.** Rejected: they are the source of the drift, and two of them
|
||||
(control plane, substrate) are metaphors that teach the wrong shape to anyone reading them cold.
|
||||
2. **master / slave, or hub / peer, for the nodes.** Rejected: both name a hierarchy the mesh does
|
||||
not have. The control-node owns no other node; lose it and the rest keep running what they were
|
||||
last told.
|
||||
3. **controller / foundation / node + control-node.** Chosen.
|
||||
|
||||
## Decision
|
||||
|
||||
The component that decides what each node should be, holds the mesh's records, and tells nodes is
|
||||
the **controller** — the module `mesh-controller`, which claims the mesh-scoped `the-controller`
|
||||
seat. The store and broker raised at genesis are the **foundation**. Machines are **nodes**;
|
||||
there are 0..n of them, and exactly one — the one running the controller — is the **control-node**.
|
||||
|
||||
Retired: *control plane*, *substrate*, *master/slave*, *hub/peer*, *worker-node*.
|
||||
[`00-META/glossary.md`](../00-META/glossary.md) is the authority, and a new name for an existing
|
||||
thing lands there in the change that introduces it in code.
|
||||
|
||||
## Consequences
|
||||
|
||||
`mesh-control` became `mesh-controller` across the module, container, image, binary, `cmd/` dir and
|
||||
the git repository; `substrate` became `foundation` in the embedded base bundles, the default
|
||||
template and the example lock; the seat `the-control-plane` became `the-controller`. The 03-DESIGN
|
||||
prose and 00-META follow the new words.
|
||||
|
||||
What got harder: the records under `02-DECISIONS/` are immutable, so they keep the words they were
|
||||
written with — this record included, whose own title names what it retires. A term retired here
|
||||
still appears there, and the glossary is how to read it. The git repository on the forge was
|
||||
renamed `mesh-control` → `mesh-controller`.
|
||||
|
||||
## References
|
||||
|
||||
- [`00-META/glossary.md`](../00-META/glossary.md) — one name per thing, and the words retired.
|
||||
- The rename shipped across all six code repositories and hq (main).
|
||||
@@ -0,0 +1,63 @@
|
||||
---
|
||||
topic: the tiers
|
||||
status: accepted
|
||||
date: 2026-09-16
|
||||
deciders: jochen
|
||||
reconstructed: false
|
||||
extends: 0033-the-substrate-is-a-store-and-a-broker.md
|
||||
---
|
||||
|
||||
# 78. The store and the broker are ordinary modules
|
||||
|
||||
## Context
|
||||
|
||||
[ADR 0033](0033-the-substrate-is-a-store-and-a-broker.md) settled that the foundation is a store
|
||||
and a broker, raised at genesis; [ADR 0006](0006-the-substrate-and-the-control-plane.md) settled
|
||||
that the controller cannot grant itself either, because it consumes them and is not running yet to
|
||||
ask. Both were raised as bundle resources — plumbing, with no record in the mesh's module graph.
|
||||
|
||||
That left two costs, named in [issue 051](../04-ISSUES/051-the-mesh-cannot-update-what-it-depends-on/00-report.md).
|
||||
The foundation's own store and broker could not be upgraded — nothing owned them as modules. And a
|
||||
mesh that wanted a database or a queue for its modules installed the `postgres`/`lavinmq` modules,
|
||||
each of which raised a **second** server: a mesh ran two postgres and two brokers.
|
||||
|
||||
## Considered Options
|
||||
|
||||
1. **Leave them as bundle-only plumbing.** Rejected: they cannot be upgraded, and the second
|
||||
server stays. The floor keeps a permanent specialty in it.
|
||||
2. **The control-plane pivot verbatim — raise a temporary one, install the module, retire the
|
||||
temporary** ([ADR 0067](0067-genesis-is-a-pivot.md)). Rejected for a *stateful* server: it means
|
||||
a handover with real downtime, tearing down the store the controller is mid-read of.
|
||||
3. **Adopt in place.** Chosen.
|
||||
|
||||
## Decision
|
||||
|
||||
The foundation's store and broker are **adopted in place** as the ordinary `postgres` and `lavinmq`
|
||||
modules. Genesis still raises them first (nothing else can — ADR 0006), then each module declares a
|
||||
container with the **same name, image and spec** the foundation raised, so the applier — which keys
|
||||
on the container name and compares a spec digest — reconciles it rather than raising a second. The
|
||||
credentials are the foundation's, made at genesis and carried in through `secret accept`, because
|
||||
the mesh cannot invent a credential that already made the databases. The servers bind mesh-wide so
|
||||
a consumer on any node can reach the one shared server.
|
||||
|
||||
A mesh runs **one postgres and one lavinmq**, and each is upgradeable through a stated window: the
|
||||
store's is a connection-pool reconnect; the broker's is the harder case of recreating the bus the
|
||||
push travels over, so the mesh reconnects to the one that returns.
|
||||
|
||||
## Consequences
|
||||
|
||||
The twelve-module floor has no specialty left in it — the store and broker are moments in a
|
||||
module's life, not a separate kind of thing. Two follow-ups are tracked:
|
||||
[issue 054](../04-ISSUES/054-the-adopted-store-and-broker-are-open-before-the-filter/00-report.md)
|
||||
(the adopted servers bind `0.0.0.0` before the packet filter is installed) and
|
||||
[issue 055](../04-ISSUES/055-the-adopted-store-and-broker-may-be-reachable-on-one-node-only/00-report.md)
|
||||
(whether a consumer on another node reaches them over the overlay).
|
||||
|
||||
What got harder: a foundation upgrade recreates the very server the controller reads from, or the
|
||||
bus the instruction to upgrade travels over — a window that a stateless module upgrade does not have.
|
||||
|
||||
## References
|
||||
|
||||
- [issue 051](../04-ISSUES/051-the-mesh-cannot-update-what-it-depends-on/00-report.md) — the gap this closes.
|
||||
- [`03-DESIGN/01-to-be/07-the-foundation.md`](../03-DESIGN/01-to-be/07-the-foundation.md) — the amended design.
|
||||
- Shipped across mesh-host, mesh-catalog and mesh-lab (main); proven 22/22 in the one-node lab.
|
||||
@@ -84,6 +84,7 @@ python3 00-META/checks/index.py fail if stale
|
||||
- **0001** — [The mesh brokers capabilities; nodes host; agents think](0001-mesh-brokers-nodes-host-agents-think.md)
|
||||
- **0002** — [Nodes communicate over a message broker, not over HTTP](0002-nodes-communicate-over-a-broker.md)
|
||||
- **0003** — [An agent is a persistent employee, not an instance of a pool](0003-agents-are-persistent-employees.md)
|
||||
- **0077** — [The parts are named controller, foundation, node — not control plane, substrate, master](0077-the-controller-and-the-foundation.md)
|
||||
|
||||
### Its tiers, from the bottom up
|
||||
|
||||
@@ -100,15 +101,13 @@ python3 00-META/checks/index.py fail if stale
|
||||
- **0036** — [Bootstrap ends at a usable mesh, and the first credential comes from a person](0036-bootstrap-ends-at-a-usable-mesh.md)
|
||||
- **0066** — [Public routing is name-agnostic, its names are resolved inside the mesh, and an internal authority can certify them](0066-public-routing-is-name-agnostic.md)
|
||||
- **0067** — [Genesis is a pivot: a temporary control plane installs the registry that makes it permanent](0067-genesis-is-a-pivot.md)
|
||||
- **0068** — [The lab takes requests, one at a time, and runs each from its own copy](0068-the-lab-takes-requests.md) *(proposed)*
|
||||
- **0069** — [A module is a repository and a path within it](0069-a-module-is-a-repository-and-a-path.md)
|
||||
- **0070** — [The catalogue owns the module graph, and genesis builds rather than carries](0070-the-catalogue-owns-the-module-graph.md)
|
||||
- **0071** — [Genesis clones from a mesh, and checks what it got](0071-where-genesis-gets-its-source.md)
|
||||
- **0072** — [Two graphs, and a build chain that orders itself](0072-two-graphs-and-the-build-chain.md)
|
||||
- **0073** — [The installer carries a builder, and the registry stays where it is](0073-the-installer-carries-a-builder.md)
|
||||
- **0074** — [The mesh defines a module protocol; an SDK is an implementation of it](0074-the-wire-is-specified-not-the-types.md)
|
||||
- **0075** — [An artifact store is a provision; a package registry is a different one](0075-two-stores-and-which-provides-what.md) *(proposed)*
|
||||
- **0076** — [The SDK is a published package, and the toolchain resolves it by version](0076-the-sdk-is-a-published-package.md) *(proposed)*
|
||||
- **0075** — [An artifact store is a provision; a package registry is a different one](0075-two-stores-and-which-provides-what.md)
|
||||
- **0078** — [The store and the broker are ordinary modules](0078-the-store-and-broker-are-modules.md)
|
||||
|
||||
### What runs on them, and how it gets there
|
||||
|
||||
@@ -146,6 +145,9 @@ python3 00-META/checks/index.py fail if stale
|
||||
- **0016** — [The lab](0016-the-lab.md)
|
||||
- **0037** — [Where a module lives](0037-where-a-module-lives.md) *(proposed)*
|
||||
- **0039** — [What the SDK holds, and what it refuses](0039-what-the-sdk-holds-and-refuses.md)
|
||||
- **0068** — [The lab takes requests, one at a time, and runs each from its own copy](0068-the-lab-takes-requests.md) *(proposed)*
|
||||
- **0069** — [A module is a repository and a path within it](0069-a-module-is-a-repository-and-a-path.md)
|
||||
- **0076** — [The SDK is a published package, and the toolchain resolves it by version](0076-the-sdk-is-a-published-package.md)
|
||||
|
||||
### How it is checked
|
||||
|
||||
|
||||
Reference in New Issue
Block a user