Research 034: the mesh in domains
mesh/merge-gate pass: the change touches no module of the mesh's graph
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery stopped: the pull request closed unmerged

The operator asked for one language per domain because the same concept
keeps arriving under different words. Inventory the words in use, test a
domain split, list the clashes with evidence, and describe how the
glossary rule would be checked.
This commit is contained in:
jochen
2026-10-07 19:37:44 +02:00
parent 79cadf6c96
commit f2abbb042c
6 changed files with 1095 additions and 0 deletions
@@ -0,0 +1,108 @@
---
status: active
initiated: 2026-10-07
touches:
- 00-META/glossary.md
- 00-META/checks/
- 02-DECISIONS/0006-the-substrate-and-the-control-plane.md
- 02-DECISIONS/0008-a-context-owns-its-store.md
- 03-DESIGN/01-to-be/06-the-controller.md
- the descriptions of every module's tools and every seat's verbs in the catalogue
---
# 034 — The mesh in domains
## What is investigated
The operator, 2026-10-07: *"I wanted to develop our nox-mesh domain driven. Meaning every concept
should fit into some domain and we try to come up with a common knowledge base/glossary/jargon for our
application. We kind-of do this already I think, yet sometimes, you return different words for existing
concepts."*
Two terms from domain-driven design are used throughout this effort, so they are explained once here.
A **domain** (in the literature, a *bounded context*) is an area of the system inside which every word
has exactly one meaning, and which owns the concepts that meaning describes. A **ubiquitous language** is
the set of words a domain uses the same way in conversation, in documents and in code. The glossary
([`00-META/glossary.md`](../../00-META/glossary.md)) is this repository's attempt at a ubiquitous
language for the whole mesh, without domains.
The effort asks five questions:
1. **Which concepts are in use**, in the glossary, the decision records, the designs and the issue
reports, and in the words the running mesh's tools use to describe themselves?
2. **Into which domains do they fall?** Each domain gets a purpose, the concepts it owns, the one word
for each, and its relation to the others. The operator's starting guess — building and delivering
changes; running modules on machines; health and alerts; data and backups; people, conversation and
approvals; the network — is tested, not assumed.
3. **Where do the words clash?** Two or more words for one concept (a *synonym*), or one word for two
concepts (a *homonym*), each with evidence and a proposed single word.
4. **How is the glossary rule checked?** [`AGENTS.md`](../../AGENTS.md) says *a rule states how it is
checked*, and "one name per thing" is checked by nothing today.
5. **How should the glossary be organised by domain?** Described only; the glossary itself changes when
this effort graduates, not before.
## Why
Because the drift is measurable, and it costs. The glossary retired *control plane* on 2026-09-16; three
weeks later 29 occurrences stand in 12 to-be designs — the documents that tell somebody what to do — and
73 files created after the retirement use it. It retired *host agent*, *the host* and `mesh-host` for the
**node-engine** on 2026-10-05; the descriptions of four tools the running mesh serves still say *"the host
will restore"*, and the glossary's own entry for node tools says *"a host-side process the host
supervises"*. The glossary defines **node**, while the decisions and designs of the last week use
*machine* twice as often as *node*, and the console's own tools are called `mesh_machine` and list
"machines". A reader — person or agent — who meets two words assumes two things, and an agent answering
from these documents repeats whichever word it read last. That is the operator's complaint, observed.
## What it touches
The glossary and how it is kept; the checks in [`00-META/checks/`](../../00-META/checks/); the seven
contexts of the controller that [ADR 0006](../../02-DECISIONS/0006-the-substrate-and-the-control-plane.md)
named and [ADR 0008](../../02-DECISIONS/0008-a-context-owns-its-store.md) gave each its own store, which
are the nearest thing the mesh already has to domains; and the descriptions of the tools and seat verbs
that the modules in the catalogue serve, which are where an agent meets the mesh's words most often.
## The documents
| | |
|---|---|
| [01 — The concepts in use](01-the-concepts-in-use.md) | the inventory: what was read, how it was counted, what the glossary holds and what it lacks, and the words the running tools use |
| [02 — The domains](02-the-domains.md) | the proposed split into ten domains plus the repository's own, each with purpose, concepts, words and relations; the operator's guess tested |
| [03 — The clashes](03-the-clashes.md) | twenty clashes with evidence and a proposed word for each, the five most costly first |
| [04 — How the glossary is checked](04-how-the-glossary-is-checked.md) | a proposed check over hq documents and over the catalogue's tool descriptions; described, not built |
| [05 — A glossary by domain](05-a-glossary-by-domain.md) | how the glossary would be organised; described, not written |
## Findings so far
- **The mesh already has domains under another name.** ADR 0006 named seven *contexts* of the controller —
inventory, config, connectivity, provisioning, delivery, observability, identity. Only three of them have
a store today (`inventory`, `identity`, and `licences`, which is not one of the seven), and the words the
mesh has grown since (seat, delivery, condition, ask, data class) are not organised by them. The
proposed split in [02](02-the-domains.md) keeps five of the seven, renames one, and adds four.
- **The operator's guess survives mostly intact.** Five of its six domains hold up. It lacks a domain for
*identity and access* (credentials, grants, licences), one for *provisioning* (provider and consumer),
the *core* the rest runs on (controller, bus, store, lease, genesis), and the *module* itself, whose
manifest is the language every other domain reads. *Health and alerts* is better called *health and
repair*: the mesh says *condition*, not *alert*.
- **The glossary is short of the vocabulary in use, and contradicts itself twice.** It has 33 entries. At
least 40 words used in more than ten decision records each — *module*, *manifest*, *assignment*,
*machine*, *provider*, *condition*, *gate*, *tier*, *operator* among them — have no entry. It defines the
console as a module and, further down, says node tools replaced that name; it says the deprecated broker
holds no seat and, in the entry for *claim*, that it claims `mesh-broker`.
- **Most drift is in two places**: governing designs written before a word was retired and never
revisited, and tool descriptions, which nothing compares with the glossary at all.
- **Homonyms cost more than synonyms**, and a word list cannot catch them. *Plan*, *push*, *release*,
*gate*, *tier*, *ask*, *store* and *record* each mean two to four things today, several of them in the
verbs of the same seat.
## Questions for graduation
- **Machine or node.** One concept, two words, both heavily used; [03](03-the-clashes.md) recommends
*machine* in prose and keeps `node` only as an identifier (a scope's value and the `node-` prefix of seat
names). This is the largest rename the effort proposes, and the operator's call.
- **Domain or context.** The repository already says *context* (ADR 0006, ADR 0008) for an owner of
records with its own store. Using *domain* for the vocabulary partition beside it would be the effort's
own synonym. [02](02-the-domains.md) proposes that a domain is the vocabulary and ownership boundary and
a context is one store inside it, and asks for that to be decided rather than left to usage.
- **Which documents the check holds to the list**, and from which date ([04](04-how-the-glossary-is-checked.md)).
- **Where the tool-description check runs**: in the catalogue repository's merge check, or as a probe of the
running mesh, or both.
@@ -0,0 +1,148 @@
# 01 — The concepts in use
What was read, how words were counted, what the glossary holds, what it lacks, and which words the
running mesh's tools use. The domains in [02](02-the-domains.md) and the clashes in
[03](03-the-clashes.md) are drawn from this.
## What was read
| Source | Size on 2026-10-07 | How |
|---|---|---|
| the glossary | 33 entries | read whole |
| decision records (`02-DECISIONS/`) | 225 records | counted; the seven-contexts record (0006), its store rule (0008) and the records from 0220 to 0240 read for their words |
| to-be designs (`03-DESIGN/01-to-be/`) | 49 documents | counted; the controller (06), connectivity (08), and 45 to 48 read for their words |
| as-is designs (`03-DESIGN/00-as-is/`) | 17 documents | counted |
| issue reports (`04-ISSUES/`) | 291 issues | counted |
| research (`01-RESEARCH/`) | 33 efforts | counted; research 005 (*which domains the catalogue groups into*) read whole, as prior art |
| the running mesh's tools | 88 modules serving 535 tools, plus the verbs of 15 seats every machine holds and 5 seats held once for the mesh | listed through the console's read tools (overview, machine, search, describe); nothing was called that changes anything |
**How words were counted.** A case-insensitive, whole-word match per file; the number given is the number
of *files* containing the word, not of occurrences, unless a statement says otherwise. Where a file's age
matters, its age is the date git first records it. The tool descriptions are the first line each tool
gives of itself in the console's listing, which is cut at about 160 characters, so a word that occurs only
late in a long description is undercounted there.
## What the glossary holds
Thirty-three entries, in seven sections: the mesh and its machines; what runs the mesh; what the mesh
stores and serves; how modules relate to the mesh; the surfaces; how a change reaches the machines; the
operator's machine. Retired words are marked three ways — struck through (`~~flavor~~`), *"Replaces
**x**"*, and *"Not x"* — so no program can read the list of retired words from it reliably today.
**It contradicts itself in two places.**
- **The console.** The surfaces section defines the console as *"the module (`mesh-console`) that puts the
mesh's tools in front of whoever is on a machine"*. The operator's machine section, further down, defines
node tools as the runtime whose *"serving mode on loopback is what was called **the console**"*, and
says node tools *"replaces 'console' as the module's name; console remains the word for the person's end
of it."* Both entries are current.
- **The deprecated broker.** Its entry says it has *"no seat, not foundation"*. The entry for *claim*
says *"the `mesh-controller`, `postgres` and `lavinmq` modules claim the `mesh-controller`, `mesh-store`
and `mesh-broker` seats"*, and the entry for *bus* says the bus is held by the `mesh-broker` seat.
**It uses a word it retired.** The node tools entry says *"a host-side process the host supervises"*,
eight lines after the node-engine entry retired *the host*.
## What the glossary lacks
Words used in more than ten decision records each, with no entry of their own (files containing each, of
225 records):
| Word | Records | Word | Records | Word | Records |
|---|---|---|---|---|---|
| machine | 177 | operator | 125 | catalogue | 120 |
| declaration | 106 | manifest | 102 | reach | 101 |
| provider | 95 | person | 91 | adopted | 84 |
| tool | 76 | holder | 75 | grant | 65 |
| assignment | 60 | secret | 56 | scope | 55 |
| apply | 54 | resolver | 51 | genesis | 46 |
| verb | 45 | firewall | 43 | route | 42 |
| converged | 40 | private network | 37 | connectivity | 34 |
| the lab | 33 | proxy | 31 | overlay | 30 |
| upgrade | 27 | gate | 25 | condition | 23 |
| endpoint | 23 | reconcile | 22 | vault | 20 |
| hub | 19 | finding | 19 | health | 19 |
| licence | 16 | probe | 15 | tier | 14 |
| membership | 14 | anchor | 14 | backup | 11 |
*Module* itself — the word the whole mesh is built on — has no entry. Nor do the words of the four
designs written in the last week: *condition*, *healer*, *self-check*, *watchdog*, *hand-act*, *drill*,
*lease*, *epoch* (to-be 45, *a core that cannot fail silently*); *data class*, *restore point* (to-be 43
and ADR 0233); *converged* and *adopted* as the two states a machine is in (the controller's `nodes` verb
answers with them).
## The seven contexts, as they stand
ADR 0006 split the controller into seven **contexts** — areas of record, each owning its own store
(ADR 0008) — and to-be 06 tabulates them:
| Context | Owns, in ADR 0006's words | A store of its own today? |
|---|---|---|
| inventory | nodes, modules, assignments, versions | yes |
| config | settings, secrets, and deriving them onto nodes | no |
| connectivity | overlay, resolution, exposure, filtering, certificates | no |
| provisioning | resource grants between modules | no |
| delivery | source to artifact to node | no — deliveries are kept by the `mesh-delivery` module since ADR 0239 |
| observability | health, logs, metrics, alerts | no |
| identity | agents, humans, services, authorisation | yes |
The store has a third database the seven do not name, `licences` (ADR 0183). The seven are the nearest
thing the mesh has to domains, and they were drawn from one question — *does answering this need more than
one node?* — which is a test for what the controller owns, not for where a word belongs. Seat, claim,
bench, delivery group, condition, ask, data class and every word of the operator's conversation arrived
after them, and none of those records says which context its words belong to.
Research 005 asked a neighbouring question in August — which *modules* group into domains — measured which
modules change together, and found that only the reachability modules do. Its conclusion, recorded in ADR
0009, was that modules are not grouped into packages; it did not touch the vocabulary. This effort groups
*concepts and words*, not modules: a module may serve several domains, and the domains are not folders in
the catalogue.
## The words the running tools use
The console's listing gives each tool's first line. Over the 535 module tools (the seat verbs are counted
separately below):
| Word | Tools | Modules | Note |
|---|---|---|---|
| machine | 39 | 25 | the word most modules use for where they run |
| node | 27 | 5 | 21 of the 27 in the agent's configuration module; the others the vault, the bus server, the packet filter and a flow editor whose own objects are called nodes |
| the host / host's | 6 | 2 | the container module's `start` and `stop` tools, meaning the node-engine; the remaining uses are a network's hosts |
| operator | 28 | 23 | the person; consistent with the glossary |
| user | 30 | 12 | almost all a wrapped program's own accounts (an identity provider's users, the forge's users, a database's users) |
| install | 43 | 16 | a package installed on a machine, never the mesh's assignment |
| condition | 0 | 0 | — while the controller's verb is `conditions` |
| seat | 0 | 0 | the module tools never name a seat; only the console and the controller do |
| deploy, rollout, pipeline, control plane | 1, 0, 0, 0 | — | the one *deploy* is a wrapped program's own (a flow editor's) |
The seat verbs say:
- `<machine>/node-service-manager.start` and `.stop`: *"the answer says **the host** will restore what its
declaration says at its next apply"*.
- the bus server module's `connections` tool: *"a machine's **host** `node.<machine>`, a machine's runtime
`<machine>.node-tools`"* — three words (host, node, runtime) for two programs, in one line.
- `mesh-controller.plan`: *"What one machine would run, and why: **the declaration** the mesh would send
it"*; `mesh-controller.plans`: *"What the last merges produced … the tiers"*;
`mesh-controller.delivery-plan`: *"The delivery plan of a diffset"*. Three meanings of *plan* on one
seat.
- `mesh-controller.queue`, `.cancel`, `.clear`: *"Every **ask** in the build queue"* — while the glossary's
*ask* is a request for the operator's input.
- `mesh-delivery.release`: *"A person's word that a held delivery goes on"*; and
`anthropic-licence-manager.release`: *"Unbind a consumer"*.
- `mesh-controller.doctor`: *"The **self-check** …"* — the verb and the concept named differently.
- the nftables module's tool is called `firewall_rules`, and the seat it holds on every machine is
`node-packet-filter`, whose verb is `rules`.
- `mesh-controller.nodes`: *"Every **machine** the mesh knows"*; the verb is named for nodes and answers
in machines.
- `node-build-agent` is the name of a seat every machine holds, while the glossary avoids *agent*
*"because the word already means two other things here, the build agent and the operator's coding
agent"*, and ADR 0237 calls the same role *the build seat*.
- `operator-channel` is a seat of the mesh, held by the conversation's router (ADR 0234); the glossary
names the router and the `channel` bench but not the seat.
**Vendor words are not drift.** A module that wraps a program speaks that program's language where it
describes the program's own objects: an identity provider has *users* and *realms*, a media manager has
*releases*, a flow editor *deploys*. That is correct and must stay so; a check that flagged it would be
wrong ([04](04-how-the-glossary-is-checked.md) scopes the list to the mesh's own words for that reason).
The drift is where a tool describes **the mesh's** objects — its machines, its engine, its seats — in a
word the glossary retired or never had.
@@ -0,0 +1,292 @@
# 02 — The domains
A proposed split of the mesh's concepts into domains, tested against the operator's starting guess and
against the seven contexts of ADR 0006.
## What a domain is here, and how one was drawn
A **domain** is an area of the mesh that **owns** a set of concepts: inside it each concept has one
word, and the domain decides what that word means. Another domain may use the word — that is what makes
it a shared language — but may not change its meaning. Two relations between domains are named:
- **upstream / downstream.** Domain A is *upstream* of B when B depends on A's concepts and A does not
depend on B's. A change of meaning upstream ripples down; never the other way.
- **shared word.** A word two domains both use. It is safe when both mean the same thing and one of
them owns it; it is a clash when they mean different things ([03](03-the-clashes.md)).
Three tests decided where a concept belongs, in this order:
1. **Who records it.** The context, module or seat that writes the record of it owns it (ADR 0008: *a
context owns its store*). A condition is the controller's record; a delivery is `mesh-delivery`'s.
2. **Whose decision records define it.** The records that introduced the word, and the to-be design that
names those records in its frontmatter.
3. **Which other words it is never used without.** *Walk* never appears without *delivery*, *tier* and
*gate*; *healer* never without *condition* and *budget*.
**Domain and context.** ADR 0006's *context* is narrower than a domain: it is one owner of records, with
one store, inside the controller. This effort proposes that a domain may hold zero, one or several
contexts, and that the two words are kept apart: **domain** for the area of vocabulary and ownership,
**context** for a store-owning part of the controller. Whether to adopt *domain* at all, or to widen
*context* to mean it, is a question for graduation ([00](00-overview.md)); this document uses *domain*.
## The split
Ten domains of the mesh, and one of this repository. They are ordered from the most upstream to the most
downstream; each lists its purpose, the concepts it owns with the proposed word for each, and its
relations.
### 1. Module — what a module is and declares
**Purpose.** To say what one module is, in the one document every other domain reads: its manifest.
**Owns.** *module*; *manifest* (the file a module is defined by — not *module definition*, not
*module.yml* in prose); *resource* (what a manifest declares a machine must have: a file, a service, a
container, a package); *declares* (the verb for what a manifest states); *provides* / *requires* (as
written in a manifest; their meaning is Provisioning's); *claim* (a manifest's request to hold a seat);
*setting* (a value a manifest declares and an assignment gives); *kept region*; *bundle* and *tools
bundle*; *tool* (what a module serves) and *verb* (what a seat carries); *invokes*; *upgrade policy*
(`roll`, `together`, `record`); the declarations of *data* and *health* (their meaning is Data's and
Health's).
**Relations.** The most upstream domain. Every other domain reads the manifest, which makes its words a
**published language** — a vocabulary fixed in a schema that others conform to. It depends on nothing
but the Core's notion of a scope.
**Against the seven contexts.** None; the seven describe the controller, and the manifest is not the
controller's.
### 2. Core — the mesh's own machinery
**Purpose.** To keep the controller, the bus, the store and every machine's engine running and agreed,
so that every other domain has something to run on.
**Owns.** *controller*; *control-node*; *node-engine*; *node tools* (the tool runtime on every machine);
*foundation*; *store* (the one database server); *bus*; *broker seat*; *genesis* (raising the foundation
on an empty mesh); *lease* and *epoch* (ADR 0229: which controller may send, and the order of what it
sent); *context* (a part of the controller that owns a store).
**Relations.** Upstream of every domain but Module. Every other domain is a **conformist** to it — it
uses the bus and the store as they are and has no say in their shape.
**Against the seven contexts.** Not one of them: ADR 0006 described what the controller owns, and the
Core is the controller itself.
### 3. Placement — what runs on which machine
**Purpose.** To decide, send and apply what each machine runs, and to say why.
**Owns.** *machine* (or *node* — see clash 1); *operator account*; *assignment* (a module put on a
machine); *seat*, *scope* (machine, site, mesh), *capacity*, *bench*, *kind*, *holder*, *holding*;
*depends on a seat*; *declaration* (what the controller sends one machine — see clash 9); *send* (the
controller giving a machine its declaration; `push` is the verb that asks for it — clash 4); *apply* (the
node-engine making a machine match its declaration); *reconcile*; *converged* and *adopted* (a machine's
two states, ADR 0100); *pin* is Provisioning's, not this domain's.
**Relations.** Downstream of Module and Core. Upstream of Provisioning, Connectivity, Data and Health,
which all need to know what runs where. Shares *setting* with Module (a manifest declares it, an
assignment gives it its value) and *declaration* with Module (clash 9).
**Against the seven contexts.** ADR 0006's *inventory* (nodes, modules, assignments, versions) and the
derivation half of *config*.
The operator's guess called this *running modules on machines (seats, benches, claims)*, and it holds.
*Claim* belongs to Module (a manifest claims) and *holding* to Placement (an assignment holds), which is
the distinction the glossary already draws in *installed / holding*.
### 4. Provisioning — one module serving another
**Purpose.** To resolve which module serves a provision for which consumer, and to wire the two.
**Owns.** *provision*; *provider*; *consumer* (the module that requires); *pin* (a person's choice of
provider); *endpoint* (where a consumer reaches its provider); *pair credential* (the two ends of one
credential; the credential itself is Identity's); *retire* (a provider stops serving a consumer the mesh
no longer asks for, ADR 0230).
**Relations.** Downstream of Module (requires/provides), Placement (what runs where) and Identity (the
credential). Upstream of Data, which watches what a provider keeps for a consumer. Shares *consumer* with
Identity's licences (a licence is bound to a consumer) — the same idea, safely shared.
**Against the seven contexts.** ADR 0006's *provisioning*, unchanged.
The operator's guess has no such domain; its words are spread across *running modules* and *data*. They
are a language of their own: 95 decision records say *provider*, and four seat verbs (`pin`, `unpin`,
`retire`, `cleanup`) are about nothing else.
### 5. Identity and access — who may do what
**Purpose.** To issue, hold, rotate and check the credentials and grants by which modules, machines,
agents and the operator act.
**Owns.** *credential* (anything that proves an identity); *secret* (a credential or other value the vault
keeps sealed); *vault*; *grant* (what an identity may call or reach); *bus account* and *membership*; *rotate*;
*licence*, *binding* (a consumer bound to a licence), *adopt* (taking in a licence that existed before);
*proof* (what an authorising answer carries: a verified sender, a one-time code, a key's touch);
*operator identity* (the list the router checks a sender against).
**Relations.** Downstream of Core (the bus's accounts) and Placement (what is assigned where). Upstream of
Provisioning, Operator and conversation, and Change and delivery (whose builds are signed and whose
merges are approved).
**Against the seven contexts.** ADR 0006's *identity*, plus the secrets half of *config*, plus the
`licences` store, which is a context the seven did not name.
The operator's guess has no such domain. It is not small: *credential* is in 78 decision records, *grant*
in 65, *secret* in 56, and two of the three context stores that exist today (`identity`, `licences`) are
its.
### 6. Change and delivery — a commit on its way to the machines
**Purpose.** To take one commit from its pull request to every machine that should run it, and to put it
back when it fails.
**Owns.** *pull request*, *commit*, *trunk*; *merge check* (the two statuses a pull request carries, the
*merge gate* and the *repository check*, ADR 0238); *build*, *build seat*, *build queue* and the entry in
it (clash 7); *package* and *package-registry*; *artifact* and *artifact store*; *catalogue* (what the mesh
holds of every module, at which commit); *delivery*, *delivery group*, *delivery plan* (its *build plan*
and *deploy plan*); *walk*; *tier* in the sense of a step of a walk (clash 8); *first machine* and its
*gate* (clash 6); *rollback*; *the lab*, *scenario*, *replay*.
**Relations.** Downstream of Module, Core, Health (the gate reads health) and Data (a module holding
irreplaceable data is recorded, not rolled out, ADR 0236). Upstream of Placement in time — a walk asks
the controller to send — and of Operator and conversation, which carries its held deliveries to a person.
**Against the seven contexts.** ADR 0006's *delivery*, now owned by the `mesh-delivery` module rather than
by a context of the controller (ADR 0239).
The operator's guess called this *building and delivering changes*; it holds, with *change* kept for a
diff (the glossary already says so) and *delivery* for the thing that travels.
### 7. Health and repair — what is wrong, and putting it right
**Purpose.** To notice what is wrong with the mesh, say it once, repair what may be repaired unattended,
and record what was done by hand.
**Owns.** *health* (a module's or core component's statement of being well, ADR 0240); *probe*;
*signal* and *watchdog*; *self-check* (clash 13); *condition* (one open fact about something wrong, with a
key and a severity); *healer*, its *repair* and *budget*; *drill*; *hand-act*; *observation* (ADR 0231:
only observation raises or clears a condition).
**Relations.** Downstream of everything it watches. Upstream of Change and delivery (the gate) and of
Operator and conversation (a condition becomes a message).
**Against the seven contexts.** ADR 0006's *observability* — whose row says *"health, logs, metrics,
alerts"*. The mesh never built *alerts*; it built conditions, and the word *alert* survives only in a
wrapped dashboard program's tool. The domain is renamed accordingly: *observability* names the watching,
and half of what this domain owns is repair.
The operator's guess called this *health and alerts*. It holds as a domain, under the word the mesh
uses: *condition*, not *alert* (clash 14).
### 8. Data — what the mesh keeps, and getting it back
**Purpose.** To know every item of data a module holds, how precious it is, and to keep it recoverable.
**Owns.** *data* as a module declares it (ADR 0233); *data class* — *irreplaceable*, *rebuildable*,
*cache*; *backup*; *restore point*; *restore* (beside the live data, never over it); the bus's *stream
snapshot* (ADR 0235); *binding* of a consumer to its data moving only by a person (ADR 0232).
**Relations.** Downstream of Module (the declaration), Placement (where the data is) and Provisioning
(data a provider keeps for a consumer). Upstream of Change and delivery (irreplaceable data holds a
module back from rolling out) and of Health (data is watched).
**Against the seven contexts.** None. Data was not foreseen in ADR 0006; the self-check measures it today
(`mesh-controller.data`), and every machine's `node-backup` seat keeps it.
The operator's guess called this *data and backups*, and it holds.
### 9. Connectivity — how machines and modules reach one another
**Purpose.** To make every machine and module reachable by name where it should be, and unreachable
where it should not.
**Owns.** *private network* (clash 15); *resolver*; *uplink*; *hostname*; *zone*; *proxy* and *public
name*; *packet filter* (clash 16); *intrusion prevention* and *ban*; *reach* (how far an
assignment's endpoint may be reached from, ADR 0138); the roles a machine plays for the network (the anchor, a hub).
**Relations.** Downstream of Placement (what runs where) and Identity (who may reach). Upstream of
Provisioning (an endpoint must be reachable) and of Health (an unreachable machine is a condition).
**Against the seven contexts.** ADR 0006's *connectivity*, unchanged — and the one domain research 005
found real in the catalogue's history, where its modules are the only ones that change together.
The operator's guess called this *the network*, and it holds.
### 10. Operator and conversation — the person the mesh works for
**Purpose.** To let the mesh and its operator talk: tell, ask, answer, and act only on an answer it can
trust.
**Owns.** *operator* (the person who runs the mesh; clash 17); *person* (any human, as against the mesh
acting unattended); *console* (the person's or agent's end of node tools, clash 5); *channel* and *intake*
benches; *router* and the `operator-channel` seat it holds; *responder*; *ask*, *authorising ask*,
*answer*; *operator message* and *untrusted input*; *reference*; *notification* on a desktop.
**Relations.** Downstream of Health (conditions become messages), Change and delivery (a held delivery
waits for a person's word) and Identity (proofs, the operator's identities). An authorising answer acts in
whichever domain asked, through that domain's own verb; the conversation owns the asking, never the act.
**Against the seven contexts.** None. ADR 0006 named `api`, *"the one interface every surface speaks
to"*, as an interface rather than a context; the console and the conversation are what it became.
The operator's guess called this *people, conversation and approvals*. It holds, with one adjustment:
an **approval** is not this domain's concept. The approval of a merge is Change and delivery's (a human
approves the pull request); the release of a held delivery is `mesh-delivery`'s verb; the conversation
carries both as asks. *Approval* is in five decision records; *ask* in 58.
### 11. The record — how this repository works
Not a domain of the mesh but of the company's way of building it, and listed because its words collide
with the mesh's. **Owns** *research effort*, *decision record* (and *supersede*, *progressive insight*),
*design* (*as-is*, *to-be*), *issue*, *playbook*, *check* (one of `00-META/checks/`), *graduation*,
*hand-off*. Its *record* and *check* collide with the mesh's (clashes 11 and 12).
## The operator's guess, scored
| Guess | Verdict |
|---|---|
| building and delivering changes | **holds** as *Change and delivery* |
| running modules on machines (seats, benches, claims) | **holds** as *Placement*, with *claim* moved to Module |
| health and alerts | **holds, renamed** *Health and repair*: the mesh's word is condition, and half the domain is repair |
| data and backups | **holds** as *Data* |
| people, conversation and approvals | **holds** as *Operator and conversation*, with *approval* owned by the domain whose act is approved |
| the network | **holds** as *Connectivity* (ADR 0006's word) |
| — | **added**: *Module* (the published language), *Core* (what the rest runs on), *Provisioning* (ADR 0006 had it), *Identity and access* (ADR 0006 had it) |
## A map
```
Module (published language)
|
Core
|
+--------------------------+---------------------------+
| | |
Identity -------------> Placement |
| / | \ |
| / | \ |
v v v v |
Provisioning <------- Connectivity Data |
| | |
+-------------> Health and repair <------------------+
| |
v v
Change and delivery Operator and conversation
| ^
+-------------------+
(a held delivery waits for a person's word)
```
Arrows point downstream. Change and delivery appears low because it reads health and data; in time it
runs first, and asks Placement to send.
## What this split does not decide
- **Module ownership.** A module may serve several domains (the controller serves five). The domains
are a partition of words and records, not of the catalogue — research 005 already found that grouping
modules into folders records nothing.
- **Whether every domain gets a context with its own store.** ADR 0008's rule applies where a domain's
records live in the controller; *Change and delivery* has moved its records to a module instead, and
that is equally sound.
- **The operator's machine.** The desktop seats (display session, launcher, clipboard, notifier) are
Placement's seats like any other, and their words are each program's own. Research 018 and 026 did not
introduce a vocabulary that needs a domain.
@@ -0,0 +1,306 @@
# 03 — The clashes
Twenty places where the mesh's words disagree with each other. A **synonym clash** is two or more words
for one concept; a **homonym clash** is one word for two or more concepts. Each entry gives the evidence
— which documents and which tool descriptions say what — and a proposed single word, with the domain
([02](02-the-domains.md)) that would own it. Counts are files containing the word, as in
[01](01-the-concepts-in-use.md), unless they say *occurrences*.
The first five are ordered by cost: how often the clash appears where somebody is told what to do (a
to-be design, `00-META`, a tool description), and how likely it is to make a reader act on the wrong
thing. The other fifteen follow by domain.
A decision record keeps the words it was written with (its immutability rule), so a retired word found in
a decision record is not a fault and is not counted as drift below unless the record was written after
the word was retired.
## The five that cost most
### 1. *machine* and *node* — one concept, two words (synonym)
**Evidence.**
- The glossary defines **node**: *"a machine in the mesh"*, and has no entry for *machine*.
- In the decisions and designs of the last week (ADRs 0220 to 0240, to-be 45 to 48), *machine* occurs 706
times and *node* 349 times. Before ADR 0150, 6 record titles say *machine* and 9 say *node*; from ADR 0150
on, 17 and 17.
- In the tool descriptions, *machine* is in 39 tools of 25 modules; *node* in 27 tools of 5 modules, 21 of
them one module's (the agent's configuration, where *node* is also a scope's value).
- The console's own tools are `mesh_machine` and an overview that lists *"machines"*. The controller's verb
is `nodes` and answers *"Every **machine** the mesh knows"*; `node` answers *"What one machine
reported"*. Every seat a machine holds is named `node-…`.
- The glossary itself switches inside one entry: *control-node* is *"the one node that also holds…"*, and
the next sentence says it *"is not a separate kind of machine"*.
**Proposed word: _machine_** (Placement). It is what the operator, the tools and the newest records already
say, and it needs no explaining. *Node* survives only as an **identifier**: the value of a scope
(`scope: node`), the `node-` prefix of seat names, and *control-node* until it is renamed. The glossary
would map the identifier to the word, as it does for `mesh-host` today. The alternative — *node* everywhere —
is defensible and cheaper in code, and is what the glossary says; it is listed in
[00](00-overview.md) as the operator's call because either choice renames something heavily used.
### 2. *node-engine*, *mesh-host*, *the host*, *node host*, *host agent* — one program (synonym)
**Evidence.**
- The glossary retired *host agent*, *the host* and `mesh-host` for **node-engine** on 2026-10-05, keeping
`mesh-host` as the name of the repository, binary and service unit until they are renamed.
- Its own node tools entry still says *"a host-side process **the host** supervises"*.
- To-be 05 is titled *the node host*; *the host* is in 34 to-be designs and *node-engine* in 7.
- Of the decision records written since the retirement, ADR 0222 says *the host* six times, ADR 0236 six
times beside *node-engine* nine times, and ADR 0223 three of each.
- Tool descriptions: `<machine>/node-service-manager.start` and `.stop`, and the container module's
`start` and `stop`, say *"the answer says **the host** will restore …"*. The bus server's `connections`
tool says *"a machine's **host** `node.<machine>`"* — naming the program *host* and its bus account
*node*.
- *Host* also keeps its ordinary meanings: a network host (the ssh client module's tools), *hosting* a
service, and the *host's* network in a container runtime.
**Proposed word: _node-engine_** (Core), as the glossary already says; *the host* and *host agent* retired
for the program. Because *host* also has ordinary networking meanings, the check in
[04](04-how-the-glossary-is-checked.md) can retire only the phrases *the host* and *host agent* and the
identifier `mesh-host` outside code spans, not the bare word. If clash 1 is decided for *machine*, the
program's name reads more naturally as **machine engine**; this effort does not propose renaming it again.
### 3. *plan* — four things (homonym), and *change plan* / *release plan* / *delivery plan* (synonyms)
**Evidence.** On one seat, the controller's:
- `mesh-controller.plan` — *"What one machine would run, and why: the declaration the mesh would send it"*.
A **machine's declaration**, previewed.
- `mesh-controller.plans` — *"What the last merges produced and where each stands (ADR 0162): the
tiers"*. ADR 0162 calls it *a tiered plan*; ADR 0218 and ADR 0236 call it the **release plan** (seven
times in ADR 0236: *"Every release plan's first machine passes a gate"*).
- `mesh-controller.delivery-plan` — *"The delivery plan of a diffset"*. The glossary: *"ADR 0238 called it the
**change plan**; that word is retired"* — and the walk replaces the release plan: *"the controller's
plan is now the walk of one delivery's trunk commit across machines"*.
- `mesh-controller.bus` — *"The bus as a **planned step**"*.
*Release plan* appears in seven files created on or after 2026-10-06, the day ADR 0239 replaced it; *change
plan* in four, including the title of ADR 0238.
**Proposed words** (Change and delivery, except the first):
| Concept | Word | Retire |
|---|---|---|
| what the controller would send one machine | **declaration** (Placement); the verb `plan` becomes `declaration` or `preview` | *plan* for this |
| what a delivery would do to the mesh | **delivery plan** | *change plan*, *release plan* |
| the controller's sending of one commit's builds across machines | **walk** | *release plan*, *plan* for this |
| a step a person starts | **planned step**, or simply *step* | — |
Bare *plan* is then never a mesh concept on its own.
### 4. *push*, *send*, *roll out*, *release*, *deploy*, *upgrade* — moving a change (synonyms and homonyms)
**Evidence.**
- **push.** `mesh-controller.push`: *"Send one machine everything it should be. With no machine named it
is a push of the WHOLE mesh"*. ADR 0221's title: *"a push sends no build a policy or a plan holds
back"*. The same word is a git push (which, per the conventions, starts the build) and a phone
notification (*"Matrix once its push is measured"*, to-be 46). *Push* is in 84 decision records and
152 issues.
- **send.** ADR 0236: *"that machine is sent it, by the ordinary send"*; the gate is judged *"from the
moment it was sent the build"*. The controller's own description of `push` uses *send*.
- **roll out.** ADR 0236's title says *rolls out unattended*; its person-facing verb is `upgrade <module>
roll-out`, and the manifest's policy for the same thing is spelt `roll`. ADR 0218: *"code rolls out one
machine first"*. *Roll out* is in 30 decision records and 36 issues.
- **release.** `mesh-delivery.release` — *"A person's word that a held delivery goes on"*;
`anthropic-licence-manager.release` — *"Unbind a consumer"*; and the retired *release plan* (clash 3).
- **deploy.** The glossary: a delivery is *"not 'deployment' (one stage of it)"*; its *delivery plan* holds
a *deploy plan*. The controller has no verb named deploy, and the only tool that says *deploy* is a
wrapped flow editor's.
- **upgrade.** `mesh-controller.upgrade` — *"How each module's new builds reach its machines … rolled out
one machine first"*: a **policy**, not an act.
**Proposed words:**
| Concept | Word | Domain |
|---|---|---|
| the controller giving one machine its declaration | **send** (the verb `push` asks for one) | Placement |
| one commit travelling to every machine | **delivery** | Change and delivery |
| the per-machine part of a delivery plan | **deploy plan** (kept; the only use of *deploy*) | Change and delivery |
| a build going to its first machine, judged, then the rest | **walk** (the act); **roll** (the policy, one spelling in the manifest and in the verb) | Change and delivery |
| a person letting a held delivery go on | **release** — this sense only | Change and delivery |
| unbinding a licence's consumer | **unbind** (rename the licence verb) | Identity |
| how a module's builds reach its machines | **upgrade policy** | Module |
*Push* is kept for the controller's verb because it names what the operator does, but prose says *send*;
*roll out* becomes the policy's value `roll` and is not a noun.
### 5. *console*, *node tools*, *mesh-console*, *the MCP server* — the operator's surface (synonym and homonym)
**Evidence.**
- The glossary's surfaces section: the console is *"the module (`mesh-console`)"*; not *"the tool bridge",
"the brain" or "the MCP server"*.
- The glossary's operator's machine section: node tools *"replaces 'console' as the module's name;
console remains the word for the person's end of it"*. Both entries are current.
- The live console introduces itself as *"The tools of a Novox mesh, reached as `<machine>.node-tools`"*,
under an MCP server named `mesh`; the organisation's instructions to the agent call that server *"the
console"*.
- *Console* is in 28 decision records; `mesh-console` in 1; *node tools* in 10. A wrapped chat program's
tool and the localisation module's tool use *console* in their own senses (a virtual terminal, a web
console).
**Proposed words:** **node tools** (Core) for the runtime that serves every module's tools and every seat's
verbs on a machine; **console** (Operator and conversation) for the end of it a person or agent uses — the
MCP endpoint and its five tools. `mesh-console` retired. The glossary's surfaces entry is rewritten at
graduation; the contradiction is removed, not annotated.
## Change and delivery
### 6. *gate* — three things (homonym)
ADR 0136 (*a step gates its module, not the machine*): a failing step of a module's apply stops that
module's later steps. ADR 0236: the **gate** on a delivery's first machine — *"healthy three times"*.
ADR 0237 and ADR 0238: the **merge gate**, a status a pull request carries (`mesh/merge-gate`). The
controller's description of `upgrade` says *"judged there at the gate"*; a wrapped forge's tools say
*branch protection*. **Proposed:** *first-machine gate* for ADR 0236's, *merge gate* for the status, and
ADR 0136's becomes *a failed step holds its module* (no noun). Bare *the gate* is not used.
### 7. *ask* — the operator's question, and an entry in the build queue (homonym)
The glossary: *"**ask** — a request for the operator's input, of a declared kind"* (ADR 0234).
`mesh-controller.queue`: *"Every **ask** in the build queue: waiting, in flight … and dead"*;
`.cancel`: *"Drop one waiting or dead ask"*; `.clear`: *"Cancel every waiting ask"*. ADR 0234's ask is in
58 decision records' worth of prose shared with the ordinary verb *to ask*. **Proposed:** *ask* stays the
operator's (Operator and conversation); an entry in the build queue is a **build request** (Change and
delivery), and the three verbs' descriptions say so.
### 8. *tier* — three things (homonym)
The `topic: the tiers` of 36 decision records, and `repos.md`'s *Tier 0 … 3*: the **layers** of the mesh
(node-engine, foundation, controller, surfaces). ADR 0162 and to-be 47: the **steps of a walk**, a module
and the modules built against it (*"its builds are asked and registered tier by tier"*). To-be 46: the
**levels of authority** of an ask (*"a kind below the tier"*, *"no P2 tier before recovery codes"*).
**Proposed:** *layer* for the first (Core); *tier* for the walk's steps (Change and delivery), which is how
the tools use it; *assurance level* for the third (Identity and access).
### 9. *declaration* — what a manifest states, and what the controller sends (homonym)
The glossary: the node-engine *"receives the node's **declaration**"* — the controller's per-machine
document. The glossary again: a module *"**declares** resources"*, and *depends on a seat* is *"derived from
the resources it declares"* — the manifest. `mesh-controller.plan` returns *"the declaration the mesh would
send"*; the container and service-manager tools say *"what its declaration says"*. *Declaration* is in 106
decision records, in both senses. **Proposed:** a manifest **declares** (Module; the noun is *the
manifest*), and what the controller sends one machine is that machine's **declaration** (Placement). The
verb and the noun then never name the same thing, and *declaration* is not used for a manifest.
### 10. *control plane* and *controller* (synonym, drift)
Retired by the glossary on 2026-09-16. Since then: 29 occurrences in 12 to-be designs (`05`, `07`, `08`,
`18`, `19`, `26`, `28`, `29`, `30`, `32`, `33`, `01`) and one as-is design; 73 files created after the
retirement use it — 36 issue reports, 29 decision records, 6 designs — among them issue 156, titled *moving a consumer's delivery subject
stops the control plane*. ADR 0006, the record the word came from, still has it in its
title. **Proposed:** *controller* (Core), as decided; the to-be designs are corrected at graduation, which
is a link-and-word fix the README's rules allow.
## The record and its checks
### 11. *record* — four things (homonym)
A **decision record** (this repository). **The record** of the mesh — the `records` module that agents
search first (*"search the record with the literal text"*), and ADR 0006's *"where the record lives is
deliberately open"*. An **upgrade policy** value: `record` means *register the build, send it nowhere*
(ADR 0236). **On record**: a seat holder the controller has written down (ADR 0223's *"each on record"*).
**Proposed:** *decision record* always qualified in hq; *the record* for the mesh's knowledge base (Operator
and conversation, or a domain of its own if the records module grows one); the policy value renamed
**hold** — which is also what *held* means for a delivery — and *on record* left as ordinary English.
### 12. *check* — at least six things (homonym)
The checks in `00-META/checks/`; a pull request's **merge check**, made of the **merge gate** and the
**repository check** (`mesh/repo-check`, ADR 0238); a delivery group's **composed check**
(`mesh-controller.delivery-check`); the state `checked` of a delivery; the **self-check** (clash 13); a
module's tool named `…_check` (the ssh client's). *Check* is in 92 decision records. **Proposed:** never
bare in a governing document; always one of *merge check*, *repository check*, *composed check*,
*self-check*, *hq check*. The word is too ordinary to retire, so this one is a writing rule, not a list
entry ([04](04-how-the-glossary-is-checked.md) says why it cannot be checked mechanically).
## Health and repair
### 13. *self-check* and *doctor* (synonym)
To-be 45 names the concept **self-check** (8 occurrences) and the verb `doctor` (14); the verb's own
description begins *"The self-check (to-be 45 §4)"*. **Proposed:** *self-check* (Health and repair); the
verb renamed `self-check`, or kept as `doctor` with the glossary mapping it — a verb name is an identifier.
### 14. *condition*, *alert*, *problem*, *incident*, *finding* (synonyms)
The controller's verb `conditions`: *"What is wrong with the mesh now: every open condition"*; to-be 45 says
*condition* 72 times. ADR 0006's observability context owns *"health, logs, metrics, **alerts**"*. ADR
0224's title: *"a provider that keeps failing a consumer is a **problem** the controller reports"*. The
container module's tool is `docker_problems`. *Incident* is in 14 decision records, mostly as *the incident
that earned a rule*. *Finding* is in 19, as what a check or a probe found. **Proposed:** *condition*
(Health and repair) for an open fact about something wrong; *finding* for what one probe or check returned
before it becomes a condition; *incident* kept for a past event that taught a rule (The record); *alert* and
*problem* retired for the mesh's own notion. A wrapped dashboard's *alerts* are its own.
## Connectivity
### 15. *private network* and *overlay* (synonym)
The operator, quoted in ADR 0226 (2026-10-06): *"we simply have a private network"*; ADR 0226's title and
the `mesh-wireguard` module's role: *the private network*, in 37 decision records. To-be 08 (connectivity)
says *overlay* 24 times; *overlay* is in 30 decision records and 13 to-be designs. No tool says either.
**Proposed:** *private network* (Connectivity), the operator's word.
### 16. *packet filter* and *firewall* (synonym)
The seat every machine holds is `node-packet-filter`, with the verb `rules` (*"The packet filter as this
machine enforces it now"*). The nftables module's tool is `firewall_rules`. *Firewall* is in 33 decision
records and 13 to-be designs; *packet filter* in 22 and 12. **Proposed:** *packet filter* (Connectivity),
after the seat; the module's tool renamed `packet_filter_rules` or described in the seat's word.
## Operator and conversation
### 17. *operator*, *the user*, *person* (synonym, partly)
The glossary's *operator account* entry: *"Not 'the user' (ambiguous with a module's own account)"*. *The
user* is in 10 to-be designs, several meaning a bus account (*"the user list"*, the bus server's word), and
in 9 decision records. *Operator* is in 125 decision records and the tools of 23 modules; *person* in 91
records, meaning a human as against the mesh acting unattended (*"a person's word"*). **Proposed:**
*operator* for the person who runs the mesh; *person* for any human acting where the mesh could have; *the
user* retired in the mesh's own prose; a bus account is a *bus account* (Identity). A wrapped program's
*users* are its own.
### 18. *agent* — three things (homonym)
The glossary avoids *agent* for the node-engine because it *"already means two other things here, the build
agent and the operator's coding agent"*. The seat every machine holds is `node-build-agent`, held by the
`build-agent` module; ADR 0237 calls the role *the build seat*, ADR 0236 *the build machine* (14 decision
records). The licence manager's verbs say *"a node's **agent**"* for the coding agent a licence is bound to.
A wrapped memory server has *agents* of its own. **Proposed:** *agent* only for a coding agent (the
operator's, or one the mesh runs); the build role is the **build seat**, its holder on a machine the
**builder** — and the seat renamed when seats are next renamed. *Build machine* retired: any machine may
hold the seat.
## Core
### 19. *store* — four things (homonym)
The glossary: **store** — *"the one postgres server"*. ADR 0189's title, *"The store keeps what the
records name"*, is about the **artifact store**. Research 015 is about the **object store**. ADR 0006: *"a
node reconciles from its own store"* — the machine's local copy of its declaration. **Proposed:** *store*
alone means only the foundation's database server (Core); the others are always *artifact store*, *object
store*, and the machine's *last declaration*.
### 20. The glossary's own contradictions
Recorded in [01](01-the-concepts-in-use.md) and listed here because the fix is the same kind: the console
(clash 5); the deprecated broker, which has no seat in its own entry and claims `mesh-broker` in the entry
for *claim*; and node tools described with the retired *the host*. **Proposed:** fixed at graduation,
in the same change that reorganises the glossary ([05](05-a-glossary-by-domain.md)).
## Checked and found consistent
Worth saying, so nobody repeats the search:
- **catalogue / catalog.** Prose says *catalogue* everywhere (no bare *catalog* in any decision, design or
`00-META` file); *catalog* appears only inside identifiers (`mesh-catalog`, `catalog_modules`). That is an
identifier, not a clash.
- **foundation / substrate.** Of the 10 files created since *substrate* was retired that still use it, 9
are decision records and research (allowed to keep their words); the tenth is the glossary, naming it
as retired.
- **flavor.** Retired; two to-be designs (08, 16) still say it, both predating the retirement.
- **operator** in the tools is used consistently for the person, in 28 tools of 23 modules.
@@ -0,0 +1,140 @@
# 04 — How the glossary is checked
[`AGENTS.md`](../../AGENTS.md): *"If a document states a rule about the mesh, it says how that rule is
verified. An unenforced rule is indistinguishable from a wrong one."* The glossary states two rules — *one
name per thing*, and *"a new name for an existing thing lands here first, in the same change that
introduces it in code"* — and nothing verifies either. [03](03-the-clashes.md) is what that costs. This
document describes a check; it does not build one. Building it follows graduation.
## What a word list can and cannot catch
A list of retired words catches **synonyms**: a word the glossary replaced, used again. It cannot catch
**homonyms** — *plan*, *gate*, *tier*, *ask*, *store*, *record*, *check* — because the word is right in one
sense and wrong in another, and telling them apart is reading, not matching. So the proposal has two
parts: a mechanical check for synonyms, and a rule for homonyms that turns each one, once decided, into a
synonym the list can hold (*release plan* → *walk*; *build machine* → *build seat*; `ask` in the build
queue's verbs → *build request*). A homonym left undecided stays a reviewer's job, and the glossary says
so next to the word.
## Part 1 — the list, kept in the glossary
The list of retired words lives **in the glossary, in one fixed form**, so there is one source and no
second file to drift from it. Every entry that retires words ends with one line:
> *Not:* ~~control plane~~, ~~substrate~~
and nothing else in the glossary is struck through. Today the glossary marks retired words three ways
(struck through, *"Replaces x"*, *"Not x"*); graduation moves all of them to this line.
Each struck word may carry a **scope**, in brackets after it, saying where it is retired:
- *(hq)* — in this repository's governing documents only;
- *(tools)* — in the descriptions of the mesh's tools and seat verbs only;
- no scope — both.
The scope exists because some words are wrong in one place and right in the other: *the user* is retired
in hq prose, but a wrapped identity provider's tool must say *user*.
An entry may also carry an **identifier** line naming code that still has the old name, and the issue that
tracks its rename:
> *Identifier until renamed:* `mesh-host` — the repository, binary and service unit (issue NNN)
An identifier is allowed inside a code span (`` `mesh-host` ``) and nowhere else; when the issue resolves,
the line goes and so does the allowance.
## Part 2 — `00-META/checks/words.py`, over this repository
**Reads** the glossary's *Not:* lines and *Identifier* lines. **Scans** the documents that tell somebody
what to do — the same set `records.py` calls *governing*: `00-META/` (the glossary's own *Not:* lines
excluded), `03-DESIGN/01-to-be/`, `AGENTS.md` and `README.md` — plus `03-DESIGN/00-as-is/`, whose words
should be today's even where its facts are yesterday's.
**Fails** on a retired word (of scope *hq* or none) in running prose. It **ignores**:
- code spans and code blocks, which hold identifiers;
- block quotes and text in quotation marks, which quote somebody — the operator, a tool, an older
record — and must quote them faithfully;
- link targets, which are file names, and file names are immutable when they are a decision record's;
- `02-DECISIONS/` entirely, and `01-RESEARCH/` and `04-ISSUES/` written before the check's start date
— records keep their words, and research and issues observe.
**For research and issues written after the start date** the check applies the same rule. An issue report
quoting a log or a tool keeps the quotation; its own prose uses today's words. This is a choice for
graduation, listed in [00](00-overview.md); the reason to include them is that issue reports are the
largest single source of drift found (36 of the 73 files that say *control plane* since its retirement).
**The reverse rule.** A to-be design that defines a word in the glossary's form — a bolded word followed by
a dash at the start of a definition — must find that word as a head word in the glossary. This is how
*"a new name lands here first"* gets checked, and it would have caught *condition*, *healer* and
*data class* arriving in to-be 43 and 45 with no entry.
**The uniqueness rule.** No head word appears in two entries, and no head word is also struck through in
another entry. This would have caught *release*: today a verb of `mesh-delivery`, and the retired *release
plan*.
**What it would fail on today** — the check is proposed because these are real, and per
[`00-META/checks/README.md`](../../00-META/checks/README.md) a check must fail on something real before
it passes:
| Retired word | Where, today |
|---|---|
| control plane | 29 occurrences in 12 to-be designs; one as-is design |
| the host (for the node-engine) | 34 to-be designs, and the glossary's own node tools entry |
| release plan, change plan | to-be 45, 47 |
| flavor | to-be 08, 16 |
| the user | 10 to-be designs (several are a bus account) |
Each is either fixed at graduation or, where it is a quotation, put in quotation marks — which is the
check doing its job, making a quotation look like one.
## Part 3 — the same list, over the catalogue's tool descriptions
An agent meets the mesh's words most often in tool descriptions: 535 module tools and the verbs of 20 seats
today. Nothing compares them with the glossary, and four of them say *the host*.
**Where it runs.** In the catalogue repository's own repository check (`mesh/repo-check`, ADR 0238), which
already reads every changed manifest. A changed manifest's tool descriptions and its seat's verb
descriptions are matched against the *Not:* words of scope *tools* or none. A finding fails the check, as
everything does on the mesh's repositories (a warning blocks a merge the same as a failure there, [issue
293](../../04-ISSUES/293-a-warning-on-a-required-check-blocked-the-merge/00-report.md), so a warning-only mode
is not available and is not proposed).
**Where the list comes from.** The catalogue cannot read this repository at build time without a new
dependency. Two options, for graduation:
1. **A copy, checked.** The catalogue keeps a copy of the list, and `words.py` here fails when the copy in
the catalogue's trunk differs from the glossary. Simple; two repositories change for one word, which is
honest about what a retired word costs.
2. **The list as an artifact.** This repository's merge publishes the list to the artifact store, and the
catalogue's check reads the newest. One source; one more thing that must be up for a catalogue merge.
The first is recommended: it fails loudly in the right place, and adds no runtime dependency.
**Vendor words.** A module wrapping a program describes that program's objects in its own words — an
identity provider's *users*, a media manager's *releases*, a flow editor's *deploy*. The list holds only
the mesh's own retired words, and a word that is also a common vendor word (*user*, *release*, *deploy*)
is never retired with scope *tools*. That keeps the check from crying wolf, which
`00-META/checks/README.md` names as the way a check gets suppressed.
**On the running mesh, later.** The descriptions an agent actually sees are the ones served, which may lag
the catalogue's trunk. A probe in the self-check could compare the controller's `tools` verb with the same
list and raise a condition. That is a second place for the same rule and is not proposed until the first
has run.
## Part 4 — homonyms, by rule
For a word the glossary marks *homonym* (*plan*, *gate*, *tier*, *store*, *record*, *check*, *ask*,
*agent*), the entry lists each sense with its qualified form and its domain, and the writing rule is: **a
homonym is never bare in a governing document; it is always the qualified form.** This is not
machine-checked — a word list cannot tell *the gate* that means a first-machine gate from one that means
the merge gate — and the glossary says so next to the rule, as AGENTS.md requires: *"checked by review;
the reviewer looks for the bare word in the diff."* Where a homonym is resolved by renaming one sense, the
old sense moves to the *Not:* line and becomes mechanical.
## What it costs
- One Python file of the size of `cycle.py`, run by `merge-check.sh`.
- A one-time correction of the governing documents it fails on, made in the graduation change.
- A copy of the list in the catalogue, and a few lines in its repository check.
- One rule for writers: a retired word may be quoted, never used.
@@ -0,0 +1,101 @@
# 05 — A glossary by domain
How [`00-META/glossary.md`](../../00-META/glossary.md) would be organised once the domains in
[02](02-the-domains.md) are decided. Described only: the glossary changes in the graduation change, with
the decision record that adopts the domains, and not before.
## What is wrong with its shape today
- **Its sections are a history, not a map.** *The operator's machine* holds node tools, bundle, kept region
and installed / holding because they arrived with research 018, not because they belong together; node
tools is a Core concept and kept region a Module one.
- **It has no home for a new word.** A writer adding *condition* would not know which section it goes in,
and so it went in none.
- **Retired words are marked three ways**, so no program can read them ([04](04-how-the-glossary-is-checked.md)).
- **It is one page for 33 entries**; with the roughly 50 words [01](01-the-concepts-in-use.md) found
missing, it is about 85, and one flat list of 85 is read by nobody.
## The proposed shape
One file, as now — it stays the single authority, and a reader searches one page. Its sections are the
domains, in the order of [02](02-the-domains.md) (most upstream first), preceded by two short sections.
### 1. How to read this page
What a domain is, in two sentences; that a word is defined once, in the domain that owns it; that other
domains may use it but not change it; and the forms of the *Not:* and *Identifier* lines the check reads.
### 2. Words every domain uses
A short **shared kernel** — the handful of words with one meaning everywhere, owned by no single domain
and changed only by a decision record: *mesh*, *machine* (or *node*, clash 1), *module*, *seat*, *operator*,
*person*. Each points to the domain where its detail lives. Kept deliberately short: a word that only one
domain refines belongs to that domain.
### 3. One section per domain
Each section opens with a fixed header, then its entries:
- **Purpose** — one sentence, from [02](02-the-domains.md).
- **Owned by** — the context, module or seat that records its concepts (*the controller's `inventory`
context*; *the `mesh-delivery` module*; *every machine's `node-backup` seat*).
- **Upstream of / downstream of** — the domains, by name.
- **Decided by** — the decision records that define the domain's words, so a reader can go from a word
to why.
Each **entry** keeps today's prose form and gains at most three fixed lines:
- the definition, in plain sentences, with its record cited (as now);
- *Not:* ~~retired word~~, ~~another~~ *(scope)* — the words it replaced;
- *Identifier until renamed:* `old-name` — what code still carries the old name, and the issue that
tracks the rename.
A word a domain uses but does not own is not repeated there; the domain's section may list it under *Uses*
with a link, so a reader of one section sees its whole vocabulary without the definition being copied.
### 4. Homonyms
One section at the end for the words that mean different things in different domains — *plan*, *gate*,
*tier*, *store*, *record*, *check*, *ask*, *agent*, *release*. For each, a small table: the sense, its
qualified form, the domain that owns it. This is the page a reader lands on from a search for a bare
word, and it says the rule beside the table: never bare in a governing document; checked by review.
### 5. How this page is kept
Today's section, extended: a new word lands here first, in the domain that owns it; a word moves domain
only with a decision record; a retired word goes on a *Not:* line and nowhere else; and `words.py`
checks the three rules it can ([04](04-how-the-glossary-is-checked.md)).
## Where today's entries would go
| Today's entry | Domain |
|---|---|
| node, control-node, operator account | shared kernel (machine); Placement (operator account); Core (control-node) |
| controller, mesh-controller, node-engine, foundation, store, bus, the deprecated broker | Core |
| package, artifact | Change and delivery |
| seat, depends on a seat, installed / holding | Placement |
| claim, provision (as declared), invokes, bundle, kept region | Module |
| provision (as resolved) | Provisioning |
| channel / intake, ask, operator message / input, reference, console | Operator and conversation |
| node tools | Core |
| delivery, delivery group, delivery plan, mesh-delivery, walk | Change and delivery |
| ~~master / slave~~, ~~hub / peer~~, ~~flavor~~ | *Not:* lines on *controller* and *setting* |
And the sections that are empty today and would be filled from the records that already define their
words: **Identity and access** (credential, secret, vault, grant, bus account, licence, binding, proof —
ADRs 0143, 0183, 0225, 0234); **Health and repair** (condition, probe, signal, watchdog, self-check, healer,
drill, hand-act — to-be 45, ADRs 0227, 0231, 0240); **Data** (data class, backup, restore point, stream
snapshot — to-be 43, ADRs 0233, 0235); **Connectivity** (private network, resolver, uplink, packet
filter, reach — ADRs 0117, 0138, 0223, 0226).
## What derives from it
- **The decision index.** The records' `topic:` (*the mesh*, *the tiers*, *what runs on it*, *building
it*, *checking it*, *how we work*) predates the domains and partly overlaps them. Whether a record also
names its domain — a new frontmatter field, and so a schema change — is left for graduation. It would let
`words.py` scope a word by domain, and `index.py` print the reading order per domain.
- **The constitution page.** The mesh injects a page derived from `how-we-build.md` into design sessions
(playbook 05). A derived glossary page per domain could be injected the same way, so an agent starts
with the words; that is a separate decision, not proposed here.
- **Tool descriptions.** Once a domain owns a word, a module describing that concept in a tool uses it; the
check in [04](04-how-the-glossary-is-checked.md) holds them to the retired half, and review to the rest.