Review of the to-be layer: check what the documents claim against what runs

First pass of a design review, done by reading documents against code
and against a raised mesh rather than against each other. Every error
below was invisible to a proofread.

**Statuses were stale, and nothing checked them.** Ten to-be documents
said `designed` while naming working, lab-proven code — several with a
*What was built* or *Raised, and observed* section. Added a
`status-vs-code` check: naming a file is a claim that the file
implements this, so a document that points at one has stopped being
merely designed. It failed on all ten before it passed, per the rule
this folder sets for its own checks.

**The bundle carries three images, not two.** 07 reasoned about which
substrate services go in and overlooked that the control plane is in
there too — it is what the substrate exists to start, and there is
nothing to fetch it with yet. Counted, not deduced.

**The bootstrap uses four shapes, not six.** It listed `file` and
`directory`, which substrate-first-node.lock never asks for. The claim
that mattered — nothing is blocked on the host — was true either way,
which is why the wrong count survived.

**The eight capabilities were documented nowhere.** Implemented in
internal/profile/detectors.go and enumerated in no document, including
the one about the host that detects them. A vocabulary modules write
against, readable only by reading the code. Now written down, with the
seat/graphical-session distinction that is wrong in both directions if
collapsed.

**MinIO swept out of the to-be layer** per 0028.

