fix(federation): remove-node also purges the mesh contact/thread (#2)

federation.remove-node only edited nodes.json, so a removed/renamed node
(e.g. a stale "Arch HP") lingered in the mesh chat list with its old
thread. Capture the node's pubkey before removal, then purge its
synthetic mesh peer, shared secret, messages, presence, and persisted
contact entry via the new mesh::purge_federation_peer. Combined with the
#42 name refresh, stale federation contacts can now be fully cleaned from
a node.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
archipelago
2026-06-17 06:12:56 -04:00
co-authored by Claude Opus 4.8
parent d2d2b9dd68
commit ab56054aeb
2 changed files with 59 additions and 0 deletions
@@ -262,9 +262,36 @@ impl RpcHandler {
.ok_or_else(|| anyhow::anyhow!("Missing 'did' parameter"))?;
validate_did(did)?;
// Capture the node's pubkey before removal so we can also purge its
// synthetic mesh contact/thread (#2) — remove_node only touches
// nodes.json, which would otherwise leave a stale chat contact behind.
let removed_pubkey = federation::load_nodes(&self.config.data_dir)
.await
.ok()
.and_then(|nodes| {
nodes
.into_iter()
.find(|n| n.did == did)
.map(|n| n.pubkey)
});
let nodes = federation::remove_node(&self.config.data_dir, did).await?;
info!(did = %did, "Removed node from federation");
if let Some(pubkey) = removed_pubkey.filter(|p| !p.is_empty()) {
let svc = self.mesh_service.read().await;
if let Some(svc) = svc.as_ref() {
let contact_id = mesh::federation_peer_contact_id(&pubkey);
mesh::purge_federation_peer(
&svc.shared_state(),
contact_id,
&pubkey,
&self.config.data_dir,
)
.await;
}
}
Ok(serde_json::json!({
"removed": true,
"nodes_remaining": nodes.len(),