workflows list shows deleted workflows indefinitely (a-tag delete doesn't soft-delete the kind:30620 events row)
- Dominant language
- Rust
- Stars
- 32.7k
- Forks
- 4.3k
- Avg merge
- 1d 13h
- Merged PRs (30d)
- 253
Description
## Summary
`workflows delete` (NIP-09 a-tag deletion targeting a kind:30620 workflow definition) genuinely deletes the workflow's row from the operational `workflows` table the scheduler reads, but `workflows list` queries the raw kind:30620 Nostr events directly with no deletion-state filtering — so a successfully deleted workflow keeps appearing in `list` forever ("zombie" listing). No scheduling risk (the scheduler can't see a row that's gone), but it's a confusing/incorrect `list` result after a confirmed-accepted delete.
## Root cause
- `buzz workflows delete` publishes a NIP-09 kind:5 deletion event with an `a`-tag coordinate `30620::` (`crates/buzz-cli/src/commands/workflows.rs:139-144` → `buzz_sdk::build_workflow_delete` → `build_delete_addressable`, `crates/buzz-sdk/src/builders.rs:1503`).
- The relay ingests it in `handle_a_tag_deletion` (`crates/buzz-relay/src/handlers/side_effects.rs:2104-2117`), which special-cases `KIND_WORKFLOW_DEF` (30620) to call `delete_workflow_for_owner` — a hard `DELETE FROM workflows WHERE ...` (`crates/buzz-db/src/workflow.rs:768-788`) against the operational `workflows` table.
- `buzz workflows list` (`crates/buzz-cli/src/commands/workflows.rs:13-19`, `cmd_list_workflows`) does not query that table. It sends a raw `REQ` for `kinds:[30620], #h:[channel_id]` directly against the event store, with no deletion-state filtering.
- The relay's own comment at `side_effects.rs:2151-2158` explains the split is deliberate: workflow a-tag deletion is called out as *not* soft-deleting the underlying `events` row "by design", unlike every other addressable/parameterized-replaceable kind, which does soft-delete the live `(kind, pubkey, d_tag)` row specifically "so REQs stop returning it."
## Impact
- No scheduling risk: `list_enabled_channel_workflows` / `list_all_enabled_workflows` (`crates/buzz-db/src/workflow.rs:425-457`, the latter doc-commented as used by the cron scheduler) filter against the same `workflows` table the delete removes the row from, so a deleted workflow cannot fire.
- User-facing confusion: `workflows delete` reports `accepted: true` (correctly — the deletion event is valid and its effect on the scheduler is real), but `workflows list` shows the definition indefinitely afterward, with no way to distinguish "actually still active" from "deleted but zombie-listed" via the CLI.
## Suggested fix
Bring workflow a-tag deletion in line with the general NIP-33 pattern: also soft-delete the kind:30620 `events` row (matching `(kind, pubkey, d_tag)`) when `delete_workflow_for_owner` succeeds, the same way every other addressable kind's deletion path already does. Alternatively, have `cmd_list_workflows` cross-reference the `workflows` table (or an equivalent still-active check) before including an entry.
## Repro
1. Create a workflow, confirm it in `buzz workflows list`.
2. `buzz workflows delete ` — returns `accepted: true`.
3. `buzz workflows list` — the deleted workflow is still present.
Happy to provide more detail if useful; found this while investigating a "zombie workflow" report in our own deployment (`larreala/AgenticOS#67`).
Contributor guide
Research direction
Start with cmd_list_workflows in crates/buzz-cli/src/commands/workflows.rs and follow the deletion path through handle_a_tag_deletion in crates/buzz-relay/src/handlers/side_effects.rs and delete_workflow_for_owner in crates/buzz-db/src/workflow.rs. Reproduce the create, list, delete, and list sequence, then verify that deleted workflows no longer appear while scheduler queries remain unaffected.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- backend, cli, database
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 56/100