+35
-52
docs/PRD_BACKLOG.md
+35
-52
docs/PRD_BACKLOG.md
···-โ `ResolveCommunityIdentifier()` already implemented at [service.go:843](../internal/core/communities/service.go#L843)···-When comments arrive before their parent post is indexed (common with cross-repo Jetstream ordering), the post's `comment_count` is never reconciled. Later, when the post consumer indexes the post, there's no logic to count pre-existing comments. This causes posts to have permanently stale `comment_count` values.-- Comment consumer updates post counts when processing comment events ([comment_consumer.go:323-343](../internal/atproto/jetstream/comment_consumer.go#L323-L343))-- When post consumer later indexes the post, it sets `comment_count = 0` with NO reconciliation-Post consumer MUST implement the same reconciliation pattern as comment consumer (see [comment_consumer.go:292-305](../internal/atproto/jetstream/comment_consumer.go#L292-L305)):···-- Post indexing from Jetstream ([post_consumer.go](../internal/atproto/jetstream/post_consumer.go))-- ๐ด Issue documented with FIXME(P1) comment at [comment_consumer.go:311-321](../internal/atproto/jetstream/comment_consumer.go#L311-L321)-- โ ๏ธ Test demonstrating limitation exists: `TestCommentConsumer_PostCountReconciliation_Limitation`-- `tests/integration/post_consumer_test.go` - Add test for out-of-order comment reconciliation
···+- Post creation already uses `ResolveCommunityIdentifier()` at [service.go:100](../internal/core/posts/service.go#L100)+- Accepts handles (`@gaming.community.coves.social`), DIDs, and scoped format (`!gaming@coves.social`)+- Added comprehensive tests: [block_handle_resolution_test.go](../tests/integration/block_handle_resolution_test.go)+โ `ResolveCommunityIdentifier()` already implemented at [service.go:852](../internal/core/communities/service.go#L852)···+When comments arrive before their parent post is indexed (common with cross-repo Jetstream ordering), the post's `comment_count` was never reconciled, causing posts to show permanently stale "0 comments" counters.+- โ Post consumer reconciliation logic WAS already implemented at [post_consumer.go:210-226](../internal/atproto/jetstream/post_consumer.go#L210-L226)+- โ Comprehensive test suite added: [post_consumer_test.go](../tests/integration/post_consumer_test.go)+- โ Updated outdated FIXME comment at [comment_consumer.go:362](../internal/atproto/jetstream/comment_consumer.go#L362)···
+45
-44
internal/api/handlers/community/block.go
+45
-44
internal/api/handlers/community/block.go
············// Extract authenticated user DID and access token from request context (injected by auth middleware)············// Extract authenticated user DID and access token from request context (injected by auth middleware)···
······+// Accepts DIDs (did:plc:xxx), handles (@gaming.community.coves.social), or scoped (!gaming@coves.social)+// The block record's "subject" field requires format: "did", so we resolve the identifier internally.······// Extract authenticated user DID and access token from request context (injected by auth middleware)···+// This allows users to block by handle: @gaming.community.coves.social or !gaming@coves.social···+// Accepts DIDs (did:plc:xxx), handles (@gaming.community.coves.social), or scoped (!gaming@coves.social)······// Extract authenticated user DID and access token from request context (injected by auth middleware)···+// This allows users to unblock by handle: @gaming.community.coves.social or !gaming@coves.social
+6
-10
internal/atproto/jetstream/comment_consumer.go
+6
-10
internal/atproto/jetstream/comment_consumer.go
···
···
+3
-2
internal/core/unfurl/providers.go
+3
-2
internal/core/unfurl/providers.go
···
···
+337
tests/integration/block_handle_resolution_test.go
+337
tests/integration/block_handle_resolution_test.go
···
···+req := httptest.NewRequest(http.MethodPost, "/xrpc/social.coves.community.blockCommunity", bytes.NewBuffer(reqJSON))+req := httptest.NewRequest(http.MethodPost, "/xrpc/social.coves.community.blockCommunity", bytes.NewBuffer(reqJSON))+req := httptest.NewRequest(http.MethodPost, "/xrpc/social.coves.community.blockCommunity", bytes.NewBuffer(reqJSON))+req := httptest.NewRequest(http.MethodPost, "/xrpc/social.coves.community.blockCommunity", bytes.NewBuffer(reqJSON))+req := httptest.NewRequest(http.MethodPost, "/xrpc/social.coves.community.blockCommunity", bytes.NewBuffer(reqJSON))+req := httptest.NewRequest(http.MethodPost, "/xrpc/social.coves.community.blockCommunity", bytes.NewBuffer(reqJSON))+req := httptest.NewRequest(http.MethodPost, "/xrpc/social.coves.community.unblockCommunity", bytes.NewBuffer(reqJSON))+req := httptest.NewRequest(http.MethodPost, "/xrpc/social.coves.community.unblockCommunity", bytes.NewBuffer(reqJSON))
+434
tests/integration/post_consumer_test.go
+434
tests/integration/post_consumer_test.go
···
···+commentURI := fmt.Sprintf("at://%s/social.coves.community.comment/%s", testUser.DID, commentRkey)+err = db.QueryRowContext(ctx, "SELECT comment_count FROM posts WHERE uri = $1", postURI).Scan(&dbCommentCount)+t.Run("Multiple comments arrive before post - count reconciled to correct total", func(t *testing.T) {