This is an object link.
", "tag": { "type": "Link", "name": "object link", "href": "https://example.com/some-object", "mediaType": "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"" } }Posts
-
Signalling "open in app" behaviour for AP contentjulian: I could theoretically override the anchor click handler to do a backend round-trip to check whether we could load the content in-app, otherwise fall back to a regular browser behaviour (a page navigation). i believe this is what mastodon does, but it's also worth mentioning fep-e232 Object Links as a way to tag a given Link with the appropriate mediaType used for content negotiation: { "@context": "https://www.w3.org/ns/activitystreams", "content": " -
How do we handle Groups (Reconciling FEP-400e and FEP-1b12)?angus: Navigating that thicket in a consistent way across the various implementations in #meeting:threadiverse-wg is the goal here. We definitely don’t want to create another standard silverpill: I don’t know how widely these features are implemented today (perhaps this is something the working group could include in the report?). devnull: we should conduct surveys to make sure we know what the implementation landscape looks like at current before attempting to write any guidelines. So I have to raise a tangential point here, which @devnull will probably be interested in as well: this is kind of what I set out to do in the WIP FEP i set out to start writing a week or two ago; at first it was 9988 "Federated Forums" to try to develop UX guidelines and map them to protocol affordances, but this eventually morphed into 8007 "A conformance profile for social networking services" (both titles pending of course). The general idea is that we all do certain things, and they map onto certain concepts, so we should map those common abstractions and primitives and try to concisely bound behavior of implementations such that you can actually know what to expect. I talk about this in 7888 a bit more, but there isn't actually a difference between the various spins of fediverse software. They're all just specific presentations of generic data. Or at least, on a protocol level, the abstractions of one specific presentation shouldn't leak in. What you have is objects or links, activities, collections. Those building blocks are then transformed into local entities, sure, but the primary focus should be on the protocol level building blocks and not on what any one platform assumes at a UX level. This is how you build commonalities. Practically speaking, a Note can be presented as a social media status or microblog entry or chat message or forum post or comment or whatever. And a Collection of Notes can be presented as a profile, thread, timeline, category, chat room, topic, et cetera. If the grouping is done with an explicit purpose, it ought to be declared as the context. With that said, there isn't really anything to "reconcile" about contextual grouping and distribution of activities. They're mostly orthogonal. The one point of intersection is whether any given actor will send out an Add or an Announce. And given that this is a working group for threaded conversations, it makes sense to me that the working group ought to describe how conversations are constructed. My personal opinion is that these conversations should be explicit based on context rather than implicit based on inReplyTo. Case in point: Consider the common forum use-case of "splitting a thread", which involves moving a post to another thread. That post may be a reply to a post from the original thread. It's important to be able to specify the intended grouping as a separate thing from who you're responding to. -
Clarification re: Inbox Forwardingthe "object being forwarded" in this case is the activity. the language is indeed ambiguous. it should say "the original activity being forwarded". the goal of the language there is to prevent new recipients from being picked up during the recursive processing of other metadata fields -- for example, you may institute a policy that incoming activities to be forwarded must be relevant to some local object, and so you check inReplyTo, etc. but you MUST NOT add inReplyTo.attributedTo if they were initially omitted from delivery addressing. you must only check that they are a local user (or whatever your check is). EDIT: https://github.com/w3c/activitypub/issues/441 -
Article vs. Note vs. Pagejulian: as:Article: Represents any kind of multi-paragraph written work. as:Note: Represents a short written work typically less than a single paragraph in length. as:Page: Represents a Web Page. these are the formal definitions, yes, but implementation practice has diverged somewhat. i think "paragraph length" is a bit of a red herring, as there are Notes with multipletags in the activitystreams/pub examples. there are also Notes with names (titles). i go into this more here: https://socialhub.activitypub.rocks/t/federating-the-content-of-posts-note-articles-and-character-limits/4087/7 julian: Mastodon only treats as:Note (and as:Question) as a first-class object and relegates anything else to a fallback handler that takes a short snippet of the content, and shows a link back to the original source, thus losing any in-app benefits (boosts, replies, etc.) Whether this is actually true or not, I do not know. https://github.com/mastodon/mastodon/blob/12ed2d793b1b4823b0df047a47677bb0667bf43d/app/lib/activitypub/activity.rb#L9 https://github.com/mastodon/mastodon/blob/65093c619fdd1b18a4cf0c288051d8c524d5f434/app/lib/activitypub/activity/create.rb#L375 julian: Lemmy, perhaps out of principle, sends out an as:Page for new generated content, and only the replies federate out as as:Note. It has unfortunately led to some assertions that Lemmy's federation is "broken", even though it is arguably not the case. to be honest i'm not sure why they do this. it's not particularly "wrong", it's just a little weird. the thing that's a bigger issue for federation is using Announce to wrap activities that ought to be forwarded. most other fediverse implementations operate at an object level, so Announce means sharing the object. Announcing activities as a substitute for proper inbox forwarding means that some implementations may interpret all of these Announces as separate "posts". This is also more of an issue when you deal with the "activity stream" directly, i.e. if you were Facebook -- there, an Announce Create Page" would be equivalent to saying in english "John reshared Sally's Create" rather than "Sally created a web page" or "John reshared Sally's web page". bringing it back to object types though, the expectation of Page is not "a submission to a link aggregating service". i would expect it to be reserved for actual web pages, like how Tumblr lets you create custom web pages in your blog theme editor. so i'd say that it breaks down more like this: Article = formally published text, like Wordpress, typically has a title and permalink (which may be used for "conversion" logic as mastodon does currently), may be read in a feed reader or syndicated to other publishers Note = informal text, like a status update or chat message or forum post or a comment in a comments section, etc. Typically viewed in context of something else (e.g. some collection of Notes, like a profile page, replies collection, context collection, or so on) Page = structured content meant to be displayed in a web browser, e.g. Neocities, or Tumblr's "custom pages". julian: that ought to change. The question is how, but this WG is not at the point where we start throwing around decrees and making up standards. What's important to me right now is what the landscape looks like right now, and why that is the case. i don't think it's "making up standards". i think it's just standards. you're not decreeing anything, you're just describing how things ought to be done. and on an ecosystem level, you get buy-in from implementers of those standards -- of which there should at least be NodeBB, Discourse, and Flarum, right? the process of standards alignment can be slow and painful, but it should be done nonetheless. the landscape right now looks like what it looks like because there hasn't been any real protocol stewardship, and Mastodon emerged as a de facto steward of its own protocol. how we change that is by developing actual standards via FEP, WG, etc. -- and then advocating other implementers use those standards for better interoperability. put another way, it's a question of trust and authority. in the absence of a trusted authority, implementers will do whatever they want. part of the argument for activitypub as a standard is that it received w3c approval as an official Technical Recommendation. at worst, it's a rubber stamp by one of the highest authorities of web standards. at best, it's a foundation for sharing activity streams on the linked data web. but it takes a lot of work from implementers and alignment initiatives to make it reach that point. "if no one implements it, all you have is a spec". strategically, another part of "how we change that" is by making it easier for implementers doing the "wrong* thing to transition to doing the "right" thing. providing migration paths. maybe even sending them PRs, instead of waiting for them to do it. it's outreach.
-
Clarification re: Inbox Forwardingjulian: If the activity is the thing being forwarded, then an additional complication could arise in that I cannot simply re-sign the activity, as my instance key does not belong to the originating actor. this is indeed an issue that arises due to the following: ActivityPub does not specify any authentication/verification mechanism HTTP Signatures, which the current fediverse uses, are not replayable or relayable. If you're concluding that this makes inbox forwarding impossible with HTTP Signatures, then congratulations, you understand why LD Signatures ended up being used for this (and why FEP-8b32 proposes using Data Integrity Proofs at the LD level as well). It's either that, or find a way to replay entire HTTP messages (so that the HTTP Signature can be validated against the original HTTP interaction). Or otherwise rethink the fundamentals of the fediverse's entire security model. -
Desired UX for forums, and accompanying user storiesOK, so here's what I've got so far, I'd really appreciate if others could add onto this with their expectations. This is basically the skeleton for what used to be FEP-9988 (which I've put on hold, since it doesn't quite make sense as a FEP in its current state -- maybe later, though!). ---Glossary
forum : A central hub of discussion bound by an audience user : Someone who makes posts post : An article of discussion topic : A collection of posts grouped by a common title and/or subject category : A collection of topics grouped by a common title and/or subject ---UX for Posts (Objects, Notes, etc) (0th order Collections)
Posts can have titles
Posts can be responding to 0-n other posts
Posts should be viewed in context of the topic
Posts can be moved to other topics
---UX for Topics (Threads, Conversations, Contexts, etc) (1st Order Collections)
Topics contain posts
Topics can be split
Topics can be closed for further posts ("locked")
Topics can have a name, summary, content that is separate from the first post
Topics can be followed for new posts
Topics exist in a category
Topics can be moved between categories
---UX for Categories (Forums/Subforums, etc) (2nd Order Collections)
Categories contain topics
Categories can be followed for new topics
Categories can feature certain topics in a certain order to the top of the list of topics ("pinned")
The "pin" can have an expiry?
Categories can have parent categories and subcategories
---UX for Users
Users can be followed for posts and topics
Users can be messaged directly
-
Handling "410 Gone" when retrieving an actorYou could do what Reddit does and just leave the posts up but pointing to a tombstone user. If you've ever seen a post attributed to
[deleted]
then you know what I'm talking about.The problem with that is it possibly (probably¿) violates social expectations around what an account deletion does. Arguably this could be solved by an extension property or type like "DeleteAllCreatedObjects" or whatever. But some implementations might not be able to do that because they don't keep track of objects by who created them. The other option is to support deleting multiple objects at a time? This stuff is best-effort, though, so it might fail for some of the objects.
-
Traversing the reply chain when working with topicsi meant the latter but you could probably do the former if there were a mechanism to link together equivalent contexts as aliases of each other. for now, the easiest thing to do would be to just copy the "authoritative" one by whoever created the thread. -
Changing the domain of an existing instancejulian:Are there any established best practices, or am I destined to lose all of my followers?
Probably the latter, as this is a Hard Problem. I think the “state of the art” is to have a long-lived domain name which redirects to the current location — see also the PURL concept. Bluesky/ATProto gets around this by having a centralized nameserver, the “placeholder server” that assigns and resolves did:placeholder DIDs. Essentially you will need some stable authority for naming things.
-
How do you use `context` (if at all)?One thing to mention about context is that there are a few somewhat open questions about its usage: Does it contain objects or activities? If it contains activities, does it contain Creates or also other activities (Like, Announce, etc)? What is the ordering? These kinds of questions are rather freeform because it's somewhat up to implementers to make a decision about that. I personally think it should be just the objects, as I'm not convinced it's particularly important to have a complete backfilled view of every single like and share, or being able to construct an edit log with every single Create/Update. From the point of view of a casual consumer, that information can be lazy-loaded through checking the likes or shares collection; an optimization would be for the producer to partially embed a representation of those collections with a totalItems and maybe the first page, in order to support a "x, y, and 8 others liked this post" type of UX. But this is a matter of preference; "object or activity" is a longer-standing philosophical debate, as much as is "what makes a conversation". For the maintainer of a context, it might make sense to say "be prepared to support heterogeneous collections of both objects and activities", as the sender might attach the context to the object, the activity, or both. In theory, if you receive a Create Note with context attached to both, you might expect that both of them will be contained in the (implicit) grouping. But for maintaining an explicit collection, you kind of get to choose how to go about that. Again, I'm a little wary of placing mandates and restrictions on this, in fear of getting it "wrong* and shutting the door on some implementers. I also think the ordering should be forward chronological instead of reverse chronological, but this is part of a larger issue with collections ordering and paging: https://socialhub.activitypub.rocks/t/stricter-specifications-for-pagination-of-collections-and-orderedcollections/2633 (btw, the assertion that "every OrderedCollection MUST be reverse chronological" has been somewhat recently clarified/relaxed to only the ones introduced in activitypub as OrderedCollection) -- the ideal would be to be able to, as a consumer, request the collection with parameters for ordering, page size, and start index. But failing that, we could just fall back to a similar requirement of reverse chronology... although I dislike and hesitate to enforce this as a MUST. (The ship may have already sailed for this, but I likewise wish/think that the activitypub OrderedCollections were forward chronological instead of reverse chronological. there's something conceptually backwards about the whole thing.) -
NodeBB v4.0.0 Betaat the risk of igniting a protocol war, i'm not sure OpenWebAuth is the best solution for cross-domain identity, for a few reasons:
- it has reliances on older and not-widely-implemented technologies. the rest of the tech space is converging on oauth and related technologies, and not the old http signatures cavage draft stuff. using webfinger to look up a "magic endpoint" for the user, and again to look up the "root url" to find a bespoke "token endpoint", is simply duplicating a lot of work that has been standardized in other specifications.
- it makes no proper distinction between the key and the actor. the problem with current public key infrastructure in fedi is that keys are not only custodial, but they may be shared across the entire server. so anyone else on your server may be able to access remote resources "on your behalf", as it were, in the case that a single keypair existed and was declared for every single actor on the local origin.
- it relies on query parameters which can easily leak into logs or get copied-and-pasted accidentally by a user. the proper place for authorization tokens and such is in the Authorization header (which does not generally get logged).
- it assumes that there is a "home instance" and does not support the possibility of external identity providers that are not themselves fediverse instances.
-
Article vs. Note (redux!) — summary of current implementationsjulian: Mike (upthread) suggested a compromise: that as:Note be reserved for content with attachments (images or otherwise), perhaps with a limited subset of html and as:Article be used for content with a richer set of html (e.g. tables), and including the ability to display inline images I explicitly did not specify that Note was for shorter content and Article for longer, because there exist plenty of examples of the reverse. Does anybody see potential complications from such an arrangement? I think the distinction that makes sense to me is still "do you intend for this to be formally published or not". Length and formatting are red herrings. The entire Note vs Article "distinction" is literally just "tweet vs blog post" in how it came about. From the perspective of a service like Twitter or Facebook, the Note indicates it's a "status update" whereas the Article indicates it should be shown/presented in their article publishing feature (which Twitter ironically called Notes). Consider this litmus test: if viewing the object at a permalink, does it make sense on its own, or do you need more context? If you need more context, it's probably a Note. If it makes sense on its own, it's probably an Article. (Note that this doesn't prevent Articles from having a context property.) -
How do you use `context` (if at all)?There's three possibilities laid out in FEP-7888 regarding the use of
context
:- It's missing. Fall back to other heuristics (inReplyTo, etc) to do implicit grouping.
- It's a non-dereferenceable URI. Do explicit grouping against this URI.
- It's a dereferenceable object. Do explicit grouping against the ID, and also:
- if it is a
Collection
/OrderedCollection
and hasattributedTo
, you can assume thatattributedTo
will be maintaining the collection; in such a case, you can opt into the rest of FEP-7888 by sending your participatory activity to theattributedTo
actor and alsoaudience
/followers
if present.
- if it is a
With that said, the use of the "root-node Object" as
context
is supported, but not recommended. It represents a sort of halfway-point where you probably have anattributedTo
that can moderate the conversation, but there isn't an explicit representation of the conversation viaitems
/orderedItems
/outbox
. The authority of theattributedTo
to moderate downstream replies is not clearly established anywhere, hence it not being a great idea to do this. -
How do you use `context` (if at all)?julian:- Short of that it's easier to just maintain your own context and canonical URL. That's this line in 7888:
- You MAY set your own context, if you wish for your object to be in a separate context owned by you.
I might have not phrased that clearly enough -- there is a soft assumption in 7888 that there is only one context set, especially when reading those bullet points. In other words, you would be overwriting the one context with another. This is the same as "starting a new thread" or "forking the topic".
At the same time, it should be possible for context collections to have multiple identifiers --
id
being "canonical" and aliases being present inalsoKnownAs
. I feel like having multiple collections for the same topic is not a good way forward; it's better to look at it as a state synchronization problem instead, with one collection at the origin being the source of truth. You maintain a local cache of that collection. -
How do you use `context` (if at all)?If "pending" is something you feel uneasy with, would it be better to look at it as "approved" or "verified" once you get the Add? The idea is that in some future where more implementations do this, it can become a policy decision whether to show "unverified" posts. In the meantime, you can show a checkmark or other icon to indicate it's been stamped by the authority.
-
Re: 400e, 7888, and conversation containersI don't think "obsolete" is the right framing here. You can mostly consider Conversation Containers to be a synthesis of 7888 and 400e, and if they dropped
target
on the object (invalid) and on the Create activity (undefined), then it would basically be 7888. -
How do we handle Groups (Reconciling FEP-400e and FEP-1b12)?julian:Sure, I'd miss some of the activities around it, so that's a concern, but it's not a dealbreaker. That's why I'm on the fence about this one.
You'd be missing activities regardless. If someone sends a
Create Note
with acontext
to the context manager, and I'm following the context and receive this activity, I might send aLike
to the author of the Note but NOT to the context manager. In that case, the only way to obtain a complete view of thelikes
collection for that Note is to ask its authoritative origin. This is going to be something that happens a lot due to the messiness of fediverse implementations -- you might have 3 Likes be delivered directly to the context manager, but 7 other Likes be delivered only to the author of the liked post. If you are only processing the context collection, then does the post in question have 3 likes, or 10? -
FEP Convergence (400e, 7888, 171b/Conversation Containers, 76ea)julian:They establish a conversational context for a given object
from my understanding, only 7888 and 171b do this. 76ea instead tries to establish a central view of a reply tree, which is not the same as a conversation. there are several cases where replies and context diverge:
- replying to something in a different conversation (for example, when conversations get forked or posts get moved to a new conversation)
- participating in a conversation without replying
- replying without participating in a conversation
also, there is the consideration that
julian:context
is used for grouping, even if it's not resolvable. so it gracefully falls back to basic grouping behavior in the simplest case.thr:thread
doesn't do this.They federate out an
Add
on collection addition. (76ea also sendsRemove
)you can send a Remove in all three FEPs, it might just not be called out explicitly. the use of Add/Remove is a courtesy to anyone else following along, so they don't have to fetch the collection manually every single time. (although fetching the collection every single time is inefficient, it is the only way to have a guaranteed consistent state, so there are reasons why you may want to browse the collection "at the authoritative origin", so to speak.)
julian:171b specifies a new object type
Context
i am not strictly opposed to this, but neither do i support it. it might end up being useful to define a type that means "this specifically represents a collection whose items share the same
context
property" (as i thinkContext
is trying to do), but this should not be required.similarly, we could define a type that means "this specifically represents a collection whose items all have
content
" (we could call itConversation
orCollectionOfPosts
orCollectionOfContentfulObjects
or whatever) but this is similarly something that shouldn't be required.the reason that i think such types shouldn't be required is that not only are they not necessary for the basic mechanisms to work, they also might be misleading or incorrect, because ultimately the contents of any collection are solely decided by whoever owns the collection. i could declare that a collection is a
julian:Context
and then immediately after this i go and Add a bunch of objects that don't have thatcontext
, or anycontext
at all for that matter. this is something that is going to be very relevant in the interim where NodeBB and similar implementations continue to have behavior for traversing reply trees and attaching posts to topics that aren't explicitly declared ascontext
. (not that i think this behavior is necessarily always correct, either -- it's just something that could be done, and is probably useful to do, insofar as other implementations continue to remain unaware ofcontext
and its grouping properties. you could just as equally convert posts withinReplyTo
but nocontext
into NodeBB Chat Messages instead of NodeBB Topic Posts... but this is an implementation decision.)Collection items:
- 7888 sends objects in chronological order
- 171b sends activities in chronological order
- 76ea sends objects in reverse chronological order
7888 is agnostic as to what the exact contents are, aside from them ideally all sharing the same
context
-- you could have a 7888 collection contain any type in any order. however, with that said: i favor post objects (anything that hascontent
) in forward chronological order, because this is what is most useful to the casual browser. i don't know of any forum software that chooses to present threads in reverse order with the newest posts at the top. they usually do this for topics, but not for posts.also: these are "defaults", and ultimately we should probably move toward explicitly signaling how collections might be ordered or sorted, as well as providing a mechanism for requesting non-default presentations like "show me this thread in reverse chronological order" (
?reversed=true
or?sort=newest
or whatever) or "show me posts starting at index 69 and containing 7 items" (?startIndex=69&window=7
). to that end, i recently submitted https://w3id.org/fep/1985 for declaring anOrderedCollection
to have an explicitorderType
ofForwardChronological
orReverseChronological
. i also have a pre-draft of a FEP dealing with collections that are not just ordered sets, but specifically sorted sets. this would defineSortedCollection
as an extension ofOrderedCollection
, as well as defining asortedBy
property pointing to a vocab term, plus asortType
of eitherAscending
orDescending
. there's https://socialhub.activitypub.rocks/t/pre-fep-evolving-orderedcollection-to-be-more-useful/4608 as the thread exploring this.regarding the signaling of any given collection or actor following a specific protocol, i think we should define that explicit protocol before defining types. my old draft of FEP-9988 for "Federated Forums" was put on hold for exactly this reason -- there are simply too many protocol considerations that need to happen first. https://socialhub.activitypub.rocks/t/desired-ux-for-forums-and-accompanying-user-stories/4181 or https://community.nodebb.org/post/99491 exists as a thread to collect user stories for forum UX that should directly inform the development of such a protocol.