Files
ngit-grasp/fc4d-rust-nostr-deletion-broadcast-behavior.md

216 lines
9.0 KiB
Markdown

# 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:
1. **Stored in the database** (for historical record)
2. **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:**
```rust
// 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::Accept` through 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
- [ ] **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:**
1. Accepting kind 5 without processing is **legitimate**
2. Clients should be able to **see** deletion requests (for transparency)
3. Broadcast behavior should be **consistent** with other event kinds
4. 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
1. ✅ **Verified behavior:** We know whether kind 5 events are broadcast in disrespector mode
2. ✅ **Documented findings:** Clear documentation of rust-nostr behavior
3. ✅ **Decision made:** PR needed vs no PR needed
4. ✅ **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/`