Issue 363: ADR 0267 was decided and never built, so a controller merge still moves three modules
mesh/merge-gate pass: the change touches no module of the mesh's graph
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery delivered

The operator took the rule as live. Track its build, as issue 354 does a deferred rename.
This commit is contained in:
jochen
2026-10-10 02:46:35 +02:00
parent 503e144ab6
commit f45f5f6f20
@@ -0,0 +1,64 @@
---
status: located
opened: 2026-10-10
located-in: [mesh-controller internal/builder (what a build says it was made from, and what an image compiling Go is handed), mesh-controller cmd/mesh-controller (the planner's mapping, touchedBy and readsFrom), mesh-controller internal/inventory (the packages edge), mesh-catalog modules/route-proxy and modules/build-agent (the package each recipe compiles)]
fixed-by:
amended-design:
---
# 363. ADR 0267 was decided and never built
## Symptom
[ADR 0267](../../02-DECISIONS/0267-an-artifact-is-rebuilt-only-when-its-build-source-changes-and-a-module-moves-only-along-build-dependencies-on-artifacts.md)
(accepted 2026-10-08) decided that a merge moves only the artifacts whose build source it touches, and a
module only along build dependencies on artifacts. [To-be 47](../../03-DESIGN/01-to-be/47-delivery-from-commit-to-delivered.md)
and [to-be 10](../../03-DESIGN/01-to-be/10-delivery.md) were amended to name it. Its consequences say "the
build handoff opens on mesh-controller and the catalogue".
On 2026-10-10 the operator took the rule as built and live. It is not:
- **The code**, at the controller's trunk on 2026-10-10: `mergeCandidates` and `readsFrom` still move a module
whose build reads a context on any merge to that repository, whatever the files; `touchedBy` still reads
every file of a repository as the module built from its root; `dependencies.go` still draws a `packages`
edge; the builder still fingerprints a context's whole tree. The planner tests still hold the rows tagged
*issue 338* as today's behaviour.
- **The plans.** Every merge to the controller's repository still plans the controller, the build seat's
holder and the route proxy, in three gated tiers, sent to every machine running them — for a change to the
controller's own command as for one to its README. This is
issue 338 (hq pull request #231, still open), unchanged.
- **The record.** No pull request in any repository names ADR 0267, and no issue tracks its build. ADR 0267's
*How this is checked* table names tests that do not exist.
## Why it is an issue
It is the pattern of [issue 354](../354-a-decided-rename-was-never-scheduled-and-the-operator-believed-it-live/00-report.md)
in its decision form: a record accepted, its designs amended, and the work it hands to code repositories
started by nobody. Everything a reader meets — the record, the two designs, the glossary's *build plan* —
describes the rule, and nothing says it is not running. The operator plans against a mesh that does not
exist: a controller merge costs three gates (about 15 minutes, against 4 to 5 for its own tier, as ADR 0267
measured) and recreates the route proxy on its node for changes that never touch its program.
Issue 354's check refuses a record that defers work without an issue. ADR 0267 defers nothing in words — it
says what is built and by whom — so that check does not see it. A decision handed to a code repository with
no pull request and no issue is the same silence.
## The fix
The build of ADR 0267, in the order its records require (each its own pull request, linked here):
1. **mesh-controller, the builder.** A build says its build source per repository: a Go program's import
closure (derived, never narrower than `go list -deps`), an archive's directory, an image's recipe and the
package it compiles (the new artifact field `compiles`). An image naming that package is handed its build
source and nothing else, so a recipe reading past it fails by name; its fingerprint is over that source.
Said only for a build of a commit on the trunk.
2. **mesh-controller, the planner.** A changed file moves the modules whose recorded build source holds it;
a module with none recorded, or with an earlier merge's build still pending, is read as before. The
`packages` edge is no longer drawn and neither widens nor orders a plan.
3. **mesh-catalog.** The route proxy and the build seat's holder name the package their recipes compile.
Merged after (1) is live: a builder that predates the field refuses the manifest.
What ADR 0267 decides and this does not build yet — artifact-grain edges in the inventory, a dependent left
out when its base is rebuilt to the same digest, declared build-source paths for an artifact without a
reader, and the catalogue check refusing a whole-repository build source — stays open here, each to be built
on its own pull request.