Three records were left describing a mechanism a new record had moved, and a reader arrives at them by following a citation: 0066 still said a routed name is written into every container after 0148 replaced that with resolution; 0016 still read as though the lab were the test bed after 0149; and issues 109 and 135 said nothing about 0148 ending the copying that 135's own fix made comparable. Each was a citation leading to the wrong answer in a record that was not wrong about anything it decided. This is the second time in one session. The playbook rule I added last round did not stop it, so the convention is now written where the record conventions live, with the shape to use and three worked examples — and with the honest note that it is NOT machine-checked and cannot be from `extends:` alone: 102 records extend another, 87 have no back-reference, and that is correct, because extending usually means building on a context. Making it mechanical means a record declaring the relationship in frontmatter, which is a schema change and is not mine to decide. Also: designs 18 and 20 claimed `updated:` dates from before I edited them, and 117's `fixed-by` gained the commit beside the record.
126 lines
9.3 KiB
Markdown
126 lines
9.3 KiB
Markdown
---
|
|
status: resolved
|
|
opened: 2026-09-25
|
|
located-in: [hq, mesh-catalog modules/showcase, mesh-sdk src/tools/index.ts, mesh-tools]
|
|
fixed-by: hq 83791f0 (PR 196) — ADR 0150: a module's own code runs as supervised processes under the module's one account; designs 18 and 20 now cite it, and ADR 0047 carries a dated note pointing at it
|
|
amended-design:
|
|
---
|
|
|
|
# 117 — A module's own code is a container in one record and a process in another
|
|
|
|
## What was observed
|
|
|
|
Asked what the "sidecar" is — the second container a code-carrying module runs beside its
|
|
service — and whether a supervised process would do instead. Reading the records to answer it,
|
|
the repository answers both ways, and nothing reconciles them.
|
|
|
|
| record | status | what runs a module's own code |
|
|
|---|---|---|
|
|
| [ADR 0047](../../02-DECISIONS/0047-a-module-runs-its-code-as-its-own-process-with-its-own-account.md) | **accepted**, 2026-09-04 | "a **container**, the tool runtime carrying that module's compiled code" — one module, one process, one account; events and tools in that same process, "not a second one to scope and seal" |
|
|
| [`01-to-be/18-building-a-module.md`](../../03-DESIGN/01-to-be/18-building-a-module.md) | proposed, 2026-09-21 | a resource type table in which `container` is "an image" and **`process`** is "**its own code**, in three modes", whose default mode is "a unit restarted when it exits", supervised by the machine |
|
|
| [`01-to-be/20-writing-a-module.md`](../../03-DESIGN/01-to-be/20-writing-a-module.md) | proposed, 2026-09-21 | one module declaring **four** `process` resources — events, tools, provisioner, a scheduled ingest — each with its own `run` argv, and the sentence "it is why these are `process` rather than four containers" |
|
|
|
|
Three disagreements, not one:
|
|
|
|
1. **Container or unit.** ADR 0047 chose a container and said why: a node-wide runtime loading
|
|
every module's code could not hold a per-module account, so the runtime is per-module. The
|
|
design docs choose a supervised unit running an argv and give no reason, because they do not
|
|
record that they are choosing.
|
|
2. **One process or several.** ADR 0047's "one module, one process, one account" is the whole
|
|
content of its second and third sections. The worked guide declares four for one module and
|
|
presents four as the point.
|
|
3. **Whether the record was consulted at all.** Neither design doc names ADR 0047 in
|
|
`decisions:`. No record supersedes or extends it on this. **The string `process` as a resource
|
|
type appears in no decision record** — the shape exists only in two `proposed` design docs.
|
|
|
|
Meanwhile the thing as built is the container. [ADR 0029](../../02-DECISIONS/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," which is one of the things the host's `network` shape was added for.
|
|
[Issue 113's diagnosis](../113-the-object-stores-images-were-withdrawn-upstream/01-diagnosis.md)
|
|
found a catalogue module declaring "two container resources," the second a runtime sidecar
|
|
"pinned at an all-zeros digest, meaning nothing was ever published for it."
|
|
[Issue 095](../095-a-module-assigned-after-genesis-has-no-broker-account/00-report.md) is a
|
|
sidecar crash-looping on a credential while its service served correctly.
|
|
[ADR 0093](../../02-DECISIONS/0093-a-fixture-that-runs-a-modules-runtime-carries-its-name.md)
|
|
records that a bed wanting "a sidecar without its server raises the server."
|
|
|
|
### And the word is in no glossary
|
|
|
|
"Sidecar" appears sixteen times across five records — two decisions and three issues. It is
|
|
absent from [`00-META/glossary.md`](../../00-META/glossary.md), and absent from every document
|
|
under [`03-DESIGN/`](../../03-DESIGN/), in both layers. ADR 0047, which creates the thing, never
|
|
uses the word; it says "runtime process" and "runtime container". The glossary's own rule is that
|
|
"a new name for an existing thing lands here first, in the same change that introduces it in
|
|
code," and the page exists because "the terms kept drifting in conversation." A reader asking
|
|
what the sidecar is has nowhere in the design layer to look, which is how this was found.
|
|
|
|
## Why it matters beyond this instance
|
|
|
|
- **A module author reading the current guide writes a `process`; the catalogue as built declares
|
|
a `container`.** [`20-writing-a-module.md`](../../03-DESIGN/01-to-be/20-writing-a-module.md) is
|
|
a worked guide with a manifest in it. Whichever of the two is wrong, somebody follows it.
|
|
- **The cost of the container shape is paid in four places and totalled in none.** A published
|
|
image per code-carrying module, a network so a module can reach itself, a bed that cannot run a
|
|
runtime without raising the server it manages, and a credential failure that presents as the
|
|
module's own bug. Each record argues its own piece is worth paying. No record puts them beside
|
|
the alternative.
|
|
- **Both shapes carry a cost the other does not, and neither is written down.** A container
|
|
carries its own interpreter; a `process` declaring `run: ["node", "index.js"]` needs an
|
|
interpreter present on the machine, which is the machine dependency the statically linked host
|
|
([ADR 0005](../../02-DECISIONS/0005-the-node-host.md)) exists to avoid. And `run` is an argv,
|
|
where [ADR 0005](../../02-DECISIONS/0005-the-node-host.md) refuses `action` because the link may
|
|
not carry a command — a refusal [`18-building-a-module.md`](../../03-DESIGN/01-to-be/18-building-a-module.md)
|
|
restates on the same page that it introduces `process`.
|
|
- **This is the repository's own named failure mode, in its own records.** `cycle.py` enforces
|
|
that a to-be doc names *at least one* decision. Both docs do, so both pass, while introducing a
|
|
resource type no decision records and contradicting an accepted one. The rule is "no design
|
|
without a decision"; the check is "no design without *a* decision." An unenforced rule is
|
|
indistinguishable from a wrong one, and these two documents are what that gap looks like when
|
|
something walks through it.
|
|
|
|
## Open questions
|
|
|
|
- Which is the decision — container or supervised unit? If the design docs are right, ADR 0047
|
|
needs superseding rather than quietly outliving. If ADR 0047 is right, two proposed documents
|
|
and a worked manifest describe a resource type that does not exist.
|
|
- Is one account per module satisfied by a per-module *unit* as well as a per-module *container*?
|
|
ADR 0047's argument rules out a node-wide runtime sharing one account. It does not appear to
|
|
rule out a unit holding one scoped credential, and nothing has said so either way.
|
|
- If several processes for one module are right, what holds the accounts? ADR 0047 refused "a
|
|
second one to scope and seal" for events beside tools. Four processes are four somethings.
|
|
- How does a `process` get its interpreter, and does declaring one reintroduce the machine
|
|
dependency the host is built to avoid?
|
|
- Is `run` an argv the link may carry, given `action` is refused for being one? If the answer is
|
|
that a `process` reconciles and an `action` does not, that distinction is not written down.
|
|
- What is the thing called, and where does the design layer describe it? Whichever shape wins, no
|
|
document in either layer currently says a code-carrying module runs a second thing beside its
|
|
service.
|
|
- **How would this have been caught?** A decision and a design doc disagreeing on a resource type
|
|
is mechanically checkable: the resource types a design doc names are a closed set, and every
|
|
member of it either appears in a decision or does not. Whether that check is worth writing is
|
|
part of this issue, not settled by it.
|
|
|
|
## Answered (2026-09-30)
|
|
|
|
[ADR 0150](../../02-DECISIONS/0150-a-modules-own-code-runs-as-supervised-processes-under-one-account.md)
|
|
settles all three disagreements, and the design documents win two of them:
|
|
|
|
1. **Container or unit — a supervised process.** ADR 0047's argument never required a container. It
|
|
argued for a runtime *per module*, because a node-wide one could not hold a per-module account and
|
|
per-module runtimes on one tool key would be handed calls for tools they do not have. A unit per
|
|
module satisfies that exactly, and a unit runs as an account. The container was the mechanism to
|
|
hand. [ADR 0142](../../02-DECISIONS/0142-the-mesh-delivers-its-own-components-as-binaries.md) had
|
|
already gone the same way for the mesh's own components, and a module is not a container.
|
|
2. **One process or several — several, under one account.** 0047's "one module, one process, one
|
|
account" carried its weight in the last clause; its stated worry was "not a second one to scope and
|
|
seal", which is about a second *identity*. Processes sharing the module's one account create none.
|
|
What a module may not have is two accounts.
|
|
3. **Whether the record was consulted — fixed rather than answered.** Designs 18 and 20 now name 0150
|
|
in `decisions:`, and 0047 carries a dated note saying where its hosting form was settled, so neither
|
|
door leads to the wrong answer any more.
|
|
|
|
**What this does not fix.** A module's code delivered as a binary is behind the same gap as the host's
|
|
own ([ADR 0141](../../02-DECISIONS/0141-the-host-delivers-its-own-successor.md), accepted and not
|
|
built): a container's code arrives by `docker pull` and this does not, so until delivery exists such a
|
|
module is one somebody places by hand. 0150 records that as the cost of the decision, unpaid.
|