Fix NIP-09 deletion for parameterized replaceable events (NIP-33)

Fixed bug where deleting a parameterized replaceable event (e.g., kind 31922)
using an 'a' tag would incorrectly delete ALL events of that kind instead of
just the specific event with the matching d-tag.

**Root Cause:**
NostrFilter's 'd' field uses a Pydantic Field alias "#d". When creating a filter
with `NostrFilter(d=[value])`, Pydantic ignores it because the parameter name
doesn't match the alias.

**Fix:**
Changed filter creation to use the alias:
```python
NostrFilter(authors=[...], kinds=[...], **{"#d": [d_tag]})
```

**Testing:**
- Created two tasks with different d-tags
- Deleted only one task
- Verified only the specified task was marked as deleted in the database
- Confirmed the other task remained unaffected

This ensures proper NIP-09 deletion behavior for NIP-33 parameterized
replaceable events using 'a' tag format (kind:pubkey:d-identifier).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Patrick Mulligan 2025-11-16 22:47:16 +01:00
parent 8bfd792548
commit dcc3204735

View file

@ -235,15 +235,20 @@ class NostrClientConnection:
kind = int(kind_str) kind = int(kind_str)
# Only delete if the address pubkey matches the deletion event author # Only delete if the address pubkey matches the deletion event author
if addr_pubkey == event.pubkey: if addr_pubkey == event.pubkey:
# NOTE: Use "#d" alias, not "d" directly (Pydantic Field alias)
nostr_filter = NostrFilter( nostr_filter = NostrFilter(
authors=[addr_pubkey], authors=[addr_pubkey],
kinds=[kind], kinds=[kind],
d=[d_tag] **{"#d": [d_tag]} # Use alias to set d field
) )
events_to_delete = await get_events(self.relay_id, nostr_filter, False) events_to_delete = await get_events(self.relay_id, nostr_filter, False)
ids_to_delete.extend([e.id for e in events_to_delete if not e.is_delete_event]) ids_to_delete.extend([e.id for e in events_to_delete if not e.is_delete_event])
else:
logger.warning(f"Deletion request pubkey mismatch: {addr_pubkey} != {event.pubkey}")
except ValueError: except ValueError:
logger.warning(f"Invalid kind in address: {addr}") logger.warning(f"Invalid kind in address: {addr}")
else:
logger.warning(f"Invalid address format (expected kind:pubkey:d-tag): {addr}")
# Only mark events as deleted if we found specific IDs # Only mark events as deleted if we found specific IDs
if ids_to_delete: if ids_to_delete: