Replaces #178 (issue 383), rebased on main and reshaped for issue 639.
Acceptance. The next decision ask the operator gets on Telegram is a bold headline saying what it changes for them, a two- or three-sentence summary and at most three points, the Approve/Decline buttons, and a collapsed note with who asked, the fingerprint and how to read the clauses; the ADR 0343 ask renders in 10 lines (it was ~30) and lists no clause. Answered, it is one line with the headline.
What.
messenger: an ask's message is the asker's headline (title) and explanation alone (body). Who asked and when with the expiry, what each answer does, where else it is answered, and the asker's Details go in the note (asks.Message.Note). Answered: "You chose Approve at 16:06 on Telegram · ", the told-line as its note, body not repeated. An explanation that fails asks.Glance is shown and logged, never refused. From #178: on a kind that proves who answers an ask's values are shown whole (asks.Ask.Whole), held to the secret rule alone (CheckSecret). The Details button of #178 is dropped: Details are now the note.
telegram: HTML; title bold, key lines monospace, note in <blockquote expandable> after a blank line; <>& escaped. Taps compared with whitespace runs taken as one; a message shown before is still compared by its old digest.
desk-channel: the note follows the body after a blank line.
mesh-knowledge: propose takes brief {headline, summary, points}; rule 30 brief requires it with needs-operator for records dated from 2026-10-13. The ask shows the brief, never the clauses; Details: record, proposer, review, fingerprint, "Read its N clauses with the knowledge base's get, number N". OperatorAsk.Form keeps an ask made before composed as it was, so its warrant still holds.
claude-code: an instructions proposal's explanation is one summary line (new optional summary, else the module's words), its text moved to the Details; a question's context is at most 300 characters and its recommendation one point. form keeps older proposals and questions composed as asked.
Design limits I chose (ADR 0345, proposed, needs the operator): summary ≤ 300 characters on one line, ≤ 3 points of ≤ 160; question context 1500 → 300 characters, why 300 → 120 bytes; more than three setting keys show two and the names of the rest.
Depends on mesh-sdk #25 (pinned at 9588871, pushed). Merge order: mesh-sdk #25, this, then mesh-controller's PR (the router must know Whole before the controller sends it, or the digests differ and the warrant is refused, loudly).
Tested.merge-check.sh with MESH_GATE (a controller built from the controller branch) and MESH_CHECK_MODULES=messenger,telegram,desk-channel,mesh-knowledge,claude-code: all green. New tests that fail on main: messenger TestAnAsksMessageIsItsSummaryWithTheRestInItsNote, TestAnAskThatIsAWallOfTextIsShownAndSaid; telegram TestTheADR0343AskFitsAGlance (≤ 12 lines, bold headline, collapsed note, no clause), TestALongNoteIsCutBeforeTheBody, TestATapOnAMessageShownBeforeIsStillTaken; mesh-knowledge TestADecisionAskReadsAtAGlance, TestABriefIsHeldToAGlance, the brief row of the rule table; claude-code TestAProposalIsAskedAtAGlanceAndAnOlderOneAsItWasAsked; desk-channel TestTheNoteFollowsTheBody. Existing tests were updated where the shape changed.
Fixes issue 639. Fixes issue 383 (with mesh-controller and hq).
Replaces #178 (issue 383), rebased on main and reshaped for issue 639.
**Acceptance.** The next decision ask the operator gets on Telegram is a bold headline saying what it changes for them, a two- or three-sentence summary and at most three points, the Approve/Decline buttons, and a collapsed note with who asked, the fingerprint and how to read the clauses; the ADR 0343 ask renders in 10 lines (it was ~30) and lists no clause. Answered, it is one line with the headline.
**What.**
- **messenger**: an ask's message is the asker's headline (title) and explanation alone (body). Who asked and when with the expiry, what each answer does, where else it is answered, and the asker's Details go in the note (`asks.Message.Note`). Answered: "You chose Approve at 16:06 on Telegram · <headline>", the told-line as its note, body not repeated. An explanation that fails `asks.Glance` is shown and logged, never refused. From #178: on a kind that proves who answers an ask's values are shown whole (`asks.Ask.Whole`), held to the secret rule alone (`CheckSecret`). The Details button of #178 is dropped: Details are now the note.
- **telegram**: HTML; title bold, key lines monospace, note in `<blockquote expandable>` after a blank line; `<>&` escaped. Taps compared with whitespace runs taken as one; a message shown before is still compared by its old digest.
- **desk-channel**: the note follows the body after a blank line.
- **mesh-knowledge**: `propose` takes `brief` {headline, summary, points}; rule 30 `brief` requires it with needs-operator for records dated from 2026-10-13. The ask shows the brief, never the clauses; Details: record, proposer, review, fingerprint, "Read its N clauses with the knowledge base's get, number N". `OperatorAsk.Form` keeps an ask made before composed as it was, so its warrant still holds.
- **claude-code**: an instructions proposal's explanation is one summary line (new optional `summary`, else the module's words), its text moved to the Details; a question's context is at most 300 characters and its recommendation one point. `form` keeps older proposals and questions composed as asked.
**Design limits I chose** (ADR 0345, proposed, needs the operator): summary ≤ 300 characters on one line, ≤ 3 points of ≤ 160; question context 1500 → 300 characters, why 300 → 120 bytes; more than three setting keys show two and the names of the rest.
**Depends on** mesh-sdk #25 (pinned at 9588871, pushed). Merge order: mesh-sdk #25, this, then mesh-controller's PR (the router must know `Whole` before the controller sends it, or the digests differ and the warrant is refused, loudly).
**Tested.** `merge-check.sh` with MESH_GATE (a controller built from the controller branch) and MESH_CHECK_MODULES=messenger,telegram,desk-channel,mesh-knowledge,claude-code: all green. New tests that fail on main: messenger `TestAnAsksMessageIsItsSummaryWithTheRestInItsNote`, `TestAnAskThatIsAWallOfTextIsShownAndSaid`; telegram `TestTheADR0343AskFitsAGlance` (≤ 12 lines, bold headline, collapsed note, no clause), `TestALongNoteIsCutBeforeTheBody`, `TestATapOnAMessageShownBeforeIsStillTaken`; mesh-knowledge `TestADecisionAskReadsAtAGlance`, `TestABriefIsHeldToAGlance`, the `brief` row of the rule table; claude-code `TestAProposalIsAskedAtAGlanceAndAnOlderOneAsItWasAsked`; desk-channel `TestTheNoteFollowsTheBody`. Existing tests were updated where the shape changed.
Fixes issue 639. Fixes issue 383 (with mesh-controller and hq).
claude-code keeps data (ADR 0233): what it holds is backed up before it moves
grants step: if this changes what the bus's user list says (a new tool, subject or user), novox is sent that list alone, every build there kept, before claude-code is judged on its first machine
composed together: pass — every machine composes with the change as it did without (4 of 4 compose)
Machines
baserow on ace: passed — carried by plan-1791918149350551946
grafana on ace: passed — carried by plan-1791918149350551946
home-assistant on ace: passed — carried by plan-1791918149350551946
icecast on ace: passed — carried by plan-1791918149350551946
influxdb on ace: passed — carried by plan-1791918149350551946
letta on ace: passed — carried by plan-1791918149350551946
mosquitto on ace: passed — carried by plan-1791918149350551946
netcheck on ace: passed — carried by plan-1791918149350551946
nodered on ace: passed — carried by plan-1791918149350551946
redis on ace: passed — carried by plan-1791918149350551946
searxng on ace: passed — carried by plan-1791918149350551946
unifi on ace: passed — carried by plan-1791918149350551946
zsh on ace: passed — carried by plan-1791918149350551946
gitea on novox: passed — carried by plan-1791918149350551946
mesh-catalog on novox: passed — carried by plan-1791918149350551946
mesh-vault on novox: passed — carried by plan-1791918149350551946
nextcloud on novox: passed — carried by plan-1791918149350551946
umami on novox: passed — carried by plan-1791918149350551946
lab on shanks: passed — carried by plan-1791918149350551946
claude-code on ace: passed — healthy 1 times over 22s
claude-code on g14: passed — carried by release-1791918739498850280
claude-code on shanks: passed — carried by release-1791918739498850280
claude-code on novox: passed — carried by release-1791918739498850280
desk-channel on novox: passed — healthy 1 times over 1m6s
mesh-knowledge on novox: passed — judged with desk-channel: healthy 1 times over 1m6s
messenger on novox: passed — judged with desk-channel: healthy 1 times over 1m6s
telegram on novox: passed — judged with desk-channel: healthy 1 times over 1m6s
claude-code on the rest running it: sent
desk-channel on the rest running it: sent
mesh-knowledge on the rest running it: sent
messenger on the rest running it: sent
telegram on the rest running it: sent
Transitions
2026-10-13 18:35 (new) → proposed (announced): novox/mesh-catalog#278's head announced
2026-10-13 18:42 proposed → checked (checked): a verdict names this commit and the trunk's head as its trunk commit
2026-10-13 18:42 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
2026-10-13 19:11 ready → published (merged): on the trunk its modules follow: merged there, and its walk opened — or nothing for a walk to move
2026-10-13 19:11 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-13 19:17 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@f09daabec3a8` — **delivered** since 2026-10-13T19:17:50Z
**Delivery plan** — builds claude-code, desk-channel, mesh-knowledge, messenger, telegram → ace, g14, novox, shanks; no bus step
- tier 0: claude-code, desk-channel, mesh-knowledge, messenger, telegram
- ace: receives claude-code
- g14: receives claude-code
- novox: receives claude-code, desk-channel, mesh-knowledge, messenger, telegram
- shanks: receives claude-code
- claude-code keeps data (ADR 0233): what it holds is backed up before it moves
- grants step: if this changes what the bus's user list says (a new tool, subject or user), novox is sent that list alone, every build there kept, before claude-code is judged on its first machine
**Group** `fix/383-an-ask-reads-at-a-glance`, in order: novox/mesh-catalog@f09daabec3a8 → novox/mesh-controller@deef9421a276
- novox/mesh-catalog@f09daabec3a8 before novox/mesh-controller@deef9421a276: declared, over built by, version skew
- composed together: pass — every machine composes with the change as it did without (4 of 4 compose)
**Machines**
- baserow on ace: passed — carried by plan-1791918149350551946
- grafana on ace: passed — carried by plan-1791918149350551946
- home-assistant on ace: passed — carried by plan-1791918149350551946
- icecast on ace: passed — carried by plan-1791918149350551946
- influxdb on ace: passed — carried by plan-1791918149350551946
- letta on ace: passed — carried by plan-1791918149350551946
- mosquitto on ace: passed — carried by plan-1791918149350551946
- netcheck on ace: passed — carried by plan-1791918149350551946
- nodered on ace: passed — carried by plan-1791918149350551946
- redis on ace: passed — carried by plan-1791918149350551946
- searxng on ace: passed — carried by plan-1791918149350551946
- unifi on ace: passed — carried by plan-1791918149350551946
- zsh on ace: passed — carried by plan-1791918149350551946
- gitea on novox: passed — carried by plan-1791918149350551946
- mesh-catalog on novox: passed — carried by plan-1791918149350551946
- mesh-vault on novox: passed — carried by plan-1791918149350551946
- nextcloud on novox: passed — carried by plan-1791918149350551946
- umami on novox: passed — carried by plan-1791918149350551946
- lab on shanks: passed — carried by plan-1791918149350551946
- claude-code on ace: passed — healthy 1 times over 22s
- claude-code on g14: passed — carried by release-1791918739498850280
- claude-code on shanks: passed — carried by release-1791918739498850280
- claude-code on novox: passed — carried by release-1791918739498850280
- desk-channel on novox: passed — healthy 1 times over 1m6s
- mesh-knowledge on novox: passed — judged with desk-channel: healthy 1 times over 1m6s
- messenger on novox: passed — judged with desk-channel: healthy 1 times over 1m6s
- telegram on novox: passed — judged with desk-channel: healthy 1 times over 1m6s
- claude-code on the rest running it: sent
- desk-channel on the rest running it: sent
- mesh-knowledge on the rest running it: sent
- messenger on the rest running it: sent
- telegram on the rest running it: sent
**Transitions**
- 2026-10-13 18:35 (new) → proposed (announced): novox/mesh-catalog#278's head announced
- 2026-10-13 18:42 proposed → checked (checked): a verdict names this commit and the trunk's head as its trunk commit
- 2026-10-13 18:42 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
- 2026-10-13 19:11 ready → published (merged): on the trunk its modules follow: merged there, and its walk opened — or nothing for a walk to move
- 2026-10-13 19:11 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-13 19:17 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`.
Merge check at ea1dfdce
Judged: head ea1dfdce5bc7 merged into trunk 5f491e0c097d; read beside it: mesh-controller 6f1a05366c1d, mesh-controller-main 6f1a05366c1d, mesh-host 0e92ef3d1b21, mesh-tools 954e1a53eef9
mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: claude-code, desk-channel, mesh-knowledge, messenger, telegram)
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 claude-code, desk-channel, mesh-knowledge, messenger, telegram → ace, g14, novox, shanks; no bus step
claude-code keeps data (ADR 0233): what it holds is backed up before it moves
grants step: if this changes what the bus's user list says (a new tool, subject or user), novox is sent that list alone, every build there kept, before claude-code is judged on its first machine
Run by the build seat on novox as build-1791902224469986315 (builds --log build-1791902224469986315).
--- the gate: claude-code, desk-channel, mesh-knowledge, messenger, telegram
claude-code: ok, 48 tool(s), keeps state servers, holdings, config, proposals, questions, memory, reads claude-licence-manager.bindings, keeps agent-home (valuable); 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)
desk-channel: ok, 1 tool(s), invokes seat:node-notifier.send, keeps state shown; 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)
mesh-knowledge: ok, 2 tool(s), invokes seat:issue-tracker.reserve, claude-code.claude_code_judge, claude-code.claude_code_judged, records.records_status, records.records_list, records.records_read, seat:operator-channel.notify, ready: keep by unit every 30s; watch by its tool knowledge_health every 1m0s
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, walks; 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)
telegram: ok, 1 tool(s), keeps state offset, messages
long-running resources without health: 0
files asking for a setting without saying whether it is trusted: 3
5 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-13T14:32:41Z 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-13T14:32:41Z
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 5 module(s) in 1 tier(s): claude-code, desk-channel, mesh-knowledge, messenger, telegram
notes:
- modules/claude-code/README.md, modules/claude-code/cmd/claude-code/proposals_test.go, modules/claude-code/cmd/claude-code/questions_test.go, modules/desk-channel/cmd/desk-channel/desk_test.go, modules/mesh-knowledge/README.md, modules/mesh-knowledge/cmd/mesh-knowledge/glance_test.go, modules/mesh-knowledge/cmd/mesh-knowledge/review_test.go, modules/mesh-knowledge/cmd/mesh-knowledge/rules_test.go, modules/messenger/README.md, modules/messenger/cmd/messenger/answers_test.go, modules/messenger/cmd/messenger/feedback_test.go, modules/messenger/cmd/messenger/glance_test.go, modules/messenger/cmd/messenger/onemessage_test.go, modules/messenger/cmd/messenger/review_test.go, modules/messenger/cmd/messenger/whole_test.go, modules/telegram/README.md, modules/telegram/cmd/telegram/channel_test.go and modules/telegram/cmd/telegram/render_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 46758 strings of 718 files
ok git.novox.be/novox/mesh-catalog/checks/agenthome 0.014s
agent-home: no archive and no file written into under the agent's home
ok git.novox.be/novox/mesh-catalog/checks/secrets 0.012s
secrets: no setting can replace a vault secret in a mergeable file (1 known, nested)
ok git.novox.be/novox/mesh-catalog/checks/paths 0.009s
paths: no module names another's state on its machine (3 known, listed to go)
long-running resources without health: 66, as kept
ok git.novox.be/novox/mesh-catalog/checks/deps 0.227s
testing modules/claude-code
ok claude-code/cmd/claude-code 8.793s
testing modules/desk-channel
ok deskchannel/cmd/desk-channel 1.014s
testing modules/mesh-knowledge
ok mesh-knowledge/cmd/mesh-knowledge 136.504s
testing modules/messenger
ok messenger/cmd/messenger 2.381s
testing modules/telegram
ok telegram/cmd/telegram 1.066s
--- its merge-check-typescript.sh (typescript toolchain)
**Merge check** at `ea1dfdce`
Judged: head `ea1dfdce5bc7` merged into trunk `5f491e0c097d`; read beside it: mesh-controller `6f1a05366c1d`, mesh-controller-main `6f1a05366c1d`, mesh-host `0e92ef3d1b21`, mesh-tools `954e1a53eef9`
- `mesh/merge-gate`: **PASS** — every machine composes with the change as it did without (4 of 4 compose) (modules: claude-code, desk-channel, mesh-knowledge, messenger, telegram)
- `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 claude-code, desk-channel, mesh-knowledge, messenger, telegram → ace, g14, novox, shanks; no bus step
- tier 0: claude-code, desk-channel, mesh-knowledge, messenger, telegram
- ace: receives claude-code
- g14: receives claude-code
- novox: receives claude-code, desk-channel, mesh-knowledge, messenger, telegram
- shanks: receives claude-code
- claude-code keeps data (ADR 0233): what it holds is backed up before it moves
- grants step: if this changes what the bus's user list says (a new tool, subject or user), novox is sent that list alone, every build there kept, before claude-code is judged on its first machine
- read by no module's build: modules/claude-code/README.md, modules/claude-code/cmd/claude-code/proposals_test.go, modules/claude-code/cmd/claude-code/questions_test.go, modules/desk-channel/cmd/desk-channel/desk_test.go, modules/mesh-knowledge/README.md, modules/mesh-knowledge/cmd/mesh-knowledge/glance_test.go, modules/mesh-knowledge/cmd/mesh-knowledge/review_test.go, modules/mesh-knowledge/cmd/mesh-knowledge/rules_test.go, modules/messenger/README.md, modules/messenger/cmd/messenger/answers_test.go, modules/messenger/cmd/messenger/feedback_test.go, modules/messenger/cmd/messenger/glance_test.go, modules/messenger/cmd/messenger/onemessage_test.go, modules/messenger/cmd/messenger/review_test.go, modules/messenger/cmd/messenger/whole_test.go, modules/telegram/README.md, modules/telegram/cmd/telegram/channel_test.go, modules/telegram/cmd/telegram/render_test.go
Run by the build seat on novox as `build-1791902224469986315` (`builds --log build-1791902224469986315`).
```
--- the gate: claude-code, desk-channel, mesh-knowledge, messenger, telegram
claude-code: ok, 48 tool(s), keeps state servers, holdings, config, proposals, questions, memory, reads claude-licence-manager.bindings, keeps agent-home (valuable); 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)
desk-channel: ok, 1 tool(s), invokes seat:node-notifier.send, keeps state shown; 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)
mesh-knowledge: ok, 2 tool(s), invokes seat:issue-tracker.reserve, claude-code.claude_code_judge, claude-code.claude_code_judged, records.records_status, records.records_list, records.records_read, seat:operator-channel.notify, ready: keep by unit every 30s; watch by its tool knowledge_health every 1m0s
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, walks; 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)
telegram: ok, 1 tool(s), keeps state offset, messages
long-running resources without health: 0
files asking for a setting without saying whether it is trusted: 3
5 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-13T14:32:41Z 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-13T14:32:41Z
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 5 module(s) in 1 tier(s): claude-code, desk-channel, mesh-knowledge, messenger, telegram
notes:
- modules/claude-code/README.md, modules/claude-code/cmd/claude-code/proposals_test.go, modules/claude-code/cmd/claude-code/questions_test.go, modules/desk-channel/cmd/desk-channel/desk_test.go, modules/mesh-knowledge/README.md, modules/mesh-knowledge/cmd/mesh-knowledge/glance_test.go, modules/mesh-knowledge/cmd/mesh-knowledge/review_test.go, modules/mesh-knowledge/cmd/mesh-knowledge/rules_test.go, modules/messenger/README.md, modules/messenger/cmd/messenger/answers_test.go, modules/messenger/cmd/messenger/feedback_test.go, modules/messenger/cmd/messenger/glance_test.go, modules/messenger/cmd/messenger/onemessage_test.go, modules/messenger/cmd/messenger/review_test.go, modules/messenger/cmd/messenger/whole_test.go, modules/telegram/README.md, modules/telegram/cmd/telegram/channel_test.go and modules/telegram/cmd/telegram/render_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 46758 strings of 718 files
ok git.novox.be/novox/mesh-catalog/checks/agenthome 0.014s
agent-home: no archive and no file written into under the agent's home
ok git.novox.be/novox/mesh-catalog/checks/secrets 0.012s
secrets: no setting can replace a vault secret in a mergeable file (1 known, nested)
ok git.novox.be/novox/mesh-catalog/checks/paths 0.009s
paths: no module names another's state on its machine (3 known, listed to go)
long-running resources without health: 66, as kept
ok git.novox.be/novox/mesh-catalog/checks/deps 0.227s
testing modules/claude-code
ok claude-code/cmd/claude-code 8.793s
testing modules/desk-channel
ok deskchannel/cmd/desk-channel 1.014s
testing modules/mesh-knowledge
ok mesh-knowledge/cmd/mesh-knowledge 136.504s
testing modules/messenger
ok messenger/cmd/messenger 2.381s
testing modules/telegram
ok telegram/cmd/telegram 1.066s
--- its merge-check-typescript.sh (typescript toolchain)
```
Independent review (issues 383 and 639, ADR 0345). The approval covers this PR's own content only. Its delivery-group partner mesh-controller#304 has a blocking finding: a settings proposal with more than 3 keys never shows the values of keys 3 and later, not even in the note. Fixing that may need a router change here so the whole words can reach the note. The router currently holds Details to the full content rule (messenger holder.go:893). If it does, this head changes and needs a new review. Do not merge the group before #304 is fixed. The checks are also out of date.
Security of the tap check (telegram channel.go:98, :354): sound.
wordsDigest collapses runs of whitespace only. Every word and its order still count, so a tap on altered words is refused (the PR's test changes "two" to "three").
The linesDigest fallback accepts nothing beyond what wordsDigest would. A match needs TrimSpace(x) to equal the collapsed text, and then both digests agree.
A warrant binds the ask's options and acts, not the text, so the text check cannot be used to replay a warrant against other words.
The remaining gap is not new and needs the bot token: someone holding it can edit with formatting, for example a spoiler, or move lines into a collapsed blockquote, and keep the plain words. Telegram gives text back without entities, so a tap still matches. This was already possible without parse_mode.
HTML escaping: every path is escaped. render.go escapes the title, every body line (inside <code> too) and the note inside the blockquote (:93). reply and the 'Replaced by' edit are escaped as well. Bot.Send and Bot.Edit (bot.go) are the only text calls. The test covers '<' and '&' in the title and the reply. Minor: no test puts '<' in the note.
Open asks at deploy:
mesh-knowledge OperatorAsk.Form and claude-code Proposal.Form and Question.Form read 0 for an existing ask, which is composed in its listed form.
The claude-code test shows the older form composes a different digest from the glance form, and that the older one is kept.
A message shown before the change is still tapped through linesDigest (TestATapOnAMessageShownBeforeIsStillTaken).
Minor findings, not blocking:
telegram render.go:56: when the body alone would pass 4096 characters, the whole note is dropped, including the fingerprint and "who asked". ADR 0345 clause 2 says "nothing of the note is dropped". This is only reachable above 4096 characters.
claude-code during a walk: a node still on old code ignores form and composes listedAsk for a glance proposal. Its warrant check fails on that node until it updates. This is transient.
An instructions proposal's summary is the proposer's own words, shown above a text that sits in the collapsed note, and nothing checks that the two agree. This is as clause 7 decides, so the risk was accepted there.
The ADR 0343 rendering test (telegram render_test.go) feeds a hand-built message. The router side of the same ask is held in messenger glance_test.go, so the pair covers clause 9.
An older channel drops Note silently, because Go's JSON ignores unknown fields. The messenger and the channels must therefore move in the same walk, which this PR does.
Tests (niced): messenger, telegram, desk-channel, mesh-knowledge and claude-code all pass. I put each module's PR tests on main's code, and every one fails there (build: Note, partsOf, linesDigest, Brief, AskGlance, Details and Glance are undefined).
Statuses at this head: mesh/merge-gate PENDING ("out of date: judged against trunk 5f491e0c09, the trunk is now 4d15a155e634; judged again on a recheck or when it is merged"), mesh/repo-check PENDING (same words), mesh/delivery PENDING ("checking"), mesh/delivery-group PENDING ("group fix/383-an-ask-reads-at-a-glance checking: composed check out of date: novox/mesh-catalog@ea1dfdce5b was judged against trunk 5f491…").
Verdict: approve at ea1dfdce5bc7973a56d491534af7031f38878774
Independent review (issues 383 and 639, ADR 0345). The approval covers this PR's own content only. Its delivery-group partner mesh-controller#304 has a blocking finding: a settings proposal with more than 3 keys never shows the values of keys 3 and later, not even in the note. Fixing that may need a router change here so the whole words can reach the note. The router currently holds Details to the full content rule (messenger holder.go:893). If it does, this head changes and needs a new review. Do not merge the group before #304 is fixed. The checks are also out of date.
Security of the tap check (telegram channel.go:98, :354): sound.
- `wordsDigest` collapses runs of whitespace only. Every word and its order still count, so a tap on altered words is refused (the PR's test changes "two" to "three").
- The `linesDigest` fallback accepts nothing beyond what `wordsDigest` would. A match needs TrimSpace(x) to equal the collapsed text, and then both digests agree.
- A warrant binds the ask's options and acts, not the text, so the text check cannot be used to replay a warrant against other words.
- The remaining gap is not new and needs the bot token: someone holding it can edit with formatting, for example a spoiler, or move lines into a collapsed blockquote, and keep the plain words. Telegram gives `text` back without entities, so a tap still matches. This was already possible without parse_mode.
HTML escaping: every path is escaped. render.go escapes the title, every body line (inside `<code>` too) and the note inside the blockquote (:93). `reply` and the 'Replaced by' edit are escaped as well. Bot.Send and Bot.Edit (bot.go) are the only text calls. The test covers '<' and '&' in the title and the reply. Minor: no test puts '<' in the note.
Open asks at deploy:
- mesh-knowledge `OperatorAsk.Form` and claude-code `Proposal.Form` and `Question.Form` read 0 for an existing ask, which is composed in its listed form.
- The claude-code test shows the older form composes a different digest from the glance form, and that the older one is kept.
- A message shown before the change is still tapped through `linesDigest` (TestATapOnAMessageShownBeforeIsStillTaken).
Minor findings, not blocking:
- telegram render.go:56: when the body alone would pass 4096 characters, the whole note is dropped, including the fingerprint and "who asked". ADR 0345 clause 2 says "nothing of the note is dropped". This is only reachable above 4096 characters.
- claude-code during a walk: a node still on old code ignores `form` and composes `listedAsk` for a glance proposal. Its warrant check fails on that node until it updates. This is transient.
- An instructions proposal's `summary` is the proposer's own words, shown above a text that sits in the collapsed note, and nothing checks that the two agree. This is as clause 7 decides, so the risk was accepted there.
- The ADR 0343 rendering test (telegram render_test.go) feeds a hand-built message. The router side of the same ask is held in messenger glance_test.go, so the pair covers clause 9.
- An older channel drops `Note` silently, because Go's JSON ignores unknown fields. The messenger and the channels must therefore move in the same walk, which this PR does.
Tests (niced): messenger, telegram, desk-channel, mesh-knowledge and claude-code all pass. I put each module's PR tests on main's code, and every one fails there (build: Note, partsOf, linesDigest, Brief, AskGlance, Details and Glance are undefined).
Statuses at this head: mesh/merge-gate PENDING ("out of date: judged against trunk 5f491e0c097d, the trunk is now 4d15a155e634; judged again on a recheck or when it is merged"), mesh/repo-check PENDING (same words), mesh/delivery PENDING ("checking"), mesh/delivery-group PENDING ("group fix/383-an-ask-reads-at-a-glance checking: composed check out of date: novox/mesh-catalog@ea1dfdce5bc7 was judged against trunk 5f491…").
New head 5dbf53e758, rebased on main, with one more commit for the review of mesh-controller #304 and the minor points here.
messenger: on a kind that proves who answers, the note shows the ask's WholeDetails in place of its Details. It is held to the secret rule alone, and an ask whose whole details carry a secret's shape is refused. Test: TestEveryKeyAndItsWholeValueIsInTheNoteWhereTheSenderIsProven (5 keys, a 300-character value: every key and full value is in the Telegram note, masked on the desk).
telegram: the note is never dropped above 4096 characters. The body is cut first and the cut is said; the note is cut only when the title and note alone do not fit, and that is said too. Tests: TestALongBodyIsCutBeforeTheNote, TestTheNoteIsEscaped ('<', '>', '&' and a stray </blockquote> in the note).
SDK at mesh-sdk f474544 (WholeDetails). Decision: ADR 0347. Local merge-check.sh with MESH_GATE and the five modules passed.
New head 5dbf53e75840, rebased on main, with one more commit for the review of mesh-controller #304 and the minor points here.
- **messenger**: on a kind that proves who answers, the note shows the ask's `WholeDetails` in place of its Details. It is held to the secret rule alone, and an ask whose whole details carry a secret's shape is refused. Test: `TestEveryKeyAndItsWholeValueIsInTheNoteWhereTheSenderIsProven` (5 keys, a 300-character value: every key and full value is in the Telegram note, masked on the desk).
- **telegram**: the note is never dropped above 4096 characters. The body is cut first and the cut is said; the note is cut only when the title and note alone do not fit, and that is said too. Tests: `TestALongBodyIsCutBeforeTheNote`, `TestTheNoteIsEscaped` ('<', '>', '&' and a stray `</blockquote>` in the note).
- SDK at mesh-sdk f474544 (`WholeDetails`). Decision: ADR 0347. Local merge-check.sh with MESH_GATE and the five modules passed.
Merge check at 5dbf53e7
Judged: head 5dbf53e75840 merged into trunk e209d46faf3d; read beside it: mesh-controller 6f1a05366c1d, mesh-controller-main 6f1a05366c1d, mesh-host 0e92ef3d1b21, mesh-tools 954e1a53eef9
mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: claude-code, desk-channel, mesh-knowledge, messenger, telegram)
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 claude-code, desk-channel, mesh-knowledge, messenger, telegram → ace, g14, novox, shanks; no bus step
claude-code keeps data (ADR 0233): what it holds is backed up before it moves
grants step: if this changes what the bus's user list says (a new tool, subject or user), novox is sent that list alone, every build there kept, before claude-code is judged on its first machine
Run by the build seat on ace as build-1791903913138216999 (builds --log build-1791903913138216999).
--- the gate: claude-code, desk-channel, mesh-knowledge, messenger, telegram
claude-code: ok, 48 tool(s), keeps state servers, holdings, config, proposals, questions, memory, reads claude-licence-manager.bindings, keeps agent-home (valuable); 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)
desk-channel: ok, 1 tool(s), invokes seat:node-notifier.send, keeps state shown; 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)
mesh-knowledge: ok, 2 tool(s), invokes seat:issue-tracker.reserve, claude-code.claude_code_judge, claude-code.claude_code_judged, records.records_status, records.records_list, records.records_read, seat:operator-channel.notify, ready: keep by unit every 30s; watch by its tool knowledge_health every 1m0s
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, walks; 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)
telegram: ok, 1 tool(s), keeps state offset, messages
long-running resources without health: 0
files asking for a setting without saying whether it is trusted: 3
5 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-13T14:52:41Z 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-13T14:52:41Z
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 5 module(s) in 1 tier(s): claude-code, desk-channel, mesh-knowledge, messenger, telegram
notes:
- modules/claude-code/README.md, modules/claude-code/cmd/claude-code/proposals_test.go, modules/claude-code/cmd/claude-code/questions_test.go, modules/desk-channel/cmd/desk-channel/desk_test.go, modules/mesh-knowledge/README.md, modules/mesh-knowledge/cmd/mesh-knowledge/glance_test.go, modules/mesh-knowledge/cmd/mesh-knowledge/review_test.go, modules/mesh-knowledge/cmd/mesh-knowledge/rules_test.go, modules/messenger/README.md, modules/messenger/cmd/messenger/answers_test.go, modules/messenger/cmd/messenger/feedback_test.go, modules/messenger/cmd/messenger/glance_test.go, modules/messenger/cmd/messenger/onemessage_test.go, modules/messenger/cmd/messenger/review_test.go, modules/messenger/cmd/messenger/whole_test.go, modules/telegram/README.md, modules/telegram/cmd/telegram/channel_test.go and modules/telegram/cmd/telegram/render_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 46786 strings of 718 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/secrets 0.011s
secrets: no setting can replace a vault secret in a mergeable file (1 known, nested)
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: 66, as kept
ok git.novox.be/novox/mesh-catalog/checks/deps 0.217s
testing modules/claude-code
ok claude-code/cmd/claude-code 5.733s
testing modules/desk-channel
ok deskchannel/cmd/desk-channel 1.012s
testing modules/mesh-knowledge
ok mesh-knowledge/cmd/mesh-knowledge 101.289s
testing modules/messenger
ok messenger/cmd/messenger 2.028s
testing modules/telegram
ok telegram/cmd/telegram 1.063s
--- its merge-check-typescript.sh (typescript toolchain)
Out of date when it landed: out of date: judged against trunk e209d46faf, the trunk is now 9c166398f204; judged again on a recheck or when it is merged
**Merge check** at `5dbf53e7`
Judged: head `5dbf53e75840` merged into trunk `e209d46faf3d`; read beside it: mesh-controller `6f1a05366c1d`, mesh-controller-main `6f1a05366c1d`, mesh-host `0e92ef3d1b21`, mesh-tools `954e1a53eef9`
- `mesh/merge-gate`: **PASS** — every machine composes with the change as it did without (4 of 4 compose) (modules: claude-code, desk-channel, mesh-knowledge, messenger, telegram)
- `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 claude-code, desk-channel, mesh-knowledge, messenger, telegram → ace, g14, novox, shanks; no bus step
- tier 0: claude-code, desk-channel, mesh-knowledge, messenger, telegram
- ace: receives claude-code
- g14: receives claude-code
- novox: receives claude-code, desk-channel, mesh-knowledge, messenger, telegram
- shanks: receives claude-code
- claude-code keeps data (ADR 0233): what it holds is backed up before it moves
- grants step: if this changes what the bus's user list says (a new tool, subject or user), novox is sent that list alone, every build there kept, before claude-code is judged on its first machine
- read by no module's build: modules/claude-code/README.md, modules/claude-code/cmd/claude-code/proposals_test.go, modules/claude-code/cmd/claude-code/questions_test.go, modules/desk-channel/cmd/desk-channel/desk_test.go, modules/mesh-knowledge/README.md, modules/mesh-knowledge/cmd/mesh-knowledge/glance_test.go, modules/mesh-knowledge/cmd/mesh-knowledge/review_test.go, modules/mesh-knowledge/cmd/mesh-knowledge/rules_test.go, modules/messenger/README.md, modules/messenger/cmd/messenger/answers_test.go, modules/messenger/cmd/messenger/feedback_test.go, modules/messenger/cmd/messenger/glance_test.go, modules/messenger/cmd/messenger/onemessage_test.go, modules/messenger/cmd/messenger/review_test.go, modules/messenger/cmd/messenger/whole_test.go, modules/telegram/README.md, modules/telegram/cmd/telegram/channel_test.go, modules/telegram/cmd/telegram/render_test.go
Run by the build seat on ace as `build-1791903913138216999` (`builds --log build-1791903913138216999`).
```
--- the gate: claude-code, desk-channel, mesh-knowledge, messenger, telegram
claude-code: ok, 48 tool(s), keeps state servers, holdings, config, proposals, questions, memory, reads claude-licence-manager.bindings, keeps agent-home (valuable); 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)
desk-channel: ok, 1 tool(s), invokes seat:node-notifier.send, keeps state shown; 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)
mesh-knowledge: ok, 2 tool(s), invokes seat:issue-tracker.reserve, claude-code.claude_code_judge, claude-code.claude_code_judged, records.records_status, records.records_list, records.records_read, seat:operator-channel.notify, ready: keep by unit every 30s; watch by its tool knowledge_health every 1m0s
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, walks; 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)
telegram: ok, 1 tool(s), keeps state offset, messages
long-running resources without health: 0
files asking for a setting without saying whether it is trusted: 3
5 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-13T14:52:41Z 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-13T14:52:41Z
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 5 module(s) in 1 tier(s): claude-code, desk-channel, mesh-knowledge, messenger, telegram
notes:
- modules/claude-code/README.md, modules/claude-code/cmd/claude-code/proposals_test.go, modules/claude-code/cmd/claude-code/questions_test.go, modules/desk-channel/cmd/desk-channel/desk_test.go, modules/mesh-knowledge/README.md, modules/mesh-knowledge/cmd/mesh-knowledge/glance_test.go, modules/mesh-knowledge/cmd/mesh-knowledge/review_test.go, modules/mesh-knowledge/cmd/mesh-knowledge/rules_test.go, modules/messenger/README.md, modules/messenger/cmd/messenger/answers_test.go, modules/messenger/cmd/messenger/feedback_test.go, modules/messenger/cmd/messenger/glance_test.go, modules/messenger/cmd/messenger/onemessage_test.go, modules/messenger/cmd/messenger/review_test.go, modules/messenger/cmd/messenger/whole_test.go, modules/telegram/README.md, modules/telegram/cmd/telegram/channel_test.go and modules/telegram/cmd/telegram/render_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 46786 strings of 718 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/secrets 0.011s
secrets: no setting can replace a vault secret in a mergeable file (1 known, nested)
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: 66, as kept
ok git.novox.be/novox/mesh-catalog/checks/deps 0.217s
testing modules/claude-code
ok claude-code/cmd/claude-code 5.733s
testing modules/desk-channel
ok deskchannel/cmd/desk-channel 1.012s
testing modules/mesh-knowledge
ok mesh-knowledge/cmd/mesh-knowledge 101.289s
testing modules/messenger
ok messenger/cmd/messenger 2.028s
testing modules/telegram
ok telegram/cmd/telegram 1.063s
--- its merge-check-typescript.sh (typescript toolchain)
```
**Out of date when it landed**: out of date: judged against trunk e209d46faf3d, the trunk is now 9c166398f204; judged again on a recheck or when it is merged
The operator would not read the Telegram ask for ADR 0343: thirty plain lines, every clause on one, no bold,
no summary. A settings proposal was the same wall of text, its values masked so the approval was blind.
- messenger: an ask's message is the asker's headline and explanation alone; who asked and when, what each
answer does, the expiry, where else it is answered and the asker's Details travel as the message's note
(asks.Message.Note). Answered, the message is one line, "You chose Approve at 16:06 on Telegram ·
<headline>". An explanation that does not read at a glance (asks.Glance) is shown and logged. On a kind
that proves who answers, an ask's values are shown whole (asks.Ask.Whole), held to the secret rule alone
(from the earlier work on issue 383, #178).
- telegram: every message in HTML, never reworded: the title bold, a key line monospace, the note apart in
a collapsed blockquote; markup escaped. A tap is compared by its words, whitespace aside, and a message
shown before is still compared by the digest it was kept under.
- desk-channel: the note follows the body.
- mesh-knowledge: a record that needs the operator carries a brief (headline, summary, at most three
points), the 30th per-record rule; its ask shows the brief and never the clauses. An ask made before is
composed again as it was asked (form), so its warrant still holds.
- claude-code: an instructions proposal's explanation is one summary line (the proposer's, or the
module's), its text in the Details; a question's context is at most 300 characters and its recommendation
one point. Older proposals and questions keep their form.
The SDK is pinned at mesh-sdk 9588871 (fix/639-an-ask-reads-at-a-glance), which adds Message.Note and
asks.Glance.
mesh/repo-check head bb5a342863ee merged into trunk 9c166398f204 — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
The review of mesh-controller #304: a proposal of more than three keys showed only the names of the rest,
and its Details could carry no value, so Approve bound values the operator never saw. The router now
shows an ask's WholeDetails in the note in place of its Details on a kind that proves who answers, held
to the secret rule alone, and refuses an ask whose whole details carry a secret's shape. Telegram keeps
the note whole when a message is too long, cutting the body first and saying so, and escapes the note
as every other part. SDK at mesh-sdk f474544.
Merge check at bb5a3428
Judged: head bb5a342863ee merged into trunk 9c166398f204; read beside it: mesh-controller 6f1a05366c1d, mesh-controller-main 6f1a05366c1d, mesh-host 0e92ef3d1b21, mesh-tools 954e1a53eef9
mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: claude-code, desk-channel, mesh-knowledge, messenger, telegram)
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 claude-code, desk-channel, mesh-knowledge, messenger, telegram → ace, g14, novox, shanks; no bus step
claude-code keeps data (ADR 0233): what it holds is backed up before it moves
grants step: if this changes what the bus's user list says (a new tool, subject or user), novox is sent that list alone, every build there kept, before claude-code is judged on its first machine
Run by the build seat on ace as build-1791904626852455819 (builds --log build-1791904626852455819).
--- the gate: claude-code, desk-channel, mesh-knowledge, messenger, telegram
claude-code: ok, 48 tool(s), keeps state servers, holdings, config, proposals, questions, memory, reads claude-licence-manager.bindings, keeps agent-home (valuable); 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)
desk-channel: ok, 1 tool(s), invokes seat:node-notifier.send, keeps state shown; 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)
mesh-knowledge: ok, 2 tool(s), invokes seat:issue-tracker.reserve, claude-code.claude_code_judge, claude-code.claude_code_judged, records.records_status, records.records_list, records.records_read, seat:operator-channel.notify, ready: keep by unit every 30s; watch by its tool knowledge_health every 1m0s
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, walks; 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)
telegram: ok, 1 tool(s), keeps state offset, messages
long-running resources without health: 0
files asking for a setting without saying whether it is trusted: 3
5 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-13T15:15:17Z 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-13T15:15:17Z
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 5 module(s) in 1 tier(s): claude-code, desk-channel, mesh-knowledge, messenger, telegram
notes:
- modules/claude-code/README.md, modules/claude-code/cmd/claude-code/proposals_test.go, modules/claude-code/cmd/claude-code/questions_test.go, modules/desk-channel/cmd/desk-channel/desk_test.go, modules/mesh-knowledge/README.md, modules/mesh-knowledge/cmd/mesh-knowledge/glance_test.go, modules/mesh-knowledge/cmd/mesh-knowledge/review_test.go, modules/mesh-knowledge/cmd/mesh-knowledge/rules_test.go, modules/messenger/README.md, modules/messenger/cmd/messenger/answers_test.go, modules/messenger/cmd/messenger/feedback_test.go, modules/messenger/cmd/messenger/glance_test.go, modules/messenger/cmd/messenger/onemessage_test.go, modules/messenger/cmd/messenger/review_test.go, modules/messenger/cmd/messenger/whole_test.go, modules/telegram/README.md, modules/telegram/cmd/telegram/channel_test.go and modules/telegram/cmd/telegram/render_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 46758 strings of 718 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/secrets 0.011s
secrets: no setting can replace a vault secret in a mergeable file (1 known, nested)
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: 66, as kept
ok git.novox.be/novox/mesh-catalog/checks/deps 0.215s
testing modules/claude-code
ok claude-code/cmd/claude-code 5.794s
testing modules/desk-channel
ok deskchannel/cmd/desk-channel 1.011s
testing modules/mesh-knowledge
ok mesh-knowledge/cmd/mesh-knowledge 101.459s
testing modules/messenger
ok messenger/cmd/messenger 2.041s
testing modules/telegram
ok telegram/cmd/telegram 1.058s
--- its merge-check-typescript.sh (typescript toolchain)
**Merge check** at `bb5a3428`
Judged: head `bb5a342863ee` merged into trunk `9c166398f204`; read beside it: mesh-controller `6f1a05366c1d`, mesh-controller-main `6f1a05366c1d`, mesh-host `0e92ef3d1b21`, mesh-tools `954e1a53eef9`
- `mesh/merge-gate`: **PASS** — every machine composes with the change as it did without (4 of 4 compose) (modules: claude-code, desk-channel, mesh-knowledge, messenger, telegram)
- `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 claude-code, desk-channel, mesh-knowledge, messenger, telegram → ace, g14, novox, shanks; no bus step
- tier 0: claude-code, desk-channel, mesh-knowledge, messenger, telegram
- ace: receives claude-code
- g14: receives claude-code
- novox: receives claude-code, desk-channel, mesh-knowledge, messenger, telegram
- shanks: receives claude-code
- claude-code keeps data (ADR 0233): what it holds is backed up before it moves
- grants step: if this changes what the bus's user list says (a new tool, subject or user), novox is sent that list alone, every build there kept, before claude-code is judged on its first machine
- read by no module's build: modules/claude-code/README.md, modules/claude-code/cmd/claude-code/proposals_test.go, modules/claude-code/cmd/claude-code/questions_test.go, modules/desk-channel/cmd/desk-channel/desk_test.go, modules/mesh-knowledge/README.md, modules/mesh-knowledge/cmd/mesh-knowledge/glance_test.go, modules/mesh-knowledge/cmd/mesh-knowledge/review_test.go, modules/mesh-knowledge/cmd/mesh-knowledge/rules_test.go, modules/messenger/README.md, modules/messenger/cmd/messenger/answers_test.go, modules/messenger/cmd/messenger/feedback_test.go, modules/messenger/cmd/messenger/glance_test.go, modules/messenger/cmd/messenger/onemessage_test.go, modules/messenger/cmd/messenger/review_test.go, modules/messenger/cmd/messenger/whole_test.go, modules/telegram/README.md, modules/telegram/cmd/telegram/channel_test.go, modules/telegram/cmd/telegram/render_test.go
Run by the build seat on ace as `build-1791904626852455819` (`builds --log build-1791904626852455819`).
```
--- the gate: claude-code, desk-channel, mesh-knowledge, messenger, telegram
claude-code: ok, 48 tool(s), keeps state servers, holdings, config, proposals, questions, memory, reads claude-licence-manager.bindings, keeps agent-home (valuable); 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)
desk-channel: ok, 1 tool(s), invokes seat:node-notifier.send, keeps state shown; 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)
mesh-knowledge: ok, 2 tool(s), invokes seat:issue-tracker.reserve, claude-code.claude_code_judge, claude-code.claude_code_judged, records.records_status, records.records_list, records.records_read, seat:operator-channel.notify, ready: keep by unit every 30s; watch by its tool knowledge_health every 1m0s
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, walks; 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)
telegram: ok, 1 tool(s), keeps state offset, messages
long-running resources without health: 0
files asking for a setting without saying whether it is trusted: 3
5 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-13T15:15:17Z 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-13T15:15:17Z
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 5 module(s) in 1 tier(s): claude-code, desk-channel, mesh-knowledge, messenger, telegram
notes:
- modules/claude-code/README.md, modules/claude-code/cmd/claude-code/proposals_test.go, modules/claude-code/cmd/claude-code/questions_test.go, modules/desk-channel/cmd/desk-channel/desk_test.go, modules/mesh-knowledge/README.md, modules/mesh-knowledge/cmd/mesh-knowledge/glance_test.go, modules/mesh-knowledge/cmd/mesh-knowledge/review_test.go, modules/mesh-knowledge/cmd/mesh-knowledge/rules_test.go, modules/messenger/README.md, modules/messenger/cmd/messenger/answers_test.go, modules/messenger/cmd/messenger/feedback_test.go, modules/messenger/cmd/messenger/glance_test.go, modules/messenger/cmd/messenger/onemessage_test.go, modules/messenger/cmd/messenger/review_test.go, modules/messenger/cmd/messenger/whole_test.go, modules/telegram/README.md, modules/telegram/cmd/telegram/channel_test.go and modules/telegram/cmd/telegram/render_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 46758 strings of 718 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/secrets 0.011s
secrets: no setting can replace a vault secret in a mergeable file (1 known, nested)
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: 66, as kept
ok git.novox.be/novox/mesh-catalog/checks/deps 0.215s
testing modules/claude-code
ok claude-code/cmd/claude-code 5.794s
testing modules/desk-channel
ok deskchannel/cmd/desk-channel 1.011s
testing modules/mesh-knowledge
ok mesh-knowledge/cmd/mesh-knowledge 101.459s
testing modules/messenger
ok messenger/cmd/messenger 2.041s
testing modules/telegram
ok telegram/cmd/telegram 1.058s
--- its merge-check-typescript.sh (typescript toolchain)
```
Independent review of the issue 383/639 group under ADR 0345 and ADR 0347. The code here is right. However, mesh-sdk #25 is asked to change its digest encoding, so this PR must re-pin the new SDK head in every module's go.mod/go.sum before it merges. That re-pin needs a fresh look at the pin only.
Checked:
(1) On an ask's own message, on a kind that proves who answers and holds a ticket, the note shows WholeDetails, held to CheckSecret (messenger holder.go:889-901, asks.go provenAsk). Everywhere else it shows Details under Check. The desk shows the note after the body (desk-channel desk.go). TestEveryKeyAndItsWholeValueIsInTheNoteWhereTheSenderIsProven covers both.
(2) TakeAsk refuses an ask whose Whole or WholeDetails carry a secret's shape (messenger asks.go:494). A tap is compared by a whitespace-normalised digest of the plain words. A message shown before this change still matches through linesDigest (telegram channel.go:93-108, :354). A hash preimage would be needed to pass either digest with other words.
(3) Escaping: every Send and Edit goes through shown.html() or escape() (channel.go:252, 296, 304, 462), and escape covers &, < and >. I probed a note holding </blockquote><a href=...> and it rendered as text, one blockquote, no link.
Cutting (ADR 0347 §5): partsOf cuts the body first and cuts the note only when the title and note alone do not fit. Each cut says itself. I probed 3000/2000 and 5 + 5000 characters; both give exactly 4096.
Tests: messenger, telegram, desk-channel, claude-code and mesh-knowledge all pass at the head (run niced). The new tests fail on main (build) and on eadf301: TestALongBodyIsCutBeforeTheNote fails there, and the messenger whole-details tests do not build.
Not blocking:
messenger holder.go:899 replaces a Details line that fails its rule with "(a line carrying … is withheld here)", which drops the key's name. ADR 0347 §2 has the asker withhold the value under its key, so with a correct asker this line should not occur. But the controller can reach it today (see the review on mesh-controller #304: a key named password, past the second). Keeping the key's name, when the line starts with "+ key:", would make the router's fallback match §3.
telegram render.go partsOf does not bound the title. A title over 4096 characters gives a message Telegram rejects. Headlines are bounded upstream, so this is theoretical.
Statuses at this head: mesh/merge-gate success ("head bb5a342863 merged into trunk 9c166398f2, pass"), mesh/repo-check success, mesh/delivery success ("ready: it delivers once merged"), mesh/delivery-group success ("group fix/383-an-ask-reads-at-a-glance ready: every member ready, and composed together they pass").
Verdict: approve at bb5a342863ee2b25373e9bb96722a6921bb92b7b
Independent review of the issue 383/639 group under ADR 0345 and ADR 0347. The code here is right. However, mesh-sdk #25 is asked to change its digest encoding, so this PR must re-pin the new SDK head in every module's go.mod/go.sum before it merges. That re-pin needs a fresh look at the pin only.
Checked:
- (1) On an ask's own message, on a kind that proves who answers and holds a ticket, the note shows WholeDetails, held to CheckSecret (messenger holder.go:889-901, asks.go provenAsk). Everywhere else it shows Details under Check. The desk shows the note after the body (desk-channel desk.go). TestEveryKeyAndItsWholeValueIsInTheNoteWhereTheSenderIsProven covers both.
- (2) TakeAsk refuses an ask whose Whole or WholeDetails carry a secret's shape (messenger asks.go:494). A tap is compared by a whitespace-normalised digest of the plain words. A message shown before this change still matches through linesDigest (telegram channel.go:93-108, :354). A hash preimage would be needed to pass either digest with other words.
- (3) Escaping: every Send and Edit goes through shown.html() or escape() (channel.go:252, 296, 304, 462), and escape covers &, < and >. I probed a note holding `</blockquote><a href=...>` and it rendered as text, one blockquote, no link.
- Cutting (ADR 0347 §5): partsOf cuts the body first and cuts the note only when the title and note alone do not fit. Each cut says itself. I probed 3000/2000 and 5 + 5000 characters; both give exactly 4096.
- Tests: messenger, telegram, desk-channel, claude-code and mesh-knowledge all pass at the head (run niced). The new tests fail on main (build) and on eadf301: TestALongBodyIsCutBeforeTheNote fails there, and the messenger whole-details tests do not build.
Not blocking:
- messenger holder.go:899 replaces a Details line that fails its rule with "(a line carrying … is withheld here)", which drops the key's name. ADR 0347 §2 has the asker withhold the value under its key, so with a correct asker this line should not occur. But the controller can reach it today (see the review on mesh-controller #304: a key named password, past the second). Keeping the key's name, when the line starts with "+ key:", would make the router's fallback match §3.
- telegram render.go partsOf does not bound the title. A title over 4096 characters gives a message Telegram rejects. Headlines are bounded upstream, so this is theoretical.
Statuses at this head: mesh/merge-gate success ("head bb5a342863ee merged into trunk 9c166398f204, pass"), mesh/repo-check success, mesh/delivery success ("ready: it delivers once merged"), mesh/delivery-group success ("group fix/383-an-ask-reads-at-a-glance ready: every member ready, and composed together they pass").
mesh/repo-check head f09daabec3a8 merged into trunk 9c166398f204 — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
The router's fallback said a refused note line as "(a line carrying … is withheld here)", so the operator
could not tell which setting held a value they were not shown. A change's line now keeps its key; any other
line, or one whose key is refused too, is said withheld whole. The SDK pin moves to mesh-sdk 5933eb7, where
no two asks digest the same.
New head f09daabec3. The router's fallback for a refused note line now keeps a change line's key (withheldLine): + password (a value carrying a value given to a secret's name is withheld here). Any other line, or one whose key is refused too, is still withheld whole. Test: TestAWithheldChangeLineKeepsItsKey. All five modules are re-pinned to mesh-sdk 5933eb7. Local merge-check.sh passed.
New head f09daabec3a8. The router's fallback for a refused note line now keeps a change line's key (`withheldLine`): `+ password (a value carrying a value given to a secret's name is withheld here)`. Any other line, or one whose key is refused too, is still withheld whole. Test: `TestAWithheldChangeLineKeepsItsKey`. All five modules are re-pinned to mesh-sdk 5933eb7. Local merge-check.sh passed.
Merge check at f09daabe
Judged: head f09daabec3a8 merged into trunk 9c166398f204; read beside it: mesh-controller 9f3aa91e812b, mesh-controller-main 332fbaa9b175, mesh-host 0e92ef3d1b21, mesh-tools 954e1a53eef9
mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: claude-code, desk-channel, mesh-knowledge, messenger, telegram)
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 claude-code, desk-channel, mesh-knowledge, messenger, telegram → ace, g14, novox, shanks; no bus step
claude-code keeps data (ADR 0233): what it holds is backed up before it moves
grants step: if this changes what the bus's user list says (a new tool, subject or user), novox is sent that list alone, every build there kept, before claude-code is judged on its first machine
Run by the build seat on ace as build-1791916538403302422 (builds --log build-1791916538403302422).
--- the gate: claude-code, desk-channel, mesh-knowledge, messenger, telegram
claude-code: ok, 48 tool(s), keeps state servers, holdings, config, proposals, questions, memory, reads claude-licence-manager.bindings, keeps agent-home (valuable); 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)
desk-channel: ok, 1 tool(s), invokes seat:node-notifier.send, keeps state shown; 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)
mesh-knowledge: ok, 2 tool(s), invokes seat:issue-tracker.reserve, claude-code.claude_code_judge, claude-code.claude_code_judged, records.records_status, records.records_list, records.records_read, seat:operator-channel.notify, ready: keep by unit every 30s; watch by its tool knowledge_health every 1m0s
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, walks; 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)
telegram: ok, 1 tool(s), keeps state offset, messages
long-running resources without health: 0
files asking for a setting without saying whether it is trusted: 3
5 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-13T18:36:27Z 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-13T18:36:27Z
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 5 module(s) in 1 tier(s): claude-code, desk-channel, mesh-knowledge, messenger, telegram
notes:
- modules/claude-code/README.md, modules/claude-code/cmd/claude-code/proposals_test.go, modules/claude-code/cmd/claude-code/questions_test.go, modules/desk-channel/cmd/desk-channel/desk_test.go, modules/mesh-knowledge/README.md, modules/mesh-knowledge/cmd/mesh-knowledge/glance_test.go, modules/mesh-knowledge/cmd/mesh-knowledge/review_test.go, modules/mesh-knowledge/cmd/mesh-knowledge/rules_test.go, modules/messenger/README.md, modules/messenger/cmd/messenger/answers_test.go, modules/messenger/cmd/messenger/feedback_test.go, modules/messenger/cmd/messenger/glance_test.go, modules/messenger/cmd/messenger/onemessage_test.go, modules/messenger/cmd/messenger/review_test.go, modules/messenger/cmd/messenger/whole_test.go, modules/telegram/README.md, modules/telegram/cmd/telegram/channel_test.go and modules/telegram/cmd/telegram/render_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 46762 strings of 718 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/secrets 0.012s
secrets: no setting can replace a vault secret in a mergeable file (1 known, nested)
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: 66, as kept
ok git.novox.be/novox/mesh-catalog/checks/deps 0.251s
testing modules/claude-code
ok claude-code/cmd/claude-code 6.623s
testing modules/desk-channel
ok deskchannel/cmd/desk-channel 1.013s
testing modules/mesh-knowledge
ok mesh-knowledge/cmd/mesh-knowledge 99.492s
testing modules/messenger
ok messenger/cmd/messenger 1.992s
testing modules/telegram
ok telegram/cmd/telegram 1.058s
--- its merge-check-typescript.sh (typescript toolchain)
**Merge check** at `f09daabe`
Judged: head `f09daabec3a8` merged into trunk `9c166398f204`; read beside it: mesh-controller `9f3aa91e812b`, mesh-controller-main `332fbaa9b175`, mesh-host `0e92ef3d1b21`, mesh-tools `954e1a53eef9`
- `mesh/merge-gate`: **PASS** — every machine composes with the change as it did without (4 of 4 compose) (modules: claude-code, desk-channel, mesh-knowledge, messenger, telegram)
- `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 claude-code, desk-channel, mesh-knowledge, messenger, telegram → ace, g14, novox, shanks; no bus step
- tier 0: claude-code, desk-channel, mesh-knowledge, messenger, telegram
- ace: receives claude-code
- g14: receives claude-code
- novox: receives claude-code, desk-channel, mesh-knowledge, messenger, telegram
- shanks: receives claude-code
- claude-code keeps data (ADR 0233): what it holds is backed up before it moves
- grants step: if this changes what the bus's user list says (a new tool, subject or user), novox is sent that list alone, every build there kept, before claude-code is judged on its first machine
- read by no module's build: modules/claude-code/README.md, modules/claude-code/cmd/claude-code/proposals_test.go, modules/claude-code/cmd/claude-code/questions_test.go, modules/desk-channel/cmd/desk-channel/desk_test.go, modules/mesh-knowledge/README.md, modules/mesh-knowledge/cmd/mesh-knowledge/glance_test.go, modules/mesh-knowledge/cmd/mesh-knowledge/review_test.go, modules/mesh-knowledge/cmd/mesh-knowledge/rules_test.go, modules/messenger/README.md, modules/messenger/cmd/messenger/answers_test.go, modules/messenger/cmd/messenger/feedback_test.go, modules/messenger/cmd/messenger/glance_test.go, modules/messenger/cmd/messenger/onemessage_test.go, modules/messenger/cmd/messenger/review_test.go, modules/messenger/cmd/messenger/whole_test.go, modules/telegram/README.md, modules/telegram/cmd/telegram/channel_test.go, modules/telegram/cmd/telegram/render_test.go
Run by the build seat on ace as `build-1791916538403302422` (`builds --log build-1791916538403302422`).
```
--- the gate: claude-code, desk-channel, mesh-knowledge, messenger, telegram
claude-code: ok, 48 tool(s), keeps state servers, holdings, config, proposals, questions, memory, reads claude-licence-manager.bindings, keeps agent-home (valuable); 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)
desk-channel: ok, 1 tool(s), invokes seat:node-notifier.send, keeps state shown; 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)
mesh-knowledge: ok, 2 tool(s), invokes seat:issue-tracker.reserve, claude-code.claude_code_judge, claude-code.claude_code_judged, records.records_status, records.records_list, records.records_read, seat:operator-channel.notify, ready: keep by unit every 30s; watch by its tool knowledge_health every 1m0s
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, walks; 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)
telegram: ok, 1 tool(s), keeps state offset, messages
long-running resources without health: 0
files asking for a setting without saying whether it is trusted: 3
5 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-13T18:36:27Z 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-13T18:36:27Z
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 5 module(s) in 1 tier(s): claude-code, desk-channel, mesh-knowledge, messenger, telegram
notes:
- modules/claude-code/README.md, modules/claude-code/cmd/claude-code/proposals_test.go, modules/claude-code/cmd/claude-code/questions_test.go, modules/desk-channel/cmd/desk-channel/desk_test.go, modules/mesh-knowledge/README.md, modules/mesh-knowledge/cmd/mesh-knowledge/glance_test.go, modules/mesh-knowledge/cmd/mesh-knowledge/review_test.go, modules/mesh-knowledge/cmd/mesh-knowledge/rules_test.go, modules/messenger/README.md, modules/messenger/cmd/messenger/answers_test.go, modules/messenger/cmd/messenger/feedback_test.go, modules/messenger/cmd/messenger/glance_test.go, modules/messenger/cmd/messenger/onemessage_test.go, modules/messenger/cmd/messenger/review_test.go, modules/messenger/cmd/messenger/whole_test.go, modules/telegram/README.md, modules/telegram/cmd/telegram/channel_test.go and modules/telegram/cmd/telegram/render_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 46762 strings of 718 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/secrets 0.012s
secrets: no setting can replace a vault secret in a mergeable file (1 known, nested)
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: 66, as kept
ok git.novox.be/novox/mesh-catalog/checks/deps 0.251s
testing modules/claude-code
ok claude-code/cmd/claude-code 6.623s
testing modules/desk-channel
ok deskchannel/cmd/desk-channel 1.013s
testing modules/mesh-knowledge
ok mesh-knowledge/cmd/mesh-knowledge 99.492s
testing modules/messenger
ok messenger/cmd/messenger 1.992s
testing modules/telegram
ok telegram/cmd/telegram 1.058s
--- its merge-check-typescript.sh (typescript toolchain)
```
Re-review after review 226. The only change since bb5a342 is one commit:
Pin: messenger, telegram, desk-channel, claude-code and mesh-knowledge all pin mesh-sdk 5933eb757d44, the approved head of mesh-sdk #25.
Withheld lines: messenger holder.go:899 now calls withheldLine (holder.go:1150-1165). A refused change line ("+ key: …") keeps its key, and the named form is itself checked against the same rule; otherwise the whole line is said withheld. A key shaped like a secret falls back to the whole-line form, so it is never echoed. TestAWithheldChangeLineKeepsItsKey covers four shapes and does not build on bb5a342.
Tests: all five modules pass at this head (run niced).
Statuses at this head: mesh/merge-gate success ("head f09daabec3 merged into trunk 9c166398f2 — pass: builds claude-code, desk-channel, mesh-knowledge, messenger, telegram → ace, g14, …"), mesh/repo-check success ("… pass: its merge-check.sh passed …"), mesh/delivery success ("ready: it delivers once merged"), mesh/delivery-group success ("group fix/383-an-ask-reads-at-a-glance ready: every member ready, and composed together they pass", 18:55:39Z, after the new controller and SDK heads).
Verdict: approve at f09daabec3a8791b4d2ba44c4d5102ed40a3f570
Re-review after review 226. The only change since bb5a342 is one commit:
- Pin: messenger, telegram, desk-channel, claude-code and mesh-knowledge all pin mesh-sdk 5933eb757d44, the approved head of mesh-sdk #25.
- Withheld lines: messenger holder.go:899 now calls withheldLine (holder.go:1150-1165). A refused change line ("+ key: …") keeps its key, and the named form is itself checked against the same rule; otherwise the whole line is said withheld. A key shaped like a secret falls back to the whole-line form, so it is never echoed. TestAWithheldChangeLineKeepsItsKey covers four shapes and does not build on bb5a342.
- Tests: all five modules pass at this head (run niced).
Statuses at this head: mesh/merge-gate success ("head f09daabec3a8 merged into trunk 9c166398f204 — pass: builds claude-code, desk-channel, mesh-knowledge, messenger, telegram → ace, g14, …"), mesh/repo-check success ("… pass: its merge-check.sh passed …"), mesh/delivery success ("ready: it delivers once merged"), mesh/delivery-group success ("group fix/383-an-ask-reads-at-a-glance ready: every member ready, and composed together they pass", 18:55:39Z, after the new controller and SDK heads).
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.
Replaces #178 (issue 383), rebased on main and reshaped for issue 639.
Acceptance. The next decision ask the operator gets on Telegram is a bold headline saying what it changes for them, a two- or three-sentence summary and at most three points, the Approve/Decline buttons, and a collapsed note with who asked, the fingerprint and how to read the clauses; the ADR 0343 ask renders in 10 lines (it was ~30) and lists no clause. Answered, it is one line with the headline.
What.
asks.Message.Note). Answered: "You chose Approve at 16:06 on Telegram · ", the told-line as its note, body not repeated. An explanation that failsasks.Glanceis shown and logged, never refused. From #178: on a kind that proves who answers an ask's values are shown whole (asks.Ask.Whole), held to the secret rule alone (CheckSecret). The Details button of #178 is dropped: Details are now the note.<blockquote expandable>after a blank line;<>&escaped. Taps compared with whitespace runs taken as one; a message shown before is still compared by its old digest.proposetakesbrief{headline, summary, points}; rule 30briefrequires it with needs-operator for records dated from 2026-10-13. The ask shows the brief, never the clauses; Details: record, proposer, review, fingerprint, "Read its N clauses with the knowledge base's get, number N".OperatorAsk.Formkeeps an ask made before composed as it was, so its warrant still holds.summary, else the module's words), its text moved to the Details; a question's context is at most 300 characters and its recommendation one point.formkeeps older proposals and questions composed as asked.Design limits I chose (ADR 0345, proposed, needs the operator): summary ≤ 300 characters on one line, ≤ 3 points of ≤ 160; question context 1500 → 300 characters, why 300 → 120 bytes; more than three setting keys show two and the names of the rest.
Depends on mesh-sdk #25 (pinned at 9588871, pushed). Merge order: mesh-sdk #25, this, then mesh-controller's PR (the router must know
Wholebefore the controller sends it, or the digests differ and the warrant is refused, loudly).Tested.
merge-check.shwith MESH_GATE (a controller built from the controller branch) and MESH_CHECK_MODULES=messenger,telegram,desk-channel,mesh-knowledge,claude-code: all green. New tests that fail on main: messengerTestAnAsksMessageIsItsSummaryWithTheRestInItsNote,TestAnAskThatIsAWallOfTextIsShownAndSaid; telegramTestTheADR0343AskFitsAGlance(≤ 12 lines, bold headline, collapsed note, no clause),TestALongNoteIsCutBeforeTheBody,TestATapOnAMessageShownBeforeIsStillTaken; mesh-knowledgeTestADecisionAskReadsAtAGlance,TestABriefIsHeldToAGlance, thebriefrow of the rule table; claude-codeTestAProposalIsAskedAtAGlanceAndAnOlderOneAsItWasAsked; desk-channelTestTheNoteFollowsTheBody. Existing tests were updated where the shape changed.Fixes issue 639. Fixes issue 383 (with mesh-controller and hq).
Delivery
novox/mesh-catalog@f09daabec3a8— delivered since 2026-10-13T19:17:50ZDelivery plan — builds claude-code, desk-channel, mesh-knowledge, messenger, telegram → ace, g14, novox, shanks; no bus step
Group
fix/383-an-ask-reads-at-a-glance, in order: novox/mesh-catalog@f09daabec3 → novox/mesh-controller@deef9421a2Machines
Transitions
The commit's note under
refs/notes/mesh-plankeeps every transition:git log --notes=mesh-plan.Merge check at
ea1dfdceJudged: head
ea1dfdce5bc7merged into trunk5f491e0c097d; read beside it: mesh-controller6f1a05366c1d, mesh-controller-main6f1a05366c1d, mesh-host0e92ef3d1b21, mesh-tools954e1a53eef9mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: claude-code, desk-channel, mesh-knowledge, messenger, telegram)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 claude-code, desk-channel, mesh-knowledge, messenger, telegram → ace, g14, novox, shanks; no bus step
Run by the build seat on novox as
build-1791902224469986315(builds --log build-1791902224469986315).Verdict: approve at
ea1dfdce5bIndependent review (issues 383 and 639, ADR 0345). The approval covers this PR's own content only. Its delivery-group partner mesh-controller#304 has a blocking finding: a settings proposal with more than 3 keys never shows the values of keys 3 and later, not even in the note. Fixing that may need a router change here so the whole words can reach the note. The router currently holds Details to the full content rule (messenger holder.go:893). If it does, this head changes and needs a new review. Do not merge the group before #304 is fixed. The checks are also out of date.
Security of the tap check (telegram channel.go:98, :354): sound.
wordsDigestcollapses runs of whitespace only. Every word and its order still count, so a tap on altered words is refused (the PR's test changes "two" to "three").linesDigestfallback accepts nothing beyond whatwordsDigestwould. A match needs TrimSpace(x) to equal the collapsed text, and then both digests agree.textback without entities, so a tap still matches. This was already possible without parse_mode.HTML escaping: every path is escaped. render.go escapes the title, every body line (inside
<code>too) and the note inside the blockquote (:93).replyand the 'Replaced by' edit are escaped as well. Bot.Send and Bot.Edit (bot.go) are the only text calls. The test covers '<' and '&' in the title and the reply. Minor: no test puts '<' in the note.Open asks at deploy:
OperatorAsk.Formand claude-codeProposal.FormandQuestion.Formread 0 for an existing ask, which is composed in its listed form.linesDigest(TestATapOnAMessageShownBeforeIsStillTaken).Minor findings, not blocking:
formand composeslistedAskfor a glance proposal. Its warrant check fails on that node until it updates. This is transient.summaryis the proposer's own words, shown above a text that sits in the collapsed note, and nothing checks that the two agree. This is as clause 7 decides, so the risk was accepted there.Notesilently, because Go's JSON ignores unknown fields. The messenger and the channels must therefore move in the same walk, which this PR does.Tests (niced): messenger, telegram, desk-channel, mesh-knowledge and claude-code all pass. I put each module's PR tests on main's code, and every one fails there (build: Note, partsOf, linesDigest, Brief, AskGlance, Details and Glance are undefined).
Statuses at this head: mesh/merge-gate PENDING ("out of date: judged against trunk
5f491e0c09, the trunk is now 4d15a155e634; judged again on a recheck or when it is merged"), mesh/repo-check PENDING (same words), mesh/delivery PENDING ("checking"), mesh/delivery-group PENDING ("group fix/383-an-ask-reads-at-a-glance checking: composed check out of date: novox/mesh-catalog@ea1dfdce5b was judged against trunk 5f491…").ea1dfdce5bto5dbf53e758New head
5dbf53e758, rebased on main, with one more commit for the review of mesh-controller #304 and the minor points here.WholeDetailsin place of its Details. It is held to the secret rule alone, and an ask whose whole details carry a secret's shape is refused. Test:TestEveryKeyAndItsWholeValueIsInTheNoteWhereTheSenderIsProven(5 keys, a 300-character value: every key and full value is in the Telegram note, masked on the desk).TestALongBodyIsCutBeforeTheNote,TestTheNoteIsEscaped('<', '>', '&' and a stray</blockquote>in the note).WholeDetails). Decision: ADR 0347. Local merge-check.sh with MESH_GATE and the five modules passed.Merge check at
5dbf53e7Judged: head
5dbf53e75840merged into trunke209d46faf3d; read beside it: mesh-controller6f1a05366c1d, mesh-controller-main6f1a05366c1d, mesh-host0e92ef3d1b21, mesh-tools954e1a53eef9mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: claude-code, desk-channel, mesh-knowledge, messenger, telegram)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 claude-code, desk-channel, mesh-knowledge, messenger, telegram → ace, g14, novox, shanks; no bus step
Run by the build seat on ace as
build-1791903913138216999(builds --log build-1791903913138216999).Out of date when it landed: out of date: judged against trunk
e209d46faf, the trunk is now 9c166398f204; judged again on a recheck or when it is merged5dbf53e758tobb5a342863Merge check at
bb5a3428Judged: head
bb5a342863eemerged into trunk9c166398f204; read beside it: mesh-controller6f1a05366c1d, mesh-controller-main6f1a05366c1d, mesh-host0e92ef3d1b21, mesh-tools954e1a53eef9mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: claude-code, desk-channel, mesh-knowledge, messenger, telegram)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 claude-code, desk-channel, mesh-knowledge, messenger, telegram → ace, g14, novox, shanks; no bus step
Run by the build seat on ace as
build-1791904626852455819(builds --log build-1791904626852455819).Verdict: approve at
bb5a342863Independent review of the issue 383/639 group under ADR 0345 and ADR 0347. The code here is right. However, mesh-sdk #25 is asked to change its digest encoding, so this PR must re-pin the new SDK head in every module's go.mod/go.sum before it merges. That re-pin needs a fresh look at the pin only.
Checked:
</blockquote><a href=...>and it rendered as text, one blockquote, no link.eadf301: TestALongBodyIsCutBeforeTheNote fails there, and the messenger whole-details tests do not build.Not blocking:
Statuses at this head: mesh/merge-gate success ("head
bb5a342863merged into trunk9c166398f2, pass"), mesh/repo-check success, mesh/delivery success ("ready: it delivers once merged"), mesh/delivery-group success ("group fix/383-an-ask-reads-at-a-glance ready: every member ready, and composed together they pass").New head
f09daabec3. The router's fallback for a refused note line now keeps a change line's key (withheldLine):+ password (a value carrying a value given to a secret's name is withheld here). Any other line, or one whose key is refused too, is still withheld whole. Test:TestAWithheldChangeLineKeepsItsKey. All five modules are re-pinned to mesh-sdk 5933eb7. Local merge-check.sh passed.Merge check at
f09daabeJudged: head
f09daabec3a8merged into trunk9c166398f204; read beside it: mesh-controller9f3aa91e812b, mesh-controller-main332fbaa9b175, mesh-host0e92ef3d1b21, mesh-tools954e1a53eef9mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: claude-code, desk-channel, mesh-knowledge, messenger, telegram)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 claude-code, desk-channel, mesh-knowledge, messenger, telegram → ace, g14, novox, shanks; no bus step
Run by the build seat on ace as
build-1791916538403302422(builds --log build-1791916538403302422).Verdict: approve at
f09daabec3Re-review after review 226. The only change since
bb5a342is one commit:bb5a342.Statuses at this head: mesh/merge-gate success ("head
f09daabec3merged into trunk9c166398f2— pass: builds claude-code, desk-channel, mesh-knowledge, messenger, telegram → ace, g14, …"), mesh/repo-check success ("… pass: its merge-check.sh passed …"), mesh/delivery success ("ready: it delivers once merged"), mesh/delivery-group success ("group fix/383-an-ask-reads-at-a-glance ready: every member ready, and composed together they pass", 18:55:39Z, after the new controller and SDK heads).