Settles the design repository now that the self-upgrade build is on main: - Records the two decisions that shipped without a record — ADR 0077 (the controller/foundation/node vocabulary) and ADR 0078 (the store and broker are ordinary modules); accepts ADR 0075 and 0076, which shipped work rests on. - Fills issue 051's amended-design and wires ADR 0078 into 07-the-foundation. - Sweeps the repo rename (mesh-control -> mesh-controller) into the mutable docs now that the forge repo is renamed; updates the glossary note and repos.md. - Fixes the six broken links from the design-doc renames, indexes the glossary, regenerates the decisions reading order. Both checks (records.py, index.py) are green. Statuses stay honest: the build is on main and lab-proven but not deployed as the production mesh, so the to-be docs remain in-progress and the as-is layer (the hal mesh) is unchanged — graduation to implemented + as-is belongs to deployment, not merge. https://claude.ai/code/session_01D6qtiYU3P9jk3pnAXyAFyx
143 lines
8.0 KiB
Markdown
143 lines
8.0 KiB
Markdown
---
|
|
layer: to-be
|
|
status: in-progress
|
|
code:
|
|
- mesh-controller cmd/mesh-controller/board.go
|
|
- mesh-controller cmd/mesh-controller/readable.go
|
|
updated: 2026-08-31
|
|
decisions:
|
|
- 02-DECISIONS/0008-a-context-owns-its-store.md
|
|
- 02-DECISIONS/0001-mesh-brokers-nodes-host-agents-think.md
|
|
---
|
|
|
|
# A board
|
|
|
|
**A place to see the mesh.** Read from a survey of the one that exists, so what is proposed here
|
|
is a shorter list than what is there, deliberately.
|
|
|
|
## What the existing board does, and what of it belongs here
|
|
|
|
Eight sections. Four are about work and workers and are held back with the rest of that domain;
|
|
the other four are about the mesh itself.
|
|
|
|
| | what it shows | where it stands here |
|
|
|---|---|---|
|
|
| **the mesh** | every node, what each runs, what each takes from another, module versions | **everything behind it exists** — it is a reader, not a second source |
|
|
| **what is wrong** | machines not doing what they were told, machines not answering | **the page nobody had thought to ask for**, and the one a person opens first |
|
|
| **builds** | a build, its stages, its log | **everything behind it exists** — every result is kept, failures included |
|
|
| **sessions** | model sessions, their usage, and switching between accounts | [ADR 0024](../../02-DECISIONS/0024-model-access-is-a-provision.md) |
|
|
| **channels** | nodes messaging each other | the agent layer |
|
|
|
|
## The constraint that matters, and it is not a feature
|
|
|
|
**The existing board is one service that reads every context's database.** It joins nodes to
|
|
provisions to modules to sessions by querying each store directly, because that is the shortest
|
|
path to a page that shows all of them at once.
|
|
|
|
That is [ADR 0008](../../02-DECISIONS/0008-a-context-owns-its-store.md) violated by the one
|
|
component with a reason to violate it, and the cost is not hypothetical — it is the same cost the
|
|
shared library has: **a boundary nothing may cross is a boundary that can move; one thing crossing
|
|
it is enough to freeze it.** A board that reads the provisioning tables directly is a board that
|
|
breaks when provisioning changes its tables, and the change then gets weighed against the board.
|
|
|
|
**So a board reads through interfaces and holds nothing.** Everything on the mesh page above is
|
|
already answerable by asking the controller — what nodes exist, what each resolves to, what it
|
|
takes from elsewhere, which module came from which commit. A board that asks those questions is a
|
|
client. A board that queries `inventory` is a second controller with a worse contract.
|
|
|
|
**It stores nothing of its own.** No cache that can disagree, no table of "what the mesh looked
|
|
like last time". If a question is slow to answer, the answer belongs in the context that owns it,
|
|
where everything else asking gets it too.
|
|
|
|
## Where it is reachable from, which decides everything else about it
|
|
|
|
*Written 2026-08-31. It was assumed throughout and stated nowhere, which is the wrong way round
|
|
for the most consequential fact about this component.*
|
|
|
|
**The board is published on a public name.** Not reachable only over the private network — on the
|
|
internet, behind the reverse proxy, like any other published workload.
|
|
|
|
**So its login is a perimeter, not defence in depth.** A board on the overlay alone would sit
|
|
inside the boundary that [ADR 0004](../../02-DECISIONS/0004-a-node-and-how-it-joins.md) already
|
|
calls the security boundary, and a login there would guard a room whose door is inside the
|
|
building. This one faces everybody.
|
|
|
|
**Which makes the identity provider the mesh's outermost gate.** The board is a presentation layer
|
|
over the controller and the controller's networked surfaces can change the mesh
|
|
([ADR 0035](../../02-DECISIONS/0035-one-implementation-several-surfaces.md)), so **whoever that
|
|
provider admits can assign modules, from anywhere.** Said flatly because it is easy to arrive at
|
|
one reasonable step at a time and then be surprised by.
|
|
|
|
Three things follow, and none of them are the board's own design:
|
|
|
|
- **Who may log in, and how, is a decision about the mesh** rather than about an application. A
|
|
realm that lets somebody in has let them into the mesh.
|
|
- **A public name needs a public certificate**, from an authority the world trusts rather than the
|
|
mesh's own — which is why that exists at all.
|
|
- **The provider failing is not only "the board is down".** Its configuration going wrong in the
|
|
other direction — a realm that admits too much — is a mesh-wide exposure with no local symptom.
|
|
|
|
**The command line is unaffected and is the reason this is tolerable.** It authenticates through
|
|
nothing, needs no network, and answers to the machine's own login — so the mesh remains operable
|
|
by somebody standing at it whatever happens to the gate. *That is the property to protect if the
|
|
rest of this is ever traded away.*
|
|
|
|
## What it is not
|
|
|
|
- **Not the way to change things.** Reading is the whole of it to begin with. Every action the
|
|
board could offer already exists as a command, and a button that does something no command does
|
|
is a second implementation of a decision.
|
|
- **Not a dashboard of graphs.** What a person needs from a mesh is *which machine is not doing
|
|
what it was told*, and that is a list, not a chart.
|
|
|
|
## The three questions, in order
|
|
|
|
Written down because the order is the design. A person opens this when something is wrong, and a
|
|
page that led with the third would bury the first:
|
|
|
|
1. **Is anything broken?** A machine whose last declaration was refused or partly failed. It has
|
|
consequences now.
|
|
2. **Is anything not answering?** A machine not heard from. It may be new, switched off or
|
|
unreachable — **which is not the same as tried and could not**, and collapsing the two sends
|
|
somebody to debug a machine that was never sent anything.
|
|
3. **Is anything out of date?** A module behind its source, and the machines running the old one.
|
|
A plan for later rather than a problem now.
|
|
|
|
**Refused and failed stay distinct all the way to the page.** Refused means the machine is exactly
|
|
as it was and what is wrong is in what was sent; failed means it is in a state nobody declared and
|
|
what is wrong is on the machine. They are fixed in different places, so a page that said "error"
|
|
for both would send half its readers to the wrong one.
|
|
|
|
## What was built
|
|
|
|
*2026-08-31.*
|
|
|
|
**One reading, three ways of saying it.** The questions are asked once, by one function, and
|
|
answered as a person's `status`, as its JSON, and as this page. Three implementations of *which
|
|
machine is not doing what it was told* would be three chances to disagree about it — and the
|
|
disagreement would surface as two people looking at two screens arguing about which machine is
|
|
broken.
|
|
|
|
**It holds nothing and changes nothing.** Every request reads the mesh now. There is no cache to
|
|
go stale, no table of what the mesh looked like last time, and no button: every action a board
|
|
could offer already exists as a command, and one that did something no command does would be a
|
|
second implementation of a decision.
|
|
|
|
**It never touches a context's store.** That is the whole constraint above, kept: the board is a
|
|
client of the same functions the commands use, so provisioning can change its tables without the
|
|
change being weighed against a page.
|
|
|
|
**A board that cannot read the mesh says so.** An empty page says *nothing is wrong* in the one
|
|
situation where nobody can know that, so the failure is rendered instead — and it says explicitly
|
|
that it is a statement about the page rather than about the mesh.
|
|
|
|
**A machine's own words are shown, and are not markup.** They are the whole reason the page is
|
|
useful — a board that said only *failed* would send a person to ask the thing they opened the
|
|
board to avoid asking. They are also the only text on the page that nobody in this repository
|
|
wrote, which is why the escaping is a test rather than an assumption.
|
|
|
|
*Checked by giving a machine a declaration it cannot apply and requiring the page to name that
|
|
machine, say `failed` rather than `error`, and quote what the host said — then by comparing the
|
|
page's own JSON against the command's, because two answers to "which machine is broken" would be
|
|
worse than either alone.*
|