Merge pull request 'Issue 300: a new module is not built at its merge' (#181) from issues/300-a-new-module-is-not-built-at-its-merge into main
This commit was merged in pull request #181.
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
---
|
||||
status: located
|
||||
opened: 2026-10-07
|
||||
located-in: [mesh-controller cmd/mesh-controller (upgrades.go, the merge handler)]
|
||||
fixed-by: mesh-controller PR #122
|
||||
amended-design:
|
||||
---
|
||||
|
||||
# 300. A new module is not built at its merge
|
||||
|
||||
## Symptom
|
||||
|
||||
A pull request to the catalogue added one module, `systemd-resolved` (ADR 0247). Its delivery plan,
|
||||
posted with the pull request's check, said:
|
||||
|
||||
> builds new: modules/systemd-resolved, sent nowhere
|
||||
|
||||
At the merge, 20:14:37 UTC on 2026-10-07, the controller said:
|
||||
|
||||
> novox/mesh-catalog merged into main (…); it changed nothing any module the mesh holds is built from
|
||||
|
||||
The module was not built and not registered. `assign` then refused it with "no module of that name".
|
||||
It took a hand `mesh-controller.build` to register it. So the plan said one thing and the merge did
|
||||
another, with nothing on the mesh noting the difference.
|
||||
|
||||
## Why it is a design issue
|
||||
|
||||
ADR 0238 makes the delivery plan the planner's one answer for a pull request's check, the merge gate and
|
||||
the merge. The plan counts a new module's directory as something the merge builds. The merge handler
|
||||
read the same answer (`touchedBy`'s `added`) and dropped it: it only walks modules the catalogue already
|
||||
holds, and a new one is not held until it is built. The code said so outright: "a new module, which a
|
||||
check judges before it merges and a merge does not build". The take-in refuses a build off the trunk
|
||||
with "merge it, and the merge builds it". So one part of the controller promised the build and another
|
||||
never made it.
|
||||
|
||||
Assigning a module is a person's act, and it needs the module registered first. A merge that leaves a
|
||||
new module unregistered turns each new module into two acts by hand, and the plan says it is one.
|
||||
|
||||
## How it is checked
|
||||
|
||||
- `TestAMergeBuildsTheNewModuleItAdds` replays this case. A held catalogue module, and a merge whose
|
||||
changed files are only a new module's directory: the merge asks the build seat for that directory, at
|
||||
the branch merged into, from the repository as the mesh spells it, and opens no plan. It fails on the
|
||||
commit before the fix.
|
||||
- `TestAMergeBuildsItsNewModuleBesideItsPlan`: a merge that changes a held module and adds a new one
|
||||
plans the held one and asks for the new one beside the plan. A merge that adds no module asks for
|
||||
nothing.
|
||||
|
||||
The trail is in [01-diagnosis.md](01-diagnosis.md). This is a core issue: at resolution it names its
|
||||
replay, or says in `replay-none:` why none is possible (ADR 0237).
|
||||
@@ -0,0 +1,45 @@
|
||||
# 300 — diagnosis
|
||||
|
||||
## 2026-10-07: where the merge decides what to build
|
||||
|
||||
The text "changed nothing any module the mesh holds is built from" is printed in one place: the
|
||||
controller's merge handler (`SourceMoved`), when the merge moves no held module. The handler takes the
|
||||
catalogue modules built from the merged repository and branch (`mergeCandidates`). It narrows them to
|
||||
the ones whose directory a changed file is in (`touchedBy`). A plan is opened only for those and for
|
||||
whatever stands on them.
|
||||
|
||||
`touchedBy` is the one place the mesh maps a changed file onto a module (ADR 0238). It returns three
|
||||
answers: the touched modules, the `added` directories (a module that no module of the mesh is known
|
||||
from) and the `unread` files. The delivery plan and the pull request's check take `added` as "new" and say
|
||||
it is built. The merge handler went through `whatTheMergeTouched`, which keeps only the first answer.
|
||||
|
||||
Ruled out:
|
||||
|
||||
- **The forge's announcement.** The plan for the same pull request found the new directory, from the same
|
||||
paths and module directories the merge carries (issue 278). `added` was computed correctly; it was just
|
||||
not used.
|
||||
- **The take-in.** A hand build of the directory was taken in and registered as usual. Nothing between a
|
||||
build's outcome and registration needed changing.
|
||||
|
||||
## The fix
|
||||
|
||||
At a merge into the branch its repository's modules follow, the handler asks the build seat for every
|
||||
added directory: at that branch, from the repository spelled and found on the seat as the modules
|
||||
already built from it are, and without waiting (`askNewModules`). The build's take-in registers the
|
||||
module, as it does for a hand `build`. Nothing is sent: no machine is assigned a new module, and
|
||||
assigning one stays a person's act.
|
||||
|
||||
The new module is outside the merge's plan. A plan walks modules the catalogue holds, tier by tier, and
|
||||
sends each built one to the machines running it. A new module has no machine and nothing standing on it,
|
||||
and the plan's ask for a module the catalogue does not hold fails the plan.
|
||||
|
||||
A merge read as history, or of a branch that no module follows, builds no new module either. The new
|
||||
module's build follows the same candidates as everything else.
|
||||
|
||||
## What it does not cover
|
||||
|
||||
- **A repository the mesh holds nothing from.** There is no module whose source spelling and seat the new
|
||||
module could use, so nothing is built. That is unchanged: "nothing the mesh holds reads it".
|
||||
- **The catch-up of merges the bus did not hand over** (issue 266) judges a missed merge by the held
|
||||
modules it would move. A merge that only adds a module, and that the bus skipped, is still not built
|
||||
by the catch-up. Counting `added` there would ask again on every pass until the build landed.
|
||||
Reference in New Issue
Block a user