Say each notification in plain words the operator reads at a glance
mesh/merge-gate pass: builds messenger → novox; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery-group group feat/plain-notifications ready: every member ready, and composed together they pass
mesh/delivery superseded: a newer head of the same pull request

The desktop popups were walls of plan ids, commits, keys and verb syntax in UTC.
The messenger now shows the condition's headline, explanation and resolved line,
since when in the operator's time zone, and a clearance in one line (hq ADR 0253).
This commit is contained in:
jochen
2026-10-08 13:26:26 +02:00
parent c78b5fc9f5
commit a6296dfd6f
12 changed files with 573 additions and 116 deletions
+13 -1
View File
@@ -35,6 +35,15 @@ what is said is decided by the state now and by when a thing happened, never by
- **Start grace.** Nothing is sent in the **first minute** after start but that one urgent message;
what arrives meanwhile goes out, coalesced, when the minute ends.
**A message reads in one glance** (novox/hq ADR 0253). Its title is the condition's headline — a few
plain words such as "openrazer not working on g14" — prefixed "Urgent:", "Still open:" or "Now urgent:"
where that applies; its body is the condition's explanation (what happened, what it means, whether the
operator needs to act) and since when, in the operator's time zone. No key, id, commit, command or markup:
those stay in the controller's `conditions` and in this module's history. A clearance is one line, the
condition's resolved line and how long it was open: "Resolved: openrazer works again on g14, after 26 min".
A condition from a controller older than plain words, or a module's notice without a headline, is said from
its summary, with code spans taken out (`cmd/messenger/words.go`).
| When | What |
|---|---|
| `condition-raised` | one message, deduplicated by the condition's key |
@@ -76,6 +85,9 @@ Nothing is sent until these are given; `messenger_status` says which is missing.
2. **The chat id**, as a setting: `settings` for `messenger` with `{"telegram-chat-id": "<id>"}`.
3. **The desktop machines**, as a setting: `{"desktop-machines": ["<the machine the operator sits at>", …]}`.
Without it, warnings go to Telegram.
4. **The time zone**, as a setting: `{"time-zone": "<an IANA zone name>"}`. Every time a message says is
said in it; not given, the zone of the machine this runs on. A name this machine does not know is
logged and that zone used instead.
## Tools
@@ -83,7 +95,7 @@ Nothing is sent until these are given; `messenger_status` says which is missing.
|---|---|
| `operator-channel.open` | what is open now, urgent first, with where it went, silenced, reminded, held, refused, unsent |
| `operator-channel.history` | what was said lately, and the refusals |
| `operator-channel.notify` | a message from a module using the seat: key, severity, summary; `clear` to end it |
| `operator-channel.notify` | a message from a module using the seat: key, severity, summary, and best a plain `headline`, `explanation` and `resolved` line; `clear` to end it |
| `messenger_status` | whether the operator can be reached and why not; `check` asks Telegram whether the token works |
| `messenger_recent` | the recent sends, edits, digests and failures |
| `messenger_test` | a test message now, to telegram, desktop or both |