Five postgres consumers say which provision their check exercises (hq issue 145, to-be 48 Phase E) #289

Merged
mesh-admin merged 2 commits from fix/145-a-consumer-is-held-under-its-provider into main 2026-10-14 05:26:48 +00:00
Contributor

Part of issue 145 (a machine reads healthy while its modules cannot reach each other).

after: mesh-controller

What

A check that names the provision it exercises in needs is held under that provision's provider while the provider is unhealthy (ADR 0240 rule 5, controller provider_hold.go). Until now 0 of 128 manifests named one. This gives five consumers of postgres-database a check that reaches their database through the module's own endpoint or tool:

module machine resource check why it reaches the database
gitea novox server http /api/healthz on web, 200 gitea's health endpoint pings the database and answers 503 when it fails
nextcloud novox server http /status.php on web, 200, body "installed":true status.php loads the enabled apps and the upgrade state from the database; a failure answers 500
umami novox server http /api/share/mesh-health on web, 404, timeout 10 s the share route looks the id up in the database with no login: an id that does not exist is 404, and a database that does not answer is 500
n8n ace server http /healthz/readiness on web, 200 n8n answers 200 only while its database connection is up and migrated, else 503
mesh-knowledge novox watch its tool knowledge_health (unchanged), now needs: postgres-database the watch's verdict is whether the database serves

The four http checks are new, so the count of long-running resources without health goes from 66 to 62 (health-undeclared). Declaring an http check recreates no container.

Read on the live mesh before choosing (netcheck from each machine to its published port): gitea 200 at /api/healthz; nextcloud 200 at /status.php; umami 404 JSON at /api/share/<id>, while an unknown route there is a 404 HTML page, so the share route is real and was answered; n8n 200 at /healthz/readiness.

Not done here, follow-up

  • s3-bucket has no consumer check. Its two consumers cannot carry one honestly. nextcloud has one long-running resource, which carries one check with one needs. status.php does not reach the object store, nothing without a login does, and a tool check alone is refused (a module never judges itself only by its own tool). invoicing-api answers 401 to every path it was asked, so the readiness route has to be added in the application's own repository first.
  • keycloak (novox): /health/ready answers 404: health is off (KC_HEALTH_ENABLED), and on Keycloak 25 or later it is served on the management port 9000, which the module does not declare. This needs the image's version read first.
  • baserow (ace): /api/_health/ and /api/settings/ answer 404 through the image's Caddy from the machine; its runtime check stays.
  • letta (ace): /v1/health/ does not touch the database. It needs a route that does, or a tool.
  • mailu (novox): the admin's endpoints that reach the database need a login. It also overlaps with #284 and #285, which change mailu's checks now.
  • claude-licence-manager, mesh-catalog and model-usage run nothing long-lived, so they have nothing to carry a check.

How it was tested

  • mesh-controller module check (controller built from main df9e572): every manifest ok, and the five read as above. needs is accepted only for a provision the module requires.
  • MESH_GATE=… MESH_CHECK_MODULES=gitea,nextcloud,umami,n8n,mesh-knowledge sh merge-check.sh: exit 0 ("long-running resources without health: 62, as kept", gitea and mesh-knowledge Go tests).
  • mesh-knowledge TestTheManifest… now holds the watch's check to needs: postgres-database, and it fails without the manifest change.
  • The bed (mesh-lab, ADR 0240 rule 7) asks a check with needs only to reach the program, so a check that wants the database proves its wiring without one.

Effect on the operator

Nothing changes while everything works. When postgres on novox is unhealthy, status shows one urgent module.postgres.novox.unhealthy that lists gitea, nextcloud, umami and mesh-knowledge as waiting on it, not five conditions. The same holds for postgres on ace and n8n. A consumer that fails while its database is healthy is raised on its own as module.<m>.<machine>.unhealthy, a warning. gitea, nextcloud, umami and n8n were judged by liveness alone, so a broken database connection is now said at all.

Part of issue 145.

Part of issue 145 (a machine reads healthy while its modules cannot reach each other). after: mesh-controller ## What A check that names the provision it exercises in `needs` is held under that provision's provider while the provider is unhealthy (ADR 0240 rule 5, controller `provider_hold.go`). Until now 0 of 128 manifests named one. This gives five consumers of `postgres-database` a check that reaches their database through the module's own endpoint or tool: | module | machine | resource | check | why it reaches the database | |---|---|---|---|---| | gitea | novox | server | http `/api/healthz` on web, 200 | gitea's health endpoint pings the database and answers 503 when it fails | | nextcloud | novox | server | http `/status.php` on web, 200, body `"installed":true` | status.php loads the enabled apps and the upgrade state from the database; a failure answers 500 | | umami | novox | server | http `/api/share/mesh-health` on web, 404, timeout 10 s | the share route looks the id up in the database with no login: an id that does not exist is 404, and a database that does not answer is 500 | | n8n | ace | server | http `/healthz/readiness` on web, 200 | n8n answers 200 only while its database connection is up and migrated, else 503 | | mesh-knowledge | novox | watch | its tool `knowledge_health` (unchanged), now `needs: postgres-database` | the watch's verdict is whether the database serves | The four http checks are new, so the count of long-running resources without `health` goes from 66 to 62 (`health-undeclared`). Declaring an http check recreates no container. Read on the live mesh before choosing (netcheck from each machine to its published port): gitea 200 at `/api/healthz`; nextcloud 200 at `/status.php`; umami 404 JSON at `/api/share/<id>`, while an unknown route there is a 404 HTML page, so the share route is real and was answered; n8n 200 at `/healthz/readiness`. ## Not done here, follow-up - **s3-bucket has no consumer check.** Its two consumers cannot carry one honestly. nextcloud has one long-running resource, which carries one check with one `needs`. status.php does not reach the object store, nothing without a login does, and a tool check alone is refused (a module never judges itself only by its own tool). invoicing-api answers 401 to every path it was asked, so the readiness route has to be added in the application's own repository first. - **keycloak** (novox): `/health/ready` answers 404: health is off (`KC_HEALTH_ENABLED`), and on Keycloak 25 or later it is served on the management port 9000, which the module does not declare. This needs the image's version read first. - **baserow** (ace): `/api/_health/` and `/api/settings/` answer 404 through the image's Caddy from the machine; its `runtime` check stays. - **letta** (ace): `/v1/health/` does not touch the database. It needs a route that does, or a tool. - **mailu** (novox): the admin's endpoints that reach the database need a login. It also overlaps with #284 and #285, which change mailu's checks now. - claude-licence-manager, mesh-catalog and model-usage run nothing long-lived, so they have nothing to carry a check. ## How it was tested - `mesh-controller module check` (controller built from main df9e572): every manifest ok, and the five read as above. `needs` is accepted only for a provision the module requires. - `MESH_GATE=… MESH_CHECK_MODULES=gitea,nextcloud,umami,n8n,mesh-knowledge sh merge-check.sh`: exit 0 ("long-running resources without health: 62, as kept", gitea and mesh-knowledge Go tests). - mesh-knowledge `TestTheManifest…` now holds the watch's check to `needs: postgres-database`, and it fails without the manifest change. - The bed (mesh-lab, ADR 0240 rule 7) asks a check with `needs` only to reach the program, so a check that wants the database proves its wiring without one. ## Effect on the operator Nothing changes while everything works. When postgres on novox is unhealthy, `status` shows one urgent `module.postgres.novox.unhealthy` that lists gitea, nextcloud, umami and mesh-knowledge as waiting on it, not five conditions. The same holds for postgres on ace and n8n. A consumer that fails while its database is healthy is raised on its own as `module.<m>.<machine>.unhealthy`, a warning. gitea, nextcloud, umami and n8n were judged by liveness alone, so a broken database connection is now said at all. Part of issue 145.
mesh-admin added 1 commit 2026-10-14 01:22:31 +00:00
Say which provision five consumers' checks exercise, so a database down is one condition (hq issue 145)
mesh/merge-gate out of date: judged against trunk ebf7f3773dc7, the trunk is now e846c289c878; judged again on a recheck or when it is merged
mesh/repo-check out of date: judged against trunk ebf7f3773dc7, the trunk is now e846c289c878; judged again on a recheck or when it is merged
mesh/delivery-group group fix/145-a-consumer-is-held-under-its-provider checking: composed check out of date: novox/mesh-catalog@b62bb158398d was judged agains…
mesh/delivery superseded: a newer head of the same pull request
b62bb15839
gitea, nextcloud, umami and n8n gain an http check that reaches their
database through their own endpoint; mesh-knowledge's watch already
asks the database and now names it. While postgres is unhealthy, their
findings are held under its condition instead of raising one each.
Author
Contributor

Delivery novox/mesh-catalog@2bb5d344f6f1 — covered since 2026-10-14T12:38:18Z

Delivery plan — builds gitea, mesh-knowledge, n8n, nextcloud, umami → ace, novox; no bus step

  • tier 0: gitea, mesh-knowledge, n8n, nextcloud, umami
  • ace: receives n8n
  • novox: receives gitea, mesh-knowledge, nextcloud, umami
  • gitea provides npm-package-registry, git: its consumers are sent again after it
  • gitea keeps data (ADR 0233): what it holds is backed up before it moves
  • n8n keeps data (ADR 0233): what it holds is backed up before it moves
  • nextcloud keeps data (ADR 0233): what it holds is backed up before it moves
  • umami provides analytics: its consumers are sent again after it
  • umami keeps data (ADR 0233): what it holds is backed up before it moves
  • grants step: if this changes what the bus's user list says (a new tool, subject or user), novox is sent that list alone, every build there kept, before n8n is judged on its first machine

Group fix/145-a-consumer-is-held-under-its-provider, in order: novox/mesh-controller@cebc593627 → novox/mesh-catalog@2bb5d344f6

Machines

  • build-agent on ace: passed — carried by plan-1791962096738242755
  • n8n on ace: passed — healthy 1 times over 1m13s, by a leaf module's rule: one reading (novox/hq ADR 0304)
  • gitea on novox: passed — healthy 1 times over 22s, 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 05:07 (new) → proposed (announced): novox/mesh-catalog#289's head announced
  • 2026-10-14 05:23 proposed → checked (checked): a verdict names this commit and the trunk's head as its trunk commit
  • 2026-10-14 05:23 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
  • 2026-10-14 05:26 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 05:27 published → held (hold): something holds it for a person: its group's composed check did not pass for the heads that merged, or it merged and no walk was opened for it
  • 2026-10-14 12:34 held → delivering (release): operator's word 2026-10-14 in the g14 session: release #289 (its own merge gate and repo check passed; the group's controller half #319 only lists tests and moved nothing); its walk plan-1791981164489044418 also carries mesh-catalog #284, the fix for mail on novox (issue 687)
  • 2026-10-14 12:38 delivering → covered (covered): covered: a later merge that contains it was delivered: novox/mesh-catalog@054dc9618c (merged as b15846dd into main, walk plan-1791981164489044418)

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

<!-- mesh-delivery:view --> **Delivery** `novox/mesh-catalog@2bb5d344f6f1` — **covered** since 2026-10-14T12:38:18Z **Delivery plan** — builds gitea, mesh-knowledge, n8n, nextcloud, umami → ace, novox; no bus step - tier 0: gitea, mesh-knowledge, n8n, nextcloud, umami - ace: receives n8n - novox: receives gitea, mesh-knowledge, nextcloud, umami - gitea provides npm-package-registry, git: its consumers are sent again after it - gitea keeps data (ADR 0233): what it holds is backed up before it moves - n8n keeps data (ADR 0233): what it holds is backed up before it moves - nextcloud keeps data (ADR 0233): what it holds is backed up before it moves - umami provides analytics: its consumers are sent again after it - umami keeps data (ADR 0233): what it holds is backed up before it moves - grants step: if this changes what the bus's user list says (a new tool, subject or user), novox is sent that list alone, every build there kept, before n8n is judged on its first machine **Group** `fix/145-a-consumer-is-held-under-its-provider`, in order: novox/mesh-controller@cebc593627d3 → novox/mesh-catalog@2bb5d344f6f1 - novox/mesh-controller@cebc593627d3 before novox/mesh-catalog@2bb5d344f6f1: declared **Machines** - build-agent on ace: passed — carried by plan-1791962096738242755 - n8n on ace: passed — healthy 1 times over 1m13s, by a leaf module's rule: one reading (novox/hq ADR 0304) - gitea on novox: passed — healthy 1 times over 22s, 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 05:07 (new) → proposed (announced): novox/mesh-catalog#289's head announced - 2026-10-14 05:23 proposed → checked (checked): a verdict names this commit and the trunk's head as its trunk commit - 2026-10-14 05:23 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail - 2026-10-14 05:26 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 05:27 published → held (hold): something holds it for a person: its group's composed check did not pass for the heads that merged, or it merged and no walk was opened for it - 2026-10-14 12:34 held → delivering (release): operator's word 2026-10-14 in the g14 session: release #289 (its own merge gate and repo check passed; the group's controller half #319 only lists tests and moved nothing); its walk plan-1791981164489044418 also carries mesh-catalog #284, the fix for mail on novox (issue 687) - 2026-10-14 12:38 delivering → covered (covered): covered: a later merge that contains it was delivered: novox/mesh-catalog@054dc9618ce3 (merged as b15846dd into main, walk plan-1791981164489044418) The commit's note under `refs/notes/mesh-plan` keeps every transition: `git log --notes=mesh-plan`.
Author
Contributor

Merge check at b62bb158
Judged: head b62bb158398d merged into trunk ebf7f3773dc7; read beside it: mesh-controller 2959c8143536, mesh-controller-main 2959c8143536, 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: gitea, mesh-knowledge, n8n, nextcloud, umami)
  • 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 gitea, mesh-knowledge, n8n, nextcloud, umami → ace, novox; no bus step

  • tier 0: gitea, mesh-knowledge, n8n, nextcloud, umami
  • ace: receives n8n
  • novox: receives gitea, mesh-knowledge, nextcloud, umami
  • gitea provides npm-package-registry, git: its consumers are sent again after it
  • gitea keeps data (ADR 0233): what it holds is backed up before it moves
  • n8n keeps data (ADR 0233): what it holds is backed up before it moves
  • nextcloud keeps data (ADR 0233): what it holds is backed up before it moves
  • umami provides analytics: its consumers are sent again after it
  • umami keeps data (ADR 0233): what it holds is backed up before it moves
  • grants step: if this changes what the bus's user list says (a new tool, subject or user), novox is sent that list alone, every build there kept, before n8n is judged on its first machine
  • read by no module's build: health-undeclared, modules/mesh-knowledge/cmd/mesh-knowledge/manifest_test.go

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

--- the gate: gitea, mesh-knowledge, n8n, nextcloud, umami
note: mesh-knowledge uses the seat "operator-channel", which no module declares and the mesh does not define among the manifests given; registration judges it against the whole catalogue, and passing the declaring module's manifest too judges it here
gitea: ok, keeps data (valuable), ready: server by http /api/healthz on web expecting 200 every 30s
mesh-knowledge: ok, 2 tool(s), invokes seat:issue-tracker.reserve, claude-code.claude_code_judge, claude-code.claude_code_judged, records.records_status, records.records_list, records.records_read, seat:operator-channel.notify, ready: keep by unit every 30s; watch by its tool knowledge_health every 1m0s
n8n: ok, keeps data (valuable), cache (cache), ready: server by http /healthz/readiness on web expecting 200 every 30s; WARNING: cache-server, browser stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
nextcloud: ok, keeps html (valuable), ready: server by http /status.php on web expecting 200 every 30s
umami: ok, ready: server by http /api/share/mesh-health on web expecting 404 every 30s
long-running resources without health: 2
files asking for a setting without saying whether it is trusted: 0
5 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here
judging 5 module(s) changed against 4 machine(s), as the snapshot of 2026-10-14T01:22:20Z 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-14T01:22:20Z

