Commit Graph
1521 Commits
Author SHA1 Message Date
jochen c2cd2e1eb1 issue 800: fix review round 3 finding, a true sliding window instead of a session quota
mesh/merge-gate head c2cd2e1eb15e merged into trunk 789b0a9474c8 — pass: builds mesh-mail, messenger, new: modules/mesh-mail-notifier → novox; no bus step;…
mesh/repo-check head c2cd2e1eb15e merged into trunk 789b0a9474c8 — pass: THE CHANGE ALTERS ITS OWN CHECK (merge-check.sh): main's version judged it; the ch…
mesh/delivery delivered
mesh/delivery-group group feat/mail-seats delivered: every member is delivered
A session that only reset after a quiet minute kept counting, and so folding, a steady
trickle of mail forever even with no burst (one mail every 50s). N is now the account's
qualifying mail arrived in the trailing 60 seconds, counted fresh on every arrival; a fold
holds only its own overflow and the notice names just that count, not the whole history.
2026-10-15 19:03:05 +02:00
jochen aa62de2e78 issue 797: a dropped tell no longer crowds the conditions' cap out of its own history
A dropped tell was kept in the same bounded send history (KeptSends)
that the conditions' and notify's cap counts sends from. A flood of
drops could push real, still-recent sends out of that bounded history,
undercounting sentLastHour and letting the conditions' cap stop
holding. A dropped tell is still said once an hour in the log and
named in Tell's own "dropped" answer; it is simply never recorded into
that shared history any more.
2026-10-15 18:51:26 +02:00
jochen 66713c5a1e issue 800: fix review round 2 findings in mesh-mail-notifier
A buffer was replaced, discarding whatever it still held unsent, once
Window had passed since its first mail — losing a failed send waiting
for its retry, or a folded mail waiting for its minute's end, if a new
mail arrived meanwhile. The window now slides on the gap since the
last mail, not on time elapsed since the first: a session's count
never resets, and its buffer is never replaced, while anything in it
is still unsent.

