mesh-mail: the operator's mail accounts, watched and said on the bus — stage 1, own server read-only (hq ADR 0359) #300

Merged
mesh-tools merged 3 commits from adr-359-mesh-mail into main 2026-10-15 08:44:08 +00:00
Contributor

Issue 710. Builds hq ADR 0359 (accepted, operator-approved): the new module modules/mesh-mail. Its stream and bus grants follow hq ADR 0363. It is assigned to no node; assigning it is the operator's step.

Delivery order

Merge and deliver this only after mesh-controller #338 (86057f45) and mesh-tools #34 (5d70eb3e) report delivered. Those two resolve issue 718: the controller creates module streams and composes their grants, and the runtime publishes and binds as the membership says (ADR 0363 §8). Before they are delivered, a manifest declaring a stream must not reach the nodes.

Before the operator grants any consumer, issues 727 and 728 must be fixed.

What

A Go module with one bundle and three processes:

  • prepare (run once): brings the index's schema to this version's. It uses numbered migrations, plus schema.sql for a fresh database.
  • keep (unit health): runs the imap adapter for each account in the setting accounts. It keeps IDLE on INBOX, ended and begun again every 2 minutes so each cycle proves the server still answers. It looks at every other folder every 5 minutes. EXAMINE and BODY.PEEK only. It indexes into its own database and keeps each attachment once, by its SHA-256, in its bucket. It writes every added, changed or removed message as an event in an outbox in the same transaction as the change.
  • watch (tool health mail_health, needs postgres-database): judges every minute and writes the verdict that the tool reads.
  • The bundle serves mail_accounts, mail_search, mail_read and mail_health. It says the outbox's events through the runtime (stdio.Emit) and removes each one once the bus took it.

ADR 0359, clause by clause

  1. One module, an adapter per kind. Kinds = [imap]. Any other kind is refused by name. An account is {kind, address, user?, incoming{host,port,security}, outgoing?, folders?}. A second imap account (Gmail, ADR 0361) is one more config entry and one more secret mail-credential-<account>. It needs no code change and no manifest change, because the stream's events are one family pattern per change. outgoing is read and never used.
  2. Watches each account and says each mail on its own stream. The manifest declares streams: [{name: mail, events: [mail.*.message.added|changed|removed], max-age-days: 7, grant: {config: grants, events: "mail.{key}.**"}}] (ADR 0363 §1-§4). The controller creates MAIL; the shared EVENTS stream never carries these events. They carry account, folder, uid, uidvalidity, message-id, in-reply-to, date, from, to, cc, subject, size, flags and attachment references (bucket, SHA-256 key, size, type, name). A changed event also carries the flags before and after. An event never carries a body or an attachment's bytes, and a test checks this. The first look at a folder indexes it without events.
  3. Index and attachment store. The index is in its own database (postgres-database, name mail). Attachments are in the bucket from s3-bucket (minio), keyed by SHA-256 and written once. S3 SigV4 uses the standard library and is tested against AWS's published example signature.
  4. Grants per account, governed by ADR 0363. The trusted config value grants (default {}: nobody) has an object per account listing a module or <machine>.<module>.
    • On the bus, a consumer hears an account's part of MAIL only when its consumes names mesh-mail and grants names it for that account (ADR 0363 §5). A withdrawal removes its consumer (§6).
    • In the tools, mail_search and mail_read enforce the same value on stdio.CallerOf, never on an argument. A person.<name> entry is honoured by the tools only; it grants nothing on the bus (§4).
  5. Read-only, first stage. The client is used only through an interface without write commands. A test fails on any Store/Move/Copy/Expunge/Append/Create/Delete/Rename/... call or net/smtp in non-test code. The password is the own-secret family mail-credential-*, issued-by: outside.
  6. Health. keep uses unit and watch uses the tool mail_health, as mesh-knowledge does. mail_health answers one of three:
    • waits, naming mail-credential-<account>, while no password is given;
    • unhealthy, naming the account and why, when the connection is down, the sign-in is refused, or the server has been silent for 5 minutes;
    • healthy otherwise.
      A fault beside a wait is unhealthy and says both.
  7. Nothing for Gmail, Graph or sending is built.

Tests and checks

