Files
hq/04-ISSUES/119-a-module-definition-decides-where-its-files-live/00-report.md
T
jochen 6e3373c879 Design pass: address the review
0113 — the plaintext claim was false under its own mechanism: handing a provider's answer to the
controller puts every secret on the broker and in the controller in the clear. The provider now seals
each secret field itself, to the consumer node's public key the mesh hands it, and the controller
carries sealed fields it cannot open. That is stricter than today, where the controller holds every
minted credential in the clear. Option 3 (plaintext to the controller) is recorded and rejected. The
foundation exception now covers root-secret rotation (0085) and forms like the broker admin's hash, so
no phase claims to remove the broker's bootstrap step. To-be 24 and 13 are named among what it amends.

27 — resolution is consistent with 0110: co-location and the only provider apply only where no seat
delivers the provision, so an unheld seat is refused even with one provider. The secret-field rule now
matches 0086 exactly (a declared env-file, never a container environment value). The seat placeholder
is the controller's, and the one module reading it moves to a host port. Contracts are held by the
controller and written down in phase 1, so they can be checked; every rule has a check. An operator's
secret is still the operator's, with the vault as custodian. Which seats a module holds is listed as
not settled.

0110 — the unheld-seat-with-one-provider case and the one-answer-for-everyone rule have checks; the
claim about moved manifests is corrected. 26 — the table governs and the code catches up, not the
reverse; scope and capacity agree with the glossary; moving a seat is described as it really is today.
0112 — aligned with 27, and lists 0049 and 26 among what it changes.

Issue 118 is renumbered 119: another branch took 118 first. 'Control-plane' is gone from 0110 and 0111.
2026-09-25 22:46:10 +02:00

3.9 KiB

status, opened, located-in, fixed-by, amended-design
status opened located-in fixed-by amended-design
open 2026-09-25

119 — 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). 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?