Issue 324 and ADR 0258: a desk click performs only an acknowledgement
Review found that ADR 0253 let any process at the operator's session release, stop or start a delivery in the operator's name, and that its tokens, fallback words and quiet warnings failed on the paths that go wrong.
This commit is contained in:
+7
@@ -132,6 +132,13 @@ What the mesh had, on the main branches of 2026-10-08:
|
||||
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.
|
||||
> **The mechanism changed — 2026-10-08, by [ADR 0258](0258-a-desk-click-performs-only-an-acknowledgement-and-an-answer-is-a-one-time-ticket.md).**
|
||||
> What stands: a notification offers answers and the operator channel performs them. What moved: a desk click
|
||||
> performs only an acknowledgement (Details, Silence for a week) until answers are authorised; release, stop,
|
||||
> start and restart are said in words. The reading of *acknowledge* below, and the promise to honour a tier
|
||||
> "when one exists", were enforced by nothing and are replaced there, with one-time tokens, a verdict that is
|
||||
> never weakened and a change of words that is said.
|
||||
|
||||
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.
|
||||
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
---
|
||||
topic: the mesh
|
||||
status: accepted
|
||||
date: 2026-10-08
|
||||
deciders: jochen
|
||||
reconstructed: false
|
||||
extends: 02-DECISIONS/0253-a-condition-says-itself-to-the-operator-in-plain-words-beside-its-summary.md
|
||||
---
|
||||
|
||||
# 258. A desk click performs only an acknowledgement, an answer is a one-time ticket, and a verdict is never weakened
|
||||
|
||||
## Context
|
||||
|
||||
ADR 0253 was merged before its review finished
|
||||
([issue 324](../04-ISSUES/324-a-desk-click-could-answer-in-the-operators-name/00-report.md)). The review found
|
||||
that its §6 let a desk click release, stop or start a delivery and restart a service in the operator's
|
||||
name. Any process of the operator's account can choose a desktop notification's action: dunst's own
|
||||
`dunstctl action` does it, and every agent that runs as the operator can run it. A click therefore proves
|
||||
that something at the operator's session chose, not that the operator did. ADR 0234 §8 holds exactly that:
|
||||
"a desk click alone never authorises". ADR 0253 §6 read *acknowledge* as any verb no table had tiered, and
|
||||
said a tier would be honoured once one existed. No tier field exists in the code, so nothing enforced that.
|
||||
|
||||
The review also found that answer tokens never expired and could be reused or replayed; that words refused by
|
||||
the plain rule weakened "Needs you" to "Nothing for you to do"; that the rule refused sound words; that a
|
||||
quiet warning whose words came to need the operator was never said; and that the desk's answers died with a
|
||||
ten-second notification or a restart of the notifier's bundle.
|
||||
|
||||
## Considered Options
|
||||
|
||||
1. **Keep §6, and ask for the operator's code at the desk** (ADR 0234's P2). That is to-be 46 phase 5: the
|
||||
factor, its enrolment and recovery, and the controller's authorise verbs. Not built, and not small.
|
||||
Rejected for now; it is the way the other answers come back.
|
||||
2. **Trust the click, and say so in the why.** The record would still say an action was the operator's
|
||||
when anything at the session could have chosen it. Rejected: failure must be loud, and a false
|
||||
attribution is quiet.
|
||||
3. **Offer only what is an acknowledgement in the plain sense:** Details, which performs nothing, and
|
||||
silencing a condition, which ADR 0234 names as acknowledge ("silencing, announced"). Everything else is
|
||||
said in words. Chosen.
|
||||
|
||||
## Decision
|
||||
|
||||
1. **A desk click performs only an acknowledgement**, until answers are authorised (to-be 46 phase 5):
|
||||
- **Details**, which performs nothing;
|
||||
- **Silence for a week**, through `conditions silence` with a why and the cause `operator-answer`.
|
||||
|
||||
The operator channel's holder keeps this as an explicit allow-list and refuses everything else. A
|
||||
condition's actions outside it are never offered, and a token for one is refused without a call. The
|
||||
controller offers no other action. **Release, stop, start and restart are said in words**: "Needs you:
|
||||
release it, or stop it." with no button. This replaces ADR 0253 §6's reading of *acknowledge* and its
|
||||
promise to honour a tier.
|
||||
2. **An answer is a one-time ticket.** A token is made for one message of one condition, together with the
|
||||
other tokens of that message; a newer message's tokens replace them. It is bound to the machines the
|
||||
message was shown on, good for a day, and used once. It is refused for a condition that cleared or is
|
||||
silenced, from another machine, used, expired or unknown. One event is acted on once, by its id. **A
|
||||
refused answer is said on the desk where it was chosen**, never dropped.
|
||||
3. **The why says what is known**: "chosen on the desktop notification … on `<machine>` (a desk click:
|
||||
whoever was at the operator's session)". A silence chosen on the desk is a decision, not a repair, and
|
||||
does not count toward a healer wanted.
|
||||
4. **A verdict is never weakened.** When a producer's words break the plain rule, the scope's words are said.
|
||||
If the producer needed the operator, its verdict stays "Needs you:" with "read the details to see what to
|
||||
do.", and its sound answers stay.
|
||||
5. **The plain rule refuses no plain words.** It refuses "agent" and, in what the operator needs, "by hand",
|
||||
but not "session". It reads "e.g." and "i.e." as words. A number is a hash only with letters a to f in it.
|
||||
An explanation too long is cut at a word, not refused.
|
||||
6. **A change of words is said.** The controller emits `condition-changed` (change `words`) when what a
|
||||
condition needs or offers changes. The holder says a warning it kept quiet when its words now need the
|
||||
operator, whether it learns that from the event or from a reading of the state. It also says once, after
|
||||
a day, a warning still kept quiet, so nothing stays silent for ever.
|
||||
7. **The desk's answers stay and come back.** A notification that offers answers stays until it is
|
||||
dismissed. When the notifier's bundle starts, it says `started`, and the holder shows the open
|
||||
notifications that offer answers there again, with fresh tokens.
|
||||
8. **The operator's zone is always known**: the holder carries the zone data, whatever the machine has
|
||||
installed.
|
||||
|
||||
## Consequences
|
||||
|
||||
- The delivery-waiting popup past its bound reads "Needs you: start it, or stop it. …" and offers Details
|
||||
only. Starting or stopping it is not possible from the desk until phase 5. That is the honest state,
|
||||
and the words say where the decision lies.
|
||||
- Failed services nobody manages, and data that shrank or went, still offer Silence for a week.
|
||||
- ADR 0253's other rules stand: the plain words, the verdict, the quiet rule, the time zone and the one-line
|
||||
clearance. Its §6 and the consequence "the verb's own record … says who chose it" are replaced here.
|
||||
- An answer chosen in a notification shown before a newer message about the same condition is refused,
|
||||
and the refusal is shown.
|
||||
|
||||
## How it is checked
|
||||
|
||||
- **The messenger** (`mesh-catalog`, `modules/messenger/cmd/messenger/answers_test.go`):
|
||||
- only an acknowledgement is answerable: Release, Restart, Start and a silence carrying another argument
|
||||
are refused by the allow-list, never offered, and a token for one put in the state is refused without a
|
||||
call and said on the desk;
|
||||
- at most four answers, Details included;
|
||||
- the same token twice is refused the second time, and the same event is acted on once;
|
||||
- a token is refused from another machine, when unknown, past its day, and for a condition silenced or
|
||||
cleared;
|
||||
- a verb the mesh refuses is said on the notification;
|
||||
- a words-only change to "Needs you" after a quiet time is said, through the event and through a reading of
|
||||
the state, and a quiet warning is said once after a day;
|
||||
- a notifier that started again is offered the open answers with fresh tokens, the old ones refused.
|
||||
|
||||
`words_test.go` holds the real notifications of issue 320 to their exact words and answers.
|
||||
- **dunst** (`modules/dunst/cmd/dunst-tools/actions_test.go`): a notification with answers is sent with no
|
||||
expiry; the bundle says `started`. Checked live on the laptop on 2026-10-08: `notify-send --print-id --wait`
|
||||
writes the id into a pipe at once, and "Wait timeout expired" when the notification expired. The latter is
|
||||
not a token, so it says nothing.
|
||||
- **The controller** (`mesh-controller`):
|
||||
- `internal/conditions/plain_test.go`: the words the rule refused wrongly pass, and a long explanation is
|
||||
cut; refused words keep their verdict and answers; a change of words is a `condition-changed`.
|
||||
- `cmd/mesh-controller/plain_words_test.go`: the module, held-delivery and waiting conditions offer no
|
||||
answer; the relogin words and the kind `relogin-needed` (ADR 0254) are held to the plain rule; a silence
|
||||
with the cause `operator-answer` does not count toward a healer wanted, and one by hand still does.
|
||||
|
||||
## References
|
||||
|
||||
- [Issue 324](../04-ISSUES/324-a-desk-click-could-answer-in-the-operators-name/00-report.md),
|
||||
[issue 320](../04-ISSUES/320-the-operator-could-not-read-the-meshs-notifications/00-report.md)
|
||||
- [ADR 0253](0253-a-condition-says-itself-to-the-operator-in-plain-words-beside-its-summary.md) (§6 replaced
|
||||
here), [ADR 0234](0234-the-mesh-holds-a-conversation-with-its-operator.md) §8 (the tiers, and the desk
|
||||
click)
|
||||
- [To-be 46](../03-DESIGN/01-to-be/46-the-conversation-with-the-operator.md) §11 and §13 phase 5
|
||||
@@ -129,7 +129,7 @@ cleared on the first that does not. Designed in [to-be 48](48-a-module-says-how-
|
||||
| severity | `urgent` (needs the operator now) or `warning` (when they can) — two levels, no more |
|
||||
| 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) |
|
||||
| actions | the answers a notification offers, each a label and the seat verb the operator channel calls when it is chosen (ADR 0253); a desk click performs only an acknowledgement — Details, Silence for a week — until answers are authorised (ADR 0258) |
|
||||
| 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 |
|
||||
@@ -304,7 +304,11 @@ section; to-be 46 §13 builds what follows from it.
|
||||
"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
|
||||
says the chosen one as its event), and the holder calls the action's verb with a why saying it was a desk
|
||||
click. *Amended 2026-10-08, [ADR 0258](../../02-DECISIONS/0258-a-desk-click-performs-only-an-acknowledgement-and-an-answer-is-a-one-time-ticket.md):*
|
||||
only an acknowledgement (Details, Silence for a week) is offered or performed; each answer is a one-time
|
||||
token bound to its condition and machine, good for a day; a change of words to "Needs you" is a
|
||||
`condition-changed`, and a quiet warning is said once after a day. 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
|
||||
|
||||
@@ -452,8 +452,10 @@ needs the lost factor's code. So:
|
||||
*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.
|
||||
output seat's holder takes it and calls the action's verb.
|
||||
*Amended 2026-10-08, [ADR 0258](../../02-DECISIONS/0258-a-desk-click-performs-only-an-acknowledgement-and-an-answer-is-a-one-time-ticket.md):*
|
||||
only an acknowledgement (Details, silencing) is offered so: any process of the account can choose an
|
||||
action, so a click is never taken for the operator's word. Every other answer 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,60 @@
|
||||
---
|
||||
status: located
|
||||
opened: 2026-10-08
|
||||
located-in: [mesh-catalog modules/messenger (the answers, the quiet rule), mesh-catalog modules/dunst (the desk's actions), mesh-controller internal/conditions (the plain rule, the change of words)]
|
||||
fixed-by:
|
||||
amended-design: 03-DESIGN/01-to-be/45-a-core-that-cannot-fail-silently.md
|
||||
---
|
||||
|
||||
# 324. A desk click could answer in the operator's name
|
||||
|
||||
## Symptom
|
||||
|
||||
ADR 0253 (issue 320) was merged at the operator's request before its review had finished. The
|
||||
controller's part began to roll out; the build of the operator channel's holder and the desktop notifier was
|
||||
published and waited for its delivery's word, so it was not yet live. The review then found:
|
||||
|
||||
1. **A desk click could release, stop or start a delivery, or restart a service, in the operator's name.**
|
||||
Any process of the operator's account can choose a desktop notification's action (`dunstctl action`), so
|
||||
a click proves nothing about who chose. The holder then recorded "the operator chose Release". ADR 0234 §8
|
||||
says a desk click alone never authorises. ADR 0253 §6 said these verbs were acknowledgements because none
|
||||
declared a tier, and that a tier would be honoured once one existed; no tier field exists in any code, so
|
||||
that promise was enforced by nothing.
|
||||
2. **An answer's token lived for ever.** It could be used twice, for a condition cleared or silenced, from
|
||||
another machine, and a redelivered event would be acted on again.
|
||||
3. **Refused words weakened the verdict.** When a producer's words broke the plain rule, the condition was
|
||||
said in its scope's words, which needed nothing: "Needs you" became "Nothing for you to do", and the
|
||||
answers were dropped. The rule also refused sound words: "session" (as in "log out of every session",
|
||||
the words a new login needs), "e.g.", any number of seven digits or more, and an explanation one word too
|
||||
long.
|
||||
4. **A warning kept quiet could stay quiet for ever.** A change of its words to "Needs you" emitted no event
|
||||
(only severity, resolver and silence did), the holder's reading of the state did not look for it, and
|
||||
nothing said a quiet warning however long it stayed open.
|
||||
5. **The desk's answers died.** A warning's notification expired in dunst's ten seconds with its answers; a
|
||||
restart of the notifier's bundle ended the waits it held, and a click after it did nothing, silently.
|
||||
6. The time zone depended on the machine having zone data installed. ADR 0253 said "the verb's own record
|
||||
says who chose it", which was false for a restart (it takes no why). A silence chosen on the desk would
|
||||
have counted as a hand repair toward a healer wanted.
|
||||
|
||||
## Cause
|
||||
|
||||
The decision outran its review: it read ADR 0234's *acknowledge* ("what any granted principal may already
|
||||
do") as covering any verb no table had tiered, without asking what a desk click proves. The tokens, the
|
||||
fallback, the event for a change of words and the notifier's restart were each designed for the path that
|
||||
works, not for the path that fails.
|
||||
|
||||
## Fix
|
||||
|
||||
[ADR 0258](../../02-DECISIONS/0258-a-desk-click-performs-only-an-acknowledgement-and-an-answer-is-a-one-time-ticket.md)
|
||||
on the branch `fix/notifications-after-review` in hq, mesh-controller and mesh-catalog.
|
||||
|
||||
## How it is checked
|
||||
|
||||
ADR 0258 §How it is checked: a test for every point above, including the same token twice, a cleared or
|
||||
silenced token, a forged and another machine's answer, a refused verb, a words-only change after a quiet time
|
||||
through the event and the reading of the state, the relogin words held to the plain rule, the fallback keeping
|
||||
its verdict and answers, and the four-answer limit.
|
||||
|
||||
## Design
|
||||
|
||||
To-be 45 §2 and §5 and to-be 46 §11 say the desk performs only an acknowledgement.
|
||||
Reference in New Issue
Block a user