--- topic: building it status: accepted date: 2026-10-04 deciders: jochen reconstructed: false extends: 02-DECISIONS/0067-genesis-is-a-pivot.md --- # 200. Genesis pivots to the controller as a container, and the first push hands it to a process ## Context The controller is Go, compiled to one static binary, and is the last of the mesh's own programs a machine runs from an image ([issue 213](../04-ISSUES/213-the-controller-is-a-go-program-run-in-a-container/00-report.md)). [ADR 0188](0188-a-modules-own-code-is-bundles-in-any-language-and-a-tools-bundle-speaks-mcp-to-the-runtime.md) §1 says a module's own code is bundles, never an image, and §3 that a service bundle is a `process` the host runs. The handover exists: a process may name the container it `replaces`, and the host removes that container only after the process has stayed up across two checks; two controllers are safe together for that moment, the second standing by on the controller's consumers and every plan held by one lock. What stands in the way is genesis ([ADR 0067](0067-genesis-is-a-pivot.md)), which [issue 223](../04-ISSUES/223-a-new-mesh-installs-its-controller-as-a-container/00-report.md) found assumes an image and a container at every step from its third: it builds the controller's image, starts a temporary controller from it, publishes it, finds the controller's container in the pivot declaration, and from then on talks to the controller through it. A process's bundle is fetched from the artifact store, and genesis raises the artifact store only after the pivot. ## Considered Options 1. **Raise the artifact store before the pivot**, publish the controller's bundle to it, and talk to the controller from the host's side. Rejected for now: it reorders genesis around a store that is itself a module the controller deploys, and rewrites the steps that talk to the controller — a larger change to the one path that is exercised least, to remove a container that exists for minutes. 2. **Pivot to the controller as a container, as today, and let the first push hand it over to the process**, through the handover that already exists. Chosen. 3. **Keep the controller a container.** Rejected: it is the exception to ADR 0188 that every other module's code has now left, and it costs a container runtime on the control machine and a container recreation in the middle of a plan. ## Decision **Genesis raises the controller as a container, under the resource the controller's process `replaces`, and the first declaration the controller composes for its own machine hands it over.** The container is genesis's own shape, built from the controller's repository, and is recorded on the control machine exactly as the manifest's `replaces` names it, so the first apply after the pivot finds a replacement for it and removes it once the process is up. The controller's manifest declares only the process; the image form exists for genesis alone and is not a second way to run the controller on a live mesh. This is the one bounded exception to ADR 0188 §1: a module's own code in an image, for the minutes between the pivot and the first push, on a mesh being created. ## Consequences - A new mesh ends where a running one is: the controller a process, no controller container. - Genesis keeps its steps; what changes is that it no longer reads the controller's container from the manifest, and that it records the container under the name the handover expects. - The controller's repository keeps its image build for genesis and the lab. - The handover is now on genesis's path too: a process that fails to stay up leaves the genesis container serving, and the apply says so — the same rule as on a live mesh. ## How it is checked The installer's test raises a mesh whose controller manifest is the process form, and asserts that the container genesis recorded is exactly what the process `replaces`, so the first apply hands over and leaves one controller. Live, on the running mesh: after the manifest change is pushed, the control machine runs the controller as a process and no controller container, and the controller's seat answers throughout. ## References - [Issue 213](../04-ISSUES/213-the-controller-is-a-go-program-run-in-a-container/00-report.md), [issue 223](../04-ISSUES/223-a-new-mesh-installs-its-controller-as-a-container/00-report.md) - mesh-host#86 (the handover), mesh-controller#252 (two controllers safe together), mesh-controller#253 (the controller's manifest as a process)