go test -race passes. The tests cover:

  • A real IMAP conversation against go-imap's in-process server, over memory and over postgres:
    • the first look is silent;
    • a delivered mail is said through IDLE with metadata and an attachment reference, and no body;
    • the attachment is kept by SHA-256;
    • a flag is said as changed and an expunge as removed;
    • another folder is said at the poll;
    • the message is never marked \Seen.
  • Password states: not given (waits), wrong (refused sign-in), given later (picked up without a restart).
  • Grants through the real MCP loop with _meta callers: a granted caller reads, an ungranted or unproven one is refused, and an argument cannot name the caller.
  • Events published through the runtime: kept when the bus refuses, removed once taken.
  • Health states, the stale verdict, the schema (consolidated equals migrations), search, the manifest against the code (stream, grant, no emits), and the SigV4 vector.

With the controller built from mesh-controller main 86057f45:

  • module check says mesh-mail: ok, 4 tool(s), ready: keep by unit every 30s; watch by its tool mail_health every 1m0s. The check reads the stream: with grant.config pointed at a value that is not trusted, it refuses the manifest.
  • merge-check.sh exits 0, with resources without health at 62, as kept.

The branch is brought up to date by a merge of main, not a rebase. The PR adds github.com/emersion/go-imap/v2 v2.0.0-beta.8 and go-message v0.18.2.

