Judge a module the node agent has not taken yet by the composition its have names, and knock the filling whenever what runs changes (issue 924; pins mesh-sdk for issue 1126)
#172
Issue 924's second meeting. From each engine start on 2026-10-29 at 00:09 UTC, ace, g14 and shanks refused power's three new shutdown drop-ins (reboot, poweroff, halt): "is not a file this node's declaration names as filled". The cause was that the filling judges by what runs. For a module the node agent has not taken yet, what runs came from the kept declaration, which is older than every composition applied since the switch. A held module on a node that composes its own never gets a new composition, so the agent never took it. The fill socket was knocked only when a module settled, so the refusals lasted until some unrelated module happened to settle. The journals show it at every engine restart since 2026-10-28 18:42 UTC. The files themselves stayed intact.
The same fallback built a composition without Data. After a restart, a data module (mongodb, mssql on novox) was then judged to move its data against its first composition, and the operator was asked a false approval.
What changes
internal/agent: at the start, once the wants and compositions are read, loadHad reads each module's have. Where the have names what runs (running, held, or a composer's mark: the phases baseline accepts), it takes the composition the have names, from the bucket or its revisions (signed or node-composed). That composition comes ahead of the kept declaration, both in what runs and in the move judgement. The kept declaration is used only when the bucket no longer keeps that composition, and that is said once.
Every composition built from the kept declaration carries Data as the module's manifest declares it (Env.HoldsData, the composer's DataItems). A module whose manifest cannot be read is said to be unjudgeable, never taken to hold no data. With mesh-sdk #129 a flag that differs alone no longer moves data, so this is a second layer: it keeps the sdk's warning from firing on kept runs.
Env.RunsChanged is told once at the start, after the haves are read, and whenever a module is taken as running without an apply. cmd/mesh-host knocks the fill socket on it, as it already does on Settled.
internal/apply: the node keeps the content of every file given by digest that it verified or fetched (<state dir>/objects), and uses a kept one before it asks the bus. An object the controller's sweep removed then never refuses a composition the node already had (novox's mesh-vault apply failed at 01:16 UTC on 2026-10-29 on such an object). A kept object unused for 14 days is let go; a fetch that still fails says the keep never held it.
cmd/mesh-host: a file that runs is composed as the node last wrote it (its record's digest and size at that path), so a stale kept declaration's export no longer names a swept object.
The go.mod pin moves to mesh-sdk 575cb82 (mesh-sdk #129, the other member of this group), merged onto main after L3 (mesh-host #168).
Quick fix or thorough fix
The quick fix: knock the fill socket once at the engine start. That covers this instance, but a module still running from the kept declaration would stay judged by it. The knock is kept as part of the thorough fix.
The thorough fix, chosen: no path judges a module that has a have by the kept declaration, and no path builds a running composition without Data. The kind recurs for every file and data flag added since the switch.
How it is checked
One table test, TestWhatRunsBeforeTheAgentTakesAModuleNamesItsFilledPaths, replaces a single-case test. Its six rows cover: kept declaration only; a have naming the bucket's value; a have naming a revision replaced since; a have naming a composition the bucket no longer keeps; a have in phase applying; and a data module from the kept declaration. The rows check the filled paths, Data, and that the filling is told at the start before any settle. The unit test count is unchanged.
The whole untagged suite passes, and go vet -tags integration ./... is clean.
file_references_test.go's whole-apply test gains five rows (a swept object kept, a file run as written); they fail on the old code. The test count stays.
Live: after the delivery, novox's mesh-vault have is no longer failed, and an engine restart on ace, g14 or shanks writes /etc/systemd/system/{reboot,poweroff,halt}.target.d/mesh-power.conf on its first fill, with no "not named as filled" line in nox-mesh-host.service. machine.<node>.apply-failing for power clears and is not raised again. mesh-provisioner.provisioning what=applied module=power reads applied on all four machines.
Group: delivered together with mesh-sdk fix/1126-held-contributes (#129), which this head pins.
## Why
Issue 924's second meeting. From each engine start on 2026-10-29 at 00:09 UTC, ace, g14 and shanks refused power's three new shutdown drop-ins (reboot, poweroff, halt): "is not a file this node's declaration names as filled". The cause was that the filling judges by what runs. For a module the node agent has not taken yet, what runs came from the kept declaration, which is older than every composition applied since the switch. A held module on a node that composes its own never gets a new composition, so the agent never took it. The fill socket was knocked only when a module settled, so the refusals lasted until some unrelated module happened to settle. The journals show it at every engine restart since 2026-10-28 18:42 UTC. The files themselves stayed intact.
The same fallback built a composition without Data. After a restart, a data module (mongodb, mssql on novox) was then judged to move its data against its first composition, and the operator was asked a false approval.
## What changes
- `internal/agent`: at the start, once the wants and compositions are read, `loadHad` reads each module's have. Where the have names what runs (running, held, or a composer's mark: the phases baseline accepts), it takes the composition the have names, from the bucket or its revisions (signed or node-composed). That composition comes ahead of the kept declaration, both in what runs and in the move judgement. The kept declaration is used only when the bucket no longer keeps that composition, and that is said once.
- Every composition built from the kept declaration carries Data as the module's manifest declares it (`Env.HoldsData`, the composer's `DataItems`). A module whose manifest cannot be read is said to be unjudgeable, never taken to hold no data. With mesh-sdk #129 a flag that differs alone no longer moves data, so this is a second layer: it keeps the sdk's warning from firing on kept runs.
- `Env.RunsChanged` is told once at the start, after the haves are read, and whenever a module is taken as running without an apply. `cmd/mesh-host` knocks the fill socket on it, as it already does on `Settled`.
- `internal/apply`: the node keeps the content of every file given by digest that it verified or fetched (`<state dir>/objects`), and uses a kept one before it asks the bus. An object the controller's sweep removed then never refuses a composition the node already had (novox's mesh-vault apply failed at 01:16 UTC on 2026-10-29 on such an object). A kept object unused for 14 days is let go; a fetch that still fails says the keep never held it.
- `cmd/mesh-host`: a file that runs is composed as the node last wrote it (its record's digest and size at that path), so a stale kept declaration's export no longer names a swept object.
- The go.mod pin moves to mesh-sdk 575cb82 (mesh-sdk #129, the other member of this group), merged onto main after L3 (mesh-host #168).
## Quick fix or thorough fix
- The quick fix: knock the fill socket once at the engine start. That covers this instance, but a module still running from the kept declaration would stay judged by it. The knock is kept as part of the thorough fix.
- The thorough fix, chosen: no path judges a module that has a have by the kept declaration, and no path builds a running composition without Data. The kind recurs for every file and data flag added since the switch.
## How it is checked
- One table test, `TestWhatRunsBeforeTheAgentTakesAModuleNamesItsFilledPaths`, replaces a single-case test. Its six rows cover: kept declaration only; a have naming the bucket's value; a have naming a revision replaced since; a have naming a composition the bucket no longer keeps; a have in phase applying; and a data module from the kept declaration. The rows check the filled paths, Data, and that the filling is told at the start before any settle. The unit test count is unchanged.
- The whole untagged suite passes, and `go vet -tags integration ./...` is clean.
- `file_references_test.go`'s whole-apply test gains five rows (a swept object kept, a file run as written); they fail on the old code. The test count stays.
- Live: after the delivery, novox's mesh-vault have is no longer failed, and an engine restart on ace, g14 or shanks writes `/etc/systemd/system/{reboot,poweroff,halt}.target.d/mesh-power.conf` on its first fill, with no "not named as filled" line in `nox-mesh-host.service`. `machine.<node>.apply-failing` for power clears and is not raised again. `mesh-provisioner.provisioning what=applied module=power` reads applied on all four machines.
Group: delivered together with mesh-sdk fix/1126-held-contributes (#129), which this head pins.
Reviewed-by: rev-held3@shanks at c7476aae09ff21a48da270e64d147b9e6eb01d40
A held module on a node composing its own never gets a composition, so the agent never took it and the filling
judged its files by the kept declaration, older than power's three new drop-ins: refused from every engine start
on ace, g14 and shanks until some module settled (2026-10-29 00:09 UTC). The second meeting of issue 924.
Quick fix: knock the filling once the haves are read at the start. Thorough fix (chosen, the kind recurs for every
file added since the switch): what runs of such a module is the composition its have names, from the bucket or
its revisions, ahead of the kept declaration; the filling is knocked on every change of what runs, not only on a
settle. One unit test replaced by a table of four cases; the count stays.
The kept-declaration fallback built a composition without Data, so after a restart a data module (mongodb, mssql
on novox) was judged to move its data against its first composition and the operator was asked a false yes. Now
every such composition takes Data from the manifest (agent.Env.HoldsData, the composer's DataItems), and a module
whose manifest cannot be read is said to be unjudgeable rather than taken to hold none. The composition a have
names comes before the kept declaration in the judgement too.
loadHad takes a have only in the phases baseline takes as running (running, held, a composer's mark): one backing
up, applying, checking, failed or waiting names a composition not applied (review of 031e106). Two rows added to
the same table test; the count stays.
On novox at 01:16 on 2026-10-29, after the node began composing its own modules, mesh-vault's apply failed while the
vault ran: its own composition carries the export as it runs (mesh-sdk frombus KeptRuns) by a digest whose object the
controller's sweep (mesh-controller cmd/mesh-controller/declaration_sweep.go, sweepNode and sweepDeclarationFiles)
had removed, since the sweep keeps only what the controller's compositions in composed-<node> and the wants name.
The node may only read its bucket (ADR 0486 §2), so the node keeps what it had: a file here that verifies, or an
object fetched, goes to <state dir>/objects under the object's name, and a kept one is used before the bus is asked.
An object unused for 14 days is let go. A fetch that still fails says the keep never held it, before its cause.
Quick fix weighed: re-put the object from the controller's store. Thorough (chosen): the node never depends on the
bucket for content it once had, for every module, since the sweep and a node composing its own can always disagree.
The whole-apply test gains three rows that fail on the old code; the test count stays.
novox's mesh-vault has failed since 01:16 on 2026-10-29: its have says failed, so loadHad (fbea777) takes no
composition from it, and what runs falls back to the kept declaration, whose export (mesh-vault.kept) names
f099eaa1, an object the controller's sweep removed. The node wrote a newer export since. The composer carries that
file as it runs (mesh-sdk frombus keptOf), so what runs now names the digest and size of what is on disk, but only
where the node's record says it wrote exactly that content at that path (Applied.Wrote, Target). The apply then
finds the file in place and needs no object.
Quick fix weighed: have the controller put the object back. Thorough (chosen, in the node): what runs is what the node
wrote, never a guess from an older declaration. The rows join the existing whole-apply test; the test count stays.
mesh/delivery-group group fix/1126-924-held-and-judged rejected: composed together: the checker's verdict at the members' heads (7e4e345e9969): mesh-build-go
Deliverynovox/mesh-host@c7476aae09ff — closed since 2026-10-29T07:48:23Z
Transitions
2026-10-29 07:48 (new) → proposed (announced): novox/mesh-host#172's head announced
2026-10-29 07:48 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)
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-host@c7476aae09ff` — **closed** since 2026-10-29T07:48:23Z
**Transitions**
- 2026-10-29 07:48 (new) → proposed (announced): novox/mesh-host#172's head announced
- 2026-10-29 07:48 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-29 07:48 ready → closed (closed): the pull request closed unmerged
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.
Why
Issue 924's second meeting. From each engine start on 2026-10-29 at 00:09 UTC, ace, g14 and shanks refused power's three new shutdown drop-ins (reboot, poweroff, halt): "is not a file this node's declaration names as filled". The cause was that the filling judges by what runs. For a module the node agent has not taken yet, what runs came from the kept declaration, which is older than every composition applied since the switch. A held module on a node that composes its own never gets a new composition, so the agent never took it. The fill socket was knocked only when a module settled, so the refusals lasted until some unrelated module happened to settle. The journals show it at every engine restart since 2026-10-28 18:42 UTC. The files themselves stayed intact.
The same fallback built a composition without Data. After a restart, a data module (mongodb, mssql on novox) was then judged to move its data against its first composition, and the operator was asked a false approval.
What changes
internal/agent: at the start, once the wants and compositions are read,loadHadreads each module's have. Where the have names what runs (running, held, or a composer's mark: the phases baseline accepts), it takes the composition the have names, from the bucket or its revisions (signed or node-composed). That composition comes ahead of the kept declaration, both in what runs and in the move judgement. The kept declaration is used only when the bucket no longer keeps that composition, and that is said once.Env.HoldsData, the composer'sDataItems). A module whose manifest cannot be read is said to be unjudgeable, never taken to hold no data. With mesh-sdk #129 a flag that differs alone no longer moves data, so this is a second layer: it keeps the sdk's warning from firing on kept runs.Env.RunsChangedis told once at the start, after the haves are read, and whenever a module is taken as running without an apply.cmd/mesh-hostknocks the fill socket on it, as it already does onSettled.internal/apply: the node keeps the content of every file given by digest that it verified or fetched (<state dir>/objects), and uses a kept one before it asks the bus. An object the controller's sweep removed then never refuses a composition the node already had (novox's mesh-vault apply failed at 01:16 UTC on 2026-10-29 on such an object). A kept object unused for 14 days is let go; a fetch that still fails says the keep never held it.cmd/mesh-host: a file that runs is composed as the node last wrote it (its record's digest and size at that path), so a stale kept declaration's export no longer names a swept object.Quick fix or thorough fix
How it is checked
TestWhatRunsBeforeTheAgentTakesAModuleNamesItsFilledPaths, replaces a single-case test. Its six rows cover: kept declaration only; a have naming the bucket's value; a have naming a revision replaced since; a have naming a composition the bucket no longer keeps; a have in phase applying; and a data module from the kept declaration. The rows check the filled paths, Data, and that the filling is told at the start before any settle. The unit test count is unchanged.go vet -tags integration ./...is clean.file_references_test.go's whole-apply test gains five rows (a swept object kept, a file run as written); they fail on the old code. The test count stays./etc/systemd/system/{reboot,poweroff,halt}.target.d/mesh-power.confon its first fill, with no "not named as filled" line innox-mesh-host.service.machine.<node>.apply-failingfor power clears and is not raised again.mesh-provisioner.provisioning what=applied module=powerreads applied on all four machines.Group: delivered together with mesh-sdk fix/1126-held-contributes (#129), which this head pins.
Reviewed-by: rev-held3@shanks at
c7476aae09Delivery
novox/mesh-host@c7476aae09ff— closed since 2026-10-29T07:48:23ZTransitions
The commit's note under
refs/notes/mesh-plankeeps every transition of this change up to its merge:git log --notes=mesh-plan.Pull request closed