From 5b76a09da678eefb42c1f53106203e562ad3f091 Mon Sep 17 00:00:00 2001 From: jochen Date: Sun, 27 Sep 2026 00:08:09 +0200 Subject: [PATCH 1/5] issue 130: undeclaring a service stops it, even one the mesh only reloads or keeps running --- .../00-report.md | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 04-ISSUES/130-undeclaring-a-service-stops-it/00-report.md diff --git a/04-ISSUES/130-undeclaring-a-service-stops-it/00-report.md b/04-ISSUES/130-undeclaring-a-service-stops-it/00-report.md new file mode 100644 index 0000000..1b6177d --- /dev/null +++ b/04-ISSUES/130-undeclaring-a-service-stops-it/00-report.md @@ -0,0 +1,43 @@ +--- +status: located +opened: 2026-09-27 +located-in: [mesh-host internal/apply/apply.go (remove), mesh-controller internal/overlay, mesh-catalog modules/sshd] +--- + +# 130 — undeclaring a service stops it, even one the mesh only reloads or only keeps running + +## What was observed + +Reviewing the uplink modules ([ADR 0117](../../02-DECISIONS/0117-a-machines-uplink-is-a-seat.md)) +found that the host's `remove` path stops every `service` resource that is no longer declared: +`SetServiceState(..., "stopped")`, reported as "stopped; the unit file is not the host's to +delete". `store.Orphans` matches by id alone. So any of these stops the unit: + +- the module is unassigned — by mistake, or to switch it for another; +- the node is sent a deliberately-empty declaration ([issue 127](../127-a-declaration-that-shrinks-to-empty-is-skipped-not-sent/00-report.md)); +- a later catalogue version renames the resource's `id`. + +That is right for a service the mesh brought into being. It is wrong for a unit the mesh +declares only to act on — and the catalogue already has two: + +- **The private network declares `docker.service`** (`registry-trust-reload`, state `running`) + so that a change to the registry trust reloads the runtime ([ADR 0102](../../02-DECISIONS/0102-the-mesh-writes-into-a-shared-file-never-over-it.md)). + Unassigning the private network stops the container runtime, and every container on the + machine with it — including ones the mesh does not manage. +- **The sshd module declares `sshd.service`.** Unassigning it stops the machine's ssh daemon: + the lockout the same module's `listens` rule says a firewall must never arrange. + +The uplink modules would have added a third and a fourth: unassigning the network manager's +module would have stopped the network manager, taking the machine off the only link the mesh +reaches it by. + +## What would have prevented it + +- A service resource that says the unit's **lifecycle is the machine's**: declared with no + `state`, the mesh never starts, stops, enables or disables it; it only reloads or restarts a + *running* unit when a trigger changes; undeclared, it is left exactly as it is. (Being built + on mesh-host `feat/a-file-written-into-a-marked-block` for the uplink modules.) +- Then: `registry-trust-reload` declared that way (the runtime is the machine's), and the sshd + module's service too — a machine's ssh daemon outlives any module that configures it. +- A plan or unassign preview that names every unit an undeclare will stop, so the consequence + is read before it happens. From dd4cbabffbc08f1e345c45dc1a7e8d456377e20f Mon Sep 17 00:00:00 2001 From: jochen Date: Sun, 27 Sep 2026 00:08:23 +0200 Subject: [PATCH 2/5] 130: ADR 0117 named, not linked, until it is on main --- 04-ISSUES/130-undeclaring-a-service-stops-it/00-report.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/04-ISSUES/130-undeclaring-a-service-stops-it/00-report.md b/04-ISSUES/130-undeclaring-a-service-stops-it/00-report.md index 1b6177d..4c0a4cd 100644 --- a/04-ISSUES/130-undeclaring-a-service-stops-it/00-report.md +++ b/04-ISSUES/130-undeclaring-a-service-stops-it/00-report.md @@ -8,7 +8,7 @@ located-in: [mesh-host internal/apply/apply.go (remove), mesh-controller interna ## What was observed -Reviewing the uplink modules ([ADR 0117](../../02-DECISIONS/0117-a-machines-uplink-is-a-seat.md)) +Reviewing the uplink modules (ADR 0117, in review) found that the host's `remove` path stops every `service` resource that is no longer declared: `SetServiceState(..., "stopped")`, reported as "stopped; the unit file is not the host's to delete". `store.Orphans` matches by id alone. So any of these stops the unit: From ebd19c4c6c9434e535887cfe7a6526af514e6912 Mon Sep 17 00:00:00 2001 From: jochen Date: Sun, 27 Sep 2026 00:16:01 +0200 Subject: [PATCH 3/5] =?UTF-8?q?ADR=200118:=20undeclaring=20removes=20what?= =?UTF-8?q?=20the=20mesh=20made,=20gives=20back=20what=20it=20changed,=20l?= =?UTF-8?q?eaves=20the=20machine's=20units=20as=20they=20are=20=E2=80=94?= =?UTF-8?q?=20resolves=20issue=20130?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...aring-leaves-the-machines-units-running.md | 100 ++++++++++++++++++ 02-DECISIONS/README.md | 1 + .../00-report.md | 13 ++- 3 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 02-DECISIONS/0118-undeclaring-leaves-the-machines-units-running.md diff --git a/02-DECISIONS/0118-undeclaring-leaves-the-machines-units-running.md b/02-DECISIONS/0118-undeclaring-leaves-the-machines-units-running.md new file mode 100644 index 0000000..6d01fe8 --- /dev/null +++ b/02-DECISIONS/0118-undeclaring-leaves-the-machines-units-running.md @@ -0,0 +1,100 @@ +--- +topic: what runs on it +status: accepted +date: 2026-09-27 +deciders: jochen +reconstructed: false +extends: 0102-the-mesh-writes-into-a-shared-file-never-over-it.md +--- + +# 118. Undeclaring removes what the mesh made, gives back what it changed, and leaves the machine's units as they are + +## Context + +When a resource stops being declared — its module unassigned, the node sent a +deliberately-empty declaration ([issue 127](../04-ISSUES/127-a-declaration-that-shrinks-to-empty-is-skipped-not-sent/00-report.md)), +or a new catalogue version renaming its id — the host undoes it. The host's own code states +the rule it means to follow: **it removes what it made and leaves what it merely configured.** +For almost every resource it does exactly that: + +- a container, a network, a process's unit, a directory it created: removed; +- a file it created: removed; a file it replaced: its kept original put back + ([ADR 0100](0100-a-node-in-use-is-adopted-before-it-is-converged.md)); +- keys and list members it wrote into a shared file: given back as they were + ([ADR 0102](0102-the-mesh-writes-into-a-shared-file-never-over-it.md)); +- a package: left installed — the host cannot know it is unused; +- an operator's path it was given access to: never touched + ([ADR 0051](0051-shared-data-is-the-operators.md)). + +**A service is the exception.** A `service` resource never installs a unit: it puts one that +already exists — the distribution's, the operator's — into a state. Undeclared, the host stops +it. That contradicts the rule above, and in practice it is the most dangerous thing an +undeclare can do. Found reviewing the uplink modules +([issue 130](../04-ISSUES/130-undeclaring-a-service-stops-it/00-report.md)): + +- the private network declares the container runtime's unit only so a change to the registry + trust reloads it — unassigning the private network stops the runtime, and every container on + the machine, the mesh's and not; +- the sshd module declares the ssh daemon — unassigning it stops ssh, the lockout that module's + own `listens` rule forbids; +- the uplink modules would have stopped the network manager, taking the machine off the only + link the mesh reaches it by. + +ADR 0117 (in review) answered that for its own modules with a +service declared with no `state`. Every other module that declares a unit it did not make is +exposed in the same way, and relying on each author to remember an opt-out is how the next one +is missed. + +## Considered Options + +**1. Undeclaring touches nothing on the machine.** Rejected. What the mesh made would outlive +the module that made it: a container nobody manages keeps serving and stops being patched; a +unit the mesh wrote keeps running a bundle nothing updates; a name collides when the module +is assigned again. An undeclare that leaves the mesh's own work behind is an orphan factory. + +**2. Keep stopping services; make "leave it running" an opt-in per resource.** Rejected. It +keeps the dangerous behaviour as the default for exactly the units that matter most — the +runtime, the ssh daemon, the network — and each new module is one forgotten field away from a +machine that goes dark when it is unassigned. + +**3. The line is ownership.** Chosen. + +## Decision + +**Undeclaring removes what the mesh made, gives back what it changed, and leaves what was the +machine's as it is.** For a unit, that means: **the host never stops, starts, disables or +enables a unit it did not create when that unit stops being declared.** An undeclared `service` +is forgotten — reported as such — and the unit keeps whatever state it is in. + +- A unit the mesh *did* create — a `process` resource's unit, which the host writes — is still + stopped and removed with it. That is the mesh's own code. +- The service's settings the mesh wrote are given back by their own resources (a kept original + restored, a region or keys removed). A running service keeps running on what it read until it + next reads its configuration; the mesh does not restart it to make it notice. +- A service declared with no `state` (ADR 0117) remains the way to say the mesh must not + **start** a unit either; this record is about what happens when a declaration goes away, and + covers every service. +- An operator who wants a unit stopped when its module goes says so first: declare it + `stopped`, push, then unassign. Stopping a machine's unit is a decision, made visibly — never + a side effect of removing a module. + +## Consequences + +- Unassigning the private network no longer stops the container runtime; unassigning sshd no + longer stops ssh; no uplink module can take a machine's network down on its way out. +- The host's removal report says "forgotten; the unit is the machine's" where it used to say + "stopped". A module that relied on its daemon stopping when unassigned — none in the catalogue + today does on purpose — needs the explicit step above. +- A daemon can keep running after its module is gone, on configuration that was taken back from + under it. That is a visible, running process the operator can see and stop; the alternative + was an invisible outage. +- **Not decided here:** an unassign preview that lists what an undeclare will remove and what it + will leave running. Issue 130 asks for it; it is the controller's to build. + +## References + +- [issue 130](../04-ISSUES/130-undeclaring-a-service-stops-it/00-report.md): the finding +- ADR 0117 (in review): the uplink modules, and a service with no state +- [ADR 0102](0102-the-mesh-writes-into-a-shared-file-never-over-it.md), [ADR 0100](0100-a-node-in-use-is-adopted-before-it-is-converged.md): + what is given back, and how +- mesh-host `internal/apply/apply.go` (`remove`, the service case) diff --git a/02-DECISIONS/README.md b/02-DECISIONS/README.md index de2b056..ba76b62 100644 --- a/02-DECISIONS/README.md +++ b/02-DECISIONS/README.md @@ -200,6 +200,7 @@ python3 00-META/checks/index.py fail if stale - **0114** — [A credential two parties hold rotates over two credentials; one a single party holds rotates in place, staged; and retiring a credential never removes what it reached](0114-a-shared-credential-rotates-over-two-credentials.md) *(proposed)* - **0115** — [One assignment of a module per node: the module's name is the assignment's identity](0115-one-assignment-of-a-module-per-node.md) *(proposed)* - **0117** — [A machine's uplink is a seat: the mesh configures the manager, never the link](0117-a-machines-uplink-is-a-seat.md) +- **0118** — [Undeclaring removes what the mesh made, gives back what it changed, and leaves the machine's units as they are](0118-undeclaring-leaves-the-machines-units-running.md) ### How it is built diff --git a/04-ISSUES/130-undeclaring-a-service-stops-it/00-report.md b/04-ISSUES/130-undeclaring-a-service-stops-it/00-report.md index 4c0a4cd..2bfbd3e 100644 --- a/04-ISSUES/130-undeclaring-a-service-stops-it/00-report.md +++ b/04-ISSUES/130-undeclaring-a-service-stops-it/00-report.md @@ -1,7 +1,8 @@ --- status: located opened: 2026-09-27 -located-in: [mesh-host internal/apply/apply.go (remove), mesh-controller internal/overlay, mesh-catalog modules/sshd] +located-in: [mesh-host internal/apply/apply.go (remove)] +amended-design: 02-DECISIONS/0118-undeclaring-leaves-the-machines-units-running.md --- # 130 — undeclaring a service stops it, even one the mesh only reloads or only keeps running @@ -41,3 +42,13 @@ reaches it by. module's service too — a machine's ssh daemon outlives any module that configures it. - A plan or unassign preview that names every unit an undeclare will stop, so the consequence is read before it happens. + +## Resolution + +[ADR 0118](../../02-DECISIONS/0118-undeclaring-leaves-the-machines-units-running.md): undeclaring +removes what the mesh made, gives back what it changed, and leaves the machine's units as they +are. An undeclared `service` is forgotten, never stopped — the host did not create the unit. +That covers the runtime, sshd and the uplink modules at once, without each module opting out; +the private network and the sshd module need no change. A `process`'s unit, which the host does +write, is still stopped and removed. The unassign preview asked for above is left open for the +controller. From 13208f0f4825962038f454b682ebd5f08d4eeef7 Mon Sep 17 00:00:00 2001 From: jochen Date: Sun, 27 Sep 2026 00:21:18 +0200 Subject: [PATCH 4/5] =?UTF-8?q?0118:=20give=20a=20unit=20back=20the=20stat?= =?UTF-8?q?e=20it=20was=20found=20in=20=E2=80=94=20never-stop=20broke=20th?= =?UTF-8?q?e=20converge=20rollback;=20process=20removal=20found=20and=20fi?= =?UTF-8?q?xed?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...-a-unit-back-the-state-it-was-found-in.md} | 51 +++++++++++++------ 02-DECISIONS/README.md | 2 +- .../00-report.md | 28 +++++++--- 3 files changed, 56 insertions(+), 25 deletions(-) rename 02-DECISIONS/{0118-undeclaring-leaves-the-machines-units-running.md => 0118-undeclaring-gives-a-unit-back-the-state-it-was-found-in.md} (60%) diff --git a/02-DECISIONS/0118-undeclaring-leaves-the-machines-units-running.md b/02-DECISIONS/0118-undeclaring-gives-a-unit-back-the-state-it-was-found-in.md similarity index 60% rename from 02-DECISIONS/0118-undeclaring-leaves-the-machines-units-running.md rename to 02-DECISIONS/0118-undeclaring-gives-a-unit-back-the-state-it-was-found-in.md index 6d01fe8..27ad6f7 100644 --- a/02-DECISIONS/0118-undeclaring-leaves-the-machines-units-running.md +++ b/02-DECISIONS/0118-undeclaring-gives-a-unit-back-the-state-it-was-found-in.md @@ -7,7 +7,7 @@ reconstructed: false extends: 0102-the-mesh-writes-into-a-shared-file-never-over-it.md --- -# 118. Undeclaring removes what the mesh made, gives back what it changed, and leaves the machine's units as they are +# 118. Undeclaring removes what the mesh made, and gives a unit back the state it was found in ## Context @@ -57,34 +57,53 @@ keeps the dangerous behaviour as the default for exactly the units that matter m runtime, the ssh daemon, the network — and each new module is one forgotten field away from a machine that goes dark when it is unassigned. -**3. The line is ownership.** Chosen. +**3. Never stop a unit the mesh did not create.** Rejected, found while implementing it. The +mesh's packet filter is a unit the distribution installed and the mesh started at converge; +returning a node to adopted ([ADR 0100](0100-a-node-in-use-is-adopted-before-it-is-converged.md)) +unloads it by undeclaring it. Never stopping it would leave the mesh's filter loaded beside the +predecessor's firewall re-enabled — the one rollback a converge promises, broken. Who wrote the +unit file is not the line; what the mesh *did* to the unit is. + +**4. Give the unit back the state it was found in.** Chosen. ## Decision -**Undeclaring removes what the mesh made, gives back what it changed, and leaves what was the -machine's as it is.** For a unit, that means: **the host never stops, starts, disables or -enables a unit it did not create when that unit stops being declared.** An undeclared `service` -is forgotten — reported as such — and the unit keeps whatever state it is in. +**Undeclaring removes what the mesh made and gives back what it changed.** For a unit the mesh +did not create, what it changed is the unit's state, so that is what is given back: **the host +records the state it first found the unit in, and undeclaring returns the unit to it.** -- A unit the mesh *did* create — a `process` resource's unit, which the host writes — is still - stopped and removed with it. That is the mesh's own code. +- **Recorded once**, the first time the host applies the service — whether it was running, and, + where the declaration sets it, whether it was enabled at boot — and carried in the host's + record from then on. Later applies never overwrite it: by then the unit's state is the mesh's + doing. +- **A unit found running is left running.** The container runtime, the ssh daemon, a network + manager: running before the mesh arrived, running after it leaves. +- **A unit the mesh started is stopped again**, and one it enabled is disabled again — the packet + filter a converge loaded, which returning to adopted unloads. +- **Never started on the way out.** A unit the mesh stopped is not started again when its + declaration goes; starting something is a decision, and the operator makes it. +- **Unknown is left alone.** A record written before the host kept what it found says nothing + about the unit before the mesh; the unit is left exactly as it is. A unit left running can be + stopped by the operator; one stopped by mistake may be the link the operator needed to do it. +- A unit the mesh *did* create — a `process` resource's unit and bundle — is stopped and removed + with its declaration. That is the mesh's own code. (Before this record there was no way to + remove one at all: an undeclared process failed every apply on its node.) - The service's settings the mesh wrote are given back by their own resources (a kept original restored, a region or keys removed). A running service keeps running on what it read until it next reads its configuration; the mesh does not restart it to make it notice. - A service declared with no `state` (ADR 0117) remains the way to say the mesh must not - **start** a unit either; this record is about what happens when a declaration goes away, and - covers every service. -- An operator who wants a unit stopped when its module goes says so first: declare it - `stopped`, push, then unassign. Stopping a machine's unit is a decision, made visibly — never - a side effect of removing a module. + **start** a unit either; undeclared, it is forgotten. ## Consequences - Unassigning the private network no longer stops the container runtime; unassigning sshd no longer stops ssh; no uplink module can take a machine's network down on its way out. -- The host's removal report says "forgotten; the unit is the machine's" where it used to say - "stopped". A module that relied on its daemon stopping when unassigned — none in the catalogue - today does on purpose — needs the explicit step above. +- The host's removal report says what it gave back — "restored: stopped again, as the host + found it" — or "forgotten: it was running before the mesh; left as it is" where it used to say + "stopped". Its plan names each unit an undeclare will stop, before it does. +- On a fresh machine where the mesh installed and started a service, unassigning its module + stops it again — the mesh gave, the mesh takes back. An operator who wants it kept declares it + in a module of their own, or starts it themselves after. - A daemon can keep running after its module is gone, on configuration that was taken back from under it. That is a visible, running process the operator can see and stop; the alternative was an invisible outage. diff --git a/02-DECISIONS/README.md b/02-DECISIONS/README.md index ba76b62..350db19 100644 --- a/02-DECISIONS/README.md +++ b/02-DECISIONS/README.md @@ -200,7 +200,7 @@ python3 00-META/checks/index.py fail if stale - **0114** — [A credential two parties hold rotates over two credentials; one a single party holds rotates in place, staged; and retiring a credential never removes what it reached](0114-a-shared-credential-rotates-over-two-credentials.md) *(proposed)* - **0115** — [One assignment of a module per node: the module's name is the assignment's identity](0115-one-assignment-of-a-module-per-node.md) *(proposed)* - **0117** — [A machine's uplink is a seat: the mesh configures the manager, never the link](0117-a-machines-uplink-is-a-seat.md) -- **0118** — [Undeclaring removes what the mesh made, gives back what it changed, and leaves the machine's units as they are](0118-undeclaring-leaves-the-machines-units-running.md) +- **0118** — [Undeclaring removes what the mesh made, and gives a unit back the state it was found in](0118-undeclaring-gives-a-unit-back-the-state-it-was-found-in.md) ### How it is built diff --git a/04-ISSUES/130-undeclaring-a-service-stops-it/00-report.md b/04-ISSUES/130-undeclaring-a-service-stops-it/00-report.md index 2bfbd3e..23e7288 100644 --- a/04-ISSUES/130-undeclaring-a-service-stops-it/00-report.md +++ b/04-ISSUES/130-undeclaring-a-service-stops-it/00-report.md @@ -2,7 +2,7 @@ status: located opened: 2026-09-27 located-in: [mesh-host internal/apply/apply.go (remove)] -amended-design: 02-DECISIONS/0118-undeclaring-leaves-the-machines-units-running.md +amended-design: 02-DECISIONS/0118-undeclaring-gives-a-unit-back-the-state-it-was-found-in.md --- # 130 — undeclaring a service stops it, even one the mesh only reloads or only keeps running @@ -45,10 +45,22 @@ reaches it by. ## Resolution -[ADR 0118](../../02-DECISIONS/0118-undeclaring-leaves-the-machines-units-running.md): undeclaring -removes what the mesh made, gives back what it changed, and leaves the machine's units as they -are. An undeclared `service` is forgotten, never stopped — the host did not create the unit. -That covers the runtime, sshd and the uplink modules at once, without each module opting out; -the private network and the sshd module need no change. A `process`'s unit, which the host does -write, is still stopped and removed. The unassign preview asked for above is left open for the -controller. +[ADR 0118](../../02-DECISIONS/0118-undeclaring-gives-a-unit-back-the-state-it-was-found-in.md): +undeclaring removes what the mesh made and gives back what it changed. The host records the state +it first found a unit in, and undeclaring returns the unit to it — a unit found running (the +container runtime, sshd, a network manager) is left running; one the mesh started (the packet +filter a converge loaded) is stopped again; nothing is started on the way out; a record from +before the host kept what it found leaves the unit alone. That covers the runtime, sshd and the +uplink modules at once, without each module opting out; the private network and the sshd module +need no change. + +A first draft — never stop a unit the mesh did not create — was rejected while implementing it: +returning a converged node to adopted unloads the mesh's filter by exactly this path. + +Found on the way: an undeclared `process` failed every apply on its node (`remove` had no case +for it). Now removed with its unit, timer and bundle — the mesh's own code. `user` and `archive` +have the same gap and are left for their own decisions: removing a login or unpacked files is not +something to settle in passing. + +The unassign preview is partly answered — the host's plan names each unit it will stop — and the +controller's side is left open. From 248c99ca6c307310e0cdad9ec1ed6876a99c53e3 Mon Sep 17 00:00:00 2001 From: jochen Date: Sun, 27 Sep 2026 00:58:17 +0200 Subject: [PATCH 5/5] 0118/130: link ADR 0117 now that it is on main --- ...undeclaring-gives-a-unit-back-the-state-it-was-found-in.md | 4 ++-- 04-ISSUES/130-undeclaring-a-service-stops-it/00-report.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/02-DECISIONS/0118-undeclaring-gives-a-unit-back-the-state-it-was-found-in.md b/02-DECISIONS/0118-undeclaring-gives-a-unit-back-the-state-it-was-found-in.md index 27ad6f7..cb925b0 100644 --- a/02-DECISIONS/0118-undeclaring-gives-a-unit-back-the-state-it-was-found-in.md +++ b/02-DECISIONS/0118-undeclaring-gives-a-unit-back-the-state-it-was-found-in.md @@ -40,7 +40,7 @@ undeclare can do. Found reviewing the uplink modules - the uplink modules would have stopped the network manager, taking the machine off the only link the mesh reaches it by. -ADR 0117 (in review) answered that for its own modules with a +[ADR 0117](0117-a-machines-uplink-is-a-seat.md) answered that for its own modules with a service declared with no `state`. Every other module that declares a unit it did not make is exposed in the same way, and relying on each author to remember an opt-out is how the next one is missed. @@ -113,7 +113,7 @@ records the state it first found the unit in, and undeclaring returns the unit t ## References - [issue 130](../04-ISSUES/130-undeclaring-a-service-stops-it/00-report.md): the finding -- ADR 0117 (in review): the uplink modules, and a service with no state +- [ADR 0117](0117-a-machines-uplink-is-a-seat.md): the uplink modules, and a service with no state - [ADR 0102](0102-the-mesh-writes-into-a-shared-file-never-over-it.md), [ADR 0100](0100-a-node-in-use-is-adopted-before-it-is-converged.md): what is given back, and how - mesh-host `internal/apply/apply.go` (`remove`, the service case) diff --git a/04-ISSUES/130-undeclaring-a-service-stops-it/00-report.md b/04-ISSUES/130-undeclaring-a-service-stops-it/00-report.md index 23e7288..4824dd2 100644 --- a/04-ISSUES/130-undeclaring-a-service-stops-it/00-report.md +++ b/04-ISSUES/130-undeclaring-a-service-stops-it/00-report.md @@ -9,7 +9,7 @@ amended-design: 02-DECISIONS/0118-undeclaring-gives-a-unit-back-the-state-it-was ## What was observed -Reviewing the uplink modules (ADR 0117, in review) +Reviewing the uplink modules ([ADR 0117](../../02-DECISIONS/0117-a-machines-uplink-is-a-seat.md)) found that the host's `remove` path stops every `service` resource that is no longer declared: `SetServiceState(..., "stopped")`, reported as "stopped; the unit file is not the host's to delete". `store.Orphans` matches by id alone. So any of these stops the unit: