Issue 009 — settings change does not restart a container-hosted runtime

Found rolling the runtime out to the catalogue: a module's runtime reads its
settings-merged config file once at start, but a container is only recreated on a
spec change, and file content is not part of the spec. So updating settings
re-renders the file and nothing re-reads it — ADR 0051's "on the fly" holds only
for config set before first start. Services have restart-on; containers do not.

Claude-Session: https://claude.ai/code/session_01LrgweAeERJYBg88c5cKDzF
This commit is contained in:
2026-09-04 23:06:48 +02:00
parent d1aa4254c9
commit 47b0ca5c90
@@ -0,0 +1,67 @@
---
status: open
opened: 2026-09-04
located-in: []
fixed-by:
amended-design:
---
# Changing a module's settings does not restart its runtime — config is stale until recreated
## What was observed
Rolling the module runtime out to the catalogue (the runtime that serves a module's tools and
runs its events under the module's own account), each tools+events module receives its
configuration the way the design intends: a mergeable config file the module declares, into
which the assignment's settings are merged. The runtime container mounts that file and reads
it once at start-up, when it builds its API client.
The design for settings says a config file a module owns can be changed **without editing
it** — a person states an intention, the file is regenerated, and the change takes effect.
The decision that config is the assignment's, not the manifest's, is explicitly so that
configuration can be updated *on the fly* and managed from a dashboard.
For a runtime delivered as a **container**, that last part does not hold. When settings
change, the control plane re-renders the config file on the node — but the runtime container
is only ever recreated when its **spec** changes, and the spec is image, name, env, ports,
volumes and args. The *content* of a mounted file is not part of it. So the file on disk
updates and the process that already read it keeps the value it read at start-up. The new
configuration does not take effect until something changes the container's spec, or it is
recreated by hand.
A **service** resource has `restart-on`, which names the resources whose change forces a
restart — exactly this problem, already solved, for units. A **container** resource has no
equivalent field, and the apply path for containers never consults the set of resources that
changed this pass. So the one kind of resource that hosts a module's runtime is the kind that
cannot say "restart me when my config changes."
The effect is quiet, which is the worst part: setting a value appears to succeed (the file is
correct on disk), and the running tools keep answering with the old configuration, or keep
failing to load because the value that would fix them is present but unread.
## Why it matters beyond this instance
Every tools+events module converted to the runtime model now takes its URL and credentials
this way, so this is not one module's quirk — it is the config path for the whole catalogue.
The gap turns the headline promise of the settings design ("change it without editing it, on
the fly") into "change it, then recreate the container by hand," which is the manual step the
design existed to remove. And because the file is genuinely updated, nothing surfaces the
staleness; a dashboard that set the value would report success while the mesh kept doing the
old thing.
Config set **before** the runtime first starts (settings, then assign, then push) does work —
the file is right when the process reads it. So the gap is specifically about *updates* to an
already-running runtime, which is precisely the case the "on the fly" promise is about.
## Open questions
- Should a `container` gain `restart-on`, mirroring the service field, so a module can point
it at its config resource?
- Or should the apply path recreate a container when a file it mounts changed this pass —
making mounted-file content behave like part of the spec, without a new field to declare?
- Should the config file's content (or a hash of it) fold into the container spec, so an
ordinary spec-diff already catches it? That restarts on every change with no new mechanism,
at the cost of a spec that is no longer only the container's own declaration.
- Is a restart even the right primitive for a runtime that could instead watch its config
file and rebuild its clients in place — and if so, is that each module's job or the
runtime host's?