fix(events): collapse own-event draft + relay copy into one card #127

Merged
padreug merged 1 commit from fix/own-event-draft-duplicate into dev 2026-06-18 22:51:04 +00:00
Owner

Problem

A creator's own event renders twice in the events feed — one full card (real organizer profile, price, ticket counts) next to a hollow duplicate (organizer "…", no price, no ticket count, "Yours" badge). Only the logged-in owner of an event sees it.

Root cause — regression from coordinate-keying (#125)

loadOwnEvents surfaces the caller's own LNbits events via REST (ticketedEventToEvent) so drafts show in the feed before their NIP-52 event reaches a relay. That adapter stamps:

  • organizer.pubkey: '' (no Nostr author yet)
  • isMine: true
  • no ticketInfo

The relay-published copy lands under the real publisher pubkeyresolve_for_wallet in the events extension, which is not the user's Nostr login key — and carries full ticket counts.

Before the store was coordinate-keyed, both copies collapsed onto the bare d-tag, so the relay copy (newer createdAt) replaced the draft. Under kind:pubkey:d-tag (#125) the empty-pubkey draft and the real-pubkey copy are distinct keys, so both persist → the hollow /no-tickets card beside the real one. It's owner-only because only own events get the REST merge.

Fix

upsertEvent now reconciles by d-tag: the published copy supersedes the provisional draft and inherits its isMine, so the creator keeps the Yours badge + Hosting filter even though the publisher key differs from their login key (ownership can't be re-derived by pubkey match here). Handles both arrival orderings; a draft with no published copy yet (pending review) still shows alone; two genuinely distinct authors sharing a d-tag are left untouched (the cross-author-hijack guard from #125 is preserved).

Tests

4 new store specs (both orderings, pending-draft-alone, distinct-authors-not-folded). Full suite green (19 passed).

Note for review

This exposes a deeper smell: the webapp's ownership check (organizer.pubkey === myPubkey) assumes the publisher key equals the user's Nostr login key, which resolve_for_wallet breaks. The draft→published isMine inheritance papers over it correctly for owned events; a longer-term fix would tie ownership to the LNbits identity rather than a pubkey match.

🤖 Generated with Claude Code

## Problem A creator's own event renders **twice** in the events feed — one full card (real organizer profile, price, ticket counts) next to a hollow duplicate (organizer "…", no price, no ticket count, "Yours" badge). Only the logged-in **owner** of an event sees it. ## Root cause — regression from coordinate-keying (#125) `loadOwnEvents` surfaces the caller's own LNbits events via REST (`ticketedEventToEvent`) so drafts show in the feed before their NIP-52 event reaches a relay. That adapter stamps: - `organizer.pubkey: ''` (no Nostr author yet) - `isMine: true` - **no** `ticketInfo` The relay-published copy lands under the **real publisher pubkey** — `resolve_for_wallet` in the events extension, which is *not* the user's Nostr login key — and carries full ticket counts. Before the store was coordinate-keyed, both copies collapsed onto the bare d-tag, so the relay copy (newer `createdAt`) replaced the draft. Under `kind:pubkey:d-tag` (#125) the empty-pubkey draft and the real-pubkey copy are **distinct keys**, so both persist → the hollow `…`/no-tickets card beside the real one. It's owner-only because only own events get the REST merge. ## Fix `upsertEvent` now reconciles by d-tag: the published copy **supersedes** the provisional draft and **inherits its `isMine`**, so the creator keeps the *Yours* badge + *Hosting* filter even though the publisher key differs from their login key (ownership can't be re-derived by pubkey match here). Handles both arrival orderings; a draft with no published copy yet (pending review) still shows alone; two genuinely distinct authors sharing a d-tag are left untouched (the cross-author-hijack guard from #125 is preserved). ## Tests 4 new store specs (both orderings, pending-draft-alone, distinct-authors-not-folded). Full suite green (19 passed). ## Note for review This exposes a deeper smell: the webapp's ownership check (`organizer.pubkey === myPubkey`) assumes the publisher key equals the user's Nostr login key, which `resolve_for_wallet` breaks. The draft→published `isMine` inheritance papers over it correctly for owned events; a longer-term fix would tie ownership to the LNbits identity rather than a pubkey match. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Coordinate-keying the events store (kind:pubkey:d-tag) regressed the
own-events merge: a creator's own event showed up twice in the feed.

`loadOwnEvents` surfaces the caller's own LNbits events via REST
(`ticketedEventToEvent`) so drafts appear before their NIP-52 event is
on a relay. That adapter stamps an empty `organizer.pubkey`, `isMine`,
and no ticket info. The relay-published copy lands under the real
publisher pubkey (`resolve_for_wallet` — NOT the user's Nostr login
key) with full ticket counts. Pre-coordinate-keying both collapsed on
the bare d-tag so the relay copy replaced the draft; under
`kind:pubkey:d-tag` the empty-pubkey draft and the real-pubkey copy are
distinct keys, so both render — the empty "..."/no-tickets card next to
the real one. Only the logged-in owner sees it, since only own events
get the REST merge.

upsertEvent now reconciles by d-tag: the published copy supersedes the
provisional draft and inherits its `isMine`, so the creator keeps the
Yours badge + Hosting filter even though the publisher key differs from
their login key. Handles both arrival orderings; a draft with no
published copy yet (pending review) still shows alone; genuinely
distinct authors sharing a d-tag are untouched.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
padreug deleted branch fix/own-event-draft-duplicate 2026-06-18 22:51:05 +00:00
Sign in to join this conversation.
No description provided.