Place the two new records in the reading order, and fix a link the merge moved

Both carried a topic outside the six the index knows, so neither had a place to
be read in — 0067 had none at all. Both are 'the tiers', beside 0036 (bootstrap
ends at a usable mesh) and 0007 (connectivity), which is what they extend.

0067 cited 0041 for tier 0's property; on this trunk 0041 is events, and the
record it meant is 0005. A citation that resolves to the wrong record reads as
corroboration, which is worse than a dead link.

Claude-Session: https://claude.ai/code/session_01LrgweAeERJYBg88c5cKDzF
This commit is contained in:
2026-09-11 00:48:20 +02:00
parent 56d0dcc4ff
commit 423fde8534
4 changed files with 71 additions and 3 deletions
@@ -1,5 +1,5 @@
---
topic: routing and names
topic: the tiers
status: proposed
date: 2026-09-09
deciders: jochen
+4 -2
View File
@@ -1,4 +1,5 @@
---
topic: the tiers
status: proposed
date: 2026-09-10
deciders: jochen
@@ -121,7 +122,8 @@ machine auditable. An installer connects to plenty. Same tier, same delivery, di
- [ADR 0006 — the substrate and the control plane](0006-the-substrate-and-the-control-plane.md),
which pinned images by digest and named what a first node fetches.
- [ADR 0041 — the host depends on nothing that must be installed first](0041-the-host-depends-on-nothing.md),
the tier 0 property this keeps true by not putting the installer inside the host.
- [ADR 0005 — the node host](0005-the-node-host.md), which makes tier 0 the one thing installed by
hand and the only thing that changes a machine — the property this keeps true by shipping the
installer beside the host rather than inside it.
- [`04-ISSUES/029`](../04-ISSUES/029-the-artifact-store-cannot-be-delivered-by-the-artifact-store/00-report.md),
the same cycle one layer down, and the rule that a registry module is named and never built.
+8
View File
@@ -98,6 +98,8 @@ python3 00-META/checks/index.py fail if stale
- **0031** — [The control plane authenticates nobody, so identity is a module](0031-the-control-plane-authenticates-nobody.md)
- **0033** — [The substrate is a store and a broker](0033-the-substrate-is-a-store-and-a-broker.md)
- **0036** — [Bootstrap ends at a usable mesh, and the first credential comes from a person](0036-bootstrap-ends-at-a-usable-mesh.md)
- **0066** — [Public routing is name-agnostic, its names are resolved inside the mesh, and an internal authority can certify them](0066-public-routing-is-name-agnostic.md) *(proposed)*
- **0067** — [Genesis is a pivot: a temporary control plane installs the registry that makes it permanent](0067-genesis-is-a-pivot.md) *(proposed)*
### What runs on them, and how it gets there
@@ -121,6 +123,7 @@ python3 00-META/checks/index.py fail if stale
- **0050** — [Model access is vendor-agnostic, and a vendor is an adapter](0050-model-access-is-vendor-agnostic.md)
- **0051** — [Shared data is the operator's, and a module is granted access to it](0051-shared-data-is-the-operators.md)
- **0052** — [An init step is a container run once to completion, gating what follows](0052-a-step-that-runs-once-before-a-container.md)
- **0053** — [A scheduled step is a container run on a recurring schedule](0053-a-step-that-runs-on-a-schedule.md)
### How it is built
@@ -149,4 +152,9 @@ python3 00-META/checks/index.py fail if stale
- **0032** — [The local account owns the mesh; a surface delegates to a module](0032-the-local-account-owns-the-mesh.md) *(superseded)*
- **0034** — [The local account owns the mesh, and a web application's login is not that](0034-the-local-account-owns-the-mesh.md)
### Unfiled
- **0054** — [Model usage is a vendor-neutral record, produced by the adapter, at two grains](0054-model-usage-is-recorded-at-two-grains.md) — `topic:` is 'model access', which is not one of building it, checking it, how we work, the mesh, the tiers, what runs on it
- **0055** — [Model access is answered by a licence, or by a node that hosts the model](0055-model-access-is-answered-by-a-licence-or-a-node.md) — `topic:` is 'model access', which is not one of building it, checking it, how we work, the mesh, the tiers, what runs on it
<!-- index:end -->
@@ -0,0 +1,58 @@
---
status: open
opened: 2026-09-10
located-in: []
fixed-by:
amended-design:
---
# 041 — A credential the mesh took care to seal ends up in the process environment
## Symptom
The mesh generates a module's own secret, **seals it to the machine and discards the plaintext** —
it cannot read the value back even if asked. The host unseals it into a file the module names, at
`0600`.
Then the module hands it to its container as an environment variable, and the runtime puts it
where anything on that machine that can talk to the runtime can read it: `docker inspect` prints
it, and `/proc/<pid>/environ` holds it for the life of the process.
Observed while making the control plane an ordinary module. Its **store** connections were moved to
files, read by a `…_FILE` variable naming the path. Its **broker** credentials have no such variable,
so they are still delivered through an env-file — which the runtime turns into exactly the
environment above. Same credential handling, same machine, two different exposures, decided by
whether the program that reads it happens to accept a path.
## Why this matters
**The care taken elsewhere is what makes this stand out.** Sealing to a machine and discarding the
plaintext is expensive and deliberate: it exists so that a credential is readable only where it is
used. Handing that same value to the runtime as an environment variable gives it back to anything
that can run `inspect` — and `inspect` is a routine operation. It lands in support output, in
captured logs, in a screenshot of a terminal, and in any tooling that dumps container state.
**It is not a module's mistake.** Nothing in the manifest format is being misused: placing a secret
into an env-file with `${secret:…}` is a supported shape and other modules use it. So each module is
correct on its own, and the property — *a sealed credential is not readable by everything on the
machine* — holds or fails per variable, by accident of what each program accepts.
**And the two halves now disagree inside one module.** The control plane reads its store connection
from a file and its broker credential from the environment. A reader cannot tell from the manifest
which secrets are protected from `inspect` and which are not, because the manifest looks the same
either way.
## Open questions
- Should every program the mesh runs accept a path for anything secret — a `…_FILE` twin as a
convention rather than a thing each program decides? That is a small change in several programs
and a large one in what the manifest can promise.
- Should the manifest layer **refuse** `${secret:…}` inside a container's `env`, or inside an
`env-file`, once a path-shaped alternative exists? A rule nothing enforces is the shape this
repository keeps finding.
- Is there a case where the environment is genuinely the only channel — a program that cannot be
changed and reads no file? If so, what should the mesh say about that module, out loud, rather
than treating it as equivalent?
- What is the actual reach of the exposure on a node — which identities can talk to the container
runtime, and is that set smaller than "anything running as the operator"? The answer decides
whether this is a hardening item or something sharper.