Why. The controller treated a changed file as shared code unless its directory was a module it holds, or the merge also changed that directory's module.json. A change to modules/showcase/index.ts alone (in merge 7f99fb4a) therefore rebuilt all 103 modules built from this repository.
What changes. After listing a merged pull request's files, the announcer looks up every directory above a changed file (never the repository root) for a module.json at the merge commit. It uses the forge's contents API; the token's write:repository scope already covers it. The pull.merged event then carries module_dirs and module_dirs_said: true. Nothing is sent in three cases, and the controller then keeps its old rule, which rebuilds too much rather than too little:
the file list was truncated;
there are more than 300 directories to look up;
the forge can't be asked (the failure is logged).
Tests (modules/gitea/test/pages.test.ts):
the directories above a set of paths;
a lookup at the commit telling a module from a plain directory;
the bound;
a refused lookup throws rather than reading as "no module".
Run with node --test --experimental-transform-types and a .js-to-.ts resolver. client.ts and index.ts type-check strict with no new errors (only the existing SDK path resolution errors remain, outside a full install).
modules/showcase is kept, because it is used:
mesh-controller's TestTheShowcaseModuleIsAValidManifest parses it as the module that exercises every manifest feature;
hq to-be 18 and to-be 20 name it as the reference module.
No machine runs it and the catalogue doesn't hold it, which is exactly the case this PR fixes.
The controller side is mesh-controller#93. Either order is safe: the fields are ignored by an older controller. Do not merge without a human approval.
**Why.** The controller treated a changed file as shared code unless its directory was a module it holds, or the merge also changed that directory's `module.json`. A change to `modules/showcase/index.ts` alone (in merge 7f99fb4a) therefore rebuilt all 103 modules built from this repository.
**What changes.** After listing a merged pull request's files, the announcer looks up every directory above a changed file (never the repository root) for a `module.json` at the merge commit. It uses the forge's contents API; the token's write:repository scope already covers it. The `pull.merged` event then carries `module_dirs` and `module_dirs_said: true`. Nothing is sent in three cases, and the controller then keeps its old rule, which rebuilds too much rather than too little:
- the file list was truncated;
- there are more than 300 directories to look up;
- the forge can't be asked (the failure is logged).
**Tests** (`modules/gitea/test/pages.test.ts`):
- the directories above a set of paths;
- a lookup at the commit telling a module from a plain directory;
- the bound;
- a refused lookup throws rather than reading as "no module".
Run with `node --test --experimental-transform-types` and a .js-to-.ts resolver. client.ts and index.ts type-check strict with no new errors (only the existing SDK path resolution errors remain, outside a full install).
**modules/showcase is kept**, because it is used:
- mesh-controller's `TestTheShowcaseModuleIsAValidManifest` parses it as the module that exercises every manifest feature;
- hq to-be 18 and to-be 20 name it as the reference module.
No machine runs it and the catalogue doesn't hold it, which is exactly the case this PR fixes.
The controller side is mesh-controller#93. Either order is safe: the fields are ignored by an older controller. Do not merge without a human approval.
The controller read a changed file as shared code unless its directory was a module it holds or
the merge also changed that directory's manifest. A merge touching modules/showcase/index.ts -
the catalogue's reference module, held by no machine - therefore rebuilt all 103 modules built
from this repository on 2026-10-06, 88 of them byte-identical, with the build agent first only
because everything else is built by it.
Whether a directory is a module is a fact of the repository at the commit, so the announcer now
looks it up: every directory above a changed file (never the root) is asked for its module.json
at the merge commit, and the ones that have one go out as module_dirs, with module_dirs_said.
Not said when the file list is cut, past 300 directories, or when the forge cannot be asked;
the controller then keeps its old rule, which rebuilds too much rather than too little.
modules/showcase stays: TestTheShowcaseModuleIsAValidManifest in mesh-controller parses it and
hq to-be 18 and 20 name it as the reference module.
Deliverynovox/mesh-catalog@1ba2c0513f90 — delivered since 2026-10-06T23:05:28Z
Machines
gitea on novox: passed — healthy 3 times over 9m8s
gitea on the rest running it: sent
Transitions
2026-10-06 23:05 (new) → proposed (announced): novox/mesh-catalog#96 merged; its head was not heard by this owner, so it is made from the forge's word
2026-10-06 23:05 proposed → held (merged-unchecked): merged without a passing check — a verdict known with it is taken first: only a person decides that it goes on
2026-10-06 23:05 held → delivering (go): its walk started on a word that was not this owner's: the controller's own path, which waits for nobody, or a person's plans go
2026-10-06 23:05 delivering → delivered (done): its walk is done: every machine of its deploy plan passed, or was left as its policy says
The commit's note under refs/notes/mesh-plan keeps every transition: git log --notes=mesh-plan.
<!-- mesh-delivery:view -->
**Delivery** `novox/mesh-catalog@1ba2c0513f90` — **delivered** since 2026-10-06T23:05:28Z
**Machines**
- gitea on novox: passed — healthy 3 times over 9m8s
- gitea on the rest running it: sent
**Transitions**
- 2026-10-06 23:05 (new) → proposed (announced): novox/mesh-catalog#96 merged; its head was not heard by this owner, so it is made from the forge's word
- 2026-10-06 23:05 proposed → held (merged-unchecked): merged without a passing check — a verdict known with it is taken first: only a person decides that it goes on
- 2026-10-06 23:05 held → delivering (go): its walk started on a word that was not this owner's: the controller's own path, which waits for nobody, or a person's `plans go`
- 2026-10-06 23:05 delivering → delivered (done): its walk is done: every machine of its deploy plan passed, or was left as its policy says
The commit's note under `refs/notes/mesh-plan` keeps every transition: `git log --notes=mesh-plan`.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Why. The controller treated a changed file as shared code unless its directory was a module it holds, or the merge also changed that directory's
module.json. A change tomodules/showcase/index.tsalone (in merge7f99fb4a) therefore rebuilt all 103 modules built from this repository.What changes. After listing a merged pull request's files, the announcer looks up every directory above a changed file (never the repository root) for a
module.jsonat the merge commit. It uses the forge's contents API; the token's write:repository scope already covers it. Thepull.mergedevent then carriesmodule_dirsandmodule_dirs_said: true. Nothing is sent in three cases, and the controller then keeps its old rule, which rebuilds too much rather than too little:Tests (
modules/gitea/test/pages.test.ts):Run with
node --test --experimental-transform-typesand a .js-to-.ts resolver. client.ts and index.ts type-check strict with no new errors (only the existing SDK path resolution errors remain, outside a full install).modules/showcase is kept, because it is used:
TestTheShowcaseModuleIsAValidManifestparses it as the module that exercises every manifest feature;No machine runs it and the catalogue doesn't hold it, which is exactly the case this PR fixes.
The controller side is mesh-controller#93. Either order is safe: the fields are ignored by an older controller. Do not merge without a human approval.
Delivery
novox/mesh-catalog@1ba2c0513f90— delivered since 2026-10-06T23:05:28ZMachines
Transitions
plans goThe commit's note under
refs/notes/mesh-plankeeps every transition:git log --notes=mesh-plan.