Fixes hq issue 687 (mail on novox refused or stuck: mailu's resolver no longer trusts the DNS root key).
What was seen
mailu-resolver logs failed to prime trust anchor -- DNSKEY rrset is not secure . DNSKEY IN every minute, keytag query _ta-4f66 (key tag 20326, KSK-2017 only).
A query to it (192.168.203.254) for anthropic.com answers SERVFAIL; novox's own resolver and a root server (198.41.0.4, UDP and TCP) answer.
Postfix refused inbound mail with 450 4.1.8 Sender address rejected: Domain not found; front's certificate renewal fails to resolve mail.novox.be.
Cause
The root zone signs with KSK-2024 since 2026-10-11. The pinned image (2024.06.59) got its anchor at image build time (unbound-anchor in the Dockerfile) and keeps it in the container, so a recreate (last 2026-10-07) reset it and RFC 5011's 30-day hold-down never let KSK-2024 in.
Change
One line: ghcr.io/mailu/unbound from the 2024.06.59 index digest to the 2024.06.63 index digest sha256:2c037bc5… (same media type, OCI image index, amd64/arm64/arm). Upstream 2024.06.63 contains:
Mailu 1903df2aceDeal with the KSK rollover: start.py runs unbound-anchor -a /etc/unbound/trusted-key.key at every start.
Mailu 08d595c751Fail the resolver healthcheck on SERVFAIL: HEALTHCHECK dig @127.0.0.1 +time=3 +tries=1 . NS | grep -q 'status: NOERROR'. The old dig @127.0.0.1 exits 0 on SERVFAIL, which is why the container stayed healthy (part of hq issue 688). Our health stays runtime, so the node-engine now judges with the fixed check.
Effect on the operator
mailu's upgrade policy is record: this waits for a person's go. Only the resolver container changes; it is recreated, and mail lookups work again once it is up.
Acceptance
After the walk: mailu-resolver answers NOERROR for anthropic.com, its log no longer says failed to prime trust anchor, and its health check output shows status: NOERROR.
Fixes hq issue 687 (mail on novox refused or stuck: mailu's resolver no longer trusts the DNS root key).
## What was seen
- `mailu-resolver` logs `failed to prime trust anchor -- DNSKEY rrset is not secure . DNSKEY IN` every minute, keytag query `_ta-4f66` (key tag 20326, KSK-2017 only).
- A query to it (192.168.203.254) for anthropic.com answers SERVFAIL; novox's own resolver and a root server (198.41.0.4, UDP and TCP) answer.
- Postfix refused inbound mail with `450 4.1.8 Sender address rejected: Domain not found`; front's certificate renewal fails to resolve mail.novox.be.
## Cause
The root zone signs with KSK-2024 since 2026-10-11. The pinned image (2024.06.59) got its anchor at image build time (`unbound-anchor` in the Dockerfile) and keeps it in the container, so a recreate (last 2026-10-07) reset it and RFC 5011's 30-day hold-down never let KSK-2024 in.
## Change
One line: `ghcr.io/mailu/unbound` from the 2024.06.59 index digest to the 2024.06.63 index digest `sha256:2c037bc5…` (same media type, OCI image index, amd64/arm64/arm). Upstream 2024.06.63 contains:
- Mailu `1903df2ace` *Deal with the KSK rollover*: `start.py` runs `unbound-anchor -a /etc/unbound/trusted-key.key` at every start.
- Mailu `08d595c751` *Fail the resolver healthcheck on SERVFAIL*: `HEALTHCHECK dig @127.0.0.1 +time=3 +tries=1 . NS | grep -q 'status: NOERROR'`. The old `dig @127.0.0.1` exits 0 on SERVFAIL, which is why the container stayed `healthy` (part of hq issue 688). Our `health` stays `runtime`, so the node-engine now judges with the fixed check.
## Effect on the operator
mailu's upgrade policy is `record`: this waits for a person's go. Only the resolver container changes; it is recreated, and mail lookups work again once it is up.
## Acceptance
After the walk: `mailu-resolver` answers NOERROR for anthropic.com, its log no longer says *failed to prime trust anchor*, and its health check output shows `status: NOERROR`.
mesh/merge-gate head 054dc9618ce3 merged into trunk a44d490d974c — pass: builds mailu, sent nowhere; no bus step; 1 wait(s) for a person; every machine com…
mesh/repo-check head 054dc9618ce3 merged into trunk a44d490d974c — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
The root zone signs with KSK-2024 since 2026-10-11. The pinned resolver
image (2024.06.59) trusted only KSK-2017 and kept its anchor inside the
container, so every lookup failed with SERVFAIL and mail was refused or
stuck (issue 687). 2024.06.63 refreshes the anchor with unbound-anchor at
every start and fails its health check on SERVFAIL, which the old
'dig @127.0.0.1' never did (issue 688).
Deliverynovox/mesh-catalog@054dc9618ce3 — delivered since 2026-10-14T12:38:18Z
Delivery plan — builds mailu, sent nowhere; no bus step; 1 wait(s) for a person
tier 0: mailu
novox: waits for a person: mailu
mailu waits for a person: its policy records (module)
mailu provides smtp: its consumers are sent again after it
mailu keeps data (ADR 0233): what it holds is backed up before it moves
Machines
gitea on novox: passed — carried by release-1791981314608316024
n8n on ace: passed — healthy 1 times over 1m13s, by a leaf module's rule: one reading (novox/hq ADR 0304)
mesh-knowledge on novox: passed — judged with gitea: healthy 1 times over 22s, by a leaf module's rule: one reading (novox/hq ADR 0304)
nextcloud on novox: passed — judged with gitea: healthy 1 times over 22s, by a leaf module's rule: one reading (novox/hq ADR 0304)
umami on novox: passed — judged with gitea: healthy 1 times over 22s, by a leaf module's rule: one reading (novox/hq ADR 0304)
gitea on the rest running it: sent
mesh-knowledge on the rest running it: sent
n8n on the rest running it: sent
nextcloud on the rest running it: sent
umami on the rest running it: sent
Transitions
2026-10-14 00:18 (new) → proposed (announced): novox/mesh-catalog#284's head announced
2026-10-14 00:21 proposed → checked (checked): a verdict names this commit and the trunk's head as its trunk commit
2026-10-14 00:21 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
2026-10-14 05:06 ready → proposed (trunk moved): out of date: judged against trunk ebf7f3773d, the trunk is now e846c289c878; judged again on a recheck or when it is merged
2026-10-14 12:32 proposed → checked (checked): a verdict names this commit and the trunk's head as its trunk commit
2026-10-14 12:32 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
2026-10-14 12:32 ready → published (merged): on the trunk its modules follow: merged there, and its walk opened — or nothing for a walk to move
2026-10-14 12:34 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-14 12:38 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@054dc9618ce3` — **delivered** since 2026-10-14T12:38:18Z
**Delivery plan** — builds mailu, sent nowhere; no bus step; 1 wait(s) for a person
- tier 0: mailu
- novox: waits for a person: mailu
- mailu waits for a person: its policy records (module)
- mailu provides smtp: its consumers are sent again after it
- mailu keeps data (ADR 0233): what it holds is backed up before it moves
**Machines**
- gitea on novox: passed — carried by release-1791981314608316024
- n8n on ace: passed — healthy 1 times over 1m13s, by a leaf module's rule: one reading (novox/hq ADR 0304)
- mesh-knowledge on novox: passed — judged with gitea: healthy 1 times over 22s, by a leaf module's rule: one reading (novox/hq ADR 0304)
- nextcloud on novox: passed — judged with gitea: healthy 1 times over 22s, by a leaf module's rule: one reading (novox/hq ADR 0304)
- umami on novox: passed — judged with gitea: healthy 1 times over 22s, by a leaf module's rule: one reading (novox/hq ADR 0304)
- gitea on the rest running it: sent
- mesh-knowledge on the rest running it: sent
- n8n on the rest running it: sent
- nextcloud on the rest running it: sent
- umami on the rest running it: sent
**Transitions**
- 2026-10-14 00:18 (new) → proposed (announced): novox/mesh-catalog#284's head announced
- 2026-10-14 00:21 proposed → checked (checked): a verdict names this commit and the trunk's head as its trunk commit
- 2026-10-14 00:21 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
- 2026-10-14 05:06 ready → proposed (trunk moved): out of date: judged against trunk ebf7f3773dc7, the trunk is now e846c289c878; judged again on a recheck or when it is merged
- 2026-10-14 12:32 proposed → checked (checked): a verdict names this commit and the trunk's head as its trunk commit
- 2026-10-14 12:32 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
- 2026-10-14 12:32 ready → published (merged): on the trunk its modules follow: merged there, and its walk opened — or nothing for a walk to move
- 2026-10-14 12:34 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-14 12:38 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 054dc961
Judged: head 054dc9618ce3 merged into trunk ebf7f3773dc7; read beside it: mesh-controller ca3f43c400ba, mesh-controller-main ca3f43c400ba, 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: mailu)
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 mailu, sent nowhere; no bus step; 1 wait(s) for a person
tier 0: mailu
novox: waits for a person: mailu
mailu waits for a person: its policy records (module)
mailu provides smtp: its consumers are sent again after it
mailu keeps data (ADR 0233): what it holds is backed up before it moves
Run by the build seat on novox as build-1791937090844060736 (builds --log build-1791937090844060736).
--- the gate: mailu
mailu: ok, keeps mail (valuable), dkim (valuable), data (valuable), dav (valuable), webmail (valuable), queue (valuable), filter (rebuildable), certs (rebuildable), automx (rebuildable), fetchmail (rebuildable), clamav (cache), redis (cache), ready: resolver by its image's own check every 30s; admin by its image's own check every 30s; imap by its image's own check every 30s; smtp by its image's own check every 30s; antispam by its image's own check every 30s; webmail by its image's own check every 30s; webdav by its image's own check every 30s; fetchmail by its image's own check every 30s; front by its image's own check every 30s; WARNING: config-env 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); WARNING: redis, antivirus, automx stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
long-running resources without health: 3
files asking for a setting without saying whether it is trusted: 1
1 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here
judging 1 module(s) changed against 4 machine(s), as the snapshot of 2026-10-13T23:54:14Z 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-13T23:54:14Z
modules the change moves:
- mailu (changed)
machines:
- a machine (f35): composes
- holds mesh-dns-resolver (idt): composes
- holds git, holds mesh-artifact-store, holds mesh-broker, holds mesh-catalog, holds mesh-delivery, holds mesh-dns-resolver, holds mesh-store, holds mesh-vault, holds npm-package-registry, the control node, the hub (ygcyr): composes
- a machine (yvbpsm): composes
a merge would rebuild 1 module(s) in 1 tier(s): mailu
--- its merge-check.sh (go toolchain)
ok git.novox.be/novox/mesh-catalog/checks/words 0.023s
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.013s
agent-home: no archive and no file written into under the agent's home
ok git.novox.be/novox/mesh-catalog/checks/secrets 0.014s
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: 66, as kept
ok git.novox.be/novox/mesh-catalog/checks/deps 0.401s
modules/mailu is TypeScript: merge-check-typescript.sh type-checks and tests it
--- its merge-check-typescript.sh (typescript toolchain)
type-checking modules/mailu (TypeScript)
testing modules/mailu (TypeScript)
✔ the vault's apiKey is used, a setting of it is ignored and said once, without its value (1.881939ms)
ℹ tests 1
ℹ suites 0
ℹ pass 1
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 86.79471
**Merge check** at `054dc961`
Judged: head `054dc9618ce3` merged into trunk `ebf7f3773dc7`; read beside it: mesh-controller `ca3f43c400ba`, mesh-controller-main `ca3f43c400ba`, 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: mailu)
- `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 mailu, sent nowhere; no bus step; 1 wait(s) for a person
- tier 0: mailu
- novox: waits for a person: mailu
- mailu waits for a person: its policy records (module)
- mailu provides smtp: its consumers are sent again after it
- mailu keeps data (ADR 0233): what it holds is backed up before it moves
Run by the build seat on novox as `build-1791937090844060736` (`builds --log build-1791937090844060736`).
```
--- the gate: mailu
mailu: ok, keeps mail (valuable), dkim (valuable), data (valuable), dav (valuable), webmail (valuable), queue (valuable), filter (rebuildable), certs (rebuildable), automx (rebuildable), fetchmail (rebuildable), clamav (cache), redis (cache), ready: resolver by its image's own check every 30s; admin by its image's own check every 30s; imap by its image's own check every 30s; smtp by its image's own check every 30s; antispam by its image's own check every 30s; webmail by its image's own check every 30s; webdav by its image's own check every 30s; fetchmail by its image's own check every 30s; front by its image's own check every 30s; WARNING: config-env 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); WARNING: redis, antivirus, automx stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
long-running resources without health: 3
files asking for a setting without saying whether it is trusted: 1
1 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here
judging 1 module(s) changed against 4 machine(s), as the snapshot of 2026-10-13T23:54:14Z 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-13T23:54:14Z
modules the change moves:
- mailu (changed)
machines:
- a machine (f35): composes
- holds mesh-dns-resolver (idt): composes
- holds git, holds mesh-artifact-store, holds mesh-broker, holds mesh-catalog, holds mesh-delivery, holds mesh-dns-resolver, holds mesh-store, holds mesh-vault, holds npm-package-registry, the control node, the hub (ygcyr): composes
- a machine (yvbpsm): composes
a merge would rebuild 1 module(s) in 1 tier(s): mailu
--- its merge-check.sh (go toolchain)
ok git.novox.be/novox/mesh-catalog/checks/words 0.023s
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.013s
agent-home: no archive and no file written into under the agent's home
ok git.novox.be/novox/mesh-catalog/checks/secrets 0.014s
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: 66, as kept
ok git.novox.be/novox/mesh-catalog/checks/deps 0.401s
modules/mailu is TypeScript: merge-check-typescript.sh type-checks and tests it
--- its merge-check-typescript.sh (typescript toolchain)
type-checking modules/mailu (TypeScript)
testing modules/mailu (TypeScript)
✔ the vault's apiKey is used, a setting of it is ignored and said once, without its value (1.881939ms)
ℹ tests 1
ℹ suites 0
ℹ pass 1
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 86.79471
```
Merge check at 054dc961
Judged: head 054dc9618ce3 merged into trunk a44d490d974c; read beside it: mesh-controller 535c7641ac41, mesh-controller-main 535c7641ac41, 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: mailu)
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 mailu, sent nowhere; no bus step; 1 wait(s) for a person
tier 0: mailu
novox: waits for a person: mailu
mailu waits for a person: its policy records (module)
mailu provides smtp: its consumers are sent again after it
mailu keeps data (ADR 0233): what it holds is backed up before it moves
Run by the build seat on shanks as build-1791980986296758498 (builds --log build-1791980986296758498).
--- the gate: mailu
mailu: ok, keeps mail (valuable), dkim (valuable), data (valuable), dav (valuable), webmail (valuable), queue (valuable), filter (rebuildable), certs (rebuildable), automx (rebuildable), fetchmail (rebuildable), clamav (cache), redis (cache), ready: resolver by its image's own check every 30s; admin by its image's own check every 30s; imap by its image's own check every 30s; smtp by its image's own check every 30s; antispam by its image's own check every 30s; webmail by its image's own check every 30s; webdav by its image's own check every 30s; fetchmail by its image's own check every 30s; front by its image's own check every 30s; WARNING: config-env 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); WARNING: redis, antivirus, automx stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
long-running resources without health: 3
files asking for a setting without saying whether it is trusted: 1
1 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here
judging 1 module(s) changed against 4 machine(s), as the snapshot of 2026-10-14T09:07:05Z 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-14T09:07:05Z
modules the change moves:
- mailu (changed)
machines:
- a machine (f35): composes
- holds mesh-dns-resolver (idt): composes
- holds git, holds mesh-artifact-store, holds mesh-broker, holds mesh-catalog, holds mesh-delivery, holds mesh-dns-resolver, holds mesh-store, holds mesh-vault, holds npm-package-registry, the control node, the hub (ygcyr): composes
- a machine (yvbpsm): composes
a merge would rebuild 1 module(s) in 1 tier(s): mailu
--- 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 46860 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.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.210s
modules/mailu is TypeScript: merge-check-typescript.sh type-checks and tests it
--- its merge-check-typescript.sh (typescript toolchain)
type-checking modules/mailu (TypeScript)
testing modules/mailu (TypeScript)
✔ the vault's apiKey is used, a setting of it is ignored and said once, without its value (1.939458ms)
ℹ tests 1
ℹ suites 0
ℹ pass 1
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 90.279318
**Merge check** at `054dc961`
Judged: head `054dc9618ce3` merged into trunk `a44d490d974c`; read beside it: mesh-controller `535c7641ac41`, mesh-controller-main `535c7641ac41`, 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: mailu)
- `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 mailu, sent nowhere; no bus step; 1 wait(s) for a person
- tier 0: mailu
- novox: waits for a person: mailu
- mailu waits for a person: its policy records (module)
- mailu provides smtp: its consumers are sent again after it
- mailu keeps data (ADR 0233): what it holds is backed up before it moves
Run by the build seat on shanks as `build-1791980986296758498` (`builds --log build-1791980986296758498`).
```
--- the gate: mailu
mailu: ok, keeps mail (valuable), dkim (valuable), data (valuable), dav (valuable), webmail (valuable), queue (valuable), filter (rebuildable), certs (rebuildable), automx (rebuildable), fetchmail (rebuildable), clamav (cache), redis (cache), ready: resolver by its image's own check every 30s; admin by its image's own check every 30s; imap by its image's own check every 30s; smtp by its image's own check every 30s; antispam by its image's own check every 30s; webmail by its image's own check every 30s; webdav by its image's own check every 30s; fetchmail by its image's own check every 30s; front by its image's own check every 30s; WARNING: config-env 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); WARNING: redis, antivirus, automx stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
long-running resources without health: 3
files asking for a setting without saying whether it is trusted: 1
1 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here
judging 1 module(s) changed against 4 machine(s), as the snapshot of 2026-10-14T09:07:05Z 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-14T09:07:05Z
modules the change moves:
- mailu (changed)
machines:
- a machine (f35): composes
- holds mesh-dns-resolver (idt): composes
- holds git, holds mesh-artifact-store, holds mesh-broker, holds mesh-catalog, holds mesh-delivery, holds mesh-dns-resolver, holds mesh-store, holds mesh-vault, holds npm-package-registry, the control node, the hub (ygcyr): composes
- a machine (yvbpsm): composes
a merge would rebuild 1 module(s) in 1 tier(s): mailu
--- 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 46860 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.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.210s
modules/mailu is TypeScript: merge-check-typescript.sh type-checks and tests it
--- its merge-check-typescript.sh (typescript toolchain)
type-checking modules/mailu (TypeScript)
testing modules/mailu (TypeScript)
✔ the vault's apiKey is used, a setting of it is ignored and said once, without its value (1.939458ms)
ℹ tests 1
ℹ suites 0
ℹ pass 1
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 90.279318
```
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Fixes hq issue 687 (mail on novox refused or stuck: mailu's resolver no longer trusts the DNS root key).
What was seen
mailu-resolverlogsfailed to prime trust anchor -- DNSKEY rrset is not secure . DNSKEY INevery minute, keytag query_ta-4f66(key tag 20326, KSK-2017 only).450 4.1.8 Sender address rejected: Domain not found; front's certificate renewal fails to resolve mail.novox.be.Cause
The root zone signs with KSK-2024 since 2026-10-11. The pinned image (2024.06.59) got its anchor at image build time (
unbound-anchorin the Dockerfile) and keeps it in the container, so a recreate (last 2026-10-07) reset it and RFC 5011's 30-day hold-down never let KSK-2024 in.Change
One line:
ghcr.io/mailu/unboundfrom the 2024.06.59 index digest to the 2024.06.63 index digestsha256:2c037bc5…(same media type, OCI image index, amd64/arm64/arm). Upstream 2024.06.63 contains:1903df2aceDeal with the KSK rollover:start.pyrunsunbound-anchor -a /etc/unbound/trusted-key.keyat every start.08d595c751Fail the resolver healthcheck on SERVFAIL:HEALTHCHECK dig @127.0.0.1 +time=3 +tries=1 . NS | grep -q 'status: NOERROR'. The olddig @127.0.0.1exits 0 on SERVFAIL, which is why the container stayedhealthy(part of hq issue 688). Ourhealthstaysruntime, so the node-engine now judges with the fixed check.Effect on the operator
mailu's upgrade policy is
record: this waits for a person's go. Only the resolver container changes; it is recreated, and mail lookups work again once it is up.Acceptance
After the walk:
mailu-resolveranswers NOERROR for anthropic.com, its log no longer says failed to prime trust anchor, and its health check output showsstatus: NOERROR.Delivery
novox/mesh-catalog@054dc9618ce3— delivered since 2026-10-14T12:38:18ZDelivery plan — builds mailu, sent nowhere; no bus step; 1 wait(s) for a person
Machines
Transitions
ebf7f3773d, the trunk is now e846c289c878; judged again on a recheck or when it is mergedThe commit's note under
refs/notes/mesh-plankeeps every transition:git log --notes=mesh-plan.Merge check at
054dc961Judged: head
054dc9618ce3merged into trunkebf7f3773dc7; read beside it: mesh-controllerca3f43c400ba, mesh-controller-mainca3f43c400ba, mesh-host1a2677882380, mesh-tools954e1a53eef9mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: mailu)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 mailu, sent nowhere; no bus step; 1 wait(s) for a person
Run by the build seat on novox as
build-1791937090844060736(builds --log build-1791937090844060736).Merge check at
054dc961Judged: head
054dc9618ce3merged into trunka44d490d974c; read beside it: mesh-controller535c7641ac41, mesh-controller-main535c7641ac41, mesh-host1a2677882380, mesh-tools954e1a53eef9mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: mailu)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 mailu, sent nowhere; no bus step; 1 wait(s) for a person
Run by the build seat on shanks as
build-1791980986296758498(builds --log build-1791980986296758498).