- Secrets follow ADR 0085 as amended: a module's own secret is a provision the controller mints and the vault records. The previous commit had that backwards. Whether the vault should generate instead is recorded as an open question, not decided. - A directory's contract is owner and mode only. The persistence flag was the keep flag ADR 0030 refused; a directory is kept while it holds anything, and disposable data is a named volume (0107). - An operator's shared data stays an access (ADR 0051), which rejected an operator-owned directory. Only where its path is written moves to the assignment. - The records it changes on acceptance are named: 0051, 0091, 0046 (settings keyed by instance), 0084 (a provider is a node and an instance), and the glossary, which gains its new words only when the record is accepted. - How it is checked covers every stated rule. Container-side paths are no longer flagged by the host-path rule, and code fallbacks are covered. - Provisions are what other modules provide. A seat's occupant is not listed as one, and the vault is not described as selectable per assignment. - 'Control plane' becomes 'controller'. The provider count is ten of eleven, not eleven of twelve.
80 lines
3.9 KiB
Markdown
80 lines
3.9 KiB
Markdown
---
|
|
status: open
|
|
opened: 2026-09-25
|
|
located-in: []
|
|
fixed-by:
|
|
amended-design:
|
|
---
|
|
|
|
# 118 — A module definition decides where its files live on the machine
|
|
|
|
## What was observed
|
|
|
|
A review of where module code reads its files turned up a cross-cutting pattern. Every module
|
|
definition in the catalogue chooses, in its own manifest, where on the machine its files live.
|
|
Counted on the catalogue's `main`, 2026-09-25:
|
|
|
|
| where in the definition | host-path strings |
|
|
|---|---|
|
|
| directory and file resources | 257 |
|
|
| container mounts, host side | 230 |
|
|
| own secrets | 78 |
|
|
| bindings | 53 |
|
|
| env-files | 50 |
|
|
| secrets | 35 |
|
|
| container environment | 28 |
|
|
| accesses | 21 |
|
|
| receives, grants | 24 |
|
|
| everything else | 13 |
|
|
|
|
**789 host-path strings in 70 of the 71 definitions.** Mounts are checked: a container may not
|
|
mount a path its module never declared ([ADR 0091](../../02-DECISIONS/0091-a-mount-is-declared-three-ways.md)).
|
|
Nothing checks the same path where it is retyped as a value: an environment variable, an env-file
|
|
line, a literal in module code.
|
|
|
|
### Where that has already gone wrong
|
|
|
|
- **A provider that would provision nobody, silently.** One DNS provider mounts its grants
|
|
directory at a short path inside its container, then tells its provisioner to read the
|
|
contributions file at the host path, which does not exist in there. Nothing requires the
|
|
provision today, so it has not failed yet. When a consumer arrives, it will get no record, and
|
|
nobody will be told.
|
|
- **The mesh's own wire carries host paths into containers.** Each contribution names its
|
|
consumer's credential as "the file on this machine holding that consumer's credential", a host
|
|
path computed from the provider's grants directory. So every provider has to mount that directory
|
|
at the *identical* path, or it cannot read what it was given. Ten of the eleven providers with a
|
|
grants directory do. It is a convention nothing states or checks, and the eleventh is the
|
|
provider above.
|
|
- **The warning that would have caught it is lost in the SDK.** The controller always writes the
|
|
contributions file, even when empty, so a provider can tell "nothing asked" from "never written".
|
|
The SDK's reconcile loop treats an unreadable file as empty, and logs nothing.
|
|
- **Code carries copies with nothing checking them.** Several modules default a path in code when an
|
|
environment variable is unset. Five of those defaults disagree with the value their own manifest
|
|
sets. One of them is a host path used inside a container that does not mount it.
|
|
|
|
### And a module cannot be assigned to one node twice
|
|
|
|
Everything that identifies a running module is keyed by the module's name: its directories, its
|
|
container names, the login it presents to a provider, its broker account. Two assignments of one
|
|
module to one node would share every one of them. Assigning the same application twice is an
|
|
ordinary need: production beside staging, one site per customer, two instances of one service
|
|
configured differently, two stores of one engine.
|
|
|
|
## Why it matters beyond this instance
|
|
|
|
A definition that names machine paths is not portable between nodes. It cannot follow data onto a
|
|
second disk, or onto a machine being adopted with its data already in place, without editing the
|
|
module. It cannot run twice on one node. It keeps every path in two or three places with nothing
|
|
checking that they agree. The defects above are what that allows, and each was found by reading,
|
|
not by any check.
|
|
|
|
## Open questions
|
|
|
|
- Should a definition name any host path at all, or should every location come from the
|
|
assignment and the mesh?
|
|
- If a directory is something a module *requires* rather than *declares*, what is its contract:
|
|
ownership, mode, whether it is kept when the module goes?
|
|
- What identifies an assignment, if a module may be assigned to one node more than once?
|
|
- What would the contributions file carry instead of host paths, so a provider needs no
|
|
identical-path mount?
|