Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
51ef3eb7e2 | ||
|
|
346e613995 | ||
|
|
25ca9898d5 | ||
|
|
709c095387 | ||
|
|
c262de3833 | ||
|
|
a815433214 | ||
|
|
61dc90e508 |
@@ -0,0 +1,154 @@
|
||||
---
|
||||
topic: what runs on it
|
||||
status: accepted
|
||||
date: 2026-09-29
|
||||
deciders: jochen
|
||||
reconstructed: false
|
||||
extends: 02-DECISIONS/0005-the-node-host.md
|
||||
---
|
||||
|
||||
# 141. The host delivers its own successor, and versions live side by side
|
||||
|
||||
## Context
|
||||
|
||||
[Issue 142](../04-ISSUES/142-the-host-is-the-one-thing-the-mesh-does-not-deliver/00-report.md). A
|
||||
merge builds every changed module and the control plane — which is itself a module — and the result
|
||||
reaches the machines running it with nobody asking. The host is the exception: it is not a build
|
||||
target, no declaration delivers it, and every machine in this mesh runs a byte-identical binary that
|
||||
somebody built on a workstation and copied out.
|
||||
|
||||
The half that *recovers* from a bad host exists. `internal/upgrade` can tell that the executable this
|
||||
process started from was replaced on disk, and it records which version last completed a reconcile.
|
||||
The launcher counts consecutive failed starts, calls a rollback at the limit, and treats a clean exit
|
||||
as the host standing aside so that the next loop runs whatever is on disk now. That supervision is
|
||||
complete and correct.
|
||||
|
||||
Two things make it dead code:
|
||||
|
||||
- **`Replaced()` is called by nothing but its own tests.** Nothing tells the running host that a
|
||||
successor is waiting.
|
||||
- **The rollback resolves a version through the machine's package manager** — `pacman -U` from the
|
||||
package cache. No machine here has the host installed as a package, so the recovery cannot run on
|
||||
any of them; and being written in one package manager's terms, it cannot run on two of the three
|
||||
operating systems the host is built for — [ADR 0005](0005-the-node-host.md) builds one binary per
|
||||
operating system, pinned at link time.
|
||||
|
||||
**The record already points at the answer.** What is kept is a *version*, not a path. Keeping a
|
||||
version is only useful to something that can choose between versions present on the machine, which is
|
||||
what the package manager was being asked to do. The versions can simply be on disk.
|
||||
|
||||
## Considered Options
|
||||
|
||||
1. **Deliver the host as a package, as the rollback assumes.** Rejected: it needs a package built and
|
||||
a repository trusted per operating system, three of each, and the existing `package` resource
|
||||
asserts presence and deliberately never a version — "version is the package manager's business and
|
||||
the mesh does not hold a second opinion about it" — so it cannot ask for a particular host anyway.
|
||||
Heaviest of the three and the only one that is different on every machine.
|
||||
2. **Write the new binary over the running one.** Rejected on a fact: a running executable cannot be
|
||||
truncated, and `archive` opens what it unpacks with `O_TRUNC`. It could be made to write and
|
||||
rename, which is better hygiene and worth doing for its own sake, but it buys nothing here that
|
||||
option 3 does not, and it leaves rollback with nowhere to go back to.
|
||||
3. **Versions side by side; the newest retires the old.** Adopted.
|
||||
|
||||
## Decision
|
||||
|
||||
**A host version is delivered as an archive into a directory named for it, and never over a running
|
||||
one.** The declaration names it like any other archive — fetched by digest, the digest checked before
|
||||
anything is unpacked. Nothing new travels, no new resource kind, and no change to how archives are
|
||||
applied, because the path being written is not the path being executed.
|
||||
|
||||
**The launcher starts the most recently delivered version.** That is what "the newest" means: the
|
||||
version whose directory arrived last. It reads no pointer and follows no link — the mesh creates no
|
||||
links ([ADR 0012](0012-the-mesh-creates-no-symlinks.md)) — and the version is in the path, so nothing
|
||||
has to be told what is running.
|
||||
|
||||
**The running host stands aside for a successor, and only between reconciles.** Finding a newer
|
||||
version delivered, it finishes the reconcile it is in and exits cleanly. The launcher already reads a
|
||||
clean exit as exactly this and starts what is on disk now. A host that stood aside mid-apply is the
|
||||
half-configured machine this project exists to prevent, so the check happens at the boundary and
|
||||
nowhere else.
|
||||
|
||||
**A version that completes a reconcile records itself, and retires what came before it.** The
|
||||
known-good record is written as it is today. Then versions older than the one before the running one
|
||||
are removed: the running version and its predecessor are kept, which is exactly what a rollback
|
||||
needs, and nothing else accumulates.
|
||||
|
||||
**Rollback starts the previous version instead of reinstalling a package.** At the failure limit the
|
||||
launcher pins the known-good version and starts that, once. The second failure is still a different
|
||||
diagnosis — the previously working version does not run either, so it is the machine and not the
|
||||
binary — and the halt is unchanged. No package manager, no package cache, and the same script on every
|
||||
operating system.
|
||||
|
||||
**A machine says which host version it is running,** on the report it already sends, beside the other
|
||||
facts it states about itself. Without it nothing can say a machine is behind, so "every machine
|
||||
current with its source" cannot include the host.
|
||||
|
||||
## Progressive insight — 2026-09-29, the same day
|
||||
|
||||
**The delivery is not "nothing new", and this record said it was.** The decision above stands and is
|
||||
built: versions side by side, the newest runs, the running host stands aside between reconciles, a
|
||||
completed reconcile retires what is older than the predecessor, rollback picks a directory. What was
|
||||
wrong was a claim about how a version reaches a machine. The paragraph on delivery said the
|
||||
declaration "names it like any other archive… nothing new travels, no new resource kind"; the second
|
||||
half is true and the first is not, because two things the delivery needs do not exist:
|
||||
|
||||
- **Nothing can compile it.** A `bundle` artifact is compiled by a closed list of toolchains —
|
||||
typescript and python — whose own comment says adding a language is a decision, because a language
|
||||
used by *modules* needs an SDK carrying the broker client, the event envelope and tool serving. The
|
||||
host uses none of that: it is what applies modules, not one of them. So the obligation that list
|
||||
warns about attaches to a module written in a language, not to the language being buildable, and
|
||||
the control plane — also written in Go — is built as an image from a Dockerfile rather than through
|
||||
a toolchain at all.
|
||||
- **A version cannot reach the path.** An `archive` resource names a fixed path in the manifest, and
|
||||
nothing interpolates the built version into it, so nothing can ask for
|
||||
`…/versions/<version>/`.
|
||||
|
||||
Neither changes what was decided, which options were weighed, or any consequence: the shape is
|
||||
unaffected and the host half is merged and tested. What it changes is the cost, which this record
|
||||
understated as none. The remaining work is a way to build the host and a way to name a version in a
|
||||
path, and until both exist nothing delivers a version and every machine takes the fallback — which is
|
||||
what every machine does today.
|
||||
|
||||
## Consequences
|
||||
|
||||
- **The host becomes a build target and a module** — a module whose resource is the next host, applied
|
||||
by the host that is running. The bootstrap is not circular because the two are different versions in
|
||||
different directories.
|
||||
- **Rollback becomes usable on every machine**, having been usable on none. It also stops being
|
||||
written in one operating system's terms.
|
||||
- **One copy by hand remains, once.** The first host that understands versioned directories cannot be
|
||||
fetched by a host that does not. That copy is the last, and it is the honest cost of the change
|
||||
rather than a step in the design.
|
||||
- **Two versions occupy disk instead of one.** About nine megabytes. The predecessor is the price of a
|
||||
rollback that does not depend on a cache somebody else may clean.
|
||||
- **What got harder:** a host must now be able to find its own successor and to judge when it is safe
|
||||
to stand aside. Both are between reconciles, which is the only moment the host is not mid-change.
|
||||
- **A machine that is never told a newer version keeps running what it has**, indefinitely and
|
||||
visibly, because its report says which version that is.
|
||||
|
||||
## How it is checked
|
||||
|
||||
- **A delivered version is run, and the old one is not.** A bed delivers a second version to a machine
|
||||
running the first; the host exits between reconciles, the launcher starts the new one, and the
|
||||
machine reports the new version. This fails against the previous behaviour, where nothing notices a
|
||||
delivered version at all.
|
||||
- **It stands aside between reconciles and never inside one.** Asserted by delivering a version while
|
||||
an apply is in flight: the apply completes, and the exit follows it.
|
||||
- **A version that will not start is rolled back to its predecessor, once**, and the second failure
|
||||
halts with the machine named rather than the binary — asserted with no package manager involved.
|
||||
- **A completed reconcile retires what is older than the predecessor**, and never the predecessor
|
||||
itself, because that is what a rollback needs. Asserted on the directory afterwards.
|
||||
- **The report names the running version**, asserted end to end rather than on the function that reads
|
||||
it, since the point is that the control plane can tell a machine is behind.
|
||||
- **The launcher picks the newest delivered version** with no pointer file and no link, asserted by
|
||||
delivering two and checking which runs.
|
||||
|
||||
## References
|
||||
|
||||
- [ADR 0005](0005-the-node-host.md) — the host, and what its supervision is for
|
||||
- [ADR 0010](0010-delivery.md) — a declaration is owned resources; this adds no kind to it
|
||||
- [ADR 0012](0012-the-mesh-creates-no-symlinks.md) — why the version is in the path
|
||||
- [ADR 0005](0005-the-node-host.md), *it is built per operating system* — why a rollback written in
|
||||
one package manager's terms was wrong for two of three
|
||||
- [issue 142](../04-ISSUES/142-the-host-is-the-one-thing-the-mesh-does-not-deliver/00-report.md) — the
|
||||
measurement
|
||||
@@ -0,0 +1,158 @@
|
||||
---
|
||||
topic: the mesh
|
||||
status: accepted
|
||||
date: 2026-09-29
|
||||
deciders: jochen
|
||||
reconstructed: false
|
||||
extends: 02-DECISIONS/0141-the-host-delivers-its-own-successor.md
|
||||
---
|
||||
|
||||
# 142. The mesh delivers its own components as binaries, not as container images
|
||||
|
||||
## Context
|
||||
|
||||
Measured on the control-node, 2026-09-29:
|
||||
|
||||
| what | how it runs | publishes |
|
||||
|---|---|---|
|
||||
| host | a binary on the machine | — |
|
||||
| controller, catalogue, builder, vault | containers | nothing |
|
||||
| store, registry, broker | containers | ports |
|
||||
|
||||
**The mesh's own software is delivered two ways, and the difference is not a property of the
|
||||
software.** The host and the controller are both written in the same language, both the mesh's own,
|
||||
both doing the mesh's own work. One is an image fetched from a registry. The other is a file somebody
|
||||
copied to four machines, owned by no package, built by nothing
|
||||
([issue 142](../04-ISSUES/142-the-host-is-the-one-thing-the-mesh-does-not-deliver/00-report.md)).
|
||||
|
||||
**The reason is not a judgement about either, it is that images are the only delivery that works.**
|
||||
There is no way to put a binary on a machine. The host is hand-copied because of that, and the
|
||||
controller is an image because of that. Neither was chosen on its merits.
|
||||
|
||||
What it costs, all of it measured rather than argued:
|
||||
|
||||
- **Genesis must raise a container runtime before the control plane can exist.** The bundle carries
|
||||
three images and one of them is the controller, *"in the bundle for the same reason they are: there
|
||||
is nothing to fetch it with yet"*
|
||||
([design 07](../03-DESIGN/01-to-be/07-the-foundation.md)). So the hardest moment in the mesh's life
|
||||
has a prerequisite that the thing being started does not need.
|
||||
- **Updating the control plane depends on the control plane.** Its image is fetched from the registry,
|
||||
which is a container the controller manages.
|
||||
- **A change to the host cannot be rolled out at all.** Every machine here runs a byte-identical
|
||||
hand-copied binary. A change merged yesterday reached none of them.
|
||||
- **Compiling the language the mesh is written in is not a capability of the builder.** The bundle
|
||||
toolchains are typescript — real, with a registered base module — and python, which is named in the
|
||||
list and absent from the catalogue. The controller is built as an image from a Dockerfile, which is
|
||||
the per-repository incantation the bundle toolchain exists to abolish
|
||||
([design 18](../03-DESIGN/01-to-be/18-building-a-module.md)).
|
||||
|
||||
The half that *receives* a binary safely is already built and tested
|
||||
([ADR 0141](0141-the-host-delivers-its-own-successor.md)): versions side by side in directories named
|
||||
for them, the newest run, the running one standing aside between reconciles, retirement keeping the
|
||||
predecessor, and a rollback that chooses a directory. What is missing is everything that puts one
|
||||
there.
|
||||
|
||||
## Considered Options
|
||||
|
||||
1. **Leave it as it is.** Rejected: it is not a design, it is the reach of one mechanism. And it is
|
||||
what makes a host change undeliverable.
|
||||
2. **Containerise the host too**, so everything is delivered one way. Rejected: the host is what
|
||||
starts the container runtime and what applies containers. A host in a container is the bootstrap
|
||||
problem made total, and the machine would have no way back from a bad one.
|
||||
3. **Deliver the mesh's components as operating-system packages.** Rejected for the reason
|
||||
[ADR 0141](0141-the-host-delivers-its-own-successor.md) rejected it for the host: a package and a
|
||||
trusted repository per operating system, three of each, and the `package` resource asserts presence
|
||||
and deliberately never a version.
|
||||
4. **Binaries for the mesh's own components, containers for third-party software.** Adopted.
|
||||
|
||||
## Decision
|
||||
|
||||
**The mesh's own components are delivered as binaries on the machine.** The host, the controller, the
|
||||
catalogue, the builder, the vault — the software this project writes. They are delivered by the
|
||||
mechanism [ADR 0141](0141-the-host-delivers-its-own-successor.md) built: an archive, fetched by
|
||||
digest, unpacked into a directory named for its version, with the running one standing aside between
|
||||
reconciles and a rollback that chooses the predecessor.
|
||||
|
||||
**Third-party software stays a container.** The store, the registry, the broker. They are somebody
|
||||
else's build, they are already adopted as modules
|
||||
([ADR 0078](0078-the-store-and-broker-are-modules.md)), and an image is the right way to carry
|
||||
somebody else's software. **The container runtime remains required** — modules use it — so this
|
||||
removes a dependency from the control plane, not from the machine.
|
||||
|
||||
**The builder compiles the languages the mesh is written in.** A toolchain for Go, with a base module
|
||||
providing the compiler, exactly as typescript has. The obligation the toolchain list warns about — an
|
||||
SDK carrying the broker client, the envelope and tool serving — attaches to a *module* written in a
|
||||
language, not to the language being compilable. None of these components is a module in that sense;
|
||||
the host is what applies modules.
|
||||
|
||||
**An artifact says what it targets.** A compiled binary is per operating system, pinned at link time
|
||||
([ADR 0005](0005-the-node-host.md)), and a toolchain deliberately takes nothing from the module,
|
||||
because anything a module could override there it would be writing a Dockerfile to override. So the
|
||||
target is a property of the artifact rather than of the recipe, and one artifact declared per target
|
||||
is one build each.
|
||||
|
||||
**A component's version comes from where it sits, not from its linker.** It is unpacked into a
|
||||
directory named for its version, so it can read its own version from its path. The stamp goes, and
|
||||
with it the need for a build to know what it will be called.
|
||||
|
||||
**Genesis carries a binary reference where it carried an image reference.** The principle does not
|
||||
change — the bundle names a thing by digest and the host fetches it, pinned because nothing can
|
||||
resolve a version when no mesh exists — and the container runtime stops being a prerequisite for the
|
||||
control plane. It stays a prerequisite for the store and the broker, which is where it belongs.
|
||||
|
||||
**The order is staged, and each step stands alone.** Compiling Go; an artifact naming its target;
|
||||
delivering a binary; the host as the first component delivered; the controller, catalogue, builder and
|
||||
vault out of their containers; genesis last. Genesis is last for the reason it is always last: it
|
||||
matters for a machine nobody has yet, and every earlier step is provable on a mesh that exists.
|
||||
|
||||
## Consequences
|
||||
|
||||
- **One delivery for the mesh's own software**, so a change to the host ships the way a change to the
|
||||
controller does, and neither is copied by hand.
|
||||
- **The control plane stops depending on a container runtime and on its own registry.** Both remain on
|
||||
the machine for other reasons; neither gates the control plane's own life any more.
|
||||
- **`Replaced()`, the known-good record and the launcher's rollback stop being dead code.** They were
|
||||
written for this and have been called by nothing but their tests.
|
||||
- **Four more components gain a rollback they do not have.** Today a bad controller image is recovered
|
||||
by an operator; under this it is recovered the way a bad host is.
|
||||
- **Two versions of each component occupy disk.** Around nine megabytes each. The predecessor is what a
|
||||
rollback needs.
|
||||
- **Genesis gets smaller, not larger.** One fewer image to carry and one fewer runtime to raise before
|
||||
the control plane.
|
||||
- **This does not make the components smaller or simpler.** They are the same programs; what changes is
|
||||
how they arrive. A reader expecting the containers to have been hiding complexity will not find any.
|
||||
- **What got harder:** the builder gains a language, artifacts gain a target, and the mesh gains a
|
||||
second kind of thing it must deliver correctly — one where getting it wrong takes the control plane
|
||||
down rather than a module. That is why the host is first: it is the component whose recovery is
|
||||
already built and tested.
|
||||
|
||||
## How it is checked
|
||||
|
||||
- **A component is delivered and runs, with nothing copied by hand.** A bed builds the host from its
|
||||
repository, delivers it to a machine running an older one, and the machine reports the new version.
|
||||
This fails today at the first step, because nothing builds it.
|
||||
- **Each target is built once and only the matching one is delivered.** Asserted by declaring an
|
||||
artifact per operating system and checking that a machine is offered the one it can run — a host
|
||||
built for another is what ADR 0005's link-time pin exists to refuse.
|
||||
- **A component reads its version from its path**, asserted by unpacking the same bytes into two
|
||||
differently named directories and seeing each report its own.
|
||||
- **A bad component is rolled back without an operator**, for the host first: a version that will not
|
||||
start is replaced by its predecessor once, and the second failure halts naming the machine.
|
||||
- **The control plane comes up with no registry reachable**, which is the dependency this removes —
|
||||
asserted by raising it with the registry stopped.
|
||||
- **Genesis raises a control plane with no container runtime running**, and raises the store and the
|
||||
broker afterwards. Last, and on a machine with nothing on it.
|
||||
- **A published port count that does not change.** The mesh's own components publish nothing today, so
|
||||
moving them out of containers must not open anything — asserted on the machine's reachable set before
|
||||
and after, which the converge preview already reads.
|
||||
|
||||
## References
|
||||
|
||||
- [ADR 0141](0141-the-host-delivers-its-own-successor.md) — the receiving half, already built
|
||||
- [ADR 0005](0005-the-node-host.md) — the host, its supervision, and one binary per operating system
|
||||
- [ADR 0078](0078-the-store-and-broker-are-modules.md) — why third-party software stays a container
|
||||
- [ADR 0006](0006-the-substrate-and-the-control-plane.md) — what genesis must raise, and in what order
|
||||
- [issue 142](../04-ISSUES/142-the-host-is-the-one-thing-the-mesh-does-not-deliver/00-report.md) — the
|
||||
measurement that started this
|
||||
- [design 07](../03-DESIGN/01-to-be/07-the-foundation.md) — the bundle's three images, one of them the
|
||||
controller
|
||||
@@ -142,6 +142,7 @@ python3 00-META/checks/index.py fail if stale
|
||||
- **0131** — [Everything on the mesh speaks to the broker seat, and AMQP is not a provision](0131-everything-on-the-mesh-speaks-to-the-broker-seat.md)
|
||||
- **0132** — [A seat carries the tools its holder must serve](0132-a-seat-carries-the-tools-its-holder-must-serve.md)
|
||||
- **0134** — [The mesh says what it applied](0134-the-mesh-says-what-it-applied.md)
|
||||
- **0142** — [The mesh delivers its own components as binaries, not as container images](0142-the-mesh-delivers-its-own-components-as-binaries.md)
|
||||
|
||||
### Its tiers, from the bottom up
|
||||
|
||||
@@ -221,6 +222,7 @@ python3 00-META/checks/index.py fail if stale
|
||||
- **0138** — [An assignment binds an endpoint and says how far it reaches](0138-an-assignment-binds-an-endpoint-and-says-how-far-it-reaches.md)
|
||||
- **0139** — [A network is forwarded because a module declared it](0139-a-network-is-forwarded-because-a-module-declared-it.md) *(superseded)*
|
||||
- **0140** — [The filter constrains what arrives from outside, and says nothing about a machine's own guests](0140-the-filter-constrains-what-arrives-from-outside.md)
|
||||
- **0141** — [The host delivers its own successor, and versions live side by side](0141-the-host-delivers-its-own-successor.md)
|
||||
|
||||
### How it is built
|
||||
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
layer: to-be
|
||||
status: in-progress
|
||||
code: [mesh-host]
|
||||
updated: 2026-09-22
|
||||
updated: 2026-09-29
|
||||
decisions:
|
||||
- 02-DECISIONS/0141-the-host-delivers-its-own-successor.md
|
||||
- 02-DECISIONS/0100-a-node-in-use-is-adopted-before-it-is-converged.md
|
||||
- 02-DECISIONS/0102-the-mesh-writes-into-a-shared-file-never-over-it.md
|
||||
- 02-DECISIONS/0103-what-an-adopted-node-holds-and-what-its-guard-refuses.md
|
||||
@@ -423,3 +424,45 @@ ignored an instruction and "applied" would be a lie. Applying stays one at a tim
|
||||
is not. **Checked** by the link's unit tests on the drain, and by the genesis bed's settle wait,
|
||||
which counts on a node catching up to the newest declaration rather than the oldest.
|
||||
|
||||
## The host delivers its own successor
|
||||
|
||||
*2026-09-29, from a change to the host that could reach no machine —
|
||||
[issue 142](../../04-ISSUES/142-the-host-is-the-one-thing-the-mesh-does-not-deliver/00-report.md),
|
||||
settled by [ADR 0141](../../02-DECISIONS/0141-the-host-delivers-its-own-successor.md).*
|
||||
|
||||
A merge builds every changed module and the control plane, and the result reaches the machines running
|
||||
it with nobody asking. The host was the exception: not a build target, named by no declaration, and
|
||||
identical on every machine because somebody had copied it there.
|
||||
|
||||
The supervision needed for this was already right. A clean exit from the host means it has stood aside,
|
||||
and the launcher's next turn runs whatever is on disk. Consecutive failed starts are counted, a
|
||||
rollback happens at the limit, and a second failure halts with the machine named rather than the binary.
|
||||
What was missing was smaller than it looked: nothing told the running host a successor was waiting, and
|
||||
the rollback resolved its known-good *version* through one operating system's package manager, which no
|
||||
machine here used.
|
||||
|
||||
Keeping a version rather than a path was the clue. That is only useful to something that can choose
|
||||
between versions present on the machine — so the versions live side by side:
|
||||
|
||||
- **A version arrives as an archive, in a directory named for it.** The ordinary resource, fetched by
|
||||
digest and checked before anything is unpacked. The path written is never the path being executed, so
|
||||
replacing a running binary — which the kernel refuses — never comes up.
|
||||
- **The launcher starts the most recently delivered version**, reading no pointer and following no
|
||||
link, because the version is in the path.
|
||||
- **The running host stands aside between reconciles and never inside one.** Standing aside mid-apply is
|
||||
the half-configured machine this document exists to prevent.
|
||||
- **A version that completes a reconcile records itself and retires what is older than its
|
||||
predecessor.** The predecessor stays, because that is what a rollback needs.
|
||||
- **Rollback starts that predecessor** instead of reinstalling a package: no package manager, no cache
|
||||
somebody else may clean, and the same script on every operating system.
|
||||
- **A machine says which host version it runs**, on the report it already sends, so being behind is
|
||||
answerable at all.
|
||||
|
||||
One copy by hand remains, once: the first host that understands versioned directories cannot be fetched
|
||||
by a host that does not.
|
||||
|
||||
*How it is checked* is stated with the decision — a second version delivered to a running machine is
|
||||
run and reported; the exit follows an in-flight apply rather than interrupting it; a version that will
|
||||
not start is rolled back once and the second failure halts; a completed reconcile retires what is older
|
||||
than the predecessor and never the predecessor; and the newest of two delivered versions is the one
|
||||
that runs.
|
||||
|
||||
@@ -11,8 +11,9 @@ code:
|
||||
- mesh-catalog modules/postgres
|
||||
- mesh-catalog modules/lavinmq
|
||||
- mesh-lab test/integration/mesh.test.ts (a bare machine becomes a mesh)
|
||||
updated: 2026-09-22
|
||||
updated: 2026-09-29
|
||||
decisions:
|
||||
- 02-DECISIONS/0142-the-mesh-delivers-its-own-components-as-binaries.md
|
||||
- 02-DECISIONS/0100-a-node-in-use-is-adopted-before-it-is-converged.md
|
||||
- 02-DECISIONS/0088-the-foundation-filters-before-anything-listens.md
|
||||
- 02-DECISIONS/0004-a-node-and-how-it-joins.md
|
||||
@@ -314,4 +315,24 @@ of a database and pushed to over the broker. What arrived and what did not is th
|
||||
|
||||
**One fault, and it was in the joining.** The token did not say what the mesh calls the machine,
|
||||
so enrolment needed a flag its own help said it did not — and failed at the broker with an empty
|
||||
username. Recorded in ADR 0004 as the fifth thing a token carries.
|
||||
username. Recorded in ADR 0004 as the fifth thing a token carries.
|
||||
|
||||
## The mesh's own components arrive as binaries
|
||||
|
||||
*2026-09-29 —
|
||||
[ADR 0142](../../02-DECISIONS/0142-the-mesh-delivers-its-own-components-as-binaries.md).*
|
||||
|
||||
The bundle carries three images and one of them is the controller, *because there is nothing to fetch
|
||||
it with yet*. That reasoning holds and its conclusion changes: the controller is carried as a **binary**
|
||||
reference rather than an image reference, pinned by digest exactly as before. Nothing about the bundle's
|
||||
shape moves — it names a thing and the host fetches it — and the container runtime stops being something
|
||||
genesis must raise before the control plane can exist. It still raises one, for the store and the broker,
|
||||
which is where somebody else's software belongs.
|
||||
|
||||
The mesh's own components — the host, the controller, the catalogue, the builder, the vault — are
|
||||
delivered as binaries into directories named for their versions, by the mechanism
|
||||
[ADR 0141](../../02-DECISIONS/0141-the-host-delivers-its-own-successor.md) describes. Third-party
|
||||
software stays a container. The split is not about isolation; it is about who built the thing.
|
||||
|
||||
Measured before deciding it: the mesh's own components publish no ports at all, so this opens nothing.
|
||||
Only the store, the registry and the broker publish, and they are staying as they are.
|
||||
|
||||
@@ -5,8 +5,9 @@ code:
|
||||
- mesh-controller cmd/mesh-builder
|
||||
- mesh-controller internal/builder
|
||||
- mesh-catalog modules/builder
|
||||
updated: 2026-09-25
|
||||
updated: 2026-09-29
|
||||
decisions:
|
||||
- 02-DECISIONS/0142-the-mesh-delivers-its-own-components-as-binaries.md
|
||||
- 02-DECISIONS/0111-a-build-source-is-on-the-git-seat-or-external.md
|
||||
- 02-DECISIONS/0097-a-vendor-image-is-a-declared-build-input.md
|
||||
- 02-DECISIONS/0096-an-upstream-image-is-copied-between-registries.md
|
||||
@@ -263,3 +264,27 @@ ships one and wrong for code the mesh built, which has no unit until the mesh wr
|
||||
|
||||
**Tools, hooks and consumers are not further modes**, which is the test of whether three is the
|
||||
right number: they are loaded by a tool host, and a tool host is a process that stays up.
|
||||
|
||||
## The builder compiles the languages the mesh is written in
|
||||
|
||||
*2026-09-29 —
|
||||
[ADR 0142](../../02-DECISIONS/0142-the-mesh-delivers-its-own-components-as-binaries.md).*
|
||||
|
||||
The toolchain list was typescript and python, and only typescript had a base module in the catalogue.
|
||||
Meanwhile the control plane — written in the language this project is mostly written in — was built as
|
||||
an image from a hand-written Dockerfile, which is the per-repository incantation this whole mechanism
|
||||
exists to abolish.
|
||||
|
||||
So the list gains Go, with a base module providing the compiler exactly as typescript has one. The
|
||||
obligation the list's own comment warns about — an SDK carrying the broker client, the event envelope
|
||||
and tool serving — attaches to a **module** written in a language, not to the language being
|
||||
compilable. The mesh's own components are not modules in that sense; the host is what applies modules.
|
||||
|
||||
**And an artifact says what it targets.** A compiled binary is per operating system, pinned at link
|
||||
time, and a toolchain deliberately accepts nothing from the module — anything a module could override
|
||||
there it would be writing a Dockerfile to override. The target is therefore a property of the artifact,
|
||||
not of the recipe: one artifact declared per target, one build each.
|
||||
|
||||
A component's version stops being stamped in at link time. It is unpacked into a directory named for
|
||||
its version, so it reads its version from its own path, and a build no longer has to know what it will
|
||||
be called.
|
||||
|
||||
@@ -6,7 +6,7 @@ located-in:
|
||||
- mesh-host cmd/mesh-host
|
||||
- mesh-controller (no build source for the host; no resource delivers it)
|
||||
fixed-by:
|
||||
amended-design:
|
||||
amended-design: 03-DESIGN/01-to-be/05-the-node-host.md
|
||||
---
|
||||
|
||||
# 142 — The host is the one thing the mesh does not deliver
|
||||
|
||||
Reference in New Issue
Block a user