Assigner: a running node gets its first want past the ordering rules, a module on neither list is raised, and a failed health holds only once a node is done moving (issue 1945)
#42
Merged
mesh-toolsmerged 6 commits from fix/r6-no-module-in-neither into main2026-10-25 14:56:26 +00:00
About 40-60 modules per machine had no want, because the ordering rules blocked the first want, and a module on neither list (no want, no hold) was raised nowhere. On g14, clipmenu, i3status-rust, screen-lock and the asus-zephyrus-g14 bundles have been missing since 05:41.
First want: a node that runs a module, with no want or a removed one, held back only by the canary or the providers rule, gets a want at the fingerprint it runs (with that version's composition and grant, Module.GrantedAt), never a newer one. The canary is not passed over.
Old-form builds (lead's design limit): a node running a pre-R6 build gets the newest F only when it is the canary or the canary runs F healthy, with everything F needs and the providers rule.
Neither is raised, urgent, only for a node whose have names the module (not removed); a new assignment still waiting raises nothing.
A failed health holds only in phase running or failed, never while backing-up, applying or checking. That is how the controller's canary was held on novox at 15:27:36. The lift rule counts only running haves.
Restart: the first pass after a start clears, once, the neither and held conditions a previous process raised that no longer stand; a hold raised again forgets its clear.
Record ask: a removed want counts as no want, so a policy-record module's first want after a removal goes through the record ask.
Tests (each written first and seen to fail): TestANodeRunningAModuleWithNoWantGetsItsFirstWantAtWhatItRuns, TestNoFirstWantWithoutTheCompositionAndGrantOfWhatItRuns, TestANewAssignmentWaitingIsNotOnNeitherList, TestAnOldFormNodeGetsItsFirstWantAtFOnlyUnderTheCanary, TestAHoldIsLiftedOverHavesThatAreNotRunning, TestTheFirstPassAfterAStartClearsWhatAPreviousProcessRaised, TestAFirstWantAfterARemovedWantGoesThroughTheRecordAsk, and the integration test TestWantsAreWrittenAndNoDifferenceIs.
Checked: gofmt, go vet with and without -tags integration, the unit suite. Tries passed on 81182e9, 3d7d65e, 706169a and 975f0ed (try-1792939684270470528, 3 min 56 s). The operator decided no checks run during the recovery (2026-10-25 15:53, issue 1945 note 27): the operator merges by hand.
On g14 the modules waiting on xorg get their wants once xorg reports healthy; mesh-host #141 does that.
Issue 1945 (R6 recovery, fix 11).
About 40-60 modules per machine had no want, because the ordering rules blocked the first want, and a module on neither list (no want, no hold) was raised nowhere. On g14, clipmenu, i3status-rust, screen-lock and the asus-zephyrus-g14 bundles have been missing since 05:41.
- **First want:** a node that runs a module, with no want or a removed one, held back only by the canary or the providers rule, gets a want at the fingerprint it runs (with that version's composition and grant, Module.GrantedAt), never a newer one. The canary is not passed over.
- **Old-form builds** (lead's design limit): a node running a pre-R6 build gets the newest F only when it is the canary or the canary runs F healthy, with everything F needs and the providers rule.
- **Neither** is raised, urgent, only for a node whose have names the module (not removed); a new assignment still waiting raises nothing.
- **A failed health holds only in phase running or failed**, never while backing-up, applying or checking. That is how the controller's canary was held on novox at 15:27:36. The lift rule counts only running haves.
- **Restart:** the first pass after a start clears, once, the neither and held conditions a previous process raised that no longer stand; a hold raised again forgets its clear.
- **Record ask:** a removed want counts as no want, so a policy-record module's first want after a removal goes through the record ask.
Tests (each written first and seen to fail): TestANodeRunningAModuleWithNoWantGetsItsFirstWantAtWhatItRuns, TestNoFirstWantWithoutTheCompositionAndGrantOfWhatItRuns, TestANewAssignmentWaitingIsNotOnNeitherList, TestAnOldFormNodeGetsItsFirstWantAtFOnlyUnderTheCanary, TestAHoldIsLiftedOverHavesThatAreNotRunning, TestTheFirstPassAfterAStartClearsWhatAPreviousProcessRaised, TestAFirstWantAfterARemovedWantGoesThroughTheRecordAsk, and the integration test TestWantsAreWrittenAndNoDifferenceIs.
Checked: gofmt, go vet with and without -tags integration, the unit suite. Tries passed on 81182e9, 3d7d65e, 706169a and 975f0ed (try-1792939684270470528, 3 min 56 s). The operator decided no checks run during the recovery (2026-10-25 15:53, issue 1945 note 27): the operator merges by hand.
On g14 the modules waiting on xorg get their wants once xorg reports healthy; mesh-host #141 does that.
Reviewed-by: reviewer-r6p@shanks at 975f0ed65460388ccef716fdaecfe4cc5321c1ed
The node's own composition gives up every module with a fingerprint of the new form, so such a module is applied only through its
want. The assigner wrote no want while a rule held it back and the node had none, so clipmenu, screen-lock, i3status-rust and every
module requiring x11-display lay on neither list on g14 and shanks: xorg's health is unknown (rule 5) and the canary never ran them
healthy (rule 3), and their files were removed and never made again.
A node that runs a module and has no want for it now gets its first want by the rules without which there is nothing to want (built,
not held, granted, composed); the canary and providers rules order every move after it. Any module still on neither list is raised
as an urgent condition naming module, node and rule, written to the journal, and cleared once it has a want (1945/AC19-AC21).
A first want at the newest fingerprint passed over the canary for every module right after the switch. It now names what the node
runs: F when it runs F (by the rules without which there is nothing to want), or an older fingerprint of the new form whose
composition and grant exist, held back from F by the rule; otherwise nothing is written and the node stays on neither list. A new
assignment, with no have, waits for the rules and raises no condition (1945/AC19-AC21).
An old-form build (not src2:) has no composition, so no want can ever name
what such a node runs. Design limit, decided by the lead (lead-47): its first
want names the newest F, by every rule as usual - the canary (rule 3: this
node is the canary, or the canary runs F healthy), everything F needs (built,
not held, granted, composed) and the providers (rule 5). Otherwise nothing is
written and the neither condition stays. The canary stays in force, and
old-form modules (clipmenu and screen-lock on g14) leave neither list by
themselves, without a hand-written want.
The code already behaved so (an old-form have falls through to Holds); the
case is now named in Wants, and proven: a unit test for both sides of the
canary, the providers and the grant, and the integration test gives g14 F
and clears its neither condition once the canary ace runs F healthy.
On novox at 15:27:36 a have reading "health failed, phase applying" at the
controller's new fingerprint held its canary two seconds before the new
build was healthy: Wants held on a failed health whatever the phase. A
failed health while the node backs up, applies or checks is a step of the
move, not its outcome, so it holds nothing now.
Every other Health read in the assigner (rule 3's healthy, rule 5's
providedHealthy, the world's lastHealthy) already asks for phase running.
Test from the live row first, seen failing before the fix.
Phase guard, same kind as the failed-health hold. allRunHealthy counted
every have whatever its phase, so a node with a removed, held or still
moving have kept a hold up for ever: it counts only phase running (healthy
or not) and failed (not healthy). The failed-health hold already ignores
removed and held haves (phase running or failed only).
Stale conditions (B1). The neither and held conditions this process said
lived only in its memory, so one raised by a previous process stayed urgent
for ever once the module had its want or was no longer held. The first pass
after a start clears, once, the neither condition of every assigned module
with a want and not on neither list, and the held condition of every
module's newest fingerprint that is not held; a clear of a condition that is
not open is quiet at the router. A hold raised again forgets that it was
cleared, so a later release clears it again.
Record ask (review note 3). mustAsk wrote no ask when the want before was
removed, so the first-want path could write a recreates or moves-data
composition of a policy-record module with no ask. A removed want is now
no want, and the first want after it goes through the record ask.
Tests first, each seen failing: a hold lifted over removed, held and moving
haves; the record ask after a removed want; a fresh pass clearing what a
previous process raised, once.
Deliverynovox/mesh-delivery@975f0ed65460 — merged since 2026-10-25T14:56:28Z
Source — source.main moved to novox/mesh-delivery@653da54c0d. Whether it reached the machines is mesh-delivery-view's, derived from source.main, the wants and the haves.
Transitions
2026-10-25 14:53 (new) → proposed (announced): novox/mesh-delivery#42's head announced
2026-10-25 14:56 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
2026-10-25 14:56 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-delivery@975f0ed65460` — **merged** since 2026-10-25T14:56:28Z
**Source** — source.main moved to novox/mesh-delivery@653da54c0da3. Whether it reached the machines is `mesh-delivery-view`'s, derived from `source.main`, the wants and the haves.
**Transitions**
- 2026-10-25 14:53 (new) → proposed (announced): novox/mesh-delivery#42's head announced
- 2026-10-25 14:56 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
- 2026-10-25 14:56 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.
Issue 1945 (R6 recovery, fix 11).
About 40-60 modules per machine had no want, because the ordering rules blocked the first want, and a module on neither list (no want, no hold) was raised nowhere. On g14, clipmenu, i3status-rust, screen-lock and the asus-zephyrus-g14 bundles have been missing since 05:41.
Tests (each written first and seen to fail): TestANodeRunningAModuleWithNoWantGetsItsFirstWantAtWhatItRuns, TestNoFirstWantWithoutTheCompositionAndGrantOfWhatItRuns, TestANewAssignmentWaitingIsNotOnNeitherList, TestAnOldFormNodeGetsItsFirstWantAtFOnlyUnderTheCanary, TestAHoldIsLiftedOverHavesThatAreNotRunning, TestTheFirstPassAfterAStartClearsWhatAPreviousProcessRaised, TestAFirstWantAfterARemovedWantGoesThroughTheRecordAsk, and the integration test TestWantsAreWrittenAndNoDifferenceIs.
Checked: gofmt, go vet with and without -tags integration, the unit suite. Tries passed on
81182e9,3d7d65e,706169aand975f0ed(try-1792939684270470528, 3 min 56 s). The operator decided no checks run during the recovery (2026-10-25 15:53, issue 1945 note 27): the operator merges by hand.On g14 the modules waiting on xorg get their wants once xorg reports healthy; mesh-host #141 does that.
Reviewed-by: reviewer-r6p@shanks at
975f0ed654f7b23033) 81182e9dcd3d7d65ed)Delivery
novox/mesh-delivery@975f0ed65460— merged since 2026-10-25T14:56:28ZSource — source.main moved to novox/mesh-delivery@653da54c0d. Whether it reached the machines is
mesh-delivery-view's, derived fromsource.main, the wants and the haves.Transitions
The commit's note under
refs/notes/mesh-plankeeps every transition of this change up to its merge:git log --notes=mesh-plan.