Skip to content

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

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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions