Merge pull request 'Issue 320 and ADR 0253: a condition says itself to the operator in plain words' (#203) from feat/plain-notifications into main

This commit was merged in pull request #203.
This commit is contained in:
2026-10-08 12:20:39 +00:00
5 changed files with 352 additions and 2 deletions
+6
View File
@@ -421,6 +421,12 @@ asking, never the act. **Decided by** ADR 0152, 0175, 0234.
holder of kind `desktop`) and not *bot* (that is one service's account).
- **router** — the module that holds the `operator-channel` seat, orders the channels and checks every
sender ([ADR 0234](../02-DECISIONS/0234-the-mesh-holds-a-conversation-with-its-operator.md)).
- **headline / verdict / explanation / resolved line** — what a condition says to the operator in plain
words: a few words naming the thing and what is wrong; "Nothing for you to do." or "Needs you:" and the
one thing the operator can do themselves (its **needs**); one or two sentences on what happened and what
it means; the line said when it clears. Its **actions** are the answers a notification offers. Carried by
the condition beside its **summary**, which keeps the plans, commits and verbs for whoever looks closer
([ADR 0253](../02-DECISIONS/0253-a-condition-says-itself-to-the-operator-in-plain-words-beside-its-summary.md)).
- **ask** — a request for the operator's input, of a declared kind (yes-no, one-of, text, number,
date, acknowledge). An **authorising ask** is one whose answer performs an action; the controller
holds it and checks its proofs (ADR 0234).
@@ -0,0 +1,219 @@
---
topic: the mesh
status: accepted
date: 2026-10-08
deciders: jochen
reconstructed: false
extends: 02-DECISIONS/0234-the-mesh-holds-a-conversation-with-its-operator.md
---
# 253. A condition says itself to the operator in plain words beside its summary, says whether the operator is needed, and is answered from the notification
## Context
The operator could not read the mesh's notifications
([issue 320](../04-ISSUES/320-the-operator-could-not-read-the-meshs-notifications/00-report.md)). A walk
waiting for its delivery's word reached the laptop's desktop as five lines: the summary, with a commit, a
plan id and two verbs' syntax in backticks; then `about:`, `since:` in UTC, `key:` and `more:`. The operator
reads a notification between other work, and has to understand it in one pass: what happened, whether
they need to act, and what to do.
A first rewording made the same popup plain: "openrazer delivery waiting to start", then "The change to
openrazer is merged and built, and has waited 56 minutes for mesh-delivery … Nothing to do yet; it becomes
urgent after 4 hours. To start it now, have an agent start it by hand." The operator read it and asked:
*what does that notification mean, I need to do something? I need to open a session and tell it to
deliver it?* Plain words were not enough. Three more things were wrong:
- **It did not say plainly whether the operator was needed.** "Nothing to do yet" and "to start it now"
in one sentence read as an instruction.
- **It was shown at all.** A walk waiting under its bound needs nothing from anyone; the mesh says it
again when it does.
- **What it offered could not be done from where it was read.** "Have an agent start it by hand" sends the
operator to open a session, find the verb and say why. That is the work a notification should save.
What the mesh had, on the main branches of 2026-10-08:
- **A condition had one line of words.** To-be 45 §2 gave it a `summary`, "one line in the mesh's words".
The producers wrote it for whoever looks closer, an agent or a person at `conditions`, and named the
plan, the commit and the verb that acts. That reader needs those, and keeps needing them.
- **Issue 277 holds every summary to the operator channel's content rule** (ADR 0234 §6): no address,
domain, path or secret. Identifiers, verbs and markup pass that rule, so they reached the operator.
- **The message added detail of its own**, and a clearance repeated the whole summary.
- **The controller raises some sixty condition kinds**, from some eighty places in its code. Several know
more than the condition's subject says: a walk knows its modules, a failed unit its name, a hand-act its
cause.
- **The verbs that answer the common questions exist**, as seat verbs any granted principal may call:
`mesh-delivery.release` and `stop` (with why), the controller's `plans` with `go` and `stop` (with why),
`conditions` with `silence` (with why), and every machine's `node-service-manager.restart`.
- **The desk could not take an answer.** `node-notifier.send` had no actions. To-be 46 §11 designs them
(phase 2 of its build): the dunst holder offers them and emits the chosen one. Its router, asks and the
controller's `authorise request` and `answer` (phases 3 to 5) are not built. No dashboard exists where an
operator could release a delivery. The one way to act was an agent session.
- **ADR 0234 §8 says a desk click alone never authorises.** It defines three tiers, and *acknowledge*
"performs only what any granted principal may already do … it is not an authorisation, and needs no
proof". No verb declares a tier yet: that is phase 5.
## Considered Options
### Where the words are made
1. **A formatter in each channel**, which turns the summary into something readable. It has to guess what
a summary means from its words, breaks silently with each new producer, and is needed again for each new
channel. Rejected as the mechanism; kept as the fallback for a condition that carries no plain words.
2. **Rewrite every summary in plain words.** The reader who looks closer loses the plan, the commit and the
verb. One line cannot serve both readers. Rejected.
3. **A table of words per condition kind in the messenger.** The router would know the controller's
kinds, which inverts ADR 0234, and could not see what only the producer knows. Rejected.
4. **The condition carries plain words beside its summary, made where the condition is made.** Chosen.
### Whether the operator is needed
1. **Leave it to each explanation's wording.** The first rewording did, and the operator could not tell.
Rejected.
2. **A verdict every explanation opens with**, from a field the condition carries (`needs`): empty is
"Nothing for you to do.", otherwise "Needs you:" and that one thing. Chosen: it is the first thing read,
it is the same on every channel, and a router can act on the field.
### What is shown
1. **Everything, gently** (the desktop's fifteen-minute rhythm for warnings). The rhythm still shows a
popup that asks nothing. Rejected.
2. **Nothing that needs nothing, while it is a warning.** It stays open in the controller's conditions and
in the channel's history, and is said when it needs the operator: at its urgent bound, or when its words
change to "Needs you:". Chosen.
### How the operator answers
1. **Name the verb in the words**, for the operator to call. It sends them to a session. Rejected.
2. **Wait for the conversation design** (to-be 46 phases 2 to 6) and say "Needs you:" with nothing to press
until then. Honest, but leaves the common answers, which already exist as verbs, a session away for
weeks. Rejected for the answers that exist.
3. **The condition names its answers as actions; the desk offers them; the operator channel's holder
calls the verb.** It builds the part of to-be 46 phase 2 these answers need (the desk's actions, and the
chosen one said as an event), and nothing of the router or of authorising. Chosen.
## Decision
1. **Every condition carries, beside its summary, words for the operator:**
- **headline**: a few words naming the thing and what is wrong, at most sixty characters, such as
"openrazer not working on `<machine>`". It is the title of every message about the condition.
- **needs**: one sentence, the one thing the operator can do themselves — "release it, or stop it.",
"log out of every session on `<machine>` and log in again." — or empty when nothing is needed.
- **explanation**: opened by its **verdict**, "Nothing for you to do." when `needs` is empty and
"Needs you:" and `needs` otherwise, then one or two sentences on what happened and what it means.
- **resolved line**: the one line said when it clears.
- **actions**: the answers the operator may give from the notification, each a label and the seat verb
with its arguments (Release, Stop, Start, Restart, Silence for a week). An argument `why` left empty is
the operator channel's to fill.
The **summary** keeps its role and its words. The events and the `conditions` verb carry all of it.
2. **They are made where the condition is made.** A producer that knows more than the subject says them
itself; otherwise the wording registered for the kind does; otherwise the scope's words do, and the
kind is reported. **A kind without words is a defect of its producer**, as a summary that carries an
address is (issue 277).
3. **The plain rule.** Headline, needs, explanation and resolved line name no hash, numbered id, dotted
name (a key, a verb, a unit's file name), duration in code, clock time, date or zone, command flag,
markup or line break, and pass the content rule. **They never send the operator elsewhere**: no
"agent", no "session", and `needs` never says "by hand". `needs` is one sentence ending in a full stop.
Words that break the rule are replaced by the scope's words and reported; a condition is never refused
for its words.
4. **Whether the operator is needed is decided per condition, by its producer.** "Nothing for you to do."
is said where the mesh handles it or it passes by itself; "Needs you:" where only the operator can do
the next thing. A condition a healer gave up on (`resolver: operator` with attempts) that needed nothing
now needs the operator: its verdict becomes "Needs you:".
5. **A warning that needs nothing is not sent.** The operator channel keeps it open, its history says it
was kept quiet, and it is said the moment it needs the operator: when it becomes urgent at its bound, or
when its words change to "Needs you:". An urgent condition is always said. At this decision these kinds
need nothing while they are warnings:
- a walk waiting for its delivery's word (under four hours), or stuck at a step;
- a machine silent, not confirming a change, waiting for a push, its tools silent or unreachable, or its
network check failing or rewritten;
- a healer wanted, a listener behind, the bus being upgraded, a check that could not run, slow status,
outdated facts or instructions, a merge or build not picked up;
- a provider failing or silent, the mesh's own software restarting, an update put back on its first
machine, data not measured, and unused data the operator chose to keep.
6. **The notification offers its answers, and the operator channel performs them.**
- The holder of `operator-channel` gives each action, and **Details**, a token, and sends them with the
message. A message that offers answers is never folded into a digest.
- **The desk:** `node-notifier.send` takes actions (token and label). The dunst holder offers them
(dunst's actions: a middle click, or its context menu) and says the chosen token as its event
`action-chosen` {id, token, machine}. It is that module's event until seats publish events of their
own (to-be 46 phase 3), when it becomes the seat's.
- **The holder calls the action's verb itself**, with a why that names the operator, the channel and the
label ("the operator chose Release on the desktop notification …"), then edits the notification to say
what came of it: done, or the refusal in words. Details shows the summary, the key and since when, on
the machine that asked; a line the content rule refuses is said withheld.
- **The tier.** None of these verbs declares an authorising tier: each is a verb any granted principal
may already call, which is ADR 0234's *acknowledge*. So a desk click performs it, as ADR 0234 allows.
When to-be 46 phase 5 declares a tier for one of them, its answer goes through `authorise request` and
`answer` instead, and the desk asks for the code. Nothing here lowers ADR 0234's bar.
- **Telegram** shows the words and no buttons until it holds the `intake` seat (to-be 46 phase 6).
7. **Times are the operator's.** The body ends with since when, in the operator's time zone (the
messenger's setting `time-zone`): a clock time today, a weekday this week, a date before. A clearance is
one line: "Resolved:", the resolved line, and how long it was open. No message carries a key, an id, a
commit, a verb or markup; those stay in the controller's `conditions`, the holder's history and Details.
8. **A condition without plain words** (a controller older than this, or a module's `notify` without a
headline) is said from its summary, with its code spans taken out, and is never kept quiet. `notify`
accepts the same words.
## Consequences
- **The popup of issue 320 is not shown.** A walk waiting under four hours needs nothing; it is in
`conditions` and in `operator-channel.history`, marked as kept quiet. Past four hours it is urgent and
reads "openrazer delivery waiting to start", then "Needs you: start it, or stop it." and why, then "Since
12:40.", with the answers Start, Stop and Details. The operator chooses Start, and the notification says
"Start: done."
- A held delivery offers Release and Stop; a failed service, Restart; failed units nobody manages, and data
that shrank or went, Silence for a week; a module whose account waits for a new login says so, which no
button can do.
- **Some "Needs you:" have no button yet**, and say what to do in words: approving a retirement, deciding
where a module's data lives, undoing a catalogue change, restarting the controller, putting the bus back.
Their verbs either take what the operator must see first (`retire approve` takes the set it approves) or
need a terminal on another machine. Each is a next step: an action where a verb exists, the authorising
path of to-be 46 phase 5 where it must be proven.
- An answer is performed by the messenger's own grant. Its manifest invokes exactly the verbs its actions
name, and a new action names a new verb there. The verb's own record (a hand-act, a delivery's
transition) says who chose it, through the why.
- dunst waits for the answer in its bundle. A restart of that bundle ends the waits it held: the
notification stays and its answers do nothing then. A notification closed or expired says nothing.
- A new condition kind needs words, including its verdict. The controller's suite fails until it has them.
- The words are English, as everything else is.
## How it is checked
- **The controller** (`mesh-controller`):
- `internal/conditions/plain_test.go`: the plain rule refuses each shape it names; an explanation opens
with its verdict; words that send the operator to an agent, a session or "by hand" are refused; a
condition carries its producer's words, else its kind's, else its scope's, and the events carry them
all; an escalated condition turns "Nothing for you to do." into "Needs you:", once.
- `cmd/mesh-controller/plain_words_test.go`: the real notifications of issue 320, raised from the same
facts, each with its exact verdict, explanation and actions — a walk waiting under its bound (nothing)
and past it (Start, Stop, and the plan each calls), a module unhealthy (Restart, the unit and the
account's manager), relogin needed (no button), failed units (Silence), a healer wanted (nothing), a
delivery held (Release, Stop); and every registered wording plain for a subject of every scope.
- **A lint over the whole suite** (`sayable_test.go`): every condition raised in any test has words of
its producer or its kind, and they pass the rule.
- **The messenger** (`mesh-catalog`, `modules/messenger`), `words_test.go`: the same notifications decoded
from the events the controller sends: a warning that needs nothing is not shown and is kept as quiet in
the history; each shown one has its exact title, body and answers; choosing an answer calls exactly the
seat verb and arguments its condition names, with the operator's why, and edits the notification; the
clearance is one line. A quiet warning is said when it becomes urgent. Details are shown where they were
asked. The holder's tests fail a message that carries a key.
- **dunst** (`mesh-catalog`, `modules/dunst`), `actions_test.go`: `send` with actions answers the id before
the answer comes, asks `notify-send` for each action and to wait, says the chosen token as
`action-chosen` with the id and machine, says nothing for a notification closed without an answer or with
an answer it did not offer, and refuses actions it cannot carry.
- **Live**, once delivered: `operator-channel.history` shows warnings kept quiet; the next held delivery
shows Release and Stop on the desk; choosing one is in `mesh-delivery.show` with the operator's why.
## References
- [Issue 320](../04-ISSUES/320-the-operator-could-not-read-the-meshs-notifications/00-report.md)
- [Issue 277](../04-ISSUES/277-one-unanswered-question-was-an-urgent-alert-nobody-could-read/00-report.md)
(a summary held to the content rule; this record's lint sits beside that one)
- [ADR 0234](0234-the-mesh-holds-a-conversation-with-its-operator.md) (the channels, the content rule, the
tiers), [ADR 0227](0227-the-core-holds-nine-rules-each-checked-and-is-built-to-them-in-six-phases.md)
(rule 6: the mesh says when it is wrong), [ADR 0239](0239-a-delivery-is-owned-by-the-mesh-delivery-module-and-runs-from-commit-to-delivered.md)
(a walk waits for its delivery's word)
- [To-be 45](../03-DESIGN/01-to-be/45-a-core-that-cannot-fail-silently.md) §2 and §5;
[to-be 46](../03-DESIGN/01-to-be/46-the-conversation-with-the-operator.md) §11 and §13
@@ -4,6 +4,7 @@ status: in-progress
code: [mesh-controller, mesh-host, mesh-tools, mesh-catalog, mesh-sdk, mesh-lab]
updated: 2026-10-08
decisions:
- 02-DECISIONS/0253-a-condition-says-itself-to-the-operator-in-plain-words-beside-its-summary.md
- 02-DECISIONS/0240-a-module-says-how-it-is-healthy-and-the-node-engine-judges-it.md
- 02-DECISIONS/0239-a-delivery-is-owned-by-the-mesh-delivery-module-and-runs-from-commit-to-delivered.md
- 02-DECISIONS/0238-a-commit-is-the-build-at-hand-one-commit-one-change-plan-checked-off-the-trunk-and-published-only-on-it.md
@@ -126,7 +127,9 @@ cleared on the first that does not. Designed in [to-be 48](48-a-module-says-how-
| kind | the condition kind, from the signals table, the probe registry or an event kind |
| subject | scope, id, and the machine it concerns when there is one |
| severity | `urgent` (needs the operator now) or `warning` (when they can) — two levels, no more |
| summary | one line in the mesh's words |
| summary | one line in the mesh's words, for whoever looks closer: it may name plans, commits and verbs |
| headline, needs, explanation, resolved | what the operator reads, in plain words (ADR 0253): a few words naming the thing and what is wrong; the one thing the operator can do themselves, or nothing; the explanation, opened by its verdict ("Nothing for you to do." or "Needs you:" and that thing); the line said when it clears |
| actions | the answers a notification offers (Release, Stop, Start, Restart, Silence for a week), each a label and the seat verb the operator channel calls when it is chosen (ADR 0253) |
| evidence | the newest observations, at most ten, each with its time |
| source | the signals-table row, probe or event that raised it |
| raised, last observed | times; and how many observations since raised |
@@ -135,6 +138,18 @@ cleared on the first that does not. Designed in [to-be 48](48-a-module-says-how-
| silenced | until when, by whom, why — empty when not silenced |
| epoch | the controller lease epoch that last wrote it |
*Added 2026-10-08, [ADR 0253](../../02-DECISIONS/0253-a-condition-says-itself-to-the-operator-in-plain-words-beside-its-summary.md):*
**a condition says itself to the operator in plain words, beside its summary, and says whether the operator
is needed.** The headline, needs, explanation, resolved line and actions are made where the condition is
made: by the producer when it knows more than the subject (a walk's modules, a failed unit's name, a
hand-act's cause), otherwise by the wording registered for the kind, otherwise from the scope, which is
reported. The explanation opens with its verdict. All of it is held to the plain rule when the controller
takes an observation: no hash, numbered id, dotted name, duration in code, clock time, flag, markup or line
break; nothing that sends the operator to an agent or a session; and the content rule besides. Words that
break the rule are replaced by the scope's words, never refused. A condition a healer gave up on that needed
nothing now needs the operator. Checked by the plain rule's test and by a lint over every condition the
controller's suite raises, which fails a kind without words.
**The life of one:**
```
@@ -284,6 +299,16 @@ section; to-be 46 §13 builds what follows from it.
secrets, and this seat's holder becomes the router (to-be 46 §2, §3, §8).
- **A message** is: the condition's key, its subject (a machine's role, a module, a plan), kind,
severity, the one-line summary, since when, and the verb that shows more. **Deduplicated by the key.**
*Amended 2026-10-08, [ADR 0253](../../02-DECISIONS/0253-a-condition-says-itself-to-the-operator-in-plain-words-beside-its-summary.md):*
a message reads in one glance. Its title is the condition's headline, with "Urgent:", "Still open:" or
"Now urgent:" before it where that applies. Its body is the explanation, opened by its verdict, and since
when, in the operator's time zone (the messenger's setting `time-zone`). It offers the condition's
actions and Details; the desk takes the answer (`node-notifier.send` gains actions, and the dunst holder
says the chosen one as its event), and the holder calls the action's verb with the operator's why. It
carries no key, id, commit, verb or markup: those stay in `conditions`, the holder's history and
Details. **A warning that needs nothing is not sent**: it is kept, and said when it becomes urgent or
needs the operator. A clearance is one line, the resolved line and how long it was open. A digest lists
titles, and a message that offers answers is never in one. Still deduplicated by the key.
- **When:** on `condition-raised`; once more if still open after 1 hour (urgent) or 12 hours
(warning); on `condition-cleared`, by editing the first message where the channel can. A silenced
condition sends nothing. Urgent goes to both channels; warning to the desktop notifier when the
@@ -2,8 +2,9 @@
layer: to-be
status: designed
code: []
updated: 2026-10-06
updated: 2026-10-08
decisions:
- 02-DECISIONS/0253-a-condition-says-itself-to-the-operator-in-plain-words-beside-its-summary.md
- 02-DECISIONS/0234-the-mesh-holds-a-conversation-with-its-operator.md
- 02-DECISIONS/0227-the-core-holds-nine-rules-each-checked-and-is-built-to-them-in-six-phases.md
---
@@ -448,6 +449,11 @@ needs the lost factor's code. So:
- **`node-notifier.send` gains actions** (token, label). It still answers at once; the dunst holder
listens for the chosen action and emits it as an event on its node seat.
*Amended 2026-10-08, [ADR 0253](../../02-DECISIONS/0253-a-condition-says-itself-to-the-operator-in-plain-words-beside-its-summary.md):*
built ahead of the router for the answers a condition offers. Until seats publish events of their own
(phase 3) the chosen token is the dunst module's event `action-chosen` {id, token, machine}, and the
output seat's holder takes it and calls the action's verb. Only verbs that declare no tier are offered
so; one that declares a tier waits for phase 5.
- The router's desktop adapter, holding `channel/desktop` and `intake/desktop`, turns that into a
`choice` envelope.
- **For `text`, `number`, `date` and codes**, the notification's single action opens the
@@ -0,0 +1,94 @@
---
status: located
opened: 2026-10-08
located-in: [mesh-controller internal/conditions (the condition's words), mesh-controller cmd/mesh-controller (every producer of a condition), mesh-catalog modules/messenger (compose, the digest, the answers), mesh-catalog modules/dunst (the desk's actions)]
fixed-by: novox/mesh-controller PR #141, novox/mesh-catalog PR #126
amended-design: 03-DESIGN/01-to-be/45-a-core-that-cannot-fail-silently.md
---
# 320. The operator could not read the mesh's notifications
## Symptom
On 2026-10-08 the operator said they could not read the mesh's desktop notifications. One, exactly as
it appeared on the laptop, with the plan id and the commit replaced here by placeholders:
> CLEARED after 26 min: the walk of novox/mesh-catalog `<commit>` has waited 56m0s for mesh-delivery's
> word to start: `mesh-delivery.show` for the delivery that landed as `<commit>` says why; `plans go
> <plan id> --why ...` starts it by hand
> about: plan `<plan id>` (waiting)
> since: 2026-10-08 10:40 UTC
> key: plan.`<plan id>`.waiting
> more: conditions show plan.`<plan id>`.waiting
What is wrong with it, as the operator listed it:
- It is a wall of text, five lines and some sixty words for one fact.
- It is full of identifiers: a plan id, a commit, a condition key and a verb's syntax.
- Its time is UTC, not the operator's.
- Its backticks are markdown, which a desktop popup shows literally.
- A clearance repeats the whole problem.
- It does not say in plain words what happened, whether the operator needs to act, or what to do.
The same shape held for every open condition on the mesh that day: a module unhealthy on the laptop
("… its unit `<name>.service` failed in the account's own service manager (exit-code)"), three failed
units on a workstation, a cause repaired by hand thirty-five times, five deliveries held past their bound,
each with `mesh-delivery.show <repository>@<commit>` in its line.
**A first fix was read, and still failed.** Reworded in plain words, the same popup said "… Nothing to do
yet; it becomes urgent after 4 hours. To start it now, have an agent start it by hand." The operator asked:
*what does that notification mean, I need to do something? I need to open a session and tell it to deliver
it?* It did not say plainly whether they were needed; it was shown although it needed nothing; and the only
thing it offered was a session.
## Cause
**The condition had one line of words, and it served two readers.** To-be 45 §2 gave a condition one
`summary`, "one line in the mesh's words", and §5 made a message out of that summary with the key,
subject, kind, since-when and the verb that shows more. The summary was written for whoever looks closer
— an agent at the mesh MCP server, a person reading `conditions` — and rightly carried what they act on:
the plan, the commit, the verb. Nothing in the condition was written for the operator who reads a popup
between other work, so the channel showed the agent's line to the operator.
Issue 277 had already found the narrower half: a summary carried detail the content rule refuses, and the
controller now holds every summary to that rule. Identifiers, verbs and markup pass that rule — they are
not addresses, paths or secrets — so they reached the operator untouched.
**Nothing said whether the operator was needed, or let them answer.** No field of a condition said whether
the operator was needed, so every warning was shown, and an explanation could imply an instruction. The
verbs that answer the common cases existed (release or stop a delivery, start a waiting walk, restart a
service, silence a condition), but the desk could not take an answer: `node-notifier.send` had no actions,
and the conversation design that adds them (to-be 46) was not built. The one way to act was a session.
**The message added its own detail.** The messenger's compose added `about:`, `since:` in UTC, `key:` and
`more:` lines to every message, and a digest added each key in brackets. A clearance was the whole
summary again behind "CLEARED after …".
## Fix
[ADR 0253](../../02-DECISIONS/0253-a-condition-says-itself-to-the-operator-in-plain-words-beside-its-summary.md):
every condition carries, beside its summary, a **headline**, what it **needs** of the operator, an
**explanation** opened by its verdict ("Nothing for you to do." or "Needs you:"), a **resolved line** and
its **actions**, made where the condition is made and held to a checked plain rule. A warning that needs
nothing is not sent. The desk offers the actions, and the operator channel's holder performs the chosen one
through its seat verb. Every channel says the time in the operator's zone; a clearance is one line.
- novox/mesh-controller: the condition's three new fields, the plain rule, a wording for every kind the
controller raises, the richer words at the producers that know more (a walk's modules, a unit's name, a
hand-act's cause, a delivery's repository), and a lint over every condition the suite raises.
- novox/mesh-catalog: the messenger shows the words, keeps quiet what needs nothing, offers and performs
the answers, says since when in the operator's zone (the new setting `time-zone`), says a clearance in
one line, names nothing but titles in a digest, and lets a module give the same words through `notify`;
dunst's `send` takes actions and says the chosen one as its event.
## How it is checked
ADR 0253 §How it is checked: the plain rule's own test, a test per real notification above showing the
words before and after, the suite-wide lint, and the messenger's tests of the four messages as the desktop
shows them.
## Design
To-be 45 §2 gains the fields, and §5's message is no longer the key, kind and verb but the headline, the
explanation with its verdict, since when and the answers; a warning that needs nothing is not sent. To-be
46 §11 notes the desk's actions built ahead of its router.