Accept ADR 0263 with the operator's choices: one share per folder so backups are never exported, mesh machines only

This commit is contained in:
jochen
2026-10-08 18:23:23 +02:00
parent 3edafd78ab
commit 34899385ec
7 changed files with 142 additions and 98 deletions
+8 -1
View File
@@ -219,7 +219,7 @@ and Health and repair. **Decided by** ADR 0100, 0126, 0176, 0181, 0207, 0221, 02
**Purpose.** To resolve which module serves a provision for which consumer, and to wire the two.
**Recorded by** the controller. **Upstream of** Data; downstream of Module, Placement and Identity.
**Decided by** ADR 0027, 0084, 0138, 0225, 0230.
**Decided by** ADR 0027, 0084, 0138, 0225, 0230, 0263.
**Uses:** module, seat, credential (Identity and access).
- **provision** — a service one module `provides` and others `require`; the mesh resolves a provider
@@ -234,6 +234,13 @@ and Health and repair. **Decided by** ADR 0100, 0126, 0176, 0181, 0207, 0221, 02
reaches ([ADR 0138](../02-DECISIONS/0138-an-assignment-binds-an-endpoint-and-says-how-far-it-reaches.md)).
- **retire** — a provider stops serving a consumer the mesh no longer asks for; what it kept is deleted
only by a person ([ADR 0230](../02-DECISIONS/0230-a-consumer-the-mesh-stops-asking-for-is-retired-and-deleted-only-by-a-person.md)).
- **share** — a folder one node offers to the mesh's other nodes over the private network: the provision
`nfs-share`, provided by the holder of the node seat `node-nfs-server`, one share per folder
([ADR 0263](../02-DECISIONS/0263-a-share-is-a-provision-a-node-mounts-it-on-demand-and-only-nodes-that-ask-get-it.md)).
- **mount** — a share, or an occasional source, made visible at a path on one node by the holder of the
node seat `node-mounts`, as a mount unit and an automount unit, mounted on access (ADR 0263).
- **occasional source** — a share on a device that is not a node and comes and goes, such as a USB disk;
its absence is a state, *not present*, never a fault (ADR 0263).
## Identity and access — who may do what
@@ -1,5 +1,5 @@
---
status: active
status: graduated
initiated: 2026-10-08
touches:
- 04-ISSUES/169-a-machine-shares-its-files-and-the-mesh-does-not-know/00-report.md
@@ -12,7 +12,9 @@ touches:
- 02-DECISIONS/0092-an-operator-delivers-a-pair-credential.md
- the catalogue's module manifests
- the controller's seat set
became: []
became:
- 03-DESIGN/01-to-be/52-shares-and-mounts.md
- 02-DECISIONS/0263-a-share-is-a-provision-a-node-mounts-it-on-demand-and-only-nodes-that-ask-get-it.md
---
# 038 — Shares and mounts the mesh manages
@@ -71,8 +73,10 @@ The detail is in [01-evidence.md](01-evidence.md). In short:
## Where it goes
[02-options.md](02-options.md) weighs the options. The proposed decision is
[02-options.md](02-options.md) weighs the options. The decision is
[ADR 0263](../../02-DECISIONS/0263-a-share-is-a-provision-a-node-mounts-it-on-demand-and-only-nodes-that-ask-get-it.md),
and the to-be design is
[52 — Shares and mounts](../../03-DESIGN/01-to-be/52-shares-and-mounts.md). Both wait for the
operator's word. The open questions are listed at the end of the options.
and the design is [52 — Shares and mounts](../../03-DESIGN/01-to-be/52-shares-and-mounts.md).
On 2026-10-08 the operator chose **one share per folder**, so the backups are never exported, and
**mesh machines only**, over the private network. Which nodes mount a share, and whether the laptop
mounts read-only, is decided at assignment.
@@ -1,7 +1,7 @@
# 038 — Options
Each question below lists the options weighed and the one recommended. The recommendations together
are [ADR 0263](../../02-DECISIONS/0263-a-share-is-a-provision-a-node-mounts-it-on-demand-and-only-nodes-that-ask-get-it.md).
became [ADR 0263](../../02-DECISIONS/0263-a-share-is-a-provision-a-node-mounts-it-on-demand-and-only-nodes-that-ask-get-it.md).
## Q1. Who writes the export
@@ -137,14 +137,10 @@ Every exchange between the modules is over NATS (research 036):
- `mounts` keeps each share's state in its bucket; a view or the controller watches it;
- no module reads another's files (ADR 0260).
## Open questions for the operator
## The operator's answers (2026-10-08)
1. **The pool's root, or one share per folder?** Recommended: one per folder (Q2 option C), so the
backup repository is never exported.
2. **Every node, or the nodes that ask?** Recommended: only the workstation and the laptop, with a
mesh-wide setting available (Q4).
3. **Underlay clients.** The private network only is recommended. Does anything on the home network
that is not a node (a TV, a media player) still need the NFS or SMB share? Today the filter closes
both, so nothing has been able to use them since 2026-10-04.
4. **Read-write from the laptop.** Should the laptop mount the library read-only? Recommended: yes,
read-only, since it travels.
1. **The pool's root, or one share per folder?** One share per folder (Q2 option C), so the backup
repository is never exported.
2. **Underlay clients?** Mesh machines only, over the private network.
3. **Every node, or the nodes that ask? Read-write from the laptop?** Decided at assignment, which is the
operator's; the recommendation (Q4 option C; the laptop read-only) stands in the design.
@@ -1,6 +1,6 @@
---
topic: what runs on it
status: proposed
status: accepted
date: 2026-10-08
deciders: jochen
reconstructed: false
@@ -56,47 +56,61 @@ Rejected:
into the library for no use. The laptop, behind a VPN client, would try a mount whenever something
looks at the path. Kept as a setting, not as the default.
7. **One `file-share` seat for NFS and SMB.** The two share an intent, not a contract (issue 169).
8. **The pool's root as one share**, with `crossmnt` and every client mapped to the library's owner. That
keeps the `0700` backup repository closed to clients, but it still exports it, and every other folder
at the root becomes writable from every node. The operator chose one share per folder on 2026-10-08,
so the backups are never exported.
9. **A provider's paths written into its binding.** A binding carries what the provider's manifest
`serves`, which is the same for every machine; a share's path is a setting of one assignment. The
consumer asks the server for it over the bus instead, so no controller change is needed for it.
## Decision
1. **A node's share is a provision.** The module `nfs-server` holds the node seat `nfs-share` and
provides the provision `nfs-share`. Its assignment's settings list the shares: a name, the path
(an `access`, ADR 0051: the module never creates, chowns or removes it), and read-only or
read-write. It writes its own file in `/etc/exports.d`, never `/etc/exports`, and listens on 2049/tcp
1. **A node's share is a provision.** The module `nfs-server` holds the node seat `node-nfs-server` and
provides the provision `nfs-share`. Its assignment's setting `shares` lists the shares: a name, the
path, and read-only or read-write. The path is the operator's data (ADR 0051): the module never
creates, chowns, chmods or removes anything under it. It writes its own file in `/etc/exports.d`, never `/etc/exports`, and listens on 2049/tcp
from the private network. It serves NFS version 4 only, so no other port opens.
2. **Every export squashes every client to the share's owner.** `all_squash`, with `anonuid` and
`anongid` read from the exported path's owner on the server (`${access:<id>:uid}`), never written as
`anongid` read by the module from the exported path's owner on the server, never written as
numbers. The clients are `${machine:mesh-range}` and nothing else. A file written from any node lands
owned by the library's owner, and no client acts as any other account on the server.
3. **The home server exports one share per folder, not the pool's root**: the library and the
downloads. The backup repository and the archive are not exported. (If the operator wants the pool's
root as one share, it is exported with `crossmnt` and the same squashing, which keeps the `0700`
backup repository closed. That is the alternative this record names, and the operator's to choose.)
3. **One share per folder, never a pool's root** (the operator's choice, 2026-10-08): on the home server,
the library and the downloads. The backup repository and the archive are not exported. The module
refuses a share that is `/` or that holds a backup repository at its path or one level below, so a
setting cannot export one by mistake.
4. **A node mounts through one module.** The module `mounts` holds the node seat `node-mounts`. For each
share it writes a `.mount` unit and an `.automount` unit, never an fstab line. Only the automount is
enabled, so nothing mounts at boot and nothing can fail the boot. Each mount has an idle timeout
(default 10 minutes) and a mount timeout (default 30 s; 10 s for an occasional source). A read-write
NFS share is mounted `hard`. A mount point is always an autofs mount, so nothing writes into the
empty directory under it (issue 169's data-loss case).
5. **Only the nodes that ask get a share.** A node mounts what its `mounts` assignment lists, plus every
share a module on that node requires. The list may be set once at the mesh-wide settings layer, which
is how "every node" is said, and a node's own layer can leave a share out. The proposal is to assign
`mounts` to the workstation and the laptop, and not to the control-node.
5. **Only the nodes that ask get a share.** A node mounts what its `mounts` assignment's setting `shares`
lists. The list may be set once at the mesh-wide settings layer, which is how "every node" is said,
and a node's own layer can leave a share out. Which nodes are assigned, and whether the laptop mounts
read-only, is decided at assignment, which is the operator's; the recommendation is the workstation
and the laptop (read-only), not the control-node.
6. **An occasional source is a share with presence `occasional`.** A device that is not a node, such as
the gaming device or a USB disk, is described in the `mounts` assignment's settings. Its absence is a
the gaming device or a USB disk, is described in the `mounts` assignment's setting `sources`. Its absence is a
state, `absent`, not a fault. It is mounted on access when it is there, and it never fails the boot or
leaves a failed unit. Mounting when a device appears on the network waits for issue 154 (mDNS is
dropped by the packet filter today).
7. **A credential for a share is an operator-delivered secret** (ADR 0092), accepted into the vault and
unsealed on the node as a file (ADR 0086), which the mount unit names. No password is written in a
7. **A credential for a share is an operator-delivered secret** (ADR 0092): the `mounts` module's own
secret `smb-credentials`, issued outside the mesh (ADR 0228), given with `secret accept`, kept by the
vault and unsealed on the node as a file (ADR 0086). The module writes one credentials file per source
from it, readable by root only, which the mount unit names. No password is written in a
repository, a manifest or `/etc/fstab`.
8. **Health:** a share that should always be reachable and is not, for 5 minutes, raises one plain
condition, `share-unreachable`, naming the share, the node and since when. An occasional source that
condition, naming the share, the node and since when. It is the `mounts` module's health (ADR 0240),
judged by its tool `mounts_health`, whose finding is *share unreachable*; no new kind of condition is
added to the controller. An occasional source that
is absent raises nothing. The server's health is its service and its export table holding every
declared export.
9. **Over the bus.** The controller wires the two through the provision. `nfs-server` keeps its exports
and clients, and `mounts` keeps each share's state, in their own key-value buckets (ADR 0201). They
ask each other by request and reply. Neither reads the other's files (ADR 0260).
9. **Over the bus.** The controller wires the two through the provision: the binding gives the consumer
the server's name. The consumer then asks the server's seat, `node-nfs-server.exports`, by request and
reply for each share's path and access, so a share's path is said once, on the server. `nfs-server`
keeps its exports, and `mounts` keeps each share's state, in their own key-value buckets (ADR 0201).
Neither reads the other's files (ADR 0260).
10. **Taking over a hand-written line is an act.** The `mounts` module's `adopt` comments out one fstab
line, keeping a copy, only after its own unit pair for that mount point is armed, and only on a
person's word. The ZFS `sharenfs` property is cleared the same way, by `nfs-server`, once its own
@@ -106,8 +120,8 @@ Rejected:
- The workstation's library comes back over the private network, and the two failed units stop
appearing at boot.
- Two node seats join the mesh's closed set, `nfs-share` and `node-mounts`. That is a controller
change.
- Two node seats join the mesh's closed set, `node-nfs-server` and `node-mounts`. That is a controller
change. The provision `nfs-share` needs none.
- What got harder: every client writes to a share as one account, so there is no per-person
permission on it. Traffic to the library crosses the private network's encryption even on the home
network; the workstation is on Wi-Fi, so the tunnel is not the limit there, and this is measured at
+72 -54
View File
@@ -1,7 +1,10 @@
---
layer: to-be
status: proposed
code: []
status: in-progress
code:
- mesh-controller internal/catalogue (the seats node-nfs-server and node-mounts)
- mesh-catalog modules/nfs-server
- mesh-catalog modules/mounts
updated: 2026-10-08
decisions:
- 02-DECISIONS/0263-a-share-is-a-provision-a-node-mounts-it-on-demand-and-only-nodes-that-ask-get-it.md
@@ -21,17 +24,17 @@ from [research 038](../../01-RESEARCH/038-shares-and-mounts-the-mesh-manages/00-
A **share** is a directory one machine offers to others over the network. A **mount** is a share made
visible at a path on one node. An **occasional source** is a share on a device that comes and goes.
These three words are proposed for the glossary with this design.
The glossary holds the three words.
## The parts
```
home server workstation, laptop (the nodes that ask)
nfs-server (seat nfs-share, node) mounts (seat node-mounts, node)
nfs-server (seat node-nfs-server) mounts (seat node-mounts, node)
├ /etc/exports.d/<its file> ├ <path>.automount enabled, idle 10 min
│ one line per share, to the ├ <path>.mount not enabled, timeout 30 s
│ private network's range only, │ What = binding at:path, options
│ private network's range only, │ What = <server>:<path>, options
│ all_squash to the share's owner ├ credentials file (vault, ADR 0086),
├ nfs-server.service, NFS v4 only │ for an SMB source only
├ listens 2049/tcp from mesh ├ its process: probes each source,
@@ -39,7 +42,7 @@ These three words are proposed for the glossary with this design.
▲ └ tools: mounts_list, mounts_exports,
│ provision nfs-share mount, unmount, test, adopt
│ (the controller wires it; ▲
│ binding: at, path, options) │ settings: shares wanted, occasional
│ binding: the server's name) │ settings: shares wanted, occasional
└──────────────── request/reply on the bus ─────────┘ sources (mesh-wide and node layers)
gaming device (not a node) ── SMB share ──► an occasional source in the workstation's mounts settings
@@ -47,61 +50,73 @@ These three words are proposed for the glossary with this design.
| part | where | does |
|---|---|---|
| seats `nfs-share` and `node-mounts` | the controller's closed set | node seats, capacity 1, with their verbs |
| `nfs-server` | the catalogue | holds `nfs-share`, provides the provision, writes its export file, runs the service, opens 2049 to the private network |
| seats `node-nfs-server` and `node-mounts` | the controller's closed set | node seats, capacity 1, with their verbs |
| `nfs-server` | the catalogue | holds `node-nfs-server`, provides the provision, writes its export file, runs the service, opens 2049 to the private network |
| `mounts` | the catalogue | holds `node-mounts`, writes a unit pair per share, keeps each share's state, serves the tools |
| the binding | the controller | gives a consumer the server's private-network name, the path and the options |
| the credential | the vault | an operator-delivered secret per SMB source, unsealed on the node as a file |
| the binding | the controller | gives a consumer the server's name; the consumer asks the server's seat for each share's path and access over the bus |
| the credential | the vault | the `mounts` module's own secret `smb-credentials`, issued outside the mesh and given with `secret accept`, unsealed on the node as a file |
## 1. The server: `nfs-server`
- **Settings.** A list of shares, each with a name, the path as an `access` (the operator's data; the
module never creates, chowns or removes it), and `read-write` or `read-only`.
- **Its file.** One file in `/etc/exports.d`, written by the node-engine. One line per share:
the path, to `${machine:mesh-range}`, with `rw` or `ro`, `sync`, `secure`, `no_subtree_check`,
`all_squash`, and `anonuid` and `anongid` taken from the path's owner on the server
(`${access:<id>:uid}` and `:gid`). The pool's root is exported only if the operator asks, and then
with `crossmnt` as well.
- **The service.** `nfs-server.service`, running and enabled, restarted when the file changes.
NFS version 4 only, set in the module's drop-in for `nfs.conf`. So only 2049/tcp is needed, declared in
`listens` with `from: mesh`.
- **The provision.** `nfs-share`, one per share, with `path` and `options` in what it serves.
- **Health.** The service is active, and the kernel's export table holds every line of the module's
file.
- **Its bucket.** The exports as the kernel holds them, and the clients that have each mounted, with
since when.
- **Tools.** `exports` (r), `clients` (r), `reload` (a), and `test` (r): does this server export this
path to this node.
- **Taking over.** An act, `adopt`, clears a dataset's `sharenfs` property for a path the module now
exports, on a person's word, and says what it did.
- **Its setting `shares`.** A list of `name=path`, each optionally `:ro`, separated by spaces: on the
home server the library and the downloads. A share's path is the operator's data (ADR 0051); the
module never creates, chowns, chmods or removes anything under it.
- **What it refuses.** A path that does not exist or is not a directory, `/`, and a path that holds a
backup repository at its root or one level below. A refused share is said by the tools and makes the
module unhealthy; the others are exported.
- **Its file.** `/etc/exports.d/mesh.exports`, written by the module's own process, which runs as root.
One line per share: the path, to `${machine:mesh-range}` and nothing else, with `rw` or `ro`, `sync`,
`secure`, `no_subtree_check`, `all_squash`, a stable `fsid`, and `anonuid` and `anongid` read from the
path's owner. `exportfs -ra` runs when the file changes.
- **The service.** `nfs-server.service`, running and enabled. NFS version 3 is turned off in the
module's drop-in for `nfs.conf`, so only 2049/tcp is needed, declared in `listens` with `from: mesh`.
- **The provision.** `nfs-share`, at the mesh's scope, with no identity: the binding gives the
consumer the server's name, and the consumer asks for the rest.
- **Health.** Its tool `nfs_health`: the service is active, every share is in the kernel's export table,
and no share was refused.
- **Its bucket.** `exports`, one entry per machine: the shares as the kernel holds them.
- **Its seat's verbs.** `exports` (r), `clients` (r), `test` (r), `reload` (a) and `adopt` (a). `adopt`
clears a ZFS dataset's `sharenfs` property for a path the module now exports, only once the mesh's
export of it is in the kernel's table, and only with a person's confirmation and reason.
## 2. The client: `mounts`
- **Settings.** `shares`: the names of the `nfs-share` provisions this node mounts, each with a mount
point and optional `read-only`. `sources`: occasional sources, each with a protocol (`smb` or `disk`),
a name or a disk's UUID, a share name, a mount point, and the name of its credential. Both may be set
at the mesh-wide layer, which is how "every node" is said, and changed at a node's own layer.
- **A share a module requires.** When a module on the node requires `nfs-share`, the controller adds that
share to the node's `mounts` set, with the mount point that module's assignment gives.
- **The unit pair.** For each share, a `.mount` and an `.automount`, named by the escaped mount point and
written in `/etc/systemd/system` by the node-engine:
- the `.automount` is enabled under `remote-fs.target`, with `TimeoutIdleSec=10min`;
- the `.mount` is not enabled; it has `TimeoutSec=30s` (10 s for an occasional source), `_netdev`,
and an order after the private network's link;
- for NFS: `vers=4.2`, `hard,timeo=150,retrans=3` when read-write, `soft` allowed when read-only;
- for SMB: `credentials=<the unsealed file>`, `uid` and `gid` of the node's account that uses it;
- for a disk: `BindsTo=` the disk's device unit, so the mount goes with the disk.
- **States**, kept in its bucket per share, with since when: `armed` (automount waiting), `mounted`,
`absent` (an occasional source not there), `unreachable` (should be there and is not), `failed`
(the mount was tried and refused, with the error).
- **Its process.** Probes each source's port every 30 s, and the device unit for a disk. It never
touches a mount point, so a hung server cannot hang it.
- **Health.** Every automount is armed, and every share that is not occasional is `armed` or `mounted`.
An occasional source that is `absent` is healthy.
- **Tools.** `mounts_list` (r), `mounts_exports` (r), `test` (r), `mount` and `unmount` (a), `adopt` (a).
- **Its setting `shares`.** A list of `name=mountpoint`, each optionally `:ro`: the `nfs-share` shares
this node mounts, by the server's name for them.
- **Its setting `sources`.** Occasional sources: `name=smb://<host>/<share>@<mountpoint>` or
`name=disk:<uuid>@<mountpoint>`, each optionally `:ro`.
- **Its secret `smb-credentials`.** One section per SMB source, `[name]` with `username=` and
`password=`, issued outside the mesh and given with `secret accept <node> mounts smb-credentials
--from <file>`. The process writes one credentials file per source, readable by root only. A source
with no section is said with that remedy and is not mounted.
- **Asking the server.** The process asks `node-nfs-server.exports` on the server named by the binding,
over the bus, for each share's path and access. A share the server does not export is said, not
guessed.
- **The unit pair.** For each share and source, a `.mount` and an `.automount`, named by the escaped
mount point, written in `/etc/systemd/system` by the module's own process with a marker line. It never
touches a unit without its marker, and it removes its own pairs that are no longer asked for:
- the `.automount` is enabled under `remote-fs.target`, with an idle time of 10 minutes;
- the `.mount` is not enabled; its mount timeout is 30 s, 10 s for an occasional source; it starts
after the network is online;
- NFS: version 4.2, `hard,timeo=150,retrans=3` when read-write; `ro,soft` when read-only;
- SMB: `credentials=<its file>`, `iocharset=utf8`, `nofail`;
- a disk: bound to the disk's device unit, so the mount goes with the disk.
- **States**, per share, with since when, in its bucket `shares` (one entry per machine): `armed`,
`mounted`, `absent` (an occasional source not there), `unreachable` (should be there and is not),
`failed` (the mount was tried and refused, with the error).
- **Its probes.** Every 30 s, a connection to the server's port (2049, or 445 for SMB) with a short
timeout, and the device for a disk. It never touches a mount point, so a hung server cannot hang it.
- **Health.** Its tool `mounts_health`: every automount is armed, and no share that is not occasional
has been `unreachable` or `failed` for 5 minutes. An absent occasional source is healthy and said as
*not present since 18:02*.
- **Its seat's verbs.** `list` (r), `test` (r), `mount` (a), `unmount` (a), `adopt` (a); its tools
`mounts_list` and `mounts_exports` (r) stay.
## 3. Which nodes get which share
Which nodes are assigned `mounts`, and with which settings, is decided at assignment, which is the
operator's. The recommendation:
| node | gets | why |
|---|---|---|
| home server | none; it holds `nfs-server` | the files are local; the media modules keep their local bind mounts |
@@ -113,8 +128,11 @@ These three words are proposed for the glossary with this design.
| condition | raised when | cleared when |
|---|---|---|
| `share-unreachable` (warning) | a share that is not occasional has been `unreachable` or `failed` for 5 minutes | the next probe reaches it |
| the server's health | the export table lacks a declared line, or the service is down | the next look finds both right |
| the `mounts` module's health, finding *share unreachable* | a share that is not occasional has been `unreachable` or `failed` for 5 minutes, or an automount is not armed | the next look finds it reached and armed |
| the `nfs-server` module's health | a share is missing from the kernel's export table, a share was refused, or the service is down | the next look finds all three right |
Both are the module's health under ADR 0240, judged by its tool; the controller raises and clears the
condition as for any module, and adds no kind of its own.
Each says the share, the node and since when: *"The home server's share `library` is not reachable
from the workstation since 19:21."* An absent occasional source raises nothing; `mounts_list` says
@@ -122,7 +140,7 @@ from the workstation since 19:21."* An absent occasional source raises nothing;
## 5. Migration
1. Build and deliver `mounts` (read-only first, already proposed) and `nfs-server`, and add the two seats.
1. Build and deliver the two seats, `nfs-server` and `mounts`.
2. Assign `nfs-server` to the home server with the library and the downloads. Check `exports` and
`test` from the workstation.
3. `adopt` on the home server clears the library's `sharenfs` property. The underlay range leaves the
+1 -1
View File
@@ -51,7 +51,7 @@ document is written and this one's status becomes `implemented`.
| [`49-the-mesh-in-domains.md`](49-the-mesh-in-domains.md) | **In progress.** Every concept belongs to one of ten domains, which owns its one word; the glossary is organised by them and is the authority, a retired word is named on its replacement's line with its scope, and two checks hold this repository's documents and the catalogue's tool descriptions to it | [ADR 0244](../../02-DECISIONS/0244-the-mesh-is-described-in-domains-and-one-word-names-one-thing.md), [ADR 0006](../../02-DECISIONS/0006-the-substrate-and-the-control-plane.md), [ADR 0008](../../02-DECISIONS/0008-a-context-owns-its-store.md) |
| [`50-split-dns-on-a-machine-with-a-vpn-client.md`](50-split-dns-on-a-machine-with-a-vpn-client.md) | **In progress.** A machine whose VPN client pushes servers of its own runs a resolver of its own, on a node seat, that routes the VPN's domains over its link and every other name to the mesh's resolvers; the VPN client's module carries the adapter | [ADR 0247](../../02-DECISIONS/0247-a-machine-with-a-vpn-client-routes-names-by-domain-through-a-resolver-of-its-own.md), [ADR 0223](../../02-DECISIONS/0223-the-mesh-has-two-resolvers-and-a-machine-lists-only-them.md) |
| [`51-the-registries-keep-what-is-named.md`](51-the-registries-keep-what-is-named.md) | **In progress.** The artifact store, the package registry and each machine's container runtime get tools that say what they hold, what names each thing and what could go; every removal is a dry run unless a person asks and says why, and what decides is always a record | [ADR 0251](../../02-DECISIONS/0251-the-registries-say-what-they-hold-and-keep-what-is-named-and-a-machine-keeps-the-image-it-runs-and-the-one-before.md), [ADR 0189](../../02-DECISIONS/0189-the-store-keeps-what-the-records-name.md) |
| [`52-shares-and-mounts.md`](52-shares-and-mounts.md) | **Proposed.** A node shares a directory through `nfs-server`, which provides it as a provision to the private network only, squashing every client to the share's owner; a node that asks mounts it through `mounts`, a mount unit and an automount per share, so nothing mounts or fails at boot; a device that comes and goes is an occasional source whose absence is a state | [ADR 0263](../../02-DECISIONS/0263-a-share-is-a-provision-a-node-mounts-it-on-demand-and-only-nodes-that-ask-get-it.md), [ADR 0051](../../02-DECISIONS/0051-shared-data-is-the-operators.md), [ADR 0092](../../02-DECISIONS/0092-an-operator-delivers-a-pair-credential.md) |
| [`52-shares-and-mounts.md`](52-shares-and-mounts.md) | **In progress.** A node shares one folder at a time through `nfs-server`, which provides it as a provision to the private network only, mapping every client to the folder's owner; a node that asks mounts it through `mounts`, a mount unit and an automount per share, so nothing mounts or fails at boot; a device that comes and goes is an occasional source whose absence is a state | [ADR 0263](../../02-DECISIONS/0263-a-share-is-a-provision-a-node-mounts-it-on-demand-and-only-nodes-that-ask-get-it.md), [ADR 0051](../../02-DECISIONS/0051-shared-data-is-the-operators.md), [ADR 0092](../../02-DECISIONS/0092-an-operator-delivers-a-pair-credential.md) |
## Not yet written
@@ -1,11 +1,11 @@
---
status: open
status: located
opened: 2026-09-30
located-in:
- mesh-catalog (no module shares a path over the network)
- hq 02-DECISIONS (a file-share seat, per ADR 0126, is a module's own to define)
fixed-by:
amended-design:
amended-design: [03-DESIGN/01-to-be/52-shares-and-mounts.md]
---
# 169 — A machine shares its files, and the mesh does not know
@@ -129,3 +129,8 @@ the mounted tree, answers it on the consumer's side too.
Re-checked 2026-10-08: still holds. No module in either catalogue shares a path over the network, and no
`nfs-share` or `smb-share` seat exists.
**Decided 2026-10-08:** [ADR 0263](../../02-DECISIONS/0263-a-share-is-a-provision-a-node-mounts-it-on-demand-and-only-nodes-that-ask-get-it.md),
from [research 038](../../01-RESEARCH/038-shares-and-mounts-the-mesh-manages/00-overview.md), which measured
the closure this report predicted: the workstation's library mount has timed out at every boot since
2026-10-04. The seats are `node-nfs-server` and `node-mounts`, the provision `nfs-share`; Samba waits.