Order the records the way the system is learned
Jochen asked whether the order made sense. It did not -- it followed when things happened to be decided, which after consolidation is fictional anyway since record 5 alone folds decisions taken across a week. Concretely wrong before: the domain statement sat at 8, after five engineering rules; the constitution was scattered across 5, 12 and 17; the tiers landed at 15, 16, 21 and 22 with process records in between. Now it walks: what the mesh is (1-3), its tiers from the bottom up (4-8), what runs on them and how it gets there (9-10), how it is built (11-16), how it is checked (17-18), how we work (19-23). Two things made this safe rather than free. It is a permutation, not a compaction, so the renames go through temporary names -- otherwise two files want one slot and one is lost. And the reference rewrite is a single simultaneous pass, because almost every number moved into a slot another number was vacating; replacing one at a time would have cascaded and pointed things at the wrong record while still resolving. Verified: 284 [ADR NNNN](path) links across the repository, all with matching text and target. The ordering principle is now stated in 19 rather than left implicit -- the repository already said "the numbering is the flow" about its folders, and there was no reason for the records to be the exception.
This commit is contained in:
@@ -4,11 +4,11 @@ status: designed
|
||||
code: []
|
||||
updated: 2026-08-27
|
||||
decisions:
|
||||
- 02-DECISIONS/0016-the-node-host.md
|
||||
- 02-DECISIONS/0021-the-substrate-and-the-control-plane.md
|
||||
- 02-DECISIONS/0011-how-this-repository-works.md
|
||||
- 02-DECISIONS/0008-mesh-brokers-nodes-host-agents-think.md
|
||||
- 02-DECISIONS/0021-the-substrate-and-the-control-plane.md
|
||||
- 02-DECISIONS/0005-the-node-host.md
|
||||
- 02-DECISIONS/0006-the-substrate-and-the-control-plane.md
|
||||
- 02-DECISIONS/0019-how-this-repository-works.md
|
||||
- 02-DECISIONS/0001-mesh-brokers-nodes-host-agents-think.md
|
||||
- 02-DECISIONS/0006-the-substrate-and-the-control-plane.md
|
||||
---
|
||||
|
||||
# The control plane
|
||||
@@ -24,7 +24,7 @@ This document defines it. It does **not** design the contexts inside it; those a
|
||||
> **The control plane is everything that needs to know about more than one node.**
|
||||
|
||||
That is the whole test, and it is not arbitrary — it follows from
|
||||
[ADR 0016](../../02-DECISIONS/0016-the-node-host.md). The host applies and
|
||||
[ADR 0005](../../02-DECISIONS/0005-the-node-host.md). The host applies and
|
||||
does not decide *because deciding needs knowledge the machine does not have*. So the line falls
|
||||
exactly there:
|
||||
|
||||
@@ -44,7 +44,7 @@ catch it because the dependency direction is still correct.
|
||||
## What is inside it
|
||||
|
||||
**Seven contexts and one interface**
|
||||
([ADR 0021](../../02-DECISIONS/0021-the-substrate-and-the-control-plane.md)) —
|
||||
([ADR 0006](../../02-DECISIONS/0006-the-substrate-and-the-control-plane.md)) —
|
||||
each one earning its place by the test above rather than by being ours:
|
||||
|
||||
| | | needs to know about more than one node because |
|
||||
@@ -64,7 +64,7 @@ anything else does. A task does not need to know a node exists, and *being ours
|
||||
something infrastructure*. `ai` is folded into `config`: a provider licence is an ordinary grant.
|
||||
|
||||
**`record` is an open question rather than an eighth entry.** Contexts integrate through it
|
||||
([ADR 0020](../../02-DECISIONS/0020-a-context-owns-its-store.md)), which makes it load-bearing,
|
||||
([ADR 0008](../../02-DECISIONS/0008-a-context-owns-its-store.md)), which makes it load-bearing,
|
||||
and [research 006](../../01-RESEARCH/006-mesh-from-scratch/skeleton.md) leaves *where it lives*
|
||||
unresolved — putting it in the substrate risks recreating the circularity the tier design just
|
||||
removed. Listing it here would settle by naming what has not been settled by arguing.
|
||||
@@ -88,10 +88,10 @@ because each one alone reads like a detail:
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| [ADR 0016](../../02-DECISIONS/0016-the-node-host.md) | the host never queries the mesh database |
|
||||
| [ADR 0015](../../02-DECISIONS/0015-a-node-and-how-it-joins.md) | a node holds its own identity **and nothing else** — the shared database credential every node carries today is the exposure this exists to remove |
|
||||
| [ADR 0020](../../02-DECISIONS/0020-a-context-owns-its-store.md) | a context is granted only what it **exclusively** owns: no shared writes, no read-only roles |
|
||||
| [ADR 0021](../../02-DECISIONS/0021-the-substrate-and-the-control-plane.md) | there is no single mesh database, and nothing reads one |
|
||||
| [ADR 0005](../../02-DECISIONS/0005-the-node-host.md) | the host never queries the mesh database |
|
||||
| [ADR 0004](../../02-DECISIONS/0004-a-node-and-how-it-joins.md) | a node holds its own identity **and nothing else** — the shared database credential every node carries today is the exposure this exists to remove |
|
||||
| [ADR 0008](../../02-DECISIONS/0008-a-context-owns-its-store.md) | a context is granted only what it **exclusively** owns: no shared writes, no read-only roles |
|
||||
| [ADR 0006](../../02-DECISIONS/0006-the-substrate-and-the-control-plane.md) | there is no single mesh database, and nothing reads one |
|
||||
|
||||
### So how does anything get in
|
||||
|
||||
@@ -123,17 +123,17 @@ node ──► broker ──► the control plane, consuming
|
||||
Seven contexts, **one deployable** — they are not separate services, so this is one process
|
||||
consuming and dispatching internally, not seven consumers racing. Each context then writes only
|
||||
the store it exclusively owns
|
||||
([ADR 0020](../../02-DECISIONS/0020-a-context-owns-its-store.md)).
|
||||
([ADR 0008](../../02-DECISIONS/0008-a-context-owns-its-store.md)).
|
||||
|
||||
**One consumer is a property worth having**, not just a consequence of
|
||||
[ADR 0021](../../02-DECISIONS/0021-the-substrate-and-the-control-plane.md). The as-is records that
|
||||
[ADR 0006](../../02-DECISIONS/0006-the-substrate-and-the-control-plane.md). The as-is records that
|
||||
*two consumers accidentally sharing one queue silently split the traffic between them, each
|
||||
receiving half of what it expects* — which has happened, between a module's daemon and its
|
||||
capability server. With one consumer that class of fault cannot arise.
|
||||
|
||||
**And the broker is the buffer while the control plane is down.** Nodes go on publishing;
|
||||
messages queue; the control plane drains them when it returns. That is what makes
|
||||
[ADR 0021](../../02-DECISIONS/0021-the-substrate-and-the-control-plane.md)'s single control plane
|
||||
[ADR 0006](../../02-DECISIONS/0006-the-substrate-and-the-control-plane.md)'s single control plane
|
||||
tolerable — an outage delays the mesh's *knowledge* rather than losing it.
|
||||
|
||||
**With one consequence that must be bounded before it is discovered:** a queue with no limit
|
||||
@@ -149,12 +149,12 @@ before designing for throughput.** The registry is `inventory`'s store: nodes, m
|
||||
assignments, versions. Those change when somebody changes something.
|
||||
|
||||
**Logs, metrics and health checks belong to `observability`**, which owns a different store
|
||||
([ADR 0020](../../02-DECISIONS/0020-a-context-owns-its-store.md)). Sending them to the registry
|
||||
([ADR 0008](../../02-DECISIONS/0008-a-context-owns-its-store.md)). Sending them to the registry
|
||||
would be exactly the shared-schema mistake 0045 exists to stop, arriving through the back door
|
||||
marked *performance*.
|
||||
|
||||
That leaves one genuine funnel: every context's writes go through the process that owns it, and
|
||||
[ADR 0021](../../02-DECISIONS/0021-the-substrate-and-the-control-plane.md) says there is one of it.
|
||||
[ADR 0006](../../02-DECISIONS/0006-the-substrate-and-the-control-plane.md) says there is one of it.
|
||||
For a mesh of a handful of machines this is not a scaling problem, and **it should not be solved
|
||||
by giving nodes database credentials** — that trades a bounded problem for an unbounded one. If
|
||||
it ever binds, the answers are at the consumer: batch, apply backpressure, or move the highest
|
||||
@@ -170,10 +170,10 @@ volume genuinely argues against a relational store.
|
||||
- **Not a surface.** Tier 3 is how people and agents reach it. It has one interface; the
|
||||
surfaces are what speak to that interface.
|
||||
- **Not the substrate.** It *runs on* tier 1 — PostgreSQL, LavinMQ, MinIO, an OCI registry
|
||||
([ADR 0021](../../02-DECISIONS/0021-the-substrate-and-the-control-plane.md)) — and cannot start without
|
||||
([ADR 0006](../../02-DECISIONS/0006-the-substrate-and-the-control-plane.md)) — and cannot start without
|
||||
them, which is what makes them a lower tier.
|
||||
- **Not privileged on a node.** It has no more access to a machine than the declaration
|
||||
vocabulary allows ([ADR 0015](../../02-DECISIONS/0015-a-node-and-how-it-joins.md)).
|
||||
vocabulary allows ([ADR 0004](../../02-DECISIONS/0004-a-node-and-how-it-joins.md)).
|
||||
|
||||
## It is also a consumer
|
||||
|
||||
@@ -184,7 +184,7 @@ module needs, granted the same way.
|
||||
That is the circularity the tiers exist to resolve rather than hide: the control plane cannot
|
||||
provision its own database, because it is not running yet. So its **store** is raised from the
|
||||
bundle the host carries, before there is a control plane to ask
|
||||
([ADR 0015](../../02-DECISIONS/0015-a-node-and-how-it-joins.md),
|
||||
([ADR 0004](../../02-DECISIONS/0004-a-node-and-how-it-joins.md),
|
||||
[research 011](../../01-RESEARCH/011-the-module-graph/worked-provider.md)).
|
||||
|
||||
Its virtual host and its bucket are **not** in the bundle — by the time they are wanted there is
|
||||
@@ -198,15 +198,15 @@ it.
|
||||
hosts, assigned to nodes by the same mechanism as everything else.
|
||||
|
||||
**One node runs it, and nothing takes over**
|
||||
([ADR 0021](../../02-DECISIONS/0021-the-substrate-and-the-control-plane.md)). The node is assigned,
|
||||
([ADR 0006](../../02-DECISIONS/0006-the-substrate-and-the-control-plane.md)). The node is assigned,
|
||||
never elected — no promotion, no quorum, no split brain.
|
||||
|
||||
That is sound rather than merely cheap, because the design already tolerates the control plane
|
||||
being absent by construction: a node reconciles from **its own** store
|
||||
([ADR 0016](../../02-DECISIONS/0016-the-node-host.md)) and
|
||||
([ADR 0005](../../02-DECISIONS/0005-the-node-host.md)) and
|
||||
never needed to ask anybody to hold the state it was last given. So the control plane being down
|
||||
is not a new failure mode — it is
|
||||
[ADR 0015](../../02-DECISIONS/0015-a-node-and-how-it-joins.md)'s ordinary disconnected
|
||||
[ADR 0004](../../02-DECISIONS/0004-a-node-and-how-it-joins.md)'s ordinary disconnected
|
||||
situation, happening to every node at once. **What is lost is change, not operation.**
|
||||
|
||||
The honest half: this node is a single point of failure, recovery is restore rather than
|
||||
@@ -216,14 +216,14 @@ every public name.
|
||||
## Open
|
||||
|
||||
- ~~**The contexts themselves.**~~ **Decided** — seven, by
|
||||
[ADR 0021](../../02-DECISIONS/0021-the-substrate-and-the-control-plane.md).
|
||||
[ADR 0006](../../02-DECISIONS/0006-the-substrate-and-the-control-plane.md).
|
||||
What remains open is narrower and named there: **where the record lives**, which research 006
|
||||
leaves unresolved because the substrate is the one place it must not go.
|
||||
- **How far it may be split.** One deployable today. Splitting a context out costs the single
|
||||
interface a surface depends on
|
||||
([research 011](../../01-RESEARCH/011-the-module-graph/00-overview.md)).
|
||||
- ~~**How many run, and what a node does without one.**~~ **Resolved** by
|
||||
[ADR 0021](../../02-DECISIONS/0021-the-substrate-and-the-control-plane.md). What remains is
|
||||
[ADR 0006](../../02-DECISIONS/0006-the-substrate-and-the-control-plane.md). What remains is
|
||||
measurement: nothing reports how long the control plane has been unreachable, or how close a
|
||||
certificate is to expiry — both needed for restore-not-failover to be a plan rather than a
|
||||
hope.
|
||||
|
||||
Reference in New Issue
Block a user