-
Notifications
You must be signed in to change notification settings - Fork 569
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
We need a way to request direct replies to a note #267
Comments
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. |
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 Use-case 2: Start at root note and fetch the child notes (building the reply tree from top down). With this proposal, can use |
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). |
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 Theoretically, I think that it would be nice to have some way of asking for the "direct children" of a note (query the I think that, if a note I suppose it would be inelegant to include the same data in an {
...,
"tags":[["e","aaa..."],["p","ccc..."],["e","bbb..."],["dd","2"]],
...
} This note would be a direct descendant of {
"#dd": ["bbb..."],
} would match the above note. For reducing amount of logic, the Seems like something like this could slowly replace |
It is late here. and perhaps my idea is ridiculous. will leave it up for posterity. EDIT (added later):
|
OP here, not main acc
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.
@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. |
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. |
Ok got it barkyq. I don't know what the best approach is but i think we do need this feature. |
Well I suppose there are (at least) three options. Option 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. The bandwidth downside to Option 1 is mitigated if compression is used. |
They can already fetch the parent note. |
|
@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:
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. |
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 Also, sidebar, there is not really a well-adopted "current standard." Half the people use There is certainly some discussion to be had whether this actually achieves anything beyond what can already be achieved using 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 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 But it seems @fiatjaf isn't convinced. |
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 |
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. |
Yes, except that an Although I guess this could be handled (in a bit of a complicated way) by checking if there is only |
I am partial to the addition of tags like 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 |
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.
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
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 If we use the Speaking of markers, now there is #293 pr for |
tl;drI'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 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. 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 The level An event can not be a reply to more than one event. (Or else it would mess with the 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 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
} |
Please people mention client authors you know so that they see this issue. |
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 An alternative solution to this problem could be to solve it on the relays' side with a new filter, for example |
@staab thank you for your feedback as a client author.
Edit: Either way, some |
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 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 Edit: added the missing '<relay-url>' part. |
You make a good point. It does can be a breaking change for clients that currently do this (Are you currently relying on this? As you said, the problem already exists for root tags so it seems clients are loading all replies at once and then filtering client-side the slice they want, so maybe won't be a problem)
It wouldn't be an arbitrary level. See how Twitter shows a branch A-B-C and A-X-Y at top if C and Y are from the same author than A? (It is an interesting thread/slice cause the original poster replied to it) So you request for replies 2 levels down A's level that has A's pubkey. This is one of many examples unlocked by the branch (where A is ancestor) and level/depth (n levels below A) tags. Likes alone may be spammed, so that's why I also added that reaction events should copy all ancestor tags and the level tag from replied to event. (But @vitorpamplona don't like it because it makes reactions bigger). Knowing from what branch and level a zap is would be also good, but i haven't read zap NIP.
I think markers were a mistake because of what you said. I think not being able to query by relay url isn't a big deal, but many times you want just the events with a specific marker but you end up getting events with a different one. Ideally,
Yes you are right. I was assuming a new way of requesting direct descendant could be used (one level down, so request with event current's Any upgrade is a win. If you think allowing more use cases with the |
@monlovesmango So if I wasn't able to change your mind regarding
While @vitorpamplona (if still not buying the
Sorry if i misunderstood. Now I ask you:
|
I like option 1 a lot. this would also enable doing thread-like queries for non-root events, which I think would be really convenient. the last 'b' tag with 'reply' marker should also be marked as optional. agree that 'e'-'root' tag should no longer be needed. I know I suggested ordering, but would prefer to use markers over ordering as nip10 deprecated using ordering and want to stay consistent. I am against option 3 with only 'e' tags as this will now make finding direct replies inefficient for non-root events as well. Sorry, I am still not buying that 'l' tag is useful/needed. But would be nice to hear what other client devs think. Thanks for pushing this conversation forward @arthurfranca ! |
To be clear, I don't have a use for What about an additional filter attribute/format for any non-index-1 tag element:
All
You could download only kind 1s that directly cite a user:
The same could happen for Then all tags should be indexed. You could even do a search by
or do a search for
What about a search for image sizes on NIP-58?
The format could be I assume this could be beneficial for other event kinds that have more information on them. |
relay devs would have to weigh in on that, as it means that more than just the first two elements of a tag need to be indexed in the relay db. if people are ok going down this route then we can probably get by with just 'e' tags. personally I do see the appeal of having these kinds of filters, however I worry more about bloating the relay db. indexing the 3rd element provides significantly less value than indexing the 2nd element, but they both have the same cost. also there are no essential use cases that need anything but the first 2 elements of a tag for querying, and all of the potential use cases you highlighted above are bit weird and made up (except the first one that this new type of filter would solely be created for). |
@monlovesmango @vitorpamplona I see we can settle that both of you liked having all ancestor ids listed, very useful for walking up the tree faster among other uses. We effectively moved away from having a parent tag. Though we still have to solve the problem of immediate replies for root events.
Although @staab, @monlovesmango, @mikedilger, @barkyq and I consider this part important, @vitorpamplona doesn't care much for his client as he said "I don't have a use for l or for a filter for immediate replies on kind 1". Yet, @vitorpamplona suggests a way of solving it: "an additional filter attribute/format for any non-index-1 tag element", which is ingenious, but would certainly have to be a new NIP (instead of NIP-10 edit, keeping an eye on breaking changes as @fiatjaf is worried), with a risk of less adoption cause it would also depend on relay operators. As @monlovesmango says, "relay devs would have to weigh in on that [...]". So, as far as I know, for root immediate replies we have this novel filter (needs new relay functionality)... {
"kinds": [1],
"#e": [ 'root id' ]
"#e:3": [ 'reply' ]
"limit": 5
} ... versus this filter (need the {
"kinds": [1, 30023],
"#b": [ 'root id' ], /* I used #b instead of #e cause of @monlovesmango*/
"#l": [ '1' ]
"limit": 5
} |
I think the main question is: Are markers good? Are markers a good design pattern for new NIPs moving forward? Do we want more If so, we should have extended filters for them. If not, we should expect, and work through all event kinds, to avoid the use of generic tags like |
Here are my 2 cents:
By moving to a IMHO, It would be better to keep using By having everything filterable, there is less of a need to create new tag names when simple extensions to the graph are required by domain-specific needs of each event kind out there. For instance, I would love to have the same direct mention/citation marker for |
I think relays aren't applying special treatment depending if the tag is
Expanding all tag values (not just the value at position 1) to be searchable may rule out some relay databases, decreasing db diversity. Perhaps it is easier to squeeze the current nostr-protocol further, as it already demonstrates it is capable of enabling many use cases without change. I really don't know. |
Now featuring @fiatjaf himself! You can see the same pattern on Twitter! How the direct reply is shown at the top of the thread, beacause it was replied by fiatjaf, the OP: |
Above screenshots show how we could load most "interesting" replies at the top, while keeping spam and least interesting replies at the bottom. All apps shown also benefit from lazy-loading the thread instead of loading everything at once. It is just not a best practice requesting all thread at once. All this would be possible with the changes I'm proposing. Changes to kind 1 creation that aren't complex at all. |
I personally think these screenshots show some of the worst aspects of these centralized social platforms. The UX is optimized for useless pumping of engagement and awful for actual conversations, it's a lab rat. So far Nostr clients have been delivering an experience that is far superior to the annoyances depicted above. |
Omg, I consider it is totally the opposite ^-^. I understand this is debatable. Also, you created Nostr so you get to decide what gets merged. A person reading a post by Alice will want to see comments that Alice replied to, because she started the coversation. If I'm reading Alice's blog, I want to know her opinion. I want to follow conversations in which she is involved. Of course not exclusively, but it has a higher probablity of being more important than a Random guy's comment that could be spam or a sub thread going totally out of topic. I also consider it a good way to push down spam. Likes are usually evil, but if we promote to the top the comments liked by your friends, I guess now they are not anymore. In the example I gave, it was a like from OP, but could be from your friends. If we are talking about a client as Twitter that limits char count, I also want to read the thread of Alice replying to herself multiple times first.
If using paid relays, paid with satoshis, that regular Joes can't use to join conversation. Haven't heard of any relay that fights spam by using another technique yet. What I presented at least may allow clients to hide spam below comments that client at least consider on topic. Lets not forget the cell phone plan spending GB quota faster than it could be by downloading entire threads from multiple relays. We need lazy-loading possibility in my opinion. |
Just as a side note: thinking about it, there is no strong reason to need a branch It works ok with regular In a nutshell, a new reply event just needs to:
But yeah, if no developer other than me gets the importance of this, this will unfortunately never see the light of the day. |
@vitorpamplona I've downloaded Amethyst and noticed it splits feed into two tabs: "New topics" and "Threads" (don't know exact text as mine is in pt-BR). In the future, if clients adopted the level/depth tag, including even on root events ( It would allow you to get only root events with the filter And also the other tab with the following filter |
The issue is that I never expect ALL clients to adopt this mode. Thus, to avoid UX inconsistency with posts that should have been there but are not, I most likely would lever use this as a filter. I would download everything and "fix stuff up" when they arrive. |
Yes many clients will want to support all the known patterns of replying to an event to not miss events when fetching them. Atleast for a transition period. For example, I don't expect the "deprecated" section of NIP-10 to be supported forever by clients, specially new ones. I wanted to point this out to show the usefulness of the proposed changes, among other uses already mentioned. This issue is aiming to reduce number of events retrieved on some event subscriptions, while unlocking a few new use cases. If it makes it into a NIP, I expect that eventually up-to-date or new clients will adopt. |
again, just to reiterate, the only posts that you currently cannot request direct replies from is the root event. with the current model you can already request direct replies of any event that is not the root event. your new proposed strategy would break this ability for clients that don't adopt I am STRONGLY AGAINST adding a whole list of However, I think you have changed my mind about the level If we keep NIP-10 as is and just add the
what do you think? if you still think we need all ancestors listed as |
@monlovesmango considering the following reply tree with three brances (R A B C D, R W X Y Z and R W X N): If i'm reading the R event view, I can get the root direct replies by subscribing to That's why we need to have all ancestors, so that in the second example we can instead use We can safely get X direct replies with Considering the screenshot examples, we can also get non-immediate descendants deeper in a branch to unlock said use cases. Just to make it clear, Y for example would have the following |
in current state, you CAN get the W direct replies filtering by
I don't think this is useful enough to warrant listing all ancestors as |
I was took by surprise when you first said that some clients are fetching direct replies of non-root events, because if I were to build a nostr client I would use just one strategy, if possible, no matter if loading a root note view or a non-root one. So currently the only strategy in common would be using So my goal when starting this gh issue was to present an alternative strategy, shareable by root and non-root views, that would allow for fetching just direct replies, while letting clients still use the previous strategy if they wish. It could be done with a capital The "all ancestors plus the
So as you can see, the "all ancestors plus the Though at this point, I'm skeptical that any of these solutions will get picked. The majority of client authors seem to be comfortable with the current way of handling event replies as things are already coded. Unfortunately just you @monlovesmango and me kept interest in this discussion. |
I'm closing to keep repo lean as this was a lost battle =) |
EDIT: Hello client authors, please skip to this comment to read the tl;dr of the last version of this proposal.
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:
e
tags mentioned in contente
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 noteSo 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.
The text was updated successfully, but these errors were encountered: