Issue 278: a module held by no machine was read as shared code
The 103-module rebuild ADR 0236 put down to the build agent came from a file of the catalogue's reference module, read as shared because its definition was not in the merge. Records the issue, corrects ADR 0236's open question as a progressive insight (the tiering was right; the build agent never widens a plan) and amends to-be 30's rule for what a merge changed.
This commit is contained in:
+14
@@ -225,6 +225,20 @@ not say which files went, marks the module deleted in its plan, which goes on.
|
||||
- **A change to the build agent rebuilds most of the catalogue** (its modules are built on what it
|
||||
builds), which is how the bus came to be rebuilt by a merge that did not touch it. Whether that tiering
|
||||
is right is left open here; a rebuild that changes nothing is at least no longer a move of the bus.
|
||||
|
||||
> **Progressive insight — 2026-10-06.** The open question rested on a wrong cause. This consequence
|
||||
> said "a change to the build agent rebuilds most of the catalogue", and the measurement in decision 4
|
||||
> said "the catalogue merge that rebuilt 103 modules for a change to the build agent". That merge did
|
||||
> not change the build agent. It changed a file of the catalogue's reference module, which no machine
|
||||
> runs. Its definition was not in the merge, so the controller read the file as shared code and
|
||||
> rebuilt everything built from the repository
|
||||
> ([issue 278](../04-ISSUES/278-a-module-held-by-no-machine-was-read-as-shared-code/00-report.md)).
|
||||
> The build agent stood in tier 0 only because everything else is built by it. A built-by edge
|
||||
> orders a plan and never widens it, so a change to the build agent rebuilds the build agent alone.
|
||||
> The controller's test checks this over the real dependency relation. The open question is answered:
|
||||
> the tiering was right. What was wrong is now fixed: the forge's announcer says which directories
|
||||
> hold a module at the merge commit, and only a file in none of them is shared. The measurement
|
||||
> stands as a count; only its cause was wrong. Everything this record decided stands.
|
||||
- **Thirteen modules still wait for a person**, each saying why in the catalogue or by its data; `status`
|
||||
lists the machines behind them and `push <machine>` walks them, as before. A person who wants another
|
||||
held says `upgrade <module> record --why …`.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
layer: to-be
|
||||
status: proposed
|
||||
code: []
|
||||
updated: 2026-10-05
|
||||
updated: 2026-10-06
|
||||
decisions:
|
||||
- 02-DECISIONS/0221-a-push-sends-no-build-a-policy-or-a-plan-holds-back-except-to-the-machine-it-names.md
|
||||
- 02-DECISIONS/0218-a-plan-sends-grants-before-code-rolls-out-one-machine-first-and-a-newer-merge-takes-over-an-older-plan.md
|
||||
@@ -150,6 +150,15 @@ What a merge changed is read from the forge whole, page by page
|
||||
module directory the mesh does not hold yet is that module's own, not shared code, when its definition is
|
||||
among the changed paths.
|
||||
|
||||
Revision, [issue 278](../../04-ISSUES/278-a-module-held-by-no-machine-was-read-as-shared-code/00-report.md)
|
||||
(2026-10-06). Whether a directory is a module is a fact of the repository at the merge commit, and the
|
||||
forge's announcer says it. With each merge it lists the directories holding the changed files that hold a
|
||||
definition at that commit. A changed path in one of them is that module's own, whether or not the mesh
|
||||
holds the module and whether or not its definition changed. Only a path in no such directory is shared
|
||||
code. From an announcer that does not list them, the rule above stands. A change to the build agent
|
||||
rebuilds the build agent alone: what it builds is ordered after it in a plan, never added to one for its
|
||||
sake.
|
||||
|
||||
## What a push does not send (2026-10-05)
|
||||
|
||||
Revision, [ADR 0221](../../02-DECISIONS/0221-a-push-sends-no-build-a-policy-or-a-plan-holds-back-except-to-the-machine-it-names.md).
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
---
|
||||
status: located
|
||||
opened: 2026-10-06
|
||||
located-in: [mesh-controller cmd/mesh-controller, mesh-catalog modules/gitea]
|
||||
fixed-by: mesh-controller PR #93, mesh-catalog PR #96
|
||||
amended-design: 03-DESIGN/01-to-be/30-the-mesh-updates-itself-on-a-push.md
|
||||
---
|
||||
|
||||
# 278. A module held by no machine was read as shared code
|
||||
|
||||
## Symptom
|
||||
|
||||
On 2026-10-06 a catalogue merge fixed two modules (the audit logger and the usage store), touched the
|
||||
event handlers of six others, and changed one file of the catalogue's reference module, `showcase`.
|
||||
The controller planned **103 modules** in two tiers: the build agent alone in tier 0, everything else
|
||||
built from the catalogue repository in tier 1. 88 of the builds came out byte-identical to the ones
|
||||
before (no move, under [ADR 0236](../../02-DECISIONS/0236-a-build-is-judged-on-its-first-machine-and-put-back-by-something-other-than-itself-and-so-it-rolls-out-unattended.md)),
|
||||
and 15 were different. The bus was rebuilt among them, though nothing touched it.
|
||||
|
||||
ADR 0236 put this down to the build agent: "a change to the build agent rebuilds most of the
|
||||
catalogue", left open there. **The build agent had not changed.** Its directory was not among the
|
||||
merge's files.
|
||||
|
||||
## Diagnosis
|
||||
|
||||
The controller's `plans` what-if, which saves nothing, reproduces it with one path: a merge changing
|
||||
only `modules/showcase/index.ts` plans the same 103 modules, and one changing only the build agent's
|
||||
manifest plans the build agent alone.
|
||||
|
||||
**Shared code was inferred from the wrong fact.** The controller reads a changed path as shared code,
|
||||
and rebuilds every module built from the repository, unless its directory is a module the mesh holds or
|
||||
the merge also changed that directory's definition (the rule from [issue 252](../252-a-merges-changed-modules-were-read-wrong/00-report.md)).
|
||||
The reference module has a definition, but no machine runs it and the catalogue does not hold it. This
|
||||
merge changed its code and left its definition alone, so its file read as shared. That rule cannot tell
|
||||
a module from a shared library: both are a directory beside the modules whose definition the merge did
|
||||
not touch. **Whether a directory is a module is a fact of the repository at the commit**, and only
|
||||
something that can read the repository can say it.
|
||||
|
||||
**Why the build agent looked like the cause.** Every module built from source is *built by* the build
|
||||
agent, so whenever the agent is in a plan it goes first. But a built-by edge orders a plan and never
|
||||
widens it: nothing depends on the agent in any other way, so a change to the agent, whether to its
|
||||
definition or its program, rebuilds the agent alone. It was in this plan only because a shared change
|
||||
rebuilds everything built from the repository, and the agent is built from it too.
|
||||
|
||||
**The reference module stays.** It is used: the controller's test suite parses it as the module that
|
||||
exercises every part of a definition, and to-be 18 and to-be 20 name it as the reference module.
|
||||
|
||||
## Fix
|
||||
|
||||
- **The forge's announcer says which directories are modules.** For each merge it looks up every
|
||||
directory above a changed file, never the root, for a definition at the merge commit. It announces the
|
||||
ones that have one, and says that it looked. It says nothing when the file list was cut, when there
|
||||
are too many directories to look up, or when the forge cannot be asked.
|
||||
- **The controller believes it.** A changed file inside such a directory is that module's business,
|
||||
whether or not the mesh holds the module and whatever the merge did to its definition. Only a file in
|
||||
no such directory is shared. From an announcer that says nothing, the old rule stands: it rebuilds too
|
||||
much rather than too little.
|
||||
- The what-if takes the same list, so a plan can be read before a merge exactly as the merge will make
|
||||
it.
|
||||
|
||||
## How it is checked
|
||||
|
||||
| Rule | Checked by |
|
||||
|---|---|
|
||||
| a module's directory is never shared code | the controller's test: a change inside a directory the announcer says is a module rebuilds nothing else, nested paths included; a directory with no definition is still shared; the root is never a module directory; an announcer that says nothing keeps the old rule |
|
||||
| the announcer says it at the commit | the forge module's test: the directories above a merge's files, each looked up at the merge commit; a module told from a plain directory; past the bound, nothing said; a refused lookup is an error, not "no module" |
|
||||
| the build agent never widens a plan | the controller's test over the real dependency relation: every edge to the build agent is built-by; a change to its definition or its program plans the agent alone, and what moved beside it comes after it |
|
||||
| live | the next catalogue merge that touches a module no machine runs plans that change and nothing else; `plans` shows it |
|
||||
Reference in New Issue
Block a user