Commit Graph
995 Commits
Author SHA1 Message Date
jochen 29ac6ee16a Say that the modules' own checks are the only line before root, since sudo grants the account everything
mesh/merge-gate pass: builds new: modules/mounts, modules/nfs-server, sent nowhere; no bus step; every machine composes with the change as it did without (…
mesh/repo-check fail: its merge-check.sh failed: --- FAIL: TestAnExportLineSquashesEveryClientToTheFoldersOwnerToTheMeshRangeOnly (0.00s)
mesh/delivery superseded: a newer head of the same pull request
mesh/delivery-group group feat/mounts-module delivering: 0 of 3 delivered
2026-10-08 20:21:28 +02:00
jochen 53cc303440 Mount a share at the access the server gave this machine, and not at all when it does not export it here 2026-10-08 20:21:17 +02:00
jochen e50978ca45 Keep a clean look below a share for an hour, so the backup check does not walk the library every 30 s 2026-10-08 20:20:05 +02:00
jochen 8738c02d00 nfs-server: export a share only to the nodes granted and wanting it, and never root's, a symlinked or nested backup, or an unmounted dataset
The review of #136 found a share could squash every client to root, be
judged at a symlink's name rather than its folder, sit inside or above a
backup repository deeper than one level, export an unmounted dataset's
empty folder, go to every address in the private network's range, and
stay exported after the module left. Each is now refused or closed, with
a test that reproduced it first:

- a folder owned by uid or gid 0 is refused;
- the path is resolved through symlinks and every check runs on the real
  folder, which the export line names;
- a share inside a backup repository (any parent) or holding one within
  four levels is refused, and a look cut short by its bound refuses;
- every line carries mp, or mp=<its filesystem's mount point>;
- a share goes only to the nodes this machine's grants setting names and
  whose mounts module wants it on the bus, at the lower access, at the
  roster's address inside the range; nothing without wants;
- the process is declared before its config, so on unassignment it finds
  the config gone, removes its export file and lets the shares go;
- confirm accepts the seat's string "true".
2026-10-08 20:20:05 +02:00
jochen d5adc1d525 Make mounts refuse what it could break: data the mesh keeps, a busy or non-empty mount point, its own share, and a mount that is not its source; say each node's wants so the server exports only to them (review of #136) 2026-10-08 20:16:27 +02:00
jochen 48fba44471 Add the nfs-server module: a node shares a folder with the mesh's machines only, every client mapped to the folder's owner (hq ADR 0263)
mesh/merge-gate fail: builds new: modules/mounts, modules/nfs-server, sent nowhere; no bus step; a manifest the change touches fails the module check: modu…
mesh/repo-check fail: its merge-check.sh failed: long-running resources without health: 70
mesh/delivery-group group feat/mounts-module rejected: a member's own check failed
mesh/delivery superseded: a newer head of the same pull request
2026-10-08 18:36:01 +02:00
jochen 2b1b9b0235 Let mounts write each share's mount and automount, so no node depends on a hand-written fstab line (hq ADR 0263)
A machine mounts what its assignment names: a node's share from the
provision nfs-share, whose path it reads from nfs-server's state on the
bus, and occasional sources (an SMB device, a disk) whose absence is a
state, not a fault. apply writes and arms the unit pairs as root; watch
tries each source and judges the health; the operator's fstab lines are
taken over only through adopt, on their word, once the replacement is
armed. SMB logins are an outside party's secret, given with secret accept.
2026-10-08 18:36:01 +02:00
jochen 3251758340 Add a read-only mounts module: no tool could read a machine's fstab, mount units or exports 2026-10-08 18:36:01 +02:00
mesh-admin 0ad8f02fab Merge pull request 'dunst: make the font size and width settings, defaulting to today's values (hq ADR 0262)' (#132) from feat/setting-defaults into main 2026-10-08 16:18:52 +00:00
mesh-admin 53c4b47da4 Merge pull request 'Serve unlink-dangling in the systemd module (hq issue 332)' (#138) from feat/systemd-unlink-dangling into main 2026-10-08 16:01:44 +00:00
jochen 1b368f9aaf Record a removal's outcome, publish it, and read one directory once
mesh/merge-gate pass: builds systemd → ace, g14, novox, shanks; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery delivered
The record kept only the intent, so a failed unlink read as removed; each
link now gets a synced intent and outcome line, and the outcome is the
module's link.removal event so it is not only a file on one machine.
The put-back hint no longer advises a symlink, an aliased directory is
read once, a machine-wide removal from user scope is said, and the state
directory names no owner a machine without an account cannot resolve.
2026-10-08 17:55:56 +02:00
jochen 87c9d9f7e5 Serve unlink-dangling, so a leftover enable link goes through the seat
systemctl disable leaves a link whose unit file is gone, and the manager
keeps asking for the unit. The verb removes only such links in the
account's or the machine's own configuration, on the person's word, and
records each with its reason before removing it (hq issue 332).
2026-10-08 17:53:53 +02:00
mesh-admin e740683ca4 Merge pull request 'Serve reset-failed and wanted-by in the systemd module (hq issue 332)' (#137) from feat/systemd-reset-failed-why-started into main 2026-10-08 15:52:52 +00:00
jochen 2ed6264b8f Refuse a glob as a unit, and make wanted-by say only what it saw
mesh/merge-gate pass: builds systemd → ace, g14, novox, shanks; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery delivered
systemctl expands *, ? and [ in a unit argument, so reset-failed or stop
of "*" would have acted on every unit. wanted-by called a link dangling on
any stat error, followed a linked .wants anywhere, and missed most of the
manager's load path; it now says each of these, and says nothing names a
unit only of the directories it searched.
2026-10-08 17:38:48 +02:00
jochen 00f1d04616 Serve reset-failed and wanted-by in the systemd module (hq issue 332)
mesh/merge-gate fail: builds systemd → ace, g14, novox, shanks; no bus step; a manifest the change touches fails the module check: systemd claims node-serv…
mesh/repo-check fail: its merge-check.sh failed: long-running resources without health: 70
mesh/delivery superseded: a newer head of the same pull request
So a leftover unit's trigger is found and its failed record cleared
through the seat, not a shell: wanted-by reads the manager's reverse
dependencies and the enable links naming the unit, saying which dangle.
2026-10-08 17:21:18 +02:00
jochen 84731d8fc6 dunst: say plainly why each default
mesh/merge-gate pass: builds dunst → g14, shanks; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery failed: its walk failed: a gate on a first machine (what it carried put back), a build, a machine
mesh/delivery-group group feat/setting-defaults failed: a member failed
2026-10-08 17:02:43 +02:00
jochen 4c34836037 dunst: make the font size and width settings, defaulting to today's values (hq ADR 0262)
The laptop's 242 DPI panel shows Inter 10 at less than half the workstation's size. The
defaults keep every machine's file byte for byte as it is; a machine sets its own.
2026-10-08 17:02:43 +02:00
mesh-admin bf542128ee Merge pull request 'The bar renders contributed blocks; the power module gives it the battery and power draw (hq ADR 0255)' (#127) from feat/the-bar-takes-blocks into main 2026-10-08 14:27:18 +00:00
jochen 5d7d9020b8 Say the laptop's scripts unparsed where the build seat has no bash
mesh/merge-gate pass: builds asus-zephyrus-g14, i3status-rust, power → ace, g14, novox, shanks; no bus step; every machine composes with the change as it d…
mesh/repo-check pass: THE CHANGE ALTERS ITS OWN CHECK (merge-check.sh): main's version judged it; the change's judges the pull requests after it merges; it…
mesh/delivery delivered
The Go toolchain the repository check runs in carries no bash, so the scripts' syntax
check failed there on a missing interpreter, not a broken script.
2026-10-08 16:20:45 +02:00
jochen 0d54ecc764 Keep the value a watch hands over at once, watch a dead watch again, and let the path lists grow only in the open (hq ADR 0260)
mesh/merge-gate pass: builds asus-zephyrus-g14, i3status-rust, power → ace, g14, novox, shanks; no bus step; every machine composes with the change as it d…
mesh/repo-check fail: THE CHANGE ALTERS ITS OWN CHECK (merge-check.sh): main's version judged it; the change's judges the pull requests after it merges; it…
mesh/delivery superseded: a newer head of the same pull request
The SDK hands the current value over before Watch returns, and the follower had no
entry for it yet, so the first value was dropped. A silent watch is now told from an
expired key and watched again rather than polled, each write takes its own temporary
file, drop-in directories are no module's, and an entry added to the path check's lists
is refused unless its line says why.
2026-10-08 16:12:37 +02:00
jochen 4f6cbd2197 Follow bar values so a dead watch speaks, date them by their reading, and widen the path check (hq ADR 0260)
A watch that died left the block silent, a removed block kept its value, and a value
frozen at its source looked fresh because its file was new. The follower now rereads a
silent value and says so, drops removed blocks, and dates each file by the reading's
own time. The path check takes /etc and /usr/local/lib in, ignores what a container sees
inside itself, and lists the five findings standing today, which may only go.
2026-10-08 16:12:37 +02:00
jochen 76b63744e6 Carry the power draw to the bar over the bus, not through a file (hq ADR 0260)
Modules talk over the bus. The power module's bundle puts each fresh reading of its own
sampler in its state draw, keyed by the machine; the bar's block shows that state, which
the bar's bundle watches under the read the mesh grants it. A new catalogue check refuses
a module naming another module's path under /run or /var/lib.
2026-10-08 16:12:37 +02:00
jochen e1b7fcd8c9 Count each processor package once, never read a sleeping card, and give no reading for a reset counter (hq ADR 0255)
Intel shows some packages twice (MSR and MMIO), an AMD card's sensors wake it, and a
counter reset after resume read as thousands of watts. The loop's cadence and the bar
script's staleness are now tested, and the sampler running on every machine is said.
2026-10-08 16:12:37 +02:00
jochen 0040c008b5 Let the bar render blocks other modules contribute, and give it the battery and power draw from the power module (hq ADR 0255)
The bar left the battery out because it belongs to whoever knows the hardware, and had
no way to take it back in. i3status-rust now renders bar-neutral blocks through its
template; the power module contributes the battery where the machine reports one and
the power draw where something measures it, sampling the root-only energy counter as
root and publishing only a rate. The memory block shows what programs hold, the figure
memory-pressure judges by, instead of counting the cache as used.
2026-10-08 16:12:37 +02:00
mesh-admin 05e5903a9b Merge pull request 'gitea: read npm lockfiles of every version and measure every version's size' (#128) from fix/npm-lockfile-shapes into main 2026-10-08 14:02:57 +00:00
mesh-admin 86d2b3b96d Merge pull request 'artifact-store-tools: a platform manifest is its index's; list unrecorded copies of upstream images (hq ADR 0257)' (#130) from feat/a-mirrored-base-is-recorded into main 2026-10-08 14:02:51 +00:00
mesh-admin bf8143ca12 Merge pull request 'sensors: read the machine's hardware condition on every machine (hq ADR 0256)' (#129) from feat/sensors into main 2026-10-08 13:21:01 +00:00
jochen 7aba612c6c sensors: take a SAS drive's standby, whose mode holds spaces
mesh/merge-gate pass: builds new: modules/sensors, sent nowhere; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery delivered
The third review found the asleep match took only one-word modes, so a SAS drive in STANDBY BY TIMER or
LOW POWER was read as a failed answer and lost its reading.
2026-10-08 15:04:02 +02:00
mesh-admin ea462666cc Merge pull request 'messenger and dunst: only acknowledgements from a desk click, one-time answer tokens (hq ADR 0258, issue 324)' (#131) from fix/notifications-after-review into main 2026-10-08 13:02:25 +00:00
jochen 66a816c3ac sensors: say a stuck drive read, and be the drives' only reader
mesh/merge-gate pass: builds new: modules/sensors, sent nowhere; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery superseded: a newer head of the same pull request
The second review of #129 found a read stuck in the kernel kept the file fresh and the module healthy,
smartd as a second reader could wake or keep awake the drives the watch spares, and a board chip's
maximum could stop a fan. Read each drive in its own goroutine from a root reader of the module's own,
mark each read in flight, and say a read past its bound or a drive not looked at for twice its cadence;
drop smartd; tell smartctl each drive's kind; take a SAS drive's standby; say a drive asleep since when.
2026-10-08 14:59:10 +02:00
jochen 700dd7fa1a Load the records the live build kept, remind every quiet warning, silence only its own condition
mesh/merge-gate pass: builds dunst, messenger → g14, novox, shanks; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery delivered
mesh/delivery-group group fix/notifications-after-review delivered: every member is delivered
The build live since 14:38 keeps tokens as token -> index; reading them as grants
failed and skipped the record. A quiet warning known from history was never
reminded, and an answer could silence another condition than its own.
2026-10-08 14:53:11 +02:00
jochen 10b5e8188a Refuse a yarn lockfile the scanner stopped in, and a forge answer the cap cut
mesh/merge-gate pass: builds gitea → novox; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery superseded: a newer delivery to the same trunk took over its walk
Either was read as whole and could leave a pinned version unnamed (review of #128).
2026-10-08 14:52:06 +02:00
jochen d83711f11e Take only acknowledgements from a desk click, and make each answer a one-time ticket
mesh/merge-gate pass: builds dunst, messenger → g14, novox, shanks; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery-group group fix/notifications-after-review ready: every member ready, and composed together they pass
mesh/delivery superseded: a newer head of the same pull request
Review found that any process of the operator's account can choose a dunst action,
so a click could release or stop a delivery in the operator's name; that tokens
lived for ever; that a warning's answers died in ten seconds; and that a restarted
notifier left dead buttons (hq ADR 0258).
2026-10-08 14:38:24 +02:00
jochen 66a32b196d sensors: raise only what the hardware says is failing, and say a hung watch
mesh/merge-gate pass: builds new: modules/sensors, sent nowhere; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery superseded: a newer head of the same pull request
The review of #129 found false alarms and a silent failure: the NVMe temperature bit, old-age
attributes, a fan's minimum or latched alarm, an unrelated hot sensor and a board chip's limits could
raise a condition, while a hung smartctl stopped the fans' looks and an old readings file passed as
healthy. Read spinning drives hourly (smartd too) so a read never keeps one from spinning down, and skip
a drive that cannot say whether it sleeps.
2026-10-08 14:35:16 +02:00
mesh-admin 541b24d96e Merge pull request 'messenger and dunst: plain notifications that say whether you are needed, and take the answer from the desk (hq ADR 0253, issue 320)' (#126) from feat/plain-notifications into main 2026-10-08 12:20:36 +00:00
jochen 2dffc48c81 Count a platform manifest as its index's, and list the unrecorded copies of upstream images
mesh/merge-gate pass: builds artifact-store-tools → novox; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery delivered
The store's tools counted each platform of an upstream image apart from its index, so a
kept copy read as unrecorded and a let-go index's bytes were never counted as freed. The
copies no record names are now listed for the controller's mirrors verb, and a dry run
says what stays yet names a platform collection would take (hq ADR 0257, issue 321).
2026-10-08 14:11:02 +02:00
jochen f00b5a19b1 Say what the operator needs to do, keep quiet what needs nothing, and take answers from the desk
mesh/merge-gate pass: builds dunst, messenger → g14, novox, shanks; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery delivered
mesh/delivery-group group feat/plain-notifications delivered: every member is delivered
The operator could not tell from a notification whether to act, nor act without
opening a session. Each message now opens with a verdict, a warning that needs
nothing is not sent, and a notification offers answers the messenger performs
through their seat verbs; dunst's send gains actions and says the chosen one
(hq ADR 0253).
2026-10-08 13:57:33 +02:00
jochen d69c0db4fc gitea: stop a real npm retention when a file was not read whole
mesh/merge-gate pass: builds gitea → novox; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery superseded: a newer head of the same pull request
A lockfile that could not be read is one of its repository's files that
could not be read (hq ADR 0251 §4): a version only it pins would be deleted
while in use. A real run now refuses on files_not_read as it does on
repositories_unread; a dry run still reports.
2026-10-08 13:52:07 +02:00
jochen 73610f8e3c sensors: read the machine's hardware condition on every machine (hq ADR 0256)
mesh/merge-gate pass: builds new: modules/sensors, sent nowhere; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery superseded: a newer head of the same pull request
Temperatures against the hardware's own thresholds, fans, each drive's health and the kernel's error
counts, read-only. A root watch reads SMART so the tools need no root and never wake a sleeping drive;
smartd and the watch carry the health that raises a condition when the hardware says it is failing.
2026-10-08 13:48:53 +02:00
jochen a9960d7a1b gitea: read npm lockfiles of every version and measure every version's size
mesh/merge-gate pass: builds gitea → novox; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery superseded: a newer head of the same pull request
Retention read no package-lock.json on the forge: in lockfile v2 and v3 a
packages entry's dependencies is a map of name to range, which the reader
decoded as nested entries, so all 32 files failed whole and the versions
they pin were kept by nothing. Entries are now read one by one, tolerating
unknown fields and skipping workspace links; an entry of an unknown shape
is said, not the whole file.

A dry run measured only the versions it would delete, so every kept
version answered 0 bytes. Every version is now measured, the registry's
total is answered, and a size that cannot be read is said (hq ADR 0251 §4).
2026-10-08 13:48:12 +02:00
jochen a6296dfd6f Say each notification in plain words the operator reads at a glance
mesh/merge-gate pass: builds messenger → novox; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery-group group feat/plain-notifications ready: every member ready, and composed together they pass
mesh/delivery superseded: a newer head of the same pull request
The desktop popups were walls of plan ids, commits, keys and verb syntax in UTC.
The messenger now shows the condition's headline, explanation and resolved line,
since when in the operator's time zone, and a clearance in one line (hq ADR 0253).
2026-10-08 13:26:26 +02:00
mesh-admin c78b5fc9f5 Merge pull request 'gitea: npm package retention — keep what is named and the newest five (hq ADR 0251 §4)' (#124) from feat/npm-retention into main 2026-10-08 11:06:14 +00:00
mesh-admin 86077780a9 Merge pull request 'artifact-store-tools: say what the artifact store holds and what the records name (hq ADR 0251)' (#123) from feat/store-tools into main 2026-10-08 11:06:11 +00:00
mesh-admin 3f552274be Merge pull request 'docker: remove images no container or declaration uses, keeping the previous (hq ADR 0251 §5)' (#122) from feat/docker-prune-images into main 2026-10-08 11:05:50 +00:00
mesh-admin a638547924 Merge pull request 'Declare the operator's account in the openrazer group (hq ADR 0252, issue 247)' (#125) from feat/module-groups into main 2026-10-08 10:09:23 +00:00
jochen 24ce702360 Move the artifact store's tools into a module beside it, as the controller requires
mesh/merge-gate pass: builds distribution, new: modules/artifact-store-tools → novox; no bus step; every machine composes with the change as it did without…
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery failed: its walk failed: a gate on a first machine (what it carried put back), a build, a machine
A module that provides the artifact store cannot build an artifact: building publishes to the store,
so the store would be needed to create itself, and the module check refuses it. The tools become
artifact-store-tools, assigned beside the store, and read manifests from the store's files through its
container as they already read the listing, so they need no address for the store's door. Named for
the artifact store, because "store" alone is the database server (hq glossary).
2026-10-08 12:04:33 +02:00
jochen da57051fa3 Declare the operator's account in the openrazer group (hq ADR 0252, issue 247)
mesh/merge-gate pass: builds openrazer → g14, shanks; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery covered: a later merge that contains it was delivered: novox/mesh-catalog@5d7d9020b8c7 (merged as bf542128 into main, walk plan-17914696454…
mesh/delivery-group group feat/module-groups delivered: every member is delivered
The daemon refuses to start outside the group, and the fix was a sudo step by hand that nothing
recorded. The module now declares it; the operator logs in again once.
2026-10-08 12:04:08 +02:00
jochen 8059f35d17 gitea: say what keeps each npm version and delete only what nothing names (hq ADR 0251)
mesh/merge-gate pass: builds gitea → novox; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery superseded: a newer delivery to the same trunk took over its walk
Every publish added a version and nothing removed one. A Go bundle beside the
TypeScript one keeps what a lockfile or a range on the forge names, what a
dist-tag names and the newest five; a dry run unless asked with a why, and
nothing deleted while any repository is unread.
2026-10-08 12:00:57 +02:00
jochen 5f22ebbe97 distribution: say what the store holds and what the records name, so collection is no longer blind (hq ADR 0251)
mesh/merge-gate fail: builds distribution → novox; no bus step; a manifest the change touches fails the module check: modules/distribution/module.json: thi…
mesh/repo-check fail: its merge-check.sh failed: long-running resources without health: 69
mesh/delivery superseded: a newer head of the same pull request
The store had no working tools: its TypeScript client was never built, and nothing could count what
the store holds that no record names. A Go bundle lists the store's files through its own container,
reads each manifest through its door, and sets that beside the controller's records. Collection is
asked of the controller, which decides and records; the store's tools never delete. The image.pushed
event was declared and never emitted, and nothing consumes it, so it goes.
2026-10-08 11:59:47 +02:00
jochen 465707d41d docker: remove images no container or declaration uses, keeping the previous of each line (hq ADR 0251)
mesh/merge-gate pass: builds docker → ace, g14, novox, shanks; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery superseded: a newer delivery to the same trunk took over its walk
Images pulled by digest are not dangling, so the weekly prune never takes an old version
and every machine keeps every image it ever ran. docker_prune_images takes them, keeps what
the declaration names (asked of the controller; no answer, nothing removed) and the one before,
and is a dry run unless asked with a why.
2026-10-08 11:56:43 +02:00