Reply
Reply is not a Post subtype -- it's a separate Mongoose model with its own self-contained handler. It does not delegate to Create; this is a deliberate architecture decision, not an oversight.
{ "type": "Reply", "objectType": "Reply", "to": "post:64f0...@kwln.org", "object": { "type": "Reply", "source": { "content": "Nice post!", "mediaType": "text/markdown" } }}A bare object.content string is also accepted as a fallback to object.source.content.
Required: actorId, objectType === "Reply", object (an object), to (the ID of whatever is being replied to -- a Post or another Reply).
Threading model
Section titled “Threading model”Threading is capped at two levels, Facebook-style. to is resolved server-side into:
target-- the root Post (always the top-level Post, soGET /posts/:id/repliescan return the entire thread in one query, and federation can route to the post's host).parent-- the immediate parent, but never deeper than a first-level reply. A reply to a second-level reply flattens onto its level-1 ancestor.
Reply.to, .canReply, and .canReact on the created document are always blank strings -- visibility is entirely inherited from the root post. These fields exist only for possible future-proofing; don't rely on them being populated.
authorizeInteraction({ actorId, targetId: rootId, capability: "canReply" }) -- gated against the root post's canReply, not the immediate parent's.
Content-based dedup
Section titled “Content-based dedup”Identical source.content from the same actor to the same parent, within a 5-minute window, returns the existing Reply instead of creating a duplicate (duplicated: true in the response). This is independent of the dedupeKey mechanism described in Overview.
Side effects
Section titled “Side effects”- Bumps
User.replyCount(the author),replyCounton the root object (tried acrossPost/Page/Bookmark/Group/Circlecollections via the raw driver, bypassing Mongoose hooks) and itsFeedItemscache entry -- and, for second-level replies only, also bumps the first-level parent reply's ownreplyCount. - Notifies the author of the thing actually replied to (the immediate parent, not necessarily the root author), respecting
prefs.notifications.reply. notifyMentionsfires for@user@domaintags in the body.- Federation is routed to the root post's host domain, plus the replied-to author's domain (via
getMultiFederationTargets).
Response
Section titled “Response”{ activity, created: <Reply doc>, federation } (or { ..., duplicated: true } on a content-dedup hit).
Client mapping
Section titled “Client mapping”reply({ postId, inReplyTo, content }) matches exactly -- inReplyTo || postId becomes to. The result's target field holds the root post's ID, not literally "the parent" in the colloquial sense; that's parent. If you're reading the created Reply back from the client, don't assume target means "what I replied to" -- use parent for that.