From 27fd5ff860b45fe4daae9dd7ab72d18ebc83c057 Mon Sep 17 00:00:00 2001 From: jochens Date: Fri, 13 Nov 2026 00:39:43 +0100 Subject: [PATCH 01/11] Design 42 zfs-owns-zfs: A-30, the snapshots ledger in the ledger's own forms --- .../01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md b/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md index c8d90802..45d4d170 100644 --- a/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md +++ b/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md @@ -98,3 +98,9 @@ settles it (`00-META/principles.md`), cited as "design 42 zfs-owns-zfs A-n". The every value is valid, and each refused value is its own `config.refused`. - **A-29** (§11, §18, met in develop; principle 3) The node's memory is read by the apply and given to the parse; a memory that cannot be read refuses `arc-max` and `arc-min`, never guesses them. +- **A-30** (§21, §22, §26, A-19, A-20, met in develop; principles 1 and 7) The ledger `snapshots` uses the ledger's + own forms (ADR 0597) and nothing new: one type `snapshot`, its fields `dataset`, `name`, `kind` and `at`, all text; + an instance `snapshot/--`, the dataset's `/` written `~` (a character no ZFS name holds); + the operation `taken` with the effect `set-fields` on those four fields, and `removed` with the effect `remove` + naming no map, so the instance's state goes while its history keeps both operations; one index `by-dataset-kind` on + `dataset` and `kind`, read through `mesh/ledger.query`, the newest `at` among a kind's entries being its last. -- 2.54.0 From fec5bc42dcaa851b04e4eb0eabf6d9b84510b80f Mon Sep 17 00:00:00 2001 From: jochens Date: Fri, 13 Nov 2026 00:40:17 +0100 Subject: [PATCH 02/11] Design 42 zfs-owns-zfs: A-31, the run reads the ledger through its module's tool --- 03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md b/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md index 45d4d170..68fd9f68 100644 --- a/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md +++ b/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md @@ -104,3 +104,6 @@ settles it (`00-META/principles.md`), cited as "design 42 zfs-owns-zfs A-n". The the operation `taken` with the effect `set-fields` on those four fields, and `removed` with the effect `remove` naming no map, so the instance's state goes while its history keeps both operations; one index `by-dataset-kind` on `dataset` and `kind`, read through `mesh/ledger.query`, the newest `at` among a kind's entries being its last. +- **A-31** (§21, §22, §28, A-20, met in develop; principles 1 and 7) The scheduled run reads the ledger as it writes + it, through its own module's tools: its process bus also invokes `zfs.zfs_snapshots_schedule`, whose answer holds + the ledger's entries (§28), and the run takes a kind's last entry and the entries to prune from that answer. -- 2.54.0 From be36341681e612c265d584a7a8d994622432f3e7 Mon Sep 17 00:00:00 2001 From: jochens Date: Fri, 13 Nov 2026 00:45:17 +0100 Subject: [PATCH 03/11] Design 42 zfs-owns-zfs: A-32 corrects A-10, findings in today's state form --- .../01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md b/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md index 68fd9f68..314df074 100644 --- a/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md +++ b/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md @@ -39,7 +39,7 @@ settles it (`00-META/principles.md`), cited as "design 42 zfs-owns-zfs A-n". The - **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: +- **A-10** (Q-10, §27; principle 7; corrected by A-32) 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. @@ -107,3 +107,9 @@ settles it (`00-META/principles.md`), cited as "design 42 zfs-owns-zfs A-n". The - **A-31** (§21, §22, §28, A-20, met in develop; principles 1 and 7) The scheduled run reads the ledger as it writes it, through its own module's tools: its process bus also invokes `zfs.zfs_snapshots_schedule`, whose answer holds the ledger's entries (§28), and the run takes a kind's last entry and the entries to prune from that answer. +- **A-32** (corrects A-10, §27, met in develop; principles 2 and 7) The writer A-10 names is not on mesh-sdk's main: it + is built only on design 47 G's branch, a milestone not yet delivered. The follower says its findings in its own + state `findings`, keyed and written as every observer on main writes its findings today, and declares no + `zfs-findings` stream; G's change of §387 writes that stream into every module that declares a state `findings` on + main when it lands, the zfs module among them. Read before A-10 was given: nothing; the lead now reads what an + answer names first (playbook 07, step 0b). -- 2.54.0 From 4001fd351544d3d4a22fbec4d1eded0f1e71d235 Mon Sep 17 00:00:00 2001 From: jochens Date: Fri, 13 Nov 2026 00:49:47 +0100 Subject: [PATCH 04/11] Design 42 zfs-owns-zfs: A-33 to A-35, met in develop --- .../01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md b/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md index 314df074..6498f9a2 100644 --- a/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md +++ b/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md @@ -113,3 +113,11 @@ settles it (`00-META/principles.md`), cited as "design 42 zfs-owns-zfs A-n". The `zfs-findings` stream; G's change of §387 writes that stream into every module that declares a state `findings` on main when it lands, the zfs module among them. Read before A-10 was given: nothing; the lead now reads what an answer names first (playbook 07, step 0b). +- **A-33** (§20, met in develop; principle 3) A trim schedule set without its `trim-day` or `trim-time` runs no trim and + is said: the parse refuses it as one refused value (A-28), naming the missing value. +- **A-34** (§24, A-18, met in develop; principle 7) A hand act's `why` and `by` are kept in its key of the state + `schedule`, which the run deletes once it acted, and its outcome is the event the act itself emits (§25); no new + event kind. +- **A-35** (§21, §22, met in develop; principle 3 and the operator's "we may absolutely not lose any data") A kind's + keep count of 0 is that kind's `none`: none is taken, its existing scheduled ZFS snapshots are kept and a warning + names them; only a count above 0 prunes past it. -- 2.54.0 From 53c407350f0568e8c9ea46e066b03d248bbd9261 Mon Sep 17 00:00:00 2001 From: jochens Date: Fri, 13 Nov 2026 01:00:37 +0100 Subject: [PATCH 05/11] Design 42 zfs-owns-zfs: A-36 corrects A-30's remove, A-37 the root processes reach the bus through a keeper --- .../42-milestones/zfs-owns-zfs-lead-answers.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md b/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md index 6498f9a2..619a85f7 100644 --- a/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md +++ b/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md @@ -121,3 +121,18 @@ settles it (`00-META/principles.md`), cited as "design 42 zfs-owns-zfs A-n". The - **A-35** (§21, §22, met in develop; principle 3 and the operator's "we may absolutely not lose any data") A kind's keep count of 0 is that kind's `none`: none is taken, its existing scheduled ZFS snapshots are kept and a warning names them; only a count above 0 prunes past it. +- **A-36** (corrects A-30, §26, met in develop; ADR 0597; principle 7) The ledger's `remove` effect names a map and a + key (the validator refuses one without), so the instance is one per dataset and kind: + `snapshot/-` (the dataset's `/` written `~`), its state a map `taken` keyed by the ZFS snapshot's + name; `taken` is the effect `set-entry` into `taken` under the field `name`, with `dataset`, `name`, `kind` and `at`; + `removed` is the effect `remove` from `taken` under `name`. A kind's live ZFS snapshots are the instance's map, its + last the newest `at` there, so no index is declared. +- **A-37** (§18, §20, §26, §27, A-6, A-20, met in develop; ADR 0436 §1, §2; principle 7) A process's bus account is a + user the module makes, never root, so the three root processes (the apply, the run, the follower) declare no `bus`. + The module makes a user `zfs-keeper` and one process `zfs-keeper` running as it, which holds the module's one process + bus account (its events, its states `applied`, `schedule` and `findings`, and its invokes of + `zfs.zfs_snapshots_record`, `zfs.zfs_snapshots_schedule` and `seat:node-service-manager.start`). It serves a unix + socket in the module's state directory that only root may open (the peer's uid checked), with a closed list of + calls: emit an event, put or delete a key of those states, and invoke one of those three. The root processes say + everything they say on the bus through it; with the keeper not answering they act as with the bus down (A-8), and + warn. The module's tools keep their own account as today. -- 2.54.0 From 0f9ab08e2d5d5802dbb3101d54c91a68bc05c746 Mon Sep 17 00:00:00 2001 From: jochens Date: Fri, 13 Nov 2026 01:01:16 +0100 Subject: [PATCH 06/11] Design 42 zfs-owns-zfs: A-38, a process's bus names what its module asks for in requires --- .../01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md b/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md index 619a85f7..b84bd3a5 100644 --- a/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md +++ b/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md @@ -136,3 +136,11 @@ settles it (`00-META/principles.md`), cited as "design 42 zfs-owns-zfs A-n". The calls: emit an event, put or delete a key of those states, and invoke one of those three. The root processes say everything they say on the bus through it; with the keeper not answering they act as with the bus down (A-8), and warn. The module's tools keep their own account as today. +- **A-38** (A-37, §25, §26, met in develop; ADR 0436 §1, ADR 0595 §1, §2; the operator's "a case the delivery cannot + handle is a gap in the build and delivery system") A process's `bus` today is judged and granted only against the + module-level `emits` and `state`, which ADR 0595 replaced by what a module asks for in `requires`. In this + milestone a process's `bus.emits` may name an event of the events stream its module asks for by template in + `requires`, and its `bus.state` a state its module asks for there: the validator accepts them (in the indexer's + process-bus rule), and the grants (mesh-grants) give the process's account publish on that stream's subjects of + its own node and the reads and writes of those states, as they give a module's tools account today. A name its + module does not ask for is refused as today. -- 2.54.0 From f7d066fb32f99647f586c254bb6ede9d8a161d79 Mon Sep 17 00:00:00 2001 From: jochens Date: Fri, 13 Nov 2026 01:10:06 +0100 Subject: [PATCH 07/11] Design 42 zfs-owns-zfs: A-39 and A-40, met in develop --- .../01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md b/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md index b84bd3a5..d5bf7984 100644 --- a/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md +++ b/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md @@ -144,3 +144,8 @@ settles it (`00-META/principles.md`), cited as "design 42 zfs-owns-zfs A-n". The process-bus rule), and the grants (mesh-grants) give the process's account publish on that stream's subjects of its own node and the reads and writes of those states, as they give a module's tools account today. A name its module does not ask for is refused as today. +- **A-39** (A-37, A-17, met in develop; principle 7) The keeper's closed list of calls also reads: `get` one key and + `keys` of the same three states, since the run reads a hand act's key and the apply its state `applied`. +- **A-40** (A-36, met in develop; principle 3) A ledger instance not yet written is the tool runner's answer to + `mesh/ledger.get` with a state `null` and sequence 0 (the tool runner's `internal/ledger/read.go` `Get`, in mesh-tools), never + an error: the module reads it so, and recognises no error by its text. -- 2.54.0 From 230dc73bc1646f908ee82c6b127d8f519ac1bcaa Mon Sep 17 00:00:00 2001 From: jochens Date: Fri, 13 Nov 2026 01:29:19 +0100 Subject: [PATCH 08/11] Design 42 zfs-owns-zfs: A-41, the keeper publishes on its events stream's subject --- .../01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md b/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md index d5bf7984..1abd0958 100644 --- a/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md +++ b/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md @@ -149,3 +149,9 @@ settles it (`00-META/principles.md`), cited as "design 42 zfs-owns-zfs A-n". The - **A-40** (A-36, met in develop; principle 3) A ledger instance not yet written is the tool runner's answer to `mesh/ledger.get` with a state `null` and sequence 0 (the tool runner's `internal/ledger/read.go` `Get`, in mesh-tools), never an error: the module reads it so, and recognises no error by its text. +- **A-41** (§25, A-37, A-38, review round 1; principles 1 and 7; shared code belongs in mesh-sdk) The events stream a + module asks for by template `events` captures `mesh.bus...>` (the bus module's keeper, `PlanOf`), and + that is what the grants of A-38 give. The keeper publishes each event there, as a JetStream publish the bus + acknowledges, on `mesh.bus...`, the subject named by a new mesh-sdk helper + `process.Account.BusSubject(local, event)` beside `EventSubject` and `StreamSubject`; never `process.Conn.Emit`, + which publishes on the module's old event subjects. -- 2.54.0 From ca142d4b98419a03fd1d7548dd8fb39dfd0148e2 Mon Sep 17 00:00:00 2001 From: jochens Date: Fri, 13 Nov 2026 01:46:09 +0100 Subject: [PATCH 09/11] Design 42 zfs-owns-zfs: A-42, a tools bundle publishes onto its own events stream by name --- .../42-milestones/zfs-owns-zfs-lead-answers.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md b/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md index 1abd0958..31ba62e5 100644 --- a/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md +++ b/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md @@ -155,3 +155,15 @@ settles it (`00-META/principles.md`), cited as "design 42 zfs-owns-zfs A-n". The acknowledges, on `mesh.bus...`, the subject named by a new mesh-sdk helper `process.Account.BusSubject(local, event)` beside `EventSubject` and `StreamSubject`; never `process.Conn.Emit`, which publishes on the module's old event subjects. +- **A-42** (§25, A-12, A-41, review round 2; principles 1, 3 and 7; the operator's "a case the delivery cannot handle + is a gap in the build and delivery system") A tools bundle has no way onto the events stream its module asks for by + template: the tool runner's `mesh/publish` publishes on the module's old event subjects and reads no binding (the + tool runner's `PublishAs`, `eventSubject`), and its `mesh/subscribe` hears only the old streams. This milestone + builds the one path it lacks, by name, beside the bus-state calls a bundle already makes: a call + `mesh/stream.publish` {stream (the local name), event, body, id} in mesh-sdk's `buscalls`, which the tool runner + answers for the bundle's own bound stream alone by an acknowledged JetStream publish on the binding's subject plus + `.`, the id as the message id, under the grant the tool runner's account already holds (`boundOf`). The zfs + tools say every event of §25 with it, never `stdio.Emit`. A hand act's tool hears its act's event by reading its own + events stream with the calls it has (`mesh/stream.fill` for the last sequence before it starts the act, then + `mesh/stream.read` from the next one with the act's subject), for at most the 30 seconds of A-12. The other modules + whose bundles emit onto a template events stream (messenger) move to the call in a change of their own. -- 2.54.0 From a7831db5166befd64b51faeb89de82031848d15a Mon Sep 17 00:00:00 2001 From: jochens Date: Fri, 13 Nov 2026 01:51:17 +0100 Subject: [PATCH 10/11] Design 42 zfs-owns-zfs: A-43 no wait in a hand act, A-44 the stream-publish capability --- .../01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md b/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md index 31ba62e5..c9a14463 100644 --- a/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md +++ b/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md @@ -167,3 +167,12 @@ settles it (`00-META/principles.md`), cited as "design 42 zfs-owns-zfs A-n". The events stream with the calls it has (`mesh/stream.fill` for the last sequence before it starts the act, then `mesh/stream.read` from the next one with the act's subject), for at most the 30 seconds of A-12. The other modules whose bundles emit onto a template events stream (messenger) move to the call in a change of their own. +- **A-43** (corrects A-12 and A-42's wait, met in develop; principles 1 and 7: nothing polls) A hand act's tool does not + wait: once its act's key is written and the run's unit started, it answers "started" at once, naming the act and that + `zfs_module_events` reads its outcome, as §24 says ("the tool answers from the state and events afterwards"). The + bundle has no watch on its events stream, and a repeated read for 30 seconds is a poll. +- **A-44** (A-42, met in develop; principle 3; the module graph orders the delivery) `mesh/stream.publish` is a family + of its own, the capability `stream-publish`, which the new tool runner states; the zfs module's `capabilities` ask + for it (and for `bus-state-calls` and `ledger-calls`, the calls it already makes), so the delivery plan places the + zfs module's new version only on a machine whose tool runner answers the call, and never one where its events would + fail. -- 2.54.0 From 8bd11f7532e20fe4d73ed18ff808e5c8c81ea942 Mon Sep 17 00:00:00 2001 From: jochens Date: Fri, 13 Nov 2026 01:59:51 +0100 Subject: [PATCH 11/11] Design 42 zfs-owns-zfs: A-45, every long-running unit declares its health --- 03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md b/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md index c9a14463..60c161d8 100644 --- a/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md +++ b/03-DESIGN/01-to-be/42-milestones/zfs-owns-zfs-lead-answers.md @@ -176,3 +176,6 @@ settles it (`00-META/principles.md`), cited as "design 42 zfs-owns-zfs A-n". The for it (and for `bus-state-calls` and `ledger-calls`, the calls it already makes), so the delivery plan places the zfs module's new version only on a machine whose tool runner answers the call, and never one where its events would fail. +- **A-45** (§13, review round 3; ADR 0240; principle 3) Each long-running unit the module declares (the services + `import-cache`, `mount`, `target` and `zed-on`) declares its health of kind `unit`, as the catalog's other + long-running resources do, so no running part of the module goes unwatched. -- 2.54.0