--- status: accepted date: 2026-08-27 deciders: jochen reconstructed: false extends: 0015-mesh-brokers-nodes-host-agents-think.md --- # 55. The control plane is the node-coordinating contexts, and the rest are hosted ## Context Three different context lists are in circulation and none of them was decided: | Where | Count | Named | |---|---|---| | [ADR 0015](0015-mesh-brokers-nodes-host-agents-think.md), **accepted** | **nine** | mesh, agents, work, stream, delivery, knowledge, ai, observability, config | | [`06-the-control-plane.md`](../03-DESIGN/01-to-be/06-the-control-plane.md) | **ten** + `api` | record, inventory, config, connectivity, provisioning, delivery, observability, identity, work, knowledge | | `01-to-be/README.md` (until today) | **eight** | — | `06` cites ADR 0015 in its own frontmatter while presenting a list that is not 0015's. And [research 006](../01-RESEARCH/006-mesh-from-scratch/skeleton.md), which produced the ten, said plainly what should happen next: > This is an addition to an accepted record, so it is a **decision, not a drafting choice**. It > belongs in a new record that extends ADR 0015 — **not written here.** **That record was never written, and the design used the list anyway.** This is exactly what `01-to-be`'s own rule forbids — *every statement here traces to a record; nothing arrives by drafting* — and it is why the count could drift three ways without anybody noticing. ### What changed silently Reconciling the two lists, the differences are not cosmetic: | | | |---|---| | **added, with reasoning** | `connectivity` (research 006 Move 3; now designed in [`08`](../03-DESIGN/01-to-be/08-connectivity.md) and settled by [ADR 0049](0049-a-route-is-a-grant.md)–[0052](0052-a-filter-rule-names-its-source.md)) | | **added, argued but open** | `record` — research 006 explicitly leaves *where the record lives* unresolved | | **split** | 0015's `mesh` became `inventory` + `provisioning` | | **renamed** | 0015's `agents` became `identity` | | **dropped with no reasoning at all** | **`stream`** — threads, mentions, messages, meetings, notifications; **`ai`** — provider grants and rotation | The last row is the finding. Two contexts holding real behaviour vanished between an accepted record and a design document, and nothing anywhere says they were removed or where their content went. ## Decision **Apply `06`'s own test honestly, and it sorts the list for us.** The test is *everything that needs to know about more than one node.* Run it: | Context | Needs to know about more than one node? | | |---|---|---| | **inventory** | which nodes exist, what is assigned where | **control plane** | | **config** | derives settings and secrets **onto nodes** | **control plane** | | **connectivity** | who peers with whom, which node is reachable | **control plane** | | **provisioning** | grants between modules on different nodes | **control plane** | | **delivery** | source to artifact **to node** | **control plane** | | **observability** | health of nodes, including *unreachable for a week* | **control plane** | | **identity** | credentials delivered per agent's node bindings and modality ([ADR 0015](0015-mesh-brokers-nodes-host-agents-think.md)) | **control plane** | | **work** | a task does not need to know a node exists | **hosted** | | **knowledge** | a document does not either | **hosted** | | **stream** | nor does a message | **hosted** | | **ai** | a provider licence is a **grant** ([ADR 0005](0005-capabilities-are-provisioned-on-declaration.md)) and its delivery is `config`'s | **folded** | **So: seven contexts and one interface.** > **inventory, config, connectivity, provisioning, delivery, observability, identity** — plus > **`api`**, the one interface every surface speaks to. **`work`, `knowledge` and `stream` are mesh-hosted applications, not control plane.** They are first-party, they ship with everything else, and they run on the mesh exactly the way anything else does. Being ours does not make them infrastructure. **`ai` is not a context.** A provider licence is a grant like a database or a bucket, and delivering it is `config`'s existing job. 0015 already did the hard part here by removing the node licence — *a node holds no licence; an agent holds credentials* — and what remains needs no authority of its own. **`record` is deferred, deliberately.** [ADR 0045](0045-a-context-owns-its-store.md) makes it load-bearing — contexts integrate through it — and research 006 leaves *where it lives* open, on the grounds that putting it in the substrate risks recreating the circularity the tier design just removed. Naming it a context here would settle by listing what has not been settled by arguing. **Seven is the decided count; the record is an eighth question, not an eighth entry.** ## The cost, stated plainly **A surface composing across this boundary now reads more than one interface.** The board shows nodes *and* tasks *and* documents; under this decision that is the control plane's `api` plus work's and knowledge's. This was raised as an objection before — *that only moves the problem up a layer* — and it deserves an honest answer rather than a reassurance. The answer is that [ADR 0045](0045-a-context-owns-its-store.md) already requires it: a surface reads **interfaces, never stores**, so a board was always going to compose rather than join. What this decision changes is the *number* of interfaces, not the kind of work. And `06`'s constraint — a single surface can compose contexts only while one interface sits in front of them — was already written about the control plane's contexts, and still holds for the seven. **The alternative is available and should be named:** keep all ten under tier 2 and accept that *control plane* means *everything first-party*, not *everything node-coordinating*. Rejected because the node-coordinating test is doing real work elsewhere — it is what justified `connectivity`, and it is the same test that defines the substrate. A definition that sorts cleanly in one place and is waved through in another is not a definition. ## Consequences - **Three lists become one, and it is a decision rather than a draft.** `06` and the to-be README are corrected to seven, and `06`'s frontmatter stops citing a record it contradicts. - **`stream` is reinstated, as a hosted application.** It was dropped by accident; this puts it somewhere on purpose. Its content — threads, notifications, meetings — is real and has to live somewhere nameable. - **Tier 4 gains its first named residents.** Until now the tier existed with nothing in it, which is part of why contexts drifted upward into tier 2 unopposed. - **The eight-nine-ten drift had no mechanism that would have caught it**, and neither does the next one. A design document cites decisions in its frontmatter and nothing checks that what it says matches what they say. - **Splitting `mesh` into `inventory` and `provisioning` is inherited without fresh argument.** It is right under [ADR 0045](0045-a-context-owns-its-store.md) — they would own separate stores — but this record adopts it from research 006 rather than re-deriving it, and that is worth saying rather than implying it was examined. ## References - [ADR 0015](0015-mesh-brokers-nodes-host-agents-think.md) — the nine this extends. - [Research 006](../01-RESEARCH/006-mesh-from-scratch/skeleton.md) — the ten, and the instruction to write this record. - [ADR 0045](0045-a-context-owns-its-store.md) — why the boundary costs what it costs. - [`06-the-control-plane.md`](../03-DESIGN/01-to-be/06-the-control-plane.md) — the document this corrects.