Merge pull request 'Issue 279: a folder cannot be owned by the account a module runs as' (#151) from issues/279-a-folder-cannot-be-owned-by-the-account-a-module-runs-as into main
mesh/delivery held for a person: merged without a passing check: only a person decides that it goes on

This commit was merged in pull request #151.
This commit is contained in:
2026-10-06 19:28:46 +00:00
@@ -0,0 +1,63 @@
---
status: open
opened: 2026-10-06
located-in: []
fixed-by:
amended-design:
---
# 279. A folder cannot be owned by the account a module runs as
## Symptom
On 2026-10-06 a catalogue merge gave four media managers — the TV, film, music and book managers —
a recycle-bin folder each: a declared directory, mounted into the app's container, where the app
keeps a file it replaces with an upgrade. The directories were declared owned by the image's usual
user and group, as the modules' configuration directories are.
On the home server the TV and film managers refused the folder — their own words: *"Folder … is not
writable by user 'abc'"* — and the run-once step that applies their settings exited non-zero. The
book manager took it. The music manager, which applies the setting from its own code rather than the
step, logged the same refusal and carried on.
The difference is the account each app runs as. A media module runs as an identity its assignment
sets per node (`puid` and `pgid`, written into an environment file the container reads, per
[ADR 0112](../../02-DECISIONS/0112-a-module-definition-names-no-node-mesh-or-path.md) and
[issue 153](../153-an-adopted-machines-data-cannot-be-placed-where-it-is/00-report.md)). On the home
server three of them run as a second account the operator has long kept for media, and the book
manager as the image's default. The configuration directory works anyway only because the images
re-own it at start; a second directory gets no such help.
The stopgap merged the same evening, by the operator's choice, makes the folder writable by every
account.
## What it cost
One step failing failed the node's whole report, so every module in the same rollout failed its gate
on that node — the book manager's too, whose step had succeeded — and the controller raised that the
book manager's build *"failed its gate … and was NOT put back"*, there being no earlier build of it
kept to put back.
## Why it matters beyond this instance
The mesh knows one account on a node: the operator's ([ADR 0181](../../02-DECISIONS/0181-the-operator-account-is-a-node-fact-and-a-home-is-a-placement-root.md)),
which a resource may name as its owner. The account a containerised module *runs as* is a number its
assignment carries and the mesh does not know: nothing ties it to an account on the machine, and a
directory's owner cannot follow it — a manifest's owner is literal, and `${setting:…}` is filled in a
file's content and a contribution, not in a resource's owner. [To-be 29](../../03-DESIGN/01-to-be/29-a-node-has-operator-accounts.md)
leaves *one account or several per node* open; this is a node that has several, in practice, for
years.
So every directory a module's app must write — beyond the one its image re-owns — can be right on one
machine and refused on another, and the definition cannot say which. The definition was checked, the
manifest passed, and the failure showed only once applied.
## Open questions
- Is the account a module runs as a node fact the mesh holds (as the operator account is), a property
of the assignment, or something a module declares and the node provides?
- Should a directory's owner be able to name it — the way `${machine:account}` names the operator's?
- What of the media library itself, which those apps write and which is owned by that same second
account: is it a fact the mesh should know, or an access it only mounts?
- Separately: should one module's failed step fail every gate in the rollout on that node, and should a
build with nothing kept to put back be judged as a failed rollback?