The gate now fails on one thing left deliberately: ADR 0024 is
`proposed` while two documents rest on it and the feature it decides is
built and lab-proven. Accepting a decision is not mine to do.
This commit is contained in:
2026-08-31 17:20:47 +02:00
parent cbcbba8099
commit 1b5308c9cc
13 changed files with 100 additions and 28 deletions
+1
View File
@@ -26,6 +26,7 @@ indistinguishable from one that cannot.
| `numbering` | the number in the filename is the number in the heading | — | | `numbering` | the number in the filename is the number in the heading | — |
| `topics` | every record names a topic the index knows | — | | `topics` | every record names a topic the index knows | — |
| *(index.py)* | the written reading order matches what the records say | — | | *(index.py)* | the written reading order matches what the records say | — |
| `status-vs-code` | a to-be document naming specific code is not still `designed` | **ten documents**, several with a *What was built* section, describing lab-proven code |
## What is deliberately not checked ## What is deliberately not checked
+32
View File
@@ -284,6 +284,37 @@ def check_numbering(failures, records):
) )
def check_status_against_code(failures):
"""A design document naming specific code may not still call itself `designed`.
**Naming a file is a claim that the file implements this**, so the two fields have to agree.
They drifted: ten to-be documents named working, lab-proven code — several with a *What was
built* or *Raised, and observed* section — while still saying nothing had been built.
Deliberately weak, and that is the point of it being mechanical. It cannot tell whether the
prose is true, only that a document has stopped claiming to be unbuilt once it points at
something. `code: [mesh-control]` — a repository with no path — is a plan and stays
`designed`.
"""
for path in markdown_files():
if not rel(path).startswith("03-DESIGN/01-to-be/") or path.endswith("README.md"):
continue
front = frontmatter(read(path))
if front.get("status") != "designed":
continue
for entry in front.get("code") or []:
named = re.sub(r"\s*\(.*\)$", "", entry).strip().split(None, 1)
if len(named) > 1:
failures.add(
"status-vs-code",
rel(path),
f"`designed`, but names {named[1]!r} in {named[0]}. Naming a file claims "
f"it implements this — use `in-progress`, or `implemented` once it is "
f"defensible from that repository's main branch.",
)
break
def main(): def main():
failures = Failures() failures = Failures()
records = load_records() records = load_records()
@@ -293,6 +324,7 @@ def main():
check_supersession_symmetry(failures, records) check_supersession_symmetry(failures, records)
check_numbering(failures, records) check_numbering(failures, records)
check_topics(failures, records) check_topics(failures, records)
check_status_against_code(failures)
print(f"records: {len(records)} decision records checked") print(f"records: {len(records)} decision records checked")
return failures.report() return failures.report()
+2 -2
View File
@@ -1,8 +1,8 @@
--- ---
layer: to-be layer: to-be
status: designed status: in-progress
code: [mesh-lab] code: [mesh-lab]
updated: 2026-08-28 updated: 2026-08-31
decisions: decisions:
- 02-DECISIONS/0016-the-lab.md - 02-DECISIONS/0016-the-lab.md
- 02-DECISIONS/0010-delivery.md - 02-DECISIONS/0010-delivery.md
+32 -1
View File
@@ -180,7 +180,10 @@ what it is. No control plane, no declarations, no network. Verifiable immediatel
the first node's path, and it is the claim the skeleton's Move 1 rests on and has never proved: the first node's path, and it is the claim the skeleton's Move 1 rests on and has never proved:
that one host can raise the substrate alone. that one host can raise the substrate alone.
Raising the substrate needs six shapes in the host's vocabulary, and **all six are built**: Raising the substrate uses **four** shapes — `package`, `container`, `service`, `action` —
counted from the bundle that exists rather than reasoned about. `file` and `directory` are listed
below because they are the cheapest to be sure of and a substrate that needed them would find them
ready; the current bundle simply does not. **All of them are built:**
| | | | | | | |
|---|---|---| |---|---|---|
@@ -272,6 +275,34 @@ nowhere else to get it — the detector is the only thing that looked.
most.** *This machine has no container runtime* is the answer; *docker is not installed* is why. most.** *This machine has no container runtime* is the answer; *docker is not installed* is why.
The first is the mesh's to say and the second is only the machine's. The first is the mesh's to say and the second is only the machine's.
### The eight, and what each one is evidence of
*Written 2026-08-31 from `internal/profile/detectors.go`, because the set was implemented and
enumerated in no document. A vocabulary a module writes against, that exists only in code, is one
nobody can write against without reading the code.*
| capability | what a detection proves |
|---|---|
| `container-runtime` | a runtime is **running**, not installed |
| `package-manager` | the machine's own package manager works |
| `service-manager` | an init that can be asked for state — including *degraded*, which reports on stdout and exits non-zero |
| `firewall` | a filter this host can write rules into |
| `overlay` | the private network can be joined |
| `graphical-session` | a display server **is running** — state |
| `seat` | hardware where one **could** run — and assignment needs this one, not the row above |
| `privileged` | the host can change the machine |
**`seat` and `graphical-session` are the pair worth reading twice**, because collapsing them is
the obvious economy and it is wrong in both directions: a machine with a seat and no session can
be given a display server, and a machine with a session running is not thereby able to host a
second one.
**A detection runs something that only succeeds if the thing is *functioning*, never `--version`.**
A version string proves a binary is on disk, which
[`04-ISSUES/007`](../../04-ISSUES/007-an-installed-package-is-not-a-capability/00-report.md)
records as false in the way that matters: the package was installed and the daemon was not
running.
**Never reported and reported nothing stay different.** One machine has not run the host yet; the **Never reported and reported nothing stay different.** One machine has not run the host yet; the
other ran it and can do nothing. Both refuse everything that requires a capability, and the other ran it and can do nothing. Both refuse everything that requires a capability, and the
remedies are not remotely alike. remedies are not remotely alike.
+3 -3
View File
@@ -1,9 +1,9 @@
--- ---
layer: to-be layer: to-be
status: designed status: in-progress
code: code:
- mesh-control - mesh-control
updated: 2026-08-29 updated: 2026-08-31
decisions: decisions:
- 02-DECISIONS/0001-mesh-brokers-nodes-host-agents-think.md - 02-DECISIONS/0001-mesh-brokers-nodes-host-agents-think.md
- 02-DECISIONS/0005-the-node-host.md - 02-DECISIONS/0005-the-node-host.md
@@ -177,7 +177,7 @@ volume genuinely argues against a relational store.
node except through the host. node except through the host.
- **Not a surface.** Tier 3 is how people and agents reach it. It has one interface; the - **Not a surface.** Tier 3 is how people and agents reach it. It has one interface; the
surfaces are what speak to that interface. surfaces are what speak to that interface.
- **Not the substrate.** It *runs on* tier 1 — PostgreSQL, LavinMQ, MinIO, an OCI registry - **Not the substrate.** It *runs on* tier 1 — PostgreSQL, LavinMQ, an OCI registry
([ADR 0006](../../02-DECISIONS/0006-the-substrate-and-the-control-plane.md)) — and cannot start without ([ADR 0006](../../02-DECISIONS/0006-the-substrate-and-the-control-plane.md)) — and cannot start without
them, which is what makes them a lower tier. them, which is what makes them a lower tier.
- **Not privileged on a node.** It has no more access to a machine than the declaration - **Not privileged on a node.** It has no more access to a machine than the declaration
+23 -15
View File
@@ -1,6 +1,6 @@
--- ---
layer: to-be layer: to-be
status: designed status: in-progress
code: code:
- mesh-host examples/substrate-first-node.lock - mesh-host examples/substrate-first-node.lock
- mesh-host internal/apply - mesh-host internal/apply
@@ -117,15 +117,20 @@ Being substrate and being in the bundle are two different questions:
|---|---|---| |---|---|---|
| PostgreSQL | yes — the control plane's own state lives in it | **yes** — there is nowhere to put that state otherwise | | PostgreSQL | yes — the control plane's own state lives in it | **yes** — there is nowhere to put that state otherwise |
| LavinMQ | yes — it cannot grant itself a virtual host | **yes** — the control plane reaches a node only over the link, and the link is the broker ([ADR 0006](../../02-DECISIONS/0006-the-substrate-and-the-control-plane.md)) | | LavinMQ | yes — it cannot grant itself a virtual host | **yes** — the control plane reaches a node only over the link, and the link is the broker ([ADR 0006](../../02-DECISIONS/0006-the-substrate-and-the-control-plane.md)) |
| MinIO | yes — it cannot grant itself a bucket | no — nothing is delivered before the mesh exists |
| the OCI registry | yes — it cannot grant itself a repository | no — the first node fetches upstream ([ADR 0006](../../02-DECISIONS/0006-the-substrate-and-the-control-plane.md)) | | the OCI registry | yes — it cannot grant itself a repository | no — the first node fetches upstream ([ADR 0006](../../02-DECISIONS/0006-the-substrate-and-the-control-plane.md)) |
The two on the bottom rows are **substrate by role and ordinary by delivery**: by the time they The registry is **substrate by role and ordinary by delivery**: by the time it is wanted there is
are wanted there is a control plane, and it provisions them the way it provisions anything. a control plane, and it provisions it the way it provisions anything. That keeps the bundle small
That keeps the bundle to two images rather than four, which is what makes it small enough for the enough for the review [ADR 0005](../../02-DECISIONS/0005-the-node-host.md) requires — one
review [ADR 0005](../../02-DECISIONS/0005-the-node-host.md) requires. It was one until substrate image until
[ADR 0006](../../02-DECISIONS/0006-the-substrate-and-the-control-plane.md) established that the broker has [ADR 0006](../../02-DECISIONS/0006-the-substrate-and-the-control-plane.md) established that the
to precede the control plane. broker has to precede the control plane, and two since.
*Corrected 2026-08-31, from counting what the bundle holds rather than reasoning about it.* **It
carries three images, not two** — PostgreSQL, LavinMQ, and the control plane itself, which the
sentence above had overlooked by counting only substrate services. The control plane is what the
substrate exists to start, and it is in the bundle for the same reason they are: there is nothing
to fetch it with yet. It also carries seven actions, a package and a service.
**Why pinned:** the bundle is applied when no mesh exists, so nothing can resolve a version, ask **Why pinned:** the bundle is applied when no mesh exists, so nothing can resolve a version, ask
a registry, or check a constraint. What the host carries must already be exact. a registry, or check a constraint. What the host carries must already be exact.
@@ -150,8 +155,8 @@ The order, from [research 011](../../01-RESEARCH/011-the-module-graph/worked-pro
5 a virtual host, a credential, and actions, run locally 5 a virtual host, a credential, and actions, run locally
a self-signed certificate a self-signed certificate
6 the control plane starts and only now is there a mesh 6 the control plane starts and only now is there a mesh
7 MinIO, the registry, and everything the ordinary path 7 the registry, and everything else the ordinary path
else are provisioned are provisioned
``` ```
**Steps 4 and 5 are why the bundle is not one image** **Steps 4 and 5 are why the bundle is not one image**
@@ -185,10 +190,13 @@ what it is called differs per system. It is:
- a package, which needs the machine's own package manager and a network — both permitted by - a package, which needs the machine's own package manager and a network — both permitted by
[ADR 0006](../../02-DECISIONS/0006-the-substrate-and-the-control-plane.md). [ADR 0006](../../02-DECISIONS/0006-the-substrate-and-the-control-plane.md).
So the host's bootstrap vocabulary is six shapes: **package**, **container**, **file**, So the bootstrap uses four shapes: **package**, **container**, **service** and **action** —
**directory**, **service**, and **action**. **All six are built** *counted from `substrate-first-node.lock`, which is the only bundle there is*. It had said six,
([`05-the-node-host.md`](05-the-node-host.md) stage 2), so nothing in this bootstrap is adding `file` and `directory`, which this bootstrap never asks for.
blocked on the host any longer.
All four are built, as are the host's other four
([`05-the-node-host.md`](05-the-node-host.md) stage 2), so nothing in this bootstrap is blocked
on the host any longer — which is the claim that mattered, and it was true either way.
**Steps 2 and 3 happen before there is a mesh to do them**, which is why provisioning is part of **Steps 2 and 3 happen before there is a mesh to do them**, which is why provisioning is part of
the bootstrap rather than a service consumers use later. They are **actions** the bundle the bootstrap rather than a service consumers use later. They are **actions** the bundle
@@ -220,7 +228,7 @@ host's vocabulary grows by one shape rather than by one resource type per substr
question was whether the host must learn what a database is, and it must not. The bundle question was whether the host must learn what a database is, and it must not. The bundle
declares an **action**; the host runs it and verifies it, and what a database means stays with declares an **action**; the host runs it and verifies it, and what a database means stays with
the module that provides one. the module that provides one.
- **Whether one host can raise all four.** The claim under stage 2 of - **Whether one host can raise all three.** The claim under stage 2 of
[the node host](05-the-node-host.md), never proved. If it is false, the tier boundary moves. [the node host](05-the-node-host.md), never proved. If it is false, the tier boundary moves.
- **How the substrate is updated once a mesh exists.** Pinned by hand at bootstrap; afterwards - **How the substrate is updated once a mesh exists.** Pinned by hand at bootstrap; afterwards
the control plane could deliver it like anything else, and nothing says whether it does. the control plane could deliver it like anything else, and nothing says whether it does.
+1 -1
View File
@@ -1,6 +1,6 @@
--- ---
layer: to-be layer: to-be
status: designed status: in-progress
code: code:
- mesh-control internal/catalogue/filtering.go - mesh-control internal/catalogue/filtering.go
- mesh-control examples/route-proxy - mesh-control examples/route-proxy
+1 -1
View File
@@ -1,6 +1,6 @@
--- ---
layer: to-be layer: to-be
status: designed status: in-progress
code: code:
- mesh-host internal/link/run.go - mesh-host internal/link/run.go
- mesh-host internal/link/enrol.go - mesh-host internal/link/enrol.go
+1 -1
View File
@@ -1,6 +1,6 @@
--- ---
layer: to-be layer: to-be
status: designed status: in-progress
code: code:
- mesh-control internal/builder - mesh-control internal/builder
- mesh-control cmd/mesh-control (build, build --behind, push, status) - mesh-control cmd/mesh-control (build, build --behind, push, status)
+1 -1
View File
@@ -1,6 +1,6 @@
--- ---
layer: to-be layer: to-be
status: designed status: in-progress
code: code:
- mesh-control cmd/mesh-control/board.go - mesh-control cmd/mesh-control/board.go
- mesh-control cmd/mesh-control/readable.go - mesh-control cmd/mesh-control/readable.go
+1 -1
View File
@@ -1,6 +1,6 @@
--- ---
layer: to-be layer: to-be
status: designed status: in-progress
code: code:
- mesh-control internal/builder - mesh-control internal/builder
- mesh-control internal/catalogue/build.go - mesh-control internal/catalogue/build.go
@@ -1,6 +1,6 @@
--- ---
layer: to-be layer: to-be
status: designed status: in-progress
code: code:
- mesh-control internal/inventory/secrets.go - mesh-control internal/inventory/secrets.go
- mesh-control cmd/mesh-control/rotate.go - mesh-control cmd/mesh-control/rotate.go
+1 -1
View File
@@ -1,6 +1,6 @@
--- ---
layer: to-be layer: to-be
status: designed status: in-progress
code: code:
- mesh-control internal/licences - mesh-control internal/licences
- mesh-control cmd/mesh-control/licence.go - mesh-control cmd/mesh-control/licence.go