Fixes issue 422 (no tool shows what a condition's message would say without sending it), which blocks the live proof of issue 400 (an alert does not say whether an issue already tracks it).
Why
The words a condition reaches the operator with are composed in the router (composeTracked: the condition's own plain words plus the tracking line of ADR 0285). Nothing keeps them: a send's history row (type Sent) holds a key and an outcome and never text, the desk notifier serves no tool that reads what is on screen or in its history, and Telegram cannot be read back. So a wording could only be proven by waiting for a real send and reading the operator's screen — which is where proving issue 400 stopped last night, with a notification left unread on the operator's desk rather than closed.
What this adds
messenger_preview, a read: for a condition the router holds open, it composes what a send would carry for that message — raised (default), reminder, quiet-reminder, escalated, reopened, cleared, silenced — and answers the title, the body, the tracking line on its own, and whether the content rule would let those words leave the mesh.
It goes through the same composeTracked a send goes through, so a preview that differs from a send is a bug in one function, not two.
It sends nothing, queues nothing and records nothing; it composes from a copy of the record.
It refreshes the tracker's word first (warmTracking, which the router already rate-limits to once a minute), so a preview does not report "could not be checked" for a word that merely went cold between ticks.
A clearing and a silence carry no tracking line, as ADR 0285 §3 says.
A key the router does not hold is refused by name, and the refusal lists what it does hold.
Checked here
go test ./... in modules/messenger: ok, including six new tests — the tracking line is in a preview's body, a preview equals what the sending path composes for the same record and moment, a clearing and a silence say no tracking line, an unheld key and an unknown message are refused by name, a cold tracking word is asked again, and words the content rule refuses are reported as not allowed.
checks/words: none of the 12 retired words in 39366 strings.
checks/agenthome: clean.
The manifest lists the new tool, and the README's tool table names it.
Fixes issue 422 (no tool shows what a condition's message would say without sending it), which blocks the live proof of issue 400 (an alert does not say whether an issue already tracks it).
## Why
The words a condition reaches the operator with are composed in the router (`composeTracked`: the condition's own plain words plus the tracking line of ADR 0285). Nothing keeps them: a send's history row (`type Sent`) holds a key and an outcome and never text, the desk notifier serves no tool that reads what is on screen or in its history, and Telegram cannot be read back. So a wording could only be proven by waiting for a real send and reading the operator's screen — which is where proving issue 400 stopped last night, with a notification left unread on the operator's desk rather than closed.
## What this adds
`messenger_preview`, a read: for a condition the router holds open, it composes what a send would carry for that message — `raised` (default), `reminder`, `quiet-reminder`, `escalated`, `reopened`, `cleared`, `silenced` — and answers the title, the body, the tracking line on its own, and whether the content rule would let those words leave the mesh.
- It goes through the same `composeTracked` a send goes through, so a preview that differs from a send is a bug in one function, not two.
- It sends nothing, queues nothing and records nothing; it composes from a copy of the record.
- It refreshes the tracker's word first (`warmTracking`, which the router already rate-limits to once a minute), so a preview does not report "could not be checked" for a word that merely went cold between ticks.
- A clearing and a silence carry no tracking line, as ADR 0285 §3 says.
- A key the router does not hold is refused by name, and the refusal lists what it does hold.
## Checked here
- `go test ./...` in modules/messenger: ok, including six new tests — the tracking line is in a preview's body, a preview equals what the sending path composes for the same record and moment, a clearing and a silence say no tracking line, an unheld key and an unknown message are refused by name, a cold tracking word is asked again, and words the content rule refuses are reported as not allowed.
- `checks/words`: none of the 12 retired words in 39366 strings.
- `checks/agenthome`: clean.
- The manifest lists the new tool, and the README's tool table names it.
The words a condition reaches the operator with are composed in the
router, and nothing kept them: a send's history row holds a key and an
outcome, never text, and a notification still on the desk is not in the
notifier's history. So a wording could only be proven by waiting for a
send and reading the operator's screen, which is why proving issue 400's
tracking line stalled.
messenger_preview composes what a send would carry for a condition the
router holds open — the same words, the same tracking line, the same
verdict — and says whether the content rule would let them out. It
sends, queues and records nothing.
Deliverynovox/mesh-catalog@15546f9d83df — delivered since 2026-10-10T23:00:44Z
Delivery plan — builds messenger → novox; no bus step
tier 0: messenger
novox: receives messenger
Machines
messenger on novox: passed — healthy 3 times over 3m28s
messenger on the rest running it: sent
Transitions
2026-10-10 22:49 (new) → proposed (announced): novox/mesh-catalog#192's head announced
2026-10-10 22:51 proposed → checked (checked): the verdict names this commit
2026-10-10 22:51 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
2026-10-10 22:56 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 22:56 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 23:00 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@15546f9d83df` — **delivered** since 2026-10-10T23:00:44Z
**Delivery plan** — builds messenger → novox; no bus step
- tier 0: messenger
- novox: receives messenger
**Machines**
- messenger on novox: passed — healthy 3 times over 3m28s
- messenger on the rest running it: sent
**Transitions**
- 2026-10-10 22:49 (new) → proposed (announced): novox/mesh-catalog#192's head announced
- 2026-10-10 22:51 proposed → checked (checked): the verdict names this commit
- 2026-10-10 22:51 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
- 2026-10-10 22:56 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 22:56 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 23:00 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/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
read by no module's build: modules/messenger/README.md, modules/messenger/cmd/messenger/preview_test.go
Run by the build seat on ace as build-1791671468294290281 (builds --log build-1791671468294290281).
--- the gate: messenger
messenger: ok, 7 tool(s), invokes seat:mesh-controller.conditions, seat:mesh-controller.root-free, seat:issue-tracker.tracking, 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 1 module(s) changed against 4 machine(s), as the snapshot of 2026-10-10T22:12:40Z 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-10T22:12:40Z
modules the change moves:
- messenger (changed)
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
notes:
- modules/messenger/README.md and modules/messenger/cmd/messenger/preview_test.go read by no module's build, and rebuild nothing (issue 280)
--- 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 39366 strings of 654 files
ok git.novox.be/novox/mesh-catalog/checks/agenthome 0.011s
agent-home: no archive and no file written into under the agent's home
ok git.novox.be/novox/mesh-catalog/checks/paths 0.006s
paths: no module names another's state on its machine (3 known, listed to go)
long-running resources without health: 69, as kept
testing modules/messenger
ok messenger/cmd/messenger 1.796s
--- its merge-check-typescript.sh (typescript toolchain)
**Merge check** at `b7b34dda`
- `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
- read by no module's build: modules/messenger/README.md, modules/messenger/cmd/messenger/preview_test.go
Run by the build seat on ace as `build-1791671468294290281` (`builds --log build-1791671468294290281`).
```
--- the gate: messenger
messenger: ok, 7 tool(s), invokes seat:mesh-controller.conditions, seat:mesh-controller.root-free, seat:issue-tracker.tracking, 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 1 module(s) changed against 4 machine(s), as the snapshot of 2026-10-10T22:12:40Z 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-10T22:12:40Z
modules the change moves:
- messenger (changed)
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
notes:
- modules/messenger/README.md and modules/messenger/cmd/messenger/preview_test.go read by no module's build, and rebuild nothing (issue 280)
--- 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 39366 strings of 654 files
ok git.novox.be/novox/mesh-catalog/checks/agenthome 0.011s
agent-home: no archive and no file written into under the agent's home
ok git.novox.be/novox/mesh-catalog/checks/paths 0.006s
paths: no module names another's state on its machine (3 known, listed to go)
long-running resources without health: 69, as kept
testing modules/messenger
ok messenger/cmd/messenger 1.796s
--- its merge-check-typescript.sh (typescript toolchain)
```
The review of #192 found three faults, all verified by running.
The tests did not prove the claim the change leads with: a probe that
sent, queued, recorded and wrote from inside Preview still passed,
because the condition they used was a warning needing nothing, which is
held rather than sent. They now hold an urgent condition, snapshot what
a send would move — the channels, the queue, the history, the refusals,
the stored record and the record held — assert none of it moved, and
tick once more. Every one of those probes now fails the tests.
`cleared` and `silenced` said wording no send would carry: an open
record has no clearing time, so a condition open four hours cleared
"after a moment", and no silence, so a silence read "until Mon 1 Jan
00:17". A clearing is now composed as if it cleared now, which the
answer says; a silence is refused unless the condition is under one.
The preview composed only its own words, while a send reduces a message
whose words the content rule refuses. The escalation walk is now one
function, allowedWords, which `words` calls for a send and the preview
calls alone — so the words read are the words that would leave, and
reading them records no refusal and states nothing on the bus.
withTracking hands back the line it put in, so the preview reports that
line instead of deciding the rule a second time; and a record that is
not a condition, or one carrying an open ask, is refused or says that a
channel's message carries more.
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
read by no module's build: modules/messenger/README.md, modules/messenger/cmd/messenger/preview_test.go, modules/messenger/cmd/messenger/tracking_test.go
Run by the build seat on novox as build-1791672256642014598 (builds --log build-1791672256642014598).
--- the gate: messenger
messenger: ok, 7 tool(s), invokes seat:mesh-controller.conditions, seat:mesh-controller.root-free, seat:issue-tracker.tracking, 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 1 module(s) changed against 4 machine(s), as the snapshot of 2026-10-10T22:12:40Z 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-10T22:12:40Z
modules the change moves:
- messenger (changed)
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
notes:
- modules/messenger/README.md, modules/messenger/cmd/messenger/preview_test.go and modules/messenger/cmd/messenger/tracking_test.go read by no module's build, and rebuild nothing (issue 280)
--- its merge-check.sh (go toolchain)
ok git.novox.be/novox/mesh-catalog/checks/words 0.005s
words: 12 retired words and 70 daemons' lines, none in the 39380 strings of 654 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.007s
paths: no module names another's state on its machine (3 known, listed to go)
long-running resources without health: 69, as kept
testing modules/messenger
ok messenger/cmd/messenger 2.081s
--- its merge-check-typescript.sh (typescript toolchain)
**Merge check** at `d00cc8ba`
- `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
- read by no module's build: modules/messenger/README.md, modules/messenger/cmd/messenger/preview_test.go, modules/messenger/cmd/messenger/tracking_test.go
Run by the build seat on novox as `build-1791672256642014598` (`builds --log build-1791672256642014598`).
```
--- the gate: messenger
messenger: ok, 7 tool(s), invokes seat:mesh-controller.conditions, seat:mesh-controller.root-free, seat:issue-tracker.tracking, 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 1 module(s) changed against 4 machine(s), as the snapshot of 2026-10-10T22:12:40Z 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-10T22:12:40Z
modules the change moves:
- messenger (changed)
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
notes:
- modules/messenger/README.md, modules/messenger/cmd/messenger/preview_test.go and modules/messenger/cmd/messenger/tracking_test.go read by no module's build, and rebuild nothing (issue 280)
--- its merge-check.sh (go toolchain)
ok git.novox.be/novox/mesh-catalog/checks/words 0.005s
words: 12 retired words and 70 daemons' lines, none in the 39380 strings of 654 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.007s
paths: no module names another's state on its machine (3 known, listed to go)
long-running resources without health: 69, as kept
testing modules/messenger
ok messenger/cmd/messenger 2.081s
--- its merge-check-typescript.sh (typescript toolchain)
```
The review's two nits. A write of bytes identical to what is stored was
invisible to a comparison of content, so the test store counts its
writes and the preview's tests read that count: a persist from inside
Preview now fails five of them instead of one. And a router holding an
ask's record and no condition said it held none, rather than saying what
that key is; the branches are the other way round, with a test that
holds nothing else.
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
read by no module's build: modules/messenger/README.md, modules/messenger/cmd/messenger/holder_test.go, modules/messenger/cmd/messenger/preview_test.go, modules/messenger/cmd/messenger/tracking_test.go
Run by the build seat on shanks as build-1791672591035104163 (builds --log build-1791672591035104163).
--- the gate: messenger
messenger: ok, 7 tool(s), invokes seat:mesh-controller.conditions, seat:mesh-controller.root-free, seat:issue-tracker.tracking, 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 1 module(s) changed against 4 machine(s), as the snapshot of 2026-10-10T22:12:40Z 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-10T22:12:40Z
modules the change moves:
- messenger (changed)
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
notes:
- modules/messenger/README.md, modules/messenger/cmd/messenger/holder_test.go, modules/messenger/cmd/messenger/preview_test.go and modules/messenger/cmd/messenger/tracking_test.go read by no module's build, and rebuild nothing (issue 280)
--- 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 39381 strings of 654 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.006s
paths: no module names another's state on its machine (3 known, listed to go)
long-running resources without health: 69, as kept
testing modules/messenger
ok messenger/cmd/messenger 2.113s
--- its merge-check-typescript.sh (typescript toolchain)
**Merge check** at `15546f9d`
- `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
- read by no module's build: modules/messenger/README.md, modules/messenger/cmd/messenger/holder_test.go, modules/messenger/cmd/messenger/preview_test.go, modules/messenger/cmd/messenger/tracking_test.go
Run by the build seat on shanks as `build-1791672591035104163` (`builds --log build-1791672591035104163`).
```
--- the gate: messenger
messenger: ok, 7 tool(s), invokes seat:mesh-controller.conditions, seat:mesh-controller.root-free, seat:issue-tracker.tracking, 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 1 module(s) changed against 4 machine(s), as the snapshot of 2026-10-10T22:12:40Z 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-10T22:12:40Z
modules the change moves:
- messenger (changed)
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
notes:
- modules/messenger/README.md, modules/messenger/cmd/messenger/holder_test.go, modules/messenger/cmd/messenger/preview_test.go and modules/messenger/cmd/messenger/tracking_test.go read by no module's build, and rebuild nothing (issue 280)
--- 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 39381 strings of 654 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.006s
paths: no module names another's state on its machine (3 known, listed to go)
long-running resources without health: 69, as kept
testing modules/messenger
ok messenger/cmd/messenger 2.113s
--- 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 422 (no tool shows what a condition's message would say without sending it), which blocks the live proof of issue 400 (an alert does not say whether an issue already tracks it).
Why
The words a condition reaches the operator with are composed in the router (
composeTracked: the condition's own plain words plus the tracking line of ADR 0285). Nothing keeps them: a send's history row (type Sent) holds a key and an outcome and never text, the desk notifier serves no tool that reads what is on screen or in its history, and Telegram cannot be read back. So a wording could only be proven by waiting for a real send and reading the operator's screen — which is where proving issue 400 stopped last night, with a notification left unread on the operator's desk rather than closed.What this adds
messenger_preview, a read: for a condition the router holds open, it composes what a send would carry for that message —raised(default),reminder,quiet-reminder,escalated,reopened,cleared,silenced— and answers the title, the body, the tracking line on its own, and whether the content rule would let those words leave the mesh.composeTrackeda send goes through, so a preview that differs from a send is a bug in one function, not two.warmTracking, which the router already rate-limits to once a minute), so a preview does not report "could not be checked" for a word that merely went cold between ticks.Checked here
go test ./...in modules/messenger: ok, including six new tests — the tracking line is in a preview's body, a preview equals what the sending path composes for the same record and moment, a clearing and a silence say no tracking line, an unheld key and an unknown message are refused by name, a cold tracking word is asked again, and words the content rule refuses are reported as not allowed.checks/words: none of the 12 retired words in 39366 strings.checks/agenthome: clean.Delivery
novox/mesh-catalog@15546f9d83df— delivered since 2026-10-10T23:00:44ZDelivery 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
b7b34ddamesh/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-1791671468294290281(builds --log build-1791671468294290281).Merge check at
d00cc8bamesh/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 novox as
build-1791672256642014598(builds --log build-1791672256642014598).Merge check at
15546f9dmesh/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 shanks as
build-1791672591035104163(builds --log build-1791672591035104163).