mesh: don't resurrect a device another owner evicted#193
Merged
Conversation
An owner keeps a local, un-synced record of the devices it claimed (`ownership.fleet_members`), and `ensure_fleet_network`'s background loop re-signs + re-approves each of them into the fleet's signed roster to keep membership authoritative. That list is only pruned locally by the owner who authors a kick — so when a *different* owner evicts a device, the claiming owner's list still carries it, and the loop re-admits it (a fresh, later-stamped member-log grant that wins the last-writer-wins tie), resurrecting the evicted device across the whole fleet. That's the "other owners can't see it gone / it stays controllable" half of the eviction bug. Before the admit loop re-asserts the list, reconcile it against the signed governance: pull the daemon's authoritative removed set (`GovernanceState`'s new `evicted` field, projected from the signed member log) and drop any locally listed device the fleet has evicted, refreshing the control-auth cache and the GUI roster when it changes. Best-effort — an empty set (no fleet, an older daemon without the field, or a read error) prunes nothing, so a transient failure never drops a live member. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018x1RV6ppUdMDTHxScVo26L
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Part of the "I evicted a node but it stays in the fleet / stays controllable, and other owners can't see it gone" report. The governance-layer half is fixed in MyOwnMesh (evicted owners/managers no longer resurrect on gossip-adopting peers). This is the AllMyStuff-side half.
An owner keeps a local, un-synced record of the devices it claimed —
ownership.fleet_members.ensure_fleet_network's background loop re-signs and re-approves each of them into the fleet's signed roster on every re-assertion, to keep membership authoritative and self-sufficient. That local list is only pruned by the owner who authors a kick (kick_member).So when a different owner evicts a device, the claiming owner's list still carries it. Its admit loop then:
RoleGrant{member}(a new member-log entry, stamped later than the evict → it wins the last-writer-wins tie), andresurrecting the evicted device across the whole fleet. That's exactly why co-owners "can't see it gone" and it stays controllable.
Fix
Before the admit loop re-asserts the claimed-list, reconcile it against the signed governance. Pull the daemon's authoritative removed set —
GovernanceState's newevictedfield (themember_log_removedprojection over the signed member log) — and drop any locally listed device the fleet has evicted, then refresh the control-authorization cache and the GUI roster if anything changed.ownership.kick_member(local-list prune only; the signed roster already converged the removal) and the sameGovernanceStaterequestsigned_role_holdersalready makes.Paired with MyOwnMesh PR #105, which fixes the governance projection and adds the
evictedfield this reads..myownmesh-revstill pins the current daemon; this activates once that daemon ships (until then,evictedis absent → no-op).Testing
cargo check+cargo clippy --all-targets -- -D warnings(node crate,stabletoolchain — matchesnode-check.yml) pass clean;cargo fmt --checkclean. The prune is thin glue over already-tested primitives:ownership.kick_member(covered inownership.rstests) and the daemon'smember_log_removedprojection (covered in MyOwnMesh's governance tests). mesh.rs has no mock-daemon test seam, so there's no unit test for the RPC wiring itself.🤖 Generated with Claude Code
https://claude.ai/code/session_018x1RV6ppUdMDTHxScVo26L
Generated by Claude Code