Desktop: Repositories list hides re-announced repos forever — deletion filter ignores `created_at`
- Dominant language
- Rust
- Stars
- 32.7k
- Forks
- 4.3k
- Avg merge
- 1d 13h
- Merged PRs (30d)
- 253
Description
## Summary
`isDeletedByA` in `desktop/src/features/projects/hooks.ts` hides a project card when any same-author kind:5 deletion references its `30617::` coordinate:
```ts
return deletionEvents.some(
(event) =>
event.pubkey.toLowerCase() === project.owner.toLowerCase() &&
event.tags.some((tag) => tag[0] === "a" && tag[1] === coordinate),
);
```
There is no `created_at` comparison. Under NIP-09, a deletion applies to events that existed when it was published — a **newer** replaceable event at the same coordinate is live. The relay gets this right (the newer 30617 is stored, served, and the git endpoint works); Desktop hides it forever. Once an owner has ever deleted a project (including via Desktop's own "Delete project" button), no re-announcement at that coordinate will ever render again for any user, even though clone/push/CLI all work.
## Repro
1. Announce a repo (kind:30617, dtag `X`).
2. Delete it (kind:5 with `a` = `30617::X` — Desktop's Delete project button does this).
3. Announce dtag `X` again (fresh 30617, newer `created_at`; relay accepts and repo works over git).
4. Desktop → Repositories: the repo never appears. `fetchProjects` filters it out via `isDeletedByA`.
Hit in the wild while recovering from #3527: both the repo owner's re-announcement and an agent's re-announcement of `bitchat` are live on the relay and clone-able, but invisible in Desktop; only never-deleted test repos render.
## Suggested fix
Only honor deletions at least as new as the announcement being filtered:
```ts
event.created_at >= project.createdAt
```
(plus the existing author check). Same consideration applies anywhere else kind:5 a-tag filtering is done client-side against replaceable events.
## Related UI gap in the same flow
The Delete-project button is gated on strict key equality (`isProjectOwnedByCurrentUser` in `desktop/src/features/projects/lib/projectsViewHelpers.ts` → `canDelete` in `ProjectsView.tsx`), but the relay's `validate_standard_deletion_event` (`crates/buzz-relay/src/handlers/side_effects.rs`) explicitly also accepts "the owning human deleting their agent's events" (`is_agent_owner`). So a user cannot delete their own managed agent's repos from Desktop even though the relay would authorize it. Desktop's client-side deletion filter (`isDeletedByA`) has the same blind spot: it only honors deletions whose pubkey equals the announcement author, so a relay-accepted owner-of-agent deletion would still leave the card rendered until the relay drops the announcement from REQs.
## Related
- #3527 (unbound-repo 404s) — this bug compounds that recovery path: users who deleted a broken repo while debugging can never see it again after re-announcing.
- The stranded `git_repo_names` reservation (separate follow-up on #3527) forces recovery re-announcements in the first place.
Contributor guide
Assessment
This issue has not been assessed yet.