The four open design questions, answered: ADRs 0148, 0149, 0150, and 0114 accepted #196
@@ -26,6 +26,14 @@ runtime is per-module, not per-node, and treating the audit-logger as special le
|
|||||||
modules' code with nothing to run it: the conversion produced tools and events that, as it stands,
|
modules' code with nothing to run it: the conversion produced tools and events that, as it stands,
|
||||||
never execute.
|
never execute.
|
||||||
|
|
||||||
|
> **The hosting form is settled elsewhere — 2026-09-30.** Where this record says "a container", read
|
||||||
|
> [ADR 0150](0150-a-modules-own-code-runs-as-supervised-processes-under-one-account.md): a module's own
|
||||||
|
> code runs as supervised processes under this record's one account. Nothing else here changes — the
|
||||||
|
> per-module runtime, the per-tool key and the single scoped account are the argument this record made
|
||||||
|
> and they are why 0150 goes the way it does. The note is here because two design documents chose the
|
||||||
|
> other form without knowing this record existed
|
||||||
|
> ([issue 117](../04-ISSUES/117-a-modules-own-code-is-a-container-and-a-process/00-report.md)).
|
||||||
|
|
||||||
## Decision
|
## Decision
|
||||||
|
|
||||||
### A module with tools or events runs a process of its own
|
### A module with tools or events runs a process of its own
|
||||||
|
|||||||
@@ -1,14 +1,21 @@
|
|||||||
---
|
---
|
||||||
topic: building it
|
topic: building it
|
||||||
status: proposed
|
status: superseded
|
||||||
date: 2026-09-12
|
date: 2026-09-12
|
||||||
deciders: jochen
|
deciders: jochen
|
||||||
reconstructed: false
|
reconstructed: false
|
||||||
extends: 0016-the-lab.md
|
extends: 0016-the-lab.md
|
||||||
|
superseded-by: 02-DECISIONS/0149-the-live-mesh-is-the-test-bed.md
|
||||||
---
|
---
|
||||||
|
|
||||||
# 68. The lab takes requests, one at a time, and runs each from its own copy
|
# 68. The lab takes requests, one at a time, and runs each from its own copy
|
||||||
|
|
||||||
|
> **Superseded — 2026-09-30, by [ADR 0149](0149-the-live-mesh-is-the-test-bed.md).** Never built. The
|
||||||
|
> live mesh became the test bed, because 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. The rule worth keeping from below is that a run reads a
|
||||||
|
> copy that is not anybody's working tree.
|
||||||
|
|
||||||
## Context
|
## Context
|
||||||
|
|
||||||
**The lab is exclusive hardware, and today a person holds it.** Raising a scenario takes over
|
**The lab is exclusive hardware, and today a person holds it.** Raising a scenario takes over
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
topic: what runs on it
|
topic: what runs on it
|
||||||
status: proposed
|
status: accepted
|
||||||
date: 2026-09-26
|
date: 2026-09-26
|
||||||
deciders: jochen
|
deciders: jochen
|
||||||
reconstructed: false
|
reconstructed: false
|
||||||
@@ -189,6 +189,23 @@ On acceptance, each of these is amended by this record, not edited:
|
|||||||
credential is no longer all-or-nothing with a window. It overlaps, with each step confirmed.
|
credential is no longer all-or-nothing with a window. It overlaps, with each step confirmed.
|
||||||
A single-party credential is staged, not replaced.
|
A single-party credential is staged, not replaced.
|
||||||
|
|
||||||
|
## Accepted, 2026-09-30, and not scheduled
|
||||||
|
|
||||||
|
Accepted as written. The separation it draws — a consumer's *resource* and a *credential that reaches
|
||||||
|
it* are different things with different lifecycles — is the part that had to be settled, because the
|
||||||
|
alternative is what the record was written against: retiring a credential taking the data it reached
|
||||||
|
with it. That is a data-loss shape, and a record that names it should not sit unresolved while the
|
||||||
|
code that could hit it is being written.
|
||||||
|
|
||||||
|
**It is not built, and accepting it does not schedule it.** The SDK's provisioner adapter is still
|
||||||
|
`create` / `remove` / `holds` rather than the four operations above, and no provider implements the
|
||||||
|
two-credential rotation. Accepted-and-not-built is an ordinary state here — 0141 and 0142 are both in
|
||||||
|
it — and it is the honest one: leaving this `proposed` made it invisible to anyone reading what the
|
||||||
|
mesh has decided, while changing nothing about what runs.
|
||||||
|
|
||||||
|
The work it implies belongs with the provisioner contract, beside
|
||||||
|
[issue 124](../04-ISSUES/124-a-consumer-cannot-be-told-what-its-provider-derived/00-report.md).
|
||||||
|
|
||||||
## Consequences
|
## Consequences
|
||||||
|
|
||||||
- **Every credential provider's adapter changes**, in two steps. The first separates *retire a
|
- **Every credential provider's adapter changes**, in two steps. The first separates *retire a
|
||||||
|
|||||||
@@ -0,0 +1,159 @@
|
|||||||
|
---
|
||||||
|
topic: the tiers
|
||||||
|
status: accepted
|
||||||
|
date: 2026-09-30
|
||||||
|
deciders: jochen
|
||||||
|
reconstructed: false
|
||||||
|
extends: 02-DECISIONS/0066-public-routing-is-name-agnostic.md
|
||||||
|
---
|
||||||
|
|
||||||
|
# 148. The mesh's names are resolved, not copied into every container
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
The mesh gives every container it declares the whole roster of mesh names as entries written into
|
||||||
|
the container's own hosts file at creation
|
||||||
|
([design 08 §2](../03-DESIGN/01-to-be/08-connectivity.md),
|
||||||
|
[ADR 0066](0066-public-routing-is-name-agnostic.md)). A container takes those entries once and never
|
||||||
|
looks again.
|
||||||
|
|
||||||
|
Three issues are the same fact arriving three times.
|
||||||
|
|
||||||
|
**A container keeps the address it was made with.** Adopting the predecessor's tunnel moved the hub's
|
||||||
|
private address; the declaration followed it within one push and nothing on the machine did. The
|
||||||
|
forge's container held the old address, lost its database, reported healthy while its existing
|
||||||
|
connections lasted, and then the public name went down
|
||||||
|
([issue 109](../04-ISSUES/109-a-container-keeps-the-address-it-was-made-with/00-report.md)).
|
||||||
|
|
||||||
|
**The same fault, four days later, undetected for five days.** One container had restarted 2286 times
|
||||||
|
against a database it could no longer find, while the mesh reported the machine as doing what it was
|
||||||
|
told. Inside it, `novox.internal` was an address that had not existed for five days
|
||||||
|
([issue 135](../04-ISSUES/135-a-containers-mesh-names-are-not-compared/00-report.md)). Forty-eight
|
||||||
|
other containers were current, none of them corrected — each had been recreated for some other
|
||||||
|
reason and picked up the roster on the way.
|
||||||
|
|
||||||
|
135 was fixed by putting the roster into the digest the host compares a container against, so a
|
||||||
|
container whose names moved is recreated like one whose image moved. **That made the roster part of
|
||||||
|
every container's identity**, which is the third arrival:
|
||||||
|
|
||||||
|
**One name moving replaces every container in the mesh.** Migrating one small module on one machine
|
||||||
|
took four routine actions; each changed the roster, and each replaced every container on the control
|
||||||
|
node — its own store, the registry, the edge proxy, the forge, the directory, mail. The control plane
|
||||||
|
was unreachable twice while its own store came back through crash recovery
|
||||||
|
([issue 151](../04-ISSUES/151-a-new-name-recreates-every-container-in-the-mesh/00-report.md)). None of
|
||||||
|
the replaced containers had anything to do with the module being migrated, or with its machine.
|
||||||
|
|
||||||
|
The blast radius of a name is now every container that carries the list, which is all of them. The
|
||||||
|
node-by-node migration ahead adds names one module at a time — on one machine alone that is around
|
||||||
|
twenty-five — and each would be a full restart of every service on the hub.
|
||||||
|
|
||||||
|
## Considered Options
|
||||||
|
|
||||||
|
**1. Keep the roster in every container and accept the churn.** Rejected. It is not a cost that can
|
||||||
|
be paid down: the mesh gets more names as it grows, and every name costs a restart of everything.
|
||||||
|
A rollback costs another.
|
||||||
|
|
||||||
|
**2. Scope each container's entries to the names it actually binds.** A container is given the names
|
||||||
|
of the things it declared a requirement on, so a name's blast radius is its consumers. Tidy, needs no
|
||||||
|
new mechanism, and keeps 135's guarantee exactly.
|
||||||
|
|
||||||
|
Rejected, and this is the close one. It contradicts the standing intent that **anything on the mesh
|
||||||
|
can call anything on it** — three cases, same machine, the private network, the public network, and
|
||||||
|
no fourth. Scoping resolution to declared couplings makes a name reachable only where the mesh was
|
||||||
|
told in advance that it would be wanted, and a person debugging inside a container would find names
|
||||||
|
missing that exist everywhere else on the machine. It also leaves the roster in the digest, so the
|
||||||
|
churn returns the moment a widely-bound name moves — smaller, not gone.
|
||||||
|
|
||||||
|
**3. Resolve at lookup time through the machine's resolver, and copy nothing.** Chosen.
|
||||||
|
|
||||||
|
## Decision
|
||||||
|
|
||||||
|
**A container resolves the mesh's names through its machine's resolver, at the moment it asks. No
|
||||||
|
mesh name and no mesh address is written into a container, and none is part of a container's
|
||||||
|
identity.**
|
||||||
|
|
||||||
|
The three consequences that make this worth doing:
|
||||||
|
|
||||||
|
- **Staleness stops being possible**, rather than being detected. 109 and 135 are not bugs that were
|
||||||
|
fixed; they are a shape that no longer exists. A name that moves is answered differently by the next
|
||||||
|
lookup, in every container, with nothing recreated and nothing restarted.
|
||||||
|
- **A name's blast radius becomes nothing.** Assigning a module on one machine does not touch a
|
||||||
|
container on another.
|
||||||
|
- **Anything can still call anything**, which option 2 gave up. The resolver answers every mesh name to
|
||||||
|
every asker on the machine, exactly as it answers the machine itself.
|
||||||
|
|
||||||
|
**The resolver is a machine-level process, not a container** — one of the modules that is not a
|
||||||
|
container at all — so a container depending on it is not the circularity it would be if the mesh's
|
||||||
|
own store had to resolve a name through something the store's own runtime had to start first.
|
||||||
|
|
||||||
|
**What a module declares for itself is untouched.** Entries a manifest asks for are the module's own,
|
||||||
|
stay in the container, and stay in its identity: they are part of what the module *is*, they do not
|
||||||
|
move when the mesh's roster does, and the mesh does not know what they mean.
|
||||||
|
|
||||||
|
**The machine's own roster file is untouched.** It is a file, rewritten in place, read by processes and
|
||||||
|
people; nothing restarts when it changes. It is only the *copy into each container* that this ends.
|
||||||
|
|
||||||
|
### The order this lands in, which is not a preference
|
||||||
|
|
||||||
|
**Nothing may stop copying names until resolution works from a container.** Removing the copy first
|
||||||
|
reintroduces 109 and 135 — silently, and on a live mesh, which is exactly how both were found.
|
||||||
|
|
||||||
|
1. **A container on any network can reach the resolver.** Today a container on the runtime's default
|
||||||
|
network asks from an address the converged filter drops, so it has no DNS at all
|
||||||
|
([issue 110](../04-ISSUES/110-a-container-on-the-runtimes-own-network-cannot-reach-the-resolver/00-report.md));
|
||||||
|
and on two of four machines the resolver binds loopback only, so the runtime hands containers a
|
||||||
|
public resolver instead. Both are prerequisites, not related work.
|
||||||
|
2. **The runtime is told which resolver to use, per machine, as a file** — not per container as a
|
||||||
|
creation-time argument, or the resolver's address is back in every container's identity and the
|
||||||
|
problem has only got smaller.
|
||||||
|
3. **Then, and only then, the roster leaves the declaration and the digest.**
|
||||||
|
|
||||||
|
Until step 3 the mesh keeps copying, and keeps comparing. 151 stays open until step 3 lands; it is not
|
||||||
|
closed by this record, only answered by it.
|
||||||
|
|
||||||
|
## How this is checked
|
||||||
|
|
||||||
|
- **A container resolves a name that moved, without being recreated.** Move a name the mesh serves;
|
||||||
|
from a container that was running before the move and has not been touched since, the name answers
|
||||||
|
with the new address. This is the one 109 and 135 would both have failed.
|
||||||
|
- **A name's blast radius is nothing.** Add a routed name on one machine; no container on any other
|
||||||
|
machine is recreated. The apply report on each machine says nothing changed. This is 151.
|
||||||
|
- **Anything calls anything.** From a container on any machine, every `<node>.internal` name and every
|
||||||
|
routed name the mesh serves resolves — including names the module never declared a requirement on,
|
||||||
|
which is the guarantee option 2 would have given up.
|
||||||
|
- **On every network the runtime offers.** The first three hold for a container on the runtime's
|
||||||
|
default network as well as one on a declared network, because the default network is the case that
|
||||||
|
has no DNS today.
|
||||||
|
- **No mesh name is in a container's spec.** A test asserts the digest a host computes for a container
|
||||||
|
does not move when the mesh's roster does, and does move when the module's own declared entries do.
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
- **The resolver becomes load-bearing for every container**, where before it was load-bearing for the
|
||||||
|
machine. This is a real cost and is accepted: a resolver that is down is a machine that cannot
|
||||||
|
resolve, which is already true of the machine itself, and is a smaller event than a roster change
|
||||||
|
destroying and recreating every container on the machine.
|
||||||
|
- **Design 08's "a file rather than a resolver" no longer describes containers.** It was written when
|
||||||
|
the mesh had no resolver and it gave the right answer then. The reasoning it rested on — every Linux
|
||||||
|
has a hosts file, no package needed — was already overtaken by names a hosts file cannot express:
|
||||||
|
service names and wildcards under `<node>.internal`, which is why the resolver was built.
|
||||||
|
- **ADR 0066's mesh-wide propagation is kept and its mechanism changes.** A routed name still reaches
|
||||||
|
every asker in the mesh; it reaches them through the resolver rather than by being written into each
|
||||||
|
container. The consequence 0066 records — that an internal issuer's challenge needs the routed name
|
||||||
|
resolvable inside the mesh — holds unchanged and by the same means the machine already uses.
|
||||||
|
- **Issue 110 stops being a container-DNS inconvenience and becomes a prerequisite** for the mesh not
|
||||||
|
restarting itself whenever it learns a name.
|
||||||
|
- **A container started by hand gets the mesh's names too**, where before only declared containers did.
|
||||||
|
Design 08 drew that boundary deliberately, on the grounds that reaching into every container is what
|
||||||
|
a nameserver would be for. This record accepts that consequence rather than working around it: a
|
||||||
|
person debugging in a hand-started container resolving the same names as everything else is the
|
||||||
|
behaviour worth having, and it is what "anything can call anything" means.
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- [issue 151](../04-ISSUES/151-a-new-name-recreates-every-container-in-the-mesh/00-report.md) — one name replaces every container; the question this answers
|
||||||
|
- [issue 135](../04-ISSUES/135-a-containers-mesh-names-are-not-compared/00-report.md) — the roster put into the digest
|
||||||
|
- [issue 109](../04-ISSUES/109-a-container-keeps-the-address-it-was-made-with/00-report.md) — the first arrival
|
||||||
|
- [issue 110](../04-ISSUES/110-a-container-on-the-runtimes-own-network-cannot-reach-the-resolver/00-report.md) — the prerequisite
|
||||||
|
- [ADR 0066](0066-public-routing-is-name-agnostic.md) — routed names propagate mesh-wide; extended here
|
||||||
|
- [design 08 §2](../03-DESIGN/01-to-be/08-connectivity.md) — the file-not-resolver reasoning this narrows
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
---
|
||||||
|
topic: building it
|
||||||
|
status: accepted
|
||||||
|
date: 2026-09-30
|
||||||
|
deciders: jochen
|
||||||
|
reconstructed: false
|
||||||
|
supersedes: 02-DECISIONS/0068-the-lab-takes-requests.md
|
||||||
|
---
|
||||||
|
|
||||||
|
# 149. The live mesh is the test bed
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
[ADR 0068](0068-the-lab-takes-requests.md) proposed that the lab accept queued requests
|
||||||
|
— a bed and a commit — answer them one at a time from a copy it owns, and expose that through tools so
|
||||||
|
an agent could start a run and come back to it. It has been `proposed` since 2026-09-12 and nothing was
|
||||||
|
built.
|
||||||
|
|
||||||
|
What happened instead is that the mesh became the thing under test. It runs on four machines; every
|
||||||
|
fault worth finding in the last month was found on them, and none was found in a bed:
|
||||||
|
|
||||||
|
- a container holding an address that had not existed for five days, on the control node
|
||||||
|
([issue 135](../04-ISSUES/135-a-containers-mesh-names-are-not-compared/00-report.md));
|
||||||
|
- a machine reading healthy for eleven hours while no module could reach another
|
||||||
|
([issue 145](../04-ISSUES/145-a-machine-reads-healthy-while-its-modules-cannot-reach-each-other/00-report.md));
|
||||||
|
- one name replacing every container on the hub
|
||||||
|
([issue 151](../04-ISSUES/151-a-new-name-recreates-every-container-in-the-mesh/00-report.md));
|
||||||
|
- a consumer assertion that is correct on a mesh being raised and fatal on one that is running
|
||||||
|
([issue 156](../04-ISSUES/156-moving-a-consumers-delivery-subject-stops-the-control-plane/00-report.md)).
|
||||||
|
|
||||||
|
The last is the one that settles it. That change was exercised on the raise path — which is what a bed
|
||||||
|
*is* — and the raise path is the only path on which the fault cannot appear. A bed raises a mesh; it
|
||||||
|
does not have a mesh that has been running for weeks, with consumers already bound, containers created
|
||||||
|
against an older roster, and an adopted machine carrying a predecessor's configuration. **The faults
|
||||||
|
that cost the most were all faults of a mesh that already exists**, and a bed is by construction a mesh
|
||||||
|
that does not.
|
||||||
|
|
||||||
|
Lab runs are also expensive in a way that changed the behaviour around them: each costs a build and
|
||||||
|
several minutes, so they were batched, and a batched test is one whose result arrives after the next
|
||||||
|
three changes were already written.
|
||||||
|
|
||||||
|
## Considered Options
|
||||||
|
|
||||||
|
**1. Build 0068 as proposed.** Rejected. It answers a question nobody is asking: the bottleneck was
|
||||||
|
never that a person had to sit at the lab, it was that a bed cannot hold the state the faults live in.
|
||||||
|
Queueing and tooling a mechanism that finds the wrong class of fault faster is not an improvement.
|
||||||
|
|
||||||
|
**2. Leave 0068 `proposed`.** Rejected, and it is why this record exists rather than nothing. A record
|
||||||
|
that contradicts current practice and sits unresolved is worse than either answer: it reads as intent
|
||||||
|
to anyone who finds it, and the practice it contradicts is written down nowhere but a handoff note.
|
||||||
|
|
||||||
|
**3. Record that the live mesh is the test bed, and supersede 0068.** Chosen.
|
||||||
|
|
||||||
|
## Decision
|
||||||
|
|
||||||
|
**A change is verified against the mesh that is running.** Not because a bed would be unwelcome, but
|
||||||
|
because the state that breaks things is state a bed does not have: containers made against an older
|
||||||
|
roster, consumers already bound, an adopted machine, a store with weeks of history.
|
||||||
|
|
||||||
|
**A change that can only be exercised on the raise path is not verified.** If the only test available
|
||||||
|
raises a fresh mesh, the record says so, and says which case was therefore not covered. The words
|
||||||
|
"exercised on a fresh mesh" are a statement about coverage, not a pass.
|
||||||
|
|
||||||
|
**The lab is not retired**, and [ADR 0016](0016-the-lab.md) stands. It remains the place to raise a
|
||||||
|
mesh from bare, which is the one thing the live mesh cannot be asked to do and the one thing a bed does
|
||||||
|
better than anything else. What this record removes is the lab as the *default* answer to "is this
|
||||||
|
change good", and with it 0068's queue, tools and request protocol.
|
||||||
|
|
||||||
|
**Accuracy over a green run.** An honest failure on the live mesh beats a pass in a bed that could not
|
||||||
|
have failed — and a change that is risky on the running mesh is a reason to make the change smaller,
|
||||||
|
not a reason to test it somewhere it cannot break.
|
||||||
|
|
||||||
|
**What 0068 got right is kept as a rule, not a mechanism:** a run reads a copy that is not anybody's
|
||||||
|
working tree. Every run of the lab that mattered was pinned to a checkout rather than a worktree, and
|
||||||
|
the ones that were not produced results about code nobody had written down.
|
||||||
|
|
||||||
|
## How this is checked
|
||||||
|
|
||||||
|
- **A record that says a change was verified says on what.** Where it was a fresh mesh, it says which
|
||||||
|
case is uncovered. This is the clause that would have caught 156: its change was verified, honestly,
|
||||||
|
on the only path where it works.
|
||||||
|
- **The lab is not in the path of a merge.** No check, playbook or handoff requires a bed to have run.
|
||||||
|
- **0068 is unreachable as intent.** Its status is `superseded` and it names this record, so a reader
|
||||||
|
arriving at the queue design finds out immediately that it was not built and why.
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
- **A fault can be introduced on the machines that serve.** This is the cost, it is real, and it was
|
||||||
|
paid twice in one evening — a control plane crash-looping for half an hour, and every container on the
|
||||||
|
hub recreated five times. Both were found in minutes because they were live, and both would have
|
||||||
|
passed a bed.
|
||||||
|
- **There is no pre-merge gate beyond the repositories' own suites.** `make check` and the three hq
|
||||||
|
checks are what stands between a change and the machines, which raises what those suites are worth
|
||||||
|
and makes a test that cannot fail a genuine defect rather than an untidiness.
|
||||||
|
- **Raising a mesh from bare is now the lab's whole job**, and is exercised deliberately rather than
|
||||||
|
as a side effect of testing something else. The foundation work
|
||||||
|
([issue 146](../04-ISSUES/146-the-foundation-cannot-be-raised-on-the-bus-the-mesh-runs-on/00-report.md))
|
||||||
|
is that job, and it is also the proof that the mesh can make another of itself.
|
||||||
|
- **An agent cannot hand a run to a queue and come back**, which 0068 would have given. In practice it
|
||||||
|
watches a push and reads the machines, which is what happened anyway.
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- [ADR 0068](0068-the-lab-takes-requests.md) — superseded by this
|
||||||
|
- [ADR 0016](0016-the-lab.md) — the lab, which stands
|
||||||
|
- [issue 156](../04-ISSUES/156-moving-a-consumers-delivery-subject-stops-the-control-plane/00-report.md) — correct on the raise path, fatal on a running mesh
|
||||||
+113
@@ -0,0 +1,113 @@
|
|||||||
|
---
|
||||||
|
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
|
||||||
@@ -174,6 +174,7 @@ python3 00-META/checks/index.py fail if stale
|
|||||||
- **0108** — [A route carries the policy applied to a request, and names a secret rather than holding one](0108-a-route-carries-the-policy-applied-to-a-request.md)
|
- **0108** — [A route carries the policy applied to a request, and names a secret rather than holding one](0108-a-route-carries-the-policy-applied-to-a-request.md)
|
||||||
- **0109** — [A package registry seat is one per ecosystem, not one for all of them](0109-a-package-registry-seat-is-one-per-ecosystem.md)
|
- **0109** — [A package registry seat is one per ecosystem, not one for all of them](0109-a-package-registry-seat-is-one-per-ecosystem.md)
|
||||||
- **0126** — [A module declares its own seats; the mesh reserves its own](0126-a-module-declares-its-own-seats.md)
|
- **0126** — [A module declares its own seats; the mesh reserves its own](0126-a-module-declares-its-own-seats.md)
|
||||||
|
- **0148** — [The mesh's names are resolved, not copied into every container](0148-the-meshs-names-are-resolved-not-copied-into-containers.md)
|
||||||
|
|
||||||
### What runs on them, and how it gets there
|
### What runs on them, and how it gets there
|
||||||
|
|
||||||
@@ -208,7 +209,7 @@ python3 00-META/checks/index.py fail if stale
|
|||||||
- **0110** — [A seat is held by one assignment, from a closed set, and it may deliver a provision](0110-a-seat-is-a-module-assignment-from-a-closed-set.md)
|
- **0110** — [A seat is held by one assignment, from a closed set, and it may deliver a provision](0110-a-seat-is-a-module-assignment-from-a-closed-set.md)
|
||||||
- **0112** — [A module definition names no node, no mesh and no path: everything it needs is a requirement the mesh resolves](0112-a-module-definition-names-no-node-mesh-or-path.md)
|
- **0112** — [A module definition names no node, no mesh and no path: everything it needs is a requirement the mesh resolves](0112-a-module-definition-names-no-node-mesh-or-path.md)
|
||||||
- **0113** — [The vault makes every shared secret, a provider makes resources and data, and the mesh carries both](0113-the-vault-makes-every-secret.md)
|
- **0113** — [The vault makes every shared secret, a provider makes resources and data, and the mesh carries both](0113-the-vault-makes-every-secret.md)
|
||||||
- **0114** — [A credential two parties hold rotates over two credentials; one a single party holds rotates in place, staged; and retiring a credential never removes what it reached](0114-a-shared-credential-rotates-over-two-credentials.md) *(proposed)*
|
- **0114** — [A credential two parties hold rotates over two credentials; one a single party holds rotates in place, staged; and retiring a credential never removes what it reached](0114-a-shared-credential-rotates-over-two-credentials.md)
|
||||||
- **0115** — [One assignment of a module per node: the module's name is the assignment's identity](0115-one-assignment-of-a-module-per-node.md)
|
- **0115** — [One assignment of a module per node: the module's name is the assignment's identity](0115-one-assignment-of-a-module-per-node.md)
|
||||||
- **0117** — [A machine's uplink is a seat: the mesh configures the manager, never the link](0117-a-machines-uplink-is-a-seat.md)
|
- **0117** — [A machine's uplink is a seat: the mesh configures the manager, never the link](0117-a-machines-uplink-is-a-seat.md)
|
||||||
- **0118** — [Undeclaring removes what the mesh made, and gives a unit back the state it was found in](0118-undeclaring-gives-a-unit-back-the-state-it-was-found-in.md)
|
- **0118** — [Undeclaring removes what the mesh made, and gives a unit back the state it was found in](0118-undeclaring-gives-a-unit-back-the-state-it-was-found-in.md)
|
||||||
@@ -228,6 +229,7 @@ python3 00-META/checks/index.py fail if stale
|
|||||||
- **0145** — [A module checks what the mesh claims is reachable, and it checks itself](0145-a-module-checks-what-the-mesh-claims-is-reachable.md) *(superseded)*
|
- **0145** — [A module checks what the mesh claims is reachable, and it checks itself](0145-a-module-checks-what-the-mesh-claims-is-reachable.md) *(superseded)*
|
||||||
- **0146** — [Connectivity is checked by name, per hosting form, with a valid certificate](0146-connectivity-is-checked-by-name-per-hosting-form.md)
|
- **0146** — [Connectivity is checked by name, per hosting form, with a valid certificate](0146-connectivity-is-checked-by-name-per-hosting-form.md)
|
||||||
- **0147** — [A module anchors the mesh's authority on a machine, and takes it away again](0147-a-module-anchors-the-meshs-authority.md)
|
- **0147** — [A module anchors the mesh's authority on a machine, and takes it away again](0147-a-module-anchors-the-meshs-authority.md)
|
||||||
|
- **0150** — [A module's own code runs as supervised processes under the module's one account](0150-a-modules-own-code-runs-as-supervised-processes-under-one-account.md)
|
||||||
|
|
||||||
### How it is built
|
### How it is built
|
||||||
|
|
||||||
@@ -239,7 +241,7 @@ python3 00-META/checks/index.py fail if stale
|
|||||||
- **0016** — [The lab](0016-the-lab.md)
|
- **0016** — [The lab](0016-the-lab.md)
|
||||||
- **0037** — [Where a module lives](0037-where-a-module-lives.md)
|
- **0037** — [Where a module lives](0037-where-a-module-lives.md)
|
||||||
- **0039** — [What the SDK holds, and what it refuses](0039-what-the-sdk-holds-and-refuses.md)
|
- **0039** — [What the SDK holds, and what it refuses](0039-what-the-sdk-holds-and-refuses.md)
|
||||||
- **0068** — [The lab takes requests, one at a time, and runs each from its own copy](0068-the-lab-takes-requests.md) *(proposed)*
|
- **0068** — [The lab takes requests, one at a time, and runs each from its own copy](0068-the-lab-takes-requests.md) *(superseded)*
|
||||||
- **0069** — [A module is a repository and a path within it](0069-a-module-is-a-repository-and-a-path.md)
|
- **0069** — [A module is a repository and a path within it](0069-a-module-is-a-repository-and-a-path.md)
|
||||||
- **0076** — [The SDK is a published package, and the toolchain resolves it by version](0076-the-sdk-is-a-published-package.md)
|
- **0076** — [The SDK is a published package, and the toolchain resolves it by version](0076-the-sdk-is-a-published-package.md)
|
||||||
- **0082** — [The registry is reached by name, and the overlay is its security](0082-the-registry-is-reached-by-name-and-trusted-by-the-overlay.md)
|
- **0082** — [The registry is reached by name, and the overlay is its security](0082-the-registry-is-reached-by-name-and-trusted-by-the-overlay.md)
|
||||||
@@ -248,6 +250,7 @@ python3 00-META/checks/index.py fail if stale
|
|||||||
- **0097** — [A vendor image is a declared build input, and a recipe fetches nothing undeclared](0097-a-vendor-image-is-a-declared-build-input.md)
|
- **0097** — [A vendor image is a declared build input, and a recipe fetches nothing undeclared](0097-a-vendor-image-is-a-declared-build-input.md)
|
||||||
- **0107** — [Persistent data is a directory bind, never a named volume](0107-persistent-data-is-a-directory-bind-never-a-named-volume.md)
|
- **0107** — [Persistent data is a directory bind, never a named volume](0107-persistent-data-is-a-directory-bind-never-a-named-volume.md)
|
||||||
- **0111** — [A build source is on the mesh's git seat, or it is an external repository](0111-a-build-source-is-on-the-git-seat-or-external.md)
|
- **0111** — [A build source is on the mesh's git seat, or it is an external repository](0111-a-build-source-is-on-the-git-seat-or-external.md)
|
||||||
|
- **0149** — [The live mesh is the test bed](0149-the-live-mesh-is-the-test-bed.md)
|
||||||
|
|
||||||
### How it is checked
|
### How it is checked
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,9 @@ code:
|
|||||||
- mesh-controller internal/identity/authority.go
|
- mesh-controller internal/identity/authority.go
|
||||||
- mesh-host internal/identity/serving.go
|
- mesh-host internal/identity/serving.go
|
||||||
- mesh-host internal/apply (the service that reflects a rule set)
|
- mesh-host internal/apply (the service that reflects a rule set)
|
||||||
updated: 2026-09-29
|
updated: 2026-09-30
|
||||||
decisions:
|
decisions:
|
||||||
|
- 02-DECISIONS/0148-the-meshs-names-are-resolved-not-copied-into-containers.md
|
||||||
- 02-DECISIONS/0147-a-module-anchors-the-meshs-authority.md
|
- 02-DECISIONS/0147-a-module-anchors-the-meshs-authority.md
|
||||||
- 02-DECISIONS/0138-an-assignment-binds-an-endpoint-and-says-how-far-it-reaches.md
|
- 02-DECISIONS/0138-an-assignment-binds-an-endpoint-and-says-how-far-it-reaches.md
|
||||||
- 02-DECISIONS/0140-the-filter-constrains-what-arrives-from-outside.md
|
- 02-DECISIONS/0140-the-filter-constrains-what-arrives-from-outside.md
|
||||||
@@ -289,6 +290,30 @@ hosts file by the runtime. That extends the file decision rather than overturnin
|
|||||||
mesh and not chosen by a module: a module that listed the machines would go stale the day one
|
mesh and not chosen by a module: a module that listed the machines would go stale the day one
|
||||||
joins, and a module that did not would be one whose containers cannot reach anything by name.
|
joins, and a module that did not would be one whose containers cannot reach anything by name.
|
||||||
|
|
||||||
|
**Superseded for containers by [ADR 0148](../../02-DECISIONS/0148-the-meshs-names-are-resolved-not-copied-into-containers.md)
|
||||||
|
(2026-09-30).** Everything above still describes the machine's own roster file, which is how it works
|
||||||
|
and how it will keep working. It no longer describes containers.
|
||||||
|
|
||||||
|
Copying the roster into each container made the roster part of each container's identity, so one name
|
||||||
|
moving replaced every container in the mesh — a module assigned on one machine restarted the store, the
|
||||||
|
registry, the edge and mail on another
|
||||||
|
([issue 151](../../04-ISSUES/151-a-new-name-recreates-every-container-in-the-mesh/00-report.md)). And it
|
||||||
|
did not stop the staleness it was meant to: a copy taken at creation is stale the moment the roster
|
||||||
|
moves, twice found as a container holding an address that had not existed for days
|
||||||
|
([issues 109](../../04-ISSUES/109-a-container-keeps-the-address-it-was-made-with/00-report.md)
|
||||||
|
and [135](../../04-ISSUES/135-a-containers-mesh-names-are-not-compared/00-report.md)).
|
||||||
|
|
||||||
|
**A container resolves the mesh's names through its machine's resolver, at the moment it asks, and
|
||||||
|
nothing is copied.** The resolver is a machine-level process rather than a container, so nothing
|
||||||
|
circular is being asked for. This is gated on a container being able to reach the resolver from any of
|
||||||
|
the runtime's networks, which it cannot today
|
||||||
|
([issue 110](../../04-ISSUES/110-a-container-on-the-runtimes-own-network-cannot-reach-the-resolver/00-report.md)) —
|
||||||
|
until that lands the mesh keeps copying and keeps comparing, and the order is stated in the record.
|
||||||
|
|
||||||
|
The paragraph below states the old boundary, and 0148 deliberately gives it up: a container somebody
|
||||||
|
started by hand resolves the same names as everything else, because the resolver answers the machine,
|
||||||
|
not a list of containers.
|
||||||
|
|
||||||
**The boundary, which is deliberate and worth stating:** *declared* containers. A container
|
**The boundary, which is deliberate and worth stating:** *declared* containers. A container
|
||||||
somebody starts by hand is not the mesh's to configure, and reaching into every container on a
|
somebody starts by hand is not the mesh's to configure, and reaching into every container on a
|
||||||
machine — declared or not — is what a nameserver in `resolv.conf` would be for.
|
machine — declared or not — is what a nameserver in `resolv.conf` would be for.
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ code:
|
|||||||
- mesh-catalog modules/builder
|
- mesh-catalog modules/builder
|
||||||
updated: 2026-09-29
|
updated: 2026-09-29
|
||||||
decisions:
|
decisions:
|
||||||
|
- 02-DECISIONS/0150-a-modules-own-code-runs-as-supervised-processes-under-one-account.md
|
||||||
- 02-DECISIONS/0142-the-mesh-delivers-its-own-components-as-binaries.md
|
- 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/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/0097-a-vendor-image-is-a-declared-build-input.md
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ code:
|
|||||||
- mesh-sdk src
|
- mesh-sdk src
|
||||||
updated: 2026-09-21
|
updated: 2026-09-21
|
||||||
decisions:
|
decisions:
|
||||||
|
- 02-DECISIONS/0150-a-modules-own-code-runs-as-supervised-processes-under-one-account.md
|
||||||
- 02-DECISIONS/0099-a-step-that-runs-once-names-what-it-reads.md
|
- 02-DECISIONS/0099-a-step-that-runs-once-names-what-it-reads.md
|
||||||
- 02-DECISIONS/0053-a-step-that-runs-on-a-schedule.md
|
- 02-DECISIONS/0053-a-step-that-runs-on-a-schedule.md
|
||||||
- 02-DECISIONS/0074-the-wire-is-specified-not-the-types.md
|
- 02-DECISIONS/0074-the-wire-is-specified-not-the-types.md
|
||||||
|
|||||||
+16
@@ -51,3 +51,19 @@ knows that is what the rule means.
|
|||||||
the runtime's default one? That is a stronger rule and would have prevented 109 as well.
|
the runtime's default one? That is a stronger rule and would have prevented 109 as well.
|
||||||
- What checks it? A converged bed with a container on the default network resolving a mesh name is
|
- What checks it? A converged bed with a container on the default network resolving a mesh name is
|
||||||
the missing assertion; nothing in the resolver's own beds covers the filter.
|
the missing assertion; nothing in the resolver's own beds covers the filter.
|
||||||
|
|
||||||
|
## What now depends on this (2026-09-30)
|
||||||
|
|
||||||
|
This stopped being a container-DNS inconvenience.
|
||||||
|
[ADR 0148](../../02-DECISIONS/0148-the-meshs-names-are-resolved-not-copied-into-containers.md) decides
|
||||||
|
that a container resolves the mesh's names rather than being given a copy of them, which is what stops
|
||||||
|
one name moving from replacing every container in the mesh
|
||||||
|
([issue 151](../151-a-new-name-recreates-every-container-in-the-mesh/00-report.md)) and what makes a
|
||||||
|
stale address impossible rather than merely noticed
|
||||||
|
([issues 109](../109-a-container-keeps-the-address-it-was-made-with/00-report.md)
|
||||||
|
and [135](../135-a-containers-mesh-names-are-not-compared/00-report.md)).
|
||||||
|
|
||||||
|
**That decision cannot land until this one does**, and not partly: a container on the runtime's default
|
||||||
|
network is the case with no DNS at all, and it is the case the mesh's own forge runs in. Two of four
|
||||||
|
machines also bind the resolver to loopback only, so the runtime hands their containers a public
|
||||||
|
resolver. Both halves are this issue.
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
---
|
---
|
||||||
status: located
|
status: resolved
|
||||||
opened: 2026-09-25
|
opened: 2026-09-25
|
||||||
located-in: [hq, mesh-catalog modules/showcase, mesh-sdk src/tools/index.ts, mesh-tools]
|
located-in: [hq, mesh-catalog modules/showcase, mesh-sdk src/tools/index.ts, mesh-tools]
|
||||||
fixed-by:
|
fixed-by: hq 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:
|
amended-design:
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -99,3 +99,27 @@ what the sidecar is has nowhere in the design layer to look, which is how this w
|
|||||||
is mechanically checkable: the resource types a design doc names are a closed set, and every
|
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
|
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.
|
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.
|
||||||
|
|||||||
@@ -75,3 +75,20 @@ the list. 152 removed the false reasons; the question below is still open.
|
|||||||
Keep 135's guarantee (no container runs with a stale address) without making the roster part of every
|
Keep 135's guarantee (no container runs with a stale address) without making the roster part of every
|
||||||
container's identity — e.g. resolve mesh names through a resolver the container asks at lookup time
|
container's identity — e.g. resolve mesh names through a resolver the container asks at lookup time
|
||||||
rather than baked entries, or scope each container's entries to the names it actually binds.
|
rather than baked entries, or scope each container's entries to the names it actually binds.
|
||||||
|
|
||||||
|
## Answered (2026-09-30): the first of those two
|
||||||
|
|
||||||
|
[ADR 0148](../../02-DECISIONS/0148-the-meshs-names-are-resolved-not-copied-into-containers.md) takes
|
||||||
|
the resolver, not the scoping. Scoping was the close call and was rejected for contradicting the
|
||||||
|
standing intent that anything on the mesh can call anything on it: it would make a name reachable only
|
||||||
|
where the mesh was told in advance it would be wanted, and it would leave the roster in the digest, so
|
||||||
|
the churn returns whenever a widely-bound name moves.
|
||||||
|
|
||||||
|
Resolving at lookup time makes staleness impossible rather than detected — 109 and 135 stop being bugs
|
||||||
|
that were fixed and become a shape that does not exist — and makes a name's blast radius nothing.
|
||||||
|
|
||||||
|
**This record stays open**, because the record answers it and the code does not. Nothing may stop
|
||||||
|
copying names until a container can reach the resolver from any of the runtime's networks
|
||||||
|
([issue 110](../110-a-container-on-the-runtimes-own-network-cannot-reach-the-resolver/00-report.md)),
|
||||||
|
which it cannot on two of four machines today. Removing the copy first reintroduces 109 and 135
|
||||||
|
silently, on a live mesh, which is how both were found. The order is in the record.
|
||||||
|
|||||||
Reference in New Issue
Block a user