An audit of the six code repositories found eleven open issues fixed on main with commits and beds to show (025, 027, 033, 036, 037, 040, 045, 047, 050, 052, 053), three partly (007, 026, 035), nine not (020, 031, 041, 046, 049, 054, 064, 065, 066) and one whose fix would live outside those repos (006). Resolved ones name their evidence; partly ones say what remains; 041 records that the exposure has widened since it was reported.
58 lines
3.5 KiB
Markdown
58 lines
3.5 KiB
Markdown
---
|
|
status: resolved
|
|
opened: 2026-09-05
|
|
located-in: [mesh-control, mesh-host, mesh-catalog]
|
|
fixed-by: ADR 0052 run-once container: mesh-host 19e5dd8, PR #5 24e9ae4; ADR 0053 scheduled twin 9d1f001; proven by mesh-lab assigned-catalogue-mqtt.test.ts
|
|
amended-design: 02-DECISIONS/0052-a-step-that-runs-once-before-a-container.md
|
|
---
|
|
|
|
# 037 — A module cannot run its own code at a lifecycle phase
|
|
|
|
## The symptom, as observed
|
|
|
|
Found while converting the catalogue (2026-09-05), across several modules at once. A module can
|
|
declare *things that exist* — a directory, a file with fixed content, a network, a container — but
|
|
it cannot declare *a step that runs* at a defined point in its own lifecycle. Three converted
|
|
modules need exactly that and have nowhere to put it:
|
|
|
|
- **mosquitto.** Its Dynamic Security plugin will not start unless `dynamic-security.json` already
|
|
contains an admin client *before the broker's first start* — the broker loads the plugin at
|
|
boot. Seeding it is a run-once step that must happen after the file resource exists and before
|
|
the container starts. The vocabulary has no "before first start."
|
|
- **The database providers (postgres/mongodb/mssql).** First-boot seeding works today only because
|
|
the *image* happens to do it from an env var. Anything the mesh itself must run once against the
|
|
server — a schema migration, an extension enable, a health gate before the module is announced
|
|
ready — has no home.
|
|
- The seed-then-mutate family already recorded in [035](../035-reconciling-a-seed-file-wipes-what-grew-in-it/00-report.md)
|
|
is the same shape seen from the *content* side; this is it seen from the *timing* side.
|
|
|
|
## Why it matters beyond the instance
|
|
|
|
This is not a defect in a module — it is a **capability the module system does not yet offer.** A
|
|
real class of modules needs to run their own code at points in the build/install/run lifecycle:
|
|
seed-before-start, migrate, post-start health-gate, pre-remove drain. The declarative resource
|
|
model deliberately describes *state*, not *steps*, and that is right for what it covers; the gap is
|
|
that some modules genuinely have a step.
|
|
|
|
**Prior art, and its warning.** An earlier mesh had exactly this as a feature: event-driven
|
|
**hooks** that ran custom code at phases of the build/publish/deploy pipeline. It was powerful and
|
|
it was **complex to set up and flaky** — which is the real content of this record. The need is not
|
|
in question; the cost of the obvious answer is. Whatever shape this takes must not reproduce that
|
|
fragility, or it will be worse than the gap.
|
|
|
|
## Open questions
|
|
|
|
- Is the right unit narrow — a **run-once / init resource** ("run this once, here, in the
|
|
lifecycle") — or general — a **per-phase lifecycle hook** on a module, and if so which phases
|
|
(build / publish / install / pre-start / post-start / pre-remove)?
|
|
- Where does a hook's code run — in the module's own runtime container under its scoped account
|
|
(ADR 0043/0047), so it inherits the same isolation as its tools and events? Or is some of it the
|
|
host's, before a container exists?
|
|
- How is a step made **idempotent and reconcilable** so a re-apply does not re-run it
|
|
destructively — the same discipline the resource model gets for free and a step does not?
|
|
- What is the smallest version that unblocks the three modules above without rebuilding the old
|
|
flaky hook engine? Is "seed-before-first-start" alone enough for now, with the general case
|
|
deferred?
|
|
- A rule states how it is checked: whatever shape is chosen, what lab scenario proves a hook runs
|
|
exactly once, at the right phase, and converges on re-apply?
|