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:1330 — handle_a_tag_deletion; the _ => branch is the gap.
crates/sprout-db/src/event.rs — soft_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)
- 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.
- 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.
Summary
handle_a_tag_deletionincrates/sprout-relay/src/handlers/side_effects.rs(≈line 1330) only implements a side-effect branch forKIND_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-cliis gainingnotes rmfor the team knowledge-base workflow (NIP-23 editable notes). The semantically correct NIP-09 deletion of a parameterized-replaceable note targets itsacoordinate (30023:<pubkey>:<slug>), not just the event id — otherwise a future re-setof 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 ana-tag (forward-compatible, currently a no-op). Once this relay-side gap is closed,rmbecomes more robust without any CLI change.Code pointers
crates/sprout-relay/src/handlers/side_effects.rs:1330—handle_a_tag_deletion; the_ =>branch is the gap.crates/sprout-db/src/event.rs—soft_delete_event(event_id)exists; nosoft_delete_by_coordinateanalogue.crates/sprout-relay/src/handlers/req.rsalready gates ondeleted_at IS NULL, so once the side-effect path soft-deletes the row, REQs hide it automatically.Proposed fix (sketch, non-binding)
sprout_db::event::soft_delete_addressable(pool, kind, pubkey, d_tag) -> Result<bool>that updatesdeleted_aton the row matching(kind, pubkey, d_tag). Thed_tagcolumn already exists and is indexed for NIP-33 kinds.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
deleted_atset; REQs hide it).validate_standard_deletion_eventcorrectly 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.