modules the change moves:
  - gitea (changed)
  - mesh-knowledge (changed)
  - n8n (changed)
  - nextcloud (changed)
  - umami (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 5 module(s) in 1 tier(s): gitea, mesh-knowledge, n8n, nextcloud, umami

notes:
  - health-undeclared and modules/mesh-knowledge/cmd/mesh-knowledge/manifest_test.go read by no module's build, and rebuild nothing (issue 280)
--- its merge-check.sh (go toolchain)
ok  	git.novox.be/novox/mesh-catalog/checks/words	0.003s
words: 12 retired words and 70 daemons' lines, none in the 46786 strings of 718 files
ok  	git.novox.be/novox/mesh-catalog/checks/agenthome	0.012s
agent-home: no archive and no file written into under the agent's home
ok  	git.novox.be/novox/mesh-catalog/checks/secrets	0.012s
secrets: no setting can replace a vault secret in a mergeable file (1 known, nested)
ok  	git.novox.be/novox/mesh-catalog/checks/paths	0.006s
paths: no module names another's state on its machine (3 known, listed to go)
long-running resources without health: 62, as kept
ok  	git.novox.be/novox/mesh-catalog/checks/deps	0.215s
testing modules/gitea
ok  	gitea/cmd/forge	1.503s
ok  	gitea/cmd/npm-registry	1.852s
?   	gitea/internal/forgehttp	[no test files]
testing modules/mesh-knowledge
ok  	mesh-knowledge/cmd/mesh-knowledge	129.031s
modules/nextcloud is TypeScript: merge-check-typescript.sh type-checks and tests it
modules/umami is TypeScript: merge-check-typescript.sh type-checks and tests it
--- its merge-check-typescript.sh (typescript toolchain)
type-checking modules/gitea (TypeScript)
testing modules/gitea (TypeScript)
✔ a pull request opened after the margin is looked at, by its own update time (13.871978ms)
✔ every open pull request is read with what its base requires and what its head has (gitea_open_pulls) (54.084599ms)
✔ a pull request or issue number that is not one is refused before the forge is asked (1.33602ms)
✔ a merged pull request whose branch was deleted is announced with its branch, not its pull ref (10.294324ms)
✔ the newest status of each context is kept, with what it said, when and by whom (16.71803ms)
✔ a commit merges only when every required status is a success; a warning blocks (0.738311ms)
✔ no rule requires nothing; a rule that cannot be read says nothing, never yes (0.306035ms)
✔ a commit is contained in another when the compare finds nothing on it the other lacks (0.954565ms)
✔ a note line is appended once, as the forge's user, in its own repository (10.271234ms)
✔ a note that cannot be written is said, never read as written (0.482457ms)
✔ one view per pull request, found by its marker; only the mesh's statuses (0.751811ms)
✔ a build machine taking the check is said on the head: building on which machine, since the local time (13.480032ms)
✔ the verdict heard while a 'building' write is in flight lands last and stays (5.703715ms)
[gitea] novox/hq@a6b08de8: the verdict of build-1791680941000000000 is an older run's than the check now pending; not written
✔ the verdict written while a start's read of the forge is in flight stays the newest status (1.079176ms)
✔ the verdict heard while a 'building' write still waits its turn: the 'building' is never written (0.524328ms)
✔ a start heard after the verdict writes nothing (0.555609ms)
✔ a start from before the check now pending (a run before a recheck, the stream's history) writes nothing (0.489898ms)
✔ an old run's verdict redelivered after a recheck's pending is not written over it (0.942374ms)
[gitea] novox/hq@a6b08de8: the verdict of build-1791680941000000000 is an older run's than the check the forge holds pending; not written
[gitea] novox/hq@a6b08de8: the verdict of build-1791680941000000000 is an older run's than the check now pending; not written
✔ an old run's verdict in flight when the recheck comes lands before the recheck's pending (1.848577ms)
✔ a rechecked head says where its new run is: building on which machine (1.023515ms)
✔ the recheck's own verdict is written, even asked a little before the pending by another machine's clock (0.68576ms)
✔ after a restart, an old run's verdict is weighed against the check the forge's history holds open (0.568289ms)
✔ a recheck the forge does not take fails its caller, and the head is as it was (0.446007ms)
✔ the status tool writes the merge check's pending through the writer, and the mesh's other statuses as they were (5.258618ms)
✔ when a check was asked is read from its id; the opening of the check now pending from the gate's history (0.263264ms)
✔ a head this process did not announce (it restarted) is said only while the forge holds its gate pending (0.394216ms)
✔ a repository as the mesh clones it is told from another (0.292185ms)
✔ gitea_api refuses the forge's administration, a branch's protection and the merge check's status, and sends nothing (5.769777ms)
✔ gitea_api refuses a file written to the default branch or one a rule guards, and writes one on a branch of its own (53.139544ms)
✔ a protection rule covers a branch as the forge decides it: classes, alternatives, a plain name in any case (issue 539) (15.774316ms)
✔ gitea_api still writes what an author writes (7.569293ms)
✔ gitea_branch_protection_set only strengthens (17.509412ms)
✔ gitea_merge_pull_request merges only a head whose required statuses all succeeded, and only that head (48.370943ms)
✔ gitea_merge_pull_request refuses a verdict judged against an earlier trunk, and asks the check once (156.738783ms)
✔ gitea_merge_pull_request merges only the head it is named, and refuses one that is not the head (16.943593ms)
✔ gitea_merge_pull_request is loud when the forge merged a head other than the one it was handed (13.667834ms)
✔ gitea_merge_pull_request says the merge happened when reading back what landed fails (25.538642ms)
✔ gitea_merge_pull_request reads back a fast-forward, and says it cannot read back a squash or a rebase (60.305431ms)
✔ gitea_delete_repo deletes only the tools' own user's repository, unguarded, untouched for 30 days, named in full (22.044169ms)
✔ gitea_api sends the path it judged, and refuses moving a pull request's base (3.834837ms)
✔ gitea_merge_pull_request merges only into a branch whose protection requires the checks (8.168802ms)
✔ a rule named for a branch is not made weaker than the glob rule that guards it now (12.919533ms)
✔ a repository owner or name is never another path (0.500807ms)
✔ the judges, without a forge (0.380636ms)
✔ gitea_api never acts as another user: sudo, in any case, and any query key it does not send are refused (1.602254ms)
✔ gitea_api never approves a pull request nor requests changes: those are the operator's (2.493657ms)
✔ no tool's caller text becomes another path or another user: `..` and `?sudo=` are refused before the forge (5.4017ms)
✔ every page of a pull request's files is read, though the forge caps a page at fifty (28.72003ms)
✔ a pass asks only the repositories that moved since the last look, every one before the first (0.457147ms)
✔ the directories above a merge's files that hold a module at the commit are said, the root never (14.239133ms)
✔ a lookup the forge refuses is thrown, not read as no module (4.67215ms)
✔ a renamed file is said under its old name too, as gone (novox/hq ADR 0267) (5.859357ms)
✔ a new head beyond the newest 20 open pull requests is announced, exactly once (48.905381ms)
✔ a pass pages until it reaches back past its floor, and no further (24.552257ms)
✔ the statuses asked for replace the rule's, and an empty list requires none (8.66208ms)
✔ a new rule refuses direct pushes unless asked; an administrator's override only when said (0.391575ms)
✔ each open pull request's new head is announced once, and nothing closed or merged (11.916259ms)
✔ a verdict is the head commit's status; an error is the forge's error, never a success (1.063506ms)
✔ each layer is its own status: the gate with the modules it judged, the repository's own check beside it (0.831542ms)
✔ no verdict sets warning on a required check; only a person's decision fails (1.141767ms)
✔ a commit status is set on the commit, under the merge check's context (33.748555ms)
✔ a change plan is the gate's result: said on the status and, when it builds something, as a comment (0.501667ms)
✔ a head announced is pending in the build queue, since the local time it was announced (0.253524ms)
✔ the vault's token is used, a setting of it is ignored and said once, without its value (2.388556ms)
✔ a consumer that asks nothing, or write, publishes: the package team (1.261809ms)
✔ a consumer that asks to read joins the readers, who write no package (0.398445ms)
✔ a reader is made, put on the readers team, and taken off the package team (0.428807ms)
✔ a publisher is made and put on the package team, as before (0.180243ms)
✔ first start: mints with the admin account, keeps the token at 0600, asks for the tools' scopes only (32.451485ms)
✔ second start: reuses the kept token, mints nothing (16.457226ms)
✔ the forge rejects the kept token (its data was restored): minted afresh, once, and the call goes through (20.73962ms)
✔ a token kept with write:admin by an earlier build is minted again without it at the next start, and the forge drops the old one (24.602638ms)
✔ a kept token lacking a scope the tools need: the forge refuses the call for the scope, the token is re-minted with the whole list, and the call goes through (18.769061ms)
✔ the kept file is gone but the forge still holds a token by that name: replaced, not refused (17.218017ms)
✔ concurrent first calls share one mint (10.855093ms)
✔ the admin account is refused: said plainly, nothing kept, and the next call fails the same way rather than crashing (12.143612ms)
✔ one process shares one source per kept file — the watcher and the tools never renew against each other (0.964765ms)
✔ a second process finds the token the first renewed, and reuses it instead of minting over it (18.147252ms)
✔ a configured token wins, and is reported rather than minted over when the forge rejects it (2.397886ms)
✔ nothing to mint with and no token: the client says what is missing (0.192003ms)
[gitea] no tools — no Gitea token, and nothing to mint one with — set MESH_GITEA_TOKEN, or MESH_GITEA_ADMIN_USER, MESH_GITEA_ADMIN_PASSWORD_FILE, MESH_GITEA_STATE_DIR
[gitea] no token kept — minting one
[gitea] the forge already holds a token named "mesh-tools" — replacing it
[gitea] minted a token for "mesh-admin" (write:repository, write:issue, read:user), kept at /tmp/gitea-r3bn2R/state/token
✔ the tools register once there is a way to a token, and the first call mints it (8.531367ms)
[gitea] no token kept — minting one
[gitea] the forge already holds a token named "mesh-tools" — replacing it
[gitea] minted a token for "mesh-admin" (write:repository, write:issue, read:user), kept at /tmp/gitea-kRdu0x/state/token
✔ a pull request can be closed, read and cleaned up through the tools (18.269073ms)
[gitea] novox/mesh-host's main moved from a2c2c35bbbbb to d28ca95ccccc: 25 open pull request(s) into it put out of date, nothing run (novox/hq ADR 0323)
[gitea] novox/mesh-host's main moved from d28ca95ccccc to ffffffffffff: 0 open pull request(s) into it put out of date, nothing run (novox/hq ADR 0323)
[gitea] novox/mesh-host: whether a trunk moved could not be weighed, so it is weighed again on the next pass — the forge is away
[gitea] novox/mesh-host's main moved from a2c2c35bbbbb to d28ca95ccccc: 0 open pull request(s) into it put out of date, nothing run (novox/hq ADR 0323)
✔ both statuses say the head and the trunk commit the verdict judged, first, whatever the summary's length (1.774196ms)
✔ a trunk's move puts an open head's merge check out of date, naming both commits, unless a check is on its way (1.236308ms)
✔ a push to a trunk puts every open pull request into it out of date — twenty-five of them — and none into another (4.291385ms)
✔ a trunk that cannot be read is weighed again on the next pass, never recorded half (0.448167ms)
✔ the trunk's move takes its turn after a verdict in flight, and weighs what the forge holds then (0.453847ms)
✔ a verdict judged against a trunk newer than the pass's first read is not put out of date (0.297284ms)
✔ a verdict that landed out of date keeps its account on the pull request (0.253383ms)
ℹ tests 89
ℹ suites 0
ℹ pass 89
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 670.764157
type-checking modules/nextcloud (TypeScript)
testing modules/nextcloud (TypeScript)
✔ the vault's password is used, a setting of it is ignored and said once, without its value (1.924758ms)
ℹ tests 1
ℹ suites 0
ℹ pass 1
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 108.314069
type-checking modules/umami (TypeScript)
NOT TESTED: modules/umami is TypeScript and has no tests of its own
**Merge check** at `b62bb158` Judged: head `b62bb158398d` merged into trunk `ebf7f3773dc7`; read beside it: mesh-controller `2959c8143536`, mesh-controller-main `2959c8143536`, 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: gitea, mesh-knowledge, n8n, nextcloud, umami) - `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 gitea, mesh-knowledge, n8n, nextcloud, umami → ace, novox; no bus step - tier 0: gitea, mesh-knowledge, n8n, nextcloud, umami - ace: receives n8n - novox: receives gitea, mesh-knowledge, nextcloud, umami - gitea provides npm-package-registry, git: its consumers are sent again after it - gitea keeps data (ADR 0233): what it holds is backed up before it moves - n8n keeps data (ADR 0233): what it holds is backed up before it moves - nextcloud keeps data (ADR 0233): what it holds is backed up before it moves - umami provides analytics: its consumers are sent again after it - umami keeps data (ADR 0233): what it holds is backed up before it moves - grants step: if this changes what the bus's user list says (a new tool, subject or user), novox is sent that list alone, every build there kept, before n8n is judged on its first machine - read by no module's build: health-undeclared, modules/mesh-knowledge/cmd/mesh-knowledge/manifest_test.go Run by the build seat on shanks as `build-1791940982470941621` (`builds --log build-1791940982470941621`). ``` --- the gate: gitea, mesh-knowledge, n8n, nextcloud, umami note: mesh-knowledge uses the seat "operator-channel", which no module declares and the mesh does not define among the manifests given; registration judges it against the whole catalogue, and passing the declaring module's manifest too judges it here gitea: ok, keeps data (valuable), ready: server by http /api/healthz on web expecting 200 every 30s mesh-knowledge: ok, 2 tool(s), invokes seat:issue-tracker.reserve, claude-code.claude_code_judge, claude-code.claude_code_judged, records.records_status, records.records_list, records.records_read, seat:operator-channel.notify, ready: keep by unit every 30s; watch by its tool knowledge_health every 1m0s n8n: ok, keeps data (valuable), cache (cache), ready: server by http /healthz/readiness on web expecting 200 every 30s; WARNING: cache-server, browser stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) nextcloud: ok, keeps html (valuable), ready: server by http /status.php on web expecting 200 every 30s umami: ok, ready: server by http /api/share/mesh-health on web expecting 404 every 30s long-running resources without health: 2 files asking for a setting without saying whether it is trusted: 0 5 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here judging 5 module(s) changed against 4 machine(s), as the snapshot of 2026-10-14T01:22:20Z 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-14T01:22:20Z modules the change moves: - gitea (changed) - mesh-knowledge (changed) - n8n (changed) - nextcloud (changed) - umami (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 5 module(s) in 1 tier(s): gitea, mesh-knowledge, n8n, nextcloud, umami notes: - health-undeclared and modules/mesh-knowledge/cmd/mesh-knowledge/manifest_test.go read by no module's build, and rebuild nothing (issue 280) --- its merge-check.sh (go toolchain) ok git.novox.be/novox/mesh-catalog/checks/words 0.003s words: 12 retired words and 70 daemons' lines, none in the 46786 strings of 718 files ok git.novox.be/novox/mesh-catalog/checks/agenthome 0.012s agent-home: no archive and no file written into under the agent's home ok git.novox.be/novox/mesh-catalog/checks/secrets 0.012s secrets: no setting can replace a vault secret in a mergeable file (1 known, nested) ok git.novox.be/novox/mesh-catalog/checks/paths 0.006s paths: no module names another's state on its machine (3 known, listed to go) long-running resources without health: 62, as kept ok git.novox.be/novox/mesh-catalog/checks/deps 0.215s testing modules/gitea ok gitea/cmd/forge 1.503s ok gitea/cmd/npm-registry 1.852s ? gitea/internal/forgehttp [no test files] testing modules/mesh-knowledge ok mesh-knowledge/cmd/mesh-knowledge 129.031s modules/nextcloud is TypeScript: merge-check-typescript.sh type-checks and tests it modules/umami is TypeScript: merge-check-typescript.sh type-checks and tests it --- its merge-check-typescript.sh (typescript toolchain) type-checking modules/gitea (TypeScript) testing modules/gitea (TypeScript) ✔ a pull request opened after the margin is looked at, by its own update time (13.871978ms) ✔ every open pull request is read with what its base requires and what its head has (gitea_open_pulls) (54.084599ms) ✔ a pull request or issue number that is not one is refused before the forge is asked (1.33602ms) ✔ a merged pull request whose branch was deleted is announced with its branch, not its pull ref (10.294324ms) ✔ the newest status of each context is kept, with what it said, when and by whom (16.71803ms) ✔ a commit merges only when every required status is a success; a warning blocks (0.738311ms) ✔ no rule requires nothing; a rule that cannot be read says nothing, never yes (0.306035ms) ✔ a commit is contained in another when the compare finds nothing on it the other lacks (0.954565ms) ✔ a note line is appended once, as the forge's user, in its own repository (10.271234ms) ✔ a note that cannot be written is said, never read as written (0.482457ms) ✔ one view per pull request, found by its marker; only the mesh's statuses (0.751811ms) ✔ a build machine taking the check is said on the head: building on which machine, since the local time (13.480032ms) ✔ the verdict heard while a 'building' write is in flight lands last and stays (5.703715ms) [gitea] novox/hq@a6b08de8: the verdict of build-1791680941000000000 is an older run's than the check now pending; not written ✔ the verdict written while a start's read of the forge is in flight stays the newest status (1.079176ms) ✔ the verdict heard while a 'building' write still waits its turn: the 'building' is never written (0.524328ms) ✔ a start heard after the verdict writes nothing (0.555609ms) ✔ a start from before the check now pending (a run before a recheck, the stream's history) writes nothing (0.489898ms) ✔ an old run's verdict redelivered after a recheck's pending is not written over it (0.942374ms) [gitea] novox/hq@a6b08de8: the verdict of build-1791680941000000000 is an older run's than the check the forge holds pending; not written [gitea] novox/hq@a6b08de8: the verdict of build-1791680941000000000 is an older run's than the check now pending; not written ✔ an old run's verdict in flight when the recheck comes lands before the recheck's pending (1.848577ms) ✔ a rechecked head says where its new run is: building on which machine (1.023515ms) ✔ the recheck's own verdict is written, even asked a little before the pending by another machine's clock (0.68576ms) ✔ after a restart, an old run's verdict is weighed against the check the forge's history holds open (0.568289ms) ✔ a recheck the forge does not take fails its caller, and the head is as it was (0.446007ms) ✔ the status tool writes the merge check's pending through the writer, and the mesh's other statuses as they were (5.258618ms) ✔ when a check was asked is read from its id; the opening of the check now pending from the gate's history (0.263264ms) ✔ a head this process did not announce (it restarted) is said only while the forge holds its gate pending (0.394216ms) ✔ a repository as the mesh clones it is told from another (0.292185ms) ✔ gitea_api refuses the forge's administration, a branch's protection and the merge check's status, and sends nothing (5.769777ms) ✔ gitea_api refuses a file written to the default branch or one a rule guards, and writes one on a branch of its own (53.139544ms) ✔ a protection rule covers a branch as the forge decides it: classes, alternatives, a plain name in any case (issue 539) (15.774316ms) ✔ gitea_api still writes what an author writes (7.569293ms) ✔ gitea_branch_protection_set only strengthens (17.509412ms) ✔ gitea_merge_pull_request merges only a head whose required statuses all succeeded, and only that head (48.370943ms) ✔ gitea_merge_pull_request refuses a verdict judged against an earlier trunk, and asks the check once (156.738783ms) ✔ gitea_merge_pull_request merges only the head it is named, and refuses one that is not the head (16.943593ms) ✔ gitea_merge_pull_request is loud when the forge merged a head other than the one it was handed (13.667834ms) ✔ gitea_merge_pull_request says the merge happened when reading back what landed fails (25.538642ms) ✔ gitea_merge_pull_request reads back a fast-forward, and says it cannot read back a squash or a rebase (60.305431ms) ✔ gitea_delete_repo deletes only the tools' own user's repository, unguarded, untouched for 30 days, named in full (22.044169ms) ✔ gitea_api sends the path it judged, and refuses moving a pull request's base (3.834837ms) ✔ gitea_merge_pull_request merges only into a branch whose protection requires the checks (8.168802ms) ✔ a rule named for a branch is not made weaker than the glob rule that guards it now (12.919533ms) ✔ a repository owner or name is never another path (0.500807ms) ✔ the judges, without a forge (0.380636ms) ✔ gitea_api never acts as another user: sudo, in any case, and any query key it does not send are refused (1.602254ms) ✔ gitea_api never approves a pull request nor requests changes: those are the operator's (2.493657ms) ✔ no tool's caller text becomes another path or another user: `..` and `?sudo=` are refused before the forge (5.4017ms) ✔ every page of a pull request's files is read, though the forge caps a page at fifty (28.72003ms) ✔ a pass asks only the repositories that moved since the last look, every one before the first (0.457147ms) ✔ the directories above a merge's files that hold a module at the commit are said, the root never (14.239133ms) ✔ a lookup the forge refuses is thrown, not read as no module (4.67215ms) ✔ a renamed file is said under its old name too, as gone (novox/hq ADR 0267) (5.859357ms) ✔ a new head beyond the newest 20 open pull requests is announced, exactly once (48.905381ms) ✔ a pass pages until it reaches back past its floor, and no further (24.552257ms) ✔ the statuses asked for replace the rule's, and an empty list requires none (8.66208ms) ✔ a new rule refuses direct pushes unless asked; an administrator's override only when said (0.391575ms) ✔ each open pull request's new head is announced once, and nothing closed or merged (11.916259ms) ✔ a verdict is the head commit's status; an error is the forge's error, never a success (1.063506ms) ✔ each layer is its own status: the gate with the modules it judged, the repository's own check beside it (0.831542ms) ✔ no verdict sets warning on a required check; only a person's decision fails (1.141767ms) ✔ a commit status is set on the commit, under the merge check's context (33.748555ms) ✔ a change plan is the gate's result: said on the status and, when it builds something, as a comment (0.501667ms) ✔ a head announced is pending in the build queue, since the local time it was announced (0.253524ms) ✔ the vault's token is used, a setting of it is ignored and said once, without its value (2.388556ms) ✔ a consumer that asks nothing, or write, publishes: the package team (1.261809ms) ✔ a consumer that asks to read joins the readers, who write no package (0.398445ms) ✔ a reader is made, put on the readers team, and taken off the package team (0.428807ms) ✔ a publisher is made and put on the package team, as before (0.180243ms) ✔ first start: mints with the admin account, keeps the token at 0600, asks for the tools' scopes only (32.451485ms) ✔ second start: reuses the kept token, mints nothing (16.457226ms) ✔ the forge rejects the kept token (its data was restored): minted afresh, once, and the call goes through (20.73962ms) ✔ a token kept with write:admin by an earlier build is minted again without it at the next start, and the forge drops the old one (24.602638ms) ✔ a kept token lacking a scope the tools need: the forge refuses the call for the scope, the token is re-minted with the whole list, and the call goes through (18.769061ms) ✔ the kept file is gone but the forge still holds a token by that name: replaced, not refused (17.218017ms) ✔ concurrent first calls share one mint (10.855093ms) ✔ the admin account is refused: said plainly, nothing kept, and the next call fails the same way rather than crashing (12.143612ms) ✔ one process shares one source per kept file — the watcher and the tools never renew against each other (0.964765ms) ✔ a second process finds the token the first renewed, and reuses it instead of minting over it (18.147252ms) ✔ a configured token wins, and is reported rather than minted over when the forge rejects it (2.397886ms) ✔ nothing to mint with and no token: the client says what is missing (0.192003ms) [gitea] no tools — no Gitea token, and nothing to mint one with — set MESH_GITEA_TOKEN, or MESH_GITEA_ADMIN_USER, MESH_GITEA_ADMIN_PASSWORD_FILE, MESH_GITEA_STATE_DIR [gitea] no token kept — minting one [gitea] the forge already holds a token named "mesh-tools" — replacing it [gitea] minted a token for "mesh-admin" (write:repository, write:issue, read:user), kept at /tmp/gitea-r3bn2R/state/token ✔ the tools register once there is a way to a token, and the first call mints it (8.531367ms) [gitea] no token kept — minting one [gitea] the forge already holds a token named "mesh-tools" — replacing it [gitea] minted a token for "mesh-admin" (write:repository, write:issue, read:user), kept at /tmp/gitea-kRdu0x/state/token ✔ a pull request can be closed, read and cleaned up through the tools (18.269073ms) [gitea] novox/mesh-host's main moved from a2c2c35bbbbb to d28ca95ccccc: 25 open pull request(s) into it put out of date, nothing run (novox/hq ADR 0323) [gitea] novox/mesh-host's main moved from d28ca95ccccc to ffffffffffff: 0 open pull request(s) into it put out of date, nothing run (novox/hq ADR 0323) [gitea] novox/mesh-host: whether a trunk moved could not be weighed, so it is weighed again on the next pass — the forge is away [gitea] novox/mesh-host's main moved from a2c2c35bbbbb to d28ca95ccccc: 0 open pull request(s) into it put out of date, nothing run (novox/hq ADR 0323) ✔ both statuses say the head and the trunk commit the verdict judged, first, whatever the summary's length (1.774196ms) ✔ a trunk's move puts an open head's merge check out of date, naming both commits, unless a check is on its way (1.236308ms) ✔ a push to a trunk puts every open pull request into it out of date — twenty-five of them — and none into another (4.291385ms) ✔ a trunk that cannot be read is weighed again on the next pass, never recorded half (0.448167ms) ✔ the trunk's move takes its turn after a verdict in flight, and weighs what the forge holds then (0.453847ms) ✔ a verdict judged against a trunk newer than the pass's first read is not put out of date (0.297284ms) ✔ a verdict that landed out of date keeps its account on the pull request (0.253383ms) ℹ tests 89 ℹ suites 0 ℹ pass 89 ℹ fail 0 ℹ cancelled 0 ℹ skipped 0 ℹ todo 0 ℹ duration_ms 670.764157 type-checking modules/nextcloud (TypeScript) testing modules/nextcloud (TypeScript) ✔ the vault's password is used, a setting of it is ignored and said once, without its value (1.924758ms) ℹ tests 1 ℹ suites 0 ℹ pass 1 ℹ fail 0 ℹ cancelled 0 ℹ skipped 0 ℹ todo 0 ℹ duration_ms 108.314069 type-checking modules/umami (TypeScript) NOT TESTED: modules/umami is TypeScript and has no tests of its own ```
Author
Contributor

