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.
Implement PutRecord in PDS client with swapRecord CID validation:
- Add ErrConflict error type for HTTP 409 responses
- Add PutRecord method to Client interface with optimistic locking
- Map 409 status to ErrConflict in wrapAPIError
Migrate UpdateComment to use PutRecord:
- Use existingRecord.CID as swapRecord for concurrent modification detection
- Add ErrConcurrentModification error type in comments package
- Return proper error when PDS detects CID mismatch
Testing:
- Add PutRecord unit tests (success, conflict, typed errors)
- Add PutRecord to mockPDSClient for unit test compatibility
- Add integration test for concurrent modification detection
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Implement comment deletion that preserves thread structure by keeping
tombstone records with blanked content instead of hiding comments entirely.
Features:
- Add deletion_reason enum (author, moderator) and deleted_by column
- Blank content on delete but preserve threading references
- Include deleted comments in thread queries as "[deleted]" placeholders
- Add RepositoryTx interface for atomic delete + count updates
- Add validation for deletion reason constants
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add SoftDeleteWithReasonTx to mockCommentRepo implementing RepositoryTx.
Update SoftDeleteWithReason to validate deletion reason and delegate
to the Tx method.
Update test for deleted comments to verify they appear as placeholders
with IsDeleted=true instead of being filtered out.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Replace inline SQL in deleteCommentAndUpdateCounts with call to
SoftDeleteWithReasonTx via type assertion to RepositoryTx interface.
This eliminates duplicate deletion logic between consumer and repo
while maintaining atomic transaction for delete + count updates.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add buildDeletedCommentView method that creates placeholder views
for deleted comments with blanked content but preserved threading.
Update buildThreadViews to include deleted comments instead of
skipping them, enabling child comments to remain visible with
their parent showing "[deleted]".
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add SoftDeleteWithReason and SoftDeleteWithReasonTx methods that:
- Blank content, facets, embed, and labels on deletion
- Set deletion_reason and deleted_by metadata
- Validate deletion reason is author or moderator
- Support optional transaction for atomic operations
- Return rows affected for idempotency checks
Update all thread queries to include deleted comments by removing
deleted_at IS NULL filter, preserving thread structure.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add SoftDeleteWithReason to Repository interface for content-blanking
soft deletes that preserve thread structure.
Add RepositoryTx interface with SoftDeleteWithReasonTx method for
transactional operations, enabling atomic delete + count updates
in the Jetstream consumer.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add IsDeleted, DeletionReason, and DeletedAt fields to CommentView
for rendering deleted comment placeholders in thread views.
Frontend can display "[deleted]" or "[removed by moderator]" based
on the deletion_reason field.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add DeletionReasonAuthor and DeletionReasonModerator constants.
Add DeletionReason and DeletedBy fields to Comment struct for
tracking who deleted a comment and why.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add migration 021 that:
- Creates deletion_reason enum type (author, moderator)
- Adds deletion_reason and deleted_by columns to comments table
- Backfills existing deleted comments as author-deleted
- Removes deleted_at IS NULL filter from thread indexes to preserve structure
- Adds indexes for deletion_reason and deleted_by for moderation queries
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add complete comment write operations (create/update/delete) with:
- XRPC lexicons for all three operations
- Service layer with validation and authorization
- HTTP handlers with proper error mapping
- Comprehensive unit and integration tests
- Proper grapheme counting with uniseg library
Follows write-forward architecture: Client → Handler → Service → PDS → Jetstream → DB
Add two P3 technical debt items for future optimistic locking:
1. Implement PutRecord in PDS Client
- Add swapRecord/swapCommit for optimistic locking
- Handle conflict responses gracefully
2. Migrate UpdateComment to Use PutRecord
- Blocked by PutRecord implementation
- Will prevent concurrent update races
These items are not urgent since concurrent comment updates are rare,
but will improve robustness when implemented.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>