Renumber the records 1 to 23

The consolidation left a sparse sequence -- 1, 4, 6, 7, 9, 10, 12, 15, 16, 18,
19, 25, 34, 35, 36, 37, 40, 42, 44, 45, 48, 49, 58 -- where the gaps were only
the archaeology of what used to be there.

Renumbered contiguously. Renames run in ascending order, so every target number
is already free and no two files ever collide.

The reference rewrite is one simultaneous pass rather than a sequence of
replacements. Numbers moved into slots other numbers were vacating -- the node
host went 37 to 16 while the lab went 16 to 9 -- so replacing one at a time
would have cascaded and silently pointed things at the wrong record.

Seven plain-text references survived the merges as prose rather than links,
naming records that no longer existed: the enrolment token, the link boundary,
what a declaration is, reachability, the repository structure. Each mapped to
the consolidated record that now holds it.

Verified rather than assumed: every [ADR NNNN](path) link now has matching text
and target, checked across the whole repository, and the checker passes.

Frontmatter `consolidates:` lists dropped -- they named records that are gone,
and each consolidated record already says in prose what it absorbed.
This commit is contained in:
2026-08-28 23:28:34 +02:00
parent 77f3a4cea7
commit e1febe8e0f
84 changed files with 441 additions and 449 deletions
+16 -16
View File
@@ -2,14 +2,14 @@
status: graduated
initiated: 2026-08-25
became:
- 02-DECISIONS/0044-modules-and-the-graph.md
- 02-DECISIONS/0045-a-context-owns-its-store.md
- 02-DECISIONS/0019-modules-and-the-graph.md
- 02-DECISIONS/0020-a-context-owns-its-store.md
- 03-DESIGN/01-to-be/06-the-control-plane.md
- 03-DESIGN/01-to-be/07-the-substrate.md
touches:
- 02-DECISIONS/0044-modules-and-the-graph.md
- 02-DECISIONS/0044-modules-and-the-graph.md
- 02-DECISIONS/0036-a-node-and-how-it-joins.md
- 02-DECISIONS/0019-modules-and-the-graph.md
- 02-DECISIONS/0019-modules-and-the-graph.md
- 02-DECISIONS/0015-a-node-and-how-it-joins.md
- 03-DESIGN/00-as-is/02-modules-and-manifests.md
- 03-DESIGN/00-as-is/10-module-catalogue.md
- 04-ISSUES/007-an-installed-package-is-not-a-capability/00-report.md
@@ -21,9 +21,9 @@ touches:
> *instantiation*, and both are **runtime** edges — they answer *what does this need in order to
> run*. Delivery needs a different question answered — *what has to be rebuilt when this changes*
> — and that is a **build** edge, fixed inside an artifact rather than negotiated when it runs.
> Recorded by [ADR 0044](../../02-DECISIONS/0044-modules-and-the-graph.md), which also
> Recorded by [ADR 0019](../../02-DECISIONS/0019-modules-and-the-graph.md), which also
> notes what this effort's three entities turn out to be good for
> ([ADR 0044](../../02-DECISIONS/0044-modules-and-the-graph.md)).
> ([ADR 0019](../../02-DECISIONS/0019-modules-and-the-graph.md)).
## What is being investigated
@@ -76,10 +76,10 @@ concluded — `provider:` is a dependency edge that is not read as one, which ma
for a working mesh come out without a database; and the resolver continues past a cycle and
past a missing dependency, contrary to ADR 0008.
[ADR 0044](../../02-DECISIONS/0044-modules-and-the-graph.md) proposes
[ADR 0019](../../02-DECISIONS/0019-modules-and-the-graph.md) proposes
grouping modules by domain. [Research 005](../005-domain-grouping/analysis.md) measured that
proposal and found its evidence holds in exactly one place — reachability — which
[ADR 0037](../../02-DECISIONS/0037-the-node-host.md) has since absorbed
[ADR 0016](../../02-DECISIONS/0016-the-node-host.md) has since absorbed
into the host. The measured case for domain grouping has therefore been consumed by a decision
taken for unrelated reasons, and what remains is fifty modules that co-change with nothing.
@@ -102,7 +102,7 @@ and abandoned in favour of one concept with facets, for a reason worth keeping:
Filing decisions that follow from nothing are the disease research 005 measured. A second
taxonomy would reproduce it.
So [ADR 0044](../../02-DECISIONS/0044-modules-and-the-graph.md) survives, and the question
So [ADR 0019](../../02-DECISIONS/0019-modules-and-the-graph.md) survives, and the question
becomes what a module must be able to **declare**.
## The shape being investigated
@@ -111,7 +111,7 @@ Five declarations, of which two exist today.
| Declaration | Today | Notes |
|---|---|---|
| **requires a resource** — a database, a bucket | yes | provisioning, [ADR 0044](../../02-DECISIONS/0044-modules-and-the-graph.md) |
| **requires a resource** — a database, a bucket | yes | provisioning, [ADR 0019](../../02-DECISIONS/0019-modules-and-the-graph.md) |
| **provides a resource** | yes | as above |
| **requires another module** | **no** | the dependency edge — the graph's substance |
| **excludes another module** | **no** | installing A makes B unavailable |
@@ -174,12 +174,12 @@ Struck-through rows are answered, with where. The rest are live.
| ~~What does the graph **delete**?~~ | For the existing system: nothing, it is already there ([`analysis.md`](analysis.md)). For the design: the module/resource distinction, the interface as a kind of thing, capability checking as a separate mechanism, domain grouping, and — the first clear deletion — **grant kinds**, once a module may only be granted what it exclusively owns ([`worked-provider.md`](worked-provider.md)). |
| ~~Is an interface a module, or a name?~~ | A **name**, and only where providers are genuinely substitutable. The adapter is what creates one; without an adapter there is a **tag**, which describes and does not bind ([`proposal.md`](proposal.md)). |
| ~~Where do domain modules fit?~~ | They do not. There is core infrastructure — concrete modules named individually, not flavourable, nothing standing in front of them. |
| ~~What happens to domain grouping?~~ | Superseded. Folders assert relationships; edges record them. What grouping was for is a tag and a query. [ADR 0044](../../02-DECISIONS/0044-modules-and-the-graph.md) is `proposed` and should be superseded rather than narrowed. |
| ~~What happens to domain grouping?~~ | Superseded. Folders assert relationships; edges record them. What grouping was for is a tag and a query. [ADR 0019](../../02-DECISIONS/0019-modules-and-the-graph.md) is `proposed` and should be superseded rather than narrowed. |
| ~~Is there one kind of edge?~~ | **No — two.** *Presence*, where a thing must exist, and *instantiation*, where a provider makes something for a consumer and hands back credentials. Instantiation implies presence, not the reverse. |
| ~~When two modules provide one name, who chooses?~~ | Neither the consumer naming a node nor the consumer not caring. The consumer declares the **scope of its own need** — shared across its instances, or one each — the mesh binds, and the binding is written down and sticky. Where it is written follows the scope. |
| ~~Can several modules share one database?~~ | **No.** A module is granted only what it exclusively owns — no shared writes and no read role on another's store, because reading couples you to its layout just as firmly. |
| ~~What about a dashboard reading a dozen stores?~~ | **The rule is about contexts, not processes.** The mesh's own board reading the mesh's own store is the mesh showing its own data — not a boundary crossing. Everything inside a context reads its store freely; what is forbidden is a *different* context reading it. An earlier answer here was wrong. |
| ~~Can every registry consumer be served another way?~~ | **Largely dissolves.** Of eighteen direct consumers, the owner keeps its database, node appliers are already stopped by ADR 0037, and the bulk are **foreign tenants** — thirteen tables across three contexts — who need to move out rather than read differently. |
| ~~Can every registry consumer be served another way?~~ | **Largely dissolves.** Of eighteen direct consumers, the owner keeps its database, node appliers are already stopped by ADR 0016, and the bulk are **foreign tenants** — thirteen tables across three contexts — who need to move out rather than read differently. |
### Live
@@ -190,10 +190,10 @@ Struck-through rows are answered, with where. The rest are live.
| What does a provider hand back? | Credentials and an address for a store; a command for a terminal. Same relation, different shape crossing it. |
| Is provisioning one mechanism or two? | The mesh's own registry is provisioned **before there is a mesh**, so provisioning is part of the bootstrap and part of what the carried bundle expresses. At bootstrap the store is local; afterwards it is on another node. Same operation, both sides of a tier boundary. |
| Is a tool surface one relation with two audiences, or two? | 56 of 126 modules carry tools — more than carry a service — and what consumes them is an **agent**, not a module. |
| ~~Do the remaining cross-context reads want an interface or events?~~ | **Derived, not chosen.** Neither is SQL — that only ever runs against your own store. ADR 0036 makes disconnection ordinary, so anything that must work while disconnected cannot use a request and needs a local copy: a subscription. Anything where a stale answer is worse than none cannot use a subscription. |
| ~~Do the remaining cross-context reads want an interface or events?~~ | **Derived, not chosen.** Neither is SQL — that only ever runs against your own store. ADR 0015 makes disconnection ordinary, so anything that must work while disconnected cannot use a request and needs a local copy: a subscription. Anything where a stale answer is worse than none cannot use a subscription. |
| What does a consumer do about events it missed while disconnected? | Replay from a point, ask once for a full picture and resume, or rebuild. The question every projection has, and unanswered here. |
| What happens to a grant when its consumer is removed? | Dropping is data loss; keeping is a leak. ADR 0043's removal rule does not obviously carry, because the thing lives inside another module's state. |
| Is a declaration composed per node, from what that node reported? | Some configuration follows the hardware. Either the host fills a blank — deciding, against ADR 0037 — or the control plane composes from the node's inventory first. |
| What happens to a grant when its consumer is removed? | Dropping is data loss; keeping is a leak. ADR 0016's removal rule does not obviously carry, because the thing lives inside another module's state. |
| Is a declaration composed per node, from what that node reported? | Some configuration follows the hardware. Either the host fills a blank — deciding, against ADR 0016 — or the control plane composes from the node's inventory first. |
| Would `excludes` and capability requirements actually be used? | Zero manifests declare either, which is equally consistent with *nobody needs them* and *nobody can express them*. |
| What does an exclusion mean for something already installed? | Refuse the install, or surface the conflict and let it be decided. |
| Are tiers a view of the graph, or a constraint on it? | If a tier is a computed level the word is a convenience. If *a tier may depend only on tiers below it* is to be enforced, it is a constraint and must be stated as one. |
+3 -3
View File
@@ -36,7 +36,7 @@ another module's provision is treated as an implicit edge to that module**, so a
not have to declare the same relationship twice.
So *ordering by the graph* — which
[ADR 0037](../../02-DECISIONS/0037-the-node-host.md) says
[ADR 0016](../../02-DECISIONS/0016-the-node-host.md) says
the control plane will do — is not a thing to build. It is a thing to call.
## Finding 3 — the most important edges in the mesh are invisible
@@ -82,7 +82,7 @@ means.
## Finding 4 — the resolver continues past faults it should stop on
Two behaviours, both contrary to
[ADR 0058](../../02-DECISIONS/0058-delivery.md):
[ADR 0023](../../02-DECISIONS/0023-delivery.md):
- **A cycle warns and falls back to input order.** A cycle means no correct order exists; the
resolver proceeds with an arbitrary one and logs a line.
@@ -91,7 +91,7 @@ Two behaviours, both contrary to
Neither has fired in the current catalogue — there are no cycles and nothing dangling — which
is why nobody has noticed. They are latent, and they are in the component that
[ADR 0037](../../02-DECISIONS/0037-the-node-host.md) makes
[ADR 0016](../../02-DECISIONS/0016-the-node-host.md) makes
responsible for the ordering a host will apply without question.
## Finding 5 — placement is decided in the catalogue
+2 -2
View File
@@ -13,7 +13,7 @@ it is simply up. *A relational store, a message broker, an object store, a dashb
**2 — A system package with configuration.** Not a container. Installed into the machine,
configured through files, run by the service manager. *A firewall, a resolver, an overlay.*
Note: [ADR 0037](../../02-DECISIONS/0037-the-node-host.md) says applying
Note: [ADR 0016](../../02-DECISIONS/0016-the-node-host.md) says applying
these is the host's job — so what the module contributes is the *deciding*, not the doing.
**3 — An application a person launches.** Installed on a node, started by a human, running only
@@ -35,7 +35,7 @@ provider behind an assistant interface.*
**9 — A standalone application in its own repository.** Same shape as any of the above; the
difference is only where its source lives
([ADR 0010](../../02-DECISIONS/0010-applications-live-in-their-own-repository.md)). Worth
([ADR 0006](../../02-DECISIONS/0006-applications-live-in-their-own-repository.md)). Worth
listing because a schema that assumes a monorepo path would exclude it.
## The cases that break a naive schema
+1 -1
View File
@@ -55,7 +55,7 @@ registry. **Tier 2, delivery.**
**Resources — desired state on a machine.** `configs`, `service`, `systemd`, `vhost`, `tools`.
Applied, converged, idempotent — which is exactly what
[ADR 0037](../../02-DECISIONS/0037-the-node-host.md)
[ADR 0016](../../02-DECISIONS/0016-the-node-host.md)
already describes and what the host already does. **Tier 0.**
**Actions — run once, against something that is not this machine.** `migrations`, `seeds`,
+1 -1
View File
@@ -132,7 +132,7 @@ The question the effort opened with, answered for the design rather than for wha
to install. There is **core infrastructure**, which is a set of concrete modules named
individually — a firewall, a store, a resolver — with no flavour and no grouping module
standing in front of them.
- **Domain grouping as structure** ([ADR 0044](../../02-DECISIONS/0044-modules-and-the-graph.md)).
- **Domain grouping as structure** ([ADR 0019](../../02-DECISIONS/0019-modules-and-the-graph.md)).
Folders assert relationships; edges record them. What grouping was for — finding things,
seeing what belongs together — is a **tag** and a *query* over the graph, neither of which
anybody has to keep true by hand.
@@ -149,7 +149,7 @@ Steps 2 and 3 happen **before there is a mesh to do them**. So provisioning is n
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 0037](../../02-DECISIONS/0037-the-node-host.md)
**Which strains what a declaration is.** [ADR 0016](../../02-DECISIONS/0016-the-node-host.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.
@@ -158,7 +158,7 @@ Later it is not. A consumer on one node provisioned from a store on another is t
case, and reaching it is not the host's job.
**Resolved as two mechanisms, which is the answer rather than a compromise**
([ADR 0037](../../02-DECISIONS/0037-the-node-host.md)). The host
([ADR 0016](../../02-DECISIONS/0016-the-node-host.md)). The host
runs bootstrap actions locally from the bundle; the control plane provisions across the mesh
afterwards. Different actors, different scopes, different trust paths — so there is no single
operation with a tier boundary running through it.
@@ -279,7 +279,7 @@ of them is work.
| Group | What happens under the rule |
|---|---|
| **The owner and its machinery** — the mesh module, the SDK, the environment and configuration synchronisers, secrets | Nothing. It owns the database. |
| **Node appliers** — the overlay, the shell daemon, the resolver | **Already resolved.** [ADR 0037](../../02-DECISIONS/0037-the-node-host.md) stops the host querying the mesh database, decided for tier reasons with nothing to do with this. |
| **Node appliers** — the overlay, the shell daemon, the resolver | **Already resolved.** [ADR 0016](../../02-DECISIONS/0016-the-node-host.md) stops the host querying the mesh database, decided for tier reasons with nothing to do with this. |
| **Foreign tenants** — the work engine (10 tables), the knowledge base (2), pipeline logs (1) | They need **their own database**. They are not reading the registry; they are storing their own data in it. |
| **Genuine cross-context reads** — the work engine reads `nodes`; two others read a handful | The only ones needing an interface or events. |
@@ -312,7 +312,7 @@ not the distinction.
| when the other side is down | you cannot answer | you answer from your copy |
| what you must handle | a round trip that can fail | events you missed while you were down |
**What decides is not taste.** [ADR 0036](../../02-DECISIONS/0036-a-node-and-how-it-joins.md)
**What decides is not taste.** [ADR 0015](../../02-DECISIONS/0015-a-node-and-how-it-joins.md)
makes disconnection an ordinary situation rather than an exception. So:
> **Anything that must keep working while disconnected cannot use a request** — there is nobody
@@ -354,14 +354,14 @@ proves it cannot be a global rule.
**What happens to a grant when the consumer is removed?** The game is uninstalled. Its database
still exists, holding its data. Dropping it silently is data loss; keeping it forever is a leak.
[ADR 0037](../../02-DECISIONS/0037-the-node-host.md) says
[ADR 0016](../../02-DECISIONS/0016-the-node-host.md) says
the host removes what it applied and no longer declares — but this is not on the host, it is
inside another module's state, and the same reasoning does not obviously carry.
**Where does node-derived configuration come from?** (3) The control plane composes a
declaration, and cannot know this machine's memory. Either the host fills in a blank the
declaration leaves — which makes the host decide something, against
[ADR 0037](../../02-DECISIONS/0037-the-node-host.md) — or the control
[ADR 0016](../../02-DECISIONS/0016-the-node-host.md) — or the control
plane reads the node's inventory first and composes with it. The second is consistent and means
a declaration is composed *per node from what the node reported*, which is a stronger claim than
anything recorded so far.
@@ -421,7 +421,7 @@ But two things differ *between* them, and both matter more than the similarity.
[ADR 0001](../../02-DECISIONS/0001-nodes-communicate-over-a-broker.md) makes the broker the
channel every node takes work from, and
[ADR 0036](../../02-DECISIONS/0036-a-node-and-how-it-joins.md) makes it the security
[ADR 0015](../../02-DECISIONS/0015-a-node-and-how-it-joins.md) makes it the security
boundary — everything a node applies arrives through it.
So the module providing the broker is also **the way modules are managed**. A declaration cannot
@@ -430,7 +430,7 @@ reconfigured. Nothing else in the catalogue has that property; the store is cons
control plane but is not how the control plane *reaches* anything.
This is exactly what the carried bundle exists for
([ADR 0036](../../02-DECISIONS/0036-a-node-and-how-it-joins.md)): the broker is raised from
([ADR 0015](../../02-DECISIONS/0015-a-node-and-how-it-joins.md)): the broker is raised from
what the host carries, before there is a channel, because there is no other way to raise it.
Recorded here because it is a constraint on *one module*, not a general rule, and a schema with
no way to say so hides it.
@@ -439,7 +439,7 @@ no way to say so hides it.
The broker is one per mesh — a single point of failure and a single point of trust, by decision
rather than by accident. The store cannot be: a node that must keep working while disconnected
([ADR 0036](../../02-DECISIONS/0036-a-node-and-how-it-joins.md)) cannot depend on a database
([ADR 0015](../../02-DECISIONS/0015-a-node-and-how-it-joins.md)) cannot depend on a database
somewhere else.
Same nine properties, opposite answers. Which settles something the cases file left open: **how