Files
hq/02-DECISIONS/0150-a-modules-own-code-runs-as-supervised-processes-under-one-account.md
jschoubben bf4d4e2e7b The three parked questions are answered: 0114 accepted, 0068 superseded, 117 settled
**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.
2026-09-30 00:39:09 +02:00

7.4 KiB

topic, status, date, deciders, reconstructed, extends
topic status date deciders reconstructed extends
what runs on it accepted 2026-09-30 jochen false 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).

ADR 0047 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 decided that the mesh's own components are binaries on the machine rather than container images, and issue 114 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 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 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, 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 — the contradiction this answers
  • ADR 0047 — extended; its "a container" clause is settled here
  • ADR 0142 — the same answer for the mesh's own components
  • ADR 0141 — the delivery this depends on and which is not built
  • ADR 0029 — the sidecar port this relieves