nips icon indicating copy to clipboard operation
nips copied to clipboard

We need a way to request direct replies to a note

Open arthurfranca opened this issue 2 years ago • 20 comments

Currently, if we use the filter { kinds: [1], #e: ['note id'] }, it won't bring only the direct replies to the note, making it hard (impossible?) to lazily (e.g. infinite scroll) build a thread, specially the ones with lots of engagement.

This is because of:

  • NIP-08 (Handling Mentions) supporting clients can add extra e tags mentioned in content
  • NIP-10 supporting clients can add many e tags (1 root, maybe 1 reply and maybe one or more mentions)

There is no way to fetch just the direct replies (that would be the NIP-10 with the root marker OR the NIP-10 with the reply marker; it depends).

Currently, nostr expects clients to fetch all thread at once (which will probably get limited by relays when the thread is big). It gets really difficult when you use limit on the request filter as it will sort by created_at desc, so it may retrieve latest non-direct replies or mentions. E.g.: { kinds: [1], #e: ['root note id'], limit: 10 } may bring 2 mentions and 8 replies not directed to the root note

So i think we need to add a tag denoting direct reply. Maybe an R tag (just one max per event).

What do you think of adding it so that a client can use the following filter? { kinds: [1], #R: ['note id or long form content address'], limit: 10 }

And this should supersede NIP-10 reply marker.

arthurfranca avatar Feb 17 '23 13:02 arthurfranca

I like this solution a lot. Replies are the one universal concept in social media applications, event tags are far too broad to support them efficiently.

staab avatar Feb 17 '23 14:02 staab

I like this too. In general, would be nice to have efficient ways to build reply trees.

Use-case 1: Start at a leaf note and move to the root note. Use the IDs field in the query filter, taking the ID from the R tag.

Use-case 2: Start at root note and fetch the child notes (building the reply tree from top down). With this proposal, can use R query tag. Anticipated improvement in bandwidth + specificity of the query. Still will probably return a fair amount spam if spammers include the R tag linking to popular messages. Limiting only one R tag per note could mitigate that a bit though.

barkyq avatar Feb 18 '23 22:02 barkyq

In principle this is fine, but this is introducing a huge breaking change that also possibly makes it more inefficient to download a full thread and get live updates from it.

And the goal is just to solve the problem of "thread too big"? What is a thread too big? A thousand replies? Clients are downloading much more than a thousand events routinely on feeds today, for reactions, contact lists and whatnot. How many threads have a thousand replies? Where are these big threads? Are these replies all in the same relay (in the future they probably would not be)?

If a thread has hundreds of replies then I think there are other problems that must be solved before you introduce a way to do these fine-grained queries, because no one is going to read these huge threads which are likely to be full of spam and valueless comments, so clients must already be mindful of querying for events in a thread only in relays that provide good signal (and other techniques).

fiatjaf avatar Feb 18 '23 23:02 fiatjaf

I guess the size is relative to the relays max # of events returned per query.

If everyone in the thread agrees to tag the "root", then any query which includes the root tag will return every note in the thread. I suppose one could paginate using since and until.

Theoretically, I think that it would be nice to have some way of asking for the "direct children" of a note (query the R tag). I also think it is nice to be able to ask for all notes which refer to a given note (query the e tag)... These two ways can hopefully coexist. Thus I disagree that it would make it more inefficient to download a full thread, since the proposal would not replace the current way of doing things.

I think that, if a note N is on Relay X, the client should ideally be able to recreate the surrounding "thread reply tree" near N without having to go to other relays. At least, I think this should be a worthwhile goal. I agree that if Relay X is a super spammy relay, then it may be difficult to achieve this, even with @arthurfranca's proposal.


I suppose it would be inelegant to include the same data in an R tag and in an e tag. But duplicating the data would be the least breaking change. There could be something like R tag is an integer pointer to the e tags index, and the relay should use the corresponding e tag data when inserting the R tag into an index. Since this is not "generic tag query" behavior, perhaps one would want to switch away from a single letter. Maybe something like dd (for direct descendant). For example:

{
  ...,
  "tags":[["e","aaa..."],["p","ccc..."],["e","bbb..."],["dd","2"]],
  ...
}

This note would be a direct descendant of bbb.... The filter:

{
  "#dd": ["bbb..."],
}

would match the above note.

For reducing amount of logic, the dd tag MUST come after the parent e tag in the list of tags. The dd tag contents MUST be a base 10 integer encoded as a string without leading 0s. The integer MUST be the 0-indexed position of an e tag in the tag array. Any dd tag after the first dd tag SHOULD be ignored by clients and relays implementing this.

Seems like something like this could slowly replace reply markers, without breaking anything too badly.

barkyq avatar Feb 19 '23 07:02 barkyq

It is late here. and perhaps my idea is ridiculous. will leave it up for posterity.

EDIT (added later):

  1. I do like that the extra data would be very lightweight for relays/clients which do not implement this...
  2. Seems a bit overkill since websocket compression would already compress repeated information quite well.
  3. Basically just moving the reply marker to its own tag, modulo the case where there is only the root marker. So seems a bit silly to add a new tag.
  4. (tongue-in-cheek) If we go with dd, then it would natural to call this NIP-221 since 0xdd=221.

barkyq avatar Feb 19 '23 07:02 barkyq

OP here, not main acc @fiatjaf main goals are:

  1. reduce bandwidth usage to lower relay hosting costs
  2. increase page load speed
  3. reduce cumulative layout shift (notes moving up an down while replies come at any order from different branches. All clients i've tested are like that)

2 and 3 are good to ux and ranking better at search engine results.

It is common for a user to read just some comments of a thread and go back to the feed. Very inneficient to request all thread for every user at every client reading a thread.

There could be something like R tag is an integer pointer to the e tags index, and the relay should use the corresponding e tag data when inserting the R tag into an index

@barkyq as you describe it, it seems the relay would have to store it either way so to index the r tag if i got it right. And the two char tag wouldn't get indexed by relays.

aaafrancaaa avatar Feb 19 '23 20:02 aaafrancaaa

Relays are able to index tags with more than 1 character, it's just not part of the generic tag queries NIP. My thought was, if the desired query behavior does not follow the generic tag query format, it should not use 1 character.

barkyq avatar Feb 19 '23 20:02 barkyq

Ok got it barkyq. I don't know what the best approach is but i think we do need this feature.

aaafrancaaa avatar Feb 19 '23 20:02 aaafrancaaa

Well I suppose there are (at least) three options.

Option 1: [["e","aaa..."], ["e","bbb..."], ["R","bbb..."]] Option 2: [["e","aaa..."], ["e","bbb..."], ["dd","1"]] Option 3: [["e","aaa..."], ["e","bbb..."], ["R","1"]]

Option 1 is nice because it leverages existing generic query tag behavior. In this sense, relays do not need to change anything to support this. A bit inelegant because of repeated info. Option 2 is nice because it has a smaller event size. It is opt-in by the relay since it does not use generic query tag format. Option 3 is bad since relays which support generic tag query but not this NIP will index these events as having useless R tag content.

The bandwidth downside to Option 1 is mitigated if compression is used.

barkyq avatar Feb 19 '23 20:02 barkyq

It is common for a user to read just some comments of a thread and go back to the feed.

They can already fetch the parent note.

fiatjaf avatar Feb 19 '23 20:02 fiatjaf

  1. reduce bandwidth usage to lower relay hosting costs
  2. increase page load speed
  3. reduce cumulative layout shift (notes moving up an down while replies come at any order from different branches. All clients i've tested are like that)
  1. How?
  2. This is not obvious at all. Doing a bunch of queries is probably much slower than a single query -- but of course it depends on many other implementation details and thread size.
  3. Web clients are horrible and there is ultimately no way to fix this. Yet it is very possible to make them better and remove these issues without breaking the current standard. Also I am pretty sure that just changing the standard wouldn't automatically make web clients better, that would still require the same amount of work to make the UIs not suck.

fiatjaf avatar Feb 19 '23 21:02 fiatjaf

@fiatjaf for instance, if we consider we can start as low as loading 5 direct children of the main note (depends on note bubble height), here it goes:

  1. { kinds: [1], #R: ['note id or long form content address'], limit: 5 } (if multiple relays, req the same for each one, merge and show at UI just the 5 latest replies)
  2. Optionally one would want to show a "continue thread" link below each children that has its own children. So for each 5 items we do { kinds: [1], #R: ['note id'], limit: 1 }, limiting to 1 item just to know if there is more or not.
  3. User scrolls to bottom
  4. Repeat 1 (add until: xxxx), 2 and 3

The inner branches use same algorithm, but triggered by user click instead of scrolling.

It is lighter bandwidth-wise and potentially faster if we consider main content comes from step 1.

aaafrancaaa avatar Feb 20 '23 10:02 aaafrancaaa

Right now most threads are pretty small so its not a big deal. I do think that this "feature" is a fairly fundamental one though. Clients should be able to say where they want their event to be positioned in the reply tree, in a way that relays can understand, and in a way which other clients can query.

I don't see why there is an emphasis on "breaking the current standard." Seems like this would be an opt-in feature which would not break the old way of doing things. Sure, if a client wanted to implement this, it would require a few new lines of code, but probably they already have that logic with deciding where to add the reply marker to.

Also, sidebar, there is not really a well-adopted "current standard." Half the people use reply and root and the other half just add a bunch of unmarked e tags.

There is certainly some discussion to be had whether this actually achieves anything beyond what can already be achieved using since, until, limit, and #e. Perhaps not. I think the lazy-loading use case described by @aaafrancaaa is nice.

In general, I think there is merit to having collections of events organized in a tree (e.g., posts in a github issues style thing, where each repo is an event, each issue event sets its parent to the repo event, each post sets its parent to the issue event).

barkyq avatar Feb 21 '23 00:02 barkyq

In general, I think there is merit to having collections of events organized in a tree (e.g., posts in a github issues style thing, where each repo is an event, each issue event sets its parent to the repo event, each post sets its parent to the issue event).

Yes @barkyq and tag name should be P for Parent event or something like that instead of R. R for direct Reply was kind of an inverted name, cause i was naming similar to NIP-10 reply marker. A tag to indicate the parent note/long form content(/any event) of which the current note is direct descendant.

The NIP-10 is marked as a draft. I can try to edit it, keeping the current way of doing things as it may be preferred by clients, just adding the P tag.

But it seems @fiatjaf isn't convinced.

arthurfranca avatar Feb 23 '23 18:02 arthurfranca

I like the idea, if it was like that since the beginning it would have probably been great. I am not convinced it's worth changing. If other client developers like it enthusiastically as @staab does, including Damus, we can for sure modify NIP-10 to include this yet new way of replying.

Although r for "root" and p for "direct parent" makes more sense to me -- so exactly the opposite of what you suggested.

fiatjaf avatar Feb 23 '23 19:02 fiatjaf

Also, sidebar, there is not really a well-adopted "current standard." Half the people use reply and root and the other half just add a bunch of unmarked e tags.

Yes, and this suggestion adds a third way. Adding new ways doesn't eliminate the old ways. https://xkcd.com/927/

If everyone were doing marked 'e' tags as recommended in NIP-10, then this suggestion could be implemented entirely by relays, right? And we wouldn't need a new tag, except we would need a new way to specify in the filter which events we were seeking.

mikedilger avatar Feb 24 '23 01:02 mikedilger

If everyone were doing marked 'e' tags as recommended in NIP-10, then this suggestion could be implemented entirely by relays, right? And we wouldn't need a new tag, except we would need a new way to specify in the filter which events we were seeking.

Yes, except that an e tag cannot be marked reply and root simultaneously.

Although I guess this could be handled (in a bit of a complicated way) by checking if there is only "root" and then assuming that is also supposed to be the "reply".

barkyq avatar Feb 24 '23 04:02 barkyq

I am partial to the addition of tags like ["dd", "3"], where "3" points to the index 3 entry in the tag array.

But I am certainly biased since it was my own idea..

One advantage is that multiple of these pointer tags could point to the same e tag. One disadvantage is new code for both relays and clients (and the XKCD comic's observation). Also having trouble thinking if this type of pointer tag would have any other use cases.

barkyq avatar Feb 24 '23 04:02 barkyq

Yes, and this suggestion adds a third way. Adding new ways doesn't eliminate the old ways. https://xkcd.com/927/

At least NIP-10 is a draft, maybe because we are at a time clients are trying things and seeing what works best or maybe we are just lucky lol cause as a draft we theoretically have the possibility to together decide how new and up-to-date social clients should work to interoperate and deprecate the old ways.

If everyone were doing marked 'e' tags as recommended in NIP-10, then this suggestion could be implemented entirely by relays, right? ...

I don't think adding relay logic and complexity, like the "dd" tag @barkyq suggests, just for an use case is better than adding a tag. But of course it is open for discussion.

The way of building all thread at once using the root marker works well (with caveats already listed) when the client is viewing the thread from the beginning. But when e.g. a twitter-like client is showing a view starting from a reply X deep in the tree it doesn't work, cause X isn't marked as root (but yeah, client could still load all thread just to show the slice). Yet, a tag/marker for root is good even when lazy loading, cause it enables showing something like this:

root
... "load more" ...
X
direct replies to X (plus "continue thread" for each one that has children)
... "load more" or infinite scroll ...

We have to think of 3 things: what is best for relays (bandwidth, disk space, simplicity), clients (lazy loading possibility? loading everything at once if it wishes? both or just one way?) and users (ux, notifications – NPT-10 lowercase p tag, discoverability by seo). Just client point of view isn't enough.

I don't see disqus, discourse, fb, instagram, twitter, telegram, whatsapp, reddit (all?) loading all thead at once. But if we still want to support the 2 ways of fetching a thread with minimum change, we could kill reply marker and add the P tag. The only "problem" is when P and e-root (or R tag as @fiatjaf said; uppercase cause r is already taken meaning reference?) have the same value we can't keep just the e-root/R as before because of lazy loading way and can't keep just the P tag because of the load-all-thread-at-once way. Not that bad the two tags having same value in this case (when at first level of replies) i guess.

If we use the R tag for root, we could kill markers, keeping e just for mentions (NIP-08 inline or reposts). R tag would allow long-form content address as value beside event id. Also it would make the load-all-thread-at-once way better by not fetching events that just mention the root when in fact one wants events that have a specific root (filter by R instead of the broader e – same that happens when using P instead of e).

Speaking of markers, now there is #293 pr for p markers which would reintroduce markers. But that should be discussed there.

arthurfranca avatar Feb 24 '23 17:02 arthurfranca

tl;dr

I've come up with an even better and simple way of connecting events as replies, needed for more advanced queries that would fight spam as a side effect.


First, an introduction to explain why it is needed. Yesterday i was paying attention to how hamstr.to ("Hamstr is a twitter-style Nostr web client") load replies compared to twitter and noticed it differs in an important way among other things.

Twitter tries to show the user the most interesting threads (MIT) on a post page first. I think MITs are the conversations/mini-threads that include OP replies or user (the one who is viewing the page) follows' replies – a series of linked replies (on twitter, these are linked by vertical lines between avatars).

MIT's also appear on Instagram (they highlight responses from OP) and on Youtube (they highlight replies liked by OP). MITs are always on top of other replies.

MITs have a great side effect of pushing down least intereresting conversations, including the damned spam, cause below MITs, considering that limit desc sort things on nostr, will be the latest direct descendant replies, which may include spam the relay wasn't able to block. (I'm considering the lazy loading way of loading threads instead of all at once that could sort however one wants).

If we consider MITs are desired, we need a way to fetch them without loading all replies at once, specially when considering spam could make threads huge and all other caveats already listed before. Loading all thread at once is just not best practice.

On twitter, when user clicks on a reply X, a page loads with MITs considering X as the OP of the branch. One example of a 2 levels MIC would be Y replying to X then X replying to Y. This is an important example that shows that sometimes we want MITs that don't consider the root as OP

Current way and my previous proposal aren't enough to request MITs. Recently, I was finally able to come up with a solution that would allow queries such as: show me X-OP direct replies to X OR X-OP/user friends replies to X's direct descendants. Also, show me X's direct descendant replies that were liked by X-OP. Examples later below.


New tags:

The branch b tags are responsible for telling what branch of the tree a reply is part of. Each b tag value is the id or address (if replaceable event) of the parent event, grandparent and so on up until reaching the root one. For instance, a reply event D should copy the replied to event C's b tags and then append C event id or address. A root event doesn't have b tags.

The level l tag is responsible for telling at what level in the tree a reply is. A reply event b tag count should be used as l value. A root event l tag has value '0' to allow requesting just root events.

An event can not be a reply to more than one event. (Or else it would mess with the l tag)

A relay may limit events to a certain max level (5 maybe?) <- Clients just need to not append a b tag if already at level 5.

Reaction events (NIP-25) must copy b and l tags from the reacted to event.

Example of a reply to 'ghi...' event:

  {
    ...,
    tags: [
      ['b', 'abc...'] // root event id or address
      ['b', 'def...']
      ['b', 'ghi...'] // replied to event id or address
      ['l', '3']
    ],
  }

Example load-all-thread-at-once filter

  {
    "kinds": [1],
    "#b": ['first X\'s b tag occurence value'], // root event id or address
  }

Example parent filter

  {
    "ids": ['last X\'s b tag occurence value'],
    "kinds": [1],
    "limit": 1
  }

Example direct descendant filter

  {
    "kinds": [1],
    "#b": ['X id or address']
    "#l": ['3'], // considering X is on level 2
    "limit": 5
  }

Example MIT filter

  {
    "authors": [X pubkey, user contact 1, user contact 2...],
    "kinds": [1],
    "#b": ['X id or address']
    "#l": ['3', '4'], // considering X is on level 2
    "limit": 5
  }

Example MIT filter by X-OP reaction

  {
    "authors": [X pubkey],
    "kinds": [7],
    "#b": ['X id or address']
    "#l": ['3'], // considering X is on level 2
    "limit": 5
  }

arthurfranca avatar Mar 01 '23 17:03 arthurfranca

Please people mention client authors you know so that they see this issue. @jb55 <- Damus (only know this one)

arthurfranca avatar Mar 04 '23 01:03 arthurfranca

I like this in the abstract, the level tags are pretty interesting. This is pretty similar to how e tags were originally specified (which ended up being unreliable because order wasn't specified?). At this point I'm with @fiatjaf because of the compatibility issue. Because a client can't rely on other clients implementing a new tag scheme, they can't rely on the tag scheme. Asking for l=3 will drop everything published by non-conforming clients. Maybe it's not time for the protocol to ossify yet, but that's the feeling I'm starting to get.

An alternative solution to this problem could be to solve it on the relays' side with a new filter, for example ["REQ", "23974", [{"marks": [["<event-id>", "reply"]]}]]. I personally tend to think marks were a mistake (in the vein of d tags, although those are better specified), but they are pretty well supported, and would solve the immediate children problem.

staab avatar Mar 04 '23 14:03 staab

@staab thank you for your feedback as a client author.

~Looking at what you said at issue #319~, it would make it possible to re-use e tags instead of adding another one. Then clients would just need to change a little (adding all ancestors as e tags instead of just root and reply ones) and add the level/depth l tag. Markers could be there unchanged just for backward compatiblity. What do you think?

Edit: Either way, some e mentions aren't that bad and could be just filtered out client-side.

arthurfranca avatar Mar 04 '23 16:03 arthurfranca

I think this issue is addressing a real need, but not one that comes up very often. So I support the effort. But I haven't taken the time to read this PR or the comments and I have no idea how to solve this. I'm just taking enough time to make this comment since you called for client authors.

mikedilger avatar Mar 04 '23 23:03 mikedilger

@mikedilger thank you for keeping an eye on this.

The tl;dr is have a way to 1) request replies to an event (not necessarily root one) n levels down on the tree of replies 2) request event ancestors n levels up on the tree.

The changes would be viable only if most client authors, like you, would be willing to add some tags when creating a kind 1 event. The least disruptive way (keeping backward-compatiblity while adding a minimum set of changes) I could come up with would be something like this example of a reply event:

{
    tags: [
      ['e', 'abc...', '<relay-url>', 'root'] // root event id
      ['e', 'def...', '<relay-url>'], // NEW - another ancestor, just like 'root' and 'reply' are ancestors of this event too ('ghi' is a reply to 'def')
      ['e', 'xyz...', '<relay-url>', 'mention'], // whatever mentions
      ['e', 'ghi...', '<relay-url>', 'reply'] // replied to event id
      ['l', '3'] // NEW - zero-based level/depth (in practice, just add up 1 to what was 'ghi' `l` tag OR count the non-mention e tags)
    ],
}

So just keeping all ancestors around inside e tags (not just root and reply) and adding an l tag to count the level/depth.

Edit: added the missing '<relay-url>' part.

arthurfranca avatar Mar 05 '23 12:03 arthurfranca

this would require finding all the ancestors for any particular event in order to create a reply which adheres to this standard. since there are already many clients not adhering to the recommendation of adding relay hints (even the example directly above neglects to show relay hint placeholder) it is pretty common to not be able to find ancestor events. if we are creating a new standard to make querying replies easier I don't want it to rely on something that is not guaranteed to be findable on nostr.

In my mind the only scenario in which querying for direct replies is problematic currently is for replies to root events, as the relay will return all events in the thread rather than just direct replies. I would support a change that gives direct reply tags and root tags different generic tags, and any event that is a direct reply to a root would have both a direct reply tag and a root tag. that way you can query the replies to a root event either by direct replies or by the whole thread.

for all non-root events we already have the ability to query for direct replies. however if we start adding 'e' tags for all ancestors this functionality will break.

also 'r' tag is being used to stand for 'relay' in nip65. not sure if we want to re-use 'r' tag with a different meaning here.

generally i don't care about knowing the exact thread depth of any particular event or querying by thread depth. I just want to be able to query for root ancestor, direct ancestor, thread replies, and direct replies for any event. currently for non-root events you can accomplish all of these. however for root events you cannot query for direct replies (and ancestor queries don't apply).

monlovesmango avatar Mar 06 '23 17:03 monlovesmango

l is not a good idea. Most client screens don't need to load the full thread. So, figuring l out for a new reply requires doing a lot more work. I am against it.

I am in favor of the practice of keeping all reply ids of the current branch of the thread (full path from leaf to root). Amethyst re-assembles the branch even if they are not there, but it's nice (faster) when they do. Current e tags are enough for that.

Reaction events (NIP-25) must copy b and l tags from the reacted-to event.

We should avoid this. Reactions need to be as lean as they can. It is just too much data to represent a "like".

An event can not be a reply to more than one event. (Or else it would mess with the l tag)

What if a reply from Thread A quotes another reply from thread B? I am in favor of differentiating "branch-path" and "citation"/"mention" e tags.

vitorpamplona avatar Mar 06 '23 18:03 vitorpamplona

@monlovesmango thank you for taking the time to give your view on it.

this would require finding all the ancestors for any particular event in order to create a reply

It would be enough to turn the previous id that has "reply" marker (or the last one, if deprecated way) into an ancestor e tag.

(even the example directly above neglects to show relay hint placeholder)

My bad. I will edit and fix it. Thanks for pointing it.

In my mind the only scenario in which querying for direct replies is problematic currently is for replies to root events

Yes it is the main problem and fixing this alone would be already a win. But some days after I created the issue, I found a recurrent use-case in major social apps (non-nostr) regarding what I called MITs, most interesting threads that would take advantage of requesting events at a specific level (sometimes deeper than direct descendant, so the l tag) and at a specific branch (that's why all ancestors would be needed).

for all non-root events we already have the ability to query for direct replies. however if we start adding 'e' tags for all ancestors this functionality will break

If i got it right, it wouldn't break if the ancestor e tags are not inserted at the last position ("deprecated" NIP-10 says the last one is the parent event). If using markers ("preferred" NIP-10) it would be there with the "reply" marker. Am I right?

also 'r' tag is being used to stand for 'relay' in nip65. not sure if we want to re-use 'r' tag with a different meaning here.

I think capital letters are allowed like 'R' instead

generally i don't care about knowing the exact thread depth of any particular event or querying by thread depth...

I understand that. If we make sure the change is backward-compatible, no clients would need to change the way they load threads, it would be just an option.

arthurfranca avatar Mar 06 '23 18:03 arthurfranca

@arthurfranca

It would be enough to turn the previous id that has "reply" marker (or the last one, if deprecated way) into an ancestor e tag.

if you do this you erode the ability to query for ONLY direct replies to the replied event's replied event. say you have event D that replies to event C (which is not the root event), and you want to reply to event D with event E. if you take event D's tag of event C and place it on event E as well, then querying for tags of event C no longer only returns direct replies but also replies of replies. the same problem we have with root events currently.

I found a recurrent use-case in major social apps (non-nostr) regarding what I called https://github.com/nostr-protocol/nips/issues/267#issuecomment-1450591924 that would take advantage of requesting events at a specific level (sometimes deeper than direct descendant, so the l tag) and at a specific branch (that's why all ancestors would be needed).

can you explain how querying for events at an arbitrary level makes it an interesting thread? comment, like, and zap counts definitely indicate whether a thread is interesting, but not level. if you use level you still have to query around for other pieces of data to truly determine if it is interesting. I am not grasping how querying by level lets you know its interesting and worth presenting to the user.

If i got it right, it wouldn't break if the ancestor e tags are not inserted at the last position ("deprecated" NIP-10 says the last one is the parent event). If using markers ("preferred" NIP-10) it would be there with the "reply" marker. Am I right?

no I don't think so. you cannot query a relay by 'e' tag position, nor 'e' tag marker. only by 'e' tag's second element, the event ID. when querying by 'e' tag, any event that has an 'e' tag (regardless of position or marker) will be returned.

I understand that. If we make sure the change is backward-compatible, no clients would need to change the way they load threads, it would be just an option.

if we don't have buy in from client authors to use this functionality to load threads then the whole incentive for implementing this is moot, regardless of whether they are willing to implement it in reply event tags. the LOE needed to implement this is still secondary to whether client authors find it useful.

I would support a branch 'b' tag to denote the thread branch a event is replying as to @vitorpamplona suggested with some stipulations:

  1. the 'b' tag for the root event can be clearly determined (either by a marker or ordering or something else)
  2. direct replies must still be tagged with 'e' tag (and can also be tagged with 'b' tag), otherwise we are just recreating the same problem we currently have of not being able to query for root event direct replies except with a whole new tag and for all events, not just root events.
  3. the only mandatory 'b' tag is for the root event, all other 'b' tags are optional

monlovesmango avatar Mar 06 '23 19:03 monlovesmango

@vitorpamplona thanks for joining the discussion!

l is not a good idea. Most client screens don't need to load the full thread. So, figuring l out for a new reply requires doing a lot more work. I am against it.

Add 1 to the parent event's l tag value. (Note: Root event is considered l zero). Alternatively, the l value it is the number of ancestors (or know ancestors in case of non conforming event, so best effort in this case).

I am in favor of the practice of keeping all reply ids of the current branch of the thread (full path from leaf to root)

That would be an upgrade indeed. Although without the l tag, it wouldn't address what @monlovesmango said: "In my mind the only scenario in which querying for direct replies is problematic currently is for replies to root events".

We should avoid this. Reactions need to be as lean as they can. It is just too much data to represent a "like".

You are right. I'm ok with keeping this part out. Although it would be a way to request branch replies that were liked by original poster or by a friend, so a missing opportunity to enhance clients further.

"An event can not be a reply to more than one event" - What if a reply from Thread A quotes another reply from thread B? I am in favor of differentiating "branch-path" and "citation"/"mention" e tags.

Can't have two parents, or else the reply would be from 2 branches (would have to copy both branch ancestor tags). Quote/Mentions kind of get in the way and should be filtered out client-side when requesting reply events if we reuse the e tag, as already happens. My previous proposal was to have a new tag for branch event ids (the b or even capital A meaning ancestor), and keeping e just for mentions. The down-side is that current clients are already using e for "root" and "reply", which are also ancestors. Using a new tag would need even more adoption from client authors. I'm ok with both ways. You, client authors, should decide.

arthurfranca avatar Mar 06 '23 19:03 arthurfranca