0034: a test defends a decision. §5 carried it marked "proposed, pending review"; the marker is removed and the rule now stands unqualified. The lab was already built to it, which is the inversion §5 exists to catch — closed now rather than left standing. 0018: the mesh creates no symlinks. §3 said the installer owns the links today and the INTENT was that the mesh creates none. It is no longer an intent, so the wording says so, and ADR 0011 becomes superseded rather than edited — its reasoning is why the rule exists at all, and the incident behind it is the reason anyone believes either record. The links the installer still reconciles are a migration, not a permission. The constitution sync (§6 step 4, playbook 05) is NOT done. An unsynced rule is a rule the mesh does not enforce, whatever this document says — and publishing it changes what every design meeting is checked against, so it wants saying out loud rather than doing quietly.
61 lines
2.9 KiB
Markdown
61 lines
2.9 KiB
Markdown
---
|
|
status: superseded
|
|
superseded-by: 02-DECISIONS/0018-the-mesh-creates-no-symlinks.md
|
|
date: 2026-07-10
|
|
deciders: jochen
|
|
reconstructed: true
|
|
---
|
|
|
|
# 11. The installer owns linking; nothing else creates a symlink
|
|
|
|
> Reconstructed after the fact from the evidence cited below. The incident that earned the rule
|
|
> predates the record, and its date is not established here.
|
|
|
|
## Context
|
|
|
|
A service's definition lives in the module catalogue; its runtime directory and persistent data
|
|
live outside it. The mesh connects the two by linking the definition into the runtime location
|
|
— deliberately, so that runtime state and source stay separate while the running service reads
|
|
a current definition.
|
|
|
|
A link is also the easiest thing in the world to create by hand while fixing something, and a
|
|
container engine resolves a bind mount through it. A hand-made link pointed a volume somewhere
|
|
it should not have, and **production data was lost**.
|
|
|
|
## Considered options
|
|
|
|
1. **Copy instead of linking.** Rejected. A copy goes stale silently, which trades data loss
|
|
for a service running a definition nobody can find.
|
|
2. **Allow links, document the hazard.** Rejected. The hazard is not knowable at the moment of
|
|
the mistake — the link looks right and the resolution happens inside the container engine.
|
|
3. **One component owns linking; everyone else is forbidden.** Chosen.
|
|
|
|
## Decision
|
|
|
|
The installer creates and repairs every link the mesh needs. It reconciles them: a missing
|
|
link is created, a stale one is repointed, and a real file found where a link belongs is
|
|
adopted into the node's override location and replaced.
|
|
|
|
**Nothing else creates a symlink** — not a hook, not a fix, not an agent, not a person
|
|
debugging. The prohibition is absolute because the judgement required to make a safe exception
|
|
is exactly the judgement that was not available at the moment it mattered.
|
|
|
|
## Consequences
|
|
|
|
- The class of failure is closed, at the cost of a rule that reads as arbitrary to anyone who
|
|
has not seen the incident. That is why it is recorded here rather than only asserted.
|
|
- Links become reconcilable state rather than incidental filesystem facts.
|
|
- The rule is stated for humans and agents and is enforced by convention, not mechanism. A
|
|
check does not exist.
|
|
- The rule as written governs the mechanism rather than removing it. A link made by the
|
|
installer resolves the same way as one made by hand, so the hazard is narrowed and not
|
|
closed. [ADR 0018](0018-the-mesh-creates-no-symlinks.md) proposes widening this to "nothing
|
|
links, the installer included"; until that is accepted, this record governs.
|
|
|
|
## References
|
|
|
|
- Recorded as a non-negotiable in the governed constitution page, §2: *"Symlinks to repos or
|
|
service directories have caused production data loss via Docker volume path resolution. The
|
|
installer handles all linking. Never create symlinks manually."*
|
|
- Knowledge base: `services` — the reconciliation behaviour, including adoption of real files.
|