Delivery group fix/1126-apply-culprit (mesh-sdk, mesh-host). Issue 1126 notes 102, 105, 106. Found by the review of design 47 L2's seed: merging it switches every node to compose its own modules, and the APPLYING path (frombus.Compose, refuse=nil) refused the whole node on one module's error. On novox (the control-node) de-spiegel's unset config (accepted until L5) would have marked all ~81 modules failed and moved nothing. Second meeting of the kind ‘one module's refusal freezes a node’ (the shadow in seed-8): fixed for the kind.
One rule, frombus.composeEach, for both Compose (apply) and Answer (shadow).
A held module (compose.Node.Held) keeps what it last applied: none of its own composition is applied; it is carried as it runs (compose.RunsAnyOf, Carried from Scope.Running), including while it leaves the fold.
What others read of a held module is what runs; dependsOnHeld composes again with stubs, and a module whose composition differs is held too; if the node's own composition differs, the node is refused.
dependents: for every held module, the providers it contributes to are held, and the filter's holder when it listens (cascading).
Only a refusal belonging to no single module refuses the node.
On novox today: de-spiegel, route-proxy and nftables are held (they keep running as now) until de-spiegel's config is declared (L5).
Cost to measure after delivery: about 7 compositions per pass on novox while held (6-30 s, the reviewer's estimate).
Tests: rows (E)-(H) in answer_rows_test.go and frombus_test.go, each failing first; no new function.
Review: three rounds (a held module leaving the fold lost its resources; providers composed from a stub; a held module's new manifest).
Reviewed-by: rev-apply-culprit@shanks at 0de3006415
Delivery group fix/1126-apply-culprit (mesh-sdk, mesh-host). Issue 1126 notes 102, 105, 106. Found by the review of design 47 L2's seed: merging it switches every node to compose its own modules, and the APPLYING path (frombus.Compose, refuse=nil) refused the whole node on one module's error. On novox (the control-node) de-spiegel's unset config (accepted until L5) would have marked all ~81 modules failed and moved nothing. Second meeting of the kind ‘one module's refusal freezes a node’ (the shadow in seed-8): fixed for the kind.
- One rule, frombus.composeEach, for both Compose (apply) and Answer (shadow).
- A held module (compose.Node.Held) keeps what it last applied: none of its own composition is applied; it is carried as it runs (compose.RunsAnyOf, Carried from Scope.Running), including while it leaves the fold.
- What others read of a held module is what runs; dependsOnHeld composes again with stubs, and a module whose composition differs is held too; if the node's own composition differs, the node is refused.
- dependents: for every held module, the providers it contributes to are held, and the filter's holder when it listens (cascading).
- Only a refusal belonging to no single module refuses the node.
On novox today: de-spiegel, route-proxy and nftables are held (they keep running as now) until de-spiegel's config is declared (L5).
Cost to measure after delivery: about 7 compositions per pass on novox while held (6-30 s, the reviewer's estimate).
Tests: rows (E)-(H) in answer_rows_test.go and frombus_test.go, each failing first; no new function.
Review: three rounds (a held module leaving the fold lost its resources; providers composed from a stub; a held module's new manifest).
Reviewed-by: rev-apply-culprit@shanks at 0de30064156a60f14da6081c975b099764bd3ee3
The applying path (frombus.Compose) composed with no culprit, so one module's
refusal came back as the whole node's: novox's apply would have refused all its
modules for de-spiegel's unset route names. composeEach is now the one rule
Compose and Answer both follow:
- a module whose stub changes the refusal is held (compose.Node.Held); in the
applying path a stand-in for a module placed here holds that module; only a
refusal of no single module refuses the node;
- a held module is composed from what runs of it (compose.Carried of its own
composition in Running) and carried in the node's own wherever that runs it,
folded or leaving the fold, so the node's own apply never removes it (issue
1945 by a new path) and what the others read of it is what runs;
- none of a held module's own composition is in what is applied;
- a module whose composition differs when the held ones are composed as stubs
is held too; the node's own differing refuses the node;
- since a held module is composed from its new manifest, what reads that
manifest is held with it: the providers of what it contributes to (the
proxy its routes) and, when it listens, the filter's holder.
Quick fix weighed: a culprit loop in Compose alone. Thorough, chosen: one
shared function, since the kind met twice (seed-8 shadow, now the apply), and
review rounds 1 and 2 found its leaks.
Deliverynovox/mesh-sdk@0de30064156a — merged since 2026-10-28T16:34:47Z
Source — source.main moved to novox/mesh-sdk@98f2f24069. Whether it reached the machines is mesh-delivery-view's, derived from source.main, the wants and the haves.
composed together: pass — the checker's verdict at the members' heads (23be06c61d1b)
Transitions
2026-10-28 16:25 (new) → proposed (announced): novox/mesh-sdk#118's head announced
2026-10-28 16:25 proposed → ready (accepted): a verdict names this commit and the trunk's head as its trunk commit, the gate passed or warned, and the repository's own check did not fail; or the check gates no merge (check-gates-merge false)
2026-10-28 16:34 ready → merged (merged): on the trunk its modules follow: merged there
The commit's note under refs/notes/mesh-plan keeps every transition of this change up to its merge: git log --notes=mesh-plan.
<!-- mesh-delivery:view -->
**Delivery** `novox/mesh-sdk@0de30064156a` — **merged** since 2026-10-28T16:34:47Z
**Source** — source.main moved to novox/mesh-sdk@98f2f2406921. Whether it reached the machines is `mesh-delivery-view`'s, derived from `source.main`, the wants and the haves.
**Group** `fix/1126-apply-culprit`: novox/mesh-host@24c23a1d066f, novox/mesh-sdk@0de30064156a
- composed together: pass — the checker's verdict at the members' heads (23be06c61d1b)
**Transitions**
- 2026-10-28 16:25 (new) → proposed (announced): novox/mesh-sdk#118's head announced
- 2026-10-28 16:25 proposed → ready (accepted): a verdict names this commit and the trunk's head as its trunk commit, the gate passed or warned, and the repository's own check did not fail; or the check gates no merge (check-gates-merge false)
- 2026-10-28 16:34 ready → merged (merged): on the trunk its modules follow: merged there
The commit's note under `refs/notes/mesh-plan` keeps every transition of this change up to its merge: `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.
Delivery group fix/1126-apply-culprit (mesh-sdk, mesh-host). Issue 1126 notes 102, 105, 106. Found by the review of design 47 L2's seed: merging it switches every node to compose its own modules, and the APPLYING path (frombus.Compose, refuse=nil) refused the whole node on one module's error. On novox (the control-node) de-spiegel's unset config (accepted until L5) would have marked all ~81 modules failed and moved nothing. Second meeting of the kind ‘one module's refusal freezes a node’ (the shadow in seed-8): fixed for the kind.
On novox today: de-spiegel, route-proxy and nftables are held (they keep running as now) until de-spiegel's config is declared (L5).
Cost to measure after delivery: about 7 compositions per pass on novox while held (6-30 s, the reviewer's estimate).
Tests: rows (E)-(H) in answer_rows_test.go and frombus_test.go, each failing first; no new function.
Review: three rounds (a held module leaving the fold lost its resources; providers composed from a stub; a held module's new manifest).
Reviewed-by: rev-apply-culprit@shanks at
0de3006415Delivery
novox/mesh-sdk@0de30064156a— merged since 2026-10-28T16:34:47ZSource — source.main moved to novox/mesh-sdk@98f2f24069. Whether it reached the machines is
mesh-delivery-view's, derived fromsource.main, the wants and the haves.Group
fix/1126-apply-culprit: novox/mesh-host@24c23a1d06, novox/mesh-sdk@0de3006415Transitions
The commit's note under
refs/notes/mesh-plankeeps every transition of this change up to its merge:git log --notes=mesh-plan.