The fold notice now counts every mail of the account in that minute,
not only the overflow, and says "mail" for one and "mails" for more.
2026-10-15 18:50:21 +02:00
jochen b771794f1c issue 800: keep notify's health as unit; the gate refuses a one-process module judged only by its own tool
ADR 0227 rule 8 / ADR 0240 rule 2 refuse a module with no health check of
another kind beside a tool check. mesh-mail-notifier has one process
(notify); wiring mail_notifier_health as its manifest health, as the review
note's wording suggested (mirroring mesh-mail's watch/mail_health), trips
that rule because mesh-mail also has keep (kind unit) beside watch.
mail_notifier_health stays built, tested and callable; notify's manifest
health stays kind unit until the lead decides how a one-process module
gets this automatically.
2026-10-15 18:33:22 +02:00
jochen 6c63a17cfa Merge branch 'feat/mail-seats' into ms-800-r1 2026-10-15 17:54:33 +02:00
jochen ed66a2e873 issue 800: fix review round 1 findings in mesh-mail-notifier
Flush now sorts accounts instead of walking a map, so notice order is
stable. A failed node-notifier.send keeps its mail pending and retries
at most once a minute, without holding up other accounts' notices, and
the failure is kept in the Store for a new health tool
(mail_notifier_health) that is unhealthy past ten minutes of failure.
The burst rule now follows the lead's reading of ADR 0378 S9: within an
account's sliding minute, the first three qualifying mails are shown
one by one and the rest are folded into one notice at the window's
end; there is no separate quiet-gap timer. The dedupe key is the
account and message id, falling back to folder/uidvalidity/uid only
when no message id is given, so a UIDVALIDITY reset cannot suppress a
new mail, and a redelivered event already buffered is never recounted.
status now lists every granted account, not only those with a notice,
and caches mail-store.accounts for a minute.
2026-10-15 17:54:27 +02:00
jochen cc73b38671 issue 797: tells no longer eat the conditions'/notify's cap, and a dropped tell is logged once an hour
Review round 1 of mesh-catalog found sentLastHour counting tells
against CapPerHour (ADR 0380 §8 says tells keep their own cap, never
shared), and the drop log firing on every drop instead of once an
hour per channel as the comment already said.
2026-10-15 17:46:39 +02:00
jochen 0993c31ad4 Merge branch 'feat/mail-seats' into ms-797 2026-10-15 17:37:22 +02:00
jochen 82475691b2 issue 797: messenger gains the tell verb for a plain notice
ADR 0380 §8: the operator channel's notify is shaped for conditions (a key that
stays open, escalation, a plain rule that rewrites a subject), so a module has
no way to say a plain notice such as new mail. tell sends a headline and one or
two lines at once to every channel, bypassing routing, the burst window and the
walk hold; it offers Details like any message, is kept in the history, but its
record is marked cleared at once so it never stays open. Its cap (10 a channel
an hour) is its own, apart from notify's and the conditions'.
2026-10-15 17:37:15 +02:00
jochen 89046e6613 mesh-mail's mail-notifier needs a list of node seats, as the controller reads it (issue 800) 2026-10-15 17:34:00 +02:00
jochen dc89995d96 Add mesh-mail-notifier, the default holder of mail-notifier (issue 800 part B)
ADR 0378 §9 as amended by ADR 0379: a module of its own, built from mesh-mail's
event shape, runs as its own account to hear mesh-mail's restricted MAIL stream
(ADR 0376 §2), shows each new inbox mail through node-notifier.send at most
once, folds more than three from one account into one notice, and emits its
own shown event.
2026-10-15 17:33:15 +02:00
jochen 6c10288f0b mesh-mail declares the mail seats and claims mail-store (issue 800 part A)
Declares mail-store and mail-webclient (held once for the mesh) and mail-notifier
(held once per machine, needing node-notifier) per ADR 0378 as amended by ADR 0379.
Claims mail-store and serves its four verbs through the same handlers as the
existing mail_* tools. Moves the event shape (EventKey, Changes) into its own
file, mailevent.go, so mesh-mail-notifier (issue 800 part B) can carry a
byte-identical copy. Adds checks/mailstore, refusing any manifest but mesh-mail's
own that claims mail-store (ADR 0378 §3), wired into merge-check.sh.
2026-10-15 17:16:53 +02:00
mesh-tools 789b0a9474 Merge pull request 'Mail and bus hardening: mesh-mail sends on Approve, desk prompt says what for, duplicate PR delivery, cpu_top (issues 790, 789, 783, 741, 811)' (#316) from feat/mail-hardening into main 2026-10-15 14:59:25 +00:00
jochen eb97a3d9a2 mesh-mail: refuse a send whose undecided index cannot be written, and never overwrite a corrupt index (issue 811, review round 3)
mesh/merge-gate head eb97a3d9a2d7 merged into trunk 0914a33fba5a — pass: builds disk-load, mesh-delivery, mesh-mail, rofi → ace, g14, novox, shanks; no bus…
mesh/repo-check head eb97a3d9a2d7 merged into trunk 0914a33fba5a — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/delivery delivered
mesh/delivery-group group feat/mail-hardening delivered: every member is delivered
2026-10-15 15:40:16 +02:00
jochen 8b2e2300d8 mesh-mail: a send whose ask was never heard settles as ended, and the sweep reads only undecided sends (issue 811)
A send whose ask never reached the router (the publish failed, or it was otherwise never recorded) stayed kept and
undecided forever, so mail_send_status kept saying "waiting" and the minute sweep kept reading it. Settle it as
ended once its asked time plus SendAskLasts has passed, with the words that say why. Keep an index of undecided
send ids beside the sends (written when kept, removed once decided) so the sweep's work grows with undecided
sends only, not with every send ever kept.
2026-10-15 15:27:56 +02:00
jochen 2f2daea415 Merge branch 'feat/mail-hardening' into mh-790-r1 2026-10-15 15:08:21 +02:00
jochen 3b48f5962a mesh-mail: send on the operator's Approve itself, sweep, stale-send status, no header injection (issue 790, review round 1) 2026-10-15 15:07:46 +02:00
jochen 2b1678f315 disk-load: cpu_top's shares use the unrounded busy time, and key units by cgroup path (issue 741) 2026-10-15 15:06:06 +02:00
jochen ab739d02dd mesh-delivery: a merge that starts over a stopped duplicate is made from the forge's word too (issue 783) 2026-10-15 15:01:23 +02:00
jochen a60020b51a issue 741: merge feature branch head 2026-10-15 14:51:12 +02:00
jochen a8d84d1730 Add disk-load's cpu_top tool: CPU by systemd unit and container (issue 741)
No tool named which units or processes used CPU outside containers during
the novox overload (issue 739). cpu_top reads each cgroup's cpu.stat (no
root needed), ranks units or containers busiest first, and says the
machine's CPU in use and the busy time no unit accounts for.
2026-10-15 14:51:08 +02:00
jochen 9e8521afb5 mesh-delivery: a stopped duplicate's delivery follows the pull request that merges it (issue 783)
A delivery keyed by commit stayed stopped forever once an earlier, closed
duplicate pull request with the same head had stopped it, even though a
later pull request went on to merge that very commit: the merge only set
merged_as on the stopped record, and the walk that carried it waited for
this owner's word with no delivery left to give it. PullUpdated and
PullMerged now start such a delivery over, under the same id, for the
pull request that announces or merges it next, naming both pull requests
in the transition's why. Any other stop (a person's, a group's, the same
pull request's own close) is untouched.
2026-10-15 14:50:57 +02:00
jochen 8c60604eb7 Show what a desk's secret prompt is for, and declare mesh-mail's (issue 789)
The desk's prompt named only the module and the secret's key, so the operator
asking for one of mesh-mail's mail-credential-* accounts could not tell which
one. node-launcher.secret (modules/rofi) now shows the controller's optional
what as its own line under the module and secret names, escaped as text so
the catalogue's words never reach the prompt as markup; omitted as before
when none is declared. mesh-mail's mail-credential-* family now declares that
line with the long-form own-secrets shape the controller's manifest parser
reads (novox/hq issue 789 part b; part a landed in mesh-controller).
2026-10-15 14:28:45 +02:00
jochen 13cd710071 mesh-mail: add mail_send, asked and sent once on the operator's Approve (issue 790) 2026-10-15 13:57:47 +02:00
mesh-tools 0914a33fba Merge pull request 'mesh-mail: byte-bounded fetch, accounts only to granted callers, grants error kept, secret only stat'ed (hq issue 733)' (#315) from adr-359-mesh-mail-733 into main 2026-10-15 08:49:32 +00:00
jochen b5417c28d0 Merge remote-tracking branch 'origin/main' into adr-359-mesh-mail-733
mesh/merge-gate head b5417c28d026 merged into trunk 5f6a41146c3a — pass: builds mesh-mail, sent nowhere; no bus step; every machine composes with the chang…
mesh/repo-check head b5417c28d026 merged into trunk 5f6a41146c3a — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/delivery covered after its stop: a later walk that contains it was delivered: plan-1792054175111921309 (novox/mesh-catalog at 0914a33f into main, do…
2026-10-15 10:44:37 +02:00
mesh-tools 5f6a41146c Merge pull request 'mesh-mail: the operator's mail accounts, watched and said on the bus — stage 1, own server read-only (hq ADR 0359)' (#300) from adr-359-mesh-mail into main 2026-10-15 08:44:07 +00:00
mesh-tools c71c513027 Merge pull request 'Read branch protection as the forge's administrator, so builds register again (issue 772, ADR 0375)' (#313) from 772-protection-read-as-admin into main 2026-10-15 00:22:49 +00:00
mesh-toolsandClaude 2e32f47e45 Read branch protection as the forge's administrator, so builds register again
mesh/merge-gate head 2e32f47e4596 merged into trunk 9492278d934b — pass: builds gitea → novox; no bus step; every machine composes with the change as it di…
mesh/repo-check head 2e32f47e4596 merged into trunk 9492278d934b — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/delivery covered after its failure: a later walk that contains it was delivered: plan-1792097717281845096 (novox/mesh-catalog at 7443938f into main,…
The forge answers a repository's protection rules to its administrator
alone, and the tools' account no longer is one (ADR 0365), so every
delivery building a module failed at the controller's build-source check
with a 403. gitea_branch_protection_get now reads the rules with the
administrator account (ADR 0375); it only reads, and the protection set
and every write stay refused to the tools' account. Issue 772.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-15 00:18:39 +00:00
mesh-admin 9492278d93 Merge pull request 'Make the forge's tools act as an account of their own, not the administrator' (#311) from 365-forge-identities into main 2026-10-14 22:51:36 +00:00
mesh-admin 5ce2d07c7f Merge pull request 'Give a rollout the word of a stopped delivery that waits for it (hq issue 753)' (#312) from fix/753-a-rollout-is-never-left-without-a-word into main 2026-10-14 22:35:38 +00:00
jschoubben 373f339750 Give a walk the word of a stopped delivery that waits for it (hq issue 753)
mesh/merge-gate head 373f33975077 merged into trunk 7913b56d66f7 — pass: builds mesh-delivery → novox; no bus step; every machine composes with the change …
mesh/repo-check head 373f33975077 merged into trunk 7913b56d66f7 — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/delivery delivered
A delivery its group stopped for a member delivered since waits for a later
walk of its repository that contains its merge (issue 747). When that walk
carried no living delivery, nothing gave it its word and it waited forever.
The delivery now takes its turn on the walk that answers its merge, in its
group's order. A walk owed such a word stays under the orphans' timer, so
past the grace without it `stalled` lists it with why (held, or the
controller's refusal), and a walk no living delivery holds names the ended
deliveries it carries.
2026-10-15 00:30:26 +02:00
mesh-adminandClaude Opus 5.5 48f0662fde Make the forge's tools act as an account of their own, not the administrator (issue 469, ADR 0365 clause 2)
mesh/merge-gate head 48f0662fdea2 merged into trunk 5ce2d07c7f47 — pass: builds gitea → novox; no bus step; every machine composes with the change as it di…
mesh/repo-check head 48f0662fdea2 merged into trunk 5ce2d07c7f47 — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/delivery delivered
The tools' token reached everything the administrator may do, so their boundary rested on their own guards.
The gitea module now makes a plain account, mesh-tools, with the admin login, gives it write on code, issues
and pull requests of every novox repository through one team, and mints the tools' token for it; the admin's
old token goes only after the new one is kept. The Go forge bundle sends that token, never the admin login.
The forge shows protection rules only to a repository administrator, so every check reads a branch's
protection from the branch. mesh-admin stays a ready author, so marks made before the move keep counting.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 22:28:25 +00:00
mesh-admin 7913b56d66 Merge pull request 'Add the kernel module: transparent huge pages set per machine (hq issue 746, ADR 0369)' (#310) from fix/746-huge-pages-madvise into main 2026-10-14 21:52:49 +00:00
jschoubben ab1811d003 Reload, not restart, the huge pages unit when the setting changes (hq issue 746)
mesh/merge-gate head ab1811d00357 merged into trunk c79337579d6b — pass: builds new: modules/kernel, sent nowhere; no bus step; every machine composes with…
mesh/repo-check head ab1811d00357 merged into trunk c79337579d6b — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/delivery delivered
A restart ran restore then apply, so every change passed back through the
found mode and rotated the journal again. Reload applies the new value
directly; restore also drops its state; no rotation while the machine boots;
the unit is sandboxed.
2026-10-14 23:42:49 +02:00
mesh-admin c79337579d Merge pull request 'Make the forge's webhook a system one, and say whether its events are heard (hq issue 729)' (#309) from fix/729-the-forge-events-are-heard-or-said into main 2026-10-14 21:40:44 +00:00
jschoubben 3a84044ece Add the kernel module: transparent huge pages set per machine (hq issue 746)
With THP 'always' journald's mmapped journal files sit in 2 MiB folios, so each small
journal write dirties and writes back 2 MiB; on the control node that saturated the
root mirror holding the bus store and the store, and the controller lost its lease.
The module sets the mode from a per-machine setting (default always, the kernel's own,
so assigning it changes nothing until a machine sets madvise), verifies it took, rotates
the journal once so new files are mapped under the new mode, gives back what it found
when stopped, and serves kernel_huge_pages to measure file_thp per unit.
2026-10-14 23:31:13 +02:00
mesh-admin c51357f8af Merge pull request 'Cover a failed or stopped delivery once a later finished walk contains it (hq issue 747)' (#308) from fix/747-a-failed-member-is-covered-by-a-later-walk into main 2026-10-14 21:30:10 +00:00
jschoubben 2833a049aa Make the forge's webhook a system one, and say whether its events are heard (hq issue 729)
mesh/merge-gate head 2833a049aa0f merged into trunk c51357f8afd4 — pass: builds gitea → novox; no bus step; every machine composes with the change as it di…
mesh/repo-check head 2833a049aa0f merged into trunk c51357f8afd4 — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/delivery delivered
POST /admin/hooks on gitea 1.27.3 makes a default webhook unless
config.is_system_webhook is "true": a default webhook fires for no existing
repository, and the system listing does not name it, so every start made
another and no event reached the receiver. Its edit never changes a secret
or a kind, so the new system webhook is made first and read back, then every
other hook at the receiver is deleted: system, default, and each
repository's copy of a default one, which would send its events twice.

gitea_events says where the receiver listens, the hook as ensured and what
it replaced, the verified and refused deliveries and the polls' pace. When
nothing verified for ten minutes, since the start or the last delivery,
while the poll found two heads or merges no event said, it is logged loudly
once per silent spell and answered unhealthy; so are deliveries refused
since the last verified one.
2026-10-14 23:28:41 +02:00
jschoubben 6f7f07635e Cover a failed or stopped delivery once a later finished walk contains it (hq issue 747)
mesh/merge-gate head 6f7f07635e02 merged into trunk 0f76b6e232a5 — pass: builds mesh-delivery → novox; no bus step; every machine composes with the change …
mesh/repo-check head 6f7f07635e02 merged into trunk 0f76b6e232a5 — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/delivery delivered
A group member whose walk failed in an outage stayed failed after a later walk
of its repository, containing its merge, was done; its group then stopped every
later walk of the other repository, and the catalogue could deliver nothing.

A failed or stopped delivery now reads covered when a done walk of its
repository, made after its merge, whose commit contains it (the forge's word,
as issue 362's containment), built every module it moves. A group counts it as
delivered, and a member the group stopped for it no longer holds a walk back:
the group stops a walk only for a member whose change is still undelivered.
A stop covered under issue 480 now likewise makes its group read reached, not
stopped.

While the forge is asked, the walk is held back rather than stopped, for at
most ten minutes from the first ask: a forge that keeps erroring or cannot say
then lets the walk be asked to leave the stopped merge out, as before. The
hold is said by waits, stalled and stalled walks. The pass reads kept walks
each tick, so today's stuck deliveries clear after a restart.
2026-10-14 23:19:06 +02:00
mesh-admin 0f76b6e232 Merge pull request 'Let an agent's session run the TypeScript check outside the toolchain image (issue 742)' (#307) from 742-ts-toolchain into main 2026-10-14 21:06:32 +00:00
mesh-adminandClaude Opus 5.5 3e16c055be Let an agent's session run the TypeScript check outside the toolchain image (issue 742)
mesh/merge-gate head 3e16c055be8e merged into trunk 0361c44a03a0 — pass: the change touches no module of the mesh's graph
mesh/repo-check head 3e16c055be8e merged into trunk 0361c44a03a0 — pass: THE CHANGE ALTERS ITS OWN CHECK (merge-check-typescript.sh): main's version judged…
mesh/delivery delivered
Outside the image, assemble the same node_modules in the check's own
workspace from mesh-tools' lock on the forge, so a module's TypeScript is
checked locally before a push.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 21:03:53 +00:00
mesh-admin 0361c44a03 Merge pull request 'Clear a forge token name held twice, and mint one process at a time (hq issue 740)' (#306) from fix/a-token-name-held-twice-is-cleared into main 2026-10-14 21:03:29 +00:00
jschoubben d1debdcce8 Clear a forge token name held twice, and mint one process at a time (hq issue 740)
mesh/merge-gate head d1debdcce816 merged into trunk 0e7d9e74d22a — pass: builds gitea → novox; no bus step; every machine composes with the change as it di…
mesh/repo-check head d1debdcce816 merged into trunk 0e7d9e74d22a — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/delivery delivered
The runtime starts the watcher and the tools as two processes over one kept
token. Both minted at once on 2026-10-14 and left two tokens named
mesh-tools; gitea refuses a delete by a name held twice, so every mint
failed and every forge tool with it. A replace now deletes each token by
the name by its id, from the account's whole list, and a mint holds a lock
file beside the kept token and reuses what another process minted.
2026-10-14 22:38:38 +02:00
mesh-admin 0e7d9e74d2 Merge pull request 'Say every forge event on the bus through a signed system webhook (hq issue 729)' (#304) from feat/729-the-forge-says-every-event-on-the-bus into main 2026-10-14 20:28:01 +00:00
jochen be53f5167a mesh-mail: bound a fetch by bytes, show mail_accounts only to its grantees, say why grants are unread, judge a secret without reading it (hq issue 733)
mesh/merge-gate out of date: judged against trunk 2130f9961291, the trunk is now 5f6a41146c3a; judged again on a recheck or when it is merged
mesh/repo-check out of date: judged against trunk 2130f9961291, the trunk is now 5f6a41146c3a; judged again on a recheck or when it is merged
mesh/delivery superseded: a newer head of the same pull request
The review of #300 found a batch of 25 whole messages could hold a gigabyte,
mail_accounts told ungranted callers folder names, counts and server errors,
an unreadable grants setting was refused without its reason, and the watch
read the password only to learn it was there.
2026-10-14 22:24:11 +02:00
jschoubben 1d8a244ba4 Say every forge event on the bus through a signed system webhook, and announce a head or merge at once (novox/hq issue 729)
mesh/merge-gate out of date: judged against trunk 2edef5a00ae0, the trunk is now 0e7d9e74d22a; judged again on a recheck or when it is merged
mesh/repo-check out of date: judged against trunk 2edef5a00ae0, the trunk is now 0e7d9e74d22a; judged again on a recheck or when it is merged
mesh/delivery covered after its stop: a later walk that contains it was delivered: plan-1792011830935225963 (novox/mesh-catalog at 0361c44a into main, do…
The gitea module keeps one system webhook for every event family, made or
corrected at start with the admin account (POST /admin/hooks, forge 1.27.3)
and a secret it mints and keeps. Its receiver, at the docker bridge's
gateway, refuses an unsigned request before reading it, a body over 5 MB,
and a signature that does not verify; it answers a verified delivery at once,
drops one already heard by its delivery id, and publishes each as
forge.<kind>.<action> on the module's events (its own stream, ADR 0363,
follows issue 725). A pull request opened, pushed to or merged is announced
at once. The polls look every five minutes only while deliveries arrive, and
every 30 s again, saying so loudly, when one finds what no event said or ten
minutes pass without a delivery. The announced records keep both paths from
announcing twice.
2026-10-14 22:21:22 +02:00
mesh-admin 2edef5a00a Merge pull request 'Build build-agent and route-proxy without a build ID (hq issue 721)' (#301) from fix/a-module-moves-only-when-its-program-changes into main 2026-10-14 20:21:12 +00:00
jochen 2130f99612 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
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.
2026-10-14 22:17:09 +02:00
jochen ed5690cee4 Merge remote-tracking branch 'origin/main' into adr-359-mesh-mail 2026-10-14 22:16:50 +02:00