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.
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>
Implement database layer for comment queries with Lemmy hot ranking:
New repository methods:
- ListByParentWithHotRank: Query with hot/top/new sorting + pagination
- Hot: log(greatest(2, score + 2)) / power(time_decay, 1.8)
- Top: Score-based with optional timeframe filter
- New: Chronological ordering
- Cursor-based pagination with composite keys
- GetByURIsBatch: Batch fetch comments by URIs (prevents N+1 queries)
- GetVoteStateForComments: Fetch viewer votes (Phase 2B ready)
Key features:
- Hydrates author handle via JOIN with users table
- Supports timeframe filters (hour/day/week/month/year/all)
- Encodes cursors with hot_rank|score|created_at|uri
- All queries use parameterized arguments (SQL injection safe)
Formula prevents brigading:
- greatest(2, score + 2) ensures log never goes negative
- Heavily downvoted comments bounded at log(2)
- Power of 1.8 for faster decay than posts (1.5)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add lexicon definitions for comment query API following Bluesky patterns:
- social.coves.community.comment.defs: Shared view definitions
- commentView: Base view for single comment with stats and viewer state
- threadViewComment: Recursive wrapper for threaded replies
- Supporting types: commentStats, commentViewerState, commentRef, etc.
- social.coves.community.comment.getComments: Query endpoint
- Parameters: post (required), sort, depth, limit, cursor, timeframe
- Returns threaded comments with nested replies up to depth limit
- Supports hot/top/new sorting with Lemmy-style hot ranking
Follows atproto best practices:
- Composition pattern (threadView wraps baseView)
- Union types for error states (notFound, blocked)
- Open unions for future extensibility
- Strong references with CID version pinning
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>