Skip to content

fix(relay): tombstone kind:30620 event row on NIP-09 a-tag workflow deletion - #2268

Open
s00ly wants to merge 1 commit into
block:mainfrom
s00ly:fix/relay-workflow-def-a-tag-tombstone
Open

fix(relay): tombstone kind:30620 event row on NIP-09 a-tag workflow deletion#2268
s00ly wants to merge 1 commit into
block:mainfrom
s00ly:fix/relay-workflow-def-a-tag-tombstone

Conversation

@s00ly

@s00ly s00ly commented Jul 21, 2026

Copy link
Copy Markdown

Problem

handle_a_tag_deletion's KIND_WORKFLOW_DEF branch deletes the workflows
projection row but never tombstones the underlying kind:30620 event row, so
REQ subscribers (e.g. buzz workflows list) keep receiving the deleted
definition. Fixes #717 — same bug shape as #714, scoped to the workflow kind
(the generic NIP-33 arm added for #714 intentionally excluded it).

Implementation

Tombstone the event row via soft_delete_by_coordinate on both deletion paths:

  • UUID path: the a-tag d-value is the workflow id, which is also the event
    row's d-tag (handle_workflow_def requires d = workflow UUID).
  • Name path: the a-tag d-value is a name, not the event coordinate, so we
    resolve the workflow row first and tombstone by its id.
  • The UUID-path tombstone is unconditional, which also heals pre-fix rows whose
    projection is already gone but whose event row stayed live (re-sending the
    deletion now converges them).

The coordinate uses the a-tag's pubkey — the NIP-33 author — matching what
validate_standard_deletion_event authorized.

Verified nothing operational relies on the row staying live: the workflow
engine and the webhook bridge load definitions from the workflows table
(never the events row), and audit lookups go through
get_event_by_id_including_deleted, which is tombstone-tolerant by design.

Composes with #2242 (same function, different concern: that PR aligns who
the projection delete targets; this one adds the missing event tombstone).
Happy to rebase over whichever lands first.

Testing

New crates/buzz-test-client/tests/e2e_workflow_def_deletion.rs (2 tests:
UUID deletion, name deletion). Verified against a local relay
(postgres/redis/minio via docker compose):

just ci not run end-to-end locally (desktop/mobile toolchain versions on
this machine); no desktop or mobile files touched — relying on GitHub CI for
those legs.

Checklist

  • cargo fmt + clippy -D warnings clean
  • Regression test included (fails without the fix)
  • No new unwrap() in production code paths
  • No new unsafe blocks

@s00ly
s00ly requested a review from a team as a code owner July 21, 2026 19:47
…eletion

handle_a_tag_deletion's KIND_WORKFLOW_DEF branch deleted the workflows
projection row but never tombstoned the underlying kind:30620 event row,
so REQ subscribers (e.g. `buzz workflows list`) kept receiving the
deleted definition.

Tombstone the event row by NIP-33 coordinate on both deletion paths:
the UUID path (a-tag d == workflow id == event d-tag) and the name path
(resolve the row, tombstone by id). The UUID-path tombstone is
unconditional, which also heals pre-fix rows whose projection is already
gone but whose event row stayed live.

Verified nothing operational relies on the row staying live: the
workflow engine and webhook bridge load from the workflows table, and
audit lookups use get_event_by_id_including_deleted.

Regression coverage: e2e_workflow_def_deletion.rs (UUID + name paths),
verified to fail against unfixed code and pass with the fix.

Fixes block#717

Signed-off-by: Sooly Kobayashi <yloos@protonmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

triage-ready Appropriate for agentic review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

relay: NIP-09 a-tag deletion of kind:30620 (workflow def) leaves the events row alive

2 participants