Tier 0: the questions answered, the decisions taken, and the design #9
@@ -268,6 +268,10 @@ Data access, business logic and the interface layer are separate.
|
||||
|
||||
### Types
|
||||
|
||||
*Scope: the mesh's services and surfaces. Tier 0 is a statically linked binary that must depend
|
||||
on nothing installed first, and is written in Go —
|
||||
[ADR 0041](../02-DECISIONS/0041-the-host-depends-on-nothing.md).*
|
||||
|
||||
- TypeScript throughout; no new untyped JavaScript.
|
||||
- Strict, with no implicit `any` and no unchecked index access.
|
||||
- Public functions state their return type. Prefer `unknown` with a guard over `any`. Errors
|
||||
|
||||
+2
-2
@@ -21,13 +21,13 @@ and a forge address is an operational detail (see [`README`](../README.md)).
|
||||
## What the mesh becomes
|
||||
|
||||
[ADR 0030](../02-DECISIONS/0030-the-repository-structure.md) records the repositories the
|
||||
monorepo decomposes into. **Only `mesh-lab` exists so far** — it is built first
|
||||
monorepo decomposes into. **`mesh-lab` and `mesh-host` exist so far** — the lab is built first
|
||||
([ADR 0029](../02-DECISIONS/0029-the-labs-first-scenario-has-no-pipeline.md)); the rest are the
|
||||
target, not the present.
|
||||
|
||||
| Repository | Tier | Holds |
|
||||
|---|---|---|
|
||||
| `mesh-host` | 0 | the node host — the one binary installed by hand |
|
||||
| `mesh-host` | 0 | **exists.** The node host — one statically linked binary, requiring nothing present ([ADR 0041](../02-DECISIONS/0041-the-host-depends-on-nothing.md)) |
|
||||
| `mesh-substrate` | 1 | the four pinned services, as declarations |
|
||||
| `mesh-control` | 2 | the control plane and its contexts |
|
||||
| `mesh-surfaces` | 3 | tools, web, cli |
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
---
|
||||
status: accepted
|
||||
date: 2026-08-26
|
||||
deciders: jochen
|
||||
reconstructed: false
|
||||
extends: 0037-the-host-applies-it-does-not-decide.md
|
||||
---
|
||||
|
||||
# 41. The host depends on nothing that must be installed first
|
||||
|
||||
## Context
|
||||
|
||||
[ADR 0030](0030-the-repository-structure.md) calls tier 0 *"the one binary installed by hand"*,
|
||||
and [research 006](../01-RESEARCH/006-mesh-from-scratch/00-overview.md) states the property the
|
||||
whole tier rests on: *"a binary whose whole argument is that it has no dependencies"*.
|
||||
|
||||
Building it forced the question that phrase had been carrying unexamined. Everything else in
|
||||
the mesh is TypeScript, and `how-we-build` §8 says so. A TypeScript host needs a runtime present
|
||||
before it can run — so the thing installed by hand becomes **two** things, and the second must
|
||||
be installed by the means the host exists to replace.
|
||||
|
||||
## Considered options
|
||||
|
||||
1. **TypeScript, with a runtime installed first.** Simplest, and matches every other
|
||||
repository. Rejected: it breaks the property the tier is built on. A host that cannot run
|
||||
until something else has been installed by hand is not the bottom of the stack.
|
||||
2. **TypeScript, bundled as a single executable.** Preserves the language and produces one
|
||||
file. Rejected on two grounds: it carries roughly ninety megabytes of runtime to preserve a
|
||||
language choice, and single-executable bundling is a young feature — tier 0 is the worst
|
||||
place in the system to discover its edges.
|
||||
3. **A statically linked binary in a language built for it.** Chosen; Go.
|
||||
|
||||
## Decision
|
||||
|
||||
**The host is a single statically linked binary that requires nothing to be present.** Copy it
|
||||
onto a machine and run it. That is the whole installation.
|
||||
|
||||
**It is written in Go.** The job is system-level — run commands, write files, speak to the
|
||||
firewall, the overlay, the service manager and the package manager — which is what Go's
|
||||
ecosystem is for, and it cross-compiles to every architecture the mesh might reach, including
|
||||
the lighter devices requirement 6 anticipates.
|
||||
|
||||
**The second language costs less here than anywhere else it could appear**, and the reason is
|
||||
architectural rather than convenient. [ADR 0037](0037-the-host-applies-it-does-not-decide.md)
|
||||
means the host never queries the mesh database.
|
||||
[ADR 0039](0039-the-link-is-the-security-boundary.md) means it only ever receives declarations.
|
||||
So the host shares **no code** with any other tier — not a client, not a schema, not the SDK.
|
||||
It is joined to the mesh by a message contract and nothing else.
|
||||
|
||||
The language boundary therefore falls exactly on an architectural boundary that already exists.
|
||||
A second language usually costs duplicated logic; here there is none to duplicate.
|
||||
|
||||
## Consequences
|
||||
|
||||
- **`how-we-build` §8 needs a scope.** It reads *"TypeScript throughout"*, which was true when
|
||||
everything was a service or a surface. It is now scoped to those, with tier 0 named as the
|
||||
exception and this record as the reason. That is a constitution change, and the sync it owes
|
||||
is part of it.
|
||||
- **Agents must write Go to work on the host.** A real cost, and the one genuine argument
|
||||
against this. It is bounded by the host being the only thing in tier 0 — nothing else in the
|
||||
mesh acquires a second language because of this.
|
||||
- **The dependency-direction lint the design calls for gets easier, not harder.** A Go module
|
||||
cannot accidentally import a TypeScript control-plane client; the boundary is enforced by
|
||||
there being no path across it.
|
||||
- **Cross-compilation replaces per-node builds.** The host is built once per architecture and
|
||||
copied, rather than built on the machine it runs on — which is what makes *"copy it and run
|
||||
it"* true rather than nearly true.
|
||||
- **Two toolchains in the lab.** Scenarios that place a host need a Go build available, and the
|
||||
lab is TypeScript. The binary is built before the scenario runs, not inside it.
|
||||
- **This is reversible at a cost that will only grow.** It is being taken at the moment the
|
||||
first line is written, which is the cheapest point it will ever be taken.
|
||||
|
||||
## References
|
||||
|
||||
- [ADR 0030](0030-the-repository-structure.md) — *the one binary installed by hand*.
|
||||
- [ADR 0037](0037-the-host-applies-it-does-not-decide.md) — why the host shares no code.
|
||||
- [ADR 0039](0039-the-link-is-the-security-boundary.md) — why it receives declarations only.
|
||||
- [`05-the-node-host.md`](../03-DESIGN/01-to-be/05-the-node-host.md) — the design this serves.
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
layer: to-be
|
||||
status: designed
|
||||
code: []
|
||||
status: in-progress
|
||||
code: [mesh-host]
|
||||
updated: 2026-08-26
|
||||
decisions:
|
||||
- 02-DECISIONS/0030-the-repository-structure.md
|
||||
@@ -10,6 +10,7 @@ decisions:
|
||||
- 02-DECISIONS/0038-a-node-joins-by-linking-first.md
|
||||
- 02-DECISIONS/0039-the-link-is-the-security-boundary.md
|
||||
- 02-DECISIONS/0008-a-failed-step-fails-the-job.md
|
||||
- 02-DECISIONS/0041-the-host-depends-on-nothing.md
|
||||
---
|
||||
|
||||
# The node host
|
||||
@@ -18,6 +19,11 @@ Tier 0. The one thing ever installed by hand, and the only thing that changes a
|
||||
|
||||
## What it is
|
||||
|
||||
A **statically linked binary that requires nothing to be present** — copy it onto a machine and
|
||||
run it, and that is the whole installation
|
||||
([ADR 0041](../../02-DECISIONS/0041-the-host-depends-on-nothing.md)). Written in Go, because the
|
||||
job is system-level and because the host shares no code with any other tier.
|
||||
|
||||
A single binary with one job: **apply declared state on this machine**
|
||||
([ADR 0037](../../02-DECISIONS/0037-the-host-applies-it-does-not-decide.md)). Overlay
|
||||
membership, packet filtering, packages, services, containers and filesystems are not six
|
||||
|
||||
Reference in New Issue
Block a user