An assignment places a module's directories and its accesses (hq 153) #176

Merged
mesh-admin merged 3 commits from feat/153-an-assignment-places-directories-and-accesses into main 2026-09-30 22:03:33 +00:00
Contributor

novox/hq issue 153 — an adopted machine's data cannot be placed where it is. Opened on a separate branch as asked; not merged by me, since shanks is working in this area (one conflict hunk in dirsFor, internal/catalogue/dir_into.go, against feat/the-mesh-places-its-own-files — my three lines that let a placement win; trivial to re-apply on either side).

The two assignment halves ADR 0112 decided, validated like endpoints (an id the module does not declare is refused, and the refusal lists what it declares):

{"places":   {"config": "/services/sonarr/config",
              "data":   {"path": "/mnt/plex/data", "owner": "1000:1000"}},
 "accesses": {"series": "/storage/media/series", "downloads": "/storage/downloads"}}
  • places: a declared directory (by id) lands at the given path on this node; an optional owner (uid:gid) overrides the manifest's — the predecessor's data is owned by whoever it ran as. Still the mesh's directory: created, chowned, removed when empty.
  • accesses: an access may now be declared by id ({"id": "series", "mode": "read-write"}) and named in mounts, env and content as ${access:<id>}; the assignment says where it is. An access nobody placed is refused by name with the setting to write. A definition still carrying a path keeps it as the default the assignment replaces (the existing manifests keep working). Still the operator's: mounted, never created, chowned or removed.
  • ${access:…} naming an undeclared access is refused at parse (module check), like ${dir:…}.
  • Resolved in composition: the host receives concrete paths and owners exactly as before and learns no field.

Tests: placement_test.go (end-to-end declaration with placed directory + owner + two accesses filled into mounts and env; unplaced access refused by name; validation of ids, absolute paths, owner shape; definition path as default; parse-time refusal). Catalogue package green; both catalogues (mesh-catalog, mesh-media-catalog) pass module check with this binary.

With this, the media catalogue's manifests move their /services/media/* paths out of the definitions into ace's assignments (a follow-up there), and hq 153's fixed-by can name this PR.

novox/hq issue 153 — an adopted machine's data cannot be placed where it is. Opened on a separate branch as asked; **not merged by me**, since shanks is working in this area (one conflict hunk in `dirsFor`, `internal/catalogue/dir_into.go`, against `feat/the-mesh-places-its-own-files` — my three lines that let a placement win; trivial to re-apply on either side). **The two assignment halves ADR 0112 decided**, validated like `endpoints` (an id the module does not declare is refused, and the refusal lists what it declares): ``` {"places": {"config": "/services/sonarr/config", "data": {"path": "/mnt/plex/data", "owner": "1000:1000"}}, "accesses": {"series": "/storage/media/series", "downloads": "/storage/downloads"}} ``` - `places`: a declared directory (by id) lands at the given path on this node; an optional `owner` (uid:gid) overrides the manifest's — the predecessor's data is owned by whoever it ran as. Still the mesh's directory: created, chowned, removed when empty. - `accesses`: an access may now be declared by **id** (`{"id": "series", "mode": "read-write"}`) and named in mounts, env and content as `${access:<id>}`; the assignment says where it is. An access nobody placed is refused by name with the setting to write. A definition still carrying a `path` keeps it as the default the assignment replaces (the existing manifests keep working). Still the operator's: mounted, never created, chowned or removed. - `${access:…}` naming an undeclared access is refused at parse (`module check`), like `${dir:…}`. - Resolved in composition: the host receives concrete paths and owners exactly as before and learns no field. Tests: `placement_test.go` (end-to-end declaration with placed directory + owner + two accesses filled into mounts and env; unplaced access refused by name; validation of ids, absolute paths, owner shape; definition path as default; parse-time refusal). Catalogue package green; both catalogues (`mesh-catalog`, `mesh-media-catalog`) pass `module check` with this binary. With this, the media catalogue's manifests move their `/services/media/*` paths out of the definitions into ace's assignments (a follow-up there), and hq 153's `fixed-by` can name this PR.
mesh-admin added 1 commit 2026-09-30 20:43:17 +00:00
A definition names no host path (ADR 0112); an adopted machine keeps its
data where the predecessor put it. Two settings, validated like endpoints:

  places:   {<directory id>: <path> | {path, owner}}
  accesses: {<access id>: <path>}

An access may now be declared by id (`{"id": "series", "mode": "read-write"}`)
and named in mounts, env and content as ${access:<id>}; the assignment
says where it is on this node, and an access nobody placed is refused by
name. A definition still carrying a path keeps it as the default the
assignment replaces. A placed directory takes the assignment's owner
where it says one. Resolved in composition, so the host receives paths
and owners exactly as before.
jschoubben added 1 commit 2026-09-30 21:47:26 +00:00
jschoubben added 1 commit 2026-09-30 22:01:42 +00:00
An access named by id (issue 153) resolves to the path the definition still carries when the
assignment says nothing, and the proof compares that — the same rule as a placed directory.
mesh-admin merged commit f6685ed22d into main 2026-09-30 22:03:33 +00:00
mesh-admin deleted branch feat/153-an-assignment-places-directories-and-accesses 2026-09-30 22:03:33 +00:00
Sign in to join this conversation.
No Reviewers
No labels
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: novox/mesh-controller#176