Design 42 zfs-owns-zfs: the lead's answers to the prepare's 24 questions, each against the principles

This commit is contained in:
2026-11-13 00:04:41 +01:00
parent 04de5c3b30
commit 435fe73a0f
@@ -0,0 +1,86 @@
---
layer: to-be
status: in-progress
design: 42
milestone: zfs-owns-zfs
updated: 2026-11-13
decisions:
- "ADR 0679"
---
# 42, milestone zfs-owns-zfs — the lead's answers to the prepare's questions
The lead's answers to the prepare's design questions (Q-n) and to the places where a design line and the code
disagree (C-n), for the milestone part [zfs-owns-zfs](zfs-owns-zfs.md): each one line, naming the principle that
settles it (`00-META/principles.md`), cited as "design 42 zfs-owns-zfs A-n". The code read is the prepare's, at the
`origin/main` commits its milestone file names.
- **A-1** (Q-1, §8; principles 2 and 7) The pool's name is not held by mesh-config: it is the zfs module's
`values` in the home server's assignment (seat `mesh-module-assigner`), a layer mesh-config's rename does not move.
So the module keeps `renamed-from: scrub-pool` for the values mesh-config holds, and at the delivery the lead moves
the assignment's value: `pool` set to that name through mesh-config for the home server, and the assignment
proposed without `scrub-pool` through `mesh-module-assigner.propose`, both before the new version is placed.
- **A-2** (Q-2, §14; principle 7) The module's ZED folder also holds the package's `zed-functions.sh`, from the
module's files archive, root's, mode 0644, under `if-config: [zed=on]` beside `zed.rc`; the handlers find it where
ZED points them, and nothing else changes.
- **A-3** (Q-3, §13; principles 2 and 7) `trim-schedule: none` is a set value meaning "no trim by the mesh": the
distribution's trim timers are held stopped for `none`, `weekly` and `monthly` alike; only an unset value leaves
them as found.
- **A-4** (Q-4, §3; principle 3) The validator refuses a `:` in a `config-lines` prefix, beside `}`, `$` and a
newline, naming the key.
- **A-5** (Q-5, §3; principle 3) The validator refuses `mib-bytes` on a value whose type is not a number, and a
`config-lines` key the module does not declare, as it refuses `${config:<key>}` of an undeclared key today.
- **A-6** (Q-6, §18, §24; principles 1 and 6) The follower's process bus declares
`invokes: ["seat:node-service-manager.start"]`, and the module's `invokes` carries the same for its tools bundle.
- **A-7** (Q-7, §14, §18; principle 7) `/etc/zfs/mesh-zed.d` is a directory resource under `if-config: [zed=on]`
with `unknown: module`; `/run/zfs-tools` is a directory resource with `unknown: program`, as `/run/zfs-events` is.
- **A-8** (Q-8, §18; principle 3) `zfs-tools apply` exits 0 on a refusal and on a wait, which it says by event and
in its state `applied` and which make the module unhealthy by §29; it exits non-zero only when a command it ran
failed, so the node-engine gates the module on a real failure.
- **A-9** (Q-9, §30; principle 7) When the module leaves a node, its kept data (the states `applied`, `schedule` and
`findings`, the ledger `snapshots`, the events stream) is kept as every module's kept data is on leaving; a return
finds its scheduled ZFS snapshots' records.
- **A-10** (Q-10, §27; principle 7) The findings stream is the one design 47 G §383 defines for every observer:
`zfs-findings`, its events `finding-written.*`, `finding-cleared.*` and `findings-stated.*`, kept 7 days and
16 MiB, said by the writer generated from the seat `mesh-conditions`' definition; the module declares it as §383
says and builds nothing of its own for it.
- **A-11** (Q-11, acceptance test 8; principles 5 and 7) Test 8 runs in the test lab, on a pool built on a
file-backed device, never on the home server's pool.
- **A-12** (Q-12, §24; principles 3 and 4) A hand act's tool waits at most 30 seconds for the act's event; past it,
it answers "started", naming the act and that `zfs_module_events` reads its outcome, and never answers "done"
for what it did not see end.
- **A-13** (C-1, §4; principle 7) The node-engine states the new reading as `word:resources.if-config` and
`form:config-lines` (and `form:config-json`, A-15), computed by `ManifestReads` and marked by `ManifestNeeds`;
stopping at the first failure is stated by no capability, since the node-engine build that reads those words is
the build that stops.
- **A-14** (C-2, §11; ADR 0679 §3; principle 7) The validator accepts a config value with neither a default nor
`required` as "not managed until set"; built in the validator's subtasks of this milestone.
- **A-15** (C-3, §9; principles 2 and 7) The config file's content is one new node-engine placeholder
`${config-json}`: the module's set config values as one JSON object, an unset value absent, lists and objects as
JSON; no unset value refuses the module. It is built with §2 and §3 in the node-engine, the validator and
mesh-sdk's form list, and stated as `form:config-json`; no existing form writes an unset value as absent.
- **A-16** (C-4, §18; principle 7) The follower, which runs from boot, starts the apply unit once at its own start
and on the events §27 names; the apply's own wait for an unimported pool (§18) stands for the order after
`zfs-import.target`. No new process field.
- **A-17** (C-5, §24; principle 7) A hand act writes its act into the state `schedule` under its own key and starts
`zfs-mesh-run.service`; the run reads the key, acts under the same lock and guards, and deletes it. No instance
units.
- **A-18** (C-6, §24; principle 7) `node-service-manager.start` is called with `{scope, unit}`; the tool keeps
`why` in its own event. The seat is not changed.
- **A-19** (C-7, §26; principle 7) The ledger `snapshots` declares a fixed `max-mib` sized from the bound of 168 per
kind (§11); a full ledger takes §21's "ledger full" path.
- **A-20** (C-8, §21, §22, §26; principles 1 and 7) A process cannot write a ledger: the ledger is served to a tools
bundle alone, through the tool runner (mesh-sdk `buscalls`, `ProcessBus` has no ledger). The scheduled run records
`taken` and `removed` by calling its own module's tool `zfs_snapshots_record` (declared in the run's process bus
`invokes`), whose bundle applies the operation to the ledger; the tool refuses a snapshot not named `mesh-`. No new
field in mesh-sdk.
- **A-21** (C-9, §13; principle 2) When one record of a unit goes while another still declares it, the found state
passes to the record that stays, as a file is handed to the resource still declaring its path (ADR 0223); built in
the node-engine's §2 subtask.
- **A-22** (C-10, the test budget; the test-budget instruction) The node-engine's repository is over its budget (about 1,742 unit tests
against 500): each new table test merges or replaces at least as many tests in the file it touches, named in the
build map, so the count does not rise.
- **A-23** (C-11, §9, §11; principle 6) The config file carries `"trusted": false`; each value's own `trusted` (§11)
decides who sets it.
- **A-24** (C-12, §2, §3; principle 3) `config-lines` and `config-json` are added to the validator's and the
composer's placeholder tables, and the validator counts `if-config`, `config-lines` and `config-json` as placing
their keys.