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:
@@ -2,14 +2,14 @@
|
||||
status: graduated
|
||||
initiated: 2026-08-25
|
||||
became:
|
||||
- 02-DECISIONS/0019-modules-and-the-graph.md
|
||||
- 02-DECISIONS/0020-a-context-owns-its-store.md
|
||||
- 02-DECISIONS/0009-modules-and-the-graph.md
|
||||
- 02-DECISIONS/0008-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/0019-modules-and-the-graph.md
|
||||
- 02-DECISIONS/0019-modules-and-the-graph.md
|
||||
- 02-DECISIONS/0015-a-node-and-how-it-joins.md
|
||||
- 02-DECISIONS/0009-modules-and-the-graph.md
|
||||
- 02-DECISIONS/0009-modules-and-the-graph.md
|
||||
- 02-DECISIONS/0004-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 0019](../../02-DECISIONS/0019-modules-and-the-graph.md), which also
|
||||
> Recorded by [ADR 0009](../../02-DECISIONS/0009-modules-and-the-graph.md), which also
|
||||
> notes what this effort's three entities turn out to be good for
|
||||
> ([ADR 0019](../../02-DECISIONS/0019-modules-and-the-graph.md)).
|
||||
> ([ADR 0009](../../02-DECISIONS/0009-modules-and-the-graph.md)).
|
||||
|
||||
## What is being investigated
|
||||
|
||||
@@ -74,12 +74,12 @@ What survives is narrower: three declarations that do not exist (`excludes`, a r
|
||||
capability, an interface with adapters), and two defects worth fixing whatever else is
|
||||
concluded — `provider:` is a dependency edge that is not read as one, which makes the closure
|
||||
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.
|
||||
past a missing dependency, contrary to ADR 0001.
|
||||
|
||||
[ADR 0019](../../02-DECISIONS/0019-modules-and-the-graph.md) proposes
|
||||
[ADR 0009](../../02-DECISIONS/0009-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 0016](../../02-DECISIONS/0016-the-node-host.md) has since absorbed
|
||||
[ADR 0005](../../02-DECISIONS/0005-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 0019](../../02-DECISIONS/0019-modules-and-the-graph.md) survives, and the question
|
||||
So [ADR 0009](../../02-DECISIONS/0009-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 0019](../../02-DECISIONS/0019-modules-and-the-graph.md) |
|
||||
| **requires a resource** — a database, a bucket | yes | provisioning, [ADR 0009](../../02-DECISIONS/0009-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 0019](../../02-DECISIONS/0019-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 0009](../../02-DECISIONS/0009-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 0016, 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 0005, 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 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. |
|
||||
| ~~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 0004 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 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. |
|
||||
| What happens to a grant when its consumer is removed? | Dropping is data loss; keeping is a leak. ADR 0005'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 0005 — 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. |
|
||||
|
||||
@@ -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 0016](../../02-DECISIONS/0016-the-node-host.md) says
|
||||
[ADR 0005](../../02-DECISIONS/0005-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 0023](../../02-DECISIONS/0023-delivery.md):
|
||||
[ADR 0010](../../02-DECISIONS/0010-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 0016](../../02-DECISIONS/0016-the-node-host.md) makes
|
||||
[ADR 0005](../../02-DECISIONS/0005-the-node-host.md) makes
|
||||
responsible for the ordering a host will apply without question.
|
||||
|
||||
## Finding 5 — placement is decided in the catalogue
|
||||
|
||||
@@ -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 0016](../../02-DECISIONS/0016-the-node-host.md) says applying
|
||||
Note: [ADR 0005](../../02-DECISIONS/0005-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 0006](../../02-DECISIONS/0006-applications-live-in-their-own-repository.md)). Worth
|
||||
([ADR 0015](../../02-DECISIONS/0015-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
|
||||
|
||||
@@ -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 0016](../../02-DECISIONS/0016-the-node-host.md)
|
||||
[ADR 0005](../../02-DECISIONS/0005-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`,
|
||||
|
||||
@@ -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 0019](../../02-DECISIONS/0019-modules-and-the-graph.md)).
|
||||
- **Domain grouping as structure** ([ADR 0009](../../02-DECISIONS/0009-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 0016](../../02-DECISIONS/0016-the-node-host.md)
|
||||
**Which strains what a declaration is.** [ADR 0005](../../02-DECISIONS/0005-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 0016](../../02-DECISIONS/0016-the-node-host.md)). The host
|
||||
([ADR 0005](../../02-DECISIONS/0005-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 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. |
|
||||
| **Node appliers** — the overlay, the shell daemon, the resolver | **Already resolved.** [ADR 0005](../../02-DECISIONS/0005-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. |
|
||||
|
||||
@@ -299,7 +299,7 @@ estimate. **The rule holds.**
|
||||
The remaining cross-context reads need one or the other. **Neither is SQL** — under exclusive
|
||||
ownership a module runs SQL against its own database and nothing else, whatever transport a
|
||||
query might travel over. Both options are the mesh's own channel, and both ride the broker
|
||||
([ADR 0001](../../02-DECISIONS/0001-nodes-communicate-over-a-broker.md)), so the transport is
|
||||
([ADR 0002](../../02-DECISIONS/0002-nodes-communicate-over-a-broker.md)), so the transport is
|
||||
not the distinction.
|
||||
|
||||
**The distinction is where the answer lives when you need it.**
|
||||
@@ -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 0015](../../02-DECISIONS/0015-a-node-and-how-it-joins.md)
|
||||
**What decides is not taste.** [ADR 0004](../../02-DECISIONS/0004-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 0016](../../02-DECISIONS/0016-the-node-host.md) says
|
||||
[ADR 0005](../../02-DECISIONS/0005-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 0016](../../02-DECISIONS/0016-the-node-host.md) — or the control
|
||||
[ADR 0005](../../02-DECISIONS/0005-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.
|
||||
@@ -419,9 +419,9 @@ But two things differ *between* them, and both matter more than the similarity.
|
||||
|
||||
### The broker cannot be managed over the broker
|
||||
|
||||
[ADR 0001](../../02-DECISIONS/0001-nodes-communicate-over-a-broker.md) makes the broker the
|
||||
[ADR 0002](../../02-DECISIONS/0002-nodes-communicate-over-a-broker.md) makes the broker the
|
||||
channel every node takes work from, and
|
||||
[ADR 0015](../../02-DECISIONS/0015-a-node-and-how-it-joins.md) makes it the security
|
||||
[ADR 0004](../../02-DECISIONS/0004-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 0015](../../02-DECISIONS/0015-a-node-and-how-it-joins.md)): the broker is raised from
|
||||
([ADR 0004](../../02-DECISIONS/0004-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 0015](../../02-DECISIONS/0015-a-node-and-how-it-joins.md)) cannot depend on a database
|
||||
([ADR 0004](../../02-DECISIONS/0004-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
|
||||
|
||||
Reference in New Issue
Block a user