skeleton: hal-agent -> hal-host, and the two gaps the questions found
Agent is a first-class concept here — a participant, some of whom are human, holding identity and memory. Using it for the tier-0 node binary put both meanings in one document: hal-agent at tier 0, agents at tier 2. That is the anatomy-naming failure again, an evocative domain word pointing at infrastructure, and how-we-build 4 exists to catch it. ADR 0015's own title supplies the fix: the mesh brokers, nodes host, agents think. So the control plane brokers (hal-mesh), the tier-0 binary hosts (hal-host), the participant thinks (agents, untouched). hal-node was rejected — Node is the inventory aggregate, the binary is what runs on it. Recorded in the document as a near-miss rather than quietly corrected. Tiers now explained before the tree, as a boot narrative, with the point they were carrying made explicit: dependencies point only downward, that is the whole bootstrap answer, and the current mesh violates it — the database is a module, modules come from the pipeline, the pipeline needs the database. Connectivity gains the part that was missing. Naming a context says who decides, not who runs it: overlay membership is tier 0 in the host, policy is tier 2, machinery is tier 4 modules. And the host's link to the control plane deliberately does not run over the overlay, or the overlay would have to exist before a node could be told how to join it. 'tier' is this document's coinage and did not land on first reading; that is now an open question rather than settled vocabulary.
This commit is contained in:
@@ -77,3 +77,4 @@ the catalogue where modules genuinely change together under one intent. The skel
|
||||
| One repository per tier, or per context? | Already open from ADR 0015 as "catalogue destination — one repository or many". The skeleton assumes per tier and does not settle it. |
|
||||
| Does an unprivileged node earn a place in the inventory, or only a presence? | Decides whether "node" means one thing or two. |
|
||||
| Does `feature` survive? | The skeleton splits it in two and argues the conflation is what makes the delivery pipeline hard to reason about. Unproven. |
|
||||
| Is `tier` the right word? | It is this document's coinage, not established vocabulary, and it did not land on first reading. `boot order` and `ring` are the alternatives. The concept is settled; the word is not. |
|
||||
|
||||
@@ -8,10 +8,45 @@ updated: 2026-08-23
|
||||
Repositories at the root, modules inside them, parts at the leaf. Four tiers, and a dependency
|
||||
rule that only points downward.
|
||||
|
||||
## What a tier is
|
||||
|
||||
A tier answers one question: **what has to exist before this can exist?** It is not importance,
|
||||
and it is not a layer in the networking sense. It is bootstrap order, made explicit.
|
||||
|
||||
Walk a bare machine to a running mesh and the tiers fall out of the story:
|
||||
|
||||
```
|
||||
bare machine
|
||||
│ one command lands ONE binary. Nothing else exists. TIER 0 host
|
||||
│
|
||||
│ it reads a pinned file it already carries and raises a
|
||||
│ database, a bus, an object store, a registry, an
|
||||
│ identity provider — locally, alone. TIER 1 substrate
|
||||
│
|
||||
│ on those, the mesh's brain starts: which nodes exist,
|
||||
│ what runs where, what is reachable. TIER 2 control plane
|
||||
│
|
||||
│ ways to talk to that brain. TIER 3 surfaces
|
||||
│
|
||||
└ everything the mesh then carries. TIER 4 workloads
|
||||
```
|
||||
|
||||
**Dependencies point only downward.** The substrate never references the control plane. That
|
||||
one constraint is the entire bootstrap answer, because it guarantees there is always a place to
|
||||
start.
|
||||
|
||||
Why it earns its keep here: **the current mesh violates this, and that is the circularity that
|
||||
keeps recurring.** The mesh database is a module; modules are installed by the delivery
|
||||
pipeline; the pipeline needs the database. No order works, so a first-node script exists to
|
||||
paper over it, and every later substrate change has to pretend the problem is not there.
|
||||
|
||||
A tier is not a repository and not a bounded context. Those are different cuts: a context says
|
||||
*who owns this concept*, a tier says *what must already be running*.
|
||||
|
||||
## The tree
|
||||
|
||||
```
|
||||
hal-agent/ TIER 0 — the only thing ever installed by hand
|
||||
hal-host/ TIER 0 — the only thing ever installed by hand
|
||||
apply/ reconcile declared state on this machine
|
||||
inventory/ what this node is, has, and is capable of
|
||||
link/ the single outbound connection to the control plane
|
||||
@@ -56,7 +91,7 @@ hal-hq/ this repository
|
||||
## The dependency rule
|
||||
|
||||
**A tier may depend only on tiers below it.** Substrate never references the control plane.
|
||||
The control plane never reaches into a node except through the agent. A surface holds no logic
|
||||
The control plane never reaches into a node except through the host. A surface holds no logic
|
||||
a second surface would have to reimplement.
|
||||
|
||||
This is the whole of the bootstrap answer, and per this repository's own rule it must say how
|
||||
@@ -72,9 +107,9 @@ needs the database and the bus. The first node is therefore raised by a special
|
||||
exists only because of the circularity, and every later change to the substrate has to pretend
|
||||
the circularity is not there.
|
||||
|
||||
**The move.** The agent can apply a declaration without anyone telling it to. The substrate is
|
||||
a **pinned bundle** the agent carries: a fixed, versioned, self-contained descriptor of the
|
||||
five services and nothing else. Raising a first node is `agent apply substrate.lock` — not a
|
||||
**The move.** The host can apply a declaration without anyone telling it to. The substrate is
|
||||
a **pinned bundle** the host carries: a fixed, versioned, self-contained descriptor of the
|
||||
five services and nothing else. Raising a first node is `host apply substrate.lock` — not a
|
||||
special path, just the ordinary one with no control plane on the other end.
|
||||
|
||||
The circularity disappears rather than being worked around: **the substrate is applied by tier
|
||||
@@ -85,13 +120,13 @@ re-applying, not by the pipeline. It gets less machinery than everything else
|
||||
selection, no provisioning, no fan-out — and that is the point. Five services justify a
|
||||
simpler mechanism than a hundred.
|
||||
|
||||
## Move 2 — the agent is one binary with capability profiles
|
||||
## Move 2 — the host is one binary with capability profiles
|
||||
|
||||
**The problem.** Everything assumes root on a machine whose packages, services and network the
|
||||
mesh owns. A phone cannot offer that, and neither can a work laptop. The current answer would
|
||||
be a lightweight fork, which means two implementations and one of them rotting.
|
||||
|
||||
**The move.** One agent, one binary, and a **profile** it detects rather than is told:
|
||||
**The move.** One host binary, and a **profile** it detects rather than is told:
|
||||
|
||||
| Profile | Can | Typical |
|
||||
|---|---|---|
|
||||
@@ -131,6 +166,29 @@ belongs in a new record that extends ADR 0015 the way
|
||||
[ADR 0017](../../02-DECISIONS/0017-modules-outside-the-core-are-grouped-by-domain.md) does —
|
||||
not written here.
|
||||
|
||||
### Where the networking actually lives
|
||||
|
||||
A context is an authority, not a running thing, so naming one does not say who brings the
|
||||
overlay up. That splits three ways, and the split is the design:
|
||||
|
||||
| Concern | Tier | Why there |
|
||||
|---|---|---|
|
||||
| **Overlay membership** — this node joins, holds an address, keeps the tunnel up | **0, in the host** | Everything cross-node needs it *before* the substrate is reachable from elsewhere. A module cannot provide it, because installing a module is itself a cross-node operation. |
|
||||
| **Policy** — who holds which address, what resolves, what is exposed, what is filtered | **2, `connectivity`** | Bookkeeping and authority. It decides; it runs nothing. |
|
||||
| **Machinery** — resolver, reverse proxy, firewall backend, certificate issuance | **4, modules** | Swappable, and not every node needs them. A node without a reverse proxy is still a node. |
|
||||
|
||||
There is a second circularity hiding here, and it has to be closed explicitly: **the host's link
|
||||
to the control plane does not run over the overlay.** If it did, the overlay would have to be up
|
||||
before the host could be told how to join it. The link is ordinary outbound internet to a public
|
||||
endpoint; the overlay carries node-to-node traffic only.
|
||||
|
||||
Joining is therefore: host lands → links out with a join token → control plane returns an
|
||||
address and keys → host raises membership → the substrate on other nodes becomes reachable.
|
||||
|
||||
This also makes the `edge` profile honest rather than special-cased. A phone can hold overlay
|
||||
membership in userspace without privilege, and cannot run the machinery. That is the profile
|
||||
distinction doing its job.
|
||||
|
||||
## Move 4 — `feature` splits in two
|
||||
|
||||
The invitation was to check whether the concept survives. It does not, in one piece.
|
||||
@@ -200,3 +258,23 @@ being the one thing nobody exercises until it breaks.
|
||||
is one concept or two.
|
||||
- The migration. Nothing here says how today's mesh becomes this, and the skeleton is worth
|
||||
little until that is costed.
|
||||
|
||||
## A naming near-miss, recorded
|
||||
|
||||
The tier-0 binary was first called `hal-agent`, because "node agent" is the reflex everywhere
|
||||
else in the industry. That is wrong here, and wrong in the specific way
|
||||
[`how-we-build.md`](../../00-META/how-we-build.md) §4 exists to catch: **Agent** is a
|
||||
first-class concept in this mesh — a participant, some of whom are human, holding identity and
|
||||
memory ([ADR 0012](../../02-DECISIONS/0012-agents-are-persistent-employees.md)). One document
|
||||
carried both meanings.
|
||||
|
||||
It is the same failure as the anatomy naming in the current runtime: an evocative domain word
|
||||
pointing at infrastructure.
|
||||
|
||||
[ADR 0015](../../02-DECISIONS/0015-mesh-brokers-nodes-host-agents-think.md) supplies the fix in
|
||||
its own title — *the mesh brokers capabilities; nodes host; agents think.* Three verbs, three
|
||||
components: the control plane **brokers** (`hal-mesh`), the tier-0 binary **hosts**
|
||||
(`hal-host`), the participant **thinks** (`agents`, untouched).
|
||||
|
||||
`hal-node` was the alternative and was rejected: *Node* is the aggregate in the inventory — the
|
||||
record of a machine — while the binary is what runs on it and does the hosting.
|
||||
|
||||
Reference in New Issue
Block a user