Merge check at b62bb158
Judged: head b62bb158398d merged into trunk ebf7f3773dc7; read beside it: mesh-controller 2959c8143536, mesh-controller-main 2959c8143536, 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: gitea, mesh-knowledge, n8n, nextcloud, umami)
  • 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 gitea, mesh-knowledge, n8n, nextcloud, umami → ace, novox; no bus step

  • tier 0: gitea, mesh-knowledge, n8n, nextcloud, umami
  • ace: receives n8n
  • novox: receives gitea, mesh-knowledge, nextcloud, umami
  • gitea provides npm-package-registry, git: its consumers are sent again after it
  • gitea keeps data (ADR 0233): what it holds is backed up before it moves
  • n8n keeps data (ADR 0233): what it holds is backed up before it moves
  • nextcloud keeps data (ADR 0233): what it holds is backed up before it moves
  • umami provides analytics: its consumers are sent again after it
  • umami keeps data (ADR 0233): what it holds is backed up before it moves
  • grants step: if this changes what the bus's user list says (a new tool, subject or user), novox is sent that list alone, every build there kept, before n8n is judged on its first machine
  • read by no module's build: health-undeclared, modules/mesh-knowledge/cmd/mesh-knowledge/manifest_test.go

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

--- the gate: gitea, mesh-knowledge, n8n, nextcloud, umami
note: mesh-knowledge uses the seat "operator-channel", which no module declares and the mesh does not define among the manifests given; registration judges it against the whole catalogue, and passing the declaring module's manifest too judges it here
gitea: ok, keeps data (valuable), ready: server by http /api/healthz on web expecting 200 every 30s
mesh-knowledge: ok, 2 tool(s), invokes seat:issue-tracker.reserve, claude-code.claude_code_judge, claude-code.claude_code_judged, records.records_status, records.records_list, records.records_read, seat:operator-channel.notify, ready: keep by unit every 30s; watch by its tool knowledge_health every 1m0s
n8n: ok, keeps data (valuable), cache (cache), ready: server by http /healthz/readiness on web expecting 200 every 30s; WARNING: cache-server, browser stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
nextcloud: ok, keeps html (valuable), ready: server by http /status.php on web expecting 200 every 30s
umami: ok, ready: server by http /api/share/mesh-health on web expecting 404 every 30s
long-running resources without health: 2
files asking for a setting without saying whether it is trusted: 0
5 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here
judging 5 module(s) changed against 4 machine(s), as the snapshot of 2026-10-14T01:31:20Z 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-14T01:31:20Z

modules the change moves:
  - gitea (changed)
  - mesh-knowledge (changed)
  - n8n (changed)
  - nextcloud (changed)
  - umami (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 5 module(s) in 1 tier(s): gitea, mesh-knowledge, n8n, nextcloud, umami

notes:
  - health-undeclared and modules/mesh-knowledge/cmd/mesh-knowledge/manifest_test.go read by no module's build, and rebuild nothing (issue 280)
--- its merge-check.sh (go toolchain)
ok  	git.novox.be/novox/mesh-catalog/checks/words	0.002s
words: 12 retired words and 70 daemons' lines, none in the 46786 strings of 718 files
ok  	git.novox.be/novox/mesh-catalog/checks/agenthome	0.012s
agent-home: no archive and no file written into under the agent's home
ok  	git.novox.be/novox/mesh-catalog/checks/secrets	0.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.207s
testing modules/gitea
ok  	gitea/cmd/forge	1.486s
ok  	gitea/cmd/npm-registry	1.847s
?   	gitea/internal/forgehttp	[no test files]
testing modules/mesh-knowledge
ok  	mesh-knowledge/cmd/mesh-knowledge	128.449s
modules/nextcloud is TypeScript: merge-check-typescript.sh type-checks and tests it
modules/umami is TypeScript: merge-check-typescript.sh type-checks and tests it
--- its merge-check-typescript.sh (typescript toolchain)
type-checking modules/gitea (TypeScript)
testing modules/gitea (TypeScript)
✔ a pull request opened after the margin is looked at, by its own update time (9.45446ms)
✔ every open pull request is read with what its base requires and what its head has (gitea_open_pulls) (51.225994ms)
✔ a pull request or issue number that is not one is refused before the forge is asked (1.251628ms)
✔ a merged pull request whose branch was deleted is announced with its branch, not its pull ref (9.760114ms)
✔ the newest status of each context is kept, with what it said, when and by whom (19.652369ms)
✔ a commit merges only when every required status is a success; a warning blocks (0.70368ms)
✔ no rule requires nothing; a rule that cannot be read says nothing, never yes (0.324835ms)
✔ a commit is contained in another when the compare finds nothing on it the other lacks (0.929664ms)
✔ a note line is appended once, as the forge's user, in its own repository (9.105124ms)
✔ a note that cannot be written is said, never read as written (0.447977ms)
✔ one view per pull request, found by its marker; only the mesh's statuses (0.866962ms)
✔ a build machine taking the check is said on the head: building on which machine, since the local time (16.574704ms)
✔ the verdict heard while a 'building' write is in flight lands last and stays (7.239927ms)
[gitea] novox/hq@a6b08de8: the verdict of build-1791680941000000000 is an older run's than the check now pending; not written
✔ the verdict written while a start's read of the forge is in flight stays the newest status (1.095556ms)
✔ the verdict heard while a 'building' write still waits its turn: the 'building' is never written (0.578219ms)
✔ a start heard after the verdict writes nothing (0.615729ms)
✔ a start from before the check now pending (a run before a recheck, the stream's history) writes nothing (0.62567ms)
✔ an old run's verdict redelivered after a recheck's pending is not written over it (0.999825ms)
[gitea] novox/hq@a6b08de8: the verdict of build-1791680941000000000 is an older run's than the check the forge holds pending; not written
[gitea] novox/hq@a6b08de8: the verdict of build-1791680941000000000 is an older run's than the check now pending; not written
✔ an old run's verdict in flight when the recheck comes lands before the recheck's pending (2.72123ms)
✔ a rechecked head says where its new run is: building on which machine (1.026325ms)
✔ the recheck's own verdict is written, even asked a little before the pending by another machine's clock (0.804632ms)
✔ after a restart, an old run's verdict is weighed against the check the forge's history holds open (0.604429ms)
✔ a recheck the forge does not take fails its caller, and the head is as it was (0.64871ms)
✔ the status tool writes the merge check's pending through the writer, and the mesh's other statuses as they were (6.291593ms)
✔ when a check was asked is read from its id; the opening of the check now pending from the gate's history (1.556713ms)
✔ a head this process did not announce (it restarted) is said only while the forge holds its gate pending (0.410616ms)
✔ a repository as the mesh clones it is told from another (0.268924ms)
✔ gitea_api refuses the forge's administration, a branch's protection and the merge check's status, and sends nothing (6.867671ms)
✔ gitea_api refuses a file written to the default branch or one a rule guards, and writes one on a branch of its own (48.16154ms)
✔ a protection rule covers a branch as the forge decides it: classes, alternatives, a plain name in any case (issue 539) (16.826728ms)
✔ gitea_api still writes what an author writes (6.780229ms)
✔ gitea_branch_protection_set only strengthens (15.018322ms)
✔ gitea_merge_pull_request merges only a head whose required statuses all succeeded, and only that head (45.252386ms)
✔ gitea_merge_pull_request refuses a verdict judged against an earlier trunk, and asks the check once (143.20375ms)
✔ gitea_merge_pull_request merges only the head it is named, and refuses one that is not the head (17.458448ms)
✔ gitea_merge_pull_request is loud when the forge merged a head other than the one it was handed (12.749717ms)
✔ gitea_merge_pull_request says the merge happened when reading back what landed fails (25.324823ms)
✔ gitea_merge_pull_request reads back a fast-forward, and says it cannot read back a squash or a rebase (50.824019ms)
✔ gitea_delete_repo deletes only the tools' own user's repository, unguarded, untouched for 30 days, named in full (20.050575ms)
✔ gitea_api sends the path it judged, and refuses moving a pull request's base (4.143091ms)
✔ gitea_merge_pull_request merges only into a branch whose protection requires the checks (6.74434ms)
✔ a rule named for a branch is not made weaker than the glob rule that guards it now (12.471444ms)
✔ a repository owner or name is never another path (0.226513ms)
✔ the judges, without a forge (0.355075ms)
✔ gitea_api never acts as another user: sudo, in any case, and any query key it does not send are refused (2.481786ms)
✔ gitea_api never approves a pull request nor requests changes: those are the operator's (2.236723ms)
✔ no tool's caller text becomes another path or another user: `..` and `?sudo=` are refused before the forge (4.845372ms)
✔ every page of a pull request's files is read, though the forge caps a page at fifty (27.690548ms)
✔ a pass asks only the repositories that moved since the last look, every one before the first (0.446436ms)
✔ the directories above a merge's files that hold a module at the commit are said, the root never (12.154699ms)
✔ a lookup the forge refuses is thrown, not read as no module (3.828596ms)
✔ a renamed file is said under its old name too, as gone (novox/hq ADR 0267) (4.876822ms)
✔ a new head beyond the newest 20 open pull requests is announced, exactly once (49.677532ms)
✔ a pass pages until it reaches back past its floor, and no further (22.690975ms)
✔ the statuses asked for replace the rule's, and an empty list requires none (7.108674ms)
✔ a new rule refuses direct pushes unless asked; an administrator's override only when said (0.350855ms)
✔ each open pull request's new head is announced once, and nothing closed or merged (10.346302ms)
✔ a verdict is the head commit's status; an error is the forge's error, never a success (1.057446ms)
✔ each layer is its own status: the gate with the modules it judged, the repository's own check beside it (0.764502ms)
✔ no verdict sets warning on a required check; only a person's decision fails (1.183038ms)
✔ a commit status is set on the commit, under the merge check's context (39.011595ms)
✔ a change plan is the gate's result: said on the status and, when it builds something, as a comment (0.649029ms)
✔ a head announced is pending in the build queue, since the local time it was announced (0.305975ms)
✔ the vault's token is used, a setting of it is ignored and said once, without its value (2.994235ms)
✔ a consumer that asks nothing, or write, publishes: the package team (1.408761ms)
✔ a consumer that asks to read joins the readers, who write no package (0.356485ms)
✔ a reader is made, put on the readers team, and taken off the package team (0.435286ms)
✔ a publisher is made and put on the package team, as before (0.240023ms)
✔ first start: mints with the admin account, keeps the token at 0600, asks for the tools' scopes only (31.731018ms)
✔ second start: reuses the kept token, mints nothing (16.744057ms)
✔ the forge rejects the kept token (its data was restored): minted afresh, once, and the call goes through (19.892033ms)
✔ a token kept with write:admin by an earlier build is minted again without it at the next start, and the forge drops the old one (23.129311ms)
✔ a kept token lacking a scope the tools need: the forge refuses the call for the scope, the token is re-minted with the whole list, and the call goes through (19.362315ms)
✔ the kept file is gone but the forge still holds a token by that name: replaced, not refused (16.128098ms)
✔ concurrent first calls share one mint (10.589276ms)
✔ the admin account is refused: said plainly, nothing kept, and the next call fails the same way rather than crashing (11.032732ms)
✔ one process shares one source per kept file — the watcher and the tools never renew against each other (0.874433ms)
✔ a second process finds the token the first renewed, and reuses it instead of minting over it (18.701335ms)
✔ a configured token wins, and is reported rather than minted over when the forge rejects it (2.331825ms)
✔ nothing to mint with and no token: the client says what is missing (0.176343ms)
[gitea] no tools — no Gitea token, and nothing to mint one with — set MESH_GITEA_TOKEN, or MESH_GITEA_ADMIN_USER, MESH_GITEA_ADMIN_PASSWORD_FILE, MESH_GITEA_STATE_DIR
[gitea] no token kept — minting one
[gitea] the forge already holds a token named "mesh-tools" — replacing it
[gitea] minted a token for "mesh-admin" (write:repository, write:issue, read:user), kept at /tmp/gitea-6HXaeZ/state/token
✔ the tools register once there is a way to a token, and the first call mints it (8.423894ms)
[gitea] no token kept — minting one
[gitea] the forge already holds a token named "mesh-tools" — replacing it
[gitea] minted a token for "mesh-admin" (write:repository, write:issue, read:user), kept at /tmp/gitea-lv6JdY/state/token
✔ a pull request can be closed, read and cleaned up through the tools (18.751936ms)
[gitea] novox/mesh-host's main moved from a2c2c35bbbbb to d28ca95ccccc: 25 open pull request(s) into it put out of date, nothing run (novox/hq ADR 0323)
[gitea] novox/mesh-host's main moved from d28ca95ccccc to ffffffffffff: 0 open pull request(s) into it put out of date, nothing run (novox/hq ADR 0323)
[gitea] novox/mesh-host: whether a trunk moved could not be weighed, so it is weighed again on the next pass — the forge is away
[gitea] novox/mesh-host's main moved from a2c2c35bbbbb to d28ca95ccccc: 0 open pull request(s) into it put out of date, nothing run (novox/hq ADR 0323)
✔ both statuses say the head and the trunk commit the verdict judged, first, whatever the summary's length (1.510792ms)
✔ a trunk's move puts an open head's merge check out of date, naming both commits, unless a check is on its way (1.025315ms)
✔ a push to a trunk puts every open pull request into it out of date — twenty-five of them — and none into another (4.055079ms)
✔ a trunk that cannot be read is weighed again on the next pass, never recorded half (0.352686ms)
✔ the trunk's move takes its turn after a verdict in flight, and weighs what the forge holds then (0.417416ms)
✔ a verdict judged against a trunk newer than the pass's first read is not put out of date (0.237744ms)
✔ a verdict that landed out of date keeps its account on the pull request (0.236844ms)
ℹ tests 89
ℹ suites 0
ℹ pass 89
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 624.726546
type-checking modules/nextcloud (TypeScript)
testing modules/nextcloud (TypeScript)
✔ the vault's password is used, a setting of it is ignored and said once, without its value (1.908059ms)
ℹ tests 1
ℹ suites 0
ℹ pass 1
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 87.682842
type-checking modules/umami (TypeScript)
NOT TESTED: modules/umami is TypeScript and has no tests of its own
**Merge check** at `b62bb158` Judged: head `b62bb158398d` merged into trunk `ebf7f3773dc7`; read beside it: mesh-controller `2959c8143536`, mesh-controller-main `2959c8143536`, 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: gitea, mesh-knowledge, n8n, nextcloud, umami) - `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 gitea, mesh-knowledge, n8n, nextcloud, umami → ace, novox; no bus step - tier 0: gitea, mesh-knowledge, n8n, nextcloud, umami - ace: receives n8n - novox: receives gitea, mesh-knowledge, nextcloud, umami - gitea provides npm-package-registry, git: its consumers are sent again after it - gitea keeps data (ADR 0233): what it holds is backed up before it moves - n8n keeps data (ADR 0233): what it holds is backed up before it moves - nextcloud keeps data (ADR 0233): what it holds is backed up before it moves - umami provides analytics: its consumers are sent again after it - umami keeps data (ADR 0233): what it holds is backed up before it moves - grants step: if this changes what the bus's user list says (a new tool, subject or user), novox is sent that list alone, every build there kept, before n8n is judged on its first machine - read by no module's build: health-undeclared, modules/mesh-knowledge/cmd/mesh-knowledge/manifest_test.go Run by the build seat on shanks as `build-1791941744946167344` (`builds --log build-1791941744946167344`). ``` --- the gate: gitea, mesh-knowledge, n8n, nextcloud, umami note: mesh-knowledge uses the seat "operator-channel", which no module declares and the mesh does not define among the manifests given; registration judges it against the whole catalogue, and passing the declaring module's manifest too judges it here gitea: ok, keeps data (valuable), ready: server by http /api/healthz on web expecting 200 every 30s mesh-knowledge: ok, 2 tool(s), invokes seat:issue-tracker.reserve, claude-code.claude_code_judge, claude-code.claude_code_judged, records.records_status, records.records_list, records.records_read, seat:operator-channel.notify, ready: keep by unit every 30s; watch by its tool knowledge_health every 1m0s n8n: ok, keeps data (valuable), cache (cache), ready: server by http /healthz/readiness on web expecting 200 every 30s; WARNING: cache-server, browser stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) nextcloud: ok, keeps html (valuable), ready: server by http /status.php on web expecting 200 every 30s umami: ok, ready: server by http /api/share/mesh-health on web expecting 404 every 30s long-running resources without health: 2 files asking for a setting without saying whether it is trusted: 0 5 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here judging 5 module(s) changed against 4 machine(s), as the snapshot of 2026-10-14T01:31:20Z 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-14T01:31:20Z modules the change moves: - gitea (changed) - mesh-knowledge (changed) - n8n (changed) - nextcloud (changed) - umami (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 5 module(s) in 1 tier(s): gitea, mesh-knowledge, n8n, nextcloud, umami notes: - health-undeclared and modules/mesh-knowledge/cmd/mesh-knowledge/manifest_test.go read by no module's build, and rebuild nothing (issue 280) --- its merge-check.sh (go toolchain) ok git.novox.be/novox/mesh-catalog/checks/words 0.002s words: 12 retired words and 70 daemons' lines, none in the 46786 strings of 718 files ok git.novox.be/novox/mesh-catalog/checks/agenthome 0.012s agent-home: no archive and no file written into under the agent's home ok git.novox.be/novox/mesh-catalog/checks/secrets 0.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.207s testing modules/gitea ok gitea/cmd/forge 1.486s ok gitea/cmd/npm-registry 1.847s ? gitea/internal/forgehttp [no test files] testing modules/mesh-knowledge ok mesh-knowledge/cmd/mesh-knowledge 128.449s modules/nextcloud is TypeScript: merge-check-typescript.sh type-checks and tests it modules/umami is TypeScript: merge-check-typescript.sh type-checks and tests it --- its merge-check-typescript.sh (typescript toolchain) type-checking modules/gitea (TypeScript) testing modules/gitea (TypeScript) ✔ a pull request opened after the margin is looked at, by its own update time (9.45446ms) ✔ every open pull request is read with what its base requires and what its head has (gitea_open_pulls) (51.225994ms) ✔ a pull request or issue number that is not one is refused before the forge is asked (1.251628ms) ✔ a merged pull request whose branch was deleted is announced with its branch, not its pull ref (9.760114ms) ✔ the newest status of each context is kept, with what it said, when and by whom (19.652369ms) ✔ a commit merges only when every required status is a success; a warning blocks (0.70368ms) ✔ no rule requires nothing; a rule that cannot be read says nothing, never yes (0.324835ms) ✔ a commit is contained in another when the compare finds nothing on it the other lacks (0.929664ms) ✔ a note line is appended once, as the forge's user, in its own repository (9.105124ms) ✔ a note that cannot be written is said, never read as written (0.447977ms) ✔ one view per pull request, found by its marker; only the mesh's statuses (0.866962ms) ✔ a build machine taking the check is said on the head: building on which machine, since the local time (16.574704ms) ✔ the verdict heard while a 'building' write is in flight lands last and stays (7.239927ms) [gitea] novox/hq@a6b08de8: the verdict of build-1791680941000000000 is an older run's than the check now pending; not written ✔ the verdict written while a start's read of the forge is in flight stays the newest status (1.095556ms) ✔ the verdict heard while a 'building' write still waits its turn: the 'building' is never written (0.578219ms) ✔ a start heard after the verdict writes nothing (0.615729ms) ✔ a start from before the check now pending (a run before a recheck, the stream's history) writes nothing (0.62567ms) ✔ an old run's verdict redelivered after a recheck's pending is not written over it (0.999825ms) [gitea] novox/hq@a6b08de8: the verdict of build-1791680941000000000 is an older run's than the check the forge holds pending; not written [gitea] novox/hq@a6b08de8: the verdict of build-1791680941000000000 is an older run's than the check now pending; not written ✔ an old run's verdict in flight when the recheck comes lands before the recheck's pending (2.72123ms) ✔ a rechecked head says where its new run is: building on which machine (1.026325ms) ✔ the recheck's own verdict is written, even asked a little before the pending by another machine's clock (0.804632ms) ✔ after a restart, an old run's verdict is weighed against the check the forge's history holds open (0.604429ms) ✔ a recheck the forge does not take fails its caller, and the head is as it was (0.64871ms) ✔ the status tool writes the merge check's pending through the writer, and the mesh's other statuses as they were (6.291593ms) ✔ when a check was asked is read from its id; the opening of the check now pending from the gate's history (1.556713ms) ✔ a head this process did not announce (it restarted) is said only while the forge holds its gate pending (0.410616ms) ✔ a repository as the mesh clones it is told from another (0.268924ms) ✔ gitea_api refuses the forge's administration, a branch's protection and the merge check's status, and sends nothing (6.867671ms) ✔ gitea_api refuses a file written to the default branch or one a rule guards, and writes one on a branch of its own (48.16154ms) ✔ a protection rule covers a branch as the forge decides it: classes, alternatives, a plain name in any case (issue 539) (16.826728ms) ✔ gitea_api still writes what an author writes (6.780229ms) ✔ gitea_branch_protection_set only strengthens (15.018322ms) ✔ gitea_merge_pull_request merges only a head whose required statuses all succeeded, and only that head (45.252386ms) ✔ gitea_merge_pull_request refuses a verdict judged against an earlier trunk, and asks the check once (143.20375ms) ✔ gitea_merge_pull_request merges only the head it is named, and refuses one that is not the head (17.458448ms) ✔ gitea_merge_pull_request is loud when the forge merged a head other than the one it was handed (12.749717ms) ✔ gitea_merge_pull_request says the merge happened when reading back what landed fails (25.324823ms) ✔ gitea_merge_pull_request reads back a fast-forward, and says it cannot read back a squash or a rebase (50.824019ms) ✔ gitea_delete_repo deletes only the tools' own user's repository, unguarded, untouched for 30 days, named in full (20.050575ms) ✔ gitea_api sends the path it judged, and refuses moving a pull request's base (4.143091ms) ✔ gitea_merge_pull_request merges only into a branch whose protection requires the checks (6.74434ms) ✔ a rule named for a branch is not made weaker than the glob rule that guards it now (12.471444ms) ✔ a repository owner or name is never another path (0.226513ms) ✔ the judges, without a forge (0.355075ms) ✔ gitea_api never acts as another user: sudo, in any case, and any query key it does not send are refused (2.481786ms) ✔ gitea_api never approves a pull request nor requests changes: those are the operator's (2.236723ms) ✔ no tool's caller text becomes another path or another user: `..` and `?sudo=` are refused before the forge (4.845372ms) ✔ every page of a pull request's files is read, though the forge caps a page at fifty (27.690548ms) ✔ a pass asks only the repositories that moved since the last look, every one before the first (0.446436ms) ✔ the directories above a merge's files that hold a module at the commit are said, the root never (12.154699ms) ✔ a lookup the forge refuses is thrown, not read as no module (3.828596ms) ✔ a renamed file is said under its old name too, as gone (novox/hq ADR 0267) (4.876822ms) ✔ a new head beyond the newest 20 open pull requests is announced, exactly once (49.677532ms) ✔ a pass pages until it reaches back past its floor, and no further (22.690975ms) ✔ the statuses asked for replace the rule's, and an empty list requires none (7.108674ms) ✔ a new rule refuses direct pushes unless asked; an administrator's override only when said (0.350855ms) ✔ each open pull request's new head is announced once, and nothing closed or merged (10.346302ms) ✔ a verdict is the head commit's status; an error is the forge's error, never a success (1.057446ms) ✔ each layer is its own status: the gate with the modules it judged, the repository's own check beside it (0.764502ms) ✔ no verdict sets warning on a required check; only a person's decision fails (1.183038ms) ✔ a commit status is set on the commit, under the merge check's context (39.011595ms) ✔ a change plan is the gate's result: said on the status and, when it builds something, as a comment (0.649029ms) ✔ a head announced is pending in the build queue, since the local time it was announced (0.305975ms) ✔ the vault's token is used, a setting of it is ignored and said once, without its value (2.994235ms) ✔ a consumer that asks nothing, or write, publishes: the package team (1.408761ms) ✔ a consumer that asks to read joins the readers, who write no package (0.356485ms) ✔ a reader is made, put on the readers team, and taken off the package team (0.435286ms) ✔ a publisher is made and put on the package team, as before (0.240023ms) ✔ first start: mints with the admin account, keeps the token at 0600, asks for the tools' scopes only (31.731018ms) ✔ second start: reuses the kept token, mints nothing (16.744057ms) ✔ the forge rejects the kept token (its data was restored): minted afresh, once, and the call goes through (19.892033ms) ✔ a token kept with write:admin by an earlier build is minted again without it at the next start, and the forge drops the old one (23.129311ms) ✔ a kept token lacking a scope the tools need: the forge refuses the call for the scope, the token is re-minted with the whole list, and the call goes through (19.362315ms) ✔ the kept file is gone but the forge still holds a token by that name: replaced, not refused (16.128098ms) ✔ concurrent first calls share one mint (10.589276ms) ✔ the admin account is refused: said plainly, nothing kept, and the next call fails the same way rather than crashing (11.032732ms) ✔ one process shares one source per kept file — the watcher and the tools never renew against each other (0.874433ms) ✔ a second process finds the token the first renewed, and reuses it instead of minting over it (18.701335ms) ✔ a configured token wins, and is reported rather than minted over when the forge rejects it (2.331825ms) ✔ nothing to mint with and no token: the client says what is missing (0.176343ms) [gitea] no tools — no Gitea token, and nothing to mint one with — set MESH_GITEA_TOKEN, or MESH_GITEA_ADMIN_USER, MESH_GITEA_ADMIN_PASSWORD_FILE, MESH_GITEA_STATE_DIR [gitea] no token kept — minting one [gitea] the forge already holds a token named "mesh-tools" — replacing it [gitea] minted a token for "mesh-admin" (write:repository, write:issue, read:user), kept at /tmp/gitea-6HXaeZ/state/token ✔ the tools register once there is a way to a token, and the first call mints it (8.423894ms) [gitea] no token kept — minting one [gitea] the forge already holds a token named "mesh-tools" — replacing it [gitea] minted a token for "mesh-admin" (write:repository, write:issue, read:user), kept at /tmp/gitea-lv6JdY/state/token ✔ a pull request can be closed, read and cleaned up through the tools (18.751936ms) [gitea] novox/mesh-host's main moved from a2c2c35bbbbb to d28ca95ccccc: 25 open pull request(s) into it put out of date, nothing run (novox/hq ADR 0323) [gitea] novox/mesh-host's main moved from d28ca95ccccc to ffffffffffff: 0 open pull request(s) into it put out of date, nothing run (novox/hq ADR 0323) [gitea] novox/mesh-host: whether a trunk moved could not be weighed, so it is weighed again on the next pass — the forge is away [gitea] novox/mesh-host's main moved from a2c2c35bbbbb to d28ca95ccccc: 0 open pull request(s) into it put out of date, nothing run (novox/hq ADR 0323) ✔ both statuses say the head and the trunk commit the verdict judged, first, whatever the summary's length (1.510792ms) ✔ a trunk's move puts an open head's merge check out of date, naming both commits, unless a check is on its way (1.025315ms) ✔ a push to a trunk puts every open pull request into it out of date — twenty-five of them — and none into another (4.055079ms) ✔ a trunk that cannot be read is weighed again on the next pass, never recorded half (0.352686ms) ✔ the trunk's move takes its turn after a verdict in flight, and weighs what the forge holds then (0.417416ms) ✔ a verdict judged against a trunk newer than the pass's first read is not put out of date (0.237744ms) ✔ a verdict that landed out of date keeps its account on the pull request (0.236844ms) ℹ tests 89 ℹ suites 0 ℹ pass 89 ℹ fail 0 ℹ cancelled 0 ℹ skipped 0 ℹ todo 0 ℹ duration_ms 624.726546 type-checking modules/nextcloud (TypeScript) testing modules/nextcloud (TypeScript) ✔ the vault's password is used, a setting of it is ignored and said once, without its value (1.908059ms) ℹ tests 1 ℹ suites 0 ℹ pass 1 ℹ fail 0 ℹ cancelled 0 ℹ skipped 0 ℹ todo 0 ℹ duration_ms 87.682842 type-checking modules/umami (TypeScript) NOT TESTED: modules/umami is TypeScript and has no tests of its own ```
mesh-admin left a comment
Author
Contributor

Verdict: changes needed at b62bb15839 (one small one): umami's check passes on any 404, so it can pass silently; also mesh/delivery-group is still red from 01:31.

Independent review for issue 145 (a machine reads healthy while its modules cannot reach each other), part E.

Checks at this head: mesh/merge-gate success ("PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: gitea, mesh-knowledge, n8n, nextcloud, umami)"), mesh/repo-check success ("PASS — its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)"), mesh/delivery success ("ready: waits for its merge"), mesh/delivery-group FAILURE, set 01:31:20 ("rejected: composed together: the check could not run: the facts snapshot cannot be read ... cannot reach the artifact store at novox.internal:5100 ... connection refused"). The artifact store answers now (200 at 05:04 from novox and shanks), but nobody has asked the composed check again.

Each check, and whether it exercises the database:

  1. gitea /api/healthz 200: sound. Gitea's health endpoint pings the database and fails when it cannot.
  2. n8n /healthz/readiness 200: sound. n8n's readiness answers 200 only while its database connection is up and migrated.
  3. mesh-knowledge's watch: sound. Its tool's verdict is whether the database serves, and the manifest test holds it to needs: postgres-database.
  4. nextcloud /status.php 200 with body "installed":true: probably sound, not proven. status.php boots lib/base.php, and I expect that to read app config from the database and answer 500 when it cannot, as the PR says. But neither the PR nor I showed status.php failing with the database down: the live read only shows it answering 200 while the database works. Please prove it once in a bed, or point to where base.php queries the database on that path.
  5. umami /api/share/mesh-health expecting 404: not sound as written. The PR's own reading says an unknown route on that port is also a 404 (an HTML page). So if the share route goes away or moves in a later image, the check passes forever whatever the database does: a silent pass, the worst kind. It holds only for the pinned digest. Fix: add a body match on the share route's JSON 404 (health already supports body, as nextcloud's check uses), so the 404 HTML page fails the check. That makes it sound.

Can a failing new check block a rollout wrongly? While postgres itself is unhealthy, no: the consumers' findings are held and their gates wait (mesh-controller provider_hold.go, tested). A wrong check beside a healthy provider would fail its own gate and stop the walk carrying these five modules. That is the one risk, and the live readings of each endpoint keep it low. Declaring an http check recreates no container, so a rollback costs little. Note that once #319 is in, the gate waits on an unhealthy provider for as long as it stays unhealthy.

Merge order: mesh-controller #319 first (after: mesh-controller), then this one, once the umami body match is in and the composed check has been asked again and is green.

Reviewed by an independent reviewer on g14; nothing was run against the live modules beyond reading the artifact store's port.

Verdict: changes needed at b62bb158398d (one small one): umami's check passes on any 404, so it can pass silently; also mesh/delivery-group is still red from 01:31. Independent review for issue 145 (a machine reads healthy while its modules cannot reach each other), part E. Checks at this head: mesh/merge-gate success ("PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: gitea, mesh-knowledge, n8n, nextcloud, umami)"), mesh/repo-check success ("PASS — its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)"), mesh/delivery success ("ready: waits for its merge"), mesh/delivery-group FAILURE, set 01:31:20 ("rejected: composed together: the check could not run: the facts snapshot cannot be read ... cannot reach the artifact store at novox.internal:5100 ... connection refused"). The artifact store answers now (200 at 05:04 from novox and shanks), but nobody has asked the composed check again. Each check, and whether it exercises the database: 1. gitea `/api/healthz` 200: sound. Gitea's health endpoint pings the database and fails when it cannot. 2. n8n `/healthz/readiness` 200: sound. n8n's readiness answers 200 only while its database connection is up and migrated. 3. mesh-knowledge's watch: sound. Its tool's verdict is whether the database serves, and the manifest test holds it to `needs: postgres-database`. 4. nextcloud `/status.php` 200 with body `"installed":true`: probably sound, not proven. status.php boots lib/base.php, and I expect that to read app config from the database and answer 500 when it cannot, as the PR says. But neither the PR nor I showed status.php failing with the database down: the live read only shows it answering 200 while the database works. Please prove it once in a bed, or point to where base.php queries the database on that path. 5. umami `/api/share/mesh-health` expecting 404: not sound as written. The PR's own reading says an unknown route on that port is also a 404 (an HTML page). So if the share route goes away or moves in a later image, the check passes forever whatever the database does: a silent pass, the worst kind. It holds only for the pinned digest. Fix: add a `body` match on the share route's JSON 404 (health already supports `body`, as nextcloud's check uses), so the 404 HTML page fails the check. That makes it sound. Can a failing new check block a rollout wrongly? While postgres itself is unhealthy, no: the consumers' findings are held and their gates wait (mesh-controller provider_hold.go, tested). A wrong check beside a healthy provider would fail its own gate and stop the walk carrying these five modules. That is the one risk, and the live readings of each endpoint keep it low. Declaring an http check recreates no container, so a rollback costs little. Note that once #319 is in, the gate waits on an unhealthy provider for as long as it stays unhealthy. Merge order: mesh-controller #319 first (after: mesh-controller), then this one, once the umami body match is in and the composed check has been asked again and is green. Reviewed by an independent reviewer on g14; nothing was run against the live modules beyond reading the artifact store's port.
jschoubben added 1 commit 2026-10-14 05:07:14 +00:00
Hold umami's check to the share route's own 404, so an unknown route cannot pass it (hq issue 145, review 262)
mesh/merge-gate head 2bb5d344f6f1 merged into trunk af5cf53a3450 — pass: builds gitea, mesh-knowledge, n8n, nextcloud, umami → ace, novox; no bus step; eve…
mesh/repo-check head 2bb5d344f6f1 merged into trunk af5cf53a3450 — pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-…
mesh/delivery covered: a later merge that contains it was delivered: novox/mesh-catalog@054dc9618ce3 (merged as b15846dd into main, walk plan-17919811644…
mesh/delivery-group group fix/145-a-consumer-is-held-under-its-provider delivered: every member is delivered
2bb5d344f6
Any route umami does not serve answers 404 too, as an HTML page. The
share route answers JSON with code not-found only after the database
was asked; with the database down it answers 500.
Author
Contributor

Merge check at 2bb5d344
Judged: head 2bb5d344f6f1 merged into trunk e846c289c878; read beside it: mesh-controller 2959c8143536, mesh-controller-main 2959c8143536, 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: gitea, mesh-knowledge, n8n, nextcloud, umami)
  • 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 gitea, mesh-knowledge, n8n, nextcloud, umami → ace, novox; no bus step

  • tier 0: gitea, mesh-knowledge, n8n, nextcloud, umami
  • ace: receives n8n
  • novox: receives gitea, mesh-knowledge, nextcloud, umami
  • gitea provides npm-package-registry, git: its consumers are sent again after it
  • gitea keeps data (ADR 0233): what it holds is backed up before it moves
  • n8n keeps data (ADR 0233): what it holds is backed up before it moves
  • nextcloud keeps data (ADR 0233): what it holds is backed up before it moves
  • umami provides analytics: its consumers are sent again after it
  • umami keeps data (ADR 0233): what it holds is backed up before it moves
  • grants step: if this changes what the bus's user list says (a new tool, subject or user), novox is sent that list alone, every build there kept, before n8n is judged on its first machine
  • read by no module's build: health-undeclared, modules/mesh-knowledge/cmd/mesh-knowledge/manifest_test.go

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

--- the gate: gitea, mesh-knowledge, n8n, nextcloud, umami
note: mesh-knowledge uses the seat "operator-channel", which no module declares and the mesh does not define among the manifests given; registration judges it against the whole catalogue, and passing the declaring module's manifest too judges it here
gitea: ok, keeps data (valuable), ready: server by http /api/healthz on web expecting 200 every 30s
mesh-knowledge: ok, 2 tool(s), invokes seat:issue-tracker.reserve, claude-code.claude_code_judge, claude-code.claude_code_judged, records.records_status, records.records_list, records.records_read, seat:operator-channel.notify, ready: keep by unit every 30s; watch by its tool knowledge_health every 1m0s
n8n: ok, keeps data (valuable), cache (cache), ready: server by http /healthz/readiness on web expecting 200 every 30s; WARNING: cache-server, browser stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
nextcloud: ok, keeps html (valuable), ready: server by http /status.php on web expecting 200 every 30s
umami: ok, ready: server by http /api/share/mesh-health on web expecting 404 every 30s
long-running resources without health: 2
files asking for a setting without saying whether it is trusted: 0
5 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here
judging 5 module(s) changed against 4 machine(s), as the snapshot of 2026-10-14T01:31:20Z 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-14T01:31:20Z

modules the change moves:
  - gitea (changed)
  - mesh-knowledge (changed)
  - n8n (changed)
  - nextcloud (changed)
  - umami (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 5 module(s) in 1 tier(s): gitea, mesh-knowledge, n8n, nextcloud, umami

notes:
  - health-undeclared and modules/mesh-knowledge/cmd/mesh-knowledge/manifest_test.go read by no module's build, and rebuild nothing (issue 280)
--- its merge-check.sh (go toolchain)
ok  	git.novox.be/novox/mesh-catalog/checks/words	0.180s
words: 12 retired words and 70 daemons' lines, none in the 46814 strings of 718 files
ok  	git.novox.be/novox/mesh-catalog/checks/agenthome	0.020s
agent-home: no archive and no file written into under the agent's home
ok  	git.novox.be/novox/mesh-catalog/checks/secrets	0.016s
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.574s
testing modules/gitea
ok  	gitea/cmd/forge	1.661s
ok  	gitea/cmd/npm-registry	2.159s
?   	gitea/internal/forgehttp	[no test files]
testing modules/mesh-knowledge
ok  	mesh-knowledge/cmd/mesh-knowledge	162.422s
modules/nextcloud is TypeScript: merge-check-typescript.sh type-checks and tests it
modules/umami is TypeScript: merge-check-typescript.sh type-checks and tests it
--- its merge-check-typescript.sh (typescript toolchain)
type-checking modules/gitea (TypeScript)
testing modules/gitea (TypeScript)
✔ a pull request opened after the margin is looked at, by its own update time (22.503476ms)
✔ every open pull request is read with what its base requires and what its head has (gitea_open_pulls) (97.229661ms)
✔ a pull request or issue number that is not one is refused before the forge is asked (5.883252ms)
✔ a merged pull request whose branch was deleted is announced with its branch, not its pull ref (44.751462ms)
✔ the newest status of each context is kept, with what it said, when and by whom (18.052107ms)
✔ a commit merges only when every required status is a success; a warning blocks (0.472881ms)
✔ no rule requires nothing; a rule that cannot be read says nothing, never yes (0.207141ms)
✔ a commit is contained in another when the compare finds nothing on it the other lacks (0.813761ms)
✔ a note line is appended once, as the forge's user, in its own repository (14.149979ms)
✔ a note that cannot be written is said, never read as written (0.549661ms)
✔ one view per pull request, found by its marker; only the mesh's statuses (0.982452ms)
✔ a build machine taking the check is said on the head: building on which machine, since the local time (54.277072ms)
✔ the verdict heard while a 'building' write is in flight lands last and stays (8.958398ms)
[gitea] novox/hq@a6b08de8: the verdict of build-1791680941000000000 is an older run's than the check now pending; not written
✔ the verdict written while a start's read of the forge is in flight stays the newest status (0.927442ms)
✔ the verdict heard while a 'building' write still waits its turn: the 'building' is never written (0.497682ms)
✔ a start heard after the verdict writes nothing (0.515601ms)
✔ a start from before the check now pending (a run before a recheck, the stream's history) writes nothing (1.112382ms)
✔ an old run's verdict redelivered after a recheck's pending is not written over it (0.890702ms)
[gitea] novox/hq@a6b08de8: the verdict of build-1791680941000000000 is an older run's than the check the forge holds pending; not written
[gitea] novox/hq@a6b08de8: the verdict of build-1791680941000000000 is an older run's than the check now pending; not written
✔ an old run's verdict in flight when the recheck comes lands before the recheck's pending (2.002114ms)
✔ a rechecked head says where its new run is: building on which machine (0.872012ms)
✔ the recheck's own verdict is written, even asked a little before the pending by another machine's clock (0.669092ms)
✔ after a restart, an old run's verdict is weighed against the check the forge's history holds open (0.563181ms)
✔ a recheck the forge does not take fails its caller, and the head is as it was (0.537341ms)
✔ the status tool writes the merge check's pending through the writer, and the mesh's other statuses as they were (12.539006ms)
✔ when a check was asked is read from its id; the opening of the check now pending from the gate's history (0.292541ms)
✔ a head this process did not announce (it restarted) is said only while the forge holds its gate pending (1.829964ms)
✔ a repository as the mesh clones it is told from another (0.29249ms)
✔ gitea_api refuses the forge's administration, a branch's protection and the merge check's status, and sends nothing (10.931593ms)
✔ gitea_api refuses a file written to the default branch or one a rule guards, and writes one on a branch of its own (104.555506ms)
✔ a protection rule covers a branch as the forge decides it: classes, alternatives, a plain name in any case (issue 539) (20.205741ms)
✔ gitea_api still writes what an author writes (7.604136ms)
✔ gitea_branch_protection_set only strengthens (17.429406ms)
✔ gitea_merge_pull_request merges only a head whose required statuses all succeeded, and only that head (53.745841ms)
✔ gitea_merge_pull_request refuses a verdict judged against an earlier trunk, and asks the check once (210.673315ms)
✔ gitea_merge_pull_request merges only the head it is named, and refuses one that is not the head (25.555433ms)
✔ gitea_merge_pull_request is loud when the forge merged a head other than the one it was handed (17.202375ms)
✔ gitea_merge_pull_request says the merge happened when reading back what landed fails (31.676585ms)
✔ gitea_merge_pull_request reads back a fast-forward, and says it cannot read back a squash or a rebase (62.309989ms)
✔ gitea_delete_repo deletes only the tools' own user's repository, unguarded, untouched for 30 days, named in full (22.207206ms)
✔ gitea_api sends the path it judged, and refuses moving a pull request's base (3.795158ms)
✔ gitea_merge_pull_request merges only into a branch whose protection requires the checks (7.851776ms)
✔ a rule named for a branch is not made weaker than the glob rule that guards it now (15.389612ms)
✔ a repository owner or name is never another path (0.281771ms)
✔ the judges, without a forge (0.344351ms)
✔ gitea_api never acts as another user: sudo, in any case, and any query key it does not send are refused (2.087164ms)
✔ gitea_api never approves a pull request nor requests changes: those are the operator's (2.694906ms)
✔ no tool's caller text becomes another path or another user: `..` and `?sudo=` are refused before the forge (5.964152ms)
✔ every page of a pull request's files is read, though the forge caps a page at fifty (43.228559ms)
✔ a pass asks only the repositories that moved since the last look, every one before the first (0.448641ms)
✔ the directories above a merge's files that hold a module at the commit are said, the root never (18.108318ms)
✔ a lookup the forge refuses is thrown, not read as no module (6.178372ms)
✔ a renamed file is said under its old name too, as gone (novox/hq ADR 0267) (10.369942ms)
✔ a new head beyond the newest 20 open pull requests is announced, exactly once (112.861933ms)
✔ a pass pages until it reaches back past its floor, and no further (48.42041ms)
✔ the statuses asked for replace the rule's, and an empty list requires none (11.084992ms)
✔ a new rule refuses direct pushes unless asked; an administrator's override only when said (2.566785ms)
✔ each open pull request's new head is announced once, and nothing closed or merged (11.163873ms)
✔ a verdict is the head commit's status; an error is the forge's error, never a success (0.996963ms)
✔ each layer is its own status: the gate with the modules it judged, the repository's own check beside it (0.748061ms)
✔ no verdict sets warning on a required check; only a person's decision fails (0.852462ms)
✔ a commit status is set on the commit, under the merge check's context (56.824467ms)
✔ a change plan is the gate's result: said on the status and, when it builds something, as a comment (0.694601ms)
✔ a head announced is pending in the build queue, since the local time it was announced (0.310921ms)
✔ the vault's token is used, a setting of it is ignored and said once, without its value (7.019124ms)
✔ a consumer that asks nothing, or write, publishes: the package team (1.652643ms)
✔ a consumer that asks to read joins the readers, who write no package (0.536191ms)
✔ a reader is made, put on the readers team, and taken off the package team (0.772991ms)
✔ a publisher is made and put on the package team, as before (0.278201ms)
✔ first start: mints with the admin account, keeps the token at 0600, asks for the tools' scopes only (46.306616ms)
✔ second start: reuses the kept token, mints nothing (22.087466ms)
✔ the forge rejects the kept token (its data was restored): minted afresh, once, and the call goes through (56.218356ms)
✔ a token kept with write:admin by an earlier build is minted again without it at the next start, and the forge drops the old one (22.780427ms)
✔ a kept token lacking a scope the tools need: the forge refuses the call for the scope, the token is re-minted with the whole list, and the call goes through (36.841206ms)
✔ the kept file is gone but the forge still holds a token by that name: replaced, not refused (32.736718ms)
✔ concurrent first calls share one mint (16.744354ms)
✔ the admin account is refused: said plainly, nothing kept, and the next call fails the same way rather than crashing (22.423266ms)
✔ one process shares one source per kept file — the watcher and the tools never renew against each other (2.023234ms)
✔ a second process finds the token the first renewed, and reuses it instead of minting over it (25.956353ms)
✔ a configured token wins, and is reported rather than minted over when the forge rejects it (7.006154ms)
✔ nothing to mint with and no token: the client says what is missing (0.294621ms)
[gitea] no tools — no Gitea token, and nothing to mint one with — set MESH_GITEA_TOKEN, or MESH_GITEA_ADMIN_USER, MESH_GITEA_ADMIN_PASSWORD_FILE, MESH_GITEA_STATE_DIR
[gitea] no token kept — minting one
[gitea] the forge already holds a token named "mesh-tools" — replacing it
[gitea] minted a token for "mesh-admin" (write:repository, write:issue, read:user), kept at /tmp/gitea-yXiKWq/state/token
✔ the tools register once there is a way to a token, and the first call mints it (15.424532ms)
[gitea] no token kept — minting one
[gitea] the forge already holds a token named "mesh-tools" — replacing it
[gitea] minted a token for "mesh-admin" (write:repository, write:issue, read:user), kept at /tmp/gitea-mONAKG/state/token
✔ a pull request can be closed, read and cleaned up through the tools (32.112136ms)
[gitea] novox/mesh-host's main moved from a2c2c35bbbbb to d28ca95ccccc: 25 open pull request(s) into it put out of date, nothing run (novox/hq ADR 0323)
[gitea] novox/mesh-host's main moved from d28ca95ccccc to ffffffffffff: 0 open pull request(s) into it put out of date, nothing run (novox/hq ADR 0323)
[gitea] novox/mesh-host: whether a trunk moved could not be weighed, so it is weighed again on the next pass — the forge is away
[gitea] novox/mesh-host's main moved from a2c2c35bbbbb to d28ca95ccccc: 0 open pull request(s) into it put out of date, nothing run (novox/hq ADR 0323)
✔ both statuses say the head and the trunk commit the verdict judged, first, whatever the summary's length (2.652006ms)
✔ a trunk's move puts an open head's merge check out of date, naming both commits, unless a check is on its way (1.282363ms)
✔ a push to a trunk puts every open pull request into it out of date — twenty-five of them — and none into another (5.20739ms)
✔ a trunk that cannot be read is weighed again on the next pass, never recorded half (0.492611ms)
✔ the trunk's move takes its turn after a verdict in flight, and weighs what the forge holds then (0.542791ms)
✔ a verdict judged against a trunk newer than the pass's first read is not put out of date (1.038882ms)
✔ a verdict that landed out of date keeps its account on the pull request (0.326461ms)
ℹ tests 89
ℹ suites 0
ℹ pass 89
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 896.796782
type-checking modules/nextcloud (TypeScript)
testing modules/nextcloud (TypeScript)
✔ the vault's password is used, a setting of it is ignored and said once, without its value (2.082904ms)
ℹ tests 1
ℹ suites 0
ℹ pass 1
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 88.536903
type-checking modules/umami (TypeScript)
NOT TESTED: modules/umami is TypeScript and has no tests of its own

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

**Merge check** at `2bb5d344` Judged: head `2bb5d344f6f1` merged into trunk `e846c289c878`; read beside it: mesh-controller `2959c8143536`, mesh-controller-main `2959c8143536`, 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: gitea, mesh-knowledge, n8n, nextcloud, umami) - `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 gitea, mesh-knowledge, n8n, nextcloud, umami → ace, novox; no bus step - tier 0: gitea, mesh-knowledge, n8n, nextcloud, umami - ace: receives n8n - novox: receives gitea, mesh-knowledge, nextcloud, umami - gitea provides npm-package-registry, git: its consumers are sent again after it - gitea keeps data (ADR 0233): what it holds is backed up before it moves - n8n keeps data (ADR 0233): what it holds is backed up before it moves - nextcloud keeps data (ADR 0233): what it holds is backed up before it moves - umami provides analytics: its consumers are sent again after it - umami keeps data (ADR 0233): what it holds is backed up before it moves - grants step: if this changes what the bus's user list says (a new tool, subject or user), novox is sent that list alone, every build there kept, before n8n is judged on its first machine - read by no module's build: health-undeclared, modules/mesh-knowledge/cmd/mesh-knowledge/manifest_test.go Run by the build seat on novox as `build-1791954439646262454` (`builds --log build-1791954439646262454`). ``` --- the gate: gitea, mesh-knowledge, n8n, nextcloud, umami note: mesh-knowledge uses the seat "operator-channel", which no module declares and the mesh does not define among the manifests given; registration judges it against the whole catalogue, and passing the declaring module's manifest too judges it here gitea: ok, keeps data (valuable), ready: server by http /api/healthz on web expecting 200 every 30s mesh-knowledge: ok, 2 tool(s), invokes seat:issue-tracker.reserve, claude-code.claude_code_judge, claude-code.claude_code_judged, records.records_status, records.records_list, records.records_read, seat:operator-channel.notify, ready: keep by unit every 30s; watch by its tool knowledge_health every 1m0s n8n: ok, keeps data (valuable), cache (cache), ready: server by http /healthz/readiness on web expecting 200 every 30s; WARNING: cache-server, browser stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) nextcloud: ok, keeps html (valuable), ready: server by http /status.php on web expecting 200 every 30s umami: ok, ready: server by http /api/share/mesh-health on web expecting 404 every 30s long-running resources without health: 2 files asking for a setting without saying whether it is trusted: 0 5 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here judging 5 module(s) changed against 4 machine(s), as the snapshot of 2026-10-14T01:31:20Z 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-14T01:31:20Z modules the change moves: - gitea (changed) - mesh-knowledge (changed) - n8n (changed) - nextcloud (changed) - umami (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 5 module(s) in 1 tier(s): gitea, mesh-knowledge, n8n, nextcloud, umami notes: - health-undeclared and modules/mesh-knowledge/cmd/mesh-knowledge/manifest_test.go read by no module's build, and rebuild nothing (issue 280) --- its merge-check.sh (go toolchain) ok git.novox.be/novox/mesh-catalog/checks/words 0.180s words: 12 retired words and 70 daemons' lines, none in the 46814 strings of 718 files ok git.novox.be/novox/mesh-catalog/checks/agenthome 0.020s agent-home: no archive and no file written into under the agent's home ok git.novox.be/novox/mesh-catalog/checks/secrets 0.016s 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.574s testing modules/gitea ok gitea/cmd/forge 1.661s ok gitea/cmd/npm-registry 2.159s ? gitea/internal/forgehttp [no test files] testing modules/mesh-knowledge ok mesh-knowledge/cmd/mesh-knowledge 162.422s modules/nextcloud is TypeScript: merge-check-typescript.sh type-checks and tests it modules/umami is TypeScript: merge-check-typescript.sh type-checks and tests it --- its merge-check-typescript.sh (typescript toolchain) type-checking modules/gitea (TypeScript) testing modules/gitea (TypeScript) ✔ a pull request opened after the margin is looked at, by its own update time (22.503476ms) ✔ every open pull request is read with what its base requires and what its head has (gitea_open_pulls) (97.229661ms) ✔ a pull request or issue number that is not one is refused before the forge is asked (5.883252ms) ✔ a merged pull request whose branch was deleted is announced with its branch, not its pull ref (44.751462ms) ✔ the newest status of each context is kept, with what it said, when and by whom (18.052107ms) ✔ a commit merges only when every required status is a success; a warning blocks (0.472881ms) ✔ no rule requires nothing; a rule that cannot be read says nothing, never yes (0.207141ms) ✔ a commit is contained in another when the compare finds nothing on it the other lacks (0.813761ms) ✔ a note line is appended once, as the forge's user, in its own repository (14.149979ms) ✔ a note that cannot be written is said, never read as written (0.549661ms) ✔ one view per pull request, found by its marker; only the mesh's statuses (0.982452ms) ✔ a build machine taking the check is said on the head: building on which machine, since the local time (54.277072ms) ✔ the verdict heard while a 'building' write is in flight lands last and stays (8.958398ms) [gitea] novox/hq@a6b08de8: the verdict of build-1791680941000000000 is an older run's than the check now pending; not written ✔ the verdict written while a start's read of the forge is in flight stays the newest status (0.927442ms) ✔ the verdict heard while a 'building' write still waits its turn: the 'building' is never written (0.497682ms) ✔ a start heard after the verdict writes nothing (0.515601ms) ✔ a start from before the check now pending (a run before a recheck, the stream's history) writes nothing (1.112382ms) ✔ an old run's verdict redelivered after a recheck's pending is not written over it (0.890702ms) [gitea] novox/hq@a6b08de8: the verdict of build-1791680941000000000 is an older run's than the check the forge holds pending; not written [gitea] novox/hq@a6b08de8: the verdict of build-1791680941000000000 is an older run's than the check now pending; not written ✔ an old run's verdict in flight when the recheck comes lands before the recheck's pending (2.002114ms) ✔ a rechecked head says where its new run is: building on which machine (0.872012ms) ✔ the recheck's own verdict is written, even asked a little before the pending by another machine's clock (0.669092ms) ✔ after a restart, an old run's verdict is weighed against the check the forge's history holds open (0.563181ms) ✔ a recheck the forge does not take fails its caller, and the head is as it was (0.537341ms) ✔ the status tool writes the merge check's pending through the writer, and the mesh's other statuses as they were (12.539006ms) ✔ when a check was asked is read from its id; the opening of the check now pending from the gate's history (0.292541ms) ✔ a head this process did not announce (it restarted) is said only while the forge holds its gate pending (1.829964ms) ✔ a repository as the mesh clones it is told from another (0.29249ms) ✔ gitea_api refuses the forge's administration, a branch's protection and the merge check's status, and sends nothing (10.931593ms) ✔ gitea_api refuses a file written to the default branch or one a rule guards, and writes one on a branch of its own (104.555506ms) ✔ a protection rule covers a branch as the forge decides it: classes, alternatives, a plain name in any case (issue 539) (20.205741ms) ✔ gitea_api still writes what an author writes (7.604136ms) ✔ gitea_branch_protection_set only strengthens (17.429406ms) ✔ gitea_merge_pull_request merges only a head whose required statuses all succeeded, and only that head (53.745841ms) ✔ gitea_merge_pull_request refuses a verdict judged against an earlier trunk, and asks the check once (210.673315ms) ✔ gitea_merge_pull_request merges only the head it is named, and refuses one that is not the head (25.555433ms) ✔ gitea_merge_pull_request is loud when the forge merged a head other than the one it was handed (17.202375ms) ✔ gitea_merge_pull_request says the merge happened when reading back what landed fails (31.676585ms) ✔ gitea_merge_pull_request reads back a fast-forward, and says it cannot read back a squash or a rebase (62.309989ms) ✔ gitea_delete_repo deletes only the tools' own user's repository, unguarded, untouched for 30 days, named in full (22.207206ms) ✔ gitea_api sends the path it judged, and refuses moving a pull request's base (3.795158ms) ✔ gitea_merge_pull_request merges only into a branch whose protection requires the checks (7.851776ms) ✔ a rule named for a branch is not made weaker than the glob rule that guards it now (15.389612ms) ✔ a repository owner or name is never another path (0.281771ms) ✔ the judges, without a forge (0.344351ms) ✔ gitea_api never acts as another user: sudo, in any case, and any query key it does not send are refused (2.087164ms) ✔ gitea_api never approves a pull request nor requests changes: those are the operator's (2.694906ms) ✔ no tool's caller text becomes another path or another user: `..` and `?sudo=` are refused before the forge (5.964152ms) ✔ every page of a pull request's files is read, though the forge caps a page at fifty (43.228559ms) ✔ a pass asks only the repositories that moved since the last look, every one before the first (0.448641ms) ✔ the directories above a merge's files that hold a module at the commit are said, the root never (18.108318ms) ✔ a lookup the forge refuses is thrown, not read as no module (6.178372ms) ✔ a renamed file is said under its old name too, as gone (novox/hq ADR 0267) (10.369942ms) ✔ a new head beyond the newest 20 open pull requests is announced, exactly once (112.861933ms) ✔ a pass pages until it reaches back past its floor, and no further (48.42041ms) ✔ the statuses asked for replace the rule's, and an empty list requires none (11.084992ms) ✔ a new rule refuses direct pushes unless asked; an administrator's override only when said (2.566785ms) ✔ each open pull request's new head is announced once, and nothing closed or merged (11.163873ms) ✔ a verdict is the head commit's status; an error is the forge's error, never a success (0.996963ms) ✔ each layer is its own status: the gate with the modules it judged, the repository's own check beside it (0.748061ms) ✔ no verdict sets warning on a required check; only a person's decision fails (0.852462ms) ✔ a commit status is set on the commit, under the merge check's context (56.824467ms) ✔ a change plan is the gate's result: said on the status and, when it builds something, as a comment (0.694601ms) ✔ a head announced is pending in the build queue, since the local time it was announced (0.310921ms) ✔ the vault's token is used, a setting of it is ignored and said once, without its value (7.019124ms) ✔ a consumer that asks nothing, or write, publishes: the package team (1.652643ms) ✔ a consumer that asks to read joins the readers, who write no package (0.536191ms) ✔ a reader is made, put on the readers team, and taken off the package team (0.772991ms) ✔ a publisher is made and put on the package team, as before (0.278201ms) ✔ first start: mints with the admin account, keeps the token at 0600, asks for the tools' scopes only (46.306616ms) ✔ second start: reuses the kept token, mints nothing (22.087466ms) ✔ the forge rejects the kept token (its data was restored): minted afresh, once, and the call goes through (56.218356ms) ✔ a token kept with write:admin by an earlier build is minted again without it at the next start, and the forge drops the old one (22.780427ms) ✔ a kept token lacking a scope the tools need: the forge refuses the call for the scope, the token is re-minted with the whole list, and the call goes through (36.841206ms) ✔ the kept file is gone but the forge still holds a token by that name: replaced, not refused (32.736718ms) ✔ concurrent first calls share one mint (16.744354ms) ✔ the admin account is refused: said plainly, nothing kept, and the next call fails the same way rather than crashing (22.423266ms) ✔ one process shares one source per kept file — the watcher and the tools never renew against each other (2.023234ms) ✔ a second process finds the token the first renewed, and reuses it instead of minting over it (25.956353ms) ✔ a configured token wins, and is reported rather than minted over when the forge rejects it (7.006154ms) ✔ nothing to mint with and no token: the client says what is missing (0.294621ms) [gitea] no tools — no Gitea token, and nothing to mint one with — set MESH_GITEA_TOKEN, or MESH_GITEA_ADMIN_USER, MESH_GITEA_ADMIN_PASSWORD_FILE, MESH_GITEA_STATE_DIR [gitea] no token kept — minting one [gitea] the forge already holds a token named "mesh-tools" — replacing it [gitea] minted a token for "mesh-admin" (write:repository, write:issue, read:user), kept at /tmp/gitea-yXiKWq/state/token ✔ the tools register once there is a way to a token, and the first call mints it (15.424532ms) [gitea] no token kept — minting one [gitea] the forge already holds a token named "mesh-tools" — replacing it [gitea] minted a token for "mesh-admin" (write:repository, write:issue, read:user), kept at /tmp/gitea-mONAKG/state/token ✔ a pull request can be closed, read and cleaned up through the tools (32.112136ms) [gitea] novox/mesh-host's main moved from a2c2c35bbbbb to d28ca95ccccc: 25 open pull request(s) into it put out of date, nothing run (novox/hq ADR 0323) [gitea] novox/mesh-host's main moved from d28ca95ccccc to ffffffffffff: 0 open pull request(s) into it put out of date, nothing run (novox/hq ADR 0323) [gitea] novox/mesh-host: whether a trunk moved could not be weighed, so it is weighed again on the next pass — the forge is away [gitea] novox/mesh-host's main moved from a2c2c35bbbbb to d28ca95ccccc: 0 open pull request(s) into it put out of date, nothing run (novox/hq ADR 0323) ✔ both statuses say the head and the trunk commit the verdict judged, first, whatever the summary's length (2.652006ms) ✔ a trunk's move puts an open head's merge check out of date, naming both commits, unless a check is on its way (1.282363ms) ✔ a push to a trunk puts every open pull request into it out of date — twenty-five of them — and none into another (5.20739ms) ✔ a trunk that cannot be read is weighed again on the next pass, never recorded half (0.492611ms) ✔ the trunk's move takes its turn after a verdict in flight, and weighs what the forge holds then (0.542791ms) ✔ a verdict judged against a trunk newer than the pass's first read is not put out of date (1.038882ms) ✔ a verdict that landed out of date keeps its account on the pull request (0.326461ms) ℹ tests 89 ℹ suites 0 ℹ pass 89 ℹ fail 0 ℹ cancelled 0 ℹ skipped 0 ℹ todo 0 ℹ duration_ms 896.796782 type-checking modules/nextcloud (TypeScript) testing modules/nextcloud (TypeScript) ✔ the vault's password is used, a setting of it is ignored and said once, without its value (2.082904ms) ℹ tests 1 ℹ suites 0 ℹ pass 1 ℹ fail 0 ℹ cancelled 0 ℹ skipped 0 ℹ todo 0 ℹ duration_ms 88.536903 type-checking modules/umami (TypeScript) NOT TESTED: modules/umami is TypeScript and has no tests of its own ``` **Out of date when it landed**: out of date: judged against trunk e846c289c878, the trunk is now af5cf53a3450; judged again on a recheck or when it is merged
Author
Contributor

Merge check at 2bb5d344
Judged: head 2bb5d344f6f1 merged into trunk af5cf53a3450; read beside it: mesh-controller 2959c8143536, mesh-controller-main 3479a35462b2, 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: gitea, mesh-knowledge, n8n, nextcloud, umami)
  • 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 gitea, mesh-knowledge, n8n, nextcloud, umami → ace, novox; no bus step

  • tier 0: gitea, mesh-knowledge, n8n, nextcloud, umami
  • ace: receives n8n
  • novox: receives gitea, mesh-knowledge, nextcloud, umami
  • gitea provides npm-package-registry, git: its consumers are sent again after it
  • gitea keeps data (ADR 0233): what it holds is backed up before it moves
  • n8n keeps data (ADR 0233): what it holds is backed up before it moves
  • nextcloud keeps data (ADR 0233): what it holds is backed up before it moves
  • umami provides analytics: its consumers are sent again after it
  • umami keeps data (ADR 0233): what it holds is backed up before it moves
  • grants step: if this changes what the bus's user list says (a new tool, subject or user), novox is sent that list alone, every build there kept, before n8n is judged on its first machine
  • read by no module's build: health-undeclared, modules/mesh-knowledge/cmd/mesh-knowledge/manifest_test.go

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

--- the gate: gitea, mesh-knowledge, n8n, nextcloud, umami
note: mesh-knowledge uses the seat "operator-channel", which no module declares and the mesh does not define among the manifests given; registration judges it against the whole catalogue, and passing the declaring module's manifest too judges it here
gitea: ok, keeps data (valuable), ready: server by http /api/healthz on web expecting 200 every 30s
mesh-knowledge: ok, 2 tool(s), invokes seat:issue-tracker.reserve, claude-code.claude_code_judge, claude-code.claude_code_judged, records.records_status, records.records_list, records.records_read, seat:operator-channel.notify, ready: keep by unit every 30s; watch by its tool knowledge_health every 1m0s
n8n: ok, keeps data (valuable), cache (cache), ready: server by http /healthz/readiness on web expecting 200 every 30s; WARNING: cache-server, browser stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
nextcloud: ok, keeps html (valuable), ready: server by http /status.php on web expecting 200 every 30s
umami: ok, ready: server by http /api/share/mesh-health on web expecting 404 every 30s
long-running resources without health: 2
files asking for a setting without saying whether it is trusted: 0
5 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here
judging 5 module(s) changed against 4 machine(s), as the snapshot of 2026-10-14T05:11:20Z 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-14T05:11:20Z

modules the change moves:
  - gitea (changed)
  - mesh-knowledge (changed)
  - n8n (changed)
  - nextcloud (changed)
  - umami (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 5 module(s) in 1 tier(s): gitea, mesh-knowledge, n8n, nextcloud, umami

notes:
  - health-undeclared and modules/mesh-knowledge/cmd/mesh-knowledge/manifest_test.go read by no module's build, and rebuild nothing (issue 280)
--- its merge-check.sh (go toolchain)
ok  	git.novox.be/novox/mesh-catalog/checks/words	0.003s
words: 12 retired words and 70 daemons' lines, none in the 46860 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.012s
secrets: no setting can replace a vault secret in a mergeable file (1 known, nested)
ok  	git.novox.be/novox/mesh-catalog/checks/paths	0.006s
paths: no module names another's state on its machine (3 known, listed to go)
long-running resources without health: 62, as kept
ok  	git.novox.be/novox/mesh-catalog/checks/deps	0.230s
testing modules/gitea
ok  	gitea/cmd/forge	1.519s
ok  	gitea/cmd/npm-registry	1.823s
?   	gitea/internal/forgehttp	[no test files]
testing modules/mesh-knowledge
ok  	mesh-knowledge/cmd/mesh-knowledge	129.071s
modules/nextcloud is TypeScript: merge-check-typescript.sh type-checks and tests it
modules/umami is TypeScript: merge-check-typescript.sh type-checks and tests it
--- its merge-check-typescript.sh (typescript toolchain)
type-checking modules/gitea (TypeScript)
testing modules/gitea (TypeScript)
✔ a pull request opened after the margin is looked at, by its own update time (20.319899ms)
✔ every open pull request is read with what its base requires and what its head has (gitea_open_pulls) (90.276687ms)
✔ a pull request or issue number that is not one is refused before the forge is asked (1.808293ms)
✔ a merged pull request whose branch was deleted is announced with its branch, not its pull ref (13.197269ms)
✔ the newest status of each context is kept, with what it said, when and by whom (21.167934ms)
✔ a commit merges only when every required status is a success; a warning blocks (0.660252ms)
✔ no rule requires nothing; a rule that cannot be read says nothing, never yes (0.293515ms)
✔ a commit is contained in another when the compare finds nothing on it the other lacks (0.884596ms)
✔ a note line is appended once, as the forge's user, in its own repository (10.925299ms)
✔ a note that cannot be written is said, never read as written (0.53907ms)
✔ one view per pull request, found by its marker; only the mesh's statuses (0.808924ms)
✔ a build machine taking the check is said on the head: building on which machine, since the local time (21.358007ms)
✔ the verdict heard while a 'building' write is in flight lands last and stays (11.348426ms)
[gitea] novox/hq@a6b08de8: the verdict of build-1791680941000000000 is an older run's than the check now pending; not written
✔ the verdict written while a start's read of the forge is in flight stays the newest status (1.493867ms)
✔ the verdict heard while a 'building' write still waits its turn: the 'building' is never written (0.55262ms)
✔ a start heard after the verdict writes nothing (1.392386ms)
✔ a start from before the check now pending (a run before a recheck, the stream's history) writes nothing (0.59599ms)
✔ an old run's verdict redelivered after a recheck's pending is not written over it (1.045179ms)
[gitea] novox/hq@a6b08de8: the verdict of build-1791680941000000000 is an older run's than the check the forge holds pending; not written
[gitea] novox/hq@a6b08de8: the verdict of build-1791680941000000000 is an older run's than the check now pending; not written
✔ an old run's verdict in flight when the recheck comes lands before the recheck's pending (2.425334ms)
✔ a rechecked head says where its new run is: building on which machine (0.952158ms)
✔ the recheck's own verdict is written, even asked a little before the pending by another machine's clock (0.760833ms)
✔ after a restart, an old run's verdict is weighed against the check the forge's history holds open (0.587041ms)
✔ a recheck the forge does not take fails its caller, and the head is as it was (0.604281ms)
✔ the status tool writes the merge check's pending through the writer, and the mesh's other statuses as they were (6.458627ms)
✔ when a check was asked is read from its id; the opening of the check now pending from the gate's history (0.295606ms)
✔ a head this process did not announce (it restarted) is said only while the forge holds its gate pending (0.444268ms)
✔ a repository as the mesh clones it is told from another (0.318486ms)
✔ gitea_api refuses the forge's administration, a branch's protection and the merge check's status, and sends nothing (6.553408ms)
✔ gitea_api refuses a file written to the default branch or one a rule guards, and writes one on a branch of its own (54.854694ms)
✔ a protection rule covers a branch as the forge decides it: classes, alternatives, a plain name in any case (issue 539) (22.143461ms)
✔ gitea_api still writes what an author writes (6.990957ms)
✔ gitea_branch_protection_set only strengthens (17.595769ms)
✔ gitea_merge_pull_request merges only a head whose required statuses all succeeded, and only that head (48.971987ms)
✔ gitea_merge_pull_request refuses a verdict judged against an earlier trunk, and asks the check once (153.062905ms)
✔ gitea_merge_pull_request merges only the head it is named, and refuses one that is not the head (17.963686ms)
✔ gitea_merge_pull_request is loud when the forge merged a head other than the one it was handed (15.039243ms)
✔ gitea_merge_pull_request says the merge happened when reading back what landed fails (26.804515ms)
✔ gitea_merge_pull_request reads back a fast-forward, and says it cannot read back a squash or a rebase (57.773547ms)
✔ gitea_delete_repo deletes only the tools' own user's repository, unguarded, untouched for 30 days, named in full (20.3688ms)
✔ gitea_api sends the path it judged, and refuses moving a pull request's base (3.84672ms)
✔ gitea_merge_pull_request merges only into a branch whose protection requires the checks (6.104801ms)
✔ a rule named for a branch is not made weaker than the glob rule that guards it now (14.451712ms)
✔ a repository owner or name is never another path (0.316736ms)
✔ the judges, without a forge (0.425807ms)
✔ gitea_api never acts as another user: sudo, in any case, and any query key it does not send are refused (2.022196ms)
✔ gitea_api never approves a pull request nor requests changes: those are the operator's (1.393775ms)
✔ no tool's caller text becomes another path or another user: `..` and `?sudo=` are refused before the forge (5.455039ms)
✔ every page of a pull request's files is read, though the forge caps a page at fifty (30.558264ms)
✔ a pass asks only the repositories that moved since the last look, every one before the first (0.517979ms)
✔ the directories above a merge's files that hold a module at the commit are said, the root never (12.352734ms)
✔ a lookup the forge refuses is thrown, not read as no module (3.610496ms)
✔ a renamed file is said under its old name too, as gone (novox/hq ADR 0267) (4.98423ms)
✔ a new head beyond the newest 20 open pull requests is announced, exactly once (64.032131ms)
✔ a pass pages until it reaches back past its floor, and no further (30.305509ms)
✔ the statuses asked for replace the rule's, and an empty list requires none (14.711237ms)
✔ a new rule refuses direct pushes unless asked; an administrator's override only when said (0.362886ms)
✔ each open pull request's new head is announced once, and nothing closed or merged (14.552963ms)
✔ a verdict is the head commit's status; an error is the forge's error, never a success (1.137841ms)
✔ each layer is its own status: the gate with the modules it judged, the repository's own check beside it (0.846175ms)
✔ no verdict sets warning on a required check; only a person's decision fails (1.110171ms)
✔ a commit status is set on the commit, under the merge check's context (56.759799ms)
✔ a change plan is the gate's result: said on the status and, when it builds something, as a comment (0.685682ms)
✔ a head announced is pending in the build queue, since the local time it was announced (0.348407ms)
✔ the vault's token is used, a setting of it is ignored and said once, without its value (5.833955ms)
✔ a consumer that asks nothing, or write, publishes: the package team (1.721671ms)
✔ a consumer that asks to read joins the readers, who write no package (0.502549ms)
✔ a reader is made, put on the readers team, and taken off the package team (0.589541ms)
✔ a publisher is made and put on the package team, as before (0.250254ms)
✔ first start: mints with the admin account, keeps the token at 0600, asks for the tools' scopes only (33.958466ms)
✔ second start: reuses the kept token, mints nothing (15.803026ms)
✔ the forge rejects the kept token (its data was restored): minted afresh, once, and the call goes through (19.924302ms)
✔ a token kept with write:admin by an earlier build is minted again without it at the next start, and the forge drops the old one (24.650796ms)
✔ a kept token lacking a scope the tools need: the forge refuses the call for the scope, the token is re-minted with the whole list, and the call goes through (21.340877ms)
✔ the kept file is gone but the forge still holds a token by that name: replaced, not refused (20.480041ms)
✔ concurrent first calls share one mint (11.663401ms)
✔ the admin account is refused: said plainly, nothing kept, and the next call fails the same way rather than crashing (11.845025ms)
✔ one process shares one source per kept file — the watcher and the tools never renew against each other (1.108521ms)
✔ a second process finds the token the first renewed, and reuses it instead of minting over it (20.45881ms)
✔ a configured token wins, and is reported rather than minted over when the forge rejects it (2.625147ms)
✔ nothing to mint with and no token: the client says what is missing (0.210504ms)
[gitea] no tools — no Gitea token, and nothing to mint one with — set MESH_GITEA_TOKEN, or MESH_GITEA_ADMIN_USER, MESH_GITEA_ADMIN_PASSWORD_FILE, MESH_GITEA_STATE_DIR
[gitea] no token kept — minting one
[gitea] the forge already holds a token named "mesh-tools" — replacing it
[gitea] minted a token for "mesh-admin" (write:repository, write:issue, read:user), kept at /tmp/gitea-ghXkiZ/state/token
✔ the tools register once there is a way to a token, and the first call mints it (9.258827ms)
[gitea] no token kept — minting one
[gitea] the forge already holds a token named "mesh-tools" — replacing it
[gitea] minted a token for "mesh-admin" (write:repository, write:issue, read:user), kept at /tmp/gitea-NpBEby/state/token
✔ a pull request can be closed, read and cleaned up through the tools (21.879907ms)
[gitea] novox/mesh-host's main moved from a2c2c35bbbbb to d28ca95ccccc: 25 open pull request(s) into it put out of date, nothing run (novox/hq ADR 0323)
[gitea] novox/mesh-host's main moved from d28ca95ccccc to ffffffffffff: 0 open pull request(s) into it put out of date, nothing run (novox/hq ADR 0323)
[gitea] novox/mesh-host: whether a trunk moved could not be weighed, so it is weighed again on the next pass — the forge is away
[gitea] novox/mesh-host's main moved from a2c2c35bbbbb to d28ca95ccccc: 0 open pull request(s) into it put out of date, nothing run (novox/hq ADR 0323)
✔ both statuses say the head and the trunk commit the verdict judged, first, whatever the summary's length (1.520507ms)
✔ a trunk's move puts an open head's merge check out of date, naming both commits, unless a check is on its way (0.963827ms)
✔ a push to a trunk puts every open pull request into it out of date — twenty-five of them — and none into another (4.132815ms)
✔ a trunk that cannot be read is weighed again on the next pass, never recorded half (0.335926ms)
✔ the trunk's move takes its turn after a verdict in flight, and weighs what the forge holds then (0.489679ms)
✔ a verdict judged against a trunk newer than the pass's first read is not put out of date (0.261115ms)
✔ a verdict that landed out of date keeps its account on the pull request (0.240955ms)
ℹ tests 89
ℹ suites 0
ℹ pass 89
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 665.80909
type-checking modules/nextcloud (TypeScript)
testing modules/nextcloud (TypeScript)
✔ the vault's password is used, a setting of it is ignored and said once, without its value (1.926635ms)
ℹ tests 1
ℹ suites 0
ℹ pass 1
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 92.36598
type-checking modules/umami (TypeScript)
NOT TESTED: modules/umami is TypeScript and has no tests of its own
**Merge check** at `2bb5d344` Judged: head `2bb5d344f6f1` merged into trunk `af5cf53a3450`; read beside it: mesh-controller `2959c8143536`, mesh-controller-main `3479a35462b2`, 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: gitea, mesh-knowledge, n8n, nextcloud, umami) - `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 gitea, mesh-knowledge, n8n, nextcloud, umami → ace, novox; no bus step - tier 0: gitea, mesh-knowledge, n8n, nextcloud, umami - ace: receives n8n - novox: receives gitea, mesh-knowledge, nextcloud, umami - gitea provides npm-package-registry, git: its consumers are sent again after it - gitea keeps data (ADR 0233): what it holds is backed up before it moves - n8n keeps data (ADR 0233): what it holds is backed up before it moves - nextcloud keeps data (ADR 0233): what it holds is backed up before it moves - umami provides analytics: its consumers are sent again after it - umami keeps data (ADR 0233): what it holds is backed up before it moves - grants step: if this changes what the bus's user list says (a new tool, subject or user), novox is sent that list alone, every build there kept, before n8n is judged on its first machine - read by no module's build: health-undeclared, modules/mesh-knowledge/cmd/mesh-knowledge/manifest_test.go Run by the build seat on shanks as `build-1791955083776952660` (`builds --log build-1791955083776952660`). ``` --- the gate: gitea, mesh-knowledge, n8n, nextcloud, umami note: mesh-knowledge uses the seat "operator-channel", which no module declares and the mesh does not define among the manifests given; registration judges it against the whole catalogue, and passing the declaring module's manifest too judges it here gitea: ok, keeps data (valuable), ready: server by http /api/healthz on web expecting 200 every 30s mesh-knowledge: ok, 2 tool(s), invokes seat:issue-tracker.reserve, claude-code.claude_code_judge, claude-code.claude_code_judged, records.records_status, records.records_list, records.records_read, seat:operator-channel.notify, ready: keep by unit every 30s; watch by its tool knowledge_health every 1m0s n8n: ok, keeps data (valuable), cache (cache), ready: server by http /healthz/readiness on web expecting 200 every 30s; WARNING: cache-server, browser stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8) nextcloud: ok, keeps html (valuable), ready: server by http /status.php on web expecting 200 every 30s umami: ok, ready: server by http /api/share/mesh-health on web expecting 404 every 30s long-running resources without health: 2 files asking for a setting without saying whether it is trusted: 0 5 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here judging 5 module(s) changed against 4 machine(s), as the snapshot of 2026-10-14T05:11:20Z 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-14T05:11:20Z modules the change moves: - gitea (changed) - mesh-knowledge (changed) - n8n (changed) - nextcloud (changed) - umami (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 5 module(s) in 1 tier(s): gitea, mesh-knowledge, n8n, nextcloud, umami notes: - health-undeclared and modules/mesh-knowledge/cmd/mesh-knowledge/manifest_test.go read by no module's build, and rebuild nothing (issue 280) --- its merge-check.sh (go toolchain) ok git.novox.be/novox/mesh-catalog/checks/words 0.003s words: 12 retired words and 70 daemons' lines, none in the 46860 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.012s secrets: no setting can replace a vault secret in a mergeable file (1 known, nested) ok git.novox.be/novox/mesh-catalog/checks/paths 0.006s paths: no module names another's state on its machine (3 known, listed to go) long-running resources without health: 62, as kept ok git.novox.be/novox/mesh-catalog/checks/deps 0.230s testing modules/gitea ok gitea/cmd/forge 1.519s ok gitea/cmd/npm-registry 1.823s ? gitea/internal/forgehttp [no test files] testing modules/mesh-knowledge ok mesh-knowledge/cmd/mesh-knowledge 129.071s modules/nextcloud is TypeScript: merge-check-typescript.sh type-checks and tests it modules/umami is TypeScript: merge-check-typescript.sh type-checks and tests it --- its merge-check-typescript.sh (typescript toolchain) type-checking modules/gitea (TypeScript) testing modules/gitea (TypeScript) ✔ a pull request opened after the margin is looked at, by its own update time (20.319899ms) ✔ every open pull request is read with what its base requires and what its head has (gitea_open_pulls) (90.276687ms) ✔ a pull request or issue number that is not one is refused before the forge is asked (1.808293ms) ✔ a merged pull request whose branch was deleted is announced with its branch, not its pull ref (13.197269ms) ✔ the newest status of each context is kept, with what it said, when and by whom (21.167934ms) ✔ a commit merges only when every required status is a success; a warning blocks (0.660252ms) ✔ no rule requires nothing; a rule that cannot be read says nothing, never yes (0.293515ms) ✔ a commit is contained in another when the compare finds nothing on it the other lacks (0.884596ms) ✔ a note line is appended once, as the forge's user, in its own repository (10.925299ms) ✔ a note that cannot be written is said, never read as written (0.53907ms) ✔ one view per pull request, found by its marker; only the mesh's statuses (0.808924ms) ✔ a build machine taking the check is said on the head: building on which machine, since the local time (21.358007ms) ✔ the verdict heard while a 'building' write is in flight lands last and stays (11.348426ms) [gitea] novox/hq@a6b08de8: the verdict of build-1791680941000000000 is an older run's than the check now pending; not written ✔ the verdict written while a start's read of the forge is in flight stays the newest status (1.493867ms) ✔ the verdict heard while a 'building' write still waits its turn: the 'building' is never written (0.55262ms) ✔ a start heard after the verdict writes nothing (1.392386ms) ✔ a start from before the check now pending (a run before a recheck, the stream's history) writes nothing (0.59599ms) ✔ an old run's verdict redelivered after a recheck's pending is not written over it (1.045179ms) [gitea] novox/hq@a6b08de8: the verdict of build-1791680941000000000 is an older run's than the check the forge holds pending; not written [gitea] novox/hq@a6b08de8: the verdict of build-1791680941000000000 is an older run's than the check now pending; not written ✔ an old run's verdict in flight when the recheck comes lands before the recheck's pending (2.425334ms) ✔ a rechecked head says where its new run is: building on which machine (0.952158ms) ✔ the recheck's own verdict is written, even asked a little before the pending by another machine's clock (0.760833ms) ✔ after a restart, an old run's verdict is weighed against the check the forge's history holds open (0.587041ms) ✔ a recheck the forge does not take fails its caller, and the head is as it was (0.604281ms) ✔ the status tool writes the merge check's pending through the writer, and the mesh's other statuses as they were (6.458627ms) ✔ when a check was asked is read from its id; the opening of the check now pending from the gate's history (0.295606ms) ✔ a head this process did not announce (it restarted) is said only while the forge holds its gate pending (0.444268ms) ✔ a repository as the mesh clones it is told from another (0.318486ms) ✔ gitea_api refuses the forge's administration, a branch's protection and the merge check's status, and sends nothing (6.553408ms) ✔ gitea_api refuses a file written to the default branch or one a rule guards, and writes one on a branch of its own (54.854694ms) ✔ a protection rule covers a branch as the forge decides it: classes, alternatives, a plain name in any case (issue 539) (22.143461ms) ✔ gitea_api still writes what an author writes (6.990957ms) ✔ gitea_branch_protection_set only strengthens (17.595769ms) ✔ gitea_merge_pull_request merges only a head whose required statuses all succeeded, and only that head (48.971987ms) ✔ gitea_merge_pull_request refuses a verdict judged against an earlier trunk, and asks the check once (153.062905ms) ✔ gitea_merge_pull_request merges only the head it is named, and refuses one that is not the head (17.963686ms) ✔ gitea_merge_pull_request is loud when the forge merged a head other than the one it was handed (15.039243ms) ✔ gitea_merge_pull_request says the merge happened when reading back what landed fails (26.804515ms) ✔ gitea_merge_pull_request reads back a fast-forward, and says it cannot read back a squash or a rebase (57.773547ms) ✔ gitea_delete_repo deletes only the tools' own user's repository, unguarded, untouched for 30 days, named in full (20.3688ms) ✔ gitea_api sends the path it judged, and refuses moving a pull request's base (3.84672ms) ✔ gitea_merge_pull_request merges only into a branch whose protection requires the checks (6.104801ms) ✔ a rule named for a branch is not made weaker than the glob rule that guards it now (14.451712ms) ✔ a repository owner or name is never another path (0.316736ms) ✔ the judges, without a forge (0.425807ms) ✔ gitea_api never acts as another user: sudo, in any case, and any query key it does not send are refused (2.022196ms) ✔ gitea_api never approves a pull request nor requests changes: those are the operator's (1.393775ms) ✔ no tool's caller text becomes another path or another user: `..` and `?sudo=` are refused before the forge (5.455039ms) ✔ every page of a pull request's files is read, though the forge caps a page at fifty (30.558264ms) ✔ a pass asks only the repositories that moved since the last look, every one before the first (0.517979ms) ✔ the directories above a merge's files that hold a module at the commit are said, the root never (12.352734ms) ✔ a lookup the forge refuses is thrown, not read as no module (3.610496ms) ✔ a renamed file is said under its old name too, as gone (novox/hq ADR 0267) (4.98423ms) ✔ a new head beyond the newest 20 open pull requests is announced, exactly once (64.032131ms) ✔ a pass pages until it reaches back past its floor, and no further (30.305509ms) ✔ the statuses asked for replace the rule's, and an empty list requires none (14.711237ms) ✔ a new rule refuses direct pushes unless asked; an administrator's override only when said (0.362886ms) ✔ each open pull request's new head is announced once, and nothing closed or merged (14.552963ms) ✔ a verdict is the head commit's status; an error is the forge's error, never a success (1.137841ms) ✔ each layer is its own status: the gate with the modules it judged, the repository's own check beside it (0.846175ms) ✔ no verdict sets warning on a required check; only a person's decision fails (1.110171ms) ✔ a commit status is set on the commit, under the merge check's context (56.759799ms) ✔ a change plan is the gate's result: said on the status and, when it builds something, as a comment (0.685682ms) ✔ a head announced is pending in the build queue, since the local time it was announced (0.348407ms) ✔ the vault's token is used, a setting of it is ignored and said once, without its value (5.833955ms) ✔ a consumer that asks nothing, or write, publishes: the package team (1.721671ms) ✔ a consumer that asks to read joins the readers, who write no package (0.502549ms) ✔ a reader is made, put on the readers team, and taken off the package team (0.589541ms) ✔ a publisher is made and put on the package team, as before (0.250254ms) ✔ first start: mints with the admin account, keeps the token at 0600, asks for the tools' scopes only (33.958466ms) ✔ second start: reuses the kept token, mints nothing (15.803026ms) ✔ the forge rejects the kept token (its data was restored): minted afresh, once, and the call goes through (19.924302ms) ✔ a token kept with write:admin by an earlier build is minted again without it at the next start, and the forge drops the old one (24.650796ms) ✔ a kept token lacking a scope the tools need: the forge refuses the call for the scope, the token is re-minted with the whole list, and the call goes through (21.340877ms) ✔ the kept file is gone but the forge still holds a token by that name: replaced, not refused (20.480041ms) ✔ concurrent first calls share one mint (11.663401ms) ✔ the admin account is refused: said plainly, nothing kept, and the next call fails the same way rather than crashing (11.845025ms) ✔ one process shares one source per kept file — the watcher and the tools never renew against each other (1.108521ms) ✔ a second process finds the token the first renewed, and reuses it instead of minting over it (20.45881ms) ✔ a configured token wins, and is reported rather than minted over when the forge rejects it (2.625147ms) ✔ nothing to mint with and no token: the client says what is missing (0.210504ms) [gitea] no tools — no Gitea token, and nothing to mint one with — set MESH_GITEA_TOKEN, or MESH_GITEA_ADMIN_USER, MESH_GITEA_ADMIN_PASSWORD_FILE, MESH_GITEA_STATE_DIR [gitea] no token kept — minting one [gitea] the forge already holds a token named "mesh-tools" — replacing it [gitea] minted a token for "mesh-admin" (write:repository, write:issue, read:user), kept at /tmp/gitea-ghXkiZ/state/token ✔ the tools register once there is a way to a token, and the first call mints it (9.258827ms) [gitea] no token kept — minting one [gitea] the forge already holds a token named "mesh-tools" — replacing it [gitea] minted a token for "mesh-admin" (write:repository, write:issue, read:user), kept at /tmp/gitea-NpBEby/state/token ✔ a pull request can be closed, read and cleaned up through the tools (21.879907ms) [gitea] novox/mesh-host's main moved from a2c2c35bbbbb to d28ca95ccccc: 25 open pull request(s) into it put out of date, nothing run (novox/hq ADR 0323) [gitea] novox/mesh-host's main moved from d28ca95ccccc to ffffffffffff: 0 open pull request(s) into it put out of date, nothing run (novox/hq ADR 0323) [gitea] novox/mesh-host: whether a trunk moved could not be weighed, so it is weighed again on the next pass — the forge is away [gitea] novox/mesh-host's main moved from a2c2c35bbbbb to d28ca95ccccc: 0 open pull request(s) into it put out of date, nothing run (novox/hq ADR 0323) ✔ both statuses say the head and the trunk commit the verdict judged, first, whatever the summary's length (1.520507ms) ✔ a trunk's move puts an open head's merge check out of date, naming both commits, unless a check is on its way (0.963827ms) ✔ a push to a trunk puts every open pull request into it out of date — twenty-five of them — and none into another (4.132815ms) ✔ a trunk that cannot be read is weighed again on the next pass, never recorded half (0.335926ms) ✔ the trunk's move takes its turn after a verdict in flight, and weighs what the forge holds then (0.489679ms) ✔ a verdict judged against a trunk newer than the pass's first read is not put out of date (0.261115ms) ✔ a verdict that landed out of date keeps its account on the pull request (0.240955ms) ℹ tests 89 ℹ suites 0 ℹ pass 89 ℹ fail 0 ℹ cancelled 0 ℹ skipped 0 ℹ todo 0 ℹ duration_ms 665.80909 type-checking modules/nextcloud (TypeScript) testing modules/nextcloud (TypeScript) ✔ the vault's password is used, a setting of it is ignored and said once, without its value (1.926635ms) ℹ tests 1 ℹ suites 0 ℹ pass 1 ℹ fail 0 ℹ cancelled 0 ℹ skipped 0 ℹ todo 0 ℹ duration_ms 92.36598 type-checking modules/umami (TypeScript) NOT TESTED: modules/umami is TypeScript and has no tests of its own ```
mesh-admin left a comment
Author
Contributor

Verdict: sound, mergeable at 2bb5d344f6f1; review 262's umami point is answered.

Re-review for issue 145 (a machine reads healthy while its modules cannot reach each other), part E.

  1. The diff from the reviewed head b62bb158 is exactly one commit, a child of it, adding one line to modules/umami/module.json: "body": "\"code\":\"not-found\"" beside status 404. Nothing else changed. An unknown route's HTML 404 now fails the check, so it can no longer pass silently. I take the builder's proof (pinned image, throwaway postgres: JSON not-found 404 with the database up, 500 with it down, HTML 404 refused) as reported; I did not repeat it.
  2. Checks at this head, judged against trunk af5cf53a34 at 07:23: mesh/merge-gate success ("PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: gitea, mesh-knowledge, n8n, nextcloud, umami)"), mesh/repo-check success ("PASS — its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)"), mesh/delivery success ("ready: waits for its merge"), mesh/delivery-group pending ("delivering: 1 of 2 delivered"). That is the group with mesh-controller #319 merged; it is no longer the 01:31 failure.
  3. Still open from review 262, not blocking: no one has shown nextcloud's /status.php failing with the database down. The gate's one-line summary does not print a check's body for umami or for nextcloud; it is a summary only.

Reviewed by an independent reviewer on g14.

Verdict: sound, mergeable at 2bb5d344f6f1; review 262's umami point is answered. Re-review for issue 145 (a machine reads healthy while its modules cannot reach each other), part E. 1. The diff from the reviewed head b62bb158 is exactly one commit, a child of it, adding one line to modules/umami/module.json: `"body": "\"code\":\"not-found\""` beside status 404. Nothing else changed. An unknown route's HTML 404 now fails the check, so it can no longer pass silently. I take the builder's proof (pinned image, throwaway postgres: JSON not-found 404 with the database up, 500 with it down, HTML 404 refused) as reported; I did not repeat it. 2. Checks at this head, judged against trunk af5cf53a3450 at 07:23: mesh/merge-gate success ("PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: gitea, mesh-knowledge, n8n, nextcloud, umami)"), mesh/repo-check success ("PASS — its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)"), mesh/delivery success ("ready: waits for its merge"), mesh/delivery-group pending ("delivering: 1 of 2 delivered"). That is the group with mesh-controller #319 merged; it is no longer the 01:31 failure. 3. Still open from review 262, not blocking: no one has shown nextcloud's /status.php failing with the database down. The gate's one-line summary does not print a check's body for umami or for nextcloud; it is a summary only. Reviewed by an independent reviewer on g14.
mesh-admin merged commit a44d490d97 into main 2026-10-14 05:26:48 +00:00
mesh-admin deleted branch fix/145-a-consumer-is-held-under-its-provider 2026-10-14 05:26:48 +00:00
Sign in to join this conversation.
No Reviewers
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: novox/mesh-catalog#289