code
Clone this repository
https://tangled.org/bretton.dev/coves
git@knot.bretton.dev:bretton.dev/coves
For self-hosted knots, clone URLs may differ based on your setup.
Run go fmt, gofumpt, and make lint-fix to ensure code quality:
Formatting fixes:
- Standardize import block formatting across all files
- Apply gofumpt strict formatting rules
- Remove nil checks where len() is sufficient (gosimple)
Code cleanup:
- Remove unused setupIdentityResolver function from tests
- Fix comment_consumer.go: omit unnecessary nil checks
All critical lint issues resolved ✅
Only fieldalignment optimization suggestions remain (non-critical)
Files affected: 17 Go files across:
- cmd/server
- internal/api/handlers/comments
- internal/atproto/jetstream
- internal/core (comments, posts)
- internal/db/postgres
- tests/integration
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit resolves 5 critical issues identified during PR review:
## P0: Missing Record Fields (Lexicon Contract Violation)
- Added buildPostRecord() to populate required postView.record field
- Added buildCommentRecord() to populate required commentView.record field
- Both lexicons mark these fields as required, null values would break clients
- Files: internal/core/comments/comment_service.go
## P0: Handle/Name Format Violations
- Fixed postView.author.handle using DID instead of proper handle format
- Fixed postView.community.name using DID instead of community name
- Added users.UserRepository and communities.Repository to service
- Hydrate real handles/names with DID fallback for missing records
- Files: internal/core/comments/comment_service.go, cmd/server/main.go
## P1: Data Loss from INNER JOIN
- Changed INNER JOIN users → LEFT JOIN users in 3 query methods
- Previous implementation dropped comments when user not indexed yet
- Violated intentional out-of-order Jetstream design principle
- Added COALESCE(u.handle, c.commenter_did) for graceful fallback
- Files: internal/db/postgres/comment_repo.go (3 methods)
## P0: Window Function SQL Bug (Critical)
- Fixed ListByParentsBatch using ORDER BY hot_rank in window function
- PostgreSQL doesn't allow SELECT aliases in window ORDER BY clause
- SQL error caused silent failure, dropping ALL nested replies in hot sort
- Solution: Inline full hot_rank formula in window ORDER BY
- Files: internal/db/postgres/comment_repo.go
## Documentation Updates
- Added detailed documentation for all 5 fixes in COMMENT_SYSTEM_IMPLEMENTATION.md
- Updated status to "Production-Ready with All PR Fixes"
- Updated test coverage counts and implementation dates
## Testing
- All integration tests passing (29 total: 18 indexing + 11 query)
- Server builds successfully
- Verified fixes with TestCommentQuery_* test suite
Technical notes:
- Service now requires all 4 repositories (comment, user, post, community)
- Updated test helpers to match new service signature
- Hot ranking still computed on-demand (caching deferred to Phase 3)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add comprehensive documentation for comment system Phase 2A:
Overview:
- Complete guide from indexing (Phase 1) through query API (Phase 2A)
- Implementation dates: November 4-5, 2025
- 30+ integration tests, all passing
- ~4,575 total lines of code
Phase 2A documentation:
- Lexicon definitions (defs.json, getComments.json)
- Database layer with Lemmy hot ranking algorithm
- Service layer with iterative loading strategy
- HTTP handlers with optional authentication
- 11 integration test scenarios
Hot ranking algorithm section:
- Full SQL formula with explanation
- Component breakdown (greatest, power, offsets)
- Sort modes (hot/top/new) with examples
- Path-based ordering for tree structure
- Behavioral characteristics
Future phases:
- Phase 2B: Vote integration (2-3 hours)
- Phase 2C: Post/user integration (2-3 hours)
- Phase 3: Advanced features (5 sub-phases)
- Distinguished comments
- Search & filtering
- Moderation tools
- Notifications
- Enhanced features
- Phase 4: Namespace migration (separate task)
Implementation statistics:
- Phase 1: 8 files created, 1 modified (~2,175 lines)
- Phase 2A: 9 files created, 6 modified (~2,400 lines)
- Combined total: ~4,575 lines
Command reference:
- Separate test commands for Phase 1 and Phase 2A
- Build and migration instructions
- Environment variable setup
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add 11 integration test scenarios covering full stack (600 lines):
Core functionality:
- TestCommentQuery_BasicFetch: Verify basic comment retrieval with stats
- TestCommentQuery_NestedReplies: Validate recursive threading structure
- TestCommentQuery_DepthLimit: Test depth boundaries (0, 3, 10, 100)
- TestCommentQuery_EmptyThread: Handle posts with no comments gracefully
- TestCommentQuery_DeletedComments: Soft-deleted comments excluded
Sorting algorithms:
- TestCommentQuery_HotSorting: Verify Lemmy hot rank formula
- Recent medium score beats old high score
- Negative scores handled (bounded at log(2))
- TestCommentQuery_TopSorting: Score-based with timeframe filters
- TestCommentQuery_NewSorting: Chronological ordering
Pagination:
- TestCommentQuery_Pagination: Cursor stability with 60 comments
- No duplicates between pages
- All comments eventually retrieved
Input validation:
- TestCommentQuery_InvalidInputs: 6 subtests for error cases
- Invalid URI, negative depth, bounds clamping
- Invalid sort/timeframe parameters
HTTP layer:
- TestCommentQuery_HTTPHandler: End-to-end request handling
- Valid requests with query params
- Missing/invalid parameter errors
Test helpers:
- setupCommentService: Initialize service with mocked dependencies
- createTestCommentWithScore: Create comments with specific stats
- Service adapter for HTTP testing
All tests passing ✅
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Integrate comment query API into server:
- Initialize comment service with repository dependencies
- Register XRPC route: /xrpc/social.coves.community.comment.getComments
- Apply OptionalAuthMiddleware for viewer-specific responses
- Add startup logging for API availability
Route supports:
- Authenticated requests (Bearer token) → viewer state included
- Anonymous requests → public read access
- Query parameters per lexicon spec
Service adapter bridges handler and domain layers for clean separation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implement HTTP layer for GET /xrpc/social.coves.community.comment.getComments:
get_comments.go (168 lines):
- GetCommentsHandler: Main XRPC endpoint handler
- Parses query parameters (post, sort, depth, limit, cursor, timeframe)
- Validates inputs with clear error messages
- Extracts viewer DID from auth context
- Returns JSON matching lexicon output schema
- Comprehensive validation:
- Required: post (AT-URI format)
- Bounds: depth (0-100), limit (1-100)
- Enums: sort (hot/top/new), timeframe (hour/day/week/...)
- Business rules: timeframe only valid with sort=top
errors.go (45 lines):
- writeError: Standardized JSON error responses
- handleServiceError: Maps domain errors to HTTP status codes
- 404: IsNotFound
- 400: IsValidationError
- 500: Unexpected errors (logged)
- Never leaks internal error details
middleware.go (22 lines):
- OptionalAuthMiddleware: Wraps existing auth middleware
- Extracts viewer DID for personalized responses
- Gracefully degrades to anonymous (never rejects)
service_adapter.go (40 lines):
- Bridges handler layer (http.Request) and service layer (context.Context)
- Adapter pattern for clean separation of concerns
Security:
- All inputs validated at handler boundary
- Resource limits enforced
- Auth optional (supports public read)
- Error messages sanitized
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add service layer orchestrating comment queries and thread assembly:
comment_service.go (285 lines):
- GetComments: Main query method with validation and pagination
- buildThreadViews: Recursively constructs comment trees
- Iterative loading strategy (loads 5 replies per level)
- Respects depth limit (default 10, max 100)
- Sets HasMore flag for pagination hints
- buildCommentView: Converts entities to API views
- Hydrates author from CommenterHandle
- Builds stats (upvotes, downvotes, score, replyCount)
- Creates post/parent references with CIDs
- Stub viewer state (Phase 2B)
- validateGetCommentsRequest: Input validation with defaults
view_models.go (150 lines):
- CommentView: Complete comment with author, stats, viewer state
- ThreadViewComment: Recursive wrapper for nested replies
- Supporting types matching lexicon definitions
- Follows existing patterns from posts.AuthorView
Changes to existing files:
- comment.go: Add CommenterHandle field (hydrated at query time)
- errors.go: Add IsValidationError helper for handler error mapping
Design decisions:
- Empty slices instead of nil (JSON serialization)
- Iterative loading prevents N+1 query explosion
- Soft-deleted comments filtered out
- Post/user integration stubbed (Phase 2C)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>