What the operator does after merge (and after #338 and #34 are delivered)

  1. Approve the config value accounts for mesh-mail: {"mesh": {"kind": "imap", "address": "jschoubben@novox.be", "incoming": {"host": "mail.novox.be", "port": 993, "security": "tls"}}}. The controller refuses a domain in a manifest, so this is not a default.
  2. Assign mesh-mail to novox.
  3. Give the IMAP password at novox's desk: nox secret ask novox mesh-mail mail-credential-mesh. Until then module.mesh-mail.novox.needs-operator stands, as a warning.
  4. Only after issues 727 and 728 are fixed, approve grants for each consumer.

Acceptance

Once assigned and given its password, a new mail to jschoubben@novox.be is on MAIL as mail.mesh.message.added within a minute, with metadata and no body. mail_search finds it. mail_read gives its body to a granted caller and refuses any other. Stopping the IMAP connection makes mail_health unhealthy within five minutes.

Issue 710. Builds hq ADR 0359 (accepted, operator-approved): the new module `modules/mesh-mail`. Its stream and bus grants follow hq ADR 0363. It is **assigned to no node**; assigning it is the operator's step. ## Delivery order Merge and deliver this **only after** mesh-controller #338 (86057f45) and mesh-tools #34 (5d70eb3e) report delivered. Those two resolve issue 718: the controller creates module streams and composes their grants, and the runtime publishes and binds as the membership says (ADR 0363 §8). Before they are delivered, a manifest declaring a stream must not reach the nodes. **Before the operator grants any consumer, issues 727 and 728 must be fixed.** ## What A Go module with one bundle and three processes: - `prepare` (run once): brings the index's schema to this version's. It uses numbered migrations, plus `schema.sql` for a fresh database. - `keep` (unit health): runs the `imap` adapter for each account in the setting `accounts`. It keeps IDLE on INBOX, ended and begun again every 2 minutes so each cycle proves the server still answers. It looks at every other folder every 5 minutes. EXAMINE and BODY.PEEK only. It indexes into its own database and keeps each attachment once, by its SHA-256, in its bucket. It writes every added, changed or removed message as an event in an outbox in the same transaction as the change. - `watch` (tool health `mail_health`, needs `postgres-database`): judges every minute and writes the verdict that the tool reads. - The bundle serves `mail_accounts`, `mail_search`, `mail_read` and `mail_health`. It says the outbox's events through the runtime (`stdio.Emit`) and removes each one once the bus took it. ## ADR 0359, clause by clause 1. **One module, an adapter per kind.** `Kinds = [imap]`. Any other kind is refused by name. An account is `{kind, address, user?, incoming{host,port,security}, outgoing?, folders?}`. A second `imap` account (Gmail, ADR 0361) is one more config entry and one more secret `mail-credential-<account>`. It needs no code change and no manifest change, because the stream's events are one family pattern per change. `outgoing` is read and never used. 2. **Watches each account and says each mail on its own stream.** The manifest declares `streams: [{name: mail, events: [mail.*.message.added|changed|removed], max-age-days: 7, grant: {config: grants, events: "mail.{key}.**"}}]` (ADR 0363 §1-§4). The controller creates `MAIL`; the shared EVENTS stream never carries these events. They carry account, folder, uid, uidvalidity, message-id, in-reply-to, date, from, to, cc, subject, size, flags and attachment references (bucket, SHA-256 key, size, type, name). A changed event also carries the flags before and after. An event never carries a body or an attachment's bytes, and a test checks this. The first look at a folder indexes it without events. 3. **Index and attachment store.** The index is in its own database (`postgres-database`, name `mail`). Attachments are in the bucket from `s3-bucket` (minio), keyed by SHA-256 and written once. S3 SigV4 uses the standard library and is tested against AWS's published example signature. 4. **Grants per account, governed by ADR 0363.** The trusted config value `grants` (default `{}`: nobody) has an object per account listing a module or `<machine>.<module>`. - On the bus, a consumer hears an account's part of `MAIL` only when its `consumes` names mesh-mail and `grants` names it for that account (ADR 0363 §5). A withdrawal removes its consumer (§6). - In the tools, `mail_search` and `mail_read` enforce the same value on `stdio.CallerOf`, never on an argument. A `person.<name>` entry is honoured by the tools only; it grants nothing on the bus (§4). 5. **Read-only, first stage.** The client is used only through an interface without write commands. A test fails on any `Store/Move/Copy/Expunge/Append/Create/Delete/Rename/...` call or `net/smtp` in non-test code. The password is the own-secret family `mail-credential-*`, `issued-by: outside`. 6. **Health.** `keep` uses `unit` and `watch` uses the tool `mail_health`, as mesh-knowledge does. `mail_health` answers one of three: - `waits`, naming `mail-credential-<account>`, while no password is given; - `unhealthy`, naming the account and why, when the connection is down, the sign-in is refused, or the server has been silent for 5 minutes; - `healthy` otherwise. A fault beside a wait is unhealthy and says both. 7. Nothing for Gmail, Graph or sending is built. ## Tests and checks `go test -race` passes. The tests cover: - A real IMAP conversation against go-imap's in-process server, over memory and over postgres: - the first look is silent; - a delivered mail is said through IDLE with metadata and an attachment reference, and no body; - the attachment is kept by SHA-256; - a flag is said as changed and an expunge as removed; - another folder is said at the poll; - the message is never marked \Seen. - Password states: not given (waits), wrong (refused sign-in), given later (picked up without a restart). - Grants through the real MCP loop with `_meta` callers: a granted caller reads, an ungranted or unproven one is refused, and an argument cannot name the caller. - Events published through the runtime: kept when the bus refuses, removed once taken. - Health states, the stale verdict, the schema (consolidated equals migrations), search, the manifest against the code (stream, grant, no emits), and the SigV4 vector. With the controller built from mesh-controller main 86057f45: - `module check` says `mesh-mail: ok, 4 tool(s), ready: keep by unit every 30s; watch by its tool mail_health every 1m0s`. The check reads the stream: with `grant.config` pointed at a value that is not trusted, it refuses the manifest. - `merge-check.sh` exits 0, with resources without health at 62, as kept. The branch is brought up to date by a merge of main, not a rebase. The PR adds `github.com/emersion/go-imap/v2` v2.0.0-beta.8 and `go-message` v0.18.2. ## What the operator does after merge (and after #338 and #34 are delivered) 1. Approve the config value `accounts` for mesh-mail: `{"mesh": {"kind": "imap", "address": "jschoubben@novox.be", "incoming": {"host": "mail.novox.be", "port": 993, "security": "tls"}}}`. The controller refuses a domain in a manifest, so this is not a default. 2. Assign mesh-mail to novox. 3. Give the IMAP password at novox's desk: `nox secret ask novox mesh-mail mail-credential-mesh`. Until then `module.mesh-mail.novox.needs-operator` stands, as a warning. 4. Only after issues 727 and 728 are fixed, approve `grants` for each consumer. ## Acceptance Once assigned and given its password, a new mail to jschoubben@novox.be is on `MAIL` as `mail.mesh.message.added` within a minute, with metadata and no body. `mail_search` finds it. `mail_read` gives its body to a granted caller and refuses any other. Stopping the IMAP connection makes `mail_health` unhealthy within five minutes.
mesh-admin added 1 commit 2026-10-14 18:15:11 +00:00
Add mesh-mail: watch the operator's own mailbox read-only and say each mail on the bus
mesh/merge-gate out of date: judged against trunk e22326240833, the trunk is now 482232e8c51c; judged again on a recheck or when it is merged
mesh/repo-check out of date: judged against trunk e22326240833, the trunk is now 482232e8c51c; judged again on a recheck or when it is merged
mesh/delivery superseded: a newer head of the same pull request
70c1110c53
ADR 0359 decided one module holds the operator's mail accounts. This is its
first stage: an imap adapter that keeps IDLE on the inbox and polls the other
folders read-only, indexes each message in its own database, keeps each
attachment once by its SHA-256 in its bucket, and says every added, changed or
removed message as a metadata-only event. Bodies and attachments are served
only by its tools, to callers the trusted setting grants names. Its health
waits for the account's own secret until it is given at the desk (issue 710).
Author
Contributor

Delivery novox/mesh-catalog@2130f9961291 — delivered since 2026-10-15T08:44:10Z

Delivery plan — builds new: modules/mesh-mail, sent nowhere; no bus step

Transitions

  • 2026-10-14 20:17 (new) → proposed (announced): novox/mesh-catalog#300's head announced
  • 2026-10-15 08:43 proposed → checked (checked): a verdict names this commit and the trunk's head as its trunk commit
  • 2026-10-15 08:43 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
  • 2026-10-15 08:44 ready → published (merged): on the trunk its modules follow: merged there, and its walk opened — or nothing for a walk to move
  • 2026-10-15 08:44 published → delivered (done): nothing for a walk to move

The commit's note under refs/notes/mesh-plan keeps every transition: git log --notes=mesh-plan.

<!-- mesh-delivery:view --> **Delivery** `novox/mesh-catalog@2130f9961291` — **delivered** since 2026-10-15T08:44:10Z **Delivery plan** — builds new: modules/mesh-mail, sent nowhere; no bus step **Transitions** - 2026-10-14 20:17 (new) → proposed (announced): novox/mesh-catalog#300's head announced - 2026-10-15 08:43 proposed → checked (checked): a verdict names this commit and the trunk's head as its trunk commit - 2026-10-15 08:43 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail - 2026-10-15 08:44 ready → published (merged): on the trunk its modules follow: merged there, and its walk opened — or nothing for a walk to move - 2026-10-15 08:44 published → delivered (done): nothing for a walk to move The commit's note under `refs/notes/mesh-plan` keeps every transition: `git log --notes=mesh-plan`.
Author
Contributor

Merge check at 70c1110c
Judged: head 70c1110c5372 merged into trunk e22326240833; read beside it: mesh-controller 622fb1e9cbac, mesh-controller-main 622fb1e9cbac, mesh-host 1a2677882380, mesh-tools 954e1a53eef9

  • mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: new:modules/mesh-mail)
  • 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 new: modules/mesh-mail, sent nowhere; no bus step

