--- status: resolved opened: 2026-09-29 located-in: - mesh-controller internal/catalogue/dir_into.go (dirsFor: a stated path or //, nothing else) - mesh-controller (accesses: the path is the manifest's literal) fixed-by: mesh-controller PR 176 (`places` and `accesses` on an assignment, `${access:}`, an owner the data already has); mesh-catalog PR 198 (ten definitions name their accesses by id) amended-design: [03-DESIGN/01-to-be/27-a-module-requires-the-mesh-resolves.md, 03-DESIGN/01-to-be/18-building-a-module.md] --- # 153 — An adopted machine's data cannot be placed where it is ## What was observed Preparing ace's media modules (plex, sonarr, radarr, lidarr, bazarr, nzbget, qbittorrent, bookshelf) for migration. ace is adopted; its data is where the predecessor put it and **must stay there**: - the library and download spool: `/storage/media/*`, `/storage/downloads` — a separate ZFS pool, ~40 TB, the operator's shared data (ADR 0051); - plex's own state: `/mnt/plex/{config,data,temp}` — 133 GB on a second disk; - large configuration directories held in place: lidarr 46 GB, radarr 17 GB, sonarr 3.2 GB. The catalogue's manifests name `/services/media/*` (as `accesses`) and `/services//config` (as owned directories), which is novox's layout, not ace's, and not a value a definition may carry. ## What was decided, and what exists [ADR 0112](../../02-DECISIONS/0112-a-module-definition-names-no-node-mesh-or-path.md) (accepted) says exactly what is needed: > *Where* it is on the machine is the assignment's. A node has a default layout, and an assignment may > place a directory elsewhere: on a second disk, or where an adopted machine's data already is. > [ADR 0051]: an access keeps its shape and its semantics; its path moves from the definition to the > assignment. What the control plane implements (`dirsFor`): a directory is either a path the manifest states, or `//` under the node's one data root. There is **no per-assignment placement of one directory**, and an `access` path is the manifest's literal — no setting reaches either. ## Consequence Every module whose data an adopted machine already holds somewhere other than the default layout can only be migrated by (a) writing the machine's path into the manifest — which 0112 forbids and which is wrong on the next machine — or (b) moving the data into the placed layout in a window. (b) is acceptable for a 40 MB configuration and impossible for a 40 TB library the operator has ruled must never be moved, copied or re-owned. The same gap covers ownership: the predecessor runs ace's media stack as `1001:2000`; a manifest's `owner` is one value for every machine. ## What would be right The two assignment halves 0112 decided: a setting that places a declared directory (by id) at a given path on this node, and a setting that says where an access's data is — both validated like `endpoints` (unknown ids refused), and an access placed by the assignment still never created, chowned or removed. ## Resolved, 2026-10-01 The two assignment halves ADR 0112 decided exist. On an assignment's settings, `places` puts a declared directory (by id) at a path on this node, with an owner where the data already has one — `{"config": "/where/it/is", "data": {"path": "…", "owner": "1001:2000"}}` — and `accesses` says where the operator's data is, by the access's id. Both are validated the way `endpoints` is: an id the definition does not declare is refused, naming what it does declare; a relative path and a non-numeric owner are refused; an access nothing places and whose definition carries no path is refused with the setting to write, rather than mounted as nothing. A placed directory is still the mesh's — created, owned as said, removed when empty and undeclared. A placed access is still the operator's — mounted, never created, owned or removed. An access now has an **id**, and the definition's mounts name it as `${access:}`, so a placement moves the mount with it. Ten catalogue definitions were given ids; each keeps its path as the default an assignment may replace, so the machine that said nothing received exactly the paths it had before (the path-preservation proof, extended to accesses). That default is still a host path in a definition, tolerated as the transition: the media modules on the control node hold it until their assignments say where the data is, and then the defaults go. What the home server's assignments say next is the operator's: per media module, `places` for the configuration on the second disk and `accesses` for the pool, with the owner the predecessor ran as.