**0114 accepted.** The separation it draws — a consumer's resource and a credential that reaches it are different things — is a data-loss rule, and a record naming one should not sit unresolved while the code that could hit it is written. Not built, and accepting it schedules nothing; accepted-and-not-built is where 0141 and 0142 already are. **0068 superseded by 0149, the live mesh is the test bed.** Never built, and contradicted by practice that was written down nowhere but a handoff note. The faults that cost the most are faults of a mesh that already exists — bound consumers, containers made against an older roster, an adopted machine — and a bed is by construction a mesh that does not. Issue 156 settles it: that change was verified honestly, on the only path where it cannot fail. The lab is not retired; raising a mesh from bare is now its whole job. **117 answered by 0150.** A module's own code runs as supervised processes under the module's one account. 0047's argument was for a runtime per module, not for a container — a unit satisfies it and runs as an account. The invariant is the account, not the process count: its worry was a second identity to scope and seal, and processes sharing one account create none. Designs 18 and 20 now cite it and 0047 carries a dated pointer, which closes the third disagreement — that neither design knew the record existed.
114 lines
7.4 KiB
Markdown
114 lines
7.4 KiB
Markdown
---
|
|
topic: what runs on it
|
|
status: accepted
|
|
date: 2026-09-30
|
|
deciders: jochen
|
|
reconstructed: false
|
|
extends: 02-DECISIONS/0047-a-module-runs-its-code-as-its-own-process-with-its-own-account.md
|
|
---
|
|
|
|
# 150. A module's own code runs as supervised processes under the module's one account
|
|
|
|
## Context
|
|
|
|
The repository answers "what runs a module's own code" two ways and reconciles them nowhere
|
|
([issue 117](../04-ISSUES/117-a-modules-own-code-is-a-container-and-a-process/00-report.md)).
|
|
|
|
[ADR 0047](0047-a-module-runs-its-code-as-its-own-process-with-its-own-account.md) is accepted and
|
|
says **a container** — "the tool runtime carrying that module's compiled code" — and "one module, one
|
|
process, one account". Two `proposed` design documents say a **`process`** resource running an argv,
|
|
supervised by the machine, and one of them declares *four* of them for a single module and presents
|
|
four as the point. Neither design document names 0047 in its `decisions:`, and the string `process`
|
|
as a resource type appears in no decision record at all. The thing as built is the container.
|
|
|
|
Two things have happened since 0047 was written that bear on it directly.
|
|
|
|
[**ADR 0142**](0142-the-mesh-delivers-its-own-components-as-binaries.md) decided that the mesh's own
|
|
components are binaries on the machine rather than container images, and
|
|
[issue 114](../04-ISSUES/114-should-the-controller-be-a-container-or-a-process/00-report.md) was closed
|
|
by it. That settled the mesh's components and deliberately said nothing about a module's.
|
|
|
|
And the standing definition of a module hardened: **a module is software that delivers one or more
|
|
services, and a module is not a container.** It may deliver them as a container, an installed package
|
|
with a unit, a binary, or configuration files; 61 of 73 happen to use a container and 11 do not,
|
|
including the resolver, sshd and fail2ban. A rule that a module's *own code* must be a container makes
|
|
the one kind of module the mesh writes itself the only kind that has no choice.
|
|
|
|
## Considered Options
|
|
|
|
**1. Hold 0047 as written: a container.** Rejected. Its own reasoning does not require one. What 0047
|
|
argued for was a runtime **per module** rather than one for the whole node, because a node-wide runtime
|
|
could not hold a per-module broker account and per-module runtimes competing on one tool key would each
|
|
be handed calls for tools they do not have. A supervised unit per module satisfies that argument
|
|
exactly — it is per module, and a unit runs as an account. The container was the mechanism to hand, not
|
|
the conclusion.
|
|
|
|
**2. Let each design document choose.** Rejected; that is the present state and it is what issue 117
|
|
reports. A module author reading the guide writes four processes; a module author reading the record
|
|
writes a container; nothing tells either that the other exists.
|
|
|
|
**3. Settle the hosting form as a supervised process, and settle the count separately.** Chosen.
|
|
|
|
## Decision
|
|
|
|
**A module's own code runs as one or more supervised processes on the machine, under the module's single
|
|
account.** Where [ADR 0047](0047-a-module-runs-its-code-as-its-own-process-with-its-own-account.md) says
|
|
"a container, the tool runtime carrying that module's compiled code", read this record. Everything else
|
|
0047 decided stands untouched: a tool is served on its own key, only the module that serves it answers,
|
|
and the module's account is scoped to exactly its tool keys.
|
|
|
|
**The invariant is the account, not the process count.** 0047's "one module, one process, one account"
|
|
carried its weight in the last clause. Its stated worry about a second process was "not a second one to
|
|
scope and seal" — a second *identity* to grant, seal a secret to, and scope on the bus. Several
|
|
processes sharing the module's one account create no second identity, so nothing further is scoped or
|
|
sealed, and a module may therefore declare as many as its work has shapes: events, tools, a
|
|
provisioner, a scheduled ingest. **What a module may not have is two accounts.**
|
|
|
|
**A module that delivers its service as a container still does.** This record is about the code the
|
|
module itself carries — its tools, its events, its provisioner — and not about the software it delivers.
|
|
A module wrapping a third-party image wraps a third-party image.
|
|
|
|
**Why supervised by the machine rather than by the mesh:** it is the same answer ADR 0142 gave for the
|
|
mesh's own components, for the same reason. A unit the machine restarts needs no image, no registry
|
|
pull and no runtime to be up before the mesh's own code can run — which matters most for exactly the
|
|
modules whose code the mesh cannot start any other way.
|
|
|
|
## How this is checked
|
|
|
|
- **No design document describes a hosting form for a module's own code without citing this record.**
|
|
Designs 18 and 20 name it in `decisions:`; this is the gap issue 117's third point reports, and
|
|
`cycle.py` already enforces that a to-be design names its decisions.
|
|
- **A module declaring several processes resolves to one account.** A test composes a module with more
|
|
than one process resource and asserts the mesh mints exactly one broker account for it, scoped to that
|
|
module's tool keys and nothing else — which is 0047's invariant stated as an assertion rather than a
|
|
sentence.
|
|
- **A module's own code does not require the container runtime.** A machine with no container runtime
|
|
can still run a module whose code is its own, which is the claim that separates this from option 1 and
|
|
is checkable on a machine that has one by asserting the declaration names no image for it.
|
|
|
|
## Consequences
|
|
|
|
- **The sidecar port stops being needed.** [ADR 0029](0029-a-network-is-a-shape-because-an-action-cannot-be-undone.md)
|
|
records that "anything that is a service plus a sidecar currently has to publish a port to talk to
|
|
itself", and the host's `network` shape exists partly for it. A process beside the service on the same
|
|
machine reaches it without publishing anything, so that pressure goes.
|
|
- **Something must supervise, and it is the machine.** This adds a unit per module's code to what the
|
|
host writes and owns. The mesh already writes and owns units — `nftables` proves a module can write one
|
|
and run it — so the mechanism exists; the count grows.
|
|
- **A module's code is delivered, not pulled**, which puts it behind the same gap as the host's own
|
|
delivery ([ADR 0141](0141-the-host-delivers-its-own-successor.md), not built): nothing yet delivers a
|
|
version of a module's binary to a machine. A container's code arrives by `docker pull`, and this does
|
|
not. **This is the cost of the decision and it is not paid**; until delivery exists, a module whose code
|
|
is its own is a module somebody places by hand.
|
|
- **Issue 117 is answered and its three disagreements close differently:** container-or-unit is decided
|
|
here; one-process-or-several is decided here as several under one account; and whether the record was
|
|
consulted is fixed by designs 18 and 20 naming this one.
|
|
|
|
## References
|
|
|
|
- [issue 117](../04-ISSUES/117-a-modules-own-code-is-a-container-and-a-process/00-report.md) — the contradiction this answers
|
|
- [ADR 0047](0047-a-module-runs-its-code-as-its-own-process-with-its-own-account.md) — extended; its "a container" clause is settled here
|
|
- [ADR 0142](0142-the-mesh-delivers-its-own-components-as-binaries.md) — the same answer for the mesh's own components
|
|
- [ADR 0141](0141-the-host-delivers-its-own-successor.md) — the delivery this depends on and which is not built
|
|
- [ADR 0029](0029-a-network-is-a-shape-because-an-action-cannot-be-undone.md) — the sidecar port this relieves
|