Run by the build seat on ace as build-1792001736329212314 (builds --log build-1792001736329212314).

--- the gate: new:modules/mesh-mail
mesh-mail: ok, 4 tool(s), ready: keep by unit every 30s; watch by its tool mail_health every 1m0s
long-running resources without health: 0
files asking for a setting without saying whether it is trusted: 0
1 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here
judging 1 module(s) changed against 4 machine(s), as the snapshot of 2026-10-14T18:13:10Z 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-14T18:13:10Z

modules the change moves:
  - mesh-mail (added)

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 0 module(s) in 0 tier(s)
--- 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 47498 strings of 729 files
ok  	git.novox.be/novox/mesh-catalog/checks/agenthome	0.011s
agent-home: no archive and no file written into under the agent's home
ok  	git.novox.be/novox/mesh-catalog/checks/secrets	0.013s
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.005s
paths: no module names another's state on its machine (3 known, listed to go)
long-running resources without health: 62, as kept
ok  	git.novox.be/novox/mesh-catalog/checks/deps	0.200s
testing modules/mesh-mail
ok  	mesh-mail/cmd/mesh-mail	2.962s
--- its merge-check-typescript.sh (typescript toolchain)
**Merge check** at `70c1110c` Judged: head `70c1110c5372` merged into trunk `e22326240833`; read beside it: mesh-controller `622fb1e9cbac`, mesh-controller-main `622fb1e9cbac`, mesh-host `1a2677882380`, mesh-tools `954e1a53eef9` - `mesh/merge-gate`: **PASS** — every machine composes with the change as it did without (4 of 4 compose) (modules: new:modules/mesh-mail) - `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 new: modules/mesh-mail, sent nowhere; no bus step Run by the build seat on ace as `build-1792001736329212314` (`builds --log build-1792001736329212314`). ``` --- the gate: new:modules/mesh-mail mesh-mail: ok, 4 tool(s), ready: keep by unit every 30s; watch by its tool mail_health every 1m0s long-running resources without health: 0 files asking for a setting without saying whether it is trusted: 0 1 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here judging 1 module(s) changed against 4 machine(s), as the snapshot of 2026-10-14T18:13:10Z 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-14T18:13:10Z modules the change moves: - mesh-mail (added) 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 0 module(s) in 0 tier(s) --- 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 47498 strings of 729 files ok git.novox.be/novox/mesh-catalog/checks/agenthome 0.011s agent-home: no archive and no file written into under the agent's home ok git.novox.be/novox/mesh-catalog/checks/secrets 0.013s 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.005s paths: no module names another's state on its machine (3 known, listed to go) long-running resources without health: 62, as kept ok git.novox.be/novox/mesh-catalog/checks/deps 0.200s testing modules/mesh-mail ok mesh-mail/cmd/mesh-mail 2.962s --- its merge-check-typescript.sh (typescript toolchain) ```
jschoubben added 2 commits 2026-10-14 20:17:11 +00:00
mesh-mail: say mail events on its own stream MAIL, granted per account by grants (hq ADR 0363)
mesh/merge-gate head 2130f9961291 merged into trunk c71c513027e5 — pass: builds new: modules/mesh-mail, sent nowhere; no bus step; every machine composes w…
mesh/repo-check head 2130f9961291 merged into trunk c71c513027e5 — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/delivery delivered
2130f99612
ADR 0359 asked for a stream of its own and a bus grant from the module's
grants; ADR 0363 built both. The events leave the shared EVENTS stream, and
one family pattern per change replaces the literal per-account emits, so a
new account changes no manifest.
Author
Contributor

Merge check at 2130f996
Judged: head 2130f9961291 merged into trunk fadf5025cc5a; read beside it: mesh-controller 86057f455194, mesh-controller-main 86057f455194, mesh-host 1a2677882380, mesh-tools 954e1a53eef9

  • mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: new:modules/mesh-mail)
  • 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 new: modules/mesh-mail, sent nowhere; no bus step

Run by the build seat on shanks as build-1792009116545584149 (builds --log build-1792009116545584149).

--- the gate: new:modules/mesh-mail
mesh-mail: ok, 4 tool(s), ready: keep by unit every 30s; watch by its tool mail_health every 1m0s
long-running resources without health: 0
files asking for a setting without saying whether it is trusted: 0
1 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here
judging 1 module(s) changed against 4 machine(s), as the snapshot of 2026-10-14T20:16:51Z 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-14T20:16:51Z

modules the change moves:
  - mesh-mail (added)

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 0 module(s) in 0 tier(s)
--- 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 47641 strings of 731 files
ok  	git.novox.be/novox/mesh-catalog/checks/agenthome	0.015s
agent-home: no archive and no file written into under the agent's home
ok  	git.novox.be/novox/mesh-catalog/checks/secrets	0.013s
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: 62, as kept
ok  	git.novox.be/novox/mesh-catalog/checks/deps	0.215s
testing modules/mesh-mail
ok  	mesh-mail/cmd/mesh-mail	3.072s
--- its merge-check-typescript.sh (typescript toolchain)

Out of date when it landed: out of date: judged against trunk fadf5025cc, the trunk is now 2edef5a00ae0; judged again on a recheck or when it is merged

**Merge check** at `2130f996` Judged: head `2130f9961291` merged into trunk `fadf5025cc5a`; read beside it: mesh-controller `86057f455194`, mesh-controller-main `86057f455194`, mesh-host `1a2677882380`, mesh-tools `954e1a53eef9` - `mesh/merge-gate`: **PASS** — every machine composes with the change as it did without (4 of 4 compose) (modules: new:modules/mesh-mail) - `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 new: modules/mesh-mail, sent nowhere; no bus step Run by the build seat on shanks as `build-1792009116545584149` (`builds --log build-1792009116545584149`). ``` --- the gate: new:modules/mesh-mail mesh-mail: ok, 4 tool(s), ready: keep by unit every 30s; watch by its tool mail_health every 1m0s long-running resources without health: 0 files asking for a setting without saying whether it is trusted: 0 1 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here judging 1 module(s) changed against 4 machine(s), as the snapshot of 2026-10-14T20:16:51Z 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-14T20:16:51Z modules the change moves: - mesh-mail (added) 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 0 module(s) in 0 tier(s) --- 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 47641 strings of 731 files ok git.novox.be/novox/mesh-catalog/checks/agenthome 0.015s agent-home: no archive and no file written into under the agent's home ok git.novox.be/novox/mesh-catalog/checks/secrets 0.013s 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: 62, as kept ok git.novox.be/novox/mesh-catalog/checks/deps 0.215s testing modules/mesh-mail ok mesh-mail/cmd/mesh-mail 3.072s --- its merge-check-typescript.sh (typescript toolchain) ``` **Out of date when it landed**: out of date: judged against trunk fadf5025cc5a, the trunk is now 2edef5a00ae0; judged again on a recheck or when it is merged
Member

