diff --git a/04-ISSUES/009-runtime-config-change-does-not-restart/00-report.md b/04-ISSUES/009-runtime-config-change-does-not-restart/00-report.md new file mode 100644 index 0000000..b7089ab --- /dev/null +++ b/04-ISSUES/009-runtime-config-change-does-not-restart/00-report.md @@ -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?