Skip to content

relay: NIP-09 a-tag deletion is a no-op for kind:30023 (and all non-workflow addressables) #714

@tlongwell-block

Description

@tlongwell-block

Summary

handle_a_tag_deletion in crates/sprout-relay/src/handlers/side_effects.rs (≈line 1330) only implements a side-effect branch for KIND_WORKFLOW_DEF. All other addressable kinds — including kind:30023 (NIP-23 long-form) — fall through to the _ => arm which only emits a debug log. The kind:5 deletion event is accepted and stored, but the targeted addressable row is never soft-deleted, so subsequent REQs still return it.

Why this matters

sprout-cli is gaining notes rm for the team knowledge-base workflow (NIP-23 editable notes). The semantically correct NIP-09 deletion of a parameterized-replaceable note targets its a coordinate (30023:<pubkey>:<slug>), not just the event id — otherwise a future re-set of the same slug could be shadowed by a stale tombstone or cause confusion about which event id is authoritative.

The CLI's v1 workaround is to include both an e-tag (current event id, which works via the existing soft-delete path) and an a-tag (forward-compatible, currently a no-op). Once this relay-side gap is closed, rm becomes more robust without any CLI change.

Code pointers

  • crates/sprout-relay/src/handlers/side_effects.rs:1330handle_a_tag_deletion; the _ => branch is the gap.
  • crates/sprout-db/src/event.rssoft_delete_event(event_id) exists; no soft_delete_by_coordinate analogue.
  • Read-path filtering in crates/sprout-relay/src/handlers/req.rs already gates on deleted_at IS NULL, so once the side-effect path soft-deletes the row, REQs hide it automatically.

Proposed fix (sketch, non-binding)

  1. Add sprout_db::event::soft_delete_addressable(pool, kind, pubkey, d_tag) -> Result<bool> that updates deleted_at on the row matching (kind, pubkey, d_tag). The d_tag column already exists and is indexed for NIP-33 kinds.
  2. In handle_a_tag_deletion, replace the unconditional _ => debug log with a call to that helper for any parameterized-replaceable kind (or a documented allowlist if we want to be cautious). Workflow-specific logic stays where it is.

Validation already done

  • e-tag deletion path works fully for kind:30023 (deleted_at set; REQs hide it).
  • a-tag kind:5 events are accepted by validation (validate_standard_deletion_event correctly checks author ownership via pubkey-in-coordinate), but have no DB-level effect.

Scope

Out of scope: rebroadcast / discovery of the deletion event to other relays. This issue is purely about the local read-path consistency.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions