The numbering is the flow: decisions are 02, design is 03
papa-hq reads 01 research -> 03 decision -> 02 design. The order is a scar, not a choice: 02-DESIGN existed from its initial commit, and when adr/ was finally promoted on 2026-07-13 it took the next free number rather than its place in the sequence. By then design was too settled to renumber. hal-hq was three commits old, so it is not. adr/ becomes 02-DECISIONS and 02-DESIGN becomes 03-DESIGN, and following the folder numbers now walks the process in the order it happens: research produces a decision, the decision authorises a design. 00-GENESIS becomes 00-META, matching papa's rename from the same restructure. Every path reference rewritten across documents, frontmatter, playbooks and skills. All links resolve; all 58 frontmatter blocks parse and their path fields still point at files that exist.
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
---
|
||||
status: accepted
|
||||
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.
|
||||
Reference in New Issue
Block a user