#2372·anytype-ts

Discussion: replies to replies (depth ≥ 2) sync and increment unread, but are never rendered

Author: GeekSquirrelCreated Sep 11, 2026Updated Sep 11, 2026

Summary

The desktop Discussion UI renders only two levels of a reply thread: top-level posts and their direct replies. A reply whose parent is itself a reply (depth ≥ 2) is stored and synced correctly — it increments the unread/mention badge and is visible on other clients — but it never appears in the desktop thread view.

Steps to reproduce

  1. Open an object with a Discussion section.
  2. Create a top-level post (A).
  3. Reply to A (B) — renders nested, as expected.
  4. Create a reply whose reply_to_message_id targets B (C). The desktop UI offers no way to post a depth-2 reply itself, so the deterministic reproduction is the local HTTP API / anytype-mcp: POST /v1/spaces/{space_id}/chats/{chat_id}/messages with reply_to_message_id = B. The official anytype-mcp server makes this easy to hit.
  5. Watch the desktop client: the unread/mention badge for the object increments, but C never appears in the thread. The same thread on Android shows A, B and C.

Actual result

  • C is persisted and synced: it shows up in ChatGetMessages, renders on Android, and increments the desktop unread/mention counters.
  • Desktop never renders it — there is no render slot for a reply whose parent is not a top-level post.

Expected result

Deeper replies should be visible: either flatten depth ≥ 2 under their thread root (Android-style, see below) or render the tree recursively. Alternatively, if single-level threading is a deliberate product decision, messages that cannot be rendered should not increment unread/mention counters.

Code reference

src/ts/component/comment/section.tsxbuildTree:

javascript
const posts   = messages.filter(it => !it.replyToMessageId);  // only these render as the main list
const replies = messages.filter(it => it.replyToMessageId);

// replies are grouped by their DIRECT parent id...
S.Comment.setPosts(sid, posts);
// ...and only groups keyed by a post id are ever rendered

A reply C with replyToMessageId = B lands in a group keyed by B's id. Since B is itself a reply (not in posts), that group has no render target and is silently dropped.

For comparison, the Android client (anytype-kotlin, DiscussionViewModel.kt) handles arbitrary depth: it resolves the parent chain (depthOf, with cycle protection) and collects the reply subtree recursively (collectReplies), flattening it into a list with depth annotations.

The data model has no depth limit — reply_to_message_id is a plain id reference and ChatGetMessages returns the full chain.

Environment

  • Anytype desktop (anytype-ts), observed on the current release line (v0.56.9-alpha, 2026-09-07) with the Discussion feature
  • Reproduced via the local HTTP API and cross-checked against Android (anytype-kotlin), where the same thread renders fully

Suggested fix

Treat threading as a tree of arbitrary depth: flatten depth ≥ 2 replies under their thread root (Android-style DFS with depth annotation) or render recursively. If single-level threading is intentional, suppress unread/mention counting for messages that cannot be displayed.