Fixes issue 371 (Details refused "it belongs to no open message" on Telegram and the desk).
Cause
choices() in modules/messenger/cmd/messenger/answers.go deleted a record's earlier Details ticket on a channel kind every time a newer message about the same record was composed. Seen on 2026-10-10: seat.operator-channel.unasked was sent on Telegram as "escalated" at 12:57:49 and as "reminder" at 12:58:20, so the first message's Details was dead; the two taps at 13:30:34 and 13:30:36 were refused. takeWords also dropped every ticket when a condition's actions changed.
Fix
Each message gets a ticket of its own; older ones stand. Still one-time, still kind-bound, still refused for a cleared or silenced record, and Details still performs nothing (ADR 0258/0259).
Bounded: at most MostDetails (8) per record and kind, none older than TokenFor (24 h), pruned whenever a new one is made.
A ticket pushed out by the bound is refused in plain words: "... this message is older than the last few about it: tap Details on the newest one".
A change of the condition's actions keeps Details tickets (Details names no action).
Tests
details_test.go: three warnings in a row (one problem said three times, and three problems), Details works on each once and a second tap is refused; the bound in number and time; Details survives an actions change; Details on a message with an open ask issues no warrant and leaves the ask open. Mutation-checked: restoring the old replacement, the old reset in takeWords, removing the bound, or not marking a ticket used each fails a new test.
Acceptance: the operator receives three warnings in a row and Details works on each of them, once each.
Fixes issue 371 (Details refused "it belongs to no open message" on Telegram and the desk).
## Cause
`choices()` in `modules/messenger/cmd/messenger/answers.go` deleted a record's earlier Details ticket on a channel kind every time a newer message about the same record was composed. Seen on 2026-10-10: `seat.operator-channel.unasked` was sent on Telegram as "escalated" at 12:57:49 and as "reminder" at 12:58:20, so the first message's Details was dead; the two taps at 13:30:34 and 13:30:36 were refused. `takeWords` also dropped every ticket when a condition's actions changed.
## Fix
- Each message gets a ticket of its own; older ones stand. Still one-time, still kind-bound, still refused for a cleared or silenced record, and Details still performs nothing (ADR 0258/0259).
- Bounded: at most `MostDetails` (8) per record and kind, none older than `TokenFor` (24 h), pruned whenever a new one is made.
- A ticket pushed out by the bound is refused in plain words: "... this message is older than the last few about it: tap Details on the newest one".
- A change of the condition's actions keeps Details tickets (Details names no action).
## Tests
`details_test.go`: three warnings in a row (one problem said three times, and three problems), Details works on each once and a second tap is refused; the bound in number and time; Details survives an actions change; Details on a message with an open ask issues no warrant and leaves the ask open. Mutation-checked: restoring the old replacement, the old reset in `takeWords`, removing the bound, or not marking a ticket used each fails a new test.
Acceptance: the operator receives three warnings in a row and Details works on each of them, once each.
A newer message about the same problem (an escalation, a reminder, a re-send) replaced the Details
ticket of the one before it on that channel kind, so tapping Details on any but the newest was refused
"it belongs to no open message". Each message now keeps a ticket of its own, used once, at most
MostDetails per record and kind and none older than TokenFor; one pushed out is refused in words that
send the operator to the newest message. A change of the condition's actions no longer drops Details,
which names no action.
Deliverynovox/mesh-catalog@6a8c718f440c — delivered since 2026-10-10T11:53:52Z
Delivery plan — builds messenger → novox; no bus step
tier 0: messenger
novox: receives messenger
Machines
messenger on novox: passed — healthy 3 times over 3m44s
messenger on the rest running it: sent
Transitions
2026-10-10 11:46 (new) → proposed (announced): novox/mesh-catalog#174's head announced
2026-10-10 11:48 proposed → checked (checked): the verdict names this commit
2026-10-10 11:48 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
2026-10-10 11:49 ready → published (merged): on the trunk its modules follow: merged there, and its walk opened — or nothing for a walk to move
2026-10-10 11:49 published → delivering (go): its walk started: let go by this owner in its group's order, by a person, or on the controller's own path — not a failed walk that carried a later commit for it, after which it waits for a walk of its own commit
2026-10-10 11:53 delivering → delivered (done): its walk is done, carrying its own commit: every machine of its deploy plan passed, or was left as its policy says
The commit's note under refs/notes/mesh-plan keeps every transition: git log --notes=mesh-plan.
<!-- mesh-delivery:view -->
**Delivery** `novox/mesh-catalog@6a8c718f440c` — **delivered** since 2026-10-10T11:53:52Z
**Delivery plan** — builds messenger → novox; no bus step
- tier 0: messenger
- novox: receives messenger
**Machines**
- messenger on novox: passed — healthy 3 times over 3m44s
- messenger on the rest running it: sent
**Transitions**
- 2026-10-10 11:46 (new) → proposed (announced): novox/mesh-catalog#174's head announced
- 2026-10-10 11:48 proposed → checked (checked): the verdict names this commit
- 2026-10-10 11:48 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
- 2026-10-10 11:49 ready → published (merged): on the trunk its modules follow: merged there, and its walk opened — or nothing for a walk to move
- 2026-10-10 11:49 published → delivering (go): its walk started: let go by this owner in its group's order, by a person, or on the controller's own path — not a failed walk that carried a later commit for it, after which it waits for a walk of its own commit
- 2026-10-10 11:53 delivering → delivered (done): its walk is done, carrying its own commit: every machine of its deploy plan passed, or was left as its policy says
The commit's note under `refs/notes/mesh-plan` keeps every transition: `git log --notes=mesh-plan`.
The review found that each try at an unready channel composed its held messages and so made a Details
ticket for each, and enough tries pushed out the tickets of messages already shown.
mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: messenger)
mesh/repo-check: PASS — its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)
Delivery plan — builds messenger → novox; no bus step
tier 0: messenger
novox: receives messenger
Run by the build seat on g14 as build-1791632735293304621 (builds --log build-1791632735293304621).
--- the gate: messenger
messenger: ok, 6 tool(s), invokes seat:mesh-controller.conditions, seat:mesh-controller.root-free, keeps state open, sent, asks, identities; WARNING: settings ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339)
long-running resources without health: 0
files asking for a setting without saying whether it is trusted: 1
1 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here
judging 0 module(s) changed against 4 machine(s), as the snapshot of 2026-10-10T11:45:18Z says they run
composing every machine as the mesh is
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
composing every machine with the change
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
merge gate: PASS — every machine composes with the change as it did without (4 of 4 compose)
judged by controller development build against the facts of 2026-10-10T11:45:18Z
machines:
- a machine (f35): composes
- holds mesh-dns-resolver (idt): composes
- holds git, holds mesh-artifact-store, holds mesh-broker, holds mesh-catalog, holds mesh-delivery, holds mesh-dns-resolver, holds mesh-store, holds mesh-vault, holds npm-package-registry, the control node, the hub (ygcyr): composes
- a machine (yvbpsm): composes
a merge would rebuild 1 module(s) in 1 tier(s): messenger
--- its merge-check.sh (go toolchain)
ok git.novox.be/novox/mesh-catalog/checks/words 0.003s
words: 12 retired words and 70 daemons' lines, none in the 37423 strings of 637 files
ok git.novox.be/novox/mesh-catalog/checks/agenthome 0.009s
agent-home: no archive and no file written into under the agent's home
ok git.novox.be/novox/mesh-catalog/checks/paths 0.005s
paths: no module names another's state on its machine (3 known, listed to go)
long-running resources without health: 70, as kept
testing modules/messenger
ok messenger/cmd/messenger 1.760s
--- its merge-check-typescript.sh (typescript toolchain)
**Merge check** at `bb96f4d1`
- `mesh/merge-gate`: **PASS** — every machine composes with the change as it did without (4 of 4 compose) (modules: messenger)
- `mesh/repo-check`: **PASS** — its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)
**Delivery plan** — builds messenger → novox; no bus step
- tier 0: messenger
- novox: receives messenger
Run by the build seat on g14 as `build-1791632735293304621` (`builds --log build-1791632735293304621`).
```
--- the gate: messenger
messenger: ok, 6 tool(s), invokes seat:mesh-controller.conditions, seat:mesh-controller.root-free, keeps state open, sent, asks, identities; WARNING: settings ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339)
long-running resources without health: 0
files asking for a setting without saying whether it is trusted: 1
1 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here
judging 0 module(s) changed against 4 machine(s), as the snapshot of 2026-10-10T11:45:18Z says they run
composing every machine as the mesh is
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
composing every machine with the change
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
merge gate: PASS — every machine composes with the change as it did without (4 of 4 compose)
judged by controller development build against the facts of 2026-10-10T11:45:18Z
machines:
- a machine (f35): composes
- holds mesh-dns-resolver (idt): composes
- holds git, holds mesh-artifact-store, holds mesh-broker, holds mesh-catalog, holds mesh-delivery, holds mesh-dns-resolver, holds mesh-store, holds mesh-vault, holds npm-package-registry, the control node, the hub (ygcyr): composes
- a machine (yvbpsm): composes
a merge would rebuild 1 module(s) in 1 tier(s): messenger
--- its merge-check.sh (go toolchain)
ok git.novox.be/novox/mesh-catalog/checks/words 0.003s
words: 12 retired words and 70 daemons' lines, none in the 37423 strings of 637 files
ok git.novox.be/novox/mesh-catalog/checks/agenthome 0.009s
agent-home: no archive and no file written into under the agent's home
ok git.novox.be/novox/mesh-catalog/checks/paths 0.005s
paths: no module names another's state on its machine (3 known, listed to go)
long-running resources without health: 70, as kept
testing modules/messenger
ok messenger/cmd/messenger 1.760s
--- its merge-check-typescript.sh (typescript toolchain)
```
mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: messenger)
mesh/repo-check: PASS — its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)
Delivery plan — builds messenger → novox; no bus step
tier 0: messenger
novox: receives messenger
Run by the build seat on ace as build-1791632797532113347 (builds --log build-1791632797532113347).
--- the gate: messenger
messenger: ok, 6 tool(s), invokes seat:mesh-controller.conditions, seat:mesh-controller.root-free, keeps state open, sent, asks, identities; WARNING: settings ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339)
long-running resources without health: 0
files asking for a setting without saying whether it is trusted: 1
1 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here
judging 0 module(s) changed against 4 machine(s), as the snapshot of 2026-10-10T11:45:18Z says they run
composing every machine as the mesh is
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
composing every machine with the change
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
merge gate: PASS — every machine composes with the change as it did without (4 of 4 compose)
judged by controller development build against the facts of 2026-10-10T11:45:18Z
machines:
- a machine (f35): composes
- holds mesh-dns-resolver (idt): composes
- holds git, holds mesh-artifact-store, holds mesh-broker, holds mesh-catalog, holds mesh-delivery, holds mesh-dns-resolver, holds mesh-store, holds mesh-vault, holds npm-package-registry, the control node, the hub (ygcyr): composes
- a machine (yvbpsm): composes
a merge would rebuild 1 module(s) in 1 tier(s): messenger
--- its merge-check.sh (go toolchain)
ok git.novox.be/novox/mesh-catalog/checks/words 0.002s
words: 12 retired words and 70 daemons' lines, none in the 37423 strings of 637 files
ok git.novox.be/novox/mesh-catalog/checks/agenthome 0.012s
agent-home: no archive and no file written into under the agent's home
ok git.novox.be/novox/mesh-catalog/checks/paths 0.005s
paths: no module names another's state on its machine (3 known, listed to go)
long-running resources without health: 70, as kept
testing modules/messenger
ok messenger/cmd/messenger 1.612s
--- its merge-check-typescript.sh (typescript toolchain)
**Merge check** at `6a8c718f`
- `mesh/merge-gate`: **PASS** — every machine composes with the change as it did without (4 of 4 compose) (modules: messenger)
- `mesh/repo-check`: **PASS** — its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)
**Delivery plan** — builds messenger → novox; no bus step
- tier 0: messenger
- novox: receives messenger
Run by the build seat on ace as `build-1791632797532113347` (`builds --log build-1791632797532113347`).
```
--- the gate: messenger
messenger: ok, 6 tool(s), invokes seat:mesh-controller.conditions, seat:mesh-controller.root-free, keeps state open, sent, asks, identities; WARNING: settings ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339)
long-running resources without health: 0
files asking for a setting without saying whether it is trusted: 1
1 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here
judging 0 module(s) changed against 4 machine(s), as the snapshot of 2026-10-10T11:45:18Z says they run
composing every machine as the mesh is
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
composing every machine with the change
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
merge gate: PASS — every machine composes with the change as it did without (4 of 4 compose)
judged by controller development build against the facts of 2026-10-10T11:45:18Z
machines:
- a machine (f35): composes
- holds mesh-dns-resolver (idt): composes
- holds git, holds mesh-artifact-store, holds mesh-broker, holds mesh-catalog, holds mesh-delivery, holds mesh-dns-resolver, holds mesh-store, holds mesh-vault, holds npm-package-registry, the control node, the hub (ygcyr): composes
- a machine (yvbpsm): composes
a merge would rebuild 1 module(s) in 1 tier(s): messenger
--- its merge-check.sh (go toolchain)
ok git.novox.be/novox/mesh-catalog/checks/words 0.002s
words: 12 retired words and 70 daemons' lines, none in the 37423 strings of 637 files
ok git.novox.be/novox/mesh-catalog/checks/agenthome 0.012s
agent-home: no archive and no file written into under the agent's home
ok git.novox.be/novox/mesh-catalog/checks/paths 0.005s
paths: no module names another's state on its machine (3 known, listed to go)
long-running resources without health: 70, as kept
testing modules/messenger
ok messenger/cmd/messenger 1.612s
--- its merge-check-typescript.sh (typescript toolchain)
```
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Fixes issue 371 (Details refused "it belongs to no open message" on Telegram and the desk).
Cause
choices()inmodules/messenger/cmd/messenger/answers.godeleted a record's earlier Details ticket on a channel kind every time a newer message about the same record was composed. Seen on 2026-10-10:seat.operator-channel.unaskedwas sent on Telegram as "escalated" at 12:57:49 and as "reminder" at 12:58:20, so the first message's Details was dead; the two taps at 13:30:34 and 13:30:36 were refused.takeWordsalso dropped every ticket when a condition's actions changed.Fix
MostDetails(8) per record and kind, none older thanTokenFor(24 h), pruned whenever a new one is made.Tests
details_test.go: three warnings in a row (one problem said three times, and three problems), Details works on each once and a second tap is refused; the bound in number and time; Details survives an actions change; Details on a message with an open ask issues no warrant and leaves the ask open. Mutation-checked: restoring the old replacement, the old reset intakeWords, removing the bound, or not marking a ticket used each fails a new test.Acceptance: the operator receives three warnings in a row and Details works on each of them, once each.
Delivery
novox/mesh-catalog@6a8c718f440c— delivered since 2026-10-10T11:53:52ZDelivery plan — builds messenger → novox; no bus step
Machines
Transitions
The commit's note under
refs/notes/mesh-plankeeps every transition:git log --notes=mesh-plan.Merge check at
bb96f4d1mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: messenger)mesh/repo-check: PASS — its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)Delivery plan — builds messenger → novox; no bus step
Run by the build seat on g14 as
build-1791632735293304621(builds --log build-1791632735293304621).Merge check at
6a8c718fmesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: messenger)mesh/repo-check: PASS — its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)Delivery plan — builds messenger → novox; no bus step
Run by the build seat on ace as
build-1791632797532113347(builds --log build-1791632797532113347).