Buzz Version 0.4.26 (0.4.26)
MacOS Sequoia 15.7.5
Summary
Deleting a workflow works: the DB row is removed, the engine cache is invalidated, and the workflow can no longer be triggered. But the kind:30620 definition event is deliberately left un-soft-deleted, and both CLI read commands query that event.
Every surface an operator can inspect reports the workflow as live. The only way to find out it is gone is to trigger it.
Environment
Source read at block/buzz commit a64cc71 (main); relay under test reports version: 0.2.0 via NIP-11 (version match, not commit-exact).
All CLI output below was executed against a live relay.
Reproduction
$ buzz workflows list --channel [ … 6f8ef4ca-697c-47d9-8aea-a0b7800300c4 still present, full YAML … ]
$ buzz workflows get --workflow 6f8ef4ca-697c-47d9-8aea-a0b7800300c4 {"workflow_id":"6f8ef4ca-…","content":"name: Approval Gate Control\n…"}
$ buzz workflows trigger --workflow 6f8ef4ca-697c-47d9-8aea-a0b7800300c4 {"error":"relay_error","message":"relay error 400: invalid: workflow not found"} ```
The delete succeeded. list and get disagree.
Confirmed on two separate workflows. Neither posted its first step after deletion, and both had posted it on every prior trigger, so the trigger failure is corroborated by an observable side effect rather than by the error string alone.
Root cause
cmd_delete_workflow (crates/buzz-cli/src/commands/workflows.rs:139-150) signs a kind:5 whose a tag is 30620:<pubkey>:<workflow_id> (crates/buzz-sdk/src/builders.rs:1498-1508).
handle_a_tag_deletion (crates/buzz-relay/src/handlers/side_effects.rs:1979-2053) dispatches on the kind in the a tag. The KIND_WORKFLOW_DEF arm calls delete_workflow_for_owner and invalidate_channel_workflows, then returns. The generic parameterized-replaceable arm below it — the one that calls soft_delete_by_coordinate so REQs stop returning the event — is never reached, because the workflow arm matched first. The code comment states this is deliberate:
rust // Listed after the workflow branch so workflow's bespoke deletion // (which doesn't soft-delete the `events` row by design — that's a // separate concern) takes precedence.
Meanwhile cmd_list_workflows and cmd_get_workflow (crates/buzz-cli/src/commands/workflows.rs:20-58) both query {"kinds":[30620]}. They read exactly the row the delete path declines to touch.
The two halves are each internally consistent. The disagreement is between them.
Impact
An operator cannot tell a deleted workflow from a live one through any shipped read path.
A definition intended to be retired stays fully readable. Since workflows list returns the complete YAML body to any channel member, a workflow deleted because its content was sensitive is still readable by every member afterwards.
Combined with workflows runs returning [] by construction (documented at crates/buzz-cli/src/commands/workflows.rs:60-65), the CLI's entire workflow-observability surface can disagree with the engine.
Secondary: accepted: true on delete carries no information about the target
$ buzz workflows delete --workflow 00000000-0000-4000-8000-000000000000 {"accepted":true,"event_id":"f5718152…","message":""}
That UUID has never existed. The response reports that the kind:5 event was stored, not that a workflow was deleted — delete_workflow_for_owner returning None is logged and otherwise ignored. An operator who typos a workflow id gets an unqualified success. (We hit this by accident before hitting it on purpose.)
Suggested fix
Soft-delete the event row as well as the DB row. Call soft_delete_by_coordinate from the KIND_WORKFLOW_DEF arm, or let that arm fall through to the generic parameterized-replaceable handler after doing its bespoke work. Either makes list/get agree with trigger.
If leaving the event live is intentional — e.g. definitions are meant to be an append-only audit trail — then cmd_list_workflows should reconcile against the engine, or mark deleted entries, rather than presenting them as current. Whichever way it is decided, the two surfaces should not disagree silently.
Report whether anything was deleted. Have the delete path surface delete_workflow_for_owner's Option so a no-op delete is distinguishable from a real one.
Found by Bumble (Buzz onboarding agent) on 2026-07-25 while deleting test artifacts from an unrelated investigation.
Buzz Version 0.4.26 (0.4.26)
MacOS Sequoia 15.7.5
Summary
Deleting a workflow works: the DB row is removed, the engine cache is invalidated, and the workflow can no longer be triggered. But the kind:30620 definition event is deliberately left un-soft-deleted, and both CLI read commands query that event.
Every surface an operator can inspect reports the workflow as live. The only way to find out it is gone is to trigger it.
Environment
Source read at block/buzz commit a64cc71 (main); relay under test reports version: 0.2.0 via NIP-11 (version match, not commit-exact).
All CLI output below was executed against a live relay.
Reproduction