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
|
### 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.
|
- TypeScript throughout; no new untyped JavaScript.
|
||||||
- Strict, with no implicit `any` and no unchecked index access.
|
- Strict, with no implicit `any` and no unchecked index access.
|
||||||
- Public functions state their return type. Prefer `unknown` with a guard over `any`. Errors
|
- 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
|
## What the mesh becomes
|
||||||
|
|
||||||
[ADR 0030](../02-DECISIONS/0030-the-repository-structure.md) records the repositories the
|
[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
|
([ADR 0029](../02-DECISIONS/0029-the-labs-first-scenario-has-no-pipeline.md)); the rest are the
|
||||||
target, not the present.
|
target, not the present.
|
||||||
|
|
||||||
| Repository | Tier | Holds |
|
| 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-substrate` | 1 | the four pinned services, as declarations |
|
||||||
| `mesh-control` | 2 | the control plane and its contexts |
|
| `mesh-control` | 2 | the control plane and its contexts |
|
||||||
| `mesh-surfaces` | 3 | tools, web, cli |
|
| `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
|
layer: to-be
|
||||||
status: designed
|
status: in-progress
|
||||||
code: []
|
code: [mesh-host]
|
||||||
updated: 2026-08-26
|
updated: 2026-08-26
|
||||||
decisions:
|
decisions:
|
||||||
- 02-DECISIONS/0030-the-repository-structure.md
|
- 02-DECISIONS/0030-the-repository-structure.md
|
||||||
@@ -10,6 +10,7 @@ decisions:
|
|||||||
- 02-DECISIONS/0038-a-node-joins-by-linking-first.md
|
- 02-DECISIONS/0038-a-node-joins-by-linking-first.md
|
||||||
- 02-DECISIONS/0039-the-link-is-the-security-boundary.md
|
- 02-DECISIONS/0039-the-link-is-the-security-boundary.md
|
||||||
- 02-DECISIONS/0008-a-failed-step-fails-the-job.md
|
- 02-DECISIONS/0008-a-failed-step-fails-the-job.md
|
||||||
|
- 02-DECISIONS/0041-the-host-depends-on-nothing.md
|
||||||
---
|
---
|
||||||
|
|
||||||
# The node host
|
# 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
|
## 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**
|
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
|
([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
|
membership, packet filtering, packages, services, containers and filesystems are not six
|
||||||
|
|||||||
Reference in New Issue
Block a user