mesh/merge-gate pass: the change touches no module of the mesh's graph
mesh/repo-check pass: THE CHANGE ALTERS ITS OWN CHECK (merge-check.sh): main's version judged it; the change's judges the pull requests after it merges; it…
mesh/delivery superseded: a newer head of the same pull request
ADR 0290 rule 9: once the import is checked record by record, hq keeps no copy. The records and efforts are removed; every link or path to them reads "ADR NNNN" or "research NNN"; a design's decisions: lists "ADR NNNN". 02-DECISIONS keeps a pointer README with the reading order's six topics, which the knowledge base reads through the records module; 01-RESEARCH keeps a pointer README. The checks drop the rules that judged records (the knowledge base holds each at propose; checks/README.md says where) and refuse a record written here again. Playbooks 01 and 02 and the skills write and read records with the knowledge base's verbs.
71 lines
4.6 KiB
Markdown
71 lines
4.6 KiB
Markdown
---
|
|
opened: 2026-10-06
|
|
---
|
|
|
|
# 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),
|
|
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 |
|
|
|
|
## Resolved — 2026-10-08
|
|
|
|
Both pull requests are merged (2026-10-06). The rule went further a day later: issue 280's fix and
|
|
ADR 0238 made a file in no module's directory touch nothing at all, and the controller maps a change
|
|
onto modules in one place, `touchedBy`, for the merge handler, the what-if and the merge gate alike.
|