block / block/buzz

Desktop: persona deletion orphans relay-resurrected agents — delete guard misses 30177-referenced agents, materialization ignores persona tombstones

Open
#7,611 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
32.7k
Forks
4.3k
Avg merge
1d 13h
Merged PRs (30d)
253

Description

### Summary

A persona-delete race between the local agent store and relay-synced agent records can permanently orphan managed agents: personas get tombstoned while the agents that reference them are not visible to the delete-time guard, and the agents then re-materialize referencing tombstoned personas. Orphaned agents refuse to spawn (`resolve_effective_config` → `OrphanedInstance`), and the UI shows "Configuration missing" with no recovery path in-app.

Observed on a real install today; all five affected agents were dead until the personas were restored by hand from the relay DB.

### Environment

- macOS desktop app (`buzz-desktop`), single machine, owner-managed relay
- 6 managed agents; 5 linked to custom (non-builtin) personas published as kind:30175

### Timeline (all times UTC, 2026-09-12, from store snapshots + relay DB)

| Time | Event |
|---|---|
| ~15:29–15:54 | Local store contains only 3 freshly-created builtin agents (created Sep 11). The five older agents + their custom personas are absent. |
| 16:19 | Identity-migration artifacts appear (`identity.migrated` marker; retention DBs of prior owner identities moved aside). |
| 16:19:55–16:20:09 | All five custom personas republished as kind:30175 under the owner key — a resurrection of pre-migration data. |
| 16:21:29 | One linked agent (Claude) spawns successfully — records and personas briefly coexisted and resolved. |
| 16:40:15–16:43:26 | Five NIP-09 kind:5 tombstones, each targeting one persona coordinate `30175::`, signed by the same owner key. The delete guard did not refuse. |
| by 16:48 | The five agent records are back in the local store **with their original Aug/Sep `created_at`** — but now reference tombstoned personas. |
| 16:48–16:57 | Repeated start attempts refused; "configuration missing" persisted to each record's `last_error`. |

### Root cause (two interacting gaps)

1. **Delete-time reference check sees only the local store.** The persona-delete guard ("*X* is still assigned to a managed agent") checks agents present in the local `managed-agents.json`. The five referencing agent records were absent locally at deletion time (they had not yet re-materialized), so deletion proceeded. The relay already had authoritative kind:30177 records for those agents that the guard never consults.

2. **Agent records resurrect, personas don't.** The agent records re-materialized afterwards with original timestamps — most plausibly from the relay's kind:30177 events (the directory already fetches them; note `run_event_sync`'s deletion reconcile deliberately excludes 30177). Nothing performs the equivalent resurrection *check* against persona tombstones: an agent whose `persona_id` coordinate has a live tombstone is materialized anyway, into a permanently unspawnable state.

The specific deletion trigger in this instance (UI delete vs. a migration cleanup path) could not be determined from the evidence — the tombstones are owner-signed either way — but both gaps above are trigger-independent.

### Affected code

- Guard: `validate_persona_activation_change` (`desktop/src-tauri/src/managed_agents/personas.rs`) — local-store-only reference check
- Delete + cascade: `delete_persona` (`desktop/src-tauri/src/commands/personas/mod.rs`) — cascade deletes local agent records; relay 30177 events outlive it
- Orphan refusal: `resolve_effective_config` → `OrphanedInstance` (`desktop/src-tauri/src/managed_agents/effective_config/mod.rs`), drift badge `persona_drift_state` (`desktop/src-tauri/src/managed_agents/runtime.rs`)
- Deletion-reconcile 30177 exclusion: `desktop/src-tauri/src/event_sync.rs` (comment at the reconcile entry point)

### Suggested directions

- Persona delete: consult the relay-side 30177 directory (already fetched elsewhere) in addition to the local store, and require explicit confirmation when any owner-published 30177 references the persona.
- Materialization: when restoring/projecting an agent record whose `persona_id` coordinate carries a live tombstone (or is absent from the relay), skip + surface loudly instead of materializing an agent that can never spawn.
- Optionally: on boot, detect `persona_orphaned` agents and offer in-app recovery (re-link persona, or clear the link), rather than a permanent dead row.

### Data repair performed (for the record)

The persona content survived (kind:30175 rows are retained under kind:5 coordinate deletes), so the five definitions were rebuilt from the newest relay events into `managed-agents.json` as key-less definition records after sha256-verifying each event's canonical content hash against the agent's pinned `persona_source_version` (all five matched). All agents recovered. Note the relay tombstones for those coordinates remain live until each persona is next edited/republished.

Contributor guide

Open the contributing guide

Research direction

Start with validate_persona_activation_change in desktop/src-tauri/src/managed_agents/personas.rs and trace delete_persona in desktop/src-tauri/src/commands/personas/mod.rs; then inspect desktop/src-tauri/src/event_sync.rs where 30177 reconciliation is excluded. Compare local and relay-backed records during deletion and materialization, including resolve_effective_config and persona_drift_state. Done means referenced relay agents cannot be silently orphaned and agents with live persona tombstones are not materialized without a visible recovery path.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
desktop, distributed-systems
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.