Skip to content

fix(threads): collect nested replies from the conversation edge - #268

Open
kevin9327 wants to merge 1 commit into
getopenpost:mainfrom
kevin9327:fix/threads-nested-replies
Open

kevin9327 wants to merge 1 commit into
getopenpost:mainfrom
kevin9327:fix/threads-nested-replies

Conversation

@kevin9327

Copy link
Copy Markdown
Contributor

Summary

ThreadsAdapter.ListComments read GET /{media-id}/replies, which returns only the top-level replies to a post. Any reply to a reply never reached the engagement inbox. That includes the most common follow-up, a follower answering the account's own reply. This change reads GET /{media-id}/conversation instead, which returns replies at every depth, and sets ParentID from replied_to so the inbox threads each reply under the one it answers.

Motivation

From the Threads Replies and Conversations reference:

  • /replies "only returns the top-level replies under the Threads ID provided in the request".
  • /conversation "returns all replies, regardless of the depth, either in chronological or reverse chronological order". Its reverse parameter defaults to true (newest first), the same as /replies.
  • Both edges take the same fields, including is_reply_owned_by_me and hide_status, which the adapter already reads. They need the same permission, since the reference's permission list scopes it to GET calls on reply endpoints.
  • replied_to is "Media ID of the immediate parent of the reply" and is returned as {"id": ...}.

This is the same gap #257 closed for PieFed's reply tree.

Threading follows what the other adapters already do (#240). A nested reply's ParentID is the ID of the reply it answers, which the inbox matches against remote_id. A top-level reply's replied_to is the post itself, which is not a collected comment, so it still shows as top level. The account's own replies keep IsOurs from is_reply_owned_by_me, so they stay out of the inbox as before.

Testing

  • Backend tests pass (go test ./internal/platform/...)
  • Frontend tests pass (bun run --filter @openpost/web test): no frontend change
  • Linting passes (go vet, gofmt, gofumpt, golangci-lint run ./internal/platform/...: 0 issues, same as main)
  • Manually tested:
    • New TestThreadsListCommentsCollectsNestedReplies serves both edges the way the reference describes them. /replies holds only the top-level reply, and /conversation holds it plus the account's own reply and a follower's answer to that reply. The test checks that all three are collected, that the follow-up is threaded under the account's reply, and that ownership is kept.
    • The existing TestThreadsListCommentsMarksOwnRepliesAsOurs now expects the /conversation path.

Fails on unmodified main:

=== RUN   TestThreadsListCommentsCollectsNestedReplies
    threads_comments_test.go:68:
        	Error:      	"map[reply-fan:{reply-fan    fan   Does it support video? ...}]" should have 3 item(s), but has 1
--- FAIL: TestThreadsListCommentsCollectsNestedReplies (0.00s)

Passes with the fix. go test ./internal/platform/... is ok, and go build -tags dev ./... is clean. go test -coverprofile shows every changed line runs under the tests. I have not tested this against a live Threads account. The behavior is taken from the reference quoted above.

Checklist

  • My code follows the project's coding conventions
  • I have added tests that prove my fix is effective
  • I have updated documentation if needed: added changes/threads-nested-replies.md
  • I have used Conventional Commits for my commit messages
  • I have checked that there are no other PRs open for the same issue/feature

Breaking Changes

  • Yes
  • No

Affected Components

  • Backend (Go)

Platform Impact

  • Threads

🤖 Generated with Claude Code

ListComments read GET /{media-id}/replies, which returns only the
top-level replies to a post. A reply to a reply, such as a follower
answering the account's own reply, never reached the inbox. Read
GET /{media-id}/conversation instead, which returns replies at every
depth with the same fields, and thread each one under replied_to.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 18, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 14 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 4 included reviews currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: ac70d5dc-7c36-4855-b9a4-83fcffca7670

📥 Commits

Reviewing files that changed from the base of the PR and between 542f87b and fbbdec0.

📒 Files selected for processing (3)
  • apps/server/internal/platform/threads.go
  • apps/server/internal/platform/threads_comments_test.go
  • changes/threads-nested-replies.md

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant