TrustedMergeable returns nothing for a module whose mergeable files all name their keys (ADR 0326), and asksFor reads a naming file's takes-settings as the keys it asks for. So for such a module only a trusted file's named keys are terminal keys (refused through the settings verb, proposed instead), and a key of a file marked "trusted": false is set through the verb. A module whose files name no keys keeps the whole-layer rule of issue 340.
Why
ADR 0329 §5: betterbird's tags (in tags.json, trusted: false) may be set through the settings verb, while accounts, identities, calendars, address-books, filters and prefs stay the terminal's or the operator's warrant. Today any trusted mergeable file puts the module's whole layer at the terminal, because such a file took any key; with takes-settings a file takes exactly its named keys, and a key no file names is stray and refused where it is set, so the whole-layer rule is no longer needed for these modules (searxng, keycloak, betterbird).
How it was tested
internal/catalogue: TestOnlyANamedKeyOfATrustedFileIsTheTerminals (betterbird's four files: terminal keys are accounts, address-books, calendars, filters, identities, prefs, not tags; a silent module keeps the whole layer). Fails without the change.
cmd/mesh-controller (store test, added to testdata/store-tests): TestOnlyATrustedFilesNamedKeyIsRefusedThroughAVerb: tags set through the verb, accounts refused, the layer holds the tags alone. Fails without the change.
go test ./internal/catalogue/ ./cmd/mesh-controller/ against a throwaway postgres 17: ok; gofmt and vet clean. module check on every catalogue manifest with this binary: 127 checked, no problem.
Part of issue 586 (with novox/mesh-catalog fix/586-betterbird-owns-its-configuration).
## What
`TrustedMergeable` returns nothing for a module whose mergeable files all name their keys (ADR 0326), and `asksFor` reads a naming file's `takes-settings` as the keys it asks for. So for such a module only a trusted file's named keys are terminal keys (refused through the `settings` verb, proposed instead), and a key of a file marked `"trusted": false` is set through the verb. A module whose files name no keys keeps the whole-layer rule of issue 340.
## Why
ADR 0329 §5: betterbird's `tags` (in `tags.json`, `trusted: false`) may be set through the `settings` verb, while `accounts`, `identities`, `calendars`, `address-books`, `filters` and `prefs` stay the terminal's or the operator's warrant. Today any trusted mergeable file puts the module's whole layer at the terminal, because such a file took any key; with `takes-settings` a file takes exactly its named keys, and a key no file names is stray and refused where it is set, so the whole-layer rule is no longer needed for these modules (searxng, keycloak, betterbird).
## How it was tested
- `internal/catalogue`: `TestOnlyANamedKeyOfATrustedFileIsTheTerminals` (betterbird's four files: terminal keys are accounts, address-books, calendars, filters, identities, prefs, not tags; a silent module keeps the whole layer). Fails without the change.
- `cmd/mesh-controller` (store test, added to `testdata/store-tests`): `TestOnlyATrustedFilesNamedKeyIsRefusedThroughAVerb`: tags set through the verb, accounts refused, the layer holds the tags alone. Fails without the change.
- `go test ./internal/catalogue/ ./cmd/mesh-controller/` against a throwaway postgres 17: ok; gofmt and vet clean. `module check` on every catalogue manifest with this binary: 127 checked, no problem.
Part of issue 586 (with novox/mesh-catalog fix/586-betterbird-owns-its-configuration).
Deliverynovox/mesh-controller@3275a16bebbb — delivered since 2026-10-13T03:46:32Z
Delivery plan — builds build-agent, mesh-controller → ace, g14, novox, shanks; no bus step
tier 0: mesh-controller
tier 1: build-agent
ace: receives build-agent
g14: receives build-agent
novox: receives mesh-controller, build-agent
shanks: receives build-agent
build-agent 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 build-agent is judged on its first machine
Machines
mesh-controller on novox: passed — healthy 3 times over 4m7s
mesh-controller on the rest running it: sent
build-agent on ace: passed — healthy 1 times over 26s
build-agent on the rest running it: sent
Transitions
2026-10-13 03:23 (new) → proposed (announced): novox/mesh-controller#286's head announced
2026-10-13 03:29 proposed → checked (checked): a verdict names this commit and the trunk's head as its trunk commit
2026-10-13 03:29 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
2026-10-13 03:38 ready → published (merged): on the trunk its modules follow: merged there, and its walk opened — or nothing for a walk to move
2026-10-13 03:38 published → delivering (go): its walk started: let go by this owner in its group's order, by a person, or on the controller's own path — not a failed walk that carried a later commit for it, after which it waits for a walk of its own commit
2026-10-13 03:46 delivering → delivered (done): its walk is done, carrying its own commit: every machine of its deploy plan passed, or was left as its policy says
The commit's note under refs/notes/mesh-plan keeps every transition: git log --notes=mesh-plan.
<!-- mesh-delivery:view -->
**Delivery** `novox/mesh-controller@3275a16bebbb` — **delivered** since 2026-10-13T03:46:32Z
**Delivery plan** — builds build-agent, mesh-controller → ace, g14, novox, shanks; no bus step
- tier 0: mesh-controller
- tier 1: build-agent
- ace: receives build-agent
- g14: receives build-agent
- novox: receives mesh-controller, build-agent
- shanks: receives build-agent
- build-agent 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 build-agent is judged on its first machine
**Machines**
- mesh-controller on novox: passed — healthy 3 times over 4m7s
- mesh-controller on the rest running it: sent
- build-agent on ace: passed — healthy 1 times over 26s
- build-agent on the rest running it: sent
**Transitions**
- 2026-10-13 03:23 (new) → proposed (announced): novox/mesh-controller#286's head announced
- 2026-10-13 03:29 proposed → checked (checked): a verdict names this commit and the trunk's head as its trunk commit
- 2026-10-13 03:29 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
- 2026-10-13 03:38 ready → published (merged): on the trunk its modules follow: merged there, and its walk opened — or nothing for a walk to move
- 2026-10-13 03:38 published → delivering (go): its walk started: let go by this owner in its group's order, by a person, or on the controller's own path — not a failed walk that carried a later commit for it, after which it waits for a walk of its own commit
- 2026-10-13 03:46 delivering → delivered (done): its walk is done, carrying its own commit: every machine of its deploy plan passed, or was left as its policy says
The commit's note under `refs/notes/mesh-plan` keeps every transition: `git log --notes=mesh-plan`.
Merge check at 3379ab3b
Judged: head 3379ab3b61ac merged into trunk 454a3db69a1e; read beside it: mesh-catalog 39e7a06e6293, mesh-controller-main 454a3db69a1e, mesh-host 7a41e120635b, mesh-tools 954e1a53eef9
mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: build-agent, mesh-controller)
mesh/repo-check: PASS — its merge-check.sh passed
Delivery plan — builds build-agent, mesh-controller → ace, g14, novox, shanks; no bus step
tier 0: mesh-controller
tier 1: build-agent
ace: receives build-agent
g14: receives build-agent
novox: receives mesh-controller, build-agent
shanks: receives build-agent
build-agent 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 build-agent is judged on its first machine
read by no module's build: cmd/mesh-controller/terminal_settings_test.go, internal/catalogue/terminal_settings_test.go, testdata/store-tests
Run by the build seat on shanks as build-1791849840531899425 (builds --log build-1791849840531899425).
--- the gate: build-agent, mesh-controller
mesh-controller: ok, 58 tool(s); WARNING: merge-window ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339); WARNING: controller stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
long-running resources without health: 1
files asking for a setting without saying whether it is trusted: 1
1 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here
judging 1 module(s) changed against 4 machine(s), as the snapshot of 2026-10-12T23:40:10Z says they run
composing every machine as the mesh is
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
composing every machine with the change
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
merge gate: PASS — every machine composes with the change as it did without (4 of 4 compose)
judged by controller development build against the facts of 2026-10-12T23:40:10Z
modules the change moves:
- mesh-controller (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 2 module(s) in 2 tier(s): build-agent, mesh-controller
notes:
- cmd/mesh-controller/terminal_settings_test.go, internal/catalogue/terminal_settings_test.go and testdata/store-tests read by no module's build, and rebuild nothing (issue 280)
--- its merge-check.sh (go toolchain)
ok github.com/novox/mesh-controller/cmd/mesh-builder 1.038s
ok github.com/novox/mesh-controller/cmd/mesh-controller 170.611s
ok github.com/novox/mesh-controller/examples/objectstore-provisioner 1.024s
ok github.com/novox/mesh-controller/examples/postgres-provisioner 1.058s
ok github.com/novox/mesh-controller/examples/redis-provisioner 1.022s
ok github.com/novox/mesh-controller/examples/route-proxy 1.243s
ok github.com/novox/mesh-controller/internal/artifacts 1.092s
? github.com/novox/mesh-controller/internal/beside [no test files]
ok github.com/novox/mesh-controller/internal/broker 4.509s
ok github.com/novox/mesh-controller/internal/builder 39.598s
ok github.com/novox/mesh-controller/internal/catalogue 8.271s
ok github.com/novox/mesh-controller/internal/conditions 2.675s
ok github.com/novox/mesh-controller/internal/envfile 1.061s
ok github.com/novox/mesh-controller/internal/facts 1.067s
ok github.com/novox/mesh-controller/internal/identity 5.011s
ok github.com/novox/mesh-controller/internal/inventory 35.403s
ok github.com/novox/mesh-controller/internal/lease 17.726s
ok github.com/novox/mesh-controller/internal/licences 4.109s
ok github.com/novox/mesh-controller/internal/licences/adapters 1.052s
ok github.com/novox/mesh-controller/internal/link 59.009s
ok github.com/novox/mesh-controller/internal/lint 2.479s
ok github.com/novox/mesh-controller/internal/outward 1.093s
ok github.com/novox/mesh-controller/internal/overlay 1.059s
ok github.com/novox/mesh-controller/internal/secrets 1.526s
ok github.com/novox/mesh-controller/internal/store 3.484s
ok github.com/novox/mesh-controller/internal/testbus 1.250s
ok github.com/novox/mesh-controller/internal/token 1.014s
store tests, each run against the store:
./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeWalksTheOthersAgain (0.22s)
./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeEndsTheMergesThatContainIt (0.22s)
./cmd/mesh-controller --- PASS: TestAStopWalksTheOthersAgainInTheOpenBatch (0.22s)
./cmd/mesh-controller --- PASS: TestAStopNamesWhatStaysOnTheMachinesAndWhatStillCarriesIt (0.21s)
./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeLeavesItOutOfABatch (0.20s)
./cmd/mesh-controller --- PASS: TestSavingPlansAndMovingMergesIsOneAct (0.17s)
./cmd/mesh-controller --- PASS: TestAPlanFollowedFromTheStoreAnswersWhenItMoves (1.97s)
./cmd/mesh-controller --- PASS: TestNodeShowAndStatusReadTheLastSendFromTheStore (0.24s)
./cmd/mesh-controller --- PASS: TestTheConditionsVerbReadsTheLooksTheBucketNoLongerHolds (0.14s)
./cmd/mesh-controller --- PASS: TestAWalkLetGoAndStoppedByVerbsIsSaidStartedAndEnded (0.25s)
./cmd/mesh-controller --- PASS: TestAWalkStoppedOrClosedByAPersonIsSaidEndedStopped (0.26s)
./cmd/mesh-controller --- PASS: TestAWalkRetriedByAPersonIsSaidStartedAgain (0.21s)
./cmd/mesh-controller --- PASS: TestABacklogReleasedByAPersonIsSaidStarted (0.22s)
./cmd/mesh-controller --- PASS: TestAWalkEndedByCancelOrClearIsSaidEnded (0.27s)
./cmd/mesh-controller --- PASS: TestAWalkRestartedByARebuildIsSaidStarted (0.21s)
./cmd/mesh-controller --- PASS: TestAWalkStoppedByHandAndRetriedEndsFailedWhenItFailsAgain (0.25s)
./cmd/mesh-controller --- PASS: TestReplay237 (0.21s)
./cmd/mesh-controller --- PASS: TestAnUnassignThatLeavesItsNodeUnresolvedSaysSoOnceInItsAnswer (0.20s)
./cmd/mesh-controller --- PASS: TestAnUnassignThatLeavesItsNodeResolvedSaysNothingOfIt (0.20s)
./cmd/mesh-controller --- PASS: TestAnAssignThatLeavesItsNodeUnresolvedSaysOnlyThePlansRefusal (0.20s)
./cmd/mesh-controller --- PASS: TestADirectoryOwnersKeyIsRefusedThroughAVerb (0.23s)
./cmd/mesh-controller --- PASS: TestTheSendMakesNoValueForAnOutsideSecretNobodyGave (0.30s)
./cmd/mesh-controller --- PASS: TestAQuestionComposesWithoutAnOutsideSecretNobodyGave (0.28s)
./cmd/mesh-controller --- PASS: TestReplay201 (0.16s)
./cmd/mesh-controller --- PASS: TestARollbackWhoseSendWasRefusedIsCompletedByTheNextSend (0.16s)
./cmd/mesh-controller --- PASS: TestAGateJudgesTheOtherMovesBesideAKeptCore (0.17s)
./cmd/mesh-controller --- PASS: TestReplay401 (0.30s)
./cmd/mesh-controller --- PASS: TestReplay201ThePlansSend (0.24s)
./cmd/mesh-controller --- PASS: TestOnlyATrustedFilesNamedKeyIsRefusedThroughAVerb (0.21s)
./internal/inventory --- PASS: TestTheLastSendSaysWhatTheMachineAnswered (0.08s)
./internal/inventory --- PASS: TestAReportIsTheLastSendsAnswerOnlyWhenItIsAboutThatSend (0.08s)
./internal/inventory --- PASS: TestAnIssuedValueIsSealedToEveryHolderOnceAndNotAgain (0.10s)
./internal/inventory --- PASS: TestAnIssuedValueIsSealedAgainAfterAKeyChangeOrAnAcceptance (0.08s)
./internal/inventory --- PASS: TestAConditionsLooksAreKeptBesideTheBucket (0.07s)
./internal/inventory --- PASS: TestAPlanIdHoldingAQuoteIsReadAsAPlainId (0.07s)
./internal/inventory --- PASS: TestAWalksStartIsKeptAndARefusedSaveLeavesItUnsaid (0.07s)
./internal/inventory --- PASS: TestAWalksRestIsReadFromEachMachinesOwnSend (0.07s)
./internal/inventory --- PASS: TestAStoredBuildWithASilentMergeableFileIsStillReadAndComposed (0.07s)
Out of date when it landed: out of date: judged against trunk 454a3db69a, the trunk is now 4473bc7d7315; judged again on a recheck or when it is merged
**Merge check** at `3379ab3b`
Judged: head `3379ab3b61ac` merged into trunk `454a3db69a1e`; read beside it: mesh-catalog `39e7a06e6293`, mesh-controller-main `454a3db69a1e`, mesh-host `7a41e120635b`, mesh-tools `954e1a53eef9`
- `mesh/merge-gate`: **PASS** — every machine composes with the change as it did without (4 of 4 compose) (modules: build-agent, mesh-controller)
- `mesh/repo-check`: **PASS** — its merge-check.sh passed
**Delivery plan** — builds build-agent, mesh-controller → ace, g14, novox, shanks; no bus step
- tier 0: mesh-controller
- tier 1: build-agent
- ace: receives build-agent
- g14: receives build-agent
- novox: receives mesh-controller, build-agent
- shanks: receives build-agent
- build-agent 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 build-agent is judged on its first machine
- read by no module's build: cmd/mesh-controller/terminal_settings_test.go, internal/catalogue/terminal_settings_test.go, testdata/store-tests
Run by the build seat on shanks as `build-1791849840531899425` (`builds --log build-1791849840531899425`).
```
--- the gate: build-agent, mesh-controller
mesh-controller: ok, 58 tool(s); WARNING: merge-window ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339); WARNING: controller stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
long-running resources without health: 1
files asking for a setting without saying whether it is trusted: 1
1 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here
judging 1 module(s) changed against 4 machine(s), as the snapshot of 2026-10-12T23:40:10Z says they run
composing every machine as the mesh is
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
composing every machine with the change
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
the bus's user list leaves out 5 user(s) the mesh has minted no credential for: controller, node.f35, node.idt, node.ygcyr, node.yvbpsm. Each is a user that cannot connect until one is issued
merge gate: PASS — every machine composes with the change as it did without (4 of 4 compose)
judged by controller development build against the facts of 2026-10-12T23:40:10Z
modules the change moves:
- mesh-controller (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 2 module(s) in 2 tier(s): build-agent, mesh-controller
notes:
- cmd/mesh-controller/terminal_settings_test.go, internal/catalogue/terminal_settings_test.go and testdata/store-tests read by no module's build, and rebuild nothing (issue 280)
--- its merge-check.sh (go toolchain)
ok github.com/novox/mesh-controller/cmd/mesh-builder 1.038s
ok github.com/novox/mesh-controller/cmd/mesh-controller 170.611s
ok github.com/novox/mesh-controller/examples/objectstore-provisioner 1.024s
ok github.com/novox/mesh-controller/examples/postgres-provisioner 1.058s
ok github.com/novox/mesh-controller/examples/redis-provisioner 1.022s
ok github.com/novox/mesh-controller/examples/route-proxy 1.243s
ok github.com/novox/mesh-controller/internal/artifacts 1.092s
? github.com/novox/mesh-controller/internal/beside [no test files]
ok github.com/novox/mesh-controller/internal/broker 4.509s
ok github.com/novox/mesh-controller/internal/builder 39.598s
ok github.com/novox/mesh-controller/internal/catalogue 8.271s
ok github.com/novox/mesh-controller/internal/conditions 2.675s
ok github.com/novox/mesh-controller/internal/envfile 1.061s
ok github.com/novox/mesh-controller/internal/facts 1.067s
ok github.com/novox/mesh-controller/internal/identity 5.011s
ok github.com/novox/mesh-controller/internal/inventory 35.403s
ok github.com/novox/mesh-controller/internal/lease 17.726s
ok github.com/novox/mesh-controller/internal/licences 4.109s
ok github.com/novox/mesh-controller/internal/licences/adapters 1.052s
ok github.com/novox/mesh-controller/internal/link 59.009s
ok github.com/novox/mesh-controller/internal/lint 2.479s
ok github.com/novox/mesh-controller/internal/outward 1.093s
ok github.com/novox/mesh-controller/internal/overlay 1.059s
ok github.com/novox/mesh-controller/internal/secrets 1.526s
ok github.com/novox/mesh-controller/internal/store 3.484s
ok github.com/novox/mesh-controller/internal/testbus 1.250s
ok github.com/novox/mesh-controller/internal/token 1.014s
store tests, each run against the store:
./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeWalksTheOthersAgain (0.22s)
./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeEndsTheMergesThatContainIt (0.22s)
./cmd/mesh-controller --- PASS: TestAStopWalksTheOthersAgainInTheOpenBatch (0.22s)
./cmd/mesh-controller --- PASS: TestAStopNamesWhatStaysOnTheMachinesAndWhatStillCarriesIt (0.21s)
./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeLeavesItOutOfABatch (0.20s)
./cmd/mesh-controller --- PASS: TestSavingPlansAndMovingMergesIsOneAct (0.17s)
./cmd/mesh-controller --- PASS: TestAPlanFollowedFromTheStoreAnswersWhenItMoves (1.97s)
./cmd/mesh-controller --- PASS: TestNodeShowAndStatusReadTheLastSendFromTheStore (0.24s)
./cmd/mesh-controller --- PASS: TestTheConditionsVerbReadsTheLooksTheBucketNoLongerHolds (0.14s)
./cmd/mesh-controller --- PASS: TestAWalkLetGoAndStoppedByVerbsIsSaidStartedAndEnded (0.25s)
./cmd/mesh-controller --- PASS: TestAWalkStoppedOrClosedByAPersonIsSaidEndedStopped (0.26s)
./cmd/mesh-controller --- PASS: TestAWalkRetriedByAPersonIsSaidStartedAgain (0.21s)
./cmd/mesh-controller --- PASS: TestABacklogReleasedByAPersonIsSaidStarted (0.22s)
./cmd/mesh-controller --- PASS: TestAWalkEndedByCancelOrClearIsSaidEnded (0.27s)
./cmd/mesh-controller --- PASS: TestAWalkRestartedByARebuildIsSaidStarted (0.21s)
./cmd/mesh-controller --- PASS: TestAWalkStoppedByHandAndRetriedEndsFailedWhenItFailsAgain (0.25s)
./cmd/mesh-controller --- PASS: TestReplay237 (0.21s)
./cmd/mesh-controller --- PASS: TestAnUnassignThatLeavesItsNodeUnresolvedSaysSoOnceInItsAnswer (0.20s)
./cmd/mesh-controller --- PASS: TestAnUnassignThatLeavesItsNodeResolvedSaysNothingOfIt (0.20s)
./cmd/mesh-controller --- PASS: TestAnAssignThatLeavesItsNodeUnresolvedSaysOnlyThePlansRefusal (0.20s)
./cmd/mesh-controller --- PASS: TestADirectoryOwnersKeyIsRefusedThroughAVerb (0.23s)
./cmd/mesh-controller --- PASS: TestTheSendMakesNoValueForAnOutsideSecretNobodyGave (0.30s)
./cmd/mesh-controller --- PASS: TestAQuestionComposesWithoutAnOutsideSecretNobodyGave (0.28s)
./cmd/mesh-controller --- PASS: TestReplay201 (0.16s)
./cmd/mesh-controller --- PASS: TestARollbackWhoseSendWasRefusedIsCompletedByTheNextSend (0.16s)
./cmd/mesh-controller --- PASS: TestAGateJudgesTheOtherMovesBesideAKeptCore (0.17s)
./cmd/mesh-controller --- PASS: TestReplay401 (0.30s)
./cmd/mesh-controller --- PASS: TestReplay201ThePlansSend (0.24s)
./cmd/mesh-controller --- PASS: TestOnlyATrustedFilesNamedKeyIsRefusedThroughAVerb (0.21s)
./internal/inventory --- PASS: TestTheLastSendSaysWhatTheMachineAnswered (0.08s)
./internal/inventory --- PASS: TestAReportIsTheLastSendsAnswerOnlyWhenItIsAboutThatSend (0.08s)
./internal/inventory --- PASS: TestAnIssuedValueIsSealedToEveryHolderOnceAndNotAgain (0.10s)
./internal/inventory --- PASS: TestAnIssuedValueIsSealedAgainAfterAKeyChangeOrAnAcceptance (0.08s)
./internal/inventory --- PASS: TestAConditionsLooksAreKeptBesideTheBucket (0.07s)
./internal/inventory --- PASS: TestAPlanIdHoldingAQuoteIsReadAsAPlainId (0.07s)
./internal/inventory --- PASS: TestAWalksStartIsKeptAndARefusedSaveLeavesItUnsaid (0.07s)
./internal/inventory --- PASS: TestAWalksRestIsReadFromEachMachinesOwnSend (0.07s)
./internal/inventory --- PASS: TestAStoredBuildWithASilentMergeableFileIsStillReadAndComposed (0.07s)
```
**Out of date when it landed**: out of date: judged against trunk 454a3db69a1e, the trunk is now 4473bc7d7315; judged again on a recheck or when it is merged
This head conflicts with main. Pull request 281 is already merged (main is 4473bc7d73), and it appended TestPlanAndNodeListAnOptionalRequirementLeftUnbound to the end of testdata/store-tests, the same place this change appends TestOnlyATrustedFilesNamedKeyIsRefusedThroughAVerb. A merge of this head into main stops with a content conflict in testdata/store-tests. The fix is a rebase that keeps both lines. I resolved it that way locally: go vet is clean and the two new tests, the issue 340 test and 281's store test pass on the result. The code itself needs no change; this is the only reason for this verdict, and a rebased head whose diff to main is these same four files is one I would approve.
Findings that do not block
The code does what ADR 0329 §5 and ADR 0326 decide and nothing broader in the files. TrustedMergeable now answers nothing for a module whose mergeable files all carry takes-settings (namesItsKeys), and asksFor gives such a file exactly its named keys plus any ${setting:} its content asks for. A file that names no keys keeps the whole-layer rule of issue 340, and a mixed module cannot reach this path, because takenSettingsProblems refuses it where it is checked and where it is composed. A key no file names is stray and refused where it is set, as before.
I composed every module of mesh-catalog and mesh-media-catalog main through this head's catalogue package. Only betterbird, keycloak and searxng name their keys. Their terminal keys are now: betterbird places, accesses, accounts, prefs (accounts is its only mergeable file, trusted; prefs comes from user.js's placeholder); keycloak places, accesses, url, user, realm, issuer and its served authorization-path, token-path, userinfo-path (its runtime-config names url, user, realm, issuer and says nothing on trust, so it counts as trusted); searxng places, accesses and all ten keys its settings file names. Every other module with a mergeable file (39 of them) names no keys and keeps its whole layer at the terminal, unchanged. No ${setting:} placeholder anywhere in those three manifests falls outside the terminal keys. So no key that lands in a trusted file of any catalogue module becomes settable through the settings verb.
What does leave the terminal for keycloak and searxng is every key that was protected only by the whole-layer rule: the mesh words (ports, expose, reach, endpoints) and the keys their contributions declare, which a setting overrides (overridden in settings.go). For keycloak that is name on its postgres-database contribution and label and endpoint on its route; for searxng label and endpoint on its route. Those values reach a provider's received file, not keycloak's or searxng's own. This is the rule every module without a trusted mergeable file already lives under (model-usage, mesh-knowledge, n8n and umami contribute postgres-database the same way), so it is issue 339's scope and not a defect of this change. I think a contribution's key that names another module's resource, such as a database name, deserves its own issue, because through a verb it could point keycloak's login at another module's database.
Rollback is safe. The change stores nothing new and has no migration. On a rollback to main, a value set through the verb (betterbird's tags once it has a file) stays in the layer and is read and composed as before, since takes-settings filtering is already on main; main would only refuse the next verb change to that module's layer, as it does today.
Tests. Both new tests pass at this head and fail with terminal_keys.go reverted to main: the unit test because TrustedMergeable answers [accounts configuration prefs], the store test because the tags change is refused under issue 340. go vet ./... is clean and gofmt lists nothing. go test -race -count=1 ./internal/catalogue/ ./cmd/mesh-controller/ passes against a throwaway postgres 17 (catalogue 10 s, mesh-controller 315 s).
Remark: the verb judges a layer change against the module's current definition in the catalogue table, while a node that has not yet received a new build composes with the build it has. That was already so before this change; it matters here only for a module whose stored build is silent and whose new definition names its keys, during its walk.
Statuses at this head, from the forge: mesh/merge-gate pending, "out of date: judged against trunk 454a3db69a, the trunk is now 4473bc7d7315; judged again on a recheck or when it is merged"; mesh/repo-check pending with the same words; mesh/delivery pending, "checking". The forge says it is not mergeable while both required checks are pending.
Verdict: request changes at 3379ab3b61ac26ecd9a5bcc10a4069af47749df5
Blocking
1. This head conflicts with main. Pull request 281 is already merged (main is 4473bc7d7315), and it appended TestPlanAndNodeListAnOptionalRequirementLeftUnbound to the end of testdata/store-tests, the same place this change appends TestOnlyATrustedFilesNamedKeyIsRefusedThroughAVerb. A merge of this head into main stops with a content conflict in testdata/store-tests. The fix is a rebase that keeps both lines. I resolved it that way locally: go vet is clean and the two new tests, the issue 340 test and 281's store test pass on the result. The code itself needs no change; this is the only reason for this verdict, and a rebased head whose diff to main is these same four files is one I would approve.
Findings that do not block
2. The code does what ADR 0329 §5 and ADR 0326 decide and nothing broader in the files. TrustedMergeable now answers nothing for a module whose mergeable files all carry takes-settings (namesItsKeys), and asksFor gives such a file exactly its named keys plus any ${setting:} its content asks for. A file that names no keys keeps the whole-layer rule of issue 340, and a mixed module cannot reach this path, because takenSettingsProblems refuses it where it is checked and where it is composed. A key no file names is stray and refused where it is set, as before.
3. I composed every module of mesh-catalog and mesh-media-catalog main through this head's catalogue package. Only betterbird, keycloak and searxng name their keys. Their terminal keys are now: betterbird places, accesses, accounts, prefs (accounts is its only mergeable file, trusted; prefs comes from user.js's placeholder); keycloak places, accesses, url, user, realm, issuer and its served authorization-path, token-path, userinfo-path (its runtime-config names url, user, realm, issuer and says nothing on trust, so it counts as trusted); searxng places, accesses and all ten keys its settings file names. Every other module with a mergeable file (39 of them) names no keys and keeps its whole layer at the terminal, unchanged. No ${setting:} placeholder anywhere in those three manifests falls outside the terminal keys. So no key that lands in a trusted file of any catalogue module becomes settable through the settings verb.
4. What does leave the terminal for keycloak and searxng is every key that was protected only by the whole-layer rule: the mesh words (ports, expose, reach, endpoints) and the keys their contributions declare, which a setting overrides (overridden in settings.go). For keycloak that is name on its postgres-database contribution and label and endpoint on its route; for searxng label and endpoint on its route. Those values reach a provider's received file, not keycloak's or searxng's own. This is the rule every module without a trusted mergeable file already lives under (model-usage, mesh-knowledge, n8n and umami contribute postgres-database the same way), so it is issue 339's scope and not a defect of this change. I think a contribution's key that names another module's resource, such as a database name, deserves its own issue, because through a verb it could point keycloak's login at another module's database.
5. Rollback is safe. The change stores nothing new and has no migration. On a rollback to main, a value set through the verb (betterbird's tags once it has a file) stays in the layer and is read and composed as before, since takes-settings filtering is already on main; main would only refuse the next verb change to that module's layer, as it does today.
6. Tests. Both new tests pass at this head and fail with terminal_keys.go reverted to main: the unit test because TrustedMergeable answers [accounts configuration prefs], the store test because the tags change is refused under issue 340. go vet ./... is clean and gofmt lists nothing. go test -race -count=1 ./internal/catalogue/ ./cmd/mesh-controller/ passes against a throwaway postgres 17 (catalogue 10 s, mesh-controller 315 s).
7. Remark: the verb judges a layer change against the module's current definition in the catalogue table, while a node that has not yet received a new build composes with the build it has. That was already so before this change; it matters here only for a module whose stored build is silent and whose new definition names its keys, during its walk.
8. Statuses at this head, from the forge: mesh/merge-gate pending, "out of date: judged against trunk 454a3db69a1e, the trunk is now 4473bc7d7315; judged again on a recheck or when it is merged"; mesh/repo-check pending with the same words; mesh/delivery pending, "checking". The forge says it is not mergeable while both required checks are pending.
The rebase adds nothing beyond itself. git range-diff 454a3db..3379ab3b against 4473bc7..4c965e3 shows one commit, with the same message and the same code. The only difference is in testdata/store-tests, which now carries both #281's TestPlanAndNodeListAnOptionalRequirementLeftUnbound and this change's TestOnlyATrustedFilesNamedKeyIsRefusedThroughAVerb. The diff to main is the same four files as before (79 lines added, 1 removed). This settles the only blocking finding of my review of 3379ab3b, and its other findings stand unchanged.
go build ./... and go vet ./... are clean, and go test -race -count=1 ./internal/catalogue/ passes in 13.8 s.
Statuses at this head, from the forge: mesh/merge-gate is pending with "building on ace since 02:21", mesh/repo-check is missing, and mesh/delivery is pending with "checking". The forge says the pull request is not mergeable until both required checks are a success, so it must not be merged before then.
Verdict: approve at 4c965e3cf6d5142ae261830ed9f045e244d15dd0
The rebase adds nothing beyond itself. git range-diff 454a3db..3379ab3b against 4473bc7..4c965e3 shows one commit, with the same message and the same code. The only difference is in testdata/store-tests, which now carries both #281's TestPlanAndNodeListAnOptionalRequirementLeftUnbound and this change's TestOnlyATrustedFilesNamedKeyIsRefusedThroughAVerb. The diff to main is the same four files as before (79 lines added, 1 removed). This settles the only blocking finding of my review of 3379ab3b, and its other findings stand unchanged.
go build ./... and go vet ./... are clean, and go test -race -count=1 ./internal/catalogue/ passes in 13.8 s.
Statuses at this head, from the forge: mesh/merge-gate is pending with "building on ace since 02:21", mesh/repo-check is missing, and mesh/delivery is pending with "checking". The forge says the pull request is not mergeable until both required checks are a success, so it must not be merged before then.
Merge check at 4c965e3c
Judged: head 4c965e3cf6d5 merged into trunk 4473bc7d7315; read beside it: mesh-catalog 39e7a06e6293, mesh-controller-main 4473bc7d7315, mesh-host 7a41e120635b, mesh-tools 954e1a53eef9
mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: build-agent, mesh-controller)
mesh/repo-check: FAIL — its merge-check.sh failed: --- FAIL: TestBorrowedWordsAreLogged (0.01s)
Delivery plan — builds build-agent, mesh-controller → ace, g14, novox, shanks; no bus step
tier 0: mesh-controller
tier 1: build-agent
ace: receives build-agent
g14: receives build-agent
novox: receives mesh-controller, build-agent
shanks: receives build-agent
build-agent 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 build-agent is judged on its first machine
read by no module's build: cmd/mesh-controller/terminal_settings_test.go, internal/catalogue/terminal_settings_test.go, testdata/store-tests
Run by the build seat on ace as build-1791850897302374619 (builds --log build-1791850897302374619).
--- the gate: build-agent, mesh-controller
mesh-controller: ok, 58 tool(s); WARNING: merge-window ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339); WARNING: controller stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
long-running resources without health: 1
files asking for a setting without saying whether it is trusted: 1
1 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here
judging 1 module(s) changed against 4 machine(s), as the snapshot of 2026-10-13T00:18:25Z 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-13T00:18:25Z
modules the change moves:
- mesh-controller (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 2 module(s) in 2 tier(s): build-agent, mesh-controller
notes:
- cmd/mesh-controller/terminal_settings_test.go, internal/catalogue/terminal_settings_test.go and testdata/store-tests read by no module's build, and rebuild nothing (issue 280)
--- its merge-check.sh (go toolchain)
ok github.com/novox/mesh-controller/cmd/mesh-builder 1.037s
ok github.com/novox/mesh-controller/cmd/mesh-controller 149.395s
ok github.com/novox/mesh-controller/examples/objectstore-provisioner 1.029s
ok github.com/novox/mesh-controller/examples/postgres-provisioner 1.035s
ok github.com/novox/mesh-controller/examples/redis-provisioner 1.033s
ok github.com/novox/mesh-controller/examples/route-proxy 1.134s
ok github.com/novox/mesh-controller/internal/artifacts 1.074s
? github.com/novox/mesh-controller/internal/beside [no test files]
ok github.com/novox/mesh-controller/internal/broker 3.948s
ok github.com/novox/mesh-controller/internal/builder 33.373s
ok github.com/novox/mesh-controller/internal/catalogue 7.515s
2026/10/13 00:23:31 the condition kind "silent" is said in the scope's words, not its own: the kind silent has no plain words
--- FAIL: TestBorrowedWordsAreLogged (0.01s)
plain_test.go:280: the log said "2026/10/13 00:23:31 the condition kind \"test-clock\" is said in the scope's words, not its own: its source is not plain: explanation: a clock time or date\n2026/10/13 00:23:31 the condition kind \"test-hash\" is said in the scope's words, not its own: its source is not plain: headline: a hash\n"
2026/10/13 00:23:31 the condition kind "resolver-wrong" is said in the scope's words, not its own: the kind resolver-wrong has no plain words
2026/10/13 00:23:31 the condition kind "silent" is said in the scope's words, not its own: the kind silent has no plain words
2026/10/13 00:23:31 the condition kind "probe-failed" is said in the scope's words, not its own: the kind probe-failed has no plain words
FAIL
FAIL github.com/novox/mesh-controller/internal/conditions 1.546s
ok github.com/novox/mesh-controller/internal/envfile 1.031s
ok github.com/novox/mesh-controller/internal/facts 1.040s
ok github.com/novox/mesh-controller/internal/identity 4.434s
ok github.com/novox/mesh-controller/internal/inventory 30.420s
ok github.com/novox/mesh-controller/internal/lease 17.686s
ok github.com/novox/mesh-controller/internal/licences 3.699s
ok github.com/novox/mesh-controller/internal/licences/adapters 1.030s
ok github.com/novox/mesh-controller/internal/link 57.854s
ok github.com/novox/mesh-controller/internal/lint 2.254s
ok github.com/novox/mesh-controller/internal/outward 1.092s
ok github.com/novox/mesh-controller/internal/overlay 1.043s
ok github.com/novox/mesh-controller/internal/secrets 1.455s
ok github.com/novox/mesh-controller/internal/store 3.287s
ok github.com/novox/mesh-controller/internal/testbus 1.203s
ok github.com/novox/mesh-controller/internal/token 1.020s
FAIL
--- what failed, picked from the whole of its output (the whole is in the build's log)
--- FAIL: TestBorrowedWordsAreLogged (0.01s)
plain_test.go:280: the log said "2026/10/13 00:23:31 the condition kind \"test-clock\" is said in the scope's words, not its own: its source is not plain: explanation: a clock time or date\n2026/10/13 00:23:31 the condition kind \"test-hash\" is said in the scope's words, not its own: its source is not plain: headline: a hash\n"
FAIL github.com/novox/mesh-controller/internal/conditions 1.546s
**Merge check** at `4c965e3c`
Judged: head `4c965e3cf6d5` merged into trunk `4473bc7d7315`; read beside it: mesh-catalog `39e7a06e6293`, mesh-controller-main `4473bc7d7315`, mesh-host `7a41e120635b`, mesh-tools `954e1a53eef9`
- `mesh/merge-gate`: **PASS** — every machine composes with the change as it did without (4 of 4 compose) (modules: build-agent, mesh-controller)
- `mesh/repo-check`: **FAIL** — its merge-check.sh failed: --- FAIL: TestBorrowedWordsAreLogged (0.01s)
**Delivery plan** — builds build-agent, mesh-controller → ace, g14, novox, shanks; no bus step
- tier 0: mesh-controller
- tier 1: build-agent
- ace: receives build-agent
- g14: receives build-agent
- novox: receives mesh-controller, build-agent
- shanks: receives build-agent
- build-agent 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 build-agent is judged on its first machine
- read by no module's build: cmd/mesh-controller/terminal_settings_test.go, internal/catalogue/terminal_settings_test.go, testdata/store-tests
Run by the build seat on ace as `build-1791850897302374619` (`builds --log build-1791850897302374619`).
```
--- the gate: build-agent, mesh-controller
mesh-controller: ok, 58 tool(s); WARNING: merge-window ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339); WARNING: controller stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
long-running resources without health: 1
files asking for a setting without saying whether it is trusted: 1
1 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here
judging 1 module(s) changed against 4 machine(s), as the snapshot of 2026-10-13T00:18:25Z 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-13T00:18:25Z
modules the change moves:
- mesh-controller (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 2 module(s) in 2 tier(s): build-agent, mesh-controller
notes:
- cmd/mesh-controller/terminal_settings_test.go, internal/catalogue/terminal_settings_test.go and testdata/store-tests read by no module's build, and rebuild nothing (issue 280)
--- its merge-check.sh (go toolchain)
ok github.com/novox/mesh-controller/cmd/mesh-builder 1.037s
ok github.com/novox/mesh-controller/cmd/mesh-controller 149.395s
ok github.com/novox/mesh-controller/examples/objectstore-provisioner 1.029s
ok github.com/novox/mesh-controller/examples/postgres-provisioner 1.035s
ok github.com/novox/mesh-controller/examples/redis-provisioner 1.033s
ok github.com/novox/mesh-controller/examples/route-proxy 1.134s
ok github.com/novox/mesh-controller/internal/artifacts 1.074s
? github.com/novox/mesh-controller/internal/beside [no test files]
ok github.com/novox/mesh-controller/internal/broker 3.948s
ok github.com/novox/mesh-controller/internal/builder 33.373s
ok github.com/novox/mesh-controller/internal/catalogue 7.515s
2026/10/13 00:23:31 the condition kind "silent" is said in the scope's words, not its own: the kind silent has no plain words
--- FAIL: TestBorrowedWordsAreLogged (0.01s)
plain_test.go:280: the log said "2026/10/13 00:23:31 the condition kind \"test-clock\" is said in the scope's words, not its own: its source is not plain: explanation: a clock time or date\n2026/10/13 00:23:31 the condition kind \"test-hash\" is said in the scope's words, not its own: its source is not plain: headline: a hash\n"
2026/10/13 00:23:31 the condition kind "resolver-wrong" is said in the scope's words, not its own: the kind resolver-wrong has no plain words
2026/10/13 00:23:31 the condition kind "silent" is said in the scope's words, not its own: the kind silent has no plain words
2026/10/13 00:23:31 the condition kind "probe-failed" is said in the scope's words, not its own: the kind probe-failed has no plain words
FAIL
FAIL github.com/novox/mesh-controller/internal/conditions 1.546s
ok github.com/novox/mesh-controller/internal/envfile 1.031s
ok github.com/novox/mesh-controller/internal/facts 1.040s
ok github.com/novox/mesh-controller/internal/identity 4.434s
ok github.com/novox/mesh-controller/internal/inventory 30.420s
ok github.com/novox/mesh-controller/internal/lease 17.686s
ok github.com/novox/mesh-controller/internal/licences 3.699s
ok github.com/novox/mesh-controller/internal/licences/adapters 1.030s
ok github.com/novox/mesh-controller/internal/link 57.854s
ok github.com/novox/mesh-controller/internal/lint 2.254s
ok github.com/novox/mesh-controller/internal/outward 1.092s
ok github.com/novox/mesh-controller/internal/overlay 1.043s
ok github.com/novox/mesh-controller/internal/secrets 1.455s
ok github.com/novox/mesh-controller/internal/store 3.287s
ok github.com/novox/mesh-controller/internal/testbus 1.203s
ok github.com/novox/mesh-controller/internal/token 1.020s
FAIL
--- what failed, picked from the whole of its output (the whole is in the build's log)
--- FAIL: TestBorrowedWordsAreLogged (0.01s)
plain_test.go:280: the log said "2026/10/13 00:23:31 the condition kind \"test-clock\" is said in the scope's words, not its own: its source is not plain: explanation: a clock time or date\n2026/10/13 00:23:31 the condition kind \"test-hash\" is said in the scope's words, not its own: its source is not plain: headline: a hash\n"
FAIL github.com/novox/mesh-controller/internal/conditions 1.546s
```
Merge check at 4c965e3c
Judged: head 4c965e3cf6d5 merged into trunk 584ee991961c
mesh/merge-gate: FAIL — head 4c965e3cf6 does not merge cleanly into trunk 584ee99196: in conflict testdata/store-tests (modules: build-agent, mesh-controller)
mesh/repo-check: FAIL — head 4c965e3cf6 does not merge cleanly into trunk 584ee99196: in conflict testdata/store-tests
Delivery plan — builds build-agent, mesh-controller → ace, g14, novox, shanks; no bus step
tier 0: mesh-controller
tier 1: build-agent
ace: receives build-agent
g14: receives build-agent
novox: receives mesh-controller, build-agent
shanks: receives build-agent
build-agent 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 build-agent is judged on its first machine
read by no module's build: cmd/mesh-controller/terminal_settings_test.go, internal/catalogue/terminal_settings_test.go, testdata/store-tests
Run by the build seat on ace as build-1791861685670977695 (builds --log build-1791861685670977695).
head 4c965e3cf6d5 does not merge cleanly into trunk 584ee991961c: in conflict testdata/store-tests
**Merge check** at `4c965e3c`
Judged: head `4c965e3cf6d5` merged into trunk `584ee991961c`
- `mesh/merge-gate`: **FAIL** — head 4c965e3cf6d5 does not merge cleanly into trunk 584ee991961c: in conflict testdata/store-tests (modules: build-agent, mesh-controller)
- `mesh/repo-check`: **FAIL** — head 4c965e3cf6d5 does not merge cleanly into trunk 584ee991961c: in conflict testdata/store-tests
**Delivery plan** — builds build-agent, mesh-controller → ace, g14, novox, shanks; no bus step
- tier 0: mesh-controller
- tier 1: build-agent
- ace: receives build-agent
- g14: receives build-agent
- novox: receives mesh-controller, build-agent
- shanks: receives build-agent
- build-agent 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 build-agent is judged on its first machine
- read by no module's build: cmd/mesh-controller/terminal_settings_test.go, internal/catalogue/terminal_settings_test.go, testdata/store-tests
Run by the build seat on ace as `build-1791861685670977695` (`builds --log build-1791861685670977695`).
```
head 4c965e3cf6d5 does not merge cleanly into trunk 584ee991961c: in conflict testdata/store-tests
```
mesh/merge-gate head 3275a16bebbb merged into trunk 584ee991961c — pass: builds build-agent, mesh-controller → ace, g14, novox, shanks; no bus step; every …
A module with a trusted mergeable file had its whole layer refused through the
settings verb, because such a file took any key. Once a module's files name the
keys they take (ADR 0326), each file takes only those, so only a trusted file's
named keys are the terminal's: betterbird's tags, in a file nothing trusts, is set
through the verb, while its accounts and identities stay the terminal's or the
operator's warrant. A module whose files name no keys keeps the whole-layer rule.
Merge check at 3275a16b
Judged: head 3275a16bebbb merged into trunk 584ee991961c; read beside it: mesh-catalog f88e3452f8b8, mesh-controller-main 584ee991961c, mesh-host 7a41e120635b, mesh-tools 954e1a53eef9
mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: build-agent, mesh-controller)
mesh/repo-check: PASS — its merge-check.sh passed
Delivery plan — builds build-agent, mesh-controller → ace, g14, novox, shanks; no bus step
tier 0: mesh-controller
tier 1: build-agent
ace: receives build-agent
g14: receives build-agent
novox: receives mesh-controller, build-agent
shanks: receives build-agent
build-agent 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 build-agent is judged on its first machine
read by no module's build: cmd/mesh-controller/terminal_settings_test.go, internal/catalogue/terminal_settings_test.go, testdata/store-tests
Run by the build seat on g14 as build-1791861829243255338 (builds --log build-1791861829243255338).
--- the gate: build-agent, mesh-controller
mesh-controller: ok, 58 tool(s); WARNING: merge-window ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339); WARNING: controller stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
long-running resources without health: 1
files asking for a setting without saying whether it is trusted: 1
1 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here
judging 1 module(s) changed against 4 machine(s), as the snapshot of 2026-10-13T00:28:25Z 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-13T00:28:25Z
modules the change moves:
- mesh-controller (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 2 module(s) in 2 tier(s): build-agent, mesh-controller
notes:
- cmd/mesh-controller/terminal_settings_test.go, internal/catalogue/terminal_settings_test.go and testdata/store-tests read by no module's build, and rebuild nothing (issue 280)
--- its merge-check.sh (go toolchain)
ok github.com/novox/mesh-controller/cmd/mesh-builder 1.039s
ok github.com/novox/mesh-controller/cmd/mesh-controller 188.537s
ok github.com/novox/mesh-controller/examples/objectstore-provisioner 1.009s
ok github.com/novox/mesh-controller/examples/postgres-provisioner 1.025s
ok github.com/novox/mesh-controller/examples/redis-provisioner 1.009s
ok github.com/novox/mesh-controller/examples/route-proxy 1.156s
ok github.com/novox/mesh-controller/internal/artifacts 1.057s
? github.com/novox/mesh-controller/internal/beside [no test files]
ok github.com/novox/mesh-controller/internal/broker 4.727s
ok github.com/novox/mesh-controller/internal/builder 32.933s
ok github.com/novox/mesh-controller/internal/catalogue 7.515s
ok github.com/novox/mesh-controller/internal/conditions 3.825s
ok github.com/novox/mesh-controller/internal/envfile 1.028s
ok github.com/novox/mesh-controller/internal/facts 1.031s
ok github.com/novox/mesh-controller/internal/identity 5.562s
ok github.com/novox/mesh-controller/internal/inventory 34.231s
ok github.com/novox/mesh-controller/internal/lease 17.693s
ok github.com/novox/mesh-controller/internal/licences 4.763s
ok github.com/novox/mesh-controller/internal/licences/adapters 1.006s
ok github.com/novox/mesh-controller/internal/link 61.788s
ok github.com/novox/mesh-controller/internal/lint 2.166s
ok github.com/novox/mesh-controller/internal/outward 1.025s
ok github.com/novox/mesh-controller/internal/overlay 1.016s
ok github.com/novox/mesh-controller/internal/secrets 1.311s
ok github.com/novox/mesh-controller/internal/store 3.500s
ok github.com/novox/mesh-controller/internal/testbus 1.197s
ok github.com/novox/mesh-controller/internal/token 1.016s
store tests, each run against the store:
./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeWalksTheOthersAgain (0.19s)
./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeEndsTheMergesThatContainIt (0.20s)
./cmd/mesh-controller --- PASS: TestAStopWalksTheOthersAgainInTheOpenBatch (0.19s)
./cmd/mesh-controller --- PASS: TestAStopNamesWhatStaysOnTheMachinesAndWhatStillCarriesIt (0.18s)
./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeLeavesItOutOfABatch (0.20s)
./cmd/mesh-controller --- PASS: TestSavingPlansAndMovingMergesIsOneAct (0.17s)
./cmd/mesh-controller --- PASS: TestAPlanFollowedFromTheStoreAnswersWhenItMoves (2.11s)
./cmd/mesh-controller --- PASS: TestNodeShowAndStatusReadTheLastSendFromTheStore (0.22s)
./cmd/mesh-controller --- PASS: TestTheConditionsVerbReadsTheLooksTheBucketNoLongerHolds (0.12s)
./cmd/mesh-controller --- PASS: TestAWalkLetGoAndStoppedByVerbsIsSaidStartedAndEnded (0.24s)
./cmd/mesh-controller --- PASS: TestAWalkStoppedOrClosedByAPersonIsSaidEndedStopped (0.23s)
./cmd/mesh-controller --- PASS: TestAWalkRetriedByAPersonIsSaidStartedAgain (0.22s)
./cmd/mesh-controller --- PASS: TestABacklogReleasedByAPersonIsSaidStarted (0.20s)
./cmd/mesh-controller --- PASS: TestAWalkEndedByCancelOrClearIsSaidEnded (0.24s)
./cmd/mesh-controller --- PASS: TestAWalkRestartedByARebuildIsSaidStarted (0.20s)
./cmd/mesh-controller --- PASS: TestAWalkStoppedByHandAndRetriedEndsFailedWhenItFailsAgain (0.22s)
./cmd/mesh-controller --- PASS: TestReplay237 (0.19s)
./cmd/mesh-controller --- PASS: TestAnUnassignThatLeavesItsNodeUnresolvedSaysSoOnceInItsAnswer (0.18s)
./cmd/mesh-controller --- PASS: TestAnUnassignThatLeavesItsNodeResolvedSaysNothingOfIt (0.30s)
./cmd/mesh-controller --- PASS: TestAnAssignThatLeavesItsNodeUnresolvedSaysOnlyThePlansRefusal (0.19s)
./cmd/mesh-controller --- PASS: TestADirectoryOwnersKeyIsRefusedThroughAVerb (0.22s)
./cmd/mesh-controller --- PASS: TestTheSendMakesNoValueForAnOutsideSecretNobodyGave (0.27s)
./cmd/mesh-controller --- PASS: TestAQuestionComposesWithoutAnOutsideSecretNobodyGave (0.23s)
./cmd/mesh-controller --- PASS: TestReplay201 (0.14s)
./cmd/mesh-controller --- PASS: TestARollbackWhoseSendWasRefusedIsCompletedByTheNextSend (0.14s)
./cmd/mesh-controller --- PASS: TestAGateJudgesTheOtherMovesBesideAKeptCore (0.15s)
./cmd/mesh-controller --- PASS: TestReplay401 (0.25s)
./cmd/mesh-controller --- PASS: TestReplay201ThePlansSend (0.20s)
./cmd/mesh-controller --- PASS: TestPlanAndNodeListAnOptionalRequirementLeftUnbound (0.24s)
./cmd/mesh-controller --- PASS: TestReplay340 (0.20s)
./cmd/mesh-controller --- PASS: TestOnlyATrustedFilesNamedKeyIsRefusedThroughAVerb (0.17s)
./internal/inventory --- PASS: TestTheLastSendSaysWhatTheMachineAnswered (0.07s)
./internal/inventory --- PASS: TestAReportIsTheLastSendsAnswerOnlyWhenItIsAboutThatSend (0.07s)
./internal/inventory --- PASS: TestAnIssuedValueIsSealedToEveryHolderOnceAndNotAgain (0.08s)
./internal/inventory --- PASS: TestAnIssuedValueIsSealedAgainAfterAKeyChangeOrAnAcceptance (0.15s)
./internal/inventory --- PASS: TestAConditionsLooksAreKeptBesideTheBucket (0.06s)
./internal/inventory --- PASS: TestAPlanIdHoldingAQuoteIsReadAsAPlainId (0.06s)
./internal/inventory --- PASS: TestAWalksStartIsKeptAndARefusedSaveLeavesItUnsaid (0.06s)
./internal/inventory --- PASS: TestAWalksRestIsReadFromEachMachinesOwnSend (0.06s)
./internal/inventory --- PASS: TestAStoredBuildWithASilentMergeableFileIsStillReadAndComposed (0.06s)
**Merge check** at `3275a16b`
Judged: head `3275a16bebbb` merged into trunk `584ee991961c`; read beside it: mesh-catalog `f88e3452f8b8`, mesh-controller-main `584ee991961c`, mesh-host `7a41e120635b`, mesh-tools `954e1a53eef9`
- `mesh/merge-gate`: **PASS** — every machine composes with the change as it did without (4 of 4 compose) (modules: build-agent, mesh-controller)
- `mesh/repo-check`: **PASS** — its merge-check.sh passed
**Delivery plan** — builds build-agent, mesh-controller → ace, g14, novox, shanks; no bus step
- tier 0: mesh-controller
- tier 1: build-agent
- ace: receives build-agent
- g14: receives build-agent
- novox: receives mesh-controller, build-agent
- shanks: receives build-agent
- build-agent 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 build-agent is judged on its first machine
- read by no module's build: cmd/mesh-controller/terminal_settings_test.go, internal/catalogue/terminal_settings_test.go, testdata/store-tests
Run by the build seat on g14 as `build-1791861829243255338` (`builds --log build-1791861829243255338`).
```
--- the gate: build-agent, mesh-controller
mesh-controller: ok, 58 tool(s); WARNING: merge-window ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted: set at the terminal alone; say "trusted" false where nothing trusts it (novox/hq issue 339); WARNING: controller stay(s) up and say(s) not how it is ready — judged by liveness alone, refused from 2026-11-18 (ADR 0240 rule 8)
long-running resources without health: 1
files asking for a setting without saying whether it is trusted: 1
1 manifest(s) checked. Judged against the seats this binary carries; a claim on one of the mesh's own seats is judged fully at registration, and a seat declared by a module not given here reads as unknown. Identities judged on a 6-character machine name, against the bounds of the providers given here
judging 1 module(s) changed against 4 machine(s), as the snapshot of 2026-10-13T00:28:25Z 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-13T00:28:25Z
modules the change moves:
- mesh-controller (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 2 module(s) in 2 tier(s): build-agent, mesh-controller
notes:
- cmd/mesh-controller/terminal_settings_test.go, internal/catalogue/terminal_settings_test.go and testdata/store-tests read by no module's build, and rebuild nothing (issue 280)
--- its merge-check.sh (go toolchain)
ok github.com/novox/mesh-controller/cmd/mesh-builder 1.039s
ok github.com/novox/mesh-controller/cmd/mesh-controller 188.537s
ok github.com/novox/mesh-controller/examples/objectstore-provisioner 1.009s
ok github.com/novox/mesh-controller/examples/postgres-provisioner 1.025s
ok github.com/novox/mesh-controller/examples/redis-provisioner 1.009s
ok github.com/novox/mesh-controller/examples/route-proxy 1.156s
ok github.com/novox/mesh-controller/internal/artifacts 1.057s
? github.com/novox/mesh-controller/internal/beside [no test files]
ok github.com/novox/mesh-controller/internal/broker 4.727s
ok github.com/novox/mesh-controller/internal/builder 32.933s
ok github.com/novox/mesh-controller/internal/catalogue 7.515s
ok github.com/novox/mesh-controller/internal/conditions 3.825s
ok github.com/novox/mesh-controller/internal/envfile 1.028s
ok github.com/novox/mesh-controller/internal/facts 1.031s
ok github.com/novox/mesh-controller/internal/identity 5.562s
ok github.com/novox/mesh-controller/internal/inventory 34.231s
ok github.com/novox/mesh-controller/internal/lease 17.693s
ok github.com/novox/mesh-controller/internal/licences 4.763s
ok github.com/novox/mesh-controller/internal/licences/adapters 1.006s
ok github.com/novox/mesh-controller/internal/link 61.788s
ok github.com/novox/mesh-controller/internal/lint 2.166s
ok github.com/novox/mesh-controller/internal/outward 1.025s
ok github.com/novox/mesh-controller/internal/overlay 1.016s
ok github.com/novox/mesh-controller/internal/secrets 1.311s
ok github.com/novox/mesh-controller/internal/store 3.500s
ok github.com/novox/mesh-controller/internal/testbus 1.197s
ok github.com/novox/mesh-controller/internal/token 1.016s
store tests, each run against the store:
./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeWalksTheOthersAgain (0.19s)
./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeEndsTheMergesThatContainIt (0.20s)
./cmd/mesh-controller --- PASS: TestAStopWalksTheOthersAgainInTheOpenBatch (0.19s)
./cmd/mesh-controller --- PASS: TestAStopNamesWhatStaysOnTheMachinesAndWhatStillCarriesIt (0.18s)
./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeLeavesItOutOfABatch (0.20s)
./cmd/mesh-controller --- PASS: TestSavingPlansAndMovingMergesIsOneAct (0.17s)
./cmd/mesh-controller --- PASS: TestAPlanFollowedFromTheStoreAnswersWhenItMoves (2.11s)
./cmd/mesh-controller --- PASS: TestNodeShowAndStatusReadTheLastSendFromTheStore (0.22s)
./cmd/mesh-controller --- PASS: TestTheConditionsVerbReadsTheLooksTheBucketNoLongerHolds (0.12s)
./cmd/mesh-controller --- PASS: TestAWalkLetGoAndStoppedByVerbsIsSaidStartedAndEnded (0.24s)
./cmd/mesh-controller --- PASS: TestAWalkStoppedOrClosedByAPersonIsSaidEndedStopped (0.23s)
./cmd/mesh-controller --- PASS: TestAWalkRetriedByAPersonIsSaidStartedAgain (0.22s)
./cmd/mesh-controller --- PASS: TestABacklogReleasedByAPersonIsSaidStarted (0.20s)
./cmd/mesh-controller --- PASS: TestAWalkEndedByCancelOrClearIsSaidEnded (0.24s)
./cmd/mesh-controller --- PASS: TestAWalkRestartedByARebuildIsSaidStarted (0.20s)
./cmd/mesh-controller --- PASS: TestAWalkStoppedByHandAndRetriedEndsFailedWhenItFailsAgain (0.22s)
./cmd/mesh-controller --- PASS: TestReplay237 (0.19s)
./cmd/mesh-controller --- PASS: TestAnUnassignThatLeavesItsNodeUnresolvedSaysSoOnceInItsAnswer (0.18s)
./cmd/mesh-controller --- PASS: TestAnUnassignThatLeavesItsNodeResolvedSaysNothingOfIt (0.30s)
./cmd/mesh-controller --- PASS: TestAnAssignThatLeavesItsNodeUnresolvedSaysOnlyThePlansRefusal (0.19s)
./cmd/mesh-controller --- PASS: TestADirectoryOwnersKeyIsRefusedThroughAVerb (0.22s)
./cmd/mesh-controller --- PASS: TestTheSendMakesNoValueForAnOutsideSecretNobodyGave (0.27s)
./cmd/mesh-controller --- PASS: TestAQuestionComposesWithoutAnOutsideSecretNobodyGave (0.23s)
./cmd/mesh-controller --- PASS: TestReplay201 (0.14s)
./cmd/mesh-controller --- PASS: TestARollbackWhoseSendWasRefusedIsCompletedByTheNextSend (0.14s)
./cmd/mesh-controller --- PASS: TestAGateJudgesTheOtherMovesBesideAKeptCore (0.15s)
./cmd/mesh-controller --- PASS: TestReplay401 (0.25s)
./cmd/mesh-controller --- PASS: TestReplay201ThePlansSend (0.20s)
./cmd/mesh-controller --- PASS: TestPlanAndNodeListAnOptionalRequirementLeftUnbound (0.24s)
./cmd/mesh-controller --- PASS: TestReplay340 (0.20s)
./cmd/mesh-controller --- PASS: TestOnlyATrustedFilesNamedKeyIsRefusedThroughAVerb (0.17s)
./internal/inventory --- PASS: TestTheLastSendSaysWhatTheMachineAnswered (0.07s)
./internal/inventory --- PASS: TestAReportIsTheLastSendsAnswerOnlyWhenItIsAboutThatSend (0.07s)
./internal/inventory --- PASS: TestAnIssuedValueIsSealedToEveryHolderOnceAndNotAgain (0.08s)
./internal/inventory --- PASS: TestAnIssuedValueIsSealedAgainAfterAKeyChangeOrAnAcceptance (0.15s)
./internal/inventory --- PASS: TestAConditionsLooksAreKeptBesideTheBucket (0.06s)
./internal/inventory --- PASS: TestAPlanIdHoldingAQuoteIsReadAsAPlainId (0.06s)
./internal/inventory --- PASS: TestAWalksStartIsKeptAndARefusedSaveLeavesItUnsaid (0.06s)
./internal/inventory --- PASS: TestAWalksRestIsReadFromEachMachinesOwnSend (0.06s)
./internal/inventory --- PASS: TestAStoredBuildWithASilentMergeableFileIsStillReadAndComposed (0.06s)
```
git range-diff 4473bc7..4c965e3c 584ee991..3275a16b shows the rebase changes only the testdata/store-tests hunk — it keeps both TestReplay340 (picked up from main) and TestOnlyATrustedFilesNamedKeyIsRefusedThroughAVerb (this PR's own line), and the diff of the actual code (internal/catalogue/terminal_keys.go and the two test files) is byte-identical to the reviewed head. go vet ./internal/catalogue/ is clean and go test -race ./internal/catalogue/ is ok (18.3s); gitea's statuses on 3275a16b read mesh/merge-gate success ("head 3275a16beb merged into trunk 584ee99196 — pass: builds build-agent, mesh-controller → ace, g14, novox, shanks"), mesh/repo-check success ("its merge-check.sh passed"), and mesh/delivery success ("ready: it delivers once merged").
Verdict: approve at 3275a16bebbbc494adb63a8800d9a9f30b9b66b7
`git range-diff 4473bc7..4c965e3c 584ee991..3275a16b` shows the rebase changes only the testdata/store-tests hunk — it keeps both TestReplay340 (picked up from main) and TestOnlyATrustedFilesNamedKeyIsRefusedThroughAVerb (this PR's own line), and the diff of the actual code (internal/catalogue/terminal_keys.go and the two test files) is byte-identical to the reviewed head. `go vet ./internal/catalogue/` is clean and `go test -race ./internal/catalogue/` is ok (18.3s); gitea's statuses on 3275a16b read mesh/merge-gate success ("head 3275a16bebbb merged into trunk 584ee991961c — pass: builds build-agent, mesh-controller → ace, g14, novox, shanks"), mesh/repo-check success ("its merge-check.sh passed"), and mesh/delivery success ("ready: it delivers once merged").
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
What
TrustedMergeablereturns nothing for a module whose mergeable files all name their keys (ADR 0326), andasksForreads a naming file'stakes-settingsas the keys it asks for. So for such a module only a trusted file's named keys are terminal keys (refused through thesettingsverb, proposed instead), and a key of a file marked"trusted": falseis set through the verb. A module whose files name no keys keeps the whole-layer rule of issue 340.Why
ADR 0329 §5: betterbird's
tags(intags.json,trusted: false) may be set through thesettingsverb, whileaccounts,identities,calendars,address-books,filtersandprefsstay the terminal's or the operator's warrant. Today any trusted mergeable file puts the module's whole layer at the terminal, because such a file took any key; withtakes-settingsa file takes exactly its named keys, and a key no file names is stray and refused where it is set, so the whole-layer rule is no longer needed for these modules (searxng, keycloak, betterbird).How it was tested
internal/catalogue:TestOnlyANamedKeyOfATrustedFileIsTheTerminals(betterbird's four files: terminal keys are accounts, address-books, calendars, filters, identities, prefs, not tags; a silent module keeps the whole layer). Fails without the change.cmd/mesh-controller(store test, added totestdata/store-tests):TestOnlyATrustedFilesNamedKeyIsRefusedThroughAVerb: tags set through the verb, accounts refused, the layer holds the tags alone. Fails without the change.go test ./internal/catalogue/ ./cmd/mesh-controller/against a throwaway postgres 17: ok; gofmt and vet clean.module checkon every catalogue manifest with this binary: 127 checked, no problem.Part of issue 586 (with novox/mesh-catalog fix/586-betterbird-owns-its-configuration).
Delivery
novox/mesh-controller@3275a16bebbb— delivered since 2026-10-13T03:46:32ZDelivery plan — builds build-agent, mesh-controller → ace, g14, novox, shanks; no bus step
Machines
Transitions
The commit's note under
refs/notes/mesh-plankeeps every transition:git log --notes=mesh-plan.Merge check at
3379ab3bJudged: head
3379ab3b61acmerged into trunk454a3db69a1e; read beside it: mesh-catalog39e7a06e6293, mesh-controller-main454a3db69a1e, mesh-host7a41e120635b, mesh-tools954e1a53eef9mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: build-agent, mesh-controller)mesh/repo-check: PASS — its merge-check.sh passedDelivery plan — builds build-agent, mesh-controller → ace, g14, novox, shanks; no bus step
Run by the build seat on shanks as
build-1791849840531899425(builds --log build-1791849840531899425).Out of date when it landed: out of date: judged against trunk
454a3db69a, the trunk is now 4473bc7d7315; judged again on a recheck or when it is mergedVerdict: request changes at
3379ab3b61Blocking
4473bc7d73), and it appended TestPlanAndNodeListAnOptionalRequirementLeftUnbound to the end of testdata/store-tests, the same place this change appends TestOnlyATrustedFilesNamedKeyIsRefusedThroughAVerb. A merge of this head into main stops with a content conflict in testdata/store-tests. The fix is a rebase that keeps both lines. I resolved it that way locally: go vet is clean and the two new tests, the issue 340 test and 281's store test pass on the result. The code itself needs no change; this is the only reason for this verdict, and a rebased head whose diff to main is these same four files is one I would approve.Findings that do not block
The code does what ADR 0329 §5 and ADR 0326 decide and nothing broader in the files. TrustedMergeable now answers nothing for a module whose mergeable files all carry takes-settings (namesItsKeys), and asksFor gives such a file exactly its named keys plus any ${setting:} its content asks for. A file that names no keys keeps the whole-layer rule of issue 340, and a mixed module cannot reach this path, because takenSettingsProblems refuses it where it is checked and where it is composed. A key no file names is stray and refused where it is set, as before.
I composed every module of mesh-catalog and mesh-media-catalog main through this head's catalogue package. Only betterbird, keycloak and searxng name their keys. Their terminal keys are now: betterbird places, accesses, accounts, prefs (accounts is its only mergeable file, trusted; prefs comes from user.js's placeholder); keycloak places, accesses, url, user, realm, issuer and its served authorization-path, token-path, userinfo-path (its runtime-config names url, user, realm, issuer and says nothing on trust, so it counts as trusted); searxng places, accesses and all ten keys its settings file names. Every other module with a mergeable file (39 of them) names no keys and keeps its whole layer at the terminal, unchanged. No ${setting:} placeholder anywhere in those three manifests falls outside the terminal keys. So no key that lands in a trusted file of any catalogue module becomes settable through the settings verb.
What does leave the terminal for keycloak and searxng is every key that was protected only by the whole-layer rule: the mesh words (ports, expose, reach, endpoints) and the keys their contributions declare, which a setting overrides (overridden in settings.go). For keycloak that is name on its postgres-database contribution and label and endpoint on its route; for searxng label and endpoint on its route. Those values reach a provider's received file, not keycloak's or searxng's own. This is the rule every module without a trusted mergeable file already lives under (model-usage, mesh-knowledge, n8n and umami contribute postgres-database the same way), so it is issue 339's scope and not a defect of this change. I think a contribution's key that names another module's resource, such as a database name, deserves its own issue, because through a verb it could point keycloak's login at another module's database.
Rollback is safe. The change stores nothing new and has no migration. On a rollback to main, a value set through the verb (betterbird's tags once it has a file) stays in the layer and is read and composed as before, since takes-settings filtering is already on main; main would only refuse the next verb change to that module's layer, as it does today.
Tests. Both new tests pass at this head and fail with terminal_keys.go reverted to main: the unit test because TrustedMergeable answers [accounts configuration prefs], the store test because the tags change is refused under issue 340. go vet ./... is clean and gofmt lists nothing. go test -race -count=1 ./internal/catalogue/ ./cmd/mesh-controller/ passes against a throwaway postgres 17 (catalogue 10 s, mesh-controller 315 s).
Remark: the verb judges a layer change against the module's current definition in the catalogue table, while a node that has not yet received a new build composes with the build it has. That was already so before this change; it matters here only for a module whose stored build is silent and whose new definition names its keys, during its walk.
Statuses at this head, from the forge: mesh/merge-gate pending, "out of date: judged against trunk
454a3db69a, the trunk is now 4473bc7d7315; judged again on a recheck or when it is merged"; mesh/repo-check pending with the same words; mesh/delivery pending, "checking". The forge says it is not mergeable while both required checks are pending.3379ab3b61to4c965e3cf6Verdict: approve at
4c965e3cf6The rebase adds nothing beyond itself. git range-diff 454a3db..3379ab3b against 4473bc7..4c965e3 shows one commit, with the same message and the same code. The only difference is in testdata/store-tests, which now carries both #281's TestPlanAndNodeListAnOptionalRequirementLeftUnbound and this change's TestOnlyATrustedFilesNamedKeyIsRefusedThroughAVerb. The diff to main is the same four files as before (79 lines added, 1 removed). This settles the only blocking finding of my review of
3379ab3b, and its other findings stand unchanged.go build ./... and go vet ./... are clean, and go test -race -count=1 ./internal/catalogue/ passes in 13.8 s.
Statuses at this head, from the forge: mesh/merge-gate is pending with "building on ace since 02:21", mesh/repo-check is missing, and mesh/delivery is pending with "checking". The forge says the pull request is not mergeable until both required checks are a success, so it must not be merged before then.
Merge check at
4c965e3cJudged: head
4c965e3cf6d5merged into trunk4473bc7d7315; read beside it: mesh-catalog39e7a06e6293, mesh-controller-main4473bc7d7315, mesh-host7a41e120635b, mesh-tools954e1a53eef9mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: build-agent, mesh-controller)mesh/repo-check: FAIL — its merge-check.sh failed: --- FAIL: TestBorrowedWordsAreLogged (0.01s)Delivery plan — builds build-agent, mesh-controller → ace, g14, novox, shanks; no bus step
Run by the build seat on ace as
build-1791850897302374619(builds --log build-1791850897302374619).Merge check at
4c965e3cJudged: head
4c965e3cf6d5merged into trunk584ee991961cmesh/merge-gate: FAIL — head4c965e3cf6does not merge cleanly into trunk584ee99196: in conflict testdata/store-tests (modules: build-agent, mesh-controller)mesh/repo-check: FAIL — head4c965e3cf6does not merge cleanly into trunk584ee99196: in conflict testdata/store-testsDelivery plan — builds build-agent, mesh-controller → ace, g14, novox, shanks; no bus step
Run by the build seat on ace as
build-1791861685670977695(builds --log build-1791861685670977695).4c965e3cf6to3275a16bebMerge check at
3275a16bJudged: head
3275a16bebbbmerged into trunk584ee991961c; read beside it: mesh-catalogf88e3452f8b8, mesh-controller-main584ee991961c, mesh-host7a41e120635b, mesh-tools954e1a53eef9mesh/merge-gate: PASS — every machine composes with the change as it did without (4 of 4 compose) (modules: build-agent, mesh-controller)mesh/repo-check: PASS — its merge-check.sh passedDelivery plan — builds build-agent, mesh-controller → ace, g14, novox, shanks; no bus step
Run by the build seat on g14 as
build-1791861829243255338(builds --log build-1791861829243255338).Verdict: approve at
3275a16bebgit range-diff 4473bc7..4c965e3c 584ee991..3275a16bshows the rebase changes only the testdata/store-tests hunk — it keeps both TestReplay340 (picked up from main) and TestOnlyATrustedFilesNamedKeyIsRefusedThroughAVerb (this PR's own line), and the diff of the actual code (internal/catalogue/terminal_keys.go and the two test files) is byte-identical to the reviewed head.go vet ./internal/catalogue/is clean andgo test -race ./internal/catalogue/is ok (18.3s); gitea's statuses on3275a16bread mesh/merge-gate success ("head3275a16bebmerged into trunk584ee99196— pass: builds build-agent, mesh-controller → ace, g14, novox, shanks"), mesh/repo-check success ("its merge-check.sh passed"), and mesh/delivery success ("ready: it delivers once merged").