block / block/buzz

relay: workflow a-tag deletion leaves current kind:30620 event live — ghost workflows in Desktop list, silent resurrection on edit

Open
#2,390 1 comment 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

Deleting a workflow (kind:5 with `a`-tag address) removes the `workflows` control-plane row (log: "Workflow deleted via NIP-09 a-tag (UUID)") but can leave the **current kind:30620 definition event live** in the event log. The Desktop workflows list is built from `/query kinds:[30620]`, so it keeps showing "ghost" workflows that no longer exist.

Worse, the ghosts are interactive: editing/toggling a ghost entry submits a kind:30620 update for the deleted id, and `handle_workflow_def` treats an unknown id as a create — silently **resurrecting the deleted workflow**. Manual-trigger (46020) on a ghost returns "workflow not found", which is how users notice.

## Observed sequence (single-node relay, `ghcr.io/block/buzz:main`)

1. Create workflow W (definition event E1). Delete W → row deleted, **E1 tombstoned** ✅
2. Ghost entry still visible in a stale Desktop list → user edits it → kind:30620 update with W's d-tag → workflow re-created with **new definition event E2** ✅ (by design, but surprising from a ghost)
3. Delete W again → relay logs "Workflow deleted via NIP-09 a-tag (UUID)", row deleted, **but E2 stays live** (`events.deleted_at IS NULL`) ❌
4. `/query kinds:[30620]` returns E2 forever → Desktop lists a workflow that `get_workflow`/trigger reject as not found.

Step 1 vs step 3 suggests event tombstoning keys on specific event ids (`e` tags from the client's possibly-stale view) rather than the a-tag address: the second delete referenced the original event id, not E2.

## Suggested fix

On NIP-09 a-tag workflow deletion, tombstone **all** live kind:30620 events whose `d` tag matches the deleted workflow id (address-based, same transaction as the row delete). Optionally: reject kind:30620 updates for ids with a deletion tombstone instead of silently re-creating.

Related UX: the workflows list should refetch after delete mutations resolve; a stale list is what makes the resurrection path reachable.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.