9.0 KiB
rust-nostr: Deletion Request Broadcast Behavior Investigation
ID: fc4d
Status: Investigation Needed
Priority: Low (Non-Urgent)
Complexity: Medium (requires rust-nostr codebase investigation)
Type: Potential Upstream PR
Problem Statement
Deletion requests (kind 5) should ALWAYS be broadcast to subscribers with matching filters, regardless of whether the relay honors the deletion.
When ngit-grasp runs in "deletion request disrespector" mode (deletion_request_disrespector = true), it accepts kind 5 (NIP-09 deletion request) events but intentionally does NOT process them (doesn't delete the target events). However, the deletion request events themselves MUST be:
- Stored in the database (for historical record)
- Broadcast to active WebSocket subscribers with matching filters (standard relay behavior)
Current uncertainty: We need to verify that rust-nostr's nostr-relay-builder actually broadcasts kind 5 events to active subscribers when WritePolicyResult::Accept is returned from the WritePolicy.
Expected behavior: Deletion requests are events like any other. Whether a relay chooses to honor the deletion is a separate concern from whether it broadcasts the deletion request event to subscribers.
Why This Matters
Archive relay use case:
- Archive relays preserve deleted content (prevent "left-pad" scenarios)
- Deletion requests are legitimate events that clients may want to track
- Clients with filters matching kind 5 should receive these events
- This is standard relay behavior: accepted events → saved + broadcast
Current implementation:
// src/nostr/builder.rs:759-766
DeletionResult::AcceptIgnore => {
tracing::debug!(
event_id = %event_id_str,
author = %event.pubkey,
"Accepted deletion request but ignoring (disrespector mode)"
);
WritePolicyResult::Accept // ← Does this trigger broadcast?
}
Investigation Tasks
Phase 1: Verify Current Behavior
-
Test current ngit-grasp behavior:
- Start relay in disrespector mode
- Connect WebSocket client with filter:
{"kinds": [5]} - Submit kind 5 deletion request
- Verify: Is event broadcast to subscriber?
- Verify: Is event stored in database?
-
Document findings:
- If YES (broadcasts): Document that current behavior is correct
- If NO (doesn't broadcast): Document the gap
Phase 2: Investigate rust-nostr Source Code
-
Examine nostr-relay-builder event flow:
- Trace
WritePolicyResult::Acceptthrough relay code - Find where events are saved to database
- Find where events are broadcast to subscribers
- Determine if kind 5 has special handling that bypasses broadcast
- Trace
-
Check for automatic NIP-09 processing:
- Verify if relay layer (not just database layer) filters kind 5
- Check if there's a "don't broadcast deletion requests" policy
- Document any hardcoded NIP-09 behavior
Phase 3: Determine If PR Is Needed
Based on investigation findings:
Scenario A: Current behavior is correct (broadcasts kind 5)
- Document that no PR is needed
- Update ngit-grasp docs to confirm broadcast behavior
- Close this issue as "working as designed"
Scenario B: rust-nostr doesn't broadcast kind 5 events
- Determine root cause (intentional vs bug)
- Design PR proposal (see below)
- Discuss with rust-nostr maintainers
- Implement and submit PR
Proposed PR (If Needed)
Option 1: Fix Bug (if it's unintentional)
If rust-nostr is accidentally not broadcasting kind 5 events when WritePolicyResult::Accept is returned:
Change: Ensure kind 5 events follow standard event flow (save + broadcast)
Rationale:
- NIP-09 says relays "MAY" honor deletions, not "MUST"
- Accepting but not processing is legitimate (archive relays)
- Accepted events should always be broadcast to matching subscribers
- This is standard relay behavior regardless of event kind
Option 2: Fix Intentional Behavior (if it's by design)
If rust-nostr intentionally doesn't broadcast kind 5 events:
Change: Remove special-casing of kind 5 events - they should follow standard event flow
Rationale:
- Deletion requests are events, not commands - they should be broadcast like any other event
- Separation of concerns: Broadcasting events vs honoring deletions are separate decisions
- Standard relay behavior: All accepted events should be broadcast to matching subscribers
- No configuration needed: There's no legitimate reason to suppress deletion request broadcasts
- Transparency: Clients should be able to see deletion requests regardless of relay policy
Strong position: We should NOT add a configuration option to suppress broadcasts. Deletion requests are events and should always be broadcast. The relay's choice to honor or ignore the deletion is orthogonal to broadcasting the event.
Option 3: No Change Needed (if configurable)
If rust-nostr already has a way to control this behavior:
- Document the configuration option
- Update ngit-grasp to use it correctly
- No upstream PR needed
NIP-09 Specification Context
From NIP-09:
Relays MAY choose to honor deletion requests or not.
Implications:
- Accepting kind 5 without processing is legitimate
- Clients should be able to see deletion requests (for transparency)
- Broadcast behavior should be consistent with other event kinds
- Archive relays need full event history including deletion requests
Use cases for seeing deletion requests:
- Audit trails (who deleted what, when)
- Research and analysis (deletion patterns)
- Client-side deletion handling (some clients may honor deletions locally)
- Transparency (users can see what was requested to be deleted)
Related Work
ngit-grasp implementation:
- Issue:
b905-deletion-request-support.md - Implementation: Phase 1-4 complete (holding database, recovery, graph algorithm)
- Disrespector mode: Working (stores events, doesn't process deletions)
- Question: Are stored events being broadcast?
rust-nostr investigation:
- Previous finding: Database layer automatically processes kind 5 (deletes events)
- Workaround: WritePolicy intercepts before database layer
- New question: Does relay layer broadcast accepted kind 5 events?
Success Criteria
- ✅ Verified behavior: We know whether kind 5 events are broadcast in disrespector mode
- ✅ Documented findings: Clear documentation of rust-nostr behavior
- ✅ Decision made: PR needed vs no PR needed
- ✅ If PR needed: Proposal written and discussed with maintainers
Timeline
Priority: Low (non-urgent)
- Not blocking ngit-grasp Phase 4-7 implementation
- Can be investigated after deletion support is complete
- Good candidate for post-implementation cleanup
Suggested timing:
- After Phase 7 (ngit-grasp deletion support complete)
- When we have working disrespector mode to test against
- Before announcing archive relay capabilities publicly
Progress
2026-01-15 [Session 10:00]
- Created issue: Based on user question about deletion request broadcast behavior
- Context: User correctly identified that "deletion request" implies optional processing
- Question raised: Are kind 5 events broadcast to WebSocket subscribers in disrespector mode?
- Pattern: ngit-grasp directly saves events to database, which triggers broadcast elsewhere
- Uncertainty: Need to verify this pattern applies to kind 5 events
- Next: Investigate current behavior with test client, then examine rust-nostr source
2026-01-15 [Session 10:15]
- Position clarified: Deletion requests should ALWAYS be broadcast
- Rationale: Deletion requests are events, not commands - broadcasting is separate from honoring
- Updated issue: Strengthened stance against configuration options for suppressing broadcasts
- Key principle: Separation of concerns - broadcasting events vs processing deletions are orthogonal
- Next: Test current behavior, then prepare PR if needed (no configuration option, just fix)
Notes
Key insight from user:
"The clue is in the name 'request'" - NIP-09 deletion requests are optional, not mandatory
Standard relay pattern:
Event arrives → WritePolicy.admit_event() → WritePolicyResult::Accept
↓
Database.save_event() → Broadcast to subscribers
Question: Does this pattern apply to kind 5 events, or do they have special handling?
Why this matters:
- Archive relays need transparency (show all events including deletion requests)
- Clients may want to track deletion requests for audit/analysis
- Standard relay behavior: accepted events are broadcast
- Consistency: kind 5 shouldn't be special-cased unless necessary
References
- NIP-09 Spec:
/persistent/dcdev/clones/nips/09.md - ngit-grasp deletion support:
b905-deletion-request-support.md - rust-nostr investigation: Previous findings in b905 Phase 6 notes
- nostr-relay-builder:
~/.cargo/git/.../nostr-relay-builder/