0003 is now superseded by 0056. Nothing is left proposed. Applied: - 06 corrected from ten contexts to seven plus the api, each row now stating why it passes the more-than-one-node test. work, knowledge and stream are named as mesh-hosted rather than dropped; `ai` folds into config; `record` is deferred explicitly rather than listed. Its frontmatter now cites 0055. - how-we-build §4 amended per 0054, and the derived page republished by playbook 05. The sync found the drift the playbook exists to catch: the published §4 and the source did not say the same thing. The source said "four accidents, not four boundaries"; the published page said "one intent expressed four times", and only the published page carried the scope caveat. Same rule, two texts, already diverging. Verified the republish by reading back -- the new rule is present and the old section's body returns nothing -- rather than trusting the success message. The two smaller findings: - 0051 separated the transport identity from the declaring authority. It said the token carries "an address" and "the identity to expect" without saying what the node dials. It dials the broker, so pinning only that would make the control plane's authority transitive and let a compromised broker forge declarations -- which, since the host applies whatever the link delivers, is the whole machine. The token now carries four things, and declarations are signed and verified per declaration. Cost recorded: rotating the signing identity is fleet-wide. - 0026 no longer restates 0022's rule about generated views. 0022's own words are "prose does not restate status; one place, and two is one too many", which is what 0026 was doing to it.
8.1 KiB
layer, status, code, updated, decisions
| layer | status | code | updated | decisions | |||||
|---|---|---|---|---|---|---|---|---|---|
| to-be | designed | 2026-08-27 |
|
The control plane
Tier 2. The term appears seventy-nine times across this repository and was defined nowhere,
which is how-we-build §5 failing on this repository's own vocabulary.
This document defines it. It does not design the contexts inside it; those are open in research 006.
The definition
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 0037. The host applies and does not decide because deciding needs knowledge the machine does not have. So the line falls exactly there:
| Question | Whose |
|---|---|
| write this file, with this content, with this mode | the host — one machine |
| which nodes should run the store | the control plane — needs every node |
| is this unit running | the host — one machine |
| which peers belong in this node's overlay | the control plane — needs every node |
| what does this machine have installed | the host reports; the control plane records |
| has this node been unreachable for a week | the control plane — nobody else is watching |
A useful consequence: anything a single machine could answer alone is not the control plane's. If it needs no second node, putting it here is a mistake, and the tier rule will not catch it because the dependency direction is still correct.
What is inside it
Seven contexts and one interface (ADR 0055) — each one earning its place by the test above rather than by being ours:
| needs to know about more than one node because | ||
|---|---|---|
| inventory | nodes, modules, assignments, versions | that is the mesh-wide fact |
| config | settings, secrets, and deriving them onto nodes | it derives onto nodes |
| connectivity | overlay, resolution, exposure, filtering, certificates — specified in full in 08-connectivity.md |
who peers with whom; which node is reachable |
| provisioning | resource grants between modules | consumer and provider may be on different nodes |
| delivery | source to artifact to node | it targets nodes |
| observability | health, logs, metrics, alerts | unreachable for a week is nobody else's to notice |
| identity | agents, humans, services, authorisation | credentials follow an agent's node bindings and modality |
| api | the one interface every surface speaks to | — it is an interface, not a context |
What is deliberately not here. work, knowledge and stream are mesh-hosted
applications — first-party, shipped with everything else, and running on the mesh the way
anything else does. A task does not need to know a node exists, and being ours does not make
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 0045), which makes it load-bearing,
and research 006 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.
These are contexts, not services. They are separate in the sense that matters — each owns
its own store, and they integrate through the record rather than by reading one another
(how-we-build §4). They are not separate deployables, and
research 011 records why that
constraint is load-bearing: a single surface can compose them only while there is one interface
in front of them.
What it is not
- Not the thing that changes machines. It decides; the host applies. It never reaches into a node except through the host.
- 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 0048) — 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 0039).
It is also a consumer
The property that makes tier 2 unlike the others: the control plane has requirements of its own. It needs a PostgreSQL database, an AMQP virtual host, and a bucket — the same things any 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 0038, research 011).
Its virtual host and its bucket are not in the bundle — by the time they are wanted there is a control plane to grant them. Whether the bus must come first is open, and it turns on whether these contexts talk to each other over it.
Where it runs
On nodes, like anything else. It is not a place outside the mesh; it is modules the mesh hosts, assigned to nodes by the same mechanism as everything else.
One node runs it, and nothing takes over (ADR 0053). 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 0043) 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 0036'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 failover, and certificate renewal is the clock — an outage outlasting a renewal window expires every public name.
Open
The contexts themselves.Decided — seven, by ADR 0055. 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).
How many run, and what a node does without one.Resolved by ADR 0053. 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.- What the interface is. One interface is stated; its shape, and whether it is request, subscription or both, is not (research 011).