What: the Go toolchain's compile line adds -buildvcs=false to GOFLAGS (beside -trimpath), in internal/builder/toolchain.go.
Why: ADR 0267 rule 6 says a Go build uses -trimpath and -buildvcs=false, so nothing in an artifact varies with the commit. The second half was never built. A module built from its repository's root (the controller) is compiled with the clone's .git in view, and Go's default -buildvcs=auto stamps vcs.revision, vcs.time and vcs.modified into the binary. A merge that changed only README.md therefore made a new digest of an unchanged program. A module in a subdirectory was not affected (its mount holds no .git), and images that name compiles are handed a narrowed tree without .git already.
Tests (fail on main):
TestAGoBundleBuiltTwiceFromOneBuildSourceIsOneDigest runs the toolchain's own compile line over a fixture repository in two clones at two paths, at two commits that differ only in README.md. On main it fails: the two binaries carry their commits and differ (41912235fa6e against e7f9391d6c08). With the fix they are one digest. It skips where go or git is missing.
TestTheGoToolchainStampsNoVersionControl: the compile line says -buildvcs=false.
go test ./internal/builder/ passes, and merge-check.sh exits 0 (without MESH_TEST_POSTGRES, so the store tests were skipped; nothing here touches the store).
Effect once live: the toolchain recipe is part of every Go bundle's source fingerprint (toolchainOf), so each Go module's next build has a new fingerprint once. A subdirectory module's binary is byte-identical, so its digests match and nothing is sent. A root-built module (the controller) gets one new digest once, then stays reproducible.
Part of issue 363 (the build of ADR 0267). The other open parts of that issue are not in this PR.
**What**: the Go toolchain's compile line adds `-buildvcs=false` to `GOFLAGS` (beside `-trimpath`), in `internal/builder/toolchain.go`.
**Why**: ADR 0267 rule 6 says a Go build uses `-trimpath` and `-buildvcs=false`, so nothing in an artifact varies with the commit. The second half was never built. A module built from its repository's root (the controller) is compiled with the clone's `.git` in view, and Go's default `-buildvcs=auto` stamps `vcs.revision`, `vcs.time` and `vcs.modified` into the binary. A merge that changed only `README.md` therefore made a new digest of an unchanged program. A module in a subdirectory was not affected (its mount holds no `.git`), and images that name `compiles` are handed a narrowed tree without `.git` already.
**Tests (fail on main)**:
- `TestAGoBundleBuiltTwiceFromOneBuildSourceIsOneDigest` runs the toolchain's own compile line over a fixture repository in two clones at two paths, at two commits that differ only in `README.md`. On main it fails: the two binaries carry their commits and differ (`41912235fa6e` against `e7f9391d6c08`). With the fix they are one digest. It skips where `go` or `git` is missing.
- `TestTheGoToolchainStampsNoVersionControl`: the compile line says `-buildvcs=false`.
`go test ./internal/builder/` passes, and `merge-check.sh` exits 0 (without `MESH_TEST_POSTGRES`, so the store tests were skipped; nothing here touches the store).
**Effect once live**: the toolchain recipe is part of every Go bundle's source fingerprint (`toolchainOf`), so each Go module's next build has a new fingerprint once. A subdirectory module's binary is byte-identical, so its digests match and nothing is sent. A root-built module (the controller) gets one new digest once, then stays reproducible.
Part of issue 363 (the build of ADR 0267). The other open parts of that issue are not in this PR.
A module built from its repository's root is compiled with the clone's .git
in view, and Go stamped the commit into the binary: a merge that changed only
a README made a new digest of an unchanged program.
build-agent keeps data (ADR 0233): what it holds is backed up before it moves
route-proxy provides route: its consumers are sent again after it
route-proxy 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, route-proxy is judged on its first machine
Machines
mesh-controller on novox: passed — healthy 3 times over 3m38s
mesh-controller on the rest running it: sent
build-agent on ace: passed — healthy 1 times over 30s
build-agent on the rest running it: sent
route-proxy on ace: passed — healthy 1 times over 30s
route-proxy on the rest running it: sent
Transitions
2026-10-13 04:47 (new) → proposed (announced): novox/mesh-controller#292's head announced
2026-10-13 04:54 proposed → checked (checked): a verdict names this commit and the trunk's head as its trunk commit
2026-10-13 04:54 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
2026-10-13 04:59 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 04:59 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 05:13 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@ef3e5ae9b0dc` — **delivered** since 2026-10-13T05:13:04Z
**Delivery plan** — builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step
- tier 0: mesh-controller
- tier 1: build-agent
- tier 2: route-proxy
- ace: receives build-agent, route-proxy
- g14: receives build-agent
- novox: receives mesh-controller, build-agent, route-proxy
- shanks: receives build-agent
- build-agent keeps data (ADR 0233): what it holds is backed up before it moves
- route-proxy provides route: its consumers are sent again after it
- route-proxy 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, route-proxy is judged on its first machine
**Machines**
- mesh-controller on novox: passed — healthy 3 times over 3m38s
- mesh-controller on the rest running it: sent
- build-agent on ace: passed — healthy 1 times over 30s
- build-agent on the rest running it: sent
- route-proxy on ace: passed — healthy 1 times over 30s
- route-proxy on the rest running it: sent
**Transitions**
- 2026-10-13 04:47 (new) → proposed (announced): novox/mesh-controller#292's head announced
- 2026-10-13 04:54 proposed → checked (checked): a verdict names this commit and the trunk's head as its trunk commit
- 2026-10-13 04:54 checked → ready (accepted): the gate passed or warned, and the repository's own check did not fail
- 2026-10-13 04:59 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 04:59 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 05:13 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 bcdb1ad4
Judged: head bcdb1ad4f897 merged into trunk e0d69ab7a05b; read beside it: mesh-catalog 53e51864969f, mesh-controller-main e0d69ab7a05b, 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: internal/builder/reproducible_test.go
Run by the build seat on ace as build-1791865799677642678 (builds --log build-1791865799677642678).
--- 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-13T04:25:17Z 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-13T04:25:17Z
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
--- its merge-check.sh (go toolchain)
ok github.com/novox/mesh-controller/cmd/mesh-builder 1.063s
ok github.com/novox/mesh-controller/cmd/mesh-controller 156.245s
ok github.com/novox/mesh-controller/examples/objectstore-provisioner 1.039s
ok github.com/novox/mesh-controller/examples/postgres-provisioner 1.039s
ok github.com/novox/mesh-controller/examples/redis-provisioner 1.036s
ok github.com/novox/mesh-controller/examples/route-proxy 1.169s
ok github.com/novox/mesh-controller/internal/artifacts 1.100s
? github.com/novox/mesh-controller/internal/beside [no test files]
ok github.com/novox/mesh-controller/internal/broker 4.172s
ok github.com/novox/mesh-controller/internal/builder 41.339s
ok github.com/novox/mesh-controller/internal/catalogue 8.180s
ok github.com/novox/mesh-controller/internal/conditions 2.667s
ok github.com/novox/mesh-controller/internal/envfile 1.041s
ok github.com/novox/mesh-controller/internal/facts 1.069s
ok github.com/novox/mesh-controller/internal/identity 5.011s
ok github.com/novox/mesh-controller/internal/inventory 33.519s
ok github.com/novox/mesh-controller/internal/lease 17.741s
ok github.com/novox/mesh-controller/internal/licences 4.270s
ok github.com/novox/mesh-controller/internal/licences/adapters 1.039s
ok github.com/novox/mesh-controller/internal/link 58.764s
ok github.com/novox/mesh-controller/internal/lint 2.479s
ok github.com/novox/mesh-controller/internal/outward 1.080s
ok github.com/novox/mesh-controller/internal/overlay 1.060s
ok github.com/novox/mesh-controller/internal/secrets 1.466s
ok github.com/novox/mesh-controller/internal/store 3.809s
ok github.com/novox/mesh-controller/internal/testbus 1.244s
ok github.com/novox/mesh-controller/internal/token 1.039s
store tests, each run against the store:
./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeWalksTheOthersAgain (0.20s)
./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeEndsTheMergesThatContainIt (0.20s)
./cmd/mesh-controller --- PASS: TestAStopWalksTheOthersAgainInTheOpenBatch (0.20s)
./cmd/mesh-controller --- PASS: TestAStopNamesWhatStaysOnTheMachinesAndWhatStillCarriesIt (0.19s)
./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeLeavesItOutOfABatch (0.19s)
./cmd/mesh-controller --- PASS: TestSavingPlansAndMovingMergesIsOneAct (0.16s)
./cmd/mesh-controller --- PASS: TestAPlanFollowedFromTheStoreAnswersWhenItMoves (1.95s)
./cmd/mesh-controller --- PASS: TestNodeShowAndStatusReadTheLastSendFromTheStore (0.23s)
./cmd/mesh-controller --- PASS: TestTheConditionsVerbReadsTheLooksTheBucketNoLongerHolds (0.12s)
./cmd/mesh-controller --- PASS: TestAWalkLetGoAndStoppedByVerbsIsSaidStartedAndEnded (0.23s)
./cmd/mesh-controller --- PASS: TestAWalkStoppedOrClosedByAPersonIsSaidEndedStopped (0.23s)
./cmd/mesh-controller --- PASS: TestAWalkRetriedByAPersonIsSaidStartedAgain (0.19s)
./cmd/mesh-controller --- PASS: TestABacklogReleasedByAPersonIsSaidStarted (0.19s)
./cmd/mesh-controller --- PASS: TestAWalkEndedByCancelOrClearIsSaidEnded (0.24s)
./cmd/mesh-controller --- PASS: TestAWalkRestartedByARebuildIsSaidStarted (0.19s)
./cmd/mesh-controller --- PASS: TestAWalkStoppedByHandAndRetriedEndsFailedWhenItFailsAgain (0.24s)
./cmd/mesh-controller --- PASS: TestReplay237 (0.18s)
./cmd/mesh-controller --- PASS: TestAnUnassignThatLeavesItsNodeUnresolvedSaysSoOnceInItsAnswer (0.19s)
./cmd/mesh-controller --- PASS: TestAnUnassignThatLeavesItsNodeResolvedSaysNothingOfIt (0.19s)
./cmd/mesh-controller --- PASS: TestAnAssignThatLeavesItsNodeUnresolvedSaysOnlyThePlansRefusal (0.18s)
./cmd/mesh-controller --- PASS: TestADirectoryOwnersKeyIsRefusedThroughAVerb (0.21s)
./cmd/mesh-controller --- PASS: TestTheSendMakesNoValueForAnOutsideSecretNobodyGave (0.26s)
./cmd/mesh-controller --- PASS: TestAQuestionComposesWithoutAnOutsideSecretNobodyGave (0.26s)
./cmd/mesh-controller --- PASS: TestReplay201 (0.15s)
./cmd/mesh-controller --- PASS: TestARollbackWhoseSendWasRefusedIsCompletedByTheNextSend (0.15s)
./cmd/mesh-controller --- PASS: TestAGateJudgesTheOtherMovesBesideAKeptCore (0.14s)
./cmd/mesh-controller --- PASS: TestReplay401 (0.27s)
./cmd/mesh-controller --- PASS: TestReplay201ThePlansSend (0.23s)
./cmd/mesh-controller --- PASS: TestPlanAndNodeListAnOptionalRequirementLeftUnbound (0.26s)
./cmd/mesh-controller --- PASS: TestReplay340 (0.24s)
./cmd/mesh-controller --- PASS: TestOnlyATrustedFilesNamedKeyIsRefusedThroughAVerb (0.20s)
./cmd/mesh-controller --- PASS: TestReplay349 (0.19s)
./internal/inventory --- PASS: TestTheLastSendSaysWhatTheMachineAnswered (0.08s)
./internal/inventory --- PASS: TestAReportIsTheLastSendsAnswerOnlyWhenItIsAboutThatSend (0.08s)
./internal/inventory --- PASS: TestAnIssuedValueIsSealedToEveryHolderOnceAndNotAgain (0.10s)
./internal/inventory --- PASS: TestAnIssuedValueIsSealedAgainAfterAKeyChangeOrAnAcceptance (0.09s)
./internal/inventory --- PASS: TestAConditionsLooksAreKeptBesideTheBucket (0.06s)
./internal/inventory --- PASS: TestAPlanIdHoldingAQuoteIsReadAsAPlainId (0.07s)
./internal/inventory --- PASS: TestAWalksStartIsKeptAndARefusedSaveLeavesItUnsaid (0.07s)
./internal/inventory --- PASS: TestAWalksRestIsReadFromEachMachinesOwnSend (0.07s)
./internal/inventory --- PASS: TestAStoredBuildWithASilentMergeableFileIsStillReadAndComposed (0.08s)
**Merge check** at `bcdb1ad4`
Judged: head `bcdb1ad4f897` merged into trunk `e0d69ab7a05b`; read beside it: mesh-catalog `53e51864969f`, mesh-controller-main `e0d69ab7a05b`, 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: internal/builder/reproducible_test.go
Run by the build seat on ace as `build-1791865799677642678` (`builds --log build-1791865799677642678`).
```
--- 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-13T04:25:17Z 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-13T04:25:17Z
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
--- its merge-check.sh (go toolchain)
ok github.com/novox/mesh-controller/cmd/mesh-builder 1.063s
ok github.com/novox/mesh-controller/cmd/mesh-controller 156.245s
ok github.com/novox/mesh-controller/examples/objectstore-provisioner 1.039s
ok github.com/novox/mesh-controller/examples/postgres-provisioner 1.039s
ok github.com/novox/mesh-controller/examples/redis-provisioner 1.036s
ok github.com/novox/mesh-controller/examples/route-proxy 1.169s
ok github.com/novox/mesh-controller/internal/artifacts 1.100s
? github.com/novox/mesh-controller/internal/beside [no test files]
ok github.com/novox/mesh-controller/internal/broker 4.172s
ok github.com/novox/mesh-controller/internal/builder 41.339s
ok github.com/novox/mesh-controller/internal/catalogue 8.180s
ok github.com/novox/mesh-controller/internal/conditions 2.667s
ok github.com/novox/mesh-controller/internal/envfile 1.041s
ok github.com/novox/mesh-controller/internal/facts 1.069s
ok github.com/novox/mesh-controller/internal/identity 5.011s
ok github.com/novox/mesh-controller/internal/inventory 33.519s
ok github.com/novox/mesh-controller/internal/lease 17.741s
ok github.com/novox/mesh-controller/internal/licences 4.270s
ok github.com/novox/mesh-controller/internal/licences/adapters 1.039s
ok github.com/novox/mesh-controller/internal/link 58.764s
ok github.com/novox/mesh-controller/internal/lint 2.479s
ok github.com/novox/mesh-controller/internal/outward 1.080s
ok github.com/novox/mesh-controller/internal/overlay 1.060s
ok github.com/novox/mesh-controller/internal/secrets 1.466s
ok github.com/novox/mesh-controller/internal/store 3.809s
ok github.com/novox/mesh-controller/internal/testbus 1.244s
ok github.com/novox/mesh-controller/internal/token 1.039s
store tests, each run against the store:
./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeWalksTheOthersAgain (0.20s)
./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeEndsTheMergesThatContainIt (0.20s)
./cmd/mesh-controller --- PASS: TestAStopWalksTheOthersAgainInTheOpenBatch (0.20s)
./cmd/mesh-controller --- PASS: TestAStopNamesWhatStaysOnTheMachinesAndWhatStillCarriesIt (0.19s)
./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeLeavesItOutOfABatch (0.19s)
./cmd/mesh-controller --- PASS: TestSavingPlansAndMovingMergesIsOneAct (0.16s)
./cmd/mesh-controller --- PASS: TestAPlanFollowedFromTheStoreAnswersWhenItMoves (1.95s)
./cmd/mesh-controller --- PASS: TestNodeShowAndStatusReadTheLastSendFromTheStore (0.23s)
./cmd/mesh-controller --- PASS: TestTheConditionsVerbReadsTheLooksTheBucketNoLongerHolds (0.12s)
./cmd/mesh-controller --- PASS: TestAWalkLetGoAndStoppedByVerbsIsSaidStartedAndEnded (0.23s)
./cmd/mesh-controller --- PASS: TestAWalkStoppedOrClosedByAPersonIsSaidEndedStopped (0.23s)
./cmd/mesh-controller --- PASS: TestAWalkRetriedByAPersonIsSaidStartedAgain (0.19s)
./cmd/mesh-controller --- PASS: TestABacklogReleasedByAPersonIsSaidStarted (0.19s)
./cmd/mesh-controller --- PASS: TestAWalkEndedByCancelOrClearIsSaidEnded (0.24s)
./cmd/mesh-controller --- PASS: TestAWalkRestartedByARebuildIsSaidStarted (0.19s)
./cmd/mesh-controller --- PASS: TestAWalkStoppedByHandAndRetriedEndsFailedWhenItFailsAgain (0.24s)
./cmd/mesh-controller --- PASS: TestReplay237 (0.18s)
./cmd/mesh-controller --- PASS: TestAnUnassignThatLeavesItsNodeUnresolvedSaysSoOnceInItsAnswer (0.19s)
./cmd/mesh-controller --- PASS: TestAnUnassignThatLeavesItsNodeResolvedSaysNothingOfIt (0.19s)
./cmd/mesh-controller --- PASS: TestAnAssignThatLeavesItsNodeUnresolvedSaysOnlyThePlansRefusal (0.18s)
./cmd/mesh-controller --- PASS: TestADirectoryOwnersKeyIsRefusedThroughAVerb (0.21s)
./cmd/mesh-controller --- PASS: TestTheSendMakesNoValueForAnOutsideSecretNobodyGave (0.26s)
./cmd/mesh-controller --- PASS: TestAQuestionComposesWithoutAnOutsideSecretNobodyGave (0.26s)
./cmd/mesh-controller --- PASS: TestReplay201 (0.15s)
./cmd/mesh-controller --- PASS: TestARollbackWhoseSendWasRefusedIsCompletedByTheNextSend (0.15s)
./cmd/mesh-controller --- PASS: TestAGateJudgesTheOtherMovesBesideAKeptCore (0.14s)
./cmd/mesh-controller --- PASS: TestReplay401 (0.27s)
./cmd/mesh-controller --- PASS: TestReplay201ThePlansSend (0.23s)
./cmd/mesh-controller --- PASS: TestPlanAndNodeListAnOptionalRequirementLeftUnbound (0.26s)
./cmd/mesh-controller --- PASS: TestReplay340 (0.24s)
./cmd/mesh-controller --- PASS: TestOnlyATrustedFilesNamedKeyIsRefusedThroughAVerb (0.20s)
./cmd/mesh-controller --- PASS: TestReplay349 (0.19s)
./internal/inventory --- PASS: TestTheLastSendSaysWhatTheMachineAnswered (0.08s)
./internal/inventory --- PASS: TestAReportIsTheLastSendsAnswerOnlyWhenItIsAboutThatSend (0.08s)
./internal/inventory --- PASS: TestAnIssuedValueIsSealedToEveryHolderOnceAndNotAgain (0.10s)
./internal/inventory --- PASS: TestAnIssuedValueIsSealedAgainAfterAKeyChangeOrAnAcceptance (0.09s)
./internal/inventory --- PASS: TestAConditionsLooksAreKeptBesideTheBucket (0.06s)
./internal/inventory --- PASS: TestAPlanIdHoldingAQuoteIsReadAsAPlainId (0.07s)
./internal/inventory --- PASS: TestAWalksStartIsKeptAndARefusedSaveLeavesItUnsaid (0.07s)
./internal/inventory --- PASS: TestAWalksRestIsReadFromEachMachinesOwnSend (0.07s)
./internal/inventory --- PASS: TestAStoredBuildWithASilentMergeableFileIsStillReadAndComposed (0.08s)
```
I read ADR 0267 (knowledge-base.get, reasoning true). Rule 6 says a build is reproducible where its fingerprint cannot be narrow: for Go, -trimpath and -buildvcs=false, and no .git in what a recipe sees, "for every kind" of artifact. This PR adds -buildvcs=false to the one Go toolchain entry in internal/builder/toolchain.go, which is the entry the issue's symptom (a README-only merge producing a new controller digest) names.
-buildvcs=false coverage is incomplete for "every Go build path" in this repository. Two other Go compiles still omit it and still see .git (there is no .dockerignore at the repository root):
The root Dockerfile, used by make image to build the control-plane image: RUN CGO_ENABLED=0 GOFLAGS=-mod=vendor GOPROXY=off go build -trimpath -ldflags "-s -w -X main.version=${VERSION}" -o /mesh-controller ./cmd/mesh-controller. No -buildvcs=false.
internal/builder/check.go, three call sites (judgeFor twice, judge once) that build a "judge" binary of ./cmd/mesh-controller with []string{"CGO_ENABLED=0", "GOFLAGS=-mod=vendor", "GOPROXY=off", ...}, "go", "build", "-o", bin, "./cmd/mesh-controller". No -buildvcs=false there either.
These may be judged out of this PR's declared scope (issue 363 lists rules 1, 2, 3 and 5 as the other open parts, not rule 6's extent), but the PR's own framing — "every Go build" — and ADR 0267 rule 6's "for every kind" do not carve them out, so I am flagging them rather than assuming they are deliberately deferred.
I built the new test file (internal/builder/reproducible_test.go) against main (1d244d5, with toolchain.go unmodified) and against the PR head. On main both new tests fail:
"--- FAIL: TestAGoBundleBuiltTwiceFromOneBuildSourceIsOneDigest (0.17s)" with "one build source, two digests: f11df5b9865f at 676a76f66278, e255b970dbc0 at 53566ea14c2c (compiled with "env CGO_ENABLED=0 GOFLAGS=-trimpath go build")", and
"--- FAIL: TestTheGoToolchainStampsNoVersionControl (0.00s)" with "the go toolchain stamps the commit into what it compiles: "env CGO_ENABLED=0 GOFLAGS=-trimpath go build"".
At the PR head both pass: "--- PASS: TestAGoBundleBuiltTwiceFromOneBuildSourceIsOneDigest (0.14s)" and "--- PASS: TestTheGoToolchainStampsNoVersionControl (0.00s)", "ok github.com/novox/mesh-controller/internal/builder 0.141s".
I grepped mesh-controller, mesh-host, mesh-tools and mesh-catalog for vcs.revision and ReadBuildInfo/BuildInfo, outside vendor/node_modules. mesh-controller's own use (cmd/mesh-controller/checks.go:321, sdkPinned) reads info.Deps for the SDK module's pinned version, not info.Settings, so -buildvcs=false does not affect it. mesh-host and mesh-catalog have no such use. mesh-tools does, and it is a real conflict with this change: node-tools/internal/alive/alive.go's Version() reads "vcs.revision" out of debug.ReadBuildInfo().Settings and publishes it every minute as Beat.Version on the tools-alive heartbeat the controller's watchdog depends on. node-tools/module.json declares its runtime bundle with "language": "go", so it compiles through this same toolchain entry. Once this PR merges, node-tools binaries carry no vcs.revision, so Version() returns "" from then on — the heartbeat's version field goes silently empty for every node, mesh-wide, and nothing in this PR's test suite (scoped to mesh-controller) catches it because the break lands in a different repository.
go vet ./... and go vet ./internal/builder/... are both clean (no output). go test -race ./internal/builder/... passes: "ok github.com/novox/mesh-controller/internal/builder 31.442s".
The current required-check statuses on bcdb1ad4 are stale: the most recent mesh/merge-gate and mesh/repo-check entries both read "out of date: judged against trunk e0d69ab7a0, the trunk is now 1d244d5aa24e; judged again on a recheck or when it is merged" (their prior run, against e0d69ab7, both read "success"). This needs a fresh mesh-delivery.recheck regardless of the finding above.
Recommendation: before merging, either give node-tools' heartbeat a version source that survives -buildvcs=false (its own -ldflags -X stamp, the way the control-plane Dockerfile already does with main.version) or explicitly decide and record that the heartbeat's version field is going away, and say in the PR body whether the root Dockerfile and check.go's judge builds are deliberately out of scope for rule 6 or need their own follow-up issue.
Verdict: request changes at bcdb1ad4f8979401661974ede5c930ab4ef2e45d
I read ADR 0267 (knowledge-base.get, reasoning true). Rule 6 says a build is reproducible where its fingerprint cannot be narrow: for Go, -trimpath and -buildvcs=false, and no .git in what a recipe sees, "for every kind" of artifact. This PR adds -buildvcs=false to the one Go toolchain entry in internal/builder/toolchain.go, which is the entry the issue's symptom (a README-only merge producing a new controller digest) names.
1. -buildvcs=false coverage is incomplete for "every Go build path" in this repository. Two other Go compiles still omit it and still see .git (there is no .dockerignore at the repository root):
- The root Dockerfile, used by `make image` to build the control-plane image: `RUN CGO_ENABLED=0 GOFLAGS=-mod=vendor GOPROXY=off go build -trimpath -ldflags "-s -w -X main.version=${VERSION}" -o /mesh-controller ./cmd/mesh-controller`. No -buildvcs=false.
- internal/builder/check.go, three call sites (judgeFor twice, judge once) that build a "judge" binary of ./cmd/mesh-controller with `[]string{"CGO_ENABLED=0", "GOFLAGS=-mod=vendor", "GOPROXY=off", ...}, "go", "build", "-o", bin, "./cmd/mesh-controller"`. No -buildvcs=false there either.
These may be judged out of this PR's declared scope (issue 363 lists rules 1, 2, 3 and 5 as the other open parts, not rule 6's extent), but the PR's own framing — "every Go build" — and ADR 0267 rule 6's "for every kind" do not carve them out, so I am flagging them rather than assuming they are deliberately deferred.
2. I built the new test file (internal/builder/reproducible_test.go) against main (1d244d5, with toolchain.go unmodified) and against the PR head. On main both new tests fail:
"--- FAIL: TestAGoBundleBuiltTwiceFromOneBuildSourceIsOneDigest (0.17s)" with "one build source, two digests: f11df5b9865f at 676a76f66278, e255b970dbc0 at 53566ea14c2c (compiled with \"env CGO_ENABLED=0 GOFLAGS=-trimpath go build\")", and
"--- FAIL: TestTheGoToolchainStampsNoVersionControl (0.00s)" with "the go toolchain stamps the commit into what it compiles: \"env CGO_ENABLED=0 GOFLAGS=-trimpath go build\"".
At the PR head both pass: "--- PASS: TestAGoBundleBuiltTwiceFromOneBuildSourceIsOneDigest (0.14s)" and "--- PASS: TestTheGoToolchainStampsNoVersionControl (0.00s)", "ok github.com/novox/mesh-controller/internal/builder 0.141s".
3. I grepped mesh-controller, mesh-host, mesh-tools and mesh-catalog for vcs.revision and ReadBuildInfo/BuildInfo, outside vendor/node_modules. mesh-controller's own use (cmd/mesh-controller/checks.go:321, sdkPinned) reads info.Deps for the SDK module's pinned version, not info.Settings, so -buildvcs=false does not affect it. mesh-host and mesh-catalog have no such use. mesh-tools does, and it is a real conflict with this change: node-tools/internal/alive/alive.go's Version() reads "vcs.revision" out of debug.ReadBuildInfo().Settings and publishes it every minute as Beat.Version on the tools-alive heartbeat the controller's watchdog depends on. node-tools/module.json declares its runtime bundle with "language": "go", so it compiles through this same toolchain entry. Once this PR merges, node-tools binaries carry no vcs.revision, so Version() returns "" from then on — the heartbeat's version field goes silently empty for every node, mesh-wide, and nothing in this PR's test suite (scoped to mesh-controller) catches it because the break lands in a different repository.
4. go vet ./... and go vet ./internal/builder/... are both clean (no output). go test -race ./internal/builder/... passes: "ok github.com/novox/mesh-controller/internal/builder 31.442s".
The current required-check statuses on bcdb1ad4 are stale: the most recent mesh/merge-gate and mesh/repo-check entries both read "out of date: judged against trunk e0d69ab7a05b, the trunk is now 1d244d5aa24e; judged again on a recheck or when it is merged" (their prior run, against e0d69ab7, both read "success"). This needs a fresh mesh-delivery.recheck regardless of the finding above.
Recommendation: before merging, either give node-tools' heartbeat a version source that survives -buildvcs=false (its own -ldflags -X stamp, the way the control-plane Dockerfile already does with main.version) or explicitly decide and record that the heartbeat's version field is going away, and say in the PR body whether the root Dockerfile and check.go's judge builds are deliberately out of scope for rule 6 or need their own follow-up issue.
Covered: the root Dockerfile, which builds the genesis/lab image. It has COPY . . and no .dockerignore, so .git is in the build. Also covered: the Makefile-built recipes cmd/mesh-builder/Dockerfile and examples/{route-proxy,postgres,objectstore,redis-provisioner}/Dockerfile. All six now say -buildvcs=false. The new TestEveryGoRecipeInThisRepositoryStampsNoVersionControl fails on bcdb1ad4 and passes now.
Not covered: the three go build calls in internal/builder/check.go (judge, and judgeFor self and validator). Each writes a throwaway judge to <check root>/bin/. The judge runs once for the check and is never published, registered or fingerprinted, so it is not an artifact and rule 6 does not apply. The controller reads its own build info only in sdkPinned (cmd/mesh-controller/checks.go:321), and that reads info.Deps, which -buildvcs does not touch.
2. node-tools alive.Version is not a regression.
node-tools is built from the subdirectory node-tools/ of mesh-tools. The toolchain mounts only the module's directory (one(..., within, ...) → compile mounts tree:/app/modules/module), so Go never sees a .git and stamps nothing today.
Live on g14: go version -m /var/lib/mesh/daemons/node-tools/node-tools shows -trimpath=true and no vcs.* setting. The field is already empty on every node.
By contrast, the root-built node-engine on g14 (/usr/lib/nox-mesh-host/versions/838d94ad46e8/nox-mesh-host) carries vcs.revision=7a41e120… and vcs.time. That is the per-commit variation this PR removes.
Nothing reads the value either. link.Beats.Heard stores it in Beat.Version, and no code outside the tests reads that field.
So mesh-tools needs no change for this PR, and I opened no PR there.
If the heartbeat should carry an identity later, ADR 0267 rule 6 ("nothing in an artifact varies with the commit") rules out an -X commit stamp. The option it favours is the running binary's own digest (sha256 of /proc/self/exe), which equals the bundle's content and changes only with the program.
Other readers of vcs.* or ReadBuildInfo: I searched mesh-controller, mesh-host, mesh-tools, mesh-catalog and mesh-sdk. The only hits are checks.go:321 (Deps only) and mesh-tools node-tools/internal/alive/alive.go:37.
Tests: go test ./internal/builder/ passes at the new head.
Answers to review 159. New head: ef3e5ae9b0dc9abc68ddb9ecbe72ef163d2a59f2.
**1. Other Go compiles in this repository.**
- **Covered:** the root `Dockerfile`, which builds the genesis/lab image. It has `COPY . .` and no `.dockerignore`, so `.git` is in the build. Also covered: the Makefile-built recipes `cmd/mesh-builder/Dockerfile` and `examples/{route-proxy,postgres,objectstore,redis-provisioner}/Dockerfile`. All six now say `-buildvcs=false`. The new `TestEveryGoRecipeInThisRepositoryStampsNoVersionControl` fails on bcdb1ad4 and passes now.
- **Not covered:** the three `go build` calls in `internal/builder/check.go` (`judge`, and `judgeFor` self and validator). Each writes a throwaway judge to `<check root>/bin/`. The judge runs once for the check and is never published, registered or fingerprinted, so it is not an artifact and rule 6 does not apply. The controller reads its own build info only in `sdkPinned` (`cmd/mesh-controller/checks.go:321`), and that reads `info.Deps`, which `-buildvcs` does not touch.
**2. node-tools `alive.Version` is not a regression.**
- node-tools is built from the subdirectory `node-tools/` of mesh-tools. The toolchain mounts only the module's directory (`one(..., within, ...)` → `compile` mounts `tree:/app/modules/module`), so Go never sees a `.git` and stamps nothing today.
- Live on g14: `go version -m /var/lib/mesh/daemons/node-tools/node-tools` shows `-trimpath=true` and no `vcs.*` setting. The field is already empty on every node.
- By contrast, the root-built node-engine on g14 (`/usr/lib/nox-mesh-host/versions/838d94ad46e8/nox-mesh-host`) carries `vcs.revision=7a41e120…` and `vcs.time`. That is the per-commit variation this PR removes.
- Nothing reads the value either. `link.Beats.Heard` stores it in `Beat.Version`, and no code outside the tests reads that field.
- So mesh-tools needs no change for this PR, and I opened no PR there.
- If the heartbeat should carry an identity later, ADR 0267 rule 6 ("nothing in an artifact varies with the commit") rules out an `-X` commit stamp. The option it favours is the running binary's own digest (sha256 of `/proc/self/exe`), which equals the bundle's content and changes only with the program.
**Other readers of `vcs.*` or `ReadBuildInfo`:** I searched mesh-controller, mesh-host, mesh-tools, mesh-catalog and mesh-sdk. The only hits are `checks.go:321` (Deps only) and mesh-tools `node-tools/internal/alive/alive.go:37`.
Tests: `go test ./internal/builder/` passes at the new head.
I verified both answers in comment 11255 myself rather than taking them on faith.
On point 1: the diff now adds -buildvcs=false to the root Dockerfile and the five Makefile-built recipes (cmd/mesh-builder, and the postgres, objectstore, redis and route-proxy examples), which is every Dockerfile in this repository outside testdata/ (I listed them: 6 total, all now covered). The new TestEveryGoRecipeInThisRepositoryStampsNoVersionControl walks the repository for every Dockerfile with a go build line and fails if -buildvcs=false is missing; I ran it and it passes. I read internal/builder/check.go's three judge-build call sites again: the binaries they produce (bin/judge-of-itself, bin/judge-with-this-validator, bin/mesh-controller) are run locally to judge a merge-gate check and never reach Store.GetTagged, PublishImage or any other digest/fingerprint path I can find in that file — so leaving them alone is consistent with ADR 0267's scope (an artifact the mesh fingerprints and delivers), not an oversight.
On point 2, both claims hold:
I traced the call path for a Go bundle (builder.go: build() computes within as the module's own directory via inside(tree, path), then calls one(ctx, run, publish, manifest.Module, within, ...), which passes that within into compile() as its tree parameter, mounted alone as --volume tree:within). For node-tools, built from path "node-tools" inside mesh-tools (not the repository root), the toolchain container only ever sees that subdirectory, never the clone's .git beside it — matching the ADR 0267 context note that a subdirectory module's mount holds no .git. I also checked the live binary directly: go version -m /var/lib/mesh/daemons/node-tools/node-tools on g14 shows no vcs.* entry in its build settings at all, confirming this empirically, independent of this PR.
I grepped mesh-controller, mesh-host, mesh-tools and mesh-catalog for .Version and Beat reads. internal/link/serve.go does store alive.Version into ToolsBeats via Beats.Heard(...), and Beat.Version exists on the struct, but the only reader, cmd/mesh-controller/watchdogs.go's collectMachineFacts, calls link.ToolsBeats.Of(n.Name) and only takes beat.At and beat.Every into machineFacts.toolsHeard/toolsEvery — machineFacts has no version field at all, and nothing else in any of the four repositories reads Beat.Version. It is written and never read, so losing its value is not an observable regression.
go vet ./... and go test -race ./internal/builder/... are both still clean at this head (ok github.com/novox/mesh-controller/internal/builder 33.753s). mesh/merge-gate and mesh/repo-check are queued/building on this head as of this review; I did not wait on them.
Verdict: approve at ef3e5ae9b0dc9abc68ddb9ecbe72ef163d2a59f2
I verified both answers in comment 11255 myself rather than taking them on faith.
On point 1: the diff now adds -buildvcs=false to the root Dockerfile and the five Makefile-built recipes (cmd/mesh-builder, and the postgres, objectstore, redis and route-proxy examples), which is every Dockerfile in this repository outside testdata/ (I listed them: 6 total, all now covered). The new TestEveryGoRecipeInThisRepositoryStampsNoVersionControl walks the repository for every Dockerfile with a `go build` line and fails if `-buildvcs=false` is missing; I ran it and it passes. I read internal/builder/check.go's three judge-build call sites again: the binaries they produce (bin/judge-of-itself, bin/judge-with-this-validator, bin/mesh-controller) are run locally to judge a merge-gate check and never reach Store.GetTagged, PublishImage or any other digest/fingerprint path I can find in that file — so leaving them alone is consistent with ADR 0267's scope (an artifact the mesh fingerprints and delivers), not an oversight.
On point 2, both claims hold:
- I traced the call path for a Go bundle (builder.go: build() computes `within` as the module's own directory via `inside(tree, path)`, then calls `one(ctx, run, publish, manifest.Module, within, ...)`, which passes that `within` into compile() as its `tree` parameter, mounted alone as `--volume tree:within`). For node-tools, built from path "node-tools" inside mesh-tools (not the repository root), the toolchain container only ever sees that subdirectory, never the clone's .git beside it — matching the ADR 0267 context note that a subdirectory module's mount holds no .git. I also checked the live binary directly: `go version -m /var/lib/mesh/daemons/node-tools/node-tools` on g14 shows no vcs.* entry in its build settings at all, confirming this empirically, independent of this PR.
- I grepped mesh-controller, mesh-host, mesh-tools and mesh-catalog for `.Version` and `Beat` reads. `internal/link/serve.go` does store `alive.Version` into `ToolsBeats` via `Beats.Heard(...)`, and `Beat.Version` exists on the struct, but the only reader, `cmd/mesh-controller/watchdogs.go`'s `collectMachineFacts`, calls `link.ToolsBeats.Of(n.Name)` and only takes `beat.At` and `beat.Every` into `machineFacts.toolsHeard`/`toolsEvery` — `machineFacts` has no version field at all, and nothing else in any of the four repositories reads `Beat.Version`. It is written and never read, so losing its value is not an observable regression.
go vet ./... and go test -race ./internal/builder/... are both still clean at this head (`ok github.com/novox/mesh-controller/internal/builder 33.753s`). mesh/merge-gate and mesh/repo-check are queued/building on this head as of this review; I did not wait on them.
build-agent keeps data (ADR 0233): what it holds is backed up before it moves
route-proxy provides route: its consumers are sent again after it
route-proxy 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, route-proxy is judged on its first machine
read by no module's build: Dockerfile, examples/objectstore-provisioner/Dockerfile, examples/postgres-provisioner/Dockerfile, examples/redis-provisioner/Dockerfile, internal/builder/reproducible_test.go
Run by the build seat on novox as build-1791866869028220388 (builds --log build-1791866869028220388).
--- the gate: build-agent, mesh-controller, route-proxy
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-13T04:34:17Z 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-13T04:34:17Z
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 3 module(s) in 3 tier(s): build-agent, mesh-controller, route-proxy
notes:
- Dockerfile, examples/objectstore-provisioner/Dockerfile, examples/postgres-provisioner/Dockerfile, examples/redis-provisioner/Dockerfile and internal/builder/reproducible_test.go 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.042s
ok github.com/novox/mesh-controller/cmd/mesh-controller 207.448s
ok github.com/novox/mesh-controller/examples/objectstore-provisioner 1.023s
ok github.com/novox/mesh-controller/examples/postgres-provisioner 1.036s
ok github.com/novox/mesh-controller/examples/redis-provisioner 1.022s
ok github.com/novox/mesh-controller/examples/route-proxy 1.135s
ok github.com/novox/mesh-controller/internal/artifacts 1.061s
? github.com/novox/mesh-controller/internal/beside [no test files]
ok github.com/novox/mesh-controller/internal/broker 6.749s
ok github.com/novox/mesh-controller/internal/builder 56.647s
ok github.com/novox/mesh-controller/internal/catalogue 9.674s
ok github.com/novox/mesh-controller/internal/conditions 2.669s
ok github.com/novox/mesh-controller/internal/envfile 1.034s
ok github.com/novox/mesh-controller/internal/facts 1.033s
ok github.com/novox/mesh-controller/internal/identity 8.851s
ok github.com/novox/mesh-controller/internal/inventory 42.534s
ok github.com/novox/mesh-controller/internal/lease 17.699s
ok github.com/novox/mesh-controller/internal/licences 7.738s
ok github.com/novox/mesh-controller/internal/licences/adapters 1.012s
ok github.com/novox/mesh-controller/internal/link 64.589s
ok github.com/novox/mesh-controller/internal/lint 2.410s
ok github.com/novox/mesh-controller/internal/outward 1.037s
ok github.com/novox/mesh-controller/internal/overlay 1.024s
ok github.com/novox/mesh-controller/internal/secrets 1.465s
ok github.com/novox/mesh-controller/internal/store 4.868s
ok github.com/novox/mesh-controller/internal/testbus 1.202s
ok github.com/novox/mesh-controller/internal/token 1.017s
store tests, each run against the store:
./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeWalksTheOthersAgain (0.23s)
./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeEndsTheMergesThatContainIt (0.24s)
./cmd/mesh-controller --- PASS: TestAStopWalksTheOthersAgainInTheOpenBatch (0.28s)
./cmd/mesh-controller --- PASS: TestAStopNamesWhatStaysOnTheMachinesAndWhatStillCarriesIt (0.26s)
./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeLeavesItOutOfABatch (0.23s)
./cmd/mesh-controller --- PASS: TestSavingPlansAndMovingMergesIsOneAct (0.19s)
./cmd/mesh-controller --- PASS: TestAPlanFollowedFromTheStoreAnswersWhenItMoves (2.02s)
./cmd/mesh-controller --- PASS: TestNodeShowAndStatusReadTheLastSendFromTheStore (0.32s)
./cmd/mesh-controller --- PASS: TestTheConditionsVerbReadsTheLooksTheBucketNoLongerHolds (0.16s)
./cmd/mesh-controller --- PASS: TestAWalkLetGoAndStoppedByVerbsIsSaidStartedAndEnded (0.27s)
./cmd/mesh-controller --- PASS: TestAWalkStoppedOrClosedByAPersonIsSaidEndedStopped (0.28s)
./cmd/mesh-controller --- PASS: TestAWalkRetriedByAPersonIsSaidStartedAgain (0.22s)
./cmd/mesh-controller --- PASS: TestABacklogReleasedByAPersonIsSaidStarted (0.28s)
./cmd/mesh-controller --- PASS: TestAWalkEndedByCancelOrClearIsSaidEnded (0.37s)
./cmd/mesh-controller --- PASS: TestAWalkRestartedByARebuildIsSaidStarted (0.23s)
./cmd/mesh-controller --- PASS: TestAWalkStoppedByHandAndRetriedEndsFailedWhenItFailsAgain (0.29s)
./cmd/mesh-controller --- PASS: TestReplay237 (0.23s)
./cmd/mesh-controller --- PASS: TestAnUnassignThatLeavesItsNodeUnresolvedSaysSoOnceInItsAnswer (0.23s)
./cmd/mesh-controller --- PASS: TestAnUnassignThatLeavesItsNodeResolvedSaysNothingOfIt (0.24s)
./cmd/mesh-controller --- PASS: TestAnAssignThatLeavesItsNodeUnresolvedSaysOnlyThePlansRefusal (0.23s)
./cmd/mesh-controller --- PASS: TestADirectoryOwnersKeyIsRefusedThroughAVerb (0.25s)
./cmd/mesh-controller --- PASS: TestTheSendMakesNoValueForAnOutsideSecretNobodyGave (0.35s)
./cmd/mesh-controller --- PASS: TestAQuestionComposesWithoutAnOutsideSecretNobodyGave (0.33s)
./cmd/mesh-controller --- PASS: TestReplay201 (0.27s)
./cmd/mesh-controller --- PASS: TestARollbackWhoseSendWasRefusedIsCompletedByTheNextSend (0.16s)
./cmd/mesh-controller --- PASS: TestAGateJudgesTheOtherMovesBesideAKeptCore (0.17s)
./cmd/mesh-controller --- PASS: TestReplay401 (0.34s)
./cmd/mesh-controller --- PASS: TestReplay201ThePlansSend (0.26s)
./cmd/mesh-controller --- PASS: TestPlanAndNodeListAnOptionalRequirementLeftUnbound (0.31s)
./cmd/mesh-controller --- PASS: TestReplay340 (0.27s)
./cmd/mesh-controller --- PASS: TestOnlyATrustedFilesNamedKeyIsRefusedThroughAVerb (0.22s)
./cmd/mesh-controller --- PASS: TestReplay349 (0.22s)
./cmd/mesh-controller --- PASS: TestReplay348AFaultFromBeforeTheSendFailsNoGate (0.19s)
./internal/inventory --- PASS: TestTheLastSendSaysWhatTheMachineAnswered (0.09s)
./internal/inventory --- PASS: TestAReportIsTheLastSendsAnswerOnlyWhenItIsAboutThatSend (0.09s)
./internal/inventory --- PASS: TestAnIssuedValueIsSealedToEveryHolderOnceAndNotAgain (0.11s)
./internal/inventory --- PASS: TestAnIssuedValueIsSealedAgainAfterAKeyChangeOrAnAcceptance (0.10s)
./internal/inventory --- PASS: TestAConditionsLooksAreKeptBesideTheBucket (0.07s)
./internal/inventory --- PASS: TestAPlanIdHoldingAQuoteIsReadAsAPlainId (0.08s)
./internal/inventory --- PASS: TestAWalksStartIsKeptAndARefusedSaveLeavesItUnsaid (0.07s)
./internal/inventory --- PASS: TestAWalksRestIsReadFromEachMachinesOwnSend (0.08s)
./internal/inventory --- PASS: TestAStoredBuildWithASilentMergeableFileIsStillReadAndComposed (0.08s)
**Merge check** at `ef3e5ae9`
Judged: head `ef3e5ae9b0dc` merged into trunk `1d244d5aa24e`; read beside it: mesh-catalog `53e51864969f`, mesh-controller-main `1d244d5aa24e`, 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, route-proxy)
- `mesh/repo-check`: **PASS** — its merge-check.sh passed
**Delivery plan** — builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step
- tier 0: mesh-controller
- tier 1: build-agent
- tier 2: route-proxy
- ace: receives build-agent, route-proxy
- g14: receives build-agent
- novox: receives mesh-controller, build-agent, route-proxy
- shanks: receives build-agent
- build-agent keeps data (ADR 0233): what it holds is backed up before it moves
- route-proxy provides route: its consumers are sent again after it
- route-proxy 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, route-proxy is judged on its first machine
- read by no module's build: Dockerfile, examples/objectstore-provisioner/Dockerfile, examples/postgres-provisioner/Dockerfile, examples/redis-provisioner/Dockerfile, internal/builder/reproducible_test.go
Run by the build seat on novox as `build-1791866869028220388` (`builds --log build-1791866869028220388`).
```
--- the gate: build-agent, mesh-controller, route-proxy
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-13T04:34:17Z 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-13T04:34:17Z
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 3 module(s) in 3 tier(s): build-agent, mesh-controller, route-proxy
notes:
- Dockerfile, examples/objectstore-provisioner/Dockerfile, examples/postgres-provisioner/Dockerfile, examples/redis-provisioner/Dockerfile and internal/builder/reproducible_test.go 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.042s
ok github.com/novox/mesh-controller/cmd/mesh-controller 207.448s
ok github.com/novox/mesh-controller/examples/objectstore-provisioner 1.023s
ok github.com/novox/mesh-controller/examples/postgres-provisioner 1.036s
ok github.com/novox/mesh-controller/examples/redis-provisioner 1.022s
ok github.com/novox/mesh-controller/examples/route-proxy 1.135s
ok github.com/novox/mesh-controller/internal/artifacts 1.061s
? github.com/novox/mesh-controller/internal/beside [no test files]
ok github.com/novox/mesh-controller/internal/broker 6.749s
ok github.com/novox/mesh-controller/internal/builder 56.647s
ok github.com/novox/mesh-controller/internal/catalogue 9.674s
ok github.com/novox/mesh-controller/internal/conditions 2.669s
ok github.com/novox/mesh-controller/internal/envfile 1.034s
ok github.com/novox/mesh-controller/internal/facts 1.033s
ok github.com/novox/mesh-controller/internal/identity 8.851s
ok github.com/novox/mesh-controller/internal/inventory 42.534s
ok github.com/novox/mesh-controller/internal/lease 17.699s
ok github.com/novox/mesh-controller/internal/licences 7.738s
ok github.com/novox/mesh-controller/internal/licences/adapters 1.012s
ok github.com/novox/mesh-controller/internal/link 64.589s
ok github.com/novox/mesh-controller/internal/lint 2.410s
ok github.com/novox/mesh-controller/internal/outward 1.037s
ok github.com/novox/mesh-controller/internal/overlay 1.024s
ok github.com/novox/mesh-controller/internal/secrets 1.465s
ok github.com/novox/mesh-controller/internal/store 4.868s
ok github.com/novox/mesh-controller/internal/testbus 1.202s
ok github.com/novox/mesh-controller/internal/token 1.017s
store tests, each run against the store:
./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeWalksTheOthersAgain (0.23s)
./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeEndsTheMergesThatContainIt (0.24s)
./cmd/mesh-controller --- PASS: TestAStopWalksTheOthersAgainInTheOpenBatch (0.28s)
./cmd/mesh-controller --- PASS: TestAStopNamesWhatStaysOnTheMachinesAndWhatStillCarriesIt (0.26s)
./cmd/mesh-controller --- PASS: TestAStopWithoutAMergeLeavesItOutOfABatch (0.23s)
./cmd/mesh-controller --- PASS: TestSavingPlansAndMovingMergesIsOneAct (0.19s)
./cmd/mesh-controller --- PASS: TestAPlanFollowedFromTheStoreAnswersWhenItMoves (2.02s)
./cmd/mesh-controller --- PASS: TestNodeShowAndStatusReadTheLastSendFromTheStore (0.32s)
./cmd/mesh-controller --- PASS: TestTheConditionsVerbReadsTheLooksTheBucketNoLongerHolds (0.16s)
./cmd/mesh-controller --- PASS: TestAWalkLetGoAndStoppedByVerbsIsSaidStartedAndEnded (0.27s)
./cmd/mesh-controller --- PASS: TestAWalkStoppedOrClosedByAPersonIsSaidEndedStopped (0.28s)
./cmd/mesh-controller --- PASS: TestAWalkRetriedByAPersonIsSaidStartedAgain (0.22s)
./cmd/mesh-controller --- PASS: TestABacklogReleasedByAPersonIsSaidStarted (0.28s)
./cmd/mesh-controller --- PASS: TestAWalkEndedByCancelOrClearIsSaidEnded (0.37s)
./cmd/mesh-controller --- PASS: TestAWalkRestartedByARebuildIsSaidStarted (0.23s)
./cmd/mesh-controller --- PASS: TestAWalkStoppedByHandAndRetriedEndsFailedWhenItFailsAgain (0.29s)
./cmd/mesh-controller --- PASS: TestReplay237 (0.23s)
./cmd/mesh-controller --- PASS: TestAnUnassignThatLeavesItsNodeUnresolvedSaysSoOnceInItsAnswer (0.23s)
./cmd/mesh-controller --- PASS: TestAnUnassignThatLeavesItsNodeResolvedSaysNothingOfIt (0.24s)
./cmd/mesh-controller --- PASS: TestAnAssignThatLeavesItsNodeUnresolvedSaysOnlyThePlansRefusal (0.23s)
./cmd/mesh-controller --- PASS: TestADirectoryOwnersKeyIsRefusedThroughAVerb (0.25s)
./cmd/mesh-controller --- PASS: TestTheSendMakesNoValueForAnOutsideSecretNobodyGave (0.35s)
./cmd/mesh-controller --- PASS: TestAQuestionComposesWithoutAnOutsideSecretNobodyGave (0.33s)
./cmd/mesh-controller --- PASS: TestReplay201 (0.27s)
./cmd/mesh-controller --- PASS: TestARollbackWhoseSendWasRefusedIsCompletedByTheNextSend (0.16s)
./cmd/mesh-controller --- PASS: TestAGateJudgesTheOtherMovesBesideAKeptCore (0.17s)
./cmd/mesh-controller --- PASS: TestReplay401 (0.34s)
./cmd/mesh-controller --- PASS: TestReplay201ThePlansSend (0.26s)
./cmd/mesh-controller --- PASS: TestPlanAndNodeListAnOptionalRequirementLeftUnbound (0.31s)
./cmd/mesh-controller --- PASS: TestReplay340 (0.27s)
./cmd/mesh-controller --- PASS: TestOnlyATrustedFilesNamedKeyIsRefusedThroughAVerb (0.22s)
./cmd/mesh-controller --- PASS: TestReplay349 (0.22s)
./cmd/mesh-controller --- PASS: TestReplay348AFaultFromBeforeTheSendFailsNoGate (0.19s)
./internal/inventory --- PASS: TestTheLastSendSaysWhatTheMachineAnswered (0.09s)
./internal/inventory --- PASS: TestAReportIsTheLastSendsAnswerOnlyWhenItIsAboutThatSend (0.09s)
./internal/inventory --- PASS: TestAnIssuedValueIsSealedToEveryHolderOnceAndNotAgain (0.11s)
./internal/inventory --- PASS: TestAnIssuedValueIsSealedAgainAfterAKeyChangeOrAnAcceptance (0.10s)
./internal/inventory --- PASS: TestAConditionsLooksAreKeptBesideTheBucket (0.07s)
./internal/inventory --- PASS: TestAPlanIdHoldingAQuoteIsReadAsAPlainId (0.08s)
./internal/inventory --- PASS: TestAWalksStartIsKeptAndARefusedSaveLeavesItUnsaid (0.07s)
./internal/inventory --- PASS: TestAWalksRestIsReadFromEachMachinesOwnSend (0.08s)
./internal/inventory --- PASS: TestAStoredBuildWithASilentMergeableFileIsStillReadAndComposed (0.08s)
```
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: the Go toolchain's compile line adds
-buildvcs=falsetoGOFLAGS(beside-trimpath), ininternal/builder/toolchain.go.Why: ADR 0267 rule 6 says a Go build uses
-trimpathand-buildvcs=false, so nothing in an artifact varies with the commit. The second half was never built. A module built from its repository's root (the controller) is compiled with the clone's.gitin view, and Go's default-buildvcs=autostampsvcs.revision,vcs.timeandvcs.modifiedinto the binary. A merge that changed onlyREADME.mdtherefore made a new digest of an unchanged program. A module in a subdirectory was not affected (its mount holds no.git), and images that namecompilesare handed a narrowed tree without.gitalready.Tests (fail on main):
TestAGoBundleBuiltTwiceFromOneBuildSourceIsOneDigestruns the toolchain's own compile line over a fixture repository in two clones at two paths, at two commits that differ only inREADME.md. On main it fails: the two binaries carry their commits and differ (41912235fa6eagainste7f9391d6c08). With the fix they are one digest. It skips wheregoorgitis missing.TestTheGoToolchainStampsNoVersionControl: the compile line says-buildvcs=false.go test ./internal/builder/passes, andmerge-check.shexits 0 (withoutMESH_TEST_POSTGRES, so the store tests were skipped; nothing here touches the store).Effect once live: the toolchain recipe is part of every Go bundle's source fingerprint (
toolchainOf), so each Go module's next build has a new fingerprint once. A subdirectory module's binary is byte-identical, so its digests match and nothing is sent. A root-built module (the controller) gets one new digest once, then stays reproducible.Part of issue 363 (the build of ADR 0267). The other open parts of that issue are not in this PR.
Delivery
novox/mesh-controller@ef3e5ae9b0dc— delivered since 2026-10-13T05:13:04ZDelivery plan — builds build-agent, mesh-controller, route-proxy → 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
bcdb1ad4Judged: head
bcdb1ad4f897merged into trunke0d69ab7a05b; read beside it: mesh-catalog53e51864969f, mesh-controller-maine0d69ab7a05b, 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 ace as
build-1791865799677642678(builds --log build-1791865799677642678).Verdict: request changes at
bcdb1ad4f8I read ADR 0267 (knowledge-base.get, reasoning true). Rule 6 says a build is reproducible where its fingerprint cannot be narrow: for Go, -trimpath and -buildvcs=false, and no .git in what a recipe sees, "for every kind" of artifact. This PR adds -buildvcs=false to the one Go toolchain entry in internal/builder/toolchain.go, which is the entry the issue's symptom (a README-only merge producing a new controller digest) names.
-buildvcs=false coverage is incomplete for "every Go build path" in this repository. Two other Go compiles still omit it and still see .git (there is no .dockerignore at the repository root):
make imageto build the control-plane image:RUN CGO_ENABLED=0 GOFLAGS=-mod=vendor GOPROXY=off go build -trimpath -ldflags "-s -w -X main.version=${VERSION}" -o /mesh-controller ./cmd/mesh-controller. No -buildvcs=false.[]string{"CGO_ENABLED=0", "GOFLAGS=-mod=vendor", "GOPROXY=off", ...}, "go", "build", "-o", bin, "./cmd/mesh-controller". No -buildvcs=false there either.These may be judged out of this PR's declared scope (issue 363 lists rules 1, 2, 3 and 5 as the other open parts, not rule 6's extent), but the PR's own framing — "every Go build" — and ADR 0267 rule 6's "for every kind" do not carve them out, so I am flagging them rather than assuming they are deliberately deferred.
I built the new test file (internal/builder/reproducible_test.go) against main (
1d244d5, with toolchain.go unmodified) and against the PR head. On main both new tests fail:"--- FAIL: TestAGoBundleBuiltTwiceFromOneBuildSourceIsOneDigest (0.17s)" with "one build source, two digests: f11df5b9865f at 676a76f66278, e255b970dbc0 at 53566ea14c2c (compiled with "env CGO_ENABLED=0 GOFLAGS=-trimpath go build")", and
"--- FAIL: TestTheGoToolchainStampsNoVersionControl (0.00s)" with "the go toolchain stamps the commit into what it compiles: "env CGO_ENABLED=0 GOFLAGS=-trimpath go build"".
At the PR head both pass: "--- PASS: TestAGoBundleBuiltTwiceFromOneBuildSourceIsOneDigest (0.14s)" and "--- PASS: TestTheGoToolchainStampsNoVersionControl (0.00s)", "ok github.com/novox/mesh-controller/internal/builder 0.141s".
I grepped mesh-controller, mesh-host, mesh-tools and mesh-catalog for vcs.revision and ReadBuildInfo/BuildInfo, outside vendor/node_modules. mesh-controller's own use (cmd/mesh-controller/checks.go:321, sdkPinned) reads info.Deps for the SDK module's pinned version, not info.Settings, so -buildvcs=false does not affect it. mesh-host and mesh-catalog have no such use. mesh-tools does, and it is a real conflict with this change: node-tools/internal/alive/alive.go's Version() reads "vcs.revision" out of debug.ReadBuildInfo().Settings and publishes it every minute as Beat.Version on the tools-alive heartbeat the controller's watchdog depends on. node-tools/module.json declares its runtime bundle with "language": "go", so it compiles through this same toolchain entry. Once this PR merges, node-tools binaries carry no vcs.revision, so Version() returns "" from then on — the heartbeat's version field goes silently empty for every node, mesh-wide, and nothing in this PR's test suite (scoped to mesh-controller) catches it because the break lands in a different repository.
go vet ./... and go vet ./internal/builder/... are both clean (no output). go test -race ./internal/builder/... passes: "ok github.com/novox/mesh-controller/internal/builder 31.442s".
The current required-check statuses on
bcdb1ad4are stale: the most recent mesh/merge-gate and mesh/repo-check entries both read "out of date: judged against trunke0d69ab7a0, the trunk is now 1d244d5aa24e; judged again on a recheck or when it is merged" (their prior run, againste0d69ab7, both read "success"). This needs a fresh mesh-delivery.recheck regardless of the finding above.Recommendation: before merging, either give node-tools' heartbeat a version source that survives -buildvcs=false (its own -ldflags -X stamp, the way the control-plane Dockerfile already does with main.version) or explicitly decide and record that the heartbeat's version field is going away, and say in the PR body whether the root Dockerfile and check.go's judge builds are deliberately out of scope for rule 6 or need their own follow-up issue.
Answers to review 159. New head:
ef3e5ae9b0.1. Other Go compiles in this repository.
Dockerfile, which builds the genesis/lab image. It hasCOPY . .and no.dockerignore, so.gitis in the build. Also covered: the Makefile-built recipescmd/mesh-builder/Dockerfileandexamples/{route-proxy,postgres,objectstore,redis-provisioner}/Dockerfile. All six now say-buildvcs=false. The newTestEveryGoRecipeInThisRepositoryStampsNoVersionControlfails onbcdb1ad4and passes now.go buildcalls ininternal/builder/check.go(judge, andjudgeForself and validator). Each writes a throwaway judge to<check root>/bin/. The judge runs once for the check and is never published, registered or fingerprinted, so it is not an artifact and rule 6 does not apply. The controller reads its own build info only insdkPinned(cmd/mesh-controller/checks.go:321), and that readsinfo.Deps, which-buildvcsdoes not touch.2. node-tools
alive.Versionis not a regression.node-tools/of mesh-tools. The toolchain mounts only the module's directory (one(..., within, ...)→compilemountstree:/app/modules/module), so Go never sees a.gitand stamps nothing today.go version -m /var/lib/mesh/daemons/node-tools/node-toolsshows-trimpath=trueand novcs.*setting. The field is already empty on every node./usr/lib/nox-mesh-host/versions/838d94ad46e8/nox-mesh-host) carriesvcs.revision=7a41e120…andvcs.time. That is the per-commit variation this PR removes.link.Beats.Heardstores it inBeat.Version, and no code outside the tests reads that field.-Xcommit stamp. The option it favours is the running binary's own digest (sha256 of/proc/self/exe), which equals the bundle's content and changes only with the program.Other readers of
vcs.*orReadBuildInfo: I searched mesh-controller, mesh-host, mesh-tools, mesh-catalog and mesh-sdk. The only hits arechecks.go:321(Deps only) and mesh-toolsnode-tools/internal/alive/alive.go:37.Tests:
go test ./internal/builder/passes at the new head.Verdict: approve at
ef3e5ae9b0I verified both answers in comment 11255 myself rather than taking them on faith.
On point 1: the diff now adds -buildvcs=false to the root Dockerfile and the five Makefile-built recipes (cmd/mesh-builder, and the postgres, objectstore, redis and route-proxy examples), which is every Dockerfile in this repository outside testdata/ (I listed them: 6 total, all now covered). The new TestEveryGoRecipeInThisRepositoryStampsNoVersionControl walks the repository for every Dockerfile with a
go buildline and fails if-buildvcs=falseis missing; I ran it and it passes. I read internal/builder/check.go's three judge-build call sites again: the binaries they produce (bin/judge-of-itself, bin/judge-with-this-validator, bin/mesh-controller) are run locally to judge a merge-gate check and never reach Store.GetTagged, PublishImage or any other digest/fingerprint path I can find in that file — so leaving them alone is consistent with ADR 0267's scope (an artifact the mesh fingerprints and delivers), not an oversight.On point 2, both claims hold:
withinas the module's own directory viainside(tree, path), then callsone(ctx, run, publish, manifest.Module, within, ...), which passes thatwithininto compile() as itstreeparameter, mounted alone as--volume tree:within). For node-tools, built from path "node-tools" inside mesh-tools (not the repository root), the toolchain container only ever sees that subdirectory, never the clone's .git beside it — matching the ADR 0267 context note that a subdirectory module's mount holds no .git. I also checked the live binary directly:go version -m /var/lib/mesh/daemons/node-tools/node-toolson g14 shows no vcs.* entry in its build settings at all, confirming this empirically, independent of this PR..VersionandBeatreads.internal/link/serve.godoes storealive.VersionintoToolsBeatsviaBeats.Heard(...), andBeat.Versionexists on the struct, but the only reader,cmd/mesh-controller/watchdogs.go'scollectMachineFacts, callslink.ToolsBeats.Of(n.Name)and only takesbeat.Atandbeat.EveryintomachineFacts.toolsHeard/toolsEvery—machineFactshas no version field at all, and nothing else in any of the four repositories readsBeat.Version. It is written and never read, so losing its value is not an observable regression.go vet ./... and go test -race ./internal/builder/... are both still clean at this head (
ok github.com/novox/mesh-controller/internal/builder 33.753s). mesh/merge-gate and mesh/repo-check are queued/building on this head as of this review; I did not wait on them.Merge check at
ef3e5ae9Judged: head
ef3e5ae9b0dcmerged into trunk1d244d5aa24e; read beside it: mesh-catalog53e51864969f, mesh-controller-main1d244d5aa24e, 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, route-proxy)mesh/repo-check: PASS — its merge-check.sh passedDelivery plan — builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step
Run by the build seat on novox as
build-1791866869028220388(builds --log build-1791866869028220388).