From fa9889536c8032c10a9c65f62d0bac6708fb4f89 Mon Sep 17 00:00:00 2001 From: jochen Date: Wed, 26 Aug 2026 23:02:52 +0200 Subject: [PATCH] 011: tools have a different audience, migrations cross the edge, provisioning is early MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three additions, and the third kills an assumption. Tools are the most common content in the catalogue — 56 of 126 modules, more than carry a service — and they survive the split without fitting either half. A tool is not an artifact and not node state; it is a contract the mesh publishes on a module's behalf, and what consumes it is an AGENT rather than another module. That is a second audience the design has not described. Whether it is one relation with two audiences or two relations is cheap to decide now and expensive later. A migration belongs to the CONSUMER and runs on the PROVIDER. A game's migrations run against the database the store granted it: owned by the consumer, hosted inside something it does not control, ordered after the provisioning edge because there is nothing to migrate until the grant exists, and scoped to that grant. Ownership crosses the edge, which nothing in provides and requires expresses — and it gives a consumer's own install an internal order, provisioned then migrated then started, that depends on an edge rather than on its contents. And provisioning is EARLY, not late. The assumption worth killing is that it is something the control plane does for consumers once a mesh is running. The mesh's own registry database is provisioned before there is a mesh, and so is its virtual host on the broker: the store runs from the carried bundle, a database is created in it, the mesh's own schema is applied, and only then does a control plane exist. Steps two and three happen before there is a mesh to do them, so provisioning is part of the bootstrap and part of what the bundle has to express. Which strains ADR 0043. The host applies declared state ON THIS MACHINE, and a database inside a running store is not a file or a unit. At bootstrap it is at least local — the store is on the same machine. Afterwards a consumer on one node provisioned from a store on another is the ordinary case and reaching it is not the host's job. The same operation is local at bootstrap and remote later, which is either two mechanisms or one with a tier boundary crossing inside it. Currently the sharpest unresolved thing in the effort. --- 01-RESEARCH/011-the-module-graph/features.md | 17 +++++++ .../011-the-module-graph/worked-provider.md | 48 +++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/01-RESEARCH/011-the-module-graph/features.md b/01-RESEARCH/011-the-module-graph/features.md index 82d05d4..0e2aa48 100644 --- a/01-RESEARCH/011-the-module-graph/features.md +++ b/01-RESEARCH/011-the-module-graph/features.md @@ -85,6 +85,23 @@ Nothing replaces it, because it was never one concept: | prerequisite-* | an **edge** in the graph | the catalogue | | verify, verifiers | the host's **read-back** | the host | +## Tools are a facet, and their consumer is not a module + +The most common content in the catalogue: 56 of 126 modules carry a tool surface, more than +carry a service. + +It survives the split, and it does not fit either half cleanly. A tool is not an artifact and +not node state — it is a **contract the mesh publishes on a module's behalf**, and what consumes +it is an **agent**, not another module. + +That is a second audience, and the design has only described one. A module `provides` things +other modules require; a module also `provides` things agents call. Same word, different +consumer, different lifecycle — a tool appears when the module is assigned somewhere and +disappears when it is not, and nothing in the graph edges says so. + +Whether that is one relation with two audiences or two relations is undecided, and it is the +kind of question that is cheap now and expensive later. + ## What is lost, and should not be **Detection.** Features are detected from the directory rather than declared, and the reason is diff --git a/01-RESEARCH/011-the-module-graph/worked-provider.md b/01-RESEARCH/011-the-module-graph/worked-provider.md index ac36f81..d016ac8 100644 --- a/01-RESEARCH/011-the-module-graph/worked-provider.md +++ b/01-RESEARCH/011-the-module-graph/worked-provider.md @@ -122,6 +122,54 @@ The pieces that follow, none of them settled here: - **Moving a binding moves data.** Whatever the mechanism, changing it is a migration and not a configuration change, and a design that lets it look like the latter will lose something. +## Provisioning is early, not late + +An assumption worth killing: that provisioning is something the control plane does for +consumers once a mesh is running. + +**The mesh's own registry is a provisioned database.** So is its virtual host on the broker. +Neither exists until something creates them, and nothing in the mesh works until they do. The +order is: + +``` +1 the store runs from the bundle the host carries +2 a database is created in it a provisioning step +3 the mesh's own schema is applied a migration, against that database +4 the control plane starts and only now is there a mesh +5 everything else is provisioned the ordinary path +``` + +Steps 2 and 3 happen **before there is a mesh to do them**. So provisioning is not a +control-plane service that consumers use; it is part of the bootstrap, and part of what the +carried bundle has to be able to express. + +**Which strains what a declaration is.** [ADR 0043](../../02-DECISIONS/0043-a-declaration-is-an-ordered-list-of-owned-resources.md) +has the host applying *declared state on this machine*. A database inside a running store is not +a file or a unit — and at bootstrap it is, at least, local: the store is on the same machine as +the host applying the bundle. + +Later it is not. A consumer on one node provisioned from a store on another is the ordinary +case, and reaching it is not the host's job. So the same operation is local at bootstrap and +remote afterwards, which is either two mechanisms or one mechanism with a boundary crossing in +it. Undecided, and it is the sharpest unresolved thing in this file. + +## A migration belongs to the consumer and runs on the provider + +A game defines migrations. They run against the database the store granted **it**. So the +migration is: + +- **owned** by the consumer — it is that module's schema, versioned with that module; +- **hosted** by the provider — it runs inside something the consumer does not control; +- **ordered** after the provisioning edge — there is nothing to migrate until the grant exists; +- **scoped** to the grant — the consumer's migrations touch its database and no other. + +Ownership crosses the edge, which nothing in *provides* and *requires* expresses. And it is the +*action* category from [`features.md`](features.md) made concrete: not an artifact, not node +state, and not something the host can apply, because the thing it changes is not the machine. + +It also gives a consumer's own install an internal order — **provisioned, then migrated, then +started** — that depends on an edge rather than on the module's contents. + ## What still has no answer **How many instances of postgres should exist?** One per mesh is wrong — a node that must work