Merge check at 2130f996
Judged: head 2130f9961291 merged into trunk c71c513027e5; read beside it: mesh-controller 0b7e740b299c, mesh-controller-main 20e58907b0f8, mesh-host 198fd34ec497, mesh-tools 6b3e15042fee

  • mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: new:modules/mesh-mail)
  • 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 new: modules/mesh-mail, sent nowhere; no bus step

Run by the build seat on novox as build-1792053596551454408 (builds --log build-1792053596551454408).

--- the gate: new:modules/mesh-mail
mesh-mail: ok, 4 tool(s), ready: keep by unit every 30s; watch by its tool mail_health every 1m0s
long-running resources without health: 0
files asking for a setting without saying whether it is trusted: 0
1 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here
judging 1 module(s) changed against 4 machine(s), as the snapshot of 2026-10-15T01:09:40Z says they run
composing every machine as the mesh is
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
composing every machine with the change
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
merge gate: PASS — every machine composes with the change as it did without (4 of 4 compose)
judged by controller development build against the facts of 2026-10-15T01:09:40Z

modules the change moves:
  - mesh-mail (added)

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 0 module(s) in 0 tier(s)
--- 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 48140 strings of 737 files
ok  	git.novox.be/novox/mesh-catalog/checks/agenthome	0.016s
agent-home: no archive and no file written into under the agent's home
ok  	git.novox.be/novox/mesh-catalog/checks/secrets	0.015s
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.007s
paths: no module names another's state on its machine (3 known, listed to go)
long-running resources without health: 62, as kept
ok  	git.novox.be/novox/mesh-catalog/checks/deps	0.319s
testing modules/mesh-mail
ok  	mesh-mail/cmd/mesh-mail	3.237s
--- its merge-check-typescript.sh (typescript toolchain)
**Merge check** at `2130f996` Judged: head `2130f9961291` merged into trunk `c71c513027e5`; read beside it: mesh-controller `0b7e740b299c`, mesh-controller-main `20e58907b0f8`, mesh-host `198fd34ec497`, mesh-tools `6b3e15042fee` - `mesh/merge-gate`: **PASS** — every machine composes with the change as it did without (4 of 4 compose) (modules: new:modules/mesh-mail) - `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 new: modules/mesh-mail, sent nowhere; no bus step Run by the build seat on novox as `build-1792053596551454408` (`builds --log build-1792053596551454408`). ``` --- the gate: new:modules/mesh-mail mesh-mail: ok, 4 tool(s), ready: keep by unit every 30s; watch by its tool mail_health every 1m0s long-running resources without health: 0 files asking for a setting without saying whether it is trusted: 0 1 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here judging 1 module(s) changed against 4 machine(s), as the snapshot of 2026-10-15T01:09:40Z says they run composing every machine as the mesh is the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued composing every machine with the change the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued merge gate: PASS — every machine composes with the change as it did without (4 of 4 compose) judged by controller development build against the facts of 2026-10-15T01:09:40Z modules the change moves: - mesh-mail (added) 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 0 module(s) in 0 tier(s) --- 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 48140 strings of 737 files ok git.novox.be/novox/mesh-catalog/checks/agenthome 0.016s agent-home: no archive and no file written into under the agent's home ok git.novox.be/novox/mesh-catalog/checks/secrets 0.015s 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.007s paths: no module names another's state on its machine (3 known, listed to go) long-running resources without health: 62, as kept ok git.novox.be/novox/mesh-catalog/checks/deps 0.319s testing modules/mesh-mail ok mesh-mail/cmd/mesh-mail 3.237s --- its merge-check-typescript.sh (typescript toolchain) ```
mesh-tools merged commit 5f6a41146c into main 2026-10-15 08:44:08 +00:00
mesh-tools deleted branch adr-359-mesh-mail 2026-10-15 08:44:08 +00:00
Sign in to join this conversation.
No Reviewers
3 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: novox/mesh-catalog#300