A module's directory is never shared code, held or not (hq issue 278)

The merge of mesh-catalog 7f99fb4a rebuilt 103 modules with the build agent in tier 0, and ADR
0236 recorded it as "a change to the build agent rebuilds most of the catalogue". The agent had
not changed: modules/showcase/index.ts had. showcase is the catalogue's reference module, held
by no machine, and its manifest was not in the merge, so whatTheMergeTouched read the file as
shared code and rebuilt everything built from the repository (88 came out byte-identical). The
agent stood first only because everything is built by it.

Whether a directory is a module is a fact of the repository at the merge commit, so the forge's
announcer now says it: module_dirs, the changed files' directories holding a module.json there,
with module_dirs_said. A changed file inside one is that module's business; only a file in no
such directory is shared. An announcer that does not say keeps the old rule. `plans` what-if
takes the same list as module-dirs.

And a regression for the open question: nothing depends on the build agent except by being
built by it, and built-by never widens a plan, so a change to the agent - manifest or program -
rebuilds the agent alone; what moved beside it is ordered after it.
This commit is contained in:
jochen
2026-10-06 19:55:25 +02:00
parent 4635341a9d
commit b1e02aca1b
8 changed files with 208 additions and 6 deletions
+26 -1
View File
@@ -640,6 +640,11 @@ func lastLookAt(entries []inventory.Entry, m link.SourceMoved) time.Time {
// library (`modules/lib`), and that is still read as shared. Rebuilding too much remains the safe
// direction: the fault this whole path exists for is a mesh that believes it is current and is not
// (novox/hq 04-ISSUES/131). A file at the root, or directly in a parent, is shared as it always was.
//
// **Whether a directory is a module is a fact of the repository at the merge commit** (novox/hq issue
// 278), and the announcer now says it: a changed file inside a directory holding a `module.json` there
// is that module's, whatever the merge did to the manifest; only a file in no such directory is shared.
// From an announcer that does not say, the rule above stands.
func whatTheMergeTouched(candidates, known []inventory.Entry, m link.SourceMoved) []inventory.Entry {
// Nothing said about the files, or not all of them said: everything built from it is affected.
if len(m.Paths) == 0 || m.PathsTruncated {
@@ -660,8 +665,9 @@ func whatTheMergeTouched(candidates, known []inventory.Entry, m link.SourceMoved
for _, p := range m.Paths {
changed[strings.TrimPrefix(p, "/")] = true
}
modules := saidModuleDirs(m)
for _, p := range m.Paths {
if insideAny(p, dirs) || inAModuleOfItsOwn(p, parents, changed) {
if insideAny(p, dirs) || inAModuleOfItsOwn(p, parents, changed) || insideAny(p, modules) {
continue
}
return candidates
@@ -675,6 +681,25 @@ func whatTheMergeTouched(candidates, known []inventory.Entry, m link.SourceMoved
return out
}
// saidModuleDirs is the directories the announcer says hold a module at the merge commit (novox/hq
// issue 278): a changed file in one of them is that module's business and nobody else's — the
// catalogue's reference module, held by no machine, whose code a merge touched beside its manifest,
// read as shared and rebuilt 103 modules. Nothing when the announcer did not look, and never the
// repository's root: a module built from the root is handled as one built from it, and a root that
// counted would make every file a module's.
func saidModuleDirs(m link.SourceMoved) []string {
if !m.ModuleDirsSaid {
return nil
}
var out []string
for _, d := range m.ModuleDirs {
if d = strings.Trim(strings.TrimSpace(d), "/"); d != "" && d != "." {
out = append(out, d)
}
}
return out
}
// inAModuleOfItsOwn is whether a changed file is inside a module directory the mesh does not know —
// `<parent>/<name>/…` under a directory known to hold modules, whose `module.json` the same merge
// changed (novox/hq issue 252). Such a file is that module's business and nobody else's.