mastodon / mastodon

Your self-hosted, globally interconnected microblogging community
https://joinmastodon.org
GNU Affero General Public License v3.0
47.2k stars 7k forks source link

Implement hushtags #32890

Open upstreamist opened 1 week ago

upstreamist commented 1 week ago

Pitch

Hushtags are a proposed complement to hashtags. Their function would be to suppress the visibility of a post to any accounts that have not specifically opted into seeing that topic.

The proposed syntax is to put the octothorpe at the end of the word, rather than at the beginning. Thus, the hashtag for ducks would be #ducks, while the hushtag for the same topic would be ducks#. Unless you follow or search the #ducks hashtag, posts tagged ducks# won't show up in your timeline, even if they originate from an account you follow.

I've elaborated more on the idea here

If the hastag/hushtag terminology is too confusing, the hushtags could also be called shibboleths, since that's effectively how they function.

Motivation

The current filtering system is great for a lot of use-cases, but places responsibility for visibility decisions on the potential recipient of a post. Hushtags are courtesy functionality—that is, they're functions employed by the creator of a post out of consideration to potential recipients. (Content warnings are a similar courtesy function.)

Consider the topic "Kansas politics." That topic is not particularly relevant to the vast majority of the people on the fediverse, and there's no particular reason they should see posts about a Kansas state legislature election unless they're specifically looking for posts on that topic. Tagging such posts KSPol# would automatically exclude those posts from the timelines of anyone who hadn't specifically opted into seeing the subject, e.g. but searching or following the #KSPol hashtag.

Regional politics is a good example, because there are so many regions with their own potential hashtags that leaving it to the end user to filter out the topics they don't want to see quickly becomes burdensome. Opt-in is a better strategy than opt-out for dealing with that volume of topics, and hushtags render topics opt-in.

Another example: consider NSFW topics. Yes, those can also be filtered out by keyword or hashtag, but guessing every possible topic that could come through your timeline is impossible, and leaves greater scope for mishap. The internet is a creative venue, and when new topics or a new name arises, there's often a lag between its creation and people's ability to update their filters. Rapid hushtag adoption would help address that lag.

Hushtags aren't a total solution to the problem of unwanted content, but broad adoption could lower the overall risk of unwanted material making it through an account's other safety precautions.

shleeable commented 6 days ago

This is an interesting concept but I'd rather just see groups get added. People who like KSPol could join a group dedicated to that topic.

trwnh commented 5 days ago

i'm generally inclined to agree that having functionality for posting in specific contexts would probably address this better than adding another microsyntax (that will at best be highly mastodon-specific if we implemented it, i don't see other projects adopting this idea) -- anything will do here, as long as it doesn't show up in followers' timelines without them explicitly following it.

more broadly, the desired functionality can be captured not only by "groups", but also by "streams". a stream is basically a collection of posts that you can post into, and it can be followed separately from the authors. the difference between a "group" and a "stream" is mostly in who is allowed to post into it. you can maintain one or more streams linked to your profile/account; say there is a default "all posts" stream but you can also have a "kspol" or "nsfw" stream, and on a per-stream or per-post level you can decide who gets to see what, by sending your post into a stream, and by letting streams have their own followers. it's kind of like multi-account separation except without having to manage multiple accounts.

there's some earlier discussion #5515 and #1208 regarding this. and of course for groups there's #139 and #19059

in a practical sense the first step would be to make it so that your posts don't necessarily always go to all of your followers? or at least, independently of delivery, there should be some signal to indicate when a post should be inserted into a timeline or not.

upstreamist commented 5 days ago

One advantage to the hushtag model, I'd argue, is that it's simpler to teach. People already bounce off of Mastodon for its perceived complexity, and I'm not sure there's an implementation of groups/streams that won't require an increase in end-user setup and informal training. Hashtags, on the other hand, are a standard feature across most social media platforms, most social media users already understand them, and this is really just a variation on their use. Anyone who groks hashtags can be taught to use hushtags in just a sentence or two: "Move the symbol to the end of the tag if you only want the post to show up for people who have searched or followed the hashtag."

Unless I'm misunderstanding the proposed functionality of groups, another advantage would be that hushtags piggyback on the global nature of hashtag use. That is to say, a post tagged mutualAid# would reach everyone who has followed the #mutualAid hashtag, whereas posting into a group first requires you to know that the group exists. Likewise, posting to everyone interested in, say, RubyOnRails# wouldn't require you to know about every group talking about Ruby On Rails.

Which isn't to deny that some users would get value out of having channels for posting only to limited membership groups. That's just not the use case that hushtags were conceived for. And the choice doesn't have to be either/or.

Cassolotl commented 5 days ago

In a microblogging context like Mastodon, hushtags seem more intuitive and more appropriate (in terms of complexity) than groups, to me.

trwnh commented 5 days ago

I think it might make sense to try to break it down into the core functions that are trying to be addressed here:

The problem is that at a protocol level it doesn't work out. Using the microsyntax will be ignored by every existing software. Even hashtags don't actually work off of the contents of the post; protocol-wise, you check the tags and not the content. You can "hashtag" something without ever using a #hashtag. Same way you can "mention" someone without ever using an @mention (using to/cc). The microsyntax is generally ignored.

In the past (before ActivityPub), there were !bangtags for groups; you could send your post to a group, which was basically a fancy hashtag.

After ActivityPub, you have things like Guppe groups which you can @mention and they will boost your post. You can follow those "groups" to explicitly opt into seeing those posts.

Generally in ActivityPub, following something is how you explicitly opt into seeing it. The harder part is in hiding it automatically for people who follow you, not the tag. You generally need a way to send your post not to your followers, but to some other audience instead.

"Groups" do this, by making your posts not go to your followers.

"Streams" can do this too, albeit in a different way -- by allowing people to follow subsets of your posts instead of all of your posts.

"Hushtags" can't really do this, at least not on their own, not without a predefined audience, or otherwise a way to send a post to your followers while indicating that they shouldn't see it (how?)

I think the challenge is in getting the behaviors that you want, in a way that everyone else will understand. It might be conceptually simple to say "move the hash symbol to the end" -- it's no different than using any other symbol in any other position. But it is technically difficult to translate that into the protocol layer. What should happen when a "hushtag" is used? Who is the post sent to? Keep in mind that sending a post to someone means they can see it.

upstreamist commented 4 days ago

I'm not really qualified to assess the technical challenge, but it seems to me that visibility settings already provide a precedent for this approach. Hushtags are effectively a granular approach to implementing a "hashtag-followers only" visibility setting. And Mastodon servers already handle half of the functionality by allowing users to follow hashtags. If servers can pick out every federated post containing a particular hashtag and insert them into the timeline of an account that has followed that hashtag, then I wouldn't expect it to be all that difficult to simply not deliver hushtagged posts to any account except those containing the same trigger.

Going back to my original post, though, I want to emphasize the part about this being courtesy functionality. The point is to make context-specific posts less intrusive while maintaining accessibility, even when you don't know who might be interested. Part of the reason hushtags would be useful, even if Mastodon were to implement groups, is that (other features not intervening) they allow anyone to reveal the conversations they tag. It isn't meant as a security feature, and shouldn't be promoted as a way to exclude specific people or pass private messages. (I may have confused that point with some of the language I've used.)

To that end, it doesn't particularly matter if other AP services ignore the syntax—at least, not from a privacy viewpoint. People using those services won't get the benefits of the added functionality, but they also won't being seeing messages that they wouldn't have gotten otherwise. On the other hand, if the syntax proves useful, then it's reasonable to expect other services to adopt it, which will expand its utility. Hashtags went through virtually the same process, and now they're considered a standard feature across platforms.

Cassolotl commented 4 days ago

Github is just a bit like that, at least on this list. You propose an intuitive feature from the perspective of the user, and the developers/programmers say "we don't know how to do that"/"that's not how we do things here" but with a lot more words and a bunch of information that you can't really use, and then 7 years later it gets implemented and no one credits you because you don't know any programming languages.

Input from people who are just users without knowing how things are made is really important for making software that is usable for average people*, but people sometimes/often don't really like that here, I find.

* Kind of related to that xkcd comic a bit - it's hard to judge what is usable to the average non-techy user when you're fully buried in behind-the-scenes code and everyone you talk to is very programmingy.

trwnh commented 4 days ago

Microsyntax is one thing. You probably could trigger special behavior in Mastodon by typing this# instead of #this. That's not the hard part.

The hard part is figuring out exactly what this# should do, and how to describe that clearly in a world where not everything is Mastodon. I'm not a developer or a programmer but I'm trying to describe the issue with this from the perspective of someone trying to model this semantically, on an information level. It's like sending someone an email that contains this# but expecting it to not show up in their inbox unless they click the appropriate button somewhere else first. The problem is that by default, emails show up in inboxes.

If it's acceptable from a functionality viewpoint (not necessarily a privacy one) to say "hushtags work like this, except when they don't work at all"... then okay, I guess there's no problem, we can proceed. But that seems like a confusing thing to me.

I might be misunderstanding the ask here, but I'm reading it as

Their function would be to suppress the visibility of a post to any accounts that have not specifically opted into seeing that topic.

Tagging such posts KSPol# would automatically exclude those posts from the timelines of anyone who hadn't specifically opted into seeing the subject, e.g. by searching or following the #KSPol hashtag.

lower the overall risk of unwanted material making it through an account's other safety precautions

So it seems to me like having them actually work the way as one would describe/expect ("specifically opted into seeing") is important... is it not? What's the point of a "hushtag" if it doesn't "hush" the post?


The way around this, at least from what I can see, is to be very clear that your post is being sent only to people who "specifically opted into seeing" the post... and the protocol way to do that is with following.

Given that one of the things said above was this:

a post tagged mutualAid# would reach everyone who has followed the #mutualAid hashtag, whereas posting into a group first requires you to know that the group exists

then it sounds like the intent is for "hushtags" to also function as "hashtags"? Which makes it seem like they could be represented as an extension of "hashtags". But you'd still have to figure out where to send your post. Unfortunately, posts don't go from server to server, they go from actor to actor -- by default, "all your followers" are included.

I guess the way forward that requires the least amount of difficult changes would be:

Overall this might be enough to get the basic feature working... it would mostly require some changes in Mastodon, but not so much on the protocol level, aside from the requirement that a) there is a shared inbox, and b) it accepts Public posts addressed to no one in particular.

I guess another thing to consider is that this doesn't even have to be limited to "hushtags"; it could be thought of as working with regular "hashtags" plus some rework of the visibility/scope system in Mastodon to allow sending a post to the Public pseudo-collection but not to your followers.

upstreamist commented 4 days ago

then it sounds like the intent is for "hushtags" to also function as "hashtags"? Which makes it seem like they could be represented as an extension of "hashtags".

Correct. They're effectively "if and only if" versions of hashtags.

So it seems to me like having them actually work the way as one would describe/expect ("specifically opted into seeing") is important... is it not? What's the point of a "hushtag" if it doesn't "hush" the post?

The same could be asked of any feature that isn't universally implemented across federated AP-based services. Preferably, it works, but we accept some level of uneven implementation as a consequence of interoperability. It seems to me that there are two principle ways to deal with that fact:

  1. Conceptual positioning Despite how I've sometimes described it above, the goal of hushtagging shouldn't be to hide the contents of a post, since the post remains Public and anyone could, in principle, see it. Rather, the point is to help others reduce the noisiness of their timelines while remaining accessible to people for whom a topic counts as signal. Setting that expectation (which, admittedly, I may not have done well above) should go a long way toward lowering the risks when the convention fails.

  2. Fallback behavior Mastodon can't ensure adoption on other services, but there may be ways to structure the feature so that its behavior is at least predictable even when it fails. That was pointed out to me in a discussion earlier today: https://mastodon.gal/@xurxodiz/113511400570209955 Xurxo pointed out that retaining a # at the beginning of the tag would ensure that other services continue to treat it as a hashtag, which would retain at least part of the expected behavior. Using a bracket-like syntax, rather than the end-tag syntax I originally suggested—i.e. #foo# rather than foo#—would make failure more elegant.

  • Make shared inboxes accept Public posts that don't address anyone else.
  • When Mastodon detects that a local user has used a "hushtag", strip all recipients before delivering to shared inboxes, but otherwise deliver to the appropriate shared inboxes as normal.

I think I understand what you're outlining and why, but I wonder if it wouldn't be less complicated to have the receiving server readdress hushtagged posts to a dummy Actor. That way, the post is still addressed, and shared inboxes can accept the post without alteration to their current behavior.

trwnh commented 4 days ago

Xurxo pointed out that retaining a # at the beginning of the tag would ensure that other services continue to treat it as a hashtag, which would retain at least part of the expected behavior. Using a bracket-like syntax, rather than the end-tag syntax I originally suggested—i.e. #foo# rather than foo#—would make failure more elegant.

This is ironically the "easy part" -- it doesn't matter "behind the scenes" whether you type #foo or foo# or #foo# or ##foo or anything at all or even nothing at all! This is because all microsyntaxes are actually ignored entirely, and we use a dedicated property tag instead. As far as interpretation is concerned, it is still (or can be) literally "just a hashtag". So it continues to function as a hashtag... by virtue of being an actual hashtag. No magic going on at all in the tag property; the magic happens during delivery using to/cc.

{
  "content": "This is a post that uses a hashtag. You can't tell just by looking at the content, but it's true!",
  "tag": [
    {
      "type": "Hashtag",
      "name": "KSPol"
    }
  ],
  "to": "as:Public"
}

This is probably not the most elegant thing ever, but you can deliver the above post to servers via their shared inboxes; the "hard part" is defining how the server should find delivery targets, and also defining what to do if you get a post like this. It's probably easier in Mastodon, because Mastodon can do whatever it wants, including "find all followers of the author, then pretend they were addressed, then deduplicate by shared inboxes, then drop anyone who wasn't explicitly mentioned (?), then finally deliver to those inboxes". It doesn't really work for generic servers unless they somehow keep track of every known shared inbox and maybe sometimes deliver to every known shared inbox. (This is a more general spec issue, by the way; just mentioning it here off-handedly.)

Out of curiosity, I went looking for the code that actually handles shared inbox delivery, and it looks like the code is shared with all inboxes, most relevant bit here:

https://github.com/mastodon/mastodon/blob/30e9c7137bf6fc2ca17766a58bd6d682971b0c7a/app/lib/activitypub/activity/create.rb#L17

https://github.com/mastodon/mastodon/blob/30e9c7137bf6fc2ca17766a58bd6d682971b0c7a/app/lib/activitypub/activity/create.rb#L393-L396

So it looks like it actually might already work, assuming that at least one local account follows the author of the received post. At least for Mastodon.

Which I guess leaves how to handle it on the UX side in the composer.

Between "define a new microsyntax" and "define a new scope", I'm not sure what the better option would be, as there are tradeoffs and negatives to both. I guess this is the part where we all bikeshed how it should look when presented to the user. xD