The whole-mesh dry-run found that a single un-hostable assignment (a module declaring a capability the node lacks — e.g. fail2ban) made push refuse to resolve the entire node ("nothing was sent"). checkCapabilities appended a whole-set refusal for any un-hostable module regardless of whether it was directly assigned or pulled in as a requirement.
Fix (skip-and-report, not validate-at-assign — the latter contradicts the deliberate "keep the assignment, the refusal is about the set" design): a directly-assigned module the machine can't host is left out of the closure and recorded in a new Resolution.Unhostable, so the healthy modules still resolve and push; an un-hostable module genuinely required by something running there still refuses (that set is incoherent). Extends the mesh's existing "one broken node mustn't stop the rest" to within a node. New tests both directions; two tests that encoded the old whole-node-refusal reconciled. go test ./... all green.
The whole-mesh dry-run found that a single un-hostable assignment (a module declaring a capability the node lacks — e.g. fail2ban) made `push` refuse to resolve the **entire** node ("nothing was sent"). `checkCapabilities` appended a whole-set refusal for any un-hostable module regardless of whether it was directly assigned or pulled in as a requirement.
Fix (skip-and-report, not validate-at-assign — the latter contradicts the deliberate "keep the assignment, the refusal is about the set" design): a **directly-assigned** module the machine can't host is left out of the closure and recorded in a new `Resolution.Unhostable`, so the healthy modules still resolve and push; an un-hostable module genuinely **required** by something running there still refuses (that set is incoherent). Extends the mesh's existing "one broken node mustn't stop the rest" to *within* a node. New tests both directions; two tests that encoded the old whole-node-refusal reconciled. `go test ./...` all green.
A module a person assigns to a machine that cannot host it — its declared
capability has no detector there, as fail2ban does on a host with no firewall —
made Resolve refuse the entire node, so a whole-node push refused to send the
healthy modules beside it too. One module on the wrong machine took down every
other module on that node.
Assign already keeps such an assignment on purpose (it is what a person meant,
and acts.go says so), so the fix is on the resolve/push side: a directly-assigned
module the machine cannot host is left out of the closure and reported as
un-applied on the Resolution, rather than refusing the set. The healthy modules
still resolve, declare, and converge. A module that is *required* by something
running here and cannot be hosted still refuses — that set is genuinely
incoherent — so the distinction is who wanted it.
assign, plan and push now name the un-applied module and the missing capability,
via a shared WrongMachine message, so it is neither silently dropped nor fatal.
Reconciled two tests that encoded the old whole-node refusal for directly-assigned
un-hostable modules; added coverage for the healthy-modules-still-converge case
and the required-un-hostable-still-refuses distinction.
Claude-Session: https://claude.ai/code/session_01LrgweAeERJYBg88c5cKDzF
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.
The whole-mesh dry-run found that a single un-hostable assignment (a module declaring a capability the node lacks — e.g. fail2ban) made
pushrefuse to resolve the entire node ("nothing was sent").checkCapabilitiesappended a whole-set refusal for any un-hostable module regardless of whether it was directly assigned or pulled in as a requirement.Fix (skip-and-report, not validate-at-assign — the latter contradicts the deliberate "keep the assignment, the refusal is about the set" design): a directly-assigned module the machine can't host is left out of the closure and recorded in a new
Resolution.Unhostable, so the healthy modules still resolve and push; an un-hostable module genuinely required by something running there still refuses (that set is incoherent). Extends the mesh's existing "one broken node mustn't stop the rest" to within a node. New tests both directions; two tests that encoded the old whole-node-refusal reconciled.go test ./...all green.