Every configurable thing on a node is a module, the home included, and a module is whatever it declares (0173, extending 0040). A node varies a module only through a setting rendered into the file or a kept region, never an edit (0174, extending 0011; issue 168 first). One tool runtime per node serves every module's tools on the host side, never in a container; the console is its serving mode, renamed node-tools (0175, extending 0150; 0047/0150/0152 carry dated notes). The login shell is a node seat held by one shell module with `execute` as its contract (0176). A unit may be user-scoped and the service manager is a node seat held by systemd (0177). To-be 37 is handed off in-progress to mesh-host, mesh-controller, mesh-tools and mesh-catalog, with the build in order: the account on every node, the runtime, zsh, systemd, then the graphical stack. To-be 29 keeps ~/.ssh and points at 37; 33 §6 and 34 are amended; the glossary gains node tools, bundle, kept region, installed/holding, and retires flavor.
5.3 KiB
topic, status, date, deciders, reconstructed, extends
| topic | status | date | deciders | reconstructed | extends |
|---|---|---|---|---|---|
| building it | accepted | 2026-10-02 | jochen | false | 02-DECISIONS/0011-managed-files-are-generated-never-edited.md |
174. A node varies a module through settings and kept regions, never through an edit
Context
ADR 0011 says a managed file is derived and an
edit to it is overwritten without warning. The predecessor said the same and then undid it twice:
a merge strategy that adopted disk drift back into its database, so a local edit became the
record; and a theming layer of about 90 environment variables substituted into templates at sync
time, with tools to list and set them, so that nearly every value was a variable — a second
configuration language laid over the first.
The operator wants both the variation and the rule. One window-manager module with one default
configuration, and each node tweaking it; and the file carrying the wanted value rather than a
variable the file reads. Two mechanisms already exist for exactly this: a setting, declared by
the module and set per mesh or per node, rendered at composition
(${setting:…} is live in the resolver's manifest); and a kept region, a block in a file the
mesh writes into where the operator's own lines survive every push
(ADR 0102, used by the ssh-client module
for the operator's own Host blocks).
What stands in the way is issue 168: a setting today reaches every mergeable file and every contribution of its module. Ninety theme knobs on that mechanism would reach ninety files. The record that fixes it — a setting declared with its type, meaning, default and the file it lands in — is proposed in an open change alongside the container-runtime records.
Considered Options
- Carry the predecessor's merge strategy. A local edit is adopted into the node's layer.
Rejected: two writers and no arbiter, which is the option 0011 removed, and the reason a
/modelchoice was silently reverted on every node for weeks before anyone found the cause. - Carry the environment-variable theming. Rejected by the operator: the value belongs in the file; a variable the file reads is a second place for the same fact.
- A per-node file override — a whole file replaced for one node. Rejected: it is a flavor under another name, and a module update then misses that node entirely.
- Settings rendered into the file, and kept regions, and nothing else. Chosen.
Decision
A node varies a module in exactly two ways.
- A setting. Declared by the module with a default, set for the mesh or for one node, rendered into the file at composition. The value is in the file. Asked, the mesh lists every setting with its effective value and where it came from.
- A kept region. A marked block in a file the mesh writes into, in which the operator's own lines are kept across every push and given back when the module goes (ADR 0102).
An edit outside a kept region is overwritten, as ADR 0011 says, and never adopted. Nothing reads a managed file back into the record.
The predecessor's theme knobs become settings of the modules whose files they render — the window manager's colours are the window manager's settings, the bar's are the bar's — each landing in the file that reads it and no other.
Issue 168 is fixed before any environment module declares a setting. A setting must name the file it lands in; until that ships, the environment modules carry their defaults in their files and no settings.
Consequences
- No flavors, no per-node file copies, no environment layer. A module's definition is one set of files; a node's difference is data in its layer, visible by asking.
- The settings record proposed alongside the container-runtime records is on the critical path of every module with a knob, and this record depends on it shipping as proposed.
- A kept region is the only place a person edits a managed file, and the file says where it is. The operator's own prompt customisations, aliases and window rules live there.
- What got harder: a change that is neither a setting the module declared nor the operator's own lines has no home, and is refused by the mechanism rather than silently kept. That is the point.
How it is checked
| Rule | Checked by |
|---|---|
| A setting reaches only the file its declaration names | the controller's settings tests, once the proposed record ships; issue 168 closes on it |
| A kept region survives a push with its content and is given back on undeclare | the host's write-into tests (ADR 0102), with a region declared by an environment module |
| An edit outside a region does not survive a push | the same tests, asserting the file equals the composed content outside the region |
| Every effective value names its source | mesh-controller.settings and the module's own show-config tool |
References
- Research 018 §"One default, varied by settings, never by edits"
- ADR 0011, ADR